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