Merge remote-tracking branch 'origin/pr/2530' into development

* origin/pr/2530: (27 commits)
  Style fix
  Fix test data
  Update test data
  Add some negative test cases
  Fix minor issues
  Add ChangeLog entry about listing all SAN
  Check that SAN is not malformed when parsing
  Documentation fixes
  Fix ChangeLog entry
  Fail in case critical crt policy not supported
  Update SAN parsing documentation
  change the type of hardware_module_name member
  Change mbedtls_x509_subject_alternative_name
  Add length checking in certificate policy parsing
  Rephrase x509_crt extension member description
  Rephrase changeLog entries
  Remove redundant memset()
  Propogate error when parsing SubjectAltNames
  Tidy up style in x509_info_subject_alt_name
  Print unparseable SubjectAlternativeNames
  ...
diff --git a/ChangeLog b/ChangeLog
index 34defcc..d333692 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -14,6 +14,14 @@
    * Extend the MBEDTLS_SSL_EXPORT_KEYS to export the handshake randbytes,
      and the used tls-prf.
    * Add public API for tls-prf function, according to requested enum.
+   * Add support for parsing otherName entries in the Subject Alternative Name
+     X.509 certificate extension, specifically type hardware module name,
+     as defined in RFC 4108 section 5.
+   * Add support for parsing certificate policies extension, as defined in
+     RFC 5280 section 4.2.1.4. Currently, only the "Any Policy" policy is
+     supported.
+   * List all SAN types in the subject_alt_names field of the certificate.
+     Resolves #459.
 
 Bugfix
    * Fix private key DER output in the key_app_writer example. File contents
diff --git a/include/mbedtls/oid.h b/include/mbedtls/oid.h
index f05a6ec..17cdba7 100644
--- a/include/mbedtls/oid.h
+++ b/include/mbedtls/oid.h
@@ -212,7 +212,10 @@
  * { iso(1) identified-organization(3) dod(6) internet(1)
  *                      private(4) enterprise(1) WiSUN(45605) FieldAreaNetwork(1) }
  */
-#define MBEDTLS_OID_WISUN_FAN                  MBEDTLS_OID_INTERNET "\x04\x01\x82\xe4\x25\x01"
+#define MBEDTLS_OID_WISUN_FAN                   MBEDTLS_OID_INTERNET "\x04\x01\x82\xe4\x25\x01"
+
+#define MBEDTLS_OID_ON                          MBEDTLS_OID_PKIX "\x08" /**< id-on OBJECT IDENTIFIER ::= { id-pkix 8 } */
+#define MBEDTLS_OID_ON_HW_MODULE_NAME           MBEDTLS_OID_ON "\x04" /**< id-on-hardwareModuleName OBJECT IDENTIFIER ::= { id-on 4 } */
 
 /*
  * PKCS definition OIDs
diff --git a/include/mbedtls/x509.h b/include/mbedtls/x509.h
index b63e864..054ff2e 100644
--- a/include/mbedtls/x509.h
+++ b/include/mbedtls/x509.h
@@ -110,6 +110,28 @@
 /* \} addtogroup x509_module */
 
 /*
+ * X.509 v3 Subject Alternative Name types.
+ *      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
+ */
+#define MBEDTLS_X509_SAN_OTHER_NAME                      0
+#define MBEDTLS_X509_SAN_RFC822_NAME                     1
+#define MBEDTLS_X509_SAN_DNS_NAME                        2
+#define MBEDTLS_X509_SAN_X400_ADDRESS_NAME               3
+#define MBEDTLS_X509_SAN_DIRECTORY_NAME                  4
+#define MBEDTLS_X509_SAN_EDI_PARTY_NAME                  5
+#define MBEDTLS_X509_SAN_UNIFORM_RESOURCE_IDENTIFIER     6
+#define MBEDTLS_X509_SAN_IP_ADDRESS                      7
+#define MBEDTLS_X509_SAN_REGISTERED_ID                   8
+
+/*
  * X.509 v3 Key Usage Extension flags
  * Reminder: update x509_info_key_usage() when adding new flags.
  */
diff --git a/include/mbedtls/x509_crt.h b/include/mbedtls/x509_crt.h
index a0f32cb..cd3be09 100644
--- a/include/mbedtls/x509_crt.h
+++ b/include/mbedtls/x509_crt.h
@@ -76,7 +76,9 @@
     mbedtls_x509_buf issuer_id;         /**< Optional X.509 v2/v3 issuer unique identifier. */
     mbedtls_x509_buf subject_id;        /**< Optional X.509 v2/v3 subject unique identifier. */
     mbedtls_x509_buf v3_ext;            /**< Optional X.509 v3 extensions.  */
-    mbedtls_x509_sequence subject_alt_names;    /**< Optional list of Subject Alternative Names (Only dNSName supported). */
+    mbedtls_x509_sequence subject_alt_names;    /**< Optional list of raw entries of Subject Alternative Names extension (currently only dNSName and OtherName are listed). */
+
+    mbedtls_x509_sequence certificate_policies; /**< Optional list of certificate policies (Only anyPolicy is printed and enforced, however the rest of the policies are still listed). */
 
     int ext_types;              /**< Bit string containing detected and parsed extensions */
     int ca_istrue;              /**< Optional Basic Constraint extension value: 1 if this certificate belongs to a CA, 0 otherwise. */
@@ -98,6 +100,53 @@
 mbedtls_x509_crt;
 
 /**
+ * From RFC 5280 section 4.2.1.6:
+ * OtherName ::= SEQUENCE {
+ *      type-id    OBJECT IDENTIFIER,
+ *      value      [0] EXPLICIT ANY DEFINED BY type-id }
+ */
+typedef struct mbedtls_x509_san_other_name
+{
+    /**
+     * The type_id is an OID as deifned in RFC 5280.
+     * To check the value of the type id, you should use
+     * \p MBEDTLS_OID_CMP with a known OID mbedtls_x509_buf.
+     */
+    mbedtls_x509_buf type_id;                   /**< The type id. */
+    union
+    {
+        /**
+         * From RFC 4108 section 5:
+         * HardwareModuleName ::= SEQUENCE {
+         *                         hwType OBJECT IDENTIFIER,
+         *                         hwSerialNum OCTET STRING }
+         */
+        struct
+        {
+            mbedtls_x509_buf oid;               /**< The object identifier. */
+            mbedtls_x509_buf val;               /**< The named value. */
+        }
+        hardware_module_name;
+    }
+    value;
+}
+mbedtls_x509_san_other_name;
+
+/**
+ * A structure for holding the parsed Subject Alternative Name, according to type
+ */
+typedef struct mbedtls_x509_subject_alternative_name
+{
+    int type;                              /**< The SAN type, value of MBEDTLS_X509_SAN_XXX. */
+    union {
+        mbedtls_x509_san_other_name other_name; /**< The otherName supported type. */
+        mbedtls_x509_buf   unstructured_name; /**< The buffer for the un constructed types. Only dnsName currently supported */
+    }
+    san; /**< A union of the supported SAN types */
+}
+mbedtls_x509_subject_alternative_name;
+
+/**
  * Build flag from an algorithm/curve identifier (pk, md, ecp)
  * Since 0 is always XXX_NONE, ignore it.
  */
@@ -346,8 +395,37 @@
  *                 if partly successful or a specific X509 or PEM error code
  */
 int mbedtls_x509_crt_parse_path( mbedtls_x509_crt *chain, const char *path );
-#endif /* MBEDTLS_FS_IO */
 
+#endif /* MBEDTLS_FS_IO */
+/**
+ * \brief          This function parses an item in the SubjectAlternativeNames
+ *                 extension.
+ *
+ * \param san_buf  The buffer holding the raw data item of the subject
+ *                 alternative name.
+ * \param san      The target structure to populate with the parsed presentation
+ *                 of the subject alternative name encoded in \p san_raw.
+ *
+ * \note           Only "dnsName" and "otherName" of type hardware_module_name
+ *                 as defined in RFC 4180 is supported.
+ *
+ * \note           This function should be called on a single raw data of
+ *                 subject alternative name. For example, after successful
+ *                 certificate parsing, one must iterate on every item in the
+ *                 \p crt->subject_alt_names sequence, and pass it to
+ *                 this function.
+ *
+ * \warning        The target structure contains pointers to the raw data of the
+ *                 parsed certificate, and its lifetime is restricted by the
+ *                 lifetime of the certificate.
+ *
+ * \return         \c 0 on success
+ * \return         #MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE for an unsupported
+ *                 SAN type.
+ * \return         Another negative value for any other failure.
+ */
+int mbedtls_x509_parse_subject_alt_name( const mbedtls_x509_buf *san_buf,
+                                         mbedtls_x509_subject_alternative_name *san );
 /**
  * \brief          Returns an informational string about the
  *                 certificate.
diff --git a/library/x509_crt.c b/library/x509_crt.c
index 97a06d5..708dbf7 100644
--- a/library/x509_crt.c
+++ b/library/x509_crt.c
@@ -618,7 +618,8 @@
  *      nameAssigner            [0]     DirectoryString OPTIONAL,
  *      partyName               [1]     DirectoryString }
  *
- * NOTE: we only parse and use dNSName at this point.
+ * 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,
@@ -641,6 +642,9 @@
 
     while( *p < end )
     {
+        mbedtls_x509_subject_alternative_name dummy_san_buf;
+        memset( &dummy_san_buf, 0, sizeof( dummy_san_buf ) );
+
         if( ( end - *p ) < 1 )
             return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS +
                     MBEDTLS_ERR_ASN1_OUT_OF_DATA );
@@ -657,11 +661,27 @@
                     MBEDTLS_ERR_ASN1_UNEXPECTED_TAG );
         }
 
-        /* Skip everything but DNS name */
-        if( tag != ( MBEDTLS_ASN1_CONTEXT_SPECIFIC | 2 ) )
+        /*
+         * Check that the SAN are structured correct.
+         */
+        ret = mbedtls_x509_parse_subject_alt_name( &(cur->buf), &dummy_san_buf );
+        /*
+         * In case the extension is malformed, return an error,
+         * and clear the allocated sequences.
+         */
+        if( ret != 0 && ret != MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE )
         {
-            *p += tag_len;
-            continue;
+            mbedtls_x509_sequence *seq_cur = subject_alt_name->next;
+            mbedtls_x509_sequence *seq_prv;
+            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 );
+            }
+            return( ret );
         }
 
         /* Allocate and assign next pointer */
@@ -697,6 +717,168 @@
 }
 
 /*
+ * id-ce-certificatePolicies OBJECT IDENTIFIER ::=  { id-ce 32 }
+ *
+ * anyPolicy OBJECT IDENTIFIER ::= { id-ce-certificatePolicies 0 }
+ *
+ * certificatePolicies ::= SEQUENCE SIZE (1..MAX) OF PolicyInformation
+ *
+ * PolicyInformation ::= SEQUENCE {
+ *     policyIdentifier   CertPolicyId,
+ *     policyQualifiers   SEQUENCE SIZE (1..MAX) OF
+ *                             PolicyQualifierInfo OPTIONAL }
+ *
+ * CertPolicyId ::= OBJECT IDENTIFIER
+ *
+ * PolicyQualifierInfo ::= SEQUENCE {
+ *      policyQualifierId  PolicyQualifierId,
+ *      qualifier          ANY DEFINED BY policyQualifierId }
+ *
+ * -- policyQualifierIds for Internet policy qualifiers
+ *
+ * id-qt          OBJECT IDENTIFIER ::=  { id-pkix 2 }
+ * id-qt-cps      OBJECT IDENTIFIER ::=  { id-qt 1 }
+ * id-qt-unotice  OBJECT IDENTIFIER ::=  { id-qt 2 }
+ *
+ * PolicyQualifierId ::= OBJECT IDENTIFIER ( id-qt-cps | id-qt-unotice )
+ *
+ * Qualifier ::= CHOICE {
+ *      cPSuri           CPSuri,
+ *      userNotice       UserNotice }
+ *
+ * CPSuri ::= IA5String
+ *
+ * UserNotice ::= SEQUENCE {
+ *      noticeRef        NoticeReference OPTIONAL,
+ *      explicitText     DisplayText OPTIONAL }
+ *
+ * NoticeReference ::= SEQUENCE {
+ *      organization     DisplayText,
+ *      noticeNumbers    SEQUENCE OF INTEGER }
+ *
+ * DisplayText ::= CHOICE {
+ *      ia5String        IA5String      (SIZE (1..200)),
+ *      visibleString    VisibleString  (SIZE (1..200)),
+ *      bmpString        BMPString      (SIZE (1..200)),
+ *      utf8String       UTF8String     (SIZE (1..200)) }
+ *
+ * NOTE: we only parse and use anyPolicy without qualifiers at this point
+ * as defined in RFC 5280.
+ */
+static int x509_get_certificate_policies( unsigned char **p,
+                                          const unsigned char *end,
+                                          mbedtls_x509_sequence *certificate_policies )
+{
+    int ret, parse_ret = 0;
+    size_t len;
+    mbedtls_asn1_buf *buf;
+    mbedtls_asn1_sequence *cur = certificate_policies;
+
+    /* Get main sequence tag */
+    ret = mbedtls_asn1_get_tag( p, end, &len,
+                             MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE );
+    if( ret != 0 )
+        return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret );
+
+    if( *p + len != end )
+        return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS +
+                MBEDTLS_ERR_ASN1_LENGTH_MISMATCH );
+
+    /*
+     * Cannot be an empty sequence.
+     */
+    if( len == 0 )
+        return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS +
+                MBEDTLS_ERR_ASN1_LENGTH_MISMATCH );
+
+    while( *p < end )
+    {
+        mbedtls_x509_buf policy_oid;
+        const unsigned char *policy_end;
+
+        /*
+         * Get the policy sequence
+         */
+        if( ( ret = mbedtls_asn1_get_tag( p, end, &len,
+                MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 )
+            return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret );
+
+        policy_end = *p + len;
+
+        if( ( ret = mbedtls_asn1_get_tag( p, policy_end, &len,
+                                          MBEDTLS_ASN1_OID ) ) != 0 )
+            return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret );
+
+        policy_oid.tag = MBEDTLS_ASN1_OID;
+        policy_oid.len = len;
+        policy_oid.p = *p;
+
+        /*
+         * Only AnyPolicy is currently supported when enforcing policy.
+         */
+        if( MBEDTLS_OID_CMP( MBEDTLS_OID_ANY_POLICY, &policy_oid ) != 0 )
+        {
+            /*
+             * Set the parsing return code but continue parsing, in case this
+             * extension is critical and MBEDTLS_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION
+             * is configured.
+             */
+            parse_ret = MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE;
+        }
+
+        /* Allocate and assign next pointer */
+        if( cur->buf.p != NULL )
+        {
+            if( cur->next != NULL )
+                return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS );
+
+            cur->next = mbedtls_calloc( 1, sizeof( mbedtls_asn1_sequence ) );
+
+            if( cur->next == NULL )
+                return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS +
+                        MBEDTLS_ERR_ASN1_ALLOC_FAILED );
+
+            cur = cur->next;
+        }
+
+        buf = &( cur->buf );
+        buf->tag = policy_oid.tag;
+        buf->p = policy_oid.p;
+        buf->len = policy_oid.len;
+
+        *p += len;
+
+       /*
+        * If there is an optional qualifier, then *p < policy_end
+        * Check the Qualifier len to verify it doesn't exceed policy_end.
+        */
+        if( *p < policy_end )
+        {
+            if( ( ret = mbedtls_asn1_get_tag( p, policy_end, &len,
+                     MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 )
+                return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret );
+            /*
+             * Skip the optional policy qualifiers.
+             */
+            *p += len;
+        }
+
+        if( *p != policy_end )
+            return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS +
+                    MBEDTLS_ERR_ASN1_LENGTH_MISMATCH );
+    }
+
+    /* Set final sequence entry's next pointer to NULL */
+    cur->next = NULL;
+
+    if( *p != end )
+        return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS +
+                MBEDTLS_ERR_ASN1_LENGTH_MISMATCH );
+
+    return( parse_ret );
+}
+
+/*
  * X.509 v3 extensions
  *
  */
@@ -823,6 +1005,27 @@
                 return( ret );
             break;
 
+        case MBEDTLS_OID_X509_EXT_CERTIFICATE_POLICIES:
+            /* Parse certificate policies type */
+            if( ( ret = x509_get_certificate_policies( p, end_ext_octet,
+                    &crt->certificate_policies ) ) != 0 )
+            {
+#if !defined(MBEDTLS_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION)
+                if( is_critical )
+                    return( ret );
+                else
+#endif
+                /*
+                 * If MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE is returned, then we
+                 * cannot interpret or enforce the policy. However, it is up to
+                 * the user to choose how to enforce the policies,
+                 * unless the extension is critical.
+                 */
+                if( ret != MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE )
+                    return( ret );
+            }
+            break;
+
         default:
             /*
              * If this is a non-critical extension, which the oid layer
@@ -1435,32 +1638,201 @@
 }
 #endif /* MBEDTLS_FS_IO */
 
-static int x509_info_subject_alt_name( char **buf, size_t *size,
-                                       const mbedtls_x509_sequence *subject_alt_name )
+/*
+ * OtherName ::= SEQUENCE {
+ *      type-id    OBJECT IDENTIFIER,
+ *      value      [0] EXPLICIT ANY DEFINED BY type-id }
+ *
+ * HardwareModuleName ::= SEQUENCE {
+ *                           hwType OBJECT IDENTIFIER,
+ *                           hwSerialNum OCTET STRING }
+ *
+ * NOTE: we currently only parse and use otherName of type HwModuleName,
+ * as defined in RFC 4108.
+ */
+static int x509_get_other_name( const mbedtls_x509_buf *subject_alt_name,
+                                mbedtls_x509_san_other_name *other_name )
 {
-    size_t i;
+    int ret = 0;
+    size_t len;
+    unsigned char *p = subject_alt_name->p;
+    const unsigned char *end = p + subject_alt_name->len;
+    mbedtls_x509_buf cur_oid;
+
+    if( ( subject_alt_name->tag &
+        ( MBEDTLS_ASN1_TAG_CLASS_MASK | MBEDTLS_ASN1_TAG_VALUE_MASK ) ) !=
+        ( MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_X509_SAN_OTHER_NAME ) )
+    {
+        /*
+         * The given subject alternative name is not of type "othername".
+         */
+        return( MBEDTLS_ERR_X509_BAD_INPUT_DATA );
+    }
+
+    if( ( ret = mbedtls_asn1_get_tag( &p, end, &len,
+                                      MBEDTLS_ASN1_OID ) ) != 0 )
+        return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret );
+
+    cur_oid.tag = MBEDTLS_ASN1_OID;
+    cur_oid.p = p;
+    cur_oid.len = len;
+
+    /*
+     * Only HwModuleName is currently supported.
+     */
+    if( MBEDTLS_OID_CMP( MBEDTLS_OID_ON_HW_MODULE_NAME, &cur_oid ) != 0 )
+    {
+        return( MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE );
+    }
+
+    if( p + len >= end )
+    {
+        mbedtls_platform_zeroize( other_name, sizeof( other_name ) );
+        return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS +
+                MBEDTLS_ERR_ASN1_LENGTH_MISMATCH );
+    }
+    p += len;
+    if( ( ret = mbedtls_asn1_get_tag( &p, end, &len,
+            MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_CONTEXT_SPECIFIC ) ) != 0 )
+        return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret );
+
+    if( ( ret = mbedtls_asn1_get_tag( &p, end, &len,
+                     MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 )
+       return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret );
+
+    if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, MBEDTLS_ASN1_OID ) ) != 0 )
+        return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret );
+
+    other_name->value.hardware_module_name.oid.tag = MBEDTLS_ASN1_OID;
+    other_name->value.hardware_module_name.oid.p = p;
+    other_name->value.hardware_module_name.oid.len = len;
+
+    if( p + len >= end )
+    {
+        mbedtls_platform_zeroize( other_name, sizeof( other_name ) );
+        return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS +
+                MBEDTLS_ERR_ASN1_LENGTH_MISMATCH );
+    }
+    p += len;
+    if( ( ret = mbedtls_asn1_get_tag( &p, end, &len,
+                                      MBEDTLS_ASN1_OCTET_STRING ) ) != 0 )
+        return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret );
+
+    other_name->value.hardware_module_name.val.tag = MBEDTLS_ASN1_OCTET_STRING;
+    other_name->value.hardware_module_name.val.p = p;
+    other_name->value.hardware_module_name.val.len = len;
+    p += len;
+    if( p != end )
+    {
+        mbedtls_platform_zeroize( other_name,
+                                  sizeof( other_name ) );
+        return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS +
+                MBEDTLS_ERR_ASN1_LENGTH_MISMATCH );
+    }
+    return( 0 );
+}
+
+static int x509_info_subject_alt_name( char **buf, size_t *size,
+                                       const mbedtls_x509_sequence
+                                                    *subject_alt_name,
+                                       const char *prefix )
+{
+    int ret;
     size_t n = *size;
     char *p = *buf;
     const mbedtls_x509_sequence *cur = subject_alt_name;
-    const char *sep = "";
-    size_t sep_len = 0;
+    mbedtls_x509_subject_alternative_name san;
+    int parse_ret;
 
     while( cur != NULL )
     {
-        if( cur->buf.len + sep_len >= n )
+        memset( &san, 0, sizeof( san ) );
+        parse_ret = mbedtls_x509_parse_subject_alt_name( &cur->buf, &san );
+        if( parse_ret != 0 )
         {
-            *p = '\0';
-            return( MBEDTLS_ERR_X509_BUFFER_TOO_SMALL );
+            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;
         }
 
-        n -= cur->buf.len + sep_len;
-        for( i = 0; i < sep_len; i++ )
-            *p++ = sep[i];
-        for( i = 0; i < cur->buf.len; i++ )
-            *p++ = cur->buf.p[i];
+        switch( san.type )
+        {
+            /*
+             * otherName
+             */
+            case MBEDTLS_X509_SAN_OTHER_NAME:
+            {
+                mbedtls_x509_san_other_name *other_name = &san.san.other_name;
 
-        sep = ", ";
-        sep_len = 2;
+                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;
+
+                    if( other_name->value.hardware_module_name.val.len >= n )
+                    {
+                        *p = '\0';
+                        return( MBEDTLS_ERR_X509_BUFFER_TOO_SMALL );
+                    }
+
+                    memcpy( p, other_name->value.hardware_module_name.val.p,
+                            other_name->value.hardware_module_name.val.len );
+                    p += other_name->value.hardware_module_name.val.len;
+
+                    n -= other_name->value.hardware_module_name.val.len;
+
+                }/* 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;
     }
@@ -1473,6 +1845,56 @@
     return( 0 );
 }
 
+int mbedtls_x509_parse_subject_alt_name( const mbedtls_x509_buf *san_buf,
+                                         mbedtls_x509_subject_alternative_name *san )
+{
+    int ret;
+    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;
+
+        /*
+         * Type not supported
+         */
+        default:
+            return( MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE );
+    }
+    return( 0 );
+}
+
 #define PRINT_ITEM(i)                           \
     {                                           \
         ret = mbedtls_snprintf( p, n, "%s" i, sep );    \
@@ -1564,6 +1986,35 @@
     return( 0 );
 }
 
+static int x509_info_cert_policies( char **buf, size_t *size,
+                                    const mbedtls_x509_sequence *certificate_policies )
+{
+    int ret;
+    const char *desc;
+    size_t n = *size;
+    char *p = *buf;
+    const mbedtls_x509_sequence *cur = certificate_policies;
+    const char *sep = "";
+
+    while( cur != NULL )
+    {
+        if( mbedtls_oid_get_certificate_policies( &cur->buf, &desc ) != 0 )
+            desc = "???";
+
+        ret = mbedtls_snprintf( p, n, "%s%s", sep, desc );
+        MBEDTLS_X509_SAFE_SNPRINTF;
+
+        sep = ", ";
+
+        cur = cur->next;
+    }
+
+    *size = n;
+    *buf = p;
+
+    return( 0 );
+}
+
 /*
  * Return an informational string about the certificate.
  */
@@ -1659,11 +2110,12 @@
 
     if( crt->ext_types & MBEDTLS_X509_EXT_SUBJECT_ALT_NAME )
     {
-        ret = mbedtls_snprintf( p, n, "\n%ssubject alt name  : ", prefix );
+        ret = mbedtls_snprintf( p, n, "\n%ssubject alt name  :", prefix );
         MBEDTLS_X509_SAFE_SNPRINTF;
 
         if( ( ret = x509_info_subject_alt_name( &p, &n,
-                                            &crt->subject_alt_names ) ) != 0 )
+                                                &crt->subject_alt_names,
+                                                prefix ) ) != 0 )
             return( ret );
     }
 
@@ -1695,6 +2147,16 @@
             return( ret );
     }
 
+    if( crt->ext_types & MBEDTLS_OID_X509_EXT_CERTIFICATE_POLICIES )
+    {
+        ret = mbedtls_snprintf( p, n, "\n%scertificate policies : ", prefix );
+        MBEDTLS_X509_SAFE_SNPRINTF;
+
+        if( ( ret = x509_info_cert_policies( &p, &n,
+                                             &crt->certificate_policies ) ) != 0 )
+            return( ret );
+    }
+
     ret = mbedtls_snprintf( p, n, "\n" );
     MBEDTLS_X509_SAFE_SNPRINTF;
 
@@ -2821,6 +3283,16 @@
             mbedtls_free( seq_prv );
         }
 
+        seq_cur = cert_cur->certificate_policies.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 )
         {
             mbedtls_platform_zeroize( cert_cur->raw.p, cert_cur->raw.len );
diff --git a/tests/data_files/Makefile b/tests/data_files/Makefile
index 748514d..d1af18c 100644
--- a/tests/data_files/Makefile
+++ b/tests/data_files/Makefile
@@ -77,6 +77,42 @@
 test_ca_crt_file_ec = test-ca2.crt
 test_ca_key_file_ec = test-ca2.key
 
+test-ca-any_policy.crt: $(test_ca_key_file_rsa) test-ca.req.sha256
+	$(OPENSSL) req -x509 -config $(test_ca_config_file) -extensions v3_any_policy_ca -key $(test_ca_key_file_rsa) -passin "pass:$(test_ca_pwd_rsa)" -set_serial 0 -days 3653 -sha256 -in test-ca.req.sha256 -out $@
+all_final += test-ca-any_policy.crt
+
+test-ca-any_policy_ec.crt: $(test_ca_key_file_ec) test-ca.req_ec.sha256
+	$(OPENSSL) req -x509 -config $(test_ca_config_file) -extensions v3_any_policy_ca -key $(test_ca_key_file_ec) -set_serial 0 -days 3653 -sha256 -in test-ca.req_ec.sha256 -out $@
+all_final += test-ca-any_policy_ec.crt
+
+test-ca-any_policy_with_qualifier.crt: $(test_ca_key_file_rsa) test-ca.req.sha256
+	$(OPENSSL) req -x509 -config $(test_ca_config_file) -extensions v3_any_policy_qualifier_ca -key $(test_ca_key_file_rsa) -passin "pass:$(test_ca_pwd_rsa)" -set_serial 0 -days 3653 -sha256 -in test-ca.req.sha256 -out $@
+all_final += test-ca-any_policy_with_qualifier.crt
+
+test-ca-any_policy_with_qualifier_ec.crt: $(test_ca_key_file_ec) test-ca.req_ec.sha256
+	$(OPENSSL) req -x509 -config $(test_ca_config_file) -extensions v3_any_policy_qualifier_ca -key $(test_ca_key_file_ec) -set_serial 0 -days 3653 -sha256 -in test-ca.req_ec.sha256 -out $@
+all_final += test-ca-any_policy_with_qualifier_ec.crt
+
+test-ca-multi_policy.crt: $(test_ca_key_file_rsa) test-ca.req.sha256
+	$(OPENSSL) req -x509 -config $(test_ca_config_file) -extensions v3_multi_policy_ca -key $(test_ca_key_file_rsa) -passin "pass:$(test_ca_pwd_rsa)" -set_serial 0 -days 3653 -sha256 -in test-ca.req.sha256 -out $@
+all_final += test-ca-multi_policy.crt
+
+test-ca-multi_policy_ec.crt: $(test_ca_key_file_ec) test-ca.req_ec.sha256
+	$(OPENSSL) req -x509 -config $(test_ca_config_file) -extensions v3_multi_policy_ca -key $(test_ca_key_file_ec) -set_serial 0 -days 3653 -sha256 -in test-ca.req_ec.sha256 -out $@
+all_final += test-ca-multi_policy_ec.crt
+
+test-ca-unsupported_policy.crt: $(test_ca_key_file_rsa) test-ca.req.sha256
+	$(OPENSSL) req -x509 -config $(test_ca_config_file) -extensions v3_unsupported_policy_ca -key $(test_ca_key_file_rsa) -passin "pass:$(test_ca_pwd_rsa)" -set_serial 0 -days 3653 -sha256 -in test-ca.req.sha256 -out $@
+all_final += test-ca-unsupported_policy.crt
+
+test-ca-unsupported_policy_ec.crt: $(test_ca_key_file_ec) test-ca.req_ec.sha256
+	$(OPENSSL) req -x509 -config $(test_ca_config_file) -extensions v3_unsupported_policy_ca -key $(test_ca_key_file_ec) -set_serial 0 -days 3653 -sha256 -in test-ca.req_ec.sha256 -out $@
+all_final += test-ca-unsupported_policy_ec.crt
+
+test-ca.req_ec.sha256: $(test_ca_key_file_ec)
+	$(MBEDTLS_CERT_REQ) output_file=$@ filename=$(test_ca_key_file_ec) subject_name="C=NL, O=PolarSSL, CN=Polarssl Test EC CA" md=SHA256
+all_intermediate += test-ca.req_ec.sha256
+
 test_ca_crt_cat12 = test-ca_cat12.crt
 $(test_ca_crt_cat12): $(test_ca_crt) $(test_ca_crt_file_ec)
 	cat $(test_ca_crt) $(test_ca_crt_file_ec) > $@
@@ -142,6 +178,15 @@
 	$(FAKETIME) '2015-09-01 14:08:43' $(OPENSSL) req -x509 -new -subj "/C=UK/O=mbed TLS/CN=mbed TLS Test intermediate CA 3" -set_serial 77 -config $(test_ca_config_file) -extensions noext_ca -days 3650 -sha256 -key $< -out $@
 all_final += server5-ss-forgeca.crt
 
+server5-othername.crt: server5.key
+	$(OPENSSL) req -x509 -new -subj "/C=UK/O=Mbed TLS/CN=Mbed TLS othername SAN" -set_serial 77 -config $(test_ca_config_file) -extensions othername_san -days 3650 -sha256 -key $< -out $@
+
+server5-unsupported_othername.crt: server5.key
+	$(OPENSSL) req -x509 -new -subj "/C=UK/O=Mbed TLS/CN=Mbed TLS unsupported othername SAN" -set_serial 77 -config $(test_ca_config_file) -extensions unsupoported_othername_san -days 3650 -sha256 -key $< -out $@
+
+server5-fan.crt: server5.key
+	$(OPENSSL) req -x509 -new -subj "/C=UK/O=Mbed TLS/CN=Mbed TLS FAN" -set_serial 77 -config $(test_ca_config_file) -extensions fan_cert -days 3650 -sha256 -key server5.key -out $@
+
 server10-badsign.crt: server10.crt
 	{ head -n-2 $<; tail -n-2 $< | sed -e '1s/0\(=*\)$$/_\1/' -e '1s/[^_=]\(=*\)$$/0\1/' -e '1s/_/1/'; } > $@
 all_final += server10-badsign.crt
diff --git a/tests/data_files/multiple_san.crt b/tests/data_files/multiple_san.crt
new file mode 100644
index 0000000..8cdc730
--- /dev/null
+++ b/tests/data_files/multiple_san.crt
@@ -0,0 +1,12 @@
+-----BEGIN CERTIFICATE-----
+MIIB2jCCAYCgAwIBAgIBBDAKBggqhkjOPQQDAjBKMQswCQYDVQQGEwJVSzERMA8G
+A1UECgwITWJlZCBUTFMxKDAmBgNVBAMMH01iZWQgVExTIG11bHRpcGxlIG90aGVy
+bmFtZSBTQU4wHhcNMTkwNDIyMTYxMDQ4WhcNMjkwNDE5MTYxMDQ4WjBKMQswCQYD
+VQQGEwJVSzERMA8GA1UECgwITWJlZCBUTFMxKDAmBgNVBAMMH01iZWQgVExTIG11
+bHRpcGxlIG90aGVybmFtZSBTQU4wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQ3
+zFbZdgkeWnI+x1kt/yBu7nz5BpF00K0UtfdoIllikk7lANgjEf/qL9I0XV0WvYqI
+wmt3DVXNiioO+gHItO3/o1cwVTBTBgNVHREETDBKggtleGFtcGxlLmNvbaAfBggr
+BgEFBQcIBKATMBEGBysGAQQBEQMEBjEyMzQ1NoILZXhhbXBsZS5uZXSCDSouZXhh
+bXBsZS5vcmcwCgYIKoZIzj0EAwIDSAAwRQIhAMZUkp+pcuFQ3WWdgvV4Y+tIXOyS
+L6p0RtEAOi/GgigVAiB50n3rIUKjapYstPp3yOpGZGyRxnc6uRdSiMH5wLA4yw==
+-----END CERTIFICATE-----
diff --git a/tests/data_files/server5-fan.crt b/tests/data_files/server5-fan.crt
new file mode 100644
index 0000000..dc1eb38
--- /dev/null
+++ b/tests/data_files/server5-fan.crt
@@ -0,0 +1,10 @@
+-----BEGIN CERTIFICATE-----
+MIIBdTCCARugAwIBAgIBTTAKBggqhkjOPQQDAjA3MQswCQYDVQQGEwJVSzERMA8G
+A1UECgwITWJlZCBUTFMxFTATBgNVBAMMDE1iZWQgVExTIEZBTjAeFw0xOTAzMjUw
+OTAzNDZaFw0yOTAzMjIwOTAzNDZaMDcxCzAJBgNVBAYTAlVLMREwDwYDVQQKDAhN
+YmVkIFRMUzEVMBMGA1UEAwwMTWJlZCBUTFMgRkFOMFkwEwYHKoZIzj0CAQYIKoZI
+zj0DAQcDQgAEN8xW2XYJHlpyPsdZLf8gbu58+QaRdNCtFLX3aCJZYpJO5QDYIxH/
+6i/SNF1dFr2KiMJrdw1VzYoqDvoByLTt/6MYMBYwFAYDVR0lBA0wCwYJKwYBBAGC
+5CUBMAoGCCqGSM49BAMCA0gAMEUCIQDp/Q5FaVy3YNeJflQKLGycQZoH6V3FQnLq
+ERUCeimLIAIgdyiA4KdHxkpQhC1L1KfmxG8YJqu31FBjmNw00Sv8J9k=
+-----END CERTIFICATE-----
diff --git a/tests/data_files/server5-othername.crt b/tests/data_files/server5-othername.crt
new file mode 100644
index 0000000..3be1a77
--- /dev/null
+++ b/tests/data_files/server5-othername.crt
@@ -0,0 +1,11 @@
+-----BEGIN CERTIFICATE-----
+MIIBnzCCAUWgAwIBAgIBTTAKBggqhkjOPQQDAjBBMQswCQYDVQQGEwJVSzERMA8G
+A1UECgwITWJlZCBUTFMxHzAdBgNVBAMMFk1iZWQgVExTIG90aGVybmFtZSBTQU4w
+HhcNMTkwMzI0MDkwNjAyWhcNMjkwMzIxMDkwNjAyWjBBMQswCQYDVQQGEwJVSzER
+MA8GA1UECgwITWJlZCBUTFMxHzAdBgNVBAMMFk1iZWQgVExTIG90aGVybmFtZSBT
+QU4wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQ3zFbZdgkeWnI+x1kt/yBu7nz5
+BpF00K0UtfdoIllikk7lANgjEf/qL9I0XV0WvYqIwmt3DVXNiioO+gHItO3/oy4w
+LDAqBgNVHREEIzAhoB8GCCsGAQUFBwgEoBMwEQYHKwYBBAERAwQGMTIzNDU2MAoG
+CCqGSM49BAMCA0gAMEUCIQCijdm1AfArx2p4cLCVciHCTE8UXRiTm8f85k4aNzzf
+sgIgCdmLyfZB9jsSPH3A3O1GATAR3O9OTtEDC+YSc+lvxSw=
+-----END CERTIFICATE-----
diff --git a/tests/data_files/server5-unsupported_othername.crt b/tests/data_files/server5-unsupported_othername.crt
new file mode 100644
index 0000000..b46fc2d
--- /dev/null
+++ b/tests/data_files/server5-unsupported_othername.crt
@@ -0,0 +1,12 @@
+-----BEGIN CERTIFICATE-----
+MIIBtjCCAVygAwIBAgIBTTAKBggqhkjOPQQDAjBNMQswCQYDVQQGEwJVSzERMA8G
+A1UECgwITWJlZCBUTFMxKzApBgNVBAMMIk1iZWQgVExTIHVuc3VwcG9ydGVkIG90
+aGVybmFtZSBTQU4wHhcNMTkwNTAxMDkxMDM1WhcNMjkwNDI4MDkxMDM1WjBNMQsw
+CQYDVQQGEwJVSzERMA8GA1UECgwITWJlZCBUTFMxKzApBgNVBAMMIk1iZWQgVExT
+IHVuc3VwcG9ydGVkIG90aGVybmFtZSBTQU4wWTATBgcqhkjOPQIBBggqhkjOPQMB
+BwNCAAQ3zFbZdgkeWnI+x1kt/yBu7nz5BpF00K0UtfdoIllikk7lANgjEf/qL9I0
+XV0WvYqIwmt3DVXNiioO+gHItO3/oy0wKzApBgNVHREEIjAgoB4GAyoDBKAXDBVz
+b21lIG90aGVyIGlkZW50aWZpZXIwCgYIKoZIzj0EAwIDSAAwRQIhANkj6n9qHYVi
+FLfb0IRZpIsvvuNCjSgT8yBLVjJYQj3nAiBffQKZ7y/F6rfon6L1GZU0BBja8BLX
+rXp8WpY7Bc8myQ==
+-----END CERTIFICATE-----
diff --git a/tests/data_files/test-ca-any_policy.crt b/tests/data_files/test-ca-any_policy.crt
new file mode 100644
index 0000000..af87439
--- /dev/null
+++ b/tests/data_files/test-ca-any_policy.crt
@@ -0,0 +1,19 @@
+-----BEGIN CERTIFICATE-----
+MIIDFDCCAfygAwIBAgIBADANBgkqhkiG9w0BAQsFADA7MQswCQYDVQQGEwJOTDER
+MA8GA1UECgwIUG9sYXJTU0wxGTAXBgNVBAMMEFBvbGFyU1NMIFRlc3QgQ0EwHhcN
+MTkwMzIxMTY0MDU5WhcNMjkwMzIxMTY0MDU5WjA7MQswCQYDVQQGEwJOTDERMA8G
+A1UECgwIUG9sYXJTU0wxGTAXBgNVBAMMEFBvbGFyU1NMIFRlc3QgQ0EwggEiMA0G
+CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDA3zf8F7vglp0/ht6WMn1EpRagzSHx
+mdTs6st8GFgIlKXsm8WL3xoemTiZhx57wI053zhdcHgH057Zk+i5clHFzqMwUqny
+50BwFMtEonILwuVA+T7lpg6z+exKY8C4KQB0nFc7qKUEkHHxvYPZP9al4jwqj+8n
+YMPGn8u67GB9t+aEMr5P+1gmIgNb1LTV+/Xjli5wwOQuvfwu7uJBVcA0Ln0kcmnL
+R7EUQIN9Z/SG9jGr8XmksrUuEvmEF/Bibyc+E1ixVA0hmnM3oTDPb5Lc9un8rNsu
+KNF+AksjoBXyOGVkCeoMbo4bF6BxyLObyavpw/LPh5aPgAIynplYb6LVAgMBAAGj
+IzAhMAwGA1UdEwQFMAMBAf8wEQYDVR0gBAowCDAGBgRVHSAAMA0GCSqGSIb3DQEB
+CwUAA4IBAQCHadUDZiIjJhcrG+rYrpOVgMu548rc5kHLC7zVSVfszfdOJq/TdXQT
+Lbn9i+AAVRYJU2kHWKD2fvgOYIIBeEGFJKohlKZ82irWxt0Ltph31cuygLcpqNq9
+KRQ/dh3S0w9vn1A1ubYGKTzTnZGELTVzMlXZGTRbAOylMu4eWac6LHymE2EBqmOq
+fPCuWdFB62ewQWRa+dRO92Aphh870u43/iLbw7hs4s8hokZP7Ewg6AHb4qjVePdF
+jjxAO6x5VCj/WQRnw7muAy0P3l5AhYXAIUdnkdYca5Ja6LfdEJiVeTdE3IU6UJg+
+gAu9swDhUlEuIlCrOdC3tOPDslsOIgTV
+-----END CERTIFICATE-----
diff --git a/tests/data_files/test-ca-any_policy_ec.crt b/tests/data_files/test-ca-any_policy_ec.crt
new file mode 100644
index 0000000..821a92c
--- /dev/null
+++ b/tests/data_files/test-ca-any_policy_ec.crt
@@ -0,0 +1,12 @@
+-----BEGIN CERTIFICATE-----
+MIIBzDCCAVGgAwIBAgIBADAKBggqhkjOPQQDAjA+MQswCQYDVQQGEwJOTDERMA8G
+A1UECgwIUG9sYXJTU0wxHDAaBgNVBAMME1BvbGFyc3NsIFRlc3QgRUMgQ0EwHhcN
+MTkwMzI1MDkwMjQ1WhcNMjkwMzI1MDkwMjQ1WjA+MQswCQYDVQQGEwJOTDERMA8G
+A1UECgwIUG9sYXJTU0wxHDAaBgNVBAMME1BvbGFyc3NsIFRlc3QgRUMgQ0EwdjAQ
+BgcqhkjOPQIBBgUrgQQAIgNiAATD2is0QTdYL4dW/vyJuilDS07gbsMOV1MzOVjU
+UrSRlTkLI99fFyRiSPwalSnOLC2HwohSgK/Waqsh3bjTHG5YuMrosmmO80GtKcO0
+X3WnR2/VGSlVaZpTOyC0ZhZgMx6jIzAhMAwGA1UdEwQFMAMBAf8wEQYDVR0gBAow
+CDAGBgRVHSAAMAoGCCqGSM49BAMCA2kAMGYCMQDWHgmWMckbGLd7XREnJVAv+XRp
+XANOCbWLDu+Fik6c28S+qR6zGEKKGiPHYeDpjRACMQDnYcFBwlfuAB6td3fteG0P
+AWngOaGHmUFEA6h24b5Z6/GSFD9FK9rVRdxQc4Olz7U=
+-----END CERTIFICATE-----
diff --git a/tests/data_files/test-ca-any_policy_with_qualifier.crt b/tests/data_files/test-ca-any_policy_with_qualifier.crt
new file mode 100644
index 0000000..a052bc6
--- /dev/null
+++ b/tests/data_files/test-ca-any_policy_with_qualifier.crt
@@ -0,0 +1,20 @@
+-----BEGIN CERTIFICATE-----
+MIIDMjCCAhqgAwIBAgIBADANBgkqhkiG9w0BAQsFADA7MQswCQYDVQQGEwJOTDER
+MA8GA1UECgwIUG9sYXJTU0wxGTAXBgNVBAMMEFBvbGFyU1NMIFRlc3QgQ0EwHhcN
+MTkwNDI4MTMxNDMxWhcNMjkwNDI4MTMxNDMxWjA7MQswCQYDVQQGEwJOTDERMA8G
+A1UECgwIUG9sYXJTU0wxGTAXBgNVBAMMEFBvbGFyU1NMIFRlc3QgQ0EwggEiMA0G
+CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDA3zf8F7vglp0/ht6WMn1EpRagzSHx
+mdTs6st8GFgIlKXsm8WL3xoemTiZhx57wI053zhdcHgH057Zk+i5clHFzqMwUqny
+50BwFMtEonILwuVA+T7lpg6z+exKY8C4KQB0nFc7qKUEkHHxvYPZP9al4jwqj+8n
+YMPGn8u67GB9t+aEMr5P+1gmIgNb1LTV+/Xjli5wwOQuvfwu7uJBVcA0Ln0kcmnL
+R7EUQIN9Z/SG9jGr8XmksrUuEvmEF/Bibyc+E1ixVA0hmnM3oTDPb5Lc9un8rNsu
+KNF+AksjoBXyOGVkCeoMbo4bF6BxyLObyavpw/LPh5aPgAIynplYb6LVAgMBAAGj
+QTA/MAwGA1UdEwQFMAMBAf8wLwYDVR0gBCgwJjAkBgRVHSAAMBwwGgYIKwYBBQUH
+AgEWDkNQUyB1cmkgc3RyaW5nMA0GCSqGSIb3DQEBCwUAA4IBAQBo3CLwvTakVDWs
+XUZz3ehGgk39KzmYOb3m9bBfMpOplDfE8Zaj8TDZZsxXpNCXT85GgbrAdr6pONQJ
+Mqd3TzTXCs6tmmIOVDToOj6nKtm2nNSf+1TUuLRgeavgCoicoQZOtW5tAehw/RTE
+4VQXSm+ZWotYwK1jvlHS0LaehUy53GsNxWBJHCc3exD+iyutXTZ89jczIKuWpEIN
+pTdI/EYVD2r6r/IITRnJpGjNXOhGB4zvgFlwv88GeF5lG6Si9YD+swO8JuJP35q6
+7cPA/vtrjoiyM3kXmmN1LZGIfEMKNwEcyVhvl+d6sReomI3HAKOj9IIG7umFKi6t
+axMwzK3Y
+-----END CERTIFICATE-----
diff --git a/tests/data_files/test-ca-any_policy_with_qualifier_ec.crt b/tests/data_files/test-ca-any_policy_with_qualifier_ec.crt
new file mode 100644
index 0000000..5e1491d
--- /dev/null
+++ b/tests/data_files/test-ca-any_policy_with_qualifier_ec.crt
@@ -0,0 +1,13 @@
+-----BEGIN CERTIFICATE-----
+MIIB6DCCAW+gAwIBAgIBADAKBggqhkjOPQQDAjA+MQswCQYDVQQGEwJOTDERMA8G
+A1UECgwIUG9sYXJTU0wxHDAaBgNVBAMME1BvbGFyc3NsIFRlc3QgRUMgQ0EwHhcN
+MTkwNDI4MTAxNjA1WhcNMjkwNDI4MTAxNjA1WjA+MQswCQYDVQQGEwJOTDERMA8G
+A1UECgwIUG9sYXJTU0wxHDAaBgNVBAMME1BvbGFyc3NsIFRlc3QgRUMgQ0EwdjAQ
+BgcqhkjOPQIBBgUrgQQAIgNiAATD2is0QTdYL4dW/vyJuilDS07gbsMOV1MzOVjU
+UrSRlTkLI99fFyRiSPwalSnOLC2HwohSgK/Waqsh3bjTHG5YuMrosmmO80GtKcO0
+X3WnR2/VGSlVaZpTOyC0ZhZgMx6jQTA/MAwGA1UdEwQFMAMBAf8wLwYDVR0gBCgw
+JjAkBgRVHSAAMBwwGgYIKwYBBQUHAgEWDkNQUyB1cmkgc3RyaW5nMAoGCCqGSM49
+BAMCA2cAMGQCMDvi5bBVplU3Gct+iYRmRW9ewty5b+1OX0ggzA+ExXpL1Obo6A16
+a2h1kb7Oy4+BSAIwXZHYb6OEWkOngISfwSZxDiiNXOTwvCu2/oFGC8xTENn0B88m
+2WwPzh4jnvXhNh0w
+-----END CERTIFICATE-----
diff --git a/tests/data_files/test-ca-multi_policy.crt b/tests/data_files/test-ca-multi_policy.crt
new file mode 100644
index 0000000..168e99f
--- /dev/null
+++ b/tests/data_files/test-ca-multi_policy.crt
@@ -0,0 +1,19 @@
+-----BEGIN CERTIFICATE-----
+MIIDGzCCAgOgAwIBAgIBADANBgkqhkiG9w0BAQsFADA7MQswCQYDVQQGEwJOTDER
+MA8GA1UECgwIUG9sYXJTU0wxGTAXBgNVBAMMEFBvbGFyU1NMIFRlc3QgQ0EwHhcN
+MTkwNDI4MTI1OTE5WhcNMjkwNDI4MTI1OTE5WjA7MQswCQYDVQQGEwJOTDERMA8G
+A1UECgwIUG9sYXJTU0wxGTAXBgNVBAMMEFBvbGFyU1NMIFRlc3QgQ0EwggEiMA0G
+CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDA3zf8F7vglp0/ht6WMn1EpRagzSHx
+mdTs6st8GFgIlKXsm8WL3xoemTiZhx57wI053zhdcHgH057Zk+i5clHFzqMwUqny
+50BwFMtEonILwuVA+T7lpg6z+exKY8C4KQB0nFc7qKUEkHHxvYPZP9al4jwqj+8n
+YMPGn8u67GB9t+aEMr5P+1gmIgNb1LTV+/Xjli5wwOQuvfwu7uJBVcA0Ln0kcmnL
+R7EUQIN9Z/SG9jGr8XmksrUuEvmEF/Bibyc+E1ixVA0hmnM3oTDPb5Lc9un8rNsu
+KNF+AksjoBXyOGVkCeoMbo4bF6BxyLObyavpw/LPh5aPgAIynplYb6LVAgMBAAGj
+KjAoMAwGA1UdEwQFMAMBAf8wGAYDVR0gBBEwDzAFBgMqAwQwBgYEVR0gADANBgkq
+hkiG9w0BAQsFAAOCAQEAPwOUmjnrcBA7dt5drCakEz9HOpj8gZQd1fyVGv221LCL
+h2W1Ngd2WlcADhPQcTdqNx4Dk+KPiBjPEooE9M7d3K33Qn/dVkmOYiW6E/4wU2tM
+cqFj7rg8Now4lBaEqEmBP+cpv+mYqavPcKy3tz4wn1SnA3MpT1hEazhNe4yInNAY
+4YqRBbWuBGkePjbce6Lf+rTfaA7kJnyuC9SHguQRmWtV3xzNzLUFn+V/jYSqYvYU
+2MjDFgCYCmW0xl5Wo8wMWWAvMbO2mRJ37OLUkSOkxgeEL6OihY1GPkbfxC2qV6mR
+4VjmfclwXumiDAvVLhW8hWjCxg8gc69G7kCkVbljLA==
+-----END CERTIFICATE-----
diff --git a/tests/data_files/test-ca-multi_policy_ec.crt b/tests/data_files/test-ca-multi_policy_ec.crt
new file mode 100644
index 0000000..70ea2eb
--- /dev/null
+++ b/tests/data_files/test-ca-multi_policy_ec.crt
@@ -0,0 +1,12 @@
+-----BEGIN CERTIFICATE-----
+MIIB0zCCAVigAwIBAgIBADAKBggqhkjOPQQDAjA+MQswCQYDVQQGEwJOTDERMA8G
+A1UECgwIUG9sYXJTU0wxHDAaBgNVBAMME1BvbGFyc3NsIFRlc3QgRUMgQ0EwHhcN
+MTkwNDI4MTI1OTUxWhcNMjkwNDI4MTI1OTUxWjA+MQswCQYDVQQGEwJOTDERMA8G
+A1UECgwIUG9sYXJTU0wxHDAaBgNVBAMME1BvbGFyc3NsIFRlc3QgRUMgQ0EwdjAQ
+BgcqhkjOPQIBBgUrgQQAIgNiAATD2is0QTdYL4dW/vyJuilDS07gbsMOV1MzOVjU
+UrSRlTkLI99fFyRiSPwalSnOLC2HwohSgK/Waqsh3bjTHG5YuMrosmmO80GtKcO0
+X3WnR2/VGSlVaZpTOyC0ZhZgMx6jKjAoMAwGA1UdEwQFMAMBAf8wGAYDVR0gBBEw
+DzAFBgMqAwQwBgYEVR0gADAKBggqhkjOPQQDAgNpADBmAjEAqyz2v+6i3xXF4qlr
+o89qxwlpIn9sR0xU+qo9tgcM6Fa7IDdAU1lhweN8MpkJTtrGAjEAmgNI/08M8n6/
+sMM0Xutt5u9EUHb+4y0uyOfYMcEPr+pCUM4GPxBP6RdqI8Wu9OQf
+-----END CERTIFICATE-----
diff --git a/tests/data_files/test-ca-unsupported_policy.crt b/tests/data_files/test-ca-unsupported_policy.crt
new file mode 100644
index 0000000..bf47d95
--- /dev/null
+++ b/tests/data_files/test-ca-unsupported_policy.crt
@@ -0,0 +1,19 @@
+-----BEGIN CERTIFICATE-----
+MIIDEzCCAfugAwIBAgIBADANBgkqhkiG9w0BAQsFADA7MQswCQYDVQQGEwJOTDER
+MA8GA1UECgwIUG9sYXJTU0wxGTAXBgNVBAMMEFBvbGFyU1NMIFRlc3QgQ0EwHhcN
+MTkwNDI4MTMwMDEzWhcNMjkwNDI4MTMwMDEzWjA7MQswCQYDVQQGEwJOTDERMA8G
+A1UECgwIUG9sYXJTU0wxGTAXBgNVBAMMEFBvbGFyU1NMIFRlc3QgQ0EwggEiMA0G
+CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDA3zf8F7vglp0/ht6WMn1EpRagzSHx
+mdTs6st8GFgIlKXsm8WL3xoemTiZhx57wI053zhdcHgH057Zk+i5clHFzqMwUqny
+50BwFMtEonILwuVA+T7lpg6z+exKY8C4KQB0nFc7qKUEkHHxvYPZP9al4jwqj+8n
+YMPGn8u67GB9t+aEMr5P+1gmIgNb1LTV+/Xjli5wwOQuvfwu7uJBVcA0Ln0kcmnL
+R7EUQIN9Z/SG9jGr8XmksrUuEvmEF/Bibyc+E1ixVA0hmnM3oTDPb5Lc9un8rNsu
+KNF+AksjoBXyOGVkCeoMbo4bF6BxyLObyavpw/LPh5aPgAIynplYb6LVAgMBAAGj
+IjAgMAwGA1UdEwQFMAMBAf8wEAYDVR0gBAkwBzAFBgMqAwQwDQYJKoZIhvcNAQEL
+BQADggEBAGvARX2orRXDmc2a7nSrbRFkdw/7qbL8Y+wLeM94SsZVgzGcxzRx1KvG
+2H5nBvPKgAzBqWVPU7eDPjrETIfsCxSu+yklBIg5QYRuOcprLtQPkFVfl+WLd31F
+lS1uMgZkahIr57aHoJLYPrEjW4CBHoliT8xfrvVZi4+ym7i/vFqXL7IJ+PIklNF8
+2/b4SAB9hRI5oPw1TV9Q0v2PqMXL/0cp/9Roe+H28Tcrody6jTtEdsU2wbaxhxMd
+YK4Ak1FkhKItumINbtAUnHgBVwO2IivGZgsYulC/9y1uh5NU1HxMzqh04UEMgre+
+9SeEjhwFkq16Njc5Cdt/7iFLeiaHcNU=
+-----END CERTIFICATE-----
diff --git a/tests/data_files/test-ca-unsupported_policy_ec.crt b/tests/data_files/test-ca-unsupported_policy_ec.crt
new file mode 100644
index 0000000..161e83c
--- /dev/null
+++ b/tests/data_files/test-ca-unsupported_policy_ec.crt
@@ -0,0 +1,12 @@
+-----BEGIN CERTIFICATE-----
+MIIByjCCAVCgAwIBAgIBADAKBggqhkjOPQQDAjA+MQswCQYDVQQGEwJOTDERMA8G
+A1UECgwIUG9sYXJTU0wxHDAaBgNVBAMME1BvbGFyc3NsIFRlc3QgRUMgQ0EwHhcN
+MTkwNDI4MTMwMDE5WhcNMjkwNDI4MTMwMDE5WjA+MQswCQYDVQQGEwJOTDERMA8G
+A1UECgwIUG9sYXJTU0wxHDAaBgNVBAMME1BvbGFyc3NsIFRlc3QgRUMgQ0EwdjAQ
+BgcqhkjOPQIBBgUrgQQAIgNiAATD2is0QTdYL4dW/vyJuilDS07gbsMOV1MzOVjU
+UrSRlTkLI99fFyRiSPwalSnOLC2HwohSgK/Waqsh3bjTHG5YuMrosmmO80GtKcO0
+X3WnR2/VGSlVaZpTOyC0ZhZgMx6jIjAgMAwGA1UdEwQFMAMBAf8wEAYDVR0gBAkw
+BzAFBgMqAwQwCgYIKoZIzj0EAwIDaAAwZQIwKUY3aTL6UR2H1Q1OzIJw7vxUso4P
+2PksCWb62kQeAnhYK85t1VGQiA49iHCXVKuXAjEAq+1qvlmwHX1E99ha/rvxcAYp
+UmxXLmSb53RT0NvhEKnUVGGUp2pBNAVVJOH+G0NI
+-----END CERTIFICATE-----
diff --git a/tests/data_files/test-ca.opensslconf b/tests/data_files/test-ca.opensslconf
index f66b39e..d2c5c06 100644
--- a/tests/data_files/test-ca.opensslconf
+++ b/tests/data_files/test-ca.opensslconf
@@ -12,6 +12,48 @@
 authorityKeyIdentifier=keyid:always,issuer:always
 basicConstraints = CA:true
 
+[othername_san]
+subjectAltName=otherName:1.3.6.1.5.5.7.8.4;SEQ:hw_module_name
+
+[unsupoported_othername_san]
+subjectAltName=otherName:1.2.3.4;UTF8:some other identifier
+
+[alt_names]
+DNS.1=example.com
+otherName.1=1.3.6.1.5.5.7.8.4;SEQ:hw_module_name
+DNS.2=example.net
+DNS.3=*.example.org
+
+[multiple_san]
+subjectAltName=@alt_names
+
+[hw_module_name]
+hwtype = OID:1.3.6.1.4.1.17.3
+hwserial = OCT:123456
+
+[v3_any_policy_ca]
+basicConstraints = CA:true
+certificatePolicies = 2.5.29.32.0
+
+[v3_any_policy_qualifier_ca]
+basicConstraints = CA:true
+certificatePolicies = @policy_info
+
+[v3_multi_policy_ca]
+basicConstraints = CA:true
+certificatePolicies = 1.2.3.4,2.5.29.32.0
+
+[v3_unsupported_policy_ca]
+basicConstraints = CA:true
+certificatePolicies = 1.2.3.4
+
+[policy_info]
+policyIdentifier = 2.5.29.32.0
+CPS.1 ="CPS uri string"
+
+[fan_cert]
+extendedKeyUsage = 1.3.6.1.4.1.45605.1
+
 [noext_ca]
 basicConstraints = CA:true
 
diff --git a/tests/suites/test_suite_x509parse.data b/tests/suites/test_suite_x509parse.data
index edd3a6f..ab3880a 100644
--- a/tests/suites/test_suite_x509parse.data
+++ b/tests/suites/test_suite_x509parse.data
@@ -94,6 +94,14 @@
 depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_ECDSA_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_SHA512_C
 x509_cert_info:"data_files/server5-sha512.crt":"cert. version     \: 3\nserial number     \: 15\nissuer name       \: C=NL, O=PolarSSL, CN=Polarssl Test EC CA\nsubject name      \: C=NL, O=PolarSSL, CN=localhost\nissued  on        \: 2013-09-24 16\:21\:27\nexpires on        \: 2023-09-22 16\:21\:27\nsigned using      \: ECDSA with SHA512\nEC key size       \: 256 bits\nbasic constraints \: CA=false\n"
 
+X509 Certificate information EC, SHA256 Digest, hardware module name SAN
+depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_ECDSA_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_SHA256_C
+x509_cert_info:"data_files/server5-othername.crt":"cert. version     \: 3\nserial number     \: 4D\nissuer name       \: C=UK, O=Mbed TLS, CN=Mbed TLS othername SAN\nsubject name      \: C=UK, O=Mbed TLS, CN=Mbed TLS othername SAN\nissued  on        \: 2019-03-24 09\:06\:02\nexpires on        \: 2029-03-21 09\:06\:02\nsigned using      \: ECDSA with SHA256\nEC key size       \: 256 bits\nsubject alt name  \:\n    otherName \:\n        hardware module name \:\n            hardware type          \: 1.3.6.1.4.1.17.3\n            hardware serial number \: 123456\n"
+
+X509 Certificate information EC, SHA256 Digest, Wisun Fan device
+depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_ECDSA_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_SHA256_C
+x509_cert_info:"data_files/server5-fan.crt":"cert. version     \: 3\nserial number     \: 4D\nissuer name       \: C=UK, O=Mbed TLS, CN=Mbed TLS FAN\nsubject name      \: C=UK, O=Mbed TLS, CN=Mbed TLS FAN\nissued  on        \: 2019-03-25 09\:03\:46\nexpires on        \: 2029-03-22 09\:03\:46\nsigned using      \: ECDSA with SHA256\nEC key size       \: 256 bits\next key usage     \: Wi-SUN Alliance Field Area Network (FAN)\n"
+
 X509 Certificate information, NS Cert Type
 depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_RSA_C:MBEDTLS_SHA1_C
 x509_cert_info:"data_files/server1.cert_type.crt":"cert. version     \: 3\nserial number     \: 01\nissuer name       \: C=NL, O=PolarSSL, CN=PolarSSL Test CA\nsubject name      \: C=NL, O=PolarSSL, CN=PolarSSL Server 1\nissued  on        \: 2011-02-12 14\:44\:06\nexpires on        \: 2021-02-12 14\:44\:06\nsigned using      \: RSA with SHA1\nRSA key size      \: 2048 bits\nbasic constraints \: CA=false\ncert. type        \: SSL Server\n"
@@ -108,11 +116,47 @@
 
 X509 Certificate information, Subject Alt Name
 depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_RSA_C:MBEDTLS_SHA1_C
-x509_cert_info:"data_files/cert_example_multi.crt":"cert. version     \: 3\nserial number     \: 11\nissuer name       \: C=NL, O=PolarSSL, CN=PolarSSL Test CA\nsubject name      \: C=NL, O=PolarSSL, CN=www.example.com\nissued  on        \: 2012-05-10 13\:23\:41\nexpires on        \: 2022-05-11 13\:23\:41\nsigned using      \: RSA with SHA1\nRSA key size      \: 2048 bits\nbasic constraints \: CA=false\nsubject alt name  \: example.com, example.net, *.example.org\n"
+x509_cert_info:"data_files/cert_example_multi.crt":"cert. version     \: 3\nserial number     \: 11\nissuer name       \: C=NL, O=PolarSSL, CN=PolarSSL Test CA\nsubject name      \: C=NL, O=PolarSSL, CN=www.example.com\nissued  on        \: 2012-05-10 13\:23\:41\nexpires on        \: 2022-05-11 13\:23\:41\nsigned using      \: RSA with SHA1\nRSA key size      \: 2048 bits\nbasic constraints \: CA=false\nsubject alt name  \:\n    dNSName \: example.com\n    dNSName \: example.net\n    dNSName \: *.example.org\n"
+
+X509 Certificate information, Multiple different Subject Alt Name
+depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_ECDSA_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_SHA256_C
+x509_cert_info:"data_files/multiple_san.crt":"cert. version     \: 3\nserial number     \: 04\nissuer name       \: C=UK, O=Mbed TLS, CN=Mbed TLS multiple othername SAN\nsubject name      \: C=UK, O=Mbed TLS, CN=Mbed TLS multiple othername SAN\nissued  on        \: 2019-04-22 16\:10\:48\nexpires on        \: 2029-04-19 16\:10\:48\nsigned using      \: ECDSA with SHA256\nEC key size       \: 256 bits\nsubject alt name  \:\n    dNSName \: example.com\n    otherName \:\n        hardware module name \:\n            hardware type          \: 1.3.6.1.4.1.17.3\n            hardware serial number \: 123456\n    dNSName \: example.net\n    dNSName \: *.example.org\n"
 
 X509 Certificate information, Subject Alt Name + Key Usage
 depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_RSA_C:MBEDTLS_SHA1_C
-x509_cert_info:"data_files/cert_example_multi_nocn.crt":"cert. version     \: 3\nserial number     \: F7\:C6\:7F\:F8\:E9\:A9\:63\:F9\nissuer name       \: C=NL\nsubject name      \: C=NL\nissued  on        \: 2014-01-22 10\:04\:33\nexpires on        \: 2024-01-22 10\:04\:33\nsigned using      \: RSA with SHA1\nRSA key size      \: 1024 bits\nbasic constraints \: CA=false\nsubject alt name  \: www.shotokan-braunschweig.de, www.massimo-abate.eu\nkey usage         \: Digital Signature, Non Repudiation, Key Encipherment\n"
+x509_cert_info:"data_files/cert_example_multi_nocn.crt":"cert. version     \: 3\nserial number     \: F7\:C6\:7F\:F8\:E9\:A9\:63\:F9\nissuer name       \: C=NL\nsubject name      \: C=NL\nissued  on        \: 2014-01-22 10\:04\:33\nexpires on        \: 2024-01-22 10\:04\:33\nsigned using      \: RSA with SHA1\nRSA key size      \: 1024 bits\nbasic constraints \: CA=false\nsubject alt name  \:\n    dNSName \: www.shotokan-braunschweig.de\n    dNSName \: www.massimo-abate.eu\n    <unsupported>\n    <unsupported>\nkey usage         \: Digital Signature, Non Repudiation, Key Encipherment\n"
+
+X509 Certificate information, RSA Certificate Policy any
+depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_RSA_C:MBEDTLS_SHA256_C
+x509_cert_info:"data_files/test-ca-any_policy.crt":"cert. version     \: 3\nserial number     \: 00\nissuer name       \: C=NL, O=PolarSSL, CN=PolarSSL Test CA\nsubject name      \: C=NL, O=PolarSSL, CN=PolarSSL Test CA\nissued  on        \: 2019-03-21 16\:40\:59\nexpires on        \: 2029-03-21 16\:40\:59\nsigned using      \: RSA with SHA-256\nRSA key size      \: 2048 bits\nbasic constraints \: CA=true\ncertificate policies \: Any Policy\n"
+
+X509 Certificate information, ECDSA Certificate Policy any
+depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_ECDSA_C:MBEDTLS_ECP_DP_SECP384R1_ENABLED:MBEDTLS_SHA256_C
+x509_cert_info:"data_files/test-ca-any_policy_ec.crt":"cert. version     \: 3\nserial number     \: 00\nissuer name       \: C=NL, O=PolarSSL, CN=Polarssl Test EC CA\nsubject name      \: C=NL, O=PolarSSL, CN=Polarssl Test EC CA\nissued  on        \: 2019-03-25 09\:02\:45\nexpires on        \: 2029-03-25 09\:02\:45\nsigned using      \: ECDSA with SHA256\nEC key size       \: 384 bits\nbasic constraints \: CA=true\ncertificate policies \: Any Policy\n"
+
+X509 Certificate information, RSA Certificate Policy any with qualifier
+depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_RSA_C:MBEDTLS_SHA256_C
+x509_cert_info:"data_files/test-ca-any_policy_with_qualifier.crt":"cert. version     \: 3\nserial number     \: 00\nissuer name       \: C=NL, O=PolarSSL, CN=PolarSSL Test CA\nsubject name      \: C=NL, O=PolarSSL, CN=PolarSSL Test CA\nissued  on        \: 2019-04-28 13\:14\:31\nexpires on        \: 2029-04-28 13\:14\:31\nsigned using      \: RSA with SHA-256\nRSA key size      \: 2048 bits\nbasic constraints \: CA=true\ncertificate policies \: Any Policy\n"
+
+X509 Certificate information, ECDSA Certificate Policy any  with qualifier
+depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_ECDSA_C:MBEDTLS_ECP_DP_SECP384R1_ENABLED:MBEDTLS_SHA256_C
+x509_cert_info:"data_files/test-ca-any_policy_with_qualifier_ec.crt":"cert. version     \: 3\nserial number     \: 00\nissuer name       \: C=NL, O=PolarSSL, CN=Polarssl Test EC CA\nsubject name      \: C=NL, O=PolarSSL, CN=Polarssl Test EC CA\nissued  on        \: 2019-04-28 10\:16\:05\nexpires on        \: 2029-04-28 10\:16\:05\nsigned using      \: ECDSA with SHA256\nEC key size       \: 384 bits\nbasic constraints \: CA=true\ncertificate policies \: Any Policy\n"
+
+X509 Certificate information, RSA Certificate multiple Policies
+depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_RSA_C:MBEDTLS_SHA256_C
+x509_cert_info:"data_files/test-ca-multi_policy.crt":"cert. version     \: 3\nserial number     \: 00\nissuer name       \: C=NL, O=PolarSSL, CN=PolarSSL Test CA\nsubject name      \: C=NL, O=PolarSSL, CN=PolarSSL Test CA\nissued  on        \: 2019-04-28 12\:59\:19\nexpires on        \: 2029-04-28 12\:59\:19\nsigned using      \: RSA with SHA-256\nRSA key size      \: 2048 bits\nbasic constraints \: CA=true\ncertificate policies \: ???, Any Policy\n"
+
+X509 Certificate information, ECDSA Certificate multiple Policies
+depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_ECDSA_C:MBEDTLS_ECP_DP_SECP384R1_ENABLED:MBEDTLS_SHA256_C
+x509_cert_info:"data_files/test-ca-multi_policy_ec.crt":"cert. version     \: 3\nserial number     \: 00\nissuer name       \: C=NL, O=PolarSSL, CN=Polarssl Test EC CA\nsubject name      \: C=NL, O=PolarSSL, CN=Polarssl Test EC CA\nissued  on        \: 2019-04-28 12\:59\:51\nexpires on        \: 2029-04-28 12\:59\:51\nsigned using      \: ECDSA with SHA256\nEC key size       \: 384 bits\nbasic constraints \: CA=true\ncertificate policies \: ???, Any Policy\n"
+
+X509 Certificate information, RSA Certificate unsupported policy
+depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_RSA_C:MBEDTLS_SHA256_C
+x509_cert_info:"data_files/test-ca-unsupported_policy.crt":"cert. version     \: 3\nserial number     \: 00\nissuer name       \: C=NL, O=PolarSSL, CN=PolarSSL Test CA\nsubject name      \: C=NL, O=PolarSSL, CN=PolarSSL Test CA\nissued  on        \: 2019-04-28 13\:00\:13\nexpires on        \: 2029-04-28 13\:00\:13\nsigned using      \: RSA with SHA-256\nRSA key size      \: 2048 bits\nbasic constraints \: CA=true\ncertificate policies \: ???\n"
+
+X509 Certificate information, ECDSA Certificate unsupported policy
+depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_ECDSA_C:MBEDTLS_ECP_DP_SECP384R1_ENABLED:MBEDTLS_SHA256_C
+x509_cert_info:"data_files/test-ca-unsupported_policy_ec.crt":"cert. version     \: 3\nserial number     \: 00\nissuer name       \: C=NL, O=PolarSSL, CN=Polarssl Test EC CA\nsubject name      \: C=NL, O=PolarSSL, CN=Polarssl Test EC CA\nissued  on        \: 2019-04-28 13\:00\:19\nexpires on        \: 2029-04-28 13\:00\:19\nsigned using      \: ECDSA with SHA256\nEC key size       \: 384 bits\nbasic constraints \: CA=true\ncertificate policies \: ???\n"
 
 X509 Certificate information, Key Usage + Extended Key Usage
 depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_RSA_C:MBEDTLS_SHA256_C
@@ -128,11 +172,31 @@
 
 X509 Certificate information Bitstring in subject name
 depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_RSA_C:MBEDTLS_SHA1_C
-x509_cert_info:"data_files/bitstring-in-dn.pem":"cert. version     \: 3\nserial number     \: 02\nissuer name       \: CN=Test CA 01, ST=Ecnivorp, C=XX, emailAddress=tca@example.com, O=Test CA Authority\nsubject name      \: C=XX, O=tca, ST=Ecnivorp, OU=TCA, CN=Client, emailAddress=client@example.com, serialNumber=7101012255, uniqueIdentifier=?7101012255\nissued  on        \: 2015-03-11 12\:06\:51\nexpires on        \: 2025-03-08 12\:06\:51\nsigned using      \: RSA with SHA1\nRSA key size      \: 2048 bits\nbasic constraints \: CA=false\nsubject alt name  \: \next key usage     \: TLS Web Client Authentication\n"
+x509_cert_info:"data_files/bitstring-in-dn.pem":"cert. version     \: 3\nserial number     \: 02\nissuer name       \: CN=Test CA 01, ST=Ecnivorp, C=XX, emailAddress=tca@example.com, O=Test CA Authority\nsubject name      \: C=XX, O=tca, ST=Ecnivorp, OU=TCA, CN=Client, emailAddress=client@example.com, serialNumber=7101012255, uniqueIdentifier=?7101012255\nissued  on        \: 2015-03-11 12\:06\:51\nexpires on        \: 2025-03-08 12\:06\:51\nsigned using      \: RSA with SHA1\nRSA key size      \: 2048 bits\nbasic constraints \: CA=false\nsubject alt name  \:\n    <unsupported>\next key usage     \: TLS Web Client Authentication\n"
 
 X509 certificate v1 with extension
 depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_RSA_C:MBEDTLS_X509_ALLOW_EXTENSIONS_NON_V3:MBEDTLS_SHA1_C
-x509_cert_info:"data_files/cert_v1_with_ext.crt":"cert. version     \: 1\nserial number     \: BD\:ED\:44\:C7\:D2\:3E\:C2\:A4\nissuer name       \: C=XX, ST=XX, L=XX, O=XX, OU=XX, emailAddress=admin@identity-check.org, CN=identity-check.org\nsubject name      \: C=XX, ST=XX, L=XX, O=XX, OU=XX, emailAddress=admin@identity-check.org, CN=identity-check.org\nissued  on        \: 2013-07-04 16\:17\:02\nexpires on        \: 2014-07-04 16\:17\:02\nsigned using      \: RSA with SHA1\nRSA key size      \: 2048 bits\nsubject alt name  \: identity-check.org, www.identity-check.org\n"
+x509_cert_info:"data_files/cert_v1_with_ext.crt":"cert. version     \: 1\nserial number     \: BD\:ED\:44\:C7\:D2\:3E\:C2\:A4\nissuer name       \: C=XX, ST=XX, L=XX, O=XX, OU=XX, emailAddress=admin@identity-check.org, CN=identity-check.org\nsubject name      \: C=XX, ST=XX, L=XX, O=XX, OU=XX, emailAddress=admin@identity-check.org, CN=identity-check.org\nissued  on        \: 2013-07-04 16\:17\:02\nexpires on        \: 2014-07-04 16\:17\:02\nsigned using      \: RSA with SHA1\nRSA key size      \: 2048 bits\nsubject alt name  \:\n    dNSName \: identity-check.org\n    dNSName \: www.identity-check.org\n"
+
+X509 SAN parsing otherName
+depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_ECDSA_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_SHA256_C
+x509_parse_san:"data_files/server5-othername.crt":"type \: 0\notherName \: hardware module name \: hardware type \: 1.3.6.1.4.1.17.3, hardware serial number \: 123456\n"
+
+X509 SAN parsing dNSName
+depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_RSA_C:MBEDTLS_SHA1_C
+x509_parse_san:"data_files/cert_example_multi.crt":"type \: 2\ndNSName \: example.com\ntype \: 2\ndNSName \: example.net\ntype \: 2\ndNSName \: *.example.org\n"
+
+X509 SAN parsing  Multiple different types
+depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_ECDSA_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_SHA256_C
+x509_parse_san:"data_files/multiple_san.crt":"type \: 2\ndNSName \: example.com\ntype \: 0\notherName \: hardware module name \: hardware type \: 1.3.6.1.4.1.17.3, hardware serial number \: 123456\ntype \: 2\ndNSName \: example.net\ntype \: 2\ndNSName \: *.example.org\n"
+
+X509 SAN parsing, no subject alt name
+depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_RSA_C:MBEDTLS_SHA256_C:MBEDTLS_ECDSA_C
+x509_parse_san:"data_files/server4.crt":""
+
+X509 SAN parsing, unsupported otherName name
+depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_ECDSA_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_SHA256_C
+x509_parse_san:"data_files/server5-unsupported_othername.crt":""
 
 X509 CRL information #1
 depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_SHA1_C:MBEDTLS_RSA_C
@@ -1134,6 +1198,22 @@
 depends_on:MBEDTLS_RSA_C:MBEDTLS_MD2_C
 x509parse_crt:"30819030818da0030201028204deadbeef300d06092a864886f70d0101020500300c310a30080600130454657374301c170c303930313031303030303030170c303931323331323335393539300c310a30080600130454657374302a300d06092A864886F70D010101050003190030160210ffffffffffffffffffffffffffffffff0202ffffa101aaa201bba3043002310000":"":MBEDTLS_ERR_X509_INVALID_EXTENSIONS + MBEDTLS_ERR_ASN1_UNEXPECTED_TAG
 
+X509 Certificate ASN1 (TBSCertificate v3, ext CertificatePolicies tag, bool len missing)
+depends_on:MBEDTLS_RSA_C:MBEDTLS_MD2_C
+x509parse_crt:"308198308195a0030201028204deadbeef300d06092a864886f70d0101020500300c310a30080600130454657374301c170c303930313031303030303030170c303931323331323335393539300c310a30080600130454657374302a300d06092A864886F70D010101050003190030160210ffffffffffffffffffffffffffffffff0202ffffa101aaa201bba30c300730050603551d2001010100":"":MBEDTLS_ERR_X509_INVALID_EXTENSIONS + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH
+
+X509 Certificate ASN1 (TBSCertificate v3, ext CertificatePolicies tag, data missing)
+depends_on:MBEDTLS_RSA_C:MBEDTLS_MD2_C
+x509parse_crt:"308198308195a0030201028204deadbeef300d06092a864886f70d0101020500300c310a30080600130454657374301c170c303930313031303030303030170c303931323331323335393539300c310a30080600130454657374302a300d06092A864886F70D010101050003190030160210ffffffffffffffffffffffffffffffff0202ffffa101aaa201bba30b300930070603551d20040001010100":"":MBEDTLS_ERR_X509_INVALID_EXTENSIONS + MBEDTLS_ERR_ASN1_OUT_OF_DATA
+
+X509 Certificate ASN1 (TBSCertificate v3, ext CertificatePolicies tag, data not oid)
+depends_on:MBEDTLS_RSA_C:MBEDTLS_MD2_C
+x509parse_crt:"3081bc3081b9a0030201028204deadbeef300d06092a864886f70d0101020500300c310a30080600130454657374301c170c303930313031303030303030170c303931323331323335393539300c310a30080600130454657374302a300d06092A864886F70D010101050003190030160210ffffffffffffffffffffffffffffffff0202ffffa101aaa201bba32e302c30290603551d2004223020301EA01C06082B06010505070804A010300E06082B060104010901030402022201010100":"":MBEDTLS_ERR_X509_INVALID_EXTENSIONS + MBEDTLS_ERR_ASN1_UNEXPECTED_TAG
+
+X509 Certificate ASN1 (TBSCertificate v3, ext CertificatePolicies tag, qualifier not complete)
+depends_on:MBEDTLS_RSA_C:MBEDTLS_MD2_C
+x509parse_crt:"308198308195a0030201028204deadbeef300d06092a864886f70d0101020500300c310a30080600130454657374301c170c303930313031303030303030170c303931323331323335393539300c310a30080600130454657374302a300d06092A864886F70D010101050003190030160210ffffffffffffffffffffffffffffffff0202ffffa101aaa201bba30c300a301F0603551d2004183020301F0603551D200418301630140604551D2000300C300A06082B0601050507020101010100":"":MBEDTLS_ERR_X509_INVALID_EXTENSIONS + MBEDTLS_ERR_ASN1_OUT_OF_DATA
+
 X509 Certificate ASN1 (TBSCertificate v3, ext BasicContraint tag, bool len missing)
 depends_on:MBEDTLS_RSA_C:MBEDTLS_MD2_C
 x509parse_crt:"308198308195a0030201028204deadbeef300d06092a864886f70d0101020500300c310a30080600130454657374301c170c303930313031303030303030170c303931323331323335393539300c310a30080600130454657374302a300d06092A864886F70D010101050003190030160210ffffffffffffffffffffffffffffffff0202ffffa101aaa201bba30c300a30060603551d1301010100":"":MBEDTLS_ERR_X509_INVALID_EXTENSIONS + MBEDTLS_ERR_ASN1_OUT_OF_DATA
diff --git a/tests/suites/test_suite_x509parse.function b/tests/suites/test_suite_x509parse.function
index b11ab84..b4e9802 100644
--- a/tests/suites/test_suite_x509parse.function
+++ b/tests/suites/test_suite_x509parse.function
@@ -219,6 +219,79 @@
 
     return( 0 );
 }
+
+int verify_parse_san( mbedtls_x509_subject_alternative_name *san,
+                      char **buf, size_t *size )
+{
+    int ret;
+    size_t i;
+    char *p = *buf;
+    size_t n = *size;
+
+    ret = mbedtls_snprintf( p, n, "type : %u", san->type );
+    MBEDTLS_X509_SAFE_SNPRINTF;
+
+    switch( san->type )
+    {
+       case( MBEDTLS_X509_SAN_OTHER_NAME ):
+           ret = mbedtls_snprintf( p, n, "\notherName :");
+           MBEDTLS_X509_SAFE_SNPRINTF;
+
+           if( MBEDTLS_OID_CMP( MBEDTLS_OID_ON_HW_MODULE_NAME,
+                    &san->san.other_name.value.hardware_module_name.oid ) != 0 )
+           {
+               ret = mbedtls_snprintf( p, n, " hardware module name :" );
+               MBEDTLS_X509_SAFE_SNPRINTF;
+               ret = mbedtls_snprintf( p, n, " hardware type : " );
+               MBEDTLS_X509_SAFE_SNPRINTF;
+
+               ret = mbedtls_oid_get_numeric_string( p, n,
+                          &san->san.other_name.value.hardware_module_name.oid );
+               MBEDTLS_X509_SAFE_SNPRINTF;
+
+               ret = mbedtls_snprintf( p, n, ", hardware serial number : " );
+               MBEDTLS_X509_SAFE_SNPRINTF;
+
+               if( san->san.other_name.value.hardware_module_name.val.len >= n )
+               {
+                   *p = '\0';
+                   return( MBEDTLS_ERR_X509_BUFFER_TOO_SMALL );
+               }
+
+               for( i=0; i < san->san.other_name.value.hardware_module_name.val.len; i++ )
+               {
+                   *p++ = san->san.other_name.value.hardware_module_name.val.p[i];
+               }
+               n -= san->san.other_name.value.hardware_module_name.val.len;
+            }
+        break;/* MBEDTLS_OID_ON_HW_MODULE_NAME */
+        case(  MBEDTLS_X509_SAN_DNS_NAME ):
+            ret = mbedtls_snprintf( p, n, "\ndNSName : " );
+            MBEDTLS_X509_SAFE_SNPRINTF;
+            if( san->san.unstructured_name.len >= n )
+            {
+                *p = '\0';
+                return( MBEDTLS_ERR_X509_BUFFER_TOO_SMALL );
+            }
+            n -= san->san.unstructured_name.len;
+            for( i = 0; i < san->san.unstructured_name.len; i++ )
+                *p++ = san->san.unstructured_name.p[i];
+        break;/* MBEDTLS_X509_SAN_DNS_NAME */
+
+        default:
+        /*
+         * Should not happen.
+         */
+        return( -1 );
+    }
+    ret = mbedtls_snprintf( p, n, "\n" );
+    MBEDTLS_X509_SAFE_SNPRINTF;
+
+    *size = n;
+    *buf = p;
+
+    return( 0 );
+}
 #endif /* MBEDTLS_X509_CRT_PARSE_C */
 /* END_HEADER */
 
@@ -228,6 +301,46 @@
  */
 
 /* BEGIN_CASE depends_on:MBEDTLS_FS_IO:MBEDTLS_X509_CRT_PARSE_C */
+void x509_parse_san( char * crt_file, char * result_str )
+{
+    int ret;
+    mbedtls_x509_crt   crt;
+    mbedtls_x509_subject_alternative_name san;
+    mbedtls_x509_sequence *cur = NULL;
+    char buf[2000];
+    char *p = buf;
+    size_t n = sizeof( buf );
+
+    mbedtls_x509_crt_init( &crt );
+    memset( buf, 0, 2000 );
+
+    TEST_ASSERT( mbedtls_x509_crt_parse_file( &crt, crt_file ) == 0 );
+
+    if( crt.ext_types & MBEDTLS_X509_EXT_SUBJECT_ALT_NAME )
+    {
+        cur = &crt.subject_alt_names;
+        while( cur != NULL )
+        {
+            ret = mbedtls_x509_parse_subject_alt_name( &cur->buf, &san );
+            TEST_ASSERT( ret == 0 || ret == MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE );
+            /*
+             * If san type not supported, ignore.
+             */
+            if( ret == 0)
+                TEST_ASSERT( verify_parse_san( &san, &p, &n ) == 0 );
+            cur = cur->next;
+        }
+    }
+
+    TEST_ASSERT( strcmp( buf, result_str ) == 0 );
+
+exit:
+
+    mbedtls_x509_crt_free( &crt );
+}
+/* END_CASE */
+
+/* BEGIN_CASE depends_on:MBEDTLS_FS_IO:MBEDTLS_X509_CRT_PARSE_C */
 void x509_cert_info( char * crt_file, char * result_str )
 {
     mbedtls_x509_crt   crt;