1 /* 2 * Copyright 1995-2023 The OpenSSL Project Authors. All Rights Reserved. 3 * 4 * Licensed under the Apache License 2.0 (the "License"). You may not use 5 * this file except in compliance with the License. You can obtain a copy 6 * in the file LICENSE in the source distribution or at 7 * https://www.openssl.org/source/license.html 8 */ 9 10 #include <stdio.h> 11 #include "crypto/ctype.h" 12 #include <limits.h> 13 #include "internal/cryptlib.h" 14 #include <openssl/lhash.h> 15 #include <openssl/asn1.h> 16 #include "crypto/objects.h" 17 #include <openssl/bn.h> 18 #include "crypto/asn1.h" 19 #include "obj_local.h" 20 21 /* obj_dat.h is generated from objects.h by obj_dat.pl */ 22 #include "obj_dat.h" 23 24 DECLARE_OBJ_BSEARCH_CMP_FN(const ASN1_OBJECT *, unsigned int, sn); 25 DECLARE_OBJ_BSEARCH_CMP_FN(const ASN1_OBJECT *, unsigned int, ln); 26 DECLARE_OBJ_BSEARCH_CMP_FN(const ASN1_OBJECT *, unsigned int, obj); 27 28 #define ADDED_DATA 0 29 #define ADDED_SNAME 1 30 #define ADDED_LNAME 2 31 #define ADDED_NID 3 32 33 struct added_obj_st { 34 int type; 35 ASN1_OBJECT *obj; 36 }; 37 38 static int new_nid = NUM_NID; 39 static LHASH_OF(ADDED_OBJ) *added = NULL; 40 41 static int sn_cmp(const ASN1_OBJECT *const *a, const unsigned int *b) 42 { 43 return strcmp((*a)->sn, nid_objs[*b].sn); 44 } 45 46 IMPLEMENT_OBJ_BSEARCH_CMP_FN(const ASN1_OBJECT *, unsigned int, sn); 47 48 static int ln_cmp(const ASN1_OBJECT *const *a, const unsigned int *b) 49 { 50 return strcmp((*a)->ln, nid_objs[*b].ln); 51 } 52 53 IMPLEMENT_OBJ_BSEARCH_CMP_FN(const ASN1_OBJECT *, unsigned int, ln); 54 55 static unsigned long added_obj_hash(const ADDED_OBJ *ca) 56 { 57 const ASN1_OBJECT *a; 58 int i; 59 unsigned long ret = 0; 60 unsigned char *p; 61 62 a = ca->obj; 63 switch (ca->type) { 64 case ADDED_DATA: 65 ret = a->length << 20L; 66 p = (unsigned char *)a->data; 67 for (i = 0; i < a->length; i++) 68 ret ^= p[i] << ((i * 3) % 24); 69 break; 70 case ADDED_SNAME: 71 ret = OPENSSL_LH_strhash(a->sn); 72 break; 73 case ADDED_LNAME: 74 ret = OPENSSL_LH_strhash(a->ln); 75 break; 76 case ADDED_NID: 77 ret = a->nid; 78 break; 79 default: 80 /* abort(); */ 81 return 0; 82 } 83 ret &= 0x3fffffffL; 84 ret |= ((unsigned long)ca->type) << 30L; 85 return ret; 86 } 87 88 static int added_obj_cmp(const ADDED_OBJ *ca, const ADDED_OBJ *cb) 89 { 90 ASN1_OBJECT *a, *b; 91 int i; 92 93 i = ca->type - cb->type; 94 if (i) 95 return i; 96 a = ca->obj; 97 b = cb->obj; 98 switch (ca->type) { 99 case ADDED_DATA: 100 i = (a->length - b->length); 101 if (i) 102 return i; 103 return memcmp(a->data, b->data, (size_t)a->length); 104 case ADDED_SNAME: 105 if (a->sn == NULL) 106 return -1; 107 else if (b->sn == NULL) 108 return 1; 109 else 110 return strcmp(a->sn, b->sn); 111 case ADDED_LNAME: 112 if (a->ln == NULL) 113 return -1; 114 else if (b->ln == NULL) 115 return 1; 116 else 117 return strcmp(a->ln, b->ln); 118 case ADDED_NID: 119 return a->nid - b->nid; 120 default: 121 /* abort(); */ 122 return 0; 123 } 124 } 125 126 static int init_added(void) 127 { 128 if (added != NULL) 129 return 1; 130 added = lh_ADDED_OBJ_new(added_obj_hash, added_obj_cmp); 131 return added != NULL; 132 } 133 134 static void cleanup1_doall(ADDED_OBJ *a) 135 { 136 a->obj->nid = 0; 137 a->obj->flags |= ASN1_OBJECT_FLAG_DYNAMIC | 138 ASN1_OBJECT_FLAG_DYNAMIC_STRINGS | ASN1_OBJECT_FLAG_DYNAMIC_DATA; 139 } 140 141 static void cleanup2_doall(ADDED_OBJ *a) 142 { 143 a->obj->nid++; 144 } 145 146 static void cleanup3_doall(ADDED_OBJ *a) 147 { 148 if (--a->obj->nid == 0) 149 ASN1_OBJECT_free(a->obj); 150 OPENSSL_free(a); 151 } 152 153 void ossl_obj_cleanup_int(void) 154 { 155 if (added == NULL) 156 return; 157 lh_ADDED_OBJ_set_down_load(added, 0); 158 lh_ADDED_OBJ_doall(added, cleanup1_doall); /* zero counters */ 159 lh_ADDED_OBJ_doall(added, cleanup2_doall); /* set counters */ 160 lh_ADDED_OBJ_doall(added, cleanup3_doall); /* free objects */ 161 lh_ADDED_OBJ_free(added); 162 added = NULL; 163 } 164 165 int OBJ_new_nid(int num) 166 { 167 int i; 168 169 i = new_nid; 170 new_nid += num; 171 return i; 172 } 173 174 int OBJ_add_object(const ASN1_OBJECT *obj) 175 { 176 ASN1_OBJECT *o; 177 ADDED_OBJ *ao[4] = { NULL, NULL, NULL, NULL }, *aop; 178 int i; 179 180 if (added == NULL) 181 if (!init_added()) 182 return 0; 183 if ((o = OBJ_dup(obj)) == NULL) 184 goto err; 185 if ((ao[ADDED_NID] = OPENSSL_malloc(sizeof(*ao[0]))) == NULL) 186 goto err2; 187 if ((o->length != 0) && (obj->data != NULL)) 188 if ((ao[ADDED_DATA] = OPENSSL_malloc(sizeof(*ao[0]))) == NULL) 189 goto err2; 190 if (o->sn != NULL) 191 if ((ao[ADDED_SNAME] = OPENSSL_malloc(sizeof(*ao[0]))) == NULL) 192 goto err2; 193 if (o->ln != NULL) 194 if ((ao[ADDED_LNAME] = OPENSSL_malloc(sizeof(*ao[0]))) == NULL) 195 goto err2; 196 197 for (i = ADDED_DATA; i <= ADDED_NID; i++) { 198 if (ao[i] != NULL) { 199 ao[i]->type = i; 200 ao[i]->obj = o; 201 aop = lh_ADDED_OBJ_insert(added, ao[i]); 202 /* memory leak, but should not normally matter */ 203 OPENSSL_free(aop); 204 } 205 } 206 o->flags &= 207 ~(ASN1_OBJECT_FLAG_DYNAMIC | ASN1_OBJECT_FLAG_DYNAMIC_STRINGS | 208 ASN1_OBJECT_FLAG_DYNAMIC_DATA); 209 210 return o->nid; 211 err2: 212 ERR_raise(ERR_LIB_OBJ, ERR_R_MALLOC_FAILURE); 213 err: 214 for (i = ADDED_DATA; i <= ADDED_NID; i++) 215 OPENSSL_free(ao[i]); 216 ASN1_OBJECT_free(o); 217 return NID_undef; 218 } 219 220 ASN1_OBJECT *OBJ_nid2obj(int n) 221 { 222 ADDED_OBJ ad, *adp; 223 ASN1_OBJECT ob; 224 225 if ((n >= 0) && (n < NUM_NID)) { 226 if ((n != NID_undef) && (nid_objs[n].nid == NID_undef)) { 227 ERR_raise(ERR_LIB_OBJ, OBJ_R_UNKNOWN_NID); 228 return NULL; 229 } 230 return (ASN1_OBJECT *)&(nid_objs[n]); 231 } 232 233 /* Make sure we've loaded config before checking for any "added" objects */ 234 OPENSSL_init_crypto(OPENSSL_INIT_LOAD_CONFIG, NULL); 235 236 if (added == NULL) 237 return NULL; 238 239 ad.type = ADDED_NID; 240 ad.obj = &ob; 241 ob.nid = n; 242 adp = lh_ADDED_OBJ_retrieve(added, &ad); 243 if (adp != NULL) 244 return adp->obj; 245 246 ERR_raise(ERR_LIB_OBJ, OBJ_R_UNKNOWN_NID); 247 return NULL; 248 } 249 250 const char *OBJ_nid2sn(int n) 251 { 252 ADDED_OBJ ad, *adp; 253 ASN1_OBJECT ob; 254 255 if ((n >= 0) && (n < NUM_NID)) { 256 if ((n != NID_undef) && (nid_objs[n].nid == NID_undef)) { 257 ERR_raise(ERR_LIB_OBJ, OBJ_R_UNKNOWN_NID); 258 return NULL; 259 } 260 return nid_objs[n].sn; 261 } 262 263 /* Make sure we've loaded config before checking for any "added" objects */ 264 OPENSSL_init_crypto(OPENSSL_INIT_LOAD_CONFIG, NULL); 265 266 if (added == NULL) 267 return NULL; 268 269 ad.type = ADDED_NID; 270 ad.obj = &ob; 271 ob.nid = n; 272 adp = lh_ADDED_OBJ_retrieve(added, &ad); 273 if (adp != NULL) 274 return adp->obj->sn; 275 276 ERR_raise(ERR_LIB_OBJ, OBJ_R_UNKNOWN_NID); 277 return NULL; 278 } 279 280 const char *OBJ_nid2ln(int n) 281 { 282 ADDED_OBJ ad, *adp; 283 ASN1_OBJECT ob; 284 285 if ((n >= 0) && (n < NUM_NID)) { 286 if ((n != NID_undef) && (nid_objs[n].nid == NID_undef)) { 287 ERR_raise(ERR_LIB_OBJ, OBJ_R_UNKNOWN_NID); 288 return NULL; 289 } 290 return nid_objs[n].ln; 291 } 292 293 /* Make sure we've loaded config before checking for any "added" objects */ 294 OPENSSL_init_crypto(OPENSSL_INIT_LOAD_CONFIG, NULL); 295 296 if (added == NULL) 297 return NULL; 298 299 ad.type = ADDED_NID; 300 ad.obj = &ob; 301 ob.nid = n; 302 adp = lh_ADDED_OBJ_retrieve(added, &ad); 303 if (adp != NULL) 304 return adp->obj->ln; 305 306 ERR_raise(ERR_LIB_OBJ, OBJ_R_UNKNOWN_NID); 307 return NULL; 308 } 309 310 static int obj_cmp(const ASN1_OBJECT *const *ap, const unsigned int *bp) 311 { 312 int j; 313 const ASN1_OBJECT *a = *ap; 314 const ASN1_OBJECT *b = &nid_objs[*bp]; 315 316 j = (a->length - b->length); 317 if (j) 318 return j; 319 if (a->length == 0) 320 return 0; 321 return memcmp(a->data, b->data, a->length); 322 } 323 324 IMPLEMENT_OBJ_BSEARCH_CMP_FN(const ASN1_OBJECT *, unsigned int, obj); 325 326 int OBJ_obj2nid(const ASN1_OBJECT *a) 327 { 328 const unsigned int *op; 329 ADDED_OBJ ad, *adp; 330 331 if (a == NULL) 332 return NID_undef; 333 if (a->nid != 0) 334 return a->nid; 335 336 if (a->length == 0) 337 return NID_undef; 338 339 /* Make sure we've loaded config before checking for any "added" objects */ 340 OPENSSL_init_crypto(OPENSSL_INIT_LOAD_CONFIG, NULL); 341 342 if (added != NULL) { 343 ad.type = ADDED_DATA; 344 ad.obj = (ASN1_OBJECT *)a; /* XXX: ugly but harmless */ 345 adp = lh_ADDED_OBJ_retrieve(added, &ad); 346 if (adp != NULL) 347 return adp->obj->nid; 348 } 349 op = OBJ_bsearch_obj(&a, obj_objs, NUM_OBJ); 350 if (op == NULL) 351 return NID_undef; 352 return nid_objs[*op].nid; 353 } 354 355 /* 356 * Convert an object name into an ASN1_OBJECT if "noname" is not set then 357 * search for short and long names first. This will convert the "dotted" form 358 * into an object: unlike OBJ_txt2nid it can be used with any objects, not 359 * just registered ones. 360 */ 361 362 ASN1_OBJECT *OBJ_txt2obj(const char *s, int no_name) 363 { 364 int nid = NID_undef; 365 ASN1_OBJECT *op; 366 unsigned char *buf; 367 unsigned char *p; 368 const unsigned char *cp; 369 int i, j; 370 371 if (!no_name) { 372 if (((nid = OBJ_sn2nid(s)) != NID_undef) || 373 ((nid = OBJ_ln2nid(s)) != NID_undef)) 374 return OBJ_nid2obj(nid); 375 if (!ossl_isdigit(*s)) { 376 ERR_raise(ERR_LIB_OBJ, OBJ_R_UNKNOWN_OBJECT_NAME); 377 return NULL; 378 } 379 } 380 381 /* Work out size of content octets */ 382 i = a2d_ASN1_OBJECT(NULL, 0, s, -1); 383 if (i <= 0) { 384 /* Don't clear the error */ 385 /* 386 * ERR_clear_error(); 387 */ 388 return NULL; 389 } 390 /* Work out total size */ 391 j = ASN1_object_size(0, i, V_ASN1_OBJECT); 392 if (j < 0) 393 return NULL; 394 395 if ((buf = OPENSSL_malloc(j)) == NULL) { 396 ERR_raise(ERR_LIB_OBJ, ERR_R_MALLOC_FAILURE); 397 return NULL; 398 } 399 400 p = buf; 401 /* Write out tag+length */ 402 ASN1_put_object(&p, 0, i, V_ASN1_OBJECT, V_ASN1_UNIVERSAL); 403 /* Write out contents */ 404 a2d_ASN1_OBJECT(p, i, s, -1); 405 406 cp = buf; 407 op = d2i_ASN1_OBJECT(NULL, &cp, j); 408 OPENSSL_free(buf); 409 return op; 410 } 411 412 int OBJ_obj2txt(char *buf, int buf_len, const ASN1_OBJECT *a, int no_name) 413 { 414 int i, n = 0, len, nid, first, use_bn; 415 BIGNUM *bl; 416 unsigned long l; 417 const unsigned char *p; 418 char tbuf[DECIMAL_SIZE(i) + DECIMAL_SIZE(l) + 2]; 419 420 /* Ensure that, at every state, |buf| is NUL-terminated. */ 421 if (buf && buf_len > 0) 422 buf[0] = '\0'; 423 424 if ((a == NULL) || (a->data == NULL)) 425 return 0; 426 427 if (!no_name && (nid = OBJ_obj2nid(a)) != NID_undef) { 428 const char *s; 429 s = OBJ_nid2ln(nid); 430 if (s == NULL) 431 s = OBJ_nid2sn(nid); 432 if (s) { 433 if (buf) 434 OPENSSL_strlcpy(buf, s, buf_len); 435 n = strlen(s); 436 return n; 437 } 438 } 439 440 len = a->length; 441 p = a->data; 442 443 first = 1; 444 bl = NULL; 445 446 /* 447 * RFC 2578 (STD 58) says this about OBJECT IDENTIFIERs: 448 * 449 * > 3.5. OBJECT IDENTIFIER values 450 * > 451 * > An OBJECT IDENTIFIER value is an ordered list of non-negative 452 * > numbers. For the SMIv2, each number in the list is referred to as a 453 * > sub-identifier, there are at most 128 sub-identifiers in a value, 454 * > and each sub-identifier has a maximum value of 2^32-1 (4294967295 455 * > decimal). 456 * 457 * So a legitimate OID according to this RFC is at most (32 * 128 / 7), 458 * i.e. 586 bytes long. 459 * 460 * Ref: https://datatracker.ietf.org/doc/html/rfc2578#section-3.5 461 */ 462 if (len > 586) 463 goto err; 464 465 while (len > 0) { 466 l = 0; 467 use_bn = 0; 468 for (;;) { 469 unsigned char c = *p++; 470 len--; 471 if ((len == 0) && (c & 0x80)) 472 goto err; 473 if (use_bn) { 474 if (!BN_add_word(bl, c & 0x7f)) 475 goto err; 476 } else 477 l |= c & 0x7f; 478 if (!(c & 0x80)) 479 break; 480 if (!use_bn && (l > (ULONG_MAX >> 7L))) { 481 if (bl == NULL && (bl = BN_new()) == NULL) 482 goto err; 483 if (!BN_set_word(bl, l)) 484 goto err; 485 use_bn = 1; 486 } 487 if (use_bn) { 488 if (!BN_lshift(bl, bl, 7)) 489 goto err; 490 } else 491 l <<= 7L; 492 } 493 494 if (first) { 495 first = 0; 496 if (l >= 80) { 497 i = 2; 498 if (use_bn) { 499 if (!BN_sub_word(bl, 80)) 500 goto err; 501 } else 502 l -= 80; 503 } else { 504 i = (int)(l / 40); 505 l -= (long)(i * 40); 506 } 507 if (buf && (buf_len > 1)) { 508 *buf++ = i + '0'; 509 *buf = '\0'; 510 buf_len--; 511 } 512 n++; 513 } 514 515 if (use_bn) { 516 char *bndec; 517 bndec = BN_bn2dec(bl); 518 if (!bndec) 519 goto err; 520 i = strlen(bndec); 521 if (buf) { 522 if (buf_len > 1) { 523 *buf++ = '.'; 524 *buf = '\0'; 525 buf_len--; 526 } 527 OPENSSL_strlcpy(buf, bndec, buf_len); 528 if (i > buf_len) { 529 buf += buf_len; 530 buf_len = 0; 531 } else { 532 buf += i; 533 buf_len -= i; 534 } 535 } 536 n++; 537 n += i; 538 OPENSSL_free(bndec); 539 } else { 540 BIO_snprintf(tbuf, sizeof(tbuf), ".%lu", l); 541 i = strlen(tbuf); 542 if (buf && (buf_len > 0)) { 543 OPENSSL_strlcpy(buf, tbuf, buf_len); 544 if (i > buf_len) { 545 buf += buf_len; 546 buf_len = 0; 547 } else { 548 buf += i; 549 buf_len -= i; 550 } 551 } 552 n += i; 553 l = 0; 554 } 555 } 556 557 BN_free(bl); 558 return n; 559 560 err: 561 BN_free(bl); 562 return -1; 563 } 564 565 int OBJ_txt2nid(const char *s) 566 { 567 ASN1_OBJECT *obj; 568 int nid; 569 obj = OBJ_txt2obj(s, 0); 570 nid = OBJ_obj2nid(obj); 571 ASN1_OBJECT_free(obj); 572 return nid; 573 } 574 575 int OBJ_ln2nid(const char *s) 576 { 577 ASN1_OBJECT o; 578 const ASN1_OBJECT *oo = &o; 579 ADDED_OBJ ad, *adp; 580 const unsigned int *op; 581 582 /* Make sure we've loaded config before checking for any "added" objects */ 583 OPENSSL_init_crypto(OPENSSL_INIT_LOAD_CONFIG, NULL); 584 585 o.ln = s; 586 if (added != NULL) { 587 ad.type = ADDED_LNAME; 588 ad.obj = &o; 589 adp = lh_ADDED_OBJ_retrieve(added, &ad); 590 if (adp != NULL) 591 return adp->obj->nid; 592 } 593 op = OBJ_bsearch_ln(&oo, ln_objs, NUM_LN); 594 if (op == NULL) 595 return NID_undef; 596 return nid_objs[*op].nid; 597 } 598 599 int OBJ_sn2nid(const char *s) 600 { 601 ASN1_OBJECT o; 602 const ASN1_OBJECT *oo = &o; 603 ADDED_OBJ ad, *adp; 604 const unsigned int *op; 605 606 /* Make sure we've loaded config before checking for any "added" objects */ 607 OPENSSL_init_crypto(OPENSSL_INIT_LOAD_CONFIG, NULL); 608 609 o.sn = s; 610 if (added != NULL) { 611 ad.type = ADDED_SNAME; 612 ad.obj = &o; 613 adp = lh_ADDED_OBJ_retrieve(added, &ad); 614 if (adp != NULL) 615 return adp->obj->nid; 616 } 617 op = OBJ_bsearch_sn(&oo, sn_objs, NUM_SN); 618 if (op == NULL) 619 return NID_undef; 620 return nid_objs[*op].nid; 621 } 622 623 const void *OBJ_bsearch_(const void *key, const void *base, int num, int size, 624 int (*cmp) (const void *, const void *)) 625 { 626 return OBJ_bsearch_ex_(key, base, num, size, cmp, 0); 627 } 628 629 const void *OBJ_bsearch_ex_(const void *key, const void *base, int num, 630 int size, 631 int (*cmp) (const void *, const void *), 632 int flags) 633 { 634 const char *p = ossl_bsearch(key, base, num, size, cmp, flags); 635 636 #ifdef CHARSET_EBCDIC 637 /* 638 * THIS IS A KLUDGE - Because the *_obj is sorted in ASCII order, and I 639 * don't have perl (yet), we revert to a *LINEAR* search when the object 640 * wasn't found in the binary search. 641 */ 642 if (p == NULL) { 643 const char *base_ = base; 644 int l, h, i = 0, c = 0; 645 char *p1; 646 647 for (i = 0; i < num; ++i) { 648 p1 = &(base_[i * size]); 649 c = (*cmp) (key, p1); 650 if (c == 0 651 || (c < 0 && (flags & OBJ_BSEARCH_VALUE_ON_NOMATCH))) 652 return p1; 653 } 654 } 655 #endif 656 return p; 657 } 658 659 /* 660 * Parse a BIO sink to create some extra oid's objects. 661 * Line format:<OID:isdigit or '.']><isspace><SN><isspace><LN> 662 */ 663 int OBJ_create_objects(BIO *in) 664 { 665 char buf[512]; 666 int i, num = 0; 667 char *o, *s, *l = NULL; 668 669 for (;;) { 670 s = o = NULL; 671 i = BIO_gets(in, buf, 512); 672 if (i <= 0) 673 return num; 674 buf[i - 1] = '\0'; 675 if (!ossl_isalnum(buf[0])) 676 return num; 677 o = s = buf; 678 while (ossl_isdigit(*s) || *s == '.') 679 s++; 680 if (*s != '\0') { 681 *(s++) = '\0'; 682 while (ossl_isspace(*s)) 683 s++; 684 if (*s == '\0') { 685 s = NULL; 686 } else { 687 l = s; 688 while (*l != '\0' && !ossl_isspace(*l)) 689 l++; 690 if (*l != '\0') { 691 *(l++) = '\0'; 692 while (ossl_isspace(*l)) 693 l++; 694 if (*l == '\0') { 695 l = NULL; 696 } 697 } else { 698 l = NULL; 699 } 700 } 701 } else { 702 s = NULL; 703 } 704 if (*o == '\0') 705 return num; 706 if (!OBJ_create(o, s, l)) 707 return num; 708 num++; 709 } 710 } 711 712 int OBJ_create(const char *oid, const char *sn, const char *ln) 713 { 714 ASN1_OBJECT *tmpoid = NULL; 715 int ok = 0; 716 717 /* Check to see if short or long name already present */ 718 if ((sn != NULL && OBJ_sn2nid(sn) != NID_undef) 719 || (ln != NULL && OBJ_ln2nid(ln) != NID_undef)) { 720 ERR_raise(ERR_LIB_OBJ, OBJ_R_OID_EXISTS); 721 return 0; 722 } 723 724 /* Convert numerical OID string to an ASN1_OBJECT structure */ 725 tmpoid = OBJ_txt2obj(oid, 1); 726 if (tmpoid == NULL) 727 return 0; 728 729 /* If NID is not NID_undef then object already exists */ 730 if (OBJ_obj2nid(tmpoid) != NID_undef) { 731 ERR_raise(ERR_LIB_OBJ, OBJ_R_OID_EXISTS); 732 goto err; 733 } 734 735 tmpoid->nid = OBJ_new_nid(1); 736 if (tmpoid->nid == NID_undef) 737 goto err; 738 739 tmpoid->sn = (char *)sn; 740 tmpoid->ln = (char *)ln; 741 742 ok = OBJ_add_object(tmpoid); 743 744 tmpoid->sn = NULL; 745 tmpoid->ln = NULL; 746 747 err: 748 ASN1_OBJECT_free(tmpoid); 749 return ok; 750 } 751 752 size_t OBJ_length(const ASN1_OBJECT *obj) 753 { 754 if (obj == NULL) 755 return 0; 756 return obj->length; 757 } 758 759 const unsigned char *OBJ_get0_data(const ASN1_OBJECT *obj) 760 { 761 if (obj == NULL) 762 return NULL; 763 return obj->data; 764 } 765