Renaming x509_get_subject_alt_name to x509_get_general_names and mbedtls_x509_parse_subject_alt_name to mbedtls_x509_parse_general_name so they can be used not only to collect subject alt name, but the V3 authority cert issuer that is also GeneralName type.

Also updated the x509_get_general_names function to be able to parse rfc822Names

Test are also updated according these changes.

Signed-off-by: toth92g <toth92g@gmail.com>
This commit is contained in:
toth92g 2021-05-10 15:16:33 +02:00 committed by Przemek Stekiel
parent 5042b104c2
commit 8d435a0c8b
5 changed files with 375 additions and 107 deletions

View file

@ -617,92 +617,6 @@ static int x509_get_subject_key_id(unsigned char **p,
}
/*
* 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 ret;
}
if ((ret = mbedtls_asn1_get_tag(p, end, &len,
MBEDTLS_ASN1_CONTEXT_SPECIFIC)) != 0) {
/* KeyIdentifier is an OPTIONAL field */
} else {
authority_key_id->keyIdentifier.len = len;
authority_key_id->keyIdentifier.p = *p;
authority_key_id->keyIdentifier.tag = MBEDTLS_ASN1_OCTET_STRING;
*p += len;
}
if (*p < end) {
if ((ret = mbedtls_asn1_get_tag(p, end, &len,
MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED |
MBEDTLS_ASN1_BOOLEAN)) != 0) {
/* authorityCertIssuer is an OPTIONAL field */
} else {
if ((ret = mbedtls_asn1_get_tag(p, end, &len,
MBEDTLS_ASN1_CONTEXT_SPECIFIC |
MBEDTLS_ASN1_CONSTRUCTED |
MBEDTLS_ASN1_OCTET_STRING)) != 0) {
return ret;
} else {
authority_key_id->raw.p = *p;
if ((ret = mbedtls_asn1_get_tag(p, end, &len,
MBEDTLS_ASN1_CONSTRUCTED |
MBEDTLS_ASN1_SEQUENCE)) != 0) {
return ret;
}
if ((ret =
mbedtls_x509_get_name(p, *p + len,
&authority_key_id->authorityCertIssuer)) != 0) {
return ret;
}
authority_key_id->raw.len = *p - authority_key_id->raw.p;
}
}
}
if (*p < end) {
if ((ret = mbedtls_asn1_get_tag(p, end, &len,
MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_INTEGER)) !=
0) {
/* authorityCertSerialNumber is an OPTIONAL field, but if there are still data it must be the serial number */
return ret;
} else {
authority_key_id->authorityCertSerialNumber.len = len;
authority_key_id->authorityCertSerialNumber.p = *p;
authority_key_id->authorityCertSerialNumber.tag = MBEDTLS_ASN1_OCTET_STRING;
*p += len;
}
}
if (*p != end) {
return MBEDTLS_ERR_X509_INVALID_EXTENSIONS +
MBEDTLS_ERR_ASN1_LENGTH_MISMATCH;
}
return 0;
}
/*
* SubjectAltName ::= GeneralNames
*
* GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName
*
* GeneralName ::= CHOICE {
@ -727,9 +641,9 @@ static int x509_get_authority_key_id(unsigned char **p,
* NOTE: we list all types, but only use dNSName and otherName
* of type HwModuleName, as defined in RFC 4108, at this point.
*/
static int x509_get_subject_alt_name(unsigned char **p,
const unsigned char *end,
mbedtls_x509_sequence *subject_alt_name)
static int x509_get_general_names(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;
@ -758,16 +672,20 @@ static int x509_get_subject_alt_name(unsigned char **p,
return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret);
}
/* Tag shall be CONTEXT_SPECIFIC or SET */
if ((tag & MBEDTLS_ASN1_TAG_CLASS_MASK) !=
MBEDTLS_ASN1_CONTEXT_SPECIFIC) {
return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS,
MBEDTLS_ERR_ASN1_UNEXPECTED_TAG);
if ((tag & (MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) !=
(MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) {
return MBEDTLS_ERR_X509_INVALID_EXTENSIONS +
MBEDTLS_ERR_ASN1_UNEXPECTED_TAG;
}
}
/*
* Check that the SAN is structured correctly.
*/
ret = mbedtls_x509_parse_subject_alt_name(&(cur->buf), &dummy_san_buf);
ret = mbedtls_x509_parse_general_name(&(cur->buf), &dummy_san_buf);
/*
* In case the extension is malformed, return an error,
* and clear the allocated sequences.
@ -812,6 +730,78 @@ static int x509_get_subject_alt_name(unsigned char **p,
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)) != 0) {
return ret;
}
if ((ret = mbedtls_asn1_get_tag(p, end, &len,
MBEDTLS_ASN1_CONTEXT_SPECIFIC)) != 0) {
/* KeyIdentifier is an OPTIONAL field */
} else {
authority_key_id->keyIdentifier.len = len;
authority_key_id->keyIdentifier.p = *p;
authority_key_id->keyIdentifier.tag = MBEDTLS_ASN1_OCTET_STRING;
*p += len;
}
if (*p < end) {
if ((ret = mbedtls_asn1_get_tag(p, end, &len,
MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED |
1)) != 0) {
/* authorityCertIssuer is an OPTIONAL field */
} else {
if ((ret = mbedtls_asn1_get_tag(p, end, &len,
MBEDTLS_ASN1_CONTEXT_SPECIFIC |
MBEDTLS_ASN1_CONSTRUCTED | 4)) != 0) {
return ret;
} else {
/* "end" also includes the CertSerialNumber field so "len" shall be used */
ret = x509_get_general_names(p,
(*p+len),
&authority_key_id->authorityCertIssuer);
}
}
}
if (*p < end) {
if ((ret = mbedtls_asn1_get_tag(p, end, &len,
MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_INTEGER)) !=
0) {
/* authorityCertSerialNumber is an OPTIONAL field, but if there are still data it must be the serial number */
return ret;
} else {
authority_key_id->authorityCertSerialNumber.len = len;
authority_key_id->authorityCertSerialNumber.p = *p;
authority_key_id->authorityCertSerialNumber.tag = MBEDTLS_ASN1_OCTET_STRING;
*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 }
*
@ -1109,6 +1099,7 @@ static int x509_get_crt_ext(unsigned char **p,
return ret;
}
break;
case MBEDTLS_X509_EXT_SUBJECT_KEY_IDENTIFIER:
/* Parse subject key identifier */
if ((ret = x509_get_subject_key_id(p, end_ext_data,
@ -1116,6 +1107,7 @@ static int x509_get_crt_ext(unsigned char **p,
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,
@ -1124,9 +1116,11 @@ static int x509_get_crt_ext(unsigned char **p,
}
break;
case MBEDTLS_X509_EXT_SUBJECT_ALT_NAME:
/* Parse subject alt name */
if ((ret = mbedtls_x509_get_subject_alt_name(p, end_ext_octet,
&crt->subject_alt_names)) != 0) {
/* Parse subject alt name
* SubjectAltName ::= GeneralNames
*/
if ((ret = x509_get_general_names(p, end_ext_octet,
&crt->subject_alt_names)) != 0) {
return ret;
}
break;
@ -1784,6 +1778,248 @@ cleanup:
#endif /* MBEDTLS_FS_IO */
#if !defined(MBEDTLS_X509_REMOVE_INFO)
static int x509_info_subject_alt_name(char **buf, size_t *size,
const mbedtls_x509_sequence
*subject_alt_name,
const char *prefix)
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
size_t i;
size_t n = *size;
char *p = *buf;
const mbedtls_x509_sequence *cur = subject_alt_name;
mbedtls_x509_subject_alternative_name san;
int parse_ret;
while (cur != NULL) {
memset(&san, 0, sizeof(san));
parse_ret = mbedtls_x509_parse_general_name(&cur->buf, &san);
if (parse_ret != 0) {
if (parse_ret == MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE) {
ret = mbedtls_snprintf(p, n, "\n%s <unsupported>", prefix);
MBEDTLS_X509_SAFE_SNPRINTF;
} else {
ret = mbedtls_snprintf(p, n, "\n%s <malformed>", prefix);
MBEDTLS_X509_SAFE_SNPRINTF;
}
cur = cur->next;
continue;
}
switch (san.type) {
/*
* otherName
*/
case MBEDTLS_X509_SAN_OTHER_NAME:
{
mbedtls_x509_san_other_name *other_name = &san.san.other_name;
ret = mbedtls_snprintf(p, n, "\n%s otherName :", prefix);
MBEDTLS_X509_SAFE_SNPRINTF;
if (MBEDTLS_OID_CMP(MBEDTLS_OID_ON_HW_MODULE_NAME,
&other_name->value.hardware_module_name.oid) != 0) {
ret = mbedtls_snprintf(p, n, "\n%s hardware module name :", prefix);
MBEDTLS_X509_SAFE_SNPRINTF;
ret =
mbedtls_snprintf(p, n, "\n%s hardware type : ", prefix);
MBEDTLS_X509_SAFE_SNPRINTF;
ret = mbedtls_oid_get_numeric_string(p,
n,
&other_name->value.hardware_module_name.oid);
MBEDTLS_X509_SAFE_SNPRINTF;
ret =
mbedtls_snprintf(p, n, "\n%s hardware serial number : ", prefix);
MBEDTLS_X509_SAFE_SNPRINTF;
for (i = 0; i < other_name->value.hardware_module_name.val.len; i++) {
ret = mbedtls_snprintf(p,
n,
"%02X",
other_name->value.hardware_module_name.val.p[i]);
MBEDTLS_X509_SAFE_SNPRINTF;
}
}/* MBEDTLS_OID_ON_HW_MODULE_NAME */
}
break;
/*
* dNSName
*/
case MBEDTLS_X509_SAN_DNS_NAME:
{
ret = mbedtls_snprintf(p, n, "\n%s dNSName : ", prefix);
MBEDTLS_X509_SAFE_SNPRINTF;
if (san.san.unstructured_name.len >= n) {
*p = '\0';
return MBEDTLS_ERR_X509_BUFFER_TOO_SMALL;
}
memcpy(p, san.san.unstructured_name.p, san.san.unstructured_name.len);
p += san.san.unstructured_name.len;
n -= san.san.unstructured_name.len;
}
break;
/*
* Type not supported, skip item.
*/
default:
ret = mbedtls_snprintf(p, n, "\n%s <unsupported>", prefix);
MBEDTLS_X509_SAFE_SNPRINTF;
break;
}
cur = cur->next;
}
*p = '\0';
*size = n;
*buf = p;
return 0;
}
int mbedtls_x509_parse_general_name(const mbedtls_x509_buf *san_buf,
mbedtls_x509_subject_alternative_name *san)
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
switch (san_buf->tag &
(MBEDTLS_ASN1_TAG_CLASS_MASK |
MBEDTLS_ASN1_TAG_VALUE_MASK)) {
/*
* otherName
*/
case (MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_X509_SAN_OTHER_NAME):
{
mbedtls_x509_san_other_name other_name;
ret = x509_get_other_name(san_buf, &other_name);
if (ret != 0) {
return ret;
}
memset(san, 0, sizeof(mbedtls_x509_subject_alternative_name));
san->type = MBEDTLS_X509_SAN_OTHER_NAME;
memcpy(&san->san.other_name,
&other_name, sizeof(other_name));
}
break;
/*
* dNSName
*/
case (MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_X509_SAN_DNS_NAME):
{
memset(san, 0, sizeof(mbedtls_x509_subject_alternative_name));
san->type = MBEDTLS_X509_SAN_DNS_NAME;
memcpy(&san->san.unstructured_name,
san_buf, sizeof(*san_buf));
}
break;
/*
* RFC822 Name
*/
case (MBEDTLS_ASN1_SEQUENCE | MBEDTLS_X509_SAN_RFC822_NAME):
{
mbedtls_x509_name rfc822Name;
unsigned char *bufferPointer = san_buf->p;
unsigned char **p = &bufferPointer;
const unsigned char *end = san_buf->p + san_buf->len;
/* The leading ASN1 tag and length has been processed. Stepping back with 2 bytes, because mbedtls_x509_get_name expects the beginning of the SET tag */
*p = *p - 2;
ret = mbedtls_x509_get_name(p, end, &rfc822Name);
if (ret != 0) {
return ret;
}
memset(san, 0, sizeof(mbedtls_x509_subject_alternative_name));
san->type = MBEDTLS_X509_SAN_OTHER_NAME;
memcpy(&san->san.unstructured_name,
&rfc822Name, sizeof(rfc822Name));
}
break;
/*
* Type not supported
*/
default:
return MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE;
}
return 0;
}
#define PRINT_ITEM(i) \
{ \
ret = mbedtls_snprintf(p, n, "%s" i, sep); \
MBEDTLS_X509_SAFE_SNPRINTF; \
sep = ", "; \
}
#define CERT_TYPE(type, name) \
if (ns_cert_type & (type)) \
PRINT_ITEM(name);
static int x509_info_cert_type(char **buf, size_t *size,
unsigned char ns_cert_type)
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
size_t n = *size;
char *p = *buf;
const char *sep = "";
CERT_TYPE(MBEDTLS_X509_NS_CERT_TYPE_SSL_CLIENT, "SSL Client");
CERT_TYPE(MBEDTLS_X509_NS_CERT_TYPE_SSL_SERVER, "SSL Server");
CERT_TYPE(MBEDTLS_X509_NS_CERT_TYPE_EMAIL, "Email");
CERT_TYPE(MBEDTLS_X509_NS_CERT_TYPE_OBJECT_SIGNING, "Object Signing");
CERT_TYPE(MBEDTLS_X509_NS_CERT_TYPE_RESERVED, "Reserved");
CERT_TYPE(MBEDTLS_X509_NS_CERT_TYPE_SSL_CA, "SSL CA");
CERT_TYPE(MBEDTLS_X509_NS_CERT_TYPE_EMAIL_CA, "Email CA");
CERT_TYPE(MBEDTLS_X509_NS_CERT_TYPE_OBJECT_SIGNING_CA, "Object Signing CA");
*size = n;
*buf = p;
return 0;
}
#define KEY_USAGE(code, name) \
if (key_usage & (code)) \
PRINT_ITEM(name);
static int x509_info_key_usage(char **buf, size_t *size,
unsigned int key_usage)
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
size_t n = *size;
char *p = *buf;
const char *sep = "";
KEY_USAGE(MBEDTLS_X509_KU_DIGITAL_SIGNATURE, "Digital Signature");
KEY_USAGE(MBEDTLS_X509_KU_NON_REPUDIATION, "Non Repudiation");
KEY_USAGE(MBEDTLS_X509_KU_KEY_ENCIPHERMENT, "Key Encipherment");
KEY_USAGE(MBEDTLS_X509_KU_DATA_ENCIPHERMENT, "Data Encipherment");
KEY_USAGE(MBEDTLS_X509_KU_KEY_AGREEMENT, "Key Agreement");
KEY_USAGE(MBEDTLS_X509_KU_KEY_CERT_SIGN, "Key Cert Sign");
KEY_USAGE(MBEDTLS_X509_KU_CRL_SIGN, "CRL Sign");
KEY_USAGE(MBEDTLS_X509_KU_ENCIPHER_ONLY, "Encipher Only");
KEY_USAGE(MBEDTLS_X509_KU_DECIPHER_ONLY, "Decipher Only");
*size = n;
*buf = p;
return 0;
}
static int x509_info_ext_key_usage(char **buf, size_t *size,
const mbedtls_x509_sequence *extended_key_usage)
{
@ -3077,12 +3313,13 @@ void mbedtls_x509_crt_free(mbedtls_x509_crt *crt)
mbedtls_asn1_sequence_free(cert_cur->subject_alt_names.next);
mbedtls_asn1_sequence_free(cert_cur->certificate_policies.next);
name_cur = cert_cur->authority_key_id.authorityCertIssuer.next;
while (name_cur != NULL) {
name_prv = name_cur;
name_cur = name_cur->next;
mbedtls_platform_zeroize(name_prv, sizeof(mbedtls_x509_name));
mbedtls_free(name_prv);
seq_cur = cert_cur->authority_key_id.authorityCertIssuer.next;
while (seq_cur != NULL) {
seq_prv = seq_cur;
seq_cur = seq_cur->next;
mbedtls_platform_zeroize(seq_prv,
sizeof(mbedtls_x509_sequence));
mbedtls_free(seq_prv);
}
if (cert_cur->raw.p != NULL && cert_cur->own_buffer) {