Coverage Report

Created: 2023-11-19 06:09

/src/boringssl/crypto/obj/obj.c
Line
Count
Source (jump to first uncovered line)
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 <inttypes.h>
60
#include <limits.h>
61
#include <string.h>
62
63
#include <openssl/asn1.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 "../asn1/internal.h"
71
#include "../internal.h"
72
#include "../lhash/internal.h"
73
74
// obj_data.h must be included after the definition of |ASN1_OBJECT|.
75
#include "obj_dat.h"
76
77
78
DEFINE_LHASH_OF(ASN1_OBJECT)
79
80
static CRYPTO_MUTEX global_added_lock = CRYPTO_MUTEX_INIT;
81
// These globals are protected by |global_added_lock|.
82
static LHASH_OF(ASN1_OBJECT) *global_added_by_data = NULL;
83
static LHASH_OF(ASN1_OBJECT) *global_added_by_nid = NULL;
84
static LHASH_OF(ASN1_OBJECT) *global_added_by_short_name = NULL;
85
static LHASH_OF(ASN1_OBJECT) *global_added_by_long_name = NULL;
86
87
static CRYPTO_MUTEX global_next_nid_lock = CRYPTO_MUTEX_INIT;
88
static unsigned global_next_nid = NUM_NID;
89
90
0
static int obj_next_nid(void) {
91
0
  CRYPTO_MUTEX_lock_write(&global_next_nid_lock);
92
0
  int ret = global_next_nid++;
93
0
  CRYPTO_MUTEX_unlock_write(&global_next_nid_lock);
94
0
  return ret;
95
0
}
96
97
2.68M
ASN1_OBJECT *OBJ_dup(const ASN1_OBJECT *o) {
98
2.68M
  ASN1_OBJECT *r;
99
2.68M
  unsigned char *data = NULL;
100
2.68M
  char *sn = NULL, *ln = NULL;
101
102
2.68M
  if (o == NULL) {
103
0
    return NULL;
104
0
  }
105
106
2.68M
  if (!(o->flags & ASN1_OBJECT_FLAG_DYNAMIC)) {
107
    // TODO(fork): this is a little dangerous.
108
36.5k
    return (ASN1_OBJECT *)o;
109
36.5k
  }
110
111
2.64M
  r = ASN1_OBJECT_new();
112
2.64M
  if (r == NULL) {
113
0
    OPENSSL_PUT_ERROR(OBJ, ERR_R_ASN1_LIB);
114
0
    return NULL;
115
0
  }
116
2.64M
  r->ln = r->sn = NULL;
117
118
  // once data is attached to an object, it remains const
119
2.64M
  r->data = OPENSSL_memdup(o->data, o->length);
120
2.64M
  if (o->length != 0 && r->data == NULL) {
121
0
    goto err;
122
0
  }
123
124
2.64M
  r->length = o->length;
125
2.64M
  r->nid = o->nid;
126
127
2.64M
  if (o->ln != NULL) {
128
0
    ln = OPENSSL_strdup(o->ln);
129
0
    if (ln == NULL) {
130
0
      goto err;
131
0
    }
132
0
  }
133
134
2.64M
  if (o->sn != NULL) {
135
0
    sn = OPENSSL_strdup(o->sn);
136
0
    if (sn == NULL) {
137
0
      goto err;
138
0
    }
139
0
  }
140
141
2.64M
  r->sn = sn;
142
2.64M
  r->ln = ln;
143
144
2.64M
  r->flags =
145
2.64M
      o->flags | (ASN1_OBJECT_FLAG_DYNAMIC | ASN1_OBJECT_FLAG_DYNAMIC_STRINGS |
146
2.64M
                  ASN1_OBJECT_FLAG_DYNAMIC_DATA);
147
2.64M
  return r;
148
149
0
err:
150
0
  OPENSSL_free(ln);
151
0
  OPENSSL_free(sn);
152
0
  OPENSSL_free(data);
153
0
  OPENSSL_free(r);
154
0
  return NULL;
155
2.64M
}
156
157
3.68M
int OBJ_cmp(const ASN1_OBJECT *a, const ASN1_OBJECT *b) {
158
3.68M
  if (a->length < b->length) {
159
1.78M
    return -1;
160
1.90M
  } else if (a->length > b->length) {
161
103k
    return 1;
162
103k
  }
163
1.79M
  return OPENSSL_memcmp(a->data, b->data, a->length);
164
3.68M
}
165
166
0
const uint8_t *OBJ_get0_data(const ASN1_OBJECT *obj) {
167
0
  if (obj == NULL) {
168
0
    return NULL;
169
0
  }
170
171
0
  return obj->data;
172
0
}
173
174
0
size_t OBJ_length(const ASN1_OBJECT *obj) {
175
0
  if (obj == NULL || obj->length < 0) {
176
0
    return 0;
177
0
  }
178
179
0
  return (size_t)obj->length;
180
0
}
181
182
7.58M
static const ASN1_OBJECT *get_builtin_object(int nid) {
183
  // |NID_undef| is stored separately, so all the indices are off by one. The
184
  // caller of this function must have a valid built-in, non-undef NID.
185
7.58M
  BSSL_CHECK(nid > 0 && nid < NUM_NID);
186
7.58M
  return &kObjects[nid - 1];
187
7.58M
}
188
189
// obj_cmp is called to search the kNIDsInOIDOrder array. The |key| argument is
190
// an |ASN1_OBJECT|* that we're looking for and |element| is a pointer to an
191
// unsigned int in the array.
192
3.68M
static int obj_cmp(const void *key, const void *element) {
193
3.68M
  uint16_t nid = *((const uint16_t *)element);
194
3.68M
  return OBJ_cmp(key, get_builtin_object(nid));
195
3.68M
}
196
197
429k
int OBJ_obj2nid(const ASN1_OBJECT *obj) {
198
429k
  if (obj == NULL) {
199
0
    return NID_undef;
200
0
  }
201
202
429k
  if (obj->nid != 0) {
203
33.3k
    return obj->nid;
204
33.3k
  }
205
206
396k
  CRYPTO_MUTEX_lock_read(&global_added_lock);
207
396k
  if (global_added_by_data != NULL) {
208
0
    ASN1_OBJECT *match;
209
210
0
    match = lh_ASN1_OBJECT_retrieve(global_added_by_data, obj);
211
0
    if (match != NULL) {
212
0
      CRYPTO_MUTEX_unlock_read(&global_added_lock);
213
0
      return match->nid;
214
0
    }
215
0
  }
216
396k
  CRYPTO_MUTEX_unlock_read(&global_added_lock);
217
218
396k
  const uint16_t *nid_ptr =
219
396k
      bsearch(obj, kNIDsInOIDOrder, OPENSSL_ARRAY_SIZE(kNIDsInOIDOrder),
220
396k
              sizeof(kNIDsInOIDOrder[0]), obj_cmp);
221
396k
  if (nid_ptr == NULL) {
222
245k
    return NID_undef;
223
245k
  }
224
225
150k
  return get_builtin_object(*nid_ptr)->nid;
226
396k
}
227
228
0
int OBJ_cbs2nid(const CBS *cbs) {
229
0
  if (CBS_len(cbs) > INT_MAX) {
230
0
    return NID_undef;
231
0
  }
232
233
0
  ASN1_OBJECT obj;
234
0
  OPENSSL_memset(&obj, 0, sizeof(obj));
235
0
  obj.data = CBS_data(cbs);
236
0
  obj.length = (int)CBS_len(cbs);
237
238
0
  return OBJ_obj2nid(&obj);
239
0
}
240
241
// short_name_cmp is called to search the kNIDsInShortNameOrder array. The
242
// |key| argument is name that we're looking for and |element| is a pointer to
243
// an unsigned int in the array.
244
2.10M
static int short_name_cmp(const void *key, const void *element) {
245
2.10M
  const char *name = (const char *)key;
246
2.10M
  uint16_t nid = *((const uint16_t *)element);
247
248
2.10M
  return strcmp(name, get_builtin_object(nid)->sn);
249
2.10M
}
250
251
217k
int OBJ_sn2nid(const char *short_name) {
252
217k
  CRYPTO_MUTEX_lock_read(&global_added_lock);
253
217k
  if (global_added_by_short_name != NULL) {
254
0
    ASN1_OBJECT *match, template;
255
256
0
    template.sn = short_name;
257
0
    match = lh_ASN1_OBJECT_retrieve(global_added_by_short_name, &template);
258
0
    if (match != NULL) {
259
0
      CRYPTO_MUTEX_unlock_read(&global_added_lock);
260
0
      return match->nid;
261
0
    }
262
0
  }
263
217k
  CRYPTO_MUTEX_unlock_read(&global_added_lock);
264
265
217k
  const uint16_t *nid_ptr =
266
217k
      bsearch(short_name, kNIDsInShortNameOrder,
267
217k
              OPENSSL_ARRAY_SIZE(kNIDsInShortNameOrder),
268
217k
              sizeof(kNIDsInShortNameOrder[0]), short_name_cmp);
269
217k
  if (nid_ptr == NULL) {
270
150k
    return NID_undef;
271
150k
  }
272
273
66.5k
  return get_builtin_object(*nid_ptr)->nid;
274
217k
}
275
276
// long_name_cmp is called to search the kNIDsInLongNameOrder array. The
277
// |key| argument is name that we're looking for and |element| is a pointer to
278
// an unsigned int in the array.
279
1.49M
static int long_name_cmp(const void *key, const void *element) {
280
1.49M
  const char *name = (const char *)key;
281
1.49M
  uint16_t nid = *((const uint16_t *)element);
282
283
1.49M
  return strcmp(name, get_builtin_object(nid)->ln);
284
1.49M
}
285
286
149k
int OBJ_ln2nid(const char *long_name) {
287
149k
  CRYPTO_MUTEX_lock_read(&global_added_lock);
288
149k
  if (global_added_by_long_name != NULL) {
289
0
    ASN1_OBJECT *match, template;
290
291
0
    template.ln = long_name;
292
0
    match = lh_ASN1_OBJECT_retrieve(global_added_by_long_name, &template);
293
0
    if (match != NULL) {
294
0
      CRYPTO_MUTEX_unlock_read(&global_added_lock);
295
0
      return match->nid;
296
0
    }
297
0
  }
298
149k
  CRYPTO_MUTEX_unlock_read(&global_added_lock);
299
300
149k
  const uint16_t *nid_ptr = bsearch(
301
149k
      long_name, kNIDsInLongNameOrder, OPENSSL_ARRAY_SIZE(kNIDsInLongNameOrder),
302
149k
      sizeof(kNIDsInLongNameOrder[0]), long_name_cmp);
303
149k
  if (nid_ptr == NULL) {
304
149k
    return NID_undef;
305
149k
  }
306
307
374
  return get_builtin_object(*nid_ptr)->nid;
308
149k
}
309
310
0
int OBJ_txt2nid(const char *s) {
311
0
  ASN1_OBJECT *obj;
312
0
  int nid;
313
314
0
  obj = OBJ_txt2obj(s, 0 /* search names */);
315
0
  nid = OBJ_obj2nid(obj);
316
0
  ASN1_OBJECT_free(obj);
317
0
  return nid;
318
0
}
319
320
0
OPENSSL_EXPORT int OBJ_nid2cbb(CBB *out, int nid) {
321
0
  const ASN1_OBJECT *obj = OBJ_nid2obj(nid);
322
0
  CBB oid;
323
324
0
  if (obj == NULL ||
325
0
      !CBB_add_asn1(out, &oid, CBS_ASN1_OBJECT) ||
326
0
      !CBB_add_bytes(&oid, obj->data, obj->length) ||
327
0
      !CBB_flush(out)) {
328
0
    return 0;
329
0
  }
330
331
0
  return 1;
332
0
}
333
334
2.59M
const ASN1_OBJECT *OBJ_get_undef(void) {
335
2.59M
  static const ASN1_OBJECT kUndef = {
336
      /*sn=*/SN_undef,
337
      /*ln=*/LN_undef,
338
      /*nid=*/NID_undef,
339
2.59M
      /*length=*/0,
340
      /*data=*/NULL,
341
2.59M
      /*flags=*/0,
342
2.59M
  };
343
2.59M
  return &kUndef;
344
2.59M
}
345
346
85.0k
ASN1_OBJECT *OBJ_nid2obj(int nid) {
347
85.0k
  if (nid == NID_undef) {
348
0
    return (ASN1_OBJECT *)OBJ_get_undef();
349
0
  }
350
351
85.0k
  if (nid > 0 && nid < NUM_NID) {
352
85.0k
    const ASN1_OBJECT *obj = get_builtin_object(nid);
353
85.0k
    if (nid != NID_undef && obj->nid == NID_undef) {
354
0
      goto err;
355
0
    }
356
85.0k
    return (ASN1_OBJECT *)obj;
357
85.0k
  }
358
359
0
  CRYPTO_MUTEX_lock_read(&global_added_lock);
360
0
  if (global_added_by_nid != NULL) {
361
0
    ASN1_OBJECT *match, template;
362
363
0
    template.nid = nid;
364
0
    match = lh_ASN1_OBJECT_retrieve(global_added_by_nid, &template);
365
0
    if (match != NULL) {
366
0
      CRYPTO_MUTEX_unlock_read(&global_added_lock);
367
0
      return match;
368
0
    }
369
0
  }
370
0
  CRYPTO_MUTEX_unlock_read(&global_added_lock);
371
372
0
err:
373
0
  OPENSSL_PUT_ERROR(OBJ, OBJ_R_UNKNOWN_NID);
374
0
  return NULL;
375
0
}
376
377
6.88k
const char *OBJ_nid2sn(int nid) {
378
6.88k
  const ASN1_OBJECT *obj = OBJ_nid2obj(nid);
379
6.88k
  if (obj == NULL) {
380
0
    return NULL;
381
0
  }
382
383
6.88k
  return obj->sn;
384
6.88k
}
385
386
14.0k
const char *OBJ_nid2ln(int nid) {
387
14.0k
  const ASN1_OBJECT *obj = OBJ_nid2obj(nid);
388
14.0k
  if (obj == NULL) {
389
0
    return NULL;
390
0
  }
391
392
14.0k
  return obj->ln;
393
14.0k
}
394
395
static ASN1_OBJECT *create_object_with_text_oid(int (*get_nid)(void),
396
                                                const char *oid,
397
                                                const char *short_name,
398
149k
                                                const char *long_name) {
399
149k
  uint8_t *buf;
400
149k
  size_t len;
401
149k
  CBB cbb;
402
149k
  if (!CBB_init(&cbb, 32) ||
403
149k
      !CBB_add_asn1_oid_from_text(&cbb, oid, strlen(oid)) ||
404
149k
      !CBB_finish(&cbb, &buf, &len)) {
405
1.53k
    OPENSSL_PUT_ERROR(OBJ, OBJ_R_INVALID_OID_STRING);
406
1.53k
    CBB_cleanup(&cbb);
407
1.53k
    return NULL;
408
1.53k
  }
409
410
147k
  ASN1_OBJECT *ret = ASN1_OBJECT_create(get_nid ? get_nid() : NID_undef, buf,
411
147k
                                        len, short_name, long_name);
412
147k
  OPENSSL_free(buf);
413
147k
  return ret;
414
149k
}
415
416
205k
ASN1_OBJECT *OBJ_txt2obj(const char *s, int dont_search_names) {
417
205k
  if (!dont_search_names) {
418
205k
    int nid = OBJ_sn2nid(s);
419
205k
    if (nid == NID_undef) {
420
149k
      nid = OBJ_ln2nid(s);
421
149k
    }
422
423
205k
    if (nid != NID_undef) {
424
56.2k
      return OBJ_nid2obj(nid);
425
56.2k
    }
426
205k
  }
427
428
149k
  return create_object_with_text_oid(NULL, s, NULL, NULL);
429
205k
}
430
431
40.2k
static int strlcpy_int(char *dst, const char *src, int dst_size) {
432
40.2k
  size_t ret = OPENSSL_strlcpy(dst, src, dst_size < 0 ? 0 : (size_t)dst_size);
433
40.2k
  if (ret > INT_MAX) {
434
0
    OPENSSL_PUT_ERROR(OBJ, ERR_R_OVERFLOW);
435
0
    return -1;
436
0
  }
437
40.2k
  return (int)ret;
438
40.2k
}
439
440
int OBJ_obj2txt(char *out, int out_len, const ASN1_OBJECT *obj,
441
40.6k
                int always_return_oid) {
442
  // Python depends on the empty OID successfully encoding as the empty
443
  // string.
444
40.6k
  if (obj == NULL || obj->length == 0) {
445
0
    return strlcpy_int(out, "", out_len);
446
0
  }
447
448
40.6k
  if (!always_return_oid) {
449
39.9k
    int nid = OBJ_obj2nid(obj);
450
39.9k
    if (nid != NID_undef) {
451
14.0k
      const char *name = OBJ_nid2ln(nid);
452
14.0k
      if (name == NULL) {
453
0
        name = OBJ_nid2sn(nid);
454
0
      }
455
14.0k
      if (name != NULL) {
456
14.0k
        return strlcpy_int(out, name, out_len);
457
14.0k
      }
458
14.0k
    }
459
39.9k
  }
460
461
26.6k
  CBS cbs;
462
26.6k
  CBS_init(&cbs, obj->data, obj->length);
463
26.6k
  char *txt = CBS_asn1_oid_to_text(&cbs);
464
26.6k
  if (txt == NULL) {
465
427
    if (out_len > 0) {
466
427
      out[0] = '\0';
467
427
    }
468
427
    return -1;
469
427
  }
470
471
26.1k
  int ret = strlcpy_int(out, txt, out_len);
472
26.1k
  OPENSSL_free(txt);
473
26.1k
  return ret;
474
26.6k
}
475
476
0
static uint32_t hash_nid(const ASN1_OBJECT *obj) {
477
0
  return obj->nid;
478
0
}
479
480
0
static int cmp_nid(const ASN1_OBJECT *a, const ASN1_OBJECT *b) {
481
0
  return a->nid - b->nid;
482
0
}
483
484
0
static uint32_t hash_data(const ASN1_OBJECT *obj) {
485
0
  return OPENSSL_hash32(obj->data, obj->length);
486
0
}
487
488
0
static uint32_t hash_short_name(const ASN1_OBJECT *obj) {
489
0
  return OPENSSL_strhash(obj->sn);
490
0
}
491
492
0
static int cmp_short_name(const ASN1_OBJECT *a, const ASN1_OBJECT *b) {
493
0
  return strcmp(a->sn, b->sn);
494
0
}
495
496
0
static uint32_t hash_long_name(const ASN1_OBJECT *obj) {
497
0
  return OPENSSL_strhash(obj->ln);
498
0
}
499
500
0
static int cmp_long_name(const ASN1_OBJECT *a, const ASN1_OBJECT *b) {
501
0
  return strcmp(a->ln, b->ln);
502
0
}
503
504
// obj_add_object inserts |obj| into the various global hashes for run-time
505
// added objects. It returns one on success or zero otherwise.
506
0
static int obj_add_object(ASN1_OBJECT *obj) {
507
0
  obj->flags &= ~(ASN1_OBJECT_FLAG_DYNAMIC | ASN1_OBJECT_FLAG_DYNAMIC_STRINGS |
508
0
                  ASN1_OBJECT_FLAG_DYNAMIC_DATA);
509
510
0
  CRYPTO_MUTEX_lock_write(&global_added_lock);
511
0
  if (global_added_by_nid == NULL) {
512
0
    global_added_by_nid = lh_ASN1_OBJECT_new(hash_nid, cmp_nid);
513
0
  }
514
0
  if (global_added_by_data == NULL) {
515
0
    global_added_by_data = lh_ASN1_OBJECT_new(hash_data, OBJ_cmp);
516
0
  }
517
0
  if (global_added_by_short_name == NULL) {
518
0
    global_added_by_short_name =
519
0
        lh_ASN1_OBJECT_new(hash_short_name, cmp_short_name);
520
0
  }
521
0
  if (global_added_by_long_name == NULL) {
522
0
    global_added_by_long_name = lh_ASN1_OBJECT_new(hash_long_name, cmp_long_name);
523
0
  }
524
525
0
  int ok = 0;
526
0
  if (global_added_by_nid == NULL ||
527
0
      global_added_by_data == NULL ||
528
0
      global_added_by_short_name == NULL ||
529
0
      global_added_by_long_name == NULL) {
530
0
    goto err;
531
0
  }
532
533
  // We don't pay attention to |old_object| (which contains any previous object
534
  // that was evicted from the hashes) because we don't have a reference count
535
  // on ASN1_OBJECT values. Also, we should never have duplicates nids and so
536
  // should always have objects in |global_added_by_nid|.
537
0
  ASN1_OBJECT *old_object;
538
0
  ok = lh_ASN1_OBJECT_insert(global_added_by_nid, &old_object, obj);
539
0
  if (obj->length != 0 && obj->data != NULL) {
540
0
    ok &= lh_ASN1_OBJECT_insert(global_added_by_data, &old_object, obj);
541
0
  }
542
0
  if (obj->sn != NULL) {
543
0
    ok &= lh_ASN1_OBJECT_insert(global_added_by_short_name, &old_object, obj);
544
0
  }
545
0
  if (obj->ln != NULL) {
546
0
    ok &= lh_ASN1_OBJECT_insert(global_added_by_long_name, &old_object, obj);
547
0
  }
548
549
0
err:
550
0
  CRYPTO_MUTEX_unlock_write(&global_added_lock);
551
0
  return ok;
552
0
}
553
554
0
int OBJ_create(const char *oid, const char *short_name, const char *long_name) {
555
0
  ASN1_OBJECT *op =
556
0
      create_object_with_text_oid(obj_next_nid, oid, short_name, long_name);
557
0
  if (op == NULL ||
558
0
      !obj_add_object(op)) {
559
0
    return NID_undef;
560
0
  }
561
0
  return op->nid;
562
0
}
563
564
0
void OBJ_cleanup(void) {}