Coverage Report

Created: 2023-06-07 07:13

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