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