]> git.proxmox.com Git - mirror_zfs.git/blob - module/os/freebsd/zfs/crypto_os.c
Add FreeBSD support to OpenZFS
[mirror_zfs.git] / module / os / freebsd / zfs / crypto_os.c
1 /*
2 * Copyright (c) 2005-2010 Pawel Jakub Dawidek <pjd@FreeBSD.org>
3 * Copyright (c) 2018 Sean Eric Fagan <sef@ixsystems.com>
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
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.
14 *
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
25 * SUCH DAMAGE.
26 *
27 * Portions of this file are derived from sys/geom/eli/g_eli_hmac.c
28 */
29
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
32
33 #include <sys/types.h>
34 #include <sys/errno.h>
35
36 #ifdef _KERNEL
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>
42 #else
43 #include <strings.h>
44 #endif
45
46 #include <sys/zio_crypt.h>
47 #include <sys/fs/zfs.h>
48 #include <sys/zio.h>
49
50 #include <sys/freebsd_crypto.h>
51
52 #define SHA512_HMAC_BLOCK_SIZE 128
53
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");
58
59 void
60 crypto_mac_init(struct hmac_ctx *ctx, const crypto_key_t *c_key)
61 {
62 uint8_t k_ipad[SHA512_HMAC_BLOCK_SIZE],
63 k_opad[SHA512_HMAC_BLOCK_SIZE],
64 key[SHA512_HMAC_BLOCK_SIZE];
65 SHA512_CTX lctx;
66 int i;
67 size_t cl_bytes = CRYPTO_BITS2BYTES(c_key->ck_length);
68
69 /*
70 * This code is based on the similar code in geom/eli/g_eli_hmac.c
71 */
72 explicit_bzero(key, sizeof (key));
73 if (c_key->ck_length == 0)
74 /* do nothing */;
75 else if (cl_bytes <= SHA512_HMAC_BLOCK_SIZE)
76 bcopy(c_key->ck_data, key, cl_bytes);
77 else {
78 /*
79 * If key is longer than 128 bytes reset it to
80 * key = SHA512(key).
81 */
82 SHA512_Init(&lctx);
83 SHA512_Update(&lctx, c_key->ck_data, cl_bytes);
84 SHA512_Final(key, &lctx);
85 }
86
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;
91 }
92 explicit_bzero(key, sizeof (key));
93
94 /* Start inner SHA512. */
95 SHA512_Init(&ctx->innerctx);
96 SHA512_Update(&ctx->innerctx, k_ipad, sizeof (k_ipad));
97 explicit_bzero(k_ipad, sizeof (k_ipad));
98 /* Start outer SHA512. */
99 SHA512_Init(&ctx->outerctx);
100 SHA512_Update(&ctx->outerctx, k_opad, sizeof (k_opad));
101 explicit_bzero(k_opad, sizeof (k_opad));
102 }
103
104 void
105 crypto_mac_update(struct hmac_ctx *ctx, const void *data, size_t datasize)
106 {
107 SHA512_Update(&ctx->innerctx, data, datasize);
108 }
109
110 void
111 crypto_mac_final(struct hmac_ctx *ctx, void *md, size_t mdsize)
112 {
113 uint8_t digest[SHA512_DIGEST_LENGTH];
114
115 /* Complete inner hash */
116 SHA512_Final(digest, &ctx->innerctx);
117
118 /* Complete outer hash */
119 SHA512_Update(&ctx->outerctx, digest, sizeof (digest));
120 SHA512_Final(digest, &ctx->outerctx);
121
122 explicit_bzero(ctx, sizeof (*ctx));
123 /* mdsize == 0 means "Give me the whole hash!" */
124 if (mdsize == 0)
125 mdsize = SHA512_DIGEST_LENGTH;
126 bcopy(digest, md, mdsize);
127 explicit_bzero(digest, sizeof (digest));
128 }
129
130 void
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)
133 {
134 struct hmac_ctx ctx;
135
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);
139 }
140
141 static int
142 freebsd_zfs_crypt_done(struct cryptop *crp)
143 {
144 freebsd_crypt_session_t *ses;
145
146 ses = crp->crp_opaque;
147 mtx_lock(&ses->fs_lock);
148 ses->fs_done = true;
149 mtx_unlock(&ses->fs_lock);
150 wakeup(crp);
151 return (0);
152 }
153
154 void
155 freebsd_crypt_freesession(freebsd_crypt_session_t *sess)
156 {
157 mtx_destroy(&sess->fs_lock);
158 crypto_freesession(sess->fs_sid);
159 explicit_bzero(sess, sizeof (*sess));
160 }
161
162 static int
163 zfs_crypto_dispatch(freebsd_crypt_session_t *session, struct cryptop *crp)
164 {
165 int error;
166
167 crp->crp_opaque = session;
168 crp->crp_callback = freebsd_zfs_crypt_done;
169 for (;;) {
170 error = crypto_dispatch(crp);
171 if (error)
172 break;
173 mtx_lock(&session->fs_lock);
174 while (session->fs_done == false)
175 msleep(crp, &session->fs_lock, PRIBIO,
176 "zfs_crypto", hz/5);
177 mtx_unlock(&session->fs_lock);
178
179 if (crp->crp_etype != EAGAIN) {
180 error = crp->crp_etype;
181 break;
182 }
183 crp->crp_etype = 0;
184 crp->crp_flags &= ~CRYPTO_F_DONE;
185 session->fs_done = false;
186 #if __FreeBSD_version < 1300087
187 /*
188 * Session ID changed, so we should record that,
189 * and try again
190 */
191 session->fs_sid = crp->crp_session;
192 #endif
193 }
194 return (error);
195 }
196 static void
197 freebsd_crypt_uio_debug_log(boolean_t encrypt,
198 freebsd_crypt_session_t *input_sessionp,
199 struct zio_crypt_info *c_info,
200 uio_t *data_uio,
201 crypto_key_t *key,
202 uint8_t *ivbuf,
203 size_t datalen,
204 size_t auth_len)
205 {
206 #ifdef FCRYPTO_DEBUG
207 struct cryptodesc *crd;
208 uint8_t *p = NULL;
209 size_t total = 0;
210
211 printf("%s(%s, %p, { %s, %d, %d, %s }, %p, { %d, %p, %u }, "
212 "%p, %u, %u)\n",
213 __FUNCTION__, encrypt ? "encrypt" : "decrypt", input_sessionp,
214 c_info->ci_algname, c_info->ci_crypt_type,
215 (unsigned int)c_info->ci_keylen, c_info->ci_name,
216 data_uio, key->ck_format, key->ck_data,
217 (unsigned int)key->ck_length,
218 ivbuf, (unsigned int)datalen, (unsigned int)auth_len);
219 printf("\tkey = { ");
220 for (int i = 0; i < key->ck_length / 8; i++) {
221 uint8_t *b = (uint8_t *)key->ck_data;
222 printf("%02x ", b[i]);
223 }
224 printf("}\n");
225 for (int i = 0; i < data_uio->uio_iovcnt; i++) {
226 printf("\tiovec #%d: <%p, %u>\n", i,
227 data_uio->uio_iov[i].iov_base,
228 (unsigned int)data_uio->uio_iov[i].iov_len);
229 total += data_uio->uio_iov[i].iov_len;
230 }
231 data_uio->uio_resid = total;
232 #endif
233 }
234 /*
235 * Create a new cryptographic session. This should
236 * happen every time the key changes (including when
237 * it's first loaded).
238 */
239 #if __FreeBSD_version >= 1300087
240 int
241 freebsd_crypt_newsession(freebsd_crypt_session_t *sessp,
242 struct zio_crypt_info *c_info, crypto_key_t *key)
243 {
244 struct crypto_session_params csp;
245 int error = 0;
246
247 #ifdef FCRYPTO_DEBUG
248 printf("%s(%p, { %s, %d, %d, %s }, { %d, %p, %u })\n",
249 __FUNCTION__, sessp,
250 c_info->ci_algname, c_info->ci_crypt_type,
251 (unsigned int)c_info->ci_keylen, c_info->ci_name,
252 key->ck_format, key->ck_data, (unsigned int)key->ck_length);
253 printf("\tkey = { ");
254 for (int i = 0; i < key->ck_length / 8; i++) {
255 uint8_t *b = (uint8_t *)key->ck_data;
256 printf("%02x ", b[i]);
257 }
258 printf("}\n");
259 #endif
260 bzero(&csp, sizeof (csp));
261 csp.csp_mode = CSP_MODE_AEAD;
262 csp.csp_cipher_key = key->ck_data;
263 csp.csp_cipher_klen = key->ck_length / 8;
264 switch (c_info->ci_crypt_type) {
265 case ZC_TYPE_GCM:
266 csp.csp_cipher_alg = CRYPTO_AES_NIST_GCM_16;
267 csp.csp_ivlen = AES_GCM_IV_LEN;
268 switch (key->ck_length/8) {
269 case AES_128_GMAC_KEY_LEN:
270 case AES_192_GMAC_KEY_LEN:
271 case AES_256_GMAC_KEY_LEN:
272 break;
273 default:
274 error = EINVAL;
275 goto bad;
276 }
277 break;
278 case ZC_TYPE_CCM:
279 csp.csp_cipher_alg = CRYPTO_AES_CCM_16;
280 csp.csp_ivlen = AES_CCM_IV_LEN;
281 switch (key->ck_length/8) {
282 case AES_128_CBC_MAC_KEY_LEN:
283 case AES_192_CBC_MAC_KEY_LEN:
284 case AES_256_CBC_MAC_KEY_LEN:
285 break;
286 default:
287 error = EINVAL;
288 goto bad;
289 break;
290 }
291 break;
292 default:
293 error = ENOTSUP;
294 goto bad;
295 }
296 error = crypto_newsession(&sessp->fs_sid, &csp,
297 CRYPTOCAP_F_HARDWARE | CRYPTOCAP_F_SOFTWARE);
298 mtx_init(&sessp->fs_lock, "FreeBSD Cryptographic Session Lock",
299 NULL, MTX_DEF);
300 crypt_sessions++;
301 bad:
302 #ifdef FCRYPTO_DEBUG
303 if (error)
304 printf("%s: returning error %d\n", __FUNCTION__, error);
305 #endif
306 return (error);
307 }
308
309 int
310 freebsd_crypt_uio(boolean_t encrypt,
311 freebsd_crypt_session_t *input_sessionp,
312 struct zio_crypt_info *c_info,
313 uio_t *data_uio,
314 crypto_key_t *key,
315 uint8_t *ivbuf,
316 size_t datalen,
317 size_t auth_len)
318 {
319 struct cryptop *crp;
320 freebsd_crypt_session_t *session = NULL;
321 int error = 0;
322 size_t total = 0;
323
324 freebsd_crypt_uio_debug_log(encrypt, input_sessionp, c_info, data_uio,
325 key, ivbuf, datalen, auth_len);
326 for (int i = 0; i < data_uio->uio_iovcnt; i++)
327 total += data_uio->uio_iov[i].iov_len;
328 data_uio->uio_resid = total;
329 if (input_sessionp == NULL) {
330 session = kmem_zalloc(sizeof (*session), KM_SLEEP);
331 error = freebsd_crypt_newsession(session, c_info, key);
332 if (error)
333 goto out;
334 } else
335 session = input_sessionp;
336
337 crp = crypto_getreq(session->fs_sid, M_WAITOK);
338 if (encrypt) {
339 crp->crp_op = CRYPTO_OP_ENCRYPT |
340 CRYPTO_OP_COMPUTE_DIGEST;
341 } else {
342 crp->crp_op = CRYPTO_OP_DECRYPT |
343 CRYPTO_OP_VERIFY_DIGEST;
344 }
345 crp->crp_flags = CRYPTO_F_CBIFSYNC | CRYPTO_F_IV_SEPARATE;
346 crp->crp_buf_type = CRYPTO_BUF_UIO;
347 crp->crp_uio = (void*)data_uio;
348 crp->crp_ilen = data_uio->uio_resid;
349
350 crp->crp_aad_start = 0;
351 crp->crp_aad_length = auth_len;
352 crp->crp_payload_start = auth_len;
353 crp->crp_payload_length = datalen;
354 crp->crp_digest_start = auth_len + datalen;
355
356 bcopy(ivbuf, crp->crp_iv, ZIO_DATA_IV_LEN);
357 error = zfs_crypto_dispatch(session, crp);
358 crypto_freereq(crp);
359 out:
360 #ifdef FCRYPTO_DEBUG
361 if (error)
362 printf("%s: returning error %d\n", __FUNCTION__, error);
363 #endif
364 if (input_sessionp == NULL) {
365 freebsd_crypt_freesession(session);
366 kmem_free(session, sizeof (*session));
367 }
368 return (error);
369 }
370
371 #else
372 int
373 freebsd_crypt_newsession(freebsd_crypt_session_t *sessp,
374 struct zio_crypt_info *c_info, crypto_key_t *key)
375 {
376 struct cryptoini cria, crie, *crip;
377 struct enc_xform *xform;
378 struct auth_hash *xauth;
379 int error = 0;
380 crypto_session_t sid;
381
382 #ifdef FCRYPTO_DEBUG
383 printf("%s(%p, { %s, %d, %d, %s }, { %d, %p, %u })\n",
384 __FUNCTION__, sessp,
385 c_info->ci_algname, c_info->ci_crypt_type,
386 (unsigned int)c_info->ci_keylen, c_info->ci_name,
387 key->ck_format, key->ck_data, (unsigned int)key->ck_length);
388 printf("\tkey = { ");
389 for (int i = 0; i < key->ck_length / 8; i++) {
390 uint8_t *b = (uint8_t *)key->ck_data;
391 printf("%02x ", b[i]);
392 }
393 printf("}\n");
394 #endif
395 switch (c_info->ci_crypt_type) {
396 case ZC_TYPE_GCM:
397 xform = &enc_xform_aes_nist_gcm;
398 switch (key->ck_length/8) {
399 case AES_128_GMAC_KEY_LEN:
400 xauth = &auth_hash_nist_gmac_aes_128;
401 break;
402 case AES_192_GMAC_KEY_LEN:
403 xauth = &auth_hash_nist_gmac_aes_192;
404 break;
405 case AES_256_GMAC_KEY_LEN:
406 xauth = &auth_hash_nist_gmac_aes_256;
407 break;
408 default:
409 error = EINVAL;
410 goto bad;
411 }
412 break;
413 case ZC_TYPE_CCM:
414 xform = &enc_xform_ccm;
415 switch (key->ck_length/8) {
416 case AES_128_CBC_MAC_KEY_LEN:
417 xauth = &auth_hash_ccm_cbc_mac_128;
418 break;
419 case AES_192_CBC_MAC_KEY_LEN:
420 xauth = &auth_hash_ccm_cbc_mac_192;
421 break;
422 case AES_256_CBC_MAC_KEY_LEN:
423 xauth = &auth_hash_ccm_cbc_mac_256;
424 break;
425 default:
426 error = EINVAL;
427 goto bad;
428 break;
429 }
430 break;
431 default:
432 error = ENOTSUP;
433 goto bad;
434 }
435 #ifdef FCRYPTO_DEBUG
436 printf("%s(%d): Using crypt %s (key length %u [%u bytes]), "
437 "auth %s (key length %d)\n",
438 __FUNCTION__, __LINE__,
439 xform->name, (unsigned int)key->ck_length,
440 (unsigned int)key->ck_length/8,
441 xauth->name, xauth->keysize);
442 #endif
443
444 bzero(&crie, sizeof (crie));
445 bzero(&cria, sizeof (cria));
446
447 crie.cri_alg = xform->type;
448 crie.cri_key = key->ck_data;
449 crie.cri_klen = key->ck_length;
450
451 cria.cri_alg = xauth->type;
452 cria.cri_key = key->ck_data;
453 cria.cri_klen = key->ck_length;
454
455 cria.cri_next = &crie;
456 crie.cri_next = NULL;
457 crip = &cria;
458 // Everything else is bzero'd
459
460 error = crypto_newsession(&sid, crip,
461 CRYPTOCAP_F_HARDWARE | CRYPTOCAP_F_SOFTWARE);
462 if (error != 0) {
463 printf("%s(%d): crypto_newsession failed with %d\n",
464 __FUNCTION__, __LINE__, error);
465 goto bad;
466 }
467 sessp->fs_sid = sid;
468 mtx_init(&sessp->fs_lock, "FreeBSD Cryptographic Session Lock",
469 NULL, MTX_DEF);
470 crypt_sessions++;
471 bad:
472 return (error);
473 }
474
475 /*
476 * The meat of encryption/decryption.
477 * If sessp is NULL, then it will create a
478 * temporary cryptographic session, and release
479 * it when done.
480 */
481 int
482 freebsd_crypt_uio(boolean_t encrypt,
483 freebsd_crypt_session_t *input_sessionp,
484 struct zio_crypt_info *c_info,
485 uio_t *data_uio,
486 crypto_key_t *key,
487 uint8_t *ivbuf,
488 size_t datalen,
489 size_t auth_len)
490 {
491 struct cryptop *crp;
492 struct cryptodesc *enc_desc, *auth_desc;
493 struct enc_xform *xform;
494 struct auth_hash *xauth;
495 freebsd_crypt_session_t *session = NULL;
496 int error;
497
498 freebsd_crypt_uio_debug_log(encrypt, input_sessionp, c_info, data_uio,
499 key, ivbuf, datalen, auth_len);
500 switch (c_info->ci_crypt_type) {
501 case ZC_TYPE_GCM:
502 xform = &enc_xform_aes_nist_gcm;
503 switch (key->ck_length/8) {
504 case AES_128_GMAC_KEY_LEN:
505 xauth = &auth_hash_nist_gmac_aes_128;
506 break;
507 case AES_192_GMAC_KEY_LEN:
508 xauth = &auth_hash_nist_gmac_aes_192;
509 break;
510 case AES_256_GMAC_KEY_LEN:
511 xauth = &auth_hash_nist_gmac_aes_256;
512 break;
513 default:
514 error = EINVAL;
515 goto bad;
516 }
517 break;
518 case ZC_TYPE_CCM:
519 xform = &enc_xform_ccm;
520 switch (key->ck_length/8) {
521 case AES_128_CBC_MAC_KEY_LEN:
522 xauth = &auth_hash_ccm_cbc_mac_128;
523 break;
524 case AES_192_CBC_MAC_KEY_LEN:
525 xauth = &auth_hash_ccm_cbc_mac_192;
526 break;
527 case AES_256_CBC_MAC_KEY_LEN:
528 xauth = &auth_hash_ccm_cbc_mac_256;
529 break;
530 default:
531 error = EINVAL;
532 goto bad;
533 break;
534 }
535 break;
536 default:
537 error = ENOTSUP;
538 goto bad;
539 }
540
541 #ifdef FCRYPTO_DEBUG
542 printf("%s(%d): Using crypt %s (key length %u [%u bytes]), "
543 "auth %s (key length %d)\n",
544 __FUNCTION__, __LINE__,
545 xform->name, (unsigned int)key->ck_length,
546 (unsigned int)key->ck_length/8,
547 xauth->name, xauth->keysize);
548 #endif
549
550 if (input_sessionp == NULL) {
551 session = kmem_zalloc(sizeof (*session), KM_SLEEP);
552 error = freebsd_crypt_newsession(session, c_info, key);
553 if (error)
554 goto out;
555 } else
556 session = input_sessionp;
557
558 crp = crypto_getreq(2);
559 if (crp == NULL) {
560 error = ENOMEM;
561 goto bad;
562 }
563
564 auth_desc = crp->crp_desc;
565 enc_desc = auth_desc->crd_next;
566
567 crp->crp_session = session->fs_sid;
568 crp->crp_ilen = auth_len + datalen;
569 crp->crp_buf = (void*)data_uio;
570 crp->crp_flags = CRYPTO_F_IOV | CRYPTO_F_CBIFSYNC;
571
572 auth_desc->crd_skip = 0;
573 auth_desc->crd_len = auth_len;
574 auth_desc->crd_inject = auth_len + datalen;
575 auth_desc->crd_alg = xauth->type;
576 #ifdef FCRYPTO_DEBUG
577 printf("%s: auth: skip = %u, len = %u, inject = %u\n",
578 __FUNCTION__, auth_desc->crd_skip, auth_desc->crd_len,
579 auth_desc->crd_inject);
580 #endif
581
582 enc_desc->crd_skip = auth_len;
583 enc_desc->crd_len = datalen;
584 enc_desc->crd_inject = auth_len;
585 enc_desc->crd_alg = xform->type;
586 enc_desc->crd_flags = CRD_F_IV_EXPLICIT | CRD_F_IV_PRESENT;
587 bcopy(ivbuf, enc_desc->crd_iv, ZIO_DATA_IV_LEN);
588 enc_desc->crd_next = NULL;
589
590 #ifdef FCRYPTO_DEBUG
591 printf("%s: enc: skip = %u, len = %u, inject = %u\n",
592 __FUNCTION__, enc_desc->crd_skip, enc_desc->crd_len,
593 enc_desc->crd_inject);
594 #endif
595
596 if (encrypt)
597 enc_desc->crd_flags |= CRD_F_ENCRYPT;
598
599 error = zfs_crypto_dispatch(session, crp);
600 crypto_freereq(crp);
601 out:
602 if (input_sessionp == NULL) {
603 freebsd_crypt_freesession(session);
604 kmem_free(session, sizeof (*session));
605 }
606 bad:
607 #ifdef FCRYPTO_DEBUG
608 if (error)
609 printf("%s: returning error %d\n", __FUNCTION__, error);
610 #endif
611 return (error);
612 }
613 #endif