/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
*/
#include <libintl.h>
#include <kmfapi.h>
#include <cryptoutil.h>
#include <errno.h>
#include <fcntl.h>
#include <libgen.h>
#include <sys/zio_crypt.h>
#include "zfs_namecheck.h"
#include "zfs_prop.h"
#include "libzfs_impl.h"
/*
* Constants and functions for parsing/validating
* the keysource property
*/
typedef enum key_format {
KEY_FORMAT_NONE = 0,
} key_format_t;
typedef enum key_locator {
KEY_LOCATOR_NONE = 0,
static boolean_t
{
if (!s)
return (B_FALSE);
*format = KEY_FORMAT_RAW;
*format = KEY_FORMAT_HEX;
else
return (B_FALSE);
return (B_TRUE);
}
static boolean_t
{
if (!s)
return (B_FALSE);
return (B_TRUE);
}
*uri = s;
return (B_TRUE);
}
/*
* Validate the PKCS#11 URI by parsing it out,
* and checking that an object is specified.
* Every other part of the PKCS#11 URI is optional.
*/
return (B_FALSE);
return (B_FALSE);
}
*uri = s;
return (B_TRUE);
}
*uri = s;
return (B_TRUE);
}
return (B_FALSE);
}
static boolean_t
{
int len;
int prop_len;
char *s = prop_value;
if (!prop_value)
return (B_FALSE);
if (prop_len > ZFS_MAXPROPLEN)
return (B_FALSE);
if (s[len] == ',')
break;
/* If we are at the end of the key property, there is a problem */
return (B_FALSE);
return (B_FALSE);
s = s + len + 1;
}
static void
{
int at;
/*
* The name needs to be that of the dataset we are creating.
* Using zc_value is wrong when doing a clone because it shows
* the name of the origin snapshot. However it is correct when
* doing a zfs recv, use zc_value upto the @ which is the
* name of the dataset getting created.
*/
if (cmd == ZFS_CRYPTO_RECV) {
}
} else {
}
}
static boolean_t
{
char *uri;
return (B_FALSE);
if (locator != KEY_LOCATOR_PROMPT)
return (B_TRUE);
return (B_FALSE);
}
return (B_TRUE);
}
static int
{
if (format == KEY_FORMAT_HEX) {
"Enter new hexadecimal key for"),
dsname);
} else {
"Enter hexadecimal key for"), dsname);
}
} else {
"Enter new passphrase for"), dsname);
} else {
"Enter passphrase for"), dsname);
}
}
return (EAGAIN);
"Must be at least %d characters.\n"), min_psize);
return (EAGAIN);
}
/*
* Loading the key is the only case were we don't reprompt.
*/
if (cmd != ZFS_CRYPTO_KEY_LOAD) {
/* clean up */
free(*passphrase);
*passphrase = NULL;
"They don't match.\n"));
return (EAGAIN);
}
}
return (0);
}
void
{
}
void
{
}
void
{
}
static int
{
char *input;
/*
* If the PKCS#11 uri has a pinfile argument read the pin from
* there.
*
* Otherwise if the libzfs_handle_t has crypto data we assume this is
* the PIN given we can only be in here with a PKCS#11 uri.
*
* Finally if that is empty then if we can prompt then do so using
* getpassphrase().
*
* Abuse zfs_can_prompt_if_needed() by pretending we are
* "passphrase,prompt".
*/
char *pbuf;
if (pinfd == -1)
return (-1);
return (-1);
return (-1);
}
}
return (0);
}
return (0);
}
if (!zfs_can_prompt_if_needed("passphrase,prompt")) {
return (-1);
}
"Enter '%s' PKCS#11 token PIN for '%s': "),
} else {
"Enter PKCS#11 token PIN for '%s': "), dsname);
}
} else {
return (-1);
}
return (0);
}
static int
{
size_t n = 0;
return (-1);
}
sizeof (kstype));
} else {
/* If the token wasn't set we assume the metaslot */
}
goto out;
goto out;
/* Always prompt for PIN since the key is likey CKA_SENSITIVE */
goto out;
&cred, sizeof (KMF_CREDENTIAL));
sizeof (keyclass));
sizeof (format));
goto out;
sizeof (KMF_KEY_HANDLE));
goto out;
out:
(void) kmf_finalize(kmfh);
return (0);
} else if (err == KMF_ERR_AUTH_FAILED) {
"PKCS#11 token login failed."));
} else if (numkeys == 0) {
"PKCS#11 token object not found."));
} else if (numkeys > 1) {
"keysource points to multiple PKCS#11"
" objects"));
}
return (-1);
}
struct cb_arg_curl {
char *cb_keydata;
};
/*ARGSUSED*/
static size_t
{
return (0);
return (datalen);
}
static int
{
int ret = 0;
char *uri;
"invalid keysource property."));
return (-1);
}
/*
* First check if there was anything in the handle already
* if so we use that and we are done with locating the data.
* Note that we may be looking at other fields
* and zic_clone_newkey even if zc_key_data_len is empty.
*
* We allow this regardless of the locator so that things
* like a PAM module can provide the passphrase but the user
* can still have "passphrase,prompt" to use zfs(1M) interactively.
*/
goto format_key;
}
/*
* Get the key from the URI or prompt for it.
* If the format is raw then prompting is a simple read(2)
* otherwise we put up a prompt saying what we are asking for.
* We can't do this with the 'zfs mount -a' that is in
* sys:/system/filesystem/local:default but we shouldn't
* cause errors or warnings there either.
*/
switch (locator) {
case KEY_LOCATOR_PROMPT:
if (format == KEY_FORMAT_RAW) {
errno = 0;
if (!ZFS_IOC_VALIDKEYLEN(keydatalen)) {
return (-1);
}
} else {
int tries = 0;
do {
/* get_passphrase allocates keydata */
if (ret)
return (-1);
}
break;
case KEY_LOCATOR_FILE_URI:
/*
* Need to tell pkcs11_read_data() how big of a key
* to be read from and not a file.
*
* Note that pkcs11_read_data allocates memory with malloc
* that we need to free.
*/
(void **)&keydata, &keydatalen);
if (ret != 0) {
return (-1);
}
break;
case KEY_LOCATOR_PKCS11_URI:
/*
* Parse out the PKCS#11 URI and
* get the value of the wrapping key.
*/
return (-1);
}
&keydata, &keydatalen);
if (ret != 0) {
return (-1);
}
break;
case KEY_LOCATOR_HTTPS_URI: {
goto curl_fail;
goto curl_fail;
goto curl_fail;
&cb_curl);
goto curl_fail;
/*
* Just deal with libcurl errors here, reading the wrong key
* size is dealt with generically in the format_key section.
*/
if (cerr != 0) {
"failed to retreive key from '%s': '%s'"),
return (-1);
}
break;
}
}
"key can not be of zero size"));
return (-1);
}
/*
* Now that we have the key do any transform that is necessary
* such as turning the hex format into raw or in the case of
* a passphrase running it through PKCS#5 to get the raw key.
*
* Note that zic_keydata is not malloc'd memory so that we
* don't have to worry about our caller freeing it.
*/
switch (format) {
case KEY_FORMAT_RAW:
break;
case KEY_FORMAT_HEX:
/*
* If the keylen is not on the byte boundary, in terms of hex
* format, and that extra char is a linefeed, we can trim it
*/
keydatalen--;
}
/*
* hexstr_to_bytes allocates memory with malloc
* but we want the data in zic_keydata which isn't malloc'd
* so to avoid a memory leak we use a tmpkeydata buffer
* and bcopy it.
*/
if (ret) {
"invalid hex format key."));
ret = -1;
goto out;
}
break;
case KEY_FORMAT_PASSPHRASE:
/* Remove any extra linefeed that may be on the end */
keydatalen--;
if (cmd == ZFS_CRYPTO_KEY_LOAD) {
} else {
if (ret) {
"failed to obtain salt: %s."),
ret = -1;
goto out;
}
}
if (ret) {
"failed to access CKM_PKCS5_PBKD2: %s."),
ret = -1;
goto out;
}
/*
* pkcs11_PasswdToKey allocates memory with malloc
* but we want the data in zic_keydata which isn't malloc'd
* so to avoid a memory leak we use a tmpkeydata buffer
* and bcopy it.
*/
(void) C_CloseSession(session);
if (ret) {
"failed to generate key: %s."),
ret = -1;
goto out;
}
break;
default:
}
"key must be 128, 192 or 256 bits, got %lu bits"),
ret = -1;
}
tmpkeydatalen > 0)
if (tmpkeydatalen == 0) {
"invalid all zeros key %lu"));
ret = -1;
}
out:
if (keydata) {
}
return (ret);
}
int
{
if (crypt == ZIO_CRYPT_OFF) {
}
"already loaded."));
}
"no keysource property available."));
}
if (!zfs_can_prompt_if_needed(keysource)) {
return (-1);
}
if (propsrctype & ZPROP_SRC_INHERITED) {
goto out;
}
if (ret != 0) {
ret = 0;
goto out;
}
out:
if (ret != 0) {
"incorrect key."));
"key must be loaded from global zone."));
} else if (!recursive) {
}
}
}
if (mount) {
if (recursive) {
} else {
}
}
}
}
return (ret);
}
int
{
int ret = 0;
int terrno;
"no key to unload when encryption=off."));
}
"key not present."));
}
/*
* We need to be sure that all the data has been written to
* disk before we unload the key so we first have to attempt
* an unmount, if that fails we don't continue with the key unload
* and instead return the error from zfs_umount.
*/
if (type == ZFS_TYPE_FILESYSTEM) {
if (ret) {
"failed to unload key: unmount failed"));
EZFS_KEYERR, errbuf));
}
}
}
errno = 0;
if (ret != 0) {
}
return (0);
}
int
{
}
return (0);
}
int
{
int ret;
if (crypt == ZIO_CRYPT_OFF) {
"cannot change key when encryption=off"));
goto error;
}
case ZFS_CRYPT_KEY_NONE:
"inconsistent state encryption enabled but "
"key not defined."));
"load existing key first: 'zfs key -l <dataset>'."));
goto error;
}
if (!(propsrctype & ZPROP_SRC_LOCAL ||
if (recursing)
return (0);
"keysource property not local, change key on '%s'."),
propsrc);
goto error;
}
/*
* The only thing we currently expect in props is a keysource
* if we have props without keysource then that isn't valid.
*/
char *nkeysource;
if (ret != 0) {
"invalid props for key change; expected "
"%s property missing."),
goto error;
}
}
if (!zfs_can_prompt_if_needed(keysource)) {
"unable to prompt for new wrapping key."));
goto error;
}
goto error;
}
if (ret == 0) {
/* Send change to kernel */
if (ret != 0) {
}
return (ret);
}
}
/*
* This is to verify that the proposed keysource property change via
* 'zfs set', and internal functions is valid.
*/
{
char *uri;
/*
* If we are calling this from a change key operation or a clone
* the valid keysource changes have no restrictions.
*/
return (zfs_valid_keysource(new));
}
return (B_FALSE);
}
if (propsrctype & ZPROP_SRC_INHERITED) {
return (B_FALSE);
}
/*
* If we are calling this from a set property operation, the valid
* keysources are limited to the same format
*/
if (!valid) {
return (B_FALSE);
}
if (old_format != new_format) {
return (B_FALSE);
}
return (valid);
}
/* Validate the keysource provided is a valid keysource */
{
char *uri;
return (B_FALSE);
}
/*
* zfs_crypto_zckey
*
* Called for creating new filesystems and clones and receiving.
*
* For encryption != off get the key material.
*/
int
{
int ret = 0;
int keystatus;
char *strval;
parent[0] = '\0';
"cannot create '%s'"), target);
} else if (nvlist_lookup_uint64(props,
} else {
}
}
}
if (cmd == ZFS_CRYPTO_CREATE) {
} else if (cmd == ZFS_CRYPTO_CLONE) {
"parent not found"));
ret = -1;
goto out;
}
} else if (cmd == ZFS_CRYPTO_RECV) {
(void) zfs_prop_index_to_string(
&pcrypt_str);
(void) zfs_prop_index_to_string(
"stream encryption '%s'(%llu) differs "
"from receiving dataset value '%s'(%llu)"),
pcrypt_str, pcrypt);
ret = -1;
goto out;
}
} else {
recv_clone = B_TRUE;
} else {
}
}
}
if (cmd != ZFS_CRYPTO_PCREATE) {
"parent not found"));
ret = -1;
goto out;
}
}
"encryption value. dataset must be encrypted."));
ret = -1;
goto out;
}
if (crypt == ZIO_CRYPT_INHERIT) {
}
/*
* If we have nothing to do then bail out, but make one last check
* that keysource wasn't specified when there is no crypto going on.
*/
"can not be specified when encryption is off."));
ret = -1;
goto out;
} else if (crypt == ZIO_CRYPT_OFF) {
ret = 0;
goto out;
}
/*
* Need to pass down the inherited crypt value so that
* dsl_crypto_key_gen() can see the same that we saw.
*/
/*
* Here we have encryption on so we need to find a valid keysource
* property.
*
* Now lets see if we have an explicit setting for keysource and
* we have validate it; otherwise, if we inherit then it is already
* validated.
*/
if (!inherit_keysource) {
if (!zfs_valid_keysource(keysource)) {
"invalid keysource \"%s\""), keysource);
ret = -1;
goto out;
}
/*
* If keysource is local then encryption has to be as well
* otherwise we could end up with the wrong sized keys.
*/
if (inherit_crypt) {
ZIO_CHECKSUM_SHA256_MAC) == 0);
}
} else {
/* Get the already validated keysource from our parent */
goto out;
}
"keysource must be provided."));
ret = -1;
goto out;
}
if (recv_existing) {
} else if (recv_clone) {
} else if (propsrctype == ZPROP_SRC_LOCAL ||
} else if (propsrctype == ZPROP_SRC_DEFAULT &&
pcrypt == ZIO_CRYPT_OFF) {
/*
* "Default" to "passphrase,prompt". The obvious
* thing to do would be to set this in zfs_prop.c
* as the property default. However that doesn't
* work here because we don't want keysource set
* for datasets that have encryption=off. If we
* ever change the default to encryption=on then
* the default of keysource can change too.
* This is needed because of how inheritance happens
* with defaulted properties, they show up as
* "default" not "inherit" but we need "inherit"
* to find the wrapping key if we are actually
* inheriting keysource.
*/
NV_UNIQUE_NAME, 0));
}
keysource) == 0);
ZIO_CHECKSUM_SHA256_MAC) == 0);
goto load_key;
} else if (propsrctype == ZPROP_SRC_DEFAULT &&
pcrypt != ZIO_CRYPT_OFF) {
abort();
/*
* Assume key is available and handle failure ioctl
* ENOKEY errors later.
*/
ret = 0;
goto out;
} else if (propsrctype != ZPROP_SRC_DEFAULT) {
}
/*
* AVAILABLE we are done other than filling in who we
* are inheriting the wrapping key from.
*
* UNAVAILABLE we need to load the key of a higher level
* dataset.
*/
if (keystatus == ZFS_CRYPT_KEY_AVAILABLE) {
ret = 0;
goto out;
} else if (keystatus == ZFS_CRYPT_KEY_UNAVAILABLE) {
"zfs key -l %s required."), parent);
ret = -1;
goto out;
}
}
if (!zfs_can_prompt_if_needed(keysource)) {
"unable to prompt for key material keysource = \"%s\"\n"),
return (-1);
}
if (ret != 0) {
ret = -1;
goto out;
}
ret = 0;
out:
if (pzhp)
if (keysource_free)
return (ret);
}
/*
* zfs_crypto_rename_check
*
* Can't rename "out" of same hierarchy if keysource would change.
*
* If this dataset isn't encrypted we allow the rename, unless it
* is being placed "below" an encrypted one.
*/
int
{
return (0);
/* Simple rename in place */
return (0);
}
/* parent should never be null */
"failed to obtain parent to check encryption property."));
}
/* If no crypt involved then we are done. */
return (0);
}
/* Just like create time no unencrypted below encrypted . */
"Can not move unencrypted dataset below "
"encrypted datasets."));
}
/*
* From here on we need to check that keysource is
* from the same dataset if it is being inherited
*/
"keysource must be provided."));
}
if (propsrctype == ZPROP_SRC_LOCAL ||
return (0);
}
"keysource must be provided."));
}
if (propsrctype == ZPROP_SRC_INHERITED &&
return (0);
}
"keysource doesn't allow for rename, make keysource local."));
}
{
return (!(crypt == ZIO_CRYPT_OFF));
}