2 * Copyright (c) 2005-2010 Pawel Jakub Dawidek <pjd@FreeBSD.org>
3 * Copyright (c) 2018 Sean Eric Fagan <sef@ixsystems.com>
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * Portions of this file are derived from sys/geom/eli/g_eli_hmac.c
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
33 #include <sys/types.h>
34 #include <sys/errno.h>
37 #include <sys/libkern.h>
38 #include <sys/malloc.h>
39 #include <sys/sysctl.h>
40 #include <opencrypto/cryptodev.h>
41 #include <opencrypto/xform.h>
46 #include <sys/zio_crypt.h>
47 #include <sys/fs/zfs.h>
50 #include <sys/freebsd_crypto.h>
52 #define SHA512_HMAC_BLOCK_SIZE 128
54 static int crypt_sessions
= 0;
55 SYSCTL_DECL(_vfs_zfs
);
56 SYSCTL_INT(_vfs_zfs
, OID_AUTO
, crypt_sessions
, CTLFLAG_RD
,
57 &crypt_sessions
, 0, "Number of cryptographic sessions created");
60 crypto_mac_init(struct hmac_ctx
*ctx
, const crypto_key_t
*c_key
)
62 uint8_t k_ipad
[SHA512_HMAC_BLOCK_SIZE
],
63 k_opad
[SHA512_HMAC_BLOCK_SIZE
],
64 key
[SHA512_HMAC_BLOCK_SIZE
];
67 size_t cl_bytes
= CRYPTO_BITS2BYTES(c_key
->ck_length
);
70 * This code is based on the similar code in geom/eli/g_eli_hmac.c
72 memset(key
, 0, sizeof (key
));
73 if (c_key
->ck_length
== 0)
75 else if (cl_bytes
<= SHA512_HMAC_BLOCK_SIZE
)
76 memcpy(key
, c_key
->ck_data
, cl_bytes
);
79 * If key is longer than 128 bytes reset it to
83 SHA512_Update(&lctx
, c_key
->ck_data
, cl_bytes
);
84 SHA512_Final(key
, &lctx
);
87 /* XOR key with ipad and opad values. */
88 for (i
= 0; i
< sizeof (key
); i
++) {
89 k_ipad
[i
] = key
[i
] ^ 0x36;
90 k_opad
[i
] = key
[i
] ^ 0x5c;
92 memset(key
, 0, sizeof (key
));
94 /* Start inner SHA512. */
95 SHA512_Init(&ctx
->innerctx
);
96 SHA512_Update(&ctx
->innerctx
, k_ipad
, sizeof (k_ipad
));
97 memset(k_ipad
, 0, sizeof (k_ipad
));
98 /* Start outer SHA512. */
99 SHA512_Init(&ctx
->outerctx
);
100 SHA512_Update(&ctx
->outerctx
, k_opad
, sizeof (k_opad
));
101 memset(k_opad
, 0, sizeof (k_opad
));
105 crypto_mac_update(struct hmac_ctx
*ctx
, const void *data
, size_t datasize
)
107 SHA512_Update(&ctx
->innerctx
, data
, datasize
);
111 crypto_mac_final(struct hmac_ctx
*ctx
, void *md
, size_t mdsize
)
113 uint8_t digest
[SHA512_DIGEST_LENGTH
];
115 /* Complete inner hash */
116 SHA512_Final(digest
, &ctx
->innerctx
);
118 /* Complete outer hash */
119 SHA512_Update(&ctx
->outerctx
, digest
, sizeof (digest
));
120 SHA512_Final(digest
, &ctx
->outerctx
);
122 memset(ctx
, 0, sizeof (*ctx
));
123 /* mdsize == 0 means "Give me the whole hash!" */
125 mdsize
= SHA512_DIGEST_LENGTH
;
126 memcpy(md
, digest
, mdsize
);
127 memset(digest
, 0, sizeof (digest
));
131 crypto_mac(const crypto_key_t
*key
, const void *in_data
, size_t in_data_size
,
132 void *out_data
, size_t out_data_size
)
136 crypto_mac_init(&ctx
, key
);
137 crypto_mac_update(&ctx
, in_data
, in_data_size
);
138 crypto_mac_final(&ctx
, out_data
, out_data_size
);
142 freebsd_zfs_crypt_done(struct cryptop
*crp
)
144 freebsd_crypt_session_t
*ses
;
146 ses
= crp
->crp_opaque
;
147 mtx_lock(&ses
->fs_lock
);
149 mtx_unlock(&ses
->fs_lock
);
155 freebsd_crypt_freesession(freebsd_crypt_session_t
*sess
)
157 mtx_destroy(&sess
->fs_lock
);
158 crypto_freesession(sess
->fs_sid
);
159 memset(sess
, 0, sizeof (*sess
));
163 zfs_crypto_dispatch(freebsd_crypt_session_t
*session
, struct cryptop
*crp
)
167 crp
->crp_opaque
= session
;
168 crp
->crp_callback
= freebsd_zfs_crypt_done
;
170 error
= crypto_dispatch(crp
);
173 mtx_lock(&session
->fs_lock
);
174 while (session
->fs_done
== false)
175 msleep(crp
, &session
->fs_lock
, 0,
177 mtx_unlock(&session
->fs_lock
);
179 if (crp
->crp_etype
== ENOMEM
) {
180 pause("zcrnomem", 1);
181 } else if (crp
->crp_etype
!= EAGAIN
) {
182 error
= crp
->crp_etype
;
186 crp
->crp_flags
&= ~CRYPTO_F_DONE
;
187 session
->fs_done
= false;
188 #if __FreeBSD_version < 1300087
190 * Session ID changed, so we should record that,
193 session
->fs_sid
= crp
->crp_session
;
199 freebsd_crypt_uio_debug_log(boolean_t encrypt
,
200 freebsd_crypt_session_t
*input_sessionp
,
201 const struct zio_crypt_info
*c_info
,
209 struct cryptodesc
*crd
;
213 printf("%s(%s, %p, { %s, %d, %d, %s }, %p, { %p, %u }, "
215 __FUNCTION__
, encrypt
? "encrypt" : "decrypt", input_sessionp
,
216 c_info
->ci_algname
, c_info
->ci_crypt_type
,
217 (unsigned int)c_info
->ci_keylen
, c_info
->ci_name
,
218 data_uio
, key
->ck_data
,
219 (unsigned int)key
->ck_length
,
220 ivbuf
, (unsigned int)datalen
, (unsigned int)auth_len
);
221 printf("\tkey = { ");
222 for (int i
= 0; i
< key
->ck_length
/ 8; i
++) {
223 uint8_t *b
= (uint8_t *)key
->ck_data
;
224 printf("%02x ", b
[i
]);
227 for (int i
= 0; i
< zfs_uio_iovcnt(data_uio
); i
++) {
228 printf("\tiovec #%d: <%p, %u>\n", i
,
229 zfs_uio_iovbase(data_uio
, i
),
230 (unsigned int)zfs_uio_iovlen(data_uio
, i
));
231 total
+= zfs_uio_iovlen(data_uio
, i
);
233 zfs_uio_resid(data_uio
) = total
;
237 * Create a new cryptographic session. This should
238 * happen every time the key changes (including when
239 * it's first loaded).
241 #if __FreeBSD_version >= 1300087
243 freebsd_crypt_newsession(freebsd_crypt_session_t
*sessp
,
244 const struct zio_crypt_info
*c_info
, crypto_key_t
*key
)
246 struct crypto_session_params csp
= {0};
250 printf("%s(%p, { %s, %d, %d, %s }, { %p, %u })\n",
252 c_info
->ci_algname
, c_info
->ci_crypt_type
,
253 (unsigned int)c_info
->ci_keylen
, c_info
->ci_name
,
254 key
->ck_data
, (unsigned int)key
->ck_length
);
255 printf("\tkey = { ");
256 for (int i
= 0; i
< key
->ck_length
/ 8; i
++) {
257 uint8_t *b
= (uint8_t *)key
->ck_data
;
258 printf("%02x ", b
[i
]);
262 csp
.csp_mode
= CSP_MODE_AEAD
;
263 csp
.csp_cipher_key
= key
->ck_data
;
264 csp
.csp_cipher_klen
= key
->ck_length
/ 8;
265 switch (c_info
->ci_crypt_type
) {
267 csp
.csp_cipher_alg
= CRYPTO_AES_NIST_GCM_16
;
268 csp
.csp_ivlen
= AES_GCM_IV_LEN
;
269 switch (key
->ck_length
/8) {
270 case AES_128_GMAC_KEY_LEN
:
271 case AES_192_GMAC_KEY_LEN
:
272 case AES_256_GMAC_KEY_LEN
:
280 csp
.csp_cipher_alg
= CRYPTO_AES_CCM_16
;
281 csp
.csp_ivlen
= AES_CCM_IV_LEN
;
282 switch (key
->ck_length
/8) {
283 case AES_128_CBC_MAC_KEY_LEN
:
284 case AES_192_CBC_MAC_KEY_LEN
:
285 case AES_256_CBC_MAC_KEY_LEN
:
299 * Disable the use of hardware drivers on FreeBSD 13 and later since
300 * common crypto offload drivers impose constraints on AES-GCM AAD
301 * lengths that make them unusable for ZFS, and we currently do not have
302 * a mechanism to fall back to a software driver for requests not
303 * handled by a hardware driver.
305 * On 12 we continue to permit the use of hardware drivers since
306 * CPU-accelerated drivers such as aesni(4) register themselves as
309 error
= crypto_newsession(&sessp
->fs_sid
, &csp
, CRYPTOCAP_F_SOFTWARE
);
310 mtx_init(&sessp
->fs_lock
, "FreeBSD Cryptographic Session Lock",
316 printf("%s: returning error %d\n", __FUNCTION__
, error
);
322 freebsd_crypt_uio(boolean_t encrypt
,
323 freebsd_crypt_session_t
*input_sessionp
,
324 const struct zio_crypt_info
*c_info
,
332 freebsd_crypt_session_t
*session
= NULL
;
336 freebsd_crypt_uio_debug_log(encrypt
, input_sessionp
, c_info
, data_uio
,
337 key
, ivbuf
, datalen
, auth_len
);
338 for (int i
= 0; i
< zfs_uio_iovcnt(data_uio
); i
++)
339 total
+= zfs_uio_iovlen(data_uio
, i
);
340 zfs_uio_resid(data_uio
) = total
;
341 if (input_sessionp
== NULL
) {
342 session
= kmem_zalloc(sizeof (*session
), KM_SLEEP
);
343 error
= freebsd_crypt_newsession(session
, c_info
, key
);
347 session
= input_sessionp
;
349 crp
= crypto_getreq(session
->fs_sid
, M_WAITOK
);
351 crp
->crp_op
= CRYPTO_OP_ENCRYPT
|
352 CRYPTO_OP_COMPUTE_DIGEST
;
354 crp
->crp_op
= CRYPTO_OP_DECRYPT
|
355 CRYPTO_OP_VERIFY_DIGEST
;
357 crp
->crp_flags
= CRYPTO_F_CBIFSYNC
| CRYPTO_F_IV_SEPARATE
;
358 crypto_use_uio(crp
, GET_UIO_STRUCT(data_uio
));
360 crp
->crp_aad_start
= 0;
361 crp
->crp_aad_length
= auth_len
;
362 crp
->crp_payload_start
= auth_len
;
363 crp
->crp_payload_length
= datalen
;
364 crp
->crp_digest_start
= auth_len
+ datalen
;
366 memcpy(crp
->crp_iv
, ivbuf
, ZIO_DATA_IV_LEN
);
367 error
= zfs_crypto_dispatch(session
, crp
);
372 printf("%s: returning error %d\n", __FUNCTION__
, error
);
374 if (input_sessionp
== NULL
) {
375 freebsd_crypt_freesession(session
);
376 kmem_free(session
, sizeof (*session
));
383 freebsd_crypt_newsession(freebsd_crypt_session_t
*sessp
,
384 const struct zio_crypt_info
*c_info
, crypto_key_t
*key
)
386 struct cryptoini cria
= {0}, crie
= {0}, *crip
;
387 struct enc_xform
*xform
;
388 struct auth_hash
*xauth
;
390 crypto_session_t sid
;
393 printf("%s(%p, { %s, %d, %d, %s }, { %p, %u })\n",
395 c_info
->ci_algname
, c_info
->ci_crypt_type
,
396 (unsigned int)c_info
->ci_keylen
, c_info
->ci_name
,
397 key
->ck_data
, (unsigned int)key
->ck_length
);
398 printf("\tkey = { ");
399 for (int i
= 0; i
< key
->ck_length
/ 8; i
++) {
400 uint8_t *b
= (uint8_t *)key
->ck_data
;
401 printf("%02x ", b
[i
]);
405 switch (c_info
->ci_crypt_type
) {
407 xform
= &enc_xform_aes_nist_gcm
;
408 switch (key
->ck_length
/8) {
409 case AES_128_GMAC_KEY_LEN
:
410 xauth
= &auth_hash_nist_gmac_aes_128
;
412 case AES_192_GMAC_KEY_LEN
:
413 xauth
= &auth_hash_nist_gmac_aes_192
;
415 case AES_256_GMAC_KEY_LEN
:
416 xauth
= &auth_hash_nist_gmac_aes_256
;
424 xform
= &enc_xform_ccm
;
425 switch (key
->ck_length
/8) {
426 case AES_128_CBC_MAC_KEY_LEN
:
427 xauth
= &auth_hash_ccm_cbc_mac_128
;
429 case AES_192_CBC_MAC_KEY_LEN
:
430 xauth
= &auth_hash_ccm_cbc_mac_192
;
432 case AES_256_CBC_MAC_KEY_LEN
:
433 xauth
= &auth_hash_ccm_cbc_mac_256
;
446 printf("%s(%d): Using crypt %s (key length %u [%u bytes]), "
447 "auth %s (key length %d)\n",
448 __FUNCTION__
, __LINE__
,
449 xform
->name
, (unsigned int)key
->ck_length
,
450 (unsigned int)key
->ck_length
/8,
451 xauth
->name
, xauth
->keysize
);
454 crie
.cri_alg
= xform
->type
;
455 crie
.cri_key
= key
->ck_data
;
456 crie
.cri_klen
= key
->ck_length
;
458 cria
.cri_alg
= xauth
->type
;
459 cria
.cri_key
= key
->ck_data
;
460 cria
.cri_klen
= key
->ck_length
;
462 cria
.cri_next
= &crie
;
463 crie
.cri_next
= NULL
;
465 // Everything else is zero-initialised
467 error
= crypto_newsession(&sid
, crip
,
468 CRYPTOCAP_F_HARDWARE
| CRYPTOCAP_F_SOFTWARE
);
470 printf("%s(%d): crypto_newsession failed with %d\n",
471 __FUNCTION__
, __LINE__
, error
);
475 mtx_init(&sessp
->fs_lock
, "FreeBSD Cryptographic Session Lock",
483 * The meat of encryption/decryption.
484 * If sessp is NULL, then it will create a
485 * temporary cryptographic session, and release
489 freebsd_crypt_uio(boolean_t encrypt
,
490 freebsd_crypt_session_t
*input_sessionp
,
491 const struct zio_crypt_info
*c_info
,
499 struct cryptodesc
*enc_desc
, *auth_desc
;
500 struct enc_xform
*xform
;
501 struct auth_hash
*xauth
;
502 freebsd_crypt_session_t
*session
= NULL
;
505 freebsd_crypt_uio_debug_log(encrypt
, input_sessionp
, c_info
, data_uio
,
506 key
, ivbuf
, datalen
, auth_len
);
507 switch (c_info
->ci_crypt_type
) {
509 xform
= &enc_xform_aes_nist_gcm
;
510 switch (key
->ck_length
/8) {
511 case AES_128_GMAC_KEY_LEN
:
512 xauth
= &auth_hash_nist_gmac_aes_128
;
514 case AES_192_GMAC_KEY_LEN
:
515 xauth
= &auth_hash_nist_gmac_aes_192
;
517 case AES_256_GMAC_KEY_LEN
:
518 xauth
= &auth_hash_nist_gmac_aes_256
;
526 xform
= &enc_xform_ccm
;
527 switch (key
->ck_length
/8) {
528 case AES_128_CBC_MAC_KEY_LEN
:
529 xauth
= &auth_hash_ccm_cbc_mac_128
;
531 case AES_192_CBC_MAC_KEY_LEN
:
532 xauth
= &auth_hash_ccm_cbc_mac_192
;
534 case AES_256_CBC_MAC_KEY_LEN
:
535 xauth
= &auth_hash_ccm_cbc_mac_256
;
549 printf("%s(%d): Using crypt %s (key length %u [%u bytes]), "
550 "auth %s (key length %d)\n",
551 __FUNCTION__
, __LINE__
,
552 xform
->name
, (unsigned int)key
->ck_length
,
553 (unsigned int)key
->ck_length
/8,
554 xauth
->name
, xauth
->keysize
);
557 if (input_sessionp
== NULL
) {
558 session
= kmem_zalloc(sizeof (*session
), KM_SLEEP
);
559 error
= freebsd_crypt_newsession(session
, c_info
, key
);
563 session
= input_sessionp
;
565 crp
= crypto_getreq(2);
571 auth_desc
= crp
->crp_desc
;
572 enc_desc
= auth_desc
->crd_next
;
574 crp
->crp_session
= session
->fs_sid
;
575 crp
->crp_ilen
= auth_len
+ datalen
;
576 crp
->crp_buf
= (void*)GET_UIO_STRUCT(data_uio
);
577 crp
->crp_flags
= CRYPTO_F_IOV
| CRYPTO_F_CBIFSYNC
;
579 auth_desc
->crd_skip
= 0;
580 auth_desc
->crd_len
= auth_len
;
581 auth_desc
->crd_inject
= auth_len
+ datalen
;
582 auth_desc
->crd_alg
= xauth
->type
;
584 printf("%s: auth: skip = %u, len = %u, inject = %u\n",
585 __FUNCTION__
, auth_desc
->crd_skip
, auth_desc
->crd_len
,
586 auth_desc
->crd_inject
);
589 enc_desc
->crd_skip
= auth_len
;
590 enc_desc
->crd_len
= datalen
;
591 enc_desc
->crd_inject
= auth_len
;
592 enc_desc
->crd_alg
= xform
->type
;
593 enc_desc
->crd_flags
= CRD_F_IV_EXPLICIT
| CRD_F_IV_PRESENT
;
594 memcpy(enc_desc
->crd_iv
, ivbuf
, ZIO_DATA_IV_LEN
);
595 enc_desc
->crd_next
= NULL
;
598 printf("%s: enc: skip = %u, len = %u, inject = %u\n",
599 __FUNCTION__
, enc_desc
->crd_skip
, enc_desc
->crd_len
,
600 enc_desc
->crd_inject
);
604 enc_desc
->crd_flags
|= CRD_F_ENCRYPT
;
606 error
= zfs_crypto_dispatch(session
, crp
);
609 if (input_sessionp
== NULL
) {
610 freebsd_crypt_freesession(session
);
611 kmem_free(session
, sizeof (*session
));
616 printf("%s: returning error %d\n", __FUNCTION__
, error
);