geom_eli.c revision 153190
12061Sjkh/*- 250479Speter * Copyright (c) 2004 Pawel Jakub Dawidek <pjd@FreeBSD.org> 32061Sjkh * All rights reserved. 438666Sjb * 532427Sjb * Redistribution and use in source and binary forms, with or without 6111131Sru * modification, are permitted provided that the following conditions 7111131Sru * are met: 838666Sjb * 1. Redistributions of source code must retain the above copyright 938666Sjb * notice, this list of conditions and the following disclaimer. 1038666Sjb * 2. Redistributions in binary form must reproduce the above copyright 11159363Strhodes * notice, this list of conditions and the following disclaimer in the 1264049Salex * documentation and/or other materials provided with the distribution. 1364049Salex * 14116679Ssimokawa * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 1566071Smarkm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16116679Ssimokawa * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1773504Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 18158962Snetchild * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1938666Sjb * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20148330Snetchild * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21148330Snetchild * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22148330Snetchild * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2332427Sjb * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2438666Sjb * SUCH DAMAGE. 25108451Sschweikh */ 2638666Sjb 2738666Sjb#include <sys/cdefs.h> 2838666Sjb__FBSDID("$FreeBSD: head/sbin/geom/class/eli/geom_eli.c 153190 2005-12-07 01:38:27Z pjd $"); 2938666Sjb 3017308Speter#include <stdio.h> 3191606Skeramida#include <stdint.h> 3219175Sbde#include <stdlib.h> 3396205Sjwd#include <unistd.h> 3496205Sjwd#include <fcntl.h> 3538042Sbde#include <readpassphrase.h> 3696205Sjwd#include <string.h> 3796205Sjwd#include <strings.h> 3838042Sbde#include <libgeom.h> 3996205Sjwd#include <paths.h> 40159363Strhodes#include <errno.h> 41159363Strhodes#include <assert.h> 4217308Speter 4396205Sjwd#include <sys/param.h> 4496205Sjwd#include <sys/mman.h> 4517308Speter#include <sys/resource.h> 46148330Snetchild#include <opencrypto/cryptodev.h> 47148330Snetchild#include <geom/eli/g_eli.h> 48148330Snetchild#include <geom/eli/pkcs5v2.h> 49148330Snetchild 50159831Sobrien#include "core/geom.h" 51148330Snetchild#include "misc/subr.h" 52148330Snetchild 53148330Snetchild 54148330Snetchilduint32_t lib_version = G_LIB_VERSION; 55148330Snetchilduint32_t version = G_ELI_VERSION; 56148330Snetchild 57148330Snetchildstatic char algo[] = "aes"; 5896205Sjwdstatic intmax_t keylen = 0; 5996205Sjwdstatic intmax_t keyno = -1; 6096205Sjwdstatic intmax_t iterations = -1; 61162147Srustatic intmax_t sectorsize = 0; 62162147Srustatic char keyfile[] = "", newkeyfile[] = ""; 6398723Sdillon 6498723Sdillonstatic void eli_main(struct gctl_req *req, unsigned flags); 6598723Sdillonstatic void eli_init(struct gctl_req *req); 6638666Sjbstatic void eli_attach(struct gctl_req *req); 6738666Sjbstatic void eli_setkey(struct gctl_req *req); 6817308Speterstatic void eli_delkey(struct gctl_req *req); 69123311Speterstatic void eli_kill(struct gctl_req *req); 70123311Speterstatic void eli_backup(struct gctl_req *req); 71123311Speterstatic void eli_restore(struct gctl_req *req); 72123311Speterstatic void eli_clear(struct gctl_req *req); 73159349Simpstatic void eli_dump(struct gctl_req *req); 74159349Simp 75159349Simp/* 76158962Snetchild * Available commands: 77158962Snetchild * 78158962Snetchild * init [-bhPv] [-a algo] [-i iterations] [-l keylen] [-K newkeyfile] prov 79156840Sru * label - alias for 'init' 80123311Speter * attach [-dpv] [-k keyfile] prov 81137288Speter * detach [-fl] prov ... 82147425Sru * stop - alias for 'detach' 83156740Sru * onetime [-d] [-a algo] [-l keylen] prov ... 842061Sjkh * setkey [-pPv] [-n keyno] [-k keyfile] [-K newkeyfile] prov 8597769Sru * delkey [-afv] [-n keyno] prov 8697252Sru * kill [-av] [prov ...] 87119579Sru * backup [-v] prov file 8897252Sru * restore [-v] file prov 8995730Sru * clear [-v] prov ... 9095793Sru * dump [-v] prov ... 91111617Sru */ 9295730Srustruct g_command class_commands[] = { 93116679Ssimokawa { "init", G_FLAG_VERBOSE, eli_main, 9495730Sru { 95116679Ssimokawa { 'a', "algo", algo, G_TYPE_STRING }, 9695730Sru { 'b', "boot", NULL, G_TYPE_NONE }, 97110035Sru { 'i', "iterations", &iterations, G_TYPE_NUMBER }, 98107516Sru { 'K', "newkeyfile", newkeyfile, G_TYPE_STRING }, 99138921Sru { 'l', "keylen", &keylen, G_TYPE_NUMBER }, 100156145Syar { 'P', "nonewpassphrase", NULL, G_TYPE_NONE }, 101138921Sru { 's', "sectorsize", §orsize, G_TYPE_NUMBER }, 102133942Sru G_OPT_SENTINEL 103133942Sru }, 104156145Syar "[-bPv] [-a algo] [-i iterations] [-l keylen] [-K newkeyfile] [-s sectorsize] prov" 105133942Sru }, 106110035Sru { "label", G_FLAG_VERBOSE, eli_main, 107117234Sru { 108110035Sru { 'a', "algo", algo, G_TYPE_STRING }, 109117229Sru { 'b', "boot", NULL, G_TYPE_NONE }, 110117234Sru { 'i', "iterations", &iterations, G_TYPE_NUMBER }, 11154324Smarcel { 'K', "newkeyfile", newkeyfile, G_TYPE_STRING }, 11217308Speter { 'l', "keylen", &keylen, G_TYPE_NUMBER }, 113119519Smarcel { 'P', "nonewpassphrase", NULL, G_TYPE_NONE }, 114119519Smarcel { 's', "sectorsize", §orsize, G_TYPE_NUMBER }, 115119519Smarcel G_OPT_SENTINEL 116119519Smarcel }, 117119519Smarcel "- an alias for 'init'" 118119519Smarcel }, 119119579Sru { "attach", G_FLAG_VERBOSE | G_FLAG_LOADKLD, eli_main, 120119519Smarcel { 121119519Smarcel { 'd', "detach", NULL, G_TYPE_NONE }, 122119519Smarcel { 'k', "keyfile", keyfile, G_TYPE_STRING }, 123119519Smarcel { 'p', "nopassphrase", NULL, G_TYPE_NONE }, 124119519Smarcel G_OPT_SENTINEL 125126031Sgad }, 126126024Sgad "[-dpv] [-k keyfile] prov" 127126024Sgad }, 128126024Sgad { "detach", 0, NULL, 129126024Sgad { 130126024Sgad { 'f', "force", NULL, G_TYPE_NONE }, 131126024Sgad { 'l', "last", NULL, G_TYPE_NONE }, 132126024Sgad G_OPT_SENTINEL 133126024Sgad }, 134126024Sgad "[-fl] prov ..." 135126024Sgad }, 136126024Sgad { "stop", 0, NULL, 137126024Sgad { 138126024Sgad { 'f', "force", NULL, G_TYPE_NONE }, 139126031Sgad { 'l', "last", NULL, G_TYPE_NONE }, 140126024Sgad G_OPT_SENTINEL 141126024Sgad }, 142126024Sgad "- an alias for 'detach'" 143126024Sgad }, 144126024Sgad { "onetime", G_FLAG_VERBOSE | G_FLAG_LOADKLD, NULL, 145126024Sgad { 146126024Sgad { 'a', "algo", algo, G_TYPE_STRING }, 147133376Sharti { 'd', "detach", NULL, G_TYPE_NONE }, 148126024Sgad { 'l', "keylen", &keylen, G_TYPE_NUMBER }, 149126024Sgad { 's', "sectorsize", §orsize, G_TYPE_NUMBER }, 150126024Sgad G_OPT_SENTINEL 151126024Sgad }, 152126024Sgad "[-d] [-a algo] [-l keylen] [-s sectorsize] prov ..." 153125885Sgad }, 154125885Sgad { "setkey", G_FLAG_VERBOSE, eli_main, 15538666Sjb { 15617308Speter { 'i', "iterations", &iterations, G_TYPE_NUMBER }, 157119519Smarcel { 'k', "keyfile", keyfile, G_TYPE_STRING }, 158119579Sru { 'K', "newkeyfile", newkeyfile, G_TYPE_STRING }, 159133376Sharti { 'n', "keyno", &keyno, G_TYPE_NUMBER }, 160110035Sru { 'p', "nopassphrase", NULL, G_TYPE_NONE }, 1612302Spaul { 'P', "nonewpassphrase", NULL, G_TYPE_NONE }, 16239206Sjkh G_OPT_SENTINEL 16339206Sjkh }, 16439206Sjkh "[-pPv] [-n keyno] [-i iterations] [-k keyfile] [-K newkeyfile] prov" 165133945Sru }, 166133945Sru { "delkey", G_FLAG_VERBOSE, eli_main, 167132358Smarkm { 16817308Speter { 'a', "all", NULL, G_TYPE_NONE }, 16954324Smarcel { 'f', "force", NULL, G_TYPE_NONE }, 17054324Smarcel { 'n', "keyno", &keyno, G_TYPE_NUMBER }, 171132234Smarcel G_OPT_SENTINEL 172132234Smarcel }, 173132234Smarcel "[-afv] [-n keyno] prov" 174132234Smarcel }, 17554324Smarcel { "kill", G_FLAG_VERBOSE, eli_main, 17654324Smarcel { 17754324Smarcel { 'a', "all", NULL, G_TYPE_NONE }, 178118531Sru G_OPT_SENTINEL 17954324Smarcel }, 18054324Smarcel "[-av] [prov ...]" 18154324Smarcel }, 18254324Smarcel { "backup", G_FLAG_VERBOSE, eli_main, G_NULL_OPTS, 18354324Smarcel "[-v] prov file" 18454324Smarcel }, 185133376Sharti { "restore", G_FLAG_VERBOSE, eli_main, G_NULL_OPTS, 18654324Smarcel "[-v] file prov" 187133376Sharti }, 188133376Sharti { "clear", G_FLAG_VERBOSE, eli_main, G_NULL_OPTS, 18954324Smarcel "[-v] prov ..." 19054324Smarcel }, 19154324Smarcel { "dump", G_FLAG_VERBOSE, eli_main, G_NULL_OPTS, 19254324Smarcel "[-v] prov ..." 19354324Smarcel }, 194133376Sharti G_CMD_SENTINEL 19554324Smarcel}; 19654324Smarcel 19754324Smarcelstatic int verbose = 0; 198118531Sru 199118531Srustatic int 20054324Smarceleli_protect(struct gctl_req *req) 201132234Smarcel{ 202132234Smarcel struct rlimit rl; 203132234Smarcel 204132234Smarcel /* Disable core dumps. */ 205132234Smarcel rl.rlim_cur = 0; 206132588Skensmith rl.rlim_max = 0; 207132358Smarkm if (setrlimit(RLIMIT_CORE, &rl) == -1) { 208132234Smarcel gctl_error(req, "Cannot disable core dumps: %s.", 209132358Smarkm strerror(errno)); 210132234Smarcel return (-1); 211132234Smarcel } 212132234Smarcel /* Disable swapping. */ 21354324Smarcel if (mlockall(MCL_FUTURE) == -1) { 21454324Smarcel gctl_error(req, "Cannot lock memory: %s.", strerror(errno)); 21595730Sru return (-1); 21695730Sru } 21795730Sru return (0); 21895730Sru} 21995730Sru 22095730Srustatic void 22195730Srueli_main(struct gctl_req *req, unsigned flags) 22238666Sjb{ 223107374Sru const char *name; 22417308Speter 22555678Smarcel if (eli_protect(req) == -1) 226143032Sharti return; 227138515Sharti 228117793Sru if ((flags & G_FLAG_VERBOSE) != 0) 229110035Sru verbose = 1; 230110035Sru 231110035Sru name = gctl_get_ascii(req, "verb"); 2322061Sjkh if (name == NULL) { 23317308Speter gctl_error(req, "No '%s' argument.", "verb"); 234107516Sru return; 235107374Sru } 23655678Smarcel if (strcmp(name, "init") == 0 || strcmp(name, "label") == 0) 237107516Sru eli_init(req); 238107516Sru else if (strcmp(name, "attach") == 0) 239107516Sru eli_attach(req); 240107516Sru else if (strcmp(name, "setkey") == 0) 241107516Sru eli_setkey(req); 242139112Sru else if (strcmp(name, "delkey") == 0) 243164470Sjb eli_delkey(req); 244107516Sru else if (strcmp(name, "kill") == 0) 245122204Skris eli_kill(req); 24655678Smarcel else if (strcmp(name, "backup") == 0) 24755678Smarcel eli_backup(req); 248116696Sru else if (strcmp(name, "restore") == 0) 24955678Smarcel eli_restore(req); 250133376Sharti else if (strcmp(name, "dump") == 0) 251107516Sru eli_dump(req); 252107516Sru else if (strcmp(name, "clear") == 0) 253107516Sru eli_clear(req); 254107516Sru else 25555678Smarcel gctl_error(req, "Unknown command: %s.", name); 25655678Smarcel} 257111131Sru 258111131Srustatic void 259111131Sruarc4rand(unsigned char *buf, size_t size) 260133945Sru{ 261111131Sru uint32_t *buf4; 262111131Sru size_t size4; 263148154Sru unsigned i; 264168280Smarcel 265168280Smarcel buf4 = (uint32_t *)buf; 266133945Sru size4 = size / 4; 267133945Sru 268103985Sphk for (i = 0; i < size4; i++) 269103985Sphk buf4[i] = arc4random(); 270103985Sphk for (i *= 4; i < size; i++) 271168280Smarcel buf[i] = arc4random() % 0xff; 272162147Sru} 273152879Sru 274152880Srustatic int 275148154Srueli_is_attached(const char *prov) 276162147Sru{ 277162147Sru char name[MAXPATHLEN]; 278162147Sru unsigned secsize; 279162147Sru 280131876Sphk /* 281162147Sru * Not the best way to do it, but the easiest. 282111131Sru * We try to open provider and check if it is a GEOM provider 283162147Sru * by asking about its sectorsize. 284162147Sru */ 285162147Sru snprintf(name, sizeof(name), "%s%s", prov, G_ELI_SUFFIX); 286162147Sru secsize = g_get_sectorsize(name); 287162147Sru if (secsize > 0) 288103985Sphk return (1); 289148154Sru return (0); 290148154Sru} 291162147Sru 292148154Srustatic unsigned char * 293148154Srueli_genkey(struct gctl_req *req, struct g_eli_metadata *md, unsigned char *key, 294162147Sru int new) 295148154Sru{ 296162147Sru struct hmac_ctx ctx; 297103985Sphk const char *str; 298133945Sru int error, nopassphrase; 299133945Sru 300103985Sphk nopassphrase = 301118531Sru gctl_get_int(req, new ? "nonewpassphrase" : "nopassphrase"); 302118531Sru 303103985Sphk g_eli_crypto_hmac_init(&ctx, NULL, 0); 304133945Sru 305 str = gctl_get_ascii(req, new ? "newkeyfile" : "keyfile"); 306 if (str[0] != '\0') { 307 char buf[MAXPHYS]; 308 ssize_t done; 309 int fd; 310 311 if (strcmp(str, "-") == 0) 312 fd = STDIN_FILENO; 313 else { 314 fd = open(str, O_RDONLY); 315 if (fd == -1) { 316 gctl_error(req, "Cannot open keyfile %s: %s.", 317 str, strerror(errno)); 318 return (NULL); 319 } 320 } 321 while ((done = read(fd, buf, sizeof(buf))) > 0) 322 g_eli_crypto_hmac_update(&ctx, buf, done); 323 error = errno; 324 if (strcmp(str, "-") != 0) 325 close(fd); 326 bzero(buf, sizeof(buf)); 327 if (done == -1) { 328 gctl_error(req, "Cannot read keyfile %s: %s.", str, 329 strerror(error)); 330 return (NULL); 331 } 332 } 333 334 if (!nopassphrase) { 335 char buf1[BUFSIZ], buf2[BUFSIZ], *p; 336 337 if (!new && md->md_iterations == -1) { 338 gctl_error(req, "Missing -p flag."); 339 return (NULL); 340 } 341 for (;;) { 342 p = readpassphrase( 343 new ? "Enter new passphrase:" : "Enter passphrase:", 344 buf1, sizeof(buf1), RPP_ECHO_OFF | RPP_REQUIRE_TTY); 345 if (p == NULL) { 346 bzero(buf1, sizeof(buf1)); 347 gctl_error(req, "Cannot read passphrase: %s.", 348 strerror(errno)); 349 return (NULL); 350 } 351 352 if (new) { 353 p = readpassphrase("Reenter new passphrase: ", 354 buf2, sizeof(buf2), 355 RPP_ECHO_OFF | RPP_REQUIRE_TTY); 356 if (p == NULL) { 357 bzero(buf1, sizeof(buf1)); 358 gctl_error(req, 359 "Cannot read passphrase: %s.", 360 strerror(errno)); 361 return (NULL); 362 } 363 364 if (strcmp(buf1, buf2) != 0) { 365 bzero(buf2, sizeof(buf2)); 366 fprintf(stderr, "They didn't match.\n"); 367 continue; 368 } 369 bzero(buf2, sizeof(buf2)); 370 } 371 break; 372 } 373 /* 374 * Field md_iterations equal to -1 means "choose some sane 375 * value for me". 376 */ 377 if (md->md_iterations == -1) { 378 assert(new); 379 if (verbose) 380 printf("Calculating number of iterations...\n"); 381 md->md_iterations = pkcs5v2_calculate(2000000); 382 assert(md->md_iterations > 0); 383 if (verbose) { 384 printf("Done, using %d iterations.\n", 385 md->md_iterations); 386 } 387 } 388 /* 389 * If md_iterations is equal to 0, user don't want PKCS5v2. 390 */ 391 if (md->md_iterations == 0) { 392 g_eli_crypto_hmac_update(&ctx, md->md_salt, 393 sizeof(md->md_salt)); 394 g_eli_crypto_hmac_update(&ctx, buf1, strlen(buf1)); 395 } else /* if (md->md_iterations > 0) */ { 396 unsigned char dkey[G_ELI_USERKEYLEN]; 397 398 pkcs5v2_genkey(dkey, sizeof(dkey), md->md_salt, 399 sizeof(md->md_salt), buf1, md->md_iterations); 400 g_eli_crypto_hmac_update(&ctx, dkey, sizeof(dkey)); 401 bzero(dkey, sizeof(dkey)); 402 } 403 bzero(buf1, sizeof(buf1)); 404 } 405 g_eli_crypto_hmac_final(&ctx, key, 0); 406 return (key); 407} 408 409static int 410eli_metadata_read(struct gctl_req *req, const char *prov, 411 struct g_eli_metadata *md) 412{ 413 unsigned char sector[sizeof(struct g_eli_metadata)]; 414 int error; 415 416 if (g_get_sectorsize(prov) == 0) { 417 int fd; 418 419 /* This is a file probably. */ 420 fd = open(prov, O_RDONLY); 421 if (fd == -1) { 422 gctl_error(req, "Cannot open %s: %s.", prov, 423 strerror(errno)); 424 return (-1); 425 } 426 if (read(fd, sector, sizeof(sector)) != sizeof(sector)) { 427 gctl_error(req, "Cannot read metadata from %s: %s.", 428 prov, strerror(errno)); 429 close(fd); 430 return (-1); 431 } 432 close(fd); 433 } else { 434 /* This is a GEOM provider. */ 435 error = g_metadata_read(prov, sector, sizeof(sector), 436 G_ELI_MAGIC); 437 if (error != 0) { 438 gctl_error(req, "Cannot read metadata from %s: %s.", 439 prov, strerror(error)); 440 return (-1); 441 } 442 } 443 if (eli_metadata_decode(sector, md) != 0) { 444 gctl_error(req, "MD5 hash mismatch for %s.", prov); 445 return (-1); 446 } 447 return (0); 448} 449 450static int 451eli_metadata_store(struct gctl_req *req, const char *prov, 452 struct g_eli_metadata *md) 453{ 454 unsigned char sector[sizeof(struct g_eli_metadata)]; 455 int error; 456 457 eli_metadata_encode(md, sector); 458 if (g_get_sectorsize(prov) == 0) { 459 int fd; 460 461 /* This is a file probably. */ 462 fd = open(prov, O_WRONLY | O_TRUNC); 463 if (fd == -1) { 464 gctl_error(req, "Cannot open %s: %s.", prov, 465 strerror(errno)); 466 bzero(sector, sizeof(sector)); 467 return (-1); 468 } 469 if (write(fd, sector, sizeof(sector)) != sizeof(sector)) { 470 gctl_error(req, "Cannot write metadata to %s: %s.", 471 prov, strerror(errno)); 472 bzero(sector, sizeof(sector)); 473 close(fd); 474 return (-1); 475 } 476 close(fd); 477 } else { 478 /* This is a GEOM provider. */ 479 error = g_metadata_store(prov, sector, sizeof(sector)); 480 if (error != 0) { 481 gctl_error(req, "Cannot write metadata to %s: %s.", 482 prov, strerror(errno)); 483 bzero(sector, sizeof(sector)); 484 return (-1); 485 } 486 } 487 bzero(sector, sizeof(sector)); 488 return (0); 489} 490 491static void 492eli_init(struct gctl_req *req) 493{ 494 struct g_eli_metadata md; 495 unsigned char sector[sizeof(struct g_eli_metadata)]; 496 unsigned char key[G_ELI_USERKEYLEN]; 497 const char *str, *prov; 498 unsigned secsize; 499 off_t mediasize; 500 intmax_t val; 501 int error, nargs, boot; 502 503 nargs = gctl_get_int(req, "nargs"); 504 if (nargs != 1) { 505 gctl_error(req, "Too few arguments."); 506 return; 507 } 508 prov = gctl_get_ascii(req, "arg0"); 509 mediasize = g_get_mediasize(prov); 510 secsize = g_get_sectorsize(prov); 511 if (mediasize == 0 || secsize == 0) { 512 gctl_error(req, "Cannot get informations about %s: %s.", prov, 513 strerror(errno)); 514 return; 515 } 516 517 bzero(&md, sizeof(md)); 518 strlcpy(md.md_magic, G_ELI_MAGIC, sizeof(md.md_magic)); 519 md.md_version = G_ELI_VERSION; 520 md.md_flags = 0; 521 boot = gctl_get_int(req, "boot"); 522 if (boot) { 523 int nonewpassphrase; 524 525 /* Part of key cannot be read on boot from a file. */ 526 str = gctl_get_ascii(req, "newkeyfile"); 527 if (str[0] != '\0') { 528 gctl_error(req, 529 "Options -b and -K are mutually exclusive."); 530 return; 531 } 532 /* Key has to be given as a passphrase on boot. */ 533 nonewpassphrase = gctl_get_int(req, "nonewpassphrase"); 534 if (nonewpassphrase) { 535 gctl_error(req, 536 "Options -b and -P are mutually exclusive."); 537 return; 538 } 539 md.md_flags |= G_ELI_FLAG_BOOT; 540 } 541 str = gctl_get_ascii(req, "algo"); 542 md.md_algo = g_eli_str2algo(str); 543 if (md.md_algo < CRYPTO_ALGORITHM_MIN || 544 md.md_algo > CRYPTO_ALGORITHM_MAX) { 545 gctl_error(req, "Invalid encryption algorithm."); 546 return; 547 } 548 val = gctl_get_intmax(req, "keylen"); 549 md.md_keylen = val; 550 md.md_keylen = g_eli_keylen(md.md_algo, md.md_keylen); 551 if (md.md_keylen == 0) { 552 gctl_error(req, "Invalid key length."); 553 return; 554 } 555 md.md_provsize = mediasize; 556 557 val = gctl_get_intmax(req, "iterations"); 558 md.md_iterations = val; 559 560 val = gctl_get_intmax(req, "sectorsize"); 561 if (val == 0) 562 md.md_sectorsize = secsize; 563 else { 564 if (val < 0 || (val % secsize) != 0) { 565 gctl_error(req, "Invalid sector size."); 566 return; 567 } 568 md.md_sectorsize = val; 569 } 570 571 md.md_keys = 0x01; 572 arc4rand(md.md_salt, sizeof(md.md_salt)); 573 arc4rand(md.md_mkeys, sizeof(md.md_mkeys)); 574 575 /* Generate user key. */ 576 if (eli_genkey(req, &md, key, 1) == NULL) { 577 bzero(key, sizeof(key)); 578 bzero(&md, sizeof(md)); 579 return; 580 } 581 582 /* Encrypt the first and the only Master Key. */ 583 error = g_eli_mkey_encrypt(md.md_algo, key, md.md_keylen, md.md_mkeys); 584 bzero(key, sizeof(key)); 585 if (error != 0) { 586 bzero(&md, sizeof(md)); 587 gctl_error(req, "Cannot encrypt Master Key: %s.", 588 strerror(error)); 589 return; 590 } 591 592 eli_metadata_encode(&md, sector); 593 bzero(&md, sizeof(md)); 594 error = g_metadata_store(prov, sector, sizeof(sector)); 595 bzero(sector, sizeof(sector)); 596 if (error != 0) { 597 gctl_error(req, "Cannot store metadata on %s: %s.", prov, 598 strerror(error)); 599 return; 600 } 601 if (verbose) 602 printf("Metadata value stored on %s.\n", prov); 603} 604 605static void 606eli_attach(struct gctl_req *req) 607{ 608 struct g_eli_metadata md; 609 unsigned char key[G_ELI_USERKEYLEN]; 610 const char *prov; 611 int nargs; 612 613 nargs = gctl_get_int(req, "nargs"); 614 if (nargs != 1) { 615 gctl_error(req, "Too few arguments."); 616 return; 617 } 618 prov = gctl_get_ascii(req, "arg0"); 619 620 if (eli_metadata_read(req, prov, &md) == -1) 621 return; 622 623 if (eli_genkey(req, &md, key, 0) == NULL) { 624 bzero(key, sizeof(key)); 625 return; 626 } 627 628 gctl_ro_param(req, "key", sizeof(key), key); 629 if (gctl_issue(req) == NULL) { 630 if (verbose) 631 printf("Attched to %s.\n", prov); 632 } 633 bzero(key, sizeof(key)); 634} 635 636static void 637eli_setkey_attached(struct gctl_req *req, const char *prov, 638 struct g_eli_metadata *md) 639{ 640 unsigned char key[G_ELI_USERKEYLEN]; 641 intmax_t val; 642 643 val = gctl_get_intmax(req, "iterations"); 644 /* Check if iterations number should be changed. */ 645 if (val != -1) 646 md->md_iterations = val; 647 648 /* Generate key for Master Key encryption. */ 649 if (eli_genkey(req, md, key, 1) == NULL) { 650 bzero(key, sizeof(key)); 651 return; 652 } 653 654 gctl_ro_param(req, "key", sizeof(key), key); 655 gctl_issue(req); 656 bzero(key, sizeof(key)); 657} 658 659static void 660eli_setkey_detached(struct gctl_req *req, const char *prov, 661 struct g_eli_metadata *md) 662{ 663 unsigned char key[G_ELI_USERKEYLEN], mkey[G_ELI_DATAIVKEYLEN]; 664 unsigned char *mkeydst; 665 intmax_t val; 666 unsigned nkey; 667 int error; 668 669 if (md->md_keys == 0) { 670 gctl_error(req, "No valid keys on %s.", prov); 671 return; 672 } 673 674 /* Generate key for Master Key decryption. */ 675 if (eli_genkey(req, md, key, 0) == NULL) { 676 bzero(key, sizeof(key)); 677 return; 678 } 679 680 /* Decrypt Master Key. */ 681 error = g_eli_mkey_decrypt(md, key, mkey, &nkey); 682 bzero(key, sizeof(key)); 683 if (error != 0) { 684 bzero(md, sizeof(*md)); 685 if (error == -1) 686 gctl_error(req, "Wrong key for %s.", prov); 687 else /* if (error > 0) */ { 688 gctl_error(req, "Cannot decrypt Master Key: %s.", 689 strerror(error)); 690 } 691 return; 692 } 693 if (verbose) 694 printf("Decrypted Master Key %u.\n", nkey); 695 696 val = gctl_get_intmax(req, "keyno"); 697 if (val != -1) 698 nkey = val; 699#if 0 700 else 701 ; /* Use the key number which was found during decryption. */ 702#endif 703 if (nkey >= G_ELI_MAXMKEYS) { 704 gctl_error(req, "Invalid '%s' argument.", "keyno"); 705 return; 706 } 707 708 val = gctl_get_intmax(req, "iterations"); 709 /* Check if iterations number should and can be changed. */ 710 if (val != -1) { 711 if (bitcount32(md->md_keys) != 1) { 712 gctl_error(req, "To be able to use '-i' option, only " 713 "one key can be defined."); 714 return; 715 } 716 if (md->md_keys != (1 << nkey)) { 717 gctl_error(req, "Only already defined key can be " 718 "changed when '-i' option is used."); 719 return; 720 } 721 md->md_iterations = val; 722 } 723 724 mkeydst = md->md_mkeys + nkey * G_ELI_MKEYLEN; 725 md->md_keys |= (1 << nkey); 726 727 bcopy(mkey, mkeydst, sizeof(mkey)); 728 bzero(mkey, sizeof(mkey)); 729 730 /* Generate key for Master Key encryption. */ 731 if (eli_genkey(req, md, key, 1) == NULL) { 732 bzero(key, sizeof(key)); 733 bzero(md, sizeof(*md)); 734 return; 735 } 736 737 /* Encrypt the Master-Key with the new key. */ 738 error = g_eli_mkey_encrypt(md->md_algo, key, md->md_keylen, mkeydst); 739 bzero(key, sizeof(key)); 740 if (error != 0) { 741 bzero(md, sizeof(*md)); 742 gctl_error(req, "Cannot encrypt Master Key: %s.", 743 strerror(error)); 744 return; 745 } 746 747 /* Store metadata with fresh key. */ 748 eli_metadata_store(req, prov, md); 749 bzero(md, sizeof(*md)); 750} 751 752static void 753eli_setkey(struct gctl_req *req) 754{ 755 struct g_eli_metadata md; 756 const char *prov; 757 int nargs; 758 759 nargs = gctl_get_int(req, "nargs"); 760 if (nargs != 1) { 761 gctl_error(req, "Too few arguments."); 762 return; 763 } 764 prov = gctl_get_ascii(req, "arg0"); 765 766 if (eli_metadata_read(req, prov, &md) == -1) 767 return; 768 769 if (eli_is_attached(prov)) 770 eli_setkey_attached(req, prov, &md); 771 else 772 eli_setkey_detached(req, prov, &md); 773} 774 775static void 776eli_delkey_attached(struct gctl_req *req, const char *prov __unused) 777{ 778 779 gctl_issue(req); 780} 781 782static void 783eli_delkey_detached(struct gctl_req *req, const char *prov) 784{ 785 struct g_eli_metadata md; 786 unsigned char *mkeydst; 787 intmax_t val; 788 unsigned nkey; 789 int all, force; 790 791 if (eli_metadata_read(req, prov, &md) == -1) 792 return; 793 794 all = gctl_get_int(req, "all"); 795 if (all) 796 arc4rand(md.md_mkeys, sizeof(md.md_mkeys)); 797 else { 798 force = gctl_get_int(req, "force"); 799 val = gctl_get_intmax(req, "keyno"); 800 if (val == -1) { 801 gctl_error(req, "Key number has to be specified."); 802 return; 803 } 804 nkey = val; 805 if (nkey >= G_ELI_MAXMKEYS) { 806 gctl_error(req, "Invalid '%s' argument.", "keyno"); 807 return; 808 } 809 if (!(md.md_keys & (1 << nkey)) && !force) { 810 gctl_error(req, "Master Key %u is not set.", nkey); 811 return; 812 } 813 md.md_keys &= ~(1 << nkey); 814 if (md.md_keys == 0 && !force) { 815 gctl_error(req, "This is the last Master Key. Use '-f' " 816 "option if you really want to remove it."); 817 return; 818 } 819 mkeydst = md.md_mkeys + nkey * G_ELI_MKEYLEN; 820 arc4rand(mkeydst, G_ELI_MKEYLEN); 821 } 822 823 eli_metadata_store(req, prov, &md); 824 bzero(&md, sizeof(md)); 825} 826 827static void 828eli_delkey(struct gctl_req *req) 829{ 830 const char *prov; 831 int nargs; 832 833 nargs = gctl_get_int(req, "nargs"); 834 if (nargs != 1) { 835 gctl_error(req, "Too few arguments."); 836 return; 837 } 838 prov = gctl_get_ascii(req, "arg0"); 839 840 if (eli_is_attached(prov)) 841 eli_delkey_attached(req, prov); 842 else 843 eli_delkey_detached(req, prov); 844} 845 846static void 847eli_kill_detached(struct gctl_req *req, const char *prov) 848{ 849 struct g_eli_metadata md; 850 int error; 851 852 /* 853 * NOTE: Maybe we should verify if this is geli provider first, 854 * but 'kill' command is quite critical so better don't waste 855 * the time. 856 */ 857#if 0 858 error = g_metadata_read(prov, (unsigned char *)&md, sizeof(md), 859 G_ELI_MAGIC); 860 if (error != 0) { 861 gctl_error(req, "Cannot read metadata from %s: %s.", prov, 862 strerror(error)); 863 return; 864 } 865#endif 866 867 arc4rand((unsigned char *)&md, sizeof(md)); 868 error = g_metadata_store(prov, (unsigned char *)&md, sizeof(md)); 869 if (error != 0) { 870 gctl_error(req, "Cannot write metadata to %s: %s.", prov, 871 strerror(error)); 872 } 873} 874 875static void 876eli_kill(struct gctl_req *req) 877{ 878 const char *prov; 879 int i, nargs, all; 880 881 nargs = gctl_get_int(req, "nargs"); 882 all = gctl_get_int(req, "all"); 883 if (!all && nargs == 0) { 884 gctl_error(req, "Too few arguments."); 885 return; 886 } 887 /* 888 * How '-a' option combine with a list of providers: 889 * Delete Master Keys from all attached providers: 890 * geli kill -a 891 * Delete Master Keys from all attached provider and from 892 * detached da0 and da1: 893 * geli kill -a da0 da1 894 * Delete Master Keys from (attached or detached) da0 and da1: 895 * geli kill da0 da1 896 */ 897 898 /* 899 * First attached providers. 900 */ 901 gctl_issue(req); 902 /* 903 * Now the rest. 904 */ 905 for (i = 0; i < nargs; i++) { 906 prov = gctl_get_ascii(req, "arg%d", i); 907 if (!eli_is_attached(prov)) 908 eli_kill_detached(req, prov); 909 } 910} 911 912static void 913eli_backup(struct gctl_req *req) 914{ 915 struct g_eli_metadata md; 916 const char *file, *prov; 917 unsigned secsize; 918 unsigned char *sector; 919 off_t mediasize; 920 int nargs, filefd, provfd; 921 922 nargs = gctl_get_int(req, "nargs"); 923 if (nargs != 2) { 924 gctl_error(req, "Invalid number of arguments."); 925 return; 926 } 927 prov = gctl_get_ascii(req, "arg0"); 928 file = gctl_get_ascii(req, "arg1"); 929 930 provfd = filefd = -1; 931 sector = NULL; 932 secsize = 0; 933 934 provfd = open(prov, O_RDONLY); 935 if (provfd == -1 && errno == ENOENT && prov[0] != '/') { 936 char devprov[MAXPATHLEN]; 937 938 snprintf(devprov, sizeof(devprov), "%s%s", _PATH_DEV, prov); 939 provfd = open(devprov, O_RDONLY); 940 } 941 if (provfd == -1) { 942 gctl_error(req, "Cannot open %s: %s.", prov, strerror(errno)); 943 return; 944 } 945 filefd = open(file, O_WRONLY | O_TRUNC | O_CREAT, 0600); 946 if (filefd == -1) { 947 gctl_error(req, "Cannot open %s: %s.", file, strerror(errno)); 948 goto out; 949 } 950 951 mediasize = g_get_mediasize(prov); 952 secsize = g_get_sectorsize(prov); 953 if (mediasize == 0 || secsize == 0) { 954 gctl_error(req, "Cannot get informations about %s: %s.", prov, 955 strerror(errno)); 956 return; 957 } 958 959 sector = malloc(secsize); 960 if (sector == NULL) { 961 gctl_error(req, "Cannot allocate memory."); 962 return; 963 } 964 965 /* Read metadata from the provider. */ 966 if (pread(provfd, sector, secsize, mediasize - secsize) != 967 (ssize_t)secsize) { 968 gctl_error(req, "Cannot read metadata: %s.", strerror(errno)); 969 goto out; 970 } 971 /* Check if this is geli provider. */ 972 if (eli_metadata_decode(sector, &md) != 0) { 973 gctl_error(req, "MD5 hash mismatch: not a geli provider?"); 974 goto out; 975 } 976 /* Write metadata to the destination file. */ 977 if (write(filefd, sector, secsize) != (ssize_t)secsize) { 978 gctl_error(req, "Cannot write to %s: %s.", file, 979 strerror(errno)); 980 goto out; 981 } 982out: 983 if (provfd > 0) 984 close(provfd); 985 if (filefd > 0) 986 close(filefd); 987 if (sector != NULL) { 988 bzero(sector, secsize); 989 free(sector); 990 } 991} 992 993static void 994eli_restore(struct gctl_req *req) 995{ 996 struct g_eli_metadata md; 997 const char *file, *prov; 998 unsigned char *sector; 999 unsigned secsize; 1000 off_t mediasize; 1001 int nargs, filefd, provfd; 1002 1003 nargs = gctl_get_int(req, "nargs"); 1004 if (nargs != 2) { 1005 gctl_error(req, "Invalid number of arguments."); 1006 return; 1007 } 1008 file = gctl_get_ascii(req, "arg0"); 1009 prov = gctl_get_ascii(req, "arg1"); 1010 1011 provfd = filefd = -1; 1012 sector = NULL; 1013 secsize = 0; 1014 1015 filefd = open(file, O_RDONLY); 1016 if (filefd == -1) { 1017 gctl_error(req, "Cannot open %s: %s.", file, strerror(errno)); 1018 goto out; 1019 } 1020 provfd = open(prov, O_WRONLY); 1021 if (provfd == -1 && errno == ENOENT && prov[0] != '/') { 1022 char devprov[MAXPATHLEN]; 1023 1024 snprintf(devprov, sizeof(devprov), "%s%s", _PATH_DEV, prov); 1025 provfd = open(devprov, O_WRONLY); 1026 } 1027 if (provfd == -1) { 1028 gctl_error(req, "Cannot open %s: %s.", prov, strerror(errno)); 1029 return; 1030 } 1031 1032 mediasize = g_get_mediasize(prov); 1033 secsize = g_get_sectorsize(prov); 1034 if (mediasize == 0 || secsize == 0) { 1035 gctl_error(req, "Cannot get informations about %s: %s.", prov, 1036 strerror(errno)); 1037 return; 1038 } 1039 1040 sector = malloc(secsize); 1041 if (sector == NULL) { 1042 gctl_error(req, "Cannot allocate memory."); 1043 return; 1044 } 1045 1046 /* Read metadata from the backup file. */ 1047 if (read(filefd, sector, secsize) != (ssize_t)secsize) { 1048 gctl_error(req, "Cannot read from %s: %s.", file, 1049 strerror(errno)); 1050 goto out; 1051 } 1052 /* Check if this file contains geli metadata. */ 1053 if (eli_metadata_decode(sector, &md) != 0) { 1054 gctl_error(req, "MD5 hash mismatch: not a geli backup file?"); 1055 goto out; 1056 } 1057 /* Read metadata from the provider. */ 1058 if (pwrite(provfd, sector, secsize, mediasize - secsize) != 1059 (ssize_t)secsize) { 1060 gctl_error(req, "Cannot write metadata: %s.", strerror(errno)); 1061 goto out; 1062 } 1063out: 1064 if (provfd > 0) 1065 close(provfd); 1066 if (filefd > 0) 1067 close(filefd); 1068 if (sector != NULL) { 1069 bzero(sector, secsize); 1070 free(sector); 1071 } 1072} 1073 1074static void 1075eli_clear(struct gctl_req *req) 1076{ 1077 const char *name; 1078 int error, i, nargs; 1079 1080 nargs = gctl_get_int(req, "nargs"); 1081 if (nargs < 1) { 1082 gctl_error(req, "Too few arguments."); 1083 return; 1084 } 1085 1086 for (i = 0; i < nargs; i++) { 1087 name = gctl_get_ascii(req, "arg%d", i); 1088 error = g_metadata_clear(name, G_ELI_MAGIC); 1089 if (error != 0) { 1090 fprintf(stderr, "Cannot clear metadata on %s: %s.\n", 1091 name, strerror(error)); 1092 gctl_error(req, "Not fully done."); 1093 continue; 1094 } 1095 if (verbose) 1096 printf("Metadata cleared on %s.\n", name); 1097 } 1098} 1099 1100static void 1101eli_dump(struct gctl_req *req) 1102{ 1103 struct g_eli_metadata md, tmpmd; 1104 const char *name; 1105 int error, i, nargs; 1106 1107 nargs = gctl_get_int(req, "nargs"); 1108 if (nargs < 1) { 1109 gctl_error(req, "Too few arguments."); 1110 return; 1111 } 1112 1113 for (i = 0; i < nargs; i++) { 1114 name = gctl_get_ascii(req, "arg%d", i); 1115 error = g_metadata_read(name, (unsigned char *)&tmpmd, 1116 sizeof(tmpmd), G_ELI_MAGIC); 1117 if (error != 0) { 1118 fprintf(stderr, "Cannot read metadata from %s: %s.\n", 1119 name, strerror(error)); 1120 gctl_error(req, "Not fully done."); 1121 continue; 1122 } 1123 if (eli_metadata_decode((unsigned char *)&tmpmd, &md) != 0) { 1124 fprintf(stderr, "MD5 hash mismatch for %s, skipping.\n", 1125 name); 1126 gctl_error(req, "Not fully done."); 1127 continue; 1128 } 1129 printf("Metadata on %s:\n", name); 1130 eli_metadata_dump(&md); 1131 printf("\n"); 1132 } 1133} 1134