xref: /netbsd-src/crypto/external/bsd/openssh/dist/sshsig.c (revision cef8759bd76c1b621f8eab8faa6f208faabc2e15)
1 /*	$NetBSD: sshsig.c,v 1.4 2020/05/28 17:05:49 christos Exp $	*/
2 
3 /*
4  * Copyright (c) 2019 Google LLC
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 #include "includes.h"
19 __RCSID("$NetBSD: sshsig.c,v 1.4 2020/05/28 17:05:49 christos Exp $");
20 
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <stdarg.h>
24 #include <errno.h>
25 #include <string.h>
26 #include <unistd.h>
27 
28 #include "authfd.h"
29 #include "authfile.h"
30 #include "log.h"
31 #include "misc.h"
32 #include "sshbuf.h"
33 #include "sshsig.h"
34 #include "ssherr.h"
35 #include "sshkey.h"
36 #include "match.h"
37 #include "digest.h"
38 
39 #define SIG_VERSION		0x01
40 #define MAGIC_PREAMBLE		"SSHSIG"
41 #define MAGIC_PREAMBLE_LEN	(sizeof(MAGIC_PREAMBLE) - 1)
42 #define BEGIN_SIGNATURE		"-----BEGIN SSH SIGNATURE-----\n"
43 #define END_SIGNATURE		"-----END SSH SIGNATURE-----"
44 #define RSA_SIGN_ALG		"rsa-sha2-512" /* XXX maybe make configurable */
45 #define RSA_SIGN_ALLOWED	"rsa-sha2-512,rsa-sha2-256"
46 #define HASHALG_DEFAULT		"sha512" /* XXX maybe make configurable */
47 #define HASHALG_ALLOWED		"sha256,sha512"
48 
49 int
50 sshsig_armor(const struct sshbuf *blob, struct sshbuf **out)
51 {
52 	struct sshbuf *buf = NULL;
53 	int r = SSH_ERR_INTERNAL_ERROR;
54 
55 	*out = NULL;
56 
57 	if ((buf = sshbuf_new()) == NULL) {
58 		error("%s: sshbuf_new failed", __func__);
59 		r = SSH_ERR_ALLOC_FAIL;
60 		goto out;
61 	}
62 
63 	if ((r = sshbuf_put(buf, BEGIN_SIGNATURE,
64 	    sizeof(BEGIN_SIGNATURE)-1)) != 0) {
65 		error("%s: sshbuf_putf failed: %s", __func__, ssh_err(r));
66 		goto out;
67 	}
68 
69 	if ((r = sshbuf_dtob64(blob, buf, 1)) != 0) {
70 		error("%s: Couldn't base64 encode signature blob: %s",
71 		    __func__, ssh_err(r));
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("%s: sshbuf_put failed: %s", __func__, ssh_err(r));
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("%s: sshbuf_fromb failed", __func__);
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("%s: sshbuf_consume failed: %s", __func__, ssh_err(r));
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("%s: sshbuf_consume failed: %s", __func__, ssh_err(r));
123 		goto done;
124 	}
125 
126 	if ((b64 = sshbuf_dup_string(sbuf)) == NULL) {
127 		error("%s: sshbuf_dup_string failed", __func__);
128 		r = SSH_ERR_ALLOC_FAIL;
129 		goto done;
130 	}
131 
132 	if ((buf = sshbuf_new()) == NULL) {
133 		error("%s: sshbuf_new() failed", __func__);
134 		r = SSH_ERR_ALLOC_FAIL;
135 		goto done;
136 	}
137 
138 	if ((r = sshbuf_b64tod(buf, b64)) != 0) {
139 		error("Couldn't decode signature: %s", ssh_err(r));
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 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("%s: sshbuf_new failed", __func__);
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("Couldn't construct message to sign: %s", ssh_err(r));
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, 0, signer_ctx)) != 0) {
191 			error("Couldn't sign message: %s", ssh_err(r));
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, 0)) != 0) {
198 			error("Couldn't sign message: %s", ssh_err(r));
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("Couldn't populate blob: %s", ssh_err(r));
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("%s: unsupported hash algorithm \"%.100s\"", __func__, 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("Couldn't parse signature blob: %s", ssh_err(r));
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("%s: verify message length %zu", __func__, 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("%s: sshbuf_new failed", __func__);
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("Couldn't construct message to verify: %s", ssh_err(r));
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("Couldn't parse signature blob: %s", ssh_err(r));
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("%s: expected namespace \"%s\" received \"%s\"",
344 		    __func__, 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("%s: expected algorithm \"%s\" received \"%s\"",
351 		    __func__, 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("Couldn't verify signature: unable to get "
359 			    "signature type: %s", ssh_err(r));
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("Signature verification failed: %s", ssh_err(r));
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("%s: can't look up hash algorithm %s",
405 		    __func__, hashalg);
406 		return SSH_ERR_INTERNAL_ERROR;
407 	}
408 	if ((r = ssh_digest_buffer(alg, m, (unsigned char *)hash, sizeof(hash))) != 0) {
409 		error("%s: ssh_digest_buffer failed: %s", __func__, ssh_err(r));
410 		return r;
411 	}
412 	if ((hex = tohex(hash, ssh_digest_bytes(alg))) != NULL) {
413 		debug3("%s: final hash: %s", __func__, hex);
414 		freezero(hex, strlen(hex));
415 	}
416 	if ((b = sshbuf_new()) == NULL) {
417 		r = SSH_ERR_ALLOC_FAIL;
418 		goto out;
419 	}
420 	if ((r = sshbuf_put(b, hash, ssh_digest_bytes(alg))) != 0) {
421 		error("%s: sshbuf_put: %s", __func__, ssh_err(r));
422 		goto out;
423 	}
424 	*bp = b;
425 	b = NULL; /* transferred */
426 	/* success */
427 	r = 0;
428  out:
429 	sshbuf_free(b);
430 	explicit_bzero(hash, sizeof(hash));
431 	return r;
432 }
433 
434 int
435 sshsig_signb(struct sshkey *key, const char *hashalg, const char *sk_provider,
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("%s: hash_buffer failed: %s", __func__, ssh_err(r));
448 		goto out;
449 	}
450 	if ((r = sshsig_wrap_sign(key, hashalg, sk_provider, 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("%s: signature made with hash \"%s\"", __func__, hashalg);
476 	if ((r = hash_buffer(message, hashalg, &b)) != 0) {
477 		error("%s: hash_buffer failed: %s", __func__, ssh_err(r));
478 		goto out;
479 	}
480 	if ((r = sshsig_wrap_verify(signature, hashalg, b, expect_namespace,
481 	    sign_keyp, sig_details)) != 0)
482 		goto out;
483 	/* success */
484 	r = 0;
485  out:
486 	sshbuf_free(b);
487 	free(hashalg);
488 	return r;
489 }
490 
491 static int
492 hash_file(int fd, const char *hashalg, struct sshbuf **bp)
493 {
494 	char *hex, rbuf[8192], hash[SSH_DIGEST_MAX_LENGTH];
495 	ssize_t n, total = 0;
496 	struct ssh_digest_ctx *ctx;
497 	int alg, oerrno, r = SSH_ERR_INTERNAL_ERROR;
498 	struct sshbuf *b = NULL;
499 
500 	*bp = NULL;
501 	memset(hash, 0, sizeof(hash));
502 
503 	if ((r = sshsig_check_hashalg(hashalg)) != 0)
504 		return r;
505 	if ((alg = ssh_digest_alg_by_name(hashalg)) == -1) {
506 		error("%s: can't look up hash algorithm %s",
507 		    __func__, hashalg);
508 		return SSH_ERR_INTERNAL_ERROR;
509 	}
510 	if ((ctx = ssh_digest_start(alg)) == NULL) {
511 		error("%s: ssh_digest_start failed", __func__);
512 		return SSH_ERR_INTERNAL_ERROR;
513 	}
514 	for (;;) {
515 		if ((n = read(fd, rbuf, sizeof(rbuf))) == -1) {
516 			if (errno == EINTR || errno == EAGAIN)
517 				continue;
518 			oerrno = errno;
519 			error("%s: read: %s", __func__, strerror(errno));
520 			ssh_digest_free(ctx);
521 			errno = oerrno;
522 			r = SSH_ERR_SYSTEM_ERROR;
523 			goto out;
524 		} else if (n == 0) {
525 			debug2("%s: hashed %zu bytes", __func__, total);
526 			break; /* EOF */
527 		}
528 		total += (size_t)n;
529 		if ((r = ssh_digest_update(ctx, rbuf, (size_t)n)) != 0) {
530 			error("%s: ssh_digest_update: %s",
531 			    __func__, ssh_err(r));
532 			goto out;
533 		}
534 	}
535 	if ((r = ssh_digest_final(ctx, (unsigned char *)hash, sizeof(hash))) != 0) {
536 		error("%s: ssh_digest_final: %s", __func__, ssh_err(r));
537 		goto out;
538 	}
539 	if ((hex = tohex(hash, ssh_digest_bytes(alg))) != NULL) {
540 		debug3("%s: final hash: %s", __func__, hex);
541 		freezero(hex, strlen(hex));
542 	}
543 	if ((b = sshbuf_new()) == NULL) {
544 		r = SSH_ERR_ALLOC_FAIL;
545 		goto out;
546 	}
547 	if ((r = sshbuf_put(b, hash, ssh_digest_bytes(alg))) != 0) {
548 		error("%s: sshbuf_put: %s", __func__, ssh_err(r));
549 		goto out;
550 	}
551 	*bp = b;
552 	b = NULL; /* transferred */
553 	/* success */
554 	r = 0;
555  out:
556 	sshbuf_free(b);
557 	ssh_digest_free(ctx);
558 	explicit_bzero(hash, sizeof(hash));
559 	return r;
560 }
561 
562 int
563 sshsig_sign_fd(struct sshkey *key, const char *hashalg, const char *sk_provider,
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("%s: hash_file failed: %s", __func__, ssh_err(r));
576 		return r;
577 	}
578 	if ((r = sshsig_wrap_sign(key, hashalg, sk_provider, 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("%s: signature made with hash \"%s\"", __func__, hashalg);
604 	if ((r = hash_file(fd, hashalg, &b)) != 0) {
605 		error("%s: hash_file failed: %s", __func__, ssh_err(r));
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 };
623 
624 struct sshsigopt *
625 sshsigopt_parse(const char *opts, const char *path, u_long linenum,
626     const char **errstrp)
627 {
628 	struct sshsigopt *ret;
629 	int r;
630 	const char *errstr = NULL;
631 
632 	if ((ret = calloc(1, sizeof(*ret))) == NULL)
633 		return NULL;
634 	if (opts == NULL || *opts == '\0')
635 		return ret; /* Empty options yields empty options :) */
636 
637 	while (*opts && *opts != ' ' && *opts != '\t') {
638 		/* flag options */
639 		if ((r = opt_flag("cert-authority", 0, &opts)) != -1) {
640 			ret->ca = 1;
641 		} else if (opt_match(&opts, "namespaces")) {
642 			if (ret->namespaces != NULL) {
643 				errstr = "multiple \"namespaces\" clauses";
644 				goto fail;
645 			}
646 			ret->namespaces = opt_dequote(&opts, &errstr);
647 			if (ret->namespaces == NULL)
648 				goto fail;
649 		}
650 		/*
651 		 * Skip the comma, and move to the next option
652 		 * (or break out if there are no more).
653 		 */
654 		if (*opts == '\0' || *opts == ' ' || *opts == '\t')
655 			break;		/* End of options. */
656 		/* Anything other than a comma is an unknown option */
657 		if (*opts != ',') {
658 			errstr = "unknown key option";
659 			goto fail;
660 		}
661 		opts++;
662 		if (*opts == '\0') {
663 			errstr = "unexpected end-of-options";
664 			goto fail;
665 		}
666 	}
667 	/* success */
668 	return ret;
669  fail:
670 	if (errstrp != NULL)
671 		*errstrp = errstr;
672 	sshsigopt_free(ret);
673 	return NULL;
674 }
675 
676 void
677 sshsigopt_free(struct sshsigopt *opts)
678 {
679 	if (opts == NULL)
680 		return;
681 	free(opts->namespaces);
682 	free(opts);
683 }
684 
685 static int
686 parse_principals_key_and_options(const char *path, u_long linenum, char *line,
687     const char *required_principal, char **principalsp, struct sshkey **keyp,
688     struct sshsigopt **sigoptsp)
689 {
690 	char *opts = NULL, *tmp, *cp, *principals = NULL;
691 	const char *reason = NULL;
692 	struct sshsigopt *sigopts = NULL;
693 	struct sshkey *key = NULL;
694 	int r = SSH_ERR_INTERNAL_ERROR;
695 
696 	if (principalsp != NULL)
697 		*principalsp = NULL;
698 	if (sigoptsp != NULL)
699 		*sigoptsp = NULL;
700 	if (keyp != NULL)
701 		*keyp = NULL;
702 
703 	cp = line;
704 	cp = cp + strspn(cp, " \t"); /* skip leading whitespace */
705 	if (*cp == '#' || *cp == '\0')
706 		return SSH_ERR_KEY_NOT_FOUND; /* blank or all-comment line */
707 
708 	/* format: identity[,identity...] [option[,option...]] key */
709 	if ((tmp = strdelimw(&cp)) == NULL) {
710 		error("%s:%lu: invalid line", path, linenum);
711 		r = SSH_ERR_INVALID_FORMAT;
712 		goto out;
713 	}
714 	if ((principals = strdup(tmp)) == NULL) {
715 		error("%s: strdup failed", __func__);
716 		r = SSH_ERR_ALLOC_FAIL;
717 		goto out;
718 	}
719 	/*
720 	 * Bail out early if we're looking for a particular principal and this
721 	 * line does not list it.
722 	 */
723 	if (required_principal != NULL) {
724 		if (match_pattern_list(required_principal,
725 		    principals, 0) != 1) {
726 			/* principal didn't match */
727 			r = SSH_ERR_KEY_NOT_FOUND;
728 			goto out;
729 		}
730 		debug("%s: %s:%lu: matched principal \"%s\"",
731 		    __func__, path, linenum, required_principal);
732 	}
733 
734 	if ((key = sshkey_new(KEY_UNSPEC)) == NULL) {
735 		error("%s: sshkey_new failed", __func__);
736 		r = SSH_ERR_ALLOC_FAIL;
737 		goto out;
738 	}
739 	if (sshkey_read(key, &cp) != 0) {
740 		/* no key? Check for options */
741 		opts = cp;
742 		if (sshkey_advance_past_options(&cp) != 0) {
743 			error("%s:%lu: invalid options", path, linenum);
744 			r = SSH_ERR_INVALID_FORMAT;
745 			goto out;
746 		}
747 		*cp++ = '\0';
748 		skip_space(&cp);
749 		if (sshkey_read(key, &cp) != 0) {
750 			error("%s:%lu: invalid key", path, linenum);
751 			r = SSH_ERR_INVALID_FORMAT;
752 			goto out;
753 		}
754 	}
755 	debug3("%s:%lu: options %s", path, linenum, opts == NULL ? "" : opts);
756 	if ((sigopts = sshsigopt_parse(opts, path, linenum, &reason)) == NULL) {
757 		error("%s:%lu: bad options: %s", path, linenum, reason);
758 		r = SSH_ERR_INVALID_FORMAT;
759 		goto out;
760 	}
761 	/* success */
762 	if (principalsp != NULL) {
763 		*principalsp = principals;
764 		principals = NULL; /* transferred */
765 	}
766 	if (sigoptsp != NULL) {
767 		*sigoptsp = sigopts;
768 		sigopts = NULL; /* transferred */
769 	}
770 	if (keyp != NULL) {
771 		*keyp = key;
772 		key = NULL; /* transferred */
773 	}
774 	r = 0;
775  out:
776 	free(principals);
777 	sshsigopt_free(sigopts);
778 	sshkey_free(key);
779 	return r;
780 }
781 
782 static int
783 check_allowed_keys_line(const char *path, u_long linenum, char *line,
784     const struct sshkey *sign_key, const char *principal,
785     const char *sig_namespace)
786 {
787 	struct sshkey *found_key = NULL;
788 	int r, found = 0;
789 	const char *reason = NULL;
790 	struct sshsigopt *sigopts = NULL;
791 
792 	/* Parse the line */
793 	if ((r = parse_principals_key_and_options(path, linenum, line,
794 	    principal, NULL, &found_key, &sigopts)) != 0) {
795 		/* error already logged */
796 		goto done;
797 	}
798 
799 	/* Check whether options preclude the use of this key */
800 	if (sigopts->namespaces != NULL &&
801 	    match_pattern_list(sig_namespace, sigopts->namespaces, 0) != 1) {
802 		error("%s:%lu: key is not permitted for use in signature "
803 		    "namespace \"%s\"", path, linenum, sig_namespace);
804 		goto done;
805 	}
806 
807 	if (!sigopts->ca && sshkey_equal(found_key, sign_key)) {
808 		/* Exact match of key */
809 		debug("%s:%lu: matched key and principal", path, linenum);
810 		/* success */
811 		found = 1;
812 	} else if (sigopts->ca && sshkey_is_cert(sign_key) &&
813 	    sshkey_equal_public(sign_key->cert->signature_key, found_key)) {
814 		/* Match of certificate's CA key */
815 		if ((r = sshkey_cert_check_authority(sign_key, 0, 1,
816 		    principal, &reason)) != 0) {
817 			error("%s:%lu: certificate not authorized: %s",
818 			    path, linenum, reason);
819 			goto done;
820 		}
821 		debug("%s:%lu: matched certificate CA key", path, linenum);
822 		/* success */
823 		found = 1;
824 	} else {
825 		/* Principal matched but key didn't */
826 		goto done;
827 	}
828  done:
829 	sshkey_free(found_key);
830 	sshsigopt_free(sigopts);
831 	return found ? 0 : SSH_ERR_KEY_NOT_FOUND;
832 }
833 
834 int
835 sshsig_check_allowed_keys(const char *path, const struct sshkey *sign_key,
836     const char *principal, const char *sig_namespace)
837 {
838 	FILE *f = NULL;
839 	char *line = NULL;
840 	size_t linesize = 0;
841 	u_long linenum = 0;
842 	int r = SSH_ERR_INTERNAL_ERROR, oerrno;
843 
844 	/* Check key and principal against file */
845 	if ((f = fopen(path, "r")) == NULL) {
846 		oerrno = errno;
847 		error("Unable to open allowed keys file \"%s\": %s",
848 		    path, strerror(errno));
849 		errno = oerrno;
850 		return SSH_ERR_SYSTEM_ERROR;
851 	}
852 
853 	while (getline(&line, &linesize, f) != -1) {
854 		linenum++;
855 		r = check_allowed_keys_line(path, linenum, line, sign_key,
856 		    principal, sig_namespace);
857 		free(line);
858 		line = NULL;
859 		if (r == SSH_ERR_KEY_NOT_FOUND)
860 			continue;
861 		else if (r == 0) {
862 			/* success */
863 			fclose(f);
864 			return 0;
865 		} else
866 			break;
867 	}
868 	/* Either we hit an error parsing or we simply didn't find the key */
869 	fclose(f);
870 	free(line);
871 	return r == 0 ? SSH_ERR_KEY_NOT_FOUND : r;
872 }
873 
874 static int
875 cert_filter_principals(const char *path, u_long linenum,
876     char **principalsp, const struct sshkey *cert)
877 {
878 	char *cp, *oprincipals, *principals;
879 	const char *reason;
880 	struct sshbuf *nprincipals;
881 	int r = SSH_ERR_INTERNAL_ERROR, success = 0;
882 
883 	oprincipals = principals = *principalsp;
884 	*principalsp = NULL;
885 
886 	if ((nprincipals = sshbuf_new()) == NULL) {
887 		r = SSH_ERR_ALLOC_FAIL;
888 		goto out;
889 	}
890 
891 	while ((cp = strsep(&principals, ",")) != NULL && *cp != '\0') {
892 		if (strcspn(cp, "!?*") != strlen(cp)) {
893 			debug("%s:%lu: principal \"%s\" not authorized: "
894 			    "contains wildcards", path, linenum, cp);
895 			continue;
896 		}
897 		/* Check against principals list in certificate */
898 		if ((r = sshkey_cert_check_authority(cert, 0, 1,
899 		    cp, &reason)) != 0) {
900 			debug("%s:%lu: principal \"%s\" not authorized: %s",
901 			    path, linenum, cp, reason);
902 			continue;
903 		}
904 		if ((r = sshbuf_putf(nprincipals, "%s%s",
905 		    sshbuf_len(nprincipals) != 0 ? "," : "", cp)) != 0) {
906 			error("%s: buffer error", __func__);
907 			goto out;
908 		}
909 	}
910 	if (sshbuf_len(nprincipals) == 0) {
911 		error("%s:%lu: no valid principals found", path, linenum);
912 		r = SSH_ERR_KEY_CERT_INVALID;
913 		goto out;
914 	}
915 	if ((principals = sshbuf_dup_string(nprincipals)) == NULL) {
916 		error("%s: buffer error", __func__);
917 		goto out;
918 	}
919 	/* success */
920 	success = 1;
921 	*principalsp = principals;
922  out:
923 	sshbuf_free(nprincipals);
924 	free(oprincipals);
925 	return success ? 0 : r;
926 }
927 
928 static int
929 get_matching_principals_from_line(const char *path, u_long linenum, char *line,
930     const struct sshkey *sign_key, char **principalsp)
931 {
932 	struct sshkey *found_key = NULL;
933 	char *principals = NULL;
934 	int r, found = 0;
935 	struct sshsigopt *sigopts = NULL;
936 
937 	if (principalsp != NULL)
938 		*principalsp = NULL;
939 
940 	/* Parse the line */
941 	if ((r = parse_principals_key_and_options(path, linenum, line,
942 	    NULL, &principals, &found_key, &sigopts)) != 0) {
943 		/* error already logged */
944 		goto done;
945 	}
946 
947 	if (!sigopts->ca && sshkey_equal(found_key, sign_key)) {
948 		/* Exact match of key */
949 		debug("%s:%lu: matched key", path, linenum);
950 		/* success */
951 		found = 1;
952 	} else if (sigopts->ca && sshkey_is_cert(sign_key) &&
953 	    sshkey_equal_public(sign_key->cert->signature_key, found_key)) {
954 		/* Remove principals listed in file but not allowed by cert */
955 		if ((r = cert_filter_principals(path, linenum,
956 		    &principals, sign_key)) != 0) {
957 			/* error already displayed */
958 			debug("%s:%lu: cert_filter_principals: %s",
959 			    path, linenum, ssh_err(r));
960 			goto done;
961 		}
962 		debug("%s:%lu: matched certificate CA key", path, linenum);
963 		/* success */
964 		found = 1;
965 	} else {
966 		/* Key didn't match */
967 		goto done;
968 	}
969  done:
970 	if (found && principalsp != NULL) {
971 		*principalsp = principals;
972 		principals = NULL; /* transferred */
973 	}
974 	free(principals);
975 	sshkey_free(found_key);
976 	sshsigopt_free(sigopts);
977 	return found ? 0 : SSH_ERR_KEY_NOT_FOUND;
978 }
979 
980 int
981 sshsig_find_principals(const char *path, const struct sshkey *sign_key,
982     char **principals)
983 {
984 	FILE *f = NULL;
985 	char *line = NULL;
986 	size_t linesize = 0;
987 	u_long linenum = 0;
988 	int r = SSH_ERR_INTERNAL_ERROR, oerrno;
989 
990 	if ((f = fopen(path, "r")) == NULL) {
991 		oerrno = errno;
992 		error("Unable to open allowed keys file \"%s\": %s",
993 		    path, strerror(errno));
994 		errno = oerrno;
995 		return SSH_ERR_SYSTEM_ERROR;
996 	}
997 
998 	while (getline(&line, &linesize, f) != -1) {
999 		linenum++;
1000 		r = get_matching_principals_from_line(path, linenum, line,
1001 		    sign_key, principals);
1002 		free(line);
1003 		line = NULL;
1004 		if (r == SSH_ERR_KEY_NOT_FOUND)
1005 			continue;
1006 		else if (r == 0) {
1007 			/* success */
1008 			fclose(f);
1009 			return 0;
1010 		} else
1011 			break;
1012 	}
1013 	free(line);
1014 	/* Either we hit an error parsing or we simply didn't find the key */
1015 	if (ferror(f) != 0) {
1016 		oerrno = errno;
1017 		fclose(f);
1018 		error("Unable to read allowed keys file \"%s\": %s",
1019 		    path, strerror(errno));
1020 		errno = oerrno;
1021 		return SSH_ERR_SYSTEM_ERROR;
1022 	}
1023 	fclose(f);
1024 	return r == 0 ? SSH_ERR_KEY_NOT_FOUND : r;
1025 }
1026 
1027 int
1028 sshsig_get_pubkey(struct sshbuf *signature, struct sshkey **pubkey)
1029 {
1030 	struct sshkey *pk = NULL;
1031 	int r = SSH_ERR_SIGNATURE_INVALID;
1032 
1033 	if (pubkey == NULL)
1034 		return SSH_ERR_INTERNAL_ERROR;
1035 	if ((r = sshsig_parse_preamble(signature)) != 0)
1036 		return r;
1037 	if ((r = sshkey_froms(signature, &pk)) != 0)
1038 		return r;
1039 
1040 	*pubkey = pk;
1041 	pk = NULL;
1042 	return 0;
1043 }
1044