Path: blob/main/sys/contrib/openzfs/lib/libzfs/libzfs_crypto.c
108062 views
// SPDX-License-Identifier: CDDL-1.01/*2* CDDL HEADER START3*4* This file and its contents are supplied under the terms of the5* Common Development and Distribution License ("CDDL"), version 1.0.6* You may only use this file in accordance with the terms of version7* 1.0 of the CDDL.8*9* A full copy of the text of the CDDL should have accompanied this10* source. A copy of the CDDL is also available via the Internet at11* http://www.illumos.org/license/CDDL.12*13* CDDL HEADER END14*/1516/*17* Copyright (c) 2017, Datto, Inc. All rights reserved.18* Copyright 2020 Joyent, Inc.19*/2021#include <sys/fs/zfs.h>22#include <sys/dsl_crypt.h>23#include <libintl.h>24#include <termios.h>25#include <signal.h>26#include <errno.h>27#include <openssl/evp.h>28#if LIBFETCH_DYNAMIC29#include <dlfcn.h>30#endif31#if LIBFETCH_IS_FETCH32#include <sys/param.h>33#include <stdio.h>34#include <fetch.h>35#elif LIBFETCH_IS_LIBCURL36#include <curl/curl.h>37#endif38#include <libzfs.h>39#include <libzutil.h>40#include "libzfs_impl.h"41#include "zfeature_common.h"4243/*44* User keys are used to decrypt the master encryption keys of a dataset. This45* indirection allows a user to change his / her access key without having to46* re-encrypt the entire dataset. User keys can be provided in one of several47* ways. Raw keys are simply given to the kernel as is. Similarly, hex keys48* are converted to binary and passed into the kernel. Password based keys are49* a bit more complicated. Passwords alone do not provide suitable entropy for50* encryption and may be too short or too long to be used. In order to derive51* a more appropriate key we use a PBKDF2 function. This function is designed52* to take a (relatively) long time to calculate in order to discourage53* attackers from guessing from a list of common passwords. PBKDF2 requires54* 2 additional parameters. The first is the number of iterations to run, which55* will ultimately determine how long it takes to derive the resulting key from56* the password. The second parameter is a salt that is randomly generated for57* each dataset. The salt is used to "tweak" PBKDF2 such that a group of58* attackers cannot reasonably generate a table of commonly known passwords to59* their output keys and expect it work for all past and future PBKDF2 users.60* We store the salt as a hidden property of the dataset (although it is61* technically ok if the salt is known to the attacker).62*/6364#define MIN_PASSPHRASE_LEN 865#define MAX_PASSPHRASE_LEN 51266#define MAX_KEY_PROMPT_ATTEMPTS 36768static int caught_interrupt;6970static int get_key_material_file(libzfs_handle_t *, const char *, const char *,71zfs_keyformat_t, boolean_t, uint8_t **, size_t *);72static int get_key_material_https(libzfs_handle_t *, const char *, const char *,73zfs_keyformat_t, boolean_t, uint8_t **, size_t *);7475static zfs_uri_handler_t uri_handlers[] = {76{ "file", get_key_material_file },77{ "https", get_key_material_https },78{ "http", get_key_material_https },79{ NULL, NULL }80};8182static int83pkcs11_get_urandom(uint8_t *buf, size_t bytes)84{85int rand;86ssize_t bytes_read = 0;8788rand = open("/dev/urandom", O_RDONLY | O_CLOEXEC);8990if (rand < 0)91return (rand);9293while (bytes_read < bytes) {94ssize_t rc = read(rand, buf + bytes_read, bytes - bytes_read);95if (rc < 0)96break;97bytes_read += rc;98}99100(void) close(rand);101102return (bytes_read);103}104105static int106zfs_prop_parse_keylocation(libzfs_handle_t *restrict hdl, const char *str,107zfs_keylocation_t *restrict locp, char **restrict schemep)108{109*locp = ZFS_KEYLOCATION_NONE;110*schemep = NULL;111112if (strcmp("prompt", str) == 0) {113*locp = ZFS_KEYLOCATION_PROMPT;114return (0);115}116117regmatch_t pmatch[2];118119if (regexec(&hdl->libzfs_urire, str, ARRAY_SIZE(pmatch),120pmatch, 0) == 0) {121size_t scheme_len;122123if (pmatch[1].rm_so == -1) {124zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,125"Invalid URI"));126return (EINVAL);127}128129scheme_len = pmatch[1].rm_eo - pmatch[1].rm_so;130131*schemep = calloc(1, scheme_len + 1);132if (*schemep == NULL) {133int ret = errno;134135errno = 0;136zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,137"Invalid URI"));138return (ret);139}140141(void) memcpy(*schemep, str + pmatch[1].rm_so, scheme_len);142*locp = ZFS_KEYLOCATION_URI;143return (0);144}145146zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "Invalid keylocation"));147return (EINVAL);148}149150static int151hex_key_to_raw(char *hex, int hexlen, uint8_t *out)152{153int ret, i;154unsigned int c;155156for (i = 0; i < hexlen; i += 2) {157if (!isxdigit(hex[i]) || !isxdigit(hex[i + 1])) {158ret = EINVAL;159goto error;160}161162ret = sscanf(&hex[i], "%02x", &c);163if (ret != 1) {164ret = EINVAL;165goto error;166}167168out[i / 2] = c;169}170171return (0);172173error:174return (ret);175}176177178static void179catch_signal(int sig)180{181caught_interrupt = sig;182}183184static const char *185get_format_prompt_string(zfs_keyformat_t format)186{187switch (format) {188case ZFS_KEYFORMAT_RAW:189return ("raw key");190case ZFS_KEYFORMAT_HEX:191return ("hex key");192case ZFS_KEYFORMAT_PASSPHRASE:193return ("passphrase");194default:195/* shouldn't happen */196return (NULL);197}198}199200/* do basic validation of the key material */201static int202validate_key(libzfs_handle_t *hdl, zfs_keyformat_t keyformat,203const char *key, size_t keylen, boolean_t do_verify)204{205switch (keyformat) {206case ZFS_KEYFORMAT_RAW:207/* verify the key length is correct */208if (keylen < WRAPPING_KEY_LEN) {209zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,210"Raw key too short (expected %u)."),211WRAPPING_KEY_LEN);212return (EINVAL);213}214215if (keylen > WRAPPING_KEY_LEN) {216zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,217"Raw key too long (expected %u)."),218WRAPPING_KEY_LEN);219return (EINVAL);220}221break;222case ZFS_KEYFORMAT_HEX:223/* verify the key length is correct */224if (keylen < WRAPPING_KEY_LEN * 2) {225zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,226"Hex key too short (expected %u)."),227WRAPPING_KEY_LEN * 2);228return (EINVAL);229}230231if (keylen > WRAPPING_KEY_LEN * 2) {232zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,233"Hex key too long (expected %u)."),234WRAPPING_KEY_LEN * 2);235return (EINVAL);236}237238/* check for invalid hex digits */239for (size_t i = 0; i < WRAPPING_KEY_LEN * 2; i++) {240if (!isxdigit(key[i])) {241zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,242"Invalid hex character detected."));243return (EINVAL);244}245}246break;247case ZFS_KEYFORMAT_PASSPHRASE:248/*249* Verify the length is within bounds when setting a new key,250* but not when loading an existing key.251*/252if (!do_verify)253break;254if (keylen > MAX_PASSPHRASE_LEN) {255zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,256"Passphrase too long (max %u)."),257MAX_PASSPHRASE_LEN);258return (EINVAL);259}260261if (keylen < MIN_PASSPHRASE_LEN) {262zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,263"Passphrase too short (min %u)."),264MIN_PASSPHRASE_LEN);265return (EINVAL);266}267break;268default:269/* can't happen, checked above */270break;271}272273return (0);274}275276static int277libzfs_getpassphrase(zfs_keyformat_t keyformat, boolean_t is_reenter,278boolean_t new_key, const char *fsname,279char **restrict res, size_t *restrict reslen)280{281FILE *f = stdin;282size_t buflen = 0;283ssize_t bytes;284int ret = 0;285struct termios old_term, new_term;286struct sigaction act, osigint, osigtstp;287288*res = NULL;289*reslen = 0;290291/*292* handle SIGINT and ignore SIGSTP. This is necessary to293* restore the state of the terminal.294*/295caught_interrupt = 0;296act.sa_flags = 0;297(void) sigemptyset(&act.sa_mask);298act.sa_handler = catch_signal;299300(void) sigaction(SIGINT, &act, &osigint);301act.sa_handler = SIG_IGN;302(void) sigaction(SIGTSTP, &act, &osigtstp);303304(void) printf("%s %s%s",305is_reenter ? "Re-enter" : "Enter",306new_key ? "new " : "",307get_format_prompt_string(keyformat));308if (fsname != NULL)309(void) printf(" for '%s'", fsname);310(void) fputc(':', stdout);311(void) fflush(stdout);312313/* disable the terminal echo for key input */314(void) tcgetattr(fileno(f), &old_term);315316new_term = old_term;317new_term.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);318319ret = tcsetattr(fileno(f), TCSAFLUSH, &new_term);320if (ret != 0) {321ret = errno;322errno = 0;323goto out;324}325326bytes = getline(res, &buflen, f);327if (bytes < 0) {328ret = errno;329errno = 0;330goto out;331}332333/* trim the ending newline if it exists */334if (bytes > 0 && (*res)[bytes - 1] == '\n') {335(*res)[bytes - 1] = '\0';336bytes--;337}338339*reslen = bytes;340341out:342/* reset the terminal */343(void) tcsetattr(fileno(f), TCSAFLUSH, &old_term);344(void) sigaction(SIGINT, &osigint, NULL);345(void) sigaction(SIGTSTP, &osigtstp, NULL);346347/* if we caught a signal, re-throw it now */348if (caught_interrupt != 0)349(void) kill(getpid(), caught_interrupt);350351/* print the newline that was not echo'd */352(void) printf("\n");353354return (ret);355}356357static int358get_key_interactive(libzfs_handle_t *restrict hdl, const char *fsname,359zfs_keyformat_t keyformat, boolean_t confirm_key, boolean_t newkey,360uint8_t **restrict outbuf, size_t *restrict len_out)361{362char *buf = NULL, *buf2 = NULL;363size_t buflen = 0, buf2len = 0;364int ret = 0;365366ASSERT(isatty(fileno(stdin)));367368/* raw keys cannot be entered on the terminal */369if (keyformat == ZFS_KEYFORMAT_RAW) {370ret = EINVAL;371zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,372"Cannot enter raw keys on the terminal"));373goto out;374}375376/* prompt for the key */377if ((ret = libzfs_getpassphrase(keyformat, B_FALSE, newkey, fsname,378&buf, &buflen)) != 0) {379free(buf);380buf = NULL;381buflen = 0;382goto out;383}384385if (!confirm_key)386goto out;387388if ((ret = validate_key(hdl, keyformat, buf, buflen, confirm_key)) !=3890) {390free(buf);391return (ret);392}393394ret = libzfs_getpassphrase(keyformat, B_TRUE, newkey, fsname, &buf2,395&buf2len);396if (ret != 0) {397free(buf);398free(buf2);399buf = buf2 = NULL;400buflen = buf2len = 0;401goto out;402}403404if (buflen != buf2len || strcmp(buf, buf2) != 0) {405free(buf);406buf = NULL;407buflen = 0;408409ret = EINVAL;410zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,411"Provided keys do not match."));412}413414free(buf2);415416out:417*outbuf = (uint8_t *)buf;418*len_out = buflen;419return (ret);420}421422static int423get_key_material_raw(FILE *fd, zfs_keyformat_t keyformat,424uint8_t **buf, size_t *len_out)425{426int ret = 0;427size_t buflen = 0;428429*len_out = 0;430431/* read the key material */432if (keyformat != ZFS_KEYFORMAT_RAW) {433ssize_t bytes;434435bytes = getline((char **)buf, &buflen, fd);436if (bytes < 0) {437ret = errno;438errno = 0;439goto out;440}441442/* trim the ending newline if it exists */443if (bytes > 0 && (*buf)[bytes - 1] == '\n') {444(*buf)[bytes - 1] = '\0';445bytes--;446}447448*len_out = bytes;449} else {450size_t n;451452/*453* Raw keys may have newline characters in them and so can't454* use getline(). Here we attempt to read 33 bytes so that we455* can properly check the key length (the file should only have456* 32 bytes).457*/458*buf = malloc((WRAPPING_KEY_LEN + 1) * sizeof (uint8_t));459if (*buf == NULL) {460ret = ENOMEM;461goto out;462}463464n = fread(*buf, 1, WRAPPING_KEY_LEN + 1, fd);465if (n == 0 || ferror(fd)) {466/* size errors are handled by the calling function */467free(*buf);468*buf = NULL;469ret = errno;470errno = 0;471goto out;472}473474*len_out = n;475}476out:477return (ret);478}479480static int481get_key_material_file(libzfs_handle_t *hdl, const char *uri,482const char *fsname, zfs_keyformat_t keyformat, boolean_t newkey,483uint8_t **restrict buf, size_t *restrict len_out)484{485(void) fsname, (void) newkey;486FILE *f = NULL;487int ret = 0;488489if (strlen(uri) < 7)490return (EINVAL);491492if ((f = fopen(uri + 7, "re")) == NULL) {493ret = errno;494errno = 0;495zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,496"Failed to open key material file: %s"), zfs_strerror(ret));497return (ret);498}499500ret = get_key_material_raw(f, keyformat, buf, len_out);501502(void) fclose(f);503504return (ret);505}506507static int508get_key_material_https(libzfs_handle_t *hdl, const char *uri,509const char *fsname, zfs_keyformat_t keyformat, boolean_t newkey,510uint8_t **restrict buf, size_t *restrict len_out)511{512(void) fsname, (void) newkey;513int ret = 0;514FILE *key = NULL;515boolean_t is_http = strncmp(uri, "http:", strlen("http:")) == 0;516517if (strlen(uri) < (is_http ? 7 : 8)) {518ret = EINVAL;519goto end;520}521522#if LIBFETCH_DYNAMIC523#define LOAD_FUNCTION(func) \524__typeof__(func) *func = dlsym(hdl->libfetch, #func);525526if (hdl->libfetch == NULL)527hdl->libfetch = dlopen(LIBFETCH_SONAME, RTLD_LAZY);528529if (hdl->libfetch == NULL) {530hdl->libfetch = (void *)-1;531char *err = dlerror();532if (err)533hdl->libfetch_load_error = strdup(err);534}535536if (hdl->libfetch == (void *)-1) {537ret = ENOSYS;538zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,539"Couldn't load %s: %s"),540LIBFETCH_SONAME, hdl->libfetch_load_error ?: "(?)");541goto end;542}543544boolean_t ok;545#if LIBFETCH_IS_FETCH546LOAD_FUNCTION(fetchGetURL);547char *fetchLastErrString = dlsym(hdl->libfetch, "fetchLastErrString");548549ok = fetchGetURL && fetchLastErrString;550#elif LIBFETCH_IS_LIBCURL551LOAD_FUNCTION(curl_easy_init);552LOAD_FUNCTION(curl_easy_setopt);553LOAD_FUNCTION(curl_easy_perform);554LOAD_FUNCTION(curl_easy_cleanup);555LOAD_FUNCTION(curl_easy_strerror);556LOAD_FUNCTION(curl_easy_getinfo);557558ok = curl_easy_init && curl_easy_setopt && curl_easy_perform &&559curl_easy_cleanup && curl_easy_strerror && curl_easy_getinfo;560#endif561if (!ok) {562zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,563"keylocation=%s back-end %s missing symbols."),564is_http ? "http://" : "https://", LIBFETCH_SONAME);565ret = ENOSYS;566goto end;567}568#endif569570#if LIBFETCH_IS_FETCH571key = fetchGetURL(uri, "");572if (key == NULL) {573zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,574"Couldn't GET %s: %s"),575uri, fetchLastErrString);576ret = ENETDOWN;577}578#elif LIBFETCH_IS_LIBCURL579CURL *curl = curl_easy_init();580if (curl == NULL) {581ret = ENOTSUP;582goto end;583}584585int kfd;586#ifdef O_TMPFILE587kfd = open(getenv("TMPDIR") ?: "/tmp",588O_RDWR | O_TMPFILE | O_EXCL | O_CLOEXEC, 0600);589if (kfd != -1)590goto kfdok;591#endif592593char *path;594if (asprintf(&path,595"%s/libzfs-XXXXXXXX.https", getenv("TMPDIR") ?: "/tmp") == -1) {596ret = ENOMEM;597zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "%s"),598zfs_strerror(ret));599goto end;600}601602kfd = mkostemps(path, strlen(".https"), O_CLOEXEC);603if (kfd == -1) {604ret = errno;605zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,606"Couldn't create temporary file %s: %s"),607path, zfs_strerror(ret));608free(path);609goto end;610}611(void) unlink(path);612free(path);613614#ifdef O_TMPFILE615kfdok:616#endif617if ((key = fdopen(kfd, "r+")) == NULL) {618ret = errno;619(void) close(kfd);620zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,621"Couldn't reopen temporary file: %s"), zfs_strerror(ret));622goto end;623}624625char errbuf[CURL_ERROR_SIZE] = "";626char *cainfo = getenv("SSL_CA_CERT_FILE"); /* matches fetch(3) */627char *capath = getenv("SSL_CA_CERT_PATH"); /* matches fetch(3) */628char *clcert = getenv("SSL_CLIENT_CERT_FILE"); /* matches fetch(3) */629char *clkey = getenv("SSL_CLIENT_KEY_FILE"); /* matches fetch(3) */630(void) curl_easy_setopt(curl, CURLOPT_URL, uri);631(void) curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);632(void) curl_easy_setopt(curl, CURLOPT_TIMEOUT_MS, 30000L);633(void) curl_easy_setopt(curl, CURLOPT_WRITEDATA, key);634(void) curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, errbuf);635if (cainfo != NULL)636(void) curl_easy_setopt(curl, CURLOPT_CAINFO, cainfo);637if (capath != NULL)638(void) curl_easy_setopt(curl, CURLOPT_CAPATH, capath);639if (clcert != NULL)640(void) curl_easy_setopt(curl, CURLOPT_SSLCERT, clcert);641if (clkey != NULL)642(void) curl_easy_setopt(curl, CURLOPT_SSLKEY, clkey);643644CURLcode res = curl_easy_perform(curl);645646if (res != CURLE_OK) {647zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,648"Failed to connect to %s: %s"),649uri, strlen(errbuf) ? errbuf : curl_easy_strerror(res));650ret = ENETDOWN;651} else {652long resp = 200;653(void) curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &resp);654655if (resp < 200 || resp >= 300) {656zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,657"Couldn't GET %s: %ld"),658uri, resp);659ret = ENOENT;660} else661rewind(key);662}663664curl_easy_cleanup(curl);665#else666zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,667"No keylocation=%s back-end."), is_http ? "http://" : "https://");668ret = ENOSYS;669#endif670671end:672if (ret == 0)673ret = get_key_material_raw(key, keyformat, buf, len_out);674675if (key != NULL)676fclose(key);677678return (ret);679}680681/*682* Attempts to fetch key material, no matter where it might live. The key683* material is allocated and returned in km_out. *can_retry_out will be set684* to B_TRUE if the user is providing the key material interactively, allowing685* for re-entry attempts.686*/687static int688get_key_material(libzfs_handle_t *hdl, boolean_t do_verify, boolean_t newkey,689zfs_keyformat_t keyformat, const char *keylocation, const char *fsname,690uint8_t **km_out, size_t *kmlen_out, boolean_t *can_retry_out)691{692int ret;693zfs_keylocation_t keyloc = ZFS_KEYLOCATION_NONE;694uint8_t *km = NULL;695size_t kmlen = 0;696char *uri_scheme = NULL;697zfs_uri_handler_t *handler = NULL;698boolean_t can_retry = B_FALSE;699700/* verify and parse the keylocation */701ret = zfs_prop_parse_keylocation(hdl, keylocation, &keyloc,702&uri_scheme);703if (ret != 0)704goto error;705706/* open the appropriate file descriptor */707switch (keyloc) {708case ZFS_KEYLOCATION_PROMPT:709if (isatty(fileno(stdin))) {710can_retry = keyformat != ZFS_KEYFORMAT_RAW;711ret = get_key_interactive(hdl, fsname, keyformat,712do_verify, newkey, &km, &kmlen);713} else {714/* fetch the key material into the buffer */715ret = get_key_material_raw(stdin, keyformat, &km,716&kmlen);717}718719if (ret != 0)720goto error;721722break;723case ZFS_KEYLOCATION_URI:724ret = ENOTSUP;725726for (handler = uri_handlers; handler->zuh_scheme != NULL;727handler++) {728if (strcmp(handler->zuh_scheme, uri_scheme) != 0)729continue;730731if ((ret = handler->zuh_handler(hdl, keylocation,732fsname, keyformat, newkey, &km, &kmlen)) != 0)733goto error;734735break;736}737738if (ret == ENOTSUP) {739zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,740"URI scheme is not supported"));741goto error;742}743744break;745default:746ret = EINVAL;747zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,748"Invalid keylocation."));749goto error;750}751752if ((ret = validate_key(hdl, keyformat, (const char *)km, kmlen,753do_verify)) != 0)754goto error;755756*km_out = km;757*kmlen_out = kmlen;758if (can_retry_out != NULL)759*can_retry_out = can_retry;760761free(uri_scheme);762return (0);763764error:765free(km);766767*km_out = NULL;768*kmlen_out = 0;769770if (can_retry_out != NULL)771*can_retry_out = can_retry;772773free(uri_scheme);774return (ret);775}776777static int778derive_key(libzfs_handle_t *hdl, zfs_keyformat_t format, uint64_t iters,779uint8_t *key_material, uint64_t salt,780uint8_t **key_out)781{782int ret;783uint8_t *key;784785*key_out = NULL;786787key = zfs_alloc(hdl, WRAPPING_KEY_LEN);788789switch (format) {790case ZFS_KEYFORMAT_RAW:791memcpy(key, key_material, WRAPPING_KEY_LEN);792break;793case ZFS_KEYFORMAT_HEX:794ret = hex_key_to_raw((char *)key_material,795WRAPPING_KEY_LEN * 2, key);796if (ret != 0) {797zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,798"Invalid hex key provided."));799goto error;800}801break;802case ZFS_KEYFORMAT_PASSPHRASE:803salt = LE_64(salt);804805ret = PKCS5_PBKDF2_HMAC_SHA1((char *)key_material,806strlen((char *)key_material), ((uint8_t *)&salt),807sizeof (uint64_t), iters, WRAPPING_KEY_LEN, key);808if (ret != 1) {809ret = EIO;810zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,811"Failed to generate key from passphrase."));812goto error;813}814break;815default:816ret = EINVAL;817goto error;818}819820*key_out = key;821return (0);822823error:824free(key);825826*key_out = NULL;827return (ret);828}829830static boolean_t831encryption_feature_is_enabled(zpool_handle_t *zph)832{833nvlist_t *features;834uint64_t feat_refcount;835836/* check that features can be enabled */837if (zpool_get_prop_int(zph, ZPOOL_PROP_VERSION, NULL)838< SPA_VERSION_FEATURES)839return (B_FALSE);840841/* check for crypto feature */842features = zpool_get_features(zph);843if (!features || nvlist_lookup_uint64(features,844spa_feature_table[SPA_FEATURE_ENCRYPTION].fi_guid,845&feat_refcount) != 0)846return (B_FALSE);847848return (B_TRUE);849}850851static int852populate_create_encryption_params_nvlists(libzfs_handle_t *hdl,853zfs_handle_t *zhp, boolean_t newkey, zfs_keyformat_t keyformat,854const char *keylocation, nvlist_t *props, uint8_t **wkeydata,855uint_t *wkeylen)856{857int ret;858uint64_t iters = 0, salt = 0;859uint8_t *key_material = NULL;860size_t key_material_len = 0;861uint8_t *key_data = NULL;862const char *fsname = (zhp) ? zfs_get_name(zhp) : NULL;863864/* get key material from keyformat and keylocation */865ret = get_key_material(hdl, B_TRUE, newkey, keyformat, keylocation,866fsname, &key_material, &key_material_len, NULL);867if (ret != 0)868goto error;869870/* passphrase formats require a salt and pbkdf2 iters property */871if (keyformat == ZFS_KEYFORMAT_PASSPHRASE) {872/* always generate a new salt */873ret = pkcs11_get_urandom((uint8_t *)&salt, sizeof (uint64_t));874if (ret != sizeof (uint64_t)) {875zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,876"Failed to generate salt."));877goto error;878}879880ret = nvlist_add_uint64(props,881zfs_prop_to_name(ZFS_PROP_PBKDF2_SALT), salt);882if (ret != 0) {883zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,884"Failed to add salt to properties."));885goto error;886}887888/*889* If not otherwise specified, use the default number of890* pbkdf2 iterations. If specified, we have already checked891* that the given value is greater than MIN_PBKDF2_ITERATIONS892* during zfs_valid_proplist().893*/894ret = nvlist_lookup_uint64(props,895zfs_prop_to_name(ZFS_PROP_PBKDF2_ITERS), &iters);896if (ret == ENOENT) {897iters = DEFAULT_PBKDF2_ITERATIONS;898ret = nvlist_add_uint64(props,899zfs_prop_to_name(ZFS_PROP_PBKDF2_ITERS), iters);900if (ret != 0)901goto error;902} else if (ret != 0) {903zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,904"Failed to get pbkdf2 iterations."));905goto error;906}907} else {908/* check that pbkdf2iters was not specified by the user */909ret = nvlist_lookup_uint64(props,910zfs_prop_to_name(ZFS_PROP_PBKDF2_ITERS), &iters);911if (ret == 0) {912ret = EINVAL;913zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,914"Cannot specify pbkdf2iters with a non-passphrase "915"keyformat."));916goto error;917}918}919920/* derive a key from the key material */921ret = derive_key(hdl, keyformat, iters, key_material, salt, &key_data);922if (ret != 0)923goto error;924925free(key_material);926927*wkeydata = key_data;928*wkeylen = WRAPPING_KEY_LEN;929return (0);930931error:932if (key_material != NULL)933free(key_material);934if (key_data != NULL)935free(key_data);936937*wkeydata = NULL;938*wkeylen = 0;939return (ret);940}941942static boolean_t943proplist_has_encryption_props(nvlist_t *props)944{945int ret;946uint64_t intval;947const char *strval;948949ret = nvlist_lookup_uint64(props,950zfs_prop_to_name(ZFS_PROP_ENCRYPTION), &intval);951if (ret == 0 && intval != ZIO_CRYPT_OFF)952return (B_TRUE);953954ret = nvlist_lookup_string(props,955zfs_prop_to_name(ZFS_PROP_KEYLOCATION), &strval);956if (ret == 0 && strcmp(strval, "none") != 0)957return (B_TRUE);958959ret = nvlist_lookup_uint64(props,960zfs_prop_to_name(ZFS_PROP_KEYFORMAT), &intval);961if (ret == 0)962return (B_TRUE);963964ret = nvlist_lookup_uint64(props,965zfs_prop_to_name(ZFS_PROP_PBKDF2_ITERS), &intval);966if (ret == 0)967return (B_TRUE);968969return (B_FALSE);970}971972int973zfs_crypto_get_encryption_root(zfs_handle_t *zhp, boolean_t *is_encroot,974char *buf)975{976int ret;977char prop_encroot[MAXNAMELEN];978979/* if the dataset isn't encrypted, just return */980if (zfs_prop_get_int(zhp, ZFS_PROP_ENCRYPTION) == ZIO_CRYPT_OFF) {981*is_encroot = B_FALSE;982if (buf != NULL)983buf[0] = '\0';984return (0);985}986987ret = zfs_prop_get(zhp, ZFS_PROP_ENCRYPTION_ROOT, prop_encroot,988sizeof (prop_encroot), NULL, NULL, 0, B_TRUE);989if (ret != 0) {990*is_encroot = B_FALSE;991if (buf != NULL)992buf[0] = '\0';993return (ret);994}995996*is_encroot = strcmp(prop_encroot, zfs_get_name(zhp)) == 0;997if (buf != NULL)998strcpy(buf, prop_encroot);9991000return (0);1001}10021003int1004zfs_crypto_create(libzfs_handle_t *hdl, char *parent_name, nvlist_t *props,1005nvlist_t *pool_props, boolean_t stdin_available, uint8_t **wkeydata_out,1006uint_t *wkeylen_out)1007{1008int ret;1009char errbuf[ERRBUFLEN];1010uint64_t crypt = ZIO_CRYPT_INHERIT, pcrypt = ZIO_CRYPT_INHERIT;1011uint64_t keyformat = ZFS_KEYFORMAT_NONE;1012const char *keylocation = NULL;1013zfs_handle_t *pzhp = NULL;1014uint8_t *wkeydata = NULL;1015uint_t wkeylen = 0;1016boolean_t local_crypt = B_TRUE;10171018(void) snprintf(errbuf, sizeof (errbuf),1019dgettext(TEXT_DOMAIN, "Encryption create error"));10201021/* lookup crypt from props */1022ret = nvlist_lookup_uint64(props,1023zfs_prop_to_name(ZFS_PROP_ENCRYPTION), &crypt);1024if (ret != 0)1025local_crypt = B_FALSE;10261027/* lookup key location and format from props */1028(void) nvlist_lookup_uint64(props,1029zfs_prop_to_name(ZFS_PROP_KEYFORMAT), &keyformat);1030(void) nvlist_lookup_string(props,1031zfs_prop_to_name(ZFS_PROP_KEYLOCATION), &keylocation);10321033if (parent_name != NULL) {1034/* get a reference to parent dataset */1035pzhp = make_dataset_handle(hdl, parent_name);1036if (pzhp == NULL) {1037ret = ENOENT;1038zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,1039"Failed to lookup parent."));1040goto out;1041}10421043/* Lookup parent's crypt */1044pcrypt = zfs_prop_get_int(pzhp, ZFS_PROP_ENCRYPTION);10451046/* Params require the encryption feature */1047if (!encryption_feature_is_enabled(pzhp->zpool_hdl)) {1048if (proplist_has_encryption_props(props)) {1049ret = EINVAL;1050zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,1051"Encryption feature not enabled."));1052goto out;1053}10541055ret = 0;1056goto out;1057}1058} else {1059/*1060* special case for root dataset where encryption feature1061* feature won't be on disk yet1062*/1063if (!nvlist_exists(pool_props, "feature@encryption")) {1064if (proplist_has_encryption_props(props)) {1065ret = EINVAL;1066zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,1067"Encryption feature not enabled."));1068goto out;1069}10701071ret = 0;1072goto out;1073}10741075pcrypt = ZIO_CRYPT_OFF;1076}10771078/* Get the inherited encryption property if we don't have it locally */1079if (!local_crypt)1080crypt = pcrypt;10811082/*1083* At this point crypt should be the actual encryption value. If1084* encryption is off just verify that no encryption properties have1085* been specified and return.1086*/1087if (crypt == ZIO_CRYPT_OFF) {1088if (proplist_has_encryption_props(props)) {1089ret = EINVAL;1090zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,1091"Encryption must be turned on to set encryption "1092"properties."));1093goto out;1094}10951096ret = 0;1097goto out;1098}10991100/*1101* If we have a parent crypt it is valid to specify encryption alone.1102* This will result in a child that is encrypted with the chosen1103* encryption suite that will also inherit the parent's key. If1104* the parent is not encrypted we need an encryption suite provided.1105*/1106if (pcrypt == ZIO_CRYPT_OFF && keylocation == NULL &&1107keyformat == ZFS_KEYFORMAT_NONE) {1108ret = EINVAL;1109zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,1110"Keyformat required for new encryption root."));1111goto out;1112}11131114/*1115* Specifying a keylocation implies this will be a new encryption root.1116* Check that a keyformat is also specified.1117*/1118if (keylocation != NULL && keyformat == ZFS_KEYFORMAT_NONE) {1119ret = EINVAL;1120zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,1121"Keyformat required for new encryption root."));1122goto out;1123}11241125/* default to prompt if no keylocation is specified */1126if (keyformat != ZFS_KEYFORMAT_NONE && keylocation == NULL) {1127keylocation = (char *)"prompt";1128ret = nvlist_add_string(props,1129zfs_prop_to_name(ZFS_PROP_KEYLOCATION), keylocation);1130if (ret != 0)1131goto out;1132}11331134/*1135* If a local key is provided, this dataset will be a new1136* encryption root. Populate the encryption params.1137*/1138if (keylocation != NULL) {1139/*1140* 'zfs recv -o keylocation=prompt' won't work because stdin1141* is being used by the send stream, so we disallow it.1142*/1143if (!stdin_available && strcmp(keylocation, "prompt") == 0) {1144ret = EINVAL;1145zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "Cannot use "1146"'prompt' keylocation because stdin is in use."));1147goto out;1148}11491150ret = populate_create_encryption_params_nvlists(hdl, NULL,1151B_TRUE, keyformat, keylocation, props, &wkeydata,1152&wkeylen);1153if (ret != 0)1154goto out;1155}11561157if (pzhp != NULL)1158zfs_close(pzhp);11591160*wkeydata_out = wkeydata;1161*wkeylen_out = wkeylen;1162return (0);11631164out:1165if (pzhp != NULL)1166zfs_close(pzhp);1167if (wkeydata != NULL)1168free(wkeydata);11691170*wkeydata_out = NULL;1171*wkeylen_out = 0;1172return (ret);1173}11741175int1176zfs_crypto_clone_check(libzfs_handle_t *hdl, zfs_handle_t *origin_zhp,1177char *parent_name, nvlist_t *props)1178{1179(void) origin_zhp, (void) parent_name;1180char errbuf[ERRBUFLEN];11811182(void) snprintf(errbuf, sizeof (errbuf),1183dgettext(TEXT_DOMAIN, "Encryption clone error"));11841185/*1186* No encryption properties should be specified. They will all be1187* inherited from the origin dataset.1188*/1189if (nvlist_exists(props, zfs_prop_to_name(ZFS_PROP_KEYFORMAT)) ||1190nvlist_exists(props, zfs_prop_to_name(ZFS_PROP_KEYLOCATION)) ||1191nvlist_exists(props, zfs_prop_to_name(ZFS_PROP_ENCRYPTION)) ||1192nvlist_exists(props, zfs_prop_to_name(ZFS_PROP_PBKDF2_ITERS))) {1193zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,1194"Encryption properties must inherit from origin dataset."));1195return (EINVAL);1196}11971198return (0);1199}12001201typedef struct loadkeys_cbdata {1202uint64_t cb_numfailed;1203uint64_t cb_numattempted;1204} loadkey_cbdata_t;12051206static int1207load_keys_cb(zfs_handle_t *zhp, void *arg)1208{1209int ret;1210boolean_t is_encroot;1211loadkey_cbdata_t *cb = arg;1212uint64_t keystatus = zfs_prop_get_int(zhp, ZFS_PROP_KEYSTATUS);12131214/* only attempt to load keys for encryption roots */1215ret = zfs_crypto_get_encryption_root(zhp, &is_encroot, NULL);1216if (ret != 0 || !is_encroot)1217goto out;12181219/* don't attempt to load already loaded keys */1220if (keystatus == ZFS_KEYSTATUS_AVAILABLE)1221goto out;12221223/* Attempt to load the key. Record status in cb. */1224cb->cb_numattempted++;12251226ret = zfs_crypto_load_key(zhp, B_FALSE, NULL);1227if (ret)1228cb->cb_numfailed++;12291230out:1231(void) zfs_iter_filesystems_v2(zhp, 0, load_keys_cb, cb);1232zfs_close(zhp);12331234/* always return 0, since this function is best effort */1235return (0);1236}12371238/*1239* This function is best effort. It attempts to load all the keys for the given1240* filesystem and all of its children.1241*/1242int1243zfs_crypto_attempt_load_keys(libzfs_handle_t *hdl, const char *fsname)1244{1245int ret;1246zfs_handle_t *zhp = NULL;1247loadkey_cbdata_t cb = { 0 };12481249zhp = zfs_open(hdl, fsname, ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME);1250if (zhp == NULL) {1251ret = ENOENT;1252goto error;1253}12541255ret = load_keys_cb(zfs_handle_dup(zhp), &cb);1256if (ret)1257goto error;12581259(void) printf(gettext("%llu / %llu keys successfully loaded\n"),1260(u_longlong_t)(cb.cb_numattempted - cb.cb_numfailed),1261(u_longlong_t)cb.cb_numattempted);12621263if (cb.cb_numfailed != 0) {1264ret = -1;1265goto error;1266}12671268zfs_close(zhp);1269return (0);12701271error:1272if (zhp != NULL)1273zfs_close(zhp);1274return (ret);1275}12761277int1278zfs_crypto_load_key(zfs_handle_t *zhp, boolean_t noop,1279const char *alt_keylocation)1280{1281int ret, attempts = 0;1282char errbuf[ERRBUFLEN];1283uint64_t keystatus, iters = 0, salt = 0;1284uint64_t keyformat = ZFS_KEYFORMAT_NONE;1285char prop_keylocation[MAXNAMELEN];1286char prop_encroot[MAXNAMELEN];1287const char *keylocation = NULL;1288uint8_t *key_material = NULL, *key_data = NULL;1289size_t key_material_len;1290boolean_t is_encroot, can_retry = B_FALSE, correctible = B_FALSE;12911292(void) snprintf(errbuf, sizeof (errbuf),1293dgettext(TEXT_DOMAIN, "Key load error"));12941295/* check that encryption is enabled for the pool */1296if (!encryption_feature_is_enabled(zhp->zpool_hdl)) {1297zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,1298"Encryption feature not enabled."));1299ret = EINVAL;1300goto error;1301}13021303/* Fetch the keyformat. Check that the dataset is encrypted. */1304keyformat = zfs_prop_get_int(zhp, ZFS_PROP_KEYFORMAT);1305if (keyformat == ZFS_KEYFORMAT_NONE) {1306zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,1307"'%s' is not encrypted."), zfs_get_name(zhp));1308ret = EINVAL;1309goto error;1310}13111312/*1313* Fetch the key location. Check that we are working with an1314* encryption root.1315*/1316ret = zfs_crypto_get_encryption_root(zhp, &is_encroot, prop_encroot);1317if (ret != 0) {1318zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,1319"Failed to get encryption root for '%s'."),1320zfs_get_name(zhp));1321goto error;1322} else if (!is_encroot) {1323zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,1324"Keys must be loaded for encryption root of '%s' (%s)."),1325zfs_get_name(zhp), prop_encroot);1326ret = EINVAL;1327goto error;1328}13291330/*1331* if the caller has elected to override the keylocation property1332* use that instead1333*/1334if (alt_keylocation != NULL) {1335keylocation = alt_keylocation;1336} else {1337ret = zfs_prop_get(zhp, ZFS_PROP_KEYLOCATION, prop_keylocation,1338sizeof (prop_keylocation), NULL, NULL, 0, B_TRUE);1339if (ret != 0) {1340zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,1341"Failed to get keylocation for '%s'."),1342zfs_get_name(zhp));1343goto error;1344}13451346keylocation = prop_keylocation;1347}13481349/* check that the key is unloaded unless this is a noop */1350if (!noop) {1351keystatus = zfs_prop_get_int(zhp, ZFS_PROP_KEYSTATUS);1352if (keystatus == ZFS_KEYSTATUS_AVAILABLE) {1353zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,1354"Key already loaded for '%s'."), zfs_get_name(zhp));1355ret = EEXIST;1356goto error;1357}1358}13591360/* passphrase formats require a salt and pbkdf2_iters property */1361if (keyformat == ZFS_KEYFORMAT_PASSPHRASE) {1362salt = zfs_prop_get_int(zhp, ZFS_PROP_PBKDF2_SALT);1363iters = zfs_prop_get_int(zhp, ZFS_PROP_PBKDF2_ITERS);1364}13651366try_again:1367/* fetching and deriving the key are correctable errors. set the flag */1368correctible = B_TRUE;13691370/* get key material from key format and location */1371ret = get_key_material(zhp->zfs_hdl, B_FALSE, B_FALSE, keyformat,1372keylocation, zfs_get_name(zhp), &key_material, &key_material_len,1373&can_retry);1374if (ret != 0)1375goto error;13761377/* derive a key from the key material */1378ret = derive_key(zhp->zfs_hdl, keyformat, iters, key_material, salt,1379&key_data);1380if (ret != 0)1381goto error;13821383correctible = B_FALSE;13841385/* pass the wrapping key and noop flag to the ioctl */1386ret = lzc_load_key(zhp->zfs_name, noop, key_data, WRAPPING_KEY_LEN);1387if (ret != 0) {1388switch (ret) {1389case EPERM:1390zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,1391"Permission denied."));1392break;1393case EINVAL:1394zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,1395"Invalid parameters provided for dataset %s."),1396zfs_get_name(zhp));1397break;1398case EEXIST:1399zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,1400"Key already loaded for '%s'."), zfs_get_name(zhp));1401break;1402case EBUSY:1403zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,1404"'%s' is busy."), zfs_get_name(zhp));1405break;1406case EACCES:1407correctible = B_TRUE;1408zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,1409"Incorrect key provided for '%s'."),1410zfs_get_name(zhp));1411break;1412case ZFS_ERR_CRYPTO_NOTSUP:1413zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,1414"'%s' uses an unsupported encryption suite."),1415zfs_get_name(zhp));1416break;1417}1418goto error;1419}14201421free(key_material);1422free(key_data);14231424return (0);14251426error:1427zfs_error(zhp->zfs_hdl, EZFS_CRYPTOFAILED, errbuf);1428if (key_material != NULL) {1429free(key_material);1430key_material = NULL;1431}1432if (key_data != NULL) {1433free(key_data);1434key_data = NULL;1435}14361437/*1438* Here we decide if it is ok to allow the user to retry entering their1439* key. The can_retry flag will be set if the user is entering their1440* key from an interactive prompt. The correctable flag will only be1441* set if an error that occurred could be corrected by retrying. Both1442* flags are needed to allow the user to attempt key entry again1443*/1444attempts++;1445if (can_retry && correctible && attempts < MAX_KEY_PROMPT_ATTEMPTS)1446goto try_again;14471448return (ret);1449}14501451int1452zfs_crypto_unload_key(zfs_handle_t *zhp)1453{1454int ret;1455char errbuf[ERRBUFLEN];1456char prop_encroot[MAXNAMELEN];1457uint64_t keystatus, keyformat;1458boolean_t is_encroot;14591460(void) snprintf(errbuf, sizeof (errbuf),1461dgettext(TEXT_DOMAIN, "Key unload error"));14621463/* check that encryption is enabled for the pool */1464if (!encryption_feature_is_enabled(zhp->zpool_hdl)) {1465zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,1466"Encryption feature not enabled."));1467ret = EINVAL;1468goto error;1469}14701471/* Fetch the keyformat. Check that the dataset is encrypted. */1472keyformat = zfs_prop_get_int(zhp, ZFS_PROP_KEYFORMAT);1473if (keyformat == ZFS_KEYFORMAT_NONE) {1474zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,1475"'%s' is not encrypted."), zfs_get_name(zhp));1476ret = EINVAL;1477goto error;1478}14791480/*1481* Fetch the key location. Check that we are working with an1482* encryption root.1483*/1484ret = zfs_crypto_get_encryption_root(zhp, &is_encroot, prop_encroot);1485if (ret != 0) {1486zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,1487"Failed to get encryption root for '%s'."),1488zfs_get_name(zhp));1489goto error;1490} else if (!is_encroot) {1491zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,1492"Keys must be unloaded for encryption root of '%s' (%s)."),1493zfs_get_name(zhp), prop_encroot);1494ret = EINVAL;1495goto error;1496}14971498/* check that the key is loaded */1499keystatus = zfs_prop_get_int(zhp, ZFS_PROP_KEYSTATUS);1500if (keystatus == ZFS_KEYSTATUS_UNAVAILABLE) {1501zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,1502"Key already unloaded for '%s'."), zfs_get_name(zhp));1503ret = EACCES;1504goto error;1505}15061507/* call the ioctl */1508ret = lzc_unload_key(zhp->zfs_name);15091510if (ret != 0) {1511switch (ret) {1512case EPERM:1513zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,1514"Permission denied."));1515break;1516case EACCES:1517zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,1518"Key already unloaded for '%s'."),1519zfs_get_name(zhp));1520break;1521case EBUSY:1522zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,1523"'%s' is busy."), zfs_get_name(zhp));1524break;1525}1526zfs_error(zhp->zfs_hdl, EZFS_CRYPTOFAILED, errbuf);1527}15281529return (ret);15301531error:1532zfs_error(zhp->zfs_hdl, EZFS_CRYPTOFAILED, errbuf);1533return (ret);1534}15351536static int1537zfs_crypto_verify_rewrap_nvlist(zfs_handle_t *zhp, nvlist_t *props,1538nvlist_t **props_out, char *errbuf)1539{1540int ret;1541nvpair_t *elem = NULL;1542zfs_prop_t prop;1543nvlist_t *new_props = NULL;15441545new_props = fnvlist_alloc();15461547/*1548* loop through all provided properties, we should only have1549* keyformat, keylocation and pbkdf2iters. The actual validation of1550* values is done by zfs_valid_proplist().1551*/1552while ((elem = nvlist_next_nvpair(props, elem)) != NULL) {1553const char *propname = nvpair_name(elem);1554prop = zfs_name_to_prop(propname);15551556switch (prop) {1557case ZFS_PROP_PBKDF2_ITERS:1558case ZFS_PROP_KEYFORMAT:1559case ZFS_PROP_KEYLOCATION:1560break;1561default:1562ret = EINVAL;1563zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,1564"Only keyformat, keylocation and pbkdf2iters may "1565"be set with this command."));1566goto error;1567}1568}15691570new_props = zfs_valid_proplist(zhp->zfs_hdl, zhp->zfs_type, props,1571zfs_prop_get_int(zhp, ZFS_PROP_ZONED), NULL, zhp->zpool_hdl,1572B_TRUE, errbuf);1573if (new_props == NULL) {1574ret = EINVAL;1575goto error;1576}15771578*props_out = new_props;1579return (0);15801581error:1582nvlist_free(new_props);1583*props_out = NULL;1584return (ret);1585}15861587int1588zfs_crypto_rewrap(zfs_handle_t *zhp, nvlist_t *raw_props, boolean_t inheritkey)1589{1590int ret;1591char errbuf[ERRBUFLEN];1592boolean_t is_encroot;1593nvlist_t *props = NULL;1594uint8_t *wkeydata = NULL;1595uint_t wkeylen = 0;1596dcp_cmd_t cmd = (inheritkey) ? DCP_CMD_INHERIT : DCP_CMD_NEW_KEY;1597uint64_t crypt, pcrypt, keystatus, pkeystatus;1598uint64_t keyformat = ZFS_KEYFORMAT_NONE;1599zfs_handle_t *pzhp = NULL;1600const char *keylocation = NULL;1601char origin_name[MAXNAMELEN];1602char prop_keylocation[MAXNAMELEN];1603char parent_name[ZFS_MAX_DATASET_NAME_LEN];16041605(void) snprintf(errbuf, sizeof (errbuf),1606dgettext(TEXT_DOMAIN, "Key change error"));16071608/* check that encryption is enabled for the pool */1609if (!encryption_feature_is_enabled(zhp->zpool_hdl)) {1610zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,1611"Encryption feature not enabled."));1612ret = EINVAL;1613goto error;1614}16151616/* get crypt from dataset */1617crypt = zfs_prop_get_int(zhp, ZFS_PROP_ENCRYPTION);1618if (crypt == ZIO_CRYPT_OFF) {1619zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,1620"Dataset not encrypted."));1621ret = EINVAL;1622goto error;1623}16241625/* get the encryption root of the dataset */1626ret = zfs_crypto_get_encryption_root(zhp, &is_encroot, NULL);1627if (ret != 0) {1628zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,1629"Failed to get encryption root for '%s'."),1630zfs_get_name(zhp));1631goto error;1632}16331634/* Clones use their origin's key and cannot rewrap it */1635ret = zfs_prop_get(zhp, ZFS_PROP_ORIGIN, origin_name,1636sizeof (origin_name), NULL, NULL, 0, B_TRUE);1637if (ret == 0 && strcmp(origin_name, "") != 0) {1638zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,1639"Keys cannot be changed on clones."));1640ret = EINVAL;1641goto error;1642}16431644/*1645* If the user wants to use the inheritkey variant of this function1646* we don't need to collect any crypto arguments.1647*/1648if (!inheritkey) {1649/* validate the provided properties */1650ret = zfs_crypto_verify_rewrap_nvlist(zhp, raw_props, &props,1651errbuf);1652if (ret != 0)1653goto error;16541655/*1656* Load keyformat and keylocation from the nvlist. Fetch from1657* the dataset properties if not specified.1658*/1659(void) nvlist_lookup_uint64(props,1660zfs_prop_to_name(ZFS_PROP_KEYFORMAT), &keyformat);1661(void) nvlist_lookup_string(props,1662zfs_prop_to_name(ZFS_PROP_KEYLOCATION), &keylocation);16631664if (is_encroot) {1665/*1666* If this is already an encryption root, just keep1667* any properties not set by the user.1668*/1669if (keyformat == ZFS_KEYFORMAT_NONE) {1670keyformat = zfs_prop_get_int(zhp,1671ZFS_PROP_KEYFORMAT);1672ret = nvlist_add_uint64(props,1673zfs_prop_to_name(ZFS_PROP_KEYFORMAT),1674keyformat);1675if (ret != 0) {1676zfs_error_aux(zhp->zfs_hdl,1677dgettext(TEXT_DOMAIN, "Failed to "1678"get existing keyformat "1679"property."));1680goto error;1681}1682}16831684if (keylocation == NULL) {1685ret = zfs_prop_get(zhp, ZFS_PROP_KEYLOCATION,1686prop_keylocation, sizeof (prop_keylocation),1687NULL, NULL, 0, B_TRUE);1688if (ret != 0) {1689zfs_error_aux(zhp->zfs_hdl,1690dgettext(TEXT_DOMAIN, "Failed to "1691"get existing keylocation "1692"property."));1693goto error;1694}16951696keylocation = prop_keylocation;1697}1698} else {1699/* need a new key for non-encryption roots */1700if (keyformat == ZFS_KEYFORMAT_NONE) {1701ret = EINVAL;1702zfs_error_aux(zhp->zfs_hdl,1703dgettext(TEXT_DOMAIN, "Keyformat required "1704"for new encryption root."));1705goto error;1706}17071708/* default to prompt if no keylocation is specified */1709if (keylocation == NULL) {1710keylocation = "prompt";1711ret = nvlist_add_string(props,1712zfs_prop_to_name(ZFS_PROP_KEYLOCATION),1713keylocation);1714if (ret != 0)1715goto error;1716}1717}17181719/* fetch the new wrapping key and associated properties */1720ret = populate_create_encryption_params_nvlists(zhp->zfs_hdl,1721zhp, B_TRUE, keyformat, keylocation, props, &wkeydata,1722&wkeylen);1723if (ret != 0)1724goto error;1725} else {1726/* check that zhp is an encryption root */1727if (!is_encroot) {1728zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,1729"Key inheritting can only be performed on "1730"encryption roots."));1731ret = EINVAL;1732goto error;1733}17341735/* get the parent's name */1736ret = zfs_parent_name(zhp, parent_name, sizeof (parent_name));1737if (ret != 0) {1738zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,1739"Root dataset cannot inherit key."));1740ret = EINVAL;1741goto error;1742}17431744/* get a handle to the parent */1745pzhp = make_dataset_handle(zhp->zfs_hdl, parent_name);1746if (pzhp == NULL) {1747zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,1748"Failed to lookup parent."));1749ret = ENOENT;1750goto error;1751}17521753/* parent must be encrypted */1754pcrypt = zfs_prop_get_int(pzhp, ZFS_PROP_ENCRYPTION);1755if (pcrypt == ZIO_CRYPT_OFF) {1756zfs_error_aux(pzhp->zfs_hdl, dgettext(TEXT_DOMAIN,1757"Parent must be encrypted."));1758ret = EINVAL;1759goto error;1760}17611762/* check that the parent's key is loaded */1763pkeystatus = zfs_prop_get_int(pzhp, ZFS_PROP_KEYSTATUS);1764if (pkeystatus == ZFS_KEYSTATUS_UNAVAILABLE) {1765zfs_error_aux(pzhp->zfs_hdl, dgettext(TEXT_DOMAIN,1766"Parent key must be loaded."));1767ret = EACCES;1768goto error;1769}1770}17711772/* check that the key is loaded */1773keystatus = zfs_prop_get_int(zhp, ZFS_PROP_KEYSTATUS);1774if (keystatus == ZFS_KEYSTATUS_UNAVAILABLE) {1775zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,1776"Key must be loaded."));1777ret = EACCES;1778goto error;1779}17801781/* call the ioctl */1782ret = lzc_change_key(zhp->zfs_name, cmd, props, wkeydata, wkeylen);1783if (ret != 0) {1784switch (ret) {1785case EPERM:1786zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,1787"Permission denied."));1788break;1789case EINVAL:1790zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,1791"Invalid properties for key change."));1792break;1793case EACCES:1794zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,1795"Key is not currently loaded."));1796break;1797}1798zfs_error(zhp->zfs_hdl, EZFS_CRYPTOFAILED, errbuf);1799}18001801if (pzhp != NULL)1802zfs_close(pzhp);1803if (props != NULL)1804nvlist_free(props);1805if (wkeydata != NULL)1806free(wkeydata);18071808return (ret);18091810error:1811if (pzhp != NULL)1812zfs_close(pzhp);1813if (props != NULL)1814nvlist_free(props);1815if (wkeydata != NULL)1816free(wkeydata);18171818zfs_error(zhp->zfs_hdl, EZFS_CRYPTOFAILED, errbuf);1819return (ret);1820}18211822boolean_t1823zfs_is_encrypted(zfs_handle_t *zhp)1824{1825uint8_t flags = zhp->zfs_dmustats.dds_flags;18261827if (flags & DDS_FLAG_HAS_ENCRYPTED)1828return ((flags & DDS_FLAG_ENCRYPTED) != 0);18291830return (zfs_prop_get_int(zhp, ZFS_PROP_ENCRYPTION) != ZIO_CRYPT_OFF);1831}183218331834