xref: /freebsd/crypto/openssh/regress/misc/sk-dummy/sk-dummy.c (revision b077aed33b7b6aefca7b17ddb250cf521f938613)
1 /*
2  * Copyright (c) 2019 Markus Friedl
3  *
4  * Permission to use, copy, modify, and distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16 
17 #include "includes.h"
18 
19 #ifdef HAVE_STDINT_H
20 #include <stdint.h>
21 #endif
22 #include <stdlib.h>
23 #include <string.h>
24 #include <stdio.h>
25 #include <stddef.h>
26 #include <stdarg.h>
27 #ifdef HAVE_SHA2_H
28 #include <sha2.h>
29 #endif
30 
31 #include "crypto_api.h"
32 #include "sk-api.h"
33 
34 #if defined(WITH_OPENSSL) && !defined(OPENSSL_HAS_ECC)
35 # undef WITH_OPENSSL
36 #endif
37 
38 #ifdef WITH_OPENSSL
39 /* We don't use sha2 from OpenSSL and they can conflict with system sha2.h */
40 #define OPENSSL_NO_SHA
41 #define USE_LIBC_SHA2	/* NetBSD 9 */
42 #include <openssl/opensslv.h>
43 #include <openssl/crypto.h>
44 #include <openssl/evp.h>
45 #include <openssl/bn.h>
46 #include <openssl/ec.h>
47 #include <openssl/ecdsa.h>
48 #include <openssl/pem.h>
49 
50 /* Compatibility with OpenSSH 1.0.x */
51 #if (OPENSSL_VERSION_NUMBER < 0x10100000L)
52 #define ECDSA_SIG_get0(sig, pr, ps) \
53 	do { \
54 		(*pr) = sig->r; \
55 		(*ps) = sig->s; \
56 	} while (0)
57 #endif
58 #endif /* WITH_OPENSSL */
59 
60 /* #define SK_DEBUG 1 */
61 
62 #if SSH_SK_VERSION_MAJOR != 0x000a0000
63 # error SK API has changed, sk-dummy.c needs an update
64 #endif
65 
66 #ifdef SK_DUMMY_INTEGRATE
67 # define sk_api_version		ssh_sk_api_version
68 # define sk_enroll		ssh_sk_enroll
69 # define sk_sign		ssh_sk_sign
70 # define sk_load_resident_keys	ssh_sk_load_resident_keys
71 #endif /* !SK_STANDALONE */
72 
73 static void skdebug(const char *func, const char *fmt, ...)
74     __attribute__((__format__ (printf, 2, 3)));
75 
76 static void
77 skdebug(const char *func, const char *fmt, ...)
78 {
79 #if defined(SK_DEBUG)
80 	va_list ap;
81 
82 	va_start(ap, fmt);
83 	fprintf(stderr, "sk-dummy %s: ", func);
84 	vfprintf(stderr, fmt, ap);
85 	fputc('\n', stderr);
86 	va_end(ap);
87 #else
88 	(void)func; /* XXX */
89 	(void)fmt; /* XXX */
90 #endif
91 }
92 
93 uint32_t
94 sk_api_version(void)
95 {
96 	return SSH_SK_VERSION_MAJOR;
97 }
98 
99 static int
100 pack_key_ecdsa(struct sk_enroll_response *response)
101 {
102 #ifdef OPENSSL_HAS_ECC
103 	EC_KEY *key = NULL;
104 	const EC_GROUP *g;
105 	const EC_POINT *q;
106 	int ret = -1;
107 	long privlen;
108 	BIO *bio = NULL;
109 	char *privptr;
110 
111 	response->public_key = NULL;
112 	response->public_key_len = 0;
113 	response->key_handle = NULL;
114 	response->key_handle_len = 0;
115 
116 	if ((key = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1)) == NULL) {
117 		skdebug(__func__, "EC_KEY_new_by_curve_name");
118 		goto out;
119 	}
120 	if (EC_KEY_generate_key(key) != 1) {
121 		skdebug(__func__, "EC_KEY_generate_key");
122 		goto out;
123 	}
124 	EC_KEY_set_asn1_flag(key, OPENSSL_EC_NAMED_CURVE);
125 	if ((bio = BIO_new(BIO_s_mem())) == NULL ||
126 	    (g = EC_KEY_get0_group(key)) == NULL ||
127 	    (q = EC_KEY_get0_public_key(key)) == NULL) {
128 		skdebug(__func__, "couldn't get key parameters");
129 		goto out;
130 	}
131 	response->public_key_len = EC_POINT_point2oct(g, q,
132 	    POINT_CONVERSION_UNCOMPRESSED, NULL, 0, NULL);
133 	if (response->public_key_len == 0 || response->public_key_len > 2048) {
134 		skdebug(__func__, "bad pubkey length %zu",
135 		    response->public_key_len);
136 		goto out;
137 	}
138 	if ((response->public_key = malloc(response->public_key_len)) == NULL) {
139 		skdebug(__func__, "malloc pubkey failed");
140 		goto out;
141 	}
142 	if (EC_POINT_point2oct(g, q, POINT_CONVERSION_UNCOMPRESSED,
143 	    response->public_key, response->public_key_len, NULL) == 0) {
144 		skdebug(__func__, "EC_POINT_point2oct failed");
145 		goto out;
146 	}
147 	/* Key handle contains PEM encoded private key */
148 	if (!PEM_write_bio_ECPrivateKey(bio, key, NULL, NULL, 0, NULL, NULL)) {
149 		skdebug(__func__, "PEM_write_bio_ECPrivateKey failed");
150 		goto out;
151 	}
152 	if ((privlen = BIO_get_mem_data(bio, &privptr)) <= 0) {
153 		skdebug(__func__, "BIO_get_mem_data failed");
154 		goto out;
155 	}
156 	if ((response->key_handle = malloc(privlen)) == NULL) {
157 		skdebug(__func__, "malloc key_handle failed");
158 		goto out;
159 	}
160 	response->key_handle_len = (size_t)privlen;
161 	memcpy(response->key_handle, privptr, response->key_handle_len);
162 	/* success */
163 	ret = 0;
164  out:
165 	if (ret != 0) {
166 		if (response->public_key != NULL) {
167 			memset(response->public_key, 0,
168 			    response->public_key_len);
169 			free(response->public_key);
170 			response->public_key = NULL;
171 		}
172 		if (response->key_handle != NULL) {
173 			memset(response->key_handle, 0,
174 			    response->key_handle_len);
175 			free(response->key_handle);
176 			response->key_handle = NULL;
177 		}
178 	}
179 	BIO_free(bio);
180 	EC_KEY_free(key);
181 	return ret;
182 #else
183 	return -1;
184 #endif
185 }
186 
187 static int
188 pack_key_ed25519(struct sk_enroll_response *response)
189 {
190 	int ret = -1;
191 	u_char pk[crypto_sign_ed25519_PUBLICKEYBYTES];
192 	u_char sk[crypto_sign_ed25519_SECRETKEYBYTES];
193 
194 	response->public_key = NULL;
195 	response->public_key_len = 0;
196 	response->key_handle = NULL;
197 	response->key_handle_len = 0;
198 
199 	memset(pk, 0, sizeof(pk));
200 	memset(sk, 0, sizeof(sk));
201 	crypto_sign_ed25519_keypair(pk, sk);
202 
203 	response->public_key_len = sizeof(pk);
204 	if ((response->public_key = malloc(response->public_key_len)) == NULL) {
205 		skdebug(__func__, "malloc pubkey failed");
206 		goto out;
207 	}
208 	memcpy(response->public_key, pk, sizeof(pk));
209 	/* Key handle contains sk */
210 	response->key_handle_len = sizeof(sk);
211 	if ((response->key_handle = malloc(response->key_handle_len)) == NULL) {
212 		skdebug(__func__, "malloc key_handle failed");
213 		goto out;
214 	}
215 	memcpy(response->key_handle, sk, sizeof(sk));
216 	/* success */
217 	ret = 0;
218  out:
219 	if (ret != 0)
220 		free(response->public_key);
221 	return ret;
222 }
223 
224 static int
225 check_options(struct sk_option **options)
226 {
227 	size_t i;
228 
229 	if (options == NULL)
230 		return 0;
231 	for (i = 0; options[i] != NULL; i++) {
232 		skdebug(__func__, "requested unsupported option %s",
233 		    options[i]->name);
234 		if (options[i]->required) {
235 			skdebug(__func__, "unknown required option");
236 			return -1;
237 		}
238 	}
239 	return 0;
240 }
241 
242 int
243 sk_enroll(uint32_t alg, const uint8_t *challenge, size_t challenge_len,
244     const char *application, uint8_t flags, const char *pin,
245     struct sk_option **options, struct sk_enroll_response **enroll_response)
246 {
247 	struct sk_enroll_response *response = NULL;
248 	int ret = SSH_SK_ERR_GENERAL;
249 
250 	(void)flags; /* XXX; unused */
251 
252 	if (enroll_response == NULL) {
253 		skdebug(__func__, "enroll_response == NULL");
254 		goto out;
255 	}
256 	*enroll_response = NULL;
257 	if (check_options(options) != 0)
258 		goto out; /* error already logged */
259 	if ((response = calloc(1, sizeof(*response))) == NULL) {
260 		skdebug(__func__, "calloc response failed");
261 		goto out;
262 	}
263 	response->flags = flags;
264 	switch(alg) {
265 	case SSH_SK_ECDSA:
266 		if (pack_key_ecdsa(response) != 0)
267 			goto out;
268 		break;
269 	case SSH_SK_ED25519:
270 		if (pack_key_ed25519(response) != 0)
271 			goto out;
272 		break;
273 	default:
274 		skdebug(__func__, "unsupported key type %d", alg);
275 		return -1;
276 	}
277 	/* Have to return something here */
278 	if ((response->signature = calloc(1, 1)) == NULL) {
279 		skdebug(__func__, "calloc signature failed");
280 		goto out;
281 	}
282 	response->signature_len = 0;
283 
284 	*enroll_response = response;
285 	response = NULL;
286 	ret = 0;
287  out:
288 	if (response != NULL) {
289 		free(response->public_key);
290 		free(response->key_handle);
291 		free(response->signature);
292 		free(response->attestation_cert);
293 		free(response);
294 	}
295 	return ret;
296 }
297 
298 static void
299 dump(const char *preamble, const void *sv, size_t l)
300 {
301 #ifdef SK_DEBUG
302 	const u_char *s = (const u_char *)sv;
303 	size_t i;
304 
305 	fprintf(stderr, "%s (len %zu):\n", preamble, l);
306 	for (i = 0; i < l; i++) {
307 		if (i % 16 == 0)
308 			fprintf(stderr, "%04zu: ", i);
309 		fprintf(stderr, "%02x", s[i]);
310 		if (i % 16 == 15 || i == l - 1)
311 			fprintf(stderr, "\n");
312 	}
313 #endif
314 }
315 
316 static int
317 sig_ecdsa(const uint8_t *message, size_t message_len,
318     const char *application, uint32_t counter, uint8_t flags,
319     const uint8_t *key_handle, size_t key_handle_len,
320     struct sk_sign_response *response)
321 {
322 #ifdef OPENSSL_HAS_ECC
323 	ECDSA_SIG *sig = NULL;
324 	const BIGNUM *sig_r, *sig_s;
325 	int ret = -1;
326 	BIO *bio = NULL;
327 	EVP_PKEY *pk = NULL;
328 	EC_KEY *ec = NULL;
329 	SHA2_CTX ctx;
330 	uint8_t	apphash[SHA256_DIGEST_LENGTH];
331 	uint8_t	sighash[SHA256_DIGEST_LENGTH];
332 	uint8_t countbuf[4];
333 
334 	/* Decode EC_KEY from key handle */
335 	if ((bio = BIO_new(BIO_s_mem())) == NULL ||
336 	    BIO_write(bio, key_handle, key_handle_len) != (int)key_handle_len) {
337 		skdebug(__func__, "BIO setup failed");
338 		goto out;
339 	}
340 	if ((pk = PEM_read_bio_PrivateKey(bio, NULL, NULL, "")) == NULL) {
341 		skdebug(__func__, "PEM_read_bio_PrivateKey failed");
342 		goto out;
343 	}
344 	if (EVP_PKEY_base_id(pk) != EVP_PKEY_EC) {
345 		skdebug(__func__, "Not an EC key: %d", EVP_PKEY_base_id(pk));
346 		goto out;
347 	}
348 	if ((ec = EVP_PKEY_get1_EC_KEY(pk)) == NULL) {
349 		skdebug(__func__, "EVP_PKEY_get1_EC_KEY failed");
350 		goto out;
351 	}
352 	/* Expect message to be pre-hashed */
353 	if (message_len != SHA256_DIGEST_LENGTH) {
354 		skdebug(__func__, "bad message len %zu", message_len);
355 		goto out;
356 	}
357 	/* Prepare data to be signed */
358 	dump("message", message, message_len);
359 	SHA256Init(&ctx);
360 	SHA256Update(&ctx, (const u_char *)application, strlen(application));
361 	SHA256Final(apphash, &ctx);
362 	dump("apphash", apphash, sizeof(apphash));
363 	countbuf[0] = (counter >> 24) & 0xff;
364 	countbuf[1] = (counter >> 16) & 0xff;
365 	countbuf[2] = (counter >> 8) & 0xff;
366 	countbuf[3] = counter & 0xff;
367 	dump("countbuf", countbuf, sizeof(countbuf));
368 	dump("flags", &flags, sizeof(flags));
369 	SHA256Init(&ctx);
370 	SHA256Update(&ctx, apphash, sizeof(apphash));
371 	SHA256Update(&ctx, &flags, sizeof(flags));
372 	SHA256Update(&ctx, countbuf, sizeof(countbuf));
373 	SHA256Update(&ctx, message, message_len);
374 	SHA256Final(sighash, &ctx);
375 	dump("sighash", sighash, sizeof(sighash));
376 	/* create and encode signature */
377 	if ((sig = ECDSA_do_sign(sighash, sizeof(sighash), ec)) == NULL) {
378 		skdebug(__func__, "ECDSA_do_sign failed");
379 		goto out;
380 	}
381 	ECDSA_SIG_get0(sig, &sig_r, &sig_s);
382 	response->sig_r_len = BN_num_bytes(sig_r);
383 	response->sig_s_len = BN_num_bytes(sig_s);
384 	if ((response->sig_r = calloc(1, response->sig_r_len)) == NULL ||
385 	    (response->sig_s = calloc(1, response->sig_s_len)) == NULL) {
386 		skdebug(__func__, "calloc signature failed");
387 		goto out;
388 	}
389 	BN_bn2bin(sig_r, response->sig_r);
390 	BN_bn2bin(sig_s, response->sig_s);
391 	ret = 0;
392  out:
393 	explicit_bzero(&ctx, sizeof(ctx));
394 	explicit_bzero(&apphash, sizeof(apphash));
395 	explicit_bzero(&sighash, sizeof(sighash));
396 	ECDSA_SIG_free(sig);
397 	if (ret != 0) {
398 		free(response->sig_r);
399 		free(response->sig_s);
400 		response->sig_r = NULL;
401 		response->sig_s = NULL;
402 	}
403 	BIO_free(bio);
404 	EC_KEY_free(ec);
405 	EVP_PKEY_free(pk);
406 	return ret;
407 #else
408 	return -1;
409 #endif
410 }
411 
412 static int
413 sig_ed25519(const uint8_t *message, size_t message_len,
414     const char *application, uint32_t counter, uint8_t flags,
415     const uint8_t *key_handle, size_t key_handle_len,
416     struct sk_sign_response *response)
417 {
418 	size_t o;
419 	int ret = -1;
420 	SHA2_CTX ctx;
421 	uint8_t	apphash[SHA256_DIGEST_LENGTH];
422 	uint8_t signbuf[sizeof(apphash) + sizeof(flags) +
423 	    sizeof(counter) + SHA256_DIGEST_LENGTH];
424 	uint8_t sig[crypto_sign_ed25519_BYTES + sizeof(signbuf)];
425 	unsigned long long smlen;
426 
427 	if (key_handle_len != crypto_sign_ed25519_SECRETKEYBYTES) {
428 		skdebug(__func__, "bad key handle length %zu", key_handle_len);
429 		goto out;
430 	}
431 	/* Expect message to be pre-hashed */
432 	if (message_len != SHA256_DIGEST_LENGTH) {
433 		skdebug(__func__, "bad message len %zu", message_len);
434 		goto out;
435 	}
436 	/* Prepare data to be signed */
437 	dump("message", message, message_len);
438 	SHA256Init(&ctx);
439 	SHA256Update(&ctx, (const u_char *)application, strlen(application));
440 	SHA256Final(apphash, &ctx);
441 	dump("apphash", apphash, sizeof(apphash));
442 
443 	memcpy(signbuf, apphash, sizeof(apphash));
444 	o = sizeof(apphash);
445 	signbuf[o++] = flags;
446 	signbuf[o++] = (counter >> 24) & 0xff;
447 	signbuf[o++] = (counter >> 16) & 0xff;
448 	signbuf[o++] = (counter >> 8) & 0xff;
449 	signbuf[o++] = counter & 0xff;
450 	memcpy(signbuf + o, message, message_len);
451 	o += message_len;
452 	if (o != sizeof(signbuf)) {
453 		skdebug(__func__, "bad sign buf len %zu, expected %zu",
454 		    o, sizeof(signbuf));
455 		goto out;
456 	}
457 	dump("signbuf", signbuf, sizeof(signbuf));
458 	/* create and encode signature */
459 	smlen = sizeof(signbuf);
460 	if (crypto_sign_ed25519(sig, &smlen, signbuf, sizeof(signbuf),
461 	    key_handle) != 0) {
462 		skdebug(__func__, "crypto_sign_ed25519 failed");
463 		goto out;
464 	}
465 	if (smlen <= sizeof(signbuf)) {
466 		skdebug(__func__, "bad sign smlen %llu, expected min %zu",
467 		    smlen, sizeof(signbuf) + 1);
468 		goto out;
469 	}
470 	response->sig_r_len = (size_t)(smlen - sizeof(signbuf));
471 	if ((response->sig_r = calloc(1, response->sig_r_len)) == NULL) {
472 		skdebug(__func__, "calloc signature failed");
473 		goto out;
474 	}
475 	memcpy(response->sig_r, sig, response->sig_r_len);
476 	dump("sig_r", response->sig_r, response->sig_r_len);
477 	ret = 0;
478  out:
479 	explicit_bzero(&ctx, sizeof(ctx));
480 	explicit_bzero(&apphash, sizeof(apphash));
481 	explicit_bzero(&signbuf, sizeof(signbuf));
482 	explicit_bzero(&sig, sizeof(sig));
483 	if (ret != 0) {
484 		free(response->sig_r);
485 		response->sig_r = NULL;
486 	}
487 	return ret;
488 }
489 
490 int
491 sk_sign(uint32_t alg, const uint8_t *data, size_t datalen,
492     const char *application, const uint8_t *key_handle, size_t key_handle_len,
493     uint8_t flags, const char *pin, struct sk_option **options,
494     struct sk_sign_response **sign_response)
495 {
496 	struct sk_sign_response *response = NULL;
497 	int ret = SSH_SK_ERR_GENERAL;
498 	SHA2_CTX ctx;
499 	uint8_t message[32];
500 
501 	if (sign_response == NULL) {
502 		skdebug(__func__, "sign_response == NULL");
503 		goto out;
504 	}
505 	*sign_response = NULL;
506 	if (check_options(options) != 0)
507 		goto out; /* error already logged */
508 	if ((response = calloc(1, sizeof(*response))) == NULL) {
509 		skdebug(__func__, "calloc response failed");
510 		goto out;
511 	}
512 	SHA256Init(&ctx);
513 	SHA256Update(&ctx, data, datalen);
514 	SHA256Final(message, &ctx);
515 	response->flags = flags;
516 	response->counter = 0x12345678;
517 	switch(alg) {
518 	case SSH_SK_ECDSA:
519 		if (sig_ecdsa(message, sizeof(message), application,
520 		    response->counter, flags, key_handle, key_handle_len,
521 		    response) != 0)
522 			goto out;
523 		break;
524 	case SSH_SK_ED25519:
525 		if (sig_ed25519(message, sizeof(message), application,
526 		    response->counter, flags, key_handle, key_handle_len,
527 		    response) != 0)
528 			goto out;
529 		break;
530 	default:
531 		skdebug(__func__, "unsupported key type %d", alg);
532 		return -1;
533 	}
534 	*sign_response = response;
535 	response = NULL;
536 	ret = 0;
537  out:
538 	explicit_bzero(message, sizeof(message));
539 	if (response != NULL) {
540 		free(response->sig_r);
541 		free(response->sig_s);
542 		free(response);
543 	}
544 	return ret;
545 }
546 
547 int
548 sk_load_resident_keys(const char *pin, struct sk_option **options,
549     struct sk_resident_key ***rks, size_t *nrks)
550 {
551 	return SSH_SK_ERR_UNSUPPORTED;
552 }
553