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