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