1 /*	$OpenBSD: evp_ecx_test.c,v 1.5 2023/03/02 20:04:42 tb Exp $ */
2 /*
3  * Copyright (c) 2022 Joel Sing <jsing@openbsd.org>
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 #include <err.h>
19 #include <string.h>
20 
21 #include <openssl/err.h>
22 #include <openssl/evp.h>
23 #include <openssl/pem.h>
24 
25 #include "curve25519_internal.h"
26 
27 static const uint8_t ed25519_priv_key_1[] =
28     "-----BEGIN PRIVATE KEY-----\n"
29     "MC4CAQAwBQYDK2VwBCIEIIkDg89yB70IpUXsAZieCcCDE2ig9nin9JJWpDQoCup8\n"
30     "-----END PRIVATE KEY-----\n";
31 
32 const uint8_t ed25519_raw_priv_key_1[] = {
33 	0x89, 0x03, 0x83, 0xcf, 0x72, 0x07, 0xbd, 0x08,
34 	0xa5, 0x45, 0xec, 0x01, 0x98, 0x9e, 0x09, 0xc0,
35 	0x83, 0x13, 0x68, 0xa0, 0xf6, 0x78, 0xa7, 0xf4,
36 	0x92, 0x56, 0xa4, 0x34, 0x28, 0x0a, 0xea, 0x7c,
37 };
38 
39 static const uint8_t ed25519_pub_key_1[] =
40     "-----BEGIN PUBLIC KEY-----\n"
41     "MCowBQYDK2VwAyEA1vxPpbnoC7G8vFmRjYVXUU2aln3hUZEgfW1atlTHF/o=\n"
42     "-----END PUBLIC KEY-----\n";
43 
44 const uint8_t ed25519_raw_pub_key_1[] = {
45 	0xd6, 0xfc, 0x4f, 0xa5, 0xb9, 0xe8, 0x0b, 0xb1,
46 	0xbc, 0xbc, 0x59, 0x91, 0x8d, 0x85, 0x57, 0x51,
47 	0x4d, 0x9a, 0x96, 0x7d, 0xe1, 0x51, 0x91, 0x20,
48 	0x7d, 0x6d, 0x5a, 0xb6, 0x54, 0xc7, 0x17, 0xfa,
49 };
50 
51 static const uint8_t message_1[] = {
52 	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
53 	0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
54 	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
55 	0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
56 };
57 
58 static const uint8_t signature_1[] = {
59 	0x1c, 0xba, 0x71, 0x5a, 0xbc, 0x7f, 0x3b, 0x6b,
60 	0xc1, 0x61, 0x04, 0x02, 0xb6, 0x37, 0x9e, 0xe1,
61 	0xa6, 0x7c, 0xfe, 0xcd, 0xdd, 0x68, 0x59, 0xb5,
62 	0xc8, 0x09, 0xa5, 0x36, 0x66, 0xfb, 0xad, 0xc5,
63 	0x68, 0x31, 0xd1, 0x7a, 0x48, 0x44, 0xaa, 0xa9,
64 	0x9c, 0xf1, 0x1a, 0xbb, 0xd5, 0x49, 0xd5, 0xe8,
65 	0x63, 0xe2, 0x94, 0x77, 0x16, 0x1a, 0x52, 0xfa,
66 	0x33, 0x6b, 0xf3, 0x57, 0x93, 0xd4, 0xc1, 0x07,
67 };
68 
69 static const uint8_t x25519_priv_key_1[] =
70     "-----BEGIN PRIVATE KEY-----\n"
71     "MC4CAQAwBQYDK2VuBCIEICi6rzFFJb02mi6sopELeshEi2vr68ul4bzEHPOz+K1o\n"
72     "-----END PRIVATE KEY-----\n";
73 
74 const uint8_t x25519_raw_priv_key_1[] = {
75 	0x28, 0xba, 0xaf, 0x31, 0x45, 0x25, 0xbd, 0x36,
76 	0x9a, 0x2e, 0xac, 0xa2, 0x91, 0x0b, 0x7a, 0xc8,
77 	0x44, 0x8b, 0x6b, 0xeb, 0xeb, 0xcb, 0xa5, 0xe1,
78 	0xbc, 0xc4, 0x1c, 0xf3, 0xb3, 0xf8, 0xad, 0x68,
79 };
80 
81 static const uint8_t x25519_pub_key_1[] =
82     "-----BEGIN PUBLIC KEY-----\n"
83     "MCowBQYDK2VuAyEAu4WHXnAQL2YfonJhuoEO9PM2WwXjveApPmCXSiDnf1M=\n"
84     "-----END PUBLIC KEY-----\n";
85 
86 static const uint8_t x25519_raw_pub_key_1[] = {
87 	0xbb, 0x85, 0x87, 0x5e, 0x70, 0x10, 0x2f, 0x66,
88 	0x1f, 0xa2, 0x72, 0x61, 0xba, 0x81, 0x0e, 0xf4,
89 	0xf3, 0x36, 0x5b, 0x05, 0xe3, 0xbd, 0xe0, 0x29,
90 	0x3e, 0x60, 0x97, 0x4a, 0x20, 0xe7, 0x7f, 0x53,
91 };
92 
93 static const uint8_t x25519_priv_key_2[] =
94     "-----BEGIN PRIVATE KEY-----\n"
95     "MC4CAQAwBQYDK2VuBCIEIAg9Jbp/Ma0TO4r179WGGiv+VnGxGNRh4VNrHUij7Ql/\n"
96     "-----END PRIVATE KEY-----\n";
97 
98 static const uint8_t x25519_raw_priv_key_2[] = {
99 	0x08, 0x3d, 0x25, 0xba, 0x7f, 0x31, 0xad, 0x13,
100 	0x3b, 0x8a, 0xf5, 0xef, 0xd5, 0x86, 0x1a, 0x2b,
101 	0xfe, 0x56, 0x71, 0xb1, 0x18, 0xd4, 0x61, 0xe1,
102 	0x53, 0x6b, 0x1d, 0x48, 0xa3, 0xed, 0x09, 0x7f,
103 };
104 
105 static const uint8_t x25519_pub_key_2[] =
106     "-----BEGIN PUBLIC KEY-----\n"
107     "MCowBQYDK2VuAyEABvksGQRgsUXEK5CaniVZ59pPvDoABgBSdAM+EF0Q9Cw=\n"
108     "-----END PUBLIC KEY-----\n";
109 
110 static const uint8_t x25519_raw_pub_key_2[] = {
111 	0x06, 0xf9, 0x2c, 0x19, 0x04, 0x60, 0xb1, 0x45,
112 	0xc4, 0x2b, 0x90, 0x9a, 0x9e, 0x25, 0x59, 0xe7,
113 	0xda, 0x4f, 0xbc, 0x3a, 0x00, 0x06, 0x00, 0x52,
114 	0x74, 0x03, 0x3e, 0x10, 0x5d, 0x10, 0xf4, 0x2c,
115 };
116 
117 static const uint8_t shared_key_1[] = {
118 	0xa2, 0x61, 0xf5, 0x91, 0x2e, 0x82, 0xbc, 0x98,
119 	0x6c, 0x85, 0xb6, 0x51, 0x1f, 0x69, 0xdb, 0xfa,
120 	0x88, 0x6c, 0x4b, 0x9e, 0x3b, 0xb0, 0x71, 0xd1,
121 	0xf3, 0xea, 0x2a, 0xd0, 0xef, 0xf6, 0xa5, 0x5a,
122 };
123 
124 static void
125 hexdump(const unsigned char *buf, size_t len)
126 {
127 	size_t i;
128 
129 	for (i = 1; i <= len; i++)
130 		fprintf(stderr, " 0x%02hhx,%s", buf[i - 1], i % 8 ? "" : "\n");
131 
132 	fprintf(stderr, "\n");
133 }
134 
135 static int
136 ecx_ed25519_keygen_test(void)
137 {
138 	EVP_PKEY_CTX *pkey_ctx = NULL;
139 	EVP_PKEY *pkey = NULL;
140 	BIO *bio = NULL;
141 	int failed = 1;
142 
143 	if ((pkey_ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_ED25519, NULL)) == NULL) {
144 		fprintf(stderr, "FAIL: failed to create ED25519 context\n");
145 		goto failure;
146 	}
147 
148 	if (EVP_PKEY_keygen_init(pkey_ctx) <= 0) {
149 		fprintf(stderr, "FAIL: failed to init keygen for ED25519\n");
150 		goto failure;
151 	}
152 	if (EVP_PKEY_keygen(pkey_ctx, &pkey) <= 0) {
153 		fprintf(stderr, "FAIL: failed to generate ED25519 key\n");
154 		goto failure;
155 	}
156 
157 	if ((bio = BIO_new(BIO_s_mem())) == NULL)
158 		goto failure;
159 	if (!PEM_write_bio_PrivateKey(bio, pkey, NULL, NULL, 0, NULL, NULL)) {
160 		fprintf(stderr, "FAIL: failed to write ED25519 to PEM\n");
161 		goto failure;
162 	}
163 
164 	failed = 0;
165 
166  failure:
167 	BIO_free(bio);
168 	EVP_PKEY_CTX_free(pkey_ctx);
169 	EVP_PKEY_free(pkey);
170 
171 	return failed;
172 }
173 
174 static int
175 ecx_ed25519_raw_key_test(void)
176 {
177 	EVP_PKEY *pkey = NULL;
178 	uint8_t *priv_key = NULL;
179 	size_t priv_key_len = 0;
180 	uint8_t *pub_key = NULL;
181 	size_t pub_key_len = 0;
182 	const uint8_t *pp;
183 	BIO *bio = NULL;
184 	int failed = 1;
185 
186 	/*
187 	 * Decode private key from PEM and check raw private and raw public.
188 	 */
189 
190 	if ((bio = BIO_new_mem_buf(ed25519_priv_key_1, -1)) == NULL)
191 		errx(1, "failed to create BIO for key");
192 	if ((pkey = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL)) == NULL) {
193 		fprintf(stderr, "FAIL: failed to read private key\n");
194 		ERR_print_errors_fp(stderr);
195 		goto failure;
196 	}
197 
198 	if (!EVP_PKEY_get_raw_private_key(pkey, NULL, &priv_key_len)) {
199 		fprintf(stderr, "FAIL: failed to get raw private key len\n");
200 		goto failure;
201 	}
202 	if (priv_key_len != sizeof(ed25519_raw_priv_key_1)) {
203 		fprintf(stderr, "FAIL: raw private key length differs "
204 		    "(%zu != %zu)\n", priv_key_len,
205 		    sizeof(ed25519_raw_priv_key_1));
206 		goto failure;
207 	}
208 	if ((priv_key = malloc(priv_key_len)) == NULL)
209 		errx(1, "failed to malloc priv key");
210 	if (!EVP_PKEY_get_raw_private_key(pkey, priv_key, &priv_key_len)) {
211 		fprintf(stderr, "FAIL: failed to get raw private key len\n");
212 		goto failure;
213 	}
214 	if (memcmp(priv_key, ed25519_raw_priv_key_1, priv_key_len) != 0) {
215 		fprintf(stderr, "FAIL: get raw private key failed\n");
216 		fprintf(stderr, "Got:\n");
217 		hexdump(priv_key, priv_key_len);
218 		fprintf(stderr, "Want:\n");
219 		hexdump(ed25519_raw_priv_key_1, sizeof(ed25519_raw_priv_key_1));
220 		goto failure;
221 	}
222 
223 	if (!EVP_PKEY_get_raw_public_key(pkey, NULL, &pub_key_len)) {
224 		fprintf(stderr, "FAIL: failed to get raw pub key len\n");
225 		goto failure;
226 	}
227 	if (pub_key_len != sizeof(ed25519_raw_pub_key_1)) {
228 		fprintf(stderr, "FAIL: raw public key length differs "
229 		    "(%zu != %zu)\n", pub_key_len,
230 		    sizeof(ed25519_raw_pub_key_1));
231 		goto failure;
232 	}
233 	if ((pub_key = malloc(pub_key_len)) == NULL)
234 		errx(1, "failed to malloc private key");
235 	if (!EVP_PKEY_get_raw_public_key(pkey, pub_key, &pub_key_len)) {
236 		fprintf(stderr, "FAIL: failed to get raw pub key len\n");
237 		goto failure;
238 	}
239 	if (memcmp(pub_key, ed25519_raw_pub_key_1, pub_key_len) != 0) {
240 		fprintf(stderr, "FAIL: get raw public key failed\n");
241 		fprintf(stderr, "Got:\n");
242 		hexdump(pub_key, pub_key_len);
243 		fprintf(stderr, "Want:\n");
244 		hexdump(ed25519_raw_pub_key_1, sizeof(ed25519_raw_pub_key_1));
245 		goto failure;
246 	}
247 
248 	BIO_free(bio);
249 	bio = NULL;
250 
251 	EVP_PKEY_free(pkey);
252 	pkey = NULL;
253 
254 	freezero(priv_key, priv_key_len);
255 	priv_key = NULL;
256 	priv_key_len = 0;
257 
258 	freezero(pub_key, pub_key_len);
259 	pub_key = NULL;
260 	pub_key_len = 0;
261 
262 	/*
263 	 * Decode public key from PEM and check raw private and raw public.
264 	 */
265 
266 	if ((bio = BIO_new_mem_buf(ed25519_pub_key_1, -1)) == NULL)
267 		errx(1, "failed to create BIO for key");
268 	if ((pkey = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL)) == NULL) {
269 		fprintf(stderr, "FAIL: failed to read public key\n");
270 		ERR_print_errors_fp(stderr);
271 		goto failure;
272 	}
273 
274 	/*
275 	 * Yet another astounding API design - we cannot tell if the private key
276 	 * is not present, or if some other failure occurred.
277 	 */
278 	if (!EVP_PKEY_get_raw_private_key(pkey, NULL, &priv_key_len)) {
279 		fprintf(stderr, "FAIL: failed to get raw priv key len\n");
280 		goto failure;
281 	}
282 	if ((priv_key = malloc(priv_key_len)) == NULL)
283 		errx(1, "failed to malloc priv key");
284 	if (EVP_PKEY_get_raw_private_key(pkey, priv_key, &priv_key_len)) {
285 		fprintf(stderr, "FAIL: got raw private key, should fail\n");
286 		goto failure;
287 	}
288 
289 	if (!EVP_PKEY_get_raw_public_key(pkey, NULL, &pub_key_len)) {
290 		fprintf(stderr, "FAIL: failed to get raw pub key len\n");
291 		goto failure;
292 	}
293 	if (pub_key_len != sizeof(ed25519_raw_pub_key_1)) {
294 		fprintf(stderr, "FAIL: raw public key length differs "
295 		    "(%zu != %zu)\n", pub_key_len,
296 		    sizeof(ed25519_raw_pub_key_1));
297 		goto failure;
298 	}
299 	if ((pub_key = malloc(pub_key_len)) == NULL)
300 		errx(1, "failed to malloc private key");
301 	if (!EVP_PKEY_get_raw_public_key(pkey, pub_key, &pub_key_len)) {
302 		fprintf(stderr, "FAIL: failed to get raw pub key len\n");
303 		goto failure;
304 	}
305 	if (memcmp(pub_key, ed25519_raw_pub_key_1, pub_key_len) != 0) {
306 		fprintf(stderr, "FAIL: get raw public key failed\n");
307 		fprintf(stderr, "Got:\n");
308 		hexdump(pub_key, pub_key_len);
309 		fprintf(stderr, "Want:\n");
310 		hexdump(ed25519_raw_pub_key_1, sizeof(ed25519_raw_pub_key_1));
311 		goto failure;
312 	}
313 
314 	BIO_free(bio);
315 	bio = NULL;
316 
317 	EVP_PKEY_free(pkey);
318 	pkey = NULL;
319 
320 	/*
321 	 * Create PKEY from raw private, check PEM encoded private and public.
322 	 */
323 	if ((pkey = EVP_PKEY_new_raw_private_key(EVP_PKEY_ED25519, NULL,
324 	    ed25519_raw_priv_key_1, sizeof(ed25519_raw_priv_key_1))) == NULL) {
325 		fprintf(stderr, "FAIL: PKEY from raw private key failed");
326 		goto failure;
327 	}
328 	if ((bio = BIO_new(BIO_s_mem())) == NULL)
329 		goto failure;
330 	if (!PEM_write_bio_PrivateKey(bio, pkey, NULL, NULL, 0, NULL, NULL)) {
331 		fprintf(stderr, "FAIL: failed to write ED25519 private to PEM\n");
332 		goto failure;
333 	}
334 	BIO_get_mem_data(bio, &pp);
335 	if (strcmp(ed25519_priv_key_1, pp) != 0) {
336 		fprintf(stderr, "FAIL: resulting private key PEM differs\n");
337 		goto failure;
338 	}
339 
340 	(void)BIO_reset(bio);
341 	if (!PEM_write_bio_PUBKEY(bio, pkey)) {
342 		fprintf(stderr, "FAIL: failed to write ED25519 public to PEM\n");
343 		goto failure;
344 	}
345 	BIO_get_mem_data(bio, &pp);
346 	if (strcmp(ed25519_pub_key_1, pp) != 0) {
347 		fprintf(stderr, "FAIL: resulting public key PEM differs\n");
348 		fprintf(stderr, "%s\n", ed25519_pub_key_1);
349 		fprintf(stderr, "%s\n", pp);
350 		//goto failure;
351 	}
352 
353 	EVP_PKEY_free(pkey);
354 	pkey = NULL;
355 
356 	/*
357 	 * Create PKEY from raw public, check public key PEM.
358 	 */
359 	if ((pkey = EVP_PKEY_new_raw_public_key(EVP_PKEY_ED25519, NULL,
360 	    ed25519_raw_pub_key_1, sizeof(ed25519_raw_pub_key_1))) == NULL) {
361 		fprintf(stderr, "FAIL: PKEY from raw public key failed");
362 		goto failure;
363 	}
364 	(void)BIO_reset(bio);
365 	if (!PEM_write_bio_PUBKEY(bio, pkey)) {
366 		fprintf(stderr, "FAIL: failed to write ED25519 public to PEM\n");
367 		goto failure;
368 	}
369 	BIO_get_mem_data(bio, &pp);
370 	if (strcmp(ed25519_pub_key_1, pp) != 0) {
371 		fprintf(stderr, "FAIL: resulting public key PEM differs\n");
372 		goto failure;
373 	}
374 
375 	failed = 0;
376 
377  failure:
378 	BIO_free(bio);
379 	EVP_PKEY_free(pkey);
380 	freezero(priv_key, priv_key_len);
381 	freezero(pub_key, pub_key_len);
382 
383 	return failed;
384 }
385 
386 static int
387 ecx_ed25519_sign_test(void)
388 {
389 	EVP_MD_CTX *md_ctx = NULL;
390 	EVP_PKEY *pkey = NULL;
391 	uint8_t *signature = NULL;
392 	size_t signature_len = 0;
393 	BIO *bio = NULL;
394 	int failed = 1;
395 
396 	if ((bio = BIO_new_mem_buf(ed25519_priv_key_1, -1)) == NULL)
397 		errx(1, "failed to create BIO for key");
398 	if ((pkey = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL)) == NULL) {
399 		fprintf(stderr, "FAIL: failed to read private key\n");
400 		ERR_print_errors_fp(stderr);
401 		goto failure;
402 	}
403 
404 	if ((md_ctx = EVP_MD_CTX_new()) == NULL)
405 		errx(1, "failed to create MD_CTX");
406 
407 	if (!EVP_DigestSignInit(md_ctx, NULL, NULL, NULL, pkey)) {
408 		fprintf(stderr, "FAIL: failed to init digest sign\n");
409 		ERR_print_errors_fp(stderr);
410 		goto failure;
411 	}
412 	if (!EVP_DigestSign(md_ctx, NULL, &signature_len, NULL, 0)) {
413 		fprintf(stderr, "FAIL: failed to digest sign update\n");
414 		goto failure;
415 	}
416 	if ((signature = calloc(1, signature_len)) == NULL)
417 		errx(1, "failed to allocate signature");
418 	if (!EVP_DigestSign(md_ctx, signature, &signature_len, message_1,
419 	    sizeof(message_1))) {
420 		fprintf(stderr, "FAIL: failed to digest sign update\n");
421 		goto failure;
422 	}
423 
424 	if (signature_len != sizeof(signature_1)) {
425 		fprintf(stderr, "FAIL: signature length differs (%zu != %zu)\n",
426 		    signature_len, sizeof(signature_1));
427 		goto failure;
428 	}
429 
430 	if (memcmp(signature, signature_1, signature_len) != 0) {
431 		fprintf(stderr, "FAIL: Ed25519 sign failed\n");
432 		fprintf(stderr, "Got:\n");
433 		hexdump(signature, signature_len);
434 		fprintf(stderr, "Want:\n");
435 		hexdump(signature_1, sizeof(signature_1));
436 		goto failure;
437 	}
438 
439 	failed = 0;
440 
441  failure:
442 	BIO_free(bio);
443 	EVP_MD_CTX_free(md_ctx);
444 	EVP_PKEY_free(pkey);
445 	free(signature);
446 
447 	return failed;
448 }
449 
450 static int
451 ecx_ed25519_verify_test(void)
452 {
453 	EVP_MD_CTX *md_ctx = NULL;
454 	EVP_PKEY *pkey = NULL;
455 	BIO *bio = NULL;
456 	int failed = 1;
457 
458 	if ((bio = BIO_new_mem_buf(ed25519_pub_key_1, -1)) == NULL)
459 		errx(1, "failed to create BIO for key");
460 	if ((pkey = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL)) == NULL) {
461 		fprintf(stderr, "FAIL: failed to read public key\n");
462 		ERR_print_errors_fp(stderr);
463 		goto failure;
464 	}
465 
466 	if ((md_ctx = EVP_MD_CTX_new()) == NULL)
467 		errx(1, "failed to create MD_CTX");
468 
469 	if (!EVP_DigestVerifyInit(md_ctx, NULL, NULL, NULL, pkey)) {
470 		fprintf(stderr, "FAIL: failed to init digest verify\n");
471 		ERR_print_errors_fp(stderr);
472 		goto failure;
473 	}
474 	if (!EVP_DigestVerify(md_ctx, signature_1, sizeof(signature_1),
475 	    message_1, sizeof(message_1))) {
476 		fprintf(stderr, "FAIL: failed to digest verify update\n");
477 		goto failure;
478 	}
479 
480 	failed = 0;
481 
482  failure:
483 	BIO_free(bio);
484 	EVP_MD_CTX_free(md_ctx);
485 	EVP_PKEY_free(pkey);
486 
487 	return failed;
488 }
489 
490 static int
491 ecx_x25519_keygen_test(void)
492 {
493 	EVP_PKEY_CTX *pkey_ctx = NULL;
494 	EVP_PKEY *pkey = NULL;
495 	BIO *bio = NULL;
496 	int failed = 1;
497 
498 	if ((pkey_ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_X25519, NULL)) == NULL) {
499 		fprintf(stderr, "FAIL: failed to create X25519 context\n");
500 		goto failure;
501 	}
502 
503 	if (EVP_PKEY_keygen_init(pkey_ctx) <= 0) {
504 		fprintf(stderr, "FAIL: failed to init keygen for X25519\n");
505 		goto failure;
506 	}
507 	if (EVP_PKEY_keygen(pkey_ctx, &pkey) <= 0) {
508 		fprintf(stderr, "FAIL: failed to generate X25519 key\n");
509 		goto failure;
510 	}
511 
512 	if ((bio = BIO_new(BIO_s_mem())) == NULL)
513 		goto failure;
514 	if (!PEM_write_bio_PrivateKey(bio, pkey, NULL, NULL, 0, NULL, NULL)) {
515 		fprintf(stderr, "FAIL: failed to write X25519 to PEM\n");
516 		goto failure;
517 	}
518 
519 	failed = 0;
520 
521  failure:
522 	BIO_free(bio);
523 	EVP_PKEY_CTX_free(pkey_ctx);
524 	EVP_PKEY_free(pkey);
525 
526 	return failed;
527 }
528 
529 static int
530 ecx_x25519_derive_test(void)
531 {
532 	EVP_PKEY_CTX *pkey_ctx = NULL;
533 	EVP_PKEY *pkey = NULL, *pkey_peer = NULL;
534 	uint8_t *shared_key = NULL;
535 	size_t shared_key_len = 0;
536 	BIO *bio = NULL;
537 	int failed = 1;
538 
539 	if ((bio = BIO_new_mem_buf(x25519_priv_key_1, -1)) == NULL)
540 		errx(1, "failed to create BIO for key");
541 	if ((pkey = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL)) == NULL) {
542 		fprintf(stderr, "FAIL: failed to read private key\n");
543 		ERR_print_errors_fp(stderr);
544 		goto failure;
545 	}
546 
547 	BIO_free(bio);
548 	if ((bio = BIO_new_mem_buf(x25519_pub_key_2, -1)) == NULL)
549 		errx(1, "failed to create BIO for key");
550 	if ((pkey_peer = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL)) == NULL) {
551 		fprintf(stderr, "FAIL: failed to read peer public key\n");
552 		ERR_print_errors_fp(stderr);
553 		goto failure;
554 	}
555 
556 	if ((pkey_ctx = EVP_PKEY_CTX_new(pkey, NULL)) == NULL) {
557 		fprintf(stderr, "FAIL: failed to create X25519 context\n");
558 		goto failure;
559 	}
560 	if (EVP_PKEY_derive_init(pkey_ctx) <= 0) {
561 		fprintf(stderr, "FAIL: failed to init derive for X25519\n");
562 		goto failure;
563 	}
564 	if (EVP_PKEY_derive_set_peer(pkey_ctx, pkey_peer) <= 0) {
565 		fprintf(stderr, "FAIL: failed to set peer key for X25519\n");
566 		goto failure;
567 	}
568 	if (EVP_PKEY_derive(pkey_ctx, NULL, &shared_key_len) <= 0) {
569 		fprintf(stderr, "FAIL: failed to derive X25519 key length\n");
570 		goto failure;
571 	}
572 	if ((shared_key = malloc(shared_key_len)) == NULL)
573 		errx(1, "failed to malloc shared key");
574 	if (EVP_PKEY_derive(pkey_ctx, shared_key, &shared_key_len) <= 0) {
575 		fprintf(stderr, "FAIL: failed to derive X25519 key\n");
576 		goto failure;
577 	}
578 
579 	if (shared_key_len != sizeof(shared_key_1)) {
580 		fprintf(stderr, "FAIL: shared key length differs (%zu != %zu)\n",
581 		    shared_key_len, sizeof(shared_key_1));
582 		goto failure;
583 	}
584 
585 	if (memcmp(shared_key, shared_key_1, shared_key_len) != 0) {
586 		fprintf(stderr, "FAIL: X25519 derive failed\n");
587 		fprintf(stderr, "Got:\n");
588 		hexdump(shared_key, shared_key_len);
589 		fprintf(stderr, "Want:\n");
590 		hexdump(shared_key_1, sizeof(shared_key_1));
591 		goto failure;
592 	}
593 
594 	failed = 0;
595 
596  failure:
597 	BIO_free(bio);
598 	EVP_PKEY_CTX_free(pkey_ctx);
599 	EVP_PKEY_free(pkey_peer);
600 	EVP_PKEY_free(pkey);
601 	freezero(shared_key, shared_key_len);
602 
603 	return failed;
604 }
605 
606 static int
607 ecx_x25519_raw_key_test(void)
608 {
609 	EVP_PKEY *pkey = NULL;
610 	uint8_t *priv_key = NULL;
611 	size_t priv_key_len = 0;
612 	uint8_t *pub_key = NULL;
613 	size_t pub_key_len = 0;
614 	const uint8_t *pp;
615 	BIO *bio = NULL;
616 	int failed = 1;
617 
618 	/*
619 	 * Decode private key from PEM and check raw private and raw public.
620 	 */
621 
622 	if ((bio = BIO_new_mem_buf(x25519_priv_key_2, -1)) == NULL)
623 		errx(1, "failed to create BIO for key");
624 	if ((pkey = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL)) == NULL) {
625 		fprintf(stderr, "FAIL: failed to read private key\n");
626 		ERR_print_errors_fp(stderr);
627 		goto failure;
628 	}
629 
630 	if (!EVP_PKEY_get_raw_private_key(pkey, NULL, &priv_key_len)) {
631 		fprintf(stderr, "FAIL: failed to get raw private key len\n");
632 		goto failure;
633 	}
634 	if (priv_key_len != sizeof(x25519_raw_priv_key_2)) {
635 		fprintf(stderr, "FAIL: raw private key length differs "
636 		    "(%zu != %zu)\n", priv_key_len,
637 		    sizeof(x25519_raw_priv_key_2));
638 		goto failure;
639 	}
640 	if ((priv_key = malloc(priv_key_len)) == NULL)
641 		errx(1, "failed to malloc priv key");
642 	if (!EVP_PKEY_get_raw_private_key(pkey, priv_key, &priv_key_len)) {
643 		fprintf(stderr, "FAIL: failed to get raw private key len\n");
644 		goto failure;
645 	}
646 	if (memcmp(priv_key, x25519_raw_priv_key_2, priv_key_len) != 0) {
647 		fprintf(stderr, "FAIL: get raw private key failed\n");
648 		fprintf(stderr, "Got:\n");
649 		hexdump(priv_key, priv_key_len);
650 		fprintf(stderr, "Want:\n");
651 		hexdump(x25519_raw_priv_key_2, sizeof(x25519_raw_priv_key_2));
652 		goto failure;
653 	}
654 
655 	if (!EVP_PKEY_get_raw_public_key(pkey, NULL, &pub_key_len)) {
656 		fprintf(stderr, "FAIL: failed to get raw pub key len\n");
657 		goto failure;
658 	}
659 	if (pub_key_len != sizeof(x25519_raw_pub_key_2)) {
660 		fprintf(stderr, "FAIL: raw public key length differs "
661 		    "(%zu != %zu)\n", pub_key_len,
662 		    sizeof(x25519_raw_pub_key_2));
663 		goto failure;
664 	}
665 	if ((pub_key = malloc(pub_key_len)) == NULL)
666 		errx(1, "failed to malloc private key");
667 	if (!EVP_PKEY_get_raw_public_key(pkey, pub_key, &pub_key_len)) {
668 		fprintf(stderr, "FAIL: failed to get raw pub key len\n");
669 		goto failure;
670 	}
671 	if (memcmp(pub_key, x25519_raw_pub_key_2, pub_key_len) != 0) {
672 		fprintf(stderr, "FAIL: get raw public key failed\n");
673 		fprintf(stderr, "Got:\n");
674 		hexdump(pub_key, pub_key_len);
675 		fprintf(stderr, "Want:\n");
676 		hexdump(x25519_raw_pub_key_2, sizeof(x25519_raw_pub_key_2));
677 		goto failure;
678 	}
679 
680 	BIO_free(bio);
681 	bio = NULL;
682 
683 	EVP_PKEY_free(pkey);
684 	pkey = NULL;
685 
686 	freezero(priv_key, priv_key_len);
687 	priv_key = NULL;
688 	priv_key_len = 0;
689 
690 	freezero(pub_key, pub_key_len);
691 	pub_key = NULL;
692 	pub_key_len = 0;
693 
694 	/*
695 	 * Decode public key from PEM and check raw private and raw public.
696 	 */
697 
698 	if ((bio = BIO_new_mem_buf(x25519_pub_key_1, -1)) == NULL)
699 		errx(1, "failed to create BIO for key");
700 	if ((pkey = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL)) == NULL) {
701 		fprintf(stderr, "FAIL: failed to read public key\n");
702 		ERR_print_errors_fp(stderr);
703 		goto failure;
704 	}
705 
706 	/*
707 	 * Yet another astounding API design - we cannot tell if the private key
708 	 * is not present, or if some other failure occurred.
709 	 */
710 	if (!EVP_PKEY_get_raw_private_key(pkey, NULL, &priv_key_len)) {
711 		fprintf(stderr, "FAIL: failed to get raw priv key len\n");
712 		goto failure;
713 	}
714 	if ((priv_key = malloc(priv_key_len)) == NULL)
715 		errx(1, "failed to malloc priv key");
716 	if (EVP_PKEY_get_raw_private_key(pkey, priv_key, &priv_key_len)) {
717 		fprintf(stderr, "FAIL: got raw private key, should fail\n");
718 		goto failure;
719 	}
720 
721 	if (!EVP_PKEY_get_raw_public_key(pkey, NULL, &pub_key_len)) {
722 		fprintf(stderr, "FAIL: failed to get raw pub key len\n");
723 		goto failure;
724 	}
725 	if (pub_key_len != sizeof(x25519_raw_pub_key_1)) {
726 		fprintf(stderr, "FAIL: raw public key length differs "
727 		    "(%zu != %zu)\n", pub_key_len,
728 		    sizeof(x25519_raw_pub_key_1));
729 		goto failure;
730 	}
731 	if ((pub_key = malloc(pub_key_len)) == NULL)
732 		errx(1, "failed to malloc private key");
733 	if (!EVP_PKEY_get_raw_public_key(pkey, pub_key, &pub_key_len)) {
734 		fprintf(stderr, "FAIL: failed to get raw pub key len\n");
735 		goto failure;
736 	}
737 	if (memcmp(pub_key, x25519_raw_pub_key_1, pub_key_len) != 0) {
738 		fprintf(stderr, "FAIL: get raw public key failed\n");
739 		fprintf(stderr, "Got:\n");
740 		hexdump(pub_key, pub_key_len);
741 		fprintf(stderr, "Want:\n");
742 		hexdump(x25519_raw_pub_key_1, sizeof(x25519_raw_pub_key_1));
743 		goto failure;
744 	}
745 
746 	BIO_free(bio);
747 	bio = NULL;
748 
749 	EVP_PKEY_free(pkey);
750 	pkey = NULL;
751 
752 	/*
753 	 * Create PKEY from raw private, check PEM encoded private and public.
754 	 */
755 	if ((pkey = EVP_PKEY_new_raw_private_key(EVP_PKEY_X25519, NULL,
756 	    x25519_raw_priv_key_2, sizeof(x25519_raw_priv_key_2))) == NULL) {
757 		fprintf(stderr, "FAIL: PKEY from raw private key failed");
758 		goto failure;
759 	}
760 	if ((bio = BIO_new(BIO_s_mem())) == NULL)
761 		goto failure;
762 	if (!PEM_write_bio_PrivateKey(bio, pkey, NULL, NULL, 0, NULL, NULL)) {
763 		fprintf(stderr, "FAIL: failed to write X25519 private to PEM\n");
764 		goto failure;
765 	}
766 	BIO_get_mem_data(bio, &pp);
767 	if (strcmp(x25519_priv_key_2, pp) != 0) {
768 		fprintf(stderr, "FAIL: resulting private key PEM differs\n");
769 		goto failure;
770 	}
771 
772 	(void)BIO_reset(bio);
773 	if (!PEM_write_bio_PUBKEY(bio, pkey)) {
774 		fprintf(stderr, "FAIL: failed to write X25519 public to PEM\n");
775 		goto failure;
776 	}
777 	BIO_get_mem_data(bio, &pp);
778 	if (strcmp(x25519_pub_key_2, pp) != 0) {
779 		fprintf(stderr, "FAIL: resulting public key PEM differs\n");
780 		goto failure;
781 	}
782 
783 	EVP_PKEY_free(pkey);
784 	pkey = NULL;
785 
786 	/*
787 	 * Create PKEY from raw public, check public key PEM.
788 	 */
789 	if ((pkey = EVP_PKEY_new_raw_public_key(EVP_PKEY_X25519, NULL,
790 	    x25519_raw_pub_key_1, sizeof(x25519_raw_pub_key_1))) == NULL) {
791 		fprintf(stderr, "FAIL: PKEY from raw public key failed");
792 		goto failure;
793 	}
794 	(void)BIO_reset(bio);
795 	if (!PEM_write_bio_PUBKEY(bio, pkey)) {
796 		fprintf(stderr, "FAIL: failed to write X25519 public to PEM\n");
797 		goto failure;
798 	}
799 	BIO_get_mem_data(bio, &pp);
800 	if (strcmp(x25519_pub_key_1, pp) != 0) {
801 		fprintf(stderr, "FAIL: resulting public key PEM differs\n");
802 		goto failure;
803 	}
804 
805 	failed = 0;
806 
807  failure:
808 	BIO_free(bio);
809 	EVP_PKEY_free(pkey);
810 	freezero(priv_key, priv_key_len);
811 	freezero(pub_key, pub_key_len);
812 
813 	return failed;
814 }
815 
816 int
817 main(int argc, char **argv)
818 {
819 	int failed = 0;
820 
821 	failed |= ecx_ed25519_raw_key_test();
822 	failed |= ecx_ed25519_keygen_test();
823 	failed |= ecx_ed25519_sign_test();
824 	failed |= ecx_ed25519_verify_test();
825 
826 	failed |= ecx_x25519_keygen_test();
827 	failed |= ecx_x25519_derive_test();
828 	failed |= ecx_x25519_raw_key_test();
829 
830 	return failed;
831 }
832