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>
diff --git a/library/x509_crt.c b/library/x509_crt.c
index 8cb78e5..d9318b8 100644
--- a/library/x509_crt.c
+++ b/library/x509_crt.c
@@ -617,92 +617,6 @@
 }
 
 /*
- * 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 @@
  * 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 @@
             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.
@@ -813,6 +731,78 @@
 }
 
 /*
+ * 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 }
  *
  * anyPolicy OBJECT IDENTIFIER ::= { id-ce-certificatePolicies 0 }
@@ -1109,6 +1099,7 @@
                     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 @@
                     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 @@
                 }
                 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 @@
 #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 @@
         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) {