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