1e1051a39Sopenharmony_ci/*
2e1051a39Sopenharmony_ci * Copyright 1999-2020 The OpenSSL Project Authors. All Rights Reserved.
3e1051a39Sopenharmony_ci *
4e1051a39Sopenharmony_ci * Licensed under the Apache License 2.0 (the "License").  You may not use
5e1051a39Sopenharmony_ci * this file except in compliance with the License.  You can obtain a copy
6e1051a39Sopenharmony_ci * in the file LICENSE in the source distribution or at
7e1051a39Sopenharmony_ci * https://www.openssl.org/source/license.html
8e1051a39Sopenharmony_ci */
9e1051a39Sopenharmony_ci
10e1051a39Sopenharmony_ci#include <stdio.h>
11e1051a39Sopenharmony_ci#include "internal/cryptlib.h"
12e1051a39Sopenharmony_ci#include <openssl/asn1.h>
13e1051a39Sopenharmony_ci#include <openssl/objects.h>
14e1051a39Sopenharmony_ci
15e1051a39Sopenharmony_cistatic STACK_OF(ASN1_STRING_TABLE) *stable = NULL;
16e1051a39Sopenharmony_cistatic void st_free(ASN1_STRING_TABLE *tbl);
17e1051a39Sopenharmony_cistatic int sk_table_cmp(const ASN1_STRING_TABLE *const *a,
18e1051a39Sopenharmony_ci                        const ASN1_STRING_TABLE *const *b);
19e1051a39Sopenharmony_ci
20e1051a39Sopenharmony_ci/*
21e1051a39Sopenharmony_ci * This is the global mask for the mbstring functions: this is use to mask
22e1051a39Sopenharmony_ci * out certain types (such as BMPString and UTF8String) because certain
23e1051a39Sopenharmony_ci * software (e.g. Netscape) has problems with them.
24e1051a39Sopenharmony_ci */
25e1051a39Sopenharmony_ci
26e1051a39Sopenharmony_cistatic unsigned long global_mask = B_ASN1_UTF8STRING;
27e1051a39Sopenharmony_ci
28e1051a39Sopenharmony_civoid ASN1_STRING_set_default_mask(unsigned long mask)
29e1051a39Sopenharmony_ci{
30e1051a39Sopenharmony_ci    global_mask = mask;
31e1051a39Sopenharmony_ci}
32e1051a39Sopenharmony_ci
33e1051a39Sopenharmony_ciunsigned long ASN1_STRING_get_default_mask(void)
34e1051a39Sopenharmony_ci{
35e1051a39Sopenharmony_ci    return global_mask;
36e1051a39Sopenharmony_ci}
37e1051a39Sopenharmony_ci
38e1051a39Sopenharmony_ci/*-
39e1051a39Sopenharmony_ci * This function sets the default to various "flavours" of configuration.
40e1051a39Sopenharmony_ci * based on an ASCII string. Currently this is:
41e1051a39Sopenharmony_ci * MASK:XXXX : a numerical mask value.
42e1051a39Sopenharmony_ci * nobmp : Don't use BMPStrings (just Printable, T61).
43e1051a39Sopenharmony_ci * pkix : PKIX recommendation in RFC2459.
44e1051a39Sopenharmony_ci * utf8only : only use UTF8Strings (RFC2459 recommendation for 2004).
45e1051a39Sopenharmony_ci * default:   the default value, Printable, T61, BMP.
46e1051a39Sopenharmony_ci */
47e1051a39Sopenharmony_ci
48e1051a39Sopenharmony_ciint ASN1_STRING_set_default_mask_asc(const char *p)
49e1051a39Sopenharmony_ci{
50e1051a39Sopenharmony_ci    unsigned long mask;
51e1051a39Sopenharmony_ci    char *end;
52e1051a39Sopenharmony_ci
53e1051a39Sopenharmony_ci    if (strncmp(p, "MASK:", 5) == 0) {
54e1051a39Sopenharmony_ci        if (p[5] == '\0')
55e1051a39Sopenharmony_ci            return 0;
56e1051a39Sopenharmony_ci        mask = strtoul(p + 5, &end, 0);
57e1051a39Sopenharmony_ci        if (*end)
58e1051a39Sopenharmony_ci            return 0;
59e1051a39Sopenharmony_ci    } else if (strcmp(p, "nombstr") == 0)
60e1051a39Sopenharmony_ci        mask = ~((unsigned long)(B_ASN1_BMPSTRING | B_ASN1_UTF8STRING));
61e1051a39Sopenharmony_ci    else if (strcmp(p, "pkix") == 0)
62e1051a39Sopenharmony_ci        mask = ~((unsigned long)B_ASN1_T61STRING);
63e1051a39Sopenharmony_ci    else if (strcmp(p, "utf8only") == 0)
64e1051a39Sopenharmony_ci        mask = B_ASN1_UTF8STRING;
65e1051a39Sopenharmony_ci    else if (strcmp(p, "default") == 0)
66e1051a39Sopenharmony_ci        mask = 0xFFFFFFFFL;
67e1051a39Sopenharmony_ci    else
68e1051a39Sopenharmony_ci        return 0;
69e1051a39Sopenharmony_ci    ASN1_STRING_set_default_mask(mask);
70e1051a39Sopenharmony_ci    return 1;
71e1051a39Sopenharmony_ci}
72e1051a39Sopenharmony_ci
73e1051a39Sopenharmony_ci/*
74e1051a39Sopenharmony_ci * The following function generates an ASN1_STRING based on limits in a
75e1051a39Sopenharmony_ci * table. Frequently the types and length of an ASN1_STRING are restricted by
76e1051a39Sopenharmony_ci * a corresponding OID. For example certificates and certificate requests.
77e1051a39Sopenharmony_ci */
78e1051a39Sopenharmony_ci
79e1051a39Sopenharmony_ciASN1_STRING *ASN1_STRING_set_by_NID(ASN1_STRING **out,
80e1051a39Sopenharmony_ci                                    const unsigned char *in, int inlen,
81e1051a39Sopenharmony_ci                                    int inform, int nid)
82e1051a39Sopenharmony_ci{
83e1051a39Sopenharmony_ci    ASN1_STRING_TABLE *tbl;
84e1051a39Sopenharmony_ci    ASN1_STRING *str = NULL;
85e1051a39Sopenharmony_ci    unsigned long mask;
86e1051a39Sopenharmony_ci    int ret;
87e1051a39Sopenharmony_ci
88e1051a39Sopenharmony_ci    if (out == NULL)
89e1051a39Sopenharmony_ci        out = &str;
90e1051a39Sopenharmony_ci    tbl = ASN1_STRING_TABLE_get(nid);
91e1051a39Sopenharmony_ci    if (tbl != NULL) {
92e1051a39Sopenharmony_ci        mask = tbl->mask;
93e1051a39Sopenharmony_ci        if (!(tbl->flags & STABLE_NO_MASK))
94e1051a39Sopenharmony_ci            mask &= global_mask;
95e1051a39Sopenharmony_ci        ret = ASN1_mbstring_ncopy(out, in, inlen, inform, mask,
96e1051a39Sopenharmony_ci                                  tbl->minsize, tbl->maxsize);
97e1051a39Sopenharmony_ci    } else {
98e1051a39Sopenharmony_ci        ret = ASN1_mbstring_copy(out, in, inlen, inform,
99e1051a39Sopenharmony_ci                                 DIRSTRING_TYPE & global_mask);
100e1051a39Sopenharmony_ci    }
101e1051a39Sopenharmony_ci    if (ret <= 0)
102e1051a39Sopenharmony_ci        return NULL;
103e1051a39Sopenharmony_ci    return *out;
104e1051a39Sopenharmony_ci}
105e1051a39Sopenharmony_ci
106e1051a39Sopenharmony_ci/*
107e1051a39Sopenharmony_ci * Now the tables and helper functions for the string table:
108e1051a39Sopenharmony_ci */
109e1051a39Sopenharmony_ci
110e1051a39Sopenharmony_ci#include "tbl_standard.h"
111e1051a39Sopenharmony_ci
112e1051a39Sopenharmony_cistatic int sk_table_cmp(const ASN1_STRING_TABLE *const *a,
113e1051a39Sopenharmony_ci                        const ASN1_STRING_TABLE *const *b)
114e1051a39Sopenharmony_ci{
115e1051a39Sopenharmony_ci    return (*a)->nid - (*b)->nid;
116e1051a39Sopenharmony_ci}
117e1051a39Sopenharmony_ci
118e1051a39Sopenharmony_ciDECLARE_OBJ_BSEARCH_CMP_FN(ASN1_STRING_TABLE, ASN1_STRING_TABLE, table);
119e1051a39Sopenharmony_ci
120e1051a39Sopenharmony_cistatic int table_cmp(const ASN1_STRING_TABLE *a, const ASN1_STRING_TABLE *b)
121e1051a39Sopenharmony_ci{
122e1051a39Sopenharmony_ci    return a->nid - b->nid;
123e1051a39Sopenharmony_ci}
124e1051a39Sopenharmony_ci
125e1051a39Sopenharmony_ciIMPLEMENT_OBJ_BSEARCH_CMP_FN(ASN1_STRING_TABLE, ASN1_STRING_TABLE, table);
126e1051a39Sopenharmony_ci
127e1051a39Sopenharmony_ciASN1_STRING_TABLE *ASN1_STRING_TABLE_get(int nid)
128e1051a39Sopenharmony_ci{
129e1051a39Sopenharmony_ci    int idx;
130e1051a39Sopenharmony_ci    ASN1_STRING_TABLE fnd;
131e1051a39Sopenharmony_ci
132e1051a39Sopenharmony_ci    /* "stable" can be impacted by config, so load the config file first */
133e1051a39Sopenharmony_ci    OPENSSL_init_crypto(OPENSSL_INIT_LOAD_CONFIG, NULL);
134e1051a39Sopenharmony_ci
135e1051a39Sopenharmony_ci    fnd.nid = nid;
136e1051a39Sopenharmony_ci    if (stable) {
137e1051a39Sopenharmony_ci        idx = sk_ASN1_STRING_TABLE_find(stable, &fnd);
138e1051a39Sopenharmony_ci        if (idx >= 0)
139e1051a39Sopenharmony_ci            return sk_ASN1_STRING_TABLE_value(stable, idx);
140e1051a39Sopenharmony_ci    }
141e1051a39Sopenharmony_ci    return OBJ_bsearch_table(&fnd, tbl_standard, OSSL_NELEM(tbl_standard));
142e1051a39Sopenharmony_ci}
143e1051a39Sopenharmony_ci
144e1051a39Sopenharmony_ci/*
145e1051a39Sopenharmony_ci * Return a string table pointer which can be modified: either directly from
146e1051a39Sopenharmony_ci * table or a copy of an internal value added to the table.
147e1051a39Sopenharmony_ci */
148e1051a39Sopenharmony_ci
149e1051a39Sopenharmony_cistatic ASN1_STRING_TABLE *stable_get(int nid)
150e1051a39Sopenharmony_ci{
151e1051a39Sopenharmony_ci    ASN1_STRING_TABLE *tmp, *rv;
152e1051a39Sopenharmony_ci
153e1051a39Sopenharmony_ci    /* Always need a string table so allocate one if NULL */
154e1051a39Sopenharmony_ci    if (stable == NULL) {
155e1051a39Sopenharmony_ci        stable = sk_ASN1_STRING_TABLE_new(sk_table_cmp);
156e1051a39Sopenharmony_ci        if (stable == NULL)
157e1051a39Sopenharmony_ci            return NULL;
158e1051a39Sopenharmony_ci    }
159e1051a39Sopenharmony_ci    tmp = ASN1_STRING_TABLE_get(nid);
160e1051a39Sopenharmony_ci    if (tmp != NULL && tmp->flags & STABLE_FLAGS_MALLOC)
161e1051a39Sopenharmony_ci        return tmp;
162e1051a39Sopenharmony_ci    if ((rv = OPENSSL_zalloc(sizeof(*rv))) == NULL) {
163e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_ASN1, ERR_R_MALLOC_FAILURE);
164e1051a39Sopenharmony_ci        return NULL;
165e1051a39Sopenharmony_ci    }
166e1051a39Sopenharmony_ci    if (!sk_ASN1_STRING_TABLE_push(stable, rv)) {
167e1051a39Sopenharmony_ci        OPENSSL_free(rv);
168e1051a39Sopenharmony_ci        return NULL;
169e1051a39Sopenharmony_ci    }
170e1051a39Sopenharmony_ci    if (tmp != NULL) {
171e1051a39Sopenharmony_ci        rv->nid = tmp->nid;
172e1051a39Sopenharmony_ci        rv->minsize = tmp->minsize;
173e1051a39Sopenharmony_ci        rv->maxsize = tmp->maxsize;
174e1051a39Sopenharmony_ci        rv->mask = tmp->mask;
175e1051a39Sopenharmony_ci        rv->flags = tmp->flags | STABLE_FLAGS_MALLOC;
176e1051a39Sopenharmony_ci    } else {
177e1051a39Sopenharmony_ci        rv->nid = nid;
178e1051a39Sopenharmony_ci        rv->minsize = -1;
179e1051a39Sopenharmony_ci        rv->maxsize = -1;
180e1051a39Sopenharmony_ci        rv->flags = STABLE_FLAGS_MALLOC;
181e1051a39Sopenharmony_ci    }
182e1051a39Sopenharmony_ci    return rv;
183e1051a39Sopenharmony_ci}
184e1051a39Sopenharmony_ci
185e1051a39Sopenharmony_ciint ASN1_STRING_TABLE_add(int nid,
186e1051a39Sopenharmony_ci                          long minsize, long maxsize, unsigned long mask,
187e1051a39Sopenharmony_ci                          unsigned long flags)
188e1051a39Sopenharmony_ci{
189e1051a39Sopenharmony_ci    ASN1_STRING_TABLE *tmp;
190e1051a39Sopenharmony_ci
191e1051a39Sopenharmony_ci    tmp = stable_get(nid);
192e1051a39Sopenharmony_ci    if (tmp == NULL) {
193e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_ASN1, ERR_R_MALLOC_FAILURE);
194e1051a39Sopenharmony_ci        return 0;
195e1051a39Sopenharmony_ci    }
196e1051a39Sopenharmony_ci    if (minsize >= 0)
197e1051a39Sopenharmony_ci        tmp->minsize = minsize;
198e1051a39Sopenharmony_ci    if (maxsize >= 0)
199e1051a39Sopenharmony_ci        tmp->maxsize = maxsize;
200e1051a39Sopenharmony_ci    if (mask)
201e1051a39Sopenharmony_ci        tmp->mask = mask;
202e1051a39Sopenharmony_ci    if (flags)
203e1051a39Sopenharmony_ci        tmp->flags = STABLE_FLAGS_MALLOC | flags;
204e1051a39Sopenharmony_ci    return 1;
205e1051a39Sopenharmony_ci}
206e1051a39Sopenharmony_ci
207e1051a39Sopenharmony_civoid ASN1_STRING_TABLE_cleanup(void)
208e1051a39Sopenharmony_ci{
209e1051a39Sopenharmony_ci    STACK_OF(ASN1_STRING_TABLE) *tmp;
210e1051a39Sopenharmony_ci
211e1051a39Sopenharmony_ci    tmp = stable;
212e1051a39Sopenharmony_ci    if (tmp == NULL)
213e1051a39Sopenharmony_ci        return;
214e1051a39Sopenharmony_ci    stable = NULL;
215e1051a39Sopenharmony_ci    sk_ASN1_STRING_TABLE_pop_free(tmp, st_free);
216e1051a39Sopenharmony_ci}
217e1051a39Sopenharmony_ci
218e1051a39Sopenharmony_cistatic void st_free(ASN1_STRING_TABLE *tbl)
219e1051a39Sopenharmony_ci{
220e1051a39Sopenharmony_ci    if (tbl->flags & STABLE_FLAGS_MALLOC)
221e1051a39Sopenharmony_ci        OPENSSL_free(tbl);
222e1051a39Sopenharmony_ci}
223