Coverage Report

Created: 2023-06-07 07:08

/src/openssh/sshsig.c
Line
Count
Source (jump to first uncovered line)
1
/* $OpenBSD: sshsig.c,v 1.32 2023/04/06 03:56:02 djm Exp $ */
2
/*
3
 * Copyright (c) 2019 Google LLC
4
 *
5
 * Permission to use, copy, modify, and distribute this software for any
6
 * purpose with or without fee is hereby granted, provided that the above
7
 * copyright notice and this permission notice appear in all copies.
8
 *
9
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16
 */
17
18
#include "includes.h"
19
20
#include <stdio.h>
21
#include <stdlib.h>
22
#include <stdarg.h>
23
#include <errno.h>
24
#include <string.h>
25
#include <unistd.h>
26
27
#include "authfd.h"
28
#include "authfile.h"
29
#include "log.h"
30
#include "misc.h"
31
#include "sshbuf.h"
32
#include "sshsig.h"
33
#include "ssherr.h"
34
#include "sshkey.h"
35
#include "match.h"
36
#include "digest.h"
37
38
0
#define SIG_VERSION   0x01
39
0
#define MAGIC_PREAMBLE    "SSHSIG"
40
0
#define MAGIC_PREAMBLE_LEN  (sizeof(MAGIC_PREAMBLE) - 1)
41
0
#define BEGIN_SIGNATURE   "-----BEGIN SSH SIGNATURE-----\n"
42
0
#define END_SIGNATURE   "-----END SSH SIGNATURE-----"
43
0
#define RSA_SIGN_ALG    "rsa-sha2-512" /* XXX maybe make configurable */
44
0
#define RSA_SIGN_ALLOWED  "rsa-sha2-512,rsa-sha2-256"
45
0
#define HASHALG_DEFAULT   "sha512" /* XXX maybe make configurable */
46
0
#define HASHALG_ALLOWED   "sha256,sha512"
47
48
int
49
sshsig_armor(const struct sshbuf *blob, struct sshbuf **out)
50
0
{
51
0
  struct sshbuf *buf = NULL;
52
0
  int r = SSH_ERR_INTERNAL_ERROR;
53
54
0
  *out = NULL;
55
56
0
  if ((buf = sshbuf_new()) == NULL) {
57
0
    error_f("sshbuf_new failed");
58
0
    r = SSH_ERR_ALLOC_FAIL;
59
0
    goto out;
60
0
  }
61
62
0
  if ((r = sshbuf_put(buf, BEGIN_SIGNATURE,
63
0
      sizeof(BEGIN_SIGNATURE)-1)) != 0) {
64
0
    error_fr(r, "sshbuf_putf");
65
0
    goto out;
66
0
  }
67
68
0
  if ((r = sshbuf_dtob64(blob, buf, 1)) != 0) {
69
0
    error_fr(r, "base64 encode signature");
70
0
    goto out;
71
0
  }
72
73
0
  if ((r = sshbuf_put(buf, END_SIGNATURE,
74
0
      sizeof(END_SIGNATURE)-1)) != 0 ||
75
0
      (r = sshbuf_put_u8(buf, '\n')) != 0) {
76
0
    error_fr(r, "sshbuf_put");
77
0
    goto out;
78
0
  }
79
  /* success */
80
0
  *out = buf;
81
0
  buf = NULL; /* transferred */
82
0
  r = 0;
83
0
 out:
84
0
  sshbuf_free(buf);
85
0
  return r;
86
0
}
87
88
int
89
sshsig_dearmor(struct sshbuf *sig, struct sshbuf **out)
90
0
{
91
0
  int r;
92
0
  size_t eoffset = 0;
93
0
  struct sshbuf *buf = NULL;
94
0
  struct sshbuf *sbuf = NULL;
95
0
  char *b64 = NULL;
96
97
0
  if ((sbuf = sshbuf_fromb(sig)) == NULL) {
98
0
    error_f("sshbuf_fromb failed");
99
0
    return SSH_ERR_ALLOC_FAIL;
100
0
  }
101
102
0
  if ((r = sshbuf_cmp(sbuf, 0,
103
0
      BEGIN_SIGNATURE, sizeof(BEGIN_SIGNATURE)-1)) != 0) {
104
0
    error("Couldn't parse signature: missing header");
105
0
    goto done;
106
0
  }
107
108
0
  if ((r = sshbuf_consume(sbuf, sizeof(BEGIN_SIGNATURE)-1)) != 0) {
109
0
    error_fr(r, "consume");
110
0
    goto done;
111
0
  }
112
113
0
  if ((r = sshbuf_find(sbuf, 0, "\n" END_SIGNATURE,
114
0
      sizeof("\n" END_SIGNATURE)-1, &eoffset)) != 0) {
115
0
    error("Couldn't parse signature: missing footer");
116
0
    goto done;
117
0
  }
118
119
0
  if ((r = sshbuf_consume_end(sbuf, sshbuf_len(sbuf)-eoffset)) != 0) {
120
0
    error_fr(r, "consume");
121
0
    goto done;
122
0
  }
123
124
0
  if ((b64 = sshbuf_dup_string(sbuf)) == NULL) {
125
0
    error_f("sshbuf_dup_string failed");
126
0
    r = SSH_ERR_ALLOC_FAIL;
127
0
    goto done;
128
0
  }
129
130
0
  if ((buf = sshbuf_new()) == NULL) {
131
0
    error_f("sshbuf_new() failed");
132
0
    r = SSH_ERR_ALLOC_FAIL;
133
0
    goto done;
134
0
  }
135
136
0
  if ((r = sshbuf_b64tod(buf, b64)) != 0) {
137
0
    error_fr(r, "decode base64");
138
0
    goto done;
139
0
  }
140
141
  /* success */
142
0
  *out = buf;
143
0
  r = 0;
144
0
  buf = NULL; /* transferred */
145
0
done:
146
0
  sshbuf_free(buf);
147
0
  sshbuf_free(sbuf);
148
0
  free(b64);
149
0
  return r;
150
0
}
151
152
static int
153
sshsig_wrap_sign(struct sshkey *key, const char *hashalg,
154
    const char *sk_provider, const char *sk_pin, const struct sshbuf *h_message,
155
    const char *sig_namespace, struct sshbuf **out,
156
    sshsig_signer *signer, void *signer_ctx)
157
0
{
158
0
  int r;
159
0
  size_t slen = 0;
160
0
  u_char *sig = NULL;
161
0
  struct sshbuf *blob = NULL;
162
0
  struct sshbuf *tosign = NULL;
163
0
  const char *sign_alg = NULL;
164
165
0
  if ((tosign = sshbuf_new()) == NULL ||
166
0
      (blob = sshbuf_new()) == NULL) {
167
0
    error_f("sshbuf_new failed");
168
0
    r = SSH_ERR_ALLOC_FAIL;
169
0
    goto done;
170
0
  }
171
172
0
  if ((r = sshbuf_put(tosign, MAGIC_PREAMBLE, MAGIC_PREAMBLE_LEN)) != 0 ||
173
0
      (r = sshbuf_put_cstring(tosign, sig_namespace)) != 0 ||
174
0
      (r = sshbuf_put_string(tosign, NULL, 0)) != 0 || /* reserved */
175
0
      (r = sshbuf_put_cstring(tosign, hashalg)) != 0 ||
176
0
      (r = sshbuf_put_stringb(tosign, h_message)) != 0) {
177
0
    error_fr(r, "assemble message to sign");
178
0
    goto done;
179
0
  }
180
181
  /* If using RSA keys then default to a good signature algorithm */
182
0
  if (sshkey_type_plain(key->type) == KEY_RSA)
183
0
    sign_alg = RSA_SIGN_ALG;
184
185
0
  if (signer != NULL) {
186
0
    if ((r = signer(key, &sig, &slen,
187
0
        sshbuf_ptr(tosign), sshbuf_len(tosign),
188
0
        sign_alg, sk_provider, sk_pin, 0, signer_ctx)) != 0) {
189
0
      error_r(r, "Couldn't sign message (signer)");
190
0
      goto done;
191
0
    }
192
0
  } else {
193
0
    if ((r = sshkey_sign(key, &sig, &slen,
194
0
        sshbuf_ptr(tosign), sshbuf_len(tosign),
195
0
        sign_alg, sk_provider, sk_pin, 0)) != 0) {
196
0
      error_r(r, "Couldn't sign message");
197
0
      goto done;
198
0
    }
199
0
  }
200
201
0
  if ((r = sshbuf_put(blob, MAGIC_PREAMBLE, MAGIC_PREAMBLE_LEN)) != 0 ||
202
0
      (r = sshbuf_put_u32(blob, SIG_VERSION)) != 0 ||
203
0
      (r = sshkey_puts(key, blob)) != 0 ||
204
0
      (r = sshbuf_put_cstring(blob, sig_namespace)) != 0 ||
205
0
      (r = sshbuf_put_string(blob, NULL, 0)) != 0 || /* reserved */
206
0
      (r = sshbuf_put_cstring(blob, hashalg)) != 0 ||
207
0
      (r = sshbuf_put_string(blob, sig, slen)) != 0) {
208
0
    error_fr(r, "assemble signature object");
209
0
    goto done;
210
0
  }
211
212
0
  if (out != NULL) {
213
0
    *out = blob;
214
0
    blob = NULL;
215
0
  }
216
0
  r = 0;
217
0
done:
218
0
  free(sig);
219
0
  sshbuf_free(blob);
220
0
  sshbuf_free(tosign);
221
0
  return r;
222
0
}
223
224
/* Check preamble and version. */
225
static int
226
sshsig_parse_preamble(struct sshbuf *buf)
227
0
{
228
0
  int r = SSH_ERR_INTERNAL_ERROR;
229
0
  uint32_t sversion;
230
231
0
  if ((r = sshbuf_cmp(buf, 0, MAGIC_PREAMBLE, MAGIC_PREAMBLE_LEN)) != 0 ||
232
0
      (r = sshbuf_consume(buf, (sizeof(MAGIC_PREAMBLE)-1))) != 0 ||
233
0
      (r = sshbuf_get_u32(buf, &sversion)) != 0) {
234
0
    error("Couldn't verify signature: invalid format");
235
0
    return r;
236
0
  }
237
238
0
  if (sversion > SIG_VERSION) {
239
0
    error("Signature version %lu is larger than supported "
240
0
        "version %u", (unsigned long)sversion, SIG_VERSION);
241
0
    return SSH_ERR_INVALID_FORMAT;
242
0
  }
243
0
  return 0;
244
0
}
245
246
static int
247
sshsig_check_hashalg(const char *hashalg)
248
0
{
249
0
  if (hashalg == NULL ||
250
0
      match_pattern_list(hashalg, HASHALG_ALLOWED, 0) == 1)
251
0
    return 0;
252
0
  error_f("unsupported hash algorithm \"%.100s\"", hashalg);
253
0
  return SSH_ERR_SIGN_ALG_UNSUPPORTED;
254
0
}
255
256
static int
257
sshsig_peek_hashalg(struct sshbuf *signature, char **hashalgp)
258
0
{
259
0
  struct sshbuf *buf = NULL;
260
0
  char *hashalg = NULL;
261
0
  int r = SSH_ERR_INTERNAL_ERROR;
262
263
0
  if (hashalgp != NULL)
264
0
    *hashalgp = NULL;
265
0
  if ((buf = sshbuf_fromb(signature)) == NULL)
266
0
    return SSH_ERR_ALLOC_FAIL;
267
0
  if ((r = sshsig_parse_preamble(buf)) != 0)
268
0
    goto done;
269
0
  if ((r = sshbuf_get_string_direct(buf, NULL, NULL)) != 0 ||
270
0
      (r = sshbuf_get_string_direct(buf, NULL, NULL)) != 0 ||
271
0
      (r = sshbuf_get_string(buf, NULL, NULL)) != 0 ||
272
0
      (r = sshbuf_get_cstring(buf, &hashalg, NULL)) != 0 ||
273
0
      (r = sshbuf_get_string_direct(buf, NULL, NULL)) != 0) {
274
0
    error_fr(r, "parse signature object");
275
0
    goto done;
276
0
  }
277
278
  /* success */
279
0
  r = 0;
280
0
  *hashalgp = hashalg;
281
0
  hashalg = NULL;
282
0
 done:
283
0
  free(hashalg);
284
0
  sshbuf_free(buf);
285
0
  return r;
286
0
}
287
288
static int
289
sshsig_wrap_verify(struct sshbuf *signature, const char *hashalg,
290
    const struct sshbuf *h_message, const char *expect_namespace,
291
    struct sshkey **sign_keyp, struct sshkey_sig_details **sig_details)
292
0
{
293
0
  int r = SSH_ERR_INTERNAL_ERROR;
294
0
  struct sshbuf *buf = NULL, *toverify = NULL;
295
0
  struct sshkey *key = NULL;
296
0
  const u_char *sig;
297
0
  char *got_namespace = NULL, *sigtype = NULL, *sig_hashalg = NULL;
298
0
  size_t siglen;
299
300
0
  debug_f("verify message length %zu", sshbuf_len(h_message));
301
0
  if (sig_details != NULL)
302
0
    *sig_details = NULL;
303
0
  if (sign_keyp != NULL)
304
0
    *sign_keyp = NULL;
305
306
0
  if ((toverify = sshbuf_new()) == NULL) {
307
0
    error_f("sshbuf_new failed");
308
0
    r = SSH_ERR_ALLOC_FAIL;
309
0
    goto done;
310
0
  }
311
0
  if ((r = sshbuf_put(toverify, MAGIC_PREAMBLE,
312
0
      MAGIC_PREAMBLE_LEN)) != 0 ||
313
0
      (r = sshbuf_put_cstring(toverify, expect_namespace)) != 0 ||
314
0
      (r = sshbuf_put_string(toverify, NULL, 0)) != 0 || /* reserved */
315
0
      (r = sshbuf_put_cstring(toverify, hashalg)) != 0 ||
316
0
      (r = sshbuf_put_stringb(toverify, h_message)) != 0) {
317
0
    error_fr(r, "assemble message to verify");
318
0
    goto done;
319
0
  }
320
321
0
  if ((r = sshsig_parse_preamble(signature)) != 0)
322
0
    goto done;
323
324
0
  if ((r = sshkey_froms(signature, &key)) != 0 ||
325
0
      (r = sshbuf_get_cstring(signature, &got_namespace, NULL)) != 0 ||
326
0
      (r = sshbuf_get_string(signature, NULL, NULL)) != 0 ||
327
0
      (r = sshbuf_get_cstring(signature, &sig_hashalg, NULL)) != 0 ||
328
0
      (r = sshbuf_get_string_direct(signature, &sig, &siglen)) != 0) {
329
0
    error_fr(r, "parse signature object");
330
0
    goto done;
331
0
  }
332
333
0
  if (sshbuf_len(signature) != 0) {
334
0
    error("Signature contains trailing data");
335
0
    r = SSH_ERR_INVALID_FORMAT;
336
0
    goto done;
337
0
  }
338
339
0
  if (strcmp(expect_namespace, got_namespace) != 0) {
340
0
    error("Couldn't verify signature: namespace does not match");
341
0
    debug_f("expected namespace \"%s\" received \"%s\"",
342
0
        expect_namespace, got_namespace);
343
0
    r = SSH_ERR_SIGNATURE_INVALID;
344
0
    goto done;
345
0
  }
346
0
  if (strcmp(hashalg, sig_hashalg) != 0) {
347
0
    error("Couldn't verify signature: hash algorithm mismatch");
348
0
    debug_f("expected algorithm \"%s\" received \"%s\"",
349
0
        hashalg, sig_hashalg);
350
0
    r = SSH_ERR_SIGNATURE_INVALID;
351
0
    goto done;
352
0
  }
353
  /* Ensure that RSA keys use an acceptable signature algorithm */
354
0
  if (sshkey_type_plain(key->type) == KEY_RSA) {
355
0
    if ((r = sshkey_get_sigtype(sig, siglen, &sigtype)) != 0) {
356
0
      error_r(r, "Couldn't verify signature: unable to get "
357
0
          "signature type");
358
0
      goto done;
359
0
    }
360
0
    if (match_pattern_list(sigtype, RSA_SIGN_ALLOWED, 0) != 1) {
361
0
      error("Couldn't verify signature: unsupported RSA "
362
0
          "signature algorithm %s", sigtype);
363
0
      r = SSH_ERR_SIGN_ALG_UNSUPPORTED;
364
0
      goto done;
365
0
    }
366
0
  }
367
0
  if ((r = sshkey_verify(key, sig, siglen, sshbuf_ptr(toverify),
368
0
      sshbuf_len(toverify), NULL, 0, sig_details)) != 0) {
369
0
    error_r(r, "Signature verification failed");
370
0
    goto done;
371
0
  }
372
373
  /* success */
374
0
  r = 0;
375
0
  if (sign_keyp != NULL) {
376
0
    *sign_keyp = key;
377
0
    key = NULL; /* transferred */
378
0
  }
379
0
done:
380
0
  free(got_namespace);
381
0
  free(sigtype);
382
0
  free(sig_hashalg);
383
0
  sshbuf_free(buf);
384
0
  sshbuf_free(toverify);
385
0
  sshkey_free(key);
386
0
  return r;
387
0
}
388
389
static int
390
hash_buffer(const struct sshbuf *m, const char *hashalg, struct sshbuf **bp)
391
0
{
392
0
  char *hex, hash[SSH_DIGEST_MAX_LENGTH];
393
0
  int alg, r = SSH_ERR_INTERNAL_ERROR;
394
0
  struct sshbuf *b = NULL;
395
396
0
  *bp = NULL;
397
0
  memset(hash, 0, sizeof(hash));
398
399
0
  if ((r = sshsig_check_hashalg(hashalg)) != 0)
400
0
    return r;
401
0
  if ((alg = ssh_digest_alg_by_name(hashalg)) == -1) {
402
0
    error_f("can't look up hash algorithm %s", hashalg);
403
0
    return SSH_ERR_INTERNAL_ERROR;
404
0
  }
405
0
  if ((r = ssh_digest_buffer(alg, m, hash, sizeof(hash))) != 0) {
406
0
    error_fr(r, "ssh_digest_buffer");
407
0
    return r;
408
0
  }
409
0
  if ((hex = tohex(hash, ssh_digest_bytes(alg))) != NULL) {
410
0
    debug3_f("final hash: %s", hex);
411
0
    freezero(hex, strlen(hex));
412
0
  }
413
0
  if ((b = sshbuf_new()) == NULL) {
414
0
    r = SSH_ERR_ALLOC_FAIL;
415
0
    goto out;
416
0
  }
417
0
  if ((r = sshbuf_put(b, hash, ssh_digest_bytes(alg))) != 0) {
418
0
    error_fr(r, "sshbuf_put");
419
0
    goto out;
420
0
  }
421
0
  *bp = b;
422
0
  b = NULL; /* transferred */
423
  /* success */
424
0
  r = 0;
425
0
 out:
426
0
  sshbuf_free(b);
427
0
  explicit_bzero(hash, sizeof(hash));
428
0
  return r;
429
0
}
430
431
int
432
sshsig_signb(struct sshkey *key, const char *hashalg,
433
    const char *sk_provider, const char *sk_pin,
434
    const struct sshbuf *message, const char *sig_namespace,
435
    struct sshbuf **out, sshsig_signer *signer, void *signer_ctx)
436
0
{
437
0
  struct sshbuf *b = NULL;
438
0
  int r = SSH_ERR_INTERNAL_ERROR;
439
440
0
  if (hashalg == NULL)
441
0
    hashalg = HASHALG_DEFAULT;
442
0
  if (out != NULL)
443
0
    *out = NULL;
444
0
  if ((r = hash_buffer(message, hashalg, &b)) != 0) {
445
0
    error_fr(r, "hash buffer");
446
0
    goto out;
447
0
  }
448
0
  if ((r = sshsig_wrap_sign(key, hashalg, sk_provider, sk_pin, b,
449
0
      sig_namespace, out, signer, signer_ctx)) != 0)
450
0
    goto out;
451
  /* success */
452
0
  r = 0;
453
0
 out:
454
0
  sshbuf_free(b);
455
0
  return r;
456
0
}
457
458
int
459
sshsig_verifyb(struct sshbuf *signature, const struct sshbuf *message,
460
    const char *expect_namespace, struct sshkey **sign_keyp,
461
    struct sshkey_sig_details **sig_details)
462
0
{
463
0
  struct sshbuf *b = NULL;
464
0
  int r = SSH_ERR_INTERNAL_ERROR;
465
0
  char *hashalg = NULL;
466
467
0
  if (sig_details != NULL)
468
0
    *sig_details = NULL;
469
0
  if (sign_keyp != NULL)
470
0
    *sign_keyp = NULL;
471
0
  if ((r = sshsig_peek_hashalg(signature, &hashalg)) != 0)
472
0
    return r;
473
0
  debug_f("signature made with hash \"%s\"", hashalg);
474
0
  if ((r = hash_buffer(message, hashalg, &b)) != 0) {
475
0
    error_fr(r, "hash buffer");
476
0
    goto out;
477
0
  }
478
0
  if ((r = sshsig_wrap_verify(signature, hashalg, b, expect_namespace,
479
0
      sign_keyp, sig_details)) != 0)
480
0
    goto out;
481
  /* success */
482
0
  r = 0;
483
0
 out:
484
0
  sshbuf_free(b);
485
0
  free(hashalg);
486
0
  return r;
487
0
}
488
489
static int
490
hash_file(int fd, const char *hashalg, struct sshbuf **bp)
491
0
{
492
0
  char *hex, rbuf[8192], hash[SSH_DIGEST_MAX_LENGTH];
493
0
  ssize_t n, total = 0;
494
0
  struct ssh_digest_ctx *ctx = NULL;
495
0
  int alg, oerrno, r = SSH_ERR_INTERNAL_ERROR;
496
0
  struct sshbuf *b = NULL;
497
498
0
  *bp = NULL;
499
0
  memset(hash, 0, sizeof(hash));
500
501
0
  if ((r = sshsig_check_hashalg(hashalg)) != 0)
502
0
    return r;
503
0
  if ((alg = ssh_digest_alg_by_name(hashalg)) == -1) {
504
0
    error_f("can't look up hash algorithm %s", hashalg);
505
0
    return SSH_ERR_INTERNAL_ERROR;
506
0
  }
507
0
  if ((ctx = ssh_digest_start(alg)) == NULL) {
508
0
    error_f("ssh_digest_start failed");
509
0
    return SSH_ERR_INTERNAL_ERROR;
510
0
  }
511
0
  for (;;) {
512
0
    if ((n = read(fd, rbuf, sizeof(rbuf))) == -1) {
513
0
      if (errno == EINTR || errno == EAGAIN)
514
0
        continue;
515
0
      oerrno = errno;
516
0
      error_f("read: %s", strerror(errno));
517
0
      errno = oerrno;
518
0
      r = SSH_ERR_SYSTEM_ERROR;
519
0
      goto out;
520
0
    } else if (n == 0) {
521
0
      debug2_f("hashed %zu bytes", total);
522
0
      break; /* EOF */
523
0
    }
524
0
    total += (size_t)n;
525
0
    if ((r = ssh_digest_update(ctx, rbuf, (size_t)n)) != 0) {
526
0
      error_fr(r, "ssh_digest_update");
527
0
      goto out;
528
0
    }
529
0
  }
530
0
  if ((r = ssh_digest_final(ctx, hash, sizeof(hash))) != 0) {
531
0
    error_fr(r, "ssh_digest_final");
532
0
    goto out;
533
0
  }
534
0
  if ((hex = tohex(hash, ssh_digest_bytes(alg))) != NULL) {
535
0
    debug3_f("final hash: %s", hex);
536
0
    freezero(hex, strlen(hex));
537
0
  }
538
0
  if ((b = sshbuf_new()) == NULL) {
539
0
    r = SSH_ERR_ALLOC_FAIL;
540
0
    goto out;
541
0
  }
542
0
  if ((r = sshbuf_put(b, hash, ssh_digest_bytes(alg))) != 0) {
543
0
    error_fr(r, "sshbuf_put");
544
0
    goto out;
545
0
  }
546
0
  *bp = b;
547
0
  b = NULL; /* transferred */
548
  /* success */
549
0
  r = 0;
550
0
 out:
551
0
  oerrno = errno;
552
0
  sshbuf_free(b);
553
0
  ssh_digest_free(ctx);
554
0
  explicit_bzero(hash, sizeof(hash));
555
0
  errno = oerrno;
556
0
  return r;
557
0
}
558
559
int
560
sshsig_sign_fd(struct sshkey *key, const char *hashalg,
561
    const char *sk_provider, const char *sk_pin,
562
    int fd, const char *sig_namespace, struct sshbuf **out,
563
    sshsig_signer *signer, void *signer_ctx)
564
0
{
565
0
  struct sshbuf *b = NULL;
566
0
  int r = SSH_ERR_INTERNAL_ERROR;
567
568
0
  if (hashalg == NULL)
569
0
    hashalg = HASHALG_DEFAULT;
570
0
  if (out != NULL)
571
0
    *out = NULL;
572
0
  if ((r = hash_file(fd, hashalg, &b)) != 0) {
573
0
    error_fr(r, "hash_file");
574
0
    return r;
575
0
  }
576
0
  if ((r = sshsig_wrap_sign(key, hashalg, sk_provider, sk_pin, b,
577
0
      sig_namespace, out, signer, signer_ctx)) != 0)
578
0
    goto out;
579
  /* success */
580
0
  r = 0;
581
0
 out:
582
0
  sshbuf_free(b);
583
0
  return r;
584
0
}
585
586
int
587
sshsig_verify_fd(struct sshbuf *signature, int fd,
588
    const char *expect_namespace, struct sshkey **sign_keyp,
589
    struct sshkey_sig_details **sig_details)
590
0
{
591
0
  struct sshbuf *b = NULL;
592
0
  int r = SSH_ERR_INTERNAL_ERROR;
593
0
  char *hashalg = NULL;
594
595
0
  if (sig_details != NULL)
596
0
    *sig_details = NULL;
597
0
  if (sign_keyp != NULL)
598
0
    *sign_keyp = NULL;
599
0
  if ((r = sshsig_peek_hashalg(signature, &hashalg)) != 0)
600
0
    return r;
601
0
  debug_f("signature made with hash \"%s\"", hashalg);
602
0
  if ((r = hash_file(fd, hashalg, &b)) != 0) {
603
0
    error_fr(r, "hash_file");
604
0
    goto out;
605
0
  }
606
0
  if ((r = sshsig_wrap_verify(signature, hashalg, b, expect_namespace,
607
0
      sign_keyp, sig_details)) != 0)
608
0
    goto out;
609
  /* success */
610
0
  r = 0;
611
0
 out:
612
0
  sshbuf_free(b);
613
0
  free(hashalg);
614
0
  return r;
615
0
}
616
617
struct sshsigopt {
618
  int ca;
619
  char *namespaces;
620
  uint64_t valid_after, valid_before;
621
};
622
623
struct sshsigopt *
624
sshsigopt_parse(const char *opts, const char *path, u_long linenum,
625
    const char **errstrp)
626
832
{
627
832
  struct sshsigopt *ret;
628
832
  int r;
629
832
  char *opt;
630
832
  const char *errstr = NULL;
631
632
832
  if ((ret = calloc(1, sizeof(*ret))) == NULL)
633
0
    return NULL;
634
832
  if (opts == NULL || *opts == '\0')
635
1
    return ret; /* Empty options yields empty options :) */
636
637
1.62k
  while (*opts && *opts != ' ' && *opts != '\t') {
638
    /* flag options */
639
1.62k
    if ((r = opt_flag("cert-authority", 0, &opts)) != -1) {
640
194
      ret->ca = 1;
641
1.42k
    } else if (opt_match(&opts, "namespaces")) {
642
75
      if (ret->namespaces != NULL) {
643
3
        errstr = "multiple \"namespaces\" clauses";
644
3
        goto fail;
645
3
      }
646
72
      ret->namespaces = opt_dequote(&opts, &errstr);
647
72
      if (ret->namespaces == NULL)
648
62
        goto fail;
649
1.35k
    } else if (opt_match(&opts, "valid-after")) {
650
436
      if (ret->valid_after != 0) {
651
37
        errstr = "multiple \"valid-after\" clauses";
652
37
        goto fail;
653
37
      }
654
399
      if ((opt = opt_dequote(&opts, &errstr)) == NULL)
655
2
        goto fail;
656
397
      if (parse_absolute_time(opt, &ret->valid_after) != 0 ||
657
397
          ret->valid_after == 0) {
658
204
        free(opt);
659
204
        errstr = "invalid \"valid-after\" time";
660
204
        goto fail;
661
204
      }
662
193
      free(opt);
663
915
    } else if (opt_match(&opts, "valid-before")) {
664
205
      if (ret->valid_before != 0) {
665
37
        errstr = "multiple \"valid-before\" clauses";
666
37
        goto fail;
667
37
      }
668
168
      if ((opt = opt_dequote(&opts, &errstr)) == NULL)
669
2
        goto fail;
670
166
      if (parse_absolute_time(opt, &ret->valid_before) != 0 ||
671
166
          ret->valid_before == 0) {
672
5
        free(opt);
673
5
        errstr = "invalid \"valid-before\" time";
674
5
        goto fail;
675
5
      }
676
161
      free(opt);
677
161
    }
678
    /*
679
     * Skip the comma, and move to the next option
680
     * (or break out if there are no more).
681
     */
682
1.26k
    if (*opts == '\0' || *opts == ' ' || *opts == '\t')
683
198
      break;    /* End of options. */
684
    /* Anything other than a comma is an unknown option */
685
1.07k
    if (*opts != ',') {
686
271
      errstr = "unknown key option";
687
271
      goto fail;
688
271
    }
689
799
    opts++;
690
799
    if (*opts == '\0') {
691
8
      errstr = "unexpected end-of-options";
692
8
      goto fail;
693
8
    }
694
799
  }
695
  /* final consistency check */
696
200
  if (ret->valid_after != 0 && ret->valid_before != 0 &&
697
200
      ret->valid_before <= ret->valid_after) {
698
18
    errstr = "\"valid-before\" time is before \"valid-after\"";
699
18
    goto fail;
700
18
  }
701
  /* success */
702
182
  return ret;
703
649
 fail:
704
649
  if (errstrp != NULL)
705
0
    *errstrp = errstr;
706
649
  sshsigopt_free(ret);
707
649
  return NULL;
708
200
}
709
710
void
711
sshsigopt_free(struct sshsigopt *opts)
712
1.48k
{
713
1.48k
  if (opts == NULL)
714
649
    return;
715
832
  free(opts->namespaces);
716
832
  free(opts);
717
832
}
718
719
static int
720
parse_principals_key_and_options(const char *path, u_long linenum, char *line,
721
    const char *required_principal, char **principalsp, struct sshkey **keyp,
722
    struct sshsigopt **sigoptsp)
723
0
{
724
0
  char *opts = NULL, *tmp, *cp, *principals = NULL;
725
0
  const char *reason = NULL;
726
0
  struct sshsigopt *sigopts = NULL;
727
0
  struct sshkey *key = NULL;
728
0
  int r = SSH_ERR_INTERNAL_ERROR;
729
730
0
  if (principalsp != NULL)
731
0
    *principalsp = NULL;
732
0
  if (sigoptsp != NULL)
733
0
    *sigoptsp = NULL;
734
0
  if (keyp != NULL)
735
0
    *keyp = NULL;
736
737
0
  cp = line;
738
0
  cp = cp + strspn(cp, " \t"); /* skip leading whitespace */
739
0
  if (*cp == '#' || *cp == '\0')
740
0
    return SSH_ERR_KEY_NOT_FOUND; /* blank or all-comment line */
741
742
  /* format: identity[,identity...] [option[,option...]] key */
743
0
  if ((tmp = strdelimw(&cp)) == NULL || cp == NULL) {
744
0
    error("%s:%lu: invalid line", path, linenum);
745
0
    r = SSH_ERR_INVALID_FORMAT;
746
0
    goto out;
747
0
  }
748
0
  if ((principals = strdup(tmp)) == NULL) {
749
0
    error_f("strdup failed");
750
0
    r = SSH_ERR_ALLOC_FAIL;
751
0
    goto out;
752
0
  }
753
  /*
754
   * Bail out early if we're looking for a particular principal and this
755
   * line does not list it.
756
   */
757
0
  if (required_principal != NULL) {
758
0
    if (match_pattern_list(required_principal,
759
0
        principals, 0) != 1) {
760
      /* principal didn't match */
761
0
      r = SSH_ERR_KEY_NOT_FOUND;
762
0
      goto out;
763
0
    }
764
0
    debug_f("%s:%lu: matched principal \"%s\"",
765
0
        path, linenum, required_principal);
766
0
  }
767
768
0
  if ((key = sshkey_new(KEY_UNSPEC)) == NULL) {
769
0
    error_f("sshkey_new failed");
770
0
    r = SSH_ERR_ALLOC_FAIL;
771
0
    goto out;
772
0
  }
773
0
  if (sshkey_read(key, &cp) != 0) {
774
    /* no key? Check for options */
775
0
    opts = cp;
776
0
    if (sshkey_advance_past_options(&cp) != 0) {
777
0
      error("%s:%lu: invalid options", path, linenum);
778
0
      r = SSH_ERR_INVALID_FORMAT;
779
0
      goto out;
780
0
    }
781
0
    if (cp == NULL || *cp == '\0') {
782
0
      error("%s:%lu: missing key", path, linenum);
783
0
      r = SSH_ERR_INVALID_FORMAT;
784
0
      goto out;
785
0
    }
786
0
    *cp++ = '\0';
787
0
    skip_space(&cp);
788
0
    if (sshkey_read(key, &cp) != 0) {
789
0
      error("%s:%lu: invalid key", path, linenum);
790
0
      r = SSH_ERR_INVALID_FORMAT;
791
0
      goto out;
792
0
    }
793
0
  }
794
0
  debug3("%s:%lu: options %s", path, linenum, opts == NULL ? "" : opts);
795
0
  if ((sigopts = sshsigopt_parse(opts, path, linenum, &reason)) == NULL) {
796
0
    error("%s:%lu: bad options: %s", path, linenum, reason);
797
0
    r = SSH_ERR_INVALID_FORMAT;
798
0
    goto out;
799
0
  }
800
  /* success */
801
0
  if (principalsp != NULL) {
802
0
    *principalsp = principals;
803
0
    principals = NULL; /* transferred */
804
0
  }
805
0
  if (sigoptsp != NULL) {
806
0
    *sigoptsp = sigopts;
807
0
    sigopts = NULL; /* transferred */
808
0
  }
809
0
  if (keyp != NULL) {
810
0
    *keyp = key;
811
0
    key = NULL; /* transferred */
812
0
  }
813
0
  r = 0;
814
0
 out:
815
0
  free(principals);
816
0
  sshsigopt_free(sigopts);
817
0
  sshkey_free(key);
818
0
  return r;
819
0
}
820
821
static int
822
cert_filter_principals(const char *path, u_long linenum,
823
    char **principalsp, const struct sshkey *cert, uint64_t verify_time)
824
0
{
825
0
  char *cp, *oprincipals, *principals;
826
0
  const char *reason;
827
0
  struct sshbuf *nprincipals;
828
0
  int r = SSH_ERR_INTERNAL_ERROR, success = 0;
829
0
  u_int i;
830
831
0
  oprincipals = principals = *principalsp;
832
0
  *principalsp = NULL;
833
834
0
  if ((nprincipals = sshbuf_new()) == NULL) {
835
0
    r = SSH_ERR_ALLOC_FAIL;
836
0
    goto out;
837
0
  }
838
839
0
  while ((cp = strsep(&principals, ",")) != NULL && *cp != '\0') {
840
    /* Check certificate validity */
841
0
    if ((r = sshkey_cert_check_authority(cert, 0, 1, 0,
842
0
        verify_time, NULL, &reason)) != 0) {
843
0
      debug("%s:%lu: principal \"%s\" not authorized: %s",
844
0
          path, linenum, cp, reason);
845
0
      continue;
846
0
    }
847
    /* Return all matching principal names from the cert */
848
0
    for (i = 0; i < cert->cert->nprincipals; i++) {
849
0
      if (match_pattern(cert->cert->principals[i], cp)) {
850
0
        if ((r = sshbuf_putf(nprincipals, "%s%s",
851
0
          sshbuf_len(nprincipals) != 0 ? "," : "",
852
0
            cert->cert->principals[i])) != 0) {
853
0
          error_f("buffer error");
854
0
          goto out;
855
0
        }
856
0
      }
857
0
    }
858
0
  }
859
0
  if (sshbuf_len(nprincipals) == 0) {
860
0
    error("%s:%lu: no valid principals found", path, linenum);
861
0
    r = SSH_ERR_KEY_CERT_INVALID;
862
0
    goto out;
863
0
  }
864
0
  if ((principals = sshbuf_dup_string(nprincipals)) == NULL) {
865
0
    error_f("buffer error");
866
0
    goto out;
867
0
  }
868
  /* success */
869
0
  success = 1;
870
0
  *principalsp = principals;
871
0
 out:
872
0
  sshbuf_free(nprincipals);
873
0
  free(oprincipals);
874
0
  return success ? 0 : r;
875
0
}
876
877
static int
878
check_allowed_keys_line(const char *path, u_long linenum, char *line,
879
    const struct sshkey *sign_key, const char *principal,
880
    const char *sig_namespace, uint64_t verify_time, char **principalsp)
881
0
{
882
0
  struct sshkey *found_key = NULL;
883
0
  char *principals = NULL;
884
0
  int r, success = 0;
885
0
  const char *reason = NULL;
886
0
  struct sshsigopt *sigopts = NULL;
887
0
  char tvalid[64], tverify[64];
888
889
0
  if (principalsp != NULL)
890
0
    *principalsp = NULL;
891
892
  /* Parse the line */
893
0
  if ((r = parse_principals_key_and_options(path, linenum, line,
894
0
      principal, &principals, &found_key, &sigopts)) != 0) {
895
    /* error already logged */
896
0
    goto done;
897
0
  }
898
899
0
  if (!sigopts->ca && sshkey_equal(found_key, sign_key)) {
900
    /* Exact match of key */
901
0
    debug("%s:%lu: matched key", path, linenum);
902
0
  } else if (sigopts->ca && sshkey_is_cert(sign_key) &&
903
0
      sshkey_equal_public(sign_key->cert->signature_key, found_key)) {
904
0
    if (principal) {
905
      /* Match certificate CA key with specified principal */
906
0
      if ((r = sshkey_cert_check_authority(sign_key, 0, 1, 0,
907
0
          verify_time, principal, &reason)) != 0) {
908
0
        error("%s:%lu: certificate not authorized: %s",
909
0
            path, linenum, reason);
910
0
        goto done;
911
0
      }
912
0
      debug("%s:%lu: matched certificate CA key",
913
0
          path, linenum);
914
0
    } else {
915
      /* No principal specified - find all matching ones */
916
0
      if ((r = cert_filter_principals(path, linenum,
917
0
          &principals, sign_key, verify_time)) != 0) {
918
        /* error already displayed */
919
0
        debug_r(r, "%s:%lu: cert_filter_principals",
920
0
            path, linenum);
921
0
        goto done;
922
0
      }
923
0
      debug("%s:%lu: matched certificate CA key",
924
0
          path, linenum);
925
0
    }
926
0
  } else {
927
    /* Didn't match key */
928
0
    goto done;
929
0
  }
930
931
  /* Check whether options preclude the use of this key */
932
0
  if (sigopts->namespaces != NULL && sig_namespace != NULL &&
933
0
      match_pattern_list(sig_namespace, sigopts->namespaces, 0) != 1) {
934
0
    error("%s:%lu: key is not permitted for use in signature "
935
0
        "namespace \"%s\"", path, linenum, sig_namespace);
936
0
    goto done;
937
0
  }
938
939
  /* check key time validity */
940
0
  format_absolute_time((uint64_t)verify_time, tverify, sizeof(tverify));
941
0
  if (sigopts->valid_after != 0 &&
942
0
      (uint64_t)verify_time < sigopts->valid_after) {
943
0
    format_absolute_time(sigopts->valid_after,
944
0
        tvalid, sizeof(tvalid));
945
0
    error("%s:%lu: key is not yet valid: "
946
0
        "verify time %s < valid-after %s", path, linenum,
947
0
        tverify, tvalid);
948
0
    goto done;
949
0
  }
950
0
  if (sigopts->valid_before != 0 &&
951
0
      (uint64_t)verify_time > sigopts->valid_before) {
952
0
    format_absolute_time(sigopts->valid_before,
953
0
        tvalid, sizeof(tvalid));
954
0
    error("%s:%lu: key has expired: "
955
0
        "verify time %s > valid-before %s", path, linenum,
956
0
        tverify, tvalid);
957
0
    goto done;
958
0
  }
959
0
  success = 1;
960
961
0
 done:
962
0
  if (success && principalsp != NULL) {
963
0
    *principalsp = principals;
964
0
    principals = NULL; /* transferred */
965
0
  }
966
0
  free(principals);
967
0
  sshkey_free(found_key);
968
0
  sshsigopt_free(sigopts);
969
0
  return success ? 0 : SSH_ERR_KEY_NOT_FOUND;
970
0
}
971
972
int
973
sshsig_check_allowed_keys(const char *path, const struct sshkey *sign_key,
974
    const char *principal, const char *sig_namespace, uint64_t verify_time)
975
0
{
976
0
  FILE *f = NULL;
977
0
  char *line = NULL;
978
0
  size_t linesize = 0;
979
0
  u_long linenum = 0;
980
0
  int r = SSH_ERR_KEY_NOT_FOUND, oerrno;
981
982
  /* Check key and principal against file */
983
0
  if ((f = fopen(path, "r")) == NULL) {
984
0
    oerrno = errno;
985
0
    error("Unable to open allowed keys file \"%s\": %s",
986
0
        path, strerror(errno));
987
0
    errno = oerrno;
988
0
    return SSH_ERR_SYSTEM_ERROR;
989
0
  }
990
991
0
  while (getline(&line, &linesize, f) != -1) {
992
0
    linenum++;
993
0
    r = check_allowed_keys_line(path, linenum, line, sign_key,
994
0
        principal, sig_namespace, verify_time, NULL);
995
0
    free(line);
996
0
    line = NULL;
997
0
    linesize = 0;
998
0
    if (r == SSH_ERR_KEY_NOT_FOUND)
999
0
      continue;
1000
0
    else if (r == 0) {
1001
      /* success */
1002
0
      fclose(f);
1003
0
      return 0;
1004
0
    } else
1005
0
      break;
1006
0
  }
1007
  /* Either we hit an error parsing or we simply didn't find the key */
1008
0
  fclose(f);
1009
0
  free(line);
1010
0
  return r;
1011
0
}
1012
1013
int
1014
sshsig_find_principals(const char *path, const struct sshkey *sign_key,
1015
    uint64_t verify_time, char **principals)
1016
0
{
1017
0
  FILE *f = NULL;
1018
0
  char *line = NULL;
1019
0
  size_t linesize = 0;
1020
0
  u_long linenum = 0;
1021
0
  int r = SSH_ERR_KEY_NOT_FOUND, oerrno;
1022
1023
0
  if ((f = fopen(path, "r")) == NULL) {
1024
0
    oerrno = errno;
1025
0
    error("Unable to open allowed keys file \"%s\": %s",
1026
0
        path, strerror(errno));
1027
0
    errno = oerrno;
1028
0
    return SSH_ERR_SYSTEM_ERROR;
1029
0
  }
1030
1031
0
  while (getline(&line, &linesize, f) != -1) {
1032
0
    linenum++;
1033
0
    r = check_allowed_keys_line(path, linenum, line,
1034
0
        sign_key, NULL, NULL, verify_time, principals);
1035
0
    free(line);
1036
0
    line = NULL;
1037
0
    linesize = 0;
1038
0
    if (r == SSH_ERR_KEY_NOT_FOUND)
1039
0
      continue;
1040
0
    else if (r == 0) {
1041
      /* success */
1042
0
      fclose(f);
1043
0
      return 0;
1044
0
    } else
1045
0
      break;
1046
0
  }
1047
0
  free(line);
1048
  /* Either we hit an error parsing or we simply didn't find the key */
1049
0
  if (ferror(f) != 0) {
1050
0
    oerrno = errno;
1051
0
    fclose(f);
1052
0
    error("Unable to read allowed keys file \"%s\": %s",
1053
0
        path, strerror(errno));
1054
0
    errno = oerrno;
1055
0
    return SSH_ERR_SYSTEM_ERROR;
1056
0
  }
1057
0
  fclose(f);
1058
0
  return r;
1059
0
}
1060
1061
int
1062
sshsig_match_principals(const char *path, const char *principal,
1063
    char ***principalsp, size_t *nprincipalsp)
1064
0
{
1065
0
  FILE *f = NULL;
1066
0
  char *found, *line = NULL, **principals = NULL, **tmp;
1067
0
  size_t i, nprincipals = 0, linesize = 0;
1068
0
  u_long linenum = 0;
1069
0
  int oerrno = 0, r, ret = 0;
1070
1071
0
  if (principalsp != NULL)
1072
0
    *principalsp = NULL;
1073
0
  if (nprincipalsp != NULL)
1074
0
    *nprincipalsp = 0;
1075
1076
  /* Check key and principal against file */
1077
0
  if ((f = fopen(path, "r")) == NULL) {
1078
0
    oerrno = errno;
1079
0
    error("Unable to open allowed keys file \"%s\": %s",
1080
0
        path, strerror(errno));
1081
0
    errno = oerrno;
1082
0
    return SSH_ERR_SYSTEM_ERROR;
1083
0
  }
1084
1085
0
  while (getline(&line, &linesize, f) != -1) {
1086
0
    linenum++;
1087
    /* Parse the line */
1088
0
    if ((r = parse_principals_key_and_options(path, linenum, line,
1089
0
        principal, &found, NULL, NULL)) != 0) {
1090
0
      if (r == SSH_ERR_KEY_NOT_FOUND)
1091
0
        continue;
1092
0
      ret = r;
1093
0
      oerrno = errno;
1094
0
      break; /* unexpected error */
1095
0
    }
1096
0
    if ((tmp = recallocarray(principals, nprincipals,
1097
0
        nprincipals + 1, sizeof(*principals))) == NULL) {
1098
0
      ret = SSH_ERR_ALLOC_FAIL;
1099
0
      free(found);
1100
0
      break;
1101
0
    }
1102
0
    principals = tmp;
1103
0
    principals[nprincipals++] = found; /* transferred */
1104
0
    free(line);
1105
0
    line = NULL;
1106
0
    linesize = 0;
1107
0
  }
1108
0
  fclose(f);
1109
1110
0
  if (ret == 0) {
1111
0
    if (nprincipals == 0)
1112
0
      ret = SSH_ERR_KEY_NOT_FOUND;
1113
0
    if (principalsp != NULL) {
1114
0
      *principalsp = principals;
1115
0
      principals = NULL; /* transferred */
1116
0
    }
1117
0
    if (nprincipalsp != 0) {
1118
0
      *nprincipalsp = nprincipals;
1119
0
      nprincipals = 0;
1120
0
    }
1121
0
  }
1122
1123
0
  for (i = 0; i < nprincipals; i++)
1124
0
    free(principals[i]);
1125
0
  free(principals);
1126
1127
0
  errno = oerrno;
1128
0
  return ret;
1129
0
}
1130
1131
int
1132
sshsig_get_pubkey(struct sshbuf *signature, struct sshkey **pubkey)
1133
0
{
1134
0
  struct sshkey *pk = NULL;
1135
0
  int r = SSH_ERR_SIGNATURE_INVALID;
1136
1137
0
  if (pubkey == NULL)
1138
0
    return SSH_ERR_INTERNAL_ERROR;
1139
0
  if ((r = sshsig_parse_preamble(signature)) != 0)
1140
0
    return r;
1141
0
  if ((r = sshkey_froms(signature, &pk)) != 0)
1142
0
    return r;
1143
1144
0
  *pubkey = pk;
1145
0
  pk = NULL;
1146
0
  return 0;
1147
0
}