xref: /openbsd-src/usr.bin/ssh/sshsig.c (revision 1a8dbaac879b9f3335ad7fb25429ce63ac1d6bac)
1 /* $OpenBSD: sshsig.c,v 1.17 2020/08/31 00:17:41 djm Exp $ */
2 /*
3  * Copyright (c) 2019 Google LLC
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <stdarg.h>
21 #include <errno.h>
22 #include <string.h>
23 #include <unistd.h>
24 
25 #include "authfd.h"
26 #include "authfile.h"
27 #include "log.h"
28 #include "misc.h"
29 #include "sshbuf.h"
30 #include "sshsig.h"
31 #include "ssherr.h"
32 #include "sshkey.h"
33 #include "match.h"
34 #include "digest.h"
35 
36 #define SIG_VERSION		0x01
37 #define MAGIC_PREAMBLE		"SSHSIG"
38 #define MAGIC_PREAMBLE_LEN	(sizeof(MAGIC_PREAMBLE) - 1)
39 #define BEGIN_SIGNATURE		"-----BEGIN SSH SIGNATURE-----\n"
40 #define END_SIGNATURE		"-----END SSH SIGNATURE-----"
41 #define RSA_SIGN_ALG		"rsa-sha2-512" /* XXX maybe make configurable */
42 #define RSA_SIGN_ALLOWED	"rsa-sha2-512,rsa-sha2-256"
43 #define HASHALG_DEFAULT		"sha512" /* XXX maybe make configurable */
44 #define HASHALG_ALLOWED		"sha256,sha512"
45 
46 int
47 sshsig_armor(const struct sshbuf *blob, struct sshbuf **out)
48 {
49 	struct sshbuf *buf = NULL;
50 	int r = SSH_ERR_INTERNAL_ERROR;
51 
52 	*out = NULL;
53 
54 	if ((buf = sshbuf_new()) == NULL) {
55 		error("%s: sshbuf_new failed", __func__);
56 		r = SSH_ERR_ALLOC_FAIL;
57 		goto out;
58 	}
59 
60 	if ((r = sshbuf_put(buf, BEGIN_SIGNATURE,
61 	    sizeof(BEGIN_SIGNATURE)-1)) != 0) {
62 		error("%s: sshbuf_putf failed: %s", __func__, ssh_err(r));
63 		goto out;
64 	}
65 
66 	if ((r = sshbuf_dtob64(blob, buf, 1)) != 0) {
67 		error("%s: Couldn't base64 encode signature blob: %s",
68 		    __func__, ssh_err(r));
69 		goto out;
70 	}
71 
72 	if ((r = sshbuf_put(buf, END_SIGNATURE,
73 	    sizeof(END_SIGNATURE)-1)) != 0 ||
74 	    (r = sshbuf_put_u8(buf, '\n')) != 0) {
75 		error("%s: sshbuf_put failed: %s", __func__, ssh_err(r));
76 		goto out;
77 	}
78 	/* success */
79 	*out = buf;
80 	buf = NULL; /* transferred */
81 	r = 0;
82  out:
83 	sshbuf_free(buf);
84 	return r;
85 }
86 
87 int
88 sshsig_dearmor(struct sshbuf *sig, struct sshbuf **out)
89 {
90 	int r;
91 	size_t eoffset = 0;
92 	struct sshbuf *buf = NULL;
93 	struct sshbuf *sbuf = NULL;
94 	char *b64 = NULL;
95 
96 	if ((sbuf = sshbuf_fromb(sig)) == NULL) {
97 		error("%s: sshbuf_fromb failed", __func__);
98 		return SSH_ERR_ALLOC_FAIL;
99 	}
100 
101 	if ((r = sshbuf_cmp(sbuf, 0,
102 	    BEGIN_SIGNATURE, sizeof(BEGIN_SIGNATURE)-1)) != 0) {
103 		error("Couldn't parse signature: missing header");
104 		goto done;
105 	}
106 
107 	if ((r = sshbuf_consume(sbuf, sizeof(BEGIN_SIGNATURE)-1)) != 0) {
108 		error("%s: sshbuf_consume failed: %s", __func__, ssh_err(r));
109 		goto done;
110 	}
111 
112 	if ((r = sshbuf_find(sbuf, 0, "\n" END_SIGNATURE,
113 	    sizeof("\n" END_SIGNATURE)-1, &eoffset)) != 0) {
114 		error("Couldn't parse signature: missing footer");
115 		goto done;
116 	}
117 
118 	if ((r = sshbuf_consume_end(sbuf, sshbuf_len(sbuf)-eoffset)) != 0) {
119 		error("%s: sshbuf_consume failed: %s", __func__, ssh_err(r));
120 		goto done;
121 	}
122 
123 	if ((b64 = sshbuf_dup_string(sbuf)) == NULL) {
124 		error("%s: sshbuf_dup_string failed", __func__);
125 		r = SSH_ERR_ALLOC_FAIL;
126 		goto done;
127 	}
128 
129 	if ((buf = sshbuf_new()) == NULL) {
130 		error("%s: sshbuf_new() failed", __func__);
131 		r = SSH_ERR_ALLOC_FAIL;
132 		goto done;
133 	}
134 
135 	if ((r = sshbuf_b64tod(buf, b64)) != 0) {
136 		error("Couldn't decode signature: %s", ssh_err(r));
137 		goto done;
138 	}
139 
140 	/* success */
141 	*out = buf;
142 	r = 0;
143 	buf = NULL; /* transferred */
144 done:
145 	sshbuf_free(buf);
146 	sshbuf_free(sbuf);
147 	free(b64);
148 	return r;
149 }
150 
151 static int
152 sshsig_wrap_sign(struct sshkey *key, const char *hashalg,
153     const char *sk_provider, const char *sk_pin, const struct sshbuf *h_message,
154     const char *sig_namespace, struct sshbuf **out,
155     sshsig_signer *signer, void *signer_ctx)
156 {
157 	int r;
158 	size_t slen = 0;
159 	u_char *sig = NULL;
160 	struct sshbuf *blob = NULL;
161 	struct sshbuf *tosign = NULL;
162 	const char *sign_alg = NULL;
163 
164 	if ((tosign = sshbuf_new()) == NULL ||
165 	    (blob = sshbuf_new()) == NULL) {
166 		error("%s: sshbuf_new failed", __func__);
167 		r = SSH_ERR_ALLOC_FAIL;
168 		goto done;
169 	}
170 
171 	if ((r = sshbuf_put(tosign, MAGIC_PREAMBLE, MAGIC_PREAMBLE_LEN)) != 0 ||
172 	    (r = sshbuf_put_cstring(tosign, sig_namespace)) != 0 ||
173 	    (r = sshbuf_put_string(tosign, NULL, 0)) != 0 || /* reserved */
174 	    (r = sshbuf_put_cstring(tosign, hashalg)) != 0 ||
175 	    (r = sshbuf_put_stringb(tosign, h_message)) != 0) {
176 		error("Couldn't construct message to sign: %s", ssh_err(r));
177 		goto done;
178 	}
179 
180 	/* If using RSA keys then default to a good signature algorithm */
181 	if (sshkey_type_plain(key->type) == KEY_RSA)
182 		sign_alg = RSA_SIGN_ALG;
183 
184 	if (signer != NULL) {
185 		if ((r = signer(key, &sig, &slen,
186 		    sshbuf_ptr(tosign), sshbuf_len(tosign),
187 		    sign_alg, sk_provider, sk_pin, 0, signer_ctx)) != 0) {
188 			error("Couldn't sign message: %s", ssh_err(r));
189 			goto done;
190 		}
191 	} else {
192 		if ((r = sshkey_sign(key, &sig, &slen,
193 		    sshbuf_ptr(tosign), sshbuf_len(tosign),
194 		    sign_alg, sk_provider, sk_pin, 0)) != 0) {
195 			error("Couldn't sign message: %s", ssh_err(r));
196 			goto done;
197 		}
198 	}
199 
200 	if ((r = sshbuf_put(blob, MAGIC_PREAMBLE, MAGIC_PREAMBLE_LEN)) != 0 ||
201 	    (r = sshbuf_put_u32(blob, SIG_VERSION)) != 0 ||
202 	    (r = sshkey_puts(key, blob)) != 0 ||
203 	    (r = sshbuf_put_cstring(blob, sig_namespace)) != 0 ||
204 	    (r = sshbuf_put_string(blob, NULL, 0)) != 0 || /* reserved */
205 	    (r = sshbuf_put_cstring(blob, hashalg)) != 0 ||
206 	    (r = sshbuf_put_string(blob, sig, slen)) != 0) {
207 		error("Couldn't populate blob: %s", ssh_err(r));
208 		goto done;
209 	}
210 
211 	if (out != NULL) {
212 		*out = blob;
213 		blob = NULL;
214 	}
215 	r = 0;
216 done:
217 	free(sig);
218 	sshbuf_free(blob);
219 	sshbuf_free(tosign);
220 	return r;
221 }
222 
223 /* Check preamble and version. */
224 static int
225 sshsig_parse_preamble(struct sshbuf *buf)
226 {
227 	int r = SSH_ERR_INTERNAL_ERROR;
228 	uint32_t sversion;
229 
230 	if ((r = sshbuf_cmp(buf, 0, MAGIC_PREAMBLE, MAGIC_PREAMBLE_LEN)) != 0 ||
231 	    (r = sshbuf_consume(buf, (sizeof(MAGIC_PREAMBLE)-1))) != 0 ||
232 	    (r = sshbuf_get_u32(buf, &sversion)) != 0) {
233 		error("Couldn't verify signature: invalid format");
234 		return r;
235 	}
236 
237 	if (sversion > SIG_VERSION) {
238 		error("Signature version %lu is larger than supported "
239 		    "version %u", (unsigned long)sversion, SIG_VERSION);
240 		return SSH_ERR_INVALID_FORMAT;
241 	}
242 	return 0;
243 }
244 
245 static int
246 sshsig_check_hashalg(const char *hashalg)
247 {
248 	if (hashalg == NULL ||
249 	    match_pattern_list(hashalg, HASHALG_ALLOWED, 0) == 1)
250 		return 0;
251 	error("%s: unsupported hash algorithm \"%.100s\"", __func__, hashalg);
252 	return SSH_ERR_SIGN_ALG_UNSUPPORTED;
253 }
254 
255 static int
256 sshsig_peek_hashalg(struct sshbuf *signature, char **hashalgp)
257 {
258 	struct sshbuf *buf = NULL;
259 	char *hashalg = NULL;
260 	int r = SSH_ERR_INTERNAL_ERROR;
261 
262 	if (hashalgp != NULL)
263 		*hashalgp = NULL;
264 	if ((buf = sshbuf_fromb(signature)) == NULL)
265 		return SSH_ERR_ALLOC_FAIL;
266 	if ((r = sshsig_parse_preamble(buf)) != 0)
267 		goto done;
268 	if ((r = sshbuf_get_string_direct(buf, NULL, NULL)) != 0 ||
269 	    (r = sshbuf_get_string_direct(buf, NULL, NULL)) != 0 ||
270 	    (r = sshbuf_get_string(buf, NULL, NULL)) != 0 ||
271 	    (r = sshbuf_get_cstring(buf, &hashalg, NULL)) != 0 ||
272 	    (r = sshbuf_get_string_direct(buf, NULL, NULL)) != 0) {
273 		error("Couldn't parse signature blob: %s", ssh_err(r));
274 		goto done;
275 	}
276 
277 	/* success */
278 	r = 0;
279 	*hashalgp = hashalg;
280 	hashalg = NULL;
281  done:
282 	free(hashalg);
283 	sshbuf_free(buf);
284 	return r;
285 }
286 
287 static int
288 sshsig_wrap_verify(struct sshbuf *signature, const char *hashalg,
289     const struct sshbuf *h_message, const char *expect_namespace,
290     struct sshkey **sign_keyp, struct sshkey_sig_details **sig_details)
291 {
292 	int r = SSH_ERR_INTERNAL_ERROR;
293 	struct sshbuf *buf = NULL, *toverify = NULL;
294 	struct sshkey *key = NULL;
295 	const u_char *sig;
296 	char *got_namespace = NULL, *sigtype = NULL, *sig_hashalg = NULL;
297 	size_t siglen;
298 
299 	debug("%s: verify message length %zu", __func__, sshbuf_len(h_message));
300 	if (sig_details != NULL)
301 		*sig_details = NULL;
302 	if (sign_keyp != NULL)
303 		*sign_keyp = NULL;
304 
305 	if ((toverify = sshbuf_new()) == NULL) {
306 		error("%s: sshbuf_new failed", __func__);
307 		r = SSH_ERR_ALLOC_FAIL;
308 		goto done;
309 	}
310 	if ((r = sshbuf_put(toverify, MAGIC_PREAMBLE,
311 	    MAGIC_PREAMBLE_LEN)) != 0 ||
312 	    (r = sshbuf_put_cstring(toverify, expect_namespace)) != 0 ||
313 	    (r = sshbuf_put_string(toverify, NULL, 0)) != 0 || /* reserved */
314 	    (r = sshbuf_put_cstring(toverify, hashalg)) != 0 ||
315 	    (r = sshbuf_put_stringb(toverify, h_message)) != 0) {
316 		error("Couldn't construct message to verify: %s", ssh_err(r));
317 		goto done;
318 	}
319 
320 	if ((r = sshsig_parse_preamble(signature)) != 0)
321 		goto done;
322 
323 	if ((r = sshkey_froms(signature, &key)) != 0 ||
324 	    (r = sshbuf_get_cstring(signature, &got_namespace, NULL)) != 0 ||
325 	    (r = sshbuf_get_string(signature, NULL, NULL)) != 0 ||
326 	    (r = sshbuf_get_cstring(signature, &sig_hashalg, NULL)) != 0 ||
327 	    (r = sshbuf_get_string_direct(signature, &sig, &siglen)) != 0) {
328 		error("Couldn't parse signature blob: %s", ssh_err(r));
329 		goto done;
330 	}
331 
332 	if (sshbuf_len(signature) != 0) {
333 		error("Signature contains trailing data");
334 		r = SSH_ERR_INVALID_FORMAT;
335 		goto done;
336 	}
337 
338 	if (strcmp(expect_namespace, got_namespace) != 0) {
339 		error("Couldn't verify signature: namespace does not match");
340 		debug("%s: expected namespace \"%s\" received \"%s\"",
341 		    __func__, expect_namespace, got_namespace);
342 		r = SSH_ERR_SIGNATURE_INVALID;
343 		goto done;
344 	}
345 	if (strcmp(hashalg, sig_hashalg) != 0) {
346 		error("Couldn't verify signature: hash algorithm mismatch");
347 		debug("%s: expected algorithm \"%s\" received \"%s\"",
348 		    __func__, hashalg, sig_hashalg);
349 		r = SSH_ERR_SIGNATURE_INVALID;
350 		goto done;
351 	}
352 	/* Ensure that RSA keys use an acceptable signature algorithm */
353 	if (sshkey_type_plain(key->type) == KEY_RSA) {
354 		if ((r = sshkey_get_sigtype(sig, siglen, &sigtype)) != 0) {
355 			error("Couldn't verify signature: unable to get "
356 			    "signature type: %s", ssh_err(r));
357 			goto done;
358 		}
359 		if (match_pattern_list(sigtype, RSA_SIGN_ALLOWED, 0) != 1) {
360 			error("Couldn't verify signature: unsupported RSA "
361 			    "signature algorithm %s", sigtype);
362 			r = SSH_ERR_SIGN_ALG_UNSUPPORTED;
363 			goto done;
364 		}
365 	}
366 	if ((r = sshkey_verify(key, sig, siglen, sshbuf_ptr(toverify),
367 	    sshbuf_len(toverify), NULL, 0, sig_details)) != 0) {
368 		error("Signature verification failed: %s", ssh_err(r));
369 		goto done;
370 	}
371 
372 	/* success */
373 	r = 0;
374 	if (sign_keyp != NULL) {
375 		*sign_keyp = key;
376 		key = NULL; /* transferred */
377 	}
378 done:
379 	free(got_namespace);
380 	free(sigtype);
381 	free(sig_hashalg);
382 	sshbuf_free(buf);
383 	sshbuf_free(toverify);
384 	sshkey_free(key);
385 	return r;
386 }
387 
388 static int
389 hash_buffer(const struct sshbuf *m, const char *hashalg, struct sshbuf **bp)
390 {
391 	char *hex, hash[SSH_DIGEST_MAX_LENGTH];
392 	int alg, r = SSH_ERR_INTERNAL_ERROR;
393 	struct sshbuf *b = NULL;
394 
395 	*bp = NULL;
396 	memset(hash, 0, sizeof(hash));
397 
398 	if ((r = sshsig_check_hashalg(hashalg)) != 0)
399 		return r;
400 	if ((alg = ssh_digest_alg_by_name(hashalg)) == -1) {
401 		error("%s: can't look up hash algorithm %s",
402 		    __func__, hashalg);
403 		return SSH_ERR_INTERNAL_ERROR;
404 	}
405 	if ((r = ssh_digest_buffer(alg, m, hash, sizeof(hash))) != 0) {
406 		error("%s: ssh_digest_buffer failed: %s", __func__, ssh_err(r));
407 		return r;
408 	}
409 	if ((hex = tohex(hash, ssh_digest_bytes(alg))) != NULL) {
410 		debug3("%s: final hash: %s", __func__, hex);
411 		freezero(hex, strlen(hex));
412 	}
413 	if ((b = sshbuf_new()) == NULL) {
414 		r = SSH_ERR_ALLOC_FAIL;
415 		goto out;
416 	}
417 	if ((r = sshbuf_put(b, hash, ssh_digest_bytes(alg))) != 0) {
418 		error("%s: sshbuf_put: %s", __func__, ssh_err(r));
419 		goto out;
420 	}
421 	*bp = b;
422 	b = NULL; /* transferred */
423 	/* success */
424 	r = 0;
425  out:
426 	sshbuf_free(b);
427 	explicit_bzero(hash, sizeof(hash));
428 	return r;
429 }
430 
431 int
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)
436 {
437 	struct sshbuf *b = NULL;
438 	int r = SSH_ERR_INTERNAL_ERROR;
439 
440 	if (hashalg == NULL)
441 		hashalg = HASHALG_DEFAULT;
442 	if (out != NULL)
443 		*out = NULL;
444 	if ((r = hash_buffer(message, hashalg, &b)) != 0) {
445 		error("%s: hash_buffer failed: %s", __func__, ssh_err(r));
446 		goto out;
447 	}
448 	if ((r = sshsig_wrap_sign(key, hashalg, sk_provider, sk_pin, b,
449 	    sig_namespace, out, signer, signer_ctx)) != 0)
450 		goto out;
451 	/* success */
452 	r = 0;
453  out:
454 	sshbuf_free(b);
455 	return r;
456 }
457 
458 int
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)
462 {
463 	struct sshbuf *b = NULL;
464 	int r = SSH_ERR_INTERNAL_ERROR;
465 	char *hashalg = NULL;
466 
467 	if (sig_details != NULL)
468 		*sig_details = NULL;
469 	if (sign_keyp != NULL)
470 		*sign_keyp = NULL;
471 	if ((r = sshsig_peek_hashalg(signature, &hashalg)) != 0)
472 		return r;
473 	debug("%s: signature made with hash \"%s\"", __func__, hashalg);
474 	if ((r = hash_buffer(message, hashalg, &b)) != 0) {
475 		error("%s: hash_buffer failed: %s", __func__, ssh_err(r));
476 		goto out;
477 	}
478 	if ((r = sshsig_wrap_verify(signature, hashalg, b, expect_namespace,
479 	    sign_keyp, sig_details)) != 0)
480 		goto out;
481 	/* success */
482 	r = 0;
483  out:
484 	sshbuf_free(b);
485 	free(hashalg);
486 	return r;
487 }
488 
489 static int
490 hash_file(int fd, const char *hashalg, struct sshbuf **bp)
491 {
492 	char *hex, rbuf[8192], hash[SSH_DIGEST_MAX_LENGTH];
493 	ssize_t n, total = 0;
494 	struct ssh_digest_ctx *ctx;
495 	int alg, oerrno, r = SSH_ERR_INTERNAL_ERROR;
496 	struct sshbuf *b = NULL;
497 
498 	*bp = NULL;
499 	memset(hash, 0, sizeof(hash));
500 
501 	if ((r = sshsig_check_hashalg(hashalg)) != 0)
502 		return r;
503 	if ((alg = ssh_digest_alg_by_name(hashalg)) == -1) {
504 		error("%s: can't look up hash algorithm %s",
505 		    __func__, hashalg);
506 		return SSH_ERR_INTERNAL_ERROR;
507 	}
508 	if ((ctx = ssh_digest_start(alg)) == NULL) {
509 		error("%s: ssh_digest_start failed", __func__);
510 		return SSH_ERR_INTERNAL_ERROR;
511 	}
512 	for (;;) {
513 		if ((n = read(fd, rbuf, sizeof(rbuf))) == -1) {
514 			if (errno == EINTR || errno == EAGAIN)
515 				continue;
516 			oerrno = errno;
517 			error("%s: read: %s", __func__, strerror(errno));
518 			ssh_digest_free(ctx);
519 			errno = oerrno;
520 			r = SSH_ERR_SYSTEM_ERROR;
521 			goto out;
522 		} else if (n == 0) {
523 			debug2("%s: hashed %zu bytes", __func__, total);
524 			break; /* EOF */
525 		}
526 		total += (size_t)n;
527 		if ((r = ssh_digest_update(ctx, rbuf, (size_t)n)) != 0) {
528 			error("%s: ssh_digest_update: %s",
529 			    __func__, ssh_err(r));
530 			goto out;
531 		}
532 	}
533 	if ((r = ssh_digest_final(ctx, hash, sizeof(hash))) != 0) {
534 		error("%s: ssh_digest_final: %s", __func__, ssh_err(r));
535 		goto out;
536 	}
537 	if ((hex = tohex(hash, ssh_digest_bytes(alg))) != NULL) {
538 		debug3("%s: final hash: %s", __func__, 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("%s: sshbuf_put: %s", __func__, ssh_err(r));
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("%s: hash_file failed: %s", __func__, ssh_err(r));
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("%s: signature made with hash \"%s\"", __func__, hashalg);
603 	if ((r = hash_file(fd, hashalg, &b)) != 0) {
604 		error("%s: hash_file failed: %s", __func__, ssh_err(r));
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("%s: strdup failed", __func__);
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("%s: %s:%lu: matched principal \"%s\"",
730 		    __func__, path, linenum, required_principal);
731 	}
732 
733 	if ((key = sshkey_new(KEY_UNSPEC)) == NULL) {
734 		error("%s: sshkey_new failed", __func__);
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,
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 		if (r == SSH_ERR_KEY_NOT_FOUND)
859 			continue;
860 		else if (r == 0) {
861 			/* success */
862 			fclose(f);
863 			return 0;
864 		} else
865 			break;
866 	}
867 	/* Either we hit an error parsing or we simply didn't find the key */
868 	fclose(f);
869 	free(line);
870 	return r == 0 ? SSH_ERR_KEY_NOT_FOUND : r;
871 }
872 
873 static int
874 cert_filter_principals(const char *path, u_long linenum,
875     char **principalsp, const struct sshkey *cert)
876 {
877 	char *cp, *oprincipals, *principals;
878 	const char *reason;
879 	struct sshbuf *nprincipals;
880 	int r = SSH_ERR_INTERNAL_ERROR, success = 0;
881 
882 	oprincipals = principals = *principalsp;
883 	*principalsp = NULL;
884 
885 	if ((nprincipals = sshbuf_new()) == NULL) {
886 		r = SSH_ERR_ALLOC_FAIL;
887 		goto out;
888 	}
889 
890 	while ((cp = strsep(&principals, ",")) != NULL && *cp != '\0') {
891 		if (strcspn(cp, "!?*") != strlen(cp)) {
892 			debug("%s:%lu: principal \"%s\" not authorized: "
893 			    "contains wildcards", path, linenum, cp);
894 			continue;
895 		}
896 		/* Check against principals list in certificate */
897 		if ((r = sshkey_cert_check_authority(cert, 0, 1,
898 		    cp, &reason)) != 0) {
899 			debug("%s:%lu: principal \"%s\" not authorized: %s",
900 			    path, linenum, cp, reason);
901 			continue;
902 		}
903 		if ((r = sshbuf_putf(nprincipals, "%s%s",
904 		    sshbuf_len(nprincipals) != 0 ? "," : "", cp)) != 0) {
905 			error("%s: buffer error", __func__);
906 			goto out;
907 		}
908 	}
909 	if (sshbuf_len(nprincipals) == 0) {
910 		error("%s:%lu: no valid principals found", path, linenum);
911 		r = SSH_ERR_KEY_CERT_INVALID;
912 		goto out;
913 	}
914 	if ((principals = sshbuf_dup_string(nprincipals)) == NULL) {
915 		error("%s: buffer error", __func__);
916 		goto out;
917 	}
918 	/* success */
919 	success = 1;
920 	*principalsp = principals;
921  out:
922 	sshbuf_free(nprincipals);
923 	free(oprincipals);
924 	return success ? 0 : r;
925 }
926 
927 static int
928 get_matching_principals_from_line(const char *path, u_long linenum, char *line,
929     const struct sshkey *sign_key, char **principalsp)
930 {
931 	struct sshkey *found_key = NULL;
932 	char *principals = NULL;
933 	int r, found = 0;
934 	struct sshsigopt *sigopts = NULL;
935 
936 	if (principalsp != NULL)
937 		*principalsp = NULL;
938 
939 	/* Parse the line */
940 	if ((r = parse_principals_key_and_options(path, linenum, line,
941 	    NULL, &principals, &found_key, &sigopts)) != 0) {
942 		/* error already logged */
943 		goto done;
944 	}
945 
946 	if (!sigopts->ca && sshkey_equal(found_key, sign_key)) {
947 		/* Exact match of key */
948 		debug("%s:%lu: matched key", path, linenum);
949 		/* success */
950 		found = 1;
951 	} else if (sigopts->ca && sshkey_is_cert(sign_key) &&
952 	    sshkey_equal_public(sign_key->cert->signature_key, found_key)) {
953 		/* Remove principals listed in file but not allowed by cert */
954 		if ((r = cert_filter_principals(path, linenum,
955 		    &principals, sign_key)) != 0) {
956 			/* error already displayed */
957 			debug("%s:%lu: cert_filter_principals: %s",
958 			    path, linenum, ssh_err(r));
959 			goto done;
960 		}
961 		debug("%s:%lu: matched certificate CA key", path, linenum);
962 		/* success */
963 		found = 1;
964 	} else {
965 		/* Key didn't match */
966 		goto done;
967 	}
968  done:
969 	if (found && principalsp != NULL) {
970 		*principalsp = principals;
971 		principals = NULL; /* transferred */
972 	}
973 	free(principals);
974 	sshkey_free(found_key);
975 	sshsigopt_free(sigopts);
976 	return found ? 0 : SSH_ERR_KEY_NOT_FOUND;
977 }
978 
979 int
980 sshsig_find_principals(const char *path, const struct sshkey *sign_key,
981     char **principals)
982 {
983 	FILE *f = NULL;
984 	char *line = NULL;
985 	size_t linesize = 0;
986 	u_long linenum = 0;
987 	int r = SSH_ERR_INTERNAL_ERROR, oerrno;
988 
989 	if ((f = fopen(path, "r")) == NULL) {
990 		oerrno = errno;
991 		error("Unable to open allowed keys file \"%s\": %s",
992 		    path, strerror(errno));
993 		errno = oerrno;
994 		return SSH_ERR_SYSTEM_ERROR;
995 	}
996 
997 	while (getline(&line, &linesize, f) != -1) {
998 		linenum++;
999 		r = get_matching_principals_from_line(path, linenum, line,
1000 		    sign_key, principals);
1001 		free(line);
1002 		line = NULL;
1003 		if (r == SSH_ERR_KEY_NOT_FOUND)
1004 			continue;
1005 		else if (r == 0) {
1006 			/* success */
1007 			fclose(f);
1008 			return 0;
1009 		} else
1010 			break;
1011 	}
1012 	free(line);
1013 	/* Either we hit an error parsing or we simply didn't find the key */
1014 	if (ferror(f) != 0) {
1015 		oerrno = errno;
1016 		fclose(f);
1017 		error("Unable to read allowed keys file \"%s\": %s",
1018 		    path, strerror(errno));
1019 		errno = oerrno;
1020 		return SSH_ERR_SYSTEM_ERROR;
1021 	}
1022 	fclose(f);
1023 	return r == 0 ? SSH_ERR_KEY_NOT_FOUND : r;
1024 }
1025 
1026 int
1027 sshsig_get_pubkey(struct sshbuf *signature, struct sshkey **pubkey)
1028 {
1029 	struct sshkey *pk = NULL;
1030 	int r = SSH_ERR_SIGNATURE_INVALID;
1031 
1032 	if (pubkey == NULL)
1033 		return SSH_ERR_INTERNAL_ERROR;
1034 	if ((r = sshsig_parse_preamble(signature)) != 0)
1035 		return r;
1036 	if ((r = sshkey_froms(signature, &pk)) != 0)
1037 		return r;
1038 
1039 	*pubkey = pk;
1040 	pk = NULL;
1041 	return 0;
1042 }
1043