Reorganise -subj option code, fix buffer overrun.
[openssl.git] / apps / ca.c
index a6e6976f7f7f5caa8ea0f79d3c15f27d26b30233..0b3c8a4397bcf75c1c134a7829cd5bdca72f3c34 100644 (file)
--- a/apps/ca.c
+++ b/apps/ca.c
@@ -90,7 +90,7 @@
 #    else
 #      include <unixlib.h>
 #    endif
-#  else
+#  elif !defined(OPENSSL_SYS_VXWORKS)
 #    include <sys/file.h>
 #  endif
 #endif
@@ -238,7 +238,6 @@ static int do_body(X509 **xret, EVP_PKEY *pkey, X509 *x509, const EVP_MD *dgst,
                int verbose, X509_REQ *req, char *ext_sect, CONF *conf,
        unsigned long certopt, unsigned long nameopt, int default_op,
        int ext_copy);
-static X509_NAME *do_subject(char *subject, int email_dn);
 static int do_revoke(X509 *x509, TXT_DB *db, int ext, char *extval);
 static int get_certificate_status(const char *ser_status, TXT_DB *db);
 static int do_updatedb(TXT_DB *db);
@@ -571,6 +570,7 @@ bad:
 #else
                strncpy(buf[0],X509_get_default_cert_area(),
                        sizeof(buf[0])-2-sizeof(CONFIG_FILE));
+               buf[0][sizeof(buf[0])-2-sizeof(CONFIG_FILE)]='\0';
                strcat(buf[0],"/");
 #endif
                strcat(buf[0],CONFIG_FILE);
@@ -590,6 +590,9 @@ bad:
                goto err;
                }
 
+       if (!load_config(bio_err, conf))
+               goto err;
+
        /* Lets get the config section we are using */
        if (section == NULL)
                {
@@ -1274,6 +1277,7 @@ bad:
                        BIO_printf(bio_err,"Write out database with %d new entries\n",sk_X509_num(cert_sk));
 
                        strncpy(buf[0],serialfile,BSIZE-4);
+                       buf[0][BSIZE-4]='\0';
 
 #ifdef OPENSSL_SYS_VMS
                        strcat(buf[0],"-new");
@@ -1284,6 +1288,7 @@ bad:
                        if (!save_serial(buf[0],serial)) goto err;
 
                        strncpy(buf[1],dbfile,BSIZE-4);
+                       buf[1][BSIZE-4]='\0';
 
 #ifdef OPENSSL_SYS_VMS
                        strcat(buf[1],"-new");
@@ -1314,6 +1319,7 @@ bad:
                        p=(char *)x->cert_info->serialNumber->data;
                        
                        strncpy(buf[2],outdir,BSIZE-(j*2)-6);
+                       buf[2][BSIZE-(j*2)-6]='\0';
 
 #ifndef OPENSSL_SYS_VMS
                        strcat(buf[2],"/");
@@ -1351,6 +1357,7 @@ bad:
                        {
                        /* Rename the database and the serial file */
                        strncpy(buf[2],serialfile,BSIZE-4);
+                       buf[2][BSIZE-4]='\0';
 
 #ifdef OPENSSL_SYS_VMS
                        strcat(buf[2],"-old");
@@ -1379,6 +1386,7 @@ bad:
                                }
 
                        strncpy(buf[2],dbfile,BSIZE-4);
+                       buf[2][BSIZE-4]='\0';
 
 #ifdef OPENSSL_SYS_VMS
                        strcat(buf[2],"-old");
@@ -1501,6 +1509,11 @@ bad:
                        if (pkey->type == EVP_PKEY_DSA) 
                                dgst=EVP_dss1();
                        else
+#endif
+#ifndef OPENSSL_NO_ECDSA
+                       if (pkey->type == EVP_PKEY_ECDSA)
+                               dgst=EVP_ecdsa();
+                       else
 #endif
                                dgst=EVP_md5();
                        }
@@ -1546,6 +1559,7 @@ bad:
                        X509_free(revcert);
 
                        strncpy(buf[0],dbfile,BSIZE-4);
+                       buf[0][BSIZE-4]='\0';
 #ifndef OPENSSL_SYS_VMS
                        strcat(buf[0],".new");
 #else
@@ -1560,11 +1574,16 @@ bad:
                        j=TXT_DB_write(out,db);
                        if (j <= 0) goto err;
                        strncpy(buf[1],dbfile,BSIZE-4);
+                       buf[1][BSIZE-4]='\0';
 #ifndef OPENSSL_SYS_VMS
                        strcat(buf[1],".old");
 #else
                        strcat(buf[1],"-old");
 #endif
+                       BIO_free(in);
+                       in = NULL;
+                       BIO_free(out);
+                       out = NULL;
                        if (rename(dbfile,buf[1]) < 0)
                                {
                                BIO_printf(bio_err,"unable to rename %s to %s\n", dbfile, buf[1]);
@@ -1859,7 +1878,7 @@ static int do_body(X509 **xret, EVP_PKEY *pkey, X509 *x509, const EVP_MD *dgst,
 
        if (subj)
                {
-               X509_NAME *n = do_subject(subj, email_dn);
+               X509_NAME *n = do_subject(subj, MBSTRING_ASC);
 
                if (!n)
                        {
@@ -1909,14 +1928,17 @@ static int do_body(X509 **xret, EVP_PKEY *pkey, X509 *x509, const EVP_MD *dgst,
                        BIO_printf(bio_err,"\nemailAddress type needs to be of type IA5STRING\n");
                        goto err;
                        }
-               j=ASN1_PRINTABLE_type(str->data,str->length);
-               if (    ((j == V_ASN1_T61STRING) &&
-                        (str->type != V_ASN1_T61STRING)) ||
-                       ((j == V_ASN1_IA5STRING) &&
-                        (str->type == V_ASN1_PRINTABLESTRING)))
+               if ((str->type != V_ASN1_BMPSTRING) && (str->type != V_ASN1_UTF8STRING))
                        {
-                       BIO_printf(bio_err,"\nThe string contains characters that are illegal for the ASN.1 type\n");
-                       goto err;
+                       j=ASN1_PRINTABLE_type(str->data,str->length);
+                       if (    ((j == V_ASN1_T61STRING) &&
+                                (str->type != V_ASN1_T61STRING)) ||
+                               ((j == V_ASN1_IA5STRING) &&
+                                (str->type == V_ASN1_PRINTABLESTRING)))
+                               {
+                               BIO_printf(bio_err,"\nThe string contains characters that are illegal for the ASN.1 type\n");
+                               goto err;
+                               }
                        }
 
                if (default_op)
@@ -2060,7 +2082,7 @@ again2:
                        goto err;
                        }
                while((i = X509_NAME_get_index_by_NID(dn_subject,
-                                       NID_pkcs9_emailAddress, -1) >= 0))
+                                       NID_pkcs9_emailAddress, -1)) >= 0)
                        {
                        tmpne = X509_NAME_get_entry(dn_subject, i);
                        X509_NAME_delete_entry(dn_subject, i);
@@ -2267,6 +2289,16 @@ again2:
                EVP_PKEY_copy_parameters(pktmp,pkey);
        EVP_PKEY_free(pktmp);
 #endif
+#ifndef OPENSSL_NO_ECDSA
+       if (pkey->type == EVP_PKEY_ECDSA)
+               dgst = EVP_ecdsa();
+       pktmp = X509_get_pubkey(ret);
+       if (EVP_PKEY_missing_parameters(pktmp) &&
+               !EVP_PKEY_missing_parameters(pkey))
+               EVP_PKEY_copy_parameters(pktmp, pkey);
+       EVP_PKEY_free(pktmp);
+#endif
+
 
        if (!X509_sign(ret,pkey,dgst))
                goto err;
@@ -2990,68 +3022,124 @@ int make_revoked(X509_REVOKED *rev, char *str)
        return ret;
        }
 
-static X509_NAME *do_subject(char *subject, int email_dn)
+/*
+ * subject is expected to be in the format /type0=value0/type1=value1/type2=...
+ * where characters may be escaped by \
+ */
+X509_NAME *do_subject(char *subject, 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 = 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 *));
 
-       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 error;
+       }
 
-       n = X509_NAME_new();
+       if (*subject != '/')
+       {
+               BIO_printf(bio_err, "Subject does not start with '/'.\n");
+               goto error;
+       }
+       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 error;
+                               }
+                       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 error;
+               }
+               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++;
+                               break;
+                       }
+                       else
+                               *bp++ = *sp++;
+               }
+               *bp++ = '\0';
+               ne_num++;
+       }
+
+       if (!(n = X509_NAME_new()))
+               goto error;
 
        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 ((nid == NID_pkcs9_emailAddress) && (email_dn == 0))
-                       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, chtype, (unsigned char*)ne_values[i], -1,-1,0))
+                       goto error;
                }
 
+       OPENSSL_free(ne_values);
+       OPENSSL_free(ne_types);
+       OPENSSL_free(buf);
        return n;
-       }
 
+error:
+       X509_NAME_free(n);
+       if (ne_values)
+               OPENSSL_free(ne_values);
+       if (ne_types)
+               OPENSSL_free(ne_types);
+       if (buf)
+               OPENSSL_free(buf);
+       return NULL;
+}
 
 int old_entry_print(BIO *bp, ASN1_OBJECT *obj, ASN1_STRING *str)
        {