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