Implement SubjectAltName traversal via ASN.1 SEQUENCE OF traversal

This commit re-implements the `SubjectAlternativeName` traversal
routine in terms of the generic ASN.1 SEQUENCE traversal routine.
diff --git a/library/x509_crt.c b/library/x509_crt.c
index 3dfa863..6d5bb6f 100644
--- a/library/x509_crt.c
+++ b/library/x509_crt.c
@@ -525,19 +525,12 @@
     mbedtls_asn1_sequence **cur_ptr = (mbedtls_asn1_sequence **) ctx;
     mbedtls_asn1_sequence *cur = *cur_ptr;
 
-    /* Skip everything but DNS name */
-    if( tag != ( MBEDTLS_ASN1_CONTEXT_SPECIFIC | 2 ) )
-        return( 0 );
-
     /* Allocate and assign next pointer */
     if( cur->buf.p != NULL )
     {
         cur->next = mbedtls_calloc( 1, sizeof( mbedtls_asn1_sequence ) );
         if( cur->next == NULL )
-        {
-            return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS +
-                    MBEDTLS_ERR_ASN1_ALLOC_FAILED );
-        }
+            return( MBEDTLS_ERR_ASN1_ALLOC_FAILED );
         cur = cur->next;
     }
 
@@ -549,63 +542,21 @@
     return( 0 );
 }
 
-static int x509_subject_alt_name_traverse( unsigned char *p,
-                                           const unsigned char *end,
-                                           int (*cb)( void *ctx,
-                                                      int tag,
-                                                      unsigned char *data,
-                                                      size_t data_len ),
-                                           void *ctx )
-{
-    int ret;
-    size_t len;
-
-    /* Get main sequence tag */
-    if( ( ret = mbedtls_asn1_get_tag( &p, end, &len,
-            MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 )
-    {
-        return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret );
-    }
-
-    if( p + len != end )
-    {
-        return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS +
-                MBEDTLS_ERR_ASN1_LENGTH_MISMATCH );
-    }
-
-    while( p < end )
-    {
-        unsigned char const tag = *p++;
-        if( ( ret = mbedtls_asn1_get_len( &p, end, &len ) ) != 0 )
-            return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret );
-
-        if( ( tag & MBEDTLS_ASN1_TAG_CLASS_MASK ) !=
-            MBEDTLS_ASN1_CONTEXT_SPECIFIC )
-        {
-            return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS +
-                    MBEDTLS_ERR_ASN1_UNEXPECTED_TAG );
-        }
-
-        if( cb != NULL )
-        {
-            ret = cb( ctx, tag, p, len );
-            if( ret != 0 )
-                return( ret );
-        }
-
-        p += len;
-    }
-
-    return( 0 );
-}
-
 static int x509_get_subject_alt_name( unsigned char *p,
                                       const unsigned char *end,
                                       mbedtls_x509_sequence *subject_alt_name )
 {
-    return( x509_subject_alt_name_traverse( p, end,
-                                            x509_get_subject_alt_name_cb,
-                                            (void*) &subject_alt_name ) );
+    int ret;
+    ret = mbedtls_asn1_traverse_sequence_of( &p, end,
+                                             MBEDTLS_ASN1_TAG_CLASS_MASK,
+                                             MBEDTLS_ASN1_CONTEXT_SPECIFIC,
+                                             MBEDTLS_ASN1_TAG_VALUE_MASK,
+                                             2 /* SubjectAlt DNS */,
+                                             x509_get_subject_alt_name_cb,
+                                             (void*) &subject_alt_name );
+    if( ret != 0 )
+        ret += MBEDTLS_ERR_X509_INVALID_EXTENSIONS;
+    return( ret );
 }
 
 /*
@@ -2460,10 +2411,7 @@
 {
     char const *cn = (char const*) ctx;
     size_t cn_len = strlen( cn );
-
-    /* Skip everything but DNS name */
-    if( tag != ( MBEDTLS_ASN1_CONTEXT_SPECIFIC | 2 ) )
-        return( 0 );
+    ((void) tag);
 
     if( x509_crt_check_cn( data, data_len, cn, cn_len ) == 0 )
         return( 1 );
@@ -2482,13 +2430,18 @@
 
     if( crt->ext_types & MBEDTLS_X509_EXT_SUBJECT_ALT_NAME )
     {
+        unsigned char *p =
+            crt->subject_alt_raw.p;
         const unsigned char *end =
             crt->subject_alt_raw.p + crt->subject_alt_raw.len;
 
-        ret = x509_subject_alt_name_traverse( crt->subject_alt_raw.p,
-                                              end,
-                                              x509_crt_subject_alt_check_name,
-                                              (void*) cn );
+        ret = mbedtls_asn1_traverse_sequence_of( &p, end,
+                                      MBEDTLS_ASN1_TAG_CLASS_MASK,
+                                      MBEDTLS_ASN1_CONTEXT_SPECIFIC,
+                                      MBEDTLS_ASN1_TAG_VALUE_MASK,
+                                      2 /* SubjectAlt DNS */,
+                                      x509_crt_subject_alt_check_name,
+                                      (void*) cn );
     }
     else
     {