1 /* $OpenBSD: a_strnid.c,v 1.24 2021/12/13 14:06:17 schwarze 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 <stdio.h> 62 #include <stdlib.h> 63 #include <string.h> 64 65 #include <openssl/asn1.h> 66 #include <openssl/err.h> 67 #include <openssl/objects.h> 68 69 static STACK_OF(ASN1_STRING_TABLE) *stable = NULL; 70 71 static ASN1_STRING_TABLE *stable_get(int nid); 72 static void st_free(ASN1_STRING_TABLE *tbl); 73 static int sk_table_cmp(const ASN1_STRING_TABLE * const *a, 74 const ASN1_STRING_TABLE * const *b); 75 76 77 /* 78 * This is the global mask for the mbstring functions: this is used to 79 * mask out certain types (such as BMPString and UTF8String) because 80 * certain software (e.g. Netscape) has problems with them. 81 */ 82 83 static unsigned long global_mask = B_ASN1_UTF8STRING; 84 85 void 86 ASN1_STRING_set_default_mask(unsigned long mask) 87 { 88 global_mask = mask; 89 } 90 91 unsigned long 92 ASN1_STRING_get_default_mask(void) 93 { 94 return global_mask; 95 } 96 97 /* 98 * This function sets the default to various "flavours" of configuration 99 * based on an ASCII string. Currently this is: 100 * MASK:XXXX : a numerical mask value. 101 * nobmp : Don't use BMPStrings (just Printable, T61). 102 * pkix : PKIX recommendation in RFC2459. 103 * utf8only : only use UTF8Strings (RFC2459 recommendation for 2004). 104 * default: the default value, Printable, T61, BMP. 105 */ 106 107 int 108 ASN1_STRING_set_default_mask_asc(const char *p) 109 { 110 unsigned long mask; 111 char *end; 112 int save_errno; 113 114 if (strncmp(p, "MASK:", 5) == 0) { 115 if (p[5] == '\0') 116 return 0; 117 save_errno = errno; 118 errno = 0; 119 mask = strtoul(p + 5, &end, 0); 120 if (errno == ERANGE && mask == ULONG_MAX) 121 return 0; 122 errno = save_errno; 123 if (*end != '\0') 124 return 0; 125 } else if (strcmp(p, "nombstr") == 0) 126 mask = ~((unsigned long)(B_ASN1_BMPSTRING|B_ASN1_UTF8STRING)); 127 else if (strcmp(p, "pkix") == 0) 128 mask = ~((unsigned long)B_ASN1_T61STRING); 129 else if (strcmp(p, "utf8only") == 0) 130 mask = B_ASN1_UTF8STRING; 131 else if (strcmp(p, "default") == 0) 132 mask = 0xFFFFFFFFL; 133 else 134 return 0; 135 ASN1_STRING_set_default_mask(mask); 136 return 1; 137 } 138 139 /* 140 * The following function generates an ASN1_STRING based on limits in a table. 141 * Frequently the types and length of an ASN1_STRING are restricted by a 142 * corresponding OID. For example certificates and certificate requests. 143 */ 144 145 ASN1_STRING * 146 ASN1_STRING_set_by_NID(ASN1_STRING **out, const unsigned char *in, int inlen, 147 int inform, int nid) 148 { 149 ASN1_STRING_TABLE *tbl; 150 ASN1_STRING *str = NULL; 151 unsigned long mask; 152 int ret; 153 154 if (out == NULL) 155 out = &str; 156 tbl = ASN1_STRING_TABLE_get(nid); 157 if (tbl != NULL) { 158 mask = tbl->mask; 159 if ((tbl->flags & STABLE_NO_MASK) == 0) 160 mask &= global_mask; 161 ret = ASN1_mbstring_ncopy(out, in, inlen, inform, mask, 162 tbl->minsize, tbl->maxsize); 163 } else 164 ret = ASN1_mbstring_copy(out, in, inlen, inform, 165 DIRSTRING_TYPE & global_mask); 166 if (ret <= 0) 167 return NULL; 168 return *out; 169 } 170 171 /* 172 * Now the tables and helper functions for the string table: 173 */ 174 175 /* size limits: this stuff is taken straight from RFC3280 */ 176 177 #define ub_name 32768 178 #define ub_common_name 64 179 #define ub_locality_name 128 180 #define ub_state_name 128 181 #define ub_organization_name 64 182 #define ub_organization_unit_name 64 183 #define ub_title 64 184 #define ub_email_address 128 185 #define ub_serial_number 64 186 187 188 /* This table must be kept in NID order */ 189 190 static const ASN1_STRING_TABLE tbl_standard[] = { 191 {NID_commonName, 1, ub_common_name, DIRSTRING_TYPE, 0}, 192 {NID_countryName, 2, 2, B_ASN1_PRINTABLESTRING, STABLE_NO_MASK}, 193 {NID_localityName, 1, ub_locality_name, DIRSTRING_TYPE, 0}, 194 {NID_stateOrProvinceName, 1, ub_state_name, DIRSTRING_TYPE, 0}, 195 {NID_organizationName, 1, ub_organization_name, DIRSTRING_TYPE, 0}, 196 {NID_organizationalUnitName, 1, ub_organization_unit_name, DIRSTRING_TYPE, 0}, 197 {NID_pkcs9_emailAddress, 1, ub_email_address, B_ASN1_IA5STRING, STABLE_NO_MASK}, 198 {NID_pkcs9_unstructuredName, 1, -1, PKCS9STRING_TYPE, 0}, 199 {NID_pkcs9_challengePassword, 1, -1, PKCS9STRING_TYPE, 0}, 200 {NID_pkcs9_unstructuredAddress, 1, -1, DIRSTRING_TYPE, 0}, 201 {NID_givenName, 1, ub_name, DIRSTRING_TYPE, 0}, 202 {NID_surname, 1, ub_name, DIRSTRING_TYPE, 0}, 203 {NID_initials, 1, ub_name, DIRSTRING_TYPE, 0}, 204 {NID_serialNumber, 1, ub_serial_number, B_ASN1_PRINTABLESTRING, STABLE_NO_MASK}, 205 {NID_friendlyName, -1, -1, B_ASN1_BMPSTRING, STABLE_NO_MASK}, 206 {NID_name, 1, ub_name, DIRSTRING_TYPE, 0}, 207 {NID_dnQualifier, -1, -1, B_ASN1_PRINTABLESTRING, STABLE_NO_MASK}, 208 {NID_domainComponent, 1, -1, B_ASN1_IA5STRING, STABLE_NO_MASK}, 209 {NID_ms_csp_name, -1, -1, B_ASN1_BMPSTRING, STABLE_NO_MASK} 210 }; 211 212 static int 213 sk_table_cmp(const ASN1_STRING_TABLE * const *a, 214 const ASN1_STRING_TABLE * const *b) 215 { 216 return (*a)->nid - (*b)->nid; 217 } 218 219 static int table_cmp_BSEARCH_CMP_FN(const void *, const void *); 220 static int table_cmp(ASN1_STRING_TABLE const *, ASN1_STRING_TABLE const *); 221 static ASN1_STRING_TABLE *OBJ_bsearch_table(ASN1_STRING_TABLE *key, ASN1_STRING_TABLE const *base, int num); 222 223 static int 224 table_cmp(const ASN1_STRING_TABLE *a, const ASN1_STRING_TABLE *b) 225 { 226 return a->nid - b->nid; 227 } 228 229 230 static int 231 table_cmp_BSEARCH_CMP_FN(const void *a_, const void *b_) 232 { 233 ASN1_STRING_TABLE const *a = a_; 234 ASN1_STRING_TABLE const *b = b_; 235 return table_cmp(a, b); 236 } 237 238 static ASN1_STRING_TABLE * 239 OBJ_bsearch_table(ASN1_STRING_TABLE *key, ASN1_STRING_TABLE const *base, int num) 240 { 241 return (ASN1_STRING_TABLE *)OBJ_bsearch_(key, base, num, sizeof(ASN1_STRING_TABLE), 242 table_cmp_BSEARCH_CMP_FN); 243 } 244 245 ASN1_STRING_TABLE * 246 ASN1_STRING_TABLE_get(int nid) 247 { 248 int idx; 249 ASN1_STRING_TABLE fnd; 250 251 fnd.nid = nid; 252 if (stable != NULL) { 253 idx = sk_ASN1_STRING_TABLE_find(stable, &fnd); 254 if (idx >= 0) 255 return sk_ASN1_STRING_TABLE_value(stable, idx); 256 } 257 return OBJ_bsearch_table(&fnd, tbl_standard, 258 sizeof(tbl_standard)/sizeof(ASN1_STRING_TABLE)); 259 } 260 261 /* 262 * Return a string table pointer which can be modified: either directly 263 * from table or a copy of an internal value added to the table. 264 */ 265 266 static ASN1_STRING_TABLE * 267 stable_get(int nid) 268 { 269 ASN1_STRING_TABLE *tmp, *rv; 270 271 /* Always need a string table so allocate one if NULL */ 272 if (stable == NULL) { 273 stable = sk_ASN1_STRING_TABLE_new(sk_table_cmp); 274 if (stable == NULL) 275 return NULL; 276 } 277 tmp = ASN1_STRING_TABLE_get(nid); 278 if (tmp != NULL && (tmp->flags & STABLE_FLAGS_MALLOC) != 0) 279 return tmp; 280 281 if ((rv = calloc(1, sizeof(*rv))) == NULL) { 282 ASN1error(ERR_R_MALLOC_FAILURE); 283 return NULL; 284 } 285 if (!sk_ASN1_STRING_TABLE_push(stable, rv)) { 286 free(rv); 287 return NULL; 288 } 289 if (tmp != NULL) { 290 rv->nid = tmp->nid; 291 rv->minsize = tmp->minsize; 292 rv->maxsize = tmp->maxsize; 293 rv->mask = tmp->mask; 294 rv->flags = tmp->flags | STABLE_FLAGS_MALLOC; 295 } else { 296 rv->nid = nid; 297 rv->minsize = -1; 298 rv->maxsize = -1; 299 rv->flags = STABLE_FLAGS_MALLOC; 300 } 301 return rv; 302 } 303 304 int 305 ASN1_STRING_TABLE_add(int nid, long minsize, long maxsize, unsigned long mask, 306 unsigned long flags) 307 { 308 ASN1_STRING_TABLE *tmp; 309 310 if ((tmp = stable_get(nid)) == NULL) { 311 ASN1error(ERR_R_MALLOC_FAILURE); 312 return 0; 313 } 314 if (minsize >= 0) 315 tmp->minsize = minsize; 316 if (maxsize >= 0) 317 tmp->maxsize = maxsize; 318 if (mask != 0) 319 tmp->mask = mask; 320 if (flags != 0) 321 tmp->flags = flags | STABLE_FLAGS_MALLOC; 322 323 return 1; 324 } 325 326 void 327 ASN1_STRING_TABLE_cleanup(void) 328 { 329 STACK_OF(ASN1_STRING_TABLE) *tmp; 330 331 tmp = stable; 332 if (tmp == NULL) 333 return; 334 stable = NULL; 335 sk_ASN1_STRING_TABLE_pop_free(tmp, st_free); 336 } 337 338 static void 339 st_free(ASN1_STRING_TABLE *tbl) 340 { 341 if (tbl->flags & STABLE_FLAGS_MALLOC) 342 free(tbl); 343 } 344