1 /* $OpenBSD: tb_asnmth.c,v 1.6 2017/01/29 17:49:23 beck Exp $ */
2 /* ====================================================================
3  * Copyright (c) 2006 The OpenSSL Project.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  *
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in
14  *    the documentation and/or other materials provided with the
15  *    distribution.
16  *
17  * 3. All advertising materials mentioning features or use of this
18  *    software must display the following acknowledgment:
19  *    "This product includes software developed by the OpenSSL Project
20  *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
21  *
22  * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
23  *    endorse or promote products derived from this software without
24  *    prior written permission. For written permission, please contact
25  *    licensing@OpenSSL.org.
26  *
27  * 5. Products derived from this software may not be called "OpenSSL"
28  *    nor may "OpenSSL" appear in their names without prior written
29  *    permission of the OpenSSL Project.
30  *
31  * 6. Redistributions of any form whatsoever must retain the following
32  *    acknowledgment:
33  *    "This product includes software developed by the OpenSSL Project
34  *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
35  *
36  * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
37  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
38  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
39  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
40  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
41  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
42  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
43  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
44  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
45  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
46  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
47  * OF THE POSSIBILITY OF SUCH DAMAGE.
48  * ====================================================================
49  *
50  * This product includes cryptographic software written by Eric Young
51  * (eay@cryptsoft.com).  This product includes software written by Tim
52  * Hudson (tjh@cryptsoft.com).
53  *
54  */
55 
56 #include <string.h>
57 
58 #include <openssl/err.h>
59 
60 #include "eng_int.h"
61 #include "asn1_locl.h"
62 #include <openssl/evp.h>
63 
64 /* If this symbol is defined then ENGINE_get_pkey_asn1_meth_engine(), the
65  * function that is used by EVP to hook in pkey_asn1_meth code and cache
66  * defaults (etc), will display brief debugging summaries to stderr with the
67  * 'nid'. */
68 /* #define ENGINE_PKEY_ASN1_METH_DEBUG */
69 
70 static ENGINE_TABLE *pkey_asn1_meth_table = NULL;
71 
72 void
73 ENGINE_unregister_pkey_asn1_meths(ENGINE *e)
74 {
75 	engine_table_unregister(&pkey_asn1_meth_table, e);
76 }
77 
78 static void
79 engine_unregister_all_pkey_asn1_meths(void)
80 {
81 	engine_table_cleanup(&pkey_asn1_meth_table);
82 }
83 
84 int
85 ENGINE_register_pkey_asn1_meths(ENGINE *e)
86 {
87 	if (e->pkey_asn1_meths) {
88 		const int *nids;
89 		int num_nids = e->pkey_asn1_meths(e, NULL, &nids, 0);
90 		if (num_nids > 0)
91 			return engine_table_register(&pkey_asn1_meth_table,
92 			    engine_unregister_all_pkey_asn1_meths, e, nids,
93 			    num_nids, 0);
94 	}
95 	return 1;
96 }
97 
98 void
99 ENGINE_register_all_pkey_asn1_meths(void)
100 {
101 	ENGINE *e;
102 
103 	for (e = ENGINE_get_first(); e; e = ENGINE_get_next(e))
104 		ENGINE_register_pkey_asn1_meths(e);
105 }
106 
107 int
108 ENGINE_set_default_pkey_asn1_meths(ENGINE *e)
109 {
110 	if (e->pkey_asn1_meths) {
111 		const int *nids;
112 		int num_nids = e->pkey_asn1_meths(e, NULL, &nids, 0);
113 		if (num_nids > 0)
114 			return engine_table_register(&pkey_asn1_meth_table,
115 			    engine_unregister_all_pkey_asn1_meths, e, nids,
116 			    num_nids, 1);
117 	}
118 	return 1;
119 }
120 
121 /* Exposed API function to get a functional reference from the implementation
122  * table (ie. try to get a functional reference from the tabled structural
123  * references) for a given pkey_asn1_meth 'nid' */
124 ENGINE *
125 ENGINE_get_pkey_asn1_meth_engine(int nid)
126 {
127 	return engine_table_select(&pkey_asn1_meth_table, nid);
128 }
129 
130 /* Obtains a pkey_asn1_meth implementation from an ENGINE functional reference */
131 const EVP_PKEY_ASN1_METHOD *
132 ENGINE_get_pkey_asn1_meth(ENGINE *e, int nid)
133 {
134 	EVP_PKEY_ASN1_METHOD *ret;
135 	ENGINE_PKEY_ASN1_METHS_PTR fn = ENGINE_get_pkey_asn1_meths(e);
136 
137 	if (!fn || !fn(e, &ret, NULL, nid)) {
138 		ENGINEerror(ENGINE_R_UNIMPLEMENTED_PUBLIC_KEY_METHOD);
139 		return NULL;
140 	}
141 	return ret;
142 }
143 
144 /* Gets the pkey_asn1_meth callback from an ENGINE structure */
145 ENGINE_PKEY_ASN1_METHS_PTR
146 ENGINE_get_pkey_asn1_meths(const ENGINE *e)
147 {
148 	return e->pkey_asn1_meths;
149 }
150 
151 /* Sets the pkey_asn1_meth callback in an ENGINE structure */
152 int
153 ENGINE_set_pkey_asn1_meths(ENGINE *e, ENGINE_PKEY_ASN1_METHS_PTR f)
154 {
155 	e->pkey_asn1_meths = f;
156 	return 1;
157 }
158 
159 /* Internal function to free up EVP_PKEY_ASN1_METHOD structures before an
160  * ENGINE is destroyed
161  */
162 
163 void
164 engine_pkey_asn1_meths_free(ENGINE *e)
165 {
166 	int i;
167 	EVP_PKEY_ASN1_METHOD *pkm;
168 
169 	if (e->pkey_asn1_meths) {
170 		const int *pknids;
171 		int npknids;
172 		npknids = e->pkey_asn1_meths(e, NULL, &pknids, 0);
173 		for (i = 0; i < npknids; i++) {
174 			if (e->pkey_asn1_meths(e, &pkm, NULL, pknids[i])) {
175 				EVP_PKEY_asn1_free(pkm);
176 			}
177 		}
178 	}
179 }
180 
181 /* Find a method based on a string. This does a linear search through
182  * all implemented algorithms. This is OK in practice because only
183  * a small number of algorithms are likely to be implemented in an engine
184  * and it is not used for speed critical operations.
185  */
186 
187 const EVP_PKEY_ASN1_METHOD *
188 ENGINE_get_pkey_asn1_meth_str(ENGINE *e, const char *str, int len)
189 {
190 	int i, nidcount;
191 	const int *nids;
192 	EVP_PKEY_ASN1_METHOD *ameth;
193 
194 	if (!e->pkey_asn1_meths)
195 		return NULL;
196 	if (len == -1)
197 		len = strlen(str);
198 	nidcount = e->pkey_asn1_meths(e, NULL, &nids, 0);
199 	for (i = 0; i < nidcount; i++) {
200 		e->pkey_asn1_meths(e, &ameth, NULL, nids[i]);
201 		if (((int)strlen(ameth->pem_str) == len) &&
202 		    !strncasecmp(ameth->pem_str, str, len))
203 			return ameth;
204 	}
205 	return NULL;
206 }
207 
208 typedef struct {
209 	ENGINE *e;
210 	const EVP_PKEY_ASN1_METHOD *ameth;
211 	const char *str;
212 	int len;
213 } ENGINE_FIND_STR;
214 
215 static void
216 look_str_cb(int nid, STACK_OF(ENGINE) *sk, ENGINE *def, void *arg)
217 {
218 	ENGINE_FIND_STR *lk = arg;
219 	int i;
220 
221 	if (lk->ameth)
222 		return;
223 	for (i = 0; i < sk_ENGINE_num(sk); i++) {
224 		ENGINE *e = sk_ENGINE_value(sk, i);
225 		EVP_PKEY_ASN1_METHOD *ameth;
226 		e->pkey_asn1_meths(e, &ameth, NULL, nid);
227 		if (((int)strlen(ameth->pem_str) == lk->len) &&
228 		    !strncasecmp(ameth->pem_str, lk->str, lk->len)) {
229 			lk->e = e;
230 			lk->ameth = ameth;
231 			return;
232 		}
233 	}
234 }
235 
236 const EVP_PKEY_ASN1_METHOD *
237 ENGINE_pkey_asn1_find_str(ENGINE **pe, const char *str, int len)
238 {
239 	ENGINE_FIND_STR fstr;
240 
241 	fstr.e = NULL;
242 	fstr.ameth = NULL;
243 	fstr.str = str;
244 	fstr.len = len;
245 	CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
246 	engine_table_doall(pkey_asn1_meth_table, look_str_cb, &fstr);
247 	/* If found obtain a structural reference to engine */
248 	if (fstr.e) {
249 		fstr.e->struct_ref++;
250 		engine_ref_debug(fstr.e, 0, 1)
251 	}
252 	*pe = fstr.e;
253 	CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
254 	return fstr.ameth;
255 }
256