summaryrefslogtreecommitdiffstats
path: root/src/crypto
diff options
context:
space:
mode:
Diffstat (limited to 'src/crypto')
-rw-r--r--src/crypto/x509.c140
1 files changed, 132 insertions, 8 deletions
diff --git a/src/crypto/x509.c b/src/crypto/x509.c
index 87b924c8..8e503f3b 100644
--- a/src/crypto/x509.c
+++ b/src/crypto/x509.c
@@ -603,7 +603,7 @@ static int x509_parse_ocsp ( struct x509_certificate *cert,
/* Enter accessLocation */
memcpy ( uri, raw, sizeof ( *uri ) );
- if ( ( rc = asn1_enter ( uri, ASN1_IMPLICIT_TAG ( 6 ) ) ) != 0 ) {
+ if ( ( rc = asn1_enter ( uri, X509_GENERAL_NAME_URI ) ) != 0 ) {
DBGC ( cert, "X509 %p OCSP does not contain "
"uniformResourceIdentifier:\n", cert );
DBGC_HDA ( cert, 0, raw->data, raw->len );
@@ -708,6 +708,33 @@ static int x509_parse_authority_info_access ( 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 *alt_name = &cert->extensions.alt_name;
+ struct asn1_cursor *names = &alt_name->names;
+ int rc;
+
+ /* Enter subjectAltName */
+ memcpy ( names, raw, sizeof ( *names ) );
+ if ( ( rc = asn1_enter ( names, ASN1_SEQUENCE ) ) != 0 ) {
+ DBGC ( cert, "X509 %p invalid subjectAltName: %s\n",
+ cert, strerror ( rc ) );
+ DBGC_HDA ( cert, 0, raw->data, raw->len );
+ return rc;
+ }
+ DBGC2 ( cert, "X509 %p has subjectAltName:\n", cert );
+ DBGC2_HDA ( cert, 0, names->data, names->len );
+
+ return 0;
+}
+
/** "id-ce-basicConstraints" object identifier */
static uint8_t oid_ce_basic_constraints[] =
{ ASN1_OID_BASICCONSTRAINTS };
@@ -724,6 +751,10 @@ static uint8_t oid_ce_ext_key_usage[] =
static uint8_t oid_pe_authority_info_access[] =
{ ASN1_OID_AUTHORITYINFOACCESS };
+/** "id-ce-subjectAltName" object identifier */
+static uint8_t oid_ce_subject_alt_name[] =
+ { ASN1_OID_SUBJECTALTNAME };
+
/** Supported certificate extensions */
static struct x509_extension x509_extensions[] = {
{
@@ -746,6 +777,11 @@ static struct x509_extension x509_extensions[] = {
.oid = ASN1_OID_CURSOR ( oid_pe_authority_info_access ),
.parse = x509_parse_authority_info_access,
},
+ {
+ .name = "subjectAltName",
+ .oid = ASN1_OID_CURSOR ( oid_ce_subject_alt_name ),
+ .parse = x509_parse_subject_alt_name,
+ },
};
/**
@@ -1341,6 +1377,82 @@ int x509_validate ( struct x509_certificate *cert,
}
/**
+ * Check X.509 certificate alternative dNSName
+ *
+ * @v cert X.509 certificate
+ * @v raw ASN.1 cursor
+ * @v name Name
+ * @ret rc Return status code
+ */
+static int x509_check_dnsname ( struct x509_certificate *cert,
+ const struct asn1_cursor *raw,
+ const char *name ) {
+ const char *fullname = name;
+ const char *dnsname = raw->data;
+ size_t len = raw->len;
+
+ /* Check for wildcards */
+ if ( ( len >= 2 ) && ( dnsname[0] == '*' ) && ( dnsname[1] == '.' ) ) {
+
+ /* Skip initial "*." */
+ dnsname += 2;
+ len -= 2;
+
+ /* Skip initial portion of name to be tested */
+ name = strchr ( name, '.' );
+ if ( ! name )
+ return -ENOENT;
+ name++;
+ }
+
+ /* Compare names */
+ if ( ! ( ( strlen ( name ) == len ) &&
+ ( memcmp ( name, dnsname, len ) == 0 ) ) )
+ return -ENOENT;
+
+ if ( name == fullname ) {
+ DBGC2 ( cert, "X509 %p \"%s\" subjectAltName matches \"%s\"\n",
+ cert, x509_name ( cert ), name );
+ } else {
+ DBGC2 ( cert, "X509 %p \"%s\" subjectAltName matches \"%s\" "
+ "(via \"*.%s\")\n", cert, x509_name ( cert ),
+ fullname, name );
+ }
+ return 0;
+}
+
+/**
+ * Check X.509 certificate alternative name
+ *
+ * @v cert X.509 certificate
+ * @v raw ASN.1 cursor
+ * @v name Name
+ * @ret rc Return status code
+ */
+static int x509_check_alt_name ( struct x509_certificate *cert,
+ const struct asn1_cursor *raw,
+ const char *name ) {
+ struct asn1_cursor alt_name;
+ unsigned int type;
+
+ /* Enter generalName */
+ memcpy ( &alt_name, raw, sizeof ( alt_name ) );
+ type = asn1_type ( &alt_name );
+ asn1_enter_any ( &alt_name );
+
+ /* Check this name */
+ switch ( type ) {
+ case X509_GENERAL_NAME_DNS :
+ return x509_check_dnsname ( cert, &alt_name, name );
+ default:
+ DBGC2 ( cert, "X509 %p \"%s\" unknown name of type %#02x:\n",
+ cert, x509_name ( cert ), type );
+ DBGC2_HDA ( cert, 0, alt_name.data, alt_name.len );
+ return -ENOTSUP;
+ }
+}
+
+/**
* Check X.509 certificate name
*
* @v cert X.509 certificate
@@ -1349,17 +1461,29 @@ int x509_validate ( struct x509_certificate *cert,
*/
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 );
+ struct asn1_cursor alt_name;
+ int rc;
/* 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;
+ if ( ( strlen ( name ) == common_name->len ) &&
+ ( memcmp ( name, common_name->data, common_name->len ) == 0 ) ) {
+ DBGC2 ( cert, "X509 %p \"%s\" commonName matches \"%s\"\n",
+ cert, x509_name ( cert ), name );
+ return 0;
}
- return 0;
+ /* Check any subjectAlternativeNames */
+ memcpy ( &alt_name, &cert->extensions.alt_name.names,
+ sizeof ( alt_name ) );
+ for ( ; alt_name.len ; asn1_skip_any ( &alt_name ) ) {
+ if ( ( rc = x509_check_alt_name ( cert, &alt_name,
+ name ) ) == 0 )
+ return 0;
+ }
+
+ DBGC ( cert, "X509 %p \"%s\" does not match name \"%s\"\n",
+ cert, x509_name ( cert ), name );
+ return -EACCES_WRONG_NAME;
}
/**