Change mbedtls_x509_subject_alternative_name

Make `mbedtls_x509_subject_alternative_name` to be a single item
rather than a list. Adapt the subject alternative name parsing function,
to receive a signle `mbedtls_x509_buf` item from the subject_alt_names
sequence of the certificate.
diff --git a/include/mbedtls/x509_crt.h b/include/mbedtls/x509_crt.h
index dbfaf9c..b321c42 100644
--- a/include/mbedtls/x509_crt.h
+++ b/include/mbedtls/x509_crt.h
@@ -107,6 +107,11 @@
  */
 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
     {
@@ -133,7 +138,6 @@
         mbedtls_x509_buf   unstructured_name; /**< The buffer for the un constructed types. Only dnsName currently supported */
     }
     san; /**< A union of the supported SAN types */
-    struct mbedtls_x509_subject_alternative_name *next; /**< The next SAN in the list. */
 }
 mbedtls_x509_subject_alternative_name;
 
@@ -389,24 +393,30 @@
 
 #endif /* MBEDTLS_FS_IO */
 /**
- * \brief          Parses the subject alternative name list of a given certificate.
+ * \brief          Parses a subject alternative name item
+ *                 to an identified structure;
  *
- * \param crt      The X509 certificate to parse.
- * \param san      A list holding the parsed certificate.
+ * \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           Any unsupported san type is ignored.
+ * \note           This function should be called on a single raw data of
+ *                 subject alternative name. For example, after successfult
+ *                 certificate parsing, one must iterate on every item in the
+ *                 \p crt->subject_alt_names sequence, and send it as parameter
+ *                 to this function.
  *
- * \note           The function allocates a list of mbedtls_x509_subject_alternative_name
- *                 and it is the caller's responsibility to free it.
- *
- * \return         Zero for success and negative
- *                 value for any other failure.
+ * \return         \c 0 on success
+ * \return         #MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE for an unsupported
+ *                 SAN type
+ * \return         Negative value for any other failure.
  */
-int mbedtls_x509_parse_subject_alternative_name( const mbedtls_x509_crt *crt,
-                                                 mbedtls_x509_subject_alternative_name **san );
+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 9777726..cce230b 100644
--- a/library/x509_crt.c
+++ b/library/x509_crt.c
@@ -1632,6 +1632,12 @@
         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 )
@@ -1648,31 +1654,30 @@
     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 )
-        goto cleanup;
+        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;
     other_name->value.hardware_module_name.next = NULL;
     other_name->value.hardware_module_name.next_merged = 0;
-
     p += len;
     if( p != end )
     {
-        ret = MBEDTLS_ERR_ASN1_LENGTH_MISMATCH;
+        mbedtls_platform_zeroize( other_name,
+                                  sizeof( other_name ) );
+        return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS +
+                MBEDTLS_ERR_ASN1_LENGTH_MISMATCH );
     }
-
-cleanup:
-
-    if( ret != 0 )
-    {
-        memset( other_name, 0, sizeof( *other_name ) );
-        return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret );
-    }
-
     return( 0 );
 }
 
@@ -1686,107 +1691,91 @@
     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 )
     {
-        switch( cur->buf.tag &
-                ( MBEDTLS_ASN1_TAG_CLASS_MASK | MBEDTLS_ASN1_TAG_VALUE_MASK ) )
+        memset( &san, 0, sizeof( san ) );
+        parse_ret = mbedtls_x509_parse_subject_alt_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_ASN1_CONTEXT_SPECIFIC | MBEDTLS_X509_SAN_OTHER_NAME ):
+            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 )
                 {
-                    mbedtls_x509_san_other_name other_name;
-
-                    int parse_ret = x509_get_other_name( &cur->buf,
-                                                         &other_name );
-
-                    ret = mbedtls_snprintf( p, n, "\n%s    otherName :",
-                                            prefix );
+                    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;
 
-                    if( parse_ret != 0 )
-                    {
-                        if( ret == MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE )
-                        {
-                            ret = mbedtls_snprintf( p, n, " <unsupported>" );
-                            MBEDTLS_X509_SAFE_SNPRINTF;
-                        }
-                        else
-                        {
-                            ret = mbedtls_snprintf( p, n, " <malformed>" );
-                            MBEDTLS_X509_SAFE_SNPRINTF;
-                        }
+                    ret = mbedtls_oid_get_numeric_string( p, n, &other_name->value.hardware_module_name.oid );
+                    MBEDTLS_X509_SAFE_SNPRINTF;
 
-                        break;
+                    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 );
                     }
 
-                    if( MBEDTLS_OID_CMP( MBEDTLS_OID_ON_HW_MODULE_NAME,
-                                 &other_name.value.hardware_module_name.oid )
-                        != 0 )
+                    for( i = 0; i < other_name->value.hardware_module_name.val.len; i++ )
                     {
-                        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;
+                        *p++ = other_name->value.hardware_module_name.val.p[i];
+                    }
+                    n -= other_name->value.hardware_module_name.val.len;
 
-                        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 );
-                        }
-
-                        for( i = 0;
-                             i < other_name.value.hardware_module_name.val.len;
-                             i++ )
-                        {
-                            *p++ =
-                                other_name.value.hardware_module_name.val.p[i];
-                        }
-                        n -= other_name.value.hardware_module_name.val.len;
-
-                    }/* MBEDTLS_OID_ON_HW_MODULE_NAME */
-
-                }
-                break;
+                }/* MBEDTLS_OID_ON_HW_MODULE_NAME */
+            }
+            break;
 
             /*
              * dNSName
              */
-            case( MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_X509_SAN_DNS_NAME ):
+            case( MBEDTLS_X509_SAN_DNS_NAME ):
+            {
                 ret = mbedtls_snprintf( p, n, "\n%s    dNSName : ", prefix );
                 MBEDTLS_X509_SAFE_SNPRINTF;
-
-                if( cur->buf.len >= n )
+                if( san.san.unstructured_name.len >= n )
                 {
                     *p = '\0';
                     return( MBEDTLS_ERR_X509_BUFFER_TOO_SMALL );
                 }
-
-                n -= cur->buf.len;
-                for( i = 0; i < cur->buf.len; i++ )
-                    *p++ = cur->buf.p[i];
-
-                break;
+                n -= san.san.unstructured_name.len;
+                for( i = 0; i < san.san.unstructured_name.len; i++ )
+                    *p++ = san.san.unstructured_name.p[i];
+            }
+            break;
 
             /*
-             * Type not supported.
+             * Type not supported, skip item.
              */
             default:
                 ret = mbedtls_snprintf( p, n, "\n%s    <unsupported>", prefix );
@@ -1805,102 +1794,53 @@
     return( 0 );
 }
 
-int mbedtls_x509_parse_subject_alternative_name( const mbedtls_x509_crt *crt,
-                                                 mbedtls_x509_subject_alternative_name **san )
+int mbedtls_x509_parse_subject_alt_name( const mbedtls_x509_buf *san_buf,
+                                         mbedtls_x509_subject_alternative_name *san )
 {
     int ret;
-    const mbedtls_x509_sequence *cur = &crt->subject_alt_names;
-    mbedtls_x509_subject_alternative_name *cur_san = *san, *prev_san = NULL;
-
-    if( crt->ext_types & MBEDTLS_X509_EXT_SUBJECT_ALT_NAME )
+    switch( san_buf->tag &
+            ( MBEDTLS_ASN1_TAG_CLASS_MASK |
+              MBEDTLS_ASN1_TAG_VALUE_MASK ) )
     {
-        if( cur_san != NULL )
+        /*
+         * otherName
+         */
+        case( MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_X509_SAN_OTHER_NAME ):
         {
-            return( MBEDTLS_ERR_X509_BAD_INPUT_DATA );
+            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;
 
-        while( cur != NULL )
+        /*
+         * dNSName
+         */
+        case( MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_X509_SAN_DNS_NAME ):
         {
-            switch( cur->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;
+            memset( san, 0, sizeof( mbedtls_x509_subject_alternative_name ) );
+            san->type = MBEDTLS_X509_SAN_DNS_NAME;
 
-                    ret = x509_get_other_name( &cur->buf, &other_name );
-                    if( ret != 0 )
-                    {
-                        /*
-                         * In case MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE is returned,
-                         * then the "otherName" is of an unsupported type. Ignore.
-                         */
-                        if( ret != MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE )
-                            return MBEDTLS_ERR_X509_INVALID_FORMAT;
+            memcpy( &san->san.unstructured_name,
+                    san_buf, sizeof( *san_buf ) );
 
-                        cur = cur->next;
-                        continue;
-                    }
+        }
+        break;
 
-                    cur_san = mbedtls_calloc( 1, sizeof( mbedtls_x509_subject_alternative_name ) );
-                    if( cur_san == NULL )
-                        return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS +
-                                MBEDTLS_ERR_ASN1_ALLOC_FAILED );
-
-                    if( prev_san != NULL )
-                        prev_san->next = cur_san;
-
-                    cur_san->type = MBEDTLS_X509_SAN_OTHER_NAME;
-                    memcpy( &cur_san->san.other_name,
-                            &other_name, sizeof( other_name ) );
-
-                }
-                break;
-
-                /*
-                 * dNSName
-                 */
-                case( MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_X509_SAN_DNS_NAME ):
-                {
-                    cur_san = mbedtls_calloc( 1, sizeof( mbedtls_x509_subject_alternative_name ) );
-                    if( cur_san == NULL )
-                        return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS +
-                                MBEDTLS_ERR_ASN1_ALLOC_FAILED );
-
-                    if( prev_san != NULL )
-                        prev_san->next = cur_san;
-
-                    cur_san->type = MBEDTLS_X509_SAN_DNS_NAME;
-
-                    memcpy( &cur_san->san.unstructured_name,
-                            &cur->buf, sizeof( cur->buf ) );
-
-                }
-                break;
-
-                /*
-                 * Type not supported, skip item.
-                 */
-                default:
-                    break;
-            }
-
-            if( *san == NULL )
-                *san = cur_san;
-
-            if( cur_san != NULL )
-            {
-                prev_san = cur_san;
-                cur_san = cur_san->next;
-            }
-
-            cur = cur->next;
-        }/* while( cur != NULL ) */
-    }/* crt->ext_types & MBEDTLS_X509_EXT_SUBJECT_ALT_NAME */
+        /*
+         * Type not supported
+         */
+        default:
+            return( MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE );
+    }
     return( 0 );
 }
 
diff --git a/tests/suites/test_suite_x509parse.function b/tests/suites/test_suite_x509parse.function
index beec52c..b4e9802 100644
--- a/tests/suites/test_suite_x509parse.function
+++ b/tests/suites/test_suite_x509parse.function
@@ -303,8 +303,10 @@
 /* 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 *cur, *next, *san = NULL;
+    mbedtls_x509_subject_alternative_name san;
+    mbedtls_x509_sequence *cur = NULL;
     char buf[2000];
     char *p = buf;
     size_t n = sizeof( buf );
@@ -313,24 +315,27 @@
     memset( buf, 0, 2000 );
 
     TEST_ASSERT( mbedtls_x509_crt_parse_file( &crt, crt_file ) == 0 );
-    TEST_ASSERT( mbedtls_x509_parse_subject_alternative_name( &crt, &san ) == 0 );
-    cur = san;
-    while( cur != NULL )
+
+    if( crt.ext_types & MBEDTLS_X509_EXT_SUBJECT_ALT_NAME )
     {
-        TEST_ASSERT( verify_parse_san( cur, &p, &n ) == 0 );
-        cur = cur->next;
+        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:
 
-    for( cur = san; cur != NULL; cur = next )
-    {
-        next = cur->next;
-        mbedtls_free( cur );
-    }
-
     mbedtls_x509_crt_free( &crt );
 }
 /* END_CASE */