Commit db4c08f0 authored by Rich Salz's avatar Rich Salz
Browse files

Rewrite parse_name



Remove need for multiple arrays, parse the X509 name
one RDN at a time.  Thanks to Andy for careful review.

Reviewed-by: default avatarAndy Polyakov <appro@openssl.org>
parent 2fa45e6e
Loading
Loading
Loading
Loading
+58 −108
Original line number Diff line number Diff line
@@ -1822,134 +1822,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));
    int nextismulti = 0;
    char *work;
    X509_NAME *n;

    char *sp = subject, *bp = buf;
    int i, ne_num = 0;

    X509_NAME *n = NULL;
    int nid;

    if (!buf || !ne_types || !ne_values || !mval) {
        BIO_printf(bio_err, "malloc error\n");
        goto error;
    }
    if (*cp++ != '/')
        return NULL;

    if (*subject != '/') {
        BIO_printf(bio_err, "Subject does not start with '/'.\n");
        goto error;
    }
    sp++;                       /* skip leading / */
    n = X509_NAME_new();
    if (n == NULL)
        return NULL;
    work = strdup(cp);
    if (work == NULL)
        goto err;

    /* no multivalued RDN by default */
    mval[ne_num] = 0;
    while (*cp) {
        char *bp = work;
        char *typestr = bp;
        unsigned char *valstr;
        int nid;
        int ismulti = nextismulti;
        nextismulti = 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 {
        /* Collect the type */
        while (*cp && *cp != '=')
            *bp++ = *cp++;
        if (*cp == '\0') {
            BIO_printf(bio_err,
                               "escape character at end of string\n");
                    goto error;
                    "%s: Hit end of string before finding the equals.\n",
                    opt_getprog());
            goto err;
        }
            } else if (*sp == '=') {
                sp++;
        *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 (!*sp) {
            if (*cp == '\\' && *++cp == '\0') {
                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;
                        "%s: escape character at end of string\n",
                        opt_getprog());
                goto err;
            }
            } 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;
                break;
            } else
                *bp++ = *sp++;
        }
        *bp++ = '\0';
        ne_num++;
    }

    if (!(n = X509_NAME_new()))
        goto error;

    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]);
            continue;
        }
        /* If not at EOS (must be + or /), move forward. */
        if (*cp)
            ++cp;

        if (!*ne_values[i]) {
            BIO_printf(bio_err,
                       "No value provided for Subject Attribute %s, 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 (!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);
    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);
    free(work);
    return NULL;
}

+1 −1
Original line number Diff line number Diff line
@@ -486,7 +486,7 @@ void free_index(CA_DB *db);
int index_name_cmp(const OPENSSL_CSTRING *a, const OPENSSL_CSTRING *b);
int parse_yesno(const char *str, int def);

X509_NAME *parse_name(char *str, long chtype, int multirdn);
X509_NAME *parse_name(const char *str, long chtype, int multirdn);
int args_verify(char ***pargs, int *pargc,
                int *badarg, X509_VERIFY_PARAM **pm);
void policies_print(X509_STORE_CTX *ctx);