Rewrite parse_name
authorRich Salz <rsalz@openssl.org>
Wed, 29 Apr 2015 18:50:00 +0000 (14:50 -0400)
committerRich Salz <rsalz@openssl.org>
Wed, 29 Apr 2015 18:50:00 +0000 (14:50 -0400)
Remove need for multiple arrays, parse the X509 name
one RDN at a time.  Thanks to Andy for careful review.

Reviewed-by: Andy Polyakov <appro@openssl.org>
apps/apps.c
apps/apps.h

index bec10a29045ba64d58d3113bfdaa320b9d6d26e1..a93151c831540323b14cbc5e778c8c638f961ef7 100644 (file)
@@ -1822,134 +1822,84 @@ int parse_yesno(const char *str, int def)
 }
 
 /*
- * subject is expected to be in the format /type0=value0/type1=value1/type2=...
+ * name is expected to be in the format /type0=value0/type1=value1/type2=...
  * where characters may be escaped by \
  */
-X509_NAME *parse_name(char *subject, long chtype, int multirdn)
+X509_NAME *parse_name(const char *cp, long chtype, int canmulti)
 {
-    size_t buflen = strlen(subject) + 1; /* to copy the types and values
-                                          * into. due to escaping, the copy
-                                          * can only become shorter */
-    char *buf = OPENSSL_malloc(buflen);
-    size_t max_ne = buflen / 2 + 1; /* maximum number of name elements */
-    char **ne_types = OPENSSL_malloc(max_ne * sizeof(char *));
-    char **ne_values = OPENSSL_malloc(max_ne * sizeof(char *));
-    int *mval = OPENSSL_malloc(max_ne * sizeof(int));
+    int nextismulti = 0;
+    char *work;
+    X509_NAME *n;
 
-    char *sp = subject, *bp = buf;
-    int i, ne_num = 0;
-
-    X509_NAME *n = NULL;
-    int nid;
+    if (*cp++ != '/')
+        return NULL;
 
-    if (!buf || !ne_types || !ne_values || !mval) {
-        BIO_printf(bio_err, "malloc error\n");
-        goto error;
-    }
+    n = X509_NAME_new();
+    if (n == NULL)
+        return NULL;
+    work = strdup(cp);
+    if (work == NULL)
+        goto err;
 
-    if (*subject != '/') {
-        BIO_printf(bio_err, "Subject does not start with '/'.\n");
-        goto error;
-    }
-    sp++;                       /* skip leading / */
-
-    /* no multivalued RDN by default */
-    mval[ne_num] = 0;
-
-    while (*sp) {
-        /* collect type */
-        ne_types[ne_num] = bp;
-        while (*sp) {
-            if (*sp == '\\') {  /* is there anything to escape in the
-                                 * type...? */
-                if (*++sp)
-                    *bp++ = *sp++;
-                else {
-                    BIO_printf(bio_err,
-                               "escape character at end of string\n");
-                    goto error;
-                }
-            } else if (*sp == '=') {
-                sp++;
-                *bp++ = '\0';
-                break;
-            } else
-                *bp++ = *sp++;
-        }
-        if (!*sp) {
+    while (*cp) {
+        char *bp = work;
+        char *typestr = bp;
+        unsigned char *valstr;
+        int nid;
+        int ismulti = nextismulti;
+        nextismulti = 0;
+
+        /* Collect the type */
+        while (*cp && *cp != '=')
+            *bp++ = *cp++;
+        if (*cp == '\0') {
             BIO_printf(bio_err,
-                       "end of string encountered while processing type of subject name element #%d\n",
-                       ne_num);
-            goto error;
+                    "%s: Hit end of string before finding the equals.\n",
+                    opt_getprog());
+            goto err;
         }
-        ne_values[ne_num] = bp;
-        while (*sp) {
-            if (*sp == '\\') {
-                if (*++sp)
-                    *bp++ = *sp++;
-                else {
-                    BIO_printf(bio_err,
-                               "escape character at end of string\n");
-                    goto error;
-                }
-            } else if (*sp == '/') {
-                sp++;
-                /* no multivalued RDN by default */
-                mval[ne_num + 1] = 0;
-                break;
-            } else if (*sp == '+' && multirdn) {
-                /*
-                 * a not escaped + signals a mutlivalued RDN
-                 */
-                sp++;
-                mval[ne_num + 1] = -1;
+        *bp++ = '\0';
+        ++cp;
+
+        /* Collect the value. */
+        valstr = (unsigned char *)bp;
+        for (; *cp && *cp != '/'; *bp++ = *cp++) {
+            if (canmulti && *cp == '+') {
+                nextismulti = 1;
                 break;
-            } else
-                *bp++ = *sp++;
+            }
+            if (*cp == '\\' && *++cp == '\0') {
+                BIO_printf(bio_err,
+                        "%s: escape character at end of string\n",
+                        opt_getprog());
+                goto err;
+            }
         }
         *bp++ = '\0';
-        ne_num++;
-    }
 
-    if (!(n = X509_NAME_new()))
-        goto error;
-
-    for (i = 0; i < ne_num; i++) {
-        if ((nid = OBJ_txt2nid(ne_types[i])) == NID_undef) {
-            BIO_printf(bio_err,
-                       "Subject Attribute %s has no known NID, skipped\n",
-                       ne_types[i]);
-            continue;
-        }
+        /* If not at EOS (must be + or /), move forward. */
+        if (*cp)
+            ++cp;
 
-        if (!*ne_values[i]) {
-            BIO_printf(bio_err,
-                       "No value provided for Subject Attribute %s, skipped\n",
-                       ne_types[i]);
+        /* Parse */
+        nid = OBJ_txt2nid(typestr);
+        if (nid == NID_undef) {
+            BIO_printf(bio_err, "%s: Skipping unknown attribute \"%s\"\n",
+                      opt_getprog(), typestr);
             continue;
         }
-
-        if (!X509_NAME_add_entry_by_NID
-            (n, nid, chtype, (unsigned char *)ne_values[i], -1, -1, mval[i]))
-            goto error;
+        if (!X509_NAME_add_entry_by_NID(n, nid, chtype,
+                                        valstr, strlen((char *)valstr),
+                                        -1, ismulti ? -1 : 0))
+            goto err;
     }
 
-    OPENSSL_free(ne_values);
-    OPENSSL_free(ne_types);
-    OPENSSL_free(buf);
-    OPENSSL_free(mval);
+    free(work);
     return n;
 
- error:
+ err:
     X509_NAME_free(n);
-    if (ne_values)
-        OPENSSL_free(ne_values);
-    if (ne_types)
-        OPENSSL_free(ne_types);
-    if (mval)
-        OPENSSL_free(mval);
-    if (buf)
-        OPENSSL_free(buf);
+    free(work);
     return NULL;
 }
 
index 1ba6485bd4017e8737387a119d26bd88131c604d..5b24233515294962af46baaa45df8f13f9ef8bb9 100644 (file)
@@ -486,7 +486,7 @@ void free_index(CA_DB *db);
 int index_name_cmp(const OPENSSL_CSTRING *a, const OPENSSL_CSTRING *b);
 int parse_yesno(const char *str, int def);
 
-X509_NAME *parse_name(char *str, long chtype, int multirdn);
+X509_NAME *parse_name(const char *str, long chtype, int multirdn);
 int args_verify(char ***pargs, int *pargc,
                 int *badarg, X509_VERIFY_PARAM **pm);
 void policies_print(X509_STORE_CTX *ctx);