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