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