diff options
author | Michael Brown | 2014-03-25 16:01:32 +0100 |
---|---|---|
committer | Michael Brown | 2014-03-25 17:30:43 +0100 |
commit | 01fa7efa38060c010103d444b47a2cd3ff684f82 (patch) | |
tree | aa9eaf98352260b208691559165696b71fb05812 /src | |
parent | [ocsp] Handle OCSP responses that don't provide certificates (diff) | |
download | ipxe-01fa7efa38060c010103d444b47a2cd3ff684f82.tar.gz ipxe-01fa7efa38060c010103d444b47a2cd3ff684f82.tar.xz ipxe-01fa7efa38060c010103d444b47a2cd3ff684f82.zip |
[crypto] Remove dynamically-allocated storage for certificate name
iPXE currently allocates a copy the certificate's common name as a
string. This string is used by the TLS and CMS code to check
certificate names against an expected name, and also appears in
debugging messages.
Provide a function x509_check_name() to centralise certificate name
checking (in preparation for adding subjectAlternativeName support),
and a function x509_name() to provide a name to be used in debugging
messages, and remove the dynamically allocated string.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Diffstat (limited to 'src')
-rw-r--r-- | src/crypto/cms.c | 5 | ||||
-rw-r--r-- | src/crypto/ocsp.c | 89 | ||||
-rw-r--r-- | src/crypto/x509.c | 136 | ||||
-rw-r--r-- | src/include/ipxe/x509.h | 5 | ||||
-rw-r--r-- | src/net/tls.c | 14 | ||||
-rw-r--r-- | src/net/validator.c | 2 |
6 files changed, 143 insertions, 108 deletions
diff --git a/src/crypto/cms.c b/src/crypto/cms.c index c0c8d144..6191d1bb 100644 --- a/src/crypto/cms.c +++ b/src/crypto/cms.c @@ -130,7 +130,7 @@ static int cms_parse_certificates ( struct cms_signature *sig, } cert = x509_last ( sig->certificates ); DBGC ( sig, "CMS %p found certificate %s\n", - sig, cert->subject.name ); + sig, x509_name ( cert ) ); /* Move to next certificate */ asn1_skip_any ( &cursor ); @@ -680,8 +680,7 @@ int cms_verify ( struct cms_signature *sig, userptr_t data, size_t len, /* Verify using all signerInfos */ list_for_each_entry ( info, &sig->info, list ) { cert = x509_first ( info->chain ); - if ( name && ( ( cert->subject.name == NULL ) || - ( strcmp ( cert->subject.name, name ) != 0 ) ) ) + if ( name && ( x509_check_name ( cert, name ) != 0 ) ) continue; if ( ( rc = cms_verify_signer_info ( sig, info, data, len, time, root ) ) != 0 ) diff --git a/src/crypto/ocsp.c b/src/crypto/ocsp.c index 27c0080c..1b39fd0d 100644 --- a/src/crypto/ocsp.c +++ b/src/crypto/ocsp.c @@ -177,11 +177,11 @@ static int ocsp_request ( struct ocsp_check *ocsp ) { asn1_wrap ( builder, ASN1_SEQUENCE ), asn1_wrap ( builder, ASN1_SEQUENCE ) ) ) != 0 ) { DBGC ( ocsp, "OCSP %p \"%s\" could not build request: %s\n", - ocsp, ocsp->cert->subject.name, strerror ( rc ) ); + ocsp, x509_name ( ocsp->cert ), strerror ( rc ) ); return rc; } DBGC2 ( ocsp, "OCSP %p \"%s\" request is:\n", - ocsp, ocsp->cert->subject.name ); + ocsp, x509_name ( ocsp->cert ) ); DBGC2_HDA ( ocsp, 0, builder->data, builder->len ); /* Parse certificate ID for comparison with response */ @@ -192,7 +192,7 @@ static int ocsp_request ( struct ocsp_check *ocsp ) { asn1_enter ( cert_id, ASN1_SEQUENCE ), asn1_enter ( cert_id, ASN1_SEQUENCE ) ) ) != 0 ) { DBGC ( ocsp, "OCSP %p \"%s\" could not locate certID: %s\n", - ocsp, ocsp->cert->subject.name, strerror ( rc ) ); + ocsp, x509_name ( ocsp->cert ), strerror ( rc ) ); return rc; } @@ -218,7 +218,7 @@ static int ocsp_uri_string ( struct ocsp_check *ocsp ) { base_uri_string = ocsp->cert->extensions.auth_info.ocsp.uri; if ( ! base_uri_string ) { DBGC ( ocsp, "OCSP %p \"%s\" has no OCSP URI\n", - ocsp, ocsp->cert->subject.name ); + ocsp, x509_name ( ocsp->cert ) ); rc = -ENOTTY; goto err_no_uri; } @@ -250,7 +250,7 @@ static int ocsp_uri_string ( struct ocsp_check *ocsp ) { goto err_ocsp_uri; } DBGC2 ( ocsp, "OCSP %p \"%s\" URI is %s\n", - ocsp, ocsp->cert->subject.name, ocsp->uri_string ); + ocsp, x509_name ( ocsp->cert ), ocsp->uri_string ); /* Success */ rc = 0; @@ -327,14 +327,14 @@ static int ocsp_parse_response_status ( struct ocsp_check *ocsp, memcpy ( &cursor, raw, sizeof ( cursor ) ); if ( ( rc = asn1_enter ( &cursor, ASN1_ENUMERATED ) ) != 0 ) { DBGC ( ocsp, "OCSP %p \"%s\" could not locate responseStatus: " - "%s\n", ocsp, ocsp->cert->subject.name, strerror ( rc )); + "%s\n", ocsp, x509_name ( ocsp->cert ), strerror ( rc )); return rc; } /* Extract response status */ if ( cursor.len != sizeof ( status ) ) { DBGC ( ocsp, "OCSP %p \"%s\" invalid status:\n", - ocsp, ocsp->cert->subject.name ); + ocsp, x509_name ( ocsp->cert ) ); DBGC_HDA ( ocsp, 0, cursor.data, cursor.len ); return -EINVAL; } @@ -343,7 +343,7 @@ static int ocsp_parse_response_status ( struct ocsp_check *ocsp, /* Check response status */ if ( status != OCSP_STATUS_SUCCESSFUL ) { DBGC ( ocsp, "OCSP %p \"%s\" response status %d\n", - ocsp, ocsp->cert->subject.name, status ); + ocsp, x509_name ( ocsp->cert ), status ); return EPROTO_STATUS ( status ); } @@ -368,7 +368,7 @@ static int ocsp_parse_response_type ( struct ocsp_check *ocsp, /* Check responseType is "basic" */ if ( asn1_compare ( &oid_basic_response_type_cursor, &cursor ) != 0 ) { DBGC ( ocsp, "OCSP %p \"%s\" response type not supported:\n", - ocsp, ocsp->cert->subject.name ); + ocsp, x509_name ( ocsp->cert ) ); DBGC_HDA ( ocsp, 0, cursor.data, cursor.len ); return -ENOTSUP_RESPONSE_TYPE; } @@ -443,17 +443,17 @@ static int ocsp_parse_responder_id ( struct ocsp_check *ocsp, switch ( type ) { case ASN1_EXPLICIT_TAG ( 1 ) : DBGC2 ( ocsp, "OCSP %p \"%s\" responder identified by name\n", - ocsp, ocsp->cert->subject.name ); + ocsp, x509_name ( ocsp->cert ) ); responder->compare = ocsp_compare_responder_name; return 0; case ASN1_EXPLICIT_TAG ( 2 ) : DBGC2 ( ocsp, "OCSP %p \"%s\" responder identified by key " - "hash\n", ocsp, ocsp->cert->subject.name ); + "hash\n", ocsp, x509_name ( ocsp->cert ) ); responder->compare = ocsp_compare_responder_key_hash; return 0; default: DBGC ( ocsp, "OCSP %p \"%s\" unsupported responder ID type " - "%d\n", ocsp, ocsp->cert->subject.name, type ); + "%d\n", ocsp, x509_name ( ocsp->cert ), type ); return -ENOTSUP_RESPONDER_ID; } } @@ -474,7 +474,7 @@ static int ocsp_parse_cert_id ( struct ocsp_check *ocsp, asn1_shrink_any ( &cursor ); if ( asn1_compare ( &cursor, &ocsp->request.cert_id ) != 0 ) { DBGC ( ocsp, "OCSP %p \"%s\" certID mismatch:\n", - ocsp, ocsp->cert->subject.name ); + ocsp, x509_name ( ocsp->cert ) ); DBGC_HDA ( ocsp, 0, ocsp->request.cert_id.data, ocsp->request.cert_id.len ); DBGC_HDA ( ocsp, 0, cursor.data, cursor.len ); @@ -512,7 +512,7 @@ static int ocsp_parse_responses ( struct ocsp_check *ocsp, /* Check certStatus */ if ( asn1_type ( &cursor ) != ASN1_IMPLICIT_TAG ( 0 ) ) { DBGC ( ocsp, "OCSP %p \"%s\" non-good certStatus:\n", - ocsp, ocsp->cert->subject.name ); + ocsp, x509_name ( ocsp->cert ) ); DBGC_HDA ( ocsp, 0, cursor.data, cursor.len ); return -EACCES_CERT_STATUS; } @@ -522,11 +522,11 @@ static int ocsp_parse_responses ( struct ocsp_check *ocsp, if ( ( rc = asn1_generalized_time ( &cursor, &response->this_update ) ) != 0 ) { DBGC ( ocsp, "OCSP %p \"%s\" could not parse thisUpdate: %s\n", - ocsp, ocsp->cert->subject.name, strerror ( rc ) ); + ocsp, x509_name ( ocsp->cert ), strerror ( rc ) ); return rc; } DBGC2 ( ocsp, "OCSP %p \"%s\" this update was at time %lld\n", - ocsp, ocsp->cert->subject.name, response->this_update ); + ocsp, x509_name ( ocsp->cert ), response->this_update ); asn1_skip_any ( &cursor ); /* Parse nextUpdate, if present */ @@ -536,11 +536,11 @@ static int ocsp_parse_responses ( struct ocsp_check *ocsp, &response->next_update ) ) != 0 ) { DBGC ( ocsp, "OCSP %p \"%s\" could not parse " "nextUpdate: %s\n", ocsp, - ocsp->cert->subject.name, strerror ( rc ) ); + x509_name ( ocsp->cert ), strerror ( rc ) ); return rc; } DBGC2 ( ocsp, "OCSP %p \"%s\" next update is at time %lld\n", - ocsp, ocsp->cert->subject.name, response->next_update ); + ocsp, x509_name ( ocsp->cert ), response->next_update ); } else { /* If no nextUpdate is present, this indicates that * "newer revocation information is available all the @@ -550,7 +550,7 @@ static int ocsp_parse_responses ( struct ocsp_check *ocsp, * time and it would still be valid. */ DBGC ( ocsp, "OCSP %p \"%s\" responder is a moron\n", - ocsp, ocsp->cert->subject.name ); + ocsp, x509_name ( ocsp->cert ) ); response->next_update = time ( NULL ); } @@ -630,7 +630,7 @@ static int ocsp_parse_certs ( struct ocsp_check *ocsp, &cert ) ) != 0 ) { DBGC ( ocsp, "OCSP %p \"%s\" could not parse " "certificate: %s\n", ocsp, - ocsp->cert->subject.name, strerror ( rc ) ); + x509_name ( ocsp->cert ), strerror ( rc ) ); DBGC_HDA ( ocsp, 0, cursor.data, cursor.len ); return rc; } @@ -638,9 +638,10 @@ static int ocsp_parse_certs ( struct ocsp_check *ocsp, /* Use if this certificate matches the responder ID */ if ( response->responder.compare ( ocsp, cert ) == 0 ) { response->signer = cert; - DBGC2 ( ocsp, "OCSP %p \"%s\" response is signed by " - "\"%s\"\n", ocsp, ocsp->cert->subject.name, - response->signer->subject.name ); + DBGC2 ( ocsp, "OCSP %p \"%s\" response is signed by ", + ocsp, x509_name ( ocsp->cert ) ); + DBGC2 ( ocsp, "\"%s\"\n", + x509_name ( response->signer ) ); return 0; } @@ -650,7 +651,7 @@ static int ocsp_parse_certs ( struct ocsp_check *ocsp, } DBGC ( ocsp, "OCSP %p \"%s\" missing responder certificate\n", - ocsp, ocsp->cert->subject.name ); + ocsp, x509_name ( ocsp->cert ) ); return -EACCES_NO_RESPONDER; } @@ -682,17 +683,17 @@ static int ocsp_parse_basic_response ( struct ocsp_check *ocsp, if ( ( rc = asn1_signature_algorithm ( &cursor, algorithm ) ) != 0 ) { DBGC ( ocsp, "OCSP %p \"%s\" cannot parse signature " "algorithm: %s\n", - ocsp, ocsp->cert->subject.name, strerror ( rc ) ); + ocsp, x509_name ( ocsp->cert ), strerror ( rc ) ); return rc; } DBGC2 ( ocsp, "OCSP %p \"%s\" signature algorithm is %s\n", - ocsp, ocsp->cert->subject.name, (*algorithm)->name ); + ocsp, x509_name ( ocsp->cert ), (*algorithm)->name ); asn1_skip_any ( &cursor ); /* Parse signature */ if ( ( rc = asn1_integral_bit_string ( &cursor, signature ) ) != 0 ) { DBGC ( ocsp, "OCSP %p \"%s\" cannot parse signature: %s\n", - ocsp, ocsp->cert->subject.name, strerror ( rc ) ); + ocsp, x509_name ( ocsp->cert ), strerror ( rc ) ); return rc; } asn1_skip_any ( &cursor ); @@ -836,7 +837,7 @@ static int ocsp_check_signature ( struct ocsp_check *ocsp, if ( ( rc = pubkey_init ( pubkey, pubkey_ctx, public_key->raw.data, public_key->raw.len ) ) != 0 ) { DBGC ( ocsp, "OCSP %p \"%s\" could not initialise public key: " - "%s\n", ocsp, ocsp->cert->subject.name, strerror ( rc )); + "%s\n", ocsp, x509_name ( ocsp->cert ), strerror ( rc )); goto err_init; } @@ -845,12 +846,12 @@ static int ocsp_check_signature ( struct ocsp_check *ocsp, response->signature.data, response->signature.len ) ) != 0 ) { DBGC ( ocsp, "OCSP %p \"%s\" signature verification failed: " - "%s\n", ocsp, ocsp->cert->subject.name, strerror ( rc )); + "%s\n", ocsp, x509_name ( ocsp->cert ), strerror ( rc )); goto err_verify; } DBGC2 ( ocsp, "OCSP %p \"%s\" signature is correct\n", - ocsp, ocsp->cert->subject.name ); + ocsp, x509_name ( ocsp->cert ) ); err_verify: pubkey_final ( pubkey, pubkey_ctx ); @@ -892,10 +893,10 @@ int ocsp_validate ( struct ocsp_check *ocsp, time_t time ) { x509_invalidate ( signer ); if ( ( rc = x509_validate ( signer, ocsp->issuer, time, &ocsp_root ) ) != 0 ) { - DBGC ( ocsp, "OCSP %p \"%s\" could not validate " - "signer \"%s\": %s\n", ocsp, - ocsp->cert->subject.name, signer->subject.name, - strerror ( rc ) ); + DBGC ( ocsp, "OCSP %p \"%s\" could not validate ", + ocsp, x509_name ( ocsp->cert ) ); + DBGC ( ocsp, "signer \"%s\": %s\n", + x509_name ( signer ), strerror ( rc ) ); return rc; } @@ -904,9 +905,10 @@ int ocsp_validate ( struct ocsp_check *ocsp, time_t time ) { */ if ( ! ( signer->extensions.ext_usage.bits & X509_OCSP_SIGNING ) ) { - DBGC ( ocsp, "OCSP %p \"%s\" signer \"%s\" is " - "not an OCSP-signing certificate\n", ocsp, - ocsp->cert->subject.name, signer->subject.name ); + DBGC ( ocsp, "OCSP %p \"%s\" ", + ocsp, x509_name ( ocsp->cert ) ); + DBGC ( ocsp, "signer \"%s\" is not an OCSP-signing " + "certificate\n", x509_name ( signer ) ); return -EACCES_NON_OCSP_SIGNING; } } @@ -920,16 +922,16 @@ int ocsp_validate ( struct ocsp_check *ocsp, time_t time ) { */ if ( response->this_update > ( time + X509_ERROR_MARGIN_TIME ) ) { DBGC ( ocsp, "OCSP %p \"%s\" response is not yet valid (at " - "time %lld)\n", ocsp, ocsp->cert->subject.name, time ); + "time %lld)\n", ocsp, x509_name ( ocsp->cert ), time ); return -EACCES_STALE; } if ( response->next_update < ( time - X509_ERROR_MARGIN_TIME ) ) { DBGC ( ocsp, "OCSP %p \"%s\" response is stale (at time " - "%lld)\n", ocsp, ocsp->cert->subject.name, time ); + "%lld)\n", ocsp, x509_name ( ocsp->cert ), time ); return -EACCES_STALE; } DBGC2 ( ocsp, "OCSP %p \"%s\" response is valid (at time %lld)\n", - ocsp, ocsp->cert->subject.name, time ); + ocsp, x509_name ( ocsp->cert ), time ); /* Mark certificate as passing OCSP verification */ ocsp->cert->extensions.auth_info.ocsp.good = 1; @@ -938,11 +940,12 @@ int ocsp_validate ( struct ocsp_check *ocsp, time_t time ) { if ( ( rc = x509_validate ( ocsp->cert, ocsp->issuer, time, &ocsp_root ) ) != 0 ) { DBGC ( ocsp, "OCSP %p \"%s\" could not validate certificate: " - "%s\n", ocsp, ocsp->cert->subject.name, strerror ( rc )); + "%s\n", ocsp, x509_name ( ocsp->cert ), strerror ( rc )); return rc; } - DBGC ( ocsp, "OCSP %p \"%s\" successfully validated using \"%s\"\n", - ocsp, ocsp->cert->subject.name, signer->subject.name ); + DBGC ( ocsp, "OCSP %p \"%s\" successfully validated ", + ocsp, x509_name ( ocsp->cert ) ); + DBGC ( ocsp, "using \"%s\"\n", x509_name ( signer ) ); return 0; } diff --git a/src/crypto/x509.c b/src/crypto/x509.c index d54124c5..eb7d5029 100644 --- a/src/crypto/x509.c +++ b/src/crypto/x509.c @@ -103,11 +103,34 @@ FILE_LICENCE ( GPL2_OR_LATER ); __einfo_error ( EINFO_EACCES_OCSP_REQUIRED ) #define EINFO_EACCES_OCSP_REQUIRED \ __einfo_uniqify ( EINFO_EACCES, 0x09, "OCSP check required" ) +#define EACCES_WRONG_NAME \ + __einfo_error ( EINFO_EACCES_WRONG_NAME ) +#define EINFO_EACCES_WRONG_NAME \ + __einfo_uniqify ( EINFO_EACCES, 0x0a, "Incorrect certificate name" ) /** Certificate cache */ static LIST_HEAD ( x509_cache ); /** + * Get X.509 certificate name (for debugging) + * + * @v cert X.509 certificate + * @ret name Name (for debugging) + */ +const char * x509_name ( struct x509_certificate *cert ) { + struct asn1_cursor *common_name = &cert->subject.common_name; + static char buf[64]; + size_t len; + + len = common_name->len; + if ( len > ( sizeof ( buf ) - 1 /* NUL */ ) ) + len = ( sizeof ( buf ) - 1 /* NUL */ ); + memcpy ( buf, common_name->data, len ); + buf[len] = '\0'; + return buf; +} + +/** * Free X.509 certificate * * @v refcnt Reference count @@ -117,7 +140,6 @@ static void x509_free ( struct refcnt *refcnt ) { container_of ( refcnt, struct x509_certificate, refcnt ); DBGC2 ( cert, "X509 %p freed\n", cert ); - free ( cert->subject.name ); free ( cert->extensions.auth_info.ocsp.uri ); free ( cert ); } @@ -292,11 +314,10 @@ static int x509_parse_validity ( struct x509_certificate *cert, * Parse X.509 certificate common name * * @v cert X.509 certificate - * @v name Common name to fill in * @v raw ASN.1 cursor * @ret rc Return status code */ -static int x509_parse_common_name ( struct x509_certificate *cert, char **name, +static int x509_parse_common_name ( struct x509_certificate *cert, const struct asn1_cursor *raw ) { struct asn1_cursor cursor; struct asn1_cursor oid_cursor; @@ -325,19 +346,9 @@ static int x509_parse_common_name ( struct x509_certificate *cert, char **name, return rc; } - /* Allocate and copy name */ - *name = zalloc ( name_cursor.len + 1 /* NUL */ ); - if ( ! *name ) - return -ENOMEM; - memcpy ( *name, name_cursor.data, name_cursor.len ); - - /* Check that name contains no NULs */ - if ( strlen ( *name ) != name_cursor.len ) { - DBGC ( cert, "X509 %p contains malicious commonName:\n", - cert ); - DBGC_HDA ( cert, 0, raw->data, raw->len ); - return rc; - } + /* Record common name */ + memcpy ( &cert->subject.common_name, &name_cursor, + sizeof ( cert->subject.common_name ) ); return 0; } @@ -357,7 +368,6 @@ static int x509_parse_common_name ( struct x509_certificate *cert, char **name, static int x509_parse_subject ( struct x509_certificate *cert, const struct asn1_cursor *raw ) { struct x509_subject *subject = &cert->subject; - char **name = &subject->name; int rc; /* Record raw subject */ @@ -367,9 +377,10 @@ static int x509_parse_subject ( struct x509_certificate *cert, DBGC2_HDA ( cert, 0, subject->raw.data, subject->raw.len ); /* Parse common name */ - if ( ( rc = x509_parse_common_name ( cert, name, raw ) ) != 0 ) + if ( ( rc = x509_parse_common_name ( cert, raw ) ) != 0 ) return rc; - DBGC2 ( cert, "X509 %p common name is \"%s\":\n", cert, *name ); + DBGC2 ( cert, "X509 %p common name is \"%s\":\n", cert, + x509_name ( cert ) ); return 0; } @@ -1045,7 +1056,7 @@ int x509_certificate ( const void *data, size_t len, if ( asn1_compare ( &cursor, &(*cert)->raw ) == 0 ) { DBGC2 ( *cert, "X509 %p \"%s\" cache hit\n", - *cert, (*cert)->subject.name ); + *cert, x509_name ( *cert ) ); /* Mark as most recently used */ list_del ( &(*cert)->list ); @@ -1109,14 +1120,14 @@ static int x509_check_signature ( struct x509_certificate *cert, digest_init ( digest, digest_ctx ); digest_update ( digest, digest_ctx, cert->tbs.data, cert->tbs.len ); digest_final ( digest, digest_ctx, digest_out ); - DBGC2 ( cert, "X509 %p \"%s\" digest:\n", cert, cert->subject.name ); + DBGC2 ( cert, "X509 %p \"%s\" digest:\n", cert, x509_name ( cert ) ); DBGC2_HDA ( cert, 0, digest_out, sizeof ( digest_out ) ); /* Check that signature public key algorithm matches signer */ if ( public_key->algorithm->pubkey != pubkey ) { DBGC ( cert, "X509 %p \"%s\" signature algorithm %s does not " "match signer's algorithm %s\n", - cert, cert->subject.name, algorithm->name, + cert, x509_name ( cert ), algorithm->name, public_key->algorithm->name ); rc = -EINVAL_ALGORITHM_MISMATCH; goto err_mismatch; @@ -1126,14 +1137,14 @@ static int x509_check_signature ( struct x509_certificate *cert, if ( ( rc = pubkey_init ( pubkey, pubkey_ctx, public_key->raw.data, public_key->raw.len ) ) != 0 ) { DBGC ( cert, "X509 %p \"%s\" cannot initialise public key: " - "%s\n", cert, cert->subject.name, strerror ( rc ) ); + "%s\n", cert, x509_name ( cert ), strerror ( rc ) ); goto err_pubkey_init; } if ( ( rc = pubkey_verify ( pubkey, pubkey_ctx, digest, digest_out, signature->value.data, signature->value.len ) ) != 0 ) { DBGC ( cert, "X509 %p \"%s\" signature verification failed: " - "%s\n", cert, cert->subject.name, strerror ( rc ) ); + "%s\n", cert, x509_name ( cert ), strerror ( rc ) ); goto err_pubkey_verify; } @@ -1172,9 +1183,10 @@ int x509_check_issuer ( struct x509_certificate *cert, * for some enjoyable ranting on this subject. */ if ( asn1_compare ( &cert->issuer.raw, &issuer->subject.raw ) != 0 ) { - DBGC ( cert, "X509 %p \"%s\" issuer does not match X509 %p " - "\"%s\" subject\n", cert, cert->subject.name, - issuer, issuer->subject.name ); + DBGC ( cert, "X509 %p \"%s\" issuer does not match ", + cert, x509_name ( cert ) ); + DBGC ( cert, "X509 %p \"%s\" subject\n", + issuer, x509_name ( issuer ) ); DBGC_HDA ( cert, 0, cert->issuer.raw.data, cert->issuer.raw.len ); DBGC_HDA ( issuer, 0, issuer->subject.raw.data, @@ -1184,16 +1196,18 @@ int x509_check_issuer ( struct x509_certificate *cert, /* Check that issuer is allowed to sign certificates */ if ( ! issuer->extensions.basic.ca ) { - DBGC ( issuer, "X509 %p \"%s\" cannot sign X509 %p \"%s\": " - "not a CA certificate\n", issuer, issuer->subject.name, - cert, cert->subject.name ); + DBGC ( issuer, "X509 %p \"%s\" cannot sign ", + issuer, x509_name ( issuer ) ); + DBGC ( issuer, "X509 %p \"%s\": not a CA certificate\n", + cert, x509_name ( cert ) ); return -EACCES_NOT_CA; } if ( issuer->extensions.usage.present && ( ! ( issuer->extensions.usage.bits & X509_KEY_CERT_SIGN ) ) ) { - DBGC ( issuer, "X509 %p \"%s\" cannot sign X509 %p \"%s\": " - "no keyCertSign usage\n", issuer, issuer->subject.name, - cert, cert->subject.name ); + DBGC ( issuer, "X509 %p \"%s\" cannot sign ", + issuer, x509_name ( issuer ) ); + DBGC ( issuer, "X509 %p \"%s\": no keyCertSign usage\n", + cert, x509_name ( cert ) ); return -EACCES_KEY_USAGE; } @@ -1243,14 +1257,14 @@ int x509_check_root ( struct x509_certificate *cert, struct x509_root *root ) { if ( memcmp ( fingerprint, root_fingerprint, sizeof ( fingerprint ) ) == 0 ) { DBGC ( cert, "X509 %p \"%s\" is a root certificate\n", - cert, cert->subject.name ); + cert, x509_name ( cert ) ); return 0; } root_fingerprint += sizeof ( fingerprint ); } DBGC2 ( cert, "X509 %p \"%s\" is not a root certificate\n", - cert, cert->subject.name ); + cert, x509_name ( cert ) ); return -ENOENT; } @@ -1267,17 +1281,17 @@ int x509_check_time ( struct x509_certificate *cert, time_t time ) { /* Check validity period */ if ( validity->not_before.time > ( time + X509_ERROR_MARGIN_TIME ) ) { DBGC ( cert, "X509 %p \"%s\" is not yet valid (at time %lld)\n", - cert, cert->subject.name, time ); + cert, x509_name ( cert ), time ); return -EACCES_EXPIRED; } if ( validity->not_after.time < ( time - X509_ERROR_MARGIN_TIME ) ) { DBGC ( cert, "X509 %p \"%s\" has expired (at time %lld)\n", - cert, cert->subject.name, time ); + cert, x509_name ( cert ), time ); return -EACCES_EXPIRED; } DBGC2 ( cert, "X509 %p \"%s\" is valid (at time %lld)\n", - cert, cert->subject.name, time ); + cert, x509_name ( cert ), time ); return 0; } @@ -1324,15 +1338,15 @@ int x509_validate ( struct x509_certificate *cert, /* Fail unless we have an issuer */ if ( ! issuer ) { DBGC2 ( cert, "X509 %p \"%s\" has no issuer\n", - cert, cert->subject.name ); + cert, x509_name ( cert ) ); return -EACCES_UNTRUSTED; } /* Fail unless issuer has already been validated */ if ( ! issuer->valid ) { - DBGC ( cert, "X509 %p \"%s\" issuer %p \"%s\" has not yet " - "been validated\n", cert, cert->subject.name, - issuer, issuer->subject.name ); + DBGC ( cert, "X509 %p \"%s\" ", cert, x509_name ( cert ) ); + DBGC ( cert, "issuer %p \"%s\" has not yet been validated\n", + issuer, x509_name ( issuer ) ); return -EACCES_OUT_OF_ORDER; } @@ -1342,9 +1356,9 @@ int x509_validate ( struct x509_certificate *cert, /* Fail if path length constraint is violated */ if ( issuer->path_remaining == 0 ) { - DBGC ( cert, "X509 %p \"%s\" issuer %p \"%s\" path length " - "exceeded\n", cert, cert->subject.name, - issuer, issuer->subject.name ); + DBGC ( cert, "X509 %p \"%s\" ", cert, x509_name ( cert ) ); + DBGC ( cert, "issuer %p \"%s\" path length exceeded\n", + issuer, x509_name ( issuer ) ); return -EACCES_PATH_LEN; } @@ -1352,7 +1366,7 @@ int x509_validate ( struct x509_certificate *cert, if ( cert->extensions.auth_info.ocsp.uri && ( ! cert->extensions.auth_info.ocsp.good ) ) { DBGC ( cert, "X509 %p \"%s\" requires an OCSP check\n", - cert, cert->subject.name ); + cert, x509_name ( cert ) ); return -EACCES_OCSP_REQUIRED; } @@ -1365,9 +1379,31 @@ int x509_validate ( struct x509_certificate *cert, /* Mark certificate as valid */ cert->valid = 1; - DBGC ( cert, "X509 %p \"%s\" successfully validated using issuer %p " - "\"%s\"\n", cert, cert->subject.name, - issuer, issuer->subject.name ); + DBGC ( cert, "X509 %p \"%s\" successfully validated using ", + cert, x509_name ( cert ) ); + DBGC ( cert, "issuer %p \"%s\"\n", issuer, x509_name ( issuer ) ); + return 0; +} + +/** + * Check X.509 certificate name + * + * @v cert X.509 certificate + * @v name Name + * @ret rc Return status code + */ +int x509_check_name ( struct x509_certificate *cert, const char *name ) { + struct asn1_cursor *common_name = &cert->subject.common_name; + size_t len = strlen ( name ); + + /* Check commonName */ + if ( ! ( ( len == common_name->len ) && + ( memcmp ( name, common_name->data, len ) == 0 ) ) ) { + DBGC ( cert, "X509 %p \"%s\" does not match name \"%s\"\n", + cert, x509_name ( cert ), name ); + return -EACCES_WRONG_NAME; + } + return 0; } @@ -1435,7 +1471,7 @@ int x509_append ( struct x509_chain *chain, struct x509_certificate *cert ) { link->cert = x509_get ( cert ); list_add_tail ( &link->list, &chain->links ); DBGC ( chain, "X509 chain %p added X509 %p \"%s\"\n", - chain, cert, cert->subject.name ); + chain, cert, x509_name ( cert ) ); return 0; } diff --git a/src/include/ipxe/x509.h b/src/include/ipxe/x509.h index a47942a7..3e4bcd20 100644 --- a/src/include/ipxe/x509.h +++ b/src/include/ipxe/x509.h @@ -65,7 +65,7 @@ struct x509_subject { /** Raw subject */ struct asn1_cursor raw; /** Common name */ - char *name; + struct asn1_cursor common_name; /** Public key information */ struct x509_public_key public_key; }; @@ -330,11 +330,14 @@ struct x509_root { const void *fingerprints; }; +extern const char * x509_name ( struct x509_certificate *cert ); + extern int x509_certificate ( const void *data, size_t len, struct x509_certificate **cert ); extern int x509_validate ( struct x509_certificate *cert, struct x509_certificate *issuer, time_t time, struct x509_root *root ); +extern int x509_check_name ( struct x509_certificate *cert, const char *name ); extern struct x509_chain * x509_alloc_chain ( void ); extern int x509_append ( struct x509_chain *chain, diff --git a/src/net/tls.c b/src/net/tls.c index 5e18f726..742a7c0b 100644 --- a/src/net/tls.c +++ b/src/net/tls.c @@ -49,10 +49,6 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include <ipxe/tls.h> /* Disambiguate the various error causes */ -#define EACCES_WRONG_NAME __einfo_error ( EINFO_EACCES_WRONG_NAME ) -#define EINFO_EACCES_WRONG_NAME \ - __einfo_uniqify ( EINFO_EACCES, 0x02, \ - "Incorrect server name" ) #define EINVAL_CHANGE_CIPHER __einfo_error ( EINFO_EINVAL_CHANGE_CIPHER ) #define EINFO_EINVAL_CHANGE_CIPHER \ __einfo_uniqify ( EINFO_EINVAL, 0x01, \ @@ -1479,7 +1475,7 @@ static int tls_parse_chain ( struct tls_session *tls, } cert = x509_last ( tls->chain ); DBGC ( tls, "TLS %p found certificate %s\n", - tls, cert->subject.name ); + tls, x509_name ( cert ) ); /* Move to next certificate in list */ data = next; @@ -2454,11 +2450,9 @@ static void tls_validator_done ( struct tls_session *tls, int rc ) { assert ( cert != NULL ); /* Verify server name */ - if ( ( cert->subject.name == NULL ) || - ( strcmp ( cert->subject.name, tls->name ) != 0 ) ) { - DBGC ( tls, "TLS %p server name incorrect (expected %s, got " - "%s)\n", tls, tls->name, cert->subject.name ); - rc = -EACCES_WRONG_NAME; + if ( ( rc = x509_check_name ( cert, tls->name ) ) != 0 ) { + DBGC ( tls, "TLS %p server certificate does not match %s: %s\n", + tls, tls->name, strerror ( rc ) ); goto err; } diff --git a/src/net/validator.c b/src/net/validator.c index 1de3bb9d..7913ed64 100644 --- a/src/net/validator.c +++ b/src/net/validator.c @@ -179,7 +179,7 @@ static int validator_append ( struct validator *validator, } cert = x509_last ( certs ); DBGC ( validator, "VALIDATOR %p found certificate %s\n", - validator, cert->subject.name ); + validator, x509_name ( cert ) ); /* Move to next certificate */ asn1_skip_any ( &cursor ); |