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