mirror of
https://github.com/yuzu-emu/mbedtls.git
synced 2024-12-23 18:15:35 +00:00
Fixed client certificate handling with TLS 1.2
This commit is contained in:
parent
e667c98fb1
commit
926af7582a
|
@ -192,6 +192,11 @@
|
||||||
|
|
||||||
#define SSL_SIG_RSA 1
|
#define SSL_SIG_RSA 1
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Client Certificate Types
|
||||||
|
*/
|
||||||
|
#define SSL_CERT_TYPE_RSA_SIGN 1
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Message, alert and handshake types
|
* Message, alert and handshake types
|
||||||
*/
|
*/
|
||||||
|
@ -351,6 +356,8 @@ struct _ssl_handshake_params
|
||||||
* Handshake specific crypto variables
|
* Handshake specific crypto variables
|
||||||
*/
|
*/
|
||||||
int sig_alg; /*!< Signature algorithm */
|
int sig_alg; /*!< Signature algorithm */
|
||||||
|
int cert_type; /*!< Requested cert type */
|
||||||
|
int verify_sig_alg; /*!< Signature algorithm for verify */
|
||||||
#if defined(POLARSSL_DHM_C)
|
#if defined(POLARSSL_DHM_C)
|
||||||
dhm_context dhm_ctx; /*!< DHM key exchange */
|
dhm_context dhm_ctx; /*!< DHM key exchange */
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -891,15 +891,19 @@ static int ssl_parse_server_key_exchange( ssl_context *ssl )
|
||||||
static int ssl_parse_certificate_request( ssl_context *ssl )
|
static int ssl_parse_certificate_request( ssl_context *ssl )
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
unsigned char *buf, *p;
|
||||||
|
size_t n = 0;
|
||||||
|
size_t cert_type_len = 0, sig_alg_len = 0, dn_len = 0;
|
||||||
|
|
||||||
SSL_DEBUG_MSG( 2, ( "=> parse certificate request" ) );
|
SSL_DEBUG_MSG( 2, ( "=> parse certificate request" ) );
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 0 . 0 handshake type
|
* 0 . 0 handshake type
|
||||||
* 1 . 3 handshake length
|
* 1 . 3 handshake length
|
||||||
* 4 . 5 SSL version
|
* 4 . 4 cert type count
|
||||||
* 6 . 6 cert type count
|
* 5 .. m-1 cert types
|
||||||
* 7 .. n-1 cert types
|
* m .. m+1 sig alg length (TLS 1.2 only)
|
||||||
|
* m+1 .. n-1 SignatureAndHashAlgorithms (TLS 1.2 only)
|
||||||
* n .. n+1 length of all DNs
|
* n .. n+1 length of all DNs
|
||||||
* n+2 .. n+3 length of DN 1
|
* n+2 .. n+3 length of DN 1
|
||||||
* n+4 .. ... Distinguished Name #1
|
* n+4 .. ... Distinguished Name #1
|
||||||
|
@ -926,6 +930,70 @@ static int ssl_parse_certificate_request( ssl_context *ssl )
|
||||||
SSL_DEBUG_MSG( 3, ( "got %s certificate request",
|
SSL_DEBUG_MSG( 3, ( "got %s certificate request",
|
||||||
ssl->client_auth ? "a" : "no" ) );
|
ssl->client_auth ? "a" : "no" ) );
|
||||||
|
|
||||||
|
if( ssl->client_auth == 0 )
|
||||||
|
goto exit;
|
||||||
|
|
||||||
|
// TODO: handshake_failure alert for an anonymous server to request
|
||||||
|
// client authentication
|
||||||
|
|
||||||
|
buf = ssl->in_msg;
|
||||||
|
|
||||||
|
// Retrieve cert types
|
||||||
|
//
|
||||||
|
cert_type_len = buf[4];
|
||||||
|
n = cert_type_len;
|
||||||
|
|
||||||
|
if( ssl->in_hslen < 6 + n )
|
||||||
|
{
|
||||||
|
SSL_DEBUG_MSG( 1, ( "bad certificate request message" ) );
|
||||||
|
return( POLARSSL_ERR_SSL_BAD_HS_CERTIFICATE_REQUEST );
|
||||||
|
}
|
||||||
|
|
||||||
|
p = buf + 4;
|
||||||
|
while( cert_type_len > 0 )
|
||||||
|
{
|
||||||
|
if( *p == SSL_CERT_TYPE_RSA_SIGN )
|
||||||
|
{
|
||||||
|
ssl->handshake->cert_type = SSL_CERT_TYPE_RSA_SIGN;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
cert_type_len--;
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( ssl->handshake->cert_type == 0 )
|
||||||
|
{
|
||||||
|
SSL_DEBUG_MSG( 1, ( "no known cert_type provided" ) );
|
||||||
|
return( POLARSSL_ERR_SSL_BAD_HS_CERTIFICATE_REQUEST );
|
||||||
|
}
|
||||||
|
|
||||||
|
if( ssl->minor_ver == SSL_MINOR_VERSION_3 )
|
||||||
|
{
|
||||||
|
sig_alg_len = ( ( buf[5 + n] << 8 )
|
||||||
|
| ( buf[6 + n] ) );
|
||||||
|
|
||||||
|
p = buf + 7 + n;
|
||||||
|
n += sig_alg_len;
|
||||||
|
|
||||||
|
if( ssl->in_hslen < 6 + n )
|
||||||
|
{
|
||||||
|
SSL_DEBUG_MSG( 1, ( "bad certificate request message" ) );
|
||||||
|
return( POLARSSL_ERR_SSL_BAD_HS_CERTIFICATE_REQUEST );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dn_len = ( ( buf[7 + n] << 8 )
|
||||||
|
| ( buf[8 + n] ) );
|
||||||
|
|
||||||
|
n += dn_len;
|
||||||
|
if( ssl->in_hslen != 9 + n )
|
||||||
|
{
|
||||||
|
SSL_DEBUG_MSG( 1, ( "bad certificate request message" ) );
|
||||||
|
return( POLARSSL_ERR_SSL_BAD_HS_CERTIFICATE_REQUEST );
|
||||||
|
}
|
||||||
|
|
||||||
|
exit:
|
||||||
SSL_DEBUG_MSG( 2, ( "<= parse certificate request" ) );
|
SSL_DEBUG_MSG( 2, ( "<= parse certificate request" ) );
|
||||||
|
|
||||||
return( 0 );
|
return( 0 );
|
||||||
|
@ -1102,25 +1170,6 @@ static int ssl_write_certificate_verify( ssl_context *ssl )
|
||||||
return( 0 );
|
return( 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
if( ssl->minor_ver == SSL_MINOR_VERSION_3 )
|
|
||||||
{
|
|
||||||
// TODO TLS1.2 Should be based on allowed signature algorithm received in
|
|
||||||
// Certificate Request according to RFC 5246. But OpenSSL only allows
|
|
||||||
// SHA256 and SHA384. Find out why OpenSSL does this.
|
|
||||||
//
|
|
||||||
if( ssl->session_negotiate->ciphersuite == TLS_RSA_WITH_AES_256_GCM_SHA384 ||
|
|
||||||
ssl->session_negotiate->ciphersuite == TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 )
|
|
||||||
{
|
|
||||||
hash_id = SIG_RSA_SHA384;
|
|
||||||
hashlen = 48;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
hash_id = SIG_RSA_SHA256;
|
|
||||||
hashlen = 32;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if( ssl->rsa_key == NULL )
|
if( ssl->rsa_key == NULL )
|
||||||
{
|
{
|
||||||
SSL_DEBUG_MSG( 1, ( "got no private key" ) );
|
SSL_DEBUG_MSG( 1, ( "got no private key" ) );
|
||||||
|
@ -1132,23 +1181,52 @@ static int ssl_write_certificate_verify( ssl_context *ssl )
|
||||||
*/
|
*/
|
||||||
ssl->handshake->calc_verify( ssl, hash );
|
ssl->handshake->calc_verify( ssl, hash );
|
||||||
|
|
||||||
if ( ssl->rsa_key )
|
if( ssl->minor_ver != SSL_MINOR_VERSION_3 )
|
||||||
n = ssl->rsa_key_len ( ssl->rsa_key );
|
|
||||||
|
|
||||||
if( ssl->minor_ver == SSL_MINOR_VERSION_3 )
|
|
||||||
{
|
{
|
||||||
// TODO TLS1.2 Should be based on allowed signature algorithm received in
|
/*
|
||||||
// Certificate Request according to RFC 5246. But OpenSSL only allows
|
* digitally-signed struct {
|
||||||
// SHA256 and SHA384. Find out why OpenSSL does this.
|
* opaque md5_hash[16];
|
||||||
//
|
* opaque sha_hash[20];
|
||||||
|
* };
|
||||||
|
*
|
||||||
|
* md5_hash
|
||||||
|
* MD5(handshake_messages);
|
||||||
|
*
|
||||||
|
* sha_hash
|
||||||
|
* SHA(handshake_messages);
|
||||||
|
*/
|
||||||
|
hashlen = 36;
|
||||||
|
hash_id = SIG_RSA_RAW;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* digitally-signed struct {
|
||||||
|
* opaque handshake_messages[handshake_messages_length];
|
||||||
|
* };
|
||||||
|
*
|
||||||
|
* Taking shortcut here. We assume that the server always allows the
|
||||||
|
* PRF Hash function and has sent it in the allowed signature
|
||||||
|
* algorithms list received in the Certificate Request message.
|
||||||
|
*
|
||||||
|
* Until we encounter a server that does not, we will take this
|
||||||
|
* shortcut.
|
||||||
|
*
|
||||||
|
* Reason: Otherwise we should have running hashes for SHA512 and SHA224
|
||||||
|
* in order to satisfy 'weird' needs from the server side.
|
||||||
|
*/
|
||||||
if( ssl->session_negotiate->ciphersuite == TLS_RSA_WITH_AES_256_GCM_SHA384 ||
|
if( ssl->session_negotiate->ciphersuite == TLS_RSA_WITH_AES_256_GCM_SHA384 ||
|
||||||
ssl->session_negotiate->ciphersuite == TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 )
|
ssl->session_negotiate->ciphersuite == TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 )
|
||||||
{
|
{
|
||||||
|
hash_id = SIG_RSA_SHA384;
|
||||||
|
hashlen = 48;
|
||||||
ssl->out_msg[4] = SSL_HASH_SHA384;
|
ssl->out_msg[4] = SSL_HASH_SHA384;
|
||||||
ssl->out_msg[5] = SSL_SIG_RSA;
|
ssl->out_msg[5] = SSL_SIG_RSA;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
hash_id = SIG_RSA_SHA256;
|
||||||
|
hashlen = 32;
|
||||||
ssl->out_msg[4] = SSL_HASH_SHA256;
|
ssl->out_msg[4] = SSL_HASH_SHA256;
|
||||||
ssl->out_msg[5] = SSL_SIG_RSA;
|
ssl->out_msg[5] = SSL_SIG_RSA;
|
||||||
}
|
}
|
||||||
|
@ -1156,6 +1234,9 @@ static int ssl_write_certificate_verify( ssl_context *ssl )
|
||||||
offset = 2;
|
offset = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( ssl->rsa_key )
|
||||||
|
n = ssl->rsa_key_len ( ssl->rsa_key );
|
||||||
|
|
||||||
ssl->out_msg[4 + offset] = (unsigned char)( n >> 8 );
|
ssl->out_msg[4 + offset] = (unsigned char)( n >> 8 );
|
||||||
ssl->out_msg[5 + offset] = (unsigned char)( n );
|
ssl->out_msg[5 + offset] = (unsigned char)( n );
|
||||||
|
|
||||||
|
|
|
@ -689,7 +689,7 @@ static int ssl_write_server_hello( ssl_context *ssl )
|
||||||
static int ssl_write_certificate_request( ssl_context *ssl )
|
static int ssl_write_certificate_request( ssl_context *ssl )
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
size_t n;
|
size_t n = 0, dn_size, total_dn_size;
|
||||||
unsigned char *buf, *p;
|
unsigned char *buf, *p;
|
||||||
const x509_cert *crt;
|
const x509_cert *crt;
|
||||||
|
|
||||||
|
@ -707,7 +707,9 @@ static int ssl_write_certificate_request( ssl_context *ssl )
|
||||||
* 0 . 0 handshake type
|
* 0 . 0 handshake type
|
||||||
* 1 . 3 handshake length
|
* 1 . 3 handshake length
|
||||||
* 4 . 4 cert type count
|
* 4 . 4 cert type count
|
||||||
* 5 .. n-1 cert types
|
* 5 .. m-1 cert types
|
||||||
|
* m .. m+1 sig alg length (TLS 1.2 only)
|
||||||
|
* m+1 .. n-1 SignatureAndHashAlgorithms (TLS 1.2 only)
|
||||||
* n .. n+1 length of all DNs
|
* n .. n+1 length of all DNs
|
||||||
* n+2 .. n+3 length of DN 1
|
* n+2 .. n+3 length of DN 1
|
||||||
* n+4 .. ... Distinguished Name #1
|
* n+4 .. ... Distinguished Name #1
|
||||||
|
@ -720,30 +722,60 @@ static int ssl_write_certificate_request( ssl_context *ssl )
|
||||||
* At the moment, only RSA certificates are supported
|
* At the moment, only RSA certificates are supported
|
||||||
*/
|
*/
|
||||||
*p++ = 1;
|
*p++ = 1;
|
||||||
*p++ = 1;
|
*p++ = SSL_CERT_TYPE_RSA_SIGN;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add signature_algorithms for verify (TLS 1.2)
|
||||||
|
* Only add current running algorithm that is already required for
|
||||||
|
* requested ciphersuite.
|
||||||
|
*
|
||||||
|
* Length is always 2
|
||||||
|
*/
|
||||||
|
if( ssl->max_minor_ver == SSL_MINOR_VERSION_3 )
|
||||||
|
{
|
||||||
|
ssl->handshake->verify_sig_alg = SSL_HASH_SHA256;
|
||||||
|
|
||||||
|
*p++ = 0;
|
||||||
|
*p++ = 2;
|
||||||
|
|
||||||
|
if( ssl->session_negotiate->ciphersuite == TLS_RSA_WITH_AES_256_GCM_SHA384 ||
|
||||||
|
ssl->session_negotiate->ciphersuite == TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 )
|
||||||
|
{
|
||||||
|
ssl->handshake->verify_sig_alg = SSL_HASH_SHA384;
|
||||||
|
}
|
||||||
|
|
||||||
|
*p++ = ssl->handshake->verify_sig_alg;
|
||||||
|
*p++ = SSL_SIG_RSA;
|
||||||
|
|
||||||
|
n += 4;
|
||||||
|
}
|
||||||
|
|
||||||
p += 2;
|
p += 2;
|
||||||
crt = ssl->ca_chain;
|
crt = ssl->ca_chain;
|
||||||
|
|
||||||
|
total_dn_size = 2;
|
||||||
while( crt != NULL )
|
while( crt != NULL )
|
||||||
{
|
{
|
||||||
if( p - buf > 4096 )
|
if( p - buf > 4096 )
|
||||||
break;
|
break;
|
||||||
|
|
||||||
n = crt->subject_raw.len;
|
dn_size = crt->subject_raw.len;
|
||||||
*p++ = (unsigned char)( n >> 8 );
|
*p++ = (unsigned char)( dn_size >> 8 );
|
||||||
*p++ = (unsigned char)( n );
|
*p++ = (unsigned char)( dn_size );
|
||||||
memcpy( p, crt->subject_raw.p, n );
|
memcpy( p, crt->subject_raw.p, dn_size );
|
||||||
|
p += dn_size;
|
||||||
|
|
||||||
SSL_DEBUG_BUF( 3, "requested DN", p, n );
|
SSL_DEBUG_BUF( 3, "requested DN", p, dn_size );
|
||||||
p += n; crt = crt->next;
|
|
||||||
|
total_dn_size += dn_size;
|
||||||
|
crt = crt->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
ssl->out_msglen = n = p - buf;
|
ssl->out_msglen = p - buf;
|
||||||
ssl->out_msgtype = SSL_MSG_HANDSHAKE;
|
ssl->out_msgtype = SSL_MSG_HANDSHAKE;
|
||||||
ssl->out_msg[0] = SSL_HS_CERTIFICATE_REQUEST;
|
ssl->out_msg[0] = SSL_HS_CERTIFICATE_REQUEST;
|
||||||
ssl->out_msg[6] = (unsigned char)( ( n - 8 ) >> 8 );
|
ssl->out_msg[6 + n] = (unsigned char)( total_dn_size >> 8 );
|
||||||
ssl->out_msg[7] = (unsigned char)( ( n - 8 ) );
|
ssl->out_msg[7 + n] = (unsigned char)( total_dn_size );
|
||||||
|
|
||||||
ret = ssl_write_record( ssl );
|
ret = ssl_write_record( ssl );
|
||||||
|
|
||||||
|
@ -1170,8 +1202,10 @@ static int ssl_parse_client_key_exchange( ssl_context *ssl )
|
||||||
static int ssl_parse_certificate_verify( ssl_context *ssl )
|
static int ssl_parse_certificate_verify( ssl_context *ssl )
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
size_t n1, n2;
|
size_t n = 0, n1, n2;
|
||||||
unsigned char hash[48];
|
unsigned char hash[48];
|
||||||
|
int hash_id;
|
||||||
|
unsigned int hashlen;
|
||||||
|
|
||||||
SSL_DEBUG_MSG( 2, ( "=> parse certificate verify" ) );
|
SSL_DEBUG_MSG( 2, ( "=> parse certificate verify" ) );
|
||||||
|
|
||||||
|
@ -1204,17 +1238,49 @@ static int ssl_parse_certificate_verify( ssl_context *ssl )
|
||||||
return( POLARSSL_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY );
|
return( POLARSSL_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY );
|
||||||
}
|
}
|
||||||
|
|
||||||
n1 = ssl->session_negotiate->peer_cert->rsa.len;
|
if( ssl->minor_ver == SSL_MINOR_VERSION_3 )
|
||||||
n2 = ( ssl->in_msg[4] << 8 ) | ssl->in_msg[5];
|
{
|
||||||
|
/*
|
||||||
|
* As server we know we either have SSL_HASH_SHA384 or
|
||||||
|
* SSL_HASH_SHA256
|
||||||
|
*/
|
||||||
|
if( ssl->in_msg[4] != ssl->handshake->verify_sig_alg ||
|
||||||
|
ssl->in_msg[5] != SSL_SIG_RSA )
|
||||||
|
{
|
||||||
|
SSL_DEBUG_MSG( 1, ( "peer not adhering to requested sig_alg for verify message" ) );
|
||||||
|
return( POLARSSL_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY );
|
||||||
|
}
|
||||||
|
|
||||||
if( n1 + 6 != ssl->in_hslen || n1 != n2 )
|
if( ssl->handshake->verify_sig_alg == SSL_HASH_SHA384 )
|
||||||
|
{
|
||||||
|
hashlen = 48;
|
||||||
|
hash_id = SIG_RSA_SHA384;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
hashlen = 32;
|
||||||
|
hash_id = SIG_RSA_SHA256;
|
||||||
|
}
|
||||||
|
|
||||||
|
n += 2;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
hashlen = 36;
|
||||||
|
hash_id = SIG_RSA_RAW;
|
||||||
|
}
|
||||||
|
|
||||||
|
n1 = ssl->session_negotiate->peer_cert->rsa.len;
|
||||||
|
n2 = ( ssl->in_msg[4 + n] << 8 ) | ssl->in_msg[5 + 2];
|
||||||
|
|
||||||
|
if( n + n1 + 6 != ssl->in_hslen || n1 != n2 )
|
||||||
{
|
{
|
||||||
SSL_DEBUG_MSG( 1, ( "bad certificate verify message" ) );
|
SSL_DEBUG_MSG( 1, ( "bad certificate verify message" ) );
|
||||||
return( POLARSSL_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY );
|
return( POLARSSL_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY );
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = rsa_pkcs1_verify( &ssl->session_negotiate->peer_cert->rsa, RSA_PUBLIC,
|
ret = rsa_pkcs1_verify( &ssl->session_negotiate->peer_cert->rsa, RSA_PUBLIC,
|
||||||
SIG_RSA_RAW, 36, hash, ssl->in_msg + 6 );
|
hash_id, hashlen, hash, ssl->in_msg + 6 + n );
|
||||||
if( ret != 0 )
|
if( ret != 0 )
|
||||||
{
|
{
|
||||||
SSL_DEBUG_RET( 1, "rsa_pkcs1_verify", ret );
|
SSL_DEBUG_RET( 1, "rsa_pkcs1_verify", ret );
|
||||||
|
|
Loading…
Reference in a new issue