Fix parsing of authorityCertIssuer
Signed-off-by: Przemek Stekiel <przemyslaw.stekiel@mobica.com>
diff --git a/library/x509_crt.c b/library/x509_crt.c
index 2477a93..abaf630 100644
--- a/library/x509_crt.c
+++ b/library/x509_crt.c
@@ -616,53 +616,21 @@
return 0;
}
-/*
- * SubjectAltName ::= GeneralNames
- * GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName
+/* Check x509_get_subject_alt_name for detailed description.
*
- * 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 }
- *
- * 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_general_names(unsigned char **p,
- const unsigned char *end,
- mbedtls_x509_sequence *subject_alt_name)
+ * In some cases while parsing subject alternative names the sequence tag is optional
+ * (e.g. CertSerialNumber). This function is designed to handle such case.
+*/
+static int x509_get_subject_alt_name_internal(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_buf *buf;
unsigned char tag;
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;
memset(&dummy_san_buf, 0, sizeof(dummy_san_buf));
@@ -673,14 +641,10 @@
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) {
- if ((tag & (MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) !=
- (MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) {
- return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS,
- MBEDTLS_ERR_ASN1_UNEXPECTED_TAG);
- }
+ return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS,
+ MBEDTLS_ERR_ASN1_UNEXPECTED_TAG);
}
/*
@@ -732,6 +696,53 @@
}
/*
+ * 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 }
+ *
+ * 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)
+{
+ 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 x509_get_subject_alt_name_internal(p, end, subject_alt_name);
+}
+
+/*
* AuthorityKeyIdentifier ::= SEQUENCE {
* keyIdentifier [0] KeyIdentifier OPTIONAL,
* authorityCertIssuer [1] GeneralNames OPTIONAL,
@@ -774,29 +785,22 @@
/* 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 |
- MBEDTLS_X509_SAN_RFC822_NAME)) != 0) {
+ 1)) != 0) {
/* authorityCertIssuer is an OPTIONAL field */
} else {
- /* Getting directoryName using the required specific class tag [4] */
- if ((ret = mbedtls_asn1_get_tag(p, end, &len,
- MBEDTLS_ASN1_CONTEXT_SPECIFIC |
- MBEDTLS_ASN1_CONSTRUCTED |
- MBEDTLS_X509_SAN_DIRECTORY_NAME)) != 0) {
- return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, 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);
- }
+ /* "end" also includes the CertSerialNumber field so "len" shall be used */
+ ret = x509_get_subject_alt_name_internal(p,
+ (*p+len),
+ &authority_key_id->authorityCertIssuer);
}
}
if (*p < end) {
+ /* Getting authorityCertSerialNumber using the required specific class tag [2] */
if ((ret = mbedtls_asn1_get_tag(p, end, &len,
- MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_INTEGER)) !=
+ MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_INTEGER | 2)) !=
0) {
- /* authorityCertSerialNumber is an OPTIONAL field, but if there are still data it must be the serial number */
+ /* authorityCertSerialNumber is an OPTIONAL field */
return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_EXTENSIONS, ret);
} else {
authority_key_id->authorityCertSerialNumber.len = len;
@@ -1131,8 +1135,8 @@
/* Parse subject alt name
* SubjectAltName ::= GeneralNames
*/
- if ((ret = x509_get_general_names(p, end_ext_octet,
- &crt->subject_alt_names)) != 0) {
+ if ((ret = x509_get_subject_alt_name(p, end_ext_octet,
+ &crt->subject_alt_names)) != 0) {
return ret;
}
break;