Coverage Report

Created: 2024-11-21 07:03

/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
0
ASN1_OBJECT *OBJ_dup(const ASN1_OBJECT *o) {
98
0
  ASN1_OBJECT *r;
99
0
  unsigned char *data = NULL;
100
0
  char *sn = NULL, *ln = NULL;
101
102
0
  if (o == NULL) {
103
0
    return NULL;
104
0
  }
105
106
0
  if (!(o->flags & ASN1_OBJECT_FLAG_DYNAMIC)) {
107
    // TODO(fork): this is a little dangerous.
108
0
    return (ASN1_OBJECT *)o;
109
0
  }
110
111
0
  r = ASN1_OBJECT_new();
112
0
  if (r == NULL) {
113
0
    OPENSSL_PUT_ERROR(OBJ, ERR_R_ASN1_LIB);
114
0
    return NULL;
115
0
  }
116
0
  r->ln = r->sn = NULL;
117
118
  // once data is attached to an object, it remains const
119
0
  r->data = OPENSSL_memdup(o->data, o->length);
120
0
  if (o->length != 0 && r->data == NULL) {
121
0
    goto err;
122
0
  }
123
124
0
  r->length = o->length;
125
0
  r->nid = o->nid;
126
127
0
  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
0
  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
0
  r->sn = sn;
142
0
  r->ln = ln;
143
144
0
  r->flags =
145
0
      o->flags | (ASN1_OBJECT_FLAG_DYNAMIC | ASN1_OBJECT_FLAG_DYNAMIC_STRINGS |
146
0
                  ASN1_OBJECT_FLAG_DYNAMIC_DATA);
147
0
  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
0
}
156
157
0
int OBJ_cmp(const ASN1_OBJECT *a, const ASN1_OBJECT *b) {
158
0
  if (a->length < b->length) {
159
0
    return -1;
160
0
  } else if (a->length > b->length) {
161
0
    return 1;
162
0
  }
163
0
  return OPENSSL_memcmp(a->data, b->data, a->length);
164
0
}
165
166
314
const uint8_t *OBJ_get0_data(const ASN1_OBJECT *obj) {
167
314
  if (obj == NULL) {
168
0
    return NULL;
169
0
  }
170
171
314
  return obj->data;
172
314
}
173
174
size_t OBJ_length(const ASN1_OBJECT *obj) {
175
  if (obj == NULL || obj->length < 0) {
176
    return 0;
177
  }
178
179
  return (size_t)obj->length;
180
}
181
182
0
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
0
  BSSL_CHECK(nid > 0 && nid < NUM_NID);
186
0
  return &kObjects[nid - 1];
187
0
}
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
0
static int obj_cmp(const void *key, const void *element) {
193
0
  uint16_t nid = *((const uint16_t *)element);
194
0
  return OBJ_cmp(key, get_builtin_object(nid));
195
0
}
196
197
0
int OBJ_obj2nid(const ASN1_OBJECT *obj) {
198
0
  if (obj == NULL) {
199
0
    return NID_undef;
200
0
  }
201
202
0
  if (obj->nid != 0) {
203
0
    return obj->nid;
204
0
  }
205
206
0
  CRYPTO_MUTEX_lock_read(&global_added_lock);
207
0
  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
0
  CRYPTO_MUTEX_unlock_read(&global_added_lock);
217
218
0
  const uint16_t *nid_ptr =
219
0
      bsearch(obj, kNIDsInOIDOrder, OPENSSL_ARRAY_SIZE(kNIDsInOIDOrder),
220
0
              sizeof(kNIDsInOIDOrder[0]), obj_cmp);
221
0
  if (nid_ptr == NULL) {
222
0
    return NID_undef;
223
0
  }
224
225
0
  return get_builtin_object(*nid_ptr)->nid;
226
0
}
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
0
static int short_name_cmp(const void *key, const void *element) {
245
0
  const char *name = (const char *)key;
246
0
  uint16_t nid = *((const uint16_t *)element);
247
248
0
  return strcmp(name, get_builtin_object(nid)->sn);
249
0
}
250
251
int OBJ_sn2nid(const char *short_name) {
252
  CRYPTO_MUTEX_lock_read(&global_added_lock);
253
  if (global_added_by_short_name != NULL) {
254
    ASN1_OBJECT *match, template;
255
256
    template.sn = short_name;
257
    match = lh_ASN1_OBJECT_retrieve(global_added_by_short_name, &template);
258
    if (match != NULL) {
259
      CRYPTO_MUTEX_unlock_read(&global_added_lock);
260
      return match->nid;
261
    }
262
  }
263
  CRYPTO_MUTEX_unlock_read(&global_added_lock);
264
265
  const uint16_t *nid_ptr =
266
      bsearch(short_name, kNIDsInShortNameOrder,
267
              OPENSSL_ARRAY_SIZE(kNIDsInShortNameOrder),
268
              sizeof(kNIDsInShortNameOrder[0]), short_name_cmp);
269
  if (nid_ptr == NULL) {
270
    return NID_undef;
271
  }
272
273
  return get_builtin_object(*nid_ptr)->nid;
274
}
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
0
static int long_name_cmp(const void *key, const void *element) {
280
0
  const char *name = (const char *)key;
281
0
  uint16_t nid = *((const uint16_t *)element);
282
283
0
  return strcmp(name, get_builtin_object(nid)->ln);
284
0
}
285
286
int OBJ_ln2nid(const char *long_name) {
287
  CRYPTO_MUTEX_lock_read(&global_added_lock);
288
  if (global_added_by_long_name != NULL) {
289
    ASN1_OBJECT *match, template;
290
291
    template.ln = long_name;
292
    match = lh_ASN1_OBJECT_retrieve(global_added_by_long_name, &template);
293
    if (match != NULL) {
294
      CRYPTO_MUTEX_unlock_read(&global_added_lock);
295
      return match->nid;
296
    }
297
  }
298
  CRYPTO_MUTEX_unlock_read(&global_added_lock);
299
300
  const uint16_t *nid_ptr = bsearch(
301
      long_name, kNIDsInLongNameOrder, OPENSSL_ARRAY_SIZE(kNIDsInLongNameOrder),
302
      sizeof(kNIDsInLongNameOrder[0]), long_name_cmp);
303
  if (nid_ptr == NULL) {
304
    return NID_undef;
305
  }
306
307
  return get_builtin_object(*nid_ptr)->nid;
308
}
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
0
const ASN1_OBJECT *OBJ_get_undef(void) {
335
0
  static const ASN1_OBJECT kUndef = {
336
0
      /*sn=*/SN_undef,
337
0
      /*ln=*/LN_undef,
338
0
      /*nid=*/NID_undef,
339
0
      /*length=*/0,
340
      /*data=*/NULL,
341
0
      /*flags=*/0,
342
0
  };
343
0
  return &kUndef;
344
0
}
345
346
ASN1_OBJECT *OBJ_nid2obj(int nid) {
347
  if (nid == NID_undef) {
348
    return (ASN1_OBJECT *)OBJ_get_undef();
349
  }
350
351
  if (nid > 0 && nid < NUM_NID) {
352
    const ASN1_OBJECT *obj = get_builtin_object(nid);
353
    if (nid != NID_undef && obj->nid == NID_undef) {
354
      goto err;
355
    }
356
    return (ASN1_OBJECT *)obj;
357
  }
358
359
  CRYPTO_MUTEX_lock_read(&global_added_lock);
360
  if (global_added_by_nid != NULL) {
361
    ASN1_OBJECT *match, template;
362
363
    template.nid = nid;
364
    match = lh_ASN1_OBJECT_retrieve(global_added_by_nid, &template);
365
    if (match != NULL) {
366
      CRYPTO_MUTEX_unlock_read(&global_added_lock);
367
      return match;
368
    }
369
  }
370
  CRYPTO_MUTEX_unlock_read(&global_added_lock);
371
372
err:
373
  OPENSSL_PUT_ERROR(OBJ, OBJ_R_UNKNOWN_NID);
374
  return NULL;
375
}
376
377
const char *OBJ_nid2sn(int nid) {
378
  const ASN1_OBJECT *obj = OBJ_nid2obj(nid);
379
  if (obj == NULL) {
380
    return NULL;
381
  }
382
383
  return obj->sn;
384
}
385
386
const char *OBJ_nid2ln(int nid) {
387
  const ASN1_OBJECT *obj = OBJ_nid2obj(nid);
388
  if (obj == NULL) {
389
    return NULL;
390
  }
391
392
  return obj->ln;
393
}
394
395
static ASN1_OBJECT *create_object_with_text_oid(int (*get_nid)(void),
396
                                                const char *oid,
397
                                                const char *short_name,
398
0
                                                const char *long_name) {
399
0
  uint8_t *buf;
400
0
  size_t len;
401
0
  CBB cbb;
402
0
  if (!CBB_init(&cbb, 32) ||
403
0
      !CBB_add_asn1_oid_from_text(&cbb, oid, strlen(oid)) ||
404
0
      !CBB_finish(&cbb, &buf, &len)) {
405
0
    OPENSSL_PUT_ERROR(OBJ, OBJ_R_INVALID_OID_STRING);
406
0
    CBB_cleanup(&cbb);
407
0
    return NULL;
408
0
  }
409
410
0
  ASN1_OBJECT *ret = ASN1_OBJECT_create(get_nid ? get_nid() : NID_undef, buf,
411
0
                                        len, short_name, long_name);
412
0
  OPENSSL_free(buf);
413
0
  return ret;
414
0
}
415
416
0
ASN1_OBJECT *OBJ_txt2obj(const char *s, int dont_search_names) {
417
0
  if (!dont_search_names) {
418
0
    int nid = OBJ_sn2nid(s);
419
0
    if (nid == NID_undef) {
420
0
      nid = OBJ_ln2nid(s);
421
0
    }
422
423
0
    if (nid != NID_undef) {
424
0
      return OBJ_nid2obj(nid);
425
0
    }
426
0
  }
427
428
0
  return create_object_with_text_oid(NULL, s, NULL, NULL);
429
0
}
430
431
0
static int strlcpy_int(char *dst, const char *src, int dst_size) {
432
0
  size_t ret = OPENSSL_strlcpy(dst, src, dst_size < 0 ? 0 : (size_t)dst_size);
433
0
  if (ret > INT_MAX) {
434
0
    OPENSSL_PUT_ERROR(OBJ, ERR_R_OVERFLOW);
435
0
    return -1;
436
0
  }
437
0
  return (int)ret;
438
0
}
439
440
int OBJ_obj2txt(char *out, int out_len, const ASN1_OBJECT *obj,
441
0
                int always_return_oid) {
442
  // Python depends on the empty OID successfully encoding as the empty
443
  // string.
444
0
  if (obj == NULL || obj->length == 0) {
445
0
    return strlcpy_int(out, "", out_len);
446
0
  }
447
448
0
  if (!always_return_oid) {
449
0
    int nid = OBJ_obj2nid(obj);
450
0
    if (nid != NID_undef) {
451
0
      const char *name = OBJ_nid2ln(nid);
452
0
      if (name == NULL) {
453
0
        name = OBJ_nid2sn(nid);
454
0
      }
455
0
      if (name != NULL) {
456
0
        return strlcpy_int(out, name, out_len);
457
0
      }
458
0
    }
459
0
  }
460
461
0
  CBS cbs;
462
0
  CBS_init(&cbs, obj->data, obj->length);
463
0
  char *txt = CBS_asn1_oid_to_text(&cbs);
464
0
  if (txt == NULL) {
465
0
    if (out_len > 0) {
466
0
      out[0] = '\0';
467
0
    }
468
0
    return -1;
469
0
  }
470
471
0
  int ret = strlcpy_int(out, txt, out_len);
472
0
  OPENSSL_free(txt);
473
0
  return ret;
474
0
}
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) {}