Store random key as dataset property

This commit is contained in:
наб 2020-10-15 12:21:17 +02:00
parent bff67ccaa6
commit e8d4c02eda
No known key found for this signature in database
GPG Key ID: BCFD0B018D2658F1
8 changed files with 177 additions and 36 deletions

View File

@ -56,8 +56,8 @@ LDD ?= ldd
AWK ?= awk
PATCHELF ?= patchelf
OBJ := .o
CXXAR := -O3 -std=c++17 -fno-exceptions -Wall -Wextra $(CXXSPECIFIC) -pipe $(INCCXXAR) $(PIC)
STRIP ?= strip
CXXAR := -g -O3 -std=c++17 -fno-exceptions -Wall -Wextra $(CXXSPECIFIC) -pipe $(INCCXXAR) $(PIC)
STRIP ?= @echo strip
STRIPAR := --strip-all --remove-section=.comment --remove-section=.note
OUTDIR := out/

View File

@ -12,23 +12,42 @@
#include "../zfs.hpp"
static const constexpr uint8_t our_test_key[WRAPPING_KEY_LEN] = {
0xe2, 0xac, 0xf7, 0x89, 0x32, 0x37, 0xcb, 0x94, 0x67, 0xeb, 0x2b, 0xe9, 0xa3, 0x48, 0x83, 0x72,
0xd5, 0x4c, 0xc5, 0x1c, 0x99, 0x65, 0xb0, 0x8d, 0x05, 0xa6, 0xd5, 0xff, 0x7a, 0xf7, 0xeb, 0xfc,
};
int main(int argc, char ** argv) {
const char * backup{};
return do_main(
argc, argv, "", [](auto) {},
[](auto dataset) {
argc, argv, "b:", [&](auto) { backup = optarg; },
[&](auto dataset) {
if(zfs_prop_get_int(dataset, ZFS_PROP_KEYSTATUS) == ZFS_KEYSTATUS_UNAVAILABLE) {
fprintf(stderr, "Key change error: Key must be loaded.\n"); // mimic libzfs error output
return __LINE__;
}
uint8_t wrap_key[WRAPPING_KEY_LEN];
TRY_MAIN(read_exact("/dev/random", wrap_key, sizeof(wrap_key)));
if(backup)
TRY_MAIN(write_exact(backup, wrap_key, sizeof(wrap_key), 0400));
auto wrap_key_s = static_cast<char *>(TRY_PTR("wrap_key_s", alloca(WRAPPING_KEY_LEN * 2 + 1)));
{
auto cur = wrap_key_s;
for(auto kb : wrap_key) {
*cur++ = "0123456789ABCDEF"[(kb >> 4) & 0x0F];
*cur++ = "0123456789ABCDEF"[(kb >> 0) & 0x0F];
}
*cur = '\0';
}
TRY_MAIN(zfs_prop_set(dataset, "xyz.nabijaczleweli:tzpfms.key", wrap_key_s));
/// zfs_crypto_rewrap() with "prompt" reads from stdin, but not if it's a TTY;
/// this user-proofs the set-up, and means we don't have to touch the filesysten:
/// instead, get an FD, write the raw key data there, dup() it onto stdin,
/// let libzfs read it, then restore stdin
int key_fd;
TRY_MAIN(filled_fd(key_fd, (void *)our_test_key, WRAPPING_KEY_LEN));
TRY_MAIN(filled_fd(key_fd, wrap_key, WRAPPING_KEY_LEN));
quickscope_wrapper key_fd_deleter{[=] { close(key_fd); }};

View File

@ -2,28 +2,83 @@
#include <libzfs.h>
// #include <sys/zio_crypt.h>
#define WRAPPING_KEY_LEN 32
#include <stdio.h>
#include "../fd.hpp"
#include "../main.hpp"
#include "../zfs.hpp"
static const constexpr uint8_t our_test_key[WRAPPING_KEY_LEN] = {
0xe2, 0xac, 0xf7, 0x89, 0x32, 0x37, 0xcb, 0x94, 0x67, 0xeb, 0x2b, 0xe9, 0xa3, 0x48, 0x83, 0x72,
0xd5, 0x4c, 0xc5, 0x1c, 0x99, 0x65, 0xb0, 0x8d, 0x05, 0xa6, 0xd5, 0xff, 0x7a, 0xf7, 0xeb, 0xfc,
};
static int hex_nibble(char c) {
switch(c) {
case '0':
return 0x0;
case '1':
return 0x1;
case '2':
return 0x2;
case '3':
return 0x3;
case '4':
return 0x4;
case '5':
return 0x5;
case '6':
return 0x6;
case '7':
return 0x7;
case '8':
return 0x8;
case '9':
return 0x9;
case 'A':
case 'a':
return 0xA;
case 'B':
case 'b':
return 0xB;
case 'C':
case 'c':
return 0xC;
case 'D':
case 'd':
return 0xD;
case 'E':
case 'e':
return 0xE;
case 'F':
case 'f':
return 0xF;
default:
fprintf(stderr, "Character %c (0x%02X) not hex?\n", c, static_cast<int>(c));
return 0;
}
}
int main(int argc, char ** argv) {
auto noop = B_FALSE;
return do_main(
argc, argv, "n", [&](char) { noop = B_TRUE; },
argc, argv, "n", [&](auto) { noop = B_TRUE; },
[&](auto dataset) {
char * stored_key_s{};
TRY_MAIN(lookup_userprop(zfs_get_user_props(dataset), "xyz.nabijaczleweli:tzpfms.key", stored_key_s));
errno = EEXIST;
TRY_PTR("find encryption key prop", stored_key_s);
auto stored_key_len = strlen(stored_key_s) / 2;
auto stored_key = static_cast<uint8_t *>(TRY_PTR("stored_key", alloca(stored_key_len)));
{
auto cur = stored_key_s;
for(auto kcur = stored_key; kcur < stored_key + stored_key_len; ++kcur) {
*kcur = (hex_nibble(cur[0]) << 4) | hex_nibble(cur[1]);
cur += 2;
}
}
int key_fd;
TRY_MAIN(filled_fd(key_fd, (void *)our_test_key, WRAPPING_KEY_LEN));
TRY_MAIN(filled_fd(key_fd, (void *)stored_key, stored_key_len));
quickscope_wrapper key_fd_deleter{[=] { close(key_fd); }};

View File

@ -1,8 +1,13 @@
/* SPDX-License-Identifier: MIT */
/* SPDX-License-Identifier: MIT */
#include "fd.hpp"
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
int filled_fd(int & fd, const void * with, size_t with_len) {
int pipes[2];
@ -19,3 +24,34 @@ int filled_fd(int & fd, const void * with, size_t with_len) {
return 0;
}
int read_exact(const char * path, void * data, size_t len) {
auto infd = TRY("open input file", open(path, O_RDONLY));
quickscope_wrapper infd_deleter{[=] { close(infd); }};
while(len)
if(const auto rd = TRY("read input file", read(infd, data, len))) {
len -= rd;
data = static_cast<char *>(data) + rd;
} else {
fprintf(stderr, "Couldn't read %zu bytes from input file: too short\n", len);
return __LINE__;
}
return 0;
}
int write_exact(const char * path, const void * data, size_t len, mode_t mode) {
auto outfd = TRY("open output file", open(path, O_WRONLY | O_CREAT | O_EXCL, mode));
quickscope_wrapper infd_deleter{[=] { close(outfd); }};
while(len) {
const auto rd = TRY("write to output file", write(outfd, data, len));
len -= rd;
data = static_cast<const char *>(data) + rd;
}
return 0;
}

View File

@ -26,3 +26,9 @@ int with_stdin_at(int fd, F && what) {
/// with_len may not exceed pipe capacity (64k by default)
extern int filled_fd(int & fd, const void * with, size_t with_len);
/// Read exactly len bytes from path into data, or error
extern int read_exact(const char * path, void * data, size_t len);
/// Write exactly len bytes from data into path, or error
extern int write_exact(const char * path, const void * data, size_t len, mode_t mode);

View File

@ -5,6 +5,7 @@
#include "common.hpp"
#include <libzfs.h>
#include <stdlib.h>
#include <unistd.h>
@ -51,7 +52,6 @@ int do_main(int argc, char ** argv, const char * getoptions, G && getoptfn, M &&
} else if(!dataset_is_root) {
printf("Using dataset %s's encryption root %s instead.\n", zfs_get_name(dataset), encryption_root);
// TODO: disallow maybe? or require force option?
strcpy(argv[1], encryption_root);
zfs_close(dataset);
dataset = TRY_PTR(nullptr, zfs_open(libz, encryption_root, ZFS_TYPE_FILESYSTEM));
}

View File

@ -7,27 +7,44 @@
#include <libzfs.h>
#define TRY_NVL(what, ...) TRY_GENERIC(what, , , _try_ret, _try_ret, __VA_ARGS__)
// Funxion statics pull in libc++'s __cxa_guard_acquire()
static nvlist_t * rrargs{};
static quickscope_wrapper ret_deleter{[] { nvlist_free(rrargs); }};
nvlist_t * rewrap_args() {
static nvlist_t * ret{};
static quickscope_wrapper ret_deleter{[&] { nvlist_free(ret); }};
if(!ret)
if(!rrargs)
if(auto err =
[&] {
TRY_NVL("allocate rewrap nvlist", nvlist_alloc(&ret, NV_UNIQUE_NAME, 0));
TRY_NVL("allocate rewrap nvlist", nvlist_alloc(&rrargs, NV_UNIQUE_NAME, 0));
TRY_NVL("add keyformat to rewrap nvlist",
nvlist_add_string(ret, zfs_prop_to_name(ZFS_PROP_KEYFORMAT), "raw")); // Why can't this be uint64 and ZFS_KEYFORMAT_RAW?
TRY_NVL("add keylocation to rewrap nvlist", nvlist_add_string(ret, zfs_prop_to_name(ZFS_PROP_KEYLOCATION), "prompt"));
nvlist_add_string(rrargs, zfs_prop_to_name(ZFS_PROP_KEYFORMAT), "raw")); // Why can't this be uint64 and ZFS_KEYFORMAT_RAW?
TRY_NVL("add keylocation to rewrap nvlist", nvlist_add_string(rrargs, zfs_prop_to_name(ZFS_PROP_KEYLOCATION), "prompt"));
return 0;
}();
err && ret) {
nvlist_free(ret);
ret = nullptr;
err && rrargs) {
nvlist_free(rrargs);
rrargs = nullptr;
errno = err;
}
return ret;
return rrargs;
}
#define TRY_LOOKUP(what, ...) \
({ \
const auto _try_retl = (__VA_ARGS__); \
if(_try_retl == ENOENT) \
return 0; \
TRY_NVL(what, _try_retl); \
})
int lookup_userprop(nvlist_t * from, const char * name, char *& out) {
// xyz.nabijaczleweli:tzpfms.key:
// value: '76B0286BEB3FAF57536C47D9A2BAD38157FD522A75A59E72867BBFD6AF167395'
// source: 'owo/enc'
nvlist_t * vs{};
TRY_LOOKUP("look up user property", nvlist_lookup_nvlist(from, name, &vs));
TRY_LOOKUP("look up user property value", nvlist_lookup_string(vs, "value", &out));
return 0;
}

View File

@ -4,12 +4,20 @@
#pragma once
#include <libnvpair.h>
#include <sys/nvpair.h>
// #include <libzfs.h>
// #include <sys/fs/zfs.h>
//// #include <sys/zio_crypt.h>
// #define WRAPPING_KEY_LEN 32
#define TRY_NVL(what, ...) TRY_GENERIC(what, , , _try_ret, _try_ret, __VA_ARGS__)
/// Static nvlist with {keyformat=raw, keylocation=prompt}
extern nvlist_t * rewrap_args();
/// Extract user property name from ZFS property list from to out.
///
/// Returns success but does not touch out on not found.
extern int lookup_userprop(nvlist_t * from, const char * name, char*&out);