1 /* Copyright (C) 1995-1998 Eric Young (eay (at) cryptsoft.com) 2 * All rights reserved. 3 * 4 * This package is an SSL implementation written 5 * by Eric Young (eay (at) cryptsoft.com). 6 * The implementation was written so as to conform with Netscapes SSL. 7 * 8 * This library is free for commercial and non-commercial use as long as 9 * the following conditions are aheared to. The following conditions 10 * apply to all code found in this distribution, be it the RC4, RSA, 11 * lhash, DES, etc., code; not just the SSL code. The SSL documentation 12 * included with this distribution is covered by the same copyright terms 13 * except that the holder is Tim Hudson (tjh (at) cryptsoft.com). 14 * 15 * Copyright remains Eric Young's, and as such any Copyright notices in 16 * the code are not to be removed. 17 * If this package is used in a product, Eric Young should be given attribution 18 * as the author of the parts of the library used. 19 * This can be in the form of a textual message at program startup or 20 * in documentation (online or textual) provided with the package. 21 * 22 * Redistribution and use in source and binary forms, with or without 23 * modification, are permitted provided that the following conditions 24 * are met: 25 * 1. Redistributions of source code must retain the copyright 26 * notice, this list of conditions and the following disclaimer. 27 * 2. Redistributions in binary form must reproduce the above copyright 28 * notice, this list of conditions and the following disclaimer in the 29 * documentation and/or other materials provided with the distribution. 30 * 3. All advertising materials mentioning features or use of this software 31 * must display the following acknowledgement: 32 * "This product includes cryptographic software written by 33 * Eric Young (eay (at) cryptsoft.com)" 34 * The word 'cryptographic' can be left out if the rouines from the library 35 * being used are not cryptographic related :-). 36 * 4. If you include any Windows specific code (or a derivative thereof) from 37 * the apps directory (application code) you must include an acknowledgement: 38 * "This product includes software written by Tim Hudson (tjh (at) cryptsoft.com)" 39 * 40 * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND 41 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 42 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 43 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 44 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 45 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 46 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 47 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 48 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 49 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 50 * SUCH DAMAGE. 51 * 52 * The licence and distribution terms for any publically available version or 53 * derivative of this code cannot be changed. i.e. this code cannot simply be 54 * copied and put under another distribution licence 55 * [including the GNU Public Licence.] */ 56 57 #if !defined(__STDC_FORMAT_MACROS) 58 #define __STDC_FORMAT_MACROS 59 #endif 60 61 #include <openssl/obj.h> 62 63 #include <inttypes.h> 64 #include <limits.h> 65 #include <string.h> 66 67 #include <openssl/asn1.h> 68 #include <openssl/buf.h> 69 #include <openssl/bytestring.h> 70 #include <openssl/err.h> 71 #include <openssl/lhash.h> 72 #include <openssl/mem.h> 73 #include <openssl/thread.h> 74 75 #include "obj_dat.h" 76 #include "../internal.h" 77 78 79 static struct CRYPTO_STATIC_MUTEX global_added_lock = CRYPTO_STATIC_MUTEX_INIT; 80 // These globals are protected by |global_added_lock|. 81 static LHASH_OF(ASN1_OBJECT) *global_added_by_data = NULL; 82 static LHASH_OF(ASN1_OBJECT) *global_added_by_nid = NULL; 83 static LHASH_OF(ASN1_OBJECT) *global_added_by_short_name = NULL; 84 static LHASH_OF(ASN1_OBJECT) *global_added_by_long_name = NULL; 85 86 static struct CRYPTO_STATIC_MUTEX global_next_nid_lock = 87 CRYPTO_STATIC_MUTEX_INIT; 88 static unsigned global_next_nid = NUM_NID; 89 90 static int obj_next_nid(void) { 91 int ret; 92 93 CRYPTO_STATIC_MUTEX_lock_write(&global_next_nid_lock); 94 ret = global_next_nid++; 95 CRYPTO_STATIC_MUTEX_unlock_write(&global_next_nid_lock); 96 97 return ret; 98 } 99 100 ASN1_OBJECT *OBJ_dup(const ASN1_OBJECT *o) { 101 ASN1_OBJECT *r; 102 unsigned char *data = NULL; 103 char *sn = NULL, *ln = NULL; 104 105 if (o == NULL) { 106 return NULL; 107 } 108 109 if (!(o->flags & ASN1_OBJECT_FLAG_DYNAMIC)) { 110 // TODO(fork): this is a little dangerous. 111 return (ASN1_OBJECT *)o; 112 } 113 114 r = ASN1_OBJECT_new(); 115 if (r == NULL) { 116 OPENSSL_PUT_ERROR(OBJ, ERR_R_ASN1_LIB); 117 return NULL; 118 } 119 r->ln = r->sn = NULL; 120 121 data = OPENSSL_malloc(o->length); 122 if (data == NULL) { 123 goto err; 124 } 125 if (o->data != NULL) { 126 OPENSSL_memcpy(data, o->data, o->length); 127 } 128 129 // once data is attached to an object, it remains const 130 r->data = data; 131 r->length = o->length; 132 r->nid = o->nid; 133 134 if (o->ln != NULL) { 135 ln = OPENSSL_strdup(o->ln); 136 if (ln == NULL) { 137 goto err; 138 } 139 } 140 141 if (o->sn != NULL) { 142 sn = OPENSSL_strdup(o->sn); 143 if (sn == NULL) { 144 goto err; 145 } 146 } 147 148 r->sn = sn; 149 r->ln = ln; 150 151 r->flags = 152 o->flags | (ASN1_OBJECT_FLAG_DYNAMIC | ASN1_OBJECT_FLAG_DYNAMIC_STRINGS | 153 ASN1_OBJECT_FLAG_DYNAMIC_DATA); 154 return r; 155 156 err: 157 OPENSSL_PUT_ERROR(OBJ, ERR_R_MALLOC_FAILURE); 158 OPENSSL_free(ln); 159 OPENSSL_free(sn); 160 OPENSSL_free(data); 161 OPENSSL_free(r); 162 return NULL; 163 } 164 165 int OBJ_cmp(const ASN1_OBJECT *a, const ASN1_OBJECT *b) { 166 int ret; 167 168 ret = a->length - b->length; 169 if (ret) { 170 return ret; 171 } 172 return OPENSSL_memcmp(a->data, b->data, a->length); 173 } 174 175 const uint8_t *OBJ_get0_data(const ASN1_OBJECT *obj) { 176 if (obj == NULL) { 177 return NULL; 178 } 179 180 return obj->data; 181 } 182 183 size_t OBJ_length(const ASN1_OBJECT *obj) { 184 if (obj == NULL || obj->length < 0) { 185 return 0; 186 } 187 188 return (size_t)obj->length; 189 } 190 191 // obj_cmp is called to search the kNIDsInOIDOrder array. The |key| argument is 192 // an |ASN1_OBJECT|* that we're looking for and |element| is a pointer to an 193 // unsigned int in the array. 194 static int obj_cmp(const void *key, const void *element) { 195 unsigned nid = *((const unsigned*) element); 196 const ASN1_OBJECT *a = key; 197 const ASN1_OBJECT *b = &kObjects[nid]; 198 199 if (a->length < b->length) { 200 return -1; 201 } else if (a->length > b->length) { 202 return 1; 203 } 204 return OPENSSL_memcmp(a->data, b->data, a->length); 205 } 206 207 int OBJ_obj2nid(const ASN1_OBJECT *obj) { 208 const unsigned int *nid_ptr; 209 210 if (obj == NULL) { 211 return NID_undef; 212 } 213 214 if (obj->nid != 0) { 215 return obj->nid; 216 } 217 218 CRYPTO_STATIC_MUTEX_lock_read(&global_added_lock); 219 if (global_added_by_data != NULL) { 220 ASN1_OBJECT *match; 221 222 match = lh_ASN1_OBJECT_retrieve(global_added_by_data, obj); 223 if (match != NULL) { 224 CRYPTO_STATIC_MUTEX_unlock_read(&global_added_lock); 225 return match->nid; 226 } 227 } 228 CRYPTO_STATIC_MUTEX_unlock_read(&global_added_lock); 229 230 nid_ptr = bsearch(obj, kNIDsInOIDOrder, OPENSSL_ARRAY_SIZE(kNIDsInOIDOrder), 231 sizeof(kNIDsInOIDOrder[0]), obj_cmp); 232 if (nid_ptr == NULL) { 233 return NID_undef; 234 } 235 236 return kObjects[*nid_ptr].nid; 237 } 238 239 int OBJ_cbs2nid(const CBS *cbs) { 240 if (CBS_len(cbs) > INT_MAX) { 241 return NID_undef; 242 } 243 244 ASN1_OBJECT obj; 245 OPENSSL_memset(&obj, 0, sizeof(obj)); 246 obj.data = CBS_data(cbs); 247 obj.length = (int)CBS_len(cbs); 248 249 return OBJ_obj2nid(&obj); 250 } 251 252 // short_name_cmp is called to search the kNIDsInShortNameOrder array. The 253 // |key| argument is name that we're looking for and |element| is a pointer to 254 // an unsigned int in the array. 255 static int short_name_cmp(const void *key, const void *element) { 256 const char *name = (const char *) key; 257 unsigned nid = *((unsigned*) element); 258 259 return strcmp(name, kObjects[nid].sn); 260 } 261 262 int OBJ_sn2nid(const char *short_name) { 263 const unsigned int *nid_ptr; 264 265 CRYPTO_STATIC_MUTEX_lock_read(&global_added_lock); 266 if (global_added_by_short_name != NULL) { 267 ASN1_OBJECT *match, template; 268 269 template.sn = short_name; 270 match = lh_ASN1_OBJECT_retrieve(global_added_by_short_name, &template); 271 if (match != NULL) { 272 CRYPTO_STATIC_MUTEX_unlock_read(&global_added_lock); 273 return match->nid; 274 } 275 } 276 CRYPTO_STATIC_MUTEX_unlock_read(&global_added_lock); 277 278 nid_ptr = bsearch(short_name, kNIDsInShortNameOrder, 279 OPENSSL_ARRAY_SIZE(kNIDsInShortNameOrder), 280 sizeof(kNIDsInShortNameOrder[0]), short_name_cmp); 281 if (nid_ptr == NULL) { 282 return NID_undef; 283 } 284 285 return kObjects[*nid_ptr].nid; 286 } 287 288 // long_name_cmp is called to search the kNIDsInLongNameOrder array. The 289 // |key| argument is name that we're looking for and |element| is a pointer to 290 // an unsigned int in the array. 291 static int long_name_cmp(const void *key, const void *element) { 292 const char *name = (const char *) key; 293 unsigned nid = *((unsigned*) element); 294 295 return strcmp(name, kObjects[nid].ln); 296 } 297 298 int OBJ_ln2nid(const char *long_name) { 299 const unsigned int *nid_ptr; 300 301 CRYPTO_STATIC_MUTEX_lock_read(&global_added_lock); 302 if (global_added_by_long_name != NULL) { 303 ASN1_OBJECT *match, template; 304 305 template.ln = long_name; 306 match = lh_ASN1_OBJECT_retrieve(global_added_by_long_name, &template); 307 if (match != NULL) { 308 CRYPTO_STATIC_MUTEX_unlock_read(&global_added_lock); 309 return match->nid; 310 } 311 } 312 CRYPTO_STATIC_MUTEX_unlock_read(&global_added_lock); 313 314 nid_ptr = bsearch(long_name, kNIDsInLongNameOrder, 315 OPENSSL_ARRAY_SIZE(kNIDsInLongNameOrder), 316 sizeof(kNIDsInLongNameOrder[0]), long_name_cmp); 317 if (nid_ptr == NULL) { 318 return NID_undef; 319 } 320 321 return kObjects[*nid_ptr].nid; 322 } 323 324 int OBJ_txt2nid(const char *s) { 325 ASN1_OBJECT *obj; 326 int nid; 327 328 obj = OBJ_txt2obj(s, 0 /* search names */); 329 nid = OBJ_obj2nid(obj); 330 ASN1_OBJECT_free(obj); 331 return nid; 332 } 333 334 OPENSSL_EXPORT int OBJ_nid2cbb(CBB *out, int nid) { 335 const ASN1_OBJECT *obj = OBJ_nid2obj(nid); 336 CBB oid; 337 338 if (obj == NULL || 339 !CBB_add_asn1(out, &oid, CBS_ASN1_OBJECT) || 340 !CBB_add_bytes(&oid, obj->data, obj->length) || 341 !CBB_flush(out)) { 342 return 0; 343 } 344 345 return 1; 346 } 347 348 const ASN1_OBJECT *OBJ_nid2obj(int nid) { 349 if (nid >= 0 && nid < NUM_NID) { 350 if (nid != NID_undef && kObjects[nid].nid == NID_undef) { 351 goto err; 352 } 353 return &kObjects[nid]; 354 } 355 356 CRYPTO_STATIC_MUTEX_lock_read(&global_added_lock); 357 if (global_added_by_nid != NULL) { 358 ASN1_OBJECT *match, template; 359 360 template.nid = nid; 361 match = lh_ASN1_OBJECT_retrieve(global_added_by_nid, &template); 362 if (match != NULL) { 363 CRYPTO_STATIC_MUTEX_unlock_read(&global_added_lock); 364 return match; 365 } 366 } 367 CRYPTO_STATIC_MUTEX_unlock_read(&global_added_lock); 368 369 err: 370 OPENSSL_PUT_ERROR(OBJ, OBJ_R_UNKNOWN_NID); 371 return NULL; 372 } 373 374 const char *OBJ_nid2sn(int nid) { 375 const ASN1_OBJECT *obj = OBJ_nid2obj(nid); 376 if (obj == NULL) { 377 return NULL; 378 } 379 380 return obj->sn; 381 } 382 383 const char *OBJ_nid2ln(int nid) { 384 const ASN1_OBJECT *obj = OBJ_nid2obj(nid); 385 if (obj == NULL) { 386 return NULL; 387 } 388 389 return obj->ln; 390 } 391 392 static ASN1_OBJECT *create_object_with_text_oid(int (*get_nid)(void), 393 const char *oid, 394 const char *short_name, 395 const char *long_name) { 396 uint8_t *buf; 397 size_t len; 398 CBB cbb; 399 if (!CBB_init(&cbb, 32) || 400 !CBB_add_asn1_oid_from_text(&cbb, oid, strlen(oid)) || 401 !CBB_finish(&cbb, &buf, &len)) { 402 OPENSSL_PUT_ERROR(OBJ, OBJ_R_INVALID_OID_STRING); 403 CBB_cleanup(&cbb); 404 return NULL; 405 } 406 407 ASN1_OBJECT *ret = ASN1_OBJECT_create(get_nid ? get_nid() : NID_undef, buf, 408 len, short_name, long_name); 409 OPENSSL_free(buf); 410 return ret; 411 } 412 413 ASN1_OBJECT *OBJ_txt2obj(const char *s, int dont_search_names) { 414 if (!dont_search_names) { 415 int nid = OBJ_sn2nid(s); 416 if (nid == NID_undef) { 417 nid = OBJ_ln2nid(s); 418 } 419 420 if (nid != NID_undef) { 421 return (ASN1_OBJECT*) OBJ_nid2obj(nid); 422 } 423 } 424 425 return create_object_with_text_oid(NULL, s, NULL, NULL); 426 } 427 428 static int strlcpy_int(char *dst, const char *src, int dst_size) { 429 size_t ret = BUF_strlcpy(dst, src, dst_size < 0 ? 0 : (size_t)dst_size); 430 if (ret > INT_MAX) { 431 OPENSSL_PUT_ERROR(OBJ, ERR_R_OVERFLOW); 432 return -1; 433 } 434 return (int)ret; 435 } 436 437 int OBJ_obj2txt(char *out, int out_len, const ASN1_OBJECT *obj, 438 int always_return_oid) { 439 // Python depends on the empty OID successfully encoding as the empty 440 // string. 441 if (obj == NULL || obj->length == 0) { 442 return strlcpy_int(out, "", out_len); 443 } 444 445 if (!always_return_oid) { 446 int nid = OBJ_obj2nid(obj); 447 if (nid != NID_undef) { 448 const char *name = OBJ_nid2ln(nid); 449 if (name == NULL) { 450 name = OBJ_nid2sn(nid); 451 } 452 if (name != NULL) { 453 return strlcpy_int(out, name, out_len); 454 } 455 } 456 } 457 458 CBS cbs; 459 CBS_init(&cbs, obj->data, obj->length); 460 char *txt = CBS_asn1_oid_to_text(&cbs); 461 if (txt == NULL) { 462 if (out_len > 0) { 463 out[0] = '\0'; 464 } 465 return -1; 466 } 467 468 int ret = strlcpy_int(out, txt, out_len); 469 OPENSSL_free(txt); 470 return ret; 471 } 472 473 static uint32_t hash_nid(const ASN1_OBJECT *obj) { 474 return obj->nid; 475 } 476 477 static int cmp_nid(const ASN1_OBJECT *a, const ASN1_OBJECT *b) { 478 return a->nid - b->nid; 479 } 480 481 static uint32_t hash_data(const ASN1_OBJECT *obj) { 482 return OPENSSL_hash32(obj->data, obj->length); 483 } 484 485 static int cmp_data(const ASN1_OBJECT *a, const ASN1_OBJECT *b) { 486 int i = a->length - b->length; 487 if (i) { 488 return i; 489 } 490 return OPENSSL_memcmp(a->data, b->data, a->length); 491 } 492 493 static uint32_t hash_short_name(const ASN1_OBJECT *obj) { 494 return lh_strhash(obj->sn); 495 } 496 497 static int cmp_short_name(const ASN1_OBJECT *a, const ASN1_OBJECT *b) { 498 return strcmp(a->sn, b->sn); 499 } 500 501 static uint32_t hash_long_name(const ASN1_OBJECT *obj) { 502 return lh_strhash(obj->ln); 503 } 504 505 static int cmp_long_name(const ASN1_OBJECT *a, const ASN1_OBJECT *b) { 506 return strcmp(a->ln, b->ln); 507 } 508 509 // obj_add_object inserts |obj| into the various global hashes for run-time 510 // added objects. It returns one on success or zero otherwise. 511 static int obj_add_object(ASN1_OBJECT *obj) { 512 int ok; 513 ASN1_OBJECT *old_object; 514 515 obj->flags &= ~(ASN1_OBJECT_FLAG_DYNAMIC | ASN1_OBJECT_FLAG_DYNAMIC_STRINGS | 516 ASN1_OBJECT_FLAG_DYNAMIC_DATA); 517 518 CRYPTO_STATIC_MUTEX_lock_write(&global_added_lock); 519 if (global_added_by_nid == NULL) { 520 global_added_by_nid = lh_ASN1_OBJECT_new(hash_nid, cmp_nid); 521 global_added_by_data = lh_ASN1_OBJECT_new(hash_data, cmp_data); 522 global_added_by_short_name = lh_ASN1_OBJECT_new(hash_short_name, cmp_short_name); 523 global_added_by_long_name = lh_ASN1_OBJECT_new(hash_long_name, cmp_long_name); 524 } 525 526 // We don't pay attention to |old_object| (which contains any previous object 527 // that was evicted from the hashes) because we don't have a reference count 528 // on ASN1_OBJECT values. Also, we should never have duplicates nids and so 529 // should always have objects in |global_added_by_nid|. 530 531 ok = lh_ASN1_OBJECT_insert(global_added_by_nid, &old_object, obj); 532 if (obj->length != 0 && obj->data != NULL) { 533 ok &= lh_ASN1_OBJECT_insert(global_added_by_data, &old_object, obj); 534 } 535 if (obj->sn != NULL) { 536 ok &= lh_ASN1_OBJECT_insert(global_added_by_short_name, &old_object, obj); 537 } 538 if (obj->ln != NULL) { 539 ok &= lh_ASN1_OBJECT_insert(global_added_by_long_name, &old_object, obj); 540 } 541 CRYPTO_STATIC_MUTEX_unlock_write(&global_added_lock); 542 543 return ok; 544 } 545 546 int OBJ_create(const char *oid, const char *short_name, const char *long_name) { 547 ASN1_OBJECT *op = 548 create_object_with_text_oid(obj_next_nid, oid, short_name, long_name); 549 if (op == NULL || 550 !obj_add_object(op)) { 551 return NID_undef; 552 } 553 return op->nid; 554 } 555