Fix escaping when using the -subj option of "openssl req", document
[openssl.git] / apps / ca.c
index 583977718969447b14de8465f1296dc604dc3311..297e3a2dfdcf8f56bae087d96043d3de9d67ba4a 100644 (file)
--- a/apps/ca.c
+++ b/apps/ca.c
@@ -3023,64 +3023,123 @@ int make_revoked(X509_REVOKED *rev, char *str)
        return ret;
        }
 
+/*
+ * subject is expected to be in the format /type0=value0/type1=value1/type2=...
+ * where characters may be escaped by \
+ */
 static X509_NAME *do_subject(char *subject)
        {
-       X509_NAME *n = NULL;
-
-       int i, nid, ne_num=0;
+       size_t buflen = strlen (subject)+1; /* to copy the types and values into. due to escaping, the copy can only become shorter */
+       char *buf = malloc (buflen);
+       size_t max_ne = buflen / 2 + 1; /* maximum number of name elements */
+       char **ne_types = malloc (max_ne * sizeof (char *));
+       char **ne_values = malloc (max_ne * sizeof (char *));
 
-       char *ne_name = NULL;
-       char *ne_value = NULL;
+       char *sp = subject, *bp = buf;
+       int i, ne_num = 0;
 
-       char *tmp = NULL;
-       char *p[2];
+       X509_NAME *n = NULL;
+       int nid;
 
-       char *str_list[256];
-       
-       p[0] = ",/";
-       p[1] = "=";
+       if (!buf || !ne_types || !ne_values)
+       {
+               BIO_printf(bio_err, "malloc error\n");
+               goto error0;
+       }
 
-       n = X509_NAME_new();
+       if (*subject != '/')
+       {
+               BIO_printf(bio_err, "Subject does not start with '/'.\n");
+               goto error0;
+       }
+       sp++; /* skip leading / */
 
-       tmp = strtok(subject, p[0]);
-       while((tmp != NULL) && (ne_num < (sizeof str_list/sizeof *str_list)))
+       while (*sp)
+       {
+               /* collect type */
+               ne_types[ne_num] = bp;
+               while (*sp)
                {
-               char *token = tmp;
-
-               while (token[0] == ' ')
-                       token++;
-               str_list[ne_num] = token;
-
-               tmp = strtok(NULL, p[0]);
-               ne_num++;
+                       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 error0;
+                               }
+                       else if (*sp == '=')
+                       {
+                               sp++;
+                               *bp++ = '\0';
+                               break;
+                       }
+                       else
+                               *bp++ = *sp++;
                }
+               if (!*sp)
+               {
+                       BIO_printf(bio_err, "end of string encountered while processing type of subject name element #%d\n", ne_num);
+                       goto error0;
+               }
+               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 error0;
+                               }
+                       else if (*sp == '/')
+                       {
+                               sp++;
+                               *bp++ = '\0';
+                               break;
+                       }
+                       else
+                               *bp++ = *sp++;
+               }
+               *bp++ = '\0';
+               ne_num++;
+       }
+
+       if (!(n = X509_NAME_new()))
+               goto error0;
 
        for (i = 0; i < ne_num; i++)
                {
-               ne_name  = strtok(str_list[i], p[1]);
-               ne_value = strtok(NULL, p[1]);
-
-               if ((nid=OBJ_txt2nid(ne_name)) == NID_undef)
+               if ((nid=OBJ_txt2nid(ne_types[i])) == NID_undef)
                        {
-                       BIO_printf(bio_err, "Subject Attribute %s has no known NID, skipped\n", ne_name);
+                       BIO_printf(bio_err, "Subject Attribute %s has no known NID, skipped\n", ne_types[i]);
                        continue;
                        }
 
-               if (ne_value == NULL)
+               if (!*ne_values[i])
                        {
-                       BIO_printf(bio_err, "No value provided for Subject Attribute %s, skipped\n", ne_name);
+                       BIO_printf(bio_err, "No value provided for Subject Attribute %s, skipped\n", ne_types[i]);
                        continue;
                        }
 
-               if (!X509_NAME_add_entry_by_NID(n, nid, MBSTRING_ASC, (unsigned char*)ne_value, -1,-1,0))
-                       {
-                       X509_NAME_free(n);
-                       return NULL;
-                       }
+               if (!X509_NAME_add_entry_by_NID(n, nid, MBSTRING_ASC, (unsigned char*)ne_values[i], -1,-1,0))
+                       goto error1;
                }
 
+       free (ne_values);
+       free (ne_types);
+       free (buf);
        return n;
-       }
+
+error1:
+       X509_NAME_free(n);
+error0:
+       free (ne_values);
+       free (ne_types);
+       free (buf);
+       return NULL;
+}
 
 
 int old_entry_print(BIO *bp, ASN1_OBJECT *obj, ASN1_STRING *str)