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