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;
}