[tls] Add support for the Extended Master Secret

RFC 7627 defines the Extended Master Secret (EMS) as an alternative
calculation that uses the digest of all handshake messages rather than
just the client and server random bytes.

Add support for negotiating the Extended Master Secret extension and
performing the relevant calculation of the master secret.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
This commit is contained in:
Michael Brown
2025-10-12 22:26:49 +01:00
parent d6656106e9
commit ab64bc5b8d
2 changed files with 55 additions and 7 deletions

View File

@@ -134,6 +134,9 @@ struct tls_header {
/* TLS signature algorithms extension */ /* TLS signature algorithms extension */
#define TLS_SIGNATURE_ALGORITHMS 13 #define TLS_SIGNATURE_ALGORITHMS 13
/* TLS extended master secret extension */
#define TLS_EXTENDED_MASTER_SECRET 23
/* TLS session ticket extension */ /* TLS session ticket extension */
#define TLS_SESSION_TICKET 35 #define TLS_SESSION_TICKET 35
@@ -452,6 +455,8 @@ struct tls_connection {
uint8_t *handshake_ctx; uint8_t *handshake_ctx;
/** Secure renegotiation flag */ /** Secure renegotiation flag */
int secure_renegotiation; int secure_renegotiation;
/** Extended master secret flag */
int extended_master_secret;
/** Verification data */ /** Verification data */
struct tls_verify_data verify; struct tls_verify_data verify;

View File

@@ -200,6 +200,7 @@ static int tls_send_plaintext ( struct tls_connection *tls, unsigned int type,
const void *data, size_t len ); const void *data, size_t len );
static void tls_clear_cipher ( struct tls_connection *tls, static void tls_clear_cipher ( struct tls_connection *tls,
struct tls_cipherspec *cipherspec ); struct tls_cipherspec *cipherspec );
static void tls_verify_handshake ( struct tls_connection *tls, void *out );
/****************************************************************************** /******************************************************************************
* *
@@ -637,21 +638,43 @@ static void tls_prf ( struct tls_connection *tls, const void *secret,
static void tls_generate_master_secret ( struct tls_connection *tls, static void tls_generate_master_secret ( struct tls_connection *tls,
const void *pre_master_secret, const void *pre_master_secret,
size_t pre_master_secret_len ) { size_t pre_master_secret_len ) {
struct digest_algorithm *digest = tls->handshake_digest;
uint8_t digest_out[ digest->digestsize ];
DBGC ( tls, "TLS %p pre-master-secret:\n", tls ); /* Generate handshake digest */
tls_verify_handshake ( tls, digest_out );
/* Show inputs */
DBGC ( tls, "TLS %p pre-master secret:\n", tls );
DBGC_HD ( tls, pre_master_secret, pre_master_secret_len ); DBGC_HD ( tls, pre_master_secret, pre_master_secret_len );
DBGC ( tls, "TLS %p client random bytes:\n", tls ); DBGC ( tls, "TLS %p client random bytes:\n", tls );
DBGC_HD ( tls, &tls->client.random, sizeof ( tls->client.random ) ); DBGC_HD ( tls, &tls->client.random, sizeof ( tls->client.random ) );
DBGC ( tls, "TLS %p server random bytes:\n", tls ); DBGC ( tls, "TLS %p server random bytes:\n", tls );
DBGC_HD ( tls, &tls->server.random, sizeof ( tls->server.random ) ); DBGC_HD ( tls, &tls->server.random, sizeof ( tls->server.random ) );
DBGC ( tls, "TLS %p session hash:\n", tls );
DBGC_HD ( tls, digest_out, sizeof ( digest_out ) );
tls_prf_label ( tls, pre_master_secret, pre_master_secret_len, /* Generate master secret */
&tls->master_secret, sizeof ( tls->master_secret ), if ( tls->extended_master_secret ) {
"master secret", tls_prf_label ( tls, pre_master_secret, pre_master_secret_len,
&tls->client.random, sizeof ( tls->client.random ), &tls->master_secret,
&tls->server.random, sizeof ( tls->server.random ) ); sizeof ( tls->master_secret ),
"extended master secret",
digest_out, sizeof ( digest_out ) );
} else {
tls_prf_label ( tls, pre_master_secret, pre_master_secret_len,
&tls->master_secret,
sizeof ( tls->master_secret ),
"master secret",
&tls->client.random,
sizeof ( tls->client.random ),
&tls->server.random,
sizeof ( tls->server.random ) );
}
DBGC ( tls, "TLS %p generated master secret:\n", tls ); /* Show output */
DBGC ( tls, "TLS %p generated %smaster secret:\n", tls,
( tls->extended_master_secret ? "extended ": "" ) );
DBGC_HD ( tls, &tls->master_secret, sizeof ( tls->master_secret ) ); DBGC_HD ( tls, &tls->master_secret, sizeof ( tls->master_secret ) );
} }
@@ -1195,12 +1218,17 @@ static int tls_client_hello ( struct tls_connection *tls,
uint16_t code[TLS_NUM_NAMED_CURVES]; uint16_t code[TLS_NUM_NAMED_CURVES];
} __attribute__ (( packed )) data; } __attribute__ (( packed )) data;
} __attribute__ (( packed )) *named_curve_ext; } __attribute__ (( packed )) *named_curve_ext;
struct {
uint16_t type;
uint16_t len;
} __attribute__ (( packed )) *extended_master_secret_ext;
struct { struct {
typeof ( *server_name_ext ) server_name; typeof ( *server_name_ext ) server_name;
typeof ( *max_fragment_length_ext ) max_fragment_length; typeof ( *max_fragment_length_ext ) max_fragment_length;
typeof ( *signature_algorithms_ext ) signature_algorithms; typeof ( *signature_algorithms_ext ) signature_algorithms;
typeof ( *renegotiation_info_ext ) renegotiation_info; typeof ( *renegotiation_info_ext ) renegotiation_info;
typeof ( *session_ticket_ext ) session_ticket; typeof ( *session_ticket_ext ) session_ticket;
typeof ( *extended_master_secret_ext ) extended_master_secret;
typeof ( *named_curve_ext ) typeof ( *named_curve_ext )
named_curve[TLS_NUM_NAMED_CURVES ? 1 : 0]; named_curve[TLS_NUM_NAMED_CURVES ? 1 : 0];
} __attribute__ (( packed )) *extensions; } __attribute__ (( packed )) *extensions;
@@ -1286,6 +1314,12 @@ static int tls_client_hello ( struct tls_connection *tls,
memcpy ( session_ticket_ext->data.data, session->ticket, memcpy ( session_ticket_ext->data.data, session->ticket,
sizeof ( session_ticket_ext->data.data ) ); sizeof ( session_ticket_ext->data.data ) );
/* Construct extended master secret extension */
extended_master_secret_ext = &extensions->extended_master_secret;
extended_master_secret_ext->type
= htons ( TLS_EXTENDED_MASTER_SECRET );
extended_master_secret_ext->len = 0;
/* Construct named curves extension, if applicable */ /* Construct named curves extension, if applicable */
if ( sizeof ( extensions->named_curve ) ) { if ( sizeof ( extensions->named_curve ) ) {
named_curve_ext = &extensions->named_curve[0]; named_curve_ext = &extensions->named_curve[0];
@@ -2091,6 +2125,9 @@ static int tls_new_server_hello ( struct tls_connection *tls,
uint8_t len; uint8_t len;
uint8_t data[0]; uint8_t data[0];
} __attribute__ (( packed )) *reneg = NULL; } __attribute__ (( packed )) *reneg = NULL;
const struct {
uint8_t data[0];
} __attribute__ (( packed )) *ems = NULL;
uint16_t version; uint16_t version;
size_t exts_len; size_t exts_len;
size_t ext_len; size_t ext_len;
@@ -2155,6 +2192,9 @@ static int tls_new_server_hello ( struct tls_connection *tls,
return -EINVAL_HELLO; return -EINVAL_HELLO;
} }
break; break;
case htons ( TLS_EXTENDED_MASTER_SECRET ) :
ems = ( ( void * ) ext->data );
break;
} }
} }
} }
@@ -2188,6 +2228,9 @@ static int tls_new_server_hello ( struct tls_connection *tls,
memcpy ( &tls->server.random, &hello_a->random, memcpy ( &tls->server.random, &hello_a->random,
sizeof ( tls->server.random ) ); sizeof ( tls->server.random ) );
/* Handle extended master secret */
tls->extended_master_secret = ( !! ems );
/* Check session ID */ /* Check session ID */
if ( hello_a->session_id_len && if ( hello_a->session_id_len &&
( hello_a->session_id_len == tls->session_id_len ) && ( hello_a->session_id_len == tls->session_id_len ) &&