Coverage Report

Created: 2023-03-26 06:46

/src/openssh/regress/misc/sk-dummy/sk-dummy.c
Line
Count
Source (jump to first uncovered line)
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
0
{
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
0
  (void)func; /* XXX */
89
0
  (void)fmt; /* XXX */
90
0
#endif
91
0
}
92
93
uint32_t
94
sk_api_version(void)
95
0
{
96
0
  return SSH_SK_VERSION_MAJOR;
97
0
}
98
99
static int
100
pack_key_ecdsa(struct sk_enroll_response *response)
101
0
{
102
0
#ifdef OPENSSL_HAS_ECC
103
0
  EC_KEY *key = NULL;
104
0
  const EC_GROUP *g;
105
0
  const EC_POINT *q;
106
0
  int ret = -1;
107
0
  long privlen;
108
0
  BIO *bio = NULL;
109
0
  char *privptr;
110
111
0
  response->public_key = NULL;
112
0
  response->public_key_len = 0;
113
0
  response->key_handle = NULL;
114
0
  response->key_handle_len = 0;
115
116
0
  if ((key = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1)) == NULL) {
117
0
    skdebug(__func__, "EC_KEY_new_by_curve_name");
118
0
    goto out;
119
0
  }
120
0
  if (EC_KEY_generate_key(key) != 1) {
121
0
    skdebug(__func__, "EC_KEY_generate_key");
122
0
    goto out;
123
0
  }
124
0
  EC_KEY_set_asn1_flag(key, OPENSSL_EC_NAMED_CURVE);
125
0
  if ((bio = BIO_new(BIO_s_mem())) == NULL ||
126
0
      (g = EC_KEY_get0_group(key)) == NULL ||
127
0
      (q = EC_KEY_get0_public_key(key)) == NULL) {
128
0
    skdebug(__func__, "couldn't get key parameters");
129
0
    goto out;
130
0
  }
131
0
  response->public_key_len = EC_POINT_point2oct(g, q,
132
0
      POINT_CONVERSION_UNCOMPRESSED, NULL, 0, NULL);
133
0
  if (response->public_key_len == 0 || response->public_key_len > 2048) {
134
0
    skdebug(__func__, "bad pubkey length %zu",
135
0
        response->public_key_len);
136
0
    goto out;
137
0
  }
138
0
  if ((response->public_key = malloc(response->public_key_len)) == NULL) {
139
0
    skdebug(__func__, "malloc pubkey failed");
140
0
    goto out;
141
0
  }
142
0
  if (EC_POINT_point2oct(g, q, POINT_CONVERSION_UNCOMPRESSED,
143
0
      response->public_key, response->public_key_len, NULL) == 0) {
144
0
    skdebug(__func__, "EC_POINT_point2oct failed");
145
0
    goto out;
146
0
  }
147
  /* Key handle contains PEM encoded private key */
148
0
  if (!PEM_write_bio_ECPrivateKey(bio, key, NULL, NULL, 0, NULL, NULL)) {
149
0
    skdebug(__func__, "PEM_write_bio_ECPrivateKey failed");
150
0
    goto out;
151
0
  }
152
0
  if ((privlen = BIO_get_mem_data(bio, &privptr)) <= 0) {
153
0
    skdebug(__func__, "BIO_get_mem_data failed");
154
0
    goto out;
155
0
  }
156
0
  if ((response->key_handle = malloc(privlen)) == NULL) {
157
0
    skdebug(__func__, "malloc key_handle failed");
158
0
    goto out;
159
0
  }
160
0
  response->key_handle_len = (size_t)privlen;
161
0
  memcpy(response->key_handle, privptr, response->key_handle_len);
162
  /* success */
163
0
  ret = 0;
164
0
 out:
165
0
  if (ret != 0) {
166
0
    if (response->public_key != NULL) {
167
0
      memset(response->public_key, 0,
168
0
          response->public_key_len);
169
0
      free(response->public_key);
170
0
      response->public_key = NULL;
171
0
    }
172
0
    if (response->key_handle != NULL) {
173
0
      memset(response->key_handle, 0,
174
0
          response->key_handle_len);
175
0
      free(response->key_handle);
176
0
      response->key_handle = NULL;
177
0
    }
178
0
  }
179
0
  BIO_free(bio);
180
0
  EC_KEY_free(key);
181
0
  return ret;
182
#else
183
  return -1;
184
#endif
185
0
}
186
187
static int
188
pack_key_ed25519(struct sk_enroll_response *response)
189
0
{
190
0
  int ret = -1;
191
0
  u_char pk[crypto_sign_ed25519_PUBLICKEYBYTES];
192
0
  u_char sk[crypto_sign_ed25519_SECRETKEYBYTES];
193
194
0
  response->public_key = NULL;
195
0
  response->public_key_len = 0;
196
0
  response->key_handle = NULL;
197
0
  response->key_handle_len = 0;
198
199
0
  memset(pk, 0, sizeof(pk));
200
0
  memset(sk, 0, sizeof(sk));
201
0
  crypto_sign_ed25519_keypair(pk, sk);
202
203
0
  response->public_key_len = sizeof(pk);
204
0
  if ((response->public_key = malloc(response->public_key_len)) == NULL) {
205
0
    skdebug(__func__, "malloc pubkey failed");
206
0
    goto out;
207
0
  }
208
0
  memcpy(response->public_key, pk, sizeof(pk));
209
  /* Key handle contains sk */
210
0
  response->key_handle_len = sizeof(sk);
211
0
  if ((response->key_handle = malloc(response->key_handle_len)) == NULL) {
212
0
    skdebug(__func__, "malloc key_handle failed");
213
0
    goto out;
214
0
  }
215
0
  memcpy(response->key_handle, sk, sizeof(sk));
216
  /* success */
217
0
  ret = 0;
218
0
 out:
219
0
  if (ret != 0)
220
0
    free(response->public_key);
221
0
  return ret;
222
0
}
223
224
static int
225
check_options(struct sk_option **options)
226
0
{
227
0
  size_t i;
228
229
0
  if (options == NULL)
230
0
    return 0;
231
0
  for (i = 0; options[i] != NULL; i++) {
232
0
    skdebug(__func__, "requested unsupported option %s",
233
0
        options[i]->name);
234
0
    if (options[i]->required) {
235
0
      skdebug(__func__, "unknown required option");
236
0
      return -1;
237
0
    }
238
0
  }
239
0
  return 0;
240
0
}
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
0
{
247
0
  struct sk_enroll_response *response = NULL;
248
0
  int ret = SSH_SK_ERR_GENERAL;
249
250
0
  (void)flags; /* XXX; unused */
251
252
0
  if (enroll_response == NULL) {
253
0
    skdebug(__func__, "enroll_response == NULL");
254
0
    goto out;
255
0
  }
256
0
  *enroll_response = NULL;
257
0
  if (check_options(options) != 0)
258
0
    goto out; /* error already logged */
259
0
  if ((response = calloc(1, sizeof(*response))) == NULL) {
260
0
    skdebug(__func__, "calloc response failed");
261
0
    goto out;
262
0
  }
263
0
  response->flags = flags;
264
0
  switch(alg) {
265
0
  case SSH_SK_ECDSA:
266
0
    if (pack_key_ecdsa(response) != 0)
267
0
      goto out;
268
0
    break;
269
0
  case SSH_SK_ED25519:
270
0
    if (pack_key_ed25519(response) != 0)
271
0
      goto out;
272
0
    break;
273
0
  default:
274
0
    skdebug(__func__, "unsupported key type %d", alg);
275
0
    return -1;
276
0
  }
277
  /* Have to return something here */
278
0
  if ((response->signature = calloc(1, 1)) == NULL) {
279
0
    skdebug(__func__, "calloc signature failed");
280
0
    goto out;
281
0
  }
282
0
  response->signature_len = 0;
283
284
0
  *enroll_response = response;
285
0
  response = NULL;
286
0
  ret = 0;
287
0
 out:
288
0
  if (response != NULL) {
289
0
    free(response->public_key);
290
0
    free(response->key_handle);
291
0
    free(response->signature);
292
0
    free(response->attestation_cert);
293
0
    free(response);
294
0
  }
295
0
  return ret;
296
0
}
297
298
static void
299
dump(const char *preamble, const void *sv, size_t l)
300
0
{
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
0
}
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
0
{
322
0
#ifdef OPENSSL_HAS_ECC
323
0
  ECDSA_SIG *sig = NULL;
324
0
  const BIGNUM *sig_r, *sig_s;
325
0
  int ret = -1;
326
0
  BIO *bio = NULL;
327
0
  EVP_PKEY *pk = NULL;
328
0
  EC_KEY *ec = NULL;
329
0
  SHA2_CTX ctx;
330
0
  uint8_t apphash[SHA256_DIGEST_LENGTH];
331
0
  uint8_t sighash[SHA256_DIGEST_LENGTH];
332
0
  uint8_t countbuf[4];
333
334
  /* Decode EC_KEY from key handle */
335
0
  if ((bio = BIO_new(BIO_s_mem())) == NULL ||
336
0
      BIO_write(bio, key_handle, key_handle_len) != (int)key_handle_len) {
337
0
    skdebug(__func__, "BIO setup failed");
338
0
    goto out;
339
0
  }
340
0
  if ((pk = PEM_read_bio_PrivateKey(bio, NULL, NULL, "")) == NULL) {
341
0
    skdebug(__func__, "PEM_read_bio_PrivateKey failed");
342
0
    goto out;
343
0
  }
344
0
  if (EVP_PKEY_base_id(pk) != EVP_PKEY_EC) {
345
0
    skdebug(__func__, "Not an EC key: %d", EVP_PKEY_base_id(pk));
346
0
    goto out;
347
0
  }
348
0
  if ((ec = EVP_PKEY_get1_EC_KEY(pk)) == NULL) {
349
0
    skdebug(__func__, "EVP_PKEY_get1_EC_KEY failed");
350
0
    goto out;
351
0
  }
352
  /* Expect message to be pre-hashed */
353
0
  if (message_len != SHA256_DIGEST_LENGTH) {
354
0
    skdebug(__func__, "bad message len %zu", message_len);
355
0
    goto out;
356
0
  }
357
  /* Prepare data to be signed */
358
0
  dump("message", message, message_len);
359
0
  SHA256Init(&ctx);
360
0
  SHA256Update(&ctx, (const u_char *)application, strlen(application));
361
0
  SHA256Final(apphash, &ctx);
362
0
  dump("apphash", apphash, sizeof(apphash));
363
0
  countbuf[0] = (counter >> 24) & 0xff;
364
0
  countbuf[1] = (counter >> 16) & 0xff;
365
0
  countbuf[2] = (counter >> 8) & 0xff;
366
0
  countbuf[3] = counter & 0xff;
367
0
  dump("countbuf", countbuf, sizeof(countbuf));
368
0
  dump("flags", &flags, sizeof(flags));
369
0
  SHA256Init(&ctx);
370
0
  SHA256Update(&ctx, apphash, sizeof(apphash));
371
0
  SHA256Update(&ctx, &flags, sizeof(flags));
372
0
  SHA256Update(&ctx, countbuf, sizeof(countbuf));
373
0
  SHA256Update(&ctx, message, message_len);
374
0
  SHA256Final(sighash, &ctx);
375
0
  dump("sighash", sighash, sizeof(sighash));
376
  /* create and encode signature */
377
0
  if ((sig = ECDSA_do_sign(sighash, sizeof(sighash), ec)) == NULL) {
378
0
    skdebug(__func__, "ECDSA_do_sign failed");
379
0
    goto out;
380
0
  }
381
0
  ECDSA_SIG_get0(sig, &sig_r, &sig_s);
382
0
  response->sig_r_len = BN_num_bytes(sig_r);
383
0
  response->sig_s_len = BN_num_bytes(sig_s);
384
0
  if ((response->sig_r = calloc(1, response->sig_r_len)) == NULL ||
385
0
      (response->sig_s = calloc(1, response->sig_s_len)) == NULL) {
386
0
    skdebug(__func__, "calloc signature failed");
387
0
    goto out;
388
0
  }
389
0
  BN_bn2bin(sig_r, response->sig_r);
390
0
  BN_bn2bin(sig_s, response->sig_s);
391
0
  ret = 0;
392
0
 out:
393
0
  explicit_bzero(&ctx, sizeof(ctx));
394
0
  explicit_bzero(&apphash, sizeof(apphash));
395
0
  explicit_bzero(&sighash, sizeof(sighash));
396
0
  ECDSA_SIG_free(sig);
397
0
  if (ret != 0) {
398
0
    free(response->sig_r);
399
0
    free(response->sig_s);
400
0
    response->sig_r = NULL;
401
0
    response->sig_s = NULL;
402
0
  }
403
0
  BIO_free(bio);
404
0
  EC_KEY_free(ec);
405
0
  EVP_PKEY_free(pk);
406
0
  return ret;
407
#else
408
  return -1;
409
#endif
410
0
}
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
0
{
418
0
  size_t o;
419
0
  int ret = -1;
420
0
  SHA2_CTX ctx;
421
0
  uint8_t apphash[SHA256_DIGEST_LENGTH];
422
0
  uint8_t signbuf[sizeof(apphash) + sizeof(flags) +
423
0
      sizeof(counter) + SHA256_DIGEST_LENGTH];
424
0
  uint8_t sig[crypto_sign_ed25519_BYTES + sizeof(signbuf)];
425
0
  unsigned long long smlen;
426
427
0
  if (key_handle_len != crypto_sign_ed25519_SECRETKEYBYTES) {
428
0
    skdebug(__func__, "bad key handle length %zu", key_handle_len);
429
0
    goto out;
430
0
  }
431
  /* Expect message to be pre-hashed */
432
0
  if (message_len != SHA256_DIGEST_LENGTH) {
433
0
    skdebug(__func__, "bad message len %zu", message_len);
434
0
    goto out;
435
0
  }
436
  /* Prepare data to be signed */
437
0
  dump("message", message, message_len);
438
0
  SHA256Init(&ctx);
439
0
  SHA256Update(&ctx, (const u_char *)application, strlen(application));
440
0
  SHA256Final(apphash, &ctx);
441
0
  dump("apphash", apphash, sizeof(apphash));
442
443
0
  memcpy(signbuf, apphash, sizeof(apphash));
444
0
  o = sizeof(apphash);
445
0
  signbuf[o++] = flags;
446
0
  signbuf[o++] = (counter >> 24) & 0xff;
447
0
  signbuf[o++] = (counter >> 16) & 0xff;
448
0
  signbuf[o++] = (counter >> 8) & 0xff;
449
0
  signbuf[o++] = counter & 0xff;
450
0
  memcpy(signbuf + o, message, message_len);
451
0
  o += message_len;
452
0
  if (o != sizeof(signbuf)) {
453
0
    skdebug(__func__, "bad sign buf len %zu, expected %zu",
454
0
        o, sizeof(signbuf));
455
0
    goto out;
456
0
  }
457
0
  dump("signbuf", signbuf, sizeof(signbuf));
458
  /* create and encode signature */
459
0
  smlen = sizeof(signbuf);
460
0
  if (crypto_sign_ed25519(sig, &smlen, signbuf, sizeof(signbuf),
461
0
      key_handle) != 0) {
462
0
    skdebug(__func__, "crypto_sign_ed25519 failed");
463
0
    goto out;
464
0
  }
465
0
  if (smlen <= sizeof(signbuf)) {
466
0
    skdebug(__func__, "bad sign smlen %llu, expected min %zu",
467
0
        smlen, sizeof(signbuf) + 1);
468
0
    goto out;
469
0
  }
470
0
  response->sig_r_len = (size_t)(smlen - sizeof(signbuf));
471
0
  if ((response->sig_r = calloc(1, response->sig_r_len)) == NULL) {
472
0
    skdebug(__func__, "calloc signature failed");
473
0
    goto out;
474
0
  }
475
0
  memcpy(response->sig_r, sig, response->sig_r_len);
476
0
  dump("sig_r", response->sig_r, response->sig_r_len);
477
0
  ret = 0;
478
0
 out:
479
0
  explicit_bzero(&ctx, sizeof(ctx));
480
0
  explicit_bzero(&apphash, sizeof(apphash));
481
0
  explicit_bzero(&signbuf, sizeof(signbuf));
482
0
  explicit_bzero(&sig, sizeof(sig));
483
0
  if (ret != 0) {
484
0
    free(response->sig_r);
485
0
    response->sig_r = NULL;
486
0
  }
487
0
  return ret;
488
0
}
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
0
{
496
0
  struct sk_sign_response *response = NULL;
497
0
  int ret = SSH_SK_ERR_GENERAL;
498
0
  SHA2_CTX ctx;
499
0
  uint8_t message[32];
500
501
0
  if (sign_response == NULL) {
502
0
    skdebug(__func__, "sign_response == NULL");
503
0
    goto out;
504
0
  }
505
0
  *sign_response = NULL;
506
0
  if (check_options(options) != 0)
507
0
    goto out; /* error already logged */
508
0
  if ((response = calloc(1, sizeof(*response))) == NULL) {
509
0
    skdebug(__func__, "calloc response failed");
510
0
    goto out;
511
0
  }
512
0
  SHA256Init(&ctx);
513
0
  SHA256Update(&ctx, data, datalen);
514
0
  SHA256Final(message, &ctx);
515
0
  response->flags = flags;
516
0
  response->counter = 0x12345678;
517
0
  switch(alg) {
518
0
  case SSH_SK_ECDSA:
519
0
    if (sig_ecdsa(message, sizeof(message), application,
520
0
        response->counter, flags, key_handle, key_handle_len,
521
0
        response) != 0)
522
0
      goto out;
523
0
    break;
524
0
  case SSH_SK_ED25519:
525
0
    if (sig_ed25519(message, sizeof(message), application,
526
0
        response->counter, flags, key_handle, key_handle_len,
527
0
        response) != 0)
528
0
      goto out;
529
0
    break;
530
0
  default:
531
0
    skdebug(__func__, "unsupported key type %d", alg);
532
0
    return -1;
533
0
  }
534
0
  *sign_response = response;
535
0
  response = NULL;
536
0
  ret = 0;
537
0
 out:
538
0
  explicit_bzero(message, sizeof(message));
539
0
  if (response != NULL) {
540
0
    free(response->sig_r);
541
0
    free(response->sig_s);
542
0
    free(response);
543
0
  }
544
0
  return ret;
545
0
}
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
0
{
551
0
  return SSH_SK_ERR_UNSUPPORTED;
552
0
}