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