STRTOK(3) Linux Programmer's Manual STRTOK(3) NAME strtok, strtok_r - extract tokens from strings
BUGS Never use these functions. ^^^^^^^^^^^^^^^^^^^^^^^^^^ no, i'm not making this up, this is a vanilla debian woody. On 02-04-17 12:41:35 CEST, Robert Joop wrote: > On 02-04-16 19:04:41 CEST, Michael Bell wrote: > > The only bad detail is now "openssl -subj" which use a DN with "," > > inside but the order is the one from X.500. > > looking at last night's snap, apps/req.c, build_subject(), i see that > one can use both , and / delimiters. > but i fail to see whether one can escape the delimiters. can one? one cannot, it uses strtok... i've souped it up a little, so that now the args for req -subj and ca -subj can contain escaped characters, e.g. req -subj '/C=US/CN=John\/Jane Doe'. except for the escaping, this is the format used by openssl in index.txt... this is also the format that will be emitted by openca when it interfaces to openssl: use X500::DN; my $dn = new X500::DN (new X500::RDN ('c'=>'US'), new X500::RDN ('o'=>'\\Acme/2, Inc.'), new X500::RDN ('cn'=>'John Doe, PhD')) or die; print $dn->getRFC2253String(), "\n"; print $dn->getOpenSSLString(), "\n"; outputs: cn=John Doe\, PhD, o=\\Acme/2\, Inc., c=US /c=US/o=\\Acme\/2, Inc./cn=John Doe, PhD a patch (based on openssl-SNAP-20020423) is attached. rj
diff -ru orig/openssl-SNAP-20020423/apps/ca.c openssl-SNAP-20020423/apps/ca.c --- orig/openssl-SNAP-20020423/apps/ca.c Fri Mar 8 21:00:46 2002 +++ openssl-SNAP-20020423/apps/ca.c Wed Apr 24 15:49:55 2002 @@ -3023,64 +3023,122 @@ 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++; + } + + n = X509_NAME_new(); 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) diff -ru orig/openssl-SNAP-20020423/apps/req.c openssl-SNAP-20020423/apps/req.c --- orig/openssl-SNAP-20020423/apps/req.c Wed Apr 17 12:00:48 2002 +++ openssl-SNAP-20020423/apps/req.c Wed Apr 24 15:50:03 2002 @@ -1210,66 +1210,125 @@ 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++; + } + + n = X509_NAME_new(); 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; } diff -ru orig/openssl-SNAP-20020423/doc/apps/ca.pod openssl-SNAP-20020423/doc/apps/ca.pod --- orig/openssl-SNAP-20020423/doc/apps/ca.pod Mon Nov 26 14:01:41 2001 +++ openssl-SNAP-20020423/doc/apps/ca.pod Wed Apr 24 15:53:13 2002 @@ -216,7 +216,9 @@ =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> diff -ru orig/openssl-SNAP-20020423/doc/apps/req.pod openssl-SNAP-20020423/doc/apps/req.pod --- orig/openssl-SNAP-20020423/doc/apps/req.pod Sun Dec 2 01:00:53 2001 +++ openssl-SNAP-20020423/doc/apps/req.pod Wed Apr 24 15:03:32 2002 @@ -168,6 +168,8 @@ 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>