diff --git a/Makefile.util.def b/Makefile.util.def index 17894b1d2..15a309367 100644 --- a/Makefile.util.def +++ b/Makefile.util.def @@ -82,6 +82,7 @@ library = { common = grub-core/fs/ufs2.c; common = grub-core/fs/ufs.c; common = grub-core/fs/xfs.c; + common = grub-core/fs/zfs/zfscrypt.c; common = grub-core/fs/zfs/zfs.c; common = grub-core/fs/zfs/zfsinfo.c; common = grub-core/fs/zfs/zfs_lzjb.c; diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def index b2e8e7aa2..9590188fb 100644 --- a/grub-core/Makefile.core.def +++ b/grub-core/Makefile.core.def @@ -1116,6 +1116,11 @@ module = { common = fs/zfs/zfs_fletcher.c; }; +module = { + name = zfscrypt; + common = fs/zfs/zfscrypt.c; +}; + module = { name = zfsinfo; common = fs/zfs/zfsinfo.c; diff --git a/grub-core/fs/zfs/zfs.c b/grub-core/fs/zfs/zfs.c index 4008d17f4..3558bd8bb 100644 --- a/grub-core/fs/zfs/zfs.c +++ b/grub-core/fs/zfs/zfs.c @@ -125,29 +125,6 @@ static grub_dl_t my_mod; #define NBBY 8 #endif -enum grub_zfs_algo - { - GRUB_ZFS_ALGO_CCM, - GRUB_ZFS_ALGO_GCM, - }; - -struct grub_zfs_key -{ - grub_uint64_t algo; - grub_uint8_t enc_nonce[13]; - grub_uint8_t unused[3]; - grub_uint8_t enc_key[48]; - grub_uint8_t unknown_purpose_nonce[13]; - grub_uint8_t unused2[3]; - grub_uint8_t unknown_purpose_key[48]; -}; - -struct grub_zfs_wrap_key -{ - struct grub_zfs_wrap_key *next; - grub_uint64_t key[GRUB_ZFS_MAX_KEYLEN / 8]; -}; - extern grub_err_t lzjb_decompress (void *, void *, grub_size_t, grub_size_t); typedef grub_err_t zfs_decomp_func_t (void *s_start, void *d_start, @@ -222,20 +199,13 @@ struct grub_zfs_data grub_uint64_t guid; }; -static struct grub_zfs_wrap_key *zfs_wrap_keys; - -grub_err_t -grub_zfs_add_key (grub_uint8_t *key_in) -{ - struct grub_zfs_wrap_key *key; - key = grub_malloc (sizeof (*key)); - if (!key) - return grub_errno; - grub_memcpy (key->key, key_in, GRUB_ZFS_MAX_KEYLEN); - key->next = zfs_wrap_keys; - zfs_wrap_keys = key; - return GRUB_ERR_NONE; -} +grub_err_t (*grub_zfs_decrypt) (grub_crypto_cipher_handle_t cipher, + void *nonce, + char *buf, grub_size_t size, + const grub_uint32_t *expected_mac, + grub_zfs_endian_t endian) = NULL; +grub_crypto_cipher_handle_t (*grub_zfs_load_key) (const struct grub_zfs_key *key, + grub_size_t keysize) = NULL; static grub_err_t zlib_decompress (void *s, void *d, @@ -409,14 +379,16 @@ static int vdev_uberblock_compare (uberblock_t * ub1, uberblock_t * ub2) { grub_zfs_endian_t ub1_endian, ub2_endian; - if (grub_zfs_to_cpu64 (ub1->ub_magic, LITTLE_ENDIAN) == UBERBLOCK_MAGIC) - ub1_endian = LITTLE_ENDIAN; + if (grub_zfs_to_cpu64 (ub1->ub_magic, GRUB_ZFS_LITTLE_ENDIAN) + == UBERBLOCK_MAGIC) + ub1_endian = GRUB_ZFS_LITTLE_ENDIAN; else - ub1_endian = BIG_ENDIAN; - if (grub_zfs_to_cpu64 (ub2->ub_magic, LITTLE_ENDIAN) == UBERBLOCK_MAGIC) - ub2_endian = LITTLE_ENDIAN; + ub1_endian = GRUB_ZFS_BIG_ENDIAN; + if (grub_zfs_to_cpu64 (ub2->ub_magic, GRUB_ZFS_LITTLE_ENDIAN) + == UBERBLOCK_MAGIC) + ub2_endian = GRUB_ZFS_LITTLE_ENDIAN; else - ub2_endian = BIG_ENDIAN; + ub2_endian = GRUB_ZFS_BIG_ENDIAN; if (grub_zfs_to_cpu64 (ub1->ub_txg, ub1_endian) < grub_zfs_to_cpu64 (ub2->ub_txg, ub2_endian)) @@ -448,20 +420,23 @@ uberblock_verify (uberblock_phys_t * ub, grub_uint64_t offset) { uberblock_t *uber = &ub->ubp_uberblock; grub_err_t err; - grub_zfs_endian_t endian = UNKNOWN_ENDIAN; + grub_zfs_endian_t endian = GRUB_ZFS_UNKNOWN_ENDIAN; zio_cksum_t zc; - if (grub_zfs_to_cpu64 (uber->ub_magic, LITTLE_ENDIAN) == UBERBLOCK_MAGIC - && grub_zfs_to_cpu64 (uber->ub_version, LITTLE_ENDIAN) > 0 - && grub_zfs_to_cpu64 (uber->ub_version, LITTLE_ENDIAN) <= SPA_VERSION) - endian = LITTLE_ENDIAN; + if (grub_zfs_to_cpu64 (uber->ub_magic, GRUB_ZFS_LITTLE_ENDIAN) + == UBERBLOCK_MAGIC + && grub_zfs_to_cpu64 (uber->ub_version, GRUB_ZFS_LITTLE_ENDIAN) > 0 + && grub_zfs_to_cpu64 (uber->ub_version, GRUB_ZFS_LITTLE_ENDIAN) + <= SPA_VERSION) + endian = GRUB_ZFS_LITTLE_ENDIAN; - if (grub_zfs_to_cpu64 (uber->ub_magic, BIG_ENDIAN) == UBERBLOCK_MAGIC - && grub_zfs_to_cpu64 (uber->ub_version, BIG_ENDIAN) > 0 - && grub_zfs_to_cpu64 (uber->ub_version, BIG_ENDIAN) <= SPA_VERSION) - endian = BIG_ENDIAN; + if (grub_zfs_to_cpu64 (uber->ub_magic, GRUB_ZFS_BIG_ENDIAN) == UBERBLOCK_MAGIC + && grub_zfs_to_cpu64 (uber->ub_version, GRUB_ZFS_BIG_ENDIAN) > 0 + && grub_zfs_to_cpu64 (uber->ub_version, GRUB_ZFS_BIG_ENDIAN) + <= SPA_VERSION) + endian = GRUB_ZFS_BIG_ENDIAN; - if (endian == UNKNOWN_ENDIAN) + if (endian == GRUB_ZFS_UNKNOWN_ENDIAN) return grub_error (GRUB_ERR_BAD_FS, "invalid uberblock magic"); grub_memset (&zc, 0, sizeof (zc)); @@ -1382,7 +1357,7 @@ zio_read_gang (blkptr_t * bp, grub_zfs_endian_t endian, dva_t * dva, void *buf, zio_gb = grub_malloc (SPA_GANGBLOCKSIZE); if (!zio_gb) return grub_errno; - grub_dprintf ("zfs", endian == LITTLE_ENDIAN ? "little-endian gang\n" + grub_dprintf ("zfs", endian == GRUB_ZFS_LITTLE_ENDIAN ? "little-endian gang\n" :"big-endian gang\n"); err = read_dva (dva, endian, data, zio_gb, SPA_GANGBLOCKSIZE); @@ -1457,57 +1432,6 @@ zio_read_data (blkptr_t * bp, grub_zfs_endian_t endian, void *buf, return err; } -static grub_err_t -grub_ccm_decrypt (grub_crypto_cipher_handle_t cipher, - grub_uint8_t *out, const grub_uint8_t *in, - grub_size_t psize, - void *mac_out, const void *nonce, - unsigned l, unsigned m) -{ - grub_uint8_t iv[16]; - grub_uint8_t mul[16]; - grub_uint32_t mac[4]; - unsigned i, j; - grub_err_t err; - - grub_memcpy (iv + 1, nonce, 15 - l); - - iv[0] = (l - 1) | (((m-2) / 2) << 3); - for (j = 0; j < l; j++) - iv[15 - j] = psize >> (8 * j); - err = grub_crypto_ecb_encrypt (cipher, mac, iv, 16); - if (err) - return err; - - iv[0] = l - 1; - - for (i = 0; i < (psize + 15) / 16; i++) - { - grub_size_t csize; - csize = 16; - if (csize > psize - 16 * i) - csize = psize - 16 * i; - for (j = 0; j < l; j++) - iv[15 - j] = (i + 1) >> (8 * j); - err = grub_crypto_ecb_encrypt (cipher, mul, iv, 16); - if (err) - return err; - grub_crypto_xor (out + 16 * i, in + 16 * i, mul, csize); - grub_crypto_xor (mac, mac, out + 16 * i, csize); - err = grub_crypto_ecb_encrypt (cipher, mac, mac, 16); - if (err) - return err; - } - for (j = 0; j < l; j++) - iv[15 - j] = 0; - err = grub_crypto_ecb_encrypt (cipher, mul, iv, 16); - if (err) - return err; - if (mac_out) - grub_crypto_xor (mac_out, mac, mul, m); - return GRUB_ERR_NONE; -} - /* * Read in a block of data, verify its checksum, decompress if needed, * and put the uncompressed data in buf. @@ -1575,41 +1499,18 @@ zio_read (blkptr_t *bp, grub_zfs_endian_t endian, void **buf, if (encrypted) { - grub_uint32_t mac[4]; - unsigned i; - grub_uint32_t sw[4]; - - grub_memcpy (sw, &(bp)->blk_dva[encrypted], 16); - for (i = 0; i < 4; i++) - sw[i] = grub_cpu_to_be32 (grub_zfs_to_cpu32 (sw[i], endian)); - - if (!data->subvol.cipher) - { - grub_free (compbuf); - *buf = NULL; - return grub_error (GRUB_ERR_ACCESS_DENIED, - "no decryption key available");; - } - err = grub_ccm_decrypt (data->subvol.cipher, - (grub_uint8_t *) compbuf, - (grub_uint8_t *) compbuf, - psize, mac, - sw + 1, 3, 12); + if (!grub_zfs_decrypt) + err = grub_error (GRUB_ERR_BAD_FS, "zfscrypto module not loaded"); + else + err = grub_zfs_decrypt (data->subvol.cipher, &(bp)->blk_dva[encrypted], + compbuf, psize, ((grub_uint32_t *) &zc + 5), + endian); if (err) { grub_free (compbuf); *buf = NULL; return err; } - - for (i = 0; i < 3; i++) - if (grub_zfs_to_cpu32 (((grub_uint32_t *) &zc + 5)[i], endian) - != grub_be_to_cpu32 (mac[i])) - { - grub_free (compbuf); - *buf = NULL; - return grub_error (GRUB_ERR_BAD_FS, "MAC verification failed"); - } } if (comp != ZIO_COMPRESS_OFF) @@ -2767,76 +2668,14 @@ dnode_get_fullpath (const char *fullpath, struct subvolume *subvol, grub_size_t nelem, grub_size_t elemsize) { - const struct grub_zfs_key *key = val_in; - unsigned keylen; - struct grub_zfs_wrap_key *wrap_key; - - if (elemsize != 1 || nelem != sizeof (*key)) + if (elemsize != 1) { - grub_dprintf ("zfs", "Unexpected key length %" PRIuGRUB_SIZE - " x %" PRIuGRUB_SIZE "\n", nelem, elemsize); + grub_dprintf ("zfs", "Unexpected key element size %" PRIuGRUB_SIZE "\n", + elemsize); return 0; } - if (grub_memcmp (key->enc_key + 32, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 16) - == 0) - keylen = 16; - else if (grub_memcmp (key->enc_key + 40, "\0\0\0\0\0\0\0\0", 8) == 0) - keylen = 24; - else - keylen = 32; - - for (wrap_key = zfs_wrap_keys; wrap_key; wrap_key = wrap_key->next) - { - grub_crypto_cipher_handle_t cipher; - grub_uint8_t decrypted[32], mac[32]; - cipher = grub_crypto_cipher_open (GRUB_CIPHER_AES); - if (!cipher) - { - grub_errno = GRUB_ERR_NONE; - return 0; - } - err = grub_crypto_cipher_set_key (cipher, - (const grub_uint8_t *) wrap_key->key, - keylen); - if (err) - { - grub_errno = GRUB_ERR_NONE; - continue; - } - - err = grub_ccm_decrypt (cipher, decrypted, key->unknown_purpose_key, 32, - mac, key->unknown_purpose_nonce, 2, 16); - if (err || (grub_crypto_memcmp (mac, key->unknown_purpose_key + 32, 16) - != 0)) - { - grub_dprintf ("zfs", "key loading failed\n"); - grub_errno = GRUB_ERR_NONE; - continue; - } - - err = grub_ccm_decrypt (cipher, decrypted, key->enc_key, keylen, mac, - key->enc_nonce, 2, 16); - if (err || grub_crypto_memcmp (mac, key->enc_key + keylen, 16) != 0) - { - grub_dprintf ("zfs", "key loading failed\n"); - grub_errno = GRUB_ERR_NONE; - continue; - } - subvol->cipher = grub_crypto_cipher_open (GRUB_CIPHER_AES); - if (!subvol->cipher) - { - grub_errno = GRUB_ERR_NONE; - continue; - } - err = grub_crypto_cipher_set_key (subvol->cipher, decrypted, keylen); - if (err) - { - grub_errno = GRUB_ERR_NONE; - continue; - } - return 0; - } + subvol->cipher = grub_zfs_load_key (val_in, nelem); return 0; } @@ -2904,7 +2743,7 @@ dnode_get_fullpath (const char *fullpath, struct subvolume *subvol, grub_dprintf ("zfs", "endian = %d\n", subvol->mdn.endian); keychainobj = grub_zfs_to_cpu64 (((dsl_dir_phys_t *) DN_BONUS (&dn->dn))->keychain, dn->endian); - if (keychainobj) + if (grub_zfs_load_key && keychainobj) { dnode_end_t keychain_dn; err = dnode_get (&(data->mos), keychainobj, DMU_OT_DSL_KEYCHAIN, @@ -2918,7 +2757,6 @@ dnode_get_fullpath (const char *fullpath, struct subvolume *subvol, zap_iterate (&keychain_dn, iterate_zap_key, data); } - if (snapname) { grub_uint64_t snapobj; @@ -3221,6 +3059,7 @@ zfs_unmount (struct grub_zfs_data *data) grub_free (data->dnode_buf); grub_free (data->dnode_mdn); grub_free (data->file_buf); + grub_crypto_cipher_close (data->subvol.cipher); grub_free (data); } @@ -3236,7 +3075,7 @@ zfs_mount (grub_device_t dev) grub_err_t err; objset_phys_t *osp = 0; grub_size_t ospsize; - grub_zfs_endian_t ub_endian = UNKNOWN_ENDIAN; + grub_zfs_endian_t ub_endian = GRUB_ZFS_UNKNOWN_ENDIAN; uberblock_t *ub; if (! dev->disk) @@ -3267,8 +3106,8 @@ zfs_mount (grub_device_t dev) ub = &(data->current_uberblock); ub_endian = (grub_zfs_to_cpu64 (ub->ub_magic, - LITTLE_ENDIAN) == UBERBLOCK_MAGIC - ? LITTLE_ENDIAN : BIG_ENDIAN); + GRUB_ZFS_LITTLE_ENDIAN) == UBERBLOCK_MAGIC + ? GRUB_ZFS_LITTLE_ENDIAN : GRUB_ZFS_BIG_ENDIAN); err = zio_read (&ub->ub_rootbp, ub_endian, (void **) &osp, &ospsize, data); @@ -3357,7 +3196,7 @@ static grub_err_t zfs_mtime (grub_device_t device, grub_int32_t *mt) { struct grub_zfs_data *data; - grub_zfs_endian_t ub_endian = UNKNOWN_ENDIAN; + grub_zfs_endian_t ub_endian = GRUB_ZFS_UNKNOWN_ENDIAN; uberblock_t *ub; *mt = 0; @@ -3368,8 +3207,8 @@ zfs_mtime (grub_device_t device, grub_int32_t *mt) ub = &(data->current_uberblock); ub_endian = (grub_zfs_to_cpu64 (ub->ub_magic, - LITTLE_ENDIAN) == UBERBLOCK_MAGIC - ? LITTLE_ENDIAN : BIG_ENDIAN); + GRUB_ZFS_LITTLE_ENDIAN) == UBERBLOCK_MAGIC + ? GRUB_ZFS_LITTLE_ENDIAN : GRUB_ZFS_BIG_ENDIAN); *mt = grub_zfs_to_cpu64 (ub->ub_timestamp, ub_endian); zfs_unmount (data); diff --git a/grub-core/fs/zfs/zfscrypt.c b/grub-core/fs/zfs/zfscrypt.c new file mode 100644 index 000000000..251538041 --- /dev/null +++ b/grub-core/fs/zfs/zfscrypt.c @@ -0,0 +1,324 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2011 Free Software Foundation, Inc. + * + * GRUB is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +GRUB_MOD_LICENSE ("GPLv3+"); + +enum grub_zfs_algo + { + GRUB_ZFS_ALGO_CCM, + GRUB_ZFS_ALGO_GCM, + }; + +struct grub_zfs_key +{ + grub_uint64_t algo; + grub_uint8_t enc_nonce[13]; + grub_uint8_t unused[3]; + grub_uint8_t enc_key[48]; + grub_uint8_t unknown_purpose_nonce[13]; + grub_uint8_t unused2[3]; + grub_uint8_t unknown_purpose_key[48]; +}; + +struct grub_zfs_wrap_key +{ + struct grub_zfs_wrap_key *next; + grub_uint64_t key[GRUB_ZFS_MAX_KEYLEN / 8]; +}; + +static struct grub_zfs_wrap_key *zfs_wrap_keys; + +grub_err_t +grub_zfs_add_key (grub_uint8_t *key_in) +{ + struct grub_zfs_wrap_key *key; + key = grub_malloc (sizeof (*key)); + if (!key) + return grub_errno; + grub_memcpy (key->key, key_in, GRUB_ZFS_MAX_KEYLEN); + key->next = zfs_wrap_keys; + zfs_wrap_keys = key; + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_ccm_decrypt (grub_crypto_cipher_handle_t cipher, + grub_uint8_t *out, const grub_uint8_t *in, + grub_size_t psize, + void *mac_out, const void *nonce, + unsigned l, unsigned m) +{ + grub_uint8_t iv[16]; + grub_uint8_t mul[16]; + grub_uint32_t mac[4]; + unsigned i, j; + grub_err_t err; + + grub_memcpy (iv + 1, nonce, 15 - l); + + iv[0] = (l - 1) | (((m-2) / 2) << 3); + for (j = 0; j < l; j++) + iv[15 - j] = psize >> (8 * j); + err = grub_crypto_ecb_encrypt (cipher, mac, iv, 16); + if (err) + return err; + + iv[0] = l - 1; + + for (i = 0; i < (psize + 15) / 16; i++) + { + grub_size_t csize; + csize = 16; + if (csize > psize - 16 * i) + csize = psize - 16 * i; + for (j = 0; j < l; j++) + iv[15 - j] = (i + 1) >> (8 * j); + err = grub_crypto_ecb_encrypt (cipher, mul, iv, 16); + if (err) + return err; + grub_crypto_xor (out + 16 * i, in + 16 * i, mul, csize); + grub_crypto_xor (mac, mac, out + 16 * i, csize); + err = grub_crypto_ecb_encrypt (cipher, mac, mac, 16); + if (err) + return err; + } + for (j = 0; j < l; j++) + iv[15 - j] = 0; + err = grub_crypto_ecb_encrypt (cipher, mul, iv, 16); + if (err) + return err; + if (mac_out) + grub_crypto_xor (mac_out, mac, mul, m); + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_zfs_decrypt_real (grub_crypto_cipher_handle_t cipher, void *nonce, + char *buf, grub_size_t size, + const grub_uint32_t *expected_mac, + grub_zfs_endian_t endian) +{ + grub_uint32_t mac[4]; + unsigned i; + grub_uint32_t sw[4]; + grub_err_t err; + + grub_memcpy (sw, nonce, 16); + for (i = 0; i < 4; i++) + sw[i] = grub_cpu_to_be32 (grub_zfs_to_cpu32 (sw[i], endian)); + + if (!cipher) + return grub_error (GRUB_ERR_ACCESS_DENIED, + "no decryption key available");; + err = grub_ccm_decrypt (cipher, + (grub_uint8_t *) buf, + (grub_uint8_t *) buf, + size, mac, + sw + 1, 3, 12); + if (err) + return err; + + for (i = 0; i < 3; i++) + if (grub_zfs_to_cpu32 (expected_mac[i], endian) + != grub_be_to_cpu32 (mac[i])) + return grub_error (GRUB_ERR_BAD_FS, "MAC verification failed"); + return GRUB_ERR_NONE; +} + +static grub_crypto_cipher_handle_t +grub_zfs_load_key_real (const struct grub_zfs_key *key, + grub_size_t keysize) +{ + unsigned keylen; + struct grub_zfs_wrap_key *wrap_key; + grub_crypto_cipher_handle_t ret = NULL; + grub_err_t err; + + if (keysize != sizeof (*key)) + { + grub_dprintf ("zfs", "Unexpected key size %" PRIuGRUB_SIZE "\n", keysize); + return 0; + } + + if (grub_memcmp (key->enc_key + 32, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 16) + == 0) + keylen = 16; + else if (grub_memcmp (key->enc_key + 40, "\0\0\0\0\0\0\0\0", 8) == 0) + keylen = 24; + else + keylen = 32; + + for (wrap_key = zfs_wrap_keys; wrap_key; wrap_key = wrap_key->next) + { + grub_crypto_cipher_handle_t cipher; + grub_uint8_t decrypted[32], mac[32]; + cipher = grub_crypto_cipher_open (GRUB_CIPHER_AES); + if (!cipher) + { + grub_errno = GRUB_ERR_NONE; + return 0; + } + err = grub_crypto_cipher_set_key (cipher, + (const grub_uint8_t *) wrap_key->key, + keylen); + if (err) + { + grub_errno = GRUB_ERR_NONE; + continue; + } + + err = grub_ccm_decrypt (cipher, decrypted, key->unknown_purpose_key, 32, + mac, key->unknown_purpose_nonce, 2, 16); + if (err || (grub_crypto_memcmp (mac, key->unknown_purpose_key + 32, 16) + != 0)) + { + grub_dprintf ("zfs", "key loading failed\n"); + grub_errno = GRUB_ERR_NONE; + continue; + } + + err = grub_ccm_decrypt (cipher, decrypted, key->enc_key, keylen, mac, + key->enc_nonce, 2, 16); + if (err || grub_crypto_memcmp (mac, key->enc_key + keylen, 16) != 0) + { + grub_dprintf ("zfs", "key loading failed\n"); + grub_errno = GRUB_ERR_NONE; + continue; + } + ret = grub_crypto_cipher_open (GRUB_CIPHER_AES); + if (!ret) + { + grub_errno = GRUB_ERR_NONE; + continue; + } + err = grub_crypto_cipher_set_key (ret, decrypted, keylen); + if (err) + { + grub_errno = GRUB_ERR_NONE; + grub_crypto_cipher_close (ret); + continue; + } + return ret; + } + return NULL; +} + +static const struct grub_arg_option options[] = + { + {"raw", 'r', 0, N_("Assume input is raw."), 0, 0}, + {"hex", 'h', 0, N_("Assume input is hex."), 0, 0}, + {"passphrase", 'p', 0, N_("Assume input is passphrase."), 0, 0}, + {0, 0, 0, 0, 0, 0} + }; + +static grub_err_t +grub_cmd_zfs_key (grub_extcmd_context_t ctxt, int argc, char **args) +{ + grub_uint8_t buf[1024]; + grub_ssize_t real_size; + + if (argc > 0) + { + grub_file_t file; + file = grub_file_open (args[0]); + if (!file) + return grub_errno; + real_size = grub_file_read (file, buf, 1024); + if (real_size < 0) + return grub_errno; + } + if (ctxt->state[0].set + || (argc > 0 && !ctxt->state[1].set && !ctxt->state[2].set)) + { + grub_err_t err; + if (real_size < GRUB_ZFS_MAX_KEYLEN) + grub_memset (buf + real_size, 0, GRUB_ZFS_MAX_KEYLEN - real_size); + err = grub_zfs_add_key (buf); + if (err) + return err; + return GRUB_ERR_NONE; + } + + if (ctxt->state[1].set) + { + int i; + grub_err_t err; + if (real_size < 2 * GRUB_ZFS_MAX_KEYLEN) + grub_memset (buf + real_size, '0', 2 * GRUB_ZFS_MAX_KEYLEN - real_size); + for (i = 0; i < GRUB_ZFS_MAX_KEYLEN; i++) + { + char c1 = grub_tolower (buf[2 * i]) - '0'; + char c2 = grub_tolower (buf[2 * i + 1]) - '0'; + if (c1 > 9) + c1 += '0' - 'a' + 10; + if (c2 > 9) + c2 += '0' - 'a' + 10; + buf[i] = (c1 << 4) | c2; + } + err = grub_zfs_add_key (buf); + if (err) + return err; + return GRUB_ERR_NONE; + } + return GRUB_ERR_NONE; +} + +static grub_extcmd_t cmd_key; + +GRUB_MOD_INIT(zfscrypto) +{ + grub_zfs_decrypt = grub_zfs_decrypt_real; + grub_zfs_load_key = grub_zfs_load_key_real; + cmd_key = grub_register_extcmd ("zfskey", grub_cmd_zfs_key, 0, + "zfskey [-h|-p|-r] [FILE]", + "Import ZFS wrapping key stored in FILE.", + options); +} + +GRUB_MOD_FINI(zfscrypto) +{ + grub_zfs_decrypt = 0; + grub_zfs_load_key = 0; + grub_unregister_extcmd (cmd_key); +} diff --git a/grub-core/fs/zfs/zfsinfo.c b/grub-core/fs/zfs/zfsinfo.c index dfc238d11..3ed2448b0 100644 --- a/grub-core/fs/zfs/zfsinfo.c +++ b/grub-core/fs/zfs/zfsinfo.c @@ -21,7 +21,6 @@ #include #include #include -#include #include #include #include @@ -391,78 +390,13 @@ grub_cmd_zfs_bootfs (grub_command_t cmd __attribute__ ((unused)), int argc, return GRUB_ERR_NONE; } -static const struct grub_arg_option options[] = - { - {"raw", 'r', 0, N_("Assume input is raw."), 0, 0}, - {"hex", 'h', 0, N_("Assume input is hex."), 0, 0}, - {"passphrase", 'p', 0, N_("Assume input is passphrase."), 0, 0}, - {0, 0, 0, 0, 0, 0} - }; - -static grub_err_t -grub_cmd_zfs_key (grub_extcmd_context_t ctxt, int argc, char **args) -{ - grub_uint8_t buf[1024]; - grub_ssize_t real_size; - - if (argc > 0) - { - grub_file_t file; - file = grub_file_open (args[0]); - if (!file) - return grub_errno; - real_size = grub_file_read (file, buf, 1024); - if (real_size < 0) - return grub_errno; - } - if (ctxt->state[0].set - || (argc > 0 && !ctxt->state[1].set && !ctxt->state[2].set)) - { - grub_err_t err; - if (real_size < GRUB_ZFS_MAX_KEYLEN) - grub_memset (buf + real_size, 0, GRUB_ZFS_MAX_KEYLEN - real_size); - err = grub_zfs_add_key (buf); - if (err) - return err; - return GRUB_ERR_NONE; - } - - if (ctxt->state[1].set) - { - int i; - grub_err_t err; - if (real_size < 2 * GRUB_ZFS_MAX_KEYLEN) - grub_memset (buf + real_size, '0', 2 * GRUB_ZFS_MAX_KEYLEN - real_size); - for (i = 0; i < GRUB_ZFS_MAX_KEYLEN; i++) - { - char c1 = grub_tolower (buf[2 * i]) - '0'; - char c2 = grub_tolower (buf[2 * i + 1]) - '0'; - if (c1 > 9) - c1 += '0' - 'a' + 10; - if (c2 > 9) - c2 += '0' - 'a' + 10; - buf[i] = (c1 << 4) | c2; - } - err = grub_zfs_add_key (buf); - if (err) - return err; - return GRUB_ERR_NONE; - } - return GRUB_ERR_NONE; -} - static grub_command_t cmd_info, cmd_bootfs; -static grub_extcmd_t cmd_key; GRUB_MOD_INIT (zfsinfo) { cmd_info = grub_register_command ("zfsinfo", grub_cmd_zfsinfo, "zfsinfo DEVICE", "Print ZFS info about DEVICE."); - cmd_key = grub_register_extcmd ("zfskey", grub_cmd_zfs_key, 0, - "zfskey [-h|-p|-r] [FILE]", - "Import ZFS wrapping key stored in FILE.", - options); cmd_bootfs = grub_register_command ("zfs-bootfs", grub_cmd_zfs_bootfs, "zfs-bootfs FILESYSTEM [VARIABLE]", "Print ZFS-BOOTFSOBJ or set it to VARIABLE"); @@ -472,5 +406,4 @@ GRUB_MOD_FINI (zfsinfo) { grub_unregister_command (cmd_info); grub_unregister_command (cmd_bootfs); - grub_unregister_extcmd (cmd_key); } diff --git a/grub-core/lib/crypto.c b/grub-core/lib/crypto.c index f858be9c6..4dec5c694 100644 --- a/grub-core/lib/crypto.c +++ b/grub-core/lib/crypto.c @@ -169,14 +169,6 @@ grub_crypto_cipher_set_key (grub_crypto_cipher_handle_t cipher, return cipher->cipher->setkey (cipher->ctx, key, keylen); } - -void -grub_crypto_cipher_close (grub_crypto_cipher_handle_t cipher) -{ - grub_free (cipher); -} - - void grub_crypto_xor (void *out, const void *in1, const void *in2, grub_size_t size) { diff --git a/include/grub/crypto.h b/include/grub/crypto.h index 573893a3e..b8a5b3a22 100644 --- a/include/grub/crypto.h +++ b/include/grub/crypto.h @@ -26,6 +26,7 @@ #include #include #include +#include typedef enum { @@ -191,8 +192,11 @@ grub_crypto_cipher_set_key (grub_crypto_cipher_handle_t cipher, const unsigned char *key, unsigned keylen); -void -grub_crypto_cipher_close (grub_crypto_cipher_handle_t cipher); +static inline void +grub_crypto_cipher_close (grub_crypto_cipher_handle_t cipher) +{ + grub_free (cipher); +} void grub_crypto_xor (void *out, const void *in1, const void *in2, grub_size_t size); diff --git a/include/grub/zfs/spa.h b/include/grub/zfs/spa.h index 22ee03b15..0e29fa44a 100644 --- a/include/grub/zfs/spa.h +++ b/include/grub/zfs/spa.h @@ -20,26 +20,24 @@ #ifndef GRUB_ZFS_SPA_HEADER #define GRUB_ZFS_SPA_HEADER 1 -typedef enum grub_zfs_endian - { - UNKNOWN_ENDIAN = -2, - LITTLE_ENDIAN = -1, - BIG_ENDIAN = 0 - } grub_zfs_endian_t; - -#define grub_zfs_to_cpu16(x,a) (((a) == BIG_ENDIAN) ? grub_be_to_cpu16(x) \ +#define grub_zfs_to_cpu16(x,a) (((a) == GRUB_ZFS_BIG_ENDIAN) ? \ + grub_be_to_cpu16(x) \ : grub_le_to_cpu16(x)) -#define grub_cpu_to_zfs16(x,a) (((a) == BIG_ENDIAN) ? grub_cpu_to_be16(x) \ +#define grub_cpu_to_zfs16(x,a) (((a) == GRUB_ZFS_BIG_ENDIAN) ? \ + grub_cpu_to_be16(x) \ : grub_cpu_to_le16(x)) -#define grub_zfs_to_cpu32(x,a) (((a) == BIG_ENDIAN) ? grub_be_to_cpu32(x) \ +#define grub_zfs_to_cpu32(x,a) (((a) == GRUB_ZFS_BIG_ENDIAN) ? \ + grub_be_to_cpu32(x) \ : grub_le_to_cpu32(x)) -#define grub_cpu_to_zfs32(x,a) (((a) == BIG_ENDIAN) ? grub_cpu_to_be32(x) \ +#define grub_cpu_to_zfs32(x,a) (((a) == GRUB_ZFS_BIG_ENDIAN) ? \ + grub_cpu_to_be32(x) \ : grub_cpu_to_le32(x)) -#define grub_zfs_to_cpu64(x,a) (((a) == BIG_ENDIAN) ? grub_be_to_cpu64(x) \ +#define grub_zfs_to_cpu64(x,a) (((a) == GRUB_ZFS_BIG_ENDIAN) \ + ? grub_be_to_cpu64(x) \ : grub_le_to_cpu64(x)) -#define grub_cpu_to_zfs64(x,a) (((a) == BIG_ENDIAN) ? grub_cpu_to_be64(x) \ +#define grub_cpu_to_zfs64(x,a) (((a) == GRUB_ZFS_BIG_ENDIAN) ? grub_cpu_to_be64(x) \ : grub_cpu_to_le64(x)) /* diff --git a/include/grub/zfs/zfs.h b/include/grub/zfs/zfs.h index 62b72776e..6c280bfe2 100644 --- a/include/grub/zfs/zfs.h +++ b/include/grub/zfs/zfs.h @@ -24,6 +24,14 @@ #include #include +#include + +typedef enum grub_zfs_endian + { + GRUB_ZFS_UNKNOWN_ENDIAN = -2, + GRUB_ZFS_LITTLE_ENDIAN = -1, + GRUB_ZFS_BIG_ENDIAN = 0 + } grub_zfs_endian_t; /* * On-disk version number. @@ -124,4 +132,17 @@ int grub_zfs_nvlist_lookup_nvlist_array_get_nelm (const char *nvlist, grub_err_t grub_zfs_add_key (grub_uint8_t *key_in); #define GRUB_ZFS_MAX_KEYLEN 32 +extern grub_err_t (*grub_zfs_decrypt) (grub_crypto_cipher_handle_t cipher, + void *nonce, + char *buf, grub_size_t size, + const grub_uint32_t *expected_mac, + grub_zfs_endian_t endian); + +struct grub_zfs_key; + +extern grub_crypto_cipher_handle_t (*grub_zfs_load_key) (const struct grub_zfs_key *key, + grub_size_t keysize); + + + #endif /* ! GRUB_ZFS_HEADER */