xref: /openbsd-src/lib/libcrypto/ec/ecx_methods.c (revision c5d7bed5dd774f32fe3ef5eeee814d3acfe35920)
1*c5d7bed5Stb /*	$OpenBSD: ecx_methods.c,v 1.14 2024/08/28 07:15:04 tb Exp $ */
2c93606bbSjsing /*
3c93606bbSjsing  * Copyright (c) 2022 Joel Sing <jsing@openbsd.org>
4c93606bbSjsing  *
5c93606bbSjsing  * Permission to use, copy, modify, and distribute this software for any
6c93606bbSjsing  * purpose with or without fee is hereby granted, provided that the above
7c93606bbSjsing  * copyright notice and this permission notice appear in all copies.
8c93606bbSjsing  *
9c93606bbSjsing  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10c93606bbSjsing  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11c93606bbSjsing  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12c93606bbSjsing  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13c93606bbSjsing  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14c93606bbSjsing  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15c93606bbSjsing  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16c93606bbSjsing  */
17c93606bbSjsing 
18c93606bbSjsing #include <string.h>
19c93606bbSjsing 
20e170a9e1Stb #include <openssl/cms.h>
21c93606bbSjsing #include <openssl/curve25519.h>
22c93606bbSjsing #include <openssl/ec.h>
23c93606bbSjsing #include <openssl/err.h>
24c93606bbSjsing #include <openssl/evp.h>
25c93606bbSjsing #include <openssl/x509.h>
26c93606bbSjsing 
27c9675a23Stb #include "asn1_local.h"
28c93606bbSjsing #include "bytestring.h"
29c93606bbSjsing #include "curve25519_internal.h"
30c9675a23Stb #include "evp_local.h"
312382ddb5Stb #include "x509_local.h"
32c93606bbSjsing 
33c93606bbSjsing /*
34c93606bbSjsing  * EVP PKEY and PKEY ASN.1 methods Ed25519 and X25519.
35c93606bbSjsing  *
36c93606bbSjsing  * RFC 7748 - Elliptic Curves for Security.
37c93606bbSjsing  * RFC 8032 - Edwards-Curve Digital Signature Algorithm (EdDSA).
38c93606bbSjsing  */
39c93606bbSjsing 
40c93606bbSjsing #define ED25519_BITS		253
41c93606bbSjsing #define ED25519_SECURITY_BITS	128
42c93606bbSjsing #define ED25519_SIG_SIZE	64
43c93606bbSjsing 
44c93606bbSjsing #define X25519_BITS		253
45c93606bbSjsing #define X25519_SECURITY_BITS	128
46c93606bbSjsing 
47c93606bbSjsing static int
48c93606bbSjsing ecx_key_len(int nid)
49c93606bbSjsing {
50c93606bbSjsing 	switch (nid) {
51c93606bbSjsing 	case NID_ED25519:
52c93606bbSjsing 		return ED25519_KEYLEN;
53c93606bbSjsing 	case NID_X25519:
54c93606bbSjsing 		return X25519_KEYLEN;
55c93606bbSjsing 	}
56c93606bbSjsing 
57c93606bbSjsing 	return 0;
58c93606bbSjsing }
59c93606bbSjsing 
60c93606bbSjsing static struct ecx_key_st *
61c93606bbSjsing ecx_key_new(int nid)
62c93606bbSjsing {
63c93606bbSjsing 	struct ecx_key_st *ecx_key;
64c93606bbSjsing 	int key_len;
65c93606bbSjsing 
66c93606bbSjsing 	if ((key_len = ecx_key_len(nid)) == 0)
67c93606bbSjsing 		return NULL;
68c93606bbSjsing 
69c93606bbSjsing 	if ((ecx_key = calloc(1, sizeof(*ecx_key))) == NULL)
70c93606bbSjsing 		return NULL;
71c93606bbSjsing 
72c93606bbSjsing 	ecx_key->nid = nid;
73c93606bbSjsing 	ecx_key->key_len = key_len;
74c93606bbSjsing 
75c93606bbSjsing 	return ecx_key;
76c93606bbSjsing }
77c93606bbSjsing 
78c93606bbSjsing static void
79c93606bbSjsing ecx_key_clear(struct ecx_key_st *ecx_key)
80c93606bbSjsing {
81c93606bbSjsing 	freezero(ecx_key->priv_key, ecx_key->priv_key_len);
82c93606bbSjsing 	ecx_key->priv_key = NULL;
83c93606bbSjsing 	ecx_key->priv_key_len = 0;
84c93606bbSjsing 
85c93606bbSjsing 	freezero(ecx_key->pub_key, ecx_key->pub_key_len);
86c93606bbSjsing 	ecx_key->pub_key = NULL;
87c93606bbSjsing 	ecx_key->pub_key_len = 0;
88c93606bbSjsing }
89c93606bbSjsing 
90c93606bbSjsing static void
91c93606bbSjsing ecx_key_free(struct ecx_key_st *ecx_key)
92c93606bbSjsing {
93c93606bbSjsing 	if (ecx_key == NULL)
94c93606bbSjsing 		return;
95c93606bbSjsing 
96c93606bbSjsing 	ecx_key_clear(ecx_key);
97c93606bbSjsing 
98c93606bbSjsing 	freezero(ecx_key, sizeof(*ecx_key));
99c93606bbSjsing }
100c93606bbSjsing 
101c93606bbSjsing static int
102c93606bbSjsing ecx_key_generate(struct ecx_key_st *ecx_key)
103c93606bbSjsing {
104c93606bbSjsing 	uint8_t *pub_key = NULL, *priv_key = NULL;
105c93606bbSjsing 	int ret = 0;
106c93606bbSjsing 
107c93606bbSjsing 	ecx_key_clear(ecx_key);
108c93606bbSjsing 
109c93606bbSjsing 	if ((pub_key = calloc(1, ecx_key->key_len)) == NULL)
110c93606bbSjsing 		goto err;
111c93606bbSjsing 	if ((priv_key = calloc(1, ecx_key->key_len)) == NULL)
112c93606bbSjsing 		goto err;
113c93606bbSjsing 
114c93606bbSjsing 	switch (ecx_key->nid) {
115c93606bbSjsing 	case NID_ED25519:
116c93606bbSjsing 		ED25519_keypair(pub_key, priv_key);
117c93606bbSjsing 		break;
118c93606bbSjsing 	case NID_X25519:
119c93606bbSjsing 		X25519_keypair(pub_key, priv_key);
120c93606bbSjsing 		break;
121c93606bbSjsing 	default:
122c93606bbSjsing 		goto err;
123c93606bbSjsing 	}
124c93606bbSjsing 
125c93606bbSjsing 	ecx_key->priv_key = priv_key;
126c93606bbSjsing 	ecx_key->priv_key_len = ecx_key->key_len;
127c93606bbSjsing 	priv_key = NULL;
128c93606bbSjsing 
129c93606bbSjsing 	ecx_key->pub_key = pub_key;
130c93606bbSjsing 	ecx_key->pub_key_len = ecx_key->key_len;
131c93606bbSjsing 	pub_key = NULL;
132c93606bbSjsing 
133c93606bbSjsing 	ret = 1;
134c93606bbSjsing 
135c93606bbSjsing  err:
136c93606bbSjsing 	freezero(pub_key, ecx_key->key_len);
137c93606bbSjsing 	freezero(priv_key, ecx_key->key_len);
138c93606bbSjsing 
139c93606bbSjsing 	return ret;
140c93606bbSjsing }
141c93606bbSjsing 
142c93606bbSjsing static int
143c93606bbSjsing ecx_key_set_priv(struct ecx_key_st *ecx_key, const uint8_t *priv_key,
144c93606bbSjsing     size_t priv_key_len)
145c93606bbSjsing {
146c93606bbSjsing 	uint8_t *pub_key = NULL;
147c93606bbSjsing 	CBS cbs;
148c93606bbSjsing 
149c93606bbSjsing 	ecx_key_clear(ecx_key);
150c93606bbSjsing 
151c93606bbSjsing 	if (priv_key_len != ecx_key->key_len)
152c93606bbSjsing 		goto err;
153c93606bbSjsing 
154c93606bbSjsing 	if ((pub_key = calloc(1, ecx_key->key_len)) == NULL)
155c93606bbSjsing 		goto err;
156c93606bbSjsing 
157c93606bbSjsing 	switch (ecx_key->nid) {
158c93606bbSjsing 	case NID_ED25519:
159c93606bbSjsing 		ED25519_public_from_private(pub_key, priv_key);
160c93606bbSjsing 		break;
161c93606bbSjsing 	case NID_X25519:
162c93606bbSjsing 		X25519_public_from_private(pub_key, priv_key);
163c93606bbSjsing 		break;
164c93606bbSjsing 	default:
165c93606bbSjsing 		goto err;
166c93606bbSjsing 	}
167c93606bbSjsing 
168c93606bbSjsing 	CBS_init(&cbs, priv_key, priv_key_len);
169c93606bbSjsing 	if (!CBS_stow(&cbs, &ecx_key->priv_key, &ecx_key->priv_key_len))
170c93606bbSjsing 		goto err;
171c93606bbSjsing 
172c93606bbSjsing 	ecx_key->pub_key = pub_key;
173c93606bbSjsing 	ecx_key->pub_key_len = ecx_key->key_len;
174c93606bbSjsing 	pub_key = NULL;
175c93606bbSjsing 
176c93606bbSjsing  err:
177c93606bbSjsing 	freezero(pub_key, ecx_key->key_len);
178c93606bbSjsing 
179c93606bbSjsing 	return 1;
180c93606bbSjsing }
181c93606bbSjsing 
182c93606bbSjsing static int
183c93606bbSjsing ecx_key_set_pub(struct ecx_key_st *ecx_key, const uint8_t *pub_key,
184c93606bbSjsing     size_t pub_key_len)
185c93606bbSjsing {
186c93606bbSjsing 	CBS cbs;
187c93606bbSjsing 
188c93606bbSjsing 	ecx_key_clear(ecx_key);
189c93606bbSjsing 
190c93606bbSjsing 	if (pub_key_len != ecx_key->key_len)
191c93606bbSjsing 		return 0;
192c93606bbSjsing 
193c93606bbSjsing 	CBS_init(&cbs, pub_key, pub_key_len);
194c93606bbSjsing 	if (!CBS_stow(&cbs, &ecx_key->pub_key, &ecx_key->pub_key_len))
195c93606bbSjsing 		return 0;
196c93606bbSjsing 
197c93606bbSjsing 	return 1;
198c93606bbSjsing }
199c93606bbSjsing 
200c93606bbSjsing static int
201c93606bbSjsing ecx_pub_decode(EVP_PKEY *pkey, X509_PUBKEY *xpubkey)
202c93606bbSjsing {
203c93606bbSjsing 	struct ecx_key_st *ecx_key = NULL;
204c93606bbSjsing 	X509_ALGOR *algor;
205c93606bbSjsing 	int algor_type;
206c93606bbSjsing 	const uint8_t *param;
207c93606bbSjsing 	int param_len;
208c93606bbSjsing 	int ret = 0;
209c93606bbSjsing 
210c93606bbSjsing 	if (!X509_PUBKEY_get0_param(NULL, &param, &param_len, &algor, xpubkey))
211c93606bbSjsing 		goto err;
212c93606bbSjsing 
213c93606bbSjsing 	/* Ensure that parameters have not been specified in the encoding. */
214c93606bbSjsing 	if (algor != NULL) {
215c93606bbSjsing 		X509_ALGOR_get0(NULL, &algor_type, NULL, algor);
216c93606bbSjsing 		if (algor_type != V_ASN1_UNDEF) {
217c93606bbSjsing 			ECerror(EC_R_INVALID_ENCODING);
218c93606bbSjsing 			goto err;
219c93606bbSjsing 		}
220c93606bbSjsing 	}
221c93606bbSjsing 
222c93606bbSjsing 	if (param == NULL || param_len != ecx_key_len(pkey->ameth->pkey_id)) {
223c93606bbSjsing 		ECerror(EC_R_INVALID_ENCODING);
224c93606bbSjsing 		goto err;
225c93606bbSjsing 	}
226c93606bbSjsing 
227c93606bbSjsing 	if ((ecx_key = ecx_key_new(pkey->ameth->pkey_id)) == NULL)
228c93606bbSjsing 		goto err;
229c93606bbSjsing 	if (!ecx_key_set_pub(ecx_key, param, param_len))
230c93606bbSjsing 		goto err;
231c93606bbSjsing 	if (!EVP_PKEY_assign(pkey, pkey->ameth->pkey_id, ecx_key))
232c93606bbSjsing 		goto err;
233c93606bbSjsing 	ecx_key = NULL;
234c93606bbSjsing 
235c93606bbSjsing 	ret = 1;
236c93606bbSjsing 
237c93606bbSjsing  err:
238c93606bbSjsing 	ecx_key_free(ecx_key);
239c93606bbSjsing 
240c93606bbSjsing 	return ret;
241c93606bbSjsing }
242c93606bbSjsing 
243c93606bbSjsing static int
244c93606bbSjsing ecx_pub_encode(X509_PUBKEY *xpubkey, const EVP_PKEY *pkey)
245c93606bbSjsing {
246c93606bbSjsing 	const struct ecx_key_st *ecx_key = pkey->pkey.ecx;
247c93606bbSjsing 	uint8_t *pub_key = NULL;
248c93606bbSjsing 	size_t pub_key_len = 0;
249c93606bbSjsing 	ASN1_OBJECT *aobj;
250c93606bbSjsing 	CBS cbs;
251c93606bbSjsing 	int ret = 0;
252c93606bbSjsing 
253c93606bbSjsing 	if (ecx_key == NULL) {
254c93606bbSjsing 		ECerror(EC_R_INVALID_KEY);
255c93606bbSjsing 		goto err;
256c93606bbSjsing 	}
257c93606bbSjsing 
258c93606bbSjsing 	if (ecx_key->pub_key_len != ecx_key->key_len)
259c93606bbSjsing 		goto err;
260c93606bbSjsing 
261c93606bbSjsing 	if ((aobj = OBJ_nid2obj(pkey->ameth->pkey_id)) == NULL)
262c93606bbSjsing 		goto err;
263c93606bbSjsing 
264c93606bbSjsing 	CBS_init(&cbs, ecx_key->pub_key, ecx_key->pub_key_len);
265c93606bbSjsing 	if (!CBS_stow(&cbs, &pub_key, &pub_key_len))
266c93606bbSjsing 		goto err;
267c93606bbSjsing 
268c93606bbSjsing 	if (!X509_PUBKEY_set0_param(xpubkey, aobj, V_ASN1_UNDEF, NULL,
269c93606bbSjsing 	    pub_key, pub_key_len))
270c93606bbSjsing 		goto err;
271c93606bbSjsing 
272c93606bbSjsing 	pub_key = NULL;
273c93606bbSjsing 	pub_key_len = 0;
274c93606bbSjsing 
275c93606bbSjsing 	ret = 1;
276c93606bbSjsing 
277c93606bbSjsing  err:
278c93606bbSjsing 	free(pub_key);
279c93606bbSjsing 
280c93606bbSjsing 	return ret;
281c93606bbSjsing }
282c93606bbSjsing 
283c93606bbSjsing static int
284c93606bbSjsing ecx_pub_cmp(const EVP_PKEY *pkey1, const EVP_PKEY *pkey2)
285c93606bbSjsing {
286c93606bbSjsing 	if (pkey1->pkey.ecx == NULL || pkey1->pkey.ecx->pub_key == NULL)
287c93606bbSjsing 		return -2;
288c93606bbSjsing 	if (pkey2->pkey.ecx == NULL || pkey2->pkey.ecx->pub_key == NULL)
289c93606bbSjsing 		return -2;
290c93606bbSjsing 	if (pkey1->pkey.ecx->pub_key_len != pkey2->pkey.ecx->pub_key_len)
291c93606bbSjsing 		return -2;
292c93606bbSjsing 
293c93606bbSjsing 	return timingsafe_memcmp(pkey1->pkey.ecx->pub_key, pkey2->pkey.ecx->pub_key,
294c93606bbSjsing 	    pkey1->pkey.ecx->pub_key_len) == 0;
295c93606bbSjsing }
296c93606bbSjsing 
2970a77e739Stb /* Reimplementation of ASN1_buf_print() that adds a secondary indent of 4. */
2980a77e739Stb static int
2990a77e739Stb ecx_buf_print(BIO *bio, const uint8_t *buf, size_t buf_len, int indent)
3000a77e739Stb {
3010a77e739Stb 	uint8_t u8;
3020a77e739Stb 	size_t octets = 0;
3030a77e739Stb 	const char *sep = ":", *nl = "";
3040a77e739Stb 	CBS cbs;
3050a77e739Stb 
306aa0e9c11Stb 	if (indent > 60)
307aa0e9c11Stb 		indent = 60;
3080a77e739Stb 	indent += 4;
3090a77e739Stb 	if (indent < 0)
3100a77e739Stb 		indent = 0;
3110a77e739Stb 
3120a77e739Stb 	CBS_init(&cbs, buf, buf_len);
3130a77e739Stb 	while (CBS_len(&cbs) > 0) {
3140a77e739Stb 		if (!CBS_get_u8(&cbs, &u8))
3150a77e739Stb 			return 0;
3160a77e739Stb 		if (octets++ % 15 == 0) {
3170a77e739Stb 			if (BIO_printf(bio, "%s%*s", nl, indent, "") < 0)
3180a77e739Stb 				return 0;
3190a77e739Stb 			nl = "\n";
3200a77e739Stb 		}
3210a77e739Stb 		if (CBS_len(&cbs) == 0)
3220a77e739Stb 			sep = "";
3230a77e739Stb 		if (BIO_printf(bio, "%02x%s", u8, sep) <= 0)
3240a77e739Stb 			return 0;
3250a77e739Stb 	}
3260a77e739Stb 
3270a77e739Stb 	if (BIO_printf(bio, "\n") <= 0)
3280a77e739Stb 		return 0;
3290a77e739Stb 
3300a77e739Stb 	return 1;
3310a77e739Stb }
3320a77e739Stb 
333c93606bbSjsing static int
334c93606bbSjsing ecx_pub_print(BIO *bio, const EVP_PKEY *pkey, int indent, ASN1_PCTX *ctx)
335c93606bbSjsing {
336c93606bbSjsing 	struct ecx_key_st *ecx_key = pkey->pkey.ecx;
337c93606bbSjsing 	const char *name;
338c93606bbSjsing 
339c93606bbSjsing 	if ((name = OBJ_nid2ln(pkey->ameth->pkey_id)) == NULL)
340c93606bbSjsing 		return 0;
341c93606bbSjsing 
342c93606bbSjsing 	if (ecx_key == NULL || ecx_key->pub_key == NULL)
343c93606bbSjsing 		return BIO_printf(bio, "%*s<INVALID PUBLIC KEY>\n",
344c93606bbSjsing 		    indent, "") > 0;
345c93606bbSjsing 
346c93606bbSjsing 	if (BIO_printf(bio, "%*s%s Public-Key:\n", indent, "", name) <= 0)
347c93606bbSjsing 		return 0;
348c93606bbSjsing 	if (BIO_printf(bio, "%*spub:\n", indent, "") <= 0)
349c93606bbSjsing 		return 0;
3500a77e739Stb 	if (!ecx_buf_print(bio, ecx_key->pub_key, ecx_key->pub_key_len, indent))
351c93606bbSjsing 		return 0;
352c93606bbSjsing 
353c93606bbSjsing 	return 1;
354c93606bbSjsing }
355c93606bbSjsing 
356c93606bbSjsing static int
357c93606bbSjsing ecx_priv_decode(EVP_PKEY *pkey, const PKCS8_PRIV_KEY_INFO *p8pki)
358c93606bbSjsing {
359c93606bbSjsing 	struct ecx_key_st *ecx_key = NULL;
360c93606bbSjsing 	ASN1_OCTET_STRING *aos = NULL;
361c93606bbSjsing 	const X509_ALGOR *algor;
362c93606bbSjsing 	int algor_type;
363c93606bbSjsing 	const uint8_t *param;
364c93606bbSjsing 	int param_len;
365c93606bbSjsing 	int ret = 0;
366c93606bbSjsing 
367c93606bbSjsing 	if (!PKCS8_pkey_get0(NULL, &param, &param_len, &algor, p8pki))
368c93606bbSjsing 		goto err;
369c93606bbSjsing 	if ((aos = d2i_ASN1_OCTET_STRING(NULL, &param, param_len)) == NULL)
370c93606bbSjsing 		goto err;
371c93606bbSjsing 
372c93606bbSjsing 	/* Ensure that parameters have not been specified in the encoding. */
373c93606bbSjsing 	if (algor != NULL) {
374c93606bbSjsing 		X509_ALGOR_get0(NULL, &algor_type, NULL, algor);
375c93606bbSjsing 		if (algor_type != V_ASN1_UNDEF) {
376c93606bbSjsing 			ECerror(EC_R_INVALID_ENCODING);
377c93606bbSjsing 			goto err;
378c93606bbSjsing 		}
379c93606bbSjsing 	}
380c93606bbSjsing 
381c93606bbSjsing 	if (ASN1_STRING_get0_data(aos) == NULL ||
382c93606bbSjsing 	    ASN1_STRING_length(aos) != ecx_key_len(pkey->ameth->pkey_id)) {
383c93606bbSjsing 		ECerror(EC_R_INVALID_ENCODING);
384c93606bbSjsing 		goto err;
385c93606bbSjsing 	}
386c93606bbSjsing 
387c93606bbSjsing 	if ((ecx_key = ecx_key_new(pkey->ameth->pkey_id)) == NULL)
388c93606bbSjsing 		goto err;
389c93606bbSjsing 	if (!ecx_key_set_priv(ecx_key, ASN1_STRING_get0_data(aos),
390c93606bbSjsing 	    ASN1_STRING_length(aos)))
391c93606bbSjsing 		goto err;
392c93606bbSjsing 	if (!EVP_PKEY_assign(pkey, pkey->ameth->pkey_id, ecx_key))
393c93606bbSjsing 		goto err;
394c93606bbSjsing 	ecx_key = NULL;
395c93606bbSjsing 
396c93606bbSjsing 	ret = 1;
397c93606bbSjsing 
398c93606bbSjsing  err:
399c93606bbSjsing 	ASN1_OCTET_STRING_free(aos);
400c93606bbSjsing 	ecx_key_free(ecx_key);
401c93606bbSjsing 
402c93606bbSjsing 	return ret;
403c93606bbSjsing }
404c93606bbSjsing 
405c93606bbSjsing static int
406c93606bbSjsing ecx_priv_encode(PKCS8_PRIV_KEY_INFO *p8pki, const EVP_PKEY *pkey)
407c93606bbSjsing {
408c93606bbSjsing 	struct ecx_key_st *ecx_key = pkey->pkey.ecx;
409c93606bbSjsing 	ASN1_OCTET_STRING *aos = NULL;
410c93606bbSjsing 	ASN1_OBJECT *aobj;
411c93606bbSjsing 	uint8_t *der = NULL;
412c93606bbSjsing 	int der_len = 0;
413c93606bbSjsing 	int ret = 0;
414c93606bbSjsing 
415c93606bbSjsing 	if (ecx_key == NULL || ecx_key->priv_key == NULL) {
416c93606bbSjsing 		ECerror(EC_R_INVALID_PRIVATE_KEY);
417c93606bbSjsing 		goto err;
418c93606bbSjsing 	}
419c93606bbSjsing 
420c93606bbSjsing 	if ((aobj = OBJ_nid2obj(pkey->ameth->pkey_id)) == NULL)
421c93606bbSjsing 		goto err;
422c93606bbSjsing 
423c93606bbSjsing 	if ((aos = ASN1_OCTET_STRING_new()) == NULL)
424c93606bbSjsing 		goto err;
425c93606bbSjsing 	if (!ASN1_OCTET_STRING_set(aos, ecx_key->priv_key,
426c93606bbSjsing 	    ecx_key->priv_key_len))
427c93606bbSjsing 		goto err;
428c93606bbSjsing 	if ((der_len = i2d_ASN1_OCTET_STRING(aos, &der)) < 0)
429c93606bbSjsing 		goto err;
430c93606bbSjsing 	if (!PKCS8_pkey_set0(p8pki, aobj, 0, V_ASN1_UNDEF, NULL, der, der_len))
431c93606bbSjsing 		goto err;
432c93606bbSjsing 
433c93606bbSjsing 	der = NULL;
434c93606bbSjsing 	der_len = 0;
435c93606bbSjsing 
436c93606bbSjsing 	ret = 1;
437c93606bbSjsing 
438c93606bbSjsing  err:
439c93606bbSjsing 	freezero(der, der_len);
440c93606bbSjsing 	ASN1_OCTET_STRING_free(aos);
441c93606bbSjsing 
442c93606bbSjsing 	return ret;
443c93606bbSjsing }
444c93606bbSjsing 
445c93606bbSjsing static int
446c93606bbSjsing ecx_priv_print(BIO *bio, const EVP_PKEY *pkey, int indent, ASN1_PCTX *ctx)
447c93606bbSjsing {
448c93606bbSjsing 	struct ecx_key_st *ecx_key = pkey->pkey.ecx;
449c93606bbSjsing 	const char *name;
450c93606bbSjsing 
451c93606bbSjsing 	if ((name = OBJ_nid2ln(pkey->ameth->pkey_id)) == NULL)
452c93606bbSjsing 		return 0;
453c93606bbSjsing 
454c93606bbSjsing 	if (ecx_key == NULL || ecx_key->priv_key == NULL)
455c93606bbSjsing 		return BIO_printf(bio, "%*s<INVALID PRIVATE KEY>\n",
456c93606bbSjsing 		    indent, "") > 0;
457c93606bbSjsing 
458c93606bbSjsing 	if (BIO_printf(bio, "%*s%s Private-Key:\n", indent, "", name) <= 0)
459c93606bbSjsing 		return 0;
460c93606bbSjsing 	if (BIO_printf(bio, "%*spriv:\n", indent, "") <= 0)
461c93606bbSjsing 		return 0;
4620a77e739Stb 	if (!ecx_buf_print(bio, ecx_key->priv_key, ecx_key->priv_key_len, indent))
463c93606bbSjsing 		return 0;
464c93606bbSjsing 	if (BIO_printf(bio, "%*spub:\n", indent, "") <= 0)
465c93606bbSjsing 		return 0;
4660a77e739Stb 	if (!ecx_buf_print(bio, ecx_key->pub_key, ecx_key->pub_key_len, indent))
467c93606bbSjsing 		return 0;
468c93606bbSjsing 
469c93606bbSjsing 	return 1;
470c93606bbSjsing }
471c93606bbSjsing 
472c93606bbSjsing static int
473c93606bbSjsing ecx_size(const EVP_PKEY *pkey)
474c93606bbSjsing {
475c93606bbSjsing 	return ecx_key_len(pkey->ameth->pkey_id);
476c93606bbSjsing }
477c93606bbSjsing 
478c93606bbSjsing static int
479c93606bbSjsing ecx_sig_size(const EVP_PKEY *pkey)
480c93606bbSjsing {
481c93606bbSjsing 	switch (pkey->ameth->pkey_id) {
482c93606bbSjsing 	case EVP_PKEY_ED25519:
483c93606bbSjsing 		return ED25519_SIG_SIZE;
484c93606bbSjsing 	}
485c93606bbSjsing 	return 0;
486c93606bbSjsing }
487c93606bbSjsing 
488c93606bbSjsing static int
489c93606bbSjsing ecx_bits(const EVP_PKEY *pkey)
490c93606bbSjsing {
491c93606bbSjsing 	switch (pkey->ameth->pkey_id) {
492c93606bbSjsing 	case EVP_PKEY_ED25519:
493c93606bbSjsing 		return ED25519_BITS;
494c93606bbSjsing 	case EVP_PKEY_X25519:
495c93606bbSjsing 		return X25519_BITS;
496c93606bbSjsing 	}
497c93606bbSjsing 	return 0;
498c93606bbSjsing }
499c93606bbSjsing 
500c93606bbSjsing static int
501c93606bbSjsing ecx_security_bits(const EVP_PKEY *pkey)
502c93606bbSjsing {
503c93606bbSjsing 	switch (pkey->ameth->pkey_id) {
504c93606bbSjsing 	case EVP_PKEY_ED25519:
505c93606bbSjsing 		return ED25519_SECURITY_BITS;
506c93606bbSjsing 	case EVP_PKEY_X25519:
507c93606bbSjsing 		return X25519_SECURITY_BITS;
508c93606bbSjsing 	}
509c93606bbSjsing 	return 0;
510c93606bbSjsing }
511c93606bbSjsing 
512c93606bbSjsing static int
513*c5d7bed5Stb ecx_signature_info(const X509_ALGOR *algor, int *md_nid, int *pkey_nid,
514*c5d7bed5Stb     int *security_bits, uint32_t *flags)
515*c5d7bed5Stb {
516*c5d7bed5Stb 	const ASN1_OBJECT *aobj;
517*c5d7bed5Stb 
518*c5d7bed5Stb 	X509_ALGOR_get0(&aobj, NULL, NULL, algor);
519*c5d7bed5Stb 	if (OBJ_obj2nid(aobj) != EVP_PKEY_ED25519)
520*c5d7bed5Stb 		return 0;
521*c5d7bed5Stb 
522*c5d7bed5Stb 	*md_nid = NID_undef;
523*c5d7bed5Stb 	*pkey_nid = NID_ED25519;
524*c5d7bed5Stb 	*security_bits = ED25519_SECURITY_BITS;
525*c5d7bed5Stb 	*flags = X509_SIG_INFO_TLS | X509_SIG_INFO_VALID;
526*c5d7bed5Stb 
527*c5d7bed5Stb 	return 1;
528*c5d7bed5Stb }
529*c5d7bed5Stb 
530*c5d7bed5Stb static int
531c93606bbSjsing ecx_param_cmp(const EVP_PKEY *pkey1, const EVP_PKEY *pkey2)
532c93606bbSjsing {
533c93606bbSjsing 	/* No parameters, so always equivalent. */
534c93606bbSjsing 	return 1;
535c93606bbSjsing }
536c93606bbSjsing 
537c93606bbSjsing static void
538c93606bbSjsing ecx_free(EVP_PKEY *pkey)
539c93606bbSjsing {
540c93606bbSjsing 	struct ecx_key_st *ecx_key = pkey->pkey.ecx;
541c93606bbSjsing 
542411f88e9Sbcook 	ecx_key_free(ecx_key);
543c93606bbSjsing }
544c93606bbSjsing 
545c93606bbSjsing static int
546c93606bbSjsing ecx_ctrl(EVP_PKEY *pkey, int op, long arg1, void *arg2)
547c93606bbSjsing {
548c93606bbSjsing 	/* Not supported. */
549c93606bbSjsing 	return -2;
550c93606bbSjsing }
551c93606bbSjsing 
552e170a9e1Stb #ifndef OPENSSL_NO_CMS
553e170a9e1Stb static int
554e170a9e1Stb ecx_cms_sign_or_verify(EVP_PKEY *pkey, long verify, CMS_SignerInfo *si)
555e170a9e1Stb {
556e170a9e1Stb 	X509_ALGOR *digestAlgorithm, *signatureAlgorithm;
557e170a9e1Stb 
558e170a9e1Stb 	if (verify != 0 && verify != 1)
559e170a9e1Stb 		return -1;
560e170a9e1Stb 
561e170a9e1Stb 	/* Check that we have an Ed25519 public key. */
562e170a9e1Stb 	if (EVP_PKEY_id(pkey) != NID_ED25519)
563e170a9e1Stb 		return -1;
564e170a9e1Stb 
565e170a9e1Stb 	CMS_SignerInfo_get0_algs(si, NULL, NULL, &digestAlgorithm,
566e170a9e1Stb 	    &signatureAlgorithm);
567e170a9e1Stb 
568e170a9e1Stb 	/* RFC 8419, section 2.3: digestAlgorithm MUST be SHA-512. */
569e170a9e1Stb 	if (digestAlgorithm == NULL)
570e170a9e1Stb 		return -1;
571e170a9e1Stb 	if (OBJ_obj2nid(digestAlgorithm->algorithm) != NID_sha512)
572e170a9e1Stb 		return -1;
573e170a9e1Stb 
574e170a9e1Stb 	/*
575e170a9e1Stb 	 * RFC 8419, section 2.4: signatureAlgorithm MUST be Ed25519, and the
576e170a9e1Stb 	 * parameters MUST be absent. For verification check that this is the
577e170a9e1Stb 	 * case, for signing set the signatureAlgorithm accordingly.
578e170a9e1Stb 	 */
579e170a9e1Stb 	if (verify) {
580e170a9e1Stb 		const ASN1_OBJECT *obj;
581e170a9e1Stb 		int param_type;
582e170a9e1Stb 
583e170a9e1Stb 		if (signatureAlgorithm == NULL)
584e170a9e1Stb 			return -1;
585e170a9e1Stb 
586e170a9e1Stb 		X509_ALGOR_get0(&obj, &param_type, NULL, signatureAlgorithm);
587e170a9e1Stb 		if (OBJ_obj2nid(obj) != NID_ED25519)
588e170a9e1Stb 			return -1;
589e170a9e1Stb 		if (param_type != V_ASN1_UNDEF)
590e170a9e1Stb 			return -1;
591e170a9e1Stb 
592e170a9e1Stb 		return 1;
593e170a9e1Stb 	}
594e170a9e1Stb 
595465c5d1eStb 	if (!X509_ALGOR_set0_by_nid(signatureAlgorithm, NID_ED25519,
596465c5d1eStb 	    V_ASN1_UNDEF, NULL))
597e170a9e1Stb 		return -1;
598e170a9e1Stb 
599e170a9e1Stb 	return 1;
600e170a9e1Stb }
601e170a9e1Stb #endif
602e170a9e1Stb 
603c93606bbSjsing static int
604c93606bbSjsing ecx_sign_ctrl(EVP_PKEY *pkey, int op, long arg1, void *arg2)
605c93606bbSjsing {
606c93606bbSjsing 	switch (op) {
607e170a9e1Stb #ifndef OPENSSL_NO_CMS
608e170a9e1Stb 	case ASN1_PKEY_CTRL_CMS_SIGN:
609e170a9e1Stb 		return ecx_cms_sign_or_verify(pkey, arg1, arg2);
610e170a9e1Stb #endif
611c93606bbSjsing 	case ASN1_PKEY_CTRL_DEFAULT_MD_NID:
612c93606bbSjsing 		/* PureEdDSA does its own hashing. */
613c93606bbSjsing 		*(int *)arg2 = NID_undef;
614c93606bbSjsing 		return 2;
615c93606bbSjsing 	}
616c93606bbSjsing 	return -2;
617c93606bbSjsing }
618c93606bbSjsing 
619c93606bbSjsing static int
620c93606bbSjsing ecx_set_priv_key(EVP_PKEY *pkey, const uint8_t *priv, size_t len)
621c93606bbSjsing {
622e309ac14Stb 	struct ecx_key_st *ecx_key = NULL;
623c93606bbSjsing 	int ret = 0;
624c93606bbSjsing 
625c93606bbSjsing 	if (priv == NULL || len != ecx_key_len(pkey->ameth->pkey_id)) {
626c93606bbSjsing 		ECerror(EC_R_INVALID_ENCODING);
627e309ac14Stb 		goto err;
628c93606bbSjsing 	}
629c93606bbSjsing 
630c93606bbSjsing 	if ((ecx_key = ecx_key_new(pkey->ameth->pkey_id)) == NULL)
631e309ac14Stb 		goto err;
632c93606bbSjsing 	if (!ecx_key_set_priv(ecx_key, priv, len))
633e309ac14Stb 		goto err;
634c93606bbSjsing 	if (!EVP_PKEY_assign(pkey, pkey->ameth->pkey_id, ecx_key))
635c93606bbSjsing 		goto err;
636c93606bbSjsing 	ecx_key = NULL;
637c93606bbSjsing 
638c93606bbSjsing 	ret = 1;
639c93606bbSjsing 
640c93606bbSjsing  err:
641c93606bbSjsing 	ecx_key_free(ecx_key);
642c93606bbSjsing 
643c93606bbSjsing 	return ret;
644c93606bbSjsing }
645c93606bbSjsing 
646c93606bbSjsing static int
647c93606bbSjsing ecx_set_pub_key(EVP_PKEY *pkey, const uint8_t *pub, size_t len)
648c93606bbSjsing {
649e309ac14Stb 	struct ecx_key_st *ecx_key = NULL;
650c93606bbSjsing 	int ret = 0;
651c93606bbSjsing 
652c93606bbSjsing 	if (pub == NULL || len != ecx_key_len(pkey->ameth->pkey_id)) {
653c93606bbSjsing 		ECerror(EC_R_INVALID_ENCODING);
654e309ac14Stb 		goto err;
655c93606bbSjsing 	}
656c93606bbSjsing 
657c93606bbSjsing 	if ((ecx_key = ecx_key_new(pkey->ameth->pkey_id)) == NULL)
658e309ac14Stb 		goto err;
659c93606bbSjsing 	if (!ecx_key_set_pub(ecx_key, pub, len))
660e309ac14Stb 		goto err;
661c93606bbSjsing 	if (!EVP_PKEY_assign(pkey, pkey->ameth->pkey_id, ecx_key))
662c93606bbSjsing 		goto err;
663c93606bbSjsing 	ecx_key = NULL;
664c93606bbSjsing 
665c93606bbSjsing 	ret = 1;
666c93606bbSjsing 
667c93606bbSjsing  err:
668c93606bbSjsing 	ecx_key_free(ecx_key);
669c93606bbSjsing 
670c93606bbSjsing 	return ret;
671c93606bbSjsing }
672c93606bbSjsing 
673c93606bbSjsing static int
674c93606bbSjsing ecx_get_priv_key(const EVP_PKEY *pkey, unsigned char *out_priv, size_t *out_len)
675c93606bbSjsing {
676c93606bbSjsing 	struct ecx_key_st *ecx_key = pkey->pkey.ecx;
677c93606bbSjsing 	CBS cbs;
678c93606bbSjsing 
679c93606bbSjsing 	if (out_priv == NULL) {
680c93606bbSjsing 		*out_len = ecx_key_len(pkey->ameth->pkey_id);
681c93606bbSjsing 		return 1;
682c93606bbSjsing 	}
683c93606bbSjsing 
684c93606bbSjsing 	if (ecx_key == NULL || ecx_key->priv_key == NULL)
685c93606bbSjsing 		return 0;
686c93606bbSjsing 
687c93606bbSjsing 	CBS_init(&cbs, ecx_key->priv_key, ecx_key->priv_key_len);
688c93606bbSjsing 	if (!CBS_write_bytes(&cbs, out_priv, *out_len, out_len))
689c93606bbSjsing 		return 0;
690c93606bbSjsing 
691c93606bbSjsing 	return 1;
692c93606bbSjsing }
693c93606bbSjsing 
694c93606bbSjsing static int
695c93606bbSjsing ecx_get_pub_key(const EVP_PKEY *pkey, unsigned char *out_pub, size_t *out_len)
696c93606bbSjsing {
697c93606bbSjsing 	struct ecx_key_st *ecx_key = pkey->pkey.ecx;
698c93606bbSjsing 	CBS cbs;
699c93606bbSjsing 
700c93606bbSjsing 	if (out_pub == NULL) {
701c93606bbSjsing 		*out_len = ecx_key_len(pkey->ameth->pkey_id);
702c93606bbSjsing 		return 1;
703c93606bbSjsing 	}
704c93606bbSjsing 
705c93606bbSjsing 	if (ecx_key == NULL || ecx_key->pub_key == NULL)
706c93606bbSjsing 		return 0;
707c93606bbSjsing 
708c93606bbSjsing 	CBS_init(&cbs, ecx_key->pub_key, ecx_key->pub_key_len);
709c93606bbSjsing 	if (!CBS_write_bytes(&cbs, out_pub, *out_len, out_len))
710c93606bbSjsing 		return 0;
711c93606bbSjsing 
712c93606bbSjsing 	return 1;
713c93606bbSjsing }
714c93606bbSjsing 
715c93606bbSjsing static int
716c93606bbSjsing pkey_ecx_keygen(EVP_PKEY_CTX *pkey_ctx, EVP_PKEY *pkey)
717c93606bbSjsing {
718c93606bbSjsing 	struct ecx_key_st *ecx_key = NULL;
719c93606bbSjsing 	int ret = 0;
720c93606bbSjsing 
721c93606bbSjsing 	if ((ecx_key = ecx_key_new(pkey_ctx->pmeth->pkey_id)) == NULL)
722c93606bbSjsing 		goto err;
723c93606bbSjsing 	if (!ecx_key_generate(ecx_key))
724c93606bbSjsing 		goto err;
725c93606bbSjsing 	if (!EVP_PKEY_assign(pkey, pkey_ctx->pmeth->pkey_id, ecx_key))
726c93606bbSjsing 		goto err;
727c93606bbSjsing 	ecx_key = NULL;
728c93606bbSjsing 
729c93606bbSjsing 	ret = 1;
730c93606bbSjsing 
731c93606bbSjsing  err:
732c93606bbSjsing 	ecx_key_free(ecx_key);
733c93606bbSjsing 
734c93606bbSjsing 	return ret;
735c93606bbSjsing }
736c93606bbSjsing 
737c93606bbSjsing static int
738c93606bbSjsing pkey_ecx_derive(EVP_PKEY_CTX *pkey_ctx, unsigned char *out_key,
739c93606bbSjsing     size_t *out_key_len)
740c93606bbSjsing {
741c93606bbSjsing 	struct ecx_key_st *ecx_key, *ecx_peer_key;
742c93606bbSjsing 
743c93606bbSjsing 	if (pkey_ctx->pkey == NULL || pkey_ctx->peerkey == NULL) {
744c93606bbSjsing 		ECerror(EC_R_KEYS_NOT_SET);
745c93606bbSjsing 		return 0;
746c93606bbSjsing 	}
747c93606bbSjsing 
748c93606bbSjsing 	if ((ecx_key = pkey_ctx->pkey->pkey.ecx) == NULL) {
749c93606bbSjsing 		ECerror(EC_R_INVALID_PRIVATE_KEY);
750c93606bbSjsing 		return 0;
751c93606bbSjsing 	}
752c93606bbSjsing 	if (ecx_key->priv_key == NULL) {
753c93606bbSjsing 		ECerror(EC_R_INVALID_PRIVATE_KEY);
754c93606bbSjsing 		return 0;
755c93606bbSjsing 	}
756c93606bbSjsing 
757c93606bbSjsing 	if ((ecx_peer_key = pkey_ctx->peerkey->pkey.ecx) == NULL) {
758c93606bbSjsing 		ECerror(EC_R_INVALID_PEER_KEY);
759c93606bbSjsing 		return 0;
760c93606bbSjsing 	}
761c93606bbSjsing 
762c93606bbSjsing 	if (out_key != NULL) {
763c93606bbSjsing 		if (!X25519(out_key, ecx_key->priv_key, ecx_peer_key->pub_key))
764c93606bbSjsing 			return 0;
765c93606bbSjsing 	}
766c93606bbSjsing 
767c93606bbSjsing 	*out_key_len = X25519_KEYLEN;
768c93606bbSjsing 
769c93606bbSjsing 	return 1;
770c93606bbSjsing }
771c93606bbSjsing 
772c93606bbSjsing static int
773c93606bbSjsing pkey_ecx_ctrl(EVP_PKEY_CTX *pkey_ctx, int op, int arg1, void *arg2)
774c93606bbSjsing {
775c93606bbSjsing 	if (op == EVP_PKEY_CTRL_PEER_KEY)
776c93606bbSjsing 		return 1;
777c93606bbSjsing 
778c93606bbSjsing 	return -2;
779c93606bbSjsing }
780c93606bbSjsing 
781c93606bbSjsing static int
782c93606bbSjsing ecx_item_verify(EVP_MD_CTX *md_ctx, const ASN1_ITEM *it, void *asn,
783c93606bbSjsing    X509_ALGOR *algor, ASN1_BIT_STRING *abs, EVP_PKEY *pkey)
784c93606bbSjsing {
785c93606bbSjsing 	const ASN1_OBJECT *aobj;
786c93606bbSjsing 	int nid, param_type;
787c93606bbSjsing 
788c93606bbSjsing 	X509_ALGOR_get0(&aobj, &param_type, NULL, algor);
789c93606bbSjsing 
790c93606bbSjsing 	nid = OBJ_obj2nid(aobj);
791c93606bbSjsing 
792c93606bbSjsing 	if (nid != NID_ED25519 || param_type != V_ASN1_UNDEF) {
793c93606bbSjsing 		ECerror(EC_R_INVALID_ENCODING);
794f45110c3Stb 		return -1;
795c93606bbSjsing 	}
796c93606bbSjsing 
797c93606bbSjsing 	if (!EVP_DigestVerifyInit(md_ctx, NULL, NULL, NULL, pkey))
798f45110c3Stb 		return -1;
799c93606bbSjsing 
800c93606bbSjsing 	return 2;
801c93606bbSjsing }
802c93606bbSjsing 
803c93606bbSjsing static int
804c93606bbSjsing ecx_item_sign(EVP_MD_CTX *md_ctx, const ASN1_ITEM *it, void *asn,
805c93606bbSjsing     X509_ALGOR *algor1, X509_ALGOR *algor2, ASN1_BIT_STRING *abs)
806c93606bbSjsing {
8072382ddb5Stb 	if (!X509_ALGOR_set0_by_nid(algor1, NID_ED25519, V_ASN1_UNDEF, NULL))
808c93606bbSjsing 		return 0;
809c93606bbSjsing 
810c93606bbSjsing 	if (algor2 != NULL) {
8112382ddb5Stb 		if (!X509_ALGOR_set0_by_nid(algor2, NID_ED25519, V_ASN1_UNDEF,
8122382ddb5Stb 		    NULL))
813c93606bbSjsing 			return 0;
814c93606bbSjsing 	}
815c93606bbSjsing 
816c93606bbSjsing 	/* Tell ASN1_item_sign_ctx() that identifiers are set and it needs to sign. */
817c93606bbSjsing 	return 3;
818c93606bbSjsing }
819c93606bbSjsing 
820c93606bbSjsing static int
821c93606bbSjsing pkey_ecx_digestsign(EVP_MD_CTX *md_ctx, unsigned char *out_sig,
822c93606bbSjsing     size_t *out_sig_len, const unsigned char *message, size_t message_len)
823c93606bbSjsing {
824c93606bbSjsing 	struct ecx_key_st *ecx_key;
825c93606bbSjsing 	EVP_PKEY_CTX *pkey_ctx;
826c93606bbSjsing 
827c93606bbSjsing 	pkey_ctx = EVP_MD_CTX_pkey_ctx(md_ctx);
828c93606bbSjsing 	ecx_key = pkey_ctx->pkey->pkey.ecx;
829c93606bbSjsing 
830c93606bbSjsing 	if (out_sig == NULL) {
831c93606bbSjsing 		*out_sig_len = ecx_sig_size(pkey_ctx->pkey);
832c93606bbSjsing 		return 1;
833c93606bbSjsing 	}
834c93606bbSjsing 	if (*out_sig_len < ecx_sig_size(pkey_ctx->pkey)) {
835c93606bbSjsing 		ECerror(EC_R_BUFFER_TOO_SMALL);
836c93606bbSjsing 		return 0;
837c93606bbSjsing 	}
838c93606bbSjsing 
839c93606bbSjsing 	if (ecx_key == NULL)
840c93606bbSjsing 		return 0;
841c93606bbSjsing 	if (ecx_key->priv_key == NULL || ecx_key->pub_key == NULL)
842c93606bbSjsing 		return 0;
843c93606bbSjsing 
844c93606bbSjsing 	if (!ED25519_sign(out_sig, message, message_len, ecx_key->pub_key,
845c93606bbSjsing 	    ecx_key->priv_key))
846c93606bbSjsing 		return 0;
847c93606bbSjsing 
848249ad34fStb 	*out_sig_len = ecx_sig_size(pkey_ctx->pkey);
849249ad34fStb 
850c93606bbSjsing 	return 1;
851c93606bbSjsing }
852c93606bbSjsing 
853c93606bbSjsing static int
854c93606bbSjsing pkey_ecx_digestverify(EVP_MD_CTX *md_ctx, const unsigned char *sig,
855c93606bbSjsing    size_t sig_len, const unsigned char *message, size_t message_len)
856c93606bbSjsing {
857c93606bbSjsing 	struct ecx_key_st *ecx_key;
858c93606bbSjsing 	EVP_PKEY_CTX *pkey_ctx;
859c93606bbSjsing 
860c93606bbSjsing 	pkey_ctx = EVP_MD_CTX_pkey_ctx(md_ctx);
861c93606bbSjsing 	ecx_key = pkey_ctx->pkey->pkey.ecx;
862c93606bbSjsing 
863c93606bbSjsing 	if (ecx_key == NULL || ecx_key->pub_key == NULL)
864f45110c3Stb 		return -1;
865c93606bbSjsing 	if (sig_len != ecx_sig_size(pkey_ctx->pkey))
866f45110c3Stb 		return -1;
867c93606bbSjsing 
868c93606bbSjsing 	return ED25519_verify(message, message_len, sig, ecx_key->pub_key);
869c93606bbSjsing }
870c93606bbSjsing 
871c93606bbSjsing static int
872c93606bbSjsing pkey_ecx_ed_ctrl(EVP_PKEY_CTX *pkey_ctx, int op, int arg1, void *arg2)
873c93606bbSjsing {
874c93606bbSjsing 	switch (op) {
875c93606bbSjsing 	case EVP_PKEY_CTRL_MD:
876c93606bbSjsing 		/* PureEdDSA does its own hashing. */
877c93606bbSjsing 		if (arg2 != NULL && (const EVP_MD *)arg2 != EVP_md_null()) {
878c93606bbSjsing 			ECerror(EC_R_INVALID_DIGEST_TYPE);
879c93606bbSjsing 			return 0;
880c93606bbSjsing 		}
881c93606bbSjsing 		return 1;
882c93606bbSjsing 
883e170a9e1Stb #ifndef OPENSSL_NO_CMS
884e170a9e1Stb 	case EVP_PKEY_CTRL_CMS_SIGN:
885e170a9e1Stb #endif
886c93606bbSjsing 	case EVP_PKEY_CTRL_DIGESTINIT:
887c93606bbSjsing 		return 1;
888c93606bbSjsing 	}
889c93606bbSjsing 	return -2;
890c93606bbSjsing }
891c93606bbSjsing 
892c93606bbSjsing const EVP_PKEY_ASN1_METHOD x25519_asn1_meth = {
8939ed721ecStb 	.base_method = &x25519_asn1_meth,
894c93606bbSjsing 	.pkey_id = EVP_PKEY_X25519,
895c93606bbSjsing 	.pkey_flags = 0,
896c93606bbSjsing 	.pem_str = "X25519",
897c93606bbSjsing 	.info = "OpenSSL X25519 algorithm",
898c93606bbSjsing 
899c93606bbSjsing 	.pub_decode = ecx_pub_decode,
900c93606bbSjsing 	.pub_encode = ecx_pub_encode,
901c93606bbSjsing 	.pub_cmp = ecx_pub_cmp,
902c93606bbSjsing 	.pub_print = ecx_pub_print,
903c93606bbSjsing 
904c93606bbSjsing 	.priv_decode = ecx_priv_decode,
905c93606bbSjsing 	.priv_encode = ecx_priv_encode,
906c93606bbSjsing 	.priv_print = ecx_priv_print,
907c93606bbSjsing 
908c93606bbSjsing 	.pkey_size = ecx_size,
909c93606bbSjsing 	.pkey_bits = ecx_bits,
910c93606bbSjsing 	.pkey_security_bits = ecx_security_bits,
911c93606bbSjsing 
912c93606bbSjsing 	.param_cmp = ecx_param_cmp,
913c93606bbSjsing 
914c93606bbSjsing 	.pkey_free = ecx_free,
915c93606bbSjsing 	.pkey_ctrl = ecx_ctrl,
916c93606bbSjsing 
917c93606bbSjsing 	.set_priv_key = ecx_set_priv_key,
918c93606bbSjsing 	.set_pub_key = ecx_set_pub_key,
919c93606bbSjsing 	.get_priv_key = ecx_get_priv_key,
920c93606bbSjsing 	.get_pub_key = ecx_get_pub_key,
921c93606bbSjsing };
922c93606bbSjsing 
923c93606bbSjsing const EVP_PKEY_METHOD x25519_pkey_meth = {
924c93606bbSjsing 	.pkey_id = EVP_PKEY_X25519,
925c93606bbSjsing 	.keygen = pkey_ecx_keygen,
926c93606bbSjsing 	.derive = pkey_ecx_derive,
927c93606bbSjsing 	.ctrl = pkey_ecx_ctrl,
928c93606bbSjsing };
929c93606bbSjsing 
930c93606bbSjsing const EVP_PKEY_ASN1_METHOD ed25519_asn1_meth = {
9319ed721ecStb 	.base_method = &ed25519_asn1_meth,
932c93606bbSjsing 	.pkey_id = EVP_PKEY_ED25519,
933c93606bbSjsing 	.pkey_flags = 0,
934c93606bbSjsing 	.pem_str = "ED25519",
935c93606bbSjsing 	.info = "OpenSSL ED25519 algorithm",
936c93606bbSjsing 
937c93606bbSjsing 	.pub_decode = ecx_pub_decode,
938c93606bbSjsing 	.pub_encode = ecx_pub_encode,
939c93606bbSjsing 	.pub_cmp = ecx_pub_cmp,
940c93606bbSjsing 	.pub_print = ecx_pub_print,
941c93606bbSjsing 
942c93606bbSjsing 	.priv_decode = ecx_priv_decode,
943c93606bbSjsing 	.priv_encode = ecx_priv_encode,
944c93606bbSjsing 	.priv_print = ecx_priv_print,
945c93606bbSjsing 
946c93606bbSjsing 	.pkey_size = ecx_sig_size,
947c93606bbSjsing 	.pkey_bits = ecx_bits,
948c93606bbSjsing 	.pkey_security_bits = ecx_security_bits,
949c93606bbSjsing 
950*c5d7bed5Stb 	.signature_info = ecx_signature_info,
951*c5d7bed5Stb 
952c93606bbSjsing 	.param_cmp = ecx_param_cmp,
953c93606bbSjsing 
954c93606bbSjsing 	.pkey_free = ecx_free,
955c93606bbSjsing 	.pkey_ctrl = ecx_sign_ctrl,
956c93606bbSjsing 
957c93606bbSjsing 	.item_verify = ecx_item_verify,
958c93606bbSjsing 	.item_sign = ecx_item_sign,
959c93606bbSjsing 
960c93606bbSjsing 	.set_priv_key = ecx_set_priv_key,
961c93606bbSjsing 	.set_pub_key = ecx_set_pub_key,
962c93606bbSjsing 	.get_priv_key = ecx_get_priv_key,
963c93606bbSjsing 	.get_pub_key = ecx_get_pub_key,
964c93606bbSjsing };
965c93606bbSjsing 
966c93606bbSjsing const EVP_PKEY_METHOD ed25519_pkey_meth = {
967c93606bbSjsing 	.pkey_id = EVP_PKEY_ED25519,
968c93606bbSjsing 	.flags = EVP_PKEY_FLAG_SIGCTX_CUSTOM,
969c93606bbSjsing 	.keygen = pkey_ecx_keygen,
970c93606bbSjsing 	.ctrl = pkey_ecx_ed_ctrl,
971c93606bbSjsing 	.digestsign = pkey_ecx_digestsign,
972c93606bbSjsing 	.digestverify = pkey_ecx_digestverify,
973c93606bbSjsing };
974