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