pkcs11: switch to RSA-OAEP SHA-256/SHA-1
RSA PKCS#1 v1.5 is vulnerable to Bleichenbacher-style padding oracle attacks, albeit very difficult and unlikely to actually happen in the real world. Still for hardedning, switch new enrollments to RSA-OAEP, with SHA-256 preferred and SHA-1 as fallback (probed at enrollment time, since e.g. SoftHSM only accepts SHA-1, and older token might as well). The actual padding scheme used to wrap a given key is recorded as a new optional 'pkcs11-padding' / 'padding' field in the LUKS2 token JSON and the homed user record. Decryption defaults to PKCS#1 v1.5 when absent so existing enrollments keep working.
This commit is contained in:
@@ -16,6 +16,7 @@ int decrypt_pkcs11_key(
|
||||
const char *volume_name,
|
||||
const char *friendly_name,
|
||||
const char *pkcs11_uri,
|
||||
Pkcs11RsaPadding rsa_padding,
|
||||
const char *key_file, /* We either expect key_file and associated parameters to be set (for file keys) … */
|
||||
size_t key_file_size,
|
||||
uint64_t key_file_offset,
|
||||
@@ -29,6 +30,7 @@ int decrypt_pkcs11_key(
|
||||
.friendly_name = friendly_name,
|
||||
.askpw_flags = askpw_flags,
|
||||
.until = until,
|
||||
.rsa_padding = rsa_padding,
|
||||
};
|
||||
int r;
|
||||
|
||||
@@ -83,6 +85,7 @@ int find_pkcs11_auto_data(
|
||||
char **ret_uri,
|
||||
void **ret_encrypted_key,
|
||||
size_t *ret_encrypted_key_size,
|
||||
Pkcs11RsaPadding *ret_rsa_padding,
|
||||
int *ret_keyslot) {
|
||||
|
||||
#if HAVE_P11KIT
|
||||
@@ -90,11 +93,13 @@ int find_pkcs11_auto_data(
|
||||
_cleanup_free_ void *key = NULL;
|
||||
int r, keyslot = -1;
|
||||
size_t key_size = 0;
|
||||
Pkcs11RsaPadding rsa_padding = PKCS11_RSA_PADDING_PKCS1V15;
|
||||
|
||||
assert(cd);
|
||||
assert(ret_uri);
|
||||
assert(ret_encrypted_key);
|
||||
assert(ret_encrypted_key_size);
|
||||
assert(ret_rsa_padding);
|
||||
assert(ret_keyslot);
|
||||
|
||||
/* Loads PKCS#11 metadata from LUKS2 JSON token headers. */
|
||||
@@ -148,6 +153,22 @@ int find_pkcs11_auto_data(
|
||||
r = sd_json_variant_unbase64(w, &key, &key_size);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to decode base64 encoded key: %m");
|
||||
|
||||
/* Optional padding-scheme tag. Absent in legacy tokens (which used PKCS#1 v1.5). */
|
||||
w = sd_json_variant_by_key(v, "pkcs11-padding");
|
||||
if (w) {
|
||||
Pkcs11RsaPadding p;
|
||||
|
||||
if (!sd_json_variant_is_string(w))
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"PKCS#11 token field 'pkcs11-padding' is not a string.");
|
||||
p = pkcs11_rsa_padding_from_string(sd_json_variant_string(w));
|
||||
if (p < 0)
|
||||
return log_error_errno(p,
|
||||
"PKCS#11 token field 'pkcs11-padding' has unsupported value '%s'.",
|
||||
sd_json_variant_string(w));
|
||||
rsa_padding = p;
|
||||
}
|
||||
}
|
||||
|
||||
if (!uri)
|
||||
@@ -159,6 +180,7 @@ int find_pkcs11_auto_data(
|
||||
*ret_uri = TAKE_PTR(uri);
|
||||
*ret_encrypted_key = TAKE_PTR(key);
|
||||
*ret_encrypted_key_size = key_size;
|
||||
*ret_rsa_padding = rsa_padding;
|
||||
*ret_keyslot = keyslot;
|
||||
return 0;
|
||||
#else
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#pragma once
|
||||
|
||||
#include "pkcs11-padding.h"
|
||||
#include "shared-forward.h"
|
||||
|
||||
int decrypt_pkcs11_key(
|
||||
const char *volume_name,
|
||||
const char *friendly_name,
|
||||
const char *pkcs11_uri,
|
||||
Pkcs11RsaPadding rsa_padding,
|
||||
const char *key_file,
|
||||
size_t key_file_size,
|
||||
uint64_t key_file_offset,
|
||||
@@ -21,4 +23,5 @@ int find_pkcs11_auto_data(
|
||||
char **ret_uri,
|
||||
void **ret_encrypted_key,
|
||||
size_t *ret_encrypted_key_size,
|
||||
Pkcs11RsaPadding *ret_rsa_padding,
|
||||
int *ret_keyslot);
|
||||
|
||||
@@ -93,11 +93,12 @@ _public_ void cryptsetup_token_dump(
|
||||
size_t pkcs11_key_size;
|
||||
_cleanup_free_ char *pkcs11_uri = NULL, *key_str = NULL;
|
||||
_cleanup_free_ void *pkcs11_key = NULL;
|
||||
Pkcs11RsaPadding rsa_padding = PKCS11_RSA_PADDING_PKCS1V15;
|
||||
|
||||
if (dlopen_cryptsetup(LOG_DEBUG) < 0)
|
||||
return;
|
||||
|
||||
r = parse_luks2_pkcs11_data(cd, json, &pkcs11_uri, &pkcs11_key, &pkcs11_key_size);
|
||||
r = parse_luks2_pkcs11_data(cd, json, &pkcs11_uri, &pkcs11_key, &pkcs11_key_size, &rsa_padding);
|
||||
if (r < 0)
|
||||
return (void) crypt_log_debug_errno(cd, r, "Failed to parse " TOKEN_NAME " metadata: %m.");
|
||||
|
||||
@@ -107,6 +108,7 @@ _public_ void cryptsetup_token_dump(
|
||||
|
||||
crypt_log(cd, "\tpkcs11-uri: %s\n", pkcs11_uri);
|
||||
crypt_log(cd, "\tpkcs11-key: %s\n", key_str);
|
||||
crypt_log(cd, "\tpkcs11-padding: %s\n", pkcs11_rsa_padding_to_string(rsa_padding));
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -152,5 +154,19 @@ _public_ int cryptsetup_token_validate(
|
||||
if (r < 0)
|
||||
return crypt_log_debug_errno(cd, r, "Failed to decode base64 encoded key: %m.");
|
||||
|
||||
/* Optional 'pkcs11-padding' field: must be a known padding scheme string if present. Older systemd
|
||||
* versions will just ignore this field entirely and assume PKCS#1 v1.5. */
|
||||
w = sd_json_variant_by_key(v, "pkcs11-padding");
|
||||
if (w) {
|
||||
if (!sd_json_variant_is_string(w)) {
|
||||
crypt_log_debug(cd, "PKCS#11 token field 'pkcs11-padding' is not a string.");
|
||||
return 1;
|
||||
}
|
||||
if (pkcs11_rsa_padding_from_string(sd_json_variant_string(w)) < 0) {
|
||||
crypt_log_debug(cd, "PKCS#11 token field 'pkcs11-padding' has unsupported value.");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ struct luks2_pkcs11_callback_data {
|
||||
size_t pin_size;
|
||||
void *encrypted_key;
|
||||
size_t encrypted_key_size;
|
||||
Pkcs11RsaPadding rsa_padding;
|
||||
void *decrypted_key;
|
||||
size_t decrypted_key_size;
|
||||
};
|
||||
@@ -90,6 +91,7 @@ static int luks2_pkcs11_callback(
|
||||
object,
|
||||
data->encrypted_key,
|
||||
data->encrypted_key_size,
|
||||
data->rsa_padding,
|
||||
&data->decrypted_key,
|
||||
&data->decrypted_key_size);
|
||||
if (r < 0)
|
||||
@@ -109,6 +111,7 @@ static int acquire_luks2_key_by_pin(
|
||||
size_t pin_size,
|
||||
void *encrypted_key,
|
||||
size_t encrypted_key_size,
|
||||
Pkcs11RsaPadding rsa_padding,
|
||||
void **ret_decrypted_key,
|
||||
size_t *ret_decrypted_key_size) {
|
||||
|
||||
@@ -119,6 +122,7 @@ static int acquire_luks2_key_by_pin(
|
||||
.pin_size = pin_size,
|
||||
.encrypted_key = encrypted_key,
|
||||
.encrypted_key_size = encrypted_key_size,
|
||||
.rsa_padding = rsa_padding,
|
||||
};
|
||||
|
||||
assert(pkcs11_uri);
|
||||
@@ -142,6 +146,7 @@ static int acquire_luks2_key_systemd(
|
||||
systemd_pkcs11_plugin_params *params,
|
||||
void *encrypted_key,
|
||||
size_t encrypted_key_size,
|
||||
Pkcs11RsaPadding rsa_padding,
|
||||
void **ret_decrypted_key,
|
||||
size_t *ret_decrypted_key_size) {
|
||||
|
||||
@@ -149,7 +154,8 @@ static int acquire_luks2_key_systemd(
|
||||
_cleanup_(pkcs11_crypt_device_callback_data_release) pkcs11_crypt_device_callback_data data = {
|
||||
.encrypted_key = encrypted_key,
|
||||
.encrypted_key_size = encrypted_key_size,
|
||||
.free_encrypted_key = false
|
||||
.free_encrypted_key = false,
|
||||
.rsa_padding = rsa_padding,
|
||||
};
|
||||
|
||||
assert(pkcs11_uri);
|
||||
@@ -189,6 +195,7 @@ int acquire_luks2_key(
|
||||
_cleanup_(erase_and_freep) char *base64_encoded = NULL;
|
||||
_cleanup_free_ char *pkcs11_uri = NULL;
|
||||
_cleanup_free_ void *encrypted_key = NULL;
|
||||
Pkcs11RsaPadding rsa_padding = PKCS11_RSA_PADDING_PKCS1V15;
|
||||
systemd_pkcs11_plugin_params *pkcs11_params = userdata;
|
||||
ssize_t base64_encoded_size;
|
||||
|
||||
@@ -196,7 +203,7 @@ int acquire_luks2_key(
|
||||
assert(ret_password);
|
||||
assert(ret_password_size);
|
||||
|
||||
r = parse_luks2_pkcs11_data(cd, json, &pkcs11_uri, &encrypted_key, &encrypted_key_size);
|
||||
r = parse_luks2_pkcs11_data(cd, json, &pkcs11_uri, &encrypted_key, &encrypted_key_size, &rsa_padding);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@@ -208,11 +215,13 @@ int acquire_luks2_key(
|
||||
pkcs11_uri,
|
||||
pkcs11_params,
|
||||
encrypted_key, encrypted_key_size,
|
||||
rsa_padding,
|
||||
&decrypted_key, &decrypted_key_size);
|
||||
else /* default activation that provides single PIN if needed */
|
||||
r = acquire_luks2_key_by_pin(
|
||||
cd, pkcs11_uri, pin, pin_size,
|
||||
encrypted_key, encrypted_key_size,
|
||||
rsa_padding,
|
||||
&decrypted_key, &decrypted_key_size);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@@ -232,7 +241,8 @@ int parse_luks2_pkcs11_data(
|
||||
const char *json,
|
||||
char **ret_uri,
|
||||
void **ret_encrypted_key,
|
||||
size_t *ret_encrypted_key_size) {
|
||||
size_t *ret_encrypted_key_size,
|
||||
Pkcs11RsaPadding *ret_rsa_padding) {
|
||||
|
||||
int r;
|
||||
size_t key_size;
|
||||
@@ -240,6 +250,7 @@ int parse_luks2_pkcs11_data(
|
||||
_cleanup_free_ void *key = NULL;
|
||||
_cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
|
||||
sd_json_variant *w;
|
||||
Pkcs11RsaPadding rsa_padding = PKCS11_RSA_PADDING_PKCS1V15;
|
||||
|
||||
assert(json);
|
||||
assert(ret_uri);
|
||||
@@ -266,9 +277,27 @@ int parse_luks2_pkcs11_data(
|
||||
if (r < 0)
|
||||
return crypt_log_debug_errno(cd, r, "Failed to decode base64 encoded key: %m.");
|
||||
|
||||
/* Optional padding-scheme tag. Absent in legacy tokens (which used PKCS#1 v1.5). */
|
||||
w = sd_json_variant_by_key(v, "pkcs11-padding");
|
||||
if (w) {
|
||||
Pkcs11RsaPadding p;
|
||||
|
||||
if (!sd_json_variant_is_string(w))
|
||||
return crypt_log_debug_errno(cd, -EINVAL,
|
||||
"LUKS2 token field 'pkcs11-padding' is not a string.");
|
||||
p = pkcs11_rsa_padding_from_string(sd_json_variant_string(w));
|
||||
if (p < 0)
|
||||
return crypt_log_debug_errno(cd, p,
|
||||
"LUKS2 token field 'pkcs11-padding' has unsupported value '%s'.",
|
||||
sd_json_variant_string(w));
|
||||
rsa_padding = p;
|
||||
}
|
||||
|
||||
*ret_uri = TAKE_PTR(uri);
|
||||
*ret_encrypted_key = TAKE_PTR(key);
|
||||
*ret_encrypted_key_size = key_size;
|
||||
if (ret_rsa_padding)
|
||||
*ret_rsa_padding = rsa_padding;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "pkcs11-util.h"
|
||||
#include "shared-forward.h"
|
||||
|
||||
int acquire_luks2_key(
|
||||
@@ -18,4 +19,5 @@ int parse_luks2_pkcs11_data(
|
||||
const char *json,
|
||||
char **ret_uri,
|
||||
void **ret_encrypted_key,
|
||||
size_t *ret_encrypted_key_size);
|
||||
size_t *ret_encrypted_key_size,
|
||||
Pkcs11RsaPadding *ret_rsa_padding);
|
||||
|
||||
@@ -1815,6 +1815,7 @@ static int attach_luks_or_plain_or_bitlk_by_pkcs11(
|
||||
_cleanup_(sd_event_unrefp) sd_event *event = NULL;
|
||||
_cleanup_free_ void *discovered_key = NULL;
|
||||
struct iovec discovered_key_data = {};
|
||||
Pkcs11RsaPadding rsa_padding = PKCS11_RSA_PADDING_PKCS1V15;
|
||||
int keyslot = arg_key_slot, r;
|
||||
const char *uri = NULL;
|
||||
bool use_libcryptsetup_plugin = use_token_plugins();
|
||||
@@ -1825,7 +1826,7 @@ static int attach_luks_or_plain_or_bitlk_by_pkcs11(
|
||||
|
||||
if (arg_pkcs11_uri_auto) {
|
||||
if (!use_libcryptsetup_plugin) {
|
||||
r = find_pkcs11_auto_data(cd, &discovered_uri, &discovered_key, &discovered_key_size, &keyslot);
|
||||
r = find_pkcs11_auto_data(cd, &discovered_uri, &discovered_key, &discovered_key_size, &rsa_padding, &keyslot);
|
||||
if (IN_SET(r, -ENOTUNIQ, -ENXIO))
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(EAGAIN),
|
||||
"Automatic PKCS#11 metadata discovery was not possible because missing or not unique, falling back to traditional unlocking.");
|
||||
@@ -1861,6 +1862,7 @@ static int attach_luks_or_plain_or_bitlk_by_pkcs11(
|
||||
name,
|
||||
friendly,
|
||||
uri,
|
||||
rsa_padding,
|
||||
key_file, arg_keyfile_size, arg_keyfile_offset,
|
||||
key_data,
|
||||
until,
|
||||
|
||||
Reference in New Issue
Block a user