xref: /openbsd-src/usr.bin/ssh/sshsig.c (revision 99fd087599a8791921855f21bd7e36130f39aadc)
1 /*
2  * Copyright (c) 2019 Google LLC
3  *
4  * Permission to use, copy, modify, and distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16 
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <stdarg.h>
20 #include <errno.h>
21 #include <string.h>
22 #include <unistd.h>
23 
24 #include "authfd.h"
25 #include "authfile.h"
26 #include "log.h"
27 #include "misc.h"
28 #include "sshbuf.h"
29 #include "sshsig.h"
30 #include "ssherr.h"
31 #include "sshkey.h"
32 #include "match.h"
33 #include "digest.h"
34 
35 #define SIG_VERSION		0x01
36 #define MAGIC_PREAMBLE		"SSHSIG"
37 #define MAGIC_PREAMBLE_LEN	(sizeof(MAGIC_PREAMBLE) - 1)
38 #define BEGIN_SIGNATURE		"-----BEGIN SSH SIGNATURE-----\n"
39 #define END_SIGNATURE		"-----END SSH SIGNATURE-----"
40 #define RSA_SIGN_ALG		"rsa-sha2-512" /* XXX maybe make configurable */
41 #define RSA_SIGN_ALLOWED	"rsa-sha2-512,rsa-sha2-256"
42 #define HASHALG_DEFAULT		"sha512" /* XXX maybe make configurable */
43 #define HASHALG_ALLOWED		"sha256,sha512"
44 
45 int
46 sshsig_armor(const struct sshbuf *blob, struct sshbuf **out)
47 {
48 	struct sshbuf *buf = NULL;
49 	int r = SSH_ERR_INTERNAL_ERROR;
50 
51 	*out = NULL;
52 
53 	if ((buf = sshbuf_new()) == NULL) {
54 		error("%s: sshbuf_new failed", __func__);
55 		r = SSH_ERR_ALLOC_FAIL;
56 		goto out;
57 	}
58 
59 	if ((r = sshbuf_put(buf, BEGIN_SIGNATURE,
60 	    sizeof(BEGIN_SIGNATURE)-1)) != 0) {
61 		error("%s: sshbuf_putf failed: %s", __func__, ssh_err(r));
62 		goto out;
63 	}
64 
65 	if ((r = sshbuf_dtob64(blob, buf, 1)) != 0) {
66 		error("%s: Couldn't base64 encode signature blob: %s",
67 		    __func__, ssh_err(r));
68 		goto out;
69 	}
70 
71 	if ((r = sshbuf_put(buf, END_SIGNATURE,
72 	    sizeof(END_SIGNATURE)-1)) != 0 ||
73 	    (r = sshbuf_put_u8(buf, '\n')) != 0) {
74 		error("%s: sshbuf_put failed: %s", __func__, ssh_err(r));
75 		goto out;
76 	}
77 	/* success */
78 	*out = buf;
79 	buf = NULL; /* transferred */
80 	r = 0;
81  out:
82 	sshbuf_free(buf);
83 	return r;
84 }
85 
86 int
87 sshsig_dearmor(struct sshbuf *sig, struct sshbuf **out)
88 {
89 	int r;
90 	size_t eoffset = 0;
91 	struct sshbuf *buf = NULL;
92 	struct sshbuf *sbuf = NULL;
93 	char *b64 = NULL;
94 
95 	if ((sbuf = sshbuf_fromb(sig)) == NULL) {
96 		error("%s: sshbuf_fromb failed", __func__);
97 		return SSH_ERR_ALLOC_FAIL;
98 	}
99 
100 	if ((r = sshbuf_cmp(sbuf, 0,
101 	    BEGIN_SIGNATURE, sizeof(BEGIN_SIGNATURE)-1)) != 0) {
102 		error("Couldn't parse signature: missing header");
103 		goto done;
104 	}
105 
106 	if ((r = sshbuf_consume(sbuf, sizeof(BEGIN_SIGNATURE)-1)) != 0) {
107 		error("%s: sshbuf_consume failed: %s", __func__, ssh_err(r));
108 		goto done;
109 	}
110 
111 	if ((r = sshbuf_find(sbuf, 0, "\n" END_SIGNATURE,
112 	    sizeof("\n" END_SIGNATURE)-1, &eoffset)) != 0) {
113 		error("Couldn't parse signature: missing footer");
114 		goto done;
115 	}
116 
117 	if ((r = sshbuf_consume_end(sbuf, sshbuf_len(sbuf)-eoffset)) != 0) {
118 		error("%s: sshbuf_consume failed: %s", __func__, ssh_err(r));
119 		goto done;
120 	}
121 
122 	if ((b64 = sshbuf_dup_string(sbuf)) == NULL) {
123 		error("%s: sshbuf_dup_string failed", __func__);
124 		r = SSH_ERR_ALLOC_FAIL;
125 		goto done;
126 	}
127 
128 	if ((buf = sshbuf_new()) == NULL) {
129 		error("%s: sshbuf_new() failed", __func__);
130 		r = SSH_ERR_ALLOC_FAIL;
131 		goto done;
132 	}
133 
134 	if ((r = sshbuf_b64tod(buf, b64)) != 0) {
135 		error("Couldn't decode signature: %s", ssh_err(r));
136 		goto done;
137 	}
138 
139 	/* success */
140 	*out = buf;
141 	r = 0;
142 	buf = NULL; /* transferred */
143 done:
144 	sshbuf_free(buf);
145 	sshbuf_free(sbuf);
146 	free(b64);
147 	return r;
148 }
149 
150 static int
151 sshsig_wrap_sign(struct sshkey *key, const char *hashalg,
152     const char *sk_provider, const struct sshbuf *h_message,
153     const char *sig_namespace, struct sshbuf **out,
154     sshsig_signer *signer, void *signer_ctx)
155 {
156 	int r;
157 	size_t slen = 0;
158 	u_char *sig = NULL;
159 	struct sshbuf *blob = NULL;
160 	struct sshbuf *tosign = NULL;
161 	const char *sign_alg = NULL;
162 
163 	if ((tosign = sshbuf_new()) == NULL ||
164 	    (blob = sshbuf_new()) == NULL) {
165 		error("%s: sshbuf_new failed", __func__);
166 		r = SSH_ERR_ALLOC_FAIL;
167 		goto done;
168 	}
169 
170 	if ((r = sshbuf_put(tosign, MAGIC_PREAMBLE, MAGIC_PREAMBLE_LEN)) != 0 ||
171 	    (r = sshbuf_put_cstring(tosign, sig_namespace)) != 0 ||
172 	    (r = sshbuf_put_string(tosign, NULL, 0)) != 0 || /* reserved */
173 	    (r = sshbuf_put_cstring(tosign, hashalg)) != 0 ||
174 	    (r = sshbuf_put_stringb(tosign, h_message)) != 0) {
175 		error("Couldn't construct message to sign: %s", ssh_err(r));
176 		goto done;
177 	}
178 
179 	/* If using RSA keys then default to a good signature algorithm */
180 	if (sshkey_type_plain(key->type) == KEY_RSA)
181 		sign_alg = RSA_SIGN_ALG;
182 
183 	if (signer != NULL) {
184 		if ((r = signer(key, &sig, &slen,
185 		    sshbuf_ptr(tosign), sshbuf_len(tosign),
186 		    sign_alg, sk_provider, 0, signer_ctx)) != 0) {
187 			error("Couldn't sign message: %s", ssh_err(r));
188 			goto done;
189 		}
190 	} else {
191 		if ((r = sshkey_sign(key, &sig, &slen,
192 		    sshbuf_ptr(tosign), sshbuf_len(tosign),
193 		    sign_alg, sk_provider, 0)) != 0) {
194 			error("Couldn't sign message: %s", ssh_err(r));
195 			goto done;
196 		}
197 	}
198 
199 	if ((r = sshbuf_put(blob, MAGIC_PREAMBLE, MAGIC_PREAMBLE_LEN)) != 0 ||
200 	    (r = sshbuf_put_u32(blob, SIG_VERSION)) != 0 ||
201 	    (r = sshkey_puts(key, blob)) != 0 ||
202 	    (r = sshbuf_put_cstring(blob, sig_namespace)) != 0 ||
203 	    (r = sshbuf_put_string(blob, NULL, 0)) != 0 || /* reserved */
204 	    (r = sshbuf_put_cstring(blob, hashalg)) != 0 ||
205 	    (r = sshbuf_put_string(blob, sig, slen)) != 0) {
206 		error("Couldn't populate blob: %s", ssh_err(r));
207 		goto done;
208 	}
209 
210 	*out = blob;
211 	blob = NULL;
212 	r = 0;
213 done:
214 	free(sig);
215 	sshbuf_free(blob);
216 	sshbuf_free(tosign);
217 	return r;
218 }
219 
220 /* Check preamble and version. */
221 static int
222 sshsig_parse_preamble(struct sshbuf *buf)
223 {
224 	int r = SSH_ERR_INTERNAL_ERROR;
225 	uint32_t sversion;
226 
227 	if ((r = sshbuf_cmp(buf, 0, MAGIC_PREAMBLE, MAGIC_PREAMBLE_LEN)) != 0 ||
228 	    (r = sshbuf_consume(buf, (sizeof(MAGIC_PREAMBLE)-1))) != 0 ||
229 	    (r = sshbuf_get_u32(buf, &sversion)) != 0) {
230 		error("Couldn't verify signature: invalid format");
231 		return r;
232 	}
233 
234 	if (sversion > SIG_VERSION) {
235 		error("Signature version %lu is larger than supported "
236 		    "version %u", (unsigned long)sversion, SIG_VERSION);
237 		return SSH_ERR_INVALID_FORMAT;
238 	}
239 	return 0;
240 }
241 
242 static int
243 sshsig_check_hashalg(const char *hashalg)
244 {
245 	if (hashalg == NULL ||
246 	    match_pattern_list(hashalg, HASHALG_ALLOWED, 0) == 1)
247 		return 0;
248 	error("%s: unsupported hash algorithm \"%.100s\"", __func__, hashalg);
249 	return SSH_ERR_SIGN_ALG_UNSUPPORTED;
250 }
251 
252 static int
253 sshsig_peek_hashalg(struct sshbuf *signature, char **hashalgp)
254 {
255 	struct sshbuf *buf = NULL;
256 	char *hashalg = NULL;
257 	int r = SSH_ERR_INTERNAL_ERROR;
258 
259 	if (hashalgp != NULL)
260 		*hashalgp = NULL;
261 	if ((buf = sshbuf_fromb(signature)) == NULL)
262 		return SSH_ERR_ALLOC_FAIL;
263 	if ((r = sshsig_parse_preamble(buf)) != 0)
264 		goto done;
265 	if ((r = sshbuf_get_string_direct(buf, NULL, NULL)) != 0 ||
266 	    (r = sshbuf_get_string_direct(buf, NULL, NULL)) != 0 ||
267 	    (r = sshbuf_get_string(buf, NULL, NULL)) != 0 ||
268 	    (r = sshbuf_get_cstring(buf, &hashalg, NULL)) != 0 ||
269 	    (r = sshbuf_get_string_direct(buf, NULL, NULL)) != 0) {
270 		error("Couldn't parse signature blob: %s", ssh_err(r));
271 		goto done;
272 	}
273 
274 	/* success */
275 	r = 0;
276 	*hashalgp = hashalg;
277 	hashalg = NULL;
278  done:
279 	free(hashalg);
280 	sshbuf_free(buf);
281 	return r;
282 }
283 
284 static int
285 sshsig_wrap_verify(struct sshbuf *signature, const char *hashalg,
286     const struct sshbuf *h_message, const char *expect_namespace,
287     struct sshkey **sign_keyp, struct sshkey_sig_details **sig_details)
288 {
289 	int r = SSH_ERR_INTERNAL_ERROR;
290 	struct sshbuf *buf = NULL, *toverify = NULL;
291 	struct sshkey *key = NULL;
292 	const u_char *sig;
293 	char *got_namespace = NULL, *sigtype = NULL, *sig_hashalg = NULL;
294 	size_t siglen;
295 
296 	debug("%s: verify message length %zu", __func__, sshbuf_len(h_message));
297 	if (sig_details != NULL)
298 		*sig_details = NULL;
299 	if (sign_keyp != NULL)
300 		*sign_keyp = NULL;
301 
302 	if ((toverify = sshbuf_new()) == NULL) {
303 		error("%s: sshbuf_new failed", __func__);
304 		r = SSH_ERR_ALLOC_FAIL;
305 		goto done;
306 	}
307 	if ((r = sshbuf_put(toverify, MAGIC_PREAMBLE,
308 	    MAGIC_PREAMBLE_LEN)) != 0 ||
309 	    (r = sshbuf_put_cstring(toverify, expect_namespace)) != 0 ||
310 	    (r = sshbuf_put_string(toverify, NULL, 0)) != 0 || /* reserved */
311 	    (r = sshbuf_put_cstring(toverify, hashalg)) != 0 ||
312 	    (r = sshbuf_put_stringb(toverify, h_message)) != 0) {
313 		error("Couldn't construct message to verify: %s", ssh_err(r));
314 		goto done;
315 	}
316 
317 	if ((r = sshsig_parse_preamble(signature)) != 0)
318 		goto done;
319 
320 	if ((r = sshkey_froms(signature, &key)) != 0 ||
321 	    (r = sshbuf_get_cstring(signature, &got_namespace, NULL)) != 0 ||
322 	    (r = sshbuf_get_string(signature, NULL, NULL)) != 0 ||
323 	    (r = sshbuf_get_cstring(signature, &sig_hashalg, NULL)) != 0 ||
324 	    (r = sshbuf_get_string_direct(signature, &sig, &siglen)) != 0) {
325 		error("Couldn't parse signature blob: %s", ssh_err(r));
326 		goto done;
327 	}
328 
329 	if (sshbuf_len(signature) != 0) {
330 		error("Signature contains trailing data");
331 		r = SSH_ERR_INVALID_FORMAT;
332 		goto done;
333 	}
334 
335 	if (strcmp(expect_namespace, got_namespace) != 0) {
336 		error("Couldn't verify signature: namespace does not match");
337 		debug("%s: expected namespace \"%s\" received \"%s\"",
338 		    __func__, expect_namespace, got_namespace);
339 		r = SSH_ERR_SIGNATURE_INVALID;
340 		goto done;
341 	}
342 	if (strcmp(hashalg, sig_hashalg) != 0) {
343 		error("Couldn't verify signature: hash algorithm mismatch");
344 		debug("%s: expected algorithm \"%s\" received \"%s\"",
345 		    __func__, hashalg, sig_hashalg);
346 		r = SSH_ERR_SIGNATURE_INVALID;
347 		goto done;
348 	}
349 	/* Ensure that RSA keys use an acceptable signature algorithm */
350 	if (sshkey_type_plain(key->type) == KEY_RSA) {
351 		if ((r = sshkey_get_sigtype(sig, siglen, &sigtype)) != 0) {
352 			error("Couldn't verify signature: unable to get "
353 			    "signature type: %s", ssh_err(r));
354 			goto done;
355 		}
356 		if (match_pattern_list(sigtype, RSA_SIGN_ALLOWED, 0) != 1) {
357 			error("Couldn't verify signature: unsupported RSA "
358 			    "signature algorithm %s", sigtype);
359 			r = SSH_ERR_SIGN_ALG_UNSUPPORTED;
360 			goto done;
361 		}
362 	}
363 	if ((r = sshkey_verify(key, sig, siglen, sshbuf_ptr(toverify),
364 	    sshbuf_len(toverify), NULL, 0, sig_details)) != 0) {
365 		error("Signature verification failed: %s", ssh_err(r));
366 		goto done;
367 	}
368 
369 	/* success */
370 	r = 0;
371 	if (sign_keyp != NULL) {
372 		*sign_keyp = key;
373 		key = NULL; /* transferred */
374 	}
375 done:
376 	free(got_namespace);
377 	free(sigtype);
378 	free(sig_hashalg);
379 	sshbuf_free(buf);
380 	sshbuf_free(toverify);
381 	sshkey_free(key);
382 	return r;
383 }
384 
385 static int
386 hash_buffer(const struct sshbuf *m, const char *hashalg, struct sshbuf **bp)
387 {
388 	char *hex, hash[SSH_DIGEST_MAX_LENGTH];
389 	int alg, r = SSH_ERR_INTERNAL_ERROR;
390 	struct sshbuf *b = NULL;
391 
392 	*bp = NULL;
393 	memset(hash, 0, sizeof(hash));
394 
395 	if ((r = sshsig_check_hashalg(hashalg)) != 0)
396 		return r;
397 	if ((alg = ssh_digest_alg_by_name(hashalg)) == -1) {
398 		error("%s: can't look up hash algorithm %s",
399 		    __func__, hashalg);
400 		return SSH_ERR_INTERNAL_ERROR;
401 	}
402 	if ((r = ssh_digest_buffer(alg, m, hash, sizeof(hash))) != 0) {
403 		error("%s: ssh_digest_buffer failed: %s", __func__, ssh_err(r));
404 		return r;
405 	}
406 	if ((hex = tohex(hash, ssh_digest_bytes(alg))) != NULL) {
407 		debug3("%s: final hash: %s", __func__, hex);
408 		freezero(hex, strlen(hex));
409 	}
410 	if ((b = sshbuf_new()) == NULL) {
411 		r = SSH_ERR_ALLOC_FAIL;
412 		goto out;
413 	}
414 	if ((r = sshbuf_put(b, hash, ssh_digest_bytes(alg))) != 0) {
415 		error("%s: sshbuf_put: %s", __func__, ssh_err(r));
416 		goto out;
417 	}
418 	*bp = b;
419 	b = NULL; /* transferred */
420 	/* success */
421 	r = 0;
422  out:
423 	sshbuf_free(b);
424 	explicit_bzero(hash, sizeof(hash));
425 	return 0;
426 }
427 
428 int
429 sshsig_signb(struct sshkey *key, const char *hashalg, const char *sk_provider,
430     const struct sshbuf *message, const char *sig_namespace,
431     struct sshbuf **out, sshsig_signer *signer, void *signer_ctx)
432 {
433 	struct sshbuf *b = NULL;
434 	int r = SSH_ERR_INTERNAL_ERROR;
435 
436 	if (hashalg == NULL)
437 		hashalg = HASHALG_DEFAULT;
438 	if (out != NULL)
439 		*out = NULL;
440 	if ((r = hash_buffer(message, hashalg, &b)) != 0) {
441 		error("%s: hash_buffer failed: %s", __func__, ssh_err(r));
442 		goto out;
443 	}
444 	if ((r = sshsig_wrap_sign(key, hashalg, sk_provider, b,
445 	    sig_namespace, out, signer, signer_ctx)) != 0)
446 		goto out;
447 	/* success */
448 	r = 0;
449  out:
450 	sshbuf_free(b);
451 	return r;
452 }
453 
454 int
455 sshsig_verifyb(struct sshbuf *signature, const struct sshbuf *message,
456     const char *expect_namespace, struct sshkey **sign_keyp,
457     struct sshkey_sig_details **sig_details)
458 {
459 	struct sshbuf *b = NULL;
460 	int r = SSH_ERR_INTERNAL_ERROR;
461 	char *hashalg = NULL;
462 
463 	if (sig_details != NULL)
464 		*sig_details = NULL;
465 	if (sign_keyp != NULL)
466 		*sign_keyp = NULL;
467 	if ((r = sshsig_peek_hashalg(signature, &hashalg)) != 0)
468 		return r;
469 	debug("%s: signature made with hash \"%s\"", __func__, hashalg);
470 	if ((r = hash_buffer(message, hashalg, &b)) != 0) {
471 		error("%s: hash_buffer failed: %s", __func__, ssh_err(r));
472 		goto out;
473 	}
474 	if ((r = sshsig_wrap_verify(signature, hashalg, b, expect_namespace,
475 	    sign_keyp, sig_details)) != 0)
476 		goto out;
477 	/* success */
478 	r = 0;
479  out:
480 	sshbuf_free(b);
481 	free(hashalg);
482 	return r;
483 }
484 
485 static int
486 hash_file(int fd, const char *hashalg, struct sshbuf **bp)
487 {
488 	char *hex, rbuf[8192], hash[SSH_DIGEST_MAX_LENGTH];
489 	ssize_t n, total = 0;
490 	struct ssh_digest_ctx *ctx;
491 	int alg, oerrno, r = SSH_ERR_INTERNAL_ERROR;
492 	struct sshbuf *b = NULL;
493 
494 	*bp = NULL;
495 	memset(hash, 0, sizeof(hash));
496 
497 	if ((r = sshsig_check_hashalg(hashalg)) != 0)
498 		return r;
499 	if ((alg = ssh_digest_alg_by_name(hashalg)) == -1) {
500 		error("%s: can't look up hash algorithm %s",
501 		    __func__, hashalg);
502 		return SSH_ERR_INTERNAL_ERROR;
503 	}
504 	if ((ctx = ssh_digest_start(alg)) == NULL) {
505 		error("%s: ssh_digest_start failed", __func__);
506 		return SSH_ERR_INTERNAL_ERROR;
507 	}
508 	for (;;) {
509 		if ((n = read(fd, rbuf, sizeof(rbuf))) == -1) {
510 			if (errno == EINTR || errno == EAGAIN)
511 				continue;
512 			oerrno = errno;
513 			error("%s: read: %s", __func__, strerror(errno));
514 			ssh_digest_free(ctx);
515 			errno = oerrno;
516 			r = SSH_ERR_SYSTEM_ERROR;
517 			goto out;
518 		} else if (n == 0) {
519 			debug2("%s: hashed %zu bytes", __func__, total);
520 			break; /* EOF */
521 		}
522 		total += (size_t)n;
523 		if ((r = ssh_digest_update(ctx, rbuf, (size_t)n)) != 0) {
524 			error("%s: ssh_digest_update: %s",
525 			    __func__, ssh_err(r));
526 			goto out;
527 		}
528 	}
529 	if ((r = ssh_digest_final(ctx, hash, sizeof(hash))) != 0) {
530 		error("%s: ssh_digest_final: %s", __func__, ssh_err(r));
531 		goto out;
532 	}
533 	if ((hex = tohex(hash, ssh_digest_bytes(alg))) != NULL) {
534 		debug3("%s: final hash: %s", __func__, hex);
535 		freezero(hex, strlen(hex));
536 	}
537 	if ((b = sshbuf_new()) == NULL) {
538 		r = SSH_ERR_ALLOC_FAIL;
539 		goto out;
540 	}
541 	if ((r = sshbuf_put(b, hash, ssh_digest_bytes(alg))) != 0) {
542 		error("%s: sshbuf_put: %s", __func__, ssh_err(r));
543 		goto out;
544 	}
545 	*bp = b;
546 	b = NULL; /* transferred */
547 	/* success */
548 	r = 0;
549  out:
550 	sshbuf_free(b);
551 	ssh_digest_free(ctx);
552 	explicit_bzero(hash, sizeof(hash));
553 	return 0;
554 }
555 
556 int
557 sshsig_sign_fd(struct sshkey *key, const char *hashalg, const char *sk_provider,
558     int fd, const char *sig_namespace, struct sshbuf **out,
559     sshsig_signer *signer, void *signer_ctx)
560 {
561 	struct sshbuf *b = NULL;
562 	int r = SSH_ERR_INTERNAL_ERROR;
563 
564 	if (hashalg == NULL)
565 		hashalg = HASHALG_DEFAULT;
566 	if (out != NULL)
567 		*out = NULL;
568 	if ((r = hash_file(fd, hashalg, &b)) != 0) {
569 		error("%s: hash_file failed: %s", __func__, ssh_err(r));
570 		return r;
571 	}
572 	if ((r = sshsig_wrap_sign(key, hashalg, sk_provider, b,
573 	    sig_namespace, out, signer, signer_ctx)) != 0)
574 		goto out;
575 	/* success */
576 	r = 0;
577  out:
578 	sshbuf_free(b);
579 	return r;
580 }
581 
582 int
583 sshsig_verify_fd(struct sshbuf *signature, int fd,
584     const char *expect_namespace, struct sshkey **sign_keyp,
585     struct sshkey_sig_details **sig_details)
586 {
587 	struct sshbuf *b = NULL;
588 	int r = SSH_ERR_INTERNAL_ERROR;
589 	char *hashalg = NULL;
590 
591 	if (sig_details != NULL)
592 		*sig_details = NULL;
593 	if (sign_keyp != NULL)
594 		*sign_keyp = NULL;
595 	if ((r = sshsig_peek_hashalg(signature, &hashalg)) != 0)
596 		return r;
597 	debug("%s: signature made with hash \"%s\"", __func__, hashalg);
598 	if ((r = hash_file(fd, hashalg, &b)) != 0) {
599 		error("%s: hash_file failed: %s", __func__, ssh_err(r));
600 		goto out;
601 	}
602 	if ((r = sshsig_wrap_verify(signature, hashalg, b, expect_namespace,
603 	    sign_keyp, sig_details)) != 0)
604 		goto out;
605 	/* success */
606 	r = 0;
607  out:
608 	sshbuf_free(b);
609 	free(hashalg);
610 	return r;
611 }
612 
613 struct sshsigopt {
614 	int ca;
615 	char *namespaces;
616 };
617 
618 struct sshsigopt *
619 sshsigopt_parse(const char *opts, const char *path, u_long linenum,
620     const char **errstrp)
621 {
622 	struct sshsigopt *ret;
623 	int r;
624 	const char *errstr = NULL;
625 
626 	if ((ret = calloc(1, sizeof(*ret))) == NULL)
627 		return NULL;
628 	if (opts == NULL || *opts == '\0')
629 		return ret; /* Empty options yields empty options :) */
630 
631 	while (*opts && *opts != ' ' && *opts != '\t') {
632 		/* flag options */
633 		if ((r = opt_flag("cert-authority", 0, &opts)) != -1) {
634 			ret->ca = 1;
635 		} else if (opt_match(&opts, "namespaces")) {
636 			if (ret->namespaces != NULL) {
637 				errstr = "multiple \"namespaces\" clauses";
638 				goto fail;
639 			}
640 			ret->namespaces = opt_dequote(&opts, &errstr);
641 			if (ret->namespaces == NULL)
642 				goto fail;
643 		}
644 		/*
645 		 * Skip the comma, and move to the next option
646 		 * (or break out if there are no more).
647 		 */
648 		if (*opts == '\0' || *opts == ' ' || *opts == '\t')
649 			break;		/* End of options. */
650 		/* Anything other than a comma is an unknown option */
651 		if (*opts != ',') {
652 			errstr = "unknown key option";
653 			goto fail;
654 		}
655 		opts++;
656 		if (*opts == '\0') {
657 			errstr = "unexpected end-of-options";
658 			goto fail;
659 		}
660 	}
661 	/* success */
662 	return ret;
663  fail:
664 	if (errstrp != NULL)
665 		*errstrp = errstr;
666 	sshsigopt_free(ret);
667 	return NULL;
668 }
669 
670 void
671 sshsigopt_free(struct sshsigopt *opts)
672 {
673 	if (opts == NULL)
674 		return;
675 	free(opts->namespaces);
676 	free(opts);
677 }
678 
679 static int
680 parse_principals_key_and_options(const char *path, u_long linenum, char *line,
681     const char *required_principal, char **principalsp, struct sshkey **keyp,
682     struct sshsigopt **sigoptsp)
683 {
684 	char *opts = NULL, *tmp, *cp, *principals = NULL;
685 	const char *reason = NULL;
686 	struct sshsigopt *sigopts = NULL;
687 	struct sshkey *key = NULL;
688 	int r = SSH_ERR_INTERNAL_ERROR;
689 
690 	if (principalsp != NULL)
691 		*principalsp = NULL;
692 	if (sigoptsp != NULL)
693 		*sigoptsp = NULL;
694 	if (keyp != NULL)
695 		*keyp = NULL;
696 
697 	cp = line;
698 	cp = cp + strspn(cp, " \t"); /* skip leading whitespace */
699 	if (*cp == '#' || *cp == '\0')
700 		return SSH_ERR_KEY_NOT_FOUND; /* blank or all-comment line */
701 
702 	/* format: identity[,identity...] [option[,option...]] key */
703 	if ((tmp = strdelimw(&cp)) == NULL) {
704 		error("%s:%lu: invalid line", path, linenum);
705 		r = SSH_ERR_INVALID_FORMAT;
706 		goto out;
707 	}
708 	if ((principals = strdup(tmp)) == NULL) {
709 		error("%s: strdup failed", __func__);
710 		r = SSH_ERR_ALLOC_FAIL;
711 		goto out;
712 	}
713 	/*
714 	 * Bail out early if we're looking for a particular principal and this
715 	 * line does not list it.
716 	 */
717 	if (required_principal != NULL) {
718 		if (match_pattern_list(required_principal,
719 		    principals, 0) != 1) {
720 			/* principal didn't match */
721 			r = SSH_ERR_KEY_NOT_FOUND;
722 			goto out;
723 		}
724 		debug("%s: %s:%lu: matched principal \"%s\"",
725 		    __func__, path, linenum, required_principal);
726 	}
727 
728 	if ((key = sshkey_new(KEY_UNSPEC)) == NULL) {
729 		error("%s: sshkey_new failed", __func__);
730 		r = SSH_ERR_ALLOC_FAIL;
731 		goto out;
732 	}
733 	if (sshkey_read(key, &cp) != 0) {
734 		/* no key? Check for options */
735 		opts = cp;
736 		if (sshkey_advance_past_options(&cp) != 0) {
737 			error("%s:%lu: invalid options", path, linenum);
738 			r = SSH_ERR_INVALID_FORMAT;
739 			goto out;
740 		}
741 		*cp++ = '\0';
742 		skip_space(&cp);
743 		if (sshkey_read(key, &cp) != 0) {
744 			error("%s:%lu: invalid key", path, linenum);
745 			r = SSH_ERR_INVALID_FORMAT;
746 			goto out;
747 		}
748 	}
749 	debug3("%s:%lu: options %s", path, linenum, opts == NULL ? "" : opts);
750 	if ((sigopts = sshsigopt_parse(opts, path, linenum, &reason)) == NULL) {
751 		error("%s:%lu: bad options: %s", path, linenum, reason);
752 		r = SSH_ERR_INVALID_FORMAT;
753 		goto out;
754 	}
755 	/* success */
756 	if (principalsp != NULL) {
757 		*principalsp = principals;
758 		principals = NULL; /* transferred */
759 	}
760 	if (sigoptsp != NULL) {
761 		*sigoptsp = sigopts;
762 		sigopts = NULL; /* transferred */
763 	}
764 	if (keyp != NULL) {
765 		*keyp = key;
766 		key = NULL; /* transferred */
767 	}
768 	r = 0;
769  out:
770 	free(principals);
771 	sshsigopt_free(sigopts);
772 	sshkey_free(key);
773 	return r;
774 }
775 
776 static int
777 check_allowed_keys_line(const char *path, u_long linenum, char *line,
778     const struct sshkey *sign_key, const char *principal,
779     const char *sig_namespace)
780 {
781 	struct sshkey *found_key = NULL;
782 	int r, found = 0;
783 	const char *reason = NULL;
784 	struct sshsigopt *sigopts = NULL;
785 
786 	/* Parse the line */
787 	if ((r = parse_principals_key_and_options(path, linenum, line,
788 	    principal, NULL, &found_key, &sigopts)) != 0) {
789 		/* error already logged */
790 		goto done;
791 	}
792 
793 	/* Check whether options preclude the use of this key */
794 	if (sigopts->namespaces != NULL &&
795 	    match_pattern_list(sig_namespace, sigopts->namespaces, 0) != 1) {
796 		error("%s:%lu: key is not permitted for use in signature "
797 		    "namespace \"%s\"", path, linenum, sig_namespace);
798 		goto done;
799 	}
800 
801 	if (!sigopts->ca && sshkey_equal(found_key, sign_key)) {
802 		/* Exact match of key */
803 		debug("%s:%lu: matched key and principal", path, linenum);
804 		/* success */
805 		found = 1;
806 	} else if (sigopts->ca && sshkey_is_cert(sign_key) &&
807 	    sshkey_equal_public(sign_key->cert->signature_key, found_key)) {
808 		/* Match of certificate's CA key */
809 		if ((r = sshkey_cert_check_authority(sign_key, 0, 1,
810 		    principal, &reason)) != 0) {
811 			error("%s:%lu: certificate not authorized: %s",
812 			    path, linenum, reason);
813 			goto done;
814 		}
815 		debug("%s:%lu: matched certificate CA key", path, linenum);
816 		/* success */
817 		found = 1;
818 	} else {
819 		/* Principal matched but key didn't */
820 		goto done;
821 	}
822  done:
823 	sshkey_free(found_key);
824 	sshsigopt_free(sigopts);
825 	return found ? 0 : SSH_ERR_KEY_NOT_FOUND;
826 }
827 
828 int
829 sshsig_check_allowed_keys(const char *path, const struct sshkey *sign_key,
830     const char *principal, const char *sig_namespace)
831 {
832 	FILE *f = NULL;
833 	char *line = NULL;
834 	size_t linesize = 0;
835 	u_long linenum = 0;
836 	int r, oerrno;
837 
838 	/* Check key and principal against file */
839 	if ((f = fopen(path, "r")) == NULL) {
840 		oerrno = errno;
841 		error("Unable to open allowed keys file \"%s\": %s",
842 		    path, strerror(errno));
843 		errno = oerrno;
844 		return SSH_ERR_SYSTEM_ERROR;
845 	}
846 
847 	while (getline(&line, &linesize, f) != -1) {
848 		linenum++;
849 		r = check_allowed_keys_line(path, linenum, line, sign_key,
850 		    principal, sig_namespace);
851 		free(line);
852 		line = NULL;
853 		if (r == SSH_ERR_KEY_NOT_FOUND)
854 			continue;
855 		else if (r == 0) {
856 			/* success */
857 			fclose(f);
858 			return 0;
859 		} else
860 			break;
861 	}
862 	/* Either we hit an error parsing or we simply didn't find the key */
863 	fclose(f);
864 	free(line);
865 	return r == 0 ? SSH_ERR_KEY_NOT_FOUND : r;
866 }
867 
868 static int
869 cert_filter_principals(const char *path, u_long linenum,
870     char **principalsp, const struct sshkey *cert)
871 {
872 	char *cp, *oprincipals, *principals;
873 	const char *reason;
874 	struct sshbuf *nprincipals;
875 	int r = SSH_ERR_INTERNAL_ERROR, success = 0;
876 
877 	oprincipals = principals = *principalsp;
878 	*principalsp = NULL;
879 
880 	if ((nprincipals = sshbuf_new()) == NULL)
881 		return SSH_ERR_ALLOC_FAIL;
882 
883 	while ((cp = strsep(&principals, ",")) != NULL && *cp != '\0') {
884 		if (strcspn(cp, "!?*") != strlen(cp)) {
885 			debug("%s:%lu: principal \"%s\" not authorized: "
886 			    "contains wildcards", path, linenum, cp);
887 			continue;
888 		}
889 		/* Check against principals list in certificate */
890 		if ((r = sshkey_cert_check_authority(cert, 0, 1,
891 		    cp, &reason)) != 0) {
892 			debug("%s:%lu: principal \"%s\" not authorized: %s",
893 			    path, linenum, cp, reason);
894 			continue;
895 		}
896 		if ((r = sshbuf_putf(nprincipals, "%s%s",
897 		    sshbuf_len(nprincipals) != 0 ? "," : "", cp)) != 0) {
898 			error("%s: buffer error", __func__);
899 			goto out;
900 		}
901 	}
902 	if (sshbuf_len(nprincipals) == 0) {
903 		error("%s:%lu: no valid principals found", path, linenum);
904 		r = SSH_ERR_KEY_CERT_INVALID;
905 		goto out;
906 	}
907 	if ((principals = sshbuf_dup_string(nprincipals)) == NULL) {
908 		error("%s: buffer error", __func__);
909 		goto out;
910 	}
911 	/* success */
912 	success = 1;
913 	*principalsp = principals;
914  out:
915 	sshbuf_free(nprincipals);
916 	free(oprincipals);
917 	return success ? 0 : r;
918 }
919 
920 static int
921 get_matching_principals_from_line(const char *path, u_long linenum, char *line,
922     const struct sshkey *sign_key, char **principalsp)
923 {
924 	struct sshkey *found_key = NULL;
925 	char *principals = NULL;
926 	int r, found = 0;
927 	struct sshsigopt *sigopts = NULL;
928 
929 	if (principalsp != NULL)
930 		*principalsp = NULL;
931 
932 	/* Parse the line */
933 	if ((r = parse_principals_key_and_options(path, linenum, line,
934 	    NULL, &principals, &found_key, &sigopts)) != 0) {
935 		/* error already logged */
936 		goto done;
937 	}
938 
939 	if (!sigopts->ca && sshkey_equal(found_key, sign_key)) {
940 		/* Exact match of key */
941 		debug("%s:%lu: matched key", path, linenum);
942 		/* success */
943 		found = 1;
944 	} else if (sigopts->ca && sshkey_is_cert(sign_key) &&
945 	    sshkey_equal_public(sign_key->cert->signature_key, found_key)) {
946 		/* Remove principals listed in file but not allowed by cert */
947 		if ((r = cert_filter_principals(path, linenum,
948 		    &principals, sign_key)) != 0) {
949 			/* error already displayed */
950 			debug("%s:%lu: cert_filter_principals: %s",
951 			    path, linenum, ssh_err(r));
952 			goto done;
953 		}
954 		debug("%s:%lu: matched certificate CA key", path, linenum);
955 		/* success */
956 		found = 1;
957 	} else {
958 		/* Key didn't match */
959 		goto done;
960 	}
961  done:
962 	if (found) {
963 		*principalsp = principals;
964 		principals = NULL; /* transferred */
965 	}
966 	free(principals);
967 	sshkey_free(found_key);
968 	sshsigopt_free(sigopts);
969 	return found ? 0 : SSH_ERR_KEY_NOT_FOUND;
970 }
971 
972 int
973 sshsig_find_principals(const char *path, const struct sshkey *sign_key,
974     char **principals)
975 {
976 	FILE *f = NULL;
977 	char *line = NULL;
978 	size_t linesize = 0;
979 	u_long linenum = 0;
980 	int r, oerrno;
981 
982 	if ((f = fopen(path, "r")) == NULL) {
983 		oerrno = errno;
984 		error("Unable to open allowed keys file \"%s\": %s",
985 		    path, strerror(errno));
986 		errno = oerrno;
987 		return SSH_ERR_SYSTEM_ERROR;
988 	}
989 
990 	while (getline(&line, &linesize, f) != -1) {
991 		linenum++;
992 		r = get_matching_principals_from_line(path, linenum, line,
993 		    sign_key, principals);
994 		free(line);
995 		line = NULL;
996 		if (r == SSH_ERR_KEY_NOT_FOUND)
997 			continue;
998 		else if (r == 0) {
999 			/* success */
1000 			fclose(f);
1001 			return 0;
1002 		} else
1003 			break;
1004 	}
1005 	free(line);
1006 	/* Either we hit an error parsing or we simply didn't find the key */
1007 	if (ferror(f) != 0) {
1008 		oerrno = errno;
1009 		fclose(f);
1010 		error("Unable to read allowed keys file \"%s\": %s",
1011 		    path, strerror(errno));
1012 		errno = oerrno;
1013 		return SSH_ERR_SYSTEM_ERROR;
1014 	}
1015 	fclose(f);
1016 	return r == 0 ? SSH_ERR_KEY_NOT_FOUND : r;
1017 }
1018 
1019 int
1020 sshsig_get_pubkey(struct sshbuf *signature, struct sshkey **pubkey)
1021 {
1022 	struct sshkey *pk = NULL;
1023 	int r = SSH_ERR_SIGNATURE_INVALID;
1024 
1025 	if (pubkey != NULL)
1026 		*pubkey = NULL;
1027 	if ((r = sshsig_parse_preamble(signature)) != 0)
1028 		return r;
1029 	if ((r = sshkey_froms(signature, &pk)) != 0)
1030 		return r;
1031 
1032 	*pubkey = pk;
1033 	pk = NULL;
1034 	return 0;
1035 }
1036