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