diff --git a/ChangeLog b/ChangeLog index fd83b9e60..b38d56f27 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,11 @@ PolarSSL ChangeLog (Sorted per branch, date) += PolarSSL 1.3.10 released ??? + +Features + * Certificate selection based on signature hash, prefering SHA-1 over SHA-2 + for pre-1.2 clients when multiple certificates are available. + = PolarSSL 1.3.9 released 2014-10-20 Security * Lowest common hash was selected from signature_algorithms extension in diff --git a/library/ssl_srv.c b/library/ssl_srv.c index 211ab5d47..04608ee98 100644 --- a/library/ssl_srv.c +++ b/library/ssl_srv.c @@ -776,7 +776,7 @@ static int ssl_check_key_curve( pk_context *pk, static int ssl_pick_cert( ssl_context *ssl, const ssl_ciphersuite_t * ciphersuite_info ) { - ssl_key_cert *cur, *list; + ssl_key_cert *cur, *list, *fallback = NULL; pk_type_t pk_alg = ssl_get_ciphersuite_sig_pk_alg( ciphersuite_info ); #if defined(POLARSSL_SSL_SERVER_NAME_INDICATION) @@ -814,15 +814,36 @@ static int ssl_pick_cert( ssl_context *ssl, continue; #endif + /* + * Try to select a SHA-1 certificate for pre-1.2 clients, but still + * present them a SHA-higher cert rather than failing if it's the only + * one we got that satisfies the other conditions. + */ + if( ssl->minor_ver < SSL_MINOR_VERSION_3 && + cur->cert->sig_md != POLARSSL_MD_SHA1 ) + { + if( fallback == NULL ) + fallback = cur; + continue; + } + /* If we get there, we got a winner */ break; } - if( cur == NULL ) - return( -1 ); + if( cur != NULL ) + { + ssl->handshake->key_cert = cur; + return( 0 ); + } - ssl->handshake->key_cert = cur; - return( 0 ); + if( fallback != NULL ) + { + ssl->handshake->key_cert = fallback; + return( 0 ); + } + + return( -1 ); } #endif /* POLARSSL_X509_CRT_PARSE_C */ diff --git a/tests/ssl-opt.sh b/tests/ssl-opt.sh index f94808d2c..2cf4b6e70 100755 --- a/tests/ssl-opt.sh +++ b/tests/ssl-opt.sh @@ -956,6 +956,60 @@ run_test "Authentication: client no cert, ssl3" \ -C "! ssl_handshake returned" \ -S "X509 - Certificate verification failed" +# Tests for certificate selection based on SHA verson + +run_test "Certificate hash: client TLS 1.2 -> SHA-2" \ + "$P_SRV crt_file=data_files/server5.crt \ + key_file=data_files/server5.key \ + crt_file2=data_files/server5-sha1.crt \ + key_file2=data_files/server5.key" \ + "$P_CLI force_version=tls1_2" \ + 0 \ + -c "signed using.*ECDSA with SHA256" \ + -C "signed using.*ECDSA with SHA1" + +run_test "Certificate hash: client TLS 1.1 -> SHA-1" \ + "$P_SRV crt_file=data_files/server5.crt \ + key_file=data_files/server5.key \ + crt_file2=data_files/server5-sha1.crt \ + key_file2=data_files/server5.key" \ + "$P_CLI force_version=tls1_1" \ + 0 \ + -C "signed using.*ECDSA with SHA256" \ + -c "signed using.*ECDSA with SHA1" + +run_test "Certificate hash: client TLS 1.0 -> SHA-1" \ + "$P_SRV crt_file=data_files/server5.crt \ + key_file=data_files/server5.key \ + crt_file2=data_files/server5-sha1.crt \ + key_file2=data_files/server5.key" \ + "$P_CLI force_version=tls1" \ + 0 \ + -C "signed using.*ECDSA with SHA256" \ + -c "signed using.*ECDSA with SHA1" + +run_test "Certificate hash: client TLS 1.1, no SHA-1 -> SHA-2 (order 1)" \ + "$P_SRV crt_file=data_files/server5.crt \ + key_file=data_files/server5.key \ + crt_file2=data_files/server6.crt \ + key_file2=data_files/server6.key" \ + "$P_CLI force_version=tls1_1" \ + 0 \ + -c "serial number.*09" \ + -c "signed using.*ECDSA with SHA256" \ + -C "signed using.*ECDSA with SHA1" + +run_test "Certificate hash: client TLS 1.1, no SHA-1 -> SHA-2 (order 2)" \ + "$P_SRV crt_file=data_files/server6.crt \ + key_file=data_files/server6.key \ + crt_file2=data_files/server5.crt \ + key_file2=data_files/server5.key" \ + "$P_CLI force_version=tls1_1" \ + 0 \ + -c "serial number.*0A" \ + -c "signed using.*ECDSA with SHA256" \ + -C "signed using.*ECDSA with SHA1" + # tests for SNI run_test "SNI: no SNI callback" \