mirror of
https://git.sr.ht/~nabijaczleweli/tzpfms
synced 2025-04-19 09:47:35 +03:00
Store random key as dataset property
This commit is contained in:
parent
bff67ccaa6
commit
e8d4c02eda
@ -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/
|
||||
|
@ -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); }};
|
||||
|
||||
|
||||
|
@ -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); }};
|
||||
|
||||
|
||||
|
38
src/fd.cpp
38
src/fd.cpp
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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));
|
||||
}
|
||||
|
45
src/zfs.cpp
45
src/zfs.cpp
@ -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;
|
||||
}
|
||||
|
10
src/zfs.hpp
10
src/zfs.hpp
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user