Skip to content

Commit

Permalink
cryptsetup: split out key loading from pkcs11 code and teach search p…
Browse files Browse the repository at this point in the history
…ath logic

Let's do some rearrangements, so that we can later on use this to
automatically search for a key file.
  • Loading branch information
poettering committed May 19, 2020
1 parent d3d49e7 commit 23769fb
Show file tree
Hide file tree
Showing 4 changed files with 128 additions and 69 deletions.
4 changes: 3 additions & 1 deletion meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -2227,8 +2227,10 @@ executable(

if conf.get('HAVE_LIBCRYPTSETUP') == 1
systemd_cryptsetup_sources = files('''
src/cryptsetup/cryptsetup.c
src/cryptsetup/cryptsetup-pkcs11.h
src/cryptsetup/cryptsetup-util.c
src/cryptsetup/cryptsetup-util.h
src/cryptsetup/cryptsetup.c
'''.split())

if conf.get('HAVE_P11KIT') == 1
Expand Down
70 changes: 2 additions & 68 deletions src/cryptsetup/cryptsetup-pkcs11.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include "alloc-util.h"
#include "ask-password-api.h"
#include "cryptsetup-pkcs11.h"
#include "cryptsetup-util.h"
#include "escape.h"
#include "fd-util.h"
#include "format-util.h"
Expand All @@ -19,73 +20,6 @@
#include "stat-util.h"
#include "strv.h"

#define KEY_FILE_SIZE_MAX (16U*1024U*1024U) /* 16 MiB */

static int load_key_file(
const char *key_file,
size_t key_file_size,
uint64_t key_file_offset,
void **ret_encrypted_key,
size_t *ret_encrypted_key_size) {

_cleanup_(erase_and_freep) char *buffer = NULL;
_cleanup_close_ int fd = -1;
ssize_t n;
int r;

assert(key_file);
assert(ret_encrypted_key);
assert(ret_encrypted_key_size);

fd = open(key_file, O_RDONLY|O_CLOEXEC);
if (fd < 0)
return log_error_errno(errno, "Failed to load encrypted PKCS#11 key: %m");

if (key_file_size == 0) {
struct stat st;

if (fstat(fd, &st) < 0)
return log_error_errno(errno, "Failed to stat key file: %m");

r = stat_verify_regular(&st);
if (r < 0)
return log_error_errno(r, "Key file is not a regular file: %m");

if (st.st_size == 0)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Key file is empty, refusing.");
if ((uint64_t) st.st_size > KEY_FILE_SIZE_MAX) {
char buf1[FORMAT_BYTES_MAX], buf2[FORMAT_BYTES_MAX];
return log_error_errno(SYNTHETIC_ERRNO(ERANGE),
"Key file larger (%s) than allowed maximum size (%s), refusing.",
format_bytes(buf1, sizeof(buf1), st.st_size),
format_bytes(buf2, sizeof(buf2), KEY_FILE_SIZE_MAX));
}

if (key_file_offset >= (uint64_t) st.st_size)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Key file offset too large for file, refusing.");

key_file_size = st.st_size - key_file_offset;
}

buffer = malloc(key_file_size);
if (!buffer)
return log_oom();

if (key_file_offset > 0)
n = pread(fd, buffer, key_file_size, key_file_offset);
else
n = read(fd, buffer, key_file_size);
if (n < 0)
return log_error_errno(errno, "Failed to read PKCS#11 key file: %m");
if (n == 0)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Empty encrypted key found, refusing.");

*ret_encrypted_key = TAKE_PTR(buffer);
*ret_encrypted_key_size = (size_t) n;

return 0;
}

struct pkcs11_callback_data {
const char *friendly_name;
usec_t until;
Expand Down Expand Up @@ -181,7 +115,7 @@ int decrypt_pkcs11_key(

/* The functions called here log about all errors, except for EAGAIN which means "token not found right now" */

r = load_key_file(key_file, key_file_size, key_file_offset, &data.encrypted_key, &data.encrypted_key_size);
r = load_key_file(key_file, NULL, key_file_size, key_file_offset, &data.encrypted_key, &data.encrypted_key_size);
if (r < 0)
return r;

Expand Down
110 changes: 110 additions & 0 deletions src/cryptsetup/cryptsetup-util.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
/* SPDX-License-Identifier: LGPL-2.1+ */

#include <unistd.h>

#include "cryptsetup-util.h"
#include "fd-util.h"
#include "format-util.h"
#include "memory-util.h"
#include "path-util.h"
#include "stat-util.h"
#include "strv.h"

#define KEY_FILE_SIZE_MAX (16U*1024U*1024U) /* 16 MiB */

int load_key_file(
const char *key_file,
char **search_path,
size_t key_file_size,
uint64_t key_file_offset,
void **ret_key,
size_t *ret_key_size) {

_cleanup_(erase_and_freep) char *buffer = NULL;
_cleanup_free_ char *discovered_path = NULL;
_cleanup_close_ int fd = -1;
ssize_t n;
int r;

assert(key_file);
assert(ret_key);
assert(ret_key_size);

if (strv_isempty(search_path) || path_is_absolute(key_file)) {
fd = open(key_file, O_RDONLY|O_CLOEXEC);
if (fd < 0)
return log_error_errno(errno, "Failed to load key file '%s': %m", key_file);
} else {
char **i;

STRV_FOREACH(i, search_path) {
_cleanup_free_ char *joined;

joined = path_join(*i, key_file);
if (!joined)
return log_oom();

fd = open(joined, O_RDONLY|O_CLOEXEC);
if (fd >= 0) {
discovered_path = TAKE_PTR(joined);
break;
}
if (errno != ENOENT)
return log_error_errno(errno, "Failed to load key file '%s': %m", joined);
}

if (!discovered_path) {
/* Search path supplied, but file not found, report by returning NULL, but not failing */
*ret_key = NULL;
*ret_key_size = 0;
return 0;
}

assert(fd >= 0);
key_file = discovered_path;
}

if (key_file_size == 0) {
struct stat st;

if (fstat(fd, &st) < 0)
return log_error_errno(errno, "Failed to stat key file '%s': %m", key_file);

r = stat_verify_regular(&st);
if (r < 0)
return log_error_errno(r, "Key file is not a regular file: %m");

if (st.st_size == 0)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Key file is empty, refusing.");
if ((uint64_t) st.st_size > KEY_FILE_SIZE_MAX) {
char buf1[FORMAT_BYTES_MAX], buf2[FORMAT_BYTES_MAX];
return log_error_errno(SYNTHETIC_ERRNO(ERANGE),
"Key file larger (%s) than allowed maximum size (%s), refusing.",
format_bytes(buf1, sizeof(buf1), st.st_size),
format_bytes(buf2, sizeof(buf2), KEY_FILE_SIZE_MAX));
}

if (key_file_offset >= (uint64_t) st.st_size)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Key file offset too large for file, refusing.");

key_file_size = st.st_size - key_file_offset;
}

buffer = malloc(key_file_size);
if (!buffer)
return log_oom();

if (key_file_offset > 0)
n = pread(fd, buffer, key_file_size, key_file_offset);
else
n = read(fd, buffer, key_file_size);
if (n < 0)
return log_error_errno(errno, "Failed to read key file '%s': %m", key_file);
if (n == 0)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Empty encrypted key found, refusing.");

*ret_key = TAKE_PTR(buffer);
*ret_key_size = (size_t) n;

return 1;
}
13 changes: 13 additions & 0 deletions src/cryptsetup/cryptsetup-util.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once

#include <inttypes.h>
#include <sys/types.h>

int load_key_file(
const char *key_file,
char **search_path,
size_t key_file_size,
uint64_t key_file_offset,
void **ret_key,
size_t *ret_key_size);

0 comments on commit 23769fb

Please sign in to comment.