From 6ba010eaada9c089c92804969f9181d88d7ccc7c Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 8 Jul 2026 14:44:55 +0100 Subject: [PATCH] [tls] Reject incorrect server names before completing validation We currently verify the certificate name only after completing validation of the certificate chain. Perform this check instead at the point of parsing the Certificate record, to create an invariant that the recorded server certificate always has the correct name (even if not yet validated). Signed-off-by: Michael Brown --- src/net/tls.c | 31 ++++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/src/net/tls.c b/src/net/tls.c index 8e91f7a85..41111b522 100644 --- a/src/net/tls.c +++ b/src/net/tls.c @@ -116,6 +116,10 @@ FILE_SECBOOT ( PERMITTED ); #define EINFO_EIO_ALERT \ __einfo_uniqify ( EINFO_EIO, 0x01, \ "Unknown alert level" ) +#define ENOENT_CERT __einfo_error ( EINFO_ENOENT_CERT ) +#define EINFO_ENOENT_CERT \ + __einfo_uniqify ( EINFO_ENOENT, 0x01, \ + "Missing server certificate" ) #define ENOMEM_CONTEXT __einfo_error ( EINFO_ENOMEM_CONTEXT ) #define EINFO_ENOMEM_CONTEXT \ __einfo_uniqify ( EINFO_ENOMEM, 0x01, \ @@ -2692,6 +2696,7 @@ static int tls_new_session_ticket ( struct tls_connection *tls, */ static int tls_parse_chain ( struct tls_connection *tls, const void *data, size_t len ) { + struct x509_certificate *cert; size_t remaining = len; int rc; @@ -2721,7 +2726,6 @@ static int tls_parse_chain ( struct tls_connection *tls, } __attribute__ (( packed )) *certificate = data; size_t certificate_len; size_t record_len; - struct x509_certificate *cert; /* Parse header */ if ( sizeof ( *certificate ) > remaining ) { @@ -2757,8 +2761,25 @@ static int tls_parse_chain ( struct tls_connection *tls, remaining -= record_len; } + /* Identify server certificate */ + cert = x509_first ( tls->server.chain ); + if ( ! cert ) { + DBGC ( tls, "TLS %p certificate chain is empty\n", tls ); + rc = -ENOENT_CERT; + goto err_empty; + } + + /* Verify server name */ + if ( ( rc = x509_check_name ( cert, tls->session->name ) ) != 0 ) { + DBGC ( tls, "TLS %p server certificate does not match %s: %s\n", + tls, tls->session->name, strerror ( rc ) ); + goto err_name; + } + return 0; + err_name: + err_empty: err_parse: err_overlength: err_underlength: @@ -4044,7 +4065,6 @@ static struct interface_descriptor tls_cipherstream_desc = * @v rc Reason for completion */ static void tls_validator_done ( struct tls_connection *tls, int rc ) { - struct tls_session *session = tls->session; struct x509_certificate *cert; /* Mark validation as complete */ @@ -4065,13 +4085,6 @@ static void tls_validator_done ( struct tls_connection *tls, int rc ) { cert = x509_first ( tls->server.chain ); assert ( cert != NULL ); - /* Verify server name */ - if ( ( rc = x509_check_name ( cert, session->name ) ) != 0 ) { - DBGC ( tls, "TLS %p server certificate does not match %s: %s\n", - tls, session->name, strerror ( rc ) ); - goto err; - } - /* Extract the now trusted server public key */ tls->server.algorithm = cert->subject.public_key.algorithm; memcpy ( &tls->server.key, &cert->subject.public_key.raw, -- 2.47.3