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