Merge smarter certificate selection for pre-TLS-1.2 clients
This commit is contained in:
commit
e522d0fa57
@ -29,6 +29,8 @@ Features
|
||||
length of an X.509 verification chain.
|
||||
* Support for renegotiation can now be disabled at compile-time
|
||||
* Support for 1/n-1 record splitting, a countermeasure against BEAST.
|
||||
* Certificate selection based on signature hash, prefering SHA-1 over SHA-2
|
||||
for pre-1.2 clients when multiple certificates are available.
|
||||
|
||||
Bugfix
|
||||
* Stack buffer overflow if ctr_drbg_update() is called with too large
|
||||
@ -51,6 +53,9 @@ Changes
|
||||
* debug_print_buf() now prints a text view in addition to hexadecimal.
|
||||
* Skip writing and parsing signature_algorithm extension if none of the
|
||||
key exchanges enabled needs certificates.
|
||||
* A specific error is now returned when there are ciphersuites in common
|
||||
but none of them is usable due to external factors such as no certificate
|
||||
with a suitable (extended)KeyUsage or curve or no PSK set.
|
||||
|
||||
= PolarSSL 1.3.9 released 2014-10-20
|
||||
Security
|
||||
|
@ -91,7 +91,7 @@
|
||||
* ECP 4 8 (Started from top)
|
||||
* MD 5 4
|
||||
* CIPHER 6 6
|
||||
* SSL 6 10 (Started from top)
|
||||
* SSL 6 11 (Started from top)
|
||||
* SSL 7 31
|
||||
*
|
||||
* Module dependent error code (5 bits 0x.00.-0x.F8.)
|
||||
|
@ -152,6 +152,7 @@
|
||||
#define POLARSSL_ERR_SSL_INTERNAL_ERROR -0x6C00 /**< Internal error (eg, unexpected failure in lower-level module) */
|
||||
#define POLARSSL_ERR_SSL_COUNTER_WRAPPING -0x6B80 /**< A counter would wrap (eg, too many messages exchanged). */
|
||||
#define POLARSSL_ERR_SSL_WAITING_SERVER_HELLO_RENEGO -0x6B00 /**< Unexpected message at ServerHello in renegotiation. */
|
||||
#define POLARSSL_ERR_SSL_NO_USABLE_CIPHERSUITE -0x6A80 /**< None of the common ciphersuites is usable (eg, no suitable certificate) */
|
||||
|
||||
/*
|
||||
* Various constants
|
||||
|
@ -452,6 +452,8 @@ void polarssl_strerror( int ret, char *buf, size_t buflen )
|
||||
snprintf( buf, buflen, "SSL - A counter would wrap (eg, too many messages exchanged)" );
|
||||
if( use_ret == -(POLARSSL_ERR_SSL_WAITING_SERVER_HELLO_RENEGO) )
|
||||
snprintf( buf, buflen, "SSL - Unexpected message at ServerHello in renegotiation" );
|
||||
if( use_ret == -(POLARSSL_ERR_SSL_NO_USABLE_CIPHERSUITE) )
|
||||
snprintf( buf, buflen, "SSL - None of the common ciphersuites is usable (eg, no suitable certificate)" );
|
||||
#endif /* POLARSSL_SSL_TLS_C */
|
||||
|
||||
#if defined(POLARSSL_X509_USE_C) || defined(POLARSSL_X509_CREATE_C)
|
||||
|
@ -801,11 +801,11 @@ static int ssl_parse_alpn_ext( ssl_context *ssl,
|
||||
|
||||
#if defined(POLARSSL_X509_CRT_PARSE_C)
|
||||
/*
|
||||
* Return 1 if the given EC key uses the given curve, 0 otherwise
|
||||
* Return 0 if the given key uses one of the acceptable curves, -1 otherwise
|
||||
*/
|
||||
#if defined(POLARSSL_ECDSA_C)
|
||||
static int ssl_key_matches_curves( pk_context *pk,
|
||||
const ecp_curve_info **curves )
|
||||
static int ssl_check_key_curve( pk_context *pk,
|
||||
const ecp_curve_info **curves )
|
||||
{
|
||||
const ecp_curve_info **crv = curves;
|
||||
ecp_group_id grp_id = pk_ec( *pk )->grp.id;
|
||||
@ -813,11 +813,11 @@ static int ssl_key_matches_curves( pk_context *pk,
|
||||
while( *crv != NULL )
|
||||
{
|
||||
if( (*crv)->grp_id == grp_id )
|
||||
return( 1 );
|
||||
return( 0 );
|
||||
crv++;
|
||||
}
|
||||
|
||||
return( 0 );
|
||||
return( -1 );
|
||||
}
|
||||
#endif /* POLARSSL_ECDSA_C */
|
||||
|
||||
@ -828,7 +828,7 @@ static int ssl_key_matches_curves( 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)
|
||||
@ -861,21 +861,41 @@ static int ssl_pick_cert( ssl_context *ssl,
|
||||
}
|
||||
|
||||
#if defined(POLARSSL_ECDSA_C)
|
||||
if( pk_alg == POLARSSL_PK_ECDSA )
|
||||
{
|
||||
if( ssl_key_matches_curves( cur->key, ssl->handshake->curves ) )
|
||||
break;
|
||||
}
|
||||
else
|
||||
if( pk_alg == POLARSSL_PK_ECDSA &&
|
||||
ssl_check_key_curve( cur->key, ssl->handshake->curves ) != 0 )
|
||||
continue;
|
||||
#endif
|
||||
break;
|
||||
|
||||
/*
|
||||
* 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 */
|
||||
|
||||
@ -891,8 +911,8 @@ static int ssl_ciphersuite_match( ssl_context *ssl, int suite_id,
|
||||
suite_info = ssl_ciphersuite_from_id( suite_id );
|
||||
if( suite_info == NULL )
|
||||
{
|
||||
SSL_DEBUG_MSG( 1, ( "ciphersuite info for %04x not found", suite_id ) );
|
||||
return( POLARSSL_ERR_SSL_BAD_INPUT_DATA );
|
||||
SSL_DEBUG_MSG( 1, ( "should never happen" ) );
|
||||
return( POLARSSL_ERR_SSL_INTERNAL_ERROR );
|
||||
}
|
||||
|
||||
if( suite_info->min_minor_ver > ssl->minor_ver ||
|
||||
@ -935,7 +955,7 @@ static int ssl_ciphersuite_match( ssl_context *ssl, int suite_id,
|
||||
#if defined(POLARSSL_SSL_SRV_SUPPORT_SSLV2_CLIENT_HELLO)
|
||||
static int ssl_parse_client_hello_v2( ssl_context *ssl )
|
||||
{
|
||||
int ret;
|
||||
int ret, got_common_suite;
|
||||
unsigned int i, j;
|
||||
size_t n;
|
||||
unsigned int ciph_len, sess_len, chal_len;
|
||||
@ -1133,6 +1153,7 @@ static int ssl_parse_client_hello_v2( ssl_context *ssl )
|
||||
}
|
||||
#endif /* POLARSSL_SSL_FALLBACK_SCSV */
|
||||
|
||||
got_common_suite = 0;
|
||||
ciphersuites = ssl->ciphersuite_list[ssl->minor_ver];
|
||||
ciphersuite_info = NULL;
|
||||
#if defined(POLARSSL_SSL_SRV_RESPECT_CLIENT_PREFERENCE)
|
||||
@ -1150,6 +1171,8 @@ static int ssl_parse_client_hello_v2( ssl_context *ssl )
|
||||
p[2] != ( ( ciphersuites[i] ) & 0xFF ) )
|
||||
continue;
|
||||
|
||||
got_common_suite = 1;
|
||||
|
||||
if( ( ret = ssl_ciphersuite_match( ssl, ciphersuites[i],
|
||||
&ciphersuite_info ) ) != 0 )
|
||||
return( ret );
|
||||
@ -1159,9 +1182,17 @@ static int ssl_parse_client_hello_v2( ssl_context *ssl )
|
||||
}
|
||||
}
|
||||
|
||||
SSL_DEBUG_MSG( 1, ( "got no ciphersuites in common" ) );
|
||||
|
||||
return( POLARSSL_ERR_SSL_NO_CIPHER_CHOSEN );
|
||||
if( got_common_suite )
|
||||
{
|
||||
SSL_DEBUG_MSG( 1, ( "got ciphersuites in common, "
|
||||
"but none of them usable" ) );
|
||||
return( POLARSSL_ERR_SSL_NO_USABLE_CIPHERSUITE );
|
||||
}
|
||||
else
|
||||
{
|
||||
SSL_DEBUG_MSG( 1, ( "got no ciphersuites in common" ) );
|
||||
return( POLARSSL_ERR_SSL_NO_CIPHER_CHOSEN );
|
||||
}
|
||||
|
||||
have_ciphersuite_v2:
|
||||
ssl->session_negotiate->ciphersuite = ciphersuites[i];
|
||||
@ -1193,7 +1224,7 @@ have_ciphersuite_v2:
|
||||
|
||||
static int ssl_parse_client_hello( ssl_context *ssl )
|
||||
{
|
||||
int ret;
|
||||
int ret, got_common_suite;
|
||||
unsigned int i, j;
|
||||
size_t n;
|
||||
unsigned int ciph_len, sess_len;
|
||||
@ -1675,6 +1706,7 @@ static int ssl_parse_client_hello( ssl_context *ssl )
|
||||
* (At the end because we need information from the EC-based extensions
|
||||
* and certificate from the SNI callback triggered by the SNI extension.)
|
||||
*/
|
||||
got_common_suite = 0;
|
||||
ciphersuites = ssl->ciphersuite_list[ssl->minor_ver];
|
||||
ciphersuite_info = NULL;
|
||||
#if defined(POLARSSL_SSL_SRV_RESPECT_CLIENT_PREFERENCE)
|
||||
@ -1691,6 +1723,8 @@ static int ssl_parse_client_hello( ssl_context *ssl )
|
||||
p[1] != ( ( ciphersuites[i] ) & 0xFF ) )
|
||||
continue;
|
||||
|
||||
got_common_suite = 1;
|
||||
|
||||
if( ( ret = ssl_ciphersuite_match( ssl, ciphersuites[i],
|
||||
&ciphersuite_info ) ) != 0 )
|
||||
return( ret );
|
||||
@ -1700,12 +1734,19 @@ static int ssl_parse_client_hello( ssl_context *ssl )
|
||||
}
|
||||
}
|
||||
|
||||
SSL_DEBUG_MSG( 1, ( "got no ciphersuites in common" ) );
|
||||
|
||||
if( ( ret = ssl_send_fatal_handshake_failure( ssl ) ) != 0 )
|
||||
return( ret );
|
||||
|
||||
return( POLARSSL_ERR_SSL_NO_CIPHER_CHOSEN );
|
||||
if( got_common_suite )
|
||||
{
|
||||
SSL_DEBUG_MSG( 1, ( "got ciphersuites in common, "
|
||||
"but none of them usable" ) );
|
||||
ssl_send_fatal_handshake_failure( ssl );
|
||||
return( POLARSSL_ERR_SSL_NO_USABLE_CIPHERSUITE );
|
||||
}
|
||||
else
|
||||
{
|
||||
SSL_DEBUG_MSG( 1, ( "got no ciphersuites in common" ) );
|
||||
ssl_send_fatal_handshake_failure( ssl );
|
||||
return( POLARSSL_ERR_SSL_NO_CIPHER_CHOSEN );
|
||||
}
|
||||
|
||||
have_ciphersuite:
|
||||
ssl->session_negotiate->ciphersuite = ciphersuites[i];
|
||||
|
@ -46,7 +46,7 @@ close(FORMAT_FILE);
|
||||
|
||||
$/ = $line_separator;
|
||||
|
||||
open(GREP, "/bin/grep \"define POLARSSL_ERR_\" $include_dir/* |") || die("Failure when calling grep: $!");
|
||||
open(GREP, "grep \"define POLARSSL_ERR_\" $include_dir/* |") || die("Failure when calling grep: $!");
|
||||
|
||||
my $ll_old_define = "";
|
||||
my $hl_old_define = "";
|
||||
|
@ -1404,6 +1404,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" \
|
||||
@ -1956,7 +2010,7 @@ run_test "PSK callback: psk, no callback" \
|
||||
"$P_CLI force_ciphersuite=TLS-PSK-WITH-AES-128-CBC-SHA \
|
||||
psk_identity=foo psk=abc123" \
|
||||
0 \
|
||||
-S "SSL - The server has no ciphersuites in common" \
|
||||
-S "SSL - None of the common ciphersuites is usable" \
|
||||
-S "SSL - Unknown identity received" \
|
||||
-S "SSL - Verification of the message MAC failed"
|
||||
|
||||
@ -1965,7 +2019,7 @@ run_test "PSK callback: no psk, no callback" \
|
||||
"$P_CLI force_ciphersuite=TLS-PSK-WITH-AES-128-CBC-SHA \
|
||||
psk_identity=foo psk=abc123" \
|
||||
1 \
|
||||
-s "SSL - The server has no ciphersuites in common" \
|
||||
-s "SSL - None of the common ciphersuites is usable" \
|
||||
-S "SSL - Unknown identity received" \
|
||||
-S "SSL - Verification of the message MAC failed"
|
||||
|
||||
@ -1974,7 +2028,7 @@ run_test "PSK callback: callback overrides other settings" \
|
||||
"$P_CLI force_ciphersuite=TLS-PSK-WITH-AES-128-CBC-SHA \
|
||||
psk_identity=foo psk=abc123" \
|
||||
1 \
|
||||
-S "SSL - The server has no ciphersuites in common" \
|
||||
-S "SSL - None of the common ciphersuites is usable" \
|
||||
-s "SSL - Unknown identity received" \
|
||||
-S "SSL - Verification of the message MAC failed"
|
||||
|
||||
@ -1983,7 +2037,7 @@ run_test "PSK callback: first id matches" \
|
||||
"$P_CLI force_ciphersuite=TLS-PSK-WITH-AES-128-CBC-SHA \
|
||||
psk_identity=abc psk=dead" \
|
||||
0 \
|
||||
-S "SSL - The server has no ciphersuites in common" \
|
||||
-S "SSL - None of the common ciphersuites is usable" \
|
||||
-S "SSL - Unknown identity received" \
|
||||
-S "SSL - Verification of the message MAC failed"
|
||||
|
||||
@ -1992,7 +2046,7 @@ run_test "PSK callback: second id matches" \
|
||||
"$P_CLI force_ciphersuite=TLS-PSK-WITH-AES-128-CBC-SHA \
|
||||
psk_identity=def psk=beef" \
|
||||
0 \
|
||||
-S "SSL - The server has no ciphersuites in common" \
|
||||
-S "SSL - None of the common ciphersuites is usable" \
|
||||
-S "SSL - Unknown identity received" \
|
||||
-S "SSL - Verification of the message MAC failed"
|
||||
|
||||
@ -2001,7 +2055,7 @@ run_test "PSK callback: no match" \
|
||||
"$P_CLI force_ciphersuite=TLS-PSK-WITH-AES-128-CBC-SHA \
|
||||
psk_identity=ghi psk=beef" \
|
||||
1 \
|
||||
-S "SSL - The server has no ciphersuites in common" \
|
||||
-S "SSL - None of the common ciphersuites is usable" \
|
||||
-s "SSL - Unknown identity received" \
|
||||
-S "SSL - Verification of the message MAC failed"
|
||||
|
||||
@ -2010,7 +2064,7 @@ run_test "PSK callback: wrong key" \
|
||||
"$P_CLI force_ciphersuite=TLS-PSK-WITH-AES-128-CBC-SHA \
|
||||
psk_identity=abc psk=beef" \
|
||||
1 \
|
||||
-S "SSL - The server has no ciphersuites in common" \
|
||||
-S "SSL - None of the common ciphersuites is usable" \
|
||||
-S "SSL - Unknown identity received" \
|
||||
-s "SSL - Verification of the message MAC failed"
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user