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