Support composite RDNs in X.509 certs parsing
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;
     }