xref: /netbsd-src/crypto/external/bsd/openssh/dist/sshsig.c (revision d16b7486a53dcb8072b60ec6fcb4373a2d0c27b7)
1 /*	$NetBSD: sshsig.c,v 1.10 2022/10/05 22:39:36 christos Exp $	*/
2 /* $OpenBSD: sshsig.c,v 1.30 2022/08/19 03:06:30 djm 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.10 2022/10/05 22:39:36 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 = NULL;
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 			errno = oerrno;
520 			r = SSH_ERR_SYSTEM_ERROR;
521 			goto out;
522 		} else if (n == 0) {
523 			debug2_f("hashed %zu bytes", total);
524 			break; /* EOF */
525 		}
526 		total += (size_t)n;
527 		if ((r = ssh_digest_update(ctx, rbuf, (size_t)n)) != 0) {
528 			error_fr(r, "ssh_digest_update");
529 			goto out;
530 		}
531 	}
532 	if ((r = ssh_digest_final(ctx, (unsigned char *)hash, sizeof(hash))) != 0) {
533 		error_fr(r, "ssh_digest_final");
534 		goto out;
535 	}
536 	if ((hex = tohex(hash, ssh_digest_bytes(alg))) != NULL) {
537 		debug3_f("final hash: %s", hex);
538 		freezero(hex, strlen(hex));
539 	}
540 	if ((b = sshbuf_new()) == NULL) {
541 		r = SSH_ERR_ALLOC_FAIL;
542 		goto out;
543 	}
544 	if ((r = sshbuf_put(b, hash, ssh_digest_bytes(alg))) != 0) {
545 		error_fr(r, "sshbuf_put");
546 		goto out;
547 	}
548 	*bp = b;
549 	b = NULL; /* transferred */
550 	/* success */
551 	r = 0;
552  out:
553 	oerrno = errno;
554 	sshbuf_free(b);
555 	ssh_digest_free(ctx);
556 	explicit_bzero(hash, sizeof(hash));
557 	errno = oerrno;
558 	return r;
559 }
560 
561 int
562 sshsig_sign_fd(struct sshkey *key, const char *hashalg,
563     const char *sk_provider, const char *sk_pin,
564     int fd, const char *sig_namespace, struct sshbuf **out,
565     sshsig_signer *signer, void *signer_ctx)
566 {
567 	struct sshbuf *b = NULL;
568 	int r = SSH_ERR_INTERNAL_ERROR;
569 
570 	if (hashalg == NULL)
571 		hashalg = HASHALG_DEFAULT;
572 	if (out != NULL)
573 		*out = NULL;
574 	if ((r = hash_file(fd, hashalg, &b)) != 0) {
575 		error_fr(r, "hash_file");
576 		return r;
577 	}
578 	if ((r = sshsig_wrap_sign(key, hashalg, sk_provider, sk_pin, b,
579 	    sig_namespace, out, signer, signer_ctx)) != 0)
580 		goto out;
581 	/* success */
582 	r = 0;
583  out:
584 	sshbuf_free(b);
585 	return r;
586 }
587 
588 int
589 sshsig_verify_fd(struct sshbuf *signature, int fd,
590     const char *expect_namespace, struct sshkey **sign_keyp,
591     struct sshkey_sig_details **sig_details)
592 {
593 	struct sshbuf *b = NULL;
594 	int r = SSH_ERR_INTERNAL_ERROR;
595 	char *hashalg = NULL;
596 
597 	if (sig_details != NULL)
598 		*sig_details = NULL;
599 	if (sign_keyp != NULL)
600 		*sign_keyp = NULL;
601 	if ((r = sshsig_peek_hashalg(signature, &hashalg)) != 0)
602 		return r;
603 	debug_f("signature made with hash \"%s\"", hashalg);
604 	if ((r = hash_file(fd, hashalg, &b)) != 0) {
605 		error_fr(r, "hash_file");
606 		goto out;
607 	}
608 	if ((r = sshsig_wrap_verify(signature, hashalg, b, expect_namespace,
609 	    sign_keyp, sig_details)) != 0)
610 		goto out;
611 	/* success */
612 	r = 0;
613  out:
614 	sshbuf_free(b);
615 	free(hashalg);
616 	return r;
617 }
618 
619 struct sshsigopt {
620 	int ca;
621 	char *namespaces;
622 	uint64_t valid_after, valid_before;
623 };
624 
625 struct sshsigopt *
626 sshsigopt_parse(const char *opts, const char *path, u_long linenum,
627     const char **errstrp)
628 {
629 	struct sshsigopt *ret;
630 	int r;
631 	char *opt;
632 	const char *errstr = NULL;
633 
634 	if ((ret = calloc(1, sizeof(*ret))) == NULL)
635 		return NULL;
636 	if (opts == NULL || *opts == '\0')
637 		return ret; /* Empty options yields empty options :) */
638 
639 	while (*opts && *opts != ' ' && *opts != '\t') {
640 		/* flag options */
641 		if ((r = opt_flag("cert-authority", 0, &opts)) != -1) {
642 			ret->ca = 1;
643 		} else if (opt_match(&opts, "namespaces")) {
644 			if (ret->namespaces != NULL) {
645 				errstr = "multiple \"namespaces\" clauses";
646 				goto fail;
647 			}
648 			ret->namespaces = opt_dequote(&opts, &errstr);
649 			if (ret->namespaces == NULL)
650 				goto fail;
651 		} else if (opt_match(&opts, "valid-after")) {
652 			if (ret->valid_after != 0) {
653 				errstr = "multiple \"valid-after\" clauses";
654 				goto fail;
655 			}
656 			if ((opt = opt_dequote(&opts, &errstr)) == NULL)
657 				goto fail;
658 			if (parse_absolute_time(opt, &ret->valid_after) != 0 ||
659 			    ret->valid_after == 0) {
660 				free(opt);
661 				errstr = "invalid \"valid-after\" time";
662 				goto fail;
663 			}
664 			free(opt);
665 		} else if (opt_match(&opts, "valid-before")) {
666 			if (ret->valid_before != 0) {
667 				errstr = "multiple \"valid-before\" clauses";
668 				goto fail;
669 			}
670 			if ((opt = opt_dequote(&opts, &errstr)) == NULL)
671 				goto fail;
672 			if (parse_absolute_time(opt, &ret->valid_before) != 0 ||
673 			    ret->valid_before == 0) {
674 				free(opt);
675 				errstr = "invalid \"valid-before\" time";
676 				goto fail;
677 			}
678 			free(opt);
679 		}
680 		/*
681 		 * Skip the comma, and move to the next option
682 		 * (or break out if there are no more).
683 		 */
684 		if (*opts == '\0' || *opts == ' ' || *opts == '\t')
685 			break;		/* End of options. */
686 		/* Anything other than a comma is an unknown option */
687 		if (*opts != ',') {
688 			errstr = "unknown key option";
689 			goto fail;
690 		}
691 		opts++;
692 		if (*opts == '\0') {
693 			errstr = "unexpected end-of-options";
694 			goto fail;
695 		}
696 	}
697 	/* final consistency check */
698 	if (ret->valid_after != 0 && ret->valid_before != 0 &&
699 	    ret->valid_before <= ret->valid_after) {
700 		errstr = "\"valid-before\" time is before \"valid-after\"";
701 		goto fail;
702 	}
703 	/* success */
704 	return ret;
705  fail:
706 	if (errstrp != NULL)
707 		*errstrp = errstr;
708 	sshsigopt_free(ret);
709 	return NULL;
710 }
711 
712 void
713 sshsigopt_free(struct sshsigopt *opts)
714 {
715 	if (opts == NULL)
716 		return;
717 	free(opts->namespaces);
718 	free(opts);
719 }
720 
721 static int
722 parse_principals_key_and_options(const char *path, u_long linenum, char *line,
723     const char *required_principal, char **principalsp, struct sshkey **keyp,
724     struct sshsigopt **sigoptsp)
725 {
726 	char *opts = NULL, *tmp, *cp, *principals = NULL;
727 	const char *reason = NULL;
728 	struct sshsigopt *sigopts = NULL;
729 	struct sshkey *key = NULL;
730 	int r = SSH_ERR_INTERNAL_ERROR;
731 
732 	if (principalsp != NULL)
733 		*principalsp = NULL;
734 	if (sigoptsp != NULL)
735 		*sigoptsp = NULL;
736 	if (keyp != NULL)
737 		*keyp = NULL;
738 
739 	cp = line;
740 	cp = cp + strspn(cp, " \t"); /* skip leading whitespace */
741 	if (*cp == '#' || *cp == '\0')
742 		return SSH_ERR_KEY_NOT_FOUND; /* blank or all-comment line */
743 
744 	/* format: identity[,identity...] [option[,option...]] key */
745 	if ((tmp = strdelimw(&cp)) == NULL || cp == NULL) {
746 		error("%s:%lu: invalid line", path, linenum);
747 		r = SSH_ERR_INVALID_FORMAT;
748 		goto out;
749 	}
750 	if ((principals = strdup(tmp)) == NULL) {
751 		error_f("strdup failed");
752 		r = SSH_ERR_ALLOC_FAIL;
753 		goto out;
754 	}
755 	/*
756 	 * Bail out early if we're looking for a particular principal and this
757 	 * line does not list it.
758 	 */
759 	if (required_principal != NULL) {
760 		if (match_pattern_list(required_principal,
761 		    principals, 0) != 1) {
762 			/* principal didn't match */
763 			r = SSH_ERR_KEY_NOT_FOUND;
764 			goto out;
765 		}
766 		debug_f("%s:%lu: matched principal \"%s\"",
767 		    path, linenum, required_principal);
768 	}
769 
770 	if ((key = sshkey_new(KEY_UNSPEC)) == NULL) {
771 		error_f("sshkey_new failed");
772 		r = SSH_ERR_ALLOC_FAIL;
773 		goto out;
774 	}
775 	if (sshkey_read(key, &cp) != 0) {
776 		/* no key? Check for options */
777 		opts = cp;
778 		if (sshkey_advance_past_options(&cp) != 0) {
779 			error("%s:%lu: invalid options", path, linenum);
780 			r = SSH_ERR_INVALID_FORMAT;
781 			goto out;
782 		}
783 		if (cp == NULL || *cp == '\0') {
784 			error("%s:%lu: missing key", path, linenum);
785 			r = SSH_ERR_INVALID_FORMAT;
786 			goto out;
787 		}
788 		*cp++ = '\0';
789 		skip_space(&cp);
790 		if (sshkey_read(key, &cp) != 0) {
791 			error("%s:%lu: invalid key", path, linenum);
792 			r = SSH_ERR_INVALID_FORMAT;
793 			goto out;
794 		}
795 	}
796 	debug3("%s:%lu: options %s", path, linenum, opts == NULL ? "" : opts);
797 	if ((sigopts = sshsigopt_parse(opts, path, linenum, &reason)) == NULL) {
798 		error("%s:%lu: bad options: %s", path, linenum, reason);
799 		r = SSH_ERR_INVALID_FORMAT;
800 		goto out;
801 	}
802 	/* success */
803 	if (principalsp != NULL) {
804 		*principalsp = principals;
805 		principals = NULL; /* transferred */
806 	}
807 	if (sigoptsp != NULL) {
808 		*sigoptsp = sigopts;
809 		sigopts = NULL; /* transferred */
810 	}
811 	if (keyp != NULL) {
812 		*keyp = key;
813 		key = NULL; /* transferred */
814 	}
815 	r = 0;
816  out:
817 	free(principals);
818 	sshsigopt_free(sigopts);
819 	sshkey_free(key);
820 	return r;
821 }
822 
823 static int
824 cert_filter_principals(const char *path, u_long linenum,
825     char **principalsp, const struct sshkey *cert, uint64_t verify_time)
826 {
827 	char *cp, *oprincipals, *principals;
828 	const char *reason;
829 	struct sshbuf *nprincipals;
830 	int r = SSH_ERR_INTERNAL_ERROR, success = 0;
831 	u_int i;
832 
833 	oprincipals = principals = *principalsp;
834 	*principalsp = NULL;
835 
836 	if ((nprincipals = sshbuf_new()) == NULL) {
837 		r = SSH_ERR_ALLOC_FAIL;
838 		goto out;
839 	}
840 
841 	while ((cp = strsep(&principals, ",")) != NULL && *cp != '\0') {
842 		/* Check certificate validity */
843 		if ((r = sshkey_cert_check_authority(cert, 0, 1, 0,
844 		    verify_time, NULL, &reason)) != 0) {
845 			debug("%s:%lu: principal \"%s\" not authorized: %s",
846 			    path, linenum, cp, reason);
847 			continue;
848 		}
849 		/* Return all matching principal names from the cert */
850 		for (i = 0; i < cert->cert->nprincipals; i++) {
851 			if (match_pattern(cert->cert->principals[i], cp)) {
852 				if ((r = sshbuf_putf(nprincipals, "%s%s",
853 					sshbuf_len(nprincipals) != 0 ? "," : "",
854 						cert->cert->principals[i])) != 0) {
855 					error_f("buffer error");
856 					goto out;
857 				}
858 			}
859 		}
860 	}
861 	if (sshbuf_len(nprincipals) == 0) {
862 		error("%s:%lu: no valid principals found", path, linenum);
863 		r = SSH_ERR_KEY_CERT_INVALID;
864 		goto out;
865 	}
866 	if ((principals = sshbuf_dup_string(nprincipals)) == NULL) {
867 		error_f("buffer error");
868 		goto out;
869 	}
870 	/* success */
871 	success = 1;
872 	*principalsp = principals;
873  out:
874 	sshbuf_free(nprincipals);
875 	free(oprincipals);
876 	return success ? 0 : r;
877 }
878 
879 static int
880 check_allowed_keys_line(const char *path, u_long linenum, char *line,
881     const struct sshkey *sign_key, const char *principal,
882     const char *sig_namespace, uint64_t verify_time, char **principalsp)
883 {
884 	struct sshkey *found_key = NULL;
885 	char *principals = NULL;
886 	int r, success = 0;
887 	const char *reason = NULL;
888 	struct sshsigopt *sigopts = NULL;
889 	char tvalid[64], tverify[64];
890 
891 	if (principalsp != NULL)
892 		*principalsp = NULL;
893 
894 	/* Parse the line */
895 	if ((r = parse_principals_key_and_options(path, linenum, line,
896 	    principal, &principals, &found_key, &sigopts)) != 0) {
897 		/* error already logged */
898 		goto done;
899 	}
900 
901 	if (!sigopts->ca && sshkey_equal(found_key, sign_key)) {
902 		/* Exact match of key */
903 		debug("%s:%lu: matched key", path, linenum);
904 	} else if (sigopts->ca && sshkey_is_cert(sign_key) &&
905 	    sshkey_equal_public(sign_key->cert->signature_key, found_key)) {
906 		if (principal) {
907 			/* Match certificate CA key with specified principal */
908 			if ((r = sshkey_cert_check_authority(sign_key, 0, 1, 0,
909 			    verify_time, principal, &reason)) != 0) {
910 				error("%s:%lu: certificate not authorized: %s",
911 				    path, linenum, reason);
912 				goto done;
913 			}
914 			debug("%s:%lu: matched certificate CA key",
915 			    path, linenum);
916 		} else {
917 			/* No principal specified - find all matching ones */
918 			if ((r = cert_filter_principals(path, linenum,
919 			    &principals, sign_key, verify_time)) != 0) {
920 				/* error already displayed */
921 				debug_r(r, "%s:%lu: cert_filter_principals",
922 				    path, linenum);
923 				goto done;
924 			}
925 			debug("%s:%lu: matched certificate CA key",
926 			    path, linenum);
927 		}
928 	} else {
929 		/* Didn't match key */
930 		goto done;
931 	}
932 
933 	/* Check whether options preclude the use of this key */
934 	if (sigopts->namespaces != NULL && sig_namespace != NULL &&
935 	    match_pattern_list(sig_namespace, sigopts->namespaces, 0) != 1) {
936 		error("%s:%lu: key is not permitted for use in signature "
937 		    "namespace \"%s\"", path, linenum, sig_namespace);
938 		goto done;
939 	}
940 
941 	/* check key time validity */
942 	format_absolute_time((uint64_t)verify_time, tverify, sizeof(tverify));
943 	if (sigopts->valid_after != 0 &&
944 	    (uint64_t)verify_time < sigopts->valid_after) {
945 		format_absolute_time(sigopts->valid_after,
946 		    tvalid, sizeof(tvalid));
947 		error("%s:%lu: key is not yet valid: "
948 		    "verify time %s < valid-after %s", path, linenum,
949 		    tverify, tvalid);
950 		goto done;
951 	}
952 	if (sigopts->valid_before != 0 &&
953 	    (uint64_t)verify_time > sigopts->valid_before) {
954 		format_absolute_time(sigopts->valid_before,
955 		    tvalid, sizeof(tvalid));
956 		error("%s:%lu: key has expired: "
957 		    "verify time %s > valid-before %s", path, linenum,
958 		    tverify, tvalid);
959 		goto done;
960 	}
961 	success = 1;
962 
963  done:
964 	if (success && principalsp != NULL) {
965 		*principalsp = principals;
966 		principals = NULL; /* transferred */
967 	}
968 	free(principals);
969 	sshkey_free(found_key);
970 	sshsigopt_free(sigopts);
971 	return success ? 0 : SSH_ERR_KEY_NOT_FOUND;
972 }
973 
974 int
975 sshsig_check_allowed_keys(const char *path, const struct sshkey *sign_key,
976     const char *principal, const char *sig_namespace, uint64_t verify_time)
977 {
978 	FILE *f = NULL;
979 	char *line = NULL;
980 	size_t linesize = 0;
981 	u_long linenum = 0;
982 	int r = SSH_ERR_INTERNAL_ERROR, oerrno;
983 
984 	/* Check key and principal against file */
985 	if ((f = fopen(path, "r")) == NULL) {
986 		oerrno = errno;
987 		error("Unable to open allowed keys file \"%s\": %s",
988 		    path, strerror(errno));
989 		errno = oerrno;
990 		return SSH_ERR_SYSTEM_ERROR;
991 	}
992 
993 	while (getline(&line, &linesize, f) != -1) {
994 		linenum++;
995 		r = check_allowed_keys_line(path, linenum, line, sign_key,
996 		    principal, sig_namespace, verify_time, NULL);
997 		free(line);
998 		line = NULL;
999 		linesize = 0;
1000 		if (r == SSH_ERR_KEY_NOT_FOUND)
1001 			continue;
1002 		else if (r == 0) {
1003 			/* success */
1004 			fclose(f);
1005 			return 0;
1006 		} else
1007 			break;
1008 	}
1009 	/* Either we hit an error parsing or we simply didn't find the key */
1010 	fclose(f);
1011 	free(line);
1012 	return r == 0 ? SSH_ERR_KEY_NOT_FOUND : r;
1013 }
1014 
1015 int
1016 sshsig_find_principals(const char *path, const struct sshkey *sign_key,
1017     uint64_t verify_time, char **principals)
1018 {
1019 	FILE *f = NULL;
1020 	char *line = NULL;
1021 	size_t linesize = 0;
1022 	u_long linenum = 0;
1023 	int r = SSH_ERR_INTERNAL_ERROR, oerrno;
1024 
1025 	if ((f = fopen(path, "r")) == NULL) {
1026 		oerrno = errno;
1027 		error("Unable to open allowed keys file \"%s\": %s",
1028 		    path, strerror(errno));
1029 		errno = oerrno;
1030 		return SSH_ERR_SYSTEM_ERROR;
1031 	}
1032 
1033 	r = SSH_ERR_KEY_NOT_FOUND;
1034 	while (getline(&line, &linesize, f) != -1) {
1035 		linenum++;
1036 		r = check_allowed_keys_line(path, linenum, line,
1037 		    sign_key, NULL, NULL, verify_time, principals);
1038 		free(line);
1039 		line = NULL;
1040 		linesize = 0;
1041 		if (r == SSH_ERR_KEY_NOT_FOUND)
1042 			continue;
1043 		else if (r == 0) {
1044 			/* success */
1045 			fclose(f);
1046 			return 0;
1047 		} else
1048 			break;
1049 	}
1050 	free(line);
1051 	/* Either we hit an error parsing or we simply didn't find the key */
1052 	if (ferror(f) != 0) {
1053 		oerrno = errno;
1054 		fclose(f);
1055 		error("Unable to read allowed keys file \"%s\": %s",
1056 		    path, strerror(errno));
1057 		errno = oerrno;
1058 		return SSH_ERR_SYSTEM_ERROR;
1059 	}
1060 	fclose(f);
1061 	return r == 0 ? SSH_ERR_KEY_NOT_FOUND : r;
1062 }
1063 
1064 int
1065 sshsig_match_principals(const char *path, const char *principal,
1066     char ***principalsp, size_t *nprincipalsp)
1067 {
1068 	FILE *f = NULL;
1069 	char *found, *line = NULL, **principals = NULL, **tmp;
1070 	size_t i, nprincipals = 0, linesize = 0;
1071 	u_long linenum = 0;
1072 	int oerrno = 0, r, ret = 0;
1073 
1074 	if (principalsp != NULL)
1075 		*principalsp = NULL;
1076 	if (nprincipalsp != NULL)
1077 		*nprincipalsp = 0;
1078 
1079 	/* Check key and principal against file */
1080 	if ((f = fopen(path, "r")) == NULL) {
1081 		oerrno = errno;
1082 		error("Unable to open allowed keys file \"%s\": %s",
1083 		    path, strerror(errno));
1084 		errno = oerrno;
1085 		return SSH_ERR_SYSTEM_ERROR;
1086 	}
1087 
1088 	while (getline(&line, &linesize, f) != -1) {
1089 		linenum++;
1090 		/* Parse the line */
1091 		if ((r = parse_principals_key_and_options(path, linenum, line,
1092 		    principal, &found, NULL, NULL)) != 0) {
1093 			if (r == SSH_ERR_KEY_NOT_FOUND)
1094 				continue;
1095 			ret = r;
1096 			oerrno = errno;
1097 			break; /* unexpected error */
1098 		}
1099 		if ((tmp = recallocarray(principals, nprincipals,
1100 		    nprincipals + 1, sizeof(*principals))) == NULL) {
1101 			ret = SSH_ERR_ALLOC_FAIL;
1102 			free(found);
1103 			break;
1104 		}
1105 		principals = tmp;
1106 		principals[nprincipals++] = found; /* transferred */
1107 		free(line);
1108 		line = NULL;
1109 		linesize = 0;
1110 	}
1111 	fclose(f);
1112 
1113 	if (ret == 0) {
1114 		if (nprincipals == 0)
1115 			ret = SSH_ERR_KEY_NOT_FOUND;
1116 		if (principalsp != NULL) {
1117 			*principalsp = principals;
1118 			principals = NULL; /* transferred */
1119 		}
1120 		if (nprincipalsp != 0) {
1121 			*nprincipalsp = nprincipals;
1122 			nprincipals = 0;
1123 		}
1124 	}
1125 
1126 	for (i = 0; i < nprincipals; i++)
1127 		free(principals[i]);
1128 	free(principals);
1129 
1130 	errno = oerrno;
1131 	return ret;
1132 }
1133 
1134 int
1135 sshsig_get_pubkey(struct sshbuf *signature, struct sshkey **pubkey)
1136 {
1137 	struct sshkey *pk = NULL;
1138 	int r = SSH_ERR_SIGNATURE_INVALID;
1139 
1140 	if (pubkey == NULL)
1141 		return SSH_ERR_INTERNAL_ERROR;
1142 	if ((r = sshsig_parse_preamble(signature)) != 0)
1143 		return r;
1144 	if ((r = sshkey_froms(signature, &pk)) != 0)
1145 		return r;
1146 
1147 	*pubkey = pk;
1148 	pk = NULL;
1149 	return 0;
1150 }
1151