Merge pull request #6866 from mprse/extract-key-ids

Extracting SubjectKeyId and AuthorityKeyId in case of x509 V3 extensions v.2
This commit is contained in:
Gilles Peskine 2023-05-08 20:38:29 +02:00 committed by GitHub
commit 97edeb4fb8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 355 additions and 43 deletions

View file

@ -318,6 +318,18 @@ static const oid_x509_ext_t oid_x509_ext[] =
"Certificate Policies"),
MBEDTLS_OID_X509_EXT_CERTIFICATE_POLICIES,
},
{
OID_DESCRIPTOR(MBEDTLS_OID_SUBJECT_KEY_IDENTIFIER,
"id-ce-subjectKeyIdentifier",
"Subject Key Identifier"),
MBEDTLS_OID_X509_EXT_SUBJECT_KEY_IDENTIFIER,
},
{
OID_DESCRIPTOR(MBEDTLS_OID_AUTHORITY_KEY_IDENTIFIER,
"id-ce-authorityKeyIdentifier",
"Authority Key Identifier"),
MBEDTLS_OID_X509_EXT_AUTHORITY_KEY_IDENTIFIER,
},
{
NULL_OID_DESCRIPTOR,
0,

View file

@ -1201,53 +1201,19 @@ static int x509_get_other_name(const mbedtls_x509_buf *subject_alt_name,
return 0;
}
/*
* SubjectAltName ::= GeneralNames
/* Check mbedtls_x509_get_subject_alt_name for detailed description.
*
* GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName
*
* GeneralName ::= CHOICE {
* otherName [0] OtherName,
* rfc822Name [1] IA5String,
* dNSName [2] IA5String,
* x400Address [3] ORAddress,
* directoryName [4] Name,
* ediPartyName [5] EDIPartyName,
* uniformResourceIdentifier [6] IA5String,
* iPAddress [7] OCTET STRING,
* registeredID [8] OBJECT IDENTIFIER }
*
* OtherName ::= SEQUENCE {
* type-id OBJECT IDENTIFIER,
* value [0] EXPLICIT ANY DEFINED BY type-id }
*
* EDIPartyName ::= SEQUENCE {
* nameAssigner [0] DirectoryString OPTIONAL,
* partyName [1] DirectoryString }
*
* We list all types, but use the following GeneralName types from RFC 5280:
* "dnsName", "uniformResourceIdentifier" and "hardware_module_name"
* of type "otherName", as defined in RFC 4108.
* In some cases while parsing subject alternative names the sequence tag is optional
* (e.g. CertSerialNumber). This function is designed to handle such case.
*/
int mbedtls_x509_get_subject_alt_name(unsigned char **p,
const unsigned char *end,
mbedtls_x509_sequence *subject_alt_name)
int mbedtls_x509_get_subject_alt_name_ext(unsigned char **p,
const unsigned char *end,
mbedtls_x509_sequence *subject_alt_name)
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
size_t len, tag_len;
size_t tag_len;
mbedtls_asn1_sequence *cur = subject_alt_name;
/* Get main sequence tag */
if ((ret = mbedtls_asn1_get_tag(p, end, &len,
MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) != 0) {
return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret);
}
if (*p + len != end) {
return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS,
MBEDTLS_ERR_ASN1_LENGTH_MISMATCH);
}
while (*p < end) {
mbedtls_x509_subject_alternative_name dummy_san_buf;
mbedtls_x509_buf tmp_san_buf;
@ -1315,6 +1281,55 @@ int mbedtls_x509_get_subject_alt_name(unsigned char **p,
return 0;
}
/*
* SubjectAltName ::= GeneralNames
*
* GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName
*
* GeneralName ::= CHOICE {
* otherName [0] OtherName,
* rfc822Name [1] IA5String,
* dNSName [2] IA5String,
* x400Address [3] ORAddress,
* directoryName [4] Name,
* ediPartyName [5] EDIPartyName,
* uniformResourceIdentifier [6] IA5String,
* iPAddress [7] OCTET STRING,
* registeredID [8] OBJECT IDENTIFIER }
*
* OtherName ::= SEQUENCE {
* type-id OBJECT IDENTIFIER,
* value [0] EXPLICIT ANY DEFINED BY type-id }
*
* EDIPartyName ::= SEQUENCE {
* nameAssigner [0] DirectoryString OPTIONAL,
* partyName [1] DirectoryString }
*
* We list all types, but use the following GeneralName types from RFC 5280:
* "dnsName", "uniformResourceIdentifier" and "hardware_module_name"
* of type "otherName", as defined in RFC 4108.
*/
int mbedtls_x509_get_subject_alt_name(unsigned char **p,
const unsigned char *end,
mbedtls_x509_sequence *subject_alt_name)
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
size_t len;
/* Get main sequence tag */
if ((ret = mbedtls_asn1_get_tag(p, end, &len,
MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) != 0) {
return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret);
}
if (*p + len != end) {
return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS,
MBEDTLS_ERR_ASN1_LENGTH_MISMATCH);
}
return mbedtls_x509_get_subject_alt_name_ext(p, end, subject_alt_name);
}
int mbedtls_x509_get_ns_cert_type(unsigned char **p,
const unsigned char *end,
unsigned char *ns_cert_type)

View file

@ -591,6 +591,114 @@ static int x509_get_ext_key_usage(unsigned char **p,
return 0;
}
/*
* SubjectKeyIdentifier ::= KeyIdentifier
*
* KeyIdentifier ::= OCTET STRING
*/
static int x509_get_subject_key_id(unsigned char **p,
const unsigned char *end,
mbedtls_x509_buf *subject_key_id)
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
size_t len = 0u;
if ((ret = mbedtls_asn1_get_tag(p, end, &len,
MBEDTLS_ASN1_OCTET_STRING)) != 0) {
return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret);
}
subject_key_id->len = len;
subject_key_id->tag = MBEDTLS_ASN1_OCTET_STRING;
subject_key_id->p = *p;
*p += len;
if (*p != end) {
return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS,
MBEDTLS_ERR_ASN1_LENGTH_MISMATCH);
}
return 0;
}
/*
* AuthorityKeyIdentifier ::= SEQUENCE {
* keyIdentifier [0] KeyIdentifier OPTIONAL,
* authorityCertIssuer [1] GeneralNames OPTIONAL,
* authorityCertSerialNumber [2] CertificateSerialNumber OPTIONAL }
*
* KeyIdentifier ::= OCTET STRING
*/
static int x509_get_authority_key_id(unsigned char **p,
unsigned char *end,
mbedtls_x509_authority *authority_key_id)
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
size_t len = 0u;
if ((ret = mbedtls_asn1_get_tag(p, end, &len,
MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) != 0) {
return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret);
}
if (*p + len != end) {
return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS,
MBEDTLS_ERR_ASN1_LENGTH_MISMATCH);
}
ret = mbedtls_asn1_get_tag(p, end, &len,
MBEDTLS_ASN1_CONTEXT_SPECIFIC);
/* KeyIdentifier is an OPTIONAL field */
if (ret == 0) {
authority_key_id->keyIdentifier.len = len;
authority_key_id->keyIdentifier.p = *p;
/* Setting tag of the keyIdentfier intentionally to 0x04.
* Although the .keyIdentfier field is CONTEXT_SPECIFIC ([0] OPTIONAL),
* its tag with the content is the payload of on OCTET STRING primitive */
authority_key_id->keyIdentifier.tag = MBEDTLS_ASN1_OCTET_STRING;
*p += len;
} else if (ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG) {
return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret);
}
if (*p < end) {
/* Getting authorityCertIssuer using the required specific class tag [1] */
if ((ret = mbedtls_asn1_get_tag(p, end, &len,
MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED |
1)) != 0) {
/* authorityCertIssuer and authorityCertSerialNumber MUST both
be present or both be absent. At this point we expect to have both. */
return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret);
}
/* "end" also includes the CertSerialNumber field so "len" shall be used */
ret = mbedtls_x509_get_subject_alt_name_ext(p,
(*p+len),
&authority_key_id->authorityCertIssuer);
if (ret != 0) {
return ret;
}
/* Getting authorityCertSerialNumber using the required specific class tag [2] */
if ((ret = mbedtls_asn1_get_tag(p, end, &len,
MBEDTLS_ASN1_CONTEXT_SPECIFIC | 2)) != 0) {
return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret);
}
authority_key_id->authorityCertSerialNumber.len = len;
authority_key_id->authorityCertSerialNumber.p = *p;
authority_key_id->authorityCertSerialNumber.tag = MBEDTLS_ASN1_INTEGER;
*p += len;
}
if (*p != end) {
return MBEDTLS_ERR_X509_INVALID_EXTENSIONS +
MBEDTLS_ERR_ASN1_LENGTH_MISMATCH;
}
return 0;
}
/*
* id-ce-certificatePolicies OBJECT IDENTIFIER ::= { id-ce 32 }
*
@ -889,8 +997,25 @@ static int x509_get_crt_ext(unsigned char **p,
}
break;
case MBEDTLS_X509_EXT_SUBJECT_KEY_IDENTIFIER:
/* Parse subject key identifier */
if ((ret = x509_get_subject_key_id(p, end_ext_data,
&crt->subject_key_id)) != 0) {
return ret;
}
break;
case MBEDTLS_X509_EXT_AUTHORITY_KEY_IDENTIFIER:
/* Parse authority key identifier */
if ((ret = x509_get_authority_key_id(p, end_ext_octet,
&crt->authority_key_id)) != 0) {
return ret;
}
break;
case MBEDTLS_X509_EXT_SUBJECT_ALT_NAME:
/* Parse subject alt name */
/* Parse subject alt name
* SubjectAltName ::= GeneralNames
*/
if ((ret = mbedtls_x509_get_subject_alt_name(p, end_ext_octet,
&crt->subject_alt_names)) != 0) {
return ret;
@ -1550,6 +1675,27 @@ cleanup:
#endif /* MBEDTLS_FS_IO */
#if !defined(MBEDTLS_X509_REMOVE_INFO)
#define PRINT_ITEM(i) \
do { \
ret = mbedtls_snprintf(p, n, "%s" i, sep); \
MBEDTLS_X509_SAFE_SNPRINTF; \
sep = ", "; \
} while (0)
#define CERT_TYPE(type, name) \
do { \
if (ns_cert_type & (type)) { \
PRINT_ITEM(name); \
} \
} while (0)
#define KEY_USAGE(code, name) \
do { \
if (key_usage & (code)) { \
PRINT_ITEM(name); \
} \
} while (0)
static int x509_info_ext_key_usage(char **buf, size_t *size,
const mbedtls_x509_sequence *extended_key_usage)
{