From 5cc3506c9f6bc2775fa3c03ca06198387c98e927 Mon Sep 17 00:00:00 2001 From: Jerry Yu Date: Fri, 28 Jan 2022 16:16:08 +0800 Subject: [PATCH] Add write certificate and client handler Signed-off-by: Jerry Yu --- library/ssl_misc.h | 5 + library/ssl_tls13_client.c | 6 +- library/ssl_tls13_generic.c | 190 ++++++++++++++++++++++++++++++++++++ 3 files changed, 199 insertions(+), 2 deletions(-) diff --git a/library/ssl_misc.h b/library/ssl_misc.h index 065643967..4b307c27e 100644 --- a/library/ssl_misc.h +++ b/library/ssl_misc.h @@ -1735,6 +1735,11 @@ int mbedtls_ssl_tls13_start_handshake_msg( mbedtls_ssl_context *ssl, */ int mbedtls_ssl_tls13_process_certificate( mbedtls_ssl_context *ssl ); +/* + * Handler of TLS 1.3 write certificate message + */ +int mbedtls_ssl_tls13_write_certificate( mbedtls_ssl_context *ssl ); + /* * Generic handler of Certificate Verify */ diff --git a/library/ssl_tls13_client.c b/library/ssl_tls13_client.c index c10b69801..f1483c78a 100644 --- a/library/ssl_tls13_client.c +++ b/library/ssl_tls13_client.c @@ -1948,9 +1948,11 @@ static int ssl_tls13_write_change_cipher_spec( mbedtls_ssl_context *ssl ) */ static int ssl_tls13_write_client_certificate( mbedtls_ssl_context *ssl ) { + MBEDTLS_SSL_DEBUG_MSG( 1, + ( "Switch to handshake traffic keys for outbound traffic" ) ); mbedtls_ssl_set_outbound_transform( ssl, ssl->handshake->transform_handshake ); - mbedtls_ssl_handshake_set_state( ssl, MBEDTLS_SSL_CLIENT_CERTIFICATE_VERIFY ); - return( 0 ); + + return( mbedtls_ssl_tls13_write_certificate( ssl ) ); } /* diff --git a/library/ssl_tls13_generic.c b/library/ssl_tls13_generic.c index 14884aa3b..513b7c03e 100644 --- a/library/ssl_tls13_generic.c +++ b/library/ssl_tls13_generic.c @@ -847,6 +847,196 @@ cleanup: return( ret ); } +/* + * STATE HANDLING: Output Certificate + */ +/* Check if a certificate should be written, and if yes, + * if it is available. + * Returns a negative error code on failure ( such as no certificate + * being available on the server ), and otherwise + * SSL_WRITE_CERTIFICATE_AVAILABLE or + * SSL_WRITE_CERTIFICATE_SKIP + * indicating that a Certificate message should be written based + * on the configured certificate, or whether it should be silently skipped. + */ +#define SSL_WRITE_CERTIFICATE_AVAILABLE 0 +#define SSL_WRITE_CERTIFICATE_SKIP 1 + + +static int ssl_tls13_write_certificate_coordinate( mbedtls_ssl_context* ssl ) +{ + + /* For PSK and ECDHE-PSK ciphersuites there is no certificate to exchange. */ + if( mbedtls_ssl_tls13_some_psk_enabled( ssl ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip write certificate" ) ); + return( SSL_WRITE_CERTIFICATE_SKIP ); + } + +#if defined(MBEDTLS_KEY_EXCHANGE_WITH_CERT_ENABLED) +#if defined(MBEDTLS_SSL_CLI_C) + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_CLIENT ) + { + /* The client MUST send a Certificate message if and only + * if the server has requested client authentication via a + * CertificateRequest message. + * + * client_auth indicates whether the server had requested + * client authentication. + */ + if( ssl->handshake->client_auth == 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip write certificate" ) ); + return( SSL_WRITE_CERTIFICATE_SKIP ); + } + } +#endif /* MBEDTLS_SSL_CLI_C */ + + return( SSL_WRITE_CERTIFICATE_AVAILABLE ); +#else /* MBEDTLS_KEY_EXCHANGE_WITH_CERT_ENABLED */ + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); +#endif /* !MBEDTLS_KEY_EXCHANGE_WITH_CERT_ENABLED */ +} + +#if defined(MBEDTLS_KEY_EXCHANGE_WITH_CERT_ENABLED) +static int ssl_tls13_write_certificate( mbedtls_ssl_context *ssl, + unsigned char *buf, + size_t buflen, + size_t *olen ) +{ + size_t i=0, n, total_len; + const mbedtls_x509_crt *crt = mbedtls_ssl_own_cert( ssl ); + unsigned char *start; + + /* TODO: Add bounds checks! Only then remove the next line. */ + ((void) buflen ); + + /* empty certificate_request_context with length 0 */ + buf[i] = 0; + /* Skip length of certificate_request_context and + * the length of CertificateEntry + */ + i += 1; + +#if defined(MBEDTLS_SSL_CLI_C) + /* If the server requests client authentication but no suitable + * certificate is available, the client MUST send a + * Certificate message containing no certificates + * ( i.e., with the "certificate_list" field having length 0 ). + * + * authmode indicates whether the client configuration required authentication. + */ + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_CLIENT && + ( ( crt == NULL ) || ssl->conf->authmode == MBEDTLS_SSL_VERIFY_NONE ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write empty client certificate" ) ); + buf[i] = 0; + buf[i + 1] = 0; + buf[i + 2] = 0; + i += 3; + *olen = i; + return( 0 ); + } +#endif /* MBEDTLS_SSL_CLI_C */ + + start = &buf[i]; + MBEDTLS_SSL_DEBUG_CRT( 3, "own certificate", crt ); + + i += 3; + + while ( crt != NULL ) + { + n = crt->raw.len; + if( n > buflen - 3 - i ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "certificate too large, %" MBEDTLS_PRINTF_SIZET " > %d", + i + 3 + n, MBEDTLS_SSL_OUT_CONTENT_LEN ) ); + return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL ); + } + + buf[i] = (unsigned char)( n >> 16 ); + buf[i + 1] = (unsigned char)( n >> 8 ); + buf[i + 2] = (unsigned char)( n ); + + i += 3; memcpy( buf + i, crt->raw.p, n ); + i += n; crt = crt->next; + + /* Currently, we don't have any certificate extensions defined. + * Hence, we are sending an empty extension with length zero. + */ + buf[i] = 0; + buf[i + 1] = 0; + i += 2; + } + total_len = &buf[i] - start - 3; + *start++ = (unsigned char)( ( total_len ) >> 16 ); + *start++ = (unsigned char)( ( total_len ) >> 8 ); + *start++ = (unsigned char)( ( total_len ) ); + + *olen = i; + + return( 0 ); +} +#endif /* MBEDTLS_KEY_EXCHANGE_WITH_CERT_ENABLED */ + +/* Update the state after handling the outgoing certificate message. */ +static int ssl_tls13_finalize_write_certificate( mbedtls_ssl_context* ssl ) +{ +#if defined(MBEDTLS_SSL_CLI_C) + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_CLIENT ) + { + mbedtls_ssl_handshake_set_state( ssl, MBEDTLS_SSL_CLIENT_CERTIFICATE_VERIFY ); + return( 0 ); + } + else +#endif /* MBEDTLS_SSL_CLI_C */ + + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); +} + +int mbedtls_ssl_tls13_write_certificate( mbedtls_ssl_context* ssl ) +{ + int ret; + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write certificate" ) ); + + /* Coordination: Check if we need to send a certificate. */ + MBEDTLS_SSL_PROC_CHK_NEG( ssl_tls13_write_certificate_coordinate( ssl ) ); + +#if defined(MBEDTLS_KEY_EXCHANGE_WITH_CERT_ENABLED) + if( ret == SSL_WRITE_CERTIFICATE_AVAILABLE ) + { + unsigned char *buf; + size_t buf_len, msg_len; + + MBEDTLS_SSL_PROC_CHK( mbedtls_ssl_tls13_start_handshake_msg( ssl, + MBEDTLS_SSL_HS_CERTIFICATE, &buf, &buf_len ) ); + + MBEDTLS_SSL_PROC_CHK( ssl_tls13_write_certificate( ssl, buf, buf_len, + &msg_len ) ); + + mbedtls_ssl_tls13_add_hs_msg_to_checksum( ssl, + MBEDTLS_SSL_HS_CERTIFICATE, + buf, + msg_len ); + + MBEDTLS_SSL_PROC_CHK( ssl_tls13_finalize_write_certificate( ssl ) ); + MBEDTLS_SSL_PROC_CHK( mbedtls_ssl_tls13_finish_handshake_msg( + ssl, buf_len, msg_len ) ); + } + else +#endif /* MBEDTLS_KEY_EXCHANGE_WITH_CERT_ENABLED */ + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip write certificate" ) ); + MBEDTLS_SSL_PROC_CHK( ssl_tls13_finalize_write_certificate( ssl ) ); + } + +cleanup: + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write certificate" ) ); + return( ret ); +} + /* * * STATE HANDLING: Incoming Finished message.