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
skdebug(const char * func,const char * fmt,...)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
sk_api_version(void)82 sk_api_version(void)
83 {
84 return SSH_SK_VERSION_MAJOR;
85 }
86
87 static int
pack_key_ecdsa(struct sk_enroll_response * response)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
pack_key_ed25519(struct sk_enroll_response * response)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
check_options(struct sk_option ** options)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
sk_enroll(uint32_t alg,const uint8_t * challenge,size_t challenge_len,const char * application,uint8_t flags,const char * pin,struct sk_option ** options,struct sk_enroll_response ** enroll_response)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
dump(const char * preamble,const void * sv,size_t l)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
sig_ecdsa(const uint8_t * message,size_t message_len,const char * application,uint32_t counter,uint8_t flags,const uint8_t * key_handle,size_t key_handle_len,struct sk_sign_response * response)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
sig_ed25519(const uint8_t * message,size_t message_len,const char * application,uint32_t counter,uint8_t flags,const uint8_t * key_handle,size_t key_handle_len,struct sk_sign_response * response)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
sk_sign(uint32_t alg,const uint8_t * data,size_t datalen,const char * application,const uint8_t * key_handle,size_t key_handle_len,uint8_t flags,const char * pin,struct sk_option ** options,struct sk_sign_response ** sign_response)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
sk_load_resident_keys(const char * pin,struct sk_option ** options,struct sk_resident_key *** rks,size_t * nrks)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