1 /* $OpenBSD: sshsig.c,v 1.37 2024/11/26 22:05:51 djm Exp $ */
3 * Copyright (c) 2019 Google LLC
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.
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.
38 #define SIG_VERSION 0x01
39 #define MAGIC_PREAMBLE "SSHSIG"
40 #define MAGIC_PREAMBLE_LEN (sizeof(MAGIC_PREAMBLE) - 1)
41 #define BEGIN_SIGNATURE "-----BEGIN SSH SIGNATURE-----"
42 #define END_SIGNATURE "-----END SSH SIGNATURE-----"
43 #define RSA_SIGN_ALG "rsa-sha2-512"
44 #define RSA_SIGN_ALLOWED "rsa-sha2-512,rsa-sha2-256"
45 #define HASHALG_DEFAULT "sha512"
46 #define HASHALG_ALLOWED "sha256,sha512"
49 sshsig_armor(const struct sshbuf
*blob
, struct sshbuf
**out
)
51 struct sshbuf
*buf
= NULL
;
52 int r
= SSH_ERR_INTERNAL_ERROR
;
56 if ((buf
= sshbuf_new()) == NULL
) {
57 error_f("sshbuf_new failed");
58 r
= SSH_ERR_ALLOC_FAIL
;
62 if ((r
= sshbuf_putf(buf
, "%s\n", BEGIN_SIGNATURE
)) != 0) {
63 error_fr(r
, "sshbuf_putf");
67 if ((r
= sshbuf_dtob64(blob
, buf
, 1)) != 0) {
68 error_fr(r
, "base64 encode signature");
72 if ((r
= sshbuf_put(buf
, END_SIGNATURE
,
73 sizeof(END_SIGNATURE
)-1)) != 0 ||
74 (r
= sshbuf_put_u8(buf
, '\n')) != 0) {
75 error_fr(r
, "sshbuf_put");
80 buf
= NULL
; /* transferred */
88 sshsig_dearmor(struct sshbuf
*sig
, struct sshbuf
**out
)
92 struct sshbuf
*buf
= NULL
;
93 struct sshbuf
*sbuf
= NULL
;
96 if ((sbuf
= sshbuf_fromb(sig
)) == NULL
) {
97 error_f("sshbuf_fromb failed");
98 return SSH_ERR_ALLOC_FAIL
;
101 /* Expect and consume preamble + lf/crlf */
102 if ((r
= sshbuf_cmp(sbuf
, 0,
103 BEGIN_SIGNATURE
, sizeof(BEGIN_SIGNATURE
)-1)) != 0) {
104 error("Couldn't parse signature: missing header");
107 if ((r
= sshbuf_consume(sbuf
, sizeof(BEGIN_SIGNATURE
)-1)) != 0) {
108 error_fr(r
, "consume");
111 if ((r
= sshbuf_cmp(sbuf
, 0, "\r\n", 2)) == 0)
113 else if ((r
= sshbuf_cmp(sbuf
, 0, "\n", 1)) == 0)
116 r
= SSH_ERR_INVALID_FORMAT
;
117 error_f("no header eol");
120 if ((r
= sshbuf_consume(sbuf
, eoffset
)) != 0) {
121 error_fr(r
, "consume eol");
124 /* Find and consume lf + suffix (any prior cr would be ignored) */
125 if ((r
= sshbuf_find(sbuf
, 0, "\n" END_SIGNATURE
,
126 sizeof(END_SIGNATURE
), &eoffset
)) != 0) {
127 error("Couldn't parse signature: missing footer");
130 if ((r
= sshbuf_consume_end(sbuf
, sshbuf_len(sbuf
)-eoffset
)) != 0) {
131 error_fr(r
, "consume");
135 if ((b64
= sshbuf_dup_string(sbuf
)) == NULL
) {
136 error_f("sshbuf_dup_string failed");
137 r
= SSH_ERR_ALLOC_FAIL
;
141 if ((buf
= sshbuf_new()) == NULL
) {
142 error_f("sshbuf_new() failed");
143 r
= SSH_ERR_ALLOC_FAIL
;
147 if ((r
= sshbuf_b64tod(buf
, b64
)) != 0) {
148 error_fr(r
, "decode base64");
155 buf
= NULL
; /* transferred */
164 sshsig_wrap_sign(struct sshkey
*key
, const char *hashalg
,
165 const char *sk_provider
, const char *sk_pin
, const struct sshbuf
*h_message
,
166 const char *sig_namespace
, struct sshbuf
**out
,
167 sshsig_signer
*signer
, void *signer_ctx
)
172 struct sshbuf
*blob
= NULL
;
173 struct sshbuf
*tosign
= NULL
;
174 const char *sign_alg
= NULL
;
176 if ((tosign
= sshbuf_new()) == NULL
||
177 (blob
= sshbuf_new()) == NULL
) {
178 error_f("sshbuf_new failed");
179 r
= SSH_ERR_ALLOC_FAIL
;
183 if ((r
= sshbuf_put(tosign
, MAGIC_PREAMBLE
, MAGIC_PREAMBLE_LEN
)) != 0 ||
184 (r
= sshbuf_put_cstring(tosign
, sig_namespace
)) != 0 ||
185 (r
= sshbuf_put_string(tosign
, NULL
, 0)) != 0 || /* reserved */
186 (r
= sshbuf_put_cstring(tosign
, hashalg
)) != 0 ||
187 (r
= sshbuf_put_stringb(tosign
, h_message
)) != 0) {
188 error_fr(r
, "assemble message to sign");
192 /* If using RSA keys then default to a good signature algorithm */
193 if (sshkey_type_plain(key
->type
) == KEY_RSA
) {
194 sign_alg
= RSA_SIGN_ALG
;
195 if (strcmp(hashalg
, "sha256") == 0)
196 sign_alg
= "rsa-sha2-256";
197 else if (strcmp(hashalg
, "sha512") == 0)
198 sign_alg
= "rsa-sha2-512";
201 if (signer
!= NULL
) {
202 if ((r
= signer(key
, &sig
, &slen
,
203 sshbuf_ptr(tosign
), sshbuf_len(tosign
),
204 sign_alg
, sk_provider
, sk_pin
, 0, signer_ctx
)) != 0) {
205 error_r(r
, "Couldn't sign message (signer)");
209 if ((r
= sshkey_sign(key
, &sig
, &slen
,
210 sshbuf_ptr(tosign
), sshbuf_len(tosign
),
211 sign_alg
, sk_provider
, sk_pin
, 0)) != 0) {
212 error_r(r
, "Couldn't sign message");
217 if ((r
= sshbuf_put(blob
, MAGIC_PREAMBLE
, MAGIC_PREAMBLE_LEN
)) != 0 ||
218 (r
= sshbuf_put_u32(blob
, SIG_VERSION
)) != 0 ||
219 (r
= sshkey_puts(key
, blob
)) != 0 ||
220 (r
= sshbuf_put_cstring(blob
, sig_namespace
)) != 0 ||
221 (r
= sshbuf_put_string(blob
, NULL
, 0)) != 0 || /* reserved */
222 (r
= sshbuf_put_cstring(blob
, hashalg
)) != 0 ||
223 (r
= sshbuf_put_string(blob
, sig
, slen
)) != 0) {
224 error_fr(r
, "assemble signature object");
240 /* Check preamble and version. */
242 sshsig_parse_preamble(struct sshbuf
*buf
)
244 int r
= SSH_ERR_INTERNAL_ERROR
;
247 if ((r
= sshbuf_cmp(buf
, 0, MAGIC_PREAMBLE
, MAGIC_PREAMBLE_LEN
)) != 0 ||
248 (r
= sshbuf_consume(buf
, (sizeof(MAGIC_PREAMBLE
)-1))) != 0 ||
249 (r
= sshbuf_get_u32(buf
, &sversion
)) != 0) {
250 error("Couldn't verify signature: invalid format");
254 if (sversion
> SIG_VERSION
) {
255 error("Signature version %lu is larger than supported "
256 "version %u", (unsigned long)sversion
, SIG_VERSION
);
257 return SSH_ERR_INVALID_FORMAT
;
263 sshsig_check_hashalg(const char *hashalg
)
265 if (hashalg
== NULL
||
266 match_pattern_list(hashalg
, HASHALG_ALLOWED
, 0) == 1)
268 error_f("unsupported hash algorithm \"%.100s\"", hashalg
);
269 return SSH_ERR_SIGN_ALG_UNSUPPORTED
;
273 sshsig_peek_hashalg(struct sshbuf
*signature
, char **hashalgp
)
275 struct sshbuf
*buf
= NULL
;
276 char *hashalg
= NULL
;
277 int r
= SSH_ERR_INTERNAL_ERROR
;
279 if (hashalgp
!= NULL
)
281 if ((buf
= sshbuf_fromb(signature
)) == NULL
)
282 return SSH_ERR_ALLOC_FAIL
;
283 if ((r
= sshsig_parse_preamble(buf
)) != 0)
285 if ((r
= sshbuf_get_string_direct(buf
, NULL
, NULL
)) != 0 ||
286 (r
= sshbuf_get_string_direct(buf
, NULL
, NULL
)) != 0 ||
287 (r
= sshbuf_get_string(buf
, NULL
, NULL
)) != 0 ||
288 (r
= sshbuf_get_cstring(buf
, &hashalg
, NULL
)) != 0 ||
289 (r
= sshbuf_get_string_direct(buf
, NULL
, NULL
)) != 0) {
290 error_fr(r
, "parse signature object");
305 sshsig_wrap_verify(struct sshbuf
*signature
, const char *hashalg
,
306 const struct sshbuf
*h_message
, const char *expect_namespace
,
307 struct sshkey
**sign_keyp
, struct sshkey_sig_details
**sig_details
)
309 int r
= SSH_ERR_INTERNAL_ERROR
;
310 struct sshbuf
*buf
= NULL
, *toverify
= NULL
;
311 struct sshkey
*key
= NULL
;
313 char *got_namespace
= NULL
, *sigtype
= NULL
, *sig_hashalg
= NULL
;
316 debug_f("verify message length %zu", sshbuf_len(h_message
));
317 if (sig_details
!= NULL
)
319 if (sign_keyp
!= NULL
)
322 if ((toverify
= sshbuf_new()) == NULL
) {
323 error_f("sshbuf_new failed");
324 r
= SSH_ERR_ALLOC_FAIL
;
327 if ((r
= sshbuf_put(toverify
, MAGIC_PREAMBLE
,
328 MAGIC_PREAMBLE_LEN
)) != 0 ||
329 (r
= sshbuf_put_cstring(toverify
, expect_namespace
)) != 0 ||
330 (r
= sshbuf_put_string(toverify
, NULL
, 0)) != 0 || /* reserved */
331 (r
= sshbuf_put_cstring(toverify
, hashalg
)) != 0 ||
332 (r
= sshbuf_put_stringb(toverify
, h_message
)) != 0) {
333 error_fr(r
, "assemble message to verify");
337 if ((r
= sshsig_parse_preamble(signature
)) != 0)
340 if ((r
= sshkey_froms(signature
, &key
)) != 0 ||
341 (r
= sshbuf_get_cstring(signature
, &got_namespace
, NULL
)) != 0 ||
342 (r
= sshbuf_get_string(signature
, NULL
, NULL
)) != 0 ||
343 (r
= sshbuf_get_cstring(signature
, &sig_hashalg
, NULL
)) != 0 ||
344 (r
= sshbuf_get_string_direct(signature
, &sig
, &siglen
)) != 0) {
345 error_fr(r
, "parse signature object");
349 if (sshbuf_len(signature
) != 0) {
350 error("Signature contains trailing data");
351 r
= SSH_ERR_INVALID_FORMAT
;
355 if (strcmp(expect_namespace
, got_namespace
) != 0) {
356 error("Couldn't verify signature: namespace does not match");
357 debug_f("expected namespace \"%s\" received \"%s\"",
358 expect_namespace
, got_namespace
);
359 r
= SSH_ERR_SIGNATURE_INVALID
;
362 if (strcmp(hashalg
, sig_hashalg
) != 0) {
363 error("Couldn't verify signature: hash algorithm mismatch");
364 debug_f("expected algorithm \"%s\" received \"%s\"",
365 hashalg
, sig_hashalg
);
366 r
= SSH_ERR_SIGNATURE_INVALID
;
369 /* Ensure that RSA keys use an acceptable signature algorithm */
370 if (sshkey_type_plain(key
->type
) == KEY_RSA
) {
371 if ((r
= sshkey_get_sigtype(sig
, siglen
, &sigtype
)) != 0) {
372 error_r(r
, "Couldn't verify signature: unable to get "
376 if (match_pattern_list(sigtype
, RSA_SIGN_ALLOWED
, 0) != 1) {
377 error("Couldn't verify signature: unsupported RSA "
378 "signature algorithm %s", sigtype
);
379 r
= SSH_ERR_SIGN_ALG_UNSUPPORTED
;
383 if ((r
= sshkey_verify(key
, sig
, siglen
, sshbuf_ptr(toverify
),
384 sshbuf_len(toverify
), NULL
, 0, sig_details
)) != 0) {
385 error_r(r
, "Signature verification failed");
391 if (sign_keyp
!= NULL
) {
393 key
= NULL
; /* transferred */
400 sshbuf_free(toverify
);
406 hash_buffer(const struct sshbuf
*m
, const char *hashalg
, struct sshbuf
**bp
)
408 char *hex
, hash
[SSH_DIGEST_MAX_LENGTH
];
409 int alg
, r
= SSH_ERR_INTERNAL_ERROR
;
410 struct sshbuf
*b
= NULL
;
413 memset(hash
, 0, sizeof(hash
));
415 if ((r
= sshsig_check_hashalg(hashalg
)) != 0)
417 if ((alg
= ssh_digest_alg_by_name(hashalg
)) == -1) {
418 error_f("can't look up hash algorithm %s", hashalg
);
419 return SSH_ERR_INTERNAL_ERROR
;
421 if ((r
= ssh_digest_buffer(alg
, m
, hash
, sizeof(hash
))) != 0) {
422 error_fr(r
, "ssh_digest_buffer");
425 if ((hex
= tohex(hash
, ssh_digest_bytes(alg
))) != NULL
) {
426 debug3_f("final hash: %s", hex
);
427 freezero(hex
, strlen(hex
));
429 if ((b
= sshbuf_new()) == NULL
) {
430 r
= SSH_ERR_ALLOC_FAIL
;
433 if ((r
= sshbuf_put(b
, hash
, ssh_digest_bytes(alg
))) != 0) {
434 error_fr(r
, "sshbuf_put");
438 b
= NULL
; /* transferred */
443 explicit_bzero(hash
, sizeof(hash
));
448 sshsig_signb(struct sshkey
*key
, const char *hashalg
,
449 const char *sk_provider
, const char *sk_pin
,
450 const struct sshbuf
*message
, const char *sig_namespace
,
451 struct sshbuf
**out
, sshsig_signer
*signer
, void *signer_ctx
)
453 struct sshbuf
*b
= NULL
;
454 int r
= SSH_ERR_INTERNAL_ERROR
;
457 hashalg
= HASHALG_DEFAULT
;
460 if ((r
= hash_buffer(message
, hashalg
, &b
)) != 0) {
461 error_fr(r
, "hash buffer");
464 if ((r
= sshsig_wrap_sign(key
, hashalg
, sk_provider
, sk_pin
, b
,
465 sig_namespace
, out
, signer
, signer_ctx
)) != 0)
475 sshsig_verifyb(struct sshbuf
*signature
, const struct sshbuf
*message
,
476 const char *expect_namespace
, struct sshkey
**sign_keyp
,
477 struct sshkey_sig_details
**sig_details
)
479 struct sshbuf
*b
= NULL
;
480 int r
= SSH_ERR_INTERNAL_ERROR
;
481 char *hashalg
= NULL
;
483 if (sig_details
!= NULL
)
485 if (sign_keyp
!= NULL
)
487 if ((r
= sshsig_peek_hashalg(signature
, &hashalg
)) != 0)
489 debug_f("signature made with hash \"%s\"", hashalg
);
490 if ((r
= hash_buffer(message
, hashalg
, &b
)) != 0) {
491 error_fr(r
, "hash buffer");
494 if ((r
= sshsig_wrap_verify(signature
, hashalg
, b
, expect_namespace
,
495 sign_keyp
, sig_details
)) != 0)
506 hash_file(int fd
, const char *hashalg
, struct sshbuf
**bp
)
508 char *hex
, rbuf
[8192], hash
[SSH_DIGEST_MAX_LENGTH
];
509 ssize_t n
, total
= 0;
510 struct ssh_digest_ctx
*ctx
= NULL
;
511 int alg
, oerrno
, r
= SSH_ERR_INTERNAL_ERROR
;
512 struct sshbuf
*b
= NULL
;
515 memset(hash
, 0, sizeof(hash
));
517 if ((r
= sshsig_check_hashalg(hashalg
)) != 0)
519 if ((alg
= ssh_digest_alg_by_name(hashalg
)) == -1) {
520 error_f("can't look up hash algorithm %s", hashalg
);
521 return SSH_ERR_INTERNAL_ERROR
;
523 if ((ctx
= ssh_digest_start(alg
)) == NULL
) {
524 error_f("ssh_digest_start failed");
525 return SSH_ERR_INTERNAL_ERROR
;
528 if ((n
= read(fd
, rbuf
, sizeof(rbuf
))) == -1) {
529 if (errno
== EINTR
|| errno
== EAGAIN
)
532 error_f("read: %s", strerror(errno
));
534 r
= SSH_ERR_SYSTEM_ERROR
;
537 debug2_f("hashed %zu bytes", total
);
541 if ((r
= ssh_digest_update(ctx
, rbuf
, (size_t)n
)) != 0) {
542 error_fr(r
, "ssh_digest_update");
546 if ((r
= ssh_digest_final(ctx
, hash
, sizeof(hash
))) != 0) {
547 error_fr(r
, "ssh_digest_final");
550 if ((hex
= tohex(hash
, ssh_digest_bytes(alg
))) != NULL
) {
551 debug3_f("final hash: %s", hex
);
552 freezero(hex
, strlen(hex
));
554 if ((b
= sshbuf_new()) == NULL
) {
555 r
= SSH_ERR_ALLOC_FAIL
;
558 if ((r
= sshbuf_put(b
, hash
, ssh_digest_bytes(alg
))) != 0) {
559 error_fr(r
, "sshbuf_put");
563 b
= NULL
; /* transferred */
569 ssh_digest_free(ctx
);
570 explicit_bzero(hash
, sizeof(hash
));
576 sshsig_sign_fd(struct sshkey
*key
, const char *hashalg
,
577 const char *sk_provider
, const char *sk_pin
,
578 int fd
, const char *sig_namespace
, struct sshbuf
**out
,
579 sshsig_signer
*signer
, void *signer_ctx
)
581 struct sshbuf
*b
= NULL
;
582 int r
= SSH_ERR_INTERNAL_ERROR
;
585 hashalg
= HASHALG_DEFAULT
;
588 if ((r
= hash_file(fd
, hashalg
, &b
)) != 0) {
589 error_fr(r
, "hash_file");
592 if ((r
= sshsig_wrap_sign(key
, hashalg
, sk_provider
, sk_pin
, b
,
593 sig_namespace
, out
, signer
, signer_ctx
)) != 0)
603 sshsig_verify_fd(struct sshbuf
*signature
, int fd
,
604 const char *expect_namespace
, struct sshkey
**sign_keyp
,
605 struct sshkey_sig_details
**sig_details
)
607 struct sshbuf
*b
= NULL
;
608 int r
= SSH_ERR_INTERNAL_ERROR
;
609 char *hashalg
= NULL
;
611 if (sig_details
!= NULL
)
613 if (sign_keyp
!= NULL
)
615 if ((r
= sshsig_peek_hashalg(signature
, &hashalg
)) != 0)
617 debug_f("signature made with hash \"%s\"", hashalg
);
618 if ((r
= hash_file(fd
, hashalg
, &b
)) != 0) {
619 error_fr(r
, "hash_file");
622 if ((r
= sshsig_wrap_verify(signature
, hashalg
, b
, expect_namespace
,
623 sign_keyp
, sig_details
)) != 0)
636 uint64_t valid_after
, valid_before
;
640 sshsigopt_parse(const char *opts
, const char *path
, u_long linenum
,
641 const char **errstrp
)
643 struct sshsigopt
*ret
;
646 const char *errstr
= NULL
;
648 if ((ret
= calloc(1, sizeof(*ret
))) == NULL
)
650 if (opts
== NULL
|| *opts
== '\0')
651 return ret
; /* Empty options yields empty options :) */
653 while (*opts
&& *opts
!= ' ' && *opts
!= '\t') {
655 if ((r
= opt_flag("cert-authority", 0, &opts
)) != -1) {
657 } else if (opt_match(&opts
, "namespaces")) {
658 if (ret
->namespaces
!= NULL
) {
659 errstr
= "multiple \"namespaces\" clauses";
662 ret
->namespaces
= opt_dequote(&opts
, &errstr
);
663 if (ret
->namespaces
== NULL
)
665 } else if (opt_match(&opts
, "valid-after")) {
666 if (ret
->valid_after
!= 0) {
667 errstr
= "multiple \"valid-after\" clauses";
670 if ((opt
= opt_dequote(&opts
, &errstr
)) == NULL
)
672 if (parse_absolute_time(opt
, &ret
->valid_after
) != 0 ||
673 ret
->valid_after
== 0) {
675 errstr
= "invalid \"valid-after\" time";
679 } else if (opt_match(&opts
, "valid-before")) {
680 if (ret
->valid_before
!= 0) {
681 errstr
= "multiple \"valid-before\" clauses";
684 if ((opt
= opt_dequote(&opts
, &errstr
)) == NULL
)
686 if (parse_absolute_time(opt
, &ret
->valid_before
) != 0 ||
687 ret
->valid_before
== 0) {
689 errstr
= "invalid \"valid-before\" time";
695 * Skip the comma, and move to the next option
696 * (or break out if there are no more).
698 if (*opts
== '\0' || *opts
== ' ' || *opts
== '\t')
699 break; /* End of options. */
700 /* Anything other than a comma is an unknown option */
702 errstr
= "unknown key option";
707 errstr
= "unexpected end-of-options";
711 /* final consistency check */
712 if (ret
->valid_after
!= 0 && ret
->valid_before
!= 0 &&
713 ret
->valid_before
<= ret
->valid_after
) {
714 errstr
= "\"valid-before\" time is before \"valid-after\"";
727 sshsigopt_free(struct sshsigopt
*opts
)
731 free(opts
->namespaces
);
736 parse_principals_key_and_options(const char *path
, u_long linenum
, char *line
,
737 const char *required_principal
, char **principalsp
, struct sshkey
**keyp
,
738 struct sshsigopt
**sigoptsp
)
740 char *opts
= NULL
, *tmp
, *cp
, *principals
= NULL
;
741 const char *reason
= NULL
;
742 struct sshsigopt
*sigopts
= NULL
;
743 struct sshkey
*key
= NULL
;
744 int r
= SSH_ERR_INTERNAL_ERROR
;
746 if (principalsp
!= NULL
)
748 if (sigoptsp
!= NULL
)
754 cp
= cp
+ strspn(cp
, " \t\n\r"); /* skip leading whitespace */
755 if (*cp
== '#' || *cp
== '\0')
756 return SSH_ERR_KEY_NOT_FOUND
; /* blank or all-comment line */
758 /* format: identity[,identity...] [option[,option...]] key */
759 if ((tmp
= strdelimw(&cp
)) == NULL
|| cp
== NULL
) {
760 error("%s:%lu: invalid line", path
, linenum
);
761 r
= SSH_ERR_INVALID_FORMAT
;
764 if ((principals
= strdup(tmp
)) == NULL
) {
765 error_f("strdup failed");
766 r
= SSH_ERR_ALLOC_FAIL
;
770 * Bail out early if we're looking for a particular principal and this
771 * line does not list it.
773 if (required_principal
!= NULL
) {
774 if (match_pattern_list(required_principal
,
775 principals
, 0) != 1) {
776 /* principal didn't match */
777 r
= SSH_ERR_KEY_NOT_FOUND
;
780 debug_f("%s:%lu: matched principal \"%s\"",
781 path
, linenum
, required_principal
);
784 if ((key
= sshkey_new(KEY_UNSPEC
)) == NULL
) {
785 error_f("sshkey_new failed");
786 r
= SSH_ERR_ALLOC_FAIL
;
789 if (sshkey_read(key
, &cp
) != 0) {
790 /* no key? Check for options */
792 if (sshkey_advance_past_options(&cp
) != 0) {
793 error("%s:%lu: invalid options", path
, linenum
);
794 r
= SSH_ERR_INVALID_FORMAT
;
797 if (cp
== NULL
|| *cp
== '\0') {
798 error("%s:%lu: missing key", path
, linenum
);
799 r
= SSH_ERR_INVALID_FORMAT
;
804 if (sshkey_read(key
, &cp
) != 0) {
805 error("%s:%lu: invalid key", path
, linenum
);
806 r
= SSH_ERR_INVALID_FORMAT
;
810 debug3("%s:%lu: options %s", path
, linenum
, opts
== NULL
? "" : opts
);
811 if ((sigopts
= sshsigopt_parse(opts
, path
, linenum
, &reason
)) == NULL
) {
812 error("%s:%lu: bad options: %s", path
, linenum
, reason
);
813 r
= SSH_ERR_INVALID_FORMAT
;
817 if (principalsp
!= NULL
) {
818 *principalsp
= principals
;
819 principals
= NULL
; /* transferred */
821 if (sigoptsp
!= NULL
) {
823 sigopts
= NULL
; /* transferred */
827 key
= NULL
; /* transferred */
832 sshsigopt_free(sigopts
);
838 cert_filter_principals(const char *path
, u_long linenum
,
839 char **principalsp
, const struct sshkey
*cert
, uint64_t verify_time
)
841 char *cp
, *oprincipals
, *principals
;
843 struct sshbuf
*nprincipals
;
844 int r
= SSH_ERR_INTERNAL_ERROR
, success
= 0;
847 oprincipals
= principals
= *principalsp
;
850 if ((nprincipals
= sshbuf_new()) == NULL
) {
851 r
= SSH_ERR_ALLOC_FAIL
;
855 while ((cp
= strsep(&principals
, ",")) != NULL
&& *cp
!= '\0') {
856 /* Check certificate validity */
857 if ((r
= sshkey_cert_check_authority(cert
, 0, 1, 0,
858 verify_time
, NULL
, &reason
)) != 0) {
859 debug("%s:%lu: principal \"%s\" not authorized: %s",
860 path
, linenum
, cp
, reason
);
863 /* Return all matching principal names from the cert */
864 for (i
= 0; i
< cert
->cert
->nprincipals
; i
++) {
865 if (match_pattern(cert
->cert
->principals
[i
], cp
)) {
866 if ((r
= sshbuf_putf(nprincipals
, "%s%s",
867 sshbuf_len(nprincipals
) != 0 ? "," : "",
868 cert
->cert
->principals
[i
])) != 0) {
869 error_f("buffer error");
875 if (sshbuf_len(nprincipals
) == 0) {
876 error("%s:%lu: no valid principals found", path
, linenum
);
877 r
= SSH_ERR_KEY_CERT_INVALID
;
880 if ((principals
= sshbuf_dup_string(nprincipals
)) == NULL
) {
881 error_f("buffer error");
886 *principalsp
= principals
;
888 sshbuf_free(nprincipals
);
890 return success
? 0 : r
;
894 check_allowed_keys_line(const char *path
, u_long linenum
, char *line
,
895 const struct sshkey
*sign_key
, const char *principal
,
896 const char *sig_namespace
, uint64_t verify_time
, char **principalsp
)
898 struct sshkey
*found_key
= NULL
;
899 char *principals
= NULL
;
901 const char *reason
= NULL
;
902 struct sshsigopt
*sigopts
= NULL
;
903 char tvalid
[64], tverify
[64];
905 if (principalsp
!= NULL
)
909 if ((r
= parse_principals_key_and_options(path
, linenum
, line
,
910 principal
, &principals
, &found_key
, &sigopts
)) != 0) {
911 /* error already logged */
915 if (!sigopts
->ca
&& sshkey_equal(found_key
, sign_key
)) {
916 /* Exact match of key */
917 debug("%s:%lu: matched key", path
, linenum
);
918 } else if (sigopts
->ca
&& sshkey_is_cert(sign_key
) &&
919 sshkey_equal_public(sign_key
->cert
->signature_key
, found_key
)) {
921 /* Match certificate CA key with specified principal */
922 if ((r
= sshkey_cert_check_authority(sign_key
, 0, 1, 0,
923 verify_time
, principal
, &reason
)) != 0) {
924 error("%s:%lu: certificate not authorized: %s",
925 path
, linenum
, reason
);
928 debug("%s:%lu: matched certificate CA key",
931 /* No principal specified - find all matching ones */
932 if ((r
= cert_filter_principals(path
, linenum
,
933 &principals
, sign_key
, verify_time
)) != 0) {
934 /* error already displayed */
935 debug_r(r
, "%s:%lu: cert_filter_principals",
939 debug("%s:%lu: matched certificate CA key",
943 /* Didn't match key */
947 /* Check whether options preclude the use of this key */
948 if (sigopts
->namespaces
!= NULL
&& sig_namespace
!= NULL
&&
949 match_pattern_list(sig_namespace
, sigopts
->namespaces
, 0) != 1) {
950 error("%s:%lu: key is not permitted for use in signature "
951 "namespace \"%s\"", path
, linenum
, sig_namespace
);
955 /* check key time validity */
956 format_absolute_time((uint64_t)verify_time
, tverify
, sizeof(tverify
));
957 if (sigopts
->valid_after
!= 0 &&
958 (uint64_t)verify_time
< sigopts
->valid_after
) {
959 format_absolute_time(sigopts
->valid_after
,
960 tvalid
, sizeof(tvalid
));
961 error("%s:%lu: key is not yet valid: "
962 "verify time %s < valid-after %s", path
, linenum
,
966 if (sigopts
->valid_before
!= 0 &&
967 (uint64_t)verify_time
> sigopts
->valid_before
) {
968 format_absolute_time(sigopts
->valid_before
,
969 tvalid
, sizeof(tvalid
));
970 error("%s:%lu: key has expired: "
971 "verify time %s > valid-before %s", path
, linenum
,
978 if (success
&& principalsp
!= NULL
) {
979 *principalsp
= principals
;
980 principals
= NULL
; /* transferred */
983 sshkey_free(found_key
);
984 sshsigopt_free(sigopts
);
985 return success
? 0 : SSH_ERR_KEY_NOT_FOUND
;
989 sshsig_check_allowed_keys(const char *path
, const struct sshkey
*sign_key
,
990 const char *principal
, const char *sig_namespace
, uint64_t verify_time
)
996 int r
= SSH_ERR_KEY_NOT_FOUND
, oerrno
;
998 /* Check key and principal against file */
999 if ((f
= fopen(path
, "r")) == NULL
) {
1001 error("Unable to open allowed keys file \"%s\": %s",
1002 path
, strerror(errno
));
1004 return SSH_ERR_SYSTEM_ERROR
;
1007 while (getline(&line
, &linesize
, f
) != -1) {
1009 r
= check_allowed_keys_line(path
, linenum
, line
, sign_key
,
1010 principal
, sig_namespace
, verify_time
, NULL
);
1014 if (r
== SSH_ERR_KEY_NOT_FOUND
)
1023 /* Either we hit an error parsing or we simply didn't find the key */
1030 sshsig_find_principals(const char *path
, const struct sshkey
*sign_key
,
1031 uint64_t verify_time
, char **principals
)
1035 size_t linesize
= 0;
1037 int r
= SSH_ERR_KEY_NOT_FOUND
, oerrno
;
1039 if ((f
= fopen(path
, "r")) == NULL
) {
1041 error("Unable to open allowed keys file \"%s\": %s",
1042 path
, strerror(errno
));
1044 return SSH_ERR_SYSTEM_ERROR
;
1047 while (getline(&line
, &linesize
, f
) != -1) {
1049 r
= check_allowed_keys_line(path
, linenum
, line
,
1050 sign_key
, NULL
, NULL
, verify_time
, principals
);
1054 if (r
== SSH_ERR_KEY_NOT_FOUND
)
1064 /* Either we hit an error parsing or we simply didn't find the key */
1065 if (ferror(f
) != 0) {
1068 error("Unable to read allowed keys file \"%s\": %s",
1069 path
, strerror(errno
));
1071 return SSH_ERR_SYSTEM_ERROR
;
1078 sshsig_match_principals(const char *path
, const char *principal
,
1079 char ***principalsp
, size_t *nprincipalsp
)
1082 char *found
, *line
= NULL
, **principals
= NULL
, **tmp
;
1083 size_t i
, nprincipals
= 0, linesize
= 0;
1085 int oerrno
= 0, r
, ret
= 0;
1087 if (principalsp
!= NULL
)
1088 *principalsp
= NULL
;
1089 if (nprincipalsp
!= NULL
)
1092 /* Check key and principal against file */
1093 if ((f
= fopen(path
, "r")) == NULL
) {
1095 error("Unable to open allowed keys file \"%s\": %s",
1096 path
, strerror(errno
));
1098 return SSH_ERR_SYSTEM_ERROR
;
1101 while (getline(&line
, &linesize
, f
) != -1) {
1103 /* Parse the line */
1104 if ((r
= parse_principals_key_and_options(path
, linenum
, line
,
1105 principal
, &found
, NULL
, NULL
)) != 0) {
1106 if (r
== SSH_ERR_KEY_NOT_FOUND
)
1110 break; /* unexpected error */
1112 if ((tmp
= recallocarray(principals
, nprincipals
,
1113 nprincipals
+ 1, sizeof(*principals
))) == NULL
) {
1114 ret
= SSH_ERR_ALLOC_FAIL
;
1119 principals
[nprincipals
++] = found
; /* transferred */
1127 if (nprincipals
== 0)
1128 ret
= SSH_ERR_KEY_NOT_FOUND
;
1129 if (nprincipalsp
!= 0)
1130 *nprincipalsp
= nprincipals
;
1131 if (principalsp
!= NULL
) {
1132 *principalsp
= principals
;
1133 principals
= NULL
; /* transferred */
1138 for (i
= 0; i
< nprincipals
; i
++)
1139 free(principals
[i
]);
1147 sshsig_get_pubkey(struct sshbuf
*signature
, struct sshkey
**pubkey
)
1149 struct sshkey
*pk
= NULL
;
1150 int r
= SSH_ERR_SIGNATURE_INVALID
;
1153 return SSH_ERR_INTERNAL_ERROR
;
1154 if ((r
= sshsig_parse_preamble(signature
)) != 0)
1156 if ((r
= sshkey_froms(signature
, &pk
)) != 0)