1 /* $NetBSD: sshkey-xmss.c,v 1.6 2020/02/27 00:24:40 christos Exp $ */ 2 /* $OpenBSD: sshkey-xmss.c,v 1.8 2019/11/13 07:53:10 markus Exp $ */ 3 /* 4 * Copyright (c) 2017 Markus Friedl. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 #include "includes.h" 27 __RCSID("$NetBSD: sshkey-xmss.c,v 1.6 2020/02/27 00:24:40 christos Exp $"); 28 29 #include <sys/types.h> 30 #include <sys/uio.h> 31 32 #include <stdio.h> 33 #include <string.h> 34 #include <unistd.h> 35 #include <fcntl.h> 36 #include <errno.h> 37 38 #include "ssh2.h" 39 #include "ssherr.h" 40 #include "sshbuf.h" 41 #include "cipher.h" 42 #include "sshkey.h" 43 #include "sshkey-xmss.h" 44 #include "atomicio.h" 45 46 #include "xmss_fast.h" 47 48 /* opaque internal XMSS state */ 49 #define XMSS_MAGIC "xmss-state-v1" 50 #define XMSS_CIPHERNAME "aes256-gcm@openssh.com" 51 struct ssh_xmss_state { 52 xmss_params params; 53 u_int32_t n, w, h, k; 54 55 bds_state bds; 56 u_char *stack; 57 u_int32_t stackoffset; 58 u_char *stacklevels; 59 u_char *auth; 60 u_char *keep; 61 u_char *th_nodes; 62 u_char *retain; 63 treehash_inst *treehash; 64 65 u_int32_t idx; /* state read from file */ 66 u_int32_t maxidx; /* restricted # of signatures */ 67 int have_state; /* .state file exists */ 68 int lockfd; /* locked in sshkey_xmss_get_state() */ 69 u_char allow_update; /* allow sshkey_xmss_update_state() */ 70 char *enc_ciphername;/* encrypt state with cipher */ 71 u_char *enc_keyiv; /* encrypt state with key */ 72 u_int32_t enc_keyiv_len; /* length of enc_keyiv */ 73 }; 74 75 int sshkey_xmss_init_bds_state(struct sshkey *); 76 int sshkey_xmss_init_enc_key(struct sshkey *, const char *); 77 void sshkey_xmss_free_bds(struct sshkey *); 78 int sshkey_xmss_get_state_from_file(struct sshkey *, const char *, 79 int *, sshkey_printfn *); 80 int sshkey_xmss_encrypt_state(const struct sshkey *, struct sshbuf *, 81 struct sshbuf **); 82 int sshkey_xmss_decrypt_state(const struct sshkey *, struct sshbuf *, 83 struct sshbuf **); 84 int sshkey_xmss_serialize_enc_key(const struct sshkey *, struct sshbuf *); 85 int sshkey_xmss_deserialize_enc_key(struct sshkey *, struct sshbuf *); 86 87 #define PRINT(s...) do { if (pr) pr(s); } while (/*CONSTCOND*/0) 88 89 int 90 sshkey_xmss_init(struct sshkey *key, const char *name) 91 { 92 struct ssh_xmss_state *state; 93 94 if (key->xmss_state != NULL) 95 return SSH_ERR_INVALID_FORMAT; 96 if (name == NULL) 97 return SSH_ERR_INVALID_FORMAT; 98 state = calloc(sizeof(struct ssh_xmss_state), 1); 99 if (state == NULL) 100 return SSH_ERR_ALLOC_FAIL; 101 if (strcmp(name, XMSS_SHA2_256_W16_H10_NAME) == 0) { 102 state->n = 32; 103 state->w = 16; 104 state->h = 10; 105 } else if (strcmp(name, XMSS_SHA2_256_W16_H16_NAME) == 0) { 106 state->n = 32; 107 state->w = 16; 108 state->h = 16; 109 } else if (strcmp(name, XMSS_SHA2_256_W16_H20_NAME) == 0) { 110 state->n = 32; 111 state->w = 16; 112 state->h = 20; 113 } else { 114 free(state); 115 return SSH_ERR_KEY_TYPE_UNKNOWN; 116 } 117 if ((key->xmss_name = strdup(name)) == NULL) { 118 free(state); 119 return SSH_ERR_ALLOC_FAIL; 120 } 121 state->k = 2; /* XXX hardcoded */ 122 state->lockfd = -1; 123 if (xmss_set_params(&state->params, state->n, state->h, state->w, 124 state->k) != 0) { 125 free(state); 126 return SSH_ERR_INVALID_FORMAT; 127 } 128 key->xmss_state = state; 129 return 0; 130 } 131 132 void 133 sshkey_xmss_free_state(struct sshkey *key) 134 { 135 struct ssh_xmss_state *state = key->xmss_state; 136 137 sshkey_xmss_free_bds(key); 138 if (state) { 139 if (state->enc_keyiv) { 140 explicit_bzero(state->enc_keyiv, state->enc_keyiv_len); 141 free(state->enc_keyiv); 142 } 143 free(state->enc_ciphername); 144 free(state); 145 } 146 key->xmss_state = NULL; 147 } 148 149 #define SSH_XMSS_K2_MAGIC "k=2" 150 #define num_stack(x) ((x->h+1)*(x->n)) 151 #define num_stacklevels(x) (x->h+1) 152 #define num_auth(x) ((x->h)*(x->n)) 153 #define num_keep(x) ((x->h >> 1)*(x->n)) 154 #define num_th_nodes(x) ((x->h - x->k)*(x->n)) 155 #define num_retain(x) (((1ULL << x->k) - x->k - 1) * (x->n)) 156 #define num_treehash(x) ((x->h) - (x->k)) 157 158 int 159 sshkey_xmss_init_bds_state(struct sshkey *key) 160 { 161 struct ssh_xmss_state *state = key->xmss_state; 162 u_int32_t i; 163 164 state->stackoffset = 0; 165 if ((state->stack = calloc(num_stack(state), 1)) == NULL || 166 (state->stacklevels = calloc(num_stacklevels(state), 1))== NULL || 167 (state->auth = calloc(num_auth(state), 1)) == NULL || 168 (state->keep = calloc(num_keep(state), 1)) == NULL || 169 (state->th_nodes = calloc(num_th_nodes(state), 1)) == NULL || 170 (state->retain = calloc(num_retain(state), 1)) == NULL || 171 (state->treehash = calloc(num_treehash(state), 172 sizeof(treehash_inst))) == NULL) { 173 sshkey_xmss_free_bds(key); 174 return SSH_ERR_ALLOC_FAIL; 175 } 176 for (i = 0; i < state->h - state->k; i++) 177 state->treehash[i].node = &state->th_nodes[state->n*i]; 178 xmss_set_bds_state(&state->bds, state->stack, state->stackoffset, 179 state->stacklevels, state->auth, state->keep, state->treehash, 180 state->retain, 0); 181 return 0; 182 } 183 184 void 185 sshkey_xmss_free_bds(struct sshkey *key) 186 { 187 struct ssh_xmss_state *state = key->xmss_state; 188 189 if (state == NULL) 190 return; 191 free(state->stack); 192 free(state->stacklevels); 193 free(state->auth); 194 free(state->keep); 195 free(state->th_nodes); 196 free(state->retain); 197 free(state->treehash); 198 state->stack = NULL; 199 state->stacklevels = NULL; 200 state->auth = NULL; 201 state->keep = NULL; 202 state->th_nodes = NULL; 203 state->retain = NULL; 204 state->treehash = NULL; 205 } 206 207 void * 208 sshkey_xmss_params(const struct sshkey *key) 209 { 210 struct ssh_xmss_state *state = key->xmss_state; 211 212 if (state == NULL) 213 return NULL; 214 return &state->params; 215 } 216 217 void * 218 sshkey_xmss_bds_state(const struct sshkey *key) 219 { 220 struct ssh_xmss_state *state = key->xmss_state; 221 222 if (state == NULL) 223 return NULL; 224 return &state->bds; 225 } 226 227 int 228 sshkey_xmss_siglen(const struct sshkey *key, size_t *lenp) 229 { 230 struct ssh_xmss_state *state = key->xmss_state; 231 232 if (lenp == NULL) 233 return SSH_ERR_INVALID_ARGUMENT; 234 if (state == NULL) 235 return SSH_ERR_INVALID_FORMAT; 236 *lenp = 4 + state->n + 237 state->params.wots_par.keysize + 238 state->h * state->n; 239 return 0; 240 } 241 242 size_t 243 sshkey_xmss_pklen(const struct sshkey *key) 244 { 245 struct ssh_xmss_state *state = key->xmss_state; 246 247 if (state == NULL) 248 return 0; 249 return state->n * 2; 250 } 251 252 size_t 253 sshkey_xmss_sklen(const struct sshkey *key) 254 { 255 struct ssh_xmss_state *state = key->xmss_state; 256 257 if (state == NULL) 258 return 0; 259 return state->n * 4 + 4; 260 } 261 262 int 263 sshkey_xmss_init_enc_key(struct sshkey *k, const char *ciphername) 264 { 265 struct ssh_xmss_state *state = k->xmss_state; 266 const struct sshcipher *cipher; 267 size_t keylen = 0, ivlen = 0; 268 269 if (state == NULL) 270 return SSH_ERR_INVALID_ARGUMENT; 271 if ((cipher = cipher_by_name(ciphername)) == NULL) 272 return SSH_ERR_INTERNAL_ERROR; 273 if ((state->enc_ciphername = strdup(ciphername)) == NULL) 274 return SSH_ERR_ALLOC_FAIL; 275 keylen = cipher_keylen(cipher); 276 ivlen = cipher_ivlen(cipher); 277 state->enc_keyiv_len = keylen + ivlen; 278 if ((state->enc_keyiv = calloc(state->enc_keyiv_len, 1)) == NULL) { 279 free(state->enc_ciphername); 280 state->enc_ciphername = NULL; 281 return SSH_ERR_ALLOC_FAIL; 282 } 283 arc4random_buf(state->enc_keyiv, state->enc_keyiv_len); 284 return 0; 285 } 286 287 int 288 sshkey_xmss_serialize_enc_key(const struct sshkey *k, struct sshbuf *b) 289 { 290 struct ssh_xmss_state *state = k->xmss_state; 291 int r; 292 293 if (state == NULL || state->enc_keyiv == NULL || 294 state->enc_ciphername == NULL) 295 return SSH_ERR_INVALID_ARGUMENT; 296 if ((r = sshbuf_put_cstring(b, state->enc_ciphername)) != 0 || 297 (r = sshbuf_put_string(b, state->enc_keyiv, 298 state->enc_keyiv_len)) != 0) 299 return r; 300 return 0; 301 } 302 303 int 304 sshkey_xmss_deserialize_enc_key(struct sshkey *k, struct sshbuf *b) 305 { 306 struct ssh_xmss_state *state = k->xmss_state; 307 size_t len; 308 int r; 309 310 if (state == NULL) 311 return SSH_ERR_INVALID_ARGUMENT; 312 if ((r = sshbuf_get_cstring(b, &state->enc_ciphername, NULL)) != 0 || 313 (r = sshbuf_get_string(b, &state->enc_keyiv, &len)) != 0) 314 return r; 315 state->enc_keyiv_len = len; 316 return 0; 317 } 318 319 int 320 sshkey_xmss_serialize_pk_info(const struct sshkey *k, struct sshbuf *b, 321 enum sshkey_serialize_rep opts) 322 { 323 struct ssh_xmss_state *state = k->xmss_state; 324 u_char have_info = 1; 325 u_int32_t idx; 326 int r; 327 328 if (state == NULL) 329 return SSH_ERR_INVALID_ARGUMENT; 330 if (opts != SSHKEY_SERIALIZE_INFO) 331 return 0; 332 idx = k->xmss_sk ? PEEK_U32(k->xmss_sk) : state->idx; 333 if ((r = sshbuf_put_u8(b, have_info)) != 0 || 334 (r = sshbuf_put_u32(b, idx)) != 0 || 335 (r = sshbuf_put_u32(b, state->maxidx)) != 0) 336 return r; 337 return 0; 338 } 339 340 int 341 sshkey_xmss_deserialize_pk_info(struct sshkey *k, struct sshbuf *b) 342 { 343 struct ssh_xmss_state *state = k->xmss_state; 344 u_char have_info; 345 int r; 346 347 if (state == NULL) 348 return SSH_ERR_INVALID_ARGUMENT; 349 /* optional */ 350 if (sshbuf_len(b) == 0) 351 return 0; 352 if ((r = sshbuf_get_u8(b, &have_info)) != 0) 353 return r; 354 if (have_info != 1) 355 return SSH_ERR_INVALID_ARGUMENT; 356 if ((r = sshbuf_get_u32(b, &state->idx)) != 0 || 357 (r = sshbuf_get_u32(b, &state->maxidx)) != 0) 358 return r; 359 return 0; 360 } 361 362 int 363 sshkey_xmss_generate_private_key(struct sshkey *k, u_int bits) 364 { 365 int r; 366 const char *name; 367 368 if (bits == 10) { 369 name = XMSS_SHA2_256_W16_H10_NAME; 370 } else if (bits == 16) { 371 name = XMSS_SHA2_256_W16_H16_NAME; 372 } else if (bits == 20) { 373 name = XMSS_SHA2_256_W16_H20_NAME; 374 } else { 375 name = XMSS_DEFAULT_NAME; 376 } 377 if ((r = sshkey_xmss_init(k, name)) != 0 || 378 (r = sshkey_xmss_init_bds_state(k)) != 0 || 379 (r = sshkey_xmss_init_enc_key(k, XMSS_CIPHERNAME)) != 0) 380 return r; 381 if ((k->xmss_pk = malloc(sshkey_xmss_pklen(k))) == NULL || 382 (k->xmss_sk = malloc(sshkey_xmss_sklen(k))) == NULL) { 383 return SSH_ERR_ALLOC_FAIL; 384 } 385 xmss_keypair(k->xmss_pk, k->xmss_sk, sshkey_xmss_bds_state(k), 386 sshkey_xmss_params(k)); 387 return 0; 388 } 389 390 int 391 sshkey_xmss_get_state_from_file(struct sshkey *k, const char *filename, 392 int *have_file, sshkey_printfn *pr) 393 { 394 struct sshbuf *b = NULL, *enc = NULL; 395 int ret = SSH_ERR_SYSTEM_ERROR, r, fd = -1; 396 u_int32_t len; 397 unsigned char buf[4], *data = NULL; 398 399 *have_file = 0; 400 if ((fd = open(filename, O_RDONLY)) >= 0) { 401 *have_file = 1; 402 if (atomicio(read, fd, buf, sizeof(buf)) != sizeof(buf)) { 403 PRINT("%s: corrupt state file: %s", __func__, filename); 404 goto done; 405 } 406 len = PEEK_U32(buf); 407 if ((data = calloc(len, 1)) == NULL) { 408 ret = SSH_ERR_ALLOC_FAIL; 409 goto done; 410 } 411 if (atomicio(read, fd, data, len) != len) { 412 PRINT("%s: cannot read blob: %s", __func__, filename); 413 goto done; 414 } 415 if ((enc = sshbuf_from(data, len)) == NULL) { 416 ret = SSH_ERR_ALLOC_FAIL; 417 goto done; 418 } 419 sshkey_xmss_free_bds(k); 420 if ((r = sshkey_xmss_decrypt_state(k, enc, &b)) != 0) { 421 ret = r; 422 goto done; 423 } 424 if ((r = sshkey_xmss_deserialize_state(k, b)) != 0) { 425 ret = r; 426 goto done; 427 } 428 ret = 0; 429 } 430 done: 431 if (fd != -1) 432 close(fd); 433 free(data); 434 sshbuf_free(enc); 435 sshbuf_free(b); 436 return ret; 437 } 438 439 int 440 sshkey_xmss_get_state(const struct sshkey *k, sshkey_printfn *pr) 441 { 442 struct ssh_xmss_state *state = k->xmss_state; 443 u_int32_t idx = 0; 444 char *filename = NULL; 445 char *statefile = NULL, *ostatefile = NULL, *lockfile = NULL; 446 int lockfd = -1, have_state = 0, have_ostate, tries = 0; 447 int ret = SSH_ERR_INVALID_ARGUMENT, r; 448 449 if (state == NULL) 450 goto done; 451 /* 452 * If maxidx is set, then we are allowed a limited number 453 * of signatures, but don't need to access the disk. 454 * Otherwise we need to deal with the on-disk state. 455 */ 456 if (state->maxidx) { 457 /* xmss_sk always contains the current state */ 458 idx = PEEK_U32(k->xmss_sk); 459 if (idx < state->maxidx) { 460 state->allow_update = 1; 461 return 0; 462 } 463 return SSH_ERR_INVALID_ARGUMENT; 464 } 465 if ((filename = k->xmss_filename) == NULL) 466 goto done; 467 if (asprintf(&lockfile, "%s.lock", filename) == -1 || 468 asprintf(&statefile, "%s.state", filename) == -1 || 469 asprintf(&ostatefile, "%s.ostate", filename) == -1) { 470 ret = SSH_ERR_ALLOC_FAIL; 471 goto done; 472 } 473 if ((lockfd = open(lockfile, O_CREAT|O_RDONLY, 0600)) == -1) { 474 ret = SSH_ERR_SYSTEM_ERROR; 475 PRINT("%s: cannot open/create: %s", __func__, lockfile); 476 goto done; 477 } 478 while (flock(lockfd, LOCK_EX|LOCK_NB) == -1) { 479 if (errno != EWOULDBLOCK) { 480 ret = SSH_ERR_SYSTEM_ERROR; 481 PRINT("%s: cannot lock: %s", __func__, lockfile); 482 goto done; 483 } 484 if (++tries > 10) { 485 ret = SSH_ERR_SYSTEM_ERROR; 486 PRINT("%s: giving up on: %s", __func__, lockfile); 487 goto done; 488 } 489 usleep(1000*100*tries); 490 } 491 /* XXX no longer const */ 492 if ((r = sshkey_xmss_get_state_from_file(__UNCONST(k), 493 statefile, &have_state, pr)) != 0) { 494 if ((r = sshkey_xmss_get_state_from_file(__UNCONST(k), 495 ostatefile, &have_ostate, pr)) == 0) { 496 state->allow_update = 1; 497 r = sshkey_xmss_forward_state(k, 1); 498 state->idx = PEEK_U32(k->xmss_sk); 499 state->allow_update = 0; 500 } 501 } 502 if (!have_state && !have_ostate) { 503 /* check that bds state is initialized */ 504 if (state->bds.auth == NULL) 505 goto done; 506 PRINT("%s: start from scratch idx 0: %u", __func__, state->idx); 507 } else if (r != 0) { 508 ret = r; 509 goto done; 510 } 511 if (state->idx + 1 < state->idx) { 512 PRINT("%s: state wrap: %u", __func__, state->idx); 513 goto done; 514 } 515 state->have_state = have_state; 516 state->lockfd = lockfd; 517 state->allow_update = 1; 518 lockfd = -1; 519 ret = 0; 520 done: 521 if (lockfd != -1) 522 close(lockfd); 523 free(lockfile); 524 free(statefile); 525 free(ostatefile); 526 return ret; 527 } 528 529 int 530 sshkey_xmss_forward_state(const struct sshkey *k, u_int32_t reserve) 531 { 532 struct ssh_xmss_state *state = k->xmss_state; 533 u_char *sig = NULL; 534 size_t required_siglen; 535 unsigned long long smlen; 536 u_char data; 537 int ret, r; 538 539 if (state == NULL || !state->allow_update) 540 return SSH_ERR_INVALID_ARGUMENT; 541 if (reserve == 0) 542 return SSH_ERR_INVALID_ARGUMENT; 543 if (state->idx + reserve <= state->idx) 544 return SSH_ERR_INVALID_ARGUMENT; 545 if ((r = sshkey_xmss_siglen(k, &required_siglen)) != 0) 546 return r; 547 if ((sig = malloc(required_siglen)) == NULL) 548 return SSH_ERR_ALLOC_FAIL; 549 while (reserve-- > 0) { 550 state->idx = PEEK_U32(k->xmss_sk); 551 smlen = required_siglen; 552 if ((ret = xmss_sign(k->xmss_sk, sshkey_xmss_bds_state(k), 553 sig, &smlen, &data, 0, sshkey_xmss_params(k))) != 0) { 554 r = SSH_ERR_INVALID_ARGUMENT; 555 break; 556 } 557 } 558 free(sig); 559 return r; 560 } 561 562 int 563 sshkey_xmss_update_state(const struct sshkey *k, sshkey_printfn *pr) 564 { 565 struct ssh_xmss_state *state = k->xmss_state; 566 struct sshbuf *b = NULL, *enc = NULL; 567 u_int32_t idx = 0; 568 unsigned char buf[4]; 569 char *filename = NULL; 570 char *statefile = NULL, *ostatefile = NULL, *nstatefile = NULL; 571 int fd = -1; 572 int ret = SSH_ERR_INVALID_ARGUMENT; 573 574 if (state == NULL || !state->allow_update) 575 return ret; 576 if (state->maxidx) { 577 /* no update since the number of signatures is limited */ 578 ret = 0; 579 goto done; 580 } 581 idx = PEEK_U32(k->xmss_sk); 582 if (idx == state->idx) { 583 /* no signature happened, no need to update */ 584 ret = 0; 585 goto done; 586 } else if (idx != state->idx + 1) { 587 PRINT("%s: more than one signature happened: idx %u state %u", 588 __func__, idx, state->idx); 589 goto done; 590 } 591 state->idx = idx; 592 if ((filename = k->xmss_filename) == NULL) 593 goto done; 594 if (asprintf(&statefile, "%s.state", filename) == -1 || 595 asprintf(&ostatefile, "%s.ostate", filename) == -1 || 596 asprintf(&nstatefile, "%s.nstate", filename) == -1) { 597 ret = SSH_ERR_ALLOC_FAIL; 598 goto done; 599 } 600 unlink(nstatefile); 601 if ((b = sshbuf_new()) == NULL) { 602 ret = SSH_ERR_ALLOC_FAIL; 603 goto done; 604 } 605 if ((ret = sshkey_xmss_serialize_state(k, b)) != 0) { 606 PRINT("%s: SERLIALIZE FAILED: %d", __func__, ret); 607 goto done; 608 } 609 if ((ret = sshkey_xmss_encrypt_state(k, b, &enc)) != 0) { 610 PRINT("%s: ENCRYPT FAILED: %d", __func__, ret); 611 goto done; 612 } 613 if ((fd = open(nstatefile, O_CREAT|O_WRONLY|O_EXCL, 0600)) == -1) { 614 ret = SSH_ERR_SYSTEM_ERROR; 615 PRINT("%s: open new state file: %s", __func__, nstatefile); 616 goto done; 617 } 618 POKE_U32(buf, sshbuf_len(enc)); 619 if (atomicio(vwrite, fd, buf, sizeof(buf)) != sizeof(buf)) { 620 ret = SSH_ERR_SYSTEM_ERROR; 621 PRINT("%s: write new state file hdr: %s", __func__, nstatefile); 622 close(fd); 623 goto done; 624 } 625 if (atomicio(vwrite, fd, sshbuf_mutable_ptr(enc), sshbuf_len(enc)) != 626 sshbuf_len(enc)) { 627 ret = SSH_ERR_SYSTEM_ERROR; 628 PRINT("%s: write new state file data: %s", __func__, nstatefile); 629 close(fd); 630 goto done; 631 } 632 if (fsync(fd) == -1) { 633 ret = SSH_ERR_SYSTEM_ERROR; 634 PRINT("%s: sync new state file: %s", __func__, nstatefile); 635 close(fd); 636 goto done; 637 } 638 if (close(fd) == -1) { 639 ret = SSH_ERR_SYSTEM_ERROR; 640 PRINT("%s: close new state file: %s", __func__, nstatefile); 641 goto done; 642 } 643 if (state->have_state) { 644 unlink(ostatefile); 645 if (link(statefile, ostatefile)) { 646 ret = SSH_ERR_SYSTEM_ERROR; 647 PRINT("%s: backup state %s to %s", __func__, statefile, 648 ostatefile); 649 goto done; 650 } 651 } 652 if (rename(nstatefile, statefile) == -1) { 653 ret = SSH_ERR_SYSTEM_ERROR; 654 PRINT("%s: rename %s to %s", __func__, nstatefile, statefile); 655 goto done; 656 } 657 ret = 0; 658 done: 659 if (state->lockfd != -1) { 660 close(state->lockfd); 661 state->lockfd = -1; 662 } 663 if (nstatefile) 664 unlink(nstatefile); 665 free(statefile); 666 free(ostatefile); 667 free(nstatefile); 668 sshbuf_free(b); 669 sshbuf_free(enc); 670 return ret; 671 } 672 673 int 674 sshkey_xmss_serialize_state(const struct sshkey *k, struct sshbuf *b) 675 { 676 struct ssh_xmss_state *state = k->xmss_state; 677 treehash_inst *th; 678 u_int32_t i, node; 679 int r; 680 681 if (state == NULL) 682 return SSH_ERR_INVALID_ARGUMENT; 683 if (state->stack == NULL) 684 return SSH_ERR_INVALID_ARGUMENT; 685 state->stackoffset = state->bds.stackoffset; /* copy back */ 686 if ((r = sshbuf_put_cstring(b, SSH_XMSS_K2_MAGIC)) != 0 || 687 (r = sshbuf_put_u32(b, state->idx)) != 0 || 688 (r = sshbuf_put_string(b, state->stack, num_stack(state))) != 0 || 689 (r = sshbuf_put_u32(b, state->stackoffset)) != 0 || 690 (r = sshbuf_put_string(b, state->stacklevels, num_stacklevels(state))) != 0 || 691 (r = sshbuf_put_string(b, state->auth, num_auth(state))) != 0 || 692 (r = sshbuf_put_string(b, state->keep, num_keep(state))) != 0 || 693 (r = sshbuf_put_string(b, state->th_nodes, num_th_nodes(state))) != 0 || 694 (r = sshbuf_put_string(b, state->retain, num_retain(state))) != 0 || 695 (r = sshbuf_put_u32(b, num_treehash(state))) != 0) 696 return r; 697 for (i = 0; i < num_treehash(state); i++) { 698 th = &state->treehash[i]; 699 node = th->node - state->th_nodes; 700 if ((r = sshbuf_put_u32(b, th->h)) != 0 || 701 (r = sshbuf_put_u32(b, th->next_idx)) != 0 || 702 (r = sshbuf_put_u32(b, th->stackusage)) != 0 || 703 (r = sshbuf_put_u8(b, th->completed)) != 0 || 704 (r = sshbuf_put_u32(b, node)) != 0) 705 return r; 706 } 707 return 0; 708 } 709 710 int 711 sshkey_xmss_serialize_state_opt(const struct sshkey *k, struct sshbuf *b, 712 enum sshkey_serialize_rep opts) 713 { 714 struct ssh_xmss_state *state = k->xmss_state; 715 int r = SSH_ERR_INVALID_ARGUMENT; 716 u_char have_stack, have_filename, have_enc; 717 718 if (state == NULL) 719 return SSH_ERR_INVALID_ARGUMENT; 720 if ((r = sshbuf_put_u8(b, opts)) != 0) 721 return r; 722 switch (opts) { 723 case SSHKEY_SERIALIZE_STATE: 724 r = sshkey_xmss_serialize_state(k, b); 725 break; 726 case SSHKEY_SERIALIZE_FULL: 727 if ((r = sshkey_xmss_serialize_enc_key(k, b)) != 0) 728 return r; 729 r = sshkey_xmss_serialize_state(k, b); 730 break; 731 case SSHKEY_SERIALIZE_SHIELD: 732 /* all of stack/filename/enc are optional */ 733 have_stack = state->stack != NULL; 734 if ((r = sshbuf_put_u8(b, have_stack)) != 0) 735 return r; 736 if (have_stack) { 737 state->idx = PEEK_U32(k->xmss_sk); /* update */ 738 if ((r = sshkey_xmss_serialize_state(k, b)) != 0) 739 return r; 740 } 741 have_filename = k->xmss_filename != NULL; 742 if ((r = sshbuf_put_u8(b, have_filename)) != 0) 743 return r; 744 if (have_filename && 745 (r = sshbuf_put_cstring(b, k->xmss_filename)) != 0) 746 return r; 747 have_enc = state->enc_keyiv != NULL; 748 if ((r = sshbuf_put_u8(b, have_enc)) != 0) 749 return r; 750 if (have_enc && 751 (r = sshkey_xmss_serialize_enc_key(k, b)) != 0) 752 return r; 753 if ((r = sshbuf_put_u32(b, state->maxidx)) != 0 || 754 (r = sshbuf_put_u8(b, state->allow_update)) != 0) 755 return r; 756 break; 757 case SSHKEY_SERIALIZE_DEFAULT: 758 r = 0; 759 break; 760 default: 761 r = SSH_ERR_INVALID_ARGUMENT; 762 break; 763 } 764 return r; 765 } 766 767 int 768 sshkey_xmss_deserialize_state(struct sshkey *k, struct sshbuf *b) 769 { 770 struct ssh_xmss_state *state = k->xmss_state; 771 treehash_inst *th; 772 u_int32_t i, lh, node; 773 size_t ls, lsl, la, lk, ln, lr; 774 char *magic; 775 int r = SSH_ERR_INTERNAL_ERROR; 776 777 if (state == NULL) 778 return SSH_ERR_INVALID_ARGUMENT; 779 if (k->xmss_sk == NULL) 780 return SSH_ERR_INVALID_ARGUMENT; 781 if ((state->treehash = calloc(num_treehash(state), 782 sizeof(treehash_inst))) == NULL) 783 return SSH_ERR_ALLOC_FAIL; 784 if ((r = sshbuf_get_cstring(b, &magic, NULL)) != 0 || 785 (r = sshbuf_get_u32(b, &state->idx)) != 0 || 786 (r = sshbuf_get_string(b, &state->stack, &ls)) != 0 || 787 (r = sshbuf_get_u32(b, &state->stackoffset)) != 0 || 788 (r = sshbuf_get_string(b, &state->stacklevels, &lsl)) != 0 || 789 (r = sshbuf_get_string(b, &state->auth, &la)) != 0 || 790 (r = sshbuf_get_string(b, &state->keep, &lk)) != 0 || 791 (r = sshbuf_get_string(b, &state->th_nodes, &ln)) != 0 || 792 (r = sshbuf_get_string(b, &state->retain, &lr)) != 0 || 793 (r = sshbuf_get_u32(b, &lh)) != 0) 794 goto out; 795 if (strcmp(magic, SSH_XMSS_K2_MAGIC) != 0) { 796 r = SSH_ERR_INVALID_ARGUMENT; 797 goto out; 798 } 799 /* XXX check stackoffset */ 800 if (ls != num_stack(state) || 801 lsl != num_stacklevels(state) || 802 la != num_auth(state) || 803 lk != num_keep(state) || 804 ln != num_th_nodes(state) || 805 lr != num_retain(state) || 806 lh != num_treehash(state)) { 807 r = SSH_ERR_INVALID_ARGUMENT; 808 goto out; 809 } 810 for (i = 0; i < num_treehash(state); i++) { 811 th = &state->treehash[i]; 812 if ((r = sshbuf_get_u32(b, &th->h)) != 0 || 813 (r = sshbuf_get_u32(b, &th->next_idx)) != 0 || 814 (r = sshbuf_get_u32(b, &th->stackusage)) != 0 || 815 (r = sshbuf_get_u8(b, &th->completed)) != 0 || 816 (r = sshbuf_get_u32(b, &node)) != 0) 817 goto out; 818 if (node < num_th_nodes(state)) 819 th->node = &state->th_nodes[node]; 820 } 821 POKE_U32(k->xmss_sk, state->idx); 822 xmss_set_bds_state(&state->bds, state->stack, state->stackoffset, 823 state->stacklevels, state->auth, state->keep, state->treehash, 824 state->retain, 0); 825 /* success */ 826 r = 0; 827 out: 828 free(magic); 829 return r; 830 } 831 832 int 833 sshkey_xmss_deserialize_state_opt(struct sshkey *k, struct sshbuf *b) 834 { 835 struct ssh_xmss_state *state = k->xmss_state; 836 enum sshkey_serialize_rep opts; 837 u_char have_state, have_stack, have_filename, have_enc; 838 int r; 839 840 if ((r = sshbuf_get_u8(b, &have_state)) != 0) 841 return r; 842 843 opts = have_state; 844 switch (opts) { 845 case SSHKEY_SERIALIZE_DEFAULT: 846 r = 0; 847 break; 848 case SSHKEY_SERIALIZE_SHIELD: 849 if ((r = sshbuf_get_u8(b, &have_stack)) != 0) 850 return r; 851 if (have_stack && 852 (r = sshkey_xmss_deserialize_state(k, b)) != 0) 853 return r; 854 if ((r = sshbuf_get_u8(b, &have_filename)) != 0) 855 return r; 856 if (have_filename && 857 (r = sshbuf_get_cstring(b, &k->xmss_filename, NULL)) != 0) 858 return r; 859 if ((r = sshbuf_get_u8(b, &have_enc)) != 0) 860 return r; 861 if (have_enc && 862 (r = sshkey_xmss_deserialize_enc_key(k, b)) != 0) 863 return r; 864 if ((r = sshbuf_get_u32(b, &state->maxidx)) != 0 || 865 (r = sshbuf_get_u8(b, &state->allow_update)) != 0) 866 return r; 867 break; 868 case SSHKEY_SERIALIZE_STATE: 869 if ((r = sshkey_xmss_deserialize_state(k, b)) != 0) 870 return r; 871 break; 872 case SSHKEY_SERIALIZE_FULL: 873 if ((r = sshkey_xmss_deserialize_enc_key(k, b)) != 0 || 874 (r = sshkey_xmss_deserialize_state(k, b)) != 0) 875 return r; 876 break; 877 default: 878 r = SSH_ERR_INVALID_FORMAT; 879 break; 880 } 881 return r; 882 } 883 884 int 885 sshkey_xmss_encrypt_state(const struct sshkey *k, struct sshbuf *b, 886 struct sshbuf **retp) 887 { 888 struct ssh_xmss_state *state = k->xmss_state; 889 struct sshbuf *encrypted = NULL, *encoded = NULL, *padded = NULL; 890 struct sshcipher_ctx *ciphercontext = NULL; 891 const struct sshcipher *cipher; 892 u_char *cp, *key, *iv = NULL; 893 size_t i, keylen, ivlen, blocksize, authlen, encrypted_len, aadlen; 894 int r = SSH_ERR_INTERNAL_ERROR; 895 896 if (retp != NULL) 897 *retp = NULL; 898 if (state == NULL || 899 state->enc_keyiv == NULL || 900 state->enc_ciphername == NULL) 901 return SSH_ERR_INTERNAL_ERROR; 902 if ((cipher = cipher_by_name(state->enc_ciphername)) == NULL) { 903 r = SSH_ERR_INTERNAL_ERROR; 904 goto out; 905 } 906 blocksize = cipher_blocksize(cipher); 907 keylen = cipher_keylen(cipher); 908 ivlen = cipher_ivlen(cipher); 909 authlen = cipher_authlen(cipher); 910 if (state->enc_keyiv_len != keylen + ivlen) { 911 r = SSH_ERR_INVALID_FORMAT; 912 goto out; 913 } 914 key = state->enc_keyiv; 915 if ((encrypted = sshbuf_new()) == NULL || 916 (encoded = sshbuf_new()) == NULL || 917 (padded = sshbuf_new()) == NULL || 918 (iv = malloc(ivlen)) == NULL) { 919 r = SSH_ERR_ALLOC_FAIL; 920 goto out; 921 } 922 923 /* replace first 4 bytes of IV with index to ensure uniqueness */ 924 memcpy(iv, key + keylen, ivlen); 925 POKE_U32(iv, state->idx); 926 927 if ((r = sshbuf_put(encoded, XMSS_MAGIC, sizeof(XMSS_MAGIC))) != 0 || 928 (r = sshbuf_put_u32(encoded, state->idx)) != 0) 929 goto out; 930 931 /* padded state will be encrypted */ 932 if ((r = sshbuf_putb(padded, b)) != 0) 933 goto out; 934 i = 0; 935 while (sshbuf_len(padded) % blocksize) { 936 if ((r = sshbuf_put_u8(padded, ++i & 0xff)) != 0) 937 goto out; 938 } 939 encrypted_len = sshbuf_len(padded); 940 941 /* header including the length of state is used as AAD */ 942 if ((r = sshbuf_put_u32(encoded, encrypted_len)) != 0) 943 goto out; 944 aadlen = sshbuf_len(encoded); 945 946 /* concat header and state */ 947 if ((r = sshbuf_putb(encoded, padded)) != 0) 948 goto out; 949 950 /* reserve space for encryption of encoded data plus auth tag */ 951 /* encrypt at offset addlen */ 952 if ((r = sshbuf_reserve(encrypted, 953 encrypted_len + aadlen + authlen, &cp)) != 0 || 954 (r = cipher_init(&ciphercontext, cipher, key, keylen, 955 iv, ivlen, 1)) != 0 || 956 (r = cipher_crypt(ciphercontext, 0, cp, sshbuf_ptr(encoded), 957 encrypted_len, aadlen, authlen)) != 0) 958 goto out; 959 960 /* success */ 961 r = 0; 962 out: 963 if (retp != NULL) { 964 *retp = encrypted; 965 encrypted = NULL; 966 } 967 sshbuf_free(padded); 968 sshbuf_free(encoded); 969 sshbuf_free(encrypted); 970 cipher_free(ciphercontext); 971 free(iv); 972 return r; 973 } 974 975 int 976 sshkey_xmss_decrypt_state(const struct sshkey *k, struct sshbuf *encoded, 977 struct sshbuf **retp) 978 { 979 struct ssh_xmss_state *state = k->xmss_state; 980 struct sshbuf *copy = NULL, *decrypted = NULL; 981 struct sshcipher_ctx *ciphercontext = NULL; 982 const struct sshcipher *cipher = NULL; 983 u_char *key, *iv = NULL, *dp; 984 size_t keylen, ivlen, authlen, aadlen; 985 u_int blocksize, encrypted_len, index; 986 int r = SSH_ERR_INTERNAL_ERROR; 987 988 if (retp != NULL) 989 *retp = NULL; 990 if (state == NULL || 991 state->enc_keyiv == NULL || 992 state->enc_ciphername == NULL) 993 return SSH_ERR_INTERNAL_ERROR; 994 if ((cipher = cipher_by_name(state->enc_ciphername)) == NULL) { 995 r = SSH_ERR_INVALID_FORMAT; 996 goto out; 997 } 998 blocksize = cipher_blocksize(cipher); 999 keylen = cipher_keylen(cipher); 1000 ivlen = cipher_ivlen(cipher); 1001 authlen = cipher_authlen(cipher); 1002 if (state->enc_keyiv_len != keylen + ivlen) { 1003 r = SSH_ERR_INTERNAL_ERROR; 1004 goto out; 1005 } 1006 key = state->enc_keyiv; 1007 1008 if ((copy = sshbuf_fromb(encoded)) == NULL || 1009 (decrypted = sshbuf_new()) == NULL || 1010 (iv = malloc(ivlen)) == NULL) { 1011 r = SSH_ERR_ALLOC_FAIL; 1012 goto out; 1013 } 1014 1015 /* check magic */ 1016 if (sshbuf_len(encoded) < sizeof(XMSS_MAGIC) || 1017 memcmp(sshbuf_ptr(encoded), XMSS_MAGIC, sizeof(XMSS_MAGIC))) { 1018 r = SSH_ERR_INVALID_FORMAT; 1019 goto out; 1020 } 1021 /* parse public portion */ 1022 if ((r = sshbuf_consume(encoded, sizeof(XMSS_MAGIC))) != 0 || 1023 (r = sshbuf_get_u32(encoded, &index)) != 0 || 1024 (r = sshbuf_get_u32(encoded, &encrypted_len)) != 0) 1025 goto out; 1026 1027 /* check size of encrypted key blob */ 1028 if (encrypted_len < blocksize || (encrypted_len % blocksize) != 0) { 1029 r = SSH_ERR_INVALID_FORMAT; 1030 goto out; 1031 } 1032 /* check that an appropriate amount of auth data is present */ 1033 if (sshbuf_len(encoded) < authlen || 1034 sshbuf_len(encoded) - authlen < encrypted_len) { 1035 r = SSH_ERR_INVALID_FORMAT; 1036 goto out; 1037 } 1038 1039 aadlen = sshbuf_len(copy) - sshbuf_len(encoded); 1040 1041 /* replace first 4 bytes of IV with index to ensure uniqueness */ 1042 memcpy(iv, key + keylen, ivlen); 1043 POKE_U32(iv, index); 1044 1045 /* decrypt private state of key */ 1046 if ((r = sshbuf_reserve(decrypted, aadlen + encrypted_len, &dp)) != 0 || 1047 (r = cipher_init(&ciphercontext, cipher, key, keylen, 1048 iv, ivlen, 0)) != 0 || 1049 (r = cipher_crypt(ciphercontext, 0, dp, sshbuf_ptr(copy), 1050 encrypted_len, aadlen, authlen)) != 0) 1051 goto out; 1052 1053 /* there should be no trailing data */ 1054 if ((r = sshbuf_consume(encoded, encrypted_len + authlen)) != 0) 1055 goto out; 1056 if (sshbuf_len(encoded) != 0) { 1057 r = SSH_ERR_INVALID_FORMAT; 1058 goto out; 1059 } 1060 1061 /* remove AAD */ 1062 if ((r = sshbuf_consume(decrypted, aadlen)) != 0) 1063 goto out; 1064 /* XXX encrypted includes unchecked padding */ 1065 1066 /* success */ 1067 r = 0; 1068 if (retp != NULL) { 1069 *retp = decrypted; 1070 decrypted = NULL; 1071 } 1072 out: 1073 cipher_free(ciphercontext); 1074 sshbuf_free(copy); 1075 sshbuf_free(decrypted); 1076 free(iv); 1077 return r; 1078 } 1079 1080 u_int32_t 1081 sshkey_xmss_signatures_left(const struct sshkey *k) 1082 { 1083 struct ssh_xmss_state *state = k->xmss_state; 1084 u_int32_t idx; 1085 1086 if (sshkey_type_plain(k->type) == KEY_XMSS && state && 1087 state->maxidx) { 1088 idx = k->xmss_sk ? PEEK_U32(k->xmss_sk) : state->idx; 1089 if (idx < state->maxidx) 1090 return state->maxidx - idx; 1091 } 1092 return 0; 1093 } 1094 1095 int 1096 sshkey_xmss_enable_maxsign(struct sshkey *k, u_int32_t maxsign) 1097 { 1098 struct ssh_xmss_state *state = k->xmss_state; 1099 1100 if (sshkey_type_plain(k->type) != KEY_XMSS) 1101 return SSH_ERR_INVALID_ARGUMENT; 1102 if (maxsign == 0) 1103 return 0; 1104 if (state->idx + maxsign < state->idx) 1105 return SSH_ERR_INVALID_ARGUMENT; 1106 state->maxidx = state->idx + maxsign; 1107 return 0; 1108 } 1109