diff --git a/ChangeLog b/ChangeLog index ef5b104f1..34defcc57 100644 --- a/ChangeLog +++ b/ChangeLog @@ -11,6 +11,9 @@ Features * Add the oid certificate policy x509 extension. * It is now possible to perform RSA PKCS v1.5 signatures with RIPEMD-160 digest. Contributed by Jack Lloyd and Fortanix Inc. + * Extend the MBEDTLS_SSL_EXPORT_KEYS to export the handshake randbytes, + and the used tls-prf. + * Add public API for tls-prf function, according to requested enum. Bugfix * Fix private key DER output in the key_app_writer example. File contents @@ -36,6 +39,11 @@ Bugfix * Add a check for MBEDTLS_X509_CRL_PARSE_C in ssl_server2, guarding the crl sni entry parameter. Reported by inestlerode in #560. +API Changes + * Extend the MBEDTLS_SSL_EXPORT_KEYS to export the handshake randbytes, + and the used tls-prf. + * Add public API for tls-prf function, according to requested enum. + Changes * Server's RSA certificate in certs.c was SHA-1 signed. In the default mbedTLS configuration only SHA-2 signed certificates are accepted. diff --git a/include/mbedtls/ssl.h b/include/mbedtls/ssl.h index 135be0501..a460e2073 100644 --- a/include/mbedtls/ssl.h +++ b/include/mbedtls/ssl.h @@ -450,6 +450,18 @@ typedef enum } mbedtls_ssl_states; +/* + * The tls_prf function types. + */ +typedef enum +{ + MBEDTLS_SSL_TLS_PRF_NONE, + MBEDTLS_SSL_TLS_PRF_SSL3, + MBEDTLS_SSL_TLS_PRF_TLS1, + MBEDTLS_SSL_TLS_PRF_SHA384, + MBEDTLS_SSL_TLS_PRF_SHA256 +} +mbedtls_tls_prf_types; /** * \brief Callback type: send data on the network. * @@ -920,6 +932,11 @@ struct mbedtls_ssl_config /** Callback to export key block and master secret */ int (*f_export_keys)( void *, const unsigned char *, const unsigned char *, size_t, size_t, size_t ); + /** Callback to export key block, master secret, + * tls_prf and random bytes. Should replace f_export_keys */ + int (*f_export_keys_ext)( void *, const unsigned char *, + const unsigned char *, size_t, size_t, size_t, + unsigned char[32], unsigned char[32], mbedtls_tls_prf_types ); void *p_export_keys; /*!< context for key export callback */ #endif @@ -1624,6 +1641,41 @@ typedef int mbedtls_ssl_export_keys_t( void *p_expkey, size_t maclen, size_t keylen, size_t ivlen ); + +/** + * \brief Callback type: Export key block, master secret, + * handshake randbytes and the tls_prf function + * used to derive keys. + * + * \note This is required for certain uses of TLS, e.g. EAP-TLS + * (RFC 5216) and Thread. The key pointers are ephemeral and + * therefore must not be stored. The master secret and keys + * should not be used directly except as an input to a key + * derivation function. + * + * \param p_expkey Context for the callback. + * \param ms Pointer to master secret (fixed length: 48 bytes). + * \param kb Pointer to key block, see RFC 5246 section 6.3. + * (variable length: 2 * maclen + 2 * keylen + 2 * ivlen). + * \param maclen MAC length. + * \param keylen Key length. + * \param ivlen IV length. + * \param client_random The client random bytes. + * \param server_random The server random bytes. + * \param tls_prf_type The tls_prf enum type. + * + * \return 0 if successful, or + * a specific MBEDTLS_ERR_XXX code. + */ +typedef int mbedtls_ssl_export_keys_ext_t( void *p_expkey, + const unsigned char *ms, + const unsigned char *kb, + size_t maclen, + size_t keylen, + size_t ivlen, + unsigned char client_random[32], + unsigned char server_random[32], + mbedtls_tls_prf_types tls_prf_type ); #endif /* MBEDTLS_SSL_EXPORT_KEYS */ /** @@ -1689,6 +1741,20 @@ void mbedtls_ssl_conf_session_tickets_cb( mbedtls_ssl_config *conf, void mbedtls_ssl_conf_export_keys_cb( mbedtls_ssl_config *conf, mbedtls_ssl_export_keys_t *f_export_keys, void *p_export_keys ); + +/** + * \brief Configure extended key export callback. + * (Default: none.) + * + * \note See \c mbedtls_ssl_export_keys_ext_t. + * + * \param conf SSL configuration context + * \param f_export_keys_ext Callback for exporting keys + * \param p_export_keys Context for the callback + */ +void mbedtls_ssl_conf_export_keys_ext_cb( mbedtls_ssl_config *conf, + mbedtls_ssl_export_keys_ext_t *f_export_keys_ext, + void *p_export_keys ); #endif /* MBEDTLS_SSL_EXPORT_KEYS */ #if defined(MBEDTLS_SSL_ASYNC_PRIVATE) @@ -3487,6 +3553,27 @@ void mbedtls_ssl_session_init( mbedtls_ssl_session *session ); */ void mbedtls_ssl_session_free( mbedtls_ssl_session *session ); +/** + * \brief TLS-PRF function for key derivation. + * + * \param prf The tls_prf type funtion type to be used. + * \param secret Secret for the key derivation function. + * \param slen Length of the secret. + * \param label String label for the key derivation function, + * terminated with null character. + * \param random Random bytes. + * \param rlen Length of the random bytes buffer. + * \param dstbuf The buffer holding the derived key. + * \param dlen Length of the output buffer. + * + * \return 0 on sucess. An SSL specific error on failure. + */ +int mbedtls_ssl_tls_prf( const mbedtls_tls_prf_types prf, + const unsigned char *secret, size_t slen, + const char *label, + const unsigned char *random, size_t rlen, + unsigned char *dstbuf, size_t dlen ); + #ifdef __cplusplus } #endif diff --git a/include/mbedtls/ssl_internal.h b/include/mbedtls/ssl_internal.h index ac4d96dbf..9c4be53f7 100644 --- a/include/mbedtls/ssl_internal.h +++ b/include/mbedtls/ssl_internal.h @@ -276,6 +276,10 @@ struct mbedtls_ssl_sig_hash_set_t #endif /* MBEDTLS_SSL_PROTO_TLS1_2 && MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED */ +typedef int mbedtls_ssl_tls_prf_cb( const unsigned char *secret, size_t slen, + const char *label, + const unsigned char *random, size_t rlen, + unsigned char *dstbuf, size_t dlen ); /* * This structure contains the parameters only needed during handshake. */ @@ -425,9 +429,7 @@ struct mbedtls_ssl_handshake_params void (*update_checksum)(mbedtls_ssl_context *, const unsigned char *, size_t); void (*calc_verify)(mbedtls_ssl_context *, unsigned char *); void (*calc_finished)(mbedtls_ssl_context *, unsigned char *, int); - int (*tls_prf)(const unsigned char *, size_t, const char *, - const unsigned char *, size_t, - unsigned char *, size_t); + mbedtls_ssl_tls_prf_cb *tls_prf; mbedtls_ssl_ciphersuite_t const *ciphersuite_info; diff --git a/library/ssl_tls.c b/library/ssl_tls.c index da42ed7ae..d25dffd07 100644 --- a/library/ssl_tls.c +++ b/library/ssl_tls.c @@ -425,7 +425,8 @@ static int tls1_prf( const unsigned char *secret, size_t slen, size_t nb, hs; size_t i, j, k; const unsigned char *S1, *S2; - unsigned char tmp[128]; + unsigned char *tmp; + size_t tmp_len = 0; unsigned char h_i[20]; const mbedtls_md_info_t *md_info; mbedtls_md_context_t md_ctx; @@ -433,8 +434,13 @@ static int tls1_prf( const unsigned char *secret, size_t slen, mbedtls_md_init( &md_ctx ); - if( sizeof( tmp ) < 20 + strlen( label ) + rlen ) - return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + tmp_len = 20 + strlen( label ) + rlen; + tmp = mbedtls_calloc( 1, tmp_len ); + if( tmp == NULL ) + { + ret = MBEDTLS_ERR_SSL_ALLOC_FAILED; + goto exit; + } hs = ( slen + 1 ) / 2; S1 = secret; @@ -449,10 +455,15 @@ static int tls1_prf( const unsigned char *secret, size_t slen, * First compute P_md5(secret,label+random)[0..dlen] */ if( ( md_info = mbedtls_md_info_from_type( MBEDTLS_MD_MD5 ) ) == NULL ) - return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + { + ret = MBEDTLS_ERR_SSL_INTERNAL_ERROR; + goto exit; + } if( ( ret = mbedtls_md_setup( &md_ctx, md_info, 1 ) ) != 0 ) - return( ret ); + { + goto exit; + } mbedtls_md_hmac_starts( &md_ctx, S1, hs ); mbedtls_md_hmac_update( &md_ctx, tmp + 20, nb ); @@ -480,10 +491,15 @@ static int tls1_prf( const unsigned char *secret, size_t slen, * XOR out with P_sha1(secret,label+random)[0..dlen] */ if( ( md_info = mbedtls_md_info_from_type( MBEDTLS_MD_SHA1 ) ) == NULL ) - return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + { + ret = MBEDTLS_ERR_SSL_INTERNAL_ERROR; + goto exit; + } if( ( ret = mbedtls_md_setup( &md_ctx, md_info, 1 ) ) != 0 ) - return( ret ); + { + goto exit; + } mbedtls_md_hmac_starts( &md_ctx, S2, hs ); mbedtls_md_hmac_update( &md_ctx, tmp + 20, nb ); @@ -505,12 +521,14 @@ static int tls1_prf( const unsigned char *secret, size_t slen, dstbuf[i + j] = (unsigned char)( dstbuf[i + j] ^ h_i[j] ); } +exit: mbedtls_md_free( &md_ctx ); - mbedtls_platform_zeroize( tmp, sizeof( tmp ) ); + mbedtls_platform_zeroize( tmp, tmp_len ); mbedtls_platform_zeroize( h_i, sizeof( h_i ) ); - return( 0 ); + mbedtls_free( tmp ); + return( ret ); } #endif /* MBEDTLS_SSL_PROTO_TLS1) || MBEDTLS_SSL_PROTO_TLS1_1 */ @@ -593,7 +611,8 @@ static int tls_prf_generic( mbedtls_md_type_t md_type, { size_t nb; size_t i, j, k, md_len; - unsigned char tmp[128]; + unsigned char *tmp; + size_t tmp_len = 0; unsigned char h_i[MBEDTLS_MD_MAX_SIZE]; const mbedtls_md_info_t *md_info; mbedtls_md_context_t md_ctx; @@ -606,8 +625,13 @@ static int tls_prf_generic( mbedtls_md_type_t md_type, md_len = mbedtls_md_get_size( md_info ); - if( sizeof( tmp ) < md_len + strlen( label ) + rlen ) - return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + tmp_len = md_len + strlen( label ) + rlen; + tmp = mbedtls_calloc( 1, tmp_len ); + if( tmp == NULL ) + { + ret = MBEDTLS_ERR_SSL_ALLOC_FAILED; + goto exit; + } nb = strlen( label ); memcpy( tmp + md_len, label, nb ); @@ -618,7 +642,7 @@ static int tls_prf_generic( mbedtls_md_type_t md_type, * Compute P_(secret, label + random)[0..dlen] */ if ( ( ret = mbedtls_md_setup( &md_ctx, md_info, 1 ) ) != 0 ) - return( ret ); + goto exit; mbedtls_md_hmac_starts( &md_ctx, secret, slen ); mbedtls_md_hmac_update( &md_ctx, tmp + md_len, nb ); @@ -640,12 +664,15 @@ static int tls_prf_generic( mbedtls_md_type_t md_type, dstbuf[i + j] = h_i[j]; } +exit: mbedtls_md_free( &md_ctx ); - mbedtls_platform_zeroize( tmp, sizeof( tmp ) ); + mbedtls_platform_zeroize( tmp, tmp_len ); mbedtls_platform_zeroize( h_i, sizeof( h_i ) ); - return( 0 ); + mbedtls_free( tmp ); + + return( ret ); } #endif /* MBEDTLS_USE_PSA_CRYPTO */ #if defined(MBEDTLS_SHA256_C) @@ -724,6 +751,83 @@ static int ssl_use_opaque_psk( mbedtls_ssl_context const *ssl ) #endif /* MBEDTLS_USE_PSA_CRYPTO && MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED */ +#if defined(MBEDTLS_SSL_EXPORT_KEYS) +static mbedtls_tls_prf_types tls_prf_get_type( mbedtls_ssl_tls_prf_cb *tls_prf ) +{ +#if defined(MBEDTLS_SSL_PROTO_SSL3) + if( tls_prf == ssl3_prf ) + { + return( MBEDTLS_SSL_TLS_PRF_SSL3 ); + } + else +#endif +#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) + if( tls_prf == tls1_prf ) + { + return( MBEDTLS_SSL_TLS_PRF_TLS1 ); + } + else +#endif +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) +#if defined(MBEDTLS_SHA512_C) + if( tls_prf == tls_prf_sha384 ) + { + return( MBEDTLS_SSL_TLS_PRF_SHA384 ); + } + else +#endif +#if defined(MBEDTLS_SHA256_C) + if( tls_prf == tls_prf_sha256 ) + { + return( MBEDTLS_SSL_TLS_PRF_SHA256 ); + } + else +#endif +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ + return( MBEDTLS_SSL_TLS_PRF_NONE ); +} +#endif /* MBEDTLS_SSL_EXPORT_KEYS */ + +int mbedtls_ssl_tls_prf( const mbedtls_tls_prf_types prf, + const unsigned char *secret, size_t slen, + const char *label, + const unsigned char *random, size_t rlen, + unsigned char *dstbuf, size_t dlen ) +{ + mbedtls_ssl_tls_prf_cb *tls_prf = NULL; + + switch( prf ) + { +#if defined(MBEDTLS_SSL_PROTO_SSL3) + case MBEDTLS_SSL_TLS_PRF_SSL3: + tls_prf = ssl3_prf; + break; +#endif /* MBEDTLS_SSL_PROTO_SSL3 */ +#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) + case MBEDTLS_SSL_TLS_PRF_TLS1: + tls_prf = tls1_prf; + break; +#endif /* MBEDTLS_SSL_PROTO_TLS1 || MBEDTLS_SSL_PROTO_TLS1_1 */ + +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) +#if defined(MBEDTLS_SHA512_C) + case MBEDTLS_SSL_TLS_PRF_SHA384: + tls_prf = tls_prf_sha384; + break; +#endif /* MBEDTLS_SHA512_C */ +#if defined(MBEDTLS_SHA256_C) + case MBEDTLS_SSL_TLS_PRF_SHA256: + tls_prf = tls_prf_sha256; + break; +#endif /* MBEDTLS_SHA256_C */ +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ + default: + return( MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE ); + } + + return( tls_prf( secret, slen, label, random, rlen, dstbuf, dlen ) ); +} + int mbedtls_ssl_derive_keys( mbedtls_ssl_context *ssl ) { int ret = 0; @@ -988,9 +1092,6 @@ int mbedtls_ssl_derive_keys( mbedtls_ssl_context *ssl ) MBEDTLS_SSL_DEBUG_BUF( 4, "random bytes", handshake->randbytes, 64 ); MBEDTLS_SSL_DEBUG_BUF( 4, "key block", keyblk, 256 ); - mbedtls_platform_zeroize( handshake->randbytes, - sizeof( handshake->randbytes ) ); - /* * Determine the appropriate key, IV and MAC length. */ @@ -1036,7 +1137,7 @@ int mbedtls_ssl_derive_keys( mbedtls_ssl_context *ssl ) ( ret = mbedtls_md_setup( &transform->md_ctx_dec, md_info, 1 ) ) != 0 ) { MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_md_setup", ret ); - return( ret ); + goto end; } /* Get MAC length */ @@ -1106,7 +1207,8 @@ int mbedtls_ssl_derive_keys( mbedtls_ssl_context *ssl ) #endif { MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); - return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + ret = MBEDTLS_ERR_SSL_INTERNAL_ERROR; + goto end; } } } @@ -1168,7 +1270,8 @@ int mbedtls_ssl_derive_keys( mbedtls_ssl_context *ssl ) #endif /* MBEDTLS_SSL_SRV_C */ { MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); - return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + ret = MBEDTLS_ERR_SSL_INTERNAL_ERROR; + goto end; } #if defined(MBEDTLS_SSL_SOME_MODES_USE_MAC) @@ -1178,7 +1281,8 @@ int mbedtls_ssl_derive_keys( mbedtls_ssl_context *ssl ) if( mac_key_len > sizeof( transform->mac_enc ) ) { MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); - return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + ret = MBEDTLS_ERR_SSL_INTERNAL_ERROR; + goto end; } memcpy( transform->mac_enc, mac_enc, mac_key_len ); @@ -1202,7 +1306,8 @@ int mbedtls_ssl_derive_keys( mbedtls_ssl_context *ssl ) #endif { MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); - return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + ret = MBEDTLS_ERR_SSL_INTERNAL_ERROR; + goto end; } #endif /* MBEDTLS_SSL_SOME_MODES_USE_MAC */ @@ -1220,7 +1325,8 @@ int mbedtls_ssl_derive_keys( mbedtls_ssl_context *ssl ) mac_key_len ) ) != 0 ) { MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_hw_record_init", ret ); - return( MBEDTLS_ERR_SSL_HW_ACCEL_FAILED ); + ret = MBEDTLS_ERR_SSL_HW_ACCEL_FAILED; + goto end; } } #else @@ -1236,6 +1342,17 @@ int mbedtls_ssl_derive_keys( mbedtls_ssl_context *ssl ) mac_key_len, keylen, iv_copy_len ); } + + if( ssl->conf->f_export_keys_ext != NULL ) + { + ssl->conf->f_export_keys_ext( ssl->conf->p_export_keys, + session->master, keyblk, + mac_key_len, keylen, + iv_copy_len, + handshake->randbytes + 32, + handshake->randbytes, + tls_prf_get_type( handshake->tls_prf ) ); + } #endif #if defined(MBEDTLS_USE_PSA_CRYPTO) @@ -1253,7 +1370,7 @@ int mbedtls_ssl_derive_keys( mbedtls_ssl_context *ssl ) if( ret != 0 && ret != MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE ) { MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_cipher_setup_psa", ret ); - return( ret ); + goto end; } if( ret == 0 ) @@ -1279,7 +1396,7 @@ int mbedtls_ssl_derive_keys( mbedtls_ssl_context *ssl ) cipher_info ) ) != 0 ) { MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_cipher_setup", ret ); - return( ret ); + goto end; } #if defined(MBEDTLS_USE_PSA_CRYPTO) @@ -1296,7 +1413,7 @@ int mbedtls_ssl_derive_keys( mbedtls_ssl_context *ssl ) if( ret != 0 && ret != MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE ) { MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_cipher_setup_psa", ret ); - return( ret ); + goto end; } if( ret == 0 ) @@ -1322,7 +1439,7 @@ int mbedtls_ssl_derive_keys( mbedtls_ssl_context *ssl ) cipher_info ) ) != 0 ) { MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_cipher_setup", ret ); - return( ret ); + goto end; } if( ( ret = mbedtls_cipher_setkey( &transform->cipher_ctx_enc, key1, @@ -1330,7 +1447,7 @@ int mbedtls_ssl_derive_keys( mbedtls_ssl_context *ssl ) MBEDTLS_ENCRYPT ) ) != 0 ) { MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_cipher_setkey", ret ); - return( ret ); + goto end; } if( ( ret = mbedtls_cipher_setkey( &transform->cipher_ctx_dec, key2, @@ -1338,7 +1455,7 @@ int mbedtls_ssl_derive_keys( mbedtls_ssl_context *ssl ) MBEDTLS_DECRYPT ) ) != 0 ) { MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_cipher_setkey", ret ); - return( ret ); + goto end; } #if defined(MBEDTLS_CIPHER_MODE_CBC) @@ -1348,19 +1465,18 @@ int mbedtls_ssl_derive_keys( mbedtls_ssl_context *ssl ) MBEDTLS_PADDING_NONE ) ) != 0 ) { MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_cipher_set_padding_mode", ret ); - return( ret ); + goto end; } if( ( ret = mbedtls_cipher_set_padding_mode( &transform->cipher_ctx_dec, MBEDTLS_PADDING_NONE ) ) != 0 ) { MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_cipher_set_padding_mode", ret ); - return( ret ); + goto end; } } #endif /* MBEDTLS_CIPHER_MODE_CBC */ - mbedtls_platform_zeroize( keyblk, sizeof( keyblk ) ); #if defined(MBEDTLS_ZLIB_SUPPORT) // Initialize compression @@ -1375,7 +1491,8 @@ int mbedtls_ssl_derive_keys( mbedtls_ssl_context *ssl ) { MBEDTLS_SSL_DEBUG_MSG( 1, ( "alloc(%d bytes) failed", MBEDTLS_SSL_COMPRESS_BUFFER_LEN ) ); - return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); + ret = MBEDTLS_ERR_SSL_ALLOC_FAILED; + goto end; } } @@ -1389,14 +1506,18 @@ int mbedtls_ssl_derive_keys( mbedtls_ssl_context *ssl ) inflateInit( &transform->ctx_inflate ) != Z_OK ) { MBEDTLS_SSL_DEBUG_MSG( 1, ( "Failed to initialize compression" ) ); - return( MBEDTLS_ERR_SSL_COMPRESSION_FAILED ); + ret = MBEDTLS_ERR_SSL_COMPRESSION_FAILED; + goto end; } } #endif /* MBEDTLS_ZLIB_SUPPORT */ MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= derive keys" ) ); - - return( 0 ); +end: + mbedtls_platform_zeroize( keyblk, sizeof( keyblk ) ); + mbedtls_platform_zeroize( handshake->randbytes, + sizeof( handshake->randbytes ) ); + return( ret ); } #if defined(MBEDTLS_SSL_PROTO_SSL3) @@ -8620,6 +8741,14 @@ void mbedtls_ssl_conf_export_keys_cb( mbedtls_ssl_config *conf, conf->f_export_keys = f_export_keys; conf->p_export_keys = p_export_keys; } + +void mbedtls_ssl_conf_export_keys_ext_cb( mbedtls_ssl_config *conf, + mbedtls_ssl_export_keys_ext_t *f_export_keys_ext, + void *p_export_keys ) +{ + conf->f_export_keys_ext = f_export_keys_ext; + conf->p_export_keys = p_export_keys; +} #endif #if defined(MBEDTLS_SSL_ASYNC_PRIVATE) diff --git a/programs/ssl/ssl_client2.c b/programs/ssl/ssl_client2.c index 2cddfb42a..62f2c5790 100644 --- a/programs/ssl/ssl_client2.c +++ b/programs/ssl/ssl_client2.c @@ -126,7 +126,7 @@ int main( void ) #define DFL_EXTENDED_MS -1 #define DFL_ETM -1 #define DFL_CA_CALLBACK 0 - +#define DFL_EAP_TLS 0 #define GET_REQUEST "GET %s HTTP/1.0\r\nExtra-header: " #define GET_REQUEST_END "\r\n\r\n" @@ -204,6 +204,13 @@ int main( void ) #define USAGE_TICKETS "" #endif /* MBEDTLS_SSL_SESSION_TICKETS */ +#if defined(MBEDTLS_SSL_EXPORT_KEYS) +#define USAGE_EAP_TLS \ + " eap_tls=%%d default: 0 (disabled)\n" +#else +#define USAGE_EAP_TLS "" +#endif /* MBEDTLS_SSL_EXPORT_KEYS */ + #if defined(MBEDTLS_SSL_TRUNCATED_HMAC) #define USAGE_TRUNC_HMAC \ " trunc_hmac=%%d default: library default\n" @@ -348,6 +355,7 @@ int main( void ) " reco_delay=%%d default: 0 seconds\n" \ " reconnect_hard=%%d default: 0 (disabled)\n" \ USAGE_TICKETS \ + USAGE_EAP_TLS \ USAGE_MAX_FRAG_LEN \ USAGE_TRUNC_HMAC \ USAGE_CONTEXT_CRT_CB \ @@ -448,10 +456,47 @@ struct options int extended_ms; /* negotiate extended master secret? */ int etm; /* negotiate encrypt then mac? */ int context_crt_cb; /* use context-specific CRT verify callback */ + int eap_tls; /* derive EAP-TLS keying material? */ } opt; int query_config( const char *config ); +#if defined(MBEDTLS_SSL_EXPORT_KEYS) +typedef struct eap_tls_keys +{ + unsigned char master_secret[48]; + unsigned char randbytes[64]; + mbedtls_tls_prf_types tls_prf_type; +} eap_tls_keys; + +static int eap_tls_key_derivation ( void *p_expkey, + const unsigned char *ms, + const unsigned char *kb, + size_t maclen, + size_t keylen, + size_t ivlen, + unsigned char client_random[32], + unsigned char server_random[32], + mbedtls_tls_prf_types tls_prf_type ) +{ + eap_tls_keys *keys = (eap_tls_keys *)p_expkey; + + ( ( void ) kb ); + memcpy( keys->master_secret, ms, sizeof( keys->master_secret ) ); + memcpy( keys->randbytes, client_random, 32 ); + memcpy( keys->randbytes + 32, server_random, 32 ); + keys->tls_prf_type = tls_prf_type; + + if( opt.debug_level > 2 ) + { + mbedtls_printf("exported maclen is %u\n", (unsigned)maclen); + mbedtls_printf("exported keylen is %u\n", (unsigned)keylen); + mbedtls_printf("exported ivlen is %u\n", (unsigned)ivlen); + } + return( 0 ); +} +#endif + static void my_debug( void *ctx, int level, const char *file, int line, const char *str ) @@ -713,6 +758,12 @@ int main( int argc, char *argv[] ) #endif char *p, *q; const int *list; +#if defined(MBEDTLS_SSL_EXPORT_KEYS) + unsigned char eap_tls_keymaterial[16]; + unsigned char eap_tls_iv[8]; + const char* eap_tls_label = "client EAP encryption"; + eap_tls_keys eap_tls_keying; +#endif /* * Make sure memory references are valid. @@ -818,6 +869,7 @@ int main( int argc, char *argv[] ) opt.extended_ms = DFL_EXTENDED_MS; opt.etm = DFL_ETM; opt.dgram_packing = DFL_DGRAM_PACKING; + opt.eap_tls = DFL_EAP_TLS; for( i = 1; i < argc; i++ ) { @@ -1176,6 +1228,12 @@ int main( int argc, char *argv[] ) { return query_config( q ); } + else if( strcmp( p, "eap_tls" ) == 0 ) + { + opt.eap_tls = atoi( q ); + if( opt.eap_tls < 0 || opt.eap_tls > 1 ) + goto usage; + } else goto usage; } @@ -1652,6 +1710,12 @@ int main( int argc, char *argv[] ) mbedtls_ssl_conf_encrypt_then_mac( &conf, opt.etm ); #endif +#if defined(MBEDTLS_SSL_EXPORT_KEYS) + if( opt.eap_tls != 0 ) + mbedtls_ssl_conf_export_keys_ext_cb( &conf, eap_tls_key_derivation, + &eap_tls_keying ); +#endif + #if defined(MBEDTLS_SSL_CBC_RECORD_SPLITTING) if( opt.recsplit != DFL_RECSPLIT ) mbedtls_ssl_conf_cbc_record_splitting( &conf, opt.recsplit @@ -1917,6 +1981,57 @@ int main( int argc, char *argv[] ) } #endif +#if defined(MBEDTLS_SSL_EXPORT_KEYS) + if( opt.eap_tls != 0 ) + { + size_t j = 0; + + if( ( ret = mbedtls_ssl_tls_prf( eap_tls_keying.tls_prf_type, + eap_tls_keying.master_secret, + sizeof( eap_tls_keying.master_secret ), + eap_tls_label, + eap_tls_keying.randbytes, + sizeof( eap_tls_keying.randbytes ), + eap_tls_keymaterial, + sizeof( eap_tls_keymaterial ) ) ) + != 0 ) + { + mbedtls_printf( " failed\n ! mbedtls_ssl_tls_prf returned -0x%x\n\n", + -ret ); + goto exit; + } + + mbedtls_printf( " EAP-TLS key material is:" ); + for( j = 0; j < sizeof( eap_tls_keymaterial ); j++ ) + { + if( j % 8 == 0 ) + mbedtls_printf("\n "); + mbedtls_printf("%02x ", eap_tls_keymaterial[j] ); + } + mbedtls_printf("\n"); + + if( ( ret = mbedtls_ssl_tls_prf( eap_tls_keying.tls_prf_type, NULL, 0, + eap_tls_label, + eap_tls_keying.randbytes, + sizeof( eap_tls_keying.randbytes ), + eap_tls_iv, + sizeof( eap_tls_iv ) ) ) != 0 ) + { + mbedtls_printf( " failed\n ! mbedtls_ssl_tls_prf returned -0x%x\n\n", + -ret ); + goto exit; + } + + mbedtls_printf( " EAP-TLS IV is:" ); + for( j = 0; j < sizeof( eap_tls_iv ); j++ ) + { + if( j % 8 == 0 ) + mbedtls_printf("\n "); + mbedtls_printf("%02x ", eap_tls_iv[j] ); + } + mbedtls_printf("\n"); + } +#endif if( opt.reconnect != 0 ) { mbedtls_printf(" . Saving session for reuse..." ); diff --git a/programs/ssl/ssl_server2.c b/programs/ssl/ssl_server2.c index 5ee90ac35..807f880f8 100644 --- a/programs/ssl/ssl_server2.c +++ b/programs/ssl/ssl_server2.c @@ -168,6 +168,7 @@ int main( void ) #define DFL_EXTENDED_MS -1 #define DFL_ETM -1 #define DFL_CA_CALLBACK 0 +#define DFL_EAP_TLS 0 #define LONG_RESPONSE "

01-blah-blah-blah-blah-blah-blah-blah-blah-blah\r\n" \ "02-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah\r\n" \ @@ -281,6 +282,13 @@ int main( void ) #define USAGE_TICKETS "" #endif /* MBEDTLS_SSL_SESSION_TICKETS */ +#if defined(MBEDTLS_SSL_EXPORT_KEYS) +#define USAGE_EAP_TLS \ + " eap_tls=%%d default: 0 (disabled)\n" +#else +#define USAGE_EAP_TLS "" +#endif /* MBEDTLS_SSL_EXPORT_KEYS */ + #if defined(MBEDTLS_SSL_CACHE_C) #define USAGE_CACHE \ " cache_max=%%d default: cache default (50)\n" \ @@ -442,6 +450,7 @@ int main( void ) " exchanges=%%d default: 1\n" \ "\n" \ USAGE_TICKETS \ + USAGE_EAP_TLS \ USAGE_CACHE \ USAGE_MAX_FRAG_LEN \ USAGE_TRUNC_HMAC \ @@ -563,10 +572,47 @@ struct options int dtls_mtu; /* UDP Maximum tranport unit for DTLS */ int dgram_packing; /* allow/forbid datagram packing */ int badmac_limit; /* Limit of records with bad MAC */ + int eap_tls; /* derive EAP-TLS keying material? */ } opt; int query_config( const char *config ); +#if defined(MBEDTLS_SSL_EXPORT_KEYS) +typedef struct eap_tls_keys +{ + unsigned char master_secret[48]; + unsigned char randbytes[64]; + mbedtls_tls_prf_types tls_prf_type; +} eap_tls_keys; + +static int eap_tls_key_derivation ( void *p_expkey, + const unsigned char *ms, + const unsigned char *kb, + size_t maclen, + size_t keylen, + size_t ivlen, + unsigned char client_random[32], + unsigned char server_random[32], + mbedtls_tls_prf_types tls_prf_type ) +{ + eap_tls_keys *keys = (eap_tls_keys *)p_expkey; + + ( ( void ) kb ); + memcpy( keys->master_secret, ms, sizeof( keys->master_secret ) ); + memcpy( keys->randbytes, client_random, 32 ); + memcpy( keys->randbytes + 32, server_random, 32 ); + keys->tls_prf_type = tls_prf_type; + + if( opt.debug_level > 2 ) + { + mbedtls_printf("exported maclen is %u\n", (unsigned)maclen); + mbedtls_printf("exported keylen is %u\n", (unsigned)keylen); + mbedtls_printf("exported ivlen is %u\n", (unsigned)ivlen); + } + return( 0 ); +} +#endif + static void my_debug( void *ctx, int level, const char *file, int line, const char *str ) @@ -1444,6 +1490,12 @@ int main( int argc, char *argv[] ) #if defined(MBEDTLS_USE_PSA_CRYPTO) psa_status_t status; #endif +#if defined(MBEDTLS_SSL_EXPORT_KEYS) + unsigned char eap_tls_keymaterial[16]; + unsigned char eap_tls_iv[8]; + const char* eap_tls_label = "client EAP encryption"; + eap_tls_keys eap_tls_keying; +#endif #if defined(MBEDTLS_MEMORY_BUFFER_ALLOC_C) mbedtls_memory_buffer_alloc_init( alloc_buf, sizeof(alloc_buf) ); @@ -1585,6 +1637,7 @@ int main( int argc, char *argv[] ) opt.badmac_limit = DFL_BADMAC_LIMIT; opt.extended_ms = DFL_EXTENDED_MS; opt.etm = DFL_ETM; + opt.eap_tls = DFL_EAP_TLS; for( i = 1; i < argc; i++ ) { @@ -1975,6 +2028,12 @@ int main( int argc, char *argv[] ) { return query_config( q ); } + else if( strcmp( p, "eap_tls" ) == 0 ) + { + opt.eap_tls = atoi( q ); + if( opt.eap_tls < 0 || opt.eap_tls > 1 ) + goto usage; + } else goto usage; } @@ -2537,6 +2596,12 @@ int main( int argc, char *argv[] ) mbedtls_ssl_conf_encrypt_then_mac( &conf, opt.etm ); #endif +#if defined(MBEDTLS_SSL_EXPORT_KEYS) + if( opt.eap_tls != 0 ) + mbedtls_ssl_conf_export_keys_ext_cb( &conf, eap_tls_key_derivation, + &eap_tls_keying ); +#endif + #if defined(MBEDTLS_SSL_ALPN) if( opt.alpn_string != NULL ) if( ( ret = mbedtls_ssl_conf_alpn_protocols( &conf, alpn_list ) ) != 0 ) @@ -3117,6 +3182,57 @@ handshake: } #endif /* MBEDTLS_X509_CRT_PARSE_C */ +#if defined(MBEDTLS_SSL_EXPORT_KEYS) + if( opt.eap_tls != 0 ) + { + size_t j = 0; + + if( ( ret = mbedtls_ssl_tls_prf( eap_tls_keying.tls_prf_type, + eap_tls_keying.master_secret, + sizeof( eap_tls_keying.master_secret ), + eap_tls_label, + eap_tls_keying.randbytes, + sizeof( eap_tls_keying.randbytes ), + eap_tls_keymaterial, + sizeof( eap_tls_keymaterial ) ) ) + != 0 ) + { + mbedtls_printf( " failed\n ! mbedtls_ssl_tls_prf returned -0x%x\n\n", + -ret ); + goto exit; + } + + mbedtls_printf( " EAP-TLS key material is:" ); + for( j = 0; j < sizeof( eap_tls_keymaterial ); j++ ) + { + if( j % 8 == 0 ) + mbedtls_printf("\n "); + mbedtls_printf("%02x ", eap_tls_keymaterial[j] ); + } + mbedtls_printf("\n"); + + if( ( ret = mbedtls_ssl_tls_prf( eap_tls_keying.tls_prf_type, NULL, 0, + eap_tls_label, + eap_tls_keying.randbytes, + sizeof( eap_tls_keying.randbytes ), + eap_tls_iv, + sizeof( eap_tls_iv ) ) ) != 0 ) + { + mbedtls_printf( " failed\n ! mbedtls_ssl_tls_prf returned -0x%x\n\n", + -ret ); + goto exit; + } + + mbedtls_printf( " EAP-TLS IV is:" ); + for( j = 0; j < sizeof( eap_tls_iv ); j++ ) + { + if( j % 8 == 0 ) + mbedtls_printf("\n "); + mbedtls_printf("%02x ", eap_tls_iv[j] ); + } + mbedtls_printf("\n"); + } +#endif if( opt.exchanges == 0 ) goto close_notify; diff --git a/tests/ssl-opt.sh b/tests/ssl-opt.sh index 08d4be308..cef87bceb 100755 --- a/tests/ssl-opt.sh +++ b/tests/ssl-opt.sh @@ -7939,6 +7939,18 @@ run_test "DTLS proxy: 3d, gnutls server, fragmentation, nbio" \ -s "Extra-header:" \ -c "Extra-header:" +requires_config_enabled MBEDTLS_SSL_EXPORT_KEYS +run_test "export keys functionality" \ + "$P_SRV eap_tls=1 debug_level=3" \ + "$P_CLI eap_tls=1 debug_level=3" \ + 0 \ + -s "exported maclen is " \ + -s "exported keylen is " \ + -s "exported ivlen is " \ + -c "exported maclen is " \ + -c "exported keylen is " \ + -c "exported ivlen is " + # Final report echo "------------------------------------------------------------------------" diff --git a/tests/suites/test_suite_ssl.data b/tests/suites/test_suite_ssl.data index 2b3517dec..fd81ffec4 100644 --- a/tests/suites/test_suite_ssl.data +++ b/tests/suites/test_suite_ssl.data @@ -5633,3 +5633,42 @@ ssl_crypt_record_small:MBEDTLS_CIPHER_NULL:MBEDTLS_MD_MD5:0:1:MBEDTLS_SSL_MINOR_ Record crypt, little space, NULL cipher, SSL3, MD5, short tag, EtM depends_on:MBEDTLS_CIPHER_NULL_CIPHER:MBEDTLS_SSL_PROTO_SSL3:MBEDTLS_MD5_C:MBEDTLS_SSL_ENCRYPT_THEN_MAC ssl_crypt_record_small:MBEDTLS_CIPHER_NULL:MBEDTLS_MD_MD5:1:1:MBEDTLS_SSL_MINOR_VERSION_0 + +SSL TLS_PRF MBEDTLS_SSL_TLS_PRF_NONE +ssl_tls_prf:MBEDTLS_SSL_TLS_PRF_NONE:"":"":"test tls_prf label":"":MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE + +SSL TLS_PRF MBEDTLS_SSL_TLS_PRF_SSL3 +depends_on:MBEDTLS_SSL_PROTO_SSL3 +ssl_tls_prf:MBEDTLS_SSL_TLS_PRF_SSL3:"1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef":"1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef":"test tls_prf label":"3ff3d192aa599255339def5a9723444a":0 + +SSL TLS_PRF MBEDTLS_SSL_TLS_PRF_TLS1 TLS 1.0 enabled +depends_on:MBEDTLS_SSL_PROTO_TLS1 +ssl_tls_prf:MBEDTLS_SSL_TLS_PRF_TLS1:"1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef":"1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef":"test tls_prf label":"8defca540d41d4c79d390027295bb4e6":0 + +SSL TLS_PRF MBEDTLS_SSL_TLS_PRF_TLS1 TLS 1.1 enabled +depends_on:MBEDTLS_SSL_PROTO_TLS1_1 +ssl_tls_prf:MBEDTLS_SSL_TLS_PRF_TLS1:"1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef":"1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef":"test tls_prf label":"8defca540d41d4c79d390027295bb4e6":0 + +SSL TLS_PRF MBEDTLS_SSL_TLS_PRF_SHA384 +depends_on:MBEDTLS_SHA512_C:MBEDTLS_SSL_PROTO_TLS1_2 +ssl_tls_prf:MBEDTLS_SSL_TLS_PRF_SHA384:"1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef":"1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef":"test tls_prf label":"a4206a36eef93f496611c2b7806625c3":0 + +SSL TLS_PRF MBEDTLS_SSL_TLS_PRF_SHA256 +depends_on:MBEDTLS_SHA256_C:MBEDTLS_SSL_PROTO_TLS1_2 +ssl_tls_prf:MBEDTLS_SSL_TLS_PRF_SHA256:"1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef":"1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef":"test tls_prf label":"7f9998393198a02c8d731ccc2ef90b2c":0 + +SSL TLS_PRF MBEDTLS_SSL_TLS_PRF_SSL3 not enabled +depends_on:!MBEDTLS_SSL_PROTO_SSL3 +ssl_tls_prf:MBEDTLS_SSL_TLS_PRF_SSL3:"1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef":"1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef":"test tls_prf label":"3ff3d192aa599255339def5a9723444a":MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE + +SSL TLS_PRF MBEDTLS_SSL_TLS_PRF_TLS1 TLS 1.X not enabled +depends_on:!MBEDTLS_SSL_PROTO_TLS1:!MBEDTLS_SSL_PROTO_TLS1_1 +ssl_tls_prf:MBEDTLS_SSL_TLS_PRF_TLS1:"1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef":"1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef":"test tls_prf label":"8defca540d41d4c79d390027295bb4e6":MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE + +SSL TLS_PRF MBEDTLS_SSL_TLS_PRF_SHA384 SHA-512 not enabled +depends_on:!MBEDTLS_SHA512_C +ssl_tls_prf:MBEDTLS_SSL_TLS_PRF_SHA384:"1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef":"1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef":"test tls_prf label":"a4206a36eef93f496611c2b7806625c3":MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE + +SSL TLS_PRF MBEDTLS_SSL_TLS_PRF_SHA256 SHA-256 not enabled +depends_on:!MBEDTLS_SHA256_C +ssl_tls_prf:MBEDTLS_SSL_TLS_PRF_SHA256:"1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef":"1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef":"test tls_prf label":"7f9998393198a02c8d731ccc2ef90b2c":MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE diff --git a/tests/suites/test_suite_ssl.function b/tests/suites/test_suite_ssl.function index 05ecd8ad5..ecf186ed3 100644 --- a/tests/suites/test_suite_ssl.function +++ b/tests/suites/test_suite_ssl.function @@ -541,3 +541,32 @@ exit: mbedtls_free( buf ); } /* END_CASE */ + +/* BEGIN_CASE */ +void ssl_tls_prf( int type, data_t * secret, data_t * random, + char *label, data_t *result_hex_str, int exp_ret ) +{ + unsigned char *output; + + output = mbedtls_calloc( 1, result_hex_str->len ); + if( output == NULL ) + goto exit; + +#if defined(MBEDTLS_USE_PSA_CRYPTO) + TEST_ASSERT( psa_crypto_init() == 0 ); +#endif + + TEST_ASSERT( mbedtls_ssl_tls_prf( type, secret->x, secret->len, + label, random->x, random->len, + output, result_hex_str->len ) == exp_ret ); + + if( exp_ret == 0 ) + { + TEST_ASSERT( hexcmp( output, result_hex_str->x, + result_hex_str->len, result_hex_str->len ) == 0 ); + } +exit: + + mbedtls_free( output ); +} +/* END_CASE */