diff --git a/ChangeLog b/ChangeLog index df0ef7711..f1312803a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -14,6 +14,11 @@ Changes * entropy_add_source(), entropy_update_manual() and entropy_gather() now thread-safe if POLARSSL_THREADING_C defined +Security + * Forbid change of server certificate during renegotiation to prevent + "triple handshake" attack when authentication mode is optional (the + attack was already impossible when authentication is required). + Bugfix * ecp_gen_keypair() does more tries to prevent failure because of statistics diff --git a/library/ssl_tls.c b/library/ssl_tls.c index 4a9211f13..4f3095caa 100644 --- a/library/ssl_tls.c +++ b/library/ssl_tls.c @@ -2650,6 +2650,30 @@ int ssl_parse_certificate( ssl_context *ssl ) SSL_DEBUG_CRT( 3, "peer certificate", ssl->session_negotiate->peer_cert ); + /* + * On client, make sure the server cert doesn't change during renego to + * avoid "triple handshake" attack: https://secure-resumption.com/ + */ + if( ssl->endpoint == SSL_IS_CLIENT && + ssl->renegotiation == SSL_RENEGOTIATION ) + { + if( ssl->session->peer_cert == NULL ) + { + SSL_DEBUG_MSG( 1, ( "new server cert during renegotiation" ) ); + return( POLARSSL_ERR_SSL_BAD_HS_CERTIFICATE ); + } + + if( ssl->session->peer_cert->raw.len != + ssl->session_negotiate->peer_cert->raw.len || + memcmp( ssl->session->peer_cert->raw.p, + ssl->session_negotiate->peer_cert->raw.p, + ssl->session->peer_cert->raw.len ) != 0 ) + { + SSL_DEBUG_MSG( 1, ( "server cert changed during renegotiation" ) ); + return( POLARSSL_ERR_SSL_BAD_HS_CERTIFICATE ); + } + } + if( ssl->authmode != SSL_VERIFY_NONE ) { if( ssl->ca_chain == NULL )