/src/openssl/crypto/objects/obj_xref.c
Line  | Count  | Source (jump to first uncovered line)  | 
1  |  | /*  | 
2  |  |  * Copyright 2006-2022 The OpenSSL Project Authors. All Rights Reserved.  | 
3  |  |  *  | 
4  |  |  * Licensed under the Apache License 2.0 (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/objects.h>  | 
11  |  | #include "obj_xref.h"  | 
12  |  | #include "internal/nelem.h"  | 
13  |  | #include "internal/thread_once.h"  | 
14  |  | #include <openssl/err.h>  | 
15  |  |  | 
16  |  | static STACK_OF(nid_triple) *sig_app, *sigx_app;  | 
17  |  | static CRYPTO_RWLOCK *sig_lock;  | 
18  |  |  | 
19  |  | static int sig_cmp(const nid_triple *a, const nid_triple *b)  | 
20  | 0  | { | 
21  | 0  |     return a->sign_id - b->sign_id;  | 
22  | 0  | }  | 
23  |  |  | 
24  |  | DECLARE_OBJ_BSEARCH_CMP_FN(nid_triple, nid_triple, sig);  | 
25  |  | IMPLEMENT_OBJ_BSEARCH_CMP_FN(nid_triple, nid_triple, sig);  | 
26  |  |  | 
27  |  | static int sig_sk_cmp(const nid_triple *const *a, const nid_triple *const *b)  | 
28  | 0  | { | 
29  | 0  |     return (*a)->sign_id - (*b)->sign_id;  | 
30  | 0  | }  | 
31  |  |  | 
32  |  | DECLARE_OBJ_BSEARCH_CMP_FN(const nid_triple *, const nid_triple *, sigx);  | 
33  |  |  | 
34  |  | static int sigx_cmp(const nid_triple *const *a, const nid_triple *const *b)  | 
35  | 0  | { | 
36  | 0  |     int ret;  | 
37  |  | 
  | 
38  | 0  |     ret = (*a)->hash_id - (*b)->hash_id;  | 
39  |  |     /* The "b" side of the comparison carries the algorithms already  | 
40  |  |      * registered. A NID_undef for 'hash_id' there means that the  | 
41  |  |      * signature algorithm doesn't need a digest to operate OK. In  | 
42  |  |      * such case, any hash_id/digest algorithm on the test side (a),  | 
43  |  |      * incl. NID_undef, is acceptable. signature algorithm NID  | 
44  |  |      * (pkey_id) must match in any case.  | 
45  |  |      */  | 
46  | 0  |     if ((ret != 0) && ((*b)->hash_id != NID_undef))  | 
47  | 0  |         return ret;  | 
48  | 0  |     return (*a)->pkey_id - (*b)->pkey_id;  | 
49  | 0  | }  | 
50  |  |  | 
51  |  | IMPLEMENT_OBJ_BSEARCH_CMP_FN(const nid_triple *, const nid_triple *, sigx);  | 
52  |  |  | 
53  |  | static CRYPTO_ONCE sig_init = CRYPTO_ONCE_STATIC_INIT;  | 
54  |  |  | 
55  |  | DEFINE_RUN_ONCE_STATIC(o_sig_init)  | 
56  | 0  | { | 
57  | 0  |     sig_lock = CRYPTO_THREAD_lock_new();  | 
58  | 0  |     return sig_lock != NULL;  | 
59  | 0  | }  | 
60  |  |  | 
61  |  | static ossl_inline int obj_sig_init(void)  | 
62  | 0  | { | 
63  | 0  |     return RUN_ONCE(&sig_init, o_sig_init);  | 
64  | 0  | }  | 
65  |  |  | 
66  |  | static int ossl_obj_find_sigid_algs(int signid, int *pdig_nid, int *ppkey_nid,  | 
67  |  |                                     int lock)  | 
68  | 0  | { | 
69  | 0  |     nid_triple tmp;  | 
70  | 0  |     const nid_triple *rv;  | 
71  | 0  |     int idx;  | 
72  |  | 
  | 
73  | 0  |     if (signid == NID_undef)  | 
74  | 0  |         return 0;  | 
75  |  |  | 
76  | 0  |     tmp.sign_id = signid;  | 
77  | 0  |     rv = OBJ_bsearch_sig(&tmp, sigoid_srt, OSSL_NELEM(sigoid_srt));  | 
78  | 0  |     if (rv == NULL) { | 
79  | 0  |         if (!obj_sig_init())  | 
80  | 0  |             return 0;  | 
81  | 0  |         if (lock && !CRYPTO_THREAD_read_lock(sig_lock)) { | 
82  | 0  |             ERR_raise(ERR_LIB_OBJ, ERR_R_UNABLE_TO_GET_READ_LOCK);  | 
83  | 0  |             return 0;  | 
84  | 0  |         }  | 
85  | 0  |         if (sig_app != NULL) { | 
86  | 0  |             idx = sk_nid_triple_find(sig_app, &tmp);  | 
87  | 0  |             if (idx >= 0)  | 
88  | 0  |                 rv = sk_nid_triple_value(sig_app, idx);  | 
89  | 0  |         }  | 
90  | 0  |         if (lock)  | 
91  | 0  |             CRYPTO_THREAD_unlock(sig_lock);  | 
92  | 0  |         if (rv == NULL)  | 
93  | 0  |             return 0;  | 
94  | 0  |     }  | 
95  |  |  | 
96  | 0  |     if (pdig_nid != NULL)  | 
97  | 0  |         *pdig_nid = rv->hash_id;  | 
98  | 0  |     if (ppkey_nid != NULL)  | 
99  | 0  |         *ppkey_nid = rv->pkey_id;  | 
100  | 0  |     return 1;  | 
101  | 0  | }  | 
102  |  |  | 
103  |  | int OBJ_find_sigid_algs(int signid, int *pdig_nid, int *ppkey_nid)  | 
104  | 0  | { | 
105  | 0  |     return ossl_obj_find_sigid_algs(signid, pdig_nid, ppkey_nid, 1);  | 
106  | 0  | }  | 
107  |  |  | 
108  |  | int OBJ_find_sigid_by_algs(int *psignid, int dig_nid, int pkey_nid)  | 
109  | 0  | { | 
110  | 0  |     nid_triple tmp;  | 
111  | 0  |     const nid_triple *t = &tmp;  | 
112  | 0  |     const nid_triple **rv;  | 
113  | 0  |     int idx;  | 
114  |  |  | 
115  |  |     /* permitting searches for sig algs without digest: */  | 
116  | 0  |     if (pkey_nid == NID_undef)  | 
117  | 0  |         return 0;  | 
118  |  |  | 
119  | 0  |     tmp.hash_id = dig_nid;  | 
120  | 0  |     tmp.pkey_id = pkey_nid;  | 
121  |  | 
  | 
122  | 0  |     rv = OBJ_bsearch_sigx(&t, sigoid_srt_xref, OSSL_NELEM(sigoid_srt_xref));  | 
123  | 0  |     if (rv == NULL) { | 
124  | 0  |         if (!obj_sig_init())  | 
125  | 0  |             return 0;  | 
126  | 0  |         if (!CRYPTO_THREAD_read_lock(sig_lock)) { | 
127  | 0  |             ERR_raise(ERR_LIB_OBJ, ERR_R_UNABLE_TO_GET_READ_LOCK);  | 
128  | 0  |             return 0;  | 
129  | 0  |         }  | 
130  | 0  |         if (sigx_app != NULL) { | 
131  | 0  |             idx = sk_nid_triple_find(sigx_app, &tmp);  | 
132  | 0  |             if (idx >= 0) { | 
133  | 0  |                 t = sk_nid_triple_value(sigx_app, idx);  | 
134  | 0  |                 rv = &t;  | 
135  | 0  |             }  | 
136  | 0  |         }  | 
137  | 0  |         CRYPTO_THREAD_unlock(sig_lock);  | 
138  | 0  |         if (rv == NULL)  | 
139  | 0  |             return 0;  | 
140  | 0  |     }  | 
141  |  |  | 
142  | 0  |     if (psignid != NULL)  | 
143  | 0  |         *psignid = (*rv)->sign_id;  | 
144  | 0  |     return 1;  | 
145  | 0  | }  | 
146  |  |  | 
147  |  | int OBJ_add_sigid(int signid, int dig_id, int pkey_id)  | 
148  | 0  | { | 
149  | 0  |     nid_triple *ntr;  | 
150  | 0  |     int dnid = NID_undef, pnid = NID_undef, ret = 0;  | 
151  |  | 
  | 
152  | 0  |     if (signid == NID_undef || pkey_id == NID_undef)  | 
153  | 0  |         return 0;  | 
154  |  |  | 
155  | 0  |     if (!obj_sig_init())  | 
156  | 0  |         return 0;  | 
157  |  |  | 
158  | 0  |     if ((ntr = OPENSSL_malloc(sizeof(*ntr))) == NULL)  | 
159  | 0  |         return 0;  | 
160  | 0  |     ntr->sign_id = signid;  | 
161  | 0  |     ntr->hash_id = dig_id;  | 
162  | 0  |     ntr->pkey_id = pkey_id;  | 
163  |  | 
  | 
164  | 0  |     if (!CRYPTO_THREAD_write_lock(sig_lock)) { | 
165  | 0  |         ERR_raise(ERR_LIB_OBJ, ERR_R_UNABLE_TO_GET_WRITE_LOCK);  | 
166  | 0  |         OPENSSL_free(ntr);  | 
167  | 0  |         return 0;  | 
168  | 0  |     }  | 
169  |  |  | 
170  |  |     /* Check that the entry doesn't exist or exists as desired */  | 
171  | 0  |     if (ossl_obj_find_sigid_algs(signid, &dnid, &pnid, 0)) { | 
172  | 0  |         ret = dnid == dig_id && pnid == pkey_id;  | 
173  | 0  |         goto err;  | 
174  | 0  |     }  | 
175  |  |  | 
176  | 0  |     if (sig_app == NULL) { | 
177  | 0  |         sig_app = sk_nid_triple_new(sig_sk_cmp);  | 
178  | 0  |         if (sig_app == NULL)  | 
179  | 0  |             goto err;  | 
180  | 0  |     }  | 
181  | 0  |     if (sigx_app == NULL) { | 
182  | 0  |         sigx_app = sk_nid_triple_new(sigx_cmp);  | 
183  | 0  |         if (sigx_app == NULL)  | 
184  | 0  |             goto err;  | 
185  | 0  |     }  | 
186  |  |  | 
187  |  |     /*  | 
188  |  |      * Better might be to find where to insert the element and insert it there.  | 
189  |  |      * This would avoid the sorting steps below.  | 
190  |  |      */  | 
191  | 0  |     if (!sk_nid_triple_push(sig_app, ntr))  | 
192  | 0  |         goto err;  | 
193  | 0  |     if (!sk_nid_triple_push(sigx_app, ntr)) { | 
194  | 0  |         ntr = NULL;             /* This is referenced by sig_app still */  | 
195  | 0  |         goto err;  | 
196  | 0  |     }  | 
197  |  |  | 
198  | 0  |     sk_nid_triple_sort(sig_app);  | 
199  | 0  |     sk_nid_triple_sort(sigx_app);  | 
200  |  | 
  | 
201  | 0  |     ntr = NULL;  | 
202  | 0  |     ret = 1;  | 
203  | 0  |  err:  | 
204  | 0  |     OPENSSL_free(ntr);  | 
205  | 0  |     CRYPTO_THREAD_unlock(sig_lock);  | 
206  | 0  |     return ret;  | 
207  | 0  | }  | 
208  |  |  | 
209  |  | static void sid_free(nid_triple *tt)  | 
210  | 0  | { | 
211  | 0  |     OPENSSL_free(tt);  | 
212  | 0  | }  | 
213  |  |  | 
214  |  | void OBJ_sigid_free(void)  | 
215  | 1  | { | 
216  | 1  |     sk_nid_triple_pop_free(sig_app, sid_free);  | 
217  | 1  |     sk_nid_triple_free(sigx_app);  | 
218  | 1  |     CRYPTO_THREAD_lock_free(sig_lock);  | 
219  | 1  |     sig_app = NULL;  | 
220  | 1  |     sigx_app = NULL;  | 
221  | 1  |     sig_lock = NULL;  | 
222  | 1  | }  |