Support composite RDNs in X.509 certs parsing
diff --git a/include/polarssl/asn1.h b/include/polarssl/asn1.h
index 6a87160..0a657e1 100644
--- a/include/polarssl/asn1.h
+++ b/include/polarssl/asn1.h
@@ -155,6 +155,7 @@
     asn1_buf oid;                   /**< The object identifier. */
     asn1_buf val;                   /**< The named value. */
     struct _asn1_named_data *next;  /**< The next entry in the sequence. */
+    unsigned char next_merged;      /**< Merge next item into the current one? */
 }
 asn1_named_data;
 
diff --git a/library/x509.c b/library/x509.c
index b34cf32..a3cb669 100644
--- a/library/x509.c
+++ b/library/x509.c
@@ -393,6 +393,11 @@
 }
 
 /*
+ *  Name ::= CHOICE { -- only one possibility for now --
+ *       rdnSequence  RDNSequence }
+ *
+ *  RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
+ *
  *  RelativeDistinguishedName ::=
  *    SET OF AttributeTypeAndValue
  *
@@ -404,9 +409,11 @@
  *
  *  AttributeValue ::= ANY DEFINED BY AttributeType
  *
- *  We restrict RelativeDistinguishedName to be a set of 1 element. This is
- *  the most common case, and our x509_name structure currently can't handle
- *  more than that.
+ * The data structure is optimized for the common case where each RDN has only
+ * one element, which is represented as a list of AttributeTypeAndValue.
+ * For the general case we still use a flat list, but we mark elements of the
+ * same set so that they are "merged" together in the functions that consume
+ * this list, eg x509_dn_gets().
  */
 int x509_get_name( unsigned char **p, const unsigned char *end,
                    x509_name *cur )
@@ -419,7 +426,7 @@
     while( 1 )
     {
         /*
-         * parse first SET, restricted to 1 element
+         * parse SET
          */
         if( ( ret = asn1_get_tag( p, end, &set_len,
                 ASN1_CONSTRUCTED | ASN1_SET ) ) != 0 )
@@ -427,11 +434,26 @@
 
         end_set  = *p + set_len;
 
-        if( ( ret = x509_get_attr_type_value( p, end_set, cur ) ) != 0 )
-            return( ret );
+        while( 1 )
+        {
+            if( ( ret = x509_get_attr_type_value( p, end_set, cur ) ) != 0 )
+                return( ret );
 
-        if( *p != end_set )
-            return( POLARSSL_ERR_X509_FEATURE_UNAVAILABLE );
+            if( *p == end_set )
+                break;
+
+            /* Mark this item as being only one in a set */
+            cur->next_merged = 1;
+
+            cur->next = (x509_name *) polarssl_malloc( sizeof( x509_name ) );
+
+            if( cur->next == NULL )
+                return( POLARSSL_ERR_X509_MALLOC_FAILED );
+
+            memset( cur->next, 0, sizeof( x509_name ) );
+
+            cur = cur->next;
+        }
 
         /*
          * continue until end of SEQUENCE is reached
@@ -690,7 +712,7 @@
 {
     int ret;
     size_t i, n;
-    unsigned char c;
+    unsigned char c, merge = 0;
     const x509_name *name;
     const char *short_name = NULL;
     char s[X509_MAX_DN_NAME_SIZE], *p;
@@ -711,7 +733,7 @@
 
         if( name != dn )
         {
-            ret = snprintf( p, n, ", " );
+            ret = snprintf( p, n, merge ? " + " : ", " );
             SAFE_SNPRINTF();
         }
 
@@ -736,6 +758,8 @@
         s[i] = '\0';
         ret = snprintf( p, n, "%s", s );
         SAFE_SNPRINTF();
+
+        merge = name->next_merged;
         name = name->next;
     }
 
diff --git a/library/x509_crt.c b/library/x509_crt.c
index e114c0f..d1d7d73 100644
--- a/library/x509_crt.c
+++ b/library/x509_crt.c
@@ -1652,6 +1652,10 @@
         if( x509_string_cmp( &a->val, &b->val ) != 0 )
             return( -1 );
 
+        /* structure of the list of sets */
+        if( a->next_merged != b->next_merged )
+            return( -1 );
+
         a = a->next;
         b = b->next;
     }
diff --git a/tests/suites/test_suite_x509parse.data b/tests/suites/test_suite_x509parse.data
index 072a667..a65ac2b 100644
--- a/tests/suites/test_suite_x509parse.data
+++ b/tests/suites/test_suite_x509parse.data
@@ -778,7 +778,7 @@
 x509parse_crt:"30253023a0030201028204deadbeef300d06092a864886f70d0101020500300731053003060013":"":POLARSSL_ERR_X509_INVALID_NAME + POLARSSL_ERR_ASN1_OUT_OF_DATA
 
 X509 Certificate ASN1 (TBSCertificate, issuer, no full following string)
-x509parse_crt:"302b3029a0030201028204deadbeef300d06092a864886f70d0101020500300d310b3009060013045465737400":"":POLARSSL_ERR_X509_FEATURE_UNAVAILABLE
+x509parse_crt:"302b3029a0030201028204deadbeef300d06092a864886f70d0101020500300d310b3009060013045465737400":"":POLARSSL_ERR_X509_INVALID_NAME+POLARSSL_ERR_ASN1_UNEXPECTED_TAG
 
 X509 Certificate ASN1 (TBSCertificate, valid issuer, no validity)
 x509parse_crt:"302a3028a0030201028204deadbeef300d06092a864886f70d0101020500300c310a30080600130454657374":"":POLARSSL_ERR_X509_INVALID_DATE + POLARSSL_ERR_ASN1_OUT_OF_DATA
@@ -961,6 +961,10 @@
 depends_on:POLARSSL_RSA_C
 x509parse_crt:"308199308183a0030201008204deadbeef300d06092a864886f70d0101020500300f310d300b06035504de130454657374301c170c303930313031303030303030170c303931323331323335393539300c310a30080600130454657374302a300d06092A864886F70D010101050003190030160210ffffffffffffffffffffffffffffffff0202ffff300d06092a864886f70d0101020500030200ff":"cert. version     \: 1\nserial number     \: DE\:AD\:BE\:EF\nissuer name       \: ?\?=Test\nsubject name      \: ?\?=Test\nissued  on        \: 2009-01-01 00\:00\:00\nexpires on        \: 2009-12-31 23\:59\:59\nsigned using      \: RSA with MD2\nRSA key size      \: 128 bits\n":0
 
+X509 Certificate ASN1 (Name with composite RDN)
+depends_on:POLARSSL_RSA_C
+x509parse_crt:"3082029f30820208a00302010202044c20e3bd300d06092a864886f70d01010505003056310b3009060355040613025553310b300906035504080c0243413121301f060355040a0c18496e7465726e6574205769646769747320507479204c74643117301506035504030c0e4672616e6b656e63657274204341301e170d3133303830323135313433375a170d3135303831373035353433315a3081d1310b3009060355040613025553311330110603550408130a57617368696e67746f6e31133011060b2b0601040182373c0201031302555331193017060b2b0601040182373c020102130844656c6177617265311a3018060355040a1311417574686f72697a652e4e6574204c4c43311d301b060355040f131450726976617465204f7267616e697a6174696f6e312a300e06035504051307343336393139313018060355040313117777772e617574686f72697a652e6e6574311630140603550407130d53616e204672616e636973636f30819f300d06092a864886f70d010101050003818d0030818902818100d885c62e209b6ac005c64f0bcfdaac1f2b67a18802f75b08851ff933deed888b7b68a62fcabdb21d4a8914becfeaaa1b7e08a09ffaf9916563586dc95e2877262b0b5f5ec27eb4d754aa6facd1d39d25b38a2372891bacdd3e919f791ed25704e8920e380e5623a38e6a23935978a3aec7a8e761e211d42effa2713e44e7de0b0203010001300d06092a864886f70d010105050003818100092f7424d3f6da4b8553829d958ed1980b9270b42c0d3d5833509a28c66bb207df9f3c51d122065e00b87c08c2730d2745fe1c279d16fae4d53b4bf5bdfa3631fceeb2e772b6b08a3eca5a2e2c687aefd23b4b73bf77ac6099711342cf070b35c6f61333a7cbf613d8dd4bd73e9df34bcd4284b0b4df57c36c450613f11e5dac":"cert. version     \: 3\nserial number     \: 4C\:20\:E3\:BD\nissuer name       \: C=US, ST=CA, O=Internet Widgits Pty Ltd, CN=Frankencert CA\nsubject name      \: C=US, ST=Washington, ??=US, ??=Delaware, O=Authorize.Net LLC, ??=Private Organization, serialNumber=4369191 + CN=www.authorize.net, L=San Francisco\nissued  on        \: 2013-08-02 15\:14\:37\nexpires on        \: 2015-08-17 05\:54\:31\nsigned using      \: RSA with SHA1\nRSA key size      \: 1024 bits\n":0
+
 X509 Certificate ASN1 (Name with PKCS9 email)
 depends_on:POLARSSL_RSA_C
 x509parse_crt:"30819f308189a0030201008204deadbeef300d06092a864886f70d010102050030153113301106092a864886f70d010901130454657374301c170c303930313031303030303030170c303931323331323335393539300c310a30080600130454657374302a300d06092A864886F70D010101050003190030160210ffffffffffffffffffffffffffffffff0202ffff300d06092a864886f70d0101020500030200ff":"cert. version     \: 1\nserial number     \: DE\:AD\:BE\:EF\nissuer name       \: emailAddress=Test\nsubject name      \: ?\?=Test\nissued  on        \: 2009-01-01 00\:00\:00\nexpires on        \: 2009-12-31 23\:59\:59\nsigned using      \: RSA with MD2\nRSA key size      \: 128 bits\n":0