Provide X.509 name comparison based on raw ASN.1 data

This commit provides a new function `mbedtls_x509_name_cmp_raw()`
to x509.c for comparing to X.509 names by traversing the raw ASN.1
data (as opposed to using the dynamically allocated linked list
of `mbedtls_x509_name` structures). It has external linkage because
it will be needed in `x509_crt` and `x509_crl`, but is marked
internal and hence not part of the public API.
diff --git a/include/mbedtls/x509.h b/include/mbedtls/x509.h
index e6781b6..13067b8 100644
--- a/include/mbedtls/x509.h
+++ b/include/mbedtls/x509.h
@@ -305,6 +305,8 @@
                      mbedtls_x509_buf *serial );
 int mbedtls_x509_name_cmp( const mbedtls_x509_name *a,
                            const mbedtls_x509_name *b );
+int mbedtls_x509_name_cmp_raw( const mbedtls_x509_buf_raw *a,
+                               const mbedtls_x509_buf_raw *b );
 int mbedtls_x509_memcasecmp( const void *s1, const void *s2, size_t len );
 int mbedtls_x509_get_ext( unsigned char **p, const unsigned char *end,
                   mbedtls_x509_buf *ext, int tag );
diff --git a/library/x509.c b/library/x509.c
index fd92747..d27c423 100644
--- a/library/x509.c
+++ b/library/x509.c
@@ -583,6 +583,57 @@
     return( 0 );
 }
 
+int mbedtls_x509_name_cmp_raw( mbedtls_x509_buf_raw const *a,
+                               mbedtls_x509_buf_raw const *b )
+{
+    int ret;
+
+    unsigned char *p_a, *end_a, *set_a;
+    unsigned char *p_b, *end_b, *set_b;
+
+    p_a = set_a = (unsigned char*) a->p;
+    p_b = set_b = (unsigned char*) b->p;
+
+    end_a = p_a + a->len;
+    end_b = p_b + b->len;
+
+    while( 1 )
+    {
+         mbedtls_x509_buf oid_a, val_a, oid_b, val_b;
+
+        ret = x509_set_sequence_iterate( &p_a, (const unsigned char **) &set_a,
+                                         end_a, &oid_a, &val_a );
+        if( ret != 0 )
+            goto exit;
+
+        ret = x509_set_sequence_iterate( &p_b, (const unsigned char **) &set_b,
+                                         end_b, &oid_b, &val_b );
+        if( ret != 0 )
+            goto exit;
+
+        if( oid_a.len != oid_b.len ||
+            memcmp( oid_a.p, oid_b.p, oid_b.len ) != 0 )
+        {
+            return( 1 );
+        }
+
+        if( x509_string_cmp( &val_a, &val_b ) != 0 )
+            return( 1 );
+
+        if( ( set_a == p_a ) != ( set_b == p_b ) )
+            return( 1 );
+
+        if( p_a == end_a && p_b == end_b )
+            break;
+    }
+
+exit:
+    if( ret < 0 )
+        ret += MBEDTLS_ERR_X509_INVALID_NAME;
+
+    return( ret );
+}
+
 static int x509_parse_int( unsigned char **p, size_t n, int *res )
 {
     *res = 0;