]> git.proxmox.com Git - mirror_zfs.git/blobdiff - module/zfs/zio_crypt.c
Encryption patch follow-up
[mirror_zfs.git] / module / zfs / zio_crypt.c
index 8fcf5155005387bba6a305ec43c1630a8c619224..6238e6f74ac6cde2bf220865d4d63bde0d7a68a0 100644 (file)
@@ -25,6 +25,7 @@
 #include <sys/zio.h>
 #include <sys/zil.h>
 #include <sys/sha2.h>
+#include <sys/hkdf.h>
 
 /*
  * This file is responsible for handling all of the details of generating
@@ -198,176 +199,6 @@ zio_crypt_info_t zio_crypt_table[ZIO_CRYPT_FUNCTIONS] = {
        {SUN_CKM_AES_GCM,       ZC_TYPE_GCM,    32,     "aes-256-gcm"}
 };
 
-static int
-hkdf_sha512_extract(uint8_t *salt, uint_t salt_len, uint8_t *key_material,
-    uint_t km_len, uint8_t *out_buf)
-{
-       int ret;
-       crypto_mechanism_t mech;
-       crypto_key_t key;
-       crypto_data_t input_cd, output_cd;
-
-       /* initialize HMAC mechanism */
-       mech.cm_type = crypto_mech2id(SUN_CKM_SHA512_HMAC);
-       mech.cm_param = NULL;
-       mech.cm_param_len = 0;
-
-       /* initialize the salt as a crypto key */
-       key.ck_format = CRYPTO_KEY_RAW;
-       key.ck_length = BYTES_TO_BITS(salt_len);
-       key.ck_data = salt;
-
-       /* initialize crypto data for the input and output data */
-       input_cd.cd_format = CRYPTO_DATA_RAW;
-       input_cd.cd_offset = 0;
-       input_cd.cd_length = km_len;
-       input_cd.cd_raw.iov_base = (char *)key_material;
-       input_cd.cd_raw.iov_len = input_cd.cd_length;
-
-       output_cd.cd_format = CRYPTO_DATA_RAW;
-       output_cd.cd_offset = 0;
-       output_cd.cd_length = SHA512_DIGEST_LEN;
-       output_cd.cd_raw.iov_base = (char *)out_buf;
-       output_cd.cd_raw.iov_len = output_cd.cd_length;
-
-       ret = crypto_mac(&mech, &input_cd, &key, NULL, &output_cd, NULL);
-       if (ret != CRYPTO_SUCCESS) {
-               ret = SET_ERROR(EIO);
-               goto error;
-       }
-
-       return (0);
-
-error:
-       return (ret);
-}
-
-static int
-hkdf_sha512_expand(uint8_t *extract_key, uint8_t *info, uint_t info_len,
-    uint8_t *out_buf, uint_t out_len)
-{
-       int ret;
-       crypto_mechanism_t mech;
-       crypto_context_t ctx;
-       crypto_key_t key;
-       crypto_data_t T_cd, info_cd, c_cd;
-       uint_t i, T_len = 0, pos = 0;
-       uint8_t c;
-       uint_t N = (out_len + SHA512_DIGEST_LEN) / SHA512_DIGEST_LEN;
-       uint8_t T[SHA512_DIGEST_LEN];
-
-       if (N > 255)
-               return (SET_ERROR(EINVAL));
-
-       /* initialize HMAC mechanism */
-       mech.cm_type = crypto_mech2id(SUN_CKM_SHA512_HMAC);
-       mech.cm_param = NULL;
-       mech.cm_param_len = 0;
-
-       /* initialize the salt as a crypto key */
-       key.ck_format = CRYPTO_KEY_RAW;
-       key.ck_length = BYTES_TO_BITS(SHA512_DIGEST_LEN);
-       key.ck_data = extract_key;
-
-       /* initialize crypto data for the input and output data */
-       T_cd.cd_format = CRYPTO_DATA_RAW;
-       T_cd.cd_offset = 0;
-       T_cd.cd_raw.iov_base = (char *)T;
-
-       c_cd.cd_format = CRYPTO_DATA_RAW;
-       c_cd.cd_offset = 0;
-       c_cd.cd_length = 1;
-       c_cd.cd_raw.iov_base = (char *)&c;
-       c_cd.cd_raw.iov_len = c_cd.cd_length;
-
-       info_cd.cd_format = CRYPTO_DATA_RAW;
-       info_cd.cd_offset = 0;
-       info_cd.cd_length = info_len;
-       info_cd.cd_raw.iov_base = (char *)info;
-       info_cd.cd_raw.iov_len = info_cd.cd_length;
-
-       for (i = 1; i <= N; i++) {
-               c = i;
-
-               T_cd.cd_length = T_len;
-               T_cd.cd_raw.iov_len = T_cd.cd_length;
-
-               ret = crypto_mac_init(&mech, &key, NULL, &ctx, NULL);
-               if (ret != CRYPTO_SUCCESS) {
-                       ret = SET_ERROR(EIO);
-                       goto error;
-               }
-
-               ret = crypto_mac_update(ctx, &T_cd, NULL);
-               if (ret != CRYPTO_SUCCESS) {
-                       ret = SET_ERROR(EIO);
-                       goto error;
-               }
-
-               ret = crypto_mac_update(ctx, &info_cd, NULL);
-               if (ret != CRYPTO_SUCCESS) {
-                       ret = SET_ERROR(EIO);
-                       goto error;
-               }
-
-               ret = crypto_mac_update(ctx, &c_cd, NULL);
-               if (ret != CRYPTO_SUCCESS) {
-                       ret = SET_ERROR(EIO);
-                       goto error;
-               }
-
-               T_len = SHA512_DIGEST_LEN;
-               T_cd.cd_length = T_len;
-               T_cd.cd_raw.iov_len = T_cd.cd_length;
-
-               ret = crypto_mac_final(ctx, &T_cd, NULL);
-               if (ret != CRYPTO_SUCCESS) {
-                       ret = SET_ERROR(EIO);
-                       goto error;
-               }
-
-               bcopy(T, out_buf + pos,
-                   (i != N) ? SHA512_DIGEST_LEN : (out_len - pos));
-               pos += SHA512_DIGEST_LEN;
-       }
-
-       return (0);
-
-error:
-       return (ret);
-}
-
-/*
- * HKDF is designed to be a relatively fast function for deriving keys from a
- * master key + a salt. We use this function to generate new encryption keys
- * so as to avoid hitting the cryptographic limits of the underlying
- * encryption modes. Note that, for the sake of deriving encryption keys, the
- * info parameter is called the "salt" everywhere else in the code.
- */
-static int
-hkdf_sha512(uint8_t *key_material, uint_t km_len, uint8_t *salt,
-    uint_t salt_len, uint8_t *info, uint_t info_len, uint8_t *output_key,
-    uint_t out_len)
-{
-       int ret;
-       uint8_t extract_key[SHA512_DIGEST_LEN];
-
-       ret = hkdf_sha512_extract(salt, salt_len, key_material, km_len,
-           extract_key);
-       if (ret != 0)
-               goto error;
-
-       ret = hkdf_sha512_expand(extract_key, info, info_len, output_key,
-           out_len);
-       if (ret != 0)
-               goto error;
-
-       return (0);
-
-error:
-       return (ret);
-}
-
 void
 zio_crypt_key_destroy(zio_crypt_key_t *key)
 {
@@ -421,11 +252,11 @@ zio_crypt_key_init(uint64_t crypt, zio_crypt_key_t *key)
        /* initialize keys for the ICP */
        key->zk_current_key.ck_format = CRYPTO_KEY_RAW;
        key->zk_current_key.ck_data = key->zk_current_keydata;
-       key->zk_current_key.ck_length = BYTES_TO_BITS(keydata_len);
+       key->zk_current_key.ck_length = CRYPTO_BYTES2BITS(keydata_len);
 
        key->zk_hmac_key.ck_format = CRYPTO_KEY_RAW;
        key->zk_hmac_key.ck_data = &key->zk_hmac_key;
-       key->zk_hmac_key.ck_length = BYTES_TO_BITS(SHA512_HMAC_KEYLEN);
+       key->zk_hmac_key.ck_length = CRYPTO_BYTES2BITS(SHA512_HMAC_KEYLEN);
 
        /*
         * Initialize the crypto templates. It's ok if this fails because
@@ -588,10 +419,10 @@ zio_do_crypt_uio(boolean_t encrypt, uint64_t crypt, crypto_key_t *key,
                mech.cm_param_len = sizeof (CK_AES_CCM_PARAMS);
        } else {
                gcmp.ulIvLen = ZIO_DATA_IV_LEN;
-               gcmp.ulIvBits = BYTES_TO_BITS(ZIO_DATA_IV_LEN);
+               gcmp.ulIvBits = CRYPTO_BYTES2BITS(ZIO_DATA_IV_LEN);
                gcmp.ulAADLen = auth_len;
                gcmp.pAAD = authbuf;
-               gcmp.ulTagBits = BYTES_TO_BITS(maclen);
+               gcmp.ulTagBits = CRYPTO_BYTES2BITS(maclen);
                gcmp.pIv = ivbuf;
 
                mech.cm_param = (char *)(&gcmp);
@@ -748,11 +579,11 @@ zio_crypt_key_unwrap(crypto_key_t *cwkey, uint64_t crypt, uint64_t guid,
        /* initialize keys for ICP */
        key->zk_current_key.ck_format = CRYPTO_KEY_RAW;
        key->zk_current_key.ck_data = key->zk_current_keydata;
-       key->zk_current_key.ck_length = BYTES_TO_BITS(keydata_len);
+       key->zk_current_key.ck_length = CRYPTO_BYTES2BITS(keydata_len);
 
        key->zk_hmac_key.ck_format = CRYPTO_KEY_RAW;
        key->zk_hmac_key.ck_data = key->zk_hmac_keydata;
-       key->zk_hmac_key.ck_length = BYTES_TO_BITS(SHA512_HMAC_KEYLEN);
+       key->zk_hmac_key.ck_length = CRYPTO_BYTES2BITS(SHA512_HMAC_KEYLEN);
 
        /*
         * Initialize the crypto templates. It's ok if this fails because
@@ -801,12 +632,14 @@ error:
 
 int
 zio_crypt_do_hmac(zio_crypt_key_t *key, uint8_t *data, uint_t datalen,
-    uint8_t *digestbuf)
+    uint8_t *digestbuf, uint_t digestlen)
 {
        int ret;
        crypto_mechanism_t mech;
        crypto_data_t in_data, digest_data;
-       uint8_t raw_digestbuf[SHA512_DIGEST_LEN];
+       uint8_t raw_digestbuf[SHA512_DIGEST_LENGTH];
+
+       ASSERT3U(digestlen, <=, SHA512_DIGEST_LENGTH);
 
        /* initialize sha512-hmac mechanism and crypto data */
        mech.cm_type = crypto_mech2id(SUN_CKM_SHA512_HMAC);
@@ -822,7 +655,7 @@ zio_crypt_do_hmac(zio_crypt_key_t *key, uint8_t *data, uint_t datalen,
 
        digest_data.cd_format = CRYPTO_DATA_RAW;
        digest_data.cd_offset = 0;
-       digest_data.cd_length = SHA512_DIGEST_LEN;
+       digest_data.cd_length = SHA512_DIGEST_LENGTH;
        digest_data.cd_raw.iov_base = (char *)raw_digestbuf;
        digest_data.cd_raw.iov_len = digest_data.cd_length;
 
@@ -834,12 +667,12 @@ zio_crypt_do_hmac(zio_crypt_key_t *key, uint8_t *data, uint_t datalen,
                goto error;
        }
 
-       bcopy(raw_digestbuf, digestbuf, ZIO_DATA_MAC_LEN);
+       bcopy(raw_digestbuf, digestbuf, digestlen);
 
        return (0);
 
 error:
-       bzero(digestbuf, ZIO_DATA_MAC_LEN);
+       bzero(digestbuf, digestlen);
        return (ret);
 }
 
@@ -848,9 +681,10 @@ zio_crypt_generate_iv_salt_dedup(zio_crypt_key_t *key, uint8_t *data,
     uint_t datalen, uint8_t *ivbuf, uint8_t *salt)
 {
        int ret;
-       uint8_t digestbuf[SHA512_DIGEST_LEN];
+       uint8_t digestbuf[SHA512_DIGEST_LENGTH];
 
-       ret = zio_crypt_do_hmac(key, data, datalen, digestbuf);
+       ret = zio_crypt_do_hmac(key, data, datalen,
+           digestbuf, SHA512_DIGEST_LENGTH);
        if (ret != 0)
                return (ret);
 
@@ -1212,8 +1046,8 @@ zio_crypt_do_objset_hmacs(zio_crypt_key_t *key, void *data, uint_t datalen,
        objset_phys_t *osp = data;
        uint64_t intval;
        boolean_t le_bswap = (should_bswap == ZFS_HOST_BYTEORDER);
-       uint8_t raw_portable_mac[SHA512_DIGEST_LEN];
-       uint8_t raw_local_mac[SHA512_DIGEST_LEN];
+       uint8_t raw_portable_mac[SHA512_DIGEST_LENGTH];
+       uint8_t raw_local_mac[SHA512_DIGEST_LENGTH];
 
        /* initialize HMAC mechanism */
        mech.cm_type = crypto_mech2id(SUN_CKM_SHA512_HMAC);
@@ -1267,7 +1101,7 @@ zio_crypt_do_objset_hmacs(zio_crypt_key_t *key, void *data, uint_t datalen,
                goto error;
 
        /* store the final digest in a temporary buffer and copy what we need */
-       cd.cd_length = SHA512_DIGEST_LEN;
+       cd.cd_length = SHA512_DIGEST_LENGTH;
        cd.cd_raw.iov_base = (char *)raw_portable_mac;
        cd.cd_raw.iov_len = cd.cd_length;
 
@@ -1284,7 +1118,7 @@ zio_crypt_do_objset_hmacs(zio_crypt_key_t *key, void *data, uint_t datalen,
         * objects are not present, the local MAC is zeroed out.
         */
        if (osp->os_userused_dnode.dn_type == DMU_OT_NONE &&
-           osp->os_userused_dnode.dn_type == DMU_OT_NONE) {
+           osp->os_groupused_dnode.dn_type == DMU_OT_NONE) {
                bzero(local_mac, ZIO_OBJSET_MAC_LEN);
                return (0);
        }
@@ -1326,7 +1160,7 @@ zio_crypt_do_objset_hmacs(zio_crypt_key_t *key, void *data, uint_t datalen,
                goto error;
 
        /* store the final digest in a temporary buffer and copy what we need */
-       cd.cd_length = SHA512_DIGEST_LEN;
+       cd.cd_length = SHA512_DIGEST_LENGTH;
        cd.cd_raw.iov_base = (char *)raw_local_mac;
        cd.cd_raw.iov_len = cd.cd_length;
 
@@ -1367,7 +1201,7 @@ zio_crypt_do_indirect_mac_checksum(boolean_t generate, void *buf,
        blkptr_t *bp;
        int i, epb = datalen >> SPA_BLKPTRSHIFT;
        SHA2_CTX ctx;
-       uint8_t digestbuf[SHA512_DIGEST_LEN];
+       uint8_t digestbuf[SHA512_DIGEST_LENGTH];
 
        /* checksum all of the MACs from the layer below */
        SHA2Init(SHA512, &ctx);
@@ -1468,7 +1302,7 @@ zio_crypt_init_uios_zil(boolean_t encrypt, uint8_t *plainbuf,
        /* allocate the iovec arrays */
        if (nr_src != 0) {
                src_iovecs = kmem_alloc(nr_src * sizeof (iovec_t), KM_SLEEP);
-               if (!src_iovecs) {
+               if (src_iovecs == NULL) {
                        ret = SET_ERROR(ENOMEM);
                        goto error;
                }
@@ -1476,7 +1310,7 @@ zio_crypt_init_uios_zil(boolean_t encrypt, uint8_t *plainbuf,
 
        if (nr_dst != 0) {
                dst_iovecs = kmem_alloc(nr_dst * sizeof (iovec_t), KM_SLEEP);
-               if (!dst_iovecs) {
+               if (dst_iovecs == NULL) {
                        ret = SET_ERROR(ENOMEM);
                        goto error;
                }
@@ -1515,6 +1349,9 @@ zio_crypt_init_uios_zil(boolean_t encrypt, uint8_t *plainbuf,
                aadp += sizeof (lr_t);
                aad_len += sizeof (lr_t);
 
+               ASSERT3P(src_iovecs, !=, NULL);
+               ASSERT3P(dst_iovecs, !=, NULL);
+
                /*
                 * If this is a TX_WRITE record we want to encrypt everything
                 * except the bp if exists. If the bp does exist we want to
@@ -1655,7 +1492,7 @@ zio_crypt_init_uios_dnode(boolean_t encrypt, uint8_t *plainbuf,
 
        if (nr_src != 0) {
                src_iovecs = kmem_alloc(nr_src * sizeof (iovec_t), KM_SLEEP);
-               if (!src_iovecs) {
+               if (src_iovecs == NULL) {
                        ret = SET_ERROR(ENOMEM);
                        goto error;
                }
@@ -1663,7 +1500,7 @@ zio_crypt_init_uios_dnode(boolean_t encrypt, uint8_t *plainbuf,
 
        if (nr_dst != 0) {
                dst_iovecs = kmem_alloc(nr_dst * sizeof (iovec_t), KM_SLEEP);
-               if (!dst_iovecs) {
+               if (dst_iovecs == NULL) {
                        ret = SET_ERROR(ENOMEM);
                        goto error;
                }
@@ -1729,6 +1566,10 @@ zio_crypt_init_uios_dnode(boolean_t encrypt, uint8_t *plainbuf,
                if (dnp->dn_type != DMU_OT_NONE &&
                    DMU_OT_IS_ENCRYPTED(dnp->dn_bonustype) &&
                    dnp->dn_bonuslen != 0) {
+                       ASSERT3U(nr_iovecs, <, nr_src);
+                       ASSERT3U(nr_iovecs, <, nr_dst);
+                       ASSERT3P(src_iovecs, !=, NULL);
+                       ASSERT3P(dst_iovecs, !=, NULL);
                        src_iovecs[nr_iovecs].iov_base = DN_BONUS(dnp);
                        src_iovecs[nr_iovecs].iov_len = crypt_len;
                        dst_iovecs[nr_iovecs].iov_base = DN_BONUS(&ddnp[i]);
@@ -1942,7 +1783,7 @@ zio_do_crypt_data(boolean_t encrypt, zio_crypt_key_t *key, uint8_t *salt,
 
                tmp_ckey.ck_format = CRYPTO_KEY_RAW;
                tmp_ckey.ck_data = enc_keydata;
-               tmp_ckey.ck_length = BYTES_TO_BITS(keydata_len);
+               tmp_ckey.ck_length = CRYPTO_BYTES2BITS(keydata_len);
 
                ckey = &tmp_ckey;
                tmpl = NULL;