1eda14cbcSMatt Macy /* 2eda14cbcSMatt Macy * CDDL HEADER START 3eda14cbcSMatt Macy * 4eda14cbcSMatt Macy * This file and its contents are supplied under the terms of the 5eda14cbcSMatt Macy * Common Development and Distribution License ("CDDL"), version 1.0. 6eda14cbcSMatt Macy * You may only use this file in accordance with the terms of version 7eda14cbcSMatt Macy * 1.0 of the CDDL. 8eda14cbcSMatt Macy * 9eda14cbcSMatt Macy * A full copy of the text of the CDDL should have accompanied this 10eda14cbcSMatt Macy * source. A copy of the CDDL is also available via the Internet at 11eda14cbcSMatt Macy * http://www.illumos.org/license/CDDL. 12eda14cbcSMatt Macy * 13eda14cbcSMatt Macy * CDDL HEADER END 14eda14cbcSMatt Macy */ 15eda14cbcSMatt Macy 16eda14cbcSMatt Macy /* 17eda14cbcSMatt Macy * Copyright (c) 2017, Datto, Inc. All rights reserved. 18eda14cbcSMatt Macy * Copyright 2020 Joyent, Inc. 19eda14cbcSMatt Macy */ 20eda14cbcSMatt Macy 21eda14cbcSMatt Macy #include <sys/zfs_context.h> 22eda14cbcSMatt Macy #include <sys/fs/zfs.h> 23eda14cbcSMatt Macy #include <sys/dsl_crypt.h> 24eda14cbcSMatt Macy #include <libintl.h> 25eda14cbcSMatt Macy #include <termios.h> 26eda14cbcSMatt Macy #include <signal.h> 27eda14cbcSMatt Macy #include <errno.h> 28eda14cbcSMatt Macy #include <openssl/evp.h> 2916038816SMartin Matuska #if LIBFETCH_DYNAMIC 3016038816SMartin Matuska #include <dlfcn.h> 3116038816SMartin Matuska #endif 3216038816SMartin Matuska #if LIBFETCH_IS_FETCH 3316038816SMartin Matuska #include <sys/param.h> 3416038816SMartin Matuska #include <stdio.h> 3516038816SMartin Matuska #include <fetch.h> 3616038816SMartin Matuska #elif LIBFETCH_IS_LIBCURL 3716038816SMartin Matuska #include <curl/curl.h> 3816038816SMartin Matuska #endif 39eda14cbcSMatt Macy #include <libzfs.h> 40eda14cbcSMatt Macy #include "libzfs_impl.h" 41eda14cbcSMatt Macy #include "zfeature_common.h" 42eda14cbcSMatt Macy 43eda14cbcSMatt Macy /* 44eda14cbcSMatt Macy * User keys are used to decrypt the master encryption keys of a dataset. This 45eda14cbcSMatt Macy * indirection allows a user to change his / her access key without having to 46eda14cbcSMatt Macy * re-encrypt the entire dataset. User keys can be provided in one of several 47eda14cbcSMatt Macy * ways. Raw keys are simply given to the kernel as is. Similarly, hex keys 48eda14cbcSMatt Macy * are converted to binary and passed into the kernel. Password based keys are 49eda14cbcSMatt Macy * a bit more complicated. Passwords alone do not provide suitable entropy for 50eda14cbcSMatt Macy * encryption and may be too short or too long to be used. In order to derive 51eda14cbcSMatt Macy * a more appropriate key we use a PBKDF2 function. This function is designed 52eda14cbcSMatt Macy * to take a (relatively) long time to calculate in order to discourage 53eda14cbcSMatt Macy * attackers from guessing from a list of common passwords. PBKDF2 requires 54eda14cbcSMatt Macy * 2 additional parameters. The first is the number of iterations to run, which 55eda14cbcSMatt Macy * will ultimately determine how long it takes to derive the resulting key from 56eda14cbcSMatt Macy * the password. The second parameter is a salt that is randomly generated for 57eda14cbcSMatt Macy * each dataset. The salt is used to "tweak" PBKDF2 such that a group of 58eda14cbcSMatt Macy * attackers cannot reasonably generate a table of commonly known passwords to 59eda14cbcSMatt Macy * their output keys and expect it work for all past and future PBKDF2 users. 60eda14cbcSMatt Macy * We store the salt as a hidden property of the dataset (although it is 61eda14cbcSMatt Macy * technically ok if the salt is known to the attacker). 62eda14cbcSMatt Macy */ 63eda14cbcSMatt Macy 64eda14cbcSMatt Macy #define MIN_PASSPHRASE_LEN 8 65eda14cbcSMatt Macy #define MAX_PASSPHRASE_LEN 512 66eda14cbcSMatt Macy #define MAX_KEY_PROMPT_ATTEMPTS 3 67eda14cbcSMatt Macy 68eda14cbcSMatt Macy static int caught_interrupt; 69eda14cbcSMatt Macy 70eda14cbcSMatt Macy static int get_key_material_file(libzfs_handle_t *, const char *, const char *, 71eda14cbcSMatt Macy zfs_keyformat_t, boolean_t, uint8_t **, size_t *); 7216038816SMartin Matuska static int get_key_material_https(libzfs_handle_t *, const char *, const char *, 7316038816SMartin Matuska zfs_keyformat_t, boolean_t, uint8_t **, size_t *); 74eda14cbcSMatt Macy 75eda14cbcSMatt Macy static zfs_uri_handler_t uri_handlers[] = { 76eda14cbcSMatt Macy { "file", get_key_material_file }, 7716038816SMartin Matuska { "https", get_key_material_https }, 7816038816SMartin Matuska { "http", get_key_material_https }, 79eda14cbcSMatt Macy { NULL, NULL } 80eda14cbcSMatt Macy }; 81eda14cbcSMatt Macy 82eda14cbcSMatt Macy static int 83eda14cbcSMatt Macy pkcs11_get_urandom(uint8_t *buf, size_t bytes) 84eda14cbcSMatt Macy { 85eda14cbcSMatt Macy int rand; 86eda14cbcSMatt Macy ssize_t bytes_read = 0; 87eda14cbcSMatt Macy 8816038816SMartin Matuska rand = open("/dev/urandom", O_RDONLY | O_CLOEXEC); 89eda14cbcSMatt Macy 90eda14cbcSMatt Macy if (rand < 0) 91eda14cbcSMatt Macy return (rand); 92eda14cbcSMatt Macy 93eda14cbcSMatt Macy while (bytes_read < bytes) { 94eda14cbcSMatt Macy ssize_t rc = read(rand, buf + bytes_read, bytes - bytes_read); 95eda14cbcSMatt Macy if (rc < 0) 96eda14cbcSMatt Macy break; 97eda14cbcSMatt Macy bytes_read += rc; 98eda14cbcSMatt Macy } 99eda14cbcSMatt Macy 100eda14cbcSMatt Macy (void) close(rand); 101eda14cbcSMatt Macy 102eda14cbcSMatt Macy return (bytes_read); 103eda14cbcSMatt Macy } 104eda14cbcSMatt Macy 105eda14cbcSMatt Macy static int 106eda14cbcSMatt Macy zfs_prop_parse_keylocation(libzfs_handle_t *restrict hdl, const char *str, 107eda14cbcSMatt Macy zfs_keylocation_t *restrict locp, char **restrict schemep) 108eda14cbcSMatt Macy { 109eda14cbcSMatt Macy *locp = ZFS_KEYLOCATION_NONE; 110eda14cbcSMatt Macy *schemep = NULL; 111eda14cbcSMatt Macy 112eda14cbcSMatt Macy if (strcmp("prompt", str) == 0) { 113eda14cbcSMatt Macy *locp = ZFS_KEYLOCATION_PROMPT; 114eda14cbcSMatt Macy return (0); 115eda14cbcSMatt Macy } 116eda14cbcSMatt Macy 117eda14cbcSMatt Macy regmatch_t pmatch[2]; 118eda14cbcSMatt Macy 119eda14cbcSMatt Macy if (regexec(&hdl->libzfs_urire, str, ARRAY_SIZE(pmatch), 120eda14cbcSMatt Macy pmatch, 0) == 0) { 121eda14cbcSMatt Macy size_t scheme_len; 122eda14cbcSMatt Macy 123eda14cbcSMatt Macy if (pmatch[1].rm_so == -1) { 124eda14cbcSMatt Macy zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 125eda14cbcSMatt Macy "Invalid URI")); 126eda14cbcSMatt Macy return (EINVAL); 127eda14cbcSMatt Macy } 128eda14cbcSMatt Macy 129eda14cbcSMatt Macy scheme_len = pmatch[1].rm_eo - pmatch[1].rm_so; 130eda14cbcSMatt Macy 131eda14cbcSMatt Macy *schemep = calloc(1, scheme_len + 1); 132eda14cbcSMatt Macy if (*schemep == NULL) { 133eda14cbcSMatt Macy int ret = errno; 134eda14cbcSMatt Macy 135eda14cbcSMatt Macy errno = 0; 136eda14cbcSMatt Macy zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 137eda14cbcSMatt Macy "Invalid URI")); 138eda14cbcSMatt Macy return (ret); 139eda14cbcSMatt Macy } 140eda14cbcSMatt Macy 141eda14cbcSMatt Macy (void) memcpy(*schemep, str + pmatch[1].rm_so, scheme_len); 142eda14cbcSMatt Macy *locp = ZFS_KEYLOCATION_URI; 143eda14cbcSMatt Macy return (0); 144eda14cbcSMatt Macy } 145eda14cbcSMatt Macy 146eda14cbcSMatt Macy zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "Invalid keylocation")); 147eda14cbcSMatt Macy return (EINVAL); 148eda14cbcSMatt Macy } 149eda14cbcSMatt Macy 150eda14cbcSMatt Macy static int 151eda14cbcSMatt Macy hex_key_to_raw(char *hex, int hexlen, uint8_t *out) 152eda14cbcSMatt Macy { 153eda14cbcSMatt Macy int ret, i; 154eda14cbcSMatt Macy unsigned int c; 155eda14cbcSMatt Macy 156eda14cbcSMatt Macy for (i = 0; i < hexlen; i += 2) { 157eda14cbcSMatt Macy if (!isxdigit(hex[i]) || !isxdigit(hex[i + 1])) { 158eda14cbcSMatt Macy ret = EINVAL; 159eda14cbcSMatt Macy goto error; 160eda14cbcSMatt Macy } 161eda14cbcSMatt Macy 162eda14cbcSMatt Macy ret = sscanf(&hex[i], "%02x", &c); 163eda14cbcSMatt Macy if (ret != 1) { 164eda14cbcSMatt Macy ret = EINVAL; 165eda14cbcSMatt Macy goto error; 166eda14cbcSMatt Macy } 167eda14cbcSMatt Macy 168eda14cbcSMatt Macy out[i / 2] = c; 169eda14cbcSMatt Macy } 170eda14cbcSMatt Macy 171eda14cbcSMatt Macy return (0); 172eda14cbcSMatt Macy 173eda14cbcSMatt Macy error: 174eda14cbcSMatt Macy return (ret); 175eda14cbcSMatt Macy } 176eda14cbcSMatt Macy 177eda14cbcSMatt Macy 178eda14cbcSMatt Macy static void 179eda14cbcSMatt Macy catch_signal(int sig) 180eda14cbcSMatt Macy { 181eda14cbcSMatt Macy caught_interrupt = sig; 182eda14cbcSMatt Macy } 183eda14cbcSMatt Macy 184eda14cbcSMatt Macy static const char * 185eda14cbcSMatt Macy get_format_prompt_string(zfs_keyformat_t format) 186eda14cbcSMatt Macy { 187eda14cbcSMatt Macy switch (format) { 188eda14cbcSMatt Macy case ZFS_KEYFORMAT_RAW: 189eda14cbcSMatt Macy return ("raw key"); 190eda14cbcSMatt Macy case ZFS_KEYFORMAT_HEX: 191eda14cbcSMatt Macy return ("hex key"); 192eda14cbcSMatt Macy case ZFS_KEYFORMAT_PASSPHRASE: 193eda14cbcSMatt Macy return ("passphrase"); 194eda14cbcSMatt Macy default: 195eda14cbcSMatt Macy /* shouldn't happen */ 196eda14cbcSMatt Macy return (NULL); 197eda14cbcSMatt Macy } 198eda14cbcSMatt Macy } 199eda14cbcSMatt Macy 200eda14cbcSMatt Macy /* do basic validation of the key material */ 201eda14cbcSMatt Macy static int 202eda14cbcSMatt Macy validate_key(libzfs_handle_t *hdl, zfs_keyformat_t keyformat, 203eda14cbcSMatt Macy const char *key, size_t keylen) 204eda14cbcSMatt Macy { 205eda14cbcSMatt Macy switch (keyformat) { 206eda14cbcSMatt Macy case ZFS_KEYFORMAT_RAW: 207eda14cbcSMatt Macy /* verify the key length is correct */ 208eda14cbcSMatt Macy if (keylen < WRAPPING_KEY_LEN) { 209eda14cbcSMatt Macy zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 210eda14cbcSMatt Macy "Raw key too short (expected %u)."), 211eda14cbcSMatt Macy WRAPPING_KEY_LEN); 212eda14cbcSMatt Macy return (EINVAL); 213eda14cbcSMatt Macy } 214eda14cbcSMatt Macy 215eda14cbcSMatt Macy if (keylen > WRAPPING_KEY_LEN) { 216eda14cbcSMatt Macy zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 217eda14cbcSMatt Macy "Raw key too long (expected %u)."), 218eda14cbcSMatt Macy WRAPPING_KEY_LEN); 219eda14cbcSMatt Macy return (EINVAL); 220eda14cbcSMatt Macy } 221eda14cbcSMatt Macy break; 222eda14cbcSMatt Macy case ZFS_KEYFORMAT_HEX: 223eda14cbcSMatt Macy /* verify the key length is correct */ 224eda14cbcSMatt Macy if (keylen < WRAPPING_KEY_LEN * 2) { 225eda14cbcSMatt Macy zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 226eda14cbcSMatt Macy "Hex key too short (expected %u)."), 227eda14cbcSMatt Macy WRAPPING_KEY_LEN * 2); 228eda14cbcSMatt Macy return (EINVAL); 229eda14cbcSMatt Macy } 230eda14cbcSMatt Macy 231eda14cbcSMatt Macy if (keylen > WRAPPING_KEY_LEN * 2) { 232eda14cbcSMatt Macy zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 233eda14cbcSMatt Macy "Hex key too long (expected %u)."), 234eda14cbcSMatt Macy WRAPPING_KEY_LEN * 2); 235eda14cbcSMatt Macy return (EINVAL); 236eda14cbcSMatt Macy } 237eda14cbcSMatt Macy 238eda14cbcSMatt Macy /* check for invalid hex digits */ 239eda14cbcSMatt Macy for (size_t i = 0; i < WRAPPING_KEY_LEN * 2; i++) { 240eda14cbcSMatt Macy if (!isxdigit(key[i])) { 241eda14cbcSMatt Macy zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 242eda14cbcSMatt Macy "Invalid hex character detected.")); 243eda14cbcSMatt Macy return (EINVAL); 244eda14cbcSMatt Macy } 245eda14cbcSMatt Macy } 246eda14cbcSMatt Macy break; 247eda14cbcSMatt Macy case ZFS_KEYFORMAT_PASSPHRASE: 248eda14cbcSMatt Macy /* verify the length is within bounds */ 249eda14cbcSMatt Macy if (keylen > MAX_PASSPHRASE_LEN) { 250eda14cbcSMatt Macy zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 251eda14cbcSMatt Macy "Passphrase too long (max %u)."), 252eda14cbcSMatt Macy MAX_PASSPHRASE_LEN); 253eda14cbcSMatt Macy return (EINVAL); 254eda14cbcSMatt Macy } 255eda14cbcSMatt Macy 256eda14cbcSMatt Macy if (keylen < MIN_PASSPHRASE_LEN) { 257eda14cbcSMatt Macy zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 258eda14cbcSMatt Macy "Passphrase too short (min %u)."), 259eda14cbcSMatt Macy MIN_PASSPHRASE_LEN); 260eda14cbcSMatt Macy return (EINVAL); 261eda14cbcSMatt Macy } 262eda14cbcSMatt Macy break; 263eda14cbcSMatt Macy default: 264eda14cbcSMatt Macy /* can't happen, checked above */ 265eda14cbcSMatt Macy break; 266eda14cbcSMatt Macy } 267eda14cbcSMatt Macy 268eda14cbcSMatt Macy return (0); 269eda14cbcSMatt Macy } 270eda14cbcSMatt Macy 271eda14cbcSMatt Macy static int 272eda14cbcSMatt Macy libzfs_getpassphrase(zfs_keyformat_t keyformat, boolean_t is_reenter, 273eda14cbcSMatt Macy boolean_t new_key, const char *fsname, 274eda14cbcSMatt Macy char **restrict res, size_t *restrict reslen) 275eda14cbcSMatt Macy { 276eda14cbcSMatt Macy FILE *f = stdin; 277eda14cbcSMatt Macy size_t buflen = 0; 278eda14cbcSMatt Macy ssize_t bytes; 279eda14cbcSMatt Macy int ret = 0; 280eda14cbcSMatt Macy struct termios old_term, new_term; 281eda14cbcSMatt Macy struct sigaction act, osigint, osigtstp; 282eda14cbcSMatt Macy 283eda14cbcSMatt Macy *res = NULL; 284eda14cbcSMatt Macy *reslen = 0; 285eda14cbcSMatt Macy 286eda14cbcSMatt Macy /* 287eda14cbcSMatt Macy * handle SIGINT and ignore SIGSTP. This is necessary to 288eda14cbcSMatt Macy * restore the state of the terminal. 289eda14cbcSMatt Macy */ 290eda14cbcSMatt Macy caught_interrupt = 0; 291eda14cbcSMatt Macy act.sa_flags = 0; 292eda14cbcSMatt Macy (void) sigemptyset(&act.sa_mask); 293eda14cbcSMatt Macy act.sa_handler = catch_signal; 294eda14cbcSMatt Macy 295eda14cbcSMatt Macy (void) sigaction(SIGINT, &act, &osigint); 296eda14cbcSMatt Macy act.sa_handler = SIG_IGN; 297eda14cbcSMatt Macy (void) sigaction(SIGTSTP, &act, &osigtstp); 298eda14cbcSMatt Macy 299eda14cbcSMatt Macy (void) printf("%s %s%s", 300eda14cbcSMatt Macy is_reenter ? "Re-enter" : "Enter", 301eda14cbcSMatt Macy new_key ? "new " : "", 302eda14cbcSMatt Macy get_format_prompt_string(keyformat)); 303eda14cbcSMatt Macy if (fsname != NULL) 304eda14cbcSMatt Macy (void) printf(" for '%s'", fsname); 305eda14cbcSMatt Macy (void) fputc(':', stdout); 306eda14cbcSMatt Macy (void) fflush(stdout); 307eda14cbcSMatt Macy 308eda14cbcSMatt Macy /* disable the terminal echo for key input */ 309eda14cbcSMatt Macy (void) tcgetattr(fileno(f), &old_term); 310eda14cbcSMatt Macy 311eda14cbcSMatt Macy new_term = old_term; 312eda14cbcSMatt Macy new_term.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL); 313eda14cbcSMatt Macy 314eda14cbcSMatt Macy ret = tcsetattr(fileno(f), TCSAFLUSH, &new_term); 315eda14cbcSMatt Macy if (ret != 0) { 316eda14cbcSMatt Macy ret = errno; 317eda14cbcSMatt Macy errno = 0; 318eda14cbcSMatt Macy goto out; 319eda14cbcSMatt Macy } 320eda14cbcSMatt Macy 321eda14cbcSMatt Macy bytes = getline(res, &buflen, f); 322eda14cbcSMatt Macy if (bytes < 0) { 323eda14cbcSMatt Macy ret = errno; 324eda14cbcSMatt Macy errno = 0; 325eda14cbcSMatt Macy goto out; 326eda14cbcSMatt Macy } 327eda14cbcSMatt Macy 328eda14cbcSMatt Macy /* trim the ending newline if it exists */ 329eda14cbcSMatt Macy if (bytes > 0 && (*res)[bytes - 1] == '\n') { 330eda14cbcSMatt Macy (*res)[bytes - 1] = '\0'; 331eda14cbcSMatt Macy bytes--; 332eda14cbcSMatt Macy } 333eda14cbcSMatt Macy 334eda14cbcSMatt Macy *reslen = bytes; 335eda14cbcSMatt Macy 336eda14cbcSMatt Macy out: 337eda14cbcSMatt Macy /* reset the terminal */ 338eda14cbcSMatt Macy (void) tcsetattr(fileno(f), TCSAFLUSH, &old_term); 339eda14cbcSMatt Macy (void) sigaction(SIGINT, &osigint, NULL); 340eda14cbcSMatt Macy (void) sigaction(SIGTSTP, &osigtstp, NULL); 341eda14cbcSMatt Macy 342eda14cbcSMatt Macy /* if we caught a signal, re-throw it now */ 343eda14cbcSMatt Macy if (caught_interrupt != 0) 344eda14cbcSMatt Macy (void) kill(getpid(), caught_interrupt); 345eda14cbcSMatt Macy 346eda14cbcSMatt Macy /* print the newline that was not echo'd */ 347eda14cbcSMatt Macy (void) printf("\n"); 348eda14cbcSMatt Macy 349eda14cbcSMatt Macy return (ret); 350eda14cbcSMatt Macy } 351eda14cbcSMatt Macy 352eda14cbcSMatt Macy static int 353eda14cbcSMatt Macy get_key_interactive(libzfs_handle_t *restrict hdl, const char *fsname, 354eda14cbcSMatt Macy zfs_keyformat_t keyformat, boolean_t confirm_key, boolean_t newkey, 355eda14cbcSMatt Macy uint8_t **restrict outbuf, size_t *restrict len_out) 356eda14cbcSMatt Macy { 357eda14cbcSMatt Macy char *buf = NULL, *buf2 = NULL; 358eda14cbcSMatt Macy size_t buflen = 0, buf2len = 0; 359eda14cbcSMatt Macy int ret = 0; 360eda14cbcSMatt Macy 361eda14cbcSMatt Macy ASSERT(isatty(fileno(stdin))); 362eda14cbcSMatt Macy 363eda14cbcSMatt Macy /* raw keys cannot be entered on the terminal */ 364eda14cbcSMatt Macy if (keyformat == ZFS_KEYFORMAT_RAW) { 365eda14cbcSMatt Macy ret = EINVAL; 366eda14cbcSMatt Macy zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 367eda14cbcSMatt Macy "Cannot enter raw keys on the terminal")); 368eda14cbcSMatt Macy goto out; 369eda14cbcSMatt Macy } 370eda14cbcSMatt Macy 371eda14cbcSMatt Macy /* prompt for the key */ 372eda14cbcSMatt Macy if ((ret = libzfs_getpassphrase(keyformat, B_FALSE, newkey, fsname, 373eda14cbcSMatt Macy &buf, &buflen)) != 0) { 374eda14cbcSMatt Macy free(buf); 375eda14cbcSMatt Macy buf = NULL; 376eda14cbcSMatt Macy buflen = 0; 377eda14cbcSMatt Macy goto out; 378eda14cbcSMatt Macy } 379eda14cbcSMatt Macy 380eda14cbcSMatt Macy if (!confirm_key) 381eda14cbcSMatt Macy goto out; 382eda14cbcSMatt Macy 383eda14cbcSMatt Macy if ((ret = validate_key(hdl, keyformat, buf, buflen)) != 0) { 384eda14cbcSMatt Macy free(buf); 385eda14cbcSMatt Macy return (ret); 386eda14cbcSMatt Macy } 387eda14cbcSMatt Macy 388eda14cbcSMatt Macy ret = libzfs_getpassphrase(keyformat, B_TRUE, newkey, fsname, &buf2, 389eda14cbcSMatt Macy &buf2len); 390eda14cbcSMatt Macy if (ret != 0) { 391eda14cbcSMatt Macy free(buf); 392eda14cbcSMatt Macy free(buf2); 393eda14cbcSMatt Macy buf = buf2 = NULL; 394eda14cbcSMatt Macy buflen = buf2len = 0; 395eda14cbcSMatt Macy goto out; 396eda14cbcSMatt Macy } 397eda14cbcSMatt Macy 398eda14cbcSMatt Macy if (buflen != buf2len || strcmp(buf, buf2) != 0) { 399eda14cbcSMatt Macy free(buf); 400eda14cbcSMatt Macy buf = NULL; 401eda14cbcSMatt Macy buflen = 0; 402eda14cbcSMatt Macy 403eda14cbcSMatt Macy ret = EINVAL; 404eda14cbcSMatt Macy zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 405eda14cbcSMatt Macy "Provided keys do not match.")); 406eda14cbcSMatt Macy } 407eda14cbcSMatt Macy 408eda14cbcSMatt Macy free(buf2); 409eda14cbcSMatt Macy 410eda14cbcSMatt Macy out: 411eda14cbcSMatt Macy *outbuf = (uint8_t *)buf; 412eda14cbcSMatt Macy *len_out = buflen; 413eda14cbcSMatt Macy return (ret); 414eda14cbcSMatt Macy } 415eda14cbcSMatt Macy 416eda14cbcSMatt Macy static int 417eda14cbcSMatt Macy get_key_material_raw(FILE *fd, zfs_keyformat_t keyformat, 418eda14cbcSMatt Macy uint8_t **buf, size_t *len_out) 419eda14cbcSMatt Macy { 420eda14cbcSMatt Macy int ret = 0; 421eda14cbcSMatt Macy size_t buflen = 0; 422eda14cbcSMatt Macy 423eda14cbcSMatt Macy *len_out = 0; 424eda14cbcSMatt Macy 425eda14cbcSMatt Macy /* read the key material */ 426eda14cbcSMatt Macy if (keyformat != ZFS_KEYFORMAT_RAW) { 427eda14cbcSMatt Macy ssize_t bytes; 428eda14cbcSMatt Macy 429eda14cbcSMatt Macy bytes = getline((char **)buf, &buflen, fd); 430eda14cbcSMatt Macy if (bytes < 0) { 431eda14cbcSMatt Macy ret = errno; 432eda14cbcSMatt Macy errno = 0; 433eda14cbcSMatt Macy goto out; 434eda14cbcSMatt Macy } 435eda14cbcSMatt Macy 436eda14cbcSMatt Macy /* trim the ending newline if it exists */ 437eda14cbcSMatt Macy if (bytes > 0 && (*buf)[bytes - 1] == '\n') { 438eda14cbcSMatt Macy (*buf)[bytes - 1] = '\0'; 439eda14cbcSMatt Macy bytes--; 440eda14cbcSMatt Macy } 441eda14cbcSMatt Macy 442eda14cbcSMatt Macy *len_out = bytes; 443eda14cbcSMatt Macy } else { 444eda14cbcSMatt Macy size_t n; 445eda14cbcSMatt Macy 446eda14cbcSMatt Macy /* 447eda14cbcSMatt Macy * Raw keys may have newline characters in them and so can't 448eda14cbcSMatt Macy * use getline(). Here we attempt to read 33 bytes so that we 449eda14cbcSMatt Macy * can properly check the key length (the file should only have 450eda14cbcSMatt Macy * 32 bytes). 451eda14cbcSMatt Macy */ 452eda14cbcSMatt Macy *buf = malloc((WRAPPING_KEY_LEN + 1) * sizeof (uint8_t)); 453eda14cbcSMatt Macy if (*buf == NULL) { 454eda14cbcSMatt Macy ret = ENOMEM; 455eda14cbcSMatt Macy goto out; 456eda14cbcSMatt Macy } 457eda14cbcSMatt Macy 458eda14cbcSMatt Macy n = fread(*buf, 1, WRAPPING_KEY_LEN + 1, fd); 459eda14cbcSMatt Macy if (n == 0 || ferror(fd)) { 460eda14cbcSMatt Macy /* size errors are handled by the calling function */ 461eda14cbcSMatt Macy free(*buf); 462eda14cbcSMatt Macy *buf = NULL; 463eda14cbcSMatt Macy ret = errno; 464eda14cbcSMatt Macy errno = 0; 465eda14cbcSMatt Macy goto out; 466eda14cbcSMatt Macy } 467eda14cbcSMatt Macy 468eda14cbcSMatt Macy *len_out = n; 469eda14cbcSMatt Macy } 470eda14cbcSMatt Macy out: 471eda14cbcSMatt Macy return (ret); 472eda14cbcSMatt Macy } 473eda14cbcSMatt Macy 474eda14cbcSMatt Macy static int 475eda14cbcSMatt Macy get_key_material_file(libzfs_handle_t *hdl, const char *uri, 476eda14cbcSMatt Macy const char *fsname, zfs_keyformat_t keyformat, boolean_t newkey, 477eda14cbcSMatt Macy uint8_t **restrict buf, size_t *restrict len_out) 478eda14cbcSMatt Macy { 479eda14cbcSMatt Macy FILE *f = NULL; 480eda14cbcSMatt Macy int ret = 0; 481eda14cbcSMatt Macy 482eda14cbcSMatt Macy if (strlen(uri) < 7) 483eda14cbcSMatt Macy return (EINVAL); 484eda14cbcSMatt Macy 48516038816SMartin Matuska if ((f = fopen(uri + 7, "re")) == NULL) { 486eda14cbcSMatt Macy ret = errno; 487eda14cbcSMatt Macy errno = 0; 488eda14cbcSMatt Macy zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 489*1f88aa09SMartin Matuska "Failed to open key material file: %s"), strerror(ret)); 490eda14cbcSMatt Macy return (ret); 491eda14cbcSMatt Macy } 492eda14cbcSMatt Macy 493eda14cbcSMatt Macy ret = get_key_material_raw(f, keyformat, buf, len_out); 494eda14cbcSMatt Macy 495eda14cbcSMatt Macy (void) fclose(f); 496eda14cbcSMatt Macy 497eda14cbcSMatt Macy return (ret); 498eda14cbcSMatt Macy } 499eda14cbcSMatt Macy 50016038816SMartin Matuska static int 50116038816SMartin Matuska get_key_material_https(libzfs_handle_t *hdl, const char *uri, 50216038816SMartin Matuska const char *fsname, zfs_keyformat_t keyformat, boolean_t newkey, 50316038816SMartin Matuska uint8_t **restrict buf, size_t *restrict len_out) 50416038816SMartin Matuska { 50516038816SMartin Matuska int ret = 0; 50616038816SMartin Matuska FILE *key = NULL; 50716038816SMartin Matuska boolean_t is_http = strncmp(uri, "http:", strlen("http:")) == 0; 50816038816SMartin Matuska 50916038816SMartin Matuska if (strlen(uri) < (is_http ? 7 : 8)) { 51016038816SMartin Matuska ret = EINVAL; 51116038816SMartin Matuska goto end; 51216038816SMartin Matuska } 51316038816SMartin Matuska 51416038816SMartin Matuska #if LIBFETCH_DYNAMIC 51516038816SMartin Matuska #define LOAD_FUNCTION(func) \ 51616038816SMartin Matuska __typeof__(func) *func = dlsym(hdl->libfetch, #func); 51716038816SMartin Matuska 51816038816SMartin Matuska if (hdl->libfetch == NULL) 51916038816SMartin Matuska hdl->libfetch = dlopen(LIBFETCH_SONAME, RTLD_LAZY); 52016038816SMartin Matuska 52116038816SMartin Matuska if (hdl->libfetch == NULL) { 52216038816SMartin Matuska hdl->libfetch = (void *)-1; 52316038816SMartin Matuska char *err = dlerror(); 52416038816SMartin Matuska if (err) 52516038816SMartin Matuska hdl->libfetch_load_error = strdup(err); 52616038816SMartin Matuska } 52716038816SMartin Matuska 52816038816SMartin Matuska if (hdl->libfetch == (void *)-1) { 52916038816SMartin Matuska ret = ENOSYS; 53016038816SMartin Matuska zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 53116038816SMartin Matuska "Couldn't load %s: %s"), 53216038816SMartin Matuska LIBFETCH_SONAME, hdl->libfetch_load_error ?: "(?)"); 53316038816SMartin Matuska goto end; 53416038816SMartin Matuska } 53516038816SMartin Matuska 53616038816SMartin Matuska boolean_t ok; 53716038816SMartin Matuska #if LIBFETCH_IS_FETCH 53816038816SMartin Matuska LOAD_FUNCTION(fetchGetURL); 53916038816SMartin Matuska char *fetchLastErrString = dlsym(hdl->libfetch, "fetchLastErrString"); 54016038816SMartin Matuska 54116038816SMartin Matuska ok = fetchGetURL && fetchLastErrString; 54216038816SMartin Matuska #elif LIBFETCH_IS_LIBCURL 54316038816SMartin Matuska LOAD_FUNCTION(curl_easy_init); 54416038816SMartin Matuska LOAD_FUNCTION(curl_easy_setopt); 54516038816SMartin Matuska LOAD_FUNCTION(curl_easy_perform); 54616038816SMartin Matuska LOAD_FUNCTION(curl_easy_cleanup); 54716038816SMartin Matuska LOAD_FUNCTION(curl_easy_strerror); 54816038816SMartin Matuska LOAD_FUNCTION(curl_easy_getinfo); 54916038816SMartin Matuska 55016038816SMartin Matuska ok = curl_easy_init && curl_easy_setopt && curl_easy_perform && 55116038816SMartin Matuska curl_easy_cleanup && curl_easy_strerror && curl_easy_getinfo; 55216038816SMartin Matuska #endif 55316038816SMartin Matuska if (!ok) { 55416038816SMartin Matuska zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 55516038816SMartin Matuska "keylocation=%s back-end %s missing symbols."), 55616038816SMartin Matuska is_http ? "http://" : "https://", LIBFETCH_SONAME); 55716038816SMartin Matuska ret = ENOSYS; 55816038816SMartin Matuska goto end; 55916038816SMartin Matuska } 56016038816SMartin Matuska #endif 56116038816SMartin Matuska 56216038816SMartin Matuska #if LIBFETCH_IS_FETCH 56316038816SMartin Matuska key = fetchGetURL(uri, ""); 56416038816SMartin Matuska if (key == NULL) { 56516038816SMartin Matuska zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 56616038816SMartin Matuska "Couldn't GET %s: %s"), 56716038816SMartin Matuska uri, fetchLastErrString); 56816038816SMartin Matuska ret = ENETDOWN; 56916038816SMartin Matuska } 57016038816SMartin Matuska #elif LIBFETCH_IS_LIBCURL 57116038816SMartin Matuska CURL *curl = curl_easy_init(); 57216038816SMartin Matuska if (curl == NULL) { 57316038816SMartin Matuska ret = ENOTSUP; 57416038816SMartin Matuska goto end; 57516038816SMartin Matuska } 57616038816SMartin Matuska 57716038816SMartin Matuska int kfd = -1; 57816038816SMartin Matuska #ifdef O_TMPFILE 57916038816SMartin Matuska kfd = open(getenv("TMPDIR") ?: "/tmp", 58016038816SMartin Matuska O_RDWR | O_TMPFILE | O_EXCL | O_CLOEXEC, 0600); 58116038816SMartin Matuska if (kfd != -1) 58216038816SMartin Matuska goto kfdok; 58316038816SMartin Matuska #endif 58416038816SMartin Matuska 58516038816SMartin Matuska char *path; 58616038816SMartin Matuska if (asprintf(&path, 58716038816SMartin Matuska "%s/libzfs-XXXXXXXX.https", getenv("TMPDIR") ?: "/tmp") == -1) { 58816038816SMartin Matuska ret = ENOMEM; 58916038816SMartin Matuska zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "%s"), 59016038816SMartin Matuska strerror(ret)); 59116038816SMartin Matuska goto end; 59216038816SMartin Matuska } 59316038816SMartin Matuska 59416038816SMartin Matuska kfd = mkostemps(path, strlen(".https"), O_CLOEXEC); 59516038816SMartin Matuska if (kfd == -1) { 59616038816SMartin Matuska ret = errno; 59716038816SMartin Matuska zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 59816038816SMartin Matuska "Couldn't create temporary file %s: %s"), 59916038816SMartin Matuska path, strerror(ret)); 60016038816SMartin Matuska free(path); 60116038816SMartin Matuska goto end; 60216038816SMartin Matuska } 60316038816SMartin Matuska (void) unlink(path); 60416038816SMartin Matuska free(path); 60516038816SMartin Matuska 60616038816SMartin Matuska kfdok: 60716038816SMartin Matuska if ((key = fdopen(kfd, "r+")) == NULL) { 60816038816SMartin Matuska ret = errno; 60916038816SMartin Matuska free(path); 61016038816SMartin Matuska (void) close(kfd); 61116038816SMartin Matuska zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 61216038816SMartin Matuska "Couldn't reopen temporary file: %s"), strerror(ret)); 61316038816SMartin Matuska goto end; 61416038816SMartin Matuska } 61516038816SMartin Matuska 61616038816SMartin Matuska char errbuf[CURL_ERROR_SIZE] = ""; 61716038816SMartin Matuska char *cainfo = getenv("SSL_CA_CERT_FILE"); /* matches fetch(3) */ 61816038816SMartin Matuska char *capath = getenv("SSL_CA_CERT_PATH"); /* matches fetch(3) */ 61916038816SMartin Matuska char *clcert = getenv("SSL_CLIENT_CERT_FILE"); /* matches fetch(3) */ 62016038816SMartin Matuska char *clkey = getenv("SSL_CLIENT_KEY_FILE"); /* matches fetch(3) */ 62116038816SMartin Matuska (void) curl_easy_setopt(curl, CURLOPT_URL, uri); 62216038816SMartin Matuska (void) curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); 62316038816SMartin Matuska (void) curl_easy_setopt(curl, CURLOPT_TIMEOUT_MS, 30000L); 62416038816SMartin Matuska (void) curl_easy_setopt(curl, CURLOPT_WRITEDATA, key); 62516038816SMartin Matuska (void) curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, errbuf); 62616038816SMartin Matuska if (cainfo != NULL) 62716038816SMartin Matuska (void) curl_easy_setopt(curl, CURLOPT_CAINFO, cainfo); 62816038816SMartin Matuska if (capath != NULL) 62916038816SMartin Matuska (void) curl_easy_setopt(curl, CURLOPT_CAPATH, capath); 63016038816SMartin Matuska if (clcert != NULL) 63116038816SMartin Matuska (void) curl_easy_setopt(curl, CURLOPT_SSLCERT, clcert); 63216038816SMartin Matuska if (clkey != NULL) 63316038816SMartin Matuska (void) curl_easy_setopt(curl, CURLOPT_SSLKEY, clkey); 63416038816SMartin Matuska 63516038816SMartin Matuska CURLcode res = curl_easy_perform(curl); 63616038816SMartin Matuska 63716038816SMartin Matuska if (res != CURLE_OK) { 63816038816SMartin Matuska zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 63916038816SMartin Matuska "Failed to connect to %s: %s"), 64016038816SMartin Matuska uri, strlen(errbuf) ? errbuf : curl_easy_strerror(res)); 64116038816SMartin Matuska ret = ENETDOWN; 64216038816SMartin Matuska } else { 64316038816SMartin Matuska long resp = 200; 64416038816SMartin Matuska (void) curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &resp); 64516038816SMartin Matuska 64616038816SMartin Matuska if (resp < 200 || resp >= 300) { 64716038816SMartin Matuska zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 64816038816SMartin Matuska "Couldn't GET %s: %ld"), 64916038816SMartin Matuska uri, resp); 65016038816SMartin Matuska ret = ENOENT; 65116038816SMartin Matuska } else 65216038816SMartin Matuska rewind(key); 65316038816SMartin Matuska } 65416038816SMartin Matuska 65516038816SMartin Matuska curl_easy_cleanup(curl); 65616038816SMartin Matuska #else 65716038816SMartin Matuska zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 65816038816SMartin Matuska "No keylocation=%s back-end."), is_http ? "http://" : "https://"); 65916038816SMartin Matuska ret = ENOSYS; 66016038816SMartin Matuska #endif 66116038816SMartin Matuska 66216038816SMartin Matuska end: 66316038816SMartin Matuska if (ret == 0) 66416038816SMartin Matuska ret = get_key_material_raw(key, keyformat, buf, len_out); 66516038816SMartin Matuska 66616038816SMartin Matuska if (key != NULL) 66716038816SMartin Matuska fclose(key); 66816038816SMartin Matuska 66916038816SMartin Matuska return (ret); 67016038816SMartin Matuska } 67116038816SMartin Matuska 672eda14cbcSMatt Macy /* 673eda14cbcSMatt Macy * Attempts to fetch key material, no matter where it might live. The key 674eda14cbcSMatt Macy * material is allocated and returned in km_out. *can_retry_out will be set 675eda14cbcSMatt Macy * to B_TRUE if the user is providing the key material interactively, allowing 676eda14cbcSMatt Macy * for re-entry attempts. 677eda14cbcSMatt Macy */ 678eda14cbcSMatt Macy static int 679eda14cbcSMatt Macy get_key_material(libzfs_handle_t *hdl, boolean_t do_verify, boolean_t newkey, 680eda14cbcSMatt Macy zfs_keyformat_t keyformat, char *keylocation, const char *fsname, 681eda14cbcSMatt Macy uint8_t **km_out, size_t *kmlen_out, boolean_t *can_retry_out) 682eda14cbcSMatt Macy { 683eda14cbcSMatt Macy int ret; 684eda14cbcSMatt Macy zfs_keylocation_t keyloc = ZFS_KEYLOCATION_NONE; 685eda14cbcSMatt Macy uint8_t *km = NULL; 686eda14cbcSMatt Macy size_t kmlen = 0; 687eda14cbcSMatt Macy char *uri_scheme = NULL; 688eda14cbcSMatt Macy zfs_uri_handler_t *handler = NULL; 689eda14cbcSMatt Macy boolean_t can_retry = B_FALSE; 690eda14cbcSMatt Macy 691eda14cbcSMatt Macy /* verify and parse the keylocation */ 692eda14cbcSMatt Macy ret = zfs_prop_parse_keylocation(hdl, keylocation, &keyloc, 693eda14cbcSMatt Macy &uri_scheme); 694eda14cbcSMatt Macy if (ret != 0) 695eda14cbcSMatt Macy goto error; 696eda14cbcSMatt Macy 697eda14cbcSMatt Macy /* open the appropriate file descriptor */ 698eda14cbcSMatt Macy switch (keyloc) { 699eda14cbcSMatt Macy case ZFS_KEYLOCATION_PROMPT: 700eda14cbcSMatt Macy if (isatty(fileno(stdin))) { 70116038816SMartin Matuska can_retry = keyformat != ZFS_KEYFORMAT_RAW; 702eda14cbcSMatt Macy ret = get_key_interactive(hdl, fsname, keyformat, 703eda14cbcSMatt Macy do_verify, newkey, &km, &kmlen); 704eda14cbcSMatt Macy } else { 705eda14cbcSMatt Macy /* fetch the key material into the buffer */ 706eda14cbcSMatt Macy ret = get_key_material_raw(stdin, keyformat, &km, 707eda14cbcSMatt Macy &kmlen); 708eda14cbcSMatt Macy } 709eda14cbcSMatt Macy 710eda14cbcSMatt Macy if (ret != 0) 711eda14cbcSMatt Macy goto error; 712eda14cbcSMatt Macy 713eda14cbcSMatt Macy break; 714eda14cbcSMatt Macy case ZFS_KEYLOCATION_URI: 7159db44a8eSMartin Matuska ret = ENOTSUP; 7169db44a8eSMartin Matuska 717eda14cbcSMatt Macy for (handler = uri_handlers; handler->zuh_scheme != NULL; 718eda14cbcSMatt Macy handler++) { 719eda14cbcSMatt Macy if (strcmp(handler->zuh_scheme, uri_scheme) != 0) 720eda14cbcSMatt Macy continue; 721eda14cbcSMatt Macy 722eda14cbcSMatt Macy if ((ret = handler->zuh_handler(hdl, keylocation, 723eda14cbcSMatt Macy fsname, keyformat, newkey, &km, &kmlen)) != 0) 724eda14cbcSMatt Macy goto error; 725eda14cbcSMatt Macy 726eda14cbcSMatt Macy break; 727eda14cbcSMatt Macy } 728eda14cbcSMatt Macy 7299db44a8eSMartin Matuska if (ret == ENOTSUP) { 730eda14cbcSMatt Macy zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 731eda14cbcSMatt Macy "URI scheme is not supported")); 7329db44a8eSMartin Matuska goto error; 7339db44a8eSMartin Matuska } 734eda14cbcSMatt Macy 735eda14cbcSMatt Macy break; 736eda14cbcSMatt Macy default: 737eda14cbcSMatt Macy ret = EINVAL; 738eda14cbcSMatt Macy zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 739eda14cbcSMatt Macy "Invalid keylocation.")); 740eda14cbcSMatt Macy goto error; 741eda14cbcSMatt Macy } 742eda14cbcSMatt Macy 743eda14cbcSMatt Macy if ((ret = validate_key(hdl, keyformat, (const char *)km, kmlen)) != 0) 744eda14cbcSMatt Macy goto error; 745eda14cbcSMatt Macy 746eda14cbcSMatt Macy *km_out = km; 747eda14cbcSMatt Macy *kmlen_out = kmlen; 748eda14cbcSMatt Macy if (can_retry_out != NULL) 749eda14cbcSMatt Macy *can_retry_out = can_retry; 750eda14cbcSMatt Macy 751eda14cbcSMatt Macy free(uri_scheme); 752eda14cbcSMatt Macy return (0); 753eda14cbcSMatt Macy 754eda14cbcSMatt Macy error: 755eda14cbcSMatt Macy free(km); 756eda14cbcSMatt Macy 757eda14cbcSMatt Macy *km_out = NULL; 758eda14cbcSMatt Macy *kmlen_out = 0; 759eda14cbcSMatt Macy 760eda14cbcSMatt Macy if (can_retry_out != NULL) 761eda14cbcSMatt Macy *can_retry_out = can_retry; 762eda14cbcSMatt Macy 763eda14cbcSMatt Macy free(uri_scheme); 764eda14cbcSMatt Macy return (ret); 765eda14cbcSMatt Macy } 766eda14cbcSMatt Macy 767eda14cbcSMatt Macy static int 768eda14cbcSMatt Macy derive_key(libzfs_handle_t *hdl, zfs_keyformat_t format, uint64_t iters, 769eda14cbcSMatt Macy uint8_t *key_material, size_t key_material_len, uint64_t salt, 770eda14cbcSMatt Macy uint8_t **key_out) 771eda14cbcSMatt Macy { 772eda14cbcSMatt Macy int ret; 773eda14cbcSMatt Macy uint8_t *key; 774eda14cbcSMatt Macy 775eda14cbcSMatt Macy *key_out = NULL; 776eda14cbcSMatt Macy 777eda14cbcSMatt Macy key = zfs_alloc(hdl, WRAPPING_KEY_LEN); 778eda14cbcSMatt Macy if (!key) 779eda14cbcSMatt Macy return (ENOMEM); 780eda14cbcSMatt Macy 781eda14cbcSMatt Macy switch (format) { 782eda14cbcSMatt Macy case ZFS_KEYFORMAT_RAW: 783eda14cbcSMatt Macy bcopy(key_material, key, WRAPPING_KEY_LEN); 784eda14cbcSMatt Macy break; 785eda14cbcSMatt Macy case ZFS_KEYFORMAT_HEX: 786eda14cbcSMatt Macy ret = hex_key_to_raw((char *)key_material, 787eda14cbcSMatt Macy WRAPPING_KEY_LEN * 2, key); 788eda14cbcSMatt Macy if (ret != 0) { 789eda14cbcSMatt Macy zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 790eda14cbcSMatt Macy "Invalid hex key provided.")); 791eda14cbcSMatt Macy goto error; 792eda14cbcSMatt Macy } 793eda14cbcSMatt Macy break; 794eda14cbcSMatt Macy case ZFS_KEYFORMAT_PASSPHRASE: 795eda14cbcSMatt Macy salt = LE_64(salt); 796eda14cbcSMatt Macy 797eda14cbcSMatt Macy ret = PKCS5_PBKDF2_HMAC_SHA1((char *)key_material, 798eda14cbcSMatt Macy strlen((char *)key_material), ((uint8_t *)&salt), 799eda14cbcSMatt Macy sizeof (uint64_t), iters, WRAPPING_KEY_LEN, key); 800eda14cbcSMatt Macy if (ret != 1) { 801eda14cbcSMatt Macy ret = EIO; 802eda14cbcSMatt Macy zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 803eda14cbcSMatt Macy "Failed to generate key from passphrase.")); 804eda14cbcSMatt Macy goto error; 805eda14cbcSMatt Macy } 806eda14cbcSMatt Macy break; 807eda14cbcSMatt Macy default: 808eda14cbcSMatt Macy ret = EINVAL; 809eda14cbcSMatt Macy goto error; 810eda14cbcSMatt Macy } 811eda14cbcSMatt Macy 812eda14cbcSMatt Macy *key_out = key; 813eda14cbcSMatt Macy return (0); 814eda14cbcSMatt Macy 815eda14cbcSMatt Macy error: 816eda14cbcSMatt Macy free(key); 817eda14cbcSMatt Macy 818eda14cbcSMatt Macy *key_out = NULL; 819eda14cbcSMatt Macy return (ret); 820eda14cbcSMatt Macy } 821eda14cbcSMatt Macy 822eda14cbcSMatt Macy static boolean_t 823eda14cbcSMatt Macy encryption_feature_is_enabled(zpool_handle_t *zph) 824eda14cbcSMatt Macy { 825eda14cbcSMatt Macy nvlist_t *features; 826eda14cbcSMatt Macy uint64_t feat_refcount; 827eda14cbcSMatt Macy 828eda14cbcSMatt Macy /* check that features can be enabled */ 829eda14cbcSMatt Macy if (zpool_get_prop_int(zph, ZPOOL_PROP_VERSION, NULL) 830eda14cbcSMatt Macy < SPA_VERSION_FEATURES) 831eda14cbcSMatt Macy return (B_FALSE); 832eda14cbcSMatt Macy 833eda14cbcSMatt Macy /* check for crypto feature */ 834eda14cbcSMatt Macy features = zpool_get_features(zph); 835eda14cbcSMatt Macy if (!features || nvlist_lookup_uint64(features, 836eda14cbcSMatt Macy spa_feature_table[SPA_FEATURE_ENCRYPTION].fi_guid, 837eda14cbcSMatt Macy &feat_refcount) != 0) 838eda14cbcSMatt Macy return (B_FALSE); 839eda14cbcSMatt Macy 840eda14cbcSMatt Macy return (B_TRUE); 841eda14cbcSMatt Macy } 842eda14cbcSMatt Macy 843eda14cbcSMatt Macy static int 844eda14cbcSMatt Macy populate_create_encryption_params_nvlists(libzfs_handle_t *hdl, 845eda14cbcSMatt Macy zfs_handle_t *zhp, boolean_t newkey, zfs_keyformat_t keyformat, 846eda14cbcSMatt Macy char *keylocation, nvlist_t *props, uint8_t **wkeydata, uint_t *wkeylen) 847eda14cbcSMatt Macy { 848eda14cbcSMatt Macy int ret; 849eda14cbcSMatt Macy uint64_t iters = 0, salt = 0; 850eda14cbcSMatt Macy uint8_t *key_material = NULL; 851eda14cbcSMatt Macy size_t key_material_len = 0; 852eda14cbcSMatt Macy uint8_t *key_data = NULL; 853eda14cbcSMatt Macy const char *fsname = (zhp) ? zfs_get_name(zhp) : NULL; 854eda14cbcSMatt Macy 855eda14cbcSMatt Macy /* get key material from keyformat and keylocation */ 856eda14cbcSMatt Macy ret = get_key_material(hdl, B_TRUE, newkey, keyformat, keylocation, 857eda14cbcSMatt Macy fsname, &key_material, &key_material_len, NULL); 858eda14cbcSMatt Macy if (ret != 0) 859eda14cbcSMatt Macy goto error; 860eda14cbcSMatt Macy 861eda14cbcSMatt Macy /* passphrase formats require a salt and pbkdf2 iters property */ 862eda14cbcSMatt Macy if (keyformat == ZFS_KEYFORMAT_PASSPHRASE) { 863eda14cbcSMatt Macy /* always generate a new salt */ 864eda14cbcSMatt Macy ret = pkcs11_get_urandom((uint8_t *)&salt, sizeof (uint64_t)); 865eda14cbcSMatt Macy if (ret != sizeof (uint64_t)) { 866eda14cbcSMatt Macy zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 867eda14cbcSMatt Macy "Failed to generate salt.")); 868eda14cbcSMatt Macy goto error; 869eda14cbcSMatt Macy } 870eda14cbcSMatt Macy 871eda14cbcSMatt Macy ret = nvlist_add_uint64(props, 872eda14cbcSMatt Macy zfs_prop_to_name(ZFS_PROP_PBKDF2_SALT), salt); 873eda14cbcSMatt Macy if (ret != 0) { 874eda14cbcSMatt Macy zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 875eda14cbcSMatt Macy "Failed to add salt to properties.")); 876eda14cbcSMatt Macy goto error; 877eda14cbcSMatt Macy } 878eda14cbcSMatt Macy 879eda14cbcSMatt Macy /* 880eda14cbcSMatt Macy * If not otherwise specified, use the default number of 881eda14cbcSMatt Macy * pbkdf2 iterations. If specified, we have already checked 882eda14cbcSMatt Macy * that the given value is greater than MIN_PBKDF2_ITERATIONS 883eda14cbcSMatt Macy * during zfs_valid_proplist(). 884eda14cbcSMatt Macy */ 885eda14cbcSMatt Macy ret = nvlist_lookup_uint64(props, 886eda14cbcSMatt Macy zfs_prop_to_name(ZFS_PROP_PBKDF2_ITERS), &iters); 887eda14cbcSMatt Macy if (ret == ENOENT) { 888eda14cbcSMatt Macy iters = DEFAULT_PBKDF2_ITERATIONS; 889eda14cbcSMatt Macy ret = nvlist_add_uint64(props, 890eda14cbcSMatt Macy zfs_prop_to_name(ZFS_PROP_PBKDF2_ITERS), iters); 891eda14cbcSMatt Macy if (ret != 0) 892eda14cbcSMatt Macy goto error; 893eda14cbcSMatt Macy } else if (ret != 0) { 894eda14cbcSMatt Macy zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 895eda14cbcSMatt Macy "Failed to get pbkdf2 iterations.")); 896eda14cbcSMatt Macy goto error; 897eda14cbcSMatt Macy } 898eda14cbcSMatt Macy } else { 899eda14cbcSMatt Macy /* check that pbkdf2iters was not specified by the user */ 900eda14cbcSMatt Macy ret = nvlist_lookup_uint64(props, 901eda14cbcSMatt Macy zfs_prop_to_name(ZFS_PROP_PBKDF2_ITERS), &iters); 902eda14cbcSMatt Macy if (ret == 0) { 903eda14cbcSMatt Macy ret = EINVAL; 904eda14cbcSMatt Macy zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 905eda14cbcSMatt Macy "Cannot specify pbkdf2iters with a non-passphrase " 906eda14cbcSMatt Macy "keyformat.")); 907eda14cbcSMatt Macy goto error; 908eda14cbcSMatt Macy } 909eda14cbcSMatt Macy } 910eda14cbcSMatt Macy 911eda14cbcSMatt Macy /* derive a key from the key material */ 912eda14cbcSMatt Macy ret = derive_key(hdl, keyformat, iters, key_material, key_material_len, 913eda14cbcSMatt Macy salt, &key_data); 914eda14cbcSMatt Macy if (ret != 0) 915eda14cbcSMatt Macy goto error; 916eda14cbcSMatt Macy 917eda14cbcSMatt Macy free(key_material); 918eda14cbcSMatt Macy 919eda14cbcSMatt Macy *wkeydata = key_data; 920eda14cbcSMatt Macy *wkeylen = WRAPPING_KEY_LEN; 921eda14cbcSMatt Macy return (0); 922eda14cbcSMatt Macy 923eda14cbcSMatt Macy error: 924eda14cbcSMatt Macy if (key_material != NULL) 925eda14cbcSMatt Macy free(key_material); 926eda14cbcSMatt Macy if (key_data != NULL) 927eda14cbcSMatt Macy free(key_data); 928eda14cbcSMatt Macy 929eda14cbcSMatt Macy *wkeydata = NULL; 930eda14cbcSMatt Macy *wkeylen = 0; 931eda14cbcSMatt Macy return (ret); 932eda14cbcSMatt Macy } 933eda14cbcSMatt Macy 934eda14cbcSMatt Macy static boolean_t 935eda14cbcSMatt Macy proplist_has_encryption_props(nvlist_t *props) 936eda14cbcSMatt Macy { 937eda14cbcSMatt Macy int ret; 938eda14cbcSMatt Macy uint64_t intval; 939eda14cbcSMatt Macy char *strval; 940eda14cbcSMatt Macy 941eda14cbcSMatt Macy ret = nvlist_lookup_uint64(props, 942eda14cbcSMatt Macy zfs_prop_to_name(ZFS_PROP_ENCRYPTION), &intval); 943eda14cbcSMatt Macy if (ret == 0 && intval != ZIO_CRYPT_OFF) 944eda14cbcSMatt Macy return (B_TRUE); 945eda14cbcSMatt Macy 946eda14cbcSMatt Macy ret = nvlist_lookup_string(props, 947eda14cbcSMatt Macy zfs_prop_to_name(ZFS_PROP_KEYLOCATION), &strval); 948eda14cbcSMatt Macy if (ret == 0 && strcmp(strval, "none") != 0) 949eda14cbcSMatt Macy return (B_TRUE); 950eda14cbcSMatt Macy 951eda14cbcSMatt Macy ret = nvlist_lookup_uint64(props, 952eda14cbcSMatt Macy zfs_prop_to_name(ZFS_PROP_KEYFORMAT), &intval); 953eda14cbcSMatt Macy if (ret == 0) 954eda14cbcSMatt Macy return (B_TRUE); 955eda14cbcSMatt Macy 956eda14cbcSMatt Macy ret = nvlist_lookup_uint64(props, 957eda14cbcSMatt Macy zfs_prop_to_name(ZFS_PROP_PBKDF2_ITERS), &intval); 958eda14cbcSMatt Macy if (ret == 0) 959eda14cbcSMatt Macy return (B_TRUE); 960eda14cbcSMatt Macy 961eda14cbcSMatt Macy return (B_FALSE); 962eda14cbcSMatt Macy } 963eda14cbcSMatt Macy 964eda14cbcSMatt Macy int 965eda14cbcSMatt Macy zfs_crypto_get_encryption_root(zfs_handle_t *zhp, boolean_t *is_encroot, 966eda14cbcSMatt Macy char *buf) 967eda14cbcSMatt Macy { 968eda14cbcSMatt Macy int ret; 969eda14cbcSMatt Macy char prop_encroot[MAXNAMELEN]; 970eda14cbcSMatt Macy 971eda14cbcSMatt Macy /* if the dataset isn't encrypted, just return */ 972eda14cbcSMatt Macy if (zfs_prop_get_int(zhp, ZFS_PROP_ENCRYPTION) == ZIO_CRYPT_OFF) { 973eda14cbcSMatt Macy *is_encroot = B_FALSE; 974eda14cbcSMatt Macy if (buf != NULL) 975eda14cbcSMatt Macy buf[0] = '\0'; 976eda14cbcSMatt Macy return (0); 977eda14cbcSMatt Macy } 978eda14cbcSMatt Macy 979eda14cbcSMatt Macy ret = zfs_prop_get(zhp, ZFS_PROP_ENCRYPTION_ROOT, prop_encroot, 980eda14cbcSMatt Macy sizeof (prop_encroot), NULL, NULL, 0, B_TRUE); 981eda14cbcSMatt Macy if (ret != 0) { 982eda14cbcSMatt Macy *is_encroot = B_FALSE; 983eda14cbcSMatt Macy if (buf != NULL) 984eda14cbcSMatt Macy buf[0] = '\0'; 985eda14cbcSMatt Macy return (ret); 986eda14cbcSMatt Macy } 987eda14cbcSMatt Macy 988eda14cbcSMatt Macy *is_encroot = strcmp(prop_encroot, zfs_get_name(zhp)) == 0; 989eda14cbcSMatt Macy if (buf != NULL) 990eda14cbcSMatt Macy strcpy(buf, prop_encroot); 991eda14cbcSMatt Macy 992eda14cbcSMatt Macy return (0); 993eda14cbcSMatt Macy } 994eda14cbcSMatt Macy 995eda14cbcSMatt Macy int 996eda14cbcSMatt Macy zfs_crypto_create(libzfs_handle_t *hdl, char *parent_name, nvlist_t *props, 997eda14cbcSMatt Macy nvlist_t *pool_props, boolean_t stdin_available, uint8_t **wkeydata_out, 998eda14cbcSMatt Macy uint_t *wkeylen_out) 999eda14cbcSMatt Macy { 1000eda14cbcSMatt Macy int ret; 1001eda14cbcSMatt Macy char errbuf[1024]; 1002eda14cbcSMatt Macy uint64_t crypt = ZIO_CRYPT_INHERIT, pcrypt = ZIO_CRYPT_INHERIT; 1003eda14cbcSMatt Macy uint64_t keyformat = ZFS_KEYFORMAT_NONE; 1004eda14cbcSMatt Macy char *keylocation = NULL; 1005eda14cbcSMatt Macy zfs_handle_t *pzhp = NULL; 1006eda14cbcSMatt Macy uint8_t *wkeydata = NULL; 1007eda14cbcSMatt Macy uint_t wkeylen = 0; 1008eda14cbcSMatt Macy boolean_t local_crypt = B_TRUE; 1009eda14cbcSMatt Macy 1010eda14cbcSMatt Macy (void) snprintf(errbuf, sizeof (errbuf), 1011eda14cbcSMatt Macy dgettext(TEXT_DOMAIN, "Encryption create error")); 1012eda14cbcSMatt Macy 1013eda14cbcSMatt Macy /* lookup crypt from props */ 1014eda14cbcSMatt Macy ret = nvlist_lookup_uint64(props, 1015eda14cbcSMatt Macy zfs_prop_to_name(ZFS_PROP_ENCRYPTION), &crypt); 1016eda14cbcSMatt Macy if (ret != 0) 1017eda14cbcSMatt Macy local_crypt = B_FALSE; 1018eda14cbcSMatt Macy 1019eda14cbcSMatt Macy /* lookup key location and format from props */ 1020eda14cbcSMatt Macy (void) nvlist_lookup_uint64(props, 1021eda14cbcSMatt Macy zfs_prop_to_name(ZFS_PROP_KEYFORMAT), &keyformat); 1022eda14cbcSMatt Macy (void) nvlist_lookup_string(props, 1023eda14cbcSMatt Macy zfs_prop_to_name(ZFS_PROP_KEYLOCATION), &keylocation); 1024eda14cbcSMatt Macy 1025eda14cbcSMatt Macy if (parent_name != NULL) { 1026eda14cbcSMatt Macy /* get a reference to parent dataset */ 1027eda14cbcSMatt Macy pzhp = make_dataset_handle(hdl, parent_name); 1028eda14cbcSMatt Macy if (pzhp == NULL) { 1029eda14cbcSMatt Macy ret = ENOENT; 1030eda14cbcSMatt Macy zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1031eda14cbcSMatt Macy "Failed to lookup parent.")); 1032eda14cbcSMatt Macy goto out; 1033eda14cbcSMatt Macy } 1034eda14cbcSMatt Macy 1035eda14cbcSMatt Macy /* Lookup parent's crypt */ 1036eda14cbcSMatt Macy pcrypt = zfs_prop_get_int(pzhp, ZFS_PROP_ENCRYPTION); 1037eda14cbcSMatt Macy 1038eda14cbcSMatt Macy /* Params require the encryption feature */ 1039eda14cbcSMatt Macy if (!encryption_feature_is_enabled(pzhp->zpool_hdl)) { 1040eda14cbcSMatt Macy if (proplist_has_encryption_props(props)) { 1041eda14cbcSMatt Macy ret = EINVAL; 1042eda14cbcSMatt Macy zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1043eda14cbcSMatt Macy "Encryption feature not enabled.")); 1044eda14cbcSMatt Macy goto out; 1045eda14cbcSMatt Macy } 1046eda14cbcSMatt Macy 1047eda14cbcSMatt Macy ret = 0; 1048eda14cbcSMatt Macy goto out; 1049eda14cbcSMatt Macy } 1050eda14cbcSMatt Macy } else { 1051eda14cbcSMatt Macy /* 1052eda14cbcSMatt Macy * special case for root dataset where encryption feature 1053eda14cbcSMatt Macy * feature won't be on disk yet 1054eda14cbcSMatt Macy */ 1055eda14cbcSMatt Macy if (!nvlist_exists(pool_props, "feature@encryption")) { 1056eda14cbcSMatt Macy if (proplist_has_encryption_props(props)) { 1057eda14cbcSMatt Macy ret = EINVAL; 1058eda14cbcSMatt Macy zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1059eda14cbcSMatt Macy "Encryption feature not enabled.")); 1060eda14cbcSMatt Macy goto out; 1061eda14cbcSMatt Macy } 1062eda14cbcSMatt Macy 1063eda14cbcSMatt Macy ret = 0; 1064eda14cbcSMatt Macy goto out; 1065eda14cbcSMatt Macy } 1066eda14cbcSMatt Macy 1067eda14cbcSMatt Macy pcrypt = ZIO_CRYPT_OFF; 1068eda14cbcSMatt Macy } 1069eda14cbcSMatt Macy 1070eda14cbcSMatt Macy /* Get the inherited encryption property if we don't have it locally */ 1071eda14cbcSMatt Macy if (!local_crypt) 1072eda14cbcSMatt Macy crypt = pcrypt; 1073eda14cbcSMatt Macy 1074eda14cbcSMatt Macy /* 1075eda14cbcSMatt Macy * At this point crypt should be the actual encryption value. If 1076eda14cbcSMatt Macy * encryption is off just verify that no encryption properties have 1077eda14cbcSMatt Macy * been specified and return. 1078eda14cbcSMatt Macy */ 1079eda14cbcSMatt Macy if (crypt == ZIO_CRYPT_OFF) { 1080eda14cbcSMatt Macy if (proplist_has_encryption_props(props)) { 1081eda14cbcSMatt Macy ret = EINVAL; 1082eda14cbcSMatt Macy zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1083eda14cbcSMatt Macy "Encryption must be turned on to set encryption " 1084eda14cbcSMatt Macy "properties.")); 1085eda14cbcSMatt Macy goto out; 1086eda14cbcSMatt Macy } 1087eda14cbcSMatt Macy 1088eda14cbcSMatt Macy ret = 0; 1089eda14cbcSMatt Macy goto out; 1090eda14cbcSMatt Macy } 1091eda14cbcSMatt Macy 1092eda14cbcSMatt Macy /* 1093eda14cbcSMatt Macy * If we have a parent crypt it is valid to specify encryption alone. 1094eda14cbcSMatt Macy * This will result in a child that is encrypted with the chosen 1095eda14cbcSMatt Macy * encryption suite that will also inherit the parent's key. If 1096eda14cbcSMatt Macy * the parent is not encrypted we need an encryption suite provided. 1097eda14cbcSMatt Macy */ 1098eda14cbcSMatt Macy if (pcrypt == ZIO_CRYPT_OFF && keylocation == NULL && 1099eda14cbcSMatt Macy keyformat == ZFS_KEYFORMAT_NONE) { 1100eda14cbcSMatt Macy ret = EINVAL; 1101eda14cbcSMatt Macy zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1102eda14cbcSMatt Macy "Keyformat required for new encryption root.")); 1103eda14cbcSMatt Macy goto out; 1104eda14cbcSMatt Macy } 1105eda14cbcSMatt Macy 1106eda14cbcSMatt Macy /* 1107eda14cbcSMatt Macy * Specifying a keylocation implies this will be a new encryption root. 1108eda14cbcSMatt Macy * Check that a keyformat is also specified. 1109eda14cbcSMatt Macy */ 1110eda14cbcSMatt Macy if (keylocation != NULL && keyformat == ZFS_KEYFORMAT_NONE) { 1111eda14cbcSMatt Macy ret = EINVAL; 1112eda14cbcSMatt Macy zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1113eda14cbcSMatt Macy "Keyformat required for new encryption root.")); 1114eda14cbcSMatt Macy goto out; 1115eda14cbcSMatt Macy } 1116eda14cbcSMatt Macy 1117eda14cbcSMatt Macy /* default to prompt if no keylocation is specified */ 1118eda14cbcSMatt Macy if (keyformat != ZFS_KEYFORMAT_NONE && keylocation == NULL) { 1119eda14cbcSMatt Macy keylocation = "prompt"; 1120eda14cbcSMatt Macy ret = nvlist_add_string(props, 1121eda14cbcSMatt Macy zfs_prop_to_name(ZFS_PROP_KEYLOCATION), keylocation); 1122eda14cbcSMatt Macy if (ret != 0) 1123eda14cbcSMatt Macy goto out; 1124eda14cbcSMatt Macy } 1125eda14cbcSMatt Macy 1126eda14cbcSMatt Macy /* 1127eda14cbcSMatt Macy * If a local key is provided, this dataset will be a new 1128eda14cbcSMatt Macy * encryption root. Populate the encryption params. 1129eda14cbcSMatt Macy */ 1130eda14cbcSMatt Macy if (keylocation != NULL) { 1131eda14cbcSMatt Macy /* 1132eda14cbcSMatt Macy * 'zfs recv -o keylocation=prompt' won't work because stdin 1133eda14cbcSMatt Macy * is being used by the send stream, so we disallow it. 1134eda14cbcSMatt Macy */ 1135eda14cbcSMatt Macy if (!stdin_available && strcmp(keylocation, "prompt") == 0) { 1136eda14cbcSMatt Macy ret = EINVAL; 1137eda14cbcSMatt Macy zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "Cannot use " 1138eda14cbcSMatt Macy "'prompt' keylocation because stdin is in use.")); 1139eda14cbcSMatt Macy goto out; 1140eda14cbcSMatt Macy } 1141eda14cbcSMatt Macy 1142eda14cbcSMatt Macy ret = populate_create_encryption_params_nvlists(hdl, NULL, 114316038816SMartin Matuska B_TRUE, keyformat, keylocation, props, &wkeydata, 1144eda14cbcSMatt Macy &wkeylen); 1145eda14cbcSMatt Macy if (ret != 0) 1146eda14cbcSMatt Macy goto out; 1147eda14cbcSMatt Macy } 1148eda14cbcSMatt Macy 1149eda14cbcSMatt Macy if (pzhp != NULL) 1150eda14cbcSMatt Macy zfs_close(pzhp); 1151eda14cbcSMatt Macy 1152eda14cbcSMatt Macy *wkeydata_out = wkeydata; 1153eda14cbcSMatt Macy *wkeylen_out = wkeylen; 1154eda14cbcSMatt Macy return (0); 1155eda14cbcSMatt Macy 1156eda14cbcSMatt Macy out: 1157eda14cbcSMatt Macy if (pzhp != NULL) 1158eda14cbcSMatt Macy zfs_close(pzhp); 1159eda14cbcSMatt Macy if (wkeydata != NULL) 1160eda14cbcSMatt Macy free(wkeydata); 1161eda14cbcSMatt Macy 1162eda14cbcSMatt Macy *wkeydata_out = NULL; 1163eda14cbcSMatt Macy *wkeylen_out = 0; 1164eda14cbcSMatt Macy return (ret); 1165eda14cbcSMatt Macy } 1166eda14cbcSMatt Macy 1167eda14cbcSMatt Macy int 1168eda14cbcSMatt Macy zfs_crypto_clone_check(libzfs_handle_t *hdl, zfs_handle_t *origin_zhp, 1169eda14cbcSMatt Macy char *parent_name, nvlist_t *props) 1170eda14cbcSMatt Macy { 1171eda14cbcSMatt Macy char errbuf[1024]; 1172eda14cbcSMatt Macy 1173eda14cbcSMatt Macy (void) snprintf(errbuf, sizeof (errbuf), 1174eda14cbcSMatt Macy dgettext(TEXT_DOMAIN, "Encryption clone error")); 1175eda14cbcSMatt Macy 1176eda14cbcSMatt Macy /* 1177eda14cbcSMatt Macy * No encryption properties should be specified. They will all be 1178eda14cbcSMatt Macy * inherited from the origin dataset. 1179eda14cbcSMatt Macy */ 1180eda14cbcSMatt Macy if (nvlist_exists(props, zfs_prop_to_name(ZFS_PROP_KEYFORMAT)) || 1181eda14cbcSMatt Macy nvlist_exists(props, zfs_prop_to_name(ZFS_PROP_KEYLOCATION)) || 1182eda14cbcSMatt Macy nvlist_exists(props, zfs_prop_to_name(ZFS_PROP_ENCRYPTION)) || 1183eda14cbcSMatt Macy nvlist_exists(props, zfs_prop_to_name(ZFS_PROP_PBKDF2_ITERS))) { 1184eda14cbcSMatt Macy zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, 1185eda14cbcSMatt Macy "Encryption properties must inherit from origin dataset.")); 1186eda14cbcSMatt Macy return (EINVAL); 1187eda14cbcSMatt Macy } 1188eda14cbcSMatt Macy 1189eda14cbcSMatt Macy return (0); 1190eda14cbcSMatt Macy } 1191eda14cbcSMatt Macy 1192eda14cbcSMatt Macy typedef struct loadkeys_cbdata { 1193eda14cbcSMatt Macy uint64_t cb_numfailed; 1194eda14cbcSMatt Macy uint64_t cb_numattempted; 1195eda14cbcSMatt Macy } loadkey_cbdata_t; 1196eda14cbcSMatt Macy 1197eda14cbcSMatt Macy static int 1198eda14cbcSMatt Macy load_keys_cb(zfs_handle_t *zhp, void *arg) 1199eda14cbcSMatt Macy { 1200eda14cbcSMatt Macy int ret; 1201eda14cbcSMatt Macy boolean_t is_encroot; 1202eda14cbcSMatt Macy loadkey_cbdata_t *cb = arg; 1203eda14cbcSMatt Macy uint64_t keystatus = zfs_prop_get_int(zhp, ZFS_PROP_KEYSTATUS); 1204eda14cbcSMatt Macy 1205eda14cbcSMatt Macy /* only attempt to load keys for encryption roots */ 1206eda14cbcSMatt Macy ret = zfs_crypto_get_encryption_root(zhp, &is_encroot, NULL); 1207eda14cbcSMatt Macy if (ret != 0 || !is_encroot) 1208eda14cbcSMatt Macy goto out; 1209eda14cbcSMatt Macy 1210eda14cbcSMatt Macy /* don't attempt to load already loaded keys */ 1211eda14cbcSMatt Macy if (keystatus == ZFS_KEYSTATUS_AVAILABLE) 1212eda14cbcSMatt Macy goto out; 1213eda14cbcSMatt Macy 1214eda14cbcSMatt Macy /* Attempt to load the key. Record status in cb. */ 1215eda14cbcSMatt Macy cb->cb_numattempted++; 1216eda14cbcSMatt Macy 1217eda14cbcSMatt Macy ret = zfs_crypto_load_key(zhp, B_FALSE, NULL); 1218eda14cbcSMatt Macy if (ret) 1219eda14cbcSMatt Macy cb->cb_numfailed++; 1220eda14cbcSMatt Macy 1221eda14cbcSMatt Macy out: 1222eda14cbcSMatt Macy (void) zfs_iter_filesystems(zhp, load_keys_cb, cb); 1223eda14cbcSMatt Macy zfs_close(zhp); 1224eda14cbcSMatt Macy 1225eda14cbcSMatt Macy /* always return 0, since this function is best effort */ 1226eda14cbcSMatt Macy return (0); 1227eda14cbcSMatt Macy } 1228eda14cbcSMatt Macy 1229eda14cbcSMatt Macy /* 1230eda14cbcSMatt Macy * This function is best effort. It attempts to load all the keys for the given 1231eda14cbcSMatt Macy * filesystem and all of its children. 1232eda14cbcSMatt Macy */ 1233eda14cbcSMatt Macy int 1234eda14cbcSMatt Macy zfs_crypto_attempt_load_keys(libzfs_handle_t *hdl, char *fsname) 1235eda14cbcSMatt Macy { 1236eda14cbcSMatt Macy int ret; 1237eda14cbcSMatt Macy zfs_handle_t *zhp = NULL; 1238eda14cbcSMatt Macy loadkey_cbdata_t cb = { 0 }; 1239eda14cbcSMatt Macy 1240eda14cbcSMatt Macy zhp = zfs_open(hdl, fsname, ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME); 1241eda14cbcSMatt Macy if (zhp == NULL) { 1242eda14cbcSMatt Macy ret = ENOENT; 1243eda14cbcSMatt Macy goto error; 1244eda14cbcSMatt Macy } 1245eda14cbcSMatt Macy 1246eda14cbcSMatt Macy ret = load_keys_cb(zfs_handle_dup(zhp), &cb); 1247eda14cbcSMatt Macy if (ret) 1248eda14cbcSMatt Macy goto error; 1249eda14cbcSMatt Macy 1250eda14cbcSMatt Macy (void) printf(gettext("%llu / %llu keys successfully loaded\n"), 1251eda14cbcSMatt Macy (u_longlong_t)(cb.cb_numattempted - cb.cb_numfailed), 1252eda14cbcSMatt Macy (u_longlong_t)cb.cb_numattempted); 1253eda14cbcSMatt Macy 1254eda14cbcSMatt Macy if (cb.cb_numfailed != 0) { 1255eda14cbcSMatt Macy ret = -1; 1256eda14cbcSMatt Macy goto error; 1257eda14cbcSMatt Macy } 1258eda14cbcSMatt Macy 1259eda14cbcSMatt Macy zfs_close(zhp); 1260eda14cbcSMatt Macy return (0); 1261eda14cbcSMatt Macy 1262eda14cbcSMatt Macy error: 1263eda14cbcSMatt Macy if (zhp != NULL) 1264eda14cbcSMatt Macy zfs_close(zhp); 1265eda14cbcSMatt Macy return (ret); 1266eda14cbcSMatt Macy } 1267eda14cbcSMatt Macy 1268eda14cbcSMatt Macy int 1269eda14cbcSMatt Macy zfs_crypto_load_key(zfs_handle_t *zhp, boolean_t noop, char *alt_keylocation) 1270eda14cbcSMatt Macy { 1271eda14cbcSMatt Macy int ret, attempts = 0; 1272eda14cbcSMatt Macy char errbuf[1024]; 1273eda14cbcSMatt Macy uint64_t keystatus, iters = 0, salt = 0; 1274eda14cbcSMatt Macy uint64_t keyformat = ZFS_KEYFORMAT_NONE; 1275eda14cbcSMatt Macy char prop_keylocation[MAXNAMELEN]; 1276eda14cbcSMatt Macy char prop_encroot[MAXNAMELEN]; 1277eda14cbcSMatt Macy char *keylocation = NULL; 1278eda14cbcSMatt Macy uint8_t *key_material = NULL, *key_data = NULL; 1279eda14cbcSMatt Macy size_t key_material_len; 1280eda14cbcSMatt Macy boolean_t is_encroot, can_retry = B_FALSE, correctible = B_FALSE; 1281eda14cbcSMatt Macy 1282eda14cbcSMatt Macy (void) snprintf(errbuf, sizeof (errbuf), 1283eda14cbcSMatt Macy dgettext(TEXT_DOMAIN, "Key load error")); 1284eda14cbcSMatt Macy 1285eda14cbcSMatt Macy /* check that encryption is enabled for the pool */ 1286eda14cbcSMatt Macy if (!encryption_feature_is_enabled(zhp->zpool_hdl)) { 1287eda14cbcSMatt Macy zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 1288eda14cbcSMatt Macy "Encryption feature not enabled.")); 1289eda14cbcSMatt Macy ret = EINVAL; 1290eda14cbcSMatt Macy goto error; 1291eda14cbcSMatt Macy } 1292eda14cbcSMatt Macy 1293eda14cbcSMatt Macy /* Fetch the keyformat. Check that the dataset is encrypted. */ 1294eda14cbcSMatt Macy keyformat = zfs_prop_get_int(zhp, ZFS_PROP_KEYFORMAT); 1295eda14cbcSMatt Macy if (keyformat == ZFS_KEYFORMAT_NONE) { 1296eda14cbcSMatt Macy zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 1297eda14cbcSMatt Macy "'%s' is not encrypted."), zfs_get_name(zhp)); 1298eda14cbcSMatt Macy ret = EINVAL; 1299eda14cbcSMatt Macy goto error; 1300eda14cbcSMatt Macy } 1301eda14cbcSMatt Macy 1302eda14cbcSMatt Macy /* 1303eda14cbcSMatt Macy * Fetch the key location. Check that we are working with an 1304eda14cbcSMatt Macy * encryption root. 1305eda14cbcSMatt Macy */ 1306eda14cbcSMatt Macy ret = zfs_crypto_get_encryption_root(zhp, &is_encroot, prop_encroot); 1307eda14cbcSMatt Macy if (ret != 0) { 1308eda14cbcSMatt Macy zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 1309eda14cbcSMatt Macy "Failed to get encryption root for '%s'."), 1310eda14cbcSMatt Macy zfs_get_name(zhp)); 1311eda14cbcSMatt Macy goto error; 1312eda14cbcSMatt Macy } else if (!is_encroot) { 1313eda14cbcSMatt Macy zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 1314eda14cbcSMatt Macy "Keys must be loaded for encryption root of '%s' (%s)."), 1315eda14cbcSMatt Macy zfs_get_name(zhp), prop_encroot); 1316eda14cbcSMatt Macy ret = EINVAL; 1317eda14cbcSMatt Macy goto error; 1318eda14cbcSMatt Macy } 1319eda14cbcSMatt Macy 1320eda14cbcSMatt Macy /* 1321eda14cbcSMatt Macy * if the caller has elected to override the keylocation property 1322eda14cbcSMatt Macy * use that instead 1323eda14cbcSMatt Macy */ 1324eda14cbcSMatt Macy if (alt_keylocation != NULL) { 1325eda14cbcSMatt Macy keylocation = alt_keylocation; 1326eda14cbcSMatt Macy } else { 1327eda14cbcSMatt Macy ret = zfs_prop_get(zhp, ZFS_PROP_KEYLOCATION, prop_keylocation, 1328eda14cbcSMatt Macy sizeof (prop_keylocation), NULL, NULL, 0, B_TRUE); 1329eda14cbcSMatt Macy if (ret != 0) { 1330eda14cbcSMatt Macy zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 1331eda14cbcSMatt Macy "Failed to get keylocation for '%s'."), 1332eda14cbcSMatt Macy zfs_get_name(zhp)); 1333eda14cbcSMatt Macy goto error; 1334eda14cbcSMatt Macy } 1335eda14cbcSMatt Macy 1336eda14cbcSMatt Macy keylocation = prop_keylocation; 1337eda14cbcSMatt Macy } 1338eda14cbcSMatt Macy 1339eda14cbcSMatt Macy /* check that the key is unloaded unless this is a noop */ 1340eda14cbcSMatt Macy if (!noop) { 1341eda14cbcSMatt Macy keystatus = zfs_prop_get_int(zhp, ZFS_PROP_KEYSTATUS); 1342eda14cbcSMatt Macy if (keystatus == ZFS_KEYSTATUS_AVAILABLE) { 1343eda14cbcSMatt Macy zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 1344eda14cbcSMatt Macy "Key already loaded for '%s'."), zfs_get_name(zhp)); 1345eda14cbcSMatt Macy ret = EEXIST; 1346eda14cbcSMatt Macy goto error; 1347eda14cbcSMatt Macy } 1348eda14cbcSMatt Macy } 1349eda14cbcSMatt Macy 1350eda14cbcSMatt Macy /* passphrase formats require a salt and pbkdf2_iters property */ 1351eda14cbcSMatt Macy if (keyformat == ZFS_KEYFORMAT_PASSPHRASE) { 1352eda14cbcSMatt Macy salt = zfs_prop_get_int(zhp, ZFS_PROP_PBKDF2_SALT); 1353eda14cbcSMatt Macy iters = zfs_prop_get_int(zhp, ZFS_PROP_PBKDF2_ITERS); 1354eda14cbcSMatt Macy } 1355eda14cbcSMatt Macy 1356eda14cbcSMatt Macy try_again: 1357eda14cbcSMatt Macy /* fetching and deriving the key are correctable errors. set the flag */ 1358eda14cbcSMatt Macy correctible = B_TRUE; 1359eda14cbcSMatt Macy 1360eda14cbcSMatt Macy /* get key material from key format and location */ 1361eda14cbcSMatt Macy ret = get_key_material(zhp->zfs_hdl, B_FALSE, B_FALSE, keyformat, 1362eda14cbcSMatt Macy keylocation, zfs_get_name(zhp), &key_material, &key_material_len, 1363eda14cbcSMatt Macy &can_retry); 1364eda14cbcSMatt Macy if (ret != 0) 1365eda14cbcSMatt Macy goto error; 1366eda14cbcSMatt Macy 1367eda14cbcSMatt Macy /* derive a key from the key material */ 1368eda14cbcSMatt Macy ret = derive_key(zhp->zfs_hdl, keyformat, iters, key_material, 1369eda14cbcSMatt Macy key_material_len, salt, &key_data); 1370eda14cbcSMatt Macy if (ret != 0) 1371eda14cbcSMatt Macy goto error; 1372eda14cbcSMatt Macy 1373eda14cbcSMatt Macy correctible = B_FALSE; 1374eda14cbcSMatt Macy 1375eda14cbcSMatt Macy /* pass the wrapping key and noop flag to the ioctl */ 1376eda14cbcSMatt Macy ret = lzc_load_key(zhp->zfs_name, noop, key_data, WRAPPING_KEY_LEN); 1377eda14cbcSMatt Macy if (ret != 0) { 1378eda14cbcSMatt Macy switch (ret) { 1379eda14cbcSMatt Macy case EPERM: 1380eda14cbcSMatt Macy zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 1381eda14cbcSMatt Macy "Permission denied.")); 1382eda14cbcSMatt Macy break; 1383eda14cbcSMatt Macy case EINVAL: 1384eda14cbcSMatt Macy zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 1385eda14cbcSMatt Macy "Invalid parameters provided for dataset %s."), 1386eda14cbcSMatt Macy zfs_get_name(zhp)); 1387eda14cbcSMatt Macy break; 1388eda14cbcSMatt Macy case EEXIST: 1389eda14cbcSMatt Macy zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 1390eda14cbcSMatt Macy "Key already loaded for '%s'."), zfs_get_name(zhp)); 1391eda14cbcSMatt Macy break; 1392eda14cbcSMatt Macy case EBUSY: 1393eda14cbcSMatt Macy zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 1394eda14cbcSMatt Macy "'%s' is busy."), zfs_get_name(zhp)); 1395eda14cbcSMatt Macy break; 1396eda14cbcSMatt Macy case EACCES: 1397eda14cbcSMatt Macy correctible = B_TRUE; 1398eda14cbcSMatt Macy zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 1399eda14cbcSMatt Macy "Incorrect key provided for '%s'."), 1400eda14cbcSMatt Macy zfs_get_name(zhp)); 1401eda14cbcSMatt Macy break; 1402eda14cbcSMatt Macy } 1403eda14cbcSMatt Macy goto error; 1404eda14cbcSMatt Macy } 1405eda14cbcSMatt Macy 1406eda14cbcSMatt Macy free(key_material); 1407eda14cbcSMatt Macy free(key_data); 1408eda14cbcSMatt Macy 1409eda14cbcSMatt Macy return (0); 1410eda14cbcSMatt Macy 1411eda14cbcSMatt Macy error: 1412eda14cbcSMatt Macy zfs_error(zhp->zfs_hdl, EZFS_CRYPTOFAILED, errbuf); 1413eda14cbcSMatt Macy if (key_material != NULL) { 1414eda14cbcSMatt Macy free(key_material); 1415eda14cbcSMatt Macy key_material = NULL; 1416eda14cbcSMatt Macy } 1417eda14cbcSMatt Macy if (key_data != NULL) { 1418eda14cbcSMatt Macy free(key_data); 1419eda14cbcSMatt Macy key_data = NULL; 1420eda14cbcSMatt Macy } 1421eda14cbcSMatt Macy 1422eda14cbcSMatt Macy /* 1423eda14cbcSMatt Macy * Here we decide if it is ok to allow the user to retry entering their 1424eda14cbcSMatt Macy * key. The can_retry flag will be set if the user is entering their 1425eda14cbcSMatt Macy * key from an interactive prompt. The correctable flag will only be 1426eda14cbcSMatt Macy * set if an error that occurred could be corrected by retrying. Both 1427eda14cbcSMatt Macy * flags are needed to allow the user to attempt key entry again 1428eda14cbcSMatt Macy */ 1429eda14cbcSMatt Macy attempts++; 1430eda14cbcSMatt Macy if (can_retry && correctible && attempts < MAX_KEY_PROMPT_ATTEMPTS) 1431eda14cbcSMatt Macy goto try_again; 1432eda14cbcSMatt Macy 1433eda14cbcSMatt Macy return (ret); 1434eda14cbcSMatt Macy } 1435eda14cbcSMatt Macy 1436eda14cbcSMatt Macy int 1437eda14cbcSMatt Macy zfs_crypto_unload_key(zfs_handle_t *zhp) 1438eda14cbcSMatt Macy { 1439eda14cbcSMatt Macy int ret; 1440eda14cbcSMatt Macy char errbuf[1024]; 1441eda14cbcSMatt Macy char prop_encroot[MAXNAMELEN]; 1442eda14cbcSMatt Macy uint64_t keystatus, keyformat; 1443eda14cbcSMatt Macy boolean_t is_encroot; 1444eda14cbcSMatt Macy 1445eda14cbcSMatt Macy (void) snprintf(errbuf, sizeof (errbuf), 1446eda14cbcSMatt Macy dgettext(TEXT_DOMAIN, "Key unload error")); 1447eda14cbcSMatt Macy 1448eda14cbcSMatt Macy /* check that encryption is enabled for the pool */ 1449eda14cbcSMatt Macy if (!encryption_feature_is_enabled(zhp->zpool_hdl)) { 1450eda14cbcSMatt Macy zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 1451eda14cbcSMatt Macy "Encryption feature not enabled.")); 1452eda14cbcSMatt Macy ret = EINVAL; 1453eda14cbcSMatt Macy goto error; 1454eda14cbcSMatt Macy } 1455eda14cbcSMatt Macy 1456eda14cbcSMatt Macy /* Fetch the keyformat. Check that the dataset is encrypted. */ 1457eda14cbcSMatt Macy keyformat = zfs_prop_get_int(zhp, ZFS_PROP_KEYFORMAT); 1458eda14cbcSMatt Macy if (keyformat == ZFS_KEYFORMAT_NONE) { 1459eda14cbcSMatt Macy zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 1460eda14cbcSMatt Macy "'%s' is not encrypted."), zfs_get_name(zhp)); 1461eda14cbcSMatt Macy ret = EINVAL; 1462eda14cbcSMatt Macy goto error; 1463eda14cbcSMatt Macy } 1464eda14cbcSMatt Macy 1465eda14cbcSMatt Macy /* 1466eda14cbcSMatt Macy * Fetch the key location. Check that we are working with an 1467eda14cbcSMatt Macy * encryption root. 1468eda14cbcSMatt Macy */ 1469eda14cbcSMatt Macy ret = zfs_crypto_get_encryption_root(zhp, &is_encroot, prop_encroot); 1470eda14cbcSMatt Macy if (ret != 0) { 1471eda14cbcSMatt Macy zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 1472eda14cbcSMatt Macy "Failed to get encryption root for '%s'."), 1473eda14cbcSMatt Macy zfs_get_name(zhp)); 1474eda14cbcSMatt Macy goto error; 1475eda14cbcSMatt Macy } else if (!is_encroot) { 1476eda14cbcSMatt Macy zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 1477eda14cbcSMatt Macy "Keys must be unloaded for encryption root of '%s' (%s)."), 1478eda14cbcSMatt Macy zfs_get_name(zhp), prop_encroot); 1479eda14cbcSMatt Macy ret = EINVAL; 1480eda14cbcSMatt Macy goto error; 1481eda14cbcSMatt Macy } 1482eda14cbcSMatt Macy 1483eda14cbcSMatt Macy /* check that the key is loaded */ 1484eda14cbcSMatt Macy keystatus = zfs_prop_get_int(zhp, ZFS_PROP_KEYSTATUS); 1485eda14cbcSMatt Macy if (keystatus == ZFS_KEYSTATUS_UNAVAILABLE) { 1486eda14cbcSMatt Macy zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 1487eda14cbcSMatt Macy "Key already unloaded for '%s'."), zfs_get_name(zhp)); 1488eda14cbcSMatt Macy ret = EACCES; 1489eda14cbcSMatt Macy goto error; 1490eda14cbcSMatt Macy } 1491eda14cbcSMatt Macy 1492eda14cbcSMatt Macy /* call the ioctl */ 1493eda14cbcSMatt Macy ret = lzc_unload_key(zhp->zfs_name); 1494eda14cbcSMatt Macy 1495eda14cbcSMatt Macy if (ret != 0) { 1496eda14cbcSMatt Macy switch (ret) { 1497eda14cbcSMatt Macy case EPERM: 1498eda14cbcSMatt Macy zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 1499eda14cbcSMatt Macy "Permission denied.")); 1500eda14cbcSMatt Macy break; 1501eda14cbcSMatt Macy case EACCES: 1502eda14cbcSMatt Macy zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 1503eda14cbcSMatt Macy "Key already unloaded for '%s'."), 1504eda14cbcSMatt Macy zfs_get_name(zhp)); 1505eda14cbcSMatt Macy break; 1506eda14cbcSMatt Macy case EBUSY: 1507eda14cbcSMatt Macy zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 1508eda14cbcSMatt Macy "'%s' is busy."), zfs_get_name(zhp)); 1509eda14cbcSMatt Macy break; 1510eda14cbcSMatt Macy } 1511eda14cbcSMatt Macy zfs_error(zhp->zfs_hdl, EZFS_CRYPTOFAILED, errbuf); 1512eda14cbcSMatt Macy } 1513eda14cbcSMatt Macy 1514eda14cbcSMatt Macy return (ret); 1515eda14cbcSMatt Macy 1516eda14cbcSMatt Macy error: 1517eda14cbcSMatt Macy zfs_error(zhp->zfs_hdl, EZFS_CRYPTOFAILED, errbuf); 1518eda14cbcSMatt Macy return (ret); 1519eda14cbcSMatt Macy } 1520eda14cbcSMatt Macy 1521eda14cbcSMatt Macy static int 1522eda14cbcSMatt Macy zfs_crypto_verify_rewrap_nvlist(zfs_handle_t *zhp, nvlist_t *props, 1523eda14cbcSMatt Macy nvlist_t **props_out, char *errbuf) 1524eda14cbcSMatt Macy { 1525eda14cbcSMatt Macy int ret; 1526eda14cbcSMatt Macy nvpair_t *elem = NULL; 1527eda14cbcSMatt Macy zfs_prop_t prop; 1528eda14cbcSMatt Macy nvlist_t *new_props = NULL; 1529eda14cbcSMatt Macy 1530eda14cbcSMatt Macy new_props = fnvlist_alloc(); 1531eda14cbcSMatt Macy 1532eda14cbcSMatt Macy /* 1533eda14cbcSMatt Macy * loop through all provided properties, we should only have 1534eda14cbcSMatt Macy * keyformat, keylocation and pbkdf2iters. The actual validation of 1535eda14cbcSMatt Macy * values is done by zfs_valid_proplist(). 1536eda14cbcSMatt Macy */ 1537eda14cbcSMatt Macy while ((elem = nvlist_next_nvpair(props, elem)) != NULL) { 1538eda14cbcSMatt Macy const char *propname = nvpair_name(elem); 1539eda14cbcSMatt Macy prop = zfs_name_to_prop(propname); 1540eda14cbcSMatt Macy 1541eda14cbcSMatt Macy switch (prop) { 1542eda14cbcSMatt Macy case ZFS_PROP_PBKDF2_ITERS: 1543eda14cbcSMatt Macy case ZFS_PROP_KEYFORMAT: 1544eda14cbcSMatt Macy case ZFS_PROP_KEYLOCATION: 1545eda14cbcSMatt Macy break; 1546eda14cbcSMatt Macy default: 1547eda14cbcSMatt Macy ret = EINVAL; 1548eda14cbcSMatt Macy zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 1549eda14cbcSMatt Macy "Only keyformat, keylocation and pbkdf2iters may " 1550eda14cbcSMatt Macy "be set with this command.")); 1551eda14cbcSMatt Macy goto error; 1552eda14cbcSMatt Macy } 1553eda14cbcSMatt Macy } 1554eda14cbcSMatt Macy 1555eda14cbcSMatt Macy new_props = zfs_valid_proplist(zhp->zfs_hdl, zhp->zfs_type, props, 1556eda14cbcSMatt Macy zfs_prop_get_int(zhp, ZFS_PROP_ZONED), NULL, zhp->zpool_hdl, 1557eda14cbcSMatt Macy B_TRUE, errbuf); 1558eda14cbcSMatt Macy if (new_props == NULL) { 1559eda14cbcSMatt Macy ret = EINVAL; 1560eda14cbcSMatt Macy goto error; 1561eda14cbcSMatt Macy } 1562eda14cbcSMatt Macy 1563eda14cbcSMatt Macy *props_out = new_props; 1564eda14cbcSMatt Macy return (0); 1565eda14cbcSMatt Macy 1566eda14cbcSMatt Macy error: 1567eda14cbcSMatt Macy nvlist_free(new_props); 1568eda14cbcSMatt Macy *props_out = NULL; 1569eda14cbcSMatt Macy return (ret); 1570eda14cbcSMatt Macy } 1571eda14cbcSMatt Macy 1572eda14cbcSMatt Macy int 1573eda14cbcSMatt Macy zfs_crypto_rewrap(zfs_handle_t *zhp, nvlist_t *raw_props, boolean_t inheritkey) 1574eda14cbcSMatt Macy { 1575eda14cbcSMatt Macy int ret; 1576eda14cbcSMatt Macy char errbuf[1024]; 1577eda14cbcSMatt Macy boolean_t is_encroot; 1578eda14cbcSMatt Macy nvlist_t *props = NULL; 1579eda14cbcSMatt Macy uint8_t *wkeydata = NULL; 1580eda14cbcSMatt Macy uint_t wkeylen = 0; 1581eda14cbcSMatt Macy dcp_cmd_t cmd = (inheritkey) ? DCP_CMD_INHERIT : DCP_CMD_NEW_KEY; 1582eda14cbcSMatt Macy uint64_t crypt, pcrypt, keystatus, pkeystatus; 1583eda14cbcSMatt Macy uint64_t keyformat = ZFS_KEYFORMAT_NONE; 1584eda14cbcSMatt Macy zfs_handle_t *pzhp = NULL; 1585eda14cbcSMatt Macy char *keylocation = NULL; 1586eda14cbcSMatt Macy char origin_name[MAXNAMELEN]; 1587eda14cbcSMatt Macy char prop_keylocation[MAXNAMELEN]; 1588eda14cbcSMatt Macy char parent_name[ZFS_MAX_DATASET_NAME_LEN]; 1589eda14cbcSMatt Macy 1590eda14cbcSMatt Macy (void) snprintf(errbuf, sizeof (errbuf), 1591eda14cbcSMatt Macy dgettext(TEXT_DOMAIN, "Key change error")); 1592eda14cbcSMatt Macy 1593eda14cbcSMatt Macy /* check that encryption is enabled for the pool */ 1594eda14cbcSMatt Macy if (!encryption_feature_is_enabled(zhp->zpool_hdl)) { 1595eda14cbcSMatt Macy zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 1596eda14cbcSMatt Macy "Encryption feature not enabled.")); 1597eda14cbcSMatt Macy ret = EINVAL; 1598eda14cbcSMatt Macy goto error; 1599eda14cbcSMatt Macy } 1600eda14cbcSMatt Macy 1601eda14cbcSMatt Macy /* get crypt from dataset */ 1602eda14cbcSMatt Macy crypt = zfs_prop_get_int(zhp, ZFS_PROP_ENCRYPTION); 1603eda14cbcSMatt Macy if (crypt == ZIO_CRYPT_OFF) { 1604eda14cbcSMatt Macy zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 1605eda14cbcSMatt Macy "Dataset not encrypted.")); 1606eda14cbcSMatt Macy ret = EINVAL; 1607eda14cbcSMatt Macy goto error; 1608eda14cbcSMatt Macy } 1609eda14cbcSMatt Macy 1610eda14cbcSMatt Macy /* get the encryption root of the dataset */ 1611eda14cbcSMatt Macy ret = zfs_crypto_get_encryption_root(zhp, &is_encroot, NULL); 1612eda14cbcSMatt Macy if (ret != 0) { 1613eda14cbcSMatt Macy zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 1614eda14cbcSMatt Macy "Failed to get encryption root for '%s'."), 1615eda14cbcSMatt Macy zfs_get_name(zhp)); 1616eda14cbcSMatt Macy goto error; 1617eda14cbcSMatt Macy } 1618eda14cbcSMatt Macy 1619eda14cbcSMatt Macy /* Clones use their origin's key and cannot rewrap it */ 1620eda14cbcSMatt Macy ret = zfs_prop_get(zhp, ZFS_PROP_ORIGIN, origin_name, 1621eda14cbcSMatt Macy sizeof (origin_name), NULL, NULL, 0, B_TRUE); 1622eda14cbcSMatt Macy if (ret == 0 && strcmp(origin_name, "") != 0) { 1623eda14cbcSMatt Macy zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 1624eda14cbcSMatt Macy "Keys cannot be changed on clones.")); 1625eda14cbcSMatt Macy ret = EINVAL; 1626eda14cbcSMatt Macy goto error; 1627eda14cbcSMatt Macy } 1628eda14cbcSMatt Macy 1629eda14cbcSMatt Macy /* 1630eda14cbcSMatt Macy * If the user wants to use the inheritkey variant of this function 1631eda14cbcSMatt Macy * we don't need to collect any crypto arguments. 1632eda14cbcSMatt Macy */ 1633eda14cbcSMatt Macy if (!inheritkey) { 1634eda14cbcSMatt Macy /* validate the provided properties */ 1635eda14cbcSMatt Macy ret = zfs_crypto_verify_rewrap_nvlist(zhp, raw_props, &props, 1636eda14cbcSMatt Macy errbuf); 1637eda14cbcSMatt Macy if (ret != 0) 1638eda14cbcSMatt Macy goto error; 1639eda14cbcSMatt Macy 1640eda14cbcSMatt Macy /* 1641eda14cbcSMatt Macy * Load keyformat and keylocation from the nvlist. Fetch from 1642eda14cbcSMatt Macy * the dataset properties if not specified. 1643eda14cbcSMatt Macy */ 1644eda14cbcSMatt Macy (void) nvlist_lookup_uint64(props, 1645eda14cbcSMatt Macy zfs_prop_to_name(ZFS_PROP_KEYFORMAT), &keyformat); 1646eda14cbcSMatt Macy (void) nvlist_lookup_string(props, 1647eda14cbcSMatt Macy zfs_prop_to_name(ZFS_PROP_KEYLOCATION), &keylocation); 1648eda14cbcSMatt Macy 1649eda14cbcSMatt Macy if (is_encroot) { 1650eda14cbcSMatt Macy /* 1651eda14cbcSMatt Macy * If this is already an encryption root, just keep 1652eda14cbcSMatt Macy * any properties not set by the user. 1653eda14cbcSMatt Macy */ 1654eda14cbcSMatt Macy if (keyformat == ZFS_KEYFORMAT_NONE) { 1655eda14cbcSMatt Macy keyformat = zfs_prop_get_int(zhp, 1656eda14cbcSMatt Macy ZFS_PROP_KEYFORMAT); 1657eda14cbcSMatt Macy ret = nvlist_add_uint64(props, 1658eda14cbcSMatt Macy zfs_prop_to_name(ZFS_PROP_KEYFORMAT), 1659eda14cbcSMatt Macy keyformat); 1660eda14cbcSMatt Macy if (ret != 0) { 1661eda14cbcSMatt Macy zfs_error_aux(zhp->zfs_hdl, 1662eda14cbcSMatt Macy dgettext(TEXT_DOMAIN, "Failed to " 1663eda14cbcSMatt Macy "get existing keyformat " 1664eda14cbcSMatt Macy "property.")); 1665eda14cbcSMatt Macy goto error; 1666eda14cbcSMatt Macy } 1667eda14cbcSMatt Macy } 1668eda14cbcSMatt Macy 1669eda14cbcSMatt Macy if (keylocation == NULL) { 1670eda14cbcSMatt Macy ret = zfs_prop_get(zhp, ZFS_PROP_KEYLOCATION, 1671eda14cbcSMatt Macy prop_keylocation, sizeof (prop_keylocation), 1672eda14cbcSMatt Macy NULL, NULL, 0, B_TRUE); 1673eda14cbcSMatt Macy if (ret != 0) { 1674eda14cbcSMatt Macy zfs_error_aux(zhp->zfs_hdl, 1675eda14cbcSMatt Macy dgettext(TEXT_DOMAIN, "Failed to " 1676eda14cbcSMatt Macy "get existing keylocation " 1677eda14cbcSMatt Macy "property.")); 1678eda14cbcSMatt Macy goto error; 1679eda14cbcSMatt Macy } 1680eda14cbcSMatt Macy 1681eda14cbcSMatt Macy keylocation = prop_keylocation; 1682eda14cbcSMatt Macy } 1683eda14cbcSMatt Macy } else { 1684eda14cbcSMatt Macy /* need a new key for non-encryption roots */ 1685eda14cbcSMatt Macy if (keyformat == ZFS_KEYFORMAT_NONE) { 1686eda14cbcSMatt Macy ret = EINVAL; 1687eda14cbcSMatt Macy zfs_error_aux(zhp->zfs_hdl, 1688eda14cbcSMatt Macy dgettext(TEXT_DOMAIN, "Keyformat required " 1689eda14cbcSMatt Macy "for new encryption root.")); 1690eda14cbcSMatt Macy goto error; 1691eda14cbcSMatt Macy } 1692eda14cbcSMatt Macy 1693eda14cbcSMatt Macy /* default to prompt if no keylocation is specified */ 1694eda14cbcSMatt Macy if (keylocation == NULL) { 1695eda14cbcSMatt Macy keylocation = "prompt"; 1696eda14cbcSMatt Macy ret = nvlist_add_string(props, 1697eda14cbcSMatt Macy zfs_prop_to_name(ZFS_PROP_KEYLOCATION), 1698eda14cbcSMatt Macy keylocation); 1699eda14cbcSMatt Macy if (ret != 0) 1700eda14cbcSMatt Macy goto error; 1701eda14cbcSMatt Macy } 1702eda14cbcSMatt Macy } 1703eda14cbcSMatt Macy 1704eda14cbcSMatt Macy /* fetch the new wrapping key and associated properties */ 1705eda14cbcSMatt Macy ret = populate_create_encryption_params_nvlists(zhp->zfs_hdl, 1706eda14cbcSMatt Macy zhp, B_TRUE, keyformat, keylocation, props, &wkeydata, 1707eda14cbcSMatt Macy &wkeylen); 1708eda14cbcSMatt Macy if (ret != 0) 1709eda14cbcSMatt Macy goto error; 1710eda14cbcSMatt Macy } else { 1711eda14cbcSMatt Macy /* check that zhp is an encryption root */ 1712eda14cbcSMatt Macy if (!is_encroot) { 1713eda14cbcSMatt Macy zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 1714eda14cbcSMatt Macy "Key inheritting can only be performed on " 1715eda14cbcSMatt Macy "encryption roots.")); 1716eda14cbcSMatt Macy ret = EINVAL; 1717eda14cbcSMatt Macy goto error; 1718eda14cbcSMatt Macy } 1719eda14cbcSMatt Macy 1720eda14cbcSMatt Macy /* get the parent's name */ 1721eda14cbcSMatt Macy ret = zfs_parent_name(zhp, parent_name, sizeof (parent_name)); 1722eda14cbcSMatt Macy if (ret != 0) { 1723eda14cbcSMatt Macy zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 1724eda14cbcSMatt Macy "Root dataset cannot inherit key.")); 1725eda14cbcSMatt Macy ret = EINVAL; 1726eda14cbcSMatt Macy goto error; 1727eda14cbcSMatt Macy } 1728eda14cbcSMatt Macy 1729eda14cbcSMatt Macy /* get a handle to the parent */ 1730eda14cbcSMatt Macy pzhp = make_dataset_handle(zhp->zfs_hdl, parent_name); 1731eda14cbcSMatt Macy if (pzhp == NULL) { 1732eda14cbcSMatt Macy zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 1733eda14cbcSMatt Macy "Failed to lookup parent.")); 1734eda14cbcSMatt Macy ret = ENOENT; 1735eda14cbcSMatt Macy goto error; 1736eda14cbcSMatt Macy } 1737eda14cbcSMatt Macy 1738eda14cbcSMatt Macy /* parent must be encrypted */ 1739eda14cbcSMatt Macy pcrypt = zfs_prop_get_int(pzhp, ZFS_PROP_ENCRYPTION); 1740eda14cbcSMatt Macy if (pcrypt == ZIO_CRYPT_OFF) { 1741eda14cbcSMatt Macy zfs_error_aux(pzhp->zfs_hdl, dgettext(TEXT_DOMAIN, 1742eda14cbcSMatt Macy "Parent must be encrypted.")); 1743eda14cbcSMatt Macy ret = EINVAL; 1744eda14cbcSMatt Macy goto error; 1745eda14cbcSMatt Macy } 1746eda14cbcSMatt Macy 1747eda14cbcSMatt Macy /* check that the parent's key is loaded */ 1748eda14cbcSMatt Macy pkeystatus = zfs_prop_get_int(pzhp, ZFS_PROP_KEYSTATUS); 1749eda14cbcSMatt Macy if (pkeystatus == ZFS_KEYSTATUS_UNAVAILABLE) { 1750eda14cbcSMatt Macy zfs_error_aux(pzhp->zfs_hdl, dgettext(TEXT_DOMAIN, 1751eda14cbcSMatt Macy "Parent key must be loaded.")); 1752eda14cbcSMatt Macy ret = EACCES; 1753eda14cbcSMatt Macy goto error; 1754eda14cbcSMatt Macy } 1755eda14cbcSMatt Macy } 1756eda14cbcSMatt Macy 1757eda14cbcSMatt Macy /* check that the key is loaded */ 1758eda14cbcSMatt Macy keystatus = zfs_prop_get_int(zhp, ZFS_PROP_KEYSTATUS); 1759eda14cbcSMatt Macy if (keystatus == ZFS_KEYSTATUS_UNAVAILABLE) { 1760eda14cbcSMatt Macy zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 1761eda14cbcSMatt Macy "Key must be loaded.")); 1762eda14cbcSMatt Macy ret = EACCES; 1763eda14cbcSMatt Macy goto error; 1764eda14cbcSMatt Macy } 1765eda14cbcSMatt Macy 1766eda14cbcSMatt Macy /* call the ioctl */ 1767eda14cbcSMatt Macy ret = lzc_change_key(zhp->zfs_name, cmd, props, wkeydata, wkeylen); 1768eda14cbcSMatt Macy if (ret != 0) { 1769eda14cbcSMatt Macy switch (ret) { 1770eda14cbcSMatt Macy case EPERM: 1771eda14cbcSMatt Macy zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 1772eda14cbcSMatt Macy "Permission denied.")); 1773eda14cbcSMatt Macy break; 1774eda14cbcSMatt Macy case EINVAL: 1775eda14cbcSMatt Macy zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 1776eda14cbcSMatt Macy "Invalid properties for key change.")); 1777eda14cbcSMatt Macy break; 1778eda14cbcSMatt Macy case EACCES: 1779eda14cbcSMatt Macy zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, 1780eda14cbcSMatt Macy "Key is not currently loaded.")); 1781eda14cbcSMatt Macy break; 1782eda14cbcSMatt Macy } 1783eda14cbcSMatt Macy zfs_error(zhp->zfs_hdl, EZFS_CRYPTOFAILED, errbuf); 1784eda14cbcSMatt Macy } 1785eda14cbcSMatt Macy 1786eda14cbcSMatt Macy if (pzhp != NULL) 1787eda14cbcSMatt Macy zfs_close(pzhp); 1788eda14cbcSMatt Macy if (props != NULL) 1789eda14cbcSMatt Macy nvlist_free(props); 1790eda14cbcSMatt Macy if (wkeydata != NULL) 1791eda14cbcSMatt Macy free(wkeydata); 1792eda14cbcSMatt Macy 1793eda14cbcSMatt Macy return (ret); 1794eda14cbcSMatt Macy 1795eda14cbcSMatt Macy error: 1796eda14cbcSMatt Macy if (pzhp != NULL) 1797eda14cbcSMatt Macy zfs_close(pzhp); 1798eda14cbcSMatt Macy if (props != NULL) 1799eda14cbcSMatt Macy nvlist_free(props); 1800eda14cbcSMatt Macy if (wkeydata != NULL) 1801eda14cbcSMatt Macy free(wkeydata); 1802eda14cbcSMatt Macy 1803eda14cbcSMatt Macy zfs_error(zhp->zfs_hdl, EZFS_CRYPTOFAILED, errbuf); 1804eda14cbcSMatt Macy return (ret); 1805eda14cbcSMatt Macy } 1806