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