xref: /openbsd/lib/libcrypto/asn1/a_strnid.c (revision acf64401)
1 /* $OpenBSD: a_strnid.c,v 1.27 2023/07/05 21:23:36 beck Exp $ */
2 /* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
3  * project 1999.
4  */
5 /* ====================================================================
6  * Copyright (c) 1999 The OpenSSL Project.  All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  *
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in
17  *    the documentation and/or other materials provided with the
18  *    distribution.
19  *
20  * 3. All advertising materials mentioning features or use of this
21  *    software must display the following acknowledgment:
22  *    "This product includes software developed by the OpenSSL Project
23  *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
24  *
25  * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
26  *    endorse or promote products derived from this software without
27  *    prior written permission. For written permission, please contact
28  *    licensing@OpenSSL.org.
29  *
30  * 5. Products derived from this software may not be called "OpenSSL"
31  *    nor may "OpenSSL" appear in their names without prior written
32  *    permission of the OpenSSL Project.
33  *
34  * 6. Redistributions of any form whatsoever must retain the following
35  *    acknowledgment:
36  *    "This product includes software developed by the OpenSSL Project
37  *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
38  *
39  * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
40  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
41  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
42  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
43  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
44  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
45  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
46  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
47  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
48  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
49  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
50  * OF THE POSSIBILITY OF SUCH DAMAGE.
51  * ====================================================================
52  *
53  * This product includes cryptographic software written by Eric Young
54  * (eay@cryptsoft.com).  This product includes software written by Tim
55  * Hudson (tjh@cryptsoft.com).
56  *
57  */
58 
59 #include <errno.h>
60 #include <limits.h>
61 #include <stdlib.h>
62 #include <string.h>
63 
64 #include <openssl/asn1.h>
65 #include <openssl/err.h>
66 #include <openssl/objects.h>
67 
68 static STACK_OF(ASN1_STRING_TABLE) *stable = NULL;
69 
70 static ASN1_STRING_TABLE *stable_get(int nid);
71 static void st_free(ASN1_STRING_TABLE *tbl);
72 static int sk_table_cmp(const ASN1_STRING_TABLE * const *a,
73     const ASN1_STRING_TABLE * const *b);
74 
75 
76 /*
77  * This is the global mask for the mbstring functions: this is used to
78  * mask out certain types (such as BMPString and UTF8String) because
79  * certain software (e.g. Netscape) has problems with them.
80  */
81 
82 static unsigned long global_mask = B_ASN1_UTF8STRING;
83 
84 void
85 ASN1_STRING_set_default_mask(unsigned long mask)
86 {
87 	global_mask = mask;
88 }
89 LCRYPTO_ALIAS(ASN1_STRING_set_default_mask);
90 
91 unsigned long
92 ASN1_STRING_get_default_mask(void)
93 {
94 	return global_mask;
95 }
96 LCRYPTO_ALIAS(ASN1_STRING_get_default_mask);
97 
98 /*
99  * This function sets the default to various "flavours" of configuration
100  * based on an ASCII string. Currently this is:
101  * MASK:XXXX : a numerical mask value.
102  * nobmp : Don't use BMPStrings (just Printable, T61).
103  * pkix : PKIX recommendation in RFC2459.
104  * utf8only : only use UTF8Strings (RFC2459 recommendation for 2004).
105  * default:   the default value, Printable, T61, BMP.
106  */
107 
108 int
109 ASN1_STRING_set_default_mask_asc(const char *p)
110 {
111 	unsigned long mask;
112 	char *end;
113 	int save_errno;
114 
115 	if (strncmp(p, "MASK:", 5) == 0) {
116 		if (p[5] == '\0')
117 			return 0;
118 		save_errno = errno;
119 		errno = 0;
120 		mask = strtoul(p + 5, &end, 0);
121 		if (errno == ERANGE && mask == ULONG_MAX)
122 			return 0;
123 		errno = save_errno;
124 		if (*end != '\0')
125 			return 0;
126 	} else if (strcmp(p, "nombstr") == 0)
127 		mask = ~((unsigned long)(B_ASN1_BMPSTRING|B_ASN1_UTF8STRING));
128 	else if (strcmp(p, "pkix") == 0)
129 		mask = ~((unsigned long)B_ASN1_T61STRING);
130 	else if (strcmp(p, "utf8only") == 0)
131 		mask = B_ASN1_UTF8STRING;
132 	else if (strcmp(p, "default") == 0)
133 		mask = 0xFFFFFFFFL;
134 	else
135 		return 0;
136 	ASN1_STRING_set_default_mask(mask);
137 	return 1;
138 }
139 LCRYPTO_ALIAS(ASN1_STRING_set_default_mask_asc);
140 
141 /*
142  * The following function generates an ASN1_STRING based on limits in a table.
143  * Frequently the types and length of an ASN1_STRING are restricted by a
144  * corresponding OID. For example certificates and certificate requests.
145  */
146 
147 ASN1_STRING *
148 ASN1_STRING_set_by_NID(ASN1_STRING **out, const unsigned char *in, int inlen,
149     int inform, int nid)
150 {
151 	ASN1_STRING_TABLE *tbl;
152 	ASN1_STRING *str = NULL;
153 	unsigned long mask;
154 	int ret;
155 
156 	if (out == NULL)
157 		out = &str;
158 	tbl = ASN1_STRING_TABLE_get(nid);
159 	if (tbl != NULL) {
160 		mask = tbl->mask;
161 		if ((tbl->flags & STABLE_NO_MASK) == 0)
162 			mask &= global_mask;
163 		ret = ASN1_mbstring_ncopy(out, in, inlen, inform, mask,
164 		    tbl->minsize, tbl->maxsize);
165 	} else
166 		ret = ASN1_mbstring_copy(out, in, inlen, inform,
167 		    DIRSTRING_TYPE & global_mask);
168 	if (ret <= 0)
169 		return NULL;
170 	return *out;
171 }
172 LCRYPTO_ALIAS(ASN1_STRING_set_by_NID);
173 
174 /*
175  * Now the tables and helper functions for the string table:
176  */
177 
178 /* size limits: this stuff is taken straight from RFC3280 */
179 
180 #define ub_name				32768
181 #define ub_common_name			64
182 #define ub_locality_name		128
183 #define ub_state_name			128
184 #define ub_organization_name		64
185 #define ub_organization_unit_name	64
186 #define ub_title			64
187 #define ub_email_address		128
188 #define ub_serial_number		64
189 
190 
191 /* This table must be kept in NID order */
192 
193 static const ASN1_STRING_TABLE tbl_standard[] = {
194 	{
195 		.nid = NID_commonName,
196 		.minsize = 1,
197 		.maxsize = ub_common_name,
198 		.mask = DIRSTRING_TYPE,
199 		.flags = 0,
200 	},
201 	{
202 		.nid = NID_countryName,
203 		.minsize = 2,
204 		.maxsize = 2,
205 		.mask = B_ASN1_PRINTABLESTRING,
206 		.flags = STABLE_NO_MASK,
207 	},
208 	{
209 		.nid = NID_localityName,
210 		.minsize = 1,
211 		.maxsize = ub_locality_name,
212 		.mask = DIRSTRING_TYPE,
213 		.flags = 0,
214 	},
215 	{
216 		.nid = NID_stateOrProvinceName,
217 		.minsize = 1,
218 		.maxsize = ub_state_name,
219 		.mask = DIRSTRING_TYPE,
220 		.flags = 0,
221 	},
222 	{
223 		.nid = NID_organizationName,
224 		.minsize = 1,
225 		.maxsize = ub_organization_name,
226 		.mask = DIRSTRING_TYPE,
227 		.flags = 0,
228 	},
229 	{
230 		.nid = NID_organizationalUnitName,
231 		.minsize = 1,
232 		.maxsize = ub_organization_unit_name,
233 		.mask = DIRSTRING_TYPE,
234 		.flags = 0,
235 	},
236 	{
237 		.nid = NID_pkcs9_emailAddress,
238 		.minsize = 1,
239 		.maxsize = ub_email_address,
240 		.mask = B_ASN1_IA5STRING,
241 		.flags = STABLE_NO_MASK,
242 	},
243 	{
244 		.nid = NID_pkcs9_unstructuredName,
245 		.minsize = 1,
246 		.maxsize = -1,
247 		.mask = PKCS9STRING_TYPE,
248 		.flags = 0,
249 	},
250 	{
251 		.nid = NID_pkcs9_challengePassword,
252 		.minsize = 1,
253 		.maxsize = -1,
254 		.mask = PKCS9STRING_TYPE,
255 		.flags = 0,
256 	},
257 	{
258 		.nid = NID_pkcs9_unstructuredAddress,
259 		.minsize = 1,
260 		.maxsize = -1,
261 		.mask = DIRSTRING_TYPE,
262 		.flags = 0,
263 	},
264 	{
265 		.nid = NID_givenName,
266 		.minsize = 1,
267 		.maxsize = ub_name,
268 		.mask = DIRSTRING_TYPE,
269 		.flags = 0,
270 	},
271 	{
272 		.nid = NID_surname,
273 		.minsize = 1,
274 		.maxsize = ub_name,
275 		.mask = DIRSTRING_TYPE,
276 		.flags = 0,
277 	},
278 	{
279 		.nid = NID_initials,
280 		.minsize = 1,
281 		.maxsize = ub_name,
282 		.mask = DIRSTRING_TYPE,
283 		.flags = 0,
284 	},
285 	{
286 		.nid = NID_serialNumber,
287 		.minsize = 1,
288 		.maxsize = ub_serial_number,
289 		.mask = B_ASN1_PRINTABLESTRING,
290 		.flags = STABLE_NO_MASK,
291 	},
292 	{
293 		.nid = NID_friendlyName,
294 		.minsize = -1,
295 		.maxsize = -1,
296 		.mask = B_ASN1_BMPSTRING,
297 		.flags = STABLE_NO_MASK,
298 	},
299 	{
300 		.nid = NID_name,
301 		.minsize = 1,
302 		.maxsize = ub_name,
303 		.mask = DIRSTRING_TYPE,
304 		.flags = 0,
305 	},
306 	{
307 		.nid = NID_dnQualifier,
308 		.minsize = -1,
309 		.maxsize = -1,
310 		.mask = B_ASN1_PRINTABLESTRING,
311 		.flags = STABLE_NO_MASK,
312 	},
313 	{
314 		.nid = NID_domainComponent,
315 		.minsize = 1,
316 		.maxsize = -1,
317 		.mask = B_ASN1_IA5STRING,
318 		.flags = STABLE_NO_MASK,
319 	},
320 	{
321 		.nid = NID_ms_csp_name,
322 		.minsize = -1,
323 		.maxsize = -1,
324 		.mask = B_ASN1_BMPSTRING,
325 		.flags = STABLE_NO_MASK,
326 	},
327 };
328 
329 static int
330 sk_table_cmp(const ASN1_STRING_TABLE * const *a,
331     const ASN1_STRING_TABLE * const *b)
332 {
333 	return (*a)->nid - (*b)->nid;
334 }
335 
336 static int table_cmp_BSEARCH_CMP_FN(const void *, const void *);
337 static int table_cmp(ASN1_STRING_TABLE const *, ASN1_STRING_TABLE const *);
338 static ASN1_STRING_TABLE *OBJ_bsearch_table(ASN1_STRING_TABLE *key, ASN1_STRING_TABLE const *base, int num);
339 
340 static int
341 table_cmp(const ASN1_STRING_TABLE *a, const ASN1_STRING_TABLE *b)
342 {
343 	return a->nid - b->nid;
344 }
345 
346 
347 static int
348 table_cmp_BSEARCH_CMP_FN(const void *a_, const void *b_)
349 {
350 	ASN1_STRING_TABLE const *a = a_;
351 	ASN1_STRING_TABLE const *b = b_;
352 	return table_cmp(a, b);
353 }
354 
355 static ASN1_STRING_TABLE *
356 OBJ_bsearch_table(ASN1_STRING_TABLE *key, ASN1_STRING_TABLE const *base, int num)
357 {
358 	return (ASN1_STRING_TABLE *)OBJ_bsearch_(key, base, num, sizeof(ASN1_STRING_TABLE),
359 	    table_cmp_BSEARCH_CMP_FN);
360 }
361 
362 ASN1_STRING_TABLE *
363 ASN1_STRING_TABLE_get(int nid)
364 {
365 	int idx;
366 	ASN1_STRING_TABLE fnd;
367 
368 	fnd.nid = nid;
369 	if (stable != NULL) {
370 		idx = sk_ASN1_STRING_TABLE_find(stable, &fnd);
371 		if (idx >= 0)
372 			return sk_ASN1_STRING_TABLE_value(stable, idx);
373 	}
374 	return OBJ_bsearch_table(&fnd, tbl_standard,
375 	    sizeof(tbl_standard) / sizeof(tbl_standard[0]));
376 }
377 LCRYPTO_ALIAS(ASN1_STRING_TABLE_get);
378 
379 /*
380  * Return a string table pointer which can be modified: either directly
381  * from table or a copy of an internal value added to the table.
382  */
383 
384 static ASN1_STRING_TABLE *
385 stable_get(int nid)
386 {
387 	ASN1_STRING_TABLE *tmp, *rv;
388 
389 	/* Always need a string table so allocate one if NULL */
390 	if (stable == NULL) {
391 		stable = sk_ASN1_STRING_TABLE_new(sk_table_cmp);
392 		if (stable == NULL)
393 			return NULL;
394 	}
395 	tmp = ASN1_STRING_TABLE_get(nid);
396 	if (tmp != NULL && (tmp->flags & STABLE_FLAGS_MALLOC) != 0)
397 		return tmp;
398 
399 	if ((rv = calloc(1, sizeof(*rv))) == NULL) {
400 		ASN1error(ERR_R_MALLOC_FAILURE);
401 		return NULL;
402 	}
403 	if (!sk_ASN1_STRING_TABLE_push(stable, rv)) {
404 		free(rv);
405 		return NULL;
406 	}
407 	if (tmp != NULL) {
408 		rv->nid = tmp->nid;
409 		rv->minsize = tmp->minsize;
410 		rv->maxsize = tmp->maxsize;
411 		rv->mask = tmp->mask;
412 		rv->flags = tmp->flags | STABLE_FLAGS_MALLOC;
413 	} else {
414 		rv->nid = nid;
415 		rv->minsize = -1;
416 		rv->maxsize = -1;
417 		rv->flags = STABLE_FLAGS_MALLOC;
418 	}
419 	return rv;
420 }
421 
422 int
423 ASN1_STRING_TABLE_add(int nid, long minsize, long maxsize, unsigned long mask,
424     unsigned long flags)
425 {
426 	ASN1_STRING_TABLE *tmp;
427 
428 	if ((tmp = stable_get(nid)) == NULL) {
429 		ASN1error(ERR_R_MALLOC_FAILURE);
430 		return 0;
431 	}
432 	if (minsize >= 0)
433 		tmp->minsize = minsize;
434 	if (maxsize >= 0)
435 		tmp->maxsize = maxsize;
436 	if (mask != 0)
437 		tmp->mask = mask;
438 	if (flags != 0)
439 		tmp->flags = flags | STABLE_FLAGS_MALLOC;
440 
441 	return 1;
442 }
443 LCRYPTO_ALIAS(ASN1_STRING_TABLE_add);
444 
445 void
446 ASN1_STRING_TABLE_cleanup(void)
447 {
448 	STACK_OF(ASN1_STRING_TABLE) *tmp;
449 
450 	tmp = stable;
451 	if (tmp == NULL)
452 		return;
453 	stable = NULL;
454 	sk_ASN1_STRING_TABLE_pop_free(tmp, st_free);
455 }
456 LCRYPTO_ALIAS(ASN1_STRING_TABLE_cleanup);
457 
458 static void
459 st_free(ASN1_STRING_TABLE *tbl)
460 {
461 	if (tbl->flags & STABLE_FLAGS_MALLOC)
462 		free(tbl);
463 }
464