Coverage Report

Created: 2026-05-20 07:05

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