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