1*d8f839f9SJason King /*
2*d8f839f9SJason King  * CDDL HEADER START
3*d8f839f9SJason King  *
4*d8f839f9SJason King  * This file and its contents are supplied under the terms of the
5*d8f839f9SJason King  * Common Development and Distribution License ("CDDL"), version 1.0.
6*d8f839f9SJason King  * You may only use this file in accordance with the terms of version
7*d8f839f9SJason King  * 1.0 of the CDDL.
8*d8f839f9SJason King  *
9*d8f839f9SJason King  * A full copy of the text of the CDDL should have accompanied this
10*d8f839f9SJason King  * source.  A copy of the CDDL is also available via the Internet at
11*d8f839f9SJason King  * http://www.illumos.org/license/CDDL.
12*d8f839f9SJason King  *
13*d8f839f9SJason King  * CDDL HEADER END
14*d8f839f9SJason King  */
15*d8f839f9SJason King 
16*d8f839f9SJason King /*
17*d8f839f9SJason King  * Copyright 2020 Joyent, Inc.
18*d8f839f9SJason King  */
19*d8f839f9SJason King 
20*d8f839f9SJason King #include <sys/ctype.h>
21*d8f839f9SJason King #include <sys/zcp.h>
22*d8f839f9SJason King #include <sys/zcp_change_key.h>
23*d8f839f9SJason King 
24*d8f839f9SJason King static uint8_t
hexval(char c)25*d8f839f9SJason King hexval(char c)
26*d8f839f9SJason King {
27*d8f839f9SJason King 	if (c >= '0' && c <= '9')
28*d8f839f9SJason King 		return (c - '0');
29*d8f839f9SJason King 	else if (c >= 'a' && c <= 'f')
30*d8f839f9SJason King 		return (c - 'a' + 10);
31*d8f839f9SJason King 	else if (c >= 'A' && c <= 'F')
32*d8f839f9SJason King 		return (c - 'A' + 10);
33*d8f839f9SJason King 
34*d8f839f9SJason King 	panic("invalid hex value");
35*d8f839f9SJason King }
36*d8f839f9SJason King 
37*d8f839f9SJason King static int
hex_to_raw(const char * key,uint8_t * buf,size_t buflen)38*d8f839f9SJason King hex_to_raw(const char *key, uint8_t *buf, size_t buflen)
39*d8f839f9SJason King {
40*d8f839f9SJason King 	uint8_t *p;
41*d8f839f9SJason King 	size_t srclen = strlen(key);
42*d8f839f9SJason King 	size_t i;
43*d8f839f9SJason King 
44*d8f839f9SJason King 	if (buflen * 2 != srclen)
45*d8f839f9SJason King 		return (SET_ERROR(EINVAL));
46*d8f839f9SJason King 
47*d8f839f9SJason King 	for (i = 0, p = buf; i < srclen; i += 2, p++) {
48*d8f839f9SJason King 		if (!isxdigit(key[i]) || !isxdigit(key[i + 1]))
49*d8f839f9SJason King 			return (SET_ERROR(EINVAL));
50*d8f839f9SJason King 
51*d8f839f9SJason King 		*p = hexval(key[i]) << 4 | hexval(key[i + 1]);
52*d8f839f9SJason King 	}
53*d8f839f9SJason King 
54*d8f839f9SJason King 	return (0);
55*d8f839f9SJason King }
56*d8f839f9SJason King 
57*d8f839f9SJason King int
zcp_synctask_change_key_create_params(const char * key,size_t keylen,zfs_keyformat_t keyformat,dsl_crypto_params_t ** dcpp)58*d8f839f9SJason King zcp_synctask_change_key_create_params(const char *key, size_t keylen,
59*d8f839f9SJason King     zfs_keyformat_t keyformat, dsl_crypto_params_t **dcpp)
60*d8f839f9SJason King {
61*d8f839f9SJason King 	nvlist_t *args = fnvlist_alloc();
62*d8f839f9SJason King 	nvlist_t *hidden_args = fnvlist_alloc();
63*d8f839f9SJason King 	uint8_t rawkey[WRAPPING_KEY_LEN];
64*d8f839f9SJason King 	uint_t rawlen = 0;
65*d8f839f9SJason King 	int err = 0;
66*d8f839f9SJason King 
67*d8f839f9SJason King 	/*
68*d8f839f9SJason King 	 * Currently, only raw and hex keys are supported in channel
69*d8f839f9SJason King 	 * programs (there is no pbkdf2 support in the kernel to convert
70*d8f839f9SJason King 	 * a passphrase).
71*d8f839f9SJason King 	 */
72*d8f839f9SJason King 	switch (keyformat) {
73*d8f839f9SJason King 	case ZFS_KEYFORMAT_RAW:
74*d8f839f9SJason King 		/*
75*d8f839f9SJason King 		 * dsl_crypto_params_create_nvlist() also verifies the
76*d8f839f9SJason King 		 * raw key is WRAPPING_KEY_LEN bytes, so this is
77*d8f839f9SJason King 		 * _almost_ redundant -- however we still want to
78*d8f839f9SJason King 		 * guarantee we won't overflow rawkey when copying
79*d8f839f9SJason King 		 * the contents over.
80*d8f839f9SJason King 		 */
81*d8f839f9SJason King 		if (keylen != WRAPPING_KEY_LEN) {
82*d8f839f9SJason King 			err = SET_ERROR(EINVAL);
83*d8f839f9SJason King 			goto done;
84*d8f839f9SJason King 		}
85*d8f839f9SJason King 
86*d8f839f9SJason King 		bcopy(key, rawkey, keylen);
87*d8f839f9SJason King 		rawlen = keylen;
88*d8f839f9SJason King 		break;
89*d8f839f9SJason King 	case ZFS_KEYFORMAT_HEX:
90*d8f839f9SJason King 		/*
91*d8f839f9SJason King 		 * hex_to_raw() will reject any input that doesn't exactly
92*d8f839f9SJason King 		 * fit into rawkey
93*d8f839f9SJason King 		 */
94*d8f839f9SJason King 		err = hex_to_raw(key, rawkey, sizeof (rawkey));
95*d8f839f9SJason King 		if (err != 0)
96*d8f839f9SJason King 			goto done;
97*d8f839f9SJason King 		rawlen = sizeof (rawkey);
98*d8f839f9SJason King 		break;
99*d8f839f9SJason King 	default:
100*d8f839f9SJason King 		err = SET_ERROR(EINVAL);
101*d8f839f9SJason King 		goto done;
102*d8f839f9SJason King 	}
103*d8f839f9SJason King 
104*d8f839f9SJason King 	fnvlist_add_uint64(args, zfs_prop_to_name(ZFS_PROP_KEYFORMAT),
105*d8f839f9SJason King 	    (uint64_t)keyformat);
106*d8f839f9SJason King 	fnvlist_add_uint8_array(hidden_args, "wkeydata", rawkey, rawlen);
107*d8f839f9SJason King 
108*d8f839f9SJason King 	err = dsl_crypto_params_create_nvlist(DCP_CMD_NEW_KEY, args,
109*d8f839f9SJason King 	    hidden_args, dcpp);
110*d8f839f9SJason King 
111*d8f839f9SJason King done:
112*d8f839f9SJason King 	fnvlist_free(args);
113*d8f839f9SJason King 	fnvlist_free(hidden_args);
114*d8f839f9SJason King 	bzero(rawkey, sizeof (rawkey));
115*d8f839f9SJason King 
116*d8f839f9SJason King 	return (err);
117*d8f839f9SJason King }
118*d8f839f9SJason King 
119*d8f839f9SJason King void
zcp_synctask_change_key_cleanup(void * arg)120*d8f839f9SJason King zcp_synctask_change_key_cleanup(void *arg)
121*d8f839f9SJason King {
122*d8f839f9SJason King 	spa_keystore_change_key_args_t *skcka = arg;
123*d8f839f9SJason King 
124*d8f839f9SJason King 	dsl_crypto_params_free(skcka->skcka_cp, B_TRUE);
125*d8f839f9SJason King }
126*d8f839f9SJason King 
127*d8f839f9SJason King int
zcp_synctask_change_key_check(void * arg,dmu_tx_t * tx)128*d8f839f9SJason King zcp_synctask_change_key_check(void *arg, dmu_tx_t *tx)
129*d8f839f9SJason King {
130*d8f839f9SJason King 	/*
131*d8f839f9SJason King 	 * zcp_synctask_change_key_create_params() already validates that
132*d8f839f9SJason King 	 * the new key is in an acceptable format and size for a channel
133*d8f839f9SJason King 	 * program. Any future channel program specific checks would go here.
134*d8f839f9SJason King 	 * For now, we just perform all the same checks done for
135*d8f839f9SJason King 	 * 'zfs change-key' by calling spa_keystore_change_key_check().
136*d8f839f9SJason King 	 */
137*d8f839f9SJason King 	return (spa_keystore_change_key_check(arg, tx));
138*d8f839f9SJason King }
139*d8f839f9SJason King 
140*d8f839f9SJason King void
zcp_synctask_change_key_sync(void * arg,dmu_tx_t * tx)141*d8f839f9SJason King zcp_synctask_change_key_sync(void *arg, dmu_tx_t *tx)
142*d8f839f9SJason King {
143*d8f839f9SJason King 	spa_keystore_change_key_sync(arg, tx);
144*d8f839f9SJason King }
145