ZFS crypto key adding
This commit is contained in:
parent
1bc7cc1b4d
commit
2cdc899567
4 changed files with 165 additions and 44 deletions
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 1999,2000,2001,2002,2003,2004,2009,2010 Free Software Foundation, Inc.
|
||||
* Copyright (C) 1999,2000,2001,2002,2003,2004,2009,2010,2011 Free Software Foundation, Inc.
|
||||
* Copyright 2010 Sun Microsystems, Inc.
|
||||
*
|
||||
* GRUB is free software; you can redistribute it and/or modify
|
||||
|
@ -142,6 +142,12 @@ struct grub_zfs_key
|
|||
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,
|
||||
|
@ -216,6 +222,21 @@ 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;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
zlib_decompress (void *s, void *d,
|
||||
grub_size_t slen, grub_size_t dlen)
|
||||
|
@ -2747,9 +2768,8 @@ dnode_get_fullpath (const char *fullpath, struct subvolume *subvol,
|
|||
grub_size_t elemsize)
|
||||
{
|
||||
const struct grub_zfs_key *key = val_in;
|
||||
grub_crypto_cipher_handle_t cipher;
|
||||
grub_uint8_t wrapping_key[32], decrypted[32], mac[32];
|
||||
unsigned keylen;
|
||||
struct grub_zfs_wrap_key *wrap_key;
|
||||
|
||||
if (elemsize != 1 || nelem != sizeof (*key))
|
||||
{
|
||||
|
@ -2766,51 +2786,57 @@ dnode_get_fullpath (const char *fullpath, struct subvolume *subvol,
|
|||
else
|
||||
keylen = 32;
|
||||
|
||||
grub_memset (wrapping_key, 0, sizeof (wrapping_key));
|
||||
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;
|
||||
}
|
||||
|
||||
cipher = grub_crypto_cipher_open (GRUB_CIPHER_AES);
|
||||
if (!cipher)
|
||||
{
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
return 0;
|
||||
}
|
||||
err = grub_crypto_cipher_set_key (cipher, wrapping_key, keylen);
|
||||
if (err)
|
||||
{
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
return 0;
|
||||
}
|
||||
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->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;
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
return 0;
|
||||
}
|
||||
subvol->cipher = grub_crypto_cipher_open (GRUB_CIPHER_AES);
|
||||
if (!subvol->cipher)
|
||||
{
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
return 0;
|
||||
}
|
||||
err = grub_crypto_cipher_set_key (subvol->cipher, decrypted, keylen);
|
||||
if (err)
|
||||
{
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -21,10 +21,12 @@
|
|||
#include <grub/device.h>
|
||||
#include <grub/file.h>
|
||||
#include <grub/command.h>
|
||||
#include <grub/extcmd.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/mm.h>
|
||||
#include <grub/dl.h>
|
||||
#include <grub/env.h>
|
||||
#include <grub/i18n.h>
|
||||
|
||||
GRUB_MOD_LICENSE ("GPLv3+");
|
||||
|
||||
|
@ -389,14 +391,78 @@ 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");
|
||||
|
@ -406,4 +472,5 @@ GRUB_MOD_FINI (zfsinfo)
|
|||
{
|
||||
grub_unregister_command (cmd_info);
|
||||
grub_unregister_command (cmd_bootfs);
|
||||
grub_unregister_extcmd (cmd_key);
|
||||
}
|
||||
|
|
|
@ -121,5 +121,7 @@ char *grub_zfs_nvlist_lookup_nvlist_array (const char *nvlist,
|
|||
grub_size_t index);
|
||||
int grub_zfs_nvlist_lookup_nvlist_array_get_nelm (const char *nvlist,
|
||||
const char *name);
|
||||
grub_err_t grub_zfs_add_key (grub_uint8_t *key_in);
|
||||
#define GRUB_ZFS_MAX_KEYLEN 32
|
||||
|
||||
#endif /* ! GRUB_ZFS_HEADER */
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
#include <grub/crypto.h>
|
||||
#include <grub/command.h>
|
||||
#include <grub/i18n.h>
|
||||
#include <grub/zfs/zfs.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
|
@ -438,6 +439,7 @@ static struct argp_option options[] = {
|
|||
{"diskcount", 'c', "N", 0, N_("N input files."), 2},
|
||||
{"debug", 'd', "S", 0, N_("Set debug environment variable."), 2},
|
||||
{"crypto", 'C', NULL, OPTION_ARG_OPTIONAL, N_("Mount crypto devices."), 2},
|
||||
{"zfs-key-file", 'K', N_("KEY_FILENAME"), 0, N_("Load zfs crypto key."), 2},
|
||||
{"verbose", 'v', NULL, OPTION_ARG_OPTIONAL, N_("Print verbose messages."), 2},
|
||||
{"uncompress", 'u', NULL, OPTION_ARG_OPTIONAL, N_("Uncompress data."), 2},
|
||||
{0, 0, 0, 0, 0, 0}
|
||||
|
@ -462,6 +464,30 @@ argp_parser (int key, char *arg, struct argp_state *state)
|
|||
root = arg;
|
||||
return 0;
|
||||
|
||||
case 'K':
|
||||
{
|
||||
FILE *f;
|
||||
ssize_t real_size;
|
||||
grub_uint8_t buf[GRUB_ZFS_MAX_KEYLEN];
|
||||
f = fopen (arg, "rb");
|
||||
if (!f)
|
||||
{
|
||||
printf ("Error loading file %s: %s\n", arg, strerror (errno));
|
||||
return 0;
|
||||
}
|
||||
real_size = fread (buf, 1, GRUB_ZFS_MAX_KEYLEN, f);
|
||||
if (real_size < 0)
|
||||
{
|
||||
printf ("Error loading file %s: %s\n", arg, strerror (errno));
|
||||
fclose (f);
|
||||
return 0;
|
||||
}
|
||||
if (real_size < GRUB_ZFS_MAX_KEYLEN)
|
||||
grub_memset (buf + real_size, 0, GRUB_ZFS_MAX_KEYLEN - real_size);
|
||||
grub_zfs_add_key (buf);
|
||||
}
|
||||
return 0;
|
||||
|
||||
case 'C':
|
||||
mount_crypt = 1;
|
||||
return 0;
|
||||
|
|
Loading…
Reference in a new issue