1/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) 2 * All rights reserved. 3 * 4 * This package is an SSL implementation written 5 * by Eric Young (eay@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@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@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@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#include <openssl/obj.h> 58 59#include <limits.h> 60#include <string.h> 61 62#include <openssl/asn1.h> 63#include <openssl/buf.h> 64#include <openssl/bytestring.h> 65#include <openssl/err.h> 66#include <openssl/lhash.h> 67#include <openssl/mem.h> 68#include <openssl/thread.h> 69 70#include "obj_dat.h" 71#include "../internal.h" 72 73 74static struct CRYPTO_STATIC_MUTEX global_added_lock = CRYPTO_STATIC_MUTEX_INIT; 75/* These globals are protected by |global_added_lock|. */ 76static LHASH_OF(ASN1_OBJECT) *global_added_by_data = NULL; 77static LHASH_OF(ASN1_OBJECT) *global_added_by_nid = NULL; 78static LHASH_OF(ASN1_OBJECT) *global_added_by_short_name = NULL; 79static LHASH_OF(ASN1_OBJECT) *global_added_by_long_name = NULL; 80 81static struct CRYPTO_STATIC_MUTEX global_next_nid_lock = 82 CRYPTO_STATIC_MUTEX_INIT; 83static unsigned global_next_nid = NUM_NID; 84 85static int obj_next_nid(void) { 86 int ret; 87 88 CRYPTO_STATIC_MUTEX_lock_write(&global_next_nid_lock); 89 ret = global_next_nid++; 90 CRYPTO_STATIC_MUTEX_unlock(&global_next_nid_lock); 91 92 return ret; 93} 94 95ASN1_OBJECT *OBJ_dup(const ASN1_OBJECT *o) { 96 ASN1_OBJECT *r; 97 unsigned char *data = NULL; 98 char *sn = NULL, *ln = NULL; 99 100 if (o == NULL) { 101 return NULL; 102 } 103 104 if (!(o->flags & ASN1_OBJECT_FLAG_DYNAMIC)) { 105 /* TODO(fork): this is a little dangerous. */ 106 return (ASN1_OBJECT *)o; 107 } 108 109 r = ASN1_OBJECT_new(); 110 if (r == NULL) { 111 OPENSSL_PUT_ERROR(OBJ, OBJ_dup, ERR_R_ASN1_LIB); 112 return NULL; 113 } 114 r->ln = r->sn = NULL; 115 116 data = OPENSSL_malloc(o->length); 117 if (data == NULL) { 118 goto err; 119 } 120 if (o->data != NULL) { 121 memcpy(data, o->data, o->length); 122 } 123 124 /* once data is attached to an object, it remains const */ 125 r->data = data; 126 r->length = o->length; 127 r->nid = o->nid; 128 129 if (o->ln != NULL) { 130 ln = OPENSSL_strdup(o->ln); 131 if (ln == NULL) { 132 goto err; 133 } 134 } 135 136 if (o->sn != NULL) { 137 sn = OPENSSL_strdup(o->sn); 138 if (sn == NULL) { 139 goto err; 140 } 141 } 142 143 r->sn = sn; 144 r->ln = ln; 145 146 r->flags = 147 o->flags | (ASN1_OBJECT_FLAG_DYNAMIC | ASN1_OBJECT_FLAG_DYNAMIC_STRINGS | 148 ASN1_OBJECT_FLAG_DYNAMIC_DATA); 149 return r; 150 151err: 152 OPENSSL_PUT_ERROR(OBJ, OBJ_dup, ERR_R_MALLOC_FAILURE); 153 OPENSSL_free(ln); 154 OPENSSL_free(sn); 155 OPENSSL_free(data); 156 OPENSSL_free(r); 157 return NULL; 158} 159 160int OBJ_cmp(const ASN1_OBJECT *a, const ASN1_OBJECT *b) { 161 int ret; 162 163 ret = a->length - b->length; 164 if (ret) { 165 return ret; 166 } 167 return memcmp(a->data, b->data, a->length); 168} 169 170/* obj_cmp is called to search the kNIDsInOIDOrder array. The |key| argument is 171 * an |ASN1_OBJECT|* that we're looking for and |element| is a pointer to an 172 * unsigned int in the array. */ 173static int obj_cmp(const void *key, const void *element) { 174 unsigned nid = *((const unsigned*) element); 175 const ASN1_OBJECT *a = key; 176 const ASN1_OBJECT *b = &kObjects[nid]; 177 178 if (a->length < b->length) { 179 return -1; 180 } else if (a->length > b->length) { 181 return 1; 182 } 183 return memcmp(a->data, b->data, a->length); 184} 185 186int OBJ_obj2nid(const ASN1_OBJECT *obj) { 187 const unsigned int *nid_ptr; 188 189 if (obj == NULL) { 190 return NID_undef; 191 } 192 193 if (obj->nid != 0) { 194 return obj->nid; 195 } 196 197 CRYPTO_STATIC_MUTEX_lock_read(&global_added_lock); 198 if (global_added_by_data != NULL) { 199 ASN1_OBJECT *match; 200 201 match = lh_ASN1_OBJECT_retrieve(global_added_by_data, obj); 202 if (match != NULL) { 203 CRYPTO_STATIC_MUTEX_unlock(&global_added_lock); 204 return match->nid; 205 } 206 } 207 CRYPTO_STATIC_MUTEX_unlock(&global_added_lock); 208 209 nid_ptr = bsearch(obj, kNIDsInOIDOrder, NUM_OBJ, sizeof(unsigned), obj_cmp); 210 if (nid_ptr == NULL) { 211 return NID_undef; 212 } 213 214 return kObjects[*nid_ptr].nid; 215} 216 217int OBJ_cbs2nid(const CBS *cbs) { 218 ASN1_OBJECT obj; 219 memset(&obj, 0, sizeof(obj)); 220 obj.data = CBS_data(cbs); 221 obj.length = CBS_len(cbs); 222 223 return OBJ_obj2nid(&obj); 224} 225 226/* short_name_cmp is called to search the kNIDsInShortNameOrder array. The 227 * |key| argument is name that we're looking for and |element| is a pointer to 228 * an unsigned int in the array. */ 229static int short_name_cmp(const void *key, const void *element) { 230 const char *name = (const char *) key; 231 unsigned nid = *((unsigned*) element); 232 233 return strcmp(name, kObjects[nid].sn); 234} 235 236int OBJ_sn2nid(const char *short_name) { 237 const unsigned int *nid_ptr; 238 239 CRYPTO_STATIC_MUTEX_lock_read(&global_added_lock); 240 if (global_added_by_short_name != NULL) { 241 ASN1_OBJECT *match, template; 242 243 template.sn = short_name; 244 match = lh_ASN1_OBJECT_retrieve(global_added_by_short_name, &template); 245 if (match != NULL) { 246 CRYPTO_STATIC_MUTEX_unlock(&global_added_lock); 247 return match->nid; 248 } 249 } 250 CRYPTO_STATIC_MUTEX_unlock(&global_added_lock); 251 252 nid_ptr = bsearch(short_name, kNIDsInShortNameOrder, NUM_SN, sizeof(unsigned), short_name_cmp); 253 if (nid_ptr == NULL) { 254 return NID_undef; 255 } 256 257 return kObjects[*nid_ptr].nid; 258} 259 260/* long_name_cmp is called to search the kNIDsInLongNameOrder array. The 261 * |key| argument is name that we're looking for and |element| is a pointer to 262 * an unsigned int in the array. */ 263static int long_name_cmp(const void *key, const void *element) { 264 const char *name = (const char *) key; 265 unsigned nid = *((unsigned*) element); 266 267 return strcmp(name, kObjects[nid].ln); 268} 269 270int OBJ_ln2nid(const char *long_name) { 271 const unsigned int *nid_ptr; 272 273 CRYPTO_STATIC_MUTEX_lock_read(&global_added_lock); 274 if (global_added_by_long_name != NULL) { 275 ASN1_OBJECT *match, template; 276 277 template.ln = long_name; 278 match = lh_ASN1_OBJECT_retrieve(global_added_by_long_name, &template); 279 if (match != NULL) { 280 CRYPTO_STATIC_MUTEX_unlock(&global_added_lock); 281 return match->nid; 282 } 283 } 284 CRYPTO_STATIC_MUTEX_unlock(&global_added_lock); 285 286 nid_ptr = bsearch(long_name, kNIDsInLongNameOrder, NUM_LN, sizeof(unsigned), long_name_cmp); 287 if (nid_ptr == NULL) { 288 return NID_undef; 289 } 290 291 return kObjects[*nid_ptr].nid; 292} 293 294int OBJ_txt2nid(const char *s) { 295 ASN1_OBJECT *obj; 296 int nid; 297 298 obj = OBJ_txt2obj(s, 0 /* search names */); 299 nid = OBJ_obj2nid(obj); 300 ASN1_OBJECT_free(obj); 301 return nid; 302} 303 304OPENSSL_EXPORT int OBJ_nid2cbb(CBB *out, int nid) { 305 const ASN1_OBJECT *obj = OBJ_nid2obj(nid); 306 CBB oid; 307 308 if (obj == NULL || 309 !CBB_add_asn1(out, &oid, CBS_ASN1_OBJECT) || 310 !CBB_add_bytes(&oid, obj->data, obj->length) || 311 !CBB_flush(out)) { 312 return 0; 313 } 314 315 return 1; 316} 317 318const ASN1_OBJECT *OBJ_nid2obj(int nid) { 319 if (nid >= 0 && nid < NUM_NID) { 320 if (nid != NID_undef && kObjects[nid].nid == NID_undef) { 321 goto err; 322 } 323 return &kObjects[nid]; 324 } 325 326 CRYPTO_STATIC_MUTEX_lock_read(&global_added_lock); 327 if (global_added_by_nid != NULL) { 328 ASN1_OBJECT *match, template; 329 330 template.nid = nid; 331 match = lh_ASN1_OBJECT_retrieve(global_added_by_nid, &template); 332 if (match != NULL) { 333 CRYPTO_STATIC_MUTEX_unlock(&global_added_lock); 334 return match; 335 } 336 } 337 CRYPTO_STATIC_MUTEX_unlock(&global_added_lock); 338 339err: 340 OPENSSL_PUT_ERROR(OBJ, OBJ_nid2obj, OBJ_R_UNKNOWN_NID); 341 return NULL; 342} 343 344const char *OBJ_nid2sn(int nid) { 345 const ASN1_OBJECT *obj = OBJ_nid2obj(nid); 346 if (obj == NULL) { 347 return NULL; 348 } 349 350 return obj->sn; 351} 352 353const char *OBJ_nid2ln(int nid) { 354 const ASN1_OBJECT *obj = OBJ_nid2obj(nid); 355 if (obj == NULL) { 356 return NULL; 357 } 358 359 return obj->ln; 360} 361 362ASN1_OBJECT *OBJ_txt2obj(const char *s, int dont_search_names) { 363 int nid = NID_undef; 364 ASN1_OBJECT *op = NULL; 365 unsigned char *buf; 366 unsigned char *p; 367 const unsigned char *bufp; 368 int contents_len, total_len; 369 370 if (!dont_search_names) { 371 nid = OBJ_sn2nid(s); 372 if (nid == NID_undef) { 373 nid = OBJ_ln2nid(s); 374 } 375 376 if (nid != NID_undef) { 377 return (ASN1_OBJECT*) OBJ_nid2obj(nid); 378 } 379 } 380 381 /* Work out size of content octets */ 382 contents_len = a2d_ASN1_OBJECT(NULL, 0, s, -1); 383 if (contents_len <= 0) { 384 return NULL; 385 } 386 /* Work out total size */ 387 total_len = ASN1_object_size(0, contents_len, V_ASN1_OBJECT); 388 389 buf = OPENSSL_malloc(total_len); 390 if (buf == NULL) { 391 OPENSSL_PUT_ERROR(OBJ, OBJ_txt2obj, ERR_R_MALLOC_FAILURE); 392 return NULL; 393 } 394 395 p = buf; 396 /* Write out tag+length */ 397 ASN1_put_object(&p, 0, contents_len, V_ASN1_OBJECT, V_ASN1_UNIVERSAL); 398 /* Write out contents */ 399 a2d_ASN1_OBJECT(p, contents_len, s, -1); 400 401 bufp = buf; 402 op = d2i_ASN1_OBJECT(NULL, &bufp, total_len); 403 OPENSSL_free(buf); 404 405 return op; 406} 407 408int OBJ_obj2txt(char *out, int out_len, const ASN1_OBJECT *obj, int dont_return_name) { 409 int i, n = 0, len, nid, first, use_bn; 410 BIGNUM *bl; 411 unsigned long l; 412 const unsigned char *p; 413 char tbuf[DECIMAL_SIZE(i) + DECIMAL_SIZE(l) + 2]; 414 415 if (out && out_len > 0) { 416 out[0] = 0; 417 } 418 419 if (obj == NULL || obj->data == NULL) { 420 return 0; 421 } 422 423 if (!dont_return_name && (nid = OBJ_obj2nid(obj)) != NID_undef) { 424 const char *s; 425 s = OBJ_nid2ln(nid); 426 if (s == NULL) { 427 s = OBJ_nid2sn(nid); 428 } 429 if (s) { 430 if (out) { 431 BUF_strlcpy(out, s, out_len); 432 } 433 return strlen(s); 434 } 435 } 436 437 len = obj->length; 438 p = obj->data; 439 440 first = 1; 441 bl = NULL; 442 443 while (len > 0) { 444 l = 0; 445 use_bn = 0; 446 for (;;) { 447 unsigned char c = *p++; 448 len--; 449 if (len == 0 && (c & 0x80)) { 450 goto err; 451 } 452 if (use_bn) { 453 if (!BN_add_word(bl, c & 0x7f)) { 454 goto err; 455 } 456 } else { 457 l |= c & 0x7f; 458 } 459 if (!(c & 0x80)) { 460 break; 461 } 462 if (!use_bn && (l > (ULONG_MAX >> 7L))) { 463 if (!bl && !(bl = BN_new())) { 464 goto err; 465 } 466 if (!BN_set_word(bl, l)) { 467 goto err; 468 } 469 use_bn = 1; 470 } 471 if (use_bn) { 472 if (!BN_lshift(bl, bl, 7)) { 473 goto err; 474 } 475 } else { 476 l <<= 7L; 477 } 478 } 479 480 if (first) { 481 first = 0; 482 if (l >= 80) { 483 i = 2; 484 if (use_bn) { 485 if (!BN_sub_word(bl, 80)) { 486 goto err; 487 } 488 } else { 489 l -= 80; 490 } 491 } else { 492 i = (int)(l / 40); 493 l -= (long)(i * 40); 494 } 495 if (out && out_len > 1) { 496 *out++ = i + '0'; 497 *out = '0'; 498 out_len--; 499 } 500 n++; 501 } 502 503 if (use_bn) { 504 char *bndec; 505 bndec = BN_bn2dec(bl); 506 if (!bndec) { 507 goto err; 508 } 509 i = strlen(bndec); 510 if (out) { 511 if (out_len > 1) { 512 *out++ = '.'; 513 *out = 0; 514 out_len--; 515 } 516 BUF_strlcpy(out, bndec, out_len); 517 if (i > out_len) { 518 out += out_len; 519 out_len = 0; 520 } else { 521 out += i; 522 out_len -= i; 523 } 524 } 525 n++; 526 n += i; 527 OPENSSL_free(bndec); 528 } else { 529 BIO_snprintf(tbuf, sizeof(tbuf), ".%lu", l); 530 i = strlen(tbuf); 531 if (out && out_len > 0) { 532 BUF_strlcpy(out, tbuf, out_len); 533 if (i > out_len) { 534 out += out_len; 535 out_len = 0; 536 } else { 537 out += i; 538 out_len -= i; 539 } 540 } 541 n += i; 542 } 543 } 544 545 BN_free(bl); 546 return n; 547 548err: 549 BN_free(bl); 550 return -1; 551} 552 553static uint32_t hash_nid(const ASN1_OBJECT *obj) { 554 return obj->nid; 555} 556 557static int cmp_nid(const ASN1_OBJECT *a, const ASN1_OBJECT *b) { 558 return a->nid - b->nid; 559} 560 561static uint32_t hash_data(const ASN1_OBJECT *obj) { 562 return OPENSSL_hash32(obj->data, obj->length); 563} 564 565static int cmp_data(const ASN1_OBJECT *a, const ASN1_OBJECT *b) { 566 int i = a->length - b->length; 567 if (i) { 568 return i; 569 } 570 return memcmp(a->data, b->data, a->length); 571} 572 573static uint32_t hash_short_name(const ASN1_OBJECT *obj) { 574 return lh_strhash(obj->sn); 575} 576 577static int cmp_short_name(const ASN1_OBJECT *a, const ASN1_OBJECT *b) { 578 return strcmp(a->sn, b->sn); 579} 580 581static uint32_t hash_long_name(const ASN1_OBJECT *obj) { 582 return lh_strhash(obj->ln); 583} 584 585static int cmp_long_name(const ASN1_OBJECT *a, const ASN1_OBJECT *b) { 586 return strcmp(a->ln, b->ln); 587} 588 589/* obj_add_object inserts |obj| into the various global hashes for run-time 590 * added objects. It returns one on success or zero otherwise. */ 591static int obj_add_object(ASN1_OBJECT *obj) { 592 int ok; 593 ASN1_OBJECT *old_object; 594 595 obj->flags &= ~(ASN1_OBJECT_FLAG_DYNAMIC | ASN1_OBJECT_FLAG_DYNAMIC_STRINGS | 596 ASN1_OBJECT_FLAG_DYNAMIC_DATA); 597 598 CRYPTO_STATIC_MUTEX_lock_write(&global_added_lock); 599 if (global_added_by_nid == NULL) { 600 global_added_by_nid = lh_ASN1_OBJECT_new(hash_nid, cmp_nid); 601 global_added_by_data = lh_ASN1_OBJECT_new(hash_data, cmp_data); 602 global_added_by_short_name = lh_ASN1_OBJECT_new(hash_short_name, cmp_short_name); 603 global_added_by_long_name = lh_ASN1_OBJECT_new(hash_long_name, cmp_long_name); 604 } 605 606 /* We don't pay attention to |old_object| (which contains any previous object 607 * that was evicted from the hashes) because we don't have a reference count 608 * on ASN1_OBJECT values. Also, we should never have duplicates nids and so 609 * should always have objects in |global_added_by_nid|. */ 610 611 ok = lh_ASN1_OBJECT_insert(global_added_by_nid, &old_object, obj); 612 if (obj->length != 0 && obj->data != NULL) { 613 ok &= lh_ASN1_OBJECT_insert(global_added_by_data, &old_object, obj); 614 } 615 if (obj->sn != NULL) { 616 ok &= lh_ASN1_OBJECT_insert(global_added_by_short_name, &old_object, obj); 617 } 618 if (obj->ln != NULL) { 619 ok &= lh_ASN1_OBJECT_insert(global_added_by_long_name, &old_object, obj); 620 } 621 CRYPTO_STATIC_MUTEX_unlock(&global_added_lock); 622 623 return ok; 624} 625 626int OBJ_create(const char *oid, const char *short_name, const char *long_name) { 627 int ret = NID_undef; 628 ASN1_OBJECT *op = NULL; 629 unsigned char *buf = NULL; 630 int len; 631 632 len = a2d_ASN1_OBJECT(NULL, 0, oid, -1); 633 if (len <= 0) { 634 goto err; 635 } 636 637 buf = OPENSSL_malloc(len); 638 if (buf == NULL) { 639 OPENSSL_PUT_ERROR(OBJ, OBJ_create, ERR_R_MALLOC_FAILURE); 640 goto err; 641 } 642 643 len = a2d_ASN1_OBJECT(buf, len, oid, -1); 644 if (len == 0) { 645 goto err; 646 } 647 648 op = (ASN1_OBJECT *)ASN1_OBJECT_create(obj_next_nid(), buf, len, short_name, 649 long_name); 650 if (op == NULL) { 651 goto err; 652 } 653 654 if (obj_add_object(op)) { 655 ret = op->nid; 656 } 657 op = NULL; 658 659err: 660 ASN1_OBJECT_free(op); 661 OPENSSL_free(buf); 662 663 return ret; 664} 665