dup_bio_* and bio_open_* are utility functions and belong in apps.c
[openssl.git] / apps / apps.c
index a4eecaed8d8a2eb41d63d286def8076009efb582..0b5f9fd062b041d56bd636b26d695907a8bf0898 100644 (file)
 #if !defined(OPENSSL_SYS_WIN32) && !defined(OPENSSL_SYS_WINCE) && !defined(NETWARE_CLIB)
 # include <strings.h>
 #endif
-#include <sys/types.h>
+#ifndef NO_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#ifndef OPENSSL_NO_POSIX_IO
+# include <sys/stat.h>
+# include <fcntl.h>
+#endif
 #include <ctype.h>
 #include <errno.h>
-#include <assert.h>
 #include <openssl/err.h>
 #include <openssl/x509.h>
 #include <openssl/x509v3.h>
@@ -164,23 +169,17 @@ static int set_table_opts(unsigned long *flags, const char *arg,
 static int set_multi_opts(unsigned long *flags, const char *arg,
                           const NAME_EX_TBL * in_tbl);
 
-#if !defined(OPENSSL_NO_RC4) && !defined(OPENSSL_NO_RSA)
-/* Looks like this stuff is worth moving into separate function */
-static EVP_PKEY *load_netscape_key(BIO *key, const char *file,
-                                   const char *key_descrip, int format);
-#endif
-
 int app_init(long mesgwin);
 
 int chopup_args(ARGS *arg, char *buf)
 {
     int quoted;
-    char c, *p;
+    char c = '\0', *p = NULL;
 
     arg->argc = 0;
     if (arg->size == 0) {
         arg->size = 20;
-        arg->argv = OPENSSL_malloc(sizeof(char *) * arg->size);
+        arg->argv = app_malloc(sizeof(*arg->argv) * arg->size, "argv space");
         if (arg->argv == NULL)
             return 0;
     }
@@ -195,7 +194,8 @@ int chopup_args(ARGS *arg, char *buf)
         /* The start of something good :-) */
         if (arg->argc >= arg->size) {
             arg->size += 20;
-            arg->argv = OPENSSL_realloc(arg->argv, sizeof(char *) * arg->size);
+            arg->argv = OPENSSL_realloc(arg->argv,
+                                        sizeof(*arg->argv) * arg->size);
             if (arg->argv == NULL)
                 return 0;
         }
@@ -367,13 +367,7 @@ int password_callback(char *buf, int bufsiz, int verify, PW_CB_DATA *cb_tmp)
             ok = UI_add_input_string(ui, prompt, ui_flags, buf,
                                      PW_MIN_LENGTH, bufsiz - 1);
         if (ok >= 0 && verify) {
-            buff = OPENSSL_malloc(bufsiz);
-            if (!buff) {
-                BIO_printf(bio_err, "Out of memory\n");
-                UI_free(ui);
-                OPENSSL_free(prompt);
-                return 0;
-            }
+            buff = app_malloc(bufsiz, "password buffer");
             ok = UI_add_verify_string(ui, prompt, ui_flags, buff,
                                       PW_MIN_LENGTH, bufsiz - 1, buf);
         }
@@ -383,10 +377,7 @@ int password_callback(char *buf, int bufsiz, int verify, PW_CB_DATA *cb_tmp)
             }
             while (ok < 0 && UI_ctrl(ui, UI_CTRL_IS_REDOABLE, 0, 0, 0));
 
-        if (buff) {
-            OPENSSL_cleanse(buff, (unsigned int)bufsiz);
-            OPENSSL_free(buff);
-        }
+        OPENSSL_clear_free(buff, (unsigned int)bufsiz);
 
         if (ok >= 0)
             res = strlen(buf);
@@ -436,9 +427,10 @@ static char *app_get_pass(char *arg, int keepbio)
     char *tmp, tpass[APP_PASS_LEN];
     static BIO *pwdbio = NULL;
     int i;
-    if (!strncmp(arg, "pass:", 5))
+
+    if (strncmp(arg, "pass:", 5) == 0)
         return BUF_strdup(arg + 5);
-    if (!strncmp(arg, "env:", 4)) {
+    if (strncmp(arg, "env:", 4) == 0) {
         tmp = getenv(arg + 4);
         if (!tmp) {
             BIO_printf(bio_err, "Can't read environment variable %s\n", arg + 4);
@@ -447,7 +439,7 @@ static char *app_get_pass(char *arg, int keepbio)
         return BUF_strdup(tmp);
     }
     if (!keepbio || !pwdbio) {
-        if (!strncmp(arg, "file:", 5)) {
+        if (strncmp(arg, "file:", 5) == 0) {
             pwdbio = BIO_new_file(arg + 5, "r");
             if (!pwdbio) {
                 BIO_printf(bio_err, "Can't open file %s\n", arg + 5);
@@ -462,7 +454,7 @@ static char *app_get_pass(char *arg, int keepbio)
              * on real Windows descriptors, such as those obtained
              * with CreateFile.
              */
-        } else if (!strncmp(arg, "fd:", 3)) {
+        } else if (strncmp(arg, "fd:", 3) == 0) {
             BIO *btmp;
             i = atoi(arg + 3);
             if (i >= 0)
@@ -477,7 +469,7 @@ static char *app_get_pass(char *arg, int keepbio)
             btmp = BIO_new(BIO_f_buffer());
             pwdbio = BIO_push(btmp, pwdbio);
 #endif
-        } else if (!strcmp(arg, "stdin")) {
+        } else if (strcmp(arg, "stdin") == 0) {
             pwdbio = dup_bio_in();
             if (!pwdbio) {
                 BIO_printf(bio_err, "Can't open BIO for stdin\n");
@@ -503,17 +495,84 @@ static char *app_get_pass(char *arg, int keepbio)
     return BUF_strdup(tpass);
 }
 
+static CONF *app_load_config_(BIO *in, const char *filename)
+{
+    long errorline = -1;
+    CONF *conf;
+    int i;
+
+    conf = NCONF_new(NULL);
+    i = NCONF_load_bio(conf, in, &errorline);
+    if (i > 0)
+        return conf;
+
+    if (errorline <= 0)
+        BIO_printf(bio_err, "%s: Can't load config file \"%s\"\n",
+                   opt_getprog(), filename);
+    else
+        BIO_printf(bio_err, "%s: Error on line %ld of config file \"%s\"\n",
+                   opt_getprog(), errorline, filename);
+    NCONF_free(conf);
+    return NULL;
+}
+CONF *app_load_config(const char *filename)
+{
+    BIO *in;
+    CONF *conf;
+
+    in = bio_open_default(filename, 'r', FORMAT_TEXT);
+    if (in == NULL)
+        return NULL;
+
+    conf = app_load_config_(in, filename);
+    BIO_free(in);
+    return conf;
+}
+CONF *app_load_config_quiet(const char *filename)
+{
+    BIO *in;
+    CONF *conf;
+
+    in = bio_open_default_quiet(filename, 'r', FORMAT_TEXT);
+    if (in == NULL)
+        return NULL;
+
+    conf = app_load_config_(in, filename);
+    BIO_free(in);
+    return conf;
+}
+
+int app_load_modules(const CONF *config)
+{
+    CONF *to_free = NULL;
+
+    if (config == NULL)
+       config = to_free = app_load_config_quiet(default_config_file);
+    if (config == NULL)
+       return 1;
+
+    if (CONF_modules_load(config, NULL, 0) <= 0) {
+        BIO_printf(bio_err, "Error configuring OpenSSL modules\n");
+        ERR_print_errors(bio_err);
+        NCONF_free(to_free);
+        return 0;
+    }
+    NCONF_free(to_free);
+    return 1;
+}
+
 int add_oid_section(CONF *conf)
 {
     char *p;
     STACK_OF(CONF_VALUE) *sktmp;
     CONF_VALUE *cnf;
     int i;
-    if (!(p = NCONF_get_string(conf, NULL, "oid_section"))) {
+
+    if ((p = NCONF_get_string(conf, NULL, "oid_section")) == NULL) {
         ERR_clear_error();
         return 1;
     }
-    if (!(sktmp = NCONF_get_section(conf, p))) {
+    if ((sktmp = NCONF_get_section(conf, p)) == NULL) {
         BIO_printf(bio_err, "problem loading oid section %s\n", p);
         return 0;
     }
@@ -601,16 +660,12 @@ int load_cert_crl_http(const char *url, X509 **pcert, X509_CRL **pcrl)
     }
 
  err:
-    if (host)
-        OPENSSL_free(host);
-    if (path)
-        OPENSSL_free(path);
-    if (port)
-        OPENSSL_free(port);
+    OPENSSL_free(host);
+    OPENSSL_free(path);
+    OPENSSL_free(port);
     if (bio)
         BIO_free_all(bio);
-    if (rctx)
-        OCSP_REQ_CTX_free(rctx);
+    OCSP_REQ_CTX_free(rctx);
     if (rv != 1) {
         BIO_printf(bio_err, "Error loading %s from %s\n",
                    pcert ? "certificate" : "CRL", url);
@@ -634,28 +689,13 @@ X509 *load_cert(const char *file, int format,
         unbuffer(stdin);
         cert = dup_bio_in();
     } else
-        cert = bio_open_default(file, RB(format));
+        cert = bio_open_default(file, 'r', format);
     if (cert == NULL)
         goto end;
 
     if (format == FORMAT_ASN1)
         x = d2i_X509_bio(cert, NULL);
-    else if (format == FORMAT_NETSCAPE) {
-        NETSCAPE_X509 *nx;
-        nx = ASN1_item_d2i_bio(ASN1_ITEM_rptr(NETSCAPE_X509), cert, NULL);
-        if (nx == NULL)
-            goto end;
-
-        if ((strncmp(NETSCAPE_CERT_HDR, (char *)nx->header->data,
-                     nx->header->length) != 0)) {
-            NETSCAPE_X509_free(nx);
-            BIO_printf(bio_err, "Error reading header on certificate\n");
-            goto end;
-        }
-        x = nx->cert;
-        nx->cert = NULL;
-        NETSCAPE_X509_free(nx);
-    } else if (format == FORMAT_PEM)
+    else if (format == FORMAT_PEM)
         x = PEM_read_bio_X509_AUX(cert, NULL,
                                   (pem_password_cb *)password_callback, NULL);
     else if (format == FORMAT_PKCS12) {
@@ -670,8 +710,7 @@ X509 *load_cert(const char *file, int format,
         BIO_printf(bio_err, "unable to load certificate\n");
         ERR_print_errors(bio_err);
     }
-    if (cert != NULL)
-        BIO_free(cert);
+    BIO_free(cert);
     return (x);
 }
 
@@ -685,7 +724,7 @@ X509_CRL *load_crl(const char *infile, int format)
         return x;
     }
 
-    in = bio_open_default(infile, RB(format));
+    in = bio_open_default(infile, 'r', format);
     if (in == NULL)
         goto end;
     if (format == FORMAT_ASN1)
@@ -739,7 +778,7 @@ EVP_PKEY *load_key(const char *file, int format, int maybe_stdin,
         unbuffer(stdin);
         key = dup_bio_in();
     } else
-        key = bio_open_default(file, RB(format));
+        key = bio_open_default(file, 'r', format);
     if (key == NULL)
         goto end;
     if (format == FORMAT_ASN1) {
@@ -749,10 +788,6 @@ EVP_PKEY *load_key(const char *file, int format, int maybe_stdin,
                                        (pem_password_cb *)password_callback,
                                        &cb_data);
     }
-#if !defined(OPENSSL_NO_RC4) && !defined(OPENSSL_NO_RSA)
-    else if (format == FORMAT_NETSCAPE)
-        pkey = load_netscape_key(key, file, key_descrip, format);
-#endif
     else if (format == FORMAT_PKCS12) {
         if (!load_pkcs12(key, key_descrip,
                          (pem_password_cb *)password_callback, &cb_data,
@@ -771,8 +806,7 @@ EVP_PKEY *load_key(const char *file, int format, int maybe_stdin,
         goto end;
     }
  end:
-    if (key != NULL)
-        BIO_free(key);
+    BIO_free(key);
     if (pkey == NULL) {
         BIO_printf(bio_err, "unable to load %s\n", key_descrip);
         ERR_print_errors(bio_err);
@@ -780,13 +814,6 @@ EVP_PKEY *load_key(const char *file, int format, int maybe_stdin,
     return (pkey);
 }
 
-static const char *key_file_format(int format)
-{
-    if (format == FORMAT_PEM || format == FORMAT_PEMRSA)
-        return "r";
-    return "rb";
-}
-
 EVP_PKEY *load_pubkey(const char *file, int format, int maybe_stdin,
                       const char *pass, ENGINE *e, const char *key_descrip)
 {
@@ -814,7 +841,7 @@ EVP_PKEY *load_pubkey(const char *file, int format, int maybe_stdin,
         unbuffer(stdin);
         key = dup_bio_in();
     } else
-        key = bio_open_default(file, key_file_format(format));
+        key = bio_open_default(file, 'r', format);
     if (key == NULL)
         goto end;
     if (format == FORMAT_ASN1) {
@@ -850,63 +877,17 @@ EVP_PKEY *load_pubkey(const char *file, int format, int maybe_stdin,
                                    (pem_password_cb *)password_callback,
                                    &cb_data);
     }
-#if !defined(OPENSSL_NO_RC4) && !defined(OPENSSL_NO_RSA)
-    else if (format == FORMAT_NETSCAPE)
-        pkey = load_netscape_key(key, file, key_descrip, format);
-#endif
 #if !defined(OPENSSL_NO_RSA) && !defined(OPENSSL_NO_DSA)
     else if (format == FORMAT_MSBLOB)
         pkey = b2i_PublicKey_bio(key);
 #endif
  end:
-    if (key != NULL)
-        BIO_free(key);
+    BIO_free(key);
     if (pkey == NULL)
         BIO_printf(bio_err, "unable to load %s\n", key_descrip);
     return (pkey);
 }
 
-#if !defined(OPENSSL_NO_RC4) && !defined(OPENSSL_NO_RSA)
-static EVP_PKEY *load_netscape_key(BIO *key, const char *file,
-                                   const char *key_descrip, int format)
-{
-    EVP_PKEY *pkey;
-    BUF_MEM *buf;
-    RSA *rsa;
-    const unsigned char *p;
-    int size, i;
-
-    buf = BUF_MEM_new();
-    pkey = EVP_PKEY_new();
-    size = 0;
-    if (buf == NULL || pkey == NULL)
-        goto error;
-    for (;;) {
-        if (!BUF_MEM_grow_clean(buf, size + 1024 * 10))
-            goto error;
-        i = BIO_read(key, &(buf->data[size]), 1024 * 10);
-        size += i;
-        if (i == 0)
-            break;
-        if (i < 0) {
-            BIO_printf(bio_err, "Error reading %s %s", key_descrip, file);
-            goto error;
-        }
-    }
-    p = (unsigned char *)buf->data;
-    rsa = d2i_RSA_NET(NULL, &p, (long)size, NULL, 0);
-    if (rsa == NULL)
-        goto error;
-    BUF_MEM_free(buf);
-    EVP_PKEY_set1_RSA(pkey, rsa);
-    return pkey;
- error:
-    BUF_MEM_free(buf);
-    EVP_PKEY_free(pkey);
-    return NULL;
-}
-#endif                          /* ndef OPENSSL_NO_RC4 */
-
 static int load_certs_crls(const char *file, int format,
                            const char *pass, ENGINE *e, const char *desc,
                            STACK_OF(X509) **pcerts,
@@ -927,7 +908,7 @@ static int load_certs_crls(const char *file, int format,
         return 0;
     }
 
-    bio = bio_open_default(file, "r");
+    bio = bio_open_default(file, 'r', FORMAT_PEM);
     if (bio == NULL)
         return 0;
 
@@ -971,8 +952,7 @@ static int load_certs_crls(const char *file, int format,
 
  end:
 
-    if (xis)
-        sk_X509_INFO_pop_free(xis, X509_INFO_free);
+    sk_X509_INFO_pop_free(xis, X509_INFO_free);
 
     if (rv == 0) {
         if (pcerts) {
@@ -990,6 +970,21 @@ static int load_certs_crls(const char *file, int format,
     return rv;
 }
 
+void* app_malloc(int sz, const char *what)
+{
+    void *vp = OPENSSL_malloc(sz);
+
+    if (vp == NULL) {
+        BIO_printf(bio_err, "%s: Could not allocate %d bytes for %s\n",
+                opt_getprog(), sz, what);
+        ERR_print_errors(bio_err);
+        exit(1);
+    }
+    return vp;
+}
+
+
+
 STACK_OF(X509) *load_certs(const char *file, int format,
                            const char *pass, ENGINE *e, const char *desc)
 {
@@ -1084,11 +1079,11 @@ int set_name_ex(unsigned long *flags, const char *arg)
 
 int set_ext_copy(int *copy_type, const char *arg)
 {
-    if (!strcasecmp(arg, "none"))
+    if (strcasecmp(arg, "none") == 0)
         *copy_type = EXT_COPY_NONE;
-    else if (!strcasecmp(arg, "copy"))
+    else if (strcasecmp(arg, "copy") == 0)
         *copy_type = EXT_COPY_ADD;
-    else if (!strcasecmp(arg, "copyall"))
+    else if (strcasecmp(arg, "copyall") == 0)
         *copy_type = EXT_COPY_ALL;
     else
         return 0;
@@ -1170,7 +1165,7 @@ static int set_table_opts(unsigned long *flags, const char *arg,
         c = 1;
 
     for (ptbl = in_tbl; ptbl->name; ptbl++) {
-        if (!strcasecmp(arg, ptbl->name)) {
+        if (strcasecmp(arg, ptbl->name) == 0) {
             *flags &= ~ptbl->mask;
             if (c)
                 *flags |= ptbl->flag;
@@ -1414,8 +1409,7 @@ BIGNUM *load_serial(char *serialfile, int create, ASN1_INTEGER **retai)
     }
  err:
     BIO_free(in);
-    if (ai != NULL)
-        ASN1_INTEGER_free(ai);
+    ASN1_INTEGER_free(ai);
     return (ret);
 }
 
@@ -1468,8 +1462,7 @@ int save_serial(char *serialfile, char *suffix, BIGNUM *serial,
     }
  err:
     BIO_free_all(out);
-    if (ai != NULL)
-        ASN1_INTEGER_free(ai);
+    ASN1_INTEGER_free(ai);
     return (ret);
 }
 
@@ -1530,6 +1523,7 @@ int rand_serial(BIGNUM *b, ASN1_INTEGER *ai)
 {
     BIGNUM *btmp;
     int ret = 0;
+
     if (b)
         btmp = b;
     else
@@ -1547,7 +1541,7 @@ int rand_serial(BIGNUM *b, ASN1_INTEGER *ai)
 
  error:
 
-    if (!b)
+    if (btmp != b)
         BN_free(btmp);
 
     return ret;
@@ -1559,8 +1553,7 @@ CA_DB *load_index(char *dbfile, DB_ATTR *db_attr)
     TXT_DB *tmpdb = NULL;
     BIO *in;
     CONF *dbattr_conf = NULL;
-    char buf[1][BSIZE];
-    long errorline = -1;
+    char buf[BSIZE];
 
     in = BIO_new_file(dbfile, "r");
     if (in == NULL) {
@@ -1571,28 +1564,13 @@ CA_DB *load_index(char *dbfile, DB_ATTR *db_attr)
         goto err;
 
 #ifndef OPENSSL_SYS_VMS
-    BIO_snprintf(buf[0], sizeof buf[0], "%s.attr", dbfile);
+    BIO_snprintf(buf, sizeof buf, "%s.attr", dbfile);
 #else
-    BIO_snprintf(buf[0], sizeof buf[0], "%s-attr", dbfile);
+    BIO_snprintf(buf, sizeof buf, "%s-attr", dbfile);
 #endif
-    dbattr_conf = NCONF_new(NULL);
-    if (NCONF_load(dbattr_conf, buf[0], &errorline) <= 0) {
-        if (errorline > 0) {
-            BIO_printf(bio_err,
-                       "error on line %ld of db attribute file '%s'\n",
-                       errorline, buf[0]);
-            goto err;
-        } else {
-            NCONF_free(dbattr_conf);
-            dbattr_conf = NULL;
-        }
-    }
-
-    if ((retdb = OPENSSL_malloc(sizeof(CA_DB))) == NULL) {
-        fprintf(stderr, "Out of memory\n");
-        goto err;
-    }
+    dbattr_conf = app_load_config(buf);
 
+    retdb = app_malloc(sizeof(*retdb), "new DB");
     retdb->db = tmpdb;
     tmpdb = NULL;
     if (db_attr)
@@ -1613,10 +1591,8 @@ CA_DB *load_index(char *dbfile, DB_ATTR *db_attr)
     }
 
  err:
-    if (dbattr_conf)
-        NCONF_free(dbattr_conf);
-    if (tmpdb)
-        TXT_DB_free(tmpdb);
+    NCONF_free(dbattr_conf);
+    TXT_DB_free(tmpdb);
     BIO_free_all(in);
     return retdb;
 }
@@ -1794,8 +1770,7 @@ int rotate_index(const char *dbfile, const char *new_suffix,
 void free_index(CA_DB *db)
 {
     if (db) {
-        if (db->db)
-            TXT_DB_free(db->db);
+        TXT_DB_free(db->db);
         OPENSSL_free(db);
     }
 }
@@ -1822,134 +1797,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));
-
-    char *sp = subject, *bp = buf;
-    int i, ne_num = 0;
+    int nextismulti = 0;
+    char *work;
+    X509_NAME *n;
 
-    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 = OPENSSL_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;
+        /* If not at EOS (must be + or /), move forward. */
+        if (*cp)
+            ++cp;
 
-    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]);
+        /* Parse */
+        nid = OBJ_txt2nid(typestr);
+        if (nid == NID_undef) {
+            BIO_printf(bio_err, "%s: Skipping unknown attribute \"%s\"\n",
+                      opt_getprog(), typestr);
             continue;
         }
-
-        if (!*ne_values[i]) {
-            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_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);
+    OPENSSL_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);
+    OPENSSL_free(work);
     return NULL;
 }
 
@@ -2218,9 +2143,7 @@ void jpake_client_auth(BIO *out, BIO *conn, const char *secret)
 
     BIO_puts(out, "JPAKE authentication succeeded, setting PSK\n");
 
-    if (psk_key)
-        OPENSSL_free(psk_key);
-
+    OPENSSL_free(psk_key);
     psk_key = BN_bn2hex(JPAKE_get_shared_key(ctx));
 
     BIO_pop(bconn);
@@ -2250,9 +2173,7 @@ void jpake_server_auth(BIO *out, BIO *conn, const char *secret)
 
     BIO_puts(out, "JPAKE authentication succeeded, setting PSK\n");
 
-    if (psk_key)
-        OPENSSL_free(psk_key);
-
+    OPENSSL_free(psk_key);
     psk_key = BN_bn2hex(JPAKE_get_shared_key(ctx));
 
     BIO_pop(bconn);
@@ -2263,7 +2184,6 @@ void jpake_server_auth(BIO *out, BIO *conn, const char *secret)
 
 #endif
 
-#ifndef OPENSSL_NO_TLSEXT
 /*-
  * next_protos_parse parses a comma separated list of strings into a string
  * in a format suitable for passing to SSL_CTX_set_next_protos_advertised.
@@ -2283,10 +2203,7 @@ unsigned char *next_protos_parse(unsigned short *outlen, const char *in)
     if (len >= 65535)
         return NULL;
 
-    out = OPENSSL_malloc(strlen(in) + 1);
-    if (!out)
-        return NULL;
-
+    out = app_malloc(strlen(in) + 1, "NPN buffer");
     for (i = 0; i <= len; ++i) {
         if (i == len || in[i] == ',') {
             if (i - start > 255) {
@@ -2302,7 +2219,6 @@ unsigned char *next_protos_parse(unsigned short *outlen, const char *in)
     *outlen = len + 1;
     return out;
 }
-#endif                          /* ndef OPENSSL_NO_TLSEXT */
 
 void print_cert_checks(BIO *bio, X509 *x,
                        const char *checkhost,
@@ -2345,7 +2261,7 @@ static const char *get_dp_url(DIST_POINT *dp)
         uri = GENERAL_NAME_get0_value(gen, &gtype);
         if (gtype == GEN_URI && ASN1_STRING_length(uri) > 6) {
             char *uptr = (char *)ASN1_STRING_data(uri);
-            if (!strncmp(uptr, "http://", 7))
+            if (strncmp(uptr, "http://", 7) == 0)
                 return uptr;
         }
     }
@@ -2431,7 +2347,7 @@ static int WIN32_rename(const char *from, const char *to)
     } else {                    /* UNICODE path */
 
         size_t i, flen = strlen(from) + 1, tlen = strlen(to) + 1;
-        tfrom = (TCHAR *)malloc(sizeof(TCHAR) * (flen + tlen));
+        tfrom = malloc(sizeof(*tfrom) * (flen + tlen));
         if (tfrom == NULL)
             goto err;
         tto = tfrom + flen;
@@ -2673,6 +2589,45 @@ int app_access(const char* name, int flag)
 #endif
 }
 
+int app_hex(char c)
+{
+    switch (c) {
+    default:
+    case '0':
+        return 0;
+    case '1':
+        return 1;
+    case '2':
+        return 2;
+    case '3':
+        return 3;
+    case '4':
+          return 4;
+    case '5':
+          return 5;
+    case '6':
+          return 6;
+    case '7':
+          return 7;
+    case '8':
+          return 8;
+    case '9':
+          return 9;
+    case 'a': case 'A':
+          return 0x0A;
+    case 'b': case 'B':
+          return 0x0B;
+    case 'c': case 'C':
+          return 0x0C;
+    case 'd': case 'D':
+          return 0x0D;
+    case 'e': case 'E':
+          return 0x0E;
+    case 'f': case 'F':
+          return 0x0F;
+    }
+}
+
 /* app_isdir section */
 #ifdef _WIN32
 int app_isdir(const char *name)
@@ -2682,7 +2637,7 @@ int app_isdir(const char *name)
 # if defined(UNICODE) || defined(_UNICODE)
     size_t i, len_0 = strlen(name) + 1;
 
-    if (len_0 > sizeof(FileData.cFileName) / sizeof(FileData.cFileName[0]))
+    if (len_0 > OSSL_NELEM(FileData.cFileName))
         return -1;
 
 #  if !defined(_WIN32_WCE) || _WIN32_WCE>=101
@@ -2758,3 +2713,154 @@ int raw_write_stdout(const void *buf, int siz)
     return write(fileno(stdout), buf, siz);
 }
 #endif
+
+/*
+ * Centralized handling if input and output files with format specification
+ * The format is meant to show what the input and output is supposed to be,
+ * and is therefore a show of intent more than anything else.  However, it
+ * does impact behavior on some platform, such as differentiating between
+ * text and binary input/output on non-Unix platforms
+ */
+BIO *dup_bio_in(void)
+{
+    return BIO_new_fp(stdin, BIO_NOCLOSE | BIO_FP_TEXT);
+}
+
+BIO *dup_bio_out(void)
+{
+    BIO *b = BIO_new_fp(stdout, BIO_NOCLOSE | BIO_FP_TEXT);
+#ifdef OPENSSL_SYS_VMS
+    b = BIO_push(BIO_new(BIO_f_linebuffer()), b);
+#endif
+    return b;
+}
+
+void unbuffer(FILE *fp)
+{
+    setbuf(fp, NULL);
+}
+
+static const char *modestr(char mode, int format)
+{
+    OPENSSL_assert(mode == 'a' || mode == 'r' || mode == 'w');
+
+    switch (mode) {
+    case 'a':
+        return (format & B_FORMAT_TEXT) ? "a" : "ab";
+    case 'r':
+        return (format & B_FORMAT_TEXT) ? "r" : "rb";
+    case 'w':
+        return (format & B_FORMAT_TEXT) ? "w" : "wb";
+    }
+    /* The assert above should make sure we never reach this point */
+    return NULL;
+}
+
+static const char *modeverb(char mode)
+{
+    switch (mode) {
+    case 'a':
+        return "appending";
+    case 'r':
+        return "reading";
+    case 'w':
+        return "writing";
+    }
+    return "(doing something)";
+}
+
+/*
+ * Open a file for writing, owner-read-only.
+ */
+BIO *bio_open_owner(const char *filename, int format, int private)
+{
+    FILE *fp = NULL;
+    BIO *b = NULL;
+    int fd = -1, bflags, mode, binmode;
+
+    if (!private || filename == NULL || strcmp(filename, "-") == 0)
+        return bio_open_default(filename, 'w', format);
+
+    mode = O_WRONLY;
+#ifdef O_CREAT
+    mode |= O_CREAT;
+#endif
+#ifdef O_TRUNC
+    mode |= O_TRUNC;
+#endif
+    binmode = !(format & B_FORMAT_TEXT);
+    if (binmode) {
+#ifdef O_BINARY
+        mode |= O_BINARY;
+#elif defined(_O_BINARY)
+        mode |= _O_BINARY;
+#endif
+    }
+
+    fd = open(filename, mode, 0600);
+    if (fd < 0)
+        goto err;
+    fp = fdopen(fd, modestr('w', format));
+    if (fp == NULL)
+        goto err;
+    bflags = BIO_CLOSE;
+    if (!binmode)
+        bflags |= BIO_FP_TEXT;
+    b = BIO_new_fp(fp, bflags);
+    if (b)
+        return b;
+
+ err:
+    BIO_printf(bio_err, "%s: Can't open \"%s\" for writing, %s\n",
+               opt_getprog(), filename, strerror(errno));
+    ERR_print_errors(bio_err);
+    /* If we have fp, then fdopen took over fd, so don't close both. */
+    if (fp)
+        fclose(fp);
+    else if (fd >= 0)
+        close(fd);
+    return NULL;
+}
+
+static BIO *bio_open_default_(const char *filename, char mode, int format,
+                              int quiet)
+{
+    BIO *ret;
+
+    if (filename == NULL || strcmp(filename, "-") == 0) {
+        ret = mode == 'r' ? dup_bio_in() : dup_bio_out();
+        if (quiet) {
+            ERR_clear_error();
+            return ret;
+        }
+        if (ret != NULL)
+            return ret;
+        BIO_printf(bio_err,
+                   "Can't open %s, %s\n",
+                   mode == 'r' ? "stdin" : "stdout", strerror(errno));
+    } else {
+        ret = BIO_new_file(filename, modestr(mode, format));
+        if (quiet) {
+            ERR_clear_error();
+            return ret;
+        }
+        if (ret != NULL)
+            return ret;
+        BIO_printf(bio_err,
+                   "Can't open %s for %s, %s\n",
+                   filename, modeverb(mode), strerror(errno));
+    }
+    ERR_print_errors(bio_err);
+    return NULL;
+}
+
+BIO *bio_open_default(const char *filename, char mode, int format)
+{
+    return bio_open_default_(filename, mode, format, 0);
+}
+
+BIO *bio_open_default_quiet(const char *filename, char mode, int format)
+{
+    return bio_open_default_(filename, mode, format, 1);
+}
+