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
|
* 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.
|
* Copyright 2010 Sun Microsystems, Inc.
|
||||||
*
|
*
|
||||||
* GRUB is free software; you can redistribute it and/or modify
|
* 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];
|
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);
|
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,
|
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;
|
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
|
static grub_err_t
|
||||||
zlib_decompress (void *s, void *d,
|
zlib_decompress (void *s, void *d,
|
||||||
grub_size_t slen, grub_size_t dlen)
|
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)
|
grub_size_t elemsize)
|
||||||
{
|
{
|
||||||
const struct grub_zfs_key *key = val_in;
|
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;
|
unsigned keylen;
|
||||||
|
struct grub_zfs_wrap_key *wrap_key;
|
||||||
|
|
||||||
if (elemsize != 1 || nelem != sizeof (*key))
|
if (elemsize != 1 || nelem != sizeof (*key))
|
||||||
{
|
{
|
||||||
|
@ -2766,28 +2786,33 @@ dnode_get_fullpath (const char *fullpath, struct subvolume *subvol,
|
||||||
else
|
else
|
||||||
keylen = 32;
|
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);
|
cipher = grub_crypto_cipher_open (GRUB_CIPHER_AES);
|
||||||
if (!cipher)
|
if (!cipher)
|
||||||
{
|
{
|
||||||
grub_errno = GRUB_ERR_NONE;
|
grub_errno = GRUB_ERR_NONE;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
err = grub_crypto_cipher_set_key (cipher, wrapping_key, keylen);
|
err = grub_crypto_cipher_set_key (cipher,
|
||||||
|
(const grub_uint8_t *) wrap_key->key,
|
||||||
|
keylen);
|
||||||
if (err)
|
if (err)
|
||||||
{
|
{
|
||||||
grub_errno = GRUB_ERR_NONE;
|
grub_errno = GRUB_ERR_NONE;
|
||||||
return 0;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = grub_ccm_decrypt (cipher, decrypted, key->unknown_purpose_key, 32,
|
err = grub_ccm_decrypt (cipher, decrypted, key->unknown_purpose_key, 32,
|
||||||
mac, key->unknown_purpose_nonce, 2, 16);
|
mac, key->unknown_purpose_nonce, 2, 16);
|
||||||
if (err || grub_crypto_memcmp (mac, key->unknown_purpose_key + 32, 16) != 0)
|
if (err || (grub_crypto_memcmp (mac, key->unknown_purpose_key + 32, 16)
|
||||||
|
!= 0))
|
||||||
{
|
{
|
||||||
grub_dprintf ("zfs", "key loading failed\n");
|
grub_dprintf ("zfs", "key loading failed\n");
|
||||||
grub_errno = GRUB_ERR_NONE;
|
grub_errno = GRUB_ERR_NONE;
|
||||||
return 0;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = grub_ccm_decrypt (cipher, decrypted, key->enc_key, keylen, mac,
|
err = grub_ccm_decrypt (cipher, decrypted, key->enc_key, keylen, mac,
|
||||||
|
@ -2796,21 +2821,22 @@ dnode_get_fullpath (const char *fullpath, struct subvolume *subvol,
|
||||||
{
|
{
|
||||||
grub_dprintf ("zfs", "key loading failed\n");
|
grub_dprintf ("zfs", "key loading failed\n");
|
||||||
grub_errno = GRUB_ERR_NONE;
|
grub_errno = GRUB_ERR_NONE;
|
||||||
return 0;
|
continue;
|
||||||
}
|
}
|
||||||
subvol->cipher = grub_crypto_cipher_open (GRUB_CIPHER_AES);
|
subvol->cipher = grub_crypto_cipher_open (GRUB_CIPHER_AES);
|
||||||
if (!subvol->cipher)
|
if (!subvol->cipher)
|
||||||
{
|
{
|
||||||
grub_errno = GRUB_ERR_NONE;
|
grub_errno = GRUB_ERR_NONE;
|
||||||
return 0;
|
continue;
|
||||||
}
|
}
|
||||||
err = grub_crypto_cipher_set_key (subvol->cipher, decrypted, keylen);
|
err = grub_crypto_cipher_set_key (subvol->cipher, decrypted, keylen);
|
||||||
if (err)
|
if (err)
|
||||||
{
|
{
|
||||||
grub_errno = GRUB_ERR_NONE;
|
grub_errno = GRUB_ERR_NONE;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,10 +21,12 @@
|
||||||
#include <grub/device.h>
|
#include <grub/device.h>
|
||||||
#include <grub/file.h>
|
#include <grub/file.h>
|
||||||
#include <grub/command.h>
|
#include <grub/command.h>
|
||||||
|
#include <grub/extcmd.h>
|
||||||
#include <grub/misc.h>
|
#include <grub/misc.h>
|
||||||
#include <grub/mm.h>
|
#include <grub/mm.h>
|
||||||
#include <grub/dl.h>
|
#include <grub/dl.h>
|
||||||
#include <grub/env.h>
|
#include <grub/env.h>
|
||||||
|
#include <grub/i18n.h>
|
||||||
|
|
||||||
GRUB_MOD_LICENSE ("GPLv3+");
|
GRUB_MOD_LICENSE ("GPLv3+");
|
||||||
|
|
||||||
|
@ -389,14 +391,78 @@ grub_cmd_zfs_bootfs (grub_command_t cmd __attribute__ ((unused)), int argc,
|
||||||
return GRUB_ERR_NONE;
|
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_command_t cmd_info, cmd_bootfs;
|
||||||
|
static grub_extcmd_t cmd_key;
|
||||||
|
|
||||||
GRUB_MOD_INIT (zfsinfo)
|
GRUB_MOD_INIT (zfsinfo)
|
||||||
{
|
{
|
||||||
cmd_info = grub_register_command ("zfsinfo", grub_cmd_zfsinfo,
|
cmd_info = grub_register_command ("zfsinfo", grub_cmd_zfsinfo,
|
||||||
"zfsinfo DEVICE",
|
"zfsinfo DEVICE",
|
||||||
"Print ZFS info about 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,
|
cmd_bootfs = grub_register_command ("zfs-bootfs", grub_cmd_zfs_bootfs,
|
||||||
"zfs-bootfs FILESYSTEM [VARIABLE]",
|
"zfs-bootfs FILESYSTEM [VARIABLE]",
|
||||||
"Print ZFS-BOOTFSOBJ or set it to 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_info);
|
||||||
grub_unregister_command (cmd_bootfs);
|
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);
|
grub_size_t index);
|
||||||
int grub_zfs_nvlist_lookup_nvlist_array_get_nelm (const char *nvlist,
|
int grub_zfs_nvlist_lookup_nvlist_array_get_nelm (const char *nvlist,
|
||||||
const char *name);
|
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 */
|
#endif /* ! GRUB_ZFS_HEADER */
|
||||||
|
|
|
@ -33,6 +33,7 @@
|
||||||
#include <grub/crypto.h>
|
#include <grub/crypto.h>
|
||||||
#include <grub/command.h>
|
#include <grub/command.h>
|
||||||
#include <grub/i18n.h>
|
#include <grub/i18n.h>
|
||||||
|
#include <grub/zfs/zfs.h>
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
@ -438,6 +439,7 @@ static struct argp_option options[] = {
|
||||||
{"diskcount", 'c', "N", 0, N_("N input files."), 2},
|
{"diskcount", 'c', "N", 0, N_("N input files."), 2},
|
||||||
{"debug", 'd', "S", 0, N_("Set debug environment variable."), 2},
|
{"debug", 'd', "S", 0, N_("Set debug environment variable."), 2},
|
||||||
{"crypto", 'C', NULL, OPTION_ARG_OPTIONAL, N_("Mount crypto devices."), 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},
|
{"verbose", 'v', NULL, OPTION_ARG_OPTIONAL, N_("Print verbose messages."), 2},
|
||||||
{"uncompress", 'u', NULL, OPTION_ARG_OPTIONAL, N_("Uncompress data."), 2},
|
{"uncompress", 'u', NULL, OPTION_ARG_OPTIONAL, N_("Uncompress data."), 2},
|
||||||
{0, 0, 0, 0, 0, 0}
|
{0, 0, 0, 0, 0, 0}
|
||||||
|
@ -462,6 +464,30 @@ argp_parser (int key, char *arg, struct argp_state *state)
|
||||||
root = arg;
|
root = arg;
|
||||||
return 0;
|
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':
|
case 'C':
|
||||||
mount_crypt = 1;
|
mount_crypt = 1;
|
||||||
return 0;
|
return 0;
|
||||||
|
|
Loading…
Reference in a new issue