1 /* $OpenBSD: sshsig.c,v 1.30 2022/08/19 03:06:30 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-----\n"
42 #define END_SIGNATURE "-----END SSH SIGNATURE-----"
43 #define RSA_SIGN_ALG "rsa-sha2-512" /* XXX maybe make configurable */
44 #define RSA_SIGN_ALLOWED "rsa-sha2-512,rsa-sha2-256"
45 #define HASHALG_DEFAULT "sha512" /* XXX maybe make configurable */
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_put(buf
, BEGIN_SIGNATURE
,
63 sizeof(BEGIN_SIGNATURE
)-1)) != 0) {
64 error_fr(r
, "sshbuf_putf");
68 if ((r
= sshbuf_dtob64(blob
, buf
, 1)) != 0) {
69 error_fr(r
, "base64 encode signature");
73 if ((r
= sshbuf_put(buf
, END_SIGNATURE
,
74 sizeof(END_SIGNATURE
)-1)) != 0 ||
75 (r
= sshbuf_put_u8(buf
, '\n')) != 0) {
76 error_fr(r
, "sshbuf_put");
81 buf
= NULL
; /* transferred */
89 sshsig_dearmor(struct sshbuf
*sig
, struct sshbuf
**out
)
93 struct sshbuf
*buf
= NULL
;
94 struct sshbuf
*sbuf
= NULL
;
97 if ((sbuf
= sshbuf_fromb(sig
)) == NULL
) {
98 error_f("sshbuf_fromb failed");
99 return SSH_ERR_ALLOC_FAIL
;
102 if ((r
= sshbuf_cmp(sbuf
, 0,
103 BEGIN_SIGNATURE
, sizeof(BEGIN_SIGNATURE
)-1)) != 0) {
104 error("Couldn't parse signature: missing header");
108 if ((r
= sshbuf_consume(sbuf
, sizeof(BEGIN_SIGNATURE
)-1)) != 0) {
109 error_fr(r
, "consume");
113 if ((r
= sshbuf_find(sbuf
, 0, "\n" END_SIGNATURE
,
114 sizeof("\n" END_SIGNATURE
)-1, &eoffset
)) != 0) {
115 error("Couldn't parse signature: missing footer");
119 if ((r
= sshbuf_consume_end(sbuf
, sshbuf_len(sbuf
)-eoffset
)) != 0) {
120 error_fr(r
, "consume");
124 if ((b64
= sshbuf_dup_string(sbuf
)) == NULL
) {
125 error_f("sshbuf_dup_string failed");
126 r
= SSH_ERR_ALLOC_FAIL
;
130 if ((buf
= sshbuf_new()) == NULL
) {
131 error_f("sshbuf_new() failed");
132 r
= SSH_ERR_ALLOC_FAIL
;
136 if ((r
= sshbuf_b64tod(buf
, b64
)) != 0) {
137 error_fr(r
, "decode base64");
144 buf
= NULL
; /* transferred */
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
)
161 struct sshbuf
*blob
= NULL
;
162 struct sshbuf
*tosign
= NULL
;
163 const char *sign_alg
= NULL
;
165 if ((tosign
= sshbuf_new()) == NULL
||
166 (blob
= sshbuf_new()) == NULL
) {
167 error_f("sshbuf_new failed");
168 r
= SSH_ERR_ALLOC_FAIL
;
172 if ((r
= sshbuf_put(tosign
, MAGIC_PREAMBLE
, MAGIC_PREAMBLE_LEN
)) != 0 ||
173 (r
= sshbuf_put_cstring(tosign
, sig_namespace
)) != 0 ||
174 (r
= sshbuf_put_string(tosign
, NULL
, 0)) != 0 || /* reserved */
175 (r
= sshbuf_put_cstring(tosign
, hashalg
)) != 0 ||
176 (r
= sshbuf_put_stringb(tosign
, h_message
)) != 0) {
177 error_fr(r
, "assemble message to sign");
181 /* If using RSA keys then default to a good signature algorithm */
182 if (sshkey_type_plain(key
->type
) == KEY_RSA
)
183 sign_alg
= RSA_SIGN_ALG
;
185 if (signer
!= NULL
) {
186 if ((r
= signer(key
, &sig
, &slen
,
187 sshbuf_ptr(tosign
), sshbuf_len(tosign
),
188 sign_alg
, sk_provider
, sk_pin
, 0, signer_ctx
)) != 0) {
189 error_r(r
, "Couldn't sign message (signer)");
193 if ((r
= sshkey_sign(key
, &sig
, &slen
,
194 sshbuf_ptr(tosign
), sshbuf_len(tosign
),
195 sign_alg
, sk_provider
, sk_pin
, 0)) != 0) {
196 error_r(r
, "Couldn't sign message");
201 if ((r
= sshbuf_put(blob
, MAGIC_PREAMBLE
, MAGIC_PREAMBLE_LEN
)) != 0 ||
202 (r
= sshbuf_put_u32(blob
, SIG_VERSION
)) != 0 ||
203 (r
= sshkey_puts(key
, blob
)) != 0 ||
204 (r
= sshbuf_put_cstring(blob
, sig_namespace
)) != 0 ||
205 (r
= sshbuf_put_string(blob
, NULL
, 0)) != 0 || /* reserved */
206 (r
= sshbuf_put_cstring(blob
, hashalg
)) != 0 ||
207 (r
= sshbuf_put_string(blob
, sig
, slen
)) != 0) {
208 error_fr(r
, "assemble signature object");
224 /* Check preamble and version. */
226 sshsig_parse_preamble(struct sshbuf
*buf
)
228 int r
= SSH_ERR_INTERNAL_ERROR
;
231 if ((r
= sshbuf_cmp(buf
, 0, MAGIC_PREAMBLE
, MAGIC_PREAMBLE_LEN
)) != 0 ||
232 (r
= sshbuf_consume(buf
, (sizeof(MAGIC_PREAMBLE
)-1))) != 0 ||
233 (r
= sshbuf_get_u32(buf
, &sversion
)) != 0) {
234 error("Couldn't verify signature: invalid format");
238 if (sversion
> SIG_VERSION
) {
239 error("Signature version %lu is larger than supported "
240 "version %u", (unsigned long)sversion
, SIG_VERSION
);
241 return SSH_ERR_INVALID_FORMAT
;
247 sshsig_check_hashalg(const char *hashalg
)
249 if (hashalg
== NULL
||
250 match_pattern_list(hashalg
, HASHALG_ALLOWED
, 0) == 1)
252 error_f("unsupported hash algorithm \"%.100s\"", hashalg
);
253 return SSH_ERR_SIGN_ALG_UNSUPPORTED
;
257 sshsig_peek_hashalg(struct sshbuf
*signature
, char **hashalgp
)
259 struct sshbuf
*buf
= NULL
;
260 char *hashalg
= NULL
;
261 int r
= SSH_ERR_INTERNAL_ERROR
;
263 if (hashalgp
!= NULL
)
265 if ((buf
= sshbuf_fromb(signature
)) == NULL
)
266 return SSH_ERR_ALLOC_FAIL
;
267 if ((r
= sshsig_parse_preamble(buf
)) != 0)
269 if ((r
= sshbuf_get_string_direct(buf
, NULL
, NULL
)) != 0 ||
270 (r
= sshbuf_get_string_direct(buf
, NULL
, NULL
)) != 0 ||
271 (r
= sshbuf_get_string(buf
, NULL
, NULL
)) != 0 ||
272 (r
= sshbuf_get_cstring(buf
, &hashalg
, NULL
)) != 0 ||
273 (r
= sshbuf_get_string_direct(buf
, NULL
, NULL
)) != 0) {
274 error_fr(r
, "parse signature object");
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
)
293 int r
= SSH_ERR_INTERNAL_ERROR
;
294 struct sshbuf
*buf
= NULL
, *toverify
= NULL
;
295 struct sshkey
*key
= NULL
;
297 char *got_namespace
= NULL
, *sigtype
= NULL
, *sig_hashalg
= NULL
;
300 debug_f("verify message length %zu", sshbuf_len(h_message
));
301 if (sig_details
!= NULL
)
303 if (sign_keyp
!= NULL
)
306 if ((toverify
= sshbuf_new()) == NULL
) {
307 error_f("sshbuf_new failed");
308 r
= SSH_ERR_ALLOC_FAIL
;
311 if ((r
= sshbuf_put(toverify
, MAGIC_PREAMBLE
,
312 MAGIC_PREAMBLE_LEN
)) != 0 ||
313 (r
= sshbuf_put_cstring(toverify
, expect_namespace
)) != 0 ||
314 (r
= sshbuf_put_string(toverify
, NULL
, 0)) != 0 || /* reserved */
315 (r
= sshbuf_put_cstring(toverify
, hashalg
)) != 0 ||
316 (r
= sshbuf_put_stringb(toverify
, h_message
)) != 0) {
317 error_fr(r
, "assemble message to verify");
321 if ((r
= sshsig_parse_preamble(signature
)) != 0)
324 if ((r
= sshkey_froms(signature
, &key
)) != 0 ||
325 (r
= sshbuf_get_cstring(signature
, &got_namespace
, NULL
)) != 0 ||
326 (r
= sshbuf_get_string(signature
, NULL
, NULL
)) != 0 ||
327 (r
= sshbuf_get_cstring(signature
, &sig_hashalg
, NULL
)) != 0 ||
328 (r
= sshbuf_get_string_direct(signature
, &sig
, &siglen
)) != 0) {
329 error_fr(r
, "parse signature object");
333 if (sshbuf_len(signature
) != 0) {
334 error("Signature contains trailing data");
335 r
= SSH_ERR_INVALID_FORMAT
;
339 if (strcmp(expect_namespace
, got_namespace
) != 0) {
340 error("Couldn't verify signature: namespace does not match");
341 debug_f("expected namespace \"%s\" received \"%s\"",
342 expect_namespace
, got_namespace
);
343 r
= SSH_ERR_SIGNATURE_INVALID
;
346 if (strcmp(hashalg
, sig_hashalg
) != 0) {
347 error("Couldn't verify signature: hash algorithm mismatch");
348 debug_f("expected algorithm \"%s\" received \"%s\"",
349 hashalg
, sig_hashalg
);
350 r
= SSH_ERR_SIGNATURE_INVALID
;
353 /* Ensure that RSA keys use an acceptable signature algorithm */
354 if (sshkey_type_plain(key
->type
) == KEY_RSA
) {
355 if ((r
= sshkey_get_sigtype(sig
, siglen
, &sigtype
)) != 0) {
356 error_r(r
, "Couldn't verify signature: unable to get "
360 if (match_pattern_list(sigtype
, RSA_SIGN_ALLOWED
, 0) != 1) {
361 error("Couldn't verify signature: unsupported RSA "
362 "signature algorithm %s", sigtype
);
363 r
= SSH_ERR_SIGN_ALG_UNSUPPORTED
;
367 if ((r
= sshkey_verify(key
, sig
, siglen
, sshbuf_ptr(toverify
),
368 sshbuf_len(toverify
), NULL
, 0, sig_details
)) != 0) {
369 error_r(r
, "Signature verification failed");
375 if (sign_keyp
!= NULL
) {
377 key
= NULL
; /* transferred */
384 sshbuf_free(toverify
);
390 hash_buffer(const struct sshbuf
*m
, const char *hashalg
, struct sshbuf
**bp
)
392 char *hex
, hash
[SSH_DIGEST_MAX_LENGTH
];
393 int alg
, r
= SSH_ERR_INTERNAL_ERROR
;
394 struct sshbuf
*b
= NULL
;
397 memset(hash
, 0, sizeof(hash
));
399 if ((r
= sshsig_check_hashalg(hashalg
)) != 0)
401 if ((alg
= ssh_digest_alg_by_name(hashalg
)) == -1) {
402 error_f("can't look up hash algorithm %s", hashalg
);
403 return SSH_ERR_INTERNAL_ERROR
;
405 if ((r
= ssh_digest_buffer(alg
, m
, hash
, sizeof(hash
))) != 0) {
406 error_fr(r
, "ssh_digest_buffer");
409 if ((hex
= tohex(hash
, ssh_digest_bytes(alg
))) != NULL
) {
410 debug3_f("final hash: %s", hex
);
411 freezero(hex
, strlen(hex
));
413 if ((b
= sshbuf_new()) == NULL
) {
414 r
= SSH_ERR_ALLOC_FAIL
;
417 if ((r
= sshbuf_put(b
, hash
, ssh_digest_bytes(alg
))) != 0) {
418 error_fr(r
, "sshbuf_put");
422 b
= NULL
; /* transferred */
427 explicit_bzero(hash
, sizeof(hash
));
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
)
437 struct sshbuf
*b
= NULL
;
438 int r
= SSH_ERR_INTERNAL_ERROR
;
441 hashalg
= HASHALG_DEFAULT
;
444 if ((r
= hash_buffer(message
, hashalg
, &b
)) != 0) {
445 error_fr(r
, "hash buffer");
448 if ((r
= sshsig_wrap_sign(key
, hashalg
, sk_provider
, sk_pin
, b
,
449 sig_namespace
, out
, signer
, signer_ctx
)) != 0)
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
)
463 struct sshbuf
*b
= NULL
;
464 int r
= SSH_ERR_INTERNAL_ERROR
;
465 char *hashalg
= NULL
;
467 if (sig_details
!= NULL
)
469 if (sign_keyp
!= NULL
)
471 if ((r
= sshsig_peek_hashalg(signature
, &hashalg
)) != 0)
473 debug_f("signature made with hash \"%s\"", hashalg
);
474 if ((r
= hash_buffer(message
, hashalg
, &b
)) != 0) {
475 error_fr(r
, "hash buffer");
478 if ((r
= sshsig_wrap_verify(signature
, hashalg
, b
, expect_namespace
,
479 sign_keyp
, sig_details
)) != 0)
490 hash_file(int fd
, const char *hashalg
, struct sshbuf
**bp
)
492 char *hex
, rbuf
[8192], hash
[SSH_DIGEST_MAX_LENGTH
];
493 ssize_t n
, total
= 0;
494 struct ssh_digest_ctx
*ctx
= NULL
;
495 int alg
, oerrno
, r
= SSH_ERR_INTERNAL_ERROR
;
496 struct sshbuf
*b
= NULL
;
499 memset(hash
, 0, sizeof(hash
));
501 if ((r
= sshsig_check_hashalg(hashalg
)) != 0)
503 if ((alg
= ssh_digest_alg_by_name(hashalg
)) == -1) {
504 error_f("can't look up hash algorithm %s", hashalg
);
505 return SSH_ERR_INTERNAL_ERROR
;
507 if ((ctx
= ssh_digest_start(alg
)) == NULL
) {
508 error_f("ssh_digest_start failed");
509 return SSH_ERR_INTERNAL_ERROR
;
512 if ((n
= read(fd
, rbuf
, sizeof(rbuf
))) == -1) {
513 if (errno
== EINTR
|| errno
== EAGAIN
)
516 error_f("read: %s", strerror(errno
));
518 r
= SSH_ERR_SYSTEM_ERROR
;
521 debug2_f("hashed %zu bytes", total
);
525 if ((r
= ssh_digest_update(ctx
, rbuf
, (size_t)n
)) != 0) {
526 error_fr(r
, "ssh_digest_update");
530 if ((r
= ssh_digest_final(ctx
, hash
, sizeof(hash
))) != 0) {
531 error_fr(r
, "ssh_digest_final");
534 if ((hex
= tohex(hash
, ssh_digest_bytes(alg
))) != NULL
) {
535 debug3_f("final hash: %s", hex
);
536 freezero(hex
, strlen(hex
));
538 if ((b
= sshbuf_new()) == NULL
) {
539 r
= SSH_ERR_ALLOC_FAIL
;
542 if ((r
= sshbuf_put(b
, hash
, ssh_digest_bytes(alg
))) != 0) {
543 error_fr(r
, "sshbuf_put");
547 b
= NULL
; /* transferred */
553 ssh_digest_free(ctx
);
554 explicit_bzero(hash
, sizeof(hash
));
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
)
565 struct sshbuf
*b
= NULL
;
566 int r
= SSH_ERR_INTERNAL_ERROR
;
569 hashalg
= HASHALG_DEFAULT
;
572 if ((r
= hash_file(fd
, hashalg
, &b
)) != 0) {
573 error_fr(r
, "hash_file");
576 if ((r
= sshsig_wrap_sign(key
, hashalg
, sk_provider
, sk_pin
, b
,
577 sig_namespace
, out
, signer
, signer_ctx
)) != 0)
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
)
591 struct sshbuf
*b
= NULL
;
592 int r
= SSH_ERR_INTERNAL_ERROR
;
593 char *hashalg
= NULL
;
595 if (sig_details
!= NULL
)
597 if (sign_keyp
!= NULL
)
599 if ((r
= sshsig_peek_hashalg(signature
, &hashalg
)) != 0)
601 debug_f("signature made with hash \"%s\"", hashalg
);
602 if ((r
= hash_file(fd
, hashalg
, &b
)) != 0) {
603 error_fr(r
, "hash_file");
606 if ((r
= sshsig_wrap_verify(signature
, hashalg
, b
, expect_namespace
,
607 sign_keyp
, sig_details
)) != 0)
620 uint64_t valid_after
, valid_before
;
624 sshsigopt_parse(const char *opts
, const char *path
, u_long linenum
,
625 const char **errstrp
)
627 struct sshsigopt
*ret
;
630 const char *errstr
= NULL
;
632 if ((ret
= calloc(1, sizeof(*ret
))) == NULL
)
634 if (opts
== NULL
|| *opts
== '\0')
635 return ret
; /* Empty options yields empty options :) */
637 while (*opts
&& *opts
!= ' ' && *opts
!= '\t') {
639 if ((r
= opt_flag("cert-authority", 0, &opts
)) != -1) {
641 } else if (opt_match(&opts
, "namespaces")) {
642 if (ret
->namespaces
!= NULL
) {
643 errstr
= "multiple \"namespaces\" clauses";
646 ret
->namespaces
= opt_dequote(&opts
, &errstr
);
647 if (ret
->namespaces
== NULL
)
649 } else if (opt_match(&opts
, "valid-after")) {
650 if (ret
->valid_after
!= 0) {
651 errstr
= "multiple \"valid-after\" clauses";
654 if ((opt
= opt_dequote(&opts
, &errstr
)) == NULL
)
656 if (parse_absolute_time(opt
, &ret
->valid_after
) != 0 ||
657 ret
->valid_after
== 0) {
659 errstr
= "invalid \"valid-after\" time";
663 } else if (opt_match(&opts
, "valid-before")) {
664 if (ret
->valid_before
!= 0) {
665 errstr
= "multiple \"valid-before\" clauses";
668 if ((opt
= opt_dequote(&opts
, &errstr
)) == NULL
)
670 if (parse_absolute_time(opt
, &ret
->valid_before
) != 0 ||
671 ret
->valid_before
== 0) {
673 errstr
= "invalid \"valid-before\" time";
679 * Skip the comma, and move to the next option
680 * (or break out if there are no more).
682 if (*opts
== '\0' || *opts
== ' ' || *opts
== '\t')
683 break; /* End of options. */
684 /* Anything other than a comma is an unknown option */
686 errstr
= "unknown key option";
691 errstr
= "unexpected end-of-options";
695 /* final consistency check */
696 if (ret
->valid_after
!= 0 && ret
->valid_before
!= 0 &&
697 ret
->valid_before
<= ret
->valid_after
) {
698 errstr
= "\"valid-before\" time is before \"valid-after\"";
711 sshsigopt_free(struct sshsigopt
*opts
)
715 free(opts
->namespaces
);
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
)
724 char *opts
= NULL
, *tmp
, *cp
, *principals
= NULL
;
725 const char *reason
= NULL
;
726 struct sshsigopt
*sigopts
= NULL
;
727 struct sshkey
*key
= NULL
;
728 int r
= SSH_ERR_INTERNAL_ERROR
;
730 if (principalsp
!= NULL
)
732 if (sigoptsp
!= NULL
)
738 cp
= cp
+ strspn(cp
, " \t"); /* skip leading whitespace */
739 if (*cp
== '#' || *cp
== '\0')
740 return SSH_ERR_KEY_NOT_FOUND
; /* blank or all-comment line */
742 /* format: identity[,identity...] [option[,option...]] key */
743 if ((tmp
= strdelimw(&cp
)) == NULL
|| cp
== NULL
) {
744 error("%s:%lu: invalid line", path
, linenum
);
745 r
= SSH_ERR_INVALID_FORMAT
;
748 if ((principals
= strdup(tmp
)) == NULL
) {
749 error_f("strdup failed");
750 r
= SSH_ERR_ALLOC_FAIL
;
754 * Bail out early if we're looking for a particular principal and this
755 * line does not list it.
757 if (required_principal
!= NULL
) {
758 if (match_pattern_list(required_principal
,
759 principals
, 0) != 1) {
760 /* principal didn't match */
761 r
= SSH_ERR_KEY_NOT_FOUND
;
764 debug_f("%s:%lu: matched principal \"%s\"",
765 path
, linenum
, required_principal
);
768 if ((key
= sshkey_new(KEY_UNSPEC
)) == NULL
) {
769 error_f("sshkey_new failed");
770 r
= SSH_ERR_ALLOC_FAIL
;
773 if (sshkey_read(key
, &cp
) != 0) {
774 /* no key? Check for options */
776 if (sshkey_advance_past_options(&cp
) != 0) {
777 error("%s:%lu: invalid options", path
, linenum
);
778 r
= SSH_ERR_INVALID_FORMAT
;
781 if (cp
== NULL
|| *cp
== '\0') {
782 error("%s:%lu: missing key", path
, linenum
);
783 r
= SSH_ERR_INVALID_FORMAT
;
788 if (sshkey_read(key
, &cp
) != 0) {
789 error("%s:%lu: invalid key", path
, linenum
);
790 r
= SSH_ERR_INVALID_FORMAT
;
794 debug3("%s:%lu: options %s", path
, linenum
, opts
== NULL
? "" : opts
);
795 if ((sigopts
= sshsigopt_parse(opts
, path
, linenum
, &reason
)) == NULL
) {
796 error("%s:%lu: bad options: %s", path
, linenum
, reason
);
797 r
= SSH_ERR_INVALID_FORMAT
;
801 if (principalsp
!= NULL
) {
802 *principalsp
= principals
;
803 principals
= NULL
; /* transferred */
805 if (sigoptsp
!= NULL
) {
807 sigopts
= NULL
; /* transferred */
811 key
= NULL
; /* transferred */
816 sshsigopt_free(sigopts
);
822 cert_filter_principals(const char *path
, u_long linenum
,
823 char **principalsp
, const struct sshkey
*cert
, uint64_t verify_time
)
825 char *cp
, *oprincipals
, *principals
;
827 struct sshbuf
*nprincipals
;
828 int r
= SSH_ERR_INTERNAL_ERROR
, success
= 0;
831 oprincipals
= principals
= *principalsp
;
834 if ((nprincipals
= sshbuf_new()) == NULL
) {
835 r
= SSH_ERR_ALLOC_FAIL
;
839 while ((cp
= strsep(&principals
, ",")) != NULL
&& *cp
!= '\0') {
840 /* Check certificate validity */
841 if ((r
= sshkey_cert_check_authority(cert
, 0, 1, 0,
842 verify_time
, NULL
, &reason
)) != 0) {
843 debug("%s:%lu: principal \"%s\" not authorized: %s",
844 path
, linenum
, cp
, reason
);
847 /* Return all matching principal names from the cert */
848 for (i
= 0; i
< cert
->cert
->nprincipals
; i
++) {
849 if (match_pattern(cert
->cert
->principals
[i
], cp
)) {
850 if ((r
= sshbuf_putf(nprincipals
, "%s%s",
851 sshbuf_len(nprincipals
) != 0 ? "," : "",
852 cert
->cert
->principals
[i
])) != 0) {
853 error_f("buffer error");
859 if (sshbuf_len(nprincipals
) == 0) {
860 error("%s:%lu: no valid principals found", path
, linenum
);
861 r
= SSH_ERR_KEY_CERT_INVALID
;
864 if ((principals
= sshbuf_dup_string(nprincipals
)) == NULL
) {
865 error_f("buffer error");
870 *principalsp
= principals
;
872 sshbuf_free(nprincipals
);
874 return success
? 0 : r
;
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
)
882 struct sshkey
*found_key
= NULL
;
883 char *principals
= NULL
;
885 const char *reason
= NULL
;
886 struct sshsigopt
*sigopts
= NULL
;
887 char tvalid
[64], tverify
[64];
889 if (principalsp
!= NULL
)
893 if ((r
= parse_principals_key_and_options(path
, linenum
, line
,
894 principal
, &principals
, &found_key
, &sigopts
)) != 0) {
895 /* error already logged */
899 if (!sigopts
->ca
&& sshkey_equal(found_key
, sign_key
)) {
900 /* Exact match of key */
901 debug("%s:%lu: matched key", path
, linenum
);
902 } else if (sigopts
->ca
&& sshkey_is_cert(sign_key
) &&
903 sshkey_equal_public(sign_key
->cert
->signature_key
, found_key
)) {
905 /* Match certificate CA key with specified principal */
906 if ((r
= sshkey_cert_check_authority(sign_key
, 0, 1, 0,
907 verify_time
, principal
, &reason
)) != 0) {
908 error("%s:%lu: certificate not authorized: %s",
909 path
, linenum
, reason
);
912 debug("%s:%lu: matched certificate CA key",
915 /* No principal specified - find all matching ones */
916 if ((r
= cert_filter_principals(path
, linenum
,
917 &principals
, sign_key
, verify_time
)) != 0) {
918 /* error already displayed */
919 debug_r(r
, "%s:%lu: cert_filter_principals",
923 debug("%s:%lu: matched certificate CA key",
927 /* Didn't match key */
931 /* Check whether options preclude the use of this key */
932 if (sigopts
->namespaces
!= NULL
&& sig_namespace
!= NULL
&&
933 match_pattern_list(sig_namespace
, sigopts
->namespaces
, 0) != 1) {
934 error("%s:%lu: key is not permitted for use in signature "
935 "namespace \"%s\"", path
, linenum
, sig_namespace
);
939 /* check key time validity */
940 format_absolute_time((uint64_t)verify_time
, tverify
, sizeof(tverify
));
941 if (sigopts
->valid_after
!= 0 &&
942 (uint64_t)verify_time
< sigopts
->valid_after
) {
943 format_absolute_time(sigopts
->valid_after
,
944 tvalid
, sizeof(tvalid
));
945 error("%s:%lu: key is not yet valid: "
946 "verify time %s < valid-after %s", path
, linenum
,
950 if (sigopts
->valid_before
!= 0 &&
951 (uint64_t)verify_time
> sigopts
->valid_before
) {
952 format_absolute_time(sigopts
->valid_before
,
953 tvalid
, sizeof(tvalid
));
954 error("%s:%lu: key has expired: "
955 "verify time %s > valid-before %s", path
, linenum
,
962 if (success
&& principalsp
!= NULL
) {
963 *principalsp
= principals
;
964 principals
= NULL
; /* transferred */
967 sshkey_free(found_key
);
968 sshsigopt_free(sigopts
);
969 return success
? 0 : SSH_ERR_KEY_NOT_FOUND
;
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
)
980 int r
= SSH_ERR_INTERNAL_ERROR
, oerrno
;
982 /* Check key and principal against file */
983 if ((f
= fopen(path
, "r")) == NULL
) {
985 error("Unable to open allowed keys file \"%s\": %s",
986 path
, strerror(errno
));
988 return SSH_ERR_SYSTEM_ERROR
;
991 while (getline(&line
, &linesize
, f
) != -1) {
993 r
= check_allowed_keys_line(path
, linenum
, line
, sign_key
,
994 principal
, sig_namespace
, verify_time
, NULL
);
998 if (r
== SSH_ERR_KEY_NOT_FOUND
)
1007 /* Either we hit an error parsing or we simply didn't find the key */
1010 return r
== 0 ? SSH_ERR_KEY_NOT_FOUND
: r
;
1014 sshsig_find_principals(const char *path
, const struct sshkey
*sign_key
,
1015 uint64_t verify_time
, char **principals
)
1019 size_t linesize
= 0;
1021 int r
= SSH_ERR_INTERNAL_ERROR
, oerrno
;
1023 if ((f
= fopen(path
, "r")) == NULL
) {
1025 error("Unable to open allowed keys file \"%s\": %s",
1026 path
, strerror(errno
));
1028 return SSH_ERR_SYSTEM_ERROR
;
1031 r
= SSH_ERR_KEY_NOT_FOUND
;
1032 while (getline(&line
, &linesize
, f
) != -1) {
1034 r
= check_allowed_keys_line(path
, linenum
, line
,
1035 sign_key
, NULL
, NULL
, verify_time
, principals
);
1039 if (r
== SSH_ERR_KEY_NOT_FOUND
)
1049 /* Either we hit an error parsing or we simply didn't find the key */
1050 if (ferror(f
) != 0) {
1053 error("Unable to read allowed keys file \"%s\": %s",
1054 path
, strerror(errno
));
1056 return SSH_ERR_SYSTEM_ERROR
;
1059 return r
== 0 ? SSH_ERR_KEY_NOT_FOUND
: r
;
1063 sshsig_match_principals(const char *path
, const char *principal
,
1064 char ***principalsp
, size_t *nprincipalsp
)
1067 char *found
, *line
= NULL
, **principals
= NULL
, **tmp
;
1068 size_t i
, nprincipals
= 0, linesize
= 0;
1070 int oerrno
= 0, r
, ret
= 0;
1072 if (principalsp
!= NULL
)
1073 *principalsp
= NULL
;
1074 if (nprincipalsp
!= NULL
)
1077 /* Check key and principal against file */
1078 if ((f
= fopen(path
, "r")) == NULL
) {
1080 error("Unable to open allowed keys file \"%s\": %s",
1081 path
, strerror(errno
));
1083 return SSH_ERR_SYSTEM_ERROR
;
1086 while (getline(&line
, &linesize
, f
) != -1) {
1088 /* Parse the line */
1089 if ((r
= parse_principals_key_and_options(path
, linenum
, line
,
1090 principal
, &found
, NULL
, NULL
)) != 0) {
1091 if (r
== SSH_ERR_KEY_NOT_FOUND
)
1095 break; /* unexpected error */
1097 if ((tmp
= recallocarray(principals
, nprincipals
,
1098 nprincipals
+ 1, sizeof(*principals
))) == NULL
) {
1099 ret
= SSH_ERR_ALLOC_FAIL
;
1104 principals
[nprincipals
++] = found
; /* transferred */
1112 if (nprincipals
== 0)
1113 ret
= SSH_ERR_KEY_NOT_FOUND
;
1114 if (principalsp
!= NULL
) {
1115 *principalsp
= principals
;
1116 principals
= NULL
; /* transferred */
1118 if (nprincipalsp
!= 0) {
1119 *nprincipalsp
= nprincipals
;
1124 for (i
= 0; i
< nprincipals
; i
++)
1125 free(principals
[i
]);
1133 sshsig_get_pubkey(struct sshbuf
*signature
, struct sshkey
**pubkey
)
1135 struct sshkey
*pk
= NULL
;
1136 int r
= SSH_ERR_SIGNATURE_INVALID
;
1139 return SSH_ERR_INTERNAL_ERROR
;
1140 if ((r
= sshsig_parse_preamble(signature
)) != 0)
1142 if ((r
= sshkey_froms(signature
, &pk
)) != 0)