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