|
@@ -603,7 +603,7 @@ static int x509_parse_ocsp ( struct x509_certificate *cert,
|
603
|
603
|
|
604
|
604
|
/* Enter accessLocation */
|
605
|
605
|
memcpy ( uri, raw, sizeof ( *uri ) );
|
606
|
|
- if ( ( rc = asn1_enter ( uri, ASN1_IMPLICIT_TAG ( 6 ) ) ) != 0 ) {
|
|
606
|
+ if ( ( rc = asn1_enter ( uri, X509_GENERAL_NAME_URI ) ) != 0 ) {
|
607
|
607
|
DBGC ( cert, "X509 %p OCSP does not contain "
|
608
|
608
|
"uniformResourceIdentifier:\n", cert );
|
609
|
609
|
DBGC_HDA ( cert, 0, raw->data, raw->len );
|
|
@@ -708,6 +708,33 @@ static int x509_parse_authority_info_access ( struct x509_certificate *cert,
|
708
|
708
|
return 0;
|
709
|
709
|
}
|
710
|
710
|
|
|
711
|
+/**
|
|
712
|
+ * Parse X.509 certificate subject alternative name
|
|
713
|
+ *
|
|
714
|
+ * @v cert X.509 certificate
|
|
715
|
+ * @v raw ASN.1 cursor
|
|
716
|
+ * @ret rc Return status code
|
|
717
|
+ */
|
|
718
|
+static int x509_parse_subject_alt_name ( struct x509_certificate *cert,
|
|
719
|
+ const struct asn1_cursor *raw ) {
|
|
720
|
+ struct x509_subject_alt_name *alt_name = &cert->extensions.alt_name;
|
|
721
|
+ struct asn1_cursor *names = &alt_name->names;
|
|
722
|
+ int rc;
|
|
723
|
+
|
|
724
|
+ /* Enter subjectAltName */
|
|
725
|
+ memcpy ( names, raw, sizeof ( *names ) );
|
|
726
|
+ if ( ( rc = asn1_enter ( names, ASN1_SEQUENCE ) ) != 0 ) {
|
|
727
|
+ DBGC ( cert, "X509 %p invalid subjectAltName: %s\n",
|
|
728
|
+ cert, strerror ( rc ) );
|
|
729
|
+ DBGC_HDA ( cert, 0, raw->data, raw->len );
|
|
730
|
+ return rc;
|
|
731
|
+ }
|
|
732
|
+ DBGC2 ( cert, "X509 %p has subjectAltName:\n", cert );
|
|
733
|
+ DBGC2_HDA ( cert, 0, names->data, names->len );
|
|
734
|
+
|
|
735
|
+ return 0;
|
|
736
|
+}
|
|
737
|
+
|
711
|
738
|
/** "id-ce-basicConstraints" object identifier */
|
712
|
739
|
static uint8_t oid_ce_basic_constraints[] =
|
713
|
740
|
{ ASN1_OID_BASICCONSTRAINTS };
|
|
@@ -724,6 +751,10 @@ static uint8_t oid_ce_ext_key_usage[] =
|
724
|
751
|
static uint8_t oid_pe_authority_info_access[] =
|
725
|
752
|
{ ASN1_OID_AUTHORITYINFOACCESS };
|
726
|
753
|
|
|
754
|
+/** "id-ce-subjectAltName" object identifier */
|
|
755
|
+static uint8_t oid_ce_subject_alt_name[] =
|
|
756
|
+ { ASN1_OID_SUBJECTALTNAME };
|
|
757
|
+
|
727
|
758
|
/** Supported certificate extensions */
|
728
|
759
|
static struct x509_extension x509_extensions[] = {
|
729
|
760
|
{
|
|
@@ -746,6 +777,11 @@ static struct x509_extension x509_extensions[] = {
|
746
|
777
|
.oid = ASN1_OID_CURSOR ( oid_pe_authority_info_access ),
|
747
|
778
|
.parse = x509_parse_authority_info_access,
|
748
|
779
|
},
|
|
780
|
+ {
|
|
781
|
+ .name = "subjectAltName",
|
|
782
|
+ .oid = ASN1_OID_CURSOR ( oid_ce_subject_alt_name ),
|
|
783
|
+ .parse = x509_parse_subject_alt_name,
|
|
784
|
+ },
|
749
|
785
|
};
|
750
|
786
|
|
751
|
787
|
/**
|
|
@@ -1340,6 +1376,82 @@ int x509_validate ( struct x509_certificate *cert,
|
1340
|
1376
|
return 0;
|
1341
|
1377
|
}
|
1342
|
1378
|
|
|
1379
|
+/**
|
|
1380
|
+ * Check X.509 certificate alternative dNSName
|
|
1381
|
+ *
|
|
1382
|
+ * @v cert X.509 certificate
|
|
1383
|
+ * @v raw ASN.1 cursor
|
|
1384
|
+ * @v name Name
|
|
1385
|
+ * @ret rc Return status code
|
|
1386
|
+ */
|
|
1387
|
+static int x509_check_dnsname ( struct x509_certificate *cert,
|
|
1388
|
+ const struct asn1_cursor *raw,
|
|
1389
|
+ const char *name ) {
|
|
1390
|
+ const char *fullname = name;
|
|
1391
|
+ const char *dnsname = raw->data;
|
|
1392
|
+ size_t len = raw->len;
|
|
1393
|
+
|
|
1394
|
+ /* Check for wildcards */
|
|
1395
|
+ if ( ( len >= 2 ) && ( dnsname[0] == '*' ) && ( dnsname[1] == '.' ) ) {
|
|
1396
|
+
|
|
1397
|
+ /* Skip initial "*." */
|
|
1398
|
+ dnsname += 2;
|
|
1399
|
+ len -= 2;
|
|
1400
|
+
|
|
1401
|
+ /* Skip initial portion of name to be tested */
|
|
1402
|
+ name = strchr ( name, '.' );
|
|
1403
|
+ if ( ! name )
|
|
1404
|
+ return -ENOENT;
|
|
1405
|
+ name++;
|
|
1406
|
+ }
|
|
1407
|
+
|
|
1408
|
+ /* Compare names */
|
|
1409
|
+ if ( ! ( ( strlen ( name ) == len ) &&
|
|
1410
|
+ ( memcmp ( name, dnsname, len ) == 0 ) ) )
|
|
1411
|
+ return -ENOENT;
|
|
1412
|
+
|
|
1413
|
+ if ( name == fullname ) {
|
|
1414
|
+ DBGC2 ( cert, "X509 %p \"%s\" subjectAltName matches \"%s\"\n",
|
|
1415
|
+ cert, x509_name ( cert ), name );
|
|
1416
|
+ } else {
|
|
1417
|
+ DBGC2 ( cert, "X509 %p \"%s\" subjectAltName matches \"%s\" "
|
|
1418
|
+ "(via \"*.%s\")\n", cert, x509_name ( cert ),
|
|
1419
|
+ fullname, name );
|
|
1420
|
+ }
|
|
1421
|
+ return 0;
|
|
1422
|
+}
|
|
1423
|
+
|
|
1424
|
+/**
|
|
1425
|
+ * Check X.509 certificate alternative name
|
|
1426
|
+ *
|
|
1427
|
+ * @v cert X.509 certificate
|
|
1428
|
+ * @v raw ASN.1 cursor
|
|
1429
|
+ * @v name Name
|
|
1430
|
+ * @ret rc Return status code
|
|
1431
|
+ */
|
|
1432
|
+static int x509_check_alt_name ( struct x509_certificate *cert,
|
|
1433
|
+ const struct asn1_cursor *raw,
|
|
1434
|
+ const char *name ) {
|
|
1435
|
+ struct asn1_cursor alt_name;
|
|
1436
|
+ unsigned int type;
|
|
1437
|
+
|
|
1438
|
+ /* Enter generalName */
|
|
1439
|
+ memcpy ( &alt_name, raw, sizeof ( alt_name ) );
|
|
1440
|
+ type = asn1_type ( &alt_name );
|
|
1441
|
+ asn1_enter_any ( &alt_name );
|
|
1442
|
+
|
|
1443
|
+ /* Check this name */
|
|
1444
|
+ switch ( type ) {
|
|
1445
|
+ case X509_GENERAL_NAME_DNS :
|
|
1446
|
+ return x509_check_dnsname ( cert, &alt_name, name );
|
|
1447
|
+ default:
|
|
1448
|
+ DBGC2 ( cert, "X509 %p \"%s\" unknown name of type %#02x:\n",
|
|
1449
|
+ cert, x509_name ( cert ), type );
|
|
1450
|
+ DBGC2_HDA ( cert, 0, alt_name.data, alt_name.len );
|
|
1451
|
+ return -ENOTSUP;
|
|
1452
|
+ }
|
|
1453
|
+}
|
|
1454
|
+
|
1343
|
1455
|
/**
|
1344
|
1456
|
* Check X.509 certificate name
|
1345
|
1457
|
*
|
|
@@ -1349,17 +1461,29 @@ int x509_validate ( struct x509_certificate *cert,
|
1349
|
1461
|
*/
|
1350
|
1462
|
int x509_check_name ( struct x509_certificate *cert, const char *name ) {
|
1351
|
1463
|
struct asn1_cursor *common_name = &cert->subject.common_name;
|
1352
|
|
- size_t len = strlen ( name );
|
|
1464
|
+ struct asn1_cursor alt_name;
|
|
1465
|
+ int rc;
|
1353
|
1466
|
|
1354
|
1467
|
/* Check commonName */
|
1355
|
|
- if ( ! ( ( len == common_name->len ) &&
|
1356
|
|
- ( memcmp ( name, common_name->data, len ) == 0 ) ) ) {
|
1357
|
|
- DBGC ( cert, "X509 %p \"%s\" does not match name \"%s\"\n",
|
1358
|
|
- cert, x509_name ( cert ), name );
|
1359
|
|
- return -EACCES_WRONG_NAME;
|
|
1468
|
+ if ( ( strlen ( name ) == common_name->len ) &&
|
|
1469
|
+ ( memcmp ( name, common_name->data, common_name->len ) == 0 ) ) {
|
|
1470
|
+ DBGC2 ( cert, "X509 %p \"%s\" commonName matches \"%s\"\n",
|
|
1471
|
+ cert, x509_name ( cert ), name );
|
|
1472
|
+ return 0;
|
1360
|
1473
|
}
|
1361
|
1474
|
|
1362
|
|
- return 0;
|
|
1475
|
+ /* Check any subjectAlternativeNames */
|
|
1476
|
+ memcpy ( &alt_name, &cert->extensions.alt_name.names,
|
|
1477
|
+ sizeof ( alt_name ) );
|
|
1478
|
+ for ( ; alt_name.len ; asn1_skip_any ( &alt_name ) ) {
|
|
1479
|
+ if ( ( rc = x509_check_alt_name ( cert, &alt_name,
|
|
1480
|
+ name ) ) == 0 )
|
|
1481
|
+ return 0;
|
|
1482
|
+ }
|
|
1483
|
+
|
|
1484
|
+ DBGC ( cert, "X509 %p \"%s\" does not match name \"%s\"\n",
|
|
1485
|
+ cert, x509_name ( cert ), name );
|
|
1486
|
+ return -EACCES_WRONG_NAME;
|
1363
|
1487
|
}
|
1364
|
1488
|
|
1365
|
1489
|
/**
|