xref: /openbsd-src/lib/libcrypto/evp/pmeth_lib.c (revision f2a19305cfc49ea4d1a5feb55cd6c283c6f1e031)
1 /* $OpenBSD: pmeth_lib.c,v 1.40 2024/04/09 13:52:41 beck Exp $ */
2 /* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
3  * project 2006.
4  */
5 /* ====================================================================
6  * Copyright (c) 2006 The OpenSSL Project.  All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  *
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in
17  *    the documentation and/or other materials provided with the
18  *    distribution.
19  *
20  * 3. All advertising materials mentioning features or use of this
21  *    software must display the following acknowledgment:
22  *    "This product includes software developed by the OpenSSL Project
23  *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
24  *
25  * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
26  *    endorse or promote products derived from this software without
27  *    prior written permission. For written permission, please contact
28  *    licensing@OpenSSL.org.
29  *
30  * 5. Products derived from this software may not be called "OpenSSL"
31  *    nor may "OpenSSL" appear in their names without prior written
32  *    permission of the OpenSSL Project.
33  *
34  * 6. Redistributions of any form whatsoever must retain the following
35  *    acknowledgment:
36  *    "This product includes software developed by the OpenSSL Project
37  *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
38  *
39  * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
40  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
41  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
42  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
43  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
44  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
45  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
46  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
47  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
48  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
49  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
50  * OF THE POSSIBILITY OF SUCH DAMAGE.
51  * ====================================================================
52  *
53  * This product includes cryptographic software written by Eric Young
54  * (eay@cryptsoft.com).  This product includes software written by Tim
55  * Hudson (tjh@cryptsoft.com).
56  *
57  */
58 
59 #include <limits.h>
60 #include <stdio.h>
61 #include <stdlib.h>
62 #include <string.h>
63 
64 #include <openssl/opensslconf.h>
65 
66 #include <openssl/err.h>
67 #include <openssl/evp.h>
68 #include <openssl/objects.h>
69 #include <openssl/x509v3.h>
70 
71 #include "asn1_local.h"
72 #include "evp_local.h"
73 
74 extern const EVP_PKEY_METHOD cmac_pkey_meth;
75 extern const EVP_PKEY_METHOD dh_pkey_meth;
76 extern const EVP_PKEY_METHOD dsa_pkey_meth;
77 extern const EVP_PKEY_METHOD ec_pkey_meth;
78 extern const EVP_PKEY_METHOD ed25519_pkey_meth;
79 extern const EVP_PKEY_METHOD hkdf_pkey_meth;
80 extern const EVP_PKEY_METHOD hmac_pkey_meth;
81 extern const EVP_PKEY_METHOD rsa_pkey_meth;
82 extern const EVP_PKEY_METHOD rsa_pss_pkey_meth;
83 extern const EVP_PKEY_METHOD x25519_pkey_meth;
84 
85 static const EVP_PKEY_METHOD *pkey_methods[] = {
86 	&cmac_pkey_meth,
87 	&dh_pkey_meth,
88 	&dsa_pkey_meth,
89 	&ec_pkey_meth,
90 	&ed25519_pkey_meth,
91 	&hkdf_pkey_meth,
92 	&hmac_pkey_meth,
93 	&rsa_pkey_meth,
94 	&rsa_pss_pkey_meth,
95 	&x25519_pkey_meth,
96 };
97 
98 #define N_PKEY_METHODS (sizeof(pkey_methods) / sizeof(pkey_methods[0]))
99 
100 static const EVP_PKEY_METHOD *
101 evp_pkey_method_find(int nid)
102 {
103 	size_t i;
104 
105 	for (i = 0; i < N_PKEY_METHODS; i++) {
106 		const EVP_PKEY_METHOD *pmeth = pkey_methods[i];
107 		if (pmeth->pkey_id == nid)
108 			return pmeth;
109 	}
110 
111 	return NULL;
112 }
113 
114 static EVP_PKEY_CTX *
115 evp_pkey_ctx_new(EVP_PKEY *pkey, int nid)
116 {
117 	EVP_PKEY_CTX *pkey_ctx = NULL;
118 	const EVP_PKEY_METHOD *pmeth;
119 
120 	if (nid == -1) {
121 		if (pkey == NULL || pkey->ameth == NULL)
122 			return NULL;
123 		nid = pkey->ameth->pkey_id;
124 	}
125 
126 	if ((pmeth = evp_pkey_method_find(nid)) == NULL) {
127 		EVPerror(EVP_R_UNSUPPORTED_ALGORITHM);
128 		goto err;
129 	}
130 
131 	if ((pkey_ctx = calloc(1, sizeof(*pkey_ctx))) == NULL) {
132 		EVPerror(ERR_R_MALLOC_FAILURE);
133 		goto err;
134 	}
135 	pkey_ctx->pmeth = pmeth;
136 	pkey_ctx->operation = EVP_PKEY_OP_UNDEFINED;
137 	if ((pkey_ctx->pkey = pkey) != NULL)
138 		EVP_PKEY_up_ref(pkey_ctx->pkey);
139 
140 	if (pmeth->init != NULL) {
141 		if (pmeth->init(pkey_ctx) <= 0)
142 			goto err;
143 	}
144 
145 	return pkey_ctx;
146 
147  err:
148 	EVP_PKEY_CTX_free(pkey_ctx);
149 
150 	return NULL;
151 }
152 
153 EVP_PKEY_CTX *
154 EVP_PKEY_CTX_new(EVP_PKEY *pkey, ENGINE *engine)
155 {
156 	return evp_pkey_ctx_new(pkey, -1);
157 }
158 LCRYPTO_ALIAS(EVP_PKEY_CTX_new);
159 
160 EVP_PKEY_CTX *
161 EVP_PKEY_CTX_new_id(int nid, ENGINE *engine)
162 {
163 	return evp_pkey_ctx_new(NULL, nid);
164 }
165 LCRYPTO_ALIAS(EVP_PKEY_CTX_new_id);
166 
167 EVP_PKEY_CTX *
168 EVP_PKEY_CTX_dup(EVP_PKEY_CTX *pctx)
169 {
170 	EVP_PKEY_CTX *rctx = NULL;
171 
172 	if (pctx->pmeth == NULL || pctx->pmeth->copy == NULL)
173 		goto err;
174 	if ((rctx = calloc(1, sizeof(*rctx))) == NULL) {
175 		EVPerror(ERR_R_MALLOC_FAILURE);
176 		goto err;
177 	}
178 
179 	rctx->pmeth = pctx->pmeth;
180 
181 	if ((rctx->pkey = pctx->pkey) != NULL)
182 		EVP_PKEY_up_ref(rctx->pkey);
183 	if ((rctx->peerkey = pctx->peerkey) != NULL)
184 		EVP_PKEY_up_ref(rctx->peerkey);
185 
186 	rctx->operation = pctx->operation;
187 
188 	if (pctx->pmeth->copy(rctx, pctx) <= 0)
189 		goto err;
190 
191 	return rctx;
192 
193  err:
194 	EVP_PKEY_CTX_free(rctx);
195 	return NULL;
196 }
197 LCRYPTO_ALIAS(EVP_PKEY_CTX_dup);
198 
199 void
200 EVP_PKEY_CTX_free(EVP_PKEY_CTX *ctx)
201 {
202 	if (ctx == NULL)
203 		return;
204 	if (ctx->pmeth && ctx->pmeth->cleanup)
205 		ctx->pmeth->cleanup(ctx);
206 	EVP_PKEY_free(ctx->pkey);
207 	EVP_PKEY_free(ctx->peerkey);
208 	free(ctx);
209 }
210 LCRYPTO_ALIAS(EVP_PKEY_CTX_free);
211 
212 int
213 EVP_PKEY_CTX_ctrl(EVP_PKEY_CTX *ctx, int keytype, int optype, int cmd,
214     int p1, void *p2)
215 {
216 	int ret;
217 
218 	if (!ctx || !ctx->pmeth || !ctx->pmeth->ctrl) {
219 		EVPerror(EVP_R_COMMAND_NOT_SUPPORTED);
220 		return -2;
221 	}
222 	if ((keytype != -1) && (ctx->pmeth->pkey_id != keytype))
223 		return -1;
224 
225 	if (ctx->operation == EVP_PKEY_OP_UNDEFINED) {
226 		EVPerror(EVP_R_NO_OPERATION_SET);
227 		return -1;
228 	}
229 
230 	if ((optype != -1) && !(ctx->operation & optype)) {
231 		EVPerror(EVP_R_INVALID_OPERATION);
232 		return -1;
233 	}
234 
235 	ret = ctx->pmeth->ctrl(ctx, cmd, p1, p2);
236 
237 	if (ret == -2)
238 		EVPerror(EVP_R_COMMAND_NOT_SUPPORTED);
239 
240 	return ret;
241 
242 }
243 LCRYPTO_ALIAS(EVP_PKEY_CTX_ctrl);
244 
245 int
246 EVP_PKEY_CTX_ctrl_str(EVP_PKEY_CTX *ctx, const char *name, const char *value)
247 {
248 	if (!ctx || !ctx->pmeth || !ctx->pmeth->ctrl_str) {
249 		EVPerror(EVP_R_COMMAND_NOT_SUPPORTED);
250 		return -2;
251 	}
252 	if (!strcmp(name, "digest")) {
253 		return EVP_PKEY_CTX_md(ctx, EVP_PKEY_OP_TYPE_SIG,
254 		    EVP_PKEY_CTRL_MD, value);
255 	}
256 	return ctx->pmeth->ctrl_str(ctx, name, value);
257 }
258 LCRYPTO_ALIAS(EVP_PKEY_CTX_ctrl_str);
259 
260 int
261 EVP_PKEY_CTX_str2ctrl(EVP_PKEY_CTX *ctx, int cmd, const char *str)
262 {
263 	size_t len;
264 
265 	if ((len = strlen(str)) > INT_MAX)
266 		return -1;
267 
268 	return ctx->pmeth->ctrl(ctx, cmd, len, (void *)str);
269 }
270 
271 int
272 EVP_PKEY_CTX_hex2ctrl(EVP_PKEY_CTX *ctx, int cmd, const char *hexstr)
273 {
274 	unsigned char *hex = NULL;
275 	long length;
276 	int ret = 0;
277 
278 	if ((hex = string_to_hex(hexstr, &length)) == NULL)
279 		goto err;
280 	if (length < 0 || length > INT_MAX) {
281 		ret = -1;
282 		goto err;
283 	}
284 
285 	ret = ctx->pmeth->ctrl(ctx, cmd, length, hex);
286 
287  err:
288 	free(hex);
289 	return ret;
290 }
291 
292 int
293 EVP_PKEY_CTX_md(EVP_PKEY_CTX *ctx, int optype, int cmd, const char *md_name)
294 {
295 	const EVP_MD *md;
296 
297 	if ((md = EVP_get_digestbyname(md_name)) == NULL) {
298 		EVPerror(EVP_R_INVALID_DIGEST);
299 		return 0;
300 	}
301 	return EVP_PKEY_CTX_ctrl(ctx, -1, optype, cmd, 0, (void *)md);
302 }
303 
304 int
305 EVP_PKEY_CTX_get_operation(EVP_PKEY_CTX *ctx)
306 {
307 	return ctx->operation;
308 }
309 LCRYPTO_ALIAS(EVP_PKEY_CTX_get_operation);
310 
311 void
312 EVP_PKEY_CTX_set0_keygen_info(EVP_PKEY_CTX *ctx, int *dat, int datlen)
313 {
314 	ctx->keygen_info = dat;
315 	ctx->keygen_info_count = datlen;
316 }
317 LCRYPTO_ALIAS(EVP_PKEY_CTX_set0_keygen_info);
318 
319 void
320 EVP_PKEY_CTX_set_data(EVP_PKEY_CTX *ctx, void *data)
321 {
322 	ctx->data = data;
323 }
324 LCRYPTO_ALIAS(EVP_PKEY_CTX_set_data);
325 
326 void *
327 EVP_PKEY_CTX_get_data(EVP_PKEY_CTX *ctx)
328 {
329 	return ctx->data;
330 }
331 LCRYPTO_ALIAS(EVP_PKEY_CTX_get_data);
332 
333 EVP_PKEY *
334 EVP_PKEY_CTX_get0_pkey(EVP_PKEY_CTX *ctx)
335 {
336 	return ctx->pkey;
337 }
338 LCRYPTO_ALIAS(EVP_PKEY_CTX_get0_pkey);
339 
340 EVP_PKEY *
341 EVP_PKEY_CTX_get0_peerkey(EVP_PKEY_CTX *ctx)
342 {
343 	return ctx->peerkey;
344 }
345 LCRYPTO_ALIAS(EVP_PKEY_CTX_get0_peerkey);
346 
347 void
348 EVP_PKEY_CTX_set_app_data(EVP_PKEY_CTX *ctx, void *data)
349 {
350 	ctx->app_data = data;
351 }
352 LCRYPTO_ALIAS(EVP_PKEY_CTX_set_app_data);
353 
354 void *
355 EVP_PKEY_CTX_get_app_data(EVP_PKEY_CTX *ctx)
356 {
357 	return ctx->app_data;
358 }
359 LCRYPTO_ALIAS(EVP_PKEY_CTX_get_app_data);
360