Fix escaping when using the -subj option of "openssl req", document
authorLutz Jänicke <jaenicke@openssl.org>
Tue, 30 Apr 2002 12:08:18 +0000 (12:08 +0000)
committerLutz Jänicke <jaenicke@openssl.org>
Tue, 30 Apr 2002 12:08:18 +0000 (12:08 +0000)
'hidden' -nameopt support. (Robert Joop <joop@fokus.gmd.de>)

CHANGES
apps/ca.c
apps/crl.c
apps/req.c
doc/apps/ca.pod
doc/apps/req.pod

diff --git a/CHANGES b/CHANGES
index 5ed923ac9ba3b08b2558453239b619e45e7f5117..303e09d526ab03d283bb76afb3ecd546b4217ba4 100644 (file)
--- a/CHANGES
+++ b/CHANGES
  
  Changes between 0.9.6d and 0.9.7  [XX xxx 2002]
 
+  *) Fix escaping of non-ASCII characters when using the -subj option
+     of the "openssl req" command line tool. (Robert Joop <joop@fokus.gmd.de>)
+     [Lutz Jaenicke]
+
   *) Make object definitions compliant to LDAP (RFC2256): SN is the short
      form for "surname", serialNumber has no short form.
      Use "mail" as the short name for "rfc822Mailbox" according to RFC2798;
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)
index f25b1877b59ed9caf3ce62808d4d6748bbd01bc1..00946b4d20fc2370cb9636ac9e41594a45e6af2f 100644 (file)
@@ -87,6 +87,7 @@ static char *crl_usage[]={
 " -noout          - no CRL output\n",
 " -CAfile  name   - verify CRL using certificates in file \"name\"\n",
 " -CApath  dir    - verify CRL using certificates in \"dir\"\n",
+" -nameopt arg    - various certificate name options\n",
 NULL
 };
 
@@ -97,6 +98,7 @@ int MAIN(int, char **);
 
 int MAIN(int argc, char **argv)
        {
+       unsigned long nmflag = 0;
        X509_CRL *x=NULL;
        char *CAfile = NULL, *CApath = NULL;
        int ret=1,i,num,badops=0;
@@ -105,7 +107,7 @@ int MAIN(int argc, char **argv)
        char *infile=NULL,*outfile=NULL;
        int hash=0,issuer=0,lastupdate=0,nextupdate=0,noout=0,text=0;
        int fingerprint = 0;
-       char **pp,buf[256];
+       char **pp;
        X509_STORE *store = NULL;
        X509_STORE_CTX ctx;
        X509_LOOKUP *lookup = NULL;
@@ -188,6 +190,11 @@ int MAIN(int argc, char **argv)
                        text = 1;
                else if (strcmp(*argv,"-hash") == 0)
                        hash= ++num;
+               else if (strcmp(*argv,"-nameopt") == 0)
+                       {
+                       if (--argc < 1) goto bad;
+                       if (!set_name_ex(&nmflag, *(++argv))) goto bad;
+                       }
                else if (strcmp(*argv,"-issuer") == 0)
                        issuer= ++num;
                else if (strcmp(*argv,"-lastupdate") == 0)
@@ -271,9 +278,7 @@ bad:
                        {
                        if (issuer == i)
                                {
-                               X509_NAME_oneline(X509_CRL_get_issuer(x),
-                                                               buf,256);
-                               BIO_printf(bio_out,"issuer= %s\n",buf);
+                               print_name(bio_out, "issuer=", X509_CRL_get_issuer(x), nmflag);
                                }
 
                        if (hash == i)
index 629a604490cf02cad769e286bde533ba8a0a7e54..db3dcb80e62b15daa07a8a02bf02c36b6451a3cb 100644 (file)
@@ -505,6 +505,7 @@ bad:
                BIO_printf(bio_err," -extensions .. specify certificate extension section (override value in config file)\n");
                BIO_printf(bio_err," -reqexts ..    specify request extension section (override value in config file)\n");
                BIO_printf(bio_err," -utf8          input characters are UTF8 (default ASCII)\n");
+               BIO_printf(bio_err," -nameopt arg    - various certificate name options\n");
                goto end;
                }
 
@@ -1210,66 +1211,126 @@ err:
        return(ret);
        }
 
+/*
+ * subject is expected to be in the format /type0=value0/type1=value1/type2=...
+ * where characters may be escaped by \
+ */
 static int build_subject(X509_REQ *req, char *subject, unsigned long chtype)
        {
-       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, chtype, (unsigned char*)ne_value, -1,-1,0))
-                       {
-                       X509_NAME_free(n);
-                       return 0;
-                       }
+               if (!X509_NAME_add_entry_by_NID(n, nid, chtype, (unsigned char*)ne_values[i], -1,-1,0))
+                       goto error1;
+
                }
 
        if (!X509_REQ_set_subject_name(req, n))
-               return 0;
+               goto error1;
        X509_NAME_free(n);
+       free (ne_values);
+       free (ne_types);
+       free (buf);
        return 1;
+
+error1:
+       X509_NAME_free(n);
+error0:
+       free (ne_values);
+       free (ne_types);
+       free (buf);
+       return 0;
 }
 
 
index 905b48a364043f4d2e999e6fe1d581eac67406bd..c2ca8f2400df0009359f269d8f6804c56ef63a3b 100644 (file)
@@ -216,7 +216,9 @@ a filename containing a certificate to revoke.
 
 =item B<-subj arg>
 
-supersedes subject name given in the request
+supersedes subject name given in the request.
+The arg must be formatted as I</type0=value0/type1=value1/type2=...>,
+characters may be escaped by \ (backslash), no spaces are skipped.
 
 =item B<-crlexts section>
 
index b627fd9bb81917fe5a6e881c3b798c47c265cd0e..10e4e12a5cdae51456a2c097544c89e3fbd86d5b 100644 (file)
@@ -38,6 +38,7 @@ B<openssl> B<req>
 [B<-extensions section>]
 [B<-reqexts section>]
 [B<-utf8>]
+[B<-nameopt>]
 [B<-batch>]
 [B<-verbose>]
 
@@ -168,6 +169,8 @@ the B<OPENSSL_CONF> environment variable.
 
 sets subject name for new request or supersedes the subject name
 when processing a request.
+The arg must be formatted as I</type0=value0/type1=value1/type2=...>,
+characters may be escaped by \ (backslash), no spaces are skipped.
 
 =item B<-x509>
 
@@ -206,6 +209,13 @@ default they are interpreted as ASCII. This means that the field
 values, whether prompted from a terminal or obtained from a
 configuration file, must be valid UTF8 strings.
 
+=item B<-nameopt option>
+
+option which determines how the subject or issuer names are displayed. The
+B<option> argument can be a single option or multiple options separated by
+commas.  Alternatively the B<-nameopt> switch may be used more than once to
+set multiple options. See the L<x509(1)|x509(1)> manual page for details.
+
 =item B<-asn1-kludge>
 
 by default the B<req> command outputs certificate requests containing