Fix coverity issues in EC after #11807
[openssl.git] / crypto / engine / tb_asnmth.c
1 /*
2  * Copyright 2006-2018 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 "e_os.h"
11 #include "eng_local.h"
12 #include <openssl/evp.h>
13 #include "crypto/asn1.h"
14
15 /*
16  * If this symbol is defined then ENGINE_get_pkey_asn1_meth_engine(), the
17  * function that is used by EVP to hook in pkey_asn1_meth code and cache
18  * defaults (etc), will display brief debugging summaries to stderr with the
19  * 'nid'.
20  */
21 /* #define ENGINE_PKEY_ASN1_METH_DEBUG */
22
23 static ENGINE_TABLE *pkey_asn1_meth_table = NULL;
24
25 void ENGINE_unregister_pkey_asn1_meths(ENGINE *e)
26 {
27     engine_table_unregister(&pkey_asn1_meth_table, e);
28 }
29
30 static void engine_unregister_all_pkey_asn1_meths(void)
31 {
32     engine_table_cleanup(&pkey_asn1_meth_table);
33 }
34
35 int ENGINE_register_pkey_asn1_meths(ENGINE *e)
36 {
37     if (e->pkey_asn1_meths) {
38         const int *nids;
39         int num_nids = e->pkey_asn1_meths(e, NULL, &nids, 0);
40         if (num_nids > 0)
41             return engine_table_register(&pkey_asn1_meth_table,
42                                          engine_unregister_all_pkey_asn1_meths,
43                                          e, nids, num_nids, 0);
44     }
45     return 1;
46 }
47
48 void ENGINE_register_all_pkey_asn1_meths(void)
49 {
50     ENGINE *e;
51
52     for (e = ENGINE_get_first(); e; e = ENGINE_get_next(e))
53         ENGINE_register_pkey_asn1_meths(e);
54 }
55
56 int ENGINE_set_default_pkey_asn1_meths(ENGINE *e)
57 {
58     if (e->pkey_asn1_meths) {
59         const int *nids;
60         int num_nids = e->pkey_asn1_meths(e, NULL, &nids, 0);
61         if (num_nids > 0)
62             return engine_table_register(&pkey_asn1_meth_table,
63                                          engine_unregister_all_pkey_asn1_meths,
64                                          e, nids, num_nids, 1);
65     }
66     return 1;
67 }
68
69 /*
70  * Exposed API function to get a functional reference from the implementation
71  * table (ie. try to get a functional reference from the tabled structural
72  * references) for a given pkey_asn1_meth 'nid'
73  */
74 ENGINE *ENGINE_get_pkey_asn1_meth_engine(int nid)
75 {
76     return engine_table_select(&pkey_asn1_meth_table, nid);
77 }
78
79 /*
80  * Obtains a pkey_asn1_meth implementation from an ENGINE functional
81  * reference
82  */
83 const EVP_PKEY_ASN1_METHOD *ENGINE_get_pkey_asn1_meth(ENGINE *e, int nid)
84 {
85     EVP_PKEY_ASN1_METHOD *ret;
86     ENGINE_PKEY_ASN1_METHS_PTR fn = ENGINE_get_pkey_asn1_meths(e);
87     if (!fn || !fn(e, &ret, NULL, nid)) {
88         ENGINEerr(ENGINE_F_ENGINE_GET_PKEY_ASN1_METH,
89                   ENGINE_R_UNIMPLEMENTED_PUBLIC_KEY_METHOD);
90         return NULL;
91     }
92     return ret;
93 }
94
95 /* Gets the pkey_asn1_meth callback from an ENGINE structure */
96 ENGINE_PKEY_ASN1_METHS_PTR ENGINE_get_pkey_asn1_meths(const ENGINE *e)
97 {
98     return e->pkey_asn1_meths;
99 }
100
101 /* Sets the pkey_asn1_meth callback in an ENGINE structure */
102 int ENGINE_set_pkey_asn1_meths(ENGINE *e, ENGINE_PKEY_ASN1_METHS_PTR f)
103 {
104     e->pkey_asn1_meths = f;
105     return 1;
106 }
107
108 /*
109  * Internal function to free up EVP_PKEY_ASN1_METHOD structures before an
110  * ENGINE is destroyed
111  */
112
113 void engine_pkey_asn1_meths_free(ENGINE *e)
114 {
115     int i;
116     EVP_PKEY_ASN1_METHOD *pkm;
117     if (e->pkey_asn1_meths) {
118         const int *pknids;
119         int npknids;
120         npknids = e->pkey_asn1_meths(e, NULL, &pknids, 0);
121         for (i = 0; i < npknids; i++) {
122             if (e->pkey_asn1_meths(e, &pkm, NULL, pknids[i])) {
123                 EVP_PKEY_asn1_free(pkm);
124             }
125         }
126     }
127 }
128
129 /*
130  * Find a method based on a string. This does a linear search through all
131  * implemented algorithms. This is OK in practice because only a small number
132  * of algorithms are likely to be implemented in an engine and it is not used
133  * for speed critical operations.
134  */
135
136 const EVP_PKEY_ASN1_METHOD *ENGINE_get_pkey_asn1_meth_str(ENGINE *e,
137                                                           const char *str,
138                                                           int len)
139 {
140     int i, nidcount;
141     const int *nids;
142     EVP_PKEY_ASN1_METHOD *ameth;
143     if (!e->pkey_asn1_meths)
144         return NULL;
145     if (len == -1)
146         len = strlen(str);
147     nidcount = e->pkey_asn1_meths(e, NULL, &nids, 0);
148     for (i = 0; i < nidcount; i++) {
149         e->pkey_asn1_meths(e, &ameth, NULL, nids[i]);
150         if (ameth != NULL
151             && ((int)strlen(ameth->pem_str) == len)
152             && strncasecmp(ameth->pem_str, str, len) == 0)
153             return ameth;
154     }
155     return NULL;
156 }
157
158 typedef struct {
159     ENGINE *e;
160     const EVP_PKEY_ASN1_METHOD *ameth;
161     const char *str;
162     int len;
163 } ENGINE_FIND_STR;
164
165 static void look_str_cb(int nid, STACK_OF(ENGINE) *sk, ENGINE *def, void *arg)
166 {
167     ENGINE_FIND_STR *lk = arg;
168     int i;
169     if (lk->ameth)
170         return;
171     for (i = 0; i < sk_ENGINE_num(sk); i++) {
172         ENGINE *e = sk_ENGINE_value(sk, i);
173         EVP_PKEY_ASN1_METHOD *ameth;
174         e->pkey_asn1_meths(e, &ameth, NULL, nid);
175         if (ameth != NULL
176                 && ((int)strlen(ameth->pem_str) == lk->len)
177                 && strncasecmp(ameth->pem_str, lk->str, lk->len) == 0) {
178             lk->e = e;
179             lk->ameth = ameth;
180             return;
181         }
182     }
183 }
184
185 const EVP_PKEY_ASN1_METHOD *ENGINE_pkey_asn1_find_str(ENGINE **pe,
186                                                       const char *str,
187                                                       int len)
188 {
189     ENGINE_FIND_STR fstr;
190     fstr.e = NULL;
191     fstr.ameth = NULL;
192     fstr.str = str;
193     fstr.len = len;
194
195     if (!RUN_ONCE(&engine_lock_init, do_engine_lock_init)) {
196         ENGINEerr(ENGINE_F_ENGINE_PKEY_ASN1_FIND_STR, ERR_R_MALLOC_FAILURE);
197         return NULL;
198     }
199
200     CRYPTO_THREAD_write_lock(global_engine_lock);
201     engine_table_doall(pkey_asn1_meth_table, look_str_cb, &fstr);
202     /* If found obtain a structural reference to engine */
203     if (fstr.e) {
204         fstr.e->struct_ref++;
205         engine_ref_debug(fstr.e, 0, 1);
206     }
207     *pe = fstr.e;
208     CRYPTO_THREAD_unlock(global_engine_lock);
209     return fstr.ameth;
210 }