]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
Internal TLS: Fix X.509 name handling to use sequency of attributes
authorJouni Malinen <jouni.malinen@atheros.com>
Tue, 25 May 2010 17:55:29 +0000 (20:55 +0300)
committerJouni Malinen <j@w1.fi>
Tue, 25 May 2010 17:55:29 +0000 (20:55 +0300)
There may be more than one attribute of same type (e.g., multiple DC
attributes), so the code needs to be able to handle that. Replace the
fixed structure with an array of attributes.

src/tls/x509v3.c
src/tls/x509v3.h

index 4fc513310f5ab9e0afc429909ee95bf3eba38dc8..bc93df6837873d9ce826f689c5ca96a47a09cc3d 100644 (file)
 
 static void x509_free_name(struct x509_name *name)
 {
-       os_free(name->dc);
-       os_free(name->cn);
-       os_free(name->c);
-       os_free(name->l);
-       os_free(name->st);
-       os_free(name->o);
-       os_free(name->ou);
+       size_t i;
+
+       for (i = 0; i < name->num_attr; i++) {
+               os_free(name->attr[i].value);
+               name->attr[i].value = NULL;
+               name->attr[i].type = X509_NAME_ATTR_NOT_USED;
+       }
+       name->num_attr = 0;
        os_free(name->email);
-       name->dc = NULL;
-       name->cn = name->c = name->l = name->st = name->o = name->ou = NULL;
        name->email = NULL;
 
        os_free(name->alt_email);
@@ -154,6 +153,7 @@ static int x509_str_compare(const char *a, const char *b)
 int x509_name_compare(struct x509_name *a, struct x509_name *b)
 {
        int res;
+       size_t i;
 
        if (!a && b)
                return -1;
@@ -161,28 +161,20 @@ int x509_name_compare(struct x509_name *a, struct x509_name *b)
                return 1;
        if (!a && !b)
                return 0;
+       if (a->num_attr < b->num_attr)
+               return -1;
+       if (a->num_attr > b->num_attr)
+               return 1;
 
-       res = x509_str_compare(a->dc, b->dc);
-       if (res)
-               return res;
-       res = x509_str_compare(a->cn, b->cn);
-       if (res)
-               return res;
-       res = x509_str_compare(a->c, b->c);
-       if (res)
-               return res;
-       res = x509_str_compare(a->l, b->l);
-       if (res)
-               return res;
-       res = x509_str_compare(a->st, b->st);
-       if (res)
-               return res;
-       res = x509_str_compare(a->o, b->o);
-       if (res)
-               return res;
-       res = x509_str_compare(a->ou, b->ou);
-       if (res)
-               return res;
+       for (i = 0; i < a->num_attr; i++) {
+               if (a->attr[i].type < b->attr[i].type)
+                       return -1;
+               if (a->attr[i].type > b->attr[i].type)
+                       return -1;
+               res = x509_str_compare(a->attr[i].value, b->attr[i].value);
+               if (res)
+                       return res;
+       }
        res = x509_str_compare(a->email, b->email);
        if (res)
                return res;
@@ -309,7 +301,7 @@ static int x509_parse_name(const u8 *buf, size_t len, struct x509_name *name,
        struct asn1_hdr hdr;
        const u8 *pos, *end, *set_pos, *set_end, *seq_pos, *seq_end;
        struct asn1_oid oid;
-       char **fieldp;
+       char *val;
 
        /*
         * Name ::= CHOICE { RDNSequence }
@@ -339,6 +331,8 @@ static int x509_parse_name(const u8 *buf, size_t len, struct x509_name *name,
        end = *next = pos + hdr.length;
 
        while (pos < end) {
+               enum x509_name_attr_type type;
+
                if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
                    hdr.class != ASN1_CLASS_UNIVERSAL ||
                    hdr.tag != ASN1_TAG_SET) {
@@ -386,34 +380,34 @@ static int x509_parse_name(const u8 *buf, size_t len, struct x509_name *name,
                 * pseudonym, generation qualifier.
                 * MUST: domainComponent (RFC 2247).
                 */
-               fieldp = NULL;
+               type = X509_NAME_ATTR_NOT_USED;
                if (oid.len == 4 &&
                    oid.oid[0] == 2 && oid.oid[1] == 5 && oid.oid[2] == 4) {
                        /* id-at ::= 2.5.4 */
                        switch (oid.oid[3]) {
                        case 3:
                                /* commonName */
-                               fieldp = &name->cn;
+                               type = X509_NAME_ATTR_CN;
                                break;
                        case 6:
                                /*  countryName */
-                               fieldp = &name->c;
+                               type = X509_NAME_ATTR_C;
                                break;
                        case 7:
                                /* localityName */
-                               fieldp = &name->l;
+                               type = X509_NAME_ATTR_L;
                                break;
                        case 8:
                                /* stateOrProvinceName */
-                               fieldp = &name->st;
+                               type = X509_NAME_ATTR_ST;
                                break;
                        case 10:
                                /* organizationName */
-                               fieldp = &name->o;
+                               type = X509_NAME_ATTR_O;
                                break;
                        case 11:
                                /* organizationalUnitName */
-                               fieldp = &name->ou;
+                               type = X509_NAME_ATTR_OU;
                                break;
                        }
                } else if (oid.len == 7 &&
@@ -422,17 +416,25 @@ static int x509_parse_name(const u8 *buf, size_t len, struct x509_name *name,
                           oid.oid[4] == 1 && oid.oid[5] == 9 &&
                           oid.oid[6] == 1) {
                        /* 1.2.840.113549.1.9.1 - e-mailAddress */
-                       fieldp = &name->email;
+                       os_free(name->email);
+                       name->email = os_malloc(hdr.length + 1);
+                       if (name->email == NULL) {
+                               x509_free_name(name);
+                               return -1;
+                       }
+                       os_memcpy(name->email, hdr.payload, hdr.length);
+                       name->email[hdr.length] = '\0';
+                       continue;
                } else if (oid.len == 7 &&
                           oid.oid[0] == 0 && oid.oid[1] == 9 &&
                           oid.oid[2] == 2342 && oid.oid[3] == 19200300 &&
                           oid.oid[4] == 100 && oid.oid[5] == 1 &&
                           oid.oid[6] == 25) {
                        /* 0.9.2342.19200300.100.1.25 - domainComponent */
-                       fieldp = &name->dc;
+                       type = X509_NAME_ATTR_DC;
                }
 
-               if (fieldp == NULL) {
+               if (type == X509_NAME_ATTR_NOT_USED) {
                        wpa_hexdump(MSG_DEBUG, "X509: Unrecognized OID",
                                    (u8 *) oid.oid,
                                    oid.len * sizeof(oid.oid[0]));
@@ -441,27 +443,60 @@ static int x509_parse_name(const u8 *buf, size_t len, struct x509_name *name,
                        continue;
                }
 
-               os_free(*fieldp);
-               *fieldp = os_malloc(hdr.length + 1);
-               if (*fieldp == NULL) {
+               if (name->num_attr == X509_MAX_NAME_ATTRIBUTES) {
+                       wpa_printf(MSG_INFO, "X509: Too many Name attributes");
+                       x509_free_name(name);
+                       return -1;
+               }
+
+               val = os_malloc(hdr.length + 1);
+               if (val == NULL) {
                        x509_free_name(name);
                        return -1;
                }
-               os_memcpy(*fieldp, hdr.payload, hdr.length);
-               (*fieldp)[hdr.length] = '\0';
-               if (os_strlen(*fieldp) != hdr.length) {
+               os_memcpy(val, hdr.payload, hdr.length);
+               val[hdr.length] = '\0';
+               if (os_strlen(val) != hdr.length) {
                        wpa_printf(MSG_INFO, "X509: Reject certificate with "
                                   "embedded NUL byte in a string (%s[NUL])",
-                                  *fieldp);
+                                  val);
                        x509_free_name(name);
                        return -1;
                }
+
+               name->attr[name->num_attr].type = type;
+               name->attr[name->num_attr].value = val;
+               name->num_attr++;
        }
 
        return 0;
 }
 
 
+static char * x509_name_attr_str(enum x509_name_attr_type type)
+{
+       switch (type) {
+       case X509_NAME_ATTR_NOT_USED:
+               return "[N/A]";
+       case X509_NAME_ATTR_DC:
+               return "DC";
+       case X509_NAME_ATTR_CN:
+               return "CN";
+       case X509_NAME_ATTR_C:
+               return "C";
+       case X509_NAME_ATTR_L:
+               return "L";
+       case X509_NAME_ATTR_ST:
+               return "ST";
+       case X509_NAME_ATTR_O:
+               return "O";
+       case X509_NAME_ATTR_OU:
+               return "OU";
+       }
+       return "?";
+}
+
+
 /**
  * x509_name_string - Convert an X.509 certificate name into a string
  * @name: Name to convert
@@ -472,6 +507,7 @@ void x509_name_string(struct x509_name *name, char *buf, size_t len)
 {
        char *pos, *end;
        int ret;
+       size_t i;
 
        if (len == 0)
                return;
@@ -479,52 +515,20 @@ void x509_name_string(struct x509_name *name, char *buf, size_t len)
        pos = buf;
        end = buf + len;
 
-       if (name->c) {
-               ret = os_snprintf(pos, end - pos, "C=%s, ", name->c);
-               if (ret < 0 || ret >= end - pos)
-                       goto done;
-               pos += ret;
-       }
-       if (name->st) {
-               ret = os_snprintf(pos, end - pos, "ST=%s, ", name->st);
-               if (ret < 0 || ret >= end - pos)
-                       goto done;
-               pos += ret;
-       }
-       if (name->l) {
-               ret = os_snprintf(pos, end - pos, "L=%s, ", name->l);
-               if (ret < 0 || ret >= end - pos)
-                       goto done;
-               pos += ret;
-       }
-       if (name->o) {
-               ret = os_snprintf(pos, end - pos, "O=%s, ", name->o);
-               if (ret < 0 || ret >= end - pos)
-                       goto done;
-               pos += ret;
-       }
-       if (name->ou) {
-               ret = os_snprintf(pos, end - pos, "OU=%s, ", name->ou);
-               if (ret < 0 || ret >= end - pos)
-                       goto done;
-               pos += ret;
-       }
-       if (name->cn) {
-               ret = os_snprintf(pos, end - pos, "CN=%s, ", name->cn);
-               if (ret < 0 || ret >= end - pos)
-                       goto done;
-               pos += ret;
-       }
-       if (name->dc) {
-               ret = os_snprintf(pos, end - pos, "DC=%s, ", name->dc);
+       for (i = 0; i < name->num_attr; i++) {
+               ret = os_snprintf(pos, end - pos, "%s=%s, ",
+                                 x509_name_attr_str(name->attr[i].type),
+                                 name->attr[i].value);
                if (ret < 0 || ret >= end - pos)
                        goto done;
                pos += ret;
        }
 
        if (pos > buf + 1 && pos[-1] == ' ' && pos[-2] == ',') {
-               *pos-- = '\0';
-               *pos-- = '\0';
+               pos--;
+               *pos = '\0';
+               pos--;
+               *pos = '\0';
        }
 
        if (name->email) {
index e7d96ad3629496dcae4fa2f999509b5a35f792f5..37292d7e7dec9b13819683331d86f050c001973f 100644 (file)
@@ -21,14 +21,25 @@ struct x509_algorithm_identifier {
        struct asn1_oid oid;
 };
 
+struct x509_name_attr {
+       enum x509_name_attr_type {
+               X509_NAME_ATTR_NOT_USED,
+               X509_NAME_ATTR_DC,
+               X509_NAME_ATTR_CN,
+               X509_NAME_ATTR_C,
+               X509_NAME_ATTR_L,
+               X509_NAME_ATTR_ST,
+               X509_NAME_ATTR_O,
+               X509_NAME_ATTR_OU
+       } type;
+       char *value;
+};
+
+#define X509_MAX_NAME_ATTRIBUTES 20
+
 struct x509_name {
-       char *dc; /* domainComponent */
-       char *cn; /* commonName */
-       char *c; /* countryName */
-       char *l; /* localityName */
-       char *st; /* stateOrProvinceName */
-       char *o; /* organizationName */
-       char *ou; /* organizationalUnitName */
+       struct x509_name_attr attr[X509_MAX_NAME_ATTRIBUTES];
+       size_t num_attr;
        char *email; /* emailAddress */
 
        /* from alternative name extension */