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