mirror of
https://github.com/xcat2/xNBA.git
synced 2024-11-28 12:19:46 +00:00
From: Alexander Chernyakhovsky <achernya@google.com>
Date: Thu, 25 Jul 2013 21:35:14 -0400 Subject: [PATCH 1/3] Implement subject-alt-name and wildcard certificates
This commit is contained in:
parent
d603ea68c4
commit
6b435d458a
@ -520,6 +520,54 @@ static int x509_parse_key_usage ( struct x509_certificate *cert,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse X.509 certificate subject alternative name
|
||||
*
|
||||
* @v cert X.509 certificate
|
||||
* @v raw ASN.1 cursor
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int x509_parse_subject_alt_name ( struct x509_certificate *cert,
|
||||
const struct asn1_cursor *raw ) {
|
||||
struct x509_subject_alt_name *subject_alt_name = &cert->extensions.subject_alt_name;
|
||||
struct asn1_cursor cursor;
|
||||
struct asn1_cursor string_cursor;
|
||||
int rc;
|
||||
|
||||
/* Mark extension as present */
|
||||
subject_alt_name->present = 1;
|
||||
|
||||
DBGC ( cert, "X509 %p parsing subjectAltName\n", cert );
|
||||
|
||||
/* Enter GeneralNames */
|
||||
memcpy ( &cursor, raw, sizeof ( cursor ) );
|
||||
asn1_enter ( &cursor, ASN1_SEQUENCE );
|
||||
DBGC_HDA ( cert, 0, cursor.data, 128 );
|
||||
|
||||
INIT_LIST_HEAD ( &subject_alt_name->names );
|
||||
|
||||
/* Parse each name in turn */
|
||||
while ( cursor.len ) {
|
||||
memcpy ( &string_cursor, &cursor, sizeof ( string_cursor ) );
|
||||
if ( ( rc = asn1_enter ( &string_cursor, ASN1_IMPLICIT_TAG ( 2 ) ) ) == 0 ) {
|
||||
char* name = zalloc ( string_cursor.len + 1 );
|
||||
memcpy ( name, string_cursor.data, string_cursor.len );
|
||||
if ( strlen ( name ) != string_cursor.len ) {
|
||||
DBGC ( cert, "X509 %p contains malicious subjectAltName\n",
|
||||
cert );
|
||||
return rc;
|
||||
}
|
||||
//DBGC ( cert, "X509 %p subjectAltName %s\n", cert, name );
|
||||
struct x509_san_link* link = zalloc ( sizeof ( struct x509_san_link ) );
|
||||
link->name = name;
|
||||
list_add ( &link->list, &subject_alt_name->names );
|
||||
}
|
||||
asn1_skip_any ( &cursor );
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** "id-kp-codeSigning" object identifier */
|
||||
static uint8_t oid_code_signing[] = { ASN1_OID_CODESIGNING };
|
||||
|
||||
@ -738,6 +786,10 @@ static uint8_t oid_ce_basic_constraints[] =
|
||||
static uint8_t oid_ce_key_usage[] =
|
||||
{ ASN1_OID_KEYUSAGE };
|
||||
|
||||
/** "id-ce-keyUsage" object identifier */
|
||||
static uint8_t oid_ce_subject_alt_name[] =
|
||||
{ ASN1_OID_SUBJECTALTNAME };
|
||||
|
||||
/** "id-ce-extKeyUsage" object identifier */
|
||||
static uint8_t oid_ce_ext_key_usage[] =
|
||||
{ ASN1_OID_EXTKEYUSAGE };
|
||||
@ -758,6 +810,11 @@ static struct x509_extension x509_extensions[] = {
|
||||
.oid = ASN1_OID_CURSOR ( oid_ce_key_usage ),
|
||||
.parse = x509_parse_key_usage,
|
||||
},
|
||||
{
|
||||
.name = "subjectAltName",
|
||||
.oid = ASN1_OID_CURSOR ( oid_ce_subject_alt_name ),
|
||||
.parse = x509_parse_subject_alt_name,
|
||||
},
|
||||
{
|
||||
.name = "extKeyUsage",
|
||||
.oid = ASN1_OID_CURSOR ( oid_ce_ext_key_usage ),
|
||||
|
@ -170,6 +170,11 @@ struct asn1_builder_header {
|
||||
ASN1_OID_INITIAL ( 2, 5 ), ASN1_OID_SINGLE ( 29 ), \
|
||||
ASN1_OID_SINGLE ( 15 )
|
||||
|
||||
/** ASN1. OID for id-ce-subjectAltname (2.5.29.17) */
|
||||
#define ASN1_OID_SUBJECTALTNAME \
|
||||
ASN1_OID_INITIAL ( 2, 5 ), ASN1_OID_SINGLE ( 29 ), \
|
||||
ASN1_OID_SINGLE ( 17 )
|
||||
|
||||
/** ASN.1 OID for id-ce-basicConstraints (2.5.29.19) */
|
||||
#define ASN1_OID_BASICCONSTRAINTS \
|
||||
ASN1_OID_INITIAL ( 2, 5 ), ASN1_OID_SINGLE ( 29 ), \
|
||||
|
@ -86,6 +86,21 @@ struct x509_basic_constraints {
|
||||
unsigned int path_len;
|
||||
};
|
||||
|
||||
/** A link in an X.509 certificate chain */
|
||||
struct x509_san_link {
|
||||
/** List of links */
|
||||
struct list_head list;
|
||||
/** name */
|
||||
char* name;
|
||||
};
|
||||
|
||||
struct x509_subject_alt_name {
|
||||
/** Subject Alternative Name extension is present */
|
||||
int present;
|
||||
/** General Name **/
|
||||
struct list_head names;
|
||||
};
|
||||
|
||||
/** Unlimited path length
|
||||
*
|
||||
* We use -2U, since this quantity represents one *fewer* than the
|
||||
@ -150,6 +165,8 @@ struct x509_extensions {
|
||||
struct x509_basic_constraints basic;
|
||||
/** Key usage */
|
||||
struct x509_key_usage usage;
|
||||
/** Subject Alternative Name */
|
||||
struct x509_subject_alt_name subject_alt_name;
|
||||
/** Extended key usage */
|
||||
struct x509_extended_key_usage ext_usage;
|
||||
/** Authority information access */
|
||||
|
@ -2427,6 +2427,37 @@ static struct interface_descriptor tls_cipherstream_desc =
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
static int dns_wildcard_matcher( const char* dns, const char* wildcard ) {
|
||||
if ( strchr ( wildcard, '*' ) == NULL ) {
|
||||
/* No wildcard, just strcmp */
|
||||
return strcmp ( dns, wildcard );
|
||||
}
|
||||
if ( strrchr(wildcard, '*') != wildcard ) {
|
||||
/* This is multiple-wildcard. We can't handle that, so bail. */
|
||||
return -1;
|
||||
}
|
||||
const char* first_dot = strchr (dns, '*') ;
|
||||
return strcmp ( first_dot, wildcard + 1 );
|
||||
}
|
||||
|
||||
static int tls_validator_name( struct tls_session *tls, struct x509_certificate *cert ) {
|
||||
/* Verify server name */
|
||||
if ( ( cert->subject.name == NULL ) && ( !cert->extensions.subject_alt_name.present ) ) {
|
||||
return -1;
|
||||
}
|
||||
struct x509_san_link* link;
|
||||
list_for_each_entry ( link, &cert->extensions.subject_alt_name.names, list ) {
|
||||
/* If the name matches, return 0, otherwise, continue */
|
||||
if ( dns_wildcard_matcher ( tls->name, link->name ) == 0) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if ( !cert->extensions.subject_alt_name.present ) {
|
||||
return dns_wildcard_matcher ( tls->name, cert->subject.name );
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle certificate validation completion
|
||||
*
|
||||
@ -2444,7 +2475,7 @@ static void tls_validator_done ( struct tls_session *tls, int rc ) {
|
||||
/* Check for validation failure */
|
||||
if ( rc != 0 ) {
|
||||
DBGC ( tls, "TLS %p certificate validation failed: %s\n",
|
||||
tls, strerror ( rc ) );
|
||||
tls, strerror ( rc ) );
|
||||
goto err;
|
||||
}
|
||||
DBGC ( tls, "TLS %p certificate validation succeeded\n", tls );
|
||||
@ -2454,8 +2485,7 @@ 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 ) ) {
|
||||
if ( tls_validator_name( tls, cert ) ) {
|
||||
DBGC ( tls, "TLS %p server name incorrect (expected %s, got "
|
||||
"%s)\n", tls, tls->name, cert->subject.name );
|
||||
rc = -EACCES_WRONG_NAME;
|
||||
|
Loading…
Reference in New Issue
Block a user