Merge pull request #28398 from ddstreet/tpm2_specify_pcr_value
Tpm2 specify pcr value
This commit is contained in:
@@ -391,13 +391,22 @@
|
||||
<term><option>--tpm2-pcrs=</option><arg rep="repeat">PCR</arg></term>
|
||||
|
||||
<listitem><para>Configures the TPM2 PCRs (Platform Configuration Registers) to bind to when
|
||||
enrollment is requested via <option>--tpm2-device=</option>. Takes a list of PCR names or numeric
|
||||
indices in the range 0…23. Multiple PCR indexes are separated by <literal>+</literal>. If not
|
||||
specified, the default is to use PCR 7 only. If an empty string is specified, binds the enrollment to
|
||||
no PCRs at all. See the table above for a list of available PCRs.</para>
|
||||
enrollment is requested via <option>--tpm2-device=</option>. Takes a list of PCR entries, where each
|
||||
entry starts with a name or numeric index in the range 0…23, optionally followed by
|
||||
<literal>:</literal> and a hash algorithm name (specifying the PCR bank), optionally followed by
|
||||
<literal>=</literal> and a hash digest value. Multiple PCR entries are separated by
|
||||
<literal>+</literal>. If not specified, the default is to use PCR 7 only. If an empty string is
|
||||
specified, binds the enrollment to no PCRs at all. See the table above for a list of available
|
||||
PCRs.</para>
|
||||
|
||||
<para>Example: <option>--tpm2-pcrs=boot-loader-code+platform-config+boot-loader-config</option>
|
||||
specifies that PCR registers 4, 1, and 5 should be used.</para>
|
||||
<para>Example: <option>--tpm2-pcrs=7:sha256</option> specifies that PCR register 7 from the SHA256
|
||||
bank should be used.</para>
|
||||
<para>Example: <option>--tpm2-pcrs=4:sha1=0x3A3F780F11A4B49969FCAA80CD6E3957C33B2275</option>
|
||||
specifies that PCR register 4 from the SHA1 bank should be used, and a hash digest value of
|
||||
0x3A3F780F11A4B49969FCAA80CD6E3957C33B2275 will be used instead of reading the current PCR
|
||||
value.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
|
||||
@@ -335,6 +335,15 @@ static inline int __coverity_check_and_return__(int condition) {
|
||||
} \
|
||||
}
|
||||
|
||||
/* When func() doesn't return the appropriate type, and is also a macro, set variable to empty afterwards. */
|
||||
#define DEFINE_TRIVIAL_CLEANUP_FUNC_FULL_MACRO(type, func, empty) \
|
||||
static inline void func##p(type *p) { \
|
||||
if (*p != (empty)) { \
|
||||
func(*p); \
|
||||
*p = (empty); \
|
||||
} \
|
||||
}
|
||||
|
||||
#define _DEFINE_TRIVIAL_REF_FUNC(type, name, scope) \
|
||||
scope type *name##_ref(type *p) { \
|
||||
if (!p) \
|
||||
|
||||
+5
-15
@@ -831,23 +831,13 @@ static int verb_sign(int argc, char *argv[], void *userdata) {
|
||||
if (tpmalg < 0)
|
||||
return log_error_errno(tpmalg, "Unsupported PCR bank");
|
||||
|
||||
TPML_PCR_SELECTION pcr_selection;
|
||||
tpm2_tpml_pcr_selection_from_mask(1 << TPM_PCR_INDEX_KERNEL_IMAGE,
|
||||
tpmalg,
|
||||
&pcr_selection);
|
||||
Tpm2PCRValue pcr_value = TPM2_PCR_VALUE_MAKE(TPM_PCR_INDEX_KERNEL_IMAGE,
|
||||
tpmalg,
|
||||
TPM2B_DIGEST_MAKE(p->value, p->value_size));
|
||||
|
||||
TPM2B_DIGEST pcr_values = {
|
||||
.size = p->value_size,
|
||||
};
|
||||
assert(sizeof(pcr_values.buffer) >= p->value_size);
|
||||
memcpy_safe(pcr_values.buffer, p->value, p->value_size);
|
||||
TPM2B_DIGEST pcr_policy_digest = TPM2B_DIGEST_MAKE(NULL, TPM2_SHA256_DIGEST_SIZE);
|
||||
|
||||
TPM2B_DIGEST pcr_policy_digest;
|
||||
r = tpm2_digest_init(TPM2_ALG_SHA256, &pcr_policy_digest);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = tpm2_calculate_policy_pcr(&pcr_selection, &pcr_values, 1, &pcr_policy_digest);
|
||||
r = tpm2_calculate_policy_pcr(&pcr_value, 1, &pcr_policy_digest);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
||||
+2
-2
@@ -860,7 +860,7 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
break;
|
||||
|
||||
case ARG_TPM2_PCRS: /* For fixed hash PCR policies only */
|
||||
r = tpm2_parse_pcr_argument(optarg, &arg_tpm2_pcr_mask);
|
||||
r = tpm2_parse_pcr_argument_to_mask(optarg, &arg_tpm2_pcr_mask);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@@ -874,7 +874,7 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
break;
|
||||
|
||||
case ARG_TPM2_PUBLIC_KEY_PCRS: /* For public key PCR policies only */
|
||||
r = tpm2_parse_pcr_argument(optarg, &arg_tpm2_public_key_pcr_mask);
|
||||
r = tpm2_parse_pcr_argument_to_mask(optarg, &arg_tpm2_public_key_pcr_mask);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
||||
@@ -133,7 +133,8 @@ int enroll_tpm2(struct crypt_device *cd,
|
||||
const void *volume_key,
|
||||
size_t volume_key_size,
|
||||
const char *device,
|
||||
uint32_t hash_pcr_mask,
|
||||
Tpm2PCRValue *hash_pcr_values,
|
||||
size_t n_hash_pcr_values,
|
||||
const char *pubkey_path,
|
||||
uint32_t pubkey_pcr_mask,
|
||||
const char *signature_path,
|
||||
@@ -143,9 +144,8 @@ int enroll_tpm2(struct crypt_device *cd,
|
||||
_cleanup_(json_variant_unrefp) JsonVariant *v = NULL, *signature_json = NULL;
|
||||
_cleanup_(erase_and_freep) char *base64_encoded = NULL;
|
||||
_cleanup_free_ void *srk_buf = NULL;
|
||||
size_t secret_size, blob_size, hash_size, pubkey_size = 0, srk_buf_size = 0;
|
||||
_cleanup_free_ void *blob = NULL, *hash = NULL, *pubkey = NULL;
|
||||
uint16_t pcr_bank, primary_alg;
|
||||
size_t secret_size, blob_size, pubkey_size = 0, srk_buf_size = 0;
|
||||
_cleanup_free_ void *blob = NULL, *pubkey = NULL;
|
||||
const char *node;
|
||||
_cleanup_(erase_and_freep) char *pin_str = NULL;
|
||||
ssize_t base64_encoded_size;
|
||||
@@ -163,7 +163,7 @@ int enroll_tpm2(struct crypt_device *cd,
|
||||
assert(cd);
|
||||
assert(volume_key);
|
||||
assert(volume_key_size > 0);
|
||||
assert(TPM2_PCR_MASK_VALID(hash_pcr_mask));
|
||||
assert(TPM2_PCR_VALUES_VALID(hash_pcr_values, n_hash_pcr_values));
|
||||
assert(TPM2_PCR_MASK_VALID(pubkey_pcr_mask));
|
||||
|
||||
assert_se(node = crypt_get_device_name(cd));
|
||||
@@ -206,23 +206,69 @@ int enroll_tpm2(struct crypt_device *cd,
|
||||
return log_debug_errno(r, "Failed to read TPM PCR signature: %m");
|
||||
}
|
||||
|
||||
r = tpm2_seal(device,
|
||||
hash_pcr_mask,
|
||||
pubkey, pubkey_size,
|
||||
pubkey_pcr_mask,
|
||||
_cleanup_(tpm2_context_unrefp) Tpm2Context *tpm2_context = NULL;
|
||||
r = tpm2_context_new(device, &tpm2_context);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
bool pcr_value_specified = false;
|
||||
for (size_t i = 0; i < n_hash_pcr_values; i++)
|
||||
if (hash_pcr_values[i].value.size > 0) {
|
||||
pcr_value_specified = true;
|
||||
break;
|
||||
}
|
||||
|
||||
r = tpm2_pcr_read_missing_values(tpm2_context, hash_pcr_values, n_hash_pcr_values);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
uint16_t hash_pcr_bank = 0;
|
||||
uint32_t hash_pcr_mask = 0;
|
||||
if (n_hash_pcr_values > 0) {
|
||||
size_t hash_count;
|
||||
r = tpm2_pcr_values_hash_count(hash_pcr_values, n_hash_pcr_values, &hash_count);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Could not get hash count: %m");
|
||||
|
||||
if (hash_count > 1)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Multiple PCR banks selected.");
|
||||
|
||||
hash_pcr_bank = hash_pcr_values[0].hash;
|
||||
r = tpm2_pcr_values_to_mask(hash_pcr_values, n_hash_pcr_values, hash_pcr_bank, &hash_pcr_mask);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Could not get hash mask: %m");
|
||||
}
|
||||
|
||||
TPM2B_PUBLIC public;
|
||||
if (pubkey) {
|
||||
r = tpm2_tpm2b_public_from_pem(pubkey, pubkey_size, &public);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Could not convert public key to TPM2B_PUBLIC: %m");
|
||||
}
|
||||
|
||||
TPM2B_DIGEST policy = TPM2B_DIGEST_MAKE(NULL, TPM2_SHA256_DIGEST_SIZE);
|
||||
r = tpm2_calculate_sealing_policy(
|
||||
hash_pcr_values,
|
||||
n_hash_pcr_values,
|
||||
pubkey ? &public : NULL,
|
||||
use_pin,
|
||||
&policy);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = tpm2_seal(tpm2_context,
|
||||
&policy,
|
||||
pin_str,
|
||||
&secret, &secret_size,
|
||||
&blob, &blob_size,
|
||||
&hash, &hash_size,
|
||||
&pcr_bank,
|
||||
&primary_alg,
|
||||
/* ret_primary_alg= */ NULL,
|
||||
&srk_buf,
|
||||
&srk_buf_size);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* Let's see if we already have this specific PCR policy hash enrolled, if so, exit early. */
|
||||
r = search_policy_hash(cd, hash, hash_size);
|
||||
r = search_policy_hash(cd, policy.buffer, policy.size);
|
||||
if (r == -ENOENT)
|
||||
log_debug_errno(r, "PCR policy hash not yet enrolled, enrolling now.");
|
||||
else if (r < 0)
|
||||
@@ -233,21 +279,21 @@ int enroll_tpm2(struct crypt_device *cd,
|
||||
}
|
||||
|
||||
/* Quick verification that everything is in order, we are not in a hurry after all. */
|
||||
if (!pubkey || signature_json) {
|
||||
if ((!pubkey || signature_json) && !pcr_value_specified) {
|
||||
_cleanup_(erase_and_freep) void *secret2 = NULL;
|
||||
size_t secret2_size;
|
||||
|
||||
log_debug("Unsealing for verification...");
|
||||
r = tpm2_unseal(device,
|
||||
hash_pcr_mask,
|
||||
pcr_bank,
|
||||
hash_pcr_bank,
|
||||
pubkey, pubkey_size,
|
||||
pubkey_pcr_mask,
|
||||
signature_json,
|
||||
pin_str,
|
||||
primary_alg,
|
||||
/* primary_alg= */ 0,
|
||||
blob, blob_size,
|
||||
hash, hash_size,
|
||||
policy.buffer, policy.size,
|
||||
srk_buf, srk_buf_size,
|
||||
&secret2, &secret2_size);
|
||||
if (r < 0)
|
||||
@@ -279,12 +325,12 @@ int enroll_tpm2(struct crypt_device *cd,
|
||||
r = tpm2_make_luks2_json(
|
||||
keyslot,
|
||||
hash_pcr_mask,
|
||||
pcr_bank,
|
||||
hash_pcr_bank,
|
||||
pubkey, pubkey_size,
|
||||
pubkey_pcr_mask,
|
||||
primary_alg,
|
||||
/* primary_alg= */ 0,
|
||||
blob, blob_size,
|
||||
hash, hash_size,
|
||||
policy.buffer, policy.size,
|
||||
use_pin ? binary_salt : NULL,
|
||||
use_pin ? sizeof(binary_salt) : 0,
|
||||
srk_buf, srk_buf_size,
|
||||
|
||||
@@ -5,11 +5,12 @@
|
||||
|
||||
#include "cryptsetup-util.h"
|
||||
#include "log.h"
|
||||
#include "tpm2-util.h"
|
||||
|
||||
#if HAVE_TPM2
|
||||
int enroll_tpm2(struct crypt_device *cd, const void *volume_key, size_t volume_key_size, const char *device, uint32_t hash_pcr_mask, const char *pubkey_path, uint32_t pubkey_pcr_mask, const char *signature_path, bool use_pin);
|
||||
int enroll_tpm2(struct crypt_device *cd, const void *volume_key, size_t volume_key_size, const char *device, Tpm2PCRValue *hash_pcrs, size_t n_hash_pcrs, const char *pubkey_path, uint32_t pubkey_pcr_mask, const char *signature_path, bool use_pin);
|
||||
#else
|
||||
static inline int enroll_tpm2(struct crypt_device *cd, const void *volume_key, size_t volume_key_size, const char *device, uint32_t hash_pcr_mask, const char *pubkey_path, uint32_t pubkey_pcr_mask, const char *signature_path, bool use_pin) {
|
||||
static inline int enroll_tpm2(struct crypt_device *cd, const void *volume_key, size_t volume_key_size, const char *device, Tpm2PCRValue *hash_pcrs, size_t n_hash_pcrs, const char *pubkey_path, uint32_t pubkey_pcr_mask, const char *signature_path, bool use_pin) {
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
|
||||
"TPM2 key enrollment not supported.");
|
||||
}
|
||||
|
||||
@@ -28,7 +28,6 @@
|
||||
#include "strv.h"
|
||||
#include "terminal-util.h"
|
||||
#include "tpm-pcr.h"
|
||||
#include "tpm2-util.h"
|
||||
|
||||
static EnrollType arg_enroll_type = _ENROLL_TYPE_INVALID;
|
||||
static char *arg_unlock_keyfile = NULL;
|
||||
@@ -37,10 +36,13 @@ static char *arg_unlock_fido2_device = NULL;
|
||||
static char *arg_pkcs11_token_uri = NULL;
|
||||
static char *arg_fido2_device = NULL;
|
||||
static char *arg_tpm2_device = NULL;
|
||||
static uint32_t arg_tpm2_pcr_mask = UINT32_MAX;
|
||||
static Tpm2PCRValue *arg_tpm2_hash_pcr_values = NULL;
|
||||
static size_t arg_tpm2_n_hash_pcr_values = 0;
|
||||
static bool arg_tpm2_hash_pcr_values_use_default = true;
|
||||
static bool arg_tpm2_pin = false;
|
||||
static char *arg_tpm2_public_key = NULL;
|
||||
static uint32_t arg_tpm2_public_key_pcr_mask = UINT32_MAX;
|
||||
static uint32_t arg_tpm2_public_key_pcr_mask = 0;
|
||||
static bool arg_tpm2_public_key_pcr_mask_use_default = true;
|
||||
static char *arg_tpm2_signature = NULL;
|
||||
static char *arg_node = NULL;
|
||||
static int *arg_wipe_slots = NULL;
|
||||
@@ -61,6 +63,7 @@ STATIC_DESTRUCTOR_REGISTER(arg_unlock_fido2_device, freep);
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_pkcs11_token_uri, freep);
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_fido2_device, freep);
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_tpm2_device, freep);
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_tpm2_hash_pcr_values, freep);
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_tpm2_public_key, freep);
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_tpm2_signature, freep);
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_node, freep);
|
||||
@@ -356,7 +359,8 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
}
|
||||
|
||||
case ARG_TPM2_PCRS:
|
||||
r = tpm2_parse_pcr_argument(optarg, &arg_tpm2_pcr_mask);
|
||||
arg_tpm2_hash_pcr_values_use_default = false;
|
||||
r = tpm2_parse_pcr_argument_append(optarg, &arg_tpm2_hash_pcr_values, &arg_tpm2_n_hash_pcr_values);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@@ -377,7 +381,8 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
break;
|
||||
|
||||
case ARG_TPM2_PUBLIC_KEY_PCRS:
|
||||
r = tpm2_parse_pcr_argument(optarg, &arg_tpm2_public_key_pcr_mask);
|
||||
arg_tpm2_public_key_pcr_mask_use_default = false;
|
||||
r = tpm2_parse_pcr_argument_to_mask(optarg, &arg_tpm2_public_key_pcr_mask);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@@ -476,10 +481,15 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (arg_tpm2_pcr_mask == UINT32_MAX)
|
||||
arg_tpm2_pcr_mask = TPM2_PCR_MASK_DEFAULT;
|
||||
if (arg_tpm2_public_key_pcr_mask == UINT32_MAX)
|
||||
arg_tpm2_public_key_pcr_mask = UINT32_C(1) << TPM_PCR_INDEX_KERNEL_IMAGE;
|
||||
if (arg_tpm2_public_key_pcr_mask_use_default && arg_tpm2_public_key)
|
||||
arg_tpm2_public_key_pcr_mask = INDEX_TO_MASK(uint32_t, TPM_PCR_INDEX_KERNEL_IMAGE);
|
||||
|
||||
if (arg_tpm2_hash_pcr_values_use_default && !GREEDY_REALLOC_APPEND(
|
||||
arg_tpm2_hash_pcr_values,
|
||||
arg_tpm2_n_hash_pcr_values,
|
||||
&TPM2_PCR_VALUE_MAKE(TPM2_PCR_INDEX_DEFAULT, /* hash= */ 0, /* value= */ {}),
|
||||
1))
|
||||
return log_oom();
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -655,7 +665,7 @@ static int run(int argc, char *argv[]) {
|
||||
break;
|
||||
|
||||
case ENROLL_TPM2:
|
||||
slot = enroll_tpm2(cd, vk, vks, arg_tpm2_device, arg_tpm2_pcr_mask, arg_tpm2_public_key, arg_tpm2_public_key_pcr_mask, arg_tpm2_signature, arg_tpm2_pin);
|
||||
slot = enroll_tpm2(cd, vk, vks, arg_tpm2_device, arg_tpm2_hash_pcr_values, arg_tpm2_n_hash_pcr_values, arg_tpm2_public_key, arg_tpm2_public_key_pcr_mask, arg_tpm2_signature, arg_tpm2_pin);
|
||||
break;
|
||||
|
||||
case _ENROLL_TYPE_INVALID:
|
||||
|
||||
@@ -278,7 +278,7 @@ _public_ int cryptsetup_token_validate(
|
||||
}
|
||||
|
||||
u = json_variant_unsigned(e);
|
||||
if (!TPM2_PCR_VALID(u)) {
|
||||
if (!TPM2_PCR_INDEX_VALID(u)) {
|
||||
crypt_log_debug(cd, "TPM2 PCR number out of range.");
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -399,7 +399,7 @@ static int parse_one_option(const char *option) {
|
||||
|
||||
} else if ((val = startswith(option, "tpm2-pcrs="))) {
|
||||
|
||||
r = tpm2_parse_pcr_argument(val, &arg_tpm2_pcr_mask);
|
||||
r = tpm2_parse_pcr_argument_to_mask(val, &arg_tpm2_pcr_mask);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@@ -435,7 +435,7 @@ static int parse_one_option(const char *option) {
|
||||
}
|
||||
|
||||
pcr = r ? TPM_PCR_INDEX_VOLUME_KEY : UINT_MAX;
|
||||
} else if (!TPM2_PCR_VALID(pcr)) {
|
||||
} else if (!TPM2_PCR_INDEX_VALID(pcr)) {
|
||||
log_warning("Selected TPM index for measurement %u outside of allowed range 0…%u, ignoring.", pcr, TPM2_PCRS_MAX-1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
+67
-24
@@ -140,9 +140,12 @@ static size_t arg_key_size = 0;
|
||||
static EVP_PKEY *arg_private_key = NULL;
|
||||
static X509 *arg_certificate = NULL;
|
||||
static char *arg_tpm2_device = NULL;
|
||||
static uint32_t arg_tpm2_pcr_mask = UINT32_MAX;
|
||||
static Tpm2PCRValue *arg_tpm2_hash_pcr_values = NULL;
|
||||
static size_t arg_tpm2_n_hash_pcr_values = 0;
|
||||
static bool arg_tpm2_hash_pcr_values_use_default = true;
|
||||
static char *arg_tpm2_public_key = NULL;
|
||||
static uint32_t arg_tpm2_public_key_pcr_mask = UINT32_MAX;
|
||||
static uint32_t arg_tpm2_public_key_pcr_mask = 0;
|
||||
static bool arg_tpm2_public_key_pcr_mask_use_default = true;
|
||||
static bool arg_split = false;
|
||||
static GptPartitionType *arg_filter_partitions = NULL;
|
||||
static size_t arg_n_filter_partitions = 0;
|
||||
@@ -162,6 +165,7 @@ STATIC_DESTRUCTOR_REGISTER(arg_key, erase_and_freep);
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_private_key, EVP_PKEY_freep);
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_certificate, X509_freep);
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_tpm2_device, freep);
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_tpm2_hash_pcr_values, freep);
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_tpm2_public_key, freep);
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_filter_partitions, freep);
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_image_policy, image_policy_freep);
|
||||
@@ -3639,10 +3643,9 @@ static int partition_encrypt(Context *context, Partition *p, PartitionTarget *ta
|
||||
_cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
|
||||
_cleanup_(erase_and_freep) void *secret = NULL;
|
||||
_cleanup_free_ void *pubkey = NULL;
|
||||
_cleanup_free_ void *blob = NULL, *hash = NULL, *srk_buf = NULL;
|
||||
size_t secret_size, blob_size, hash_size, pubkey_size = 0, srk_buf_size = 0;
|
||||
_cleanup_free_ void *blob = NULL, *srk_buf = NULL;
|
||||
size_t secret_size, blob_size, pubkey_size = 0, srk_buf_size = 0;
|
||||
ssize_t base64_encoded_size;
|
||||
uint16_t pcr_bank, primary_alg;
|
||||
int keyslot;
|
||||
|
||||
if (arg_tpm2_public_key_pcr_mask != 0) {
|
||||
@@ -3656,18 +3659,51 @@ static int partition_encrypt(Context *context, Partition *p, PartitionTarget *ta
|
||||
}
|
||||
}
|
||||
|
||||
r = tpm2_seal(arg_tpm2_device,
|
||||
arg_tpm2_pcr_mask,
|
||||
pubkey, pubkey_size,
|
||||
arg_tpm2_public_key_pcr_mask,
|
||||
_cleanup_(tpm2_context_unrefp) Tpm2Context *tpm2_context = NULL;
|
||||
r = tpm2_context_new(arg_tpm2_device, &tpm2_context);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
TPM2B_PUBLIC public;
|
||||
if (pubkey) {
|
||||
r = tpm2_tpm2b_public_from_pem(pubkey, pubkey_size, &public);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Could not convert public key to TPM2B_PUBLIC: %m");
|
||||
}
|
||||
|
||||
r = tpm2_pcr_read_missing_values(tpm2_context, arg_tpm2_hash_pcr_values, arg_tpm2_n_hash_pcr_values);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
uint16_t hash_pcr_bank = 0;
|
||||
uint32_t hash_pcr_mask = 0;
|
||||
if (arg_tpm2_n_hash_pcr_values > 0) {
|
||||
size_t hash_count;
|
||||
r = tpm2_pcr_values_hash_count(arg_tpm2_hash_pcr_values, arg_tpm2_n_hash_pcr_values, &hash_count);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Could not get hash count: %m");
|
||||
|
||||
if (hash_count > 1)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Multiple PCR banks selected.");
|
||||
|
||||
hash_pcr_bank = arg_tpm2_hash_pcr_values[0].hash;
|
||||
r = tpm2_pcr_values_to_mask(arg_tpm2_hash_pcr_values, arg_tpm2_n_hash_pcr_values, hash_pcr_bank, &hash_pcr_mask);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Could not get hash mask: %m");
|
||||
}
|
||||
|
||||
TPM2B_DIGEST policy = TPM2B_DIGEST_MAKE(NULL, TPM2_SHA256_DIGEST_SIZE);
|
||||
r = tpm2_calculate_sealing_policy(arg_tpm2_hash_pcr_values, arg_tpm2_n_hash_pcr_values, &public, /* use_pin= */ false, &policy);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = tpm2_seal(tpm2_context,
|
||||
&policy,
|
||||
/* pin= */ NULL,
|
||||
&secret, &secret_size,
|
||||
&blob, &blob_size,
|
||||
&hash, &hash_size,
|
||||
&pcr_bank,
|
||||
&primary_alg,
|
||||
&srk_buf,
|
||||
&srk_buf_size);
|
||||
/* ret_primary_alg= */ NULL,
|
||||
&srk_buf, &srk_buf_size);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to seal to TPM2: %m");
|
||||
|
||||
@@ -3691,13 +3727,13 @@ static int partition_encrypt(Context *context, Partition *p, PartitionTarget *ta
|
||||
|
||||
r = tpm2_make_luks2_json(
|
||||
keyslot,
|
||||
arg_tpm2_pcr_mask,
|
||||
pcr_bank,
|
||||
hash_pcr_mask,
|
||||
hash_pcr_bank,
|
||||
pubkey, pubkey_size,
|
||||
arg_tpm2_public_key_pcr_mask,
|
||||
primary_alg,
|
||||
/* primary_alg= */ 0,
|
||||
blob, blob_size,
|
||||
hash, hash_size,
|
||||
policy.buffer, policy.size,
|
||||
NULL, 0, /* no salt because tpm2_seal has no pin */
|
||||
srk_buf, srk_buf_size,
|
||||
0,
|
||||
@@ -6447,7 +6483,8 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
}
|
||||
|
||||
case ARG_TPM2_PCRS:
|
||||
r = tpm2_parse_pcr_argument(optarg, &arg_tpm2_pcr_mask);
|
||||
arg_tpm2_hash_pcr_values_use_default = false;
|
||||
r = tpm2_parse_pcr_argument_append(optarg, &arg_tpm2_hash_pcr_values, &arg_tpm2_n_hash_pcr_values);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@@ -6461,7 +6498,8 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
break;
|
||||
|
||||
case ARG_TPM2_PUBLIC_KEY_PCRS:
|
||||
r = tpm2_parse_pcr_argument(optarg, &arg_tpm2_public_key_pcr_mask);
|
||||
arg_tpm2_public_key_pcr_mask_use_default = false;
|
||||
r = tpm2_parse_pcr_argument_to_mask(optarg, &arg_tpm2_public_key_pcr_mask);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@@ -6597,10 +6635,15 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"A path to a loopback file must be specified when --split is used.");
|
||||
|
||||
if (arg_tpm2_pcr_mask == UINT32_MAX)
|
||||
arg_tpm2_pcr_mask = TPM2_PCR_MASK_DEFAULT;
|
||||
if (arg_tpm2_public_key_pcr_mask == UINT32_MAX)
|
||||
arg_tpm2_public_key_pcr_mask = UINT32_C(1) << TPM_PCR_INDEX_KERNEL_IMAGE;
|
||||
if (arg_tpm2_public_key_pcr_mask_use_default && arg_tpm2_public_key)
|
||||
arg_tpm2_public_key_pcr_mask = INDEX_TO_MASK(uint32_t, TPM_PCR_INDEX_KERNEL_IMAGE);
|
||||
|
||||
if (arg_tpm2_hash_pcr_values_use_default && !GREEDY_REALLOC_APPEND(
|
||||
arg_tpm2_hash_pcr_values,
|
||||
arg_tpm2_n_hash_pcr_values,
|
||||
&TPM2_PCR_VALUE_MAKE(TPM2_PCR_INDEX_DEFAULT, /* hash= */ 0, /* value= */ {}),
|
||||
1))
|
||||
return log_oom();
|
||||
|
||||
if (arg_pretty < 0 && isatty(STDOUT_FILENO))
|
||||
arg_pretty = true;
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
#include "sort-util.h"
|
||||
#include "string-table.h"
|
||||
|
||||
#if PREFER_OPENSSL
|
||||
#if PREFER_OPENSSL && OPENSSL_VERSION_MAJOR >= 3
|
||||
# pragma GCC diagnostic push
|
||||
# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(RSA*, RSA_free, NULL);
|
||||
|
||||
+44
-7
@@ -825,18 +825,49 @@ int encrypt_credential_and_warn(
|
||||
if (!pubkey)
|
||||
tpm2_pubkey_pcr_mask = 0;
|
||||
|
||||
r = tpm2_seal(tpm2_device,
|
||||
tpm2_hash_pcr_mask,
|
||||
pubkey, pubkey_size,
|
||||
tpm2_pubkey_pcr_mask,
|
||||
_cleanup_(tpm2_context_unrefp) Tpm2Context *tpm2_context = NULL;
|
||||
r = tpm2_context_new(tpm2_device, &tpm2_context);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = tpm2_get_best_pcr_bank(tpm2_context, tpm2_hash_pcr_mask | tpm2_pubkey_pcr_mask, &tpm2_pcr_bank);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
TPML_PCR_SELECTION tpm2_hash_pcr_selection;
|
||||
tpm2_tpml_pcr_selection_from_mask(tpm2_hash_pcr_mask, tpm2_pcr_bank, &tpm2_hash_pcr_selection);
|
||||
|
||||
_cleanup_free_ Tpm2PCRValue *tpm2_hash_pcr_values = NULL;
|
||||
size_t tpm2_n_hash_pcr_values;
|
||||
r = tpm2_pcr_read(tpm2_context, &tpm2_hash_pcr_selection, &tpm2_hash_pcr_values, &tpm2_n_hash_pcr_values);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
TPM2B_PUBLIC public;
|
||||
if (pubkey) {
|
||||
r = tpm2_tpm2b_public_from_pem(pubkey, pubkey_size, &public);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Could not convert public key to TPM2B_PUBLIC: %m");
|
||||
}
|
||||
|
||||
TPM2B_DIGEST tpm2_policy = TPM2B_DIGEST_MAKE(NULL, TPM2_SHA256_DIGEST_SIZE);
|
||||
r = tpm2_calculate_sealing_policy(
|
||||
tpm2_hash_pcr_values,
|
||||
tpm2_n_hash_pcr_values,
|
||||
pubkey ? &public : NULL,
|
||||
/* use_pin= */ false,
|
||||
&tpm2_policy);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = tpm2_seal(tpm2_context,
|
||||
&tpm2_policy,
|
||||
/* pin= */ NULL,
|
||||
&tpm2_key, &tpm2_key_size,
|
||||
&tpm2_blob, &tpm2_blob_size,
|
||||
&tpm2_policy_hash, &tpm2_policy_hash_size,
|
||||
&tpm2_pcr_bank,
|
||||
&tpm2_primary_alg,
|
||||
/* ret_srk_buf= */ NULL,
|
||||
/* ret_srk_buf_size= */ 0);
|
||||
/* ret_srk_buf_size= */ NULL);
|
||||
if (r < 0) {
|
||||
if (sd_id128_equal(with_key, _CRED_AUTO_INITRD))
|
||||
log_warning("TPM2 present and used, but we didn't manage to talk to it. Credential will be refused if SecureBoot is enabled.");
|
||||
@@ -846,6 +877,12 @@ int encrypt_credential_and_warn(
|
||||
log_notice_errno(r, "TPM2 sealing didn't work, continuing without TPM2: %m");
|
||||
}
|
||||
|
||||
tpm2_policy_hash_size = tpm2_policy.size;
|
||||
tpm2_policy_hash = malloc(tpm2_policy_hash_size);
|
||||
if (!tpm2_policy_hash)
|
||||
return log_oom();
|
||||
memcpy(tpm2_policy_hash, tpm2_policy.buffer, tpm2_policy_hash_size);
|
||||
|
||||
assert(tpm2_blob_size <= CREDENTIAL_FIELD_SIZE_MAX);
|
||||
assert(tpm2_policy_hash_size <= CREDENTIAL_FIELD_SIZE_MAX);
|
||||
}
|
||||
|
||||
@@ -1,10 +1,29 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include "fd-util.h"
|
||||
#include "openssl-util.h"
|
||||
#include "alloc-util.h"
|
||||
#include "hexdecoct.h"
|
||||
|
||||
#if HAVE_OPENSSL
|
||||
int openssl_pkey_from_pem(const void *pem, size_t pem_size, EVP_PKEY **ret) {
|
||||
assert(pem);
|
||||
assert(ret);
|
||||
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
f = fmemopen((void*) pem, pem_size, "r");
|
||||
if (!f)
|
||||
return log_oom_debug();
|
||||
|
||||
_cleanup_(EVP_PKEY_freep) EVP_PKEY *pkey = PEM_read_PUBKEY(f, NULL, NULL, NULL);
|
||||
if (!pkey)
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(EIO), "Failed to parse PEM.");
|
||||
|
||||
*ret = TAKE_PTR(pkey);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int openssl_hash(const EVP_MD *alg,
|
||||
const void *msg,
|
||||
size_t msg_len,
|
||||
@@ -109,6 +128,342 @@ int rsa_pkey_to_suitable_key_size(
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Generate RSA public key from provided "n" and "e" values. Note that if "e" is a number (e.g. uint32_t), it
|
||||
* must be provided here big-endian, e.g. wrap it with htobe32(). */
|
||||
int rsa_pkey_from_n_e(const void *n, size_t n_size, const void *e, size_t e_size, EVP_PKEY **ret) {
|
||||
_cleanup_(EVP_PKEY_freep) EVP_PKEY *pkey = NULL;
|
||||
|
||||
assert(n);
|
||||
assert(e);
|
||||
assert(ret);
|
||||
|
||||
_cleanup_(EVP_PKEY_CTX_freep) EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL);
|
||||
if (!ctx)
|
||||
return log_oom_debug();
|
||||
|
||||
_cleanup_(BN_freep) BIGNUM *bn_n = BN_bin2bn(n, n_size, NULL);
|
||||
if (!bn_n)
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(EIO), "Failed to create BIGNUM for RSA n.");
|
||||
|
||||
_cleanup_(BN_freep) BIGNUM *bn_e = BN_bin2bn(e, e_size, NULL);
|
||||
if (!bn_e)
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(EIO), "Failed to create BIGNUM for RSA e.");
|
||||
|
||||
#if OPENSSL_VERSION_MAJOR >= 3
|
||||
if (EVP_PKEY_fromdata_init(ctx) <= 0)
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(EIO), "Failed to initialize EVP_PKEY_CTX.");
|
||||
|
||||
_cleanup_(OSSL_PARAM_BLD_freep) OSSL_PARAM_BLD *bld = OSSL_PARAM_BLD_new();
|
||||
if (!bld)
|
||||
return log_oom_debug();
|
||||
|
||||
if (!OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_N, bn_n))
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(EIO), "Failed to set RSA OSSL_PKEY_PARAM_RSA_N.");
|
||||
|
||||
if (!OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_E, bn_e))
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(EIO), "Failed to set RSA OSSL_PKEY_PARAM_RSA_E.");
|
||||
|
||||
_cleanup_(OSSL_PARAM_freep) OSSL_PARAM *params = OSSL_PARAM_BLD_to_param(bld);
|
||||
if (!params)
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(EIO), "Failed to build RSA OSSL_PARAM.");
|
||||
|
||||
if (EVP_PKEY_fromdata(ctx, &pkey, EVP_PKEY_PUBLIC_KEY, params) <= 0)
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(EIO), "Failed to create RSA EVP_PKEY.");
|
||||
#else
|
||||
_cleanup_(RSA_freep) RSA *rsa_key = RSA_new();
|
||||
if (!rsa_key)
|
||||
return log_oom_debug();
|
||||
|
||||
if (!RSA_set0_key(rsa_key, bn_n, bn_e, NULL))
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(EIO), "Failed to set RSA n/e.");
|
||||
/* rsa_key owns these now, don't free */
|
||||
TAKE_PTR(bn_n);
|
||||
TAKE_PTR(bn_e);
|
||||
|
||||
pkey = EVP_PKEY_new();
|
||||
if (!pkey)
|
||||
return log_oom_debug();
|
||||
|
||||
if (!EVP_PKEY_assign_RSA(pkey, rsa_key))
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(EIO), "Failed to assign RSA key.");
|
||||
/* pkey owns this now, don't free */
|
||||
TAKE_PTR(rsa_key);
|
||||
#endif
|
||||
|
||||
*ret = TAKE_PTR(pkey);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Get the "n" and "e" values from the pkey. The values are returned in "bin" format, i.e. BN_bn2bin(). */
|
||||
int rsa_pkey_to_n_e(
|
||||
const EVP_PKEY *pkey,
|
||||
void **ret_n,
|
||||
size_t *ret_n_size,
|
||||
void **ret_e,
|
||||
size_t *ret_e_size) {
|
||||
|
||||
assert(pkey);
|
||||
assert(ret_n);
|
||||
assert(ret_n_size);
|
||||
assert(ret_e);
|
||||
assert(ret_e_size);
|
||||
|
||||
#if OPENSSL_VERSION_MAJOR >= 3
|
||||
_cleanup_(BN_freep) BIGNUM *bn_n = NULL;
|
||||
if (!EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_N, &bn_n))
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to get RSA n.");
|
||||
|
||||
_cleanup_(BN_freep) BIGNUM *bn_e = NULL;
|
||||
if (!EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_E, &bn_e))
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to get RSA e.");
|
||||
#else
|
||||
const RSA *rsa = EVP_PKEY_get0_RSA((EVP_PKEY*) pkey);
|
||||
if (!rsa)
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(EIO),
|
||||
"Failed to get RSA key from public key.");
|
||||
|
||||
const BIGNUM *bn_n = RSA_get0_n(rsa);
|
||||
if (!bn_n)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to get RSA n.");
|
||||
|
||||
const BIGNUM *bn_e = RSA_get0_e(rsa);
|
||||
if (!bn_e)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to get RSA e.");
|
||||
#endif
|
||||
|
||||
size_t n_size = BN_num_bytes(bn_n), e_size = BN_num_bytes(bn_e);
|
||||
_cleanup_free_ void *n = malloc(n_size), *e = malloc(e_size);
|
||||
if (!n || !e)
|
||||
return log_oom_debug();
|
||||
|
||||
assert(BN_bn2bin(bn_n, n) == (int) n_size);
|
||||
assert(BN_bn2bin(bn_e, e) == (int) e_size);
|
||||
|
||||
*ret_n = TAKE_PTR(n);
|
||||
*ret_n_size = n_size;
|
||||
*ret_e = TAKE_PTR(e);
|
||||
*ret_e_size = e_size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Generate a new RSA key with the specified number of bits. */
|
||||
int rsa_pkey_new(size_t bits, EVP_PKEY **ret) {
|
||||
assert(ret);
|
||||
|
||||
_cleanup_(EVP_PKEY_CTX_freep) EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL);
|
||||
if (!ctx)
|
||||
return log_oom_debug();
|
||||
|
||||
if (EVP_PKEY_keygen_init(ctx) <= 0)
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(EIO), "Failed to initialize EVP_PKEY_CTX.");
|
||||
|
||||
if (EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, (int) bits) <= 0)
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(EIO), "Failed to set RSA bits to %zu.", bits);
|
||||
|
||||
_cleanup_(EVP_PKEY_freep) EVP_PKEY *pkey = NULL;
|
||||
if (EVP_PKEY_keygen(ctx, &pkey) <= 0)
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(EIO), "Failed to generate ECC key.");
|
||||
|
||||
*ret = TAKE_PTR(pkey);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Generate ECC public key from provided curve ID and x/y points. */
|
||||
int ecc_pkey_from_curve_x_y(
|
||||
int curve_id,
|
||||
const void *x,
|
||||
size_t x_size,
|
||||
const void *y,
|
||||
size_t y_size,
|
||||
EVP_PKEY **ret) {
|
||||
|
||||
assert(x);
|
||||
assert(y);
|
||||
assert(ret);
|
||||
|
||||
_cleanup_(EVP_PKEY_CTX_freep) EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL);
|
||||
if (!ctx)
|
||||
return log_oom_debug();
|
||||
|
||||
_cleanup_(BN_freep) BIGNUM *bn_x = BN_bin2bn(x, x_size, NULL), *bn_y = BN_bin2bn(y, y_size, NULL);
|
||||
if (!bn_x || !bn_y)
|
||||
return log_oom_debug();
|
||||
|
||||
_cleanup_(EC_GROUP_freep) EC_GROUP *group = EC_GROUP_new_by_curve_name(curve_id);
|
||||
if (!group)
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
|
||||
"ECC curve id %d not supported.", curve_id);
|
||||
|
||||
_cleanup_(EC_POINT_freep) EC_POINT *point = EC_POINT_new(group);
|
||||
if (!point)
|
||||
return log_oom_debug();
|
||||
|
||||
if (!EC_POINT_set_affine_coordinates(group, point, bn_x, bn_y, NULL))
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(EIO), "Failed to set ECC coordinates.");
|
||||
|
||||
#if OPENSSL_VERSION_MAJOR >= 3
|
||||
if (EVP_PKEY_fromdata_init(ctx) <= 0)
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
|
||||
"Failed to initialize EVP_PKEY_CTX.");
|
||||
|
||||
_cleanup_(OSSL_PARAM_BLD_freep) OSSL_PARAM_BLD *bld = OSSL_PARAM_BLD_new();
|
||||
if (!bld)
|
||||
return log_oom_debug();
|
||||
|
||||
if (!OSSL_PARAM_BLD_push_utf8_string(bld, OSSL_PKEY_PARAM_GROUP_NAME, (char*) OSSL_EC_curve_nid2name(curve_id), 0))
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(EIO), "Failed to add ECC OSSL_PKEY_PARAM_GROUP_NAME.");
|
||||
|
||||
_cleanup_(OPENSSL_freep) void *pbuf = NULL;
|
||||
size_t pbuf_len = 0;
|
||||
pbuf_len = EC_POINT_point2buf(group, point, POINT_CONVERSION_UNCOMPRESSED, (unsigned char**) &pbuf, NULL);
|
||||
if (pbuf_len == 0)
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(EIO), "Failed to convert ECC point to buffer.");
|
||||
|
||||
if (!OSSL_PARAM_BLD_push_octet_string(bld, OSSL_PKEY_PARAM_PUB_KEY, pbuf, pbuf_len))
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(EIO), "Failed to add ECC OSSL_PKEY_PARAM_PUB_KEY.");
|
||||
|
||||
_cleanup_(OSSL_PARAM_freep) OSSL_PARAM *params = OSSL_PARAM_BLD_to_param(bld);
|
||||
if (!params)
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(EIO), "Failed to build ECC OSSL_PARAM.");
|
||||
|
||||
_cleanup_(EVP_PKEY_freep) EVP_PKEY *pkey = NULL;
|
||||
if (EVP_PKEY_fromdata(ctx, &pkey, EVP_PKEY_PUBLIC_KEY, params) <= 0)
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
|
||||
"Failed to create ECC EVP_PKEY.");
|
||||
#else
|
||||
_cleanup_(EC_KEY_freep) EC_KEY *eckey = EC_KEY_new();
|
||||
if (!eckey)
|
||||
return log_oom_debug();
|
||||
|
||||
if (!EC_KEY_set_group(eckey, group))
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(EIO), "Failed to set ECC group.");
|
||||
|
||||
if (!EC_KEY_set_public_key(eckey, point))
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(EIO), "Failed to set ECC point.");
|
||||
|
||||
_cleanup_(EVP_PKEY_freep) EVP_PKEY *pkey = EVP_PKEY_new();
|
||||
if (!pkey)
|
||||
return log_oom_debug();
|
||||
|
||||
if (!EVP_PKEY_assign_EC_KEY(pkey, eckey))
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(EIO), "Failed to assign ECC key.");
|
||||
/* pkey owns this now, don't free */
|
||||
TAKE_PTR(eckey);
|
||||
#endif
|
||||
|
||||
*ret = TAKE_PTR(pkey);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ecc_pkey_to_curve_x_y(
|
||||
const EVP_PKEY *pkey,
|
||||
int *ret_curve_id,
|
||||
void **ret_x,
|
||||
size_t *ret_x_size,
|
||||
void **ret_y,
|
||||
size_t *ret_y_size) {
|
||||
|
||||
_cleanup_(BN_freep) BIGNUM *bn_x = NULL, *bn_y = NULL;
|
||||
int curve_id;
|
||||
|
||||
assert(pkey);
|
||||
|
||||
#if OPENSSL_VERSION_MAJOR >= 3
|
||||
size_t name_size;
|
||||
if (!EVP_PKEY_get_utf8_string_param(pkey, OSSL_PKEY_PARAM_GROUP_NAME, NULL, 0, &name_size))
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(EIO), "Failed to get ECC group name size.");
|
||||
|
||||
_cleanup_free_ char *name = malloc(name_size + 1);
|
||||
if (!name)
|
||||
return log_oom_debug();
|
||||
|
||||
if (!EVP_PKEY_get_utf8_string_param(pkey, OSSL_PKEY_PARAM_GROUP_NAME, name, name_size + 1, NULL))
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(EIO), "Failed to get ECC group name.");
|
||||
|
||||
curve_id = OBJ_sn2nid(name);
|
||||
if (curve_id == NID_undef)
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(EIO), "Failed to get ECC curve id.");
|
||||
|
||||
if (!EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_EC_PUB_X, &bn_x))
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(EIO), "Failed to get ECC point x.");
|
||||
|
||||
if (!EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_EC_PUB_Y, &bn_y))
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(EIO), "Failed to get ECC point y.");
|
||||
#else
|
||||
const EC_KEY *eckey = EVP_PKEY_get0_EC_KEY((EVP_PKEY*) pkey);
|
||||
if (!eckey)
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(EIO), "Failed to get EC_KEY.");
|
||||
|
||||
const EC_GROUP *group = EC_KEY_get0_group(eckey);
|
||||
if (!group)
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(EIO), "Failed to get EC_GROUP.");
|
||||
|
||||
curve_id = EC_GROUP_get_curve_name(group);
|
||||
if (curve_id == NID_undef)
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(EIO), "Failed to get ECC curve id.");
|
||||
|
||||
const EC_POINT *point = EC_KEY_get0_public_key(eckey);
|
||||
if (!point)
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(EIO), "Failed to get EC_POINT.");
|
||||
|
||||
bn_x = BN_new();
|
||||
bn_y = BN_new();
|
||||
if (!bn_x || !bn_y)
|
||||
return log_oom_debug();
|
||||
|
||||
if (!EC_POINT_get_affine_coordinates(group, point, bn_x, bn_y, NULL))
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(EIO), "Failed to get ECC x/y.");
|
||||
#endif
|
||||
|
||||
size_t x_size = BN_num_bytes(bn_x), y_size = BN_num_bytes(bn_y);
|
||||
_cleanup_free_ void *x = malloc(x_size), *y = malloc(y_size);
|
||||
if (!x || !y)
|
||||
return log_oom_debug();
|
||||
|
||||
assert(BN_bn2bin(bn_x, x) == (int) x_size);
|
||||
assert(BN_bn2bin(bn_y, y) == (int) y_size);
|
||||
|
||||
if (ret_curve_id)
|
||||
*ret_curve_id = curve_id;
|
||||
if (ret_x)
|
||||
*ret_x = TAKE_PTR(x);
|
||||
if (ret_x_size)
|
||||
*ret_x_size = x_size;
|
||||
if (ret_y)
|
||||
*ret_y = TAKE_PTR(y);
|
||||
if (ret_y_size)
|
||||
*ret_y_size = y_size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Generate a new ECC key for the specified ECC curve id. */
|
||||
int ecc_pkey_new(int curve_id, EVP_PKEY **ret) {
|
||||
assert(ret);
|
||||
|
||||
_cleanup_(EVP_PKEY_CTX_freep) EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL);
|
||||
if (!ctx)
|
||||
return log_oom_debug();
|
||||
|
||||
if (EVP_PKEY_keygen_init(ctx) <= 0)
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(EIO), "Failed to initialize EVP_PKEY_CTX.");
|
||||
|
||||
if (EVP_PKEY_CTX_set_ec_paramgen_curve_nid(ctx, curve_id) <= 0)
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(EIO), "Failed to set ECC curve %d.", curve_id);
|
||||
|
||||
_cleanup_(EVP_PKEY_freep) EVP_PKEY *pkey = NULL;
|
||||
if (EVP_PKEY_keygen(ctx, &pkey) <= 0)
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(EIO), "Failed to generate ECC key.");
|
||||
|
||||
*ret = TAKE_PTR(pkey);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pubkey_fingerprint(EVP_PKEY *pk, const EVP_MD *md, void **ret, size_t *ret_size) {
|
||||
_cleanup_(EVP_MD_CTX_freep) EVP_MD_CTX* m = NULL;
|
||||
_cleanup_free_ void *d = NULL, *h = NULL;
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#if HAVE_OPENSSL
|
||||
# include <openssl/bio.h>
|
||||
# include <openssl/bn.h>
|
||||
# include <openssl/crypto.h>
|
||||
# include <openssl/err.h>
|
||||
# include <openssl/evp.h>
|
||||
# include <openssl/opensslv.h>
|
||||
@@ -21,8 +22,10 @@
|
||||
# endif
|
||||
# if OPENSSL_VERSION_MAJOR >= 3
|
||||
# include <openssl/core_names.h>
|
||||
# include <openssl/param_build.h>
|
||||
# endif
|
||||
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL_MACRO(void*, OPENSSL_free, NULL);
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(X509_NAME*, X509_NAME_free, NULL);
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(EVP_PKEY_CTX*, EVP_PKEY_CTX_free, NULL);
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(EVP_CIPHER_CTX*, EVP_CIPHER_CTX_free, NULL);
|
||||
@@ -35,6 +38,13 @@ DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(PKCS7*, PKCS7_free, NULL);
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(SSL*, SSL_free, NULL);
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(BIO*, BIO_free, NULL);
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(EVP_MD_CTX*, EVP_MD_CTX_free, NULL);
|
||||
#if OPENSSL_VERSION_MAJOR >= 3
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(OSSL_PARAM*, OSSL_PARAM_free, NULL);
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(OSSL_PARAM_BLD*, OSSL_PARAM_BLD_free, NULL);
|
||||
#else
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(EC_KEY*, EC_KEY_free, NULL);
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(RSA*, RSA_free, NULL);
|
||||
#endif
|
||||
|
||||
static inline void sk_X509_free_allp(STACK_OF(X509) **sk) {
|
||||
if (!sk || !*sk)
|
||||
@@ -43,12 +53,26 @@ static inline void sk_X509_free_allp(STACK_OF(X509) **sk) {
|
||||
sk_X509_pop_free(*sk, X509_free);
|
||||
}
|
||||
|
||||
int openssl_pkey_from_pem(const void *pem, size_t pem_size, EVP_PKEY **ret);
|
||||
|
||||
int openssl_hash(const EVP_MD *alg, const void *msg, size_t msg_len, uint8_t *ret_hash, size_t *ret_hash_len);
|
||||
|
||||
int rsa_encrypt_bytes(EVP_PKEY *pkey, const void *decrypted_key, size_t decrypted_key_size, void **ret_encrypt_key, size_t *ret_encrypt_key_size);
|
||||
|
||||
int rsa_pkey_to_suitable_key_size(EVP_PKEY *pkey, size_t *ret_suitable_key_size);
|
||||
|
||||
int rsa_pkey_new(size_t bits, EVP_PKEY **ret);
|
||||
|
||||
int rsa_pkey_from_n_e(const void *n, size_t n_size, const void *e, size_t e_size, EVP_PKEY **ret);
|
||||
|
||||
int rsa_pkey_to_n_e(const EVP_PKEY *pkey, void **ret_n, size_t *ret_n_size, void **ret_e, size_t *ret_e_size);
|
||||
|
||||
int ecc_pkey_from_curve_x_y(int curve_id, const void *x, size_t x_size, const void *y, size_t y_size, EVP_PKEY **ret);
|
||||
|
||||
int ecc_pkey_to_curve_x_y(const EVP_PKEY *pkey, int *ret_curve_id, void **ret_x, size_t *ret_x_size, void **ret_y, size_t *ret_y_size);
|
||||
|
||||
int ecc_pkey_new(int curve_id, EVP_PKEY **ret);
|
||||
|
||||
int pubkey_fingerprint(EVP_PKEY *pk, const EVP_MD *md, void **ret, size_t *ret_size);
|
||||
|
||||
#else
|
||||
|
||||
@@ -39,6 +39,12 @@ bool have_namespaces(void);
|
||||
#define CAN_MEMLOCK_SIZE (512 * 1024U)
|
||||
bool can_memlock(void);
|
||||
|
||||
/* Define void* buffer and size_t length variables from a hex string. */
|
||||
#define DEFINE_HEX_PTR(name, hex) \
|
||||
_cleanup_free_ void *name = NULL; \
|
||||
size_t name##_len = 0; \
|
||||
assert_se(unhexmem(hex, strlen(hex), &name, &name##_len) >= 0);
|
||||
|
||||
#define TEST_REQ_RUNNING_SYSTEMD(x) \
|
||||
if (sd_booted() > 0) { \
|
||||
x; \
|
||||
|
||||
+902
-357
File diff suppressed because it is too large
Load Diff
+135
-26
@@ -7,6 +7,7 @@
|
||||
#include "io-util.h"
|
||||
#include "json.h"
|
||||
#include "macro.h"
|
||||
#include "openssl-util.h"
|
||||
#include "sha256.h"
|
||||
|
||||
typedef enum TPM2Flags {
|
||||
@@ -17,7 +18,7 @@ typedef enum TPM2Flags {
|
||||
* TPM2 on a Client PC must have at least 24 PCRs. This hardcodes our expectation of 24. */
|
||||
#define TPM2_PCRS_MAX 24U
|
||||
#define TPM2_PCRS_MASK ((UINT32_C(1) << TPM2_PCRS_MAX) - 1)
|
||||
static inline bool TPM2_PCR_VALID(unsigned pcr) {
|
||||
static inline bool TPM2_PCR_INDEX_VALID(unsigned pcr) {
|
||||
return pcr < TPM2_PCRS_MAX;
|
||||
}
|
||||
static inline bool TPM2_PCR_MASK_VALID(uint32_t pcr_mask) {
|
||||
@@ -34,26 +35,6 @@ static inline bool TPM2_PCR_MASK_VALID(uint32_t pcr_mask) {
|
||||
|
||||
int dlopen_tpm2(void);
|
||||
|
||||
int tpm2_digest_many(TPMI_ALG_HASH alg, TPM2B_DIGEST *digest, const struct iovec data[], size_t count, bool extend);
|
||||
static inline int tpm2_digest_buffer(TPMI_ALG_HASH alg, TPM2B_DIGEST *digest, const void *data, size_t len, bool extend) {
|
||||
return tpm2_digest_many(alg, digest, &IOVEC_MAKE((void*) data, len), 1, extend);
|
||||
}
|
||||
int tpm2_digest_many_digests(TPMI_ALG_HASH alg, TPM2B_DIGEST *digest, const TPM2B_DIGEST data[], size_t count, bool extend);
|
||||
static inline int tpm2_digest_rehash(TPMI_ALG_HASH alg, TPM2B_DIGEST *digest) {
|
||||
return tpm2_digest_many(alg, digest, NULL, 0, true);
|
||||
}
|
||||
static inline int tpm2_digest_init(TPMI_ALG_HASH alg, TPM2B_DIGEST *digest) {
|
||||
return tpm2_digest_many(alg, digest, NULL, 0, false);
|
||||
}
|
||||
|
||||
int tpm2_calculate_name(const TPMT_PUBLIC *public, TPM2B_NAME *ret_name);
|
||||
int tpm2_calculate_policy_auth_value(TPM2B_DIGEST *digest);
|
||||
int tpm2_calculate_policy_authorize(const TPM2B_PUBLIC *public, const TPM2B_DIGEST *policy_ref, TPM2B_DIGEST *digest);
|
||||
int tpm2_calculate_policy_pcr(const TPML_PCR_SELECTION *pcr_selection, const TPM2B_DIGEST pcr_values[], size_t pcr_values_count, TPM2B_DIGEST *digest);
|
||||
|
||||
int tpm2_seal(const char *device, uint32_t hash_pcr_mask, const void *pubkey, size_t pubkey_size, uint32_t pubkey_pcr_mask, const char *pin, void **ret_secret, size_t *ret_secret_size, void **ret_blob, size_t *ret_blob_size, void **ret_pcr_hash, size_t *ret_pcr_hash_size, uint16_t *ret_pcr_bank, uint16_t *ret_primary_alg, void **ret_srk_buf, size_t *ret_srk_buf_size);
|
||||
int tpm2_unseal(const char *device, uint32_t hash_pcr_mask, uint16_t pcr_bank, const void *pubkey, size_t pubkey_size, uint32_t pubkey_pcr_mask, JsonVariant *signature, const char *pin, uint16_t primary_alg, const void *blob, size_t blob_size, const void *policy_hash, size_t policy_hash_size, const void *srk_buf, size_t srk_buf_size, void **ret_secret, size_t *ret_secret_size);
|
||||
|
||||
typedef struct {
|
||||
unsigned n_ref;
|
||||
|
||||
@@ -88,6 +69,26 @@ int tpm2_handle_new(Tpm2Context *context, Tpm2Handle **ret_handle);
|
||||
Tpm2Handle *tpm2_handle_free(Tpm2Handle *handle);
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(Tpm2Handle*, tpm2_handle_free);
|
||||
|
||||
typedef struct {
|
||||
unsigned index;
|
||||
TPMI_ALG_HASH hash;
|
||||
TPM2B_DIGEST value;
|
||||
} Tpm2PCRValue;
|
||||
|
||||
#define TPM2_PCR_VALUE_MAKE(i, h, v) (Tpm2PCRValue) { .index = (i), .hash = (h), .value = ((TPM2B_DIGEST) v), }
|
||||
bool TPM2_PCR_VALUE_VALID(const Tpm2PCRValue *pcr_value);
|
||||
int tpm2_pcr_value_from_string(const char *arg, Tpm2PCRValue *ret_pcr_value);
|
||||
char *tpm2_pcr_value_to_string(const Tpm2PCRValue *pcr_value);
|
||||
|
||||
bool TPM2_PCR_VALUES_VALID(const Tpm2PCRValue *pcr_values, size_t n_pcr_values);
|
||||
void tpm2_sort_pcr_values(Tpm2PCRValue *pcr_values, size_t n_pcr_values);
|
||||
int tpm2_pcr_values_from_mask(uint32_t mask, TPMI_ALG_HASH hash, Tpm2PCRValue **ret_pcr_values, size_t *ret_n_pcr_values);
|
||||
int tpm2_pcr_values_to_mask(const Tpm2PCRValue *pcr_values, size_t n_pcr_values, TPMI_ALG_HASH hash, uint32_t *ret_mask);
|
||||
int tpm2_pcr_values_from_string(const char *arg, Tpm2PCRValue **ret_pcr_values, size_t *ret_n_pcr_values);
|
||||
char *tpm2_pcr_values_to_string(const Tpm2PCRValue *pcr_values, size_t n_pcr_values);
|
||||
int tpm2_pcr_values_hash_count(const Tpm2PCRValue *pcr_values, size_t n_pcr_values, size_t *ret_count);
|
||||
int tpm2_tpml_pcr_selection_from_pcr_values(const Tpm2PCRValue *pcr_values, size_t n_pcr_values, TPML_PCR_SELECTION *ret_selection, TPM2B_DIGEST **ret_values, size_t *ret_n_values);
|
||||
|
||||
int tpm2_create_primary(Tpm2Context *c, const Tpm2Handle *session, const TPM2B_PUBLIC *template, const TPM2B_SENSITIVE_CREATE *sensitive, TPM2B_PUBLIC **ret_public, Tpm2Handle **ret_handle);
|
||||
int tpm2_create(Tpm2Context *c, const Tpm2Handle *parent, const Tpm2Handle *session, const TPMT_PUBLIC *template, const TPMS_SENSITIVE_CREATE *sensitive, TPM2B_PUBLIC **ret_public, TPM2B_PRIVATE **ret_private);
|
||||
int tpm2_create_loaded(Tpm2Context *c, const Tpm2Handle *parent, const Tpm2Handle *session, const TPMT_PUBLIC *template, const TPMS_SENSITIVE_CREATE *sensitive, TPM2B_PUBLIC **ret_public, TPM2B_PRIVATE **ret_private, Tpm2Handle **ret_handle);
|
||||
@@ -99,11 +100,15 @@ bool tpm2_test_parms(Tpm2Context *c, TPMI_ALG_PUBLIC alg, const TPMU_PUBLIC_PARM
|
||||
|
||||
int tpm2_get_good_pcr_banks(Tpm2Context *c, uint32_t pcr_mask, TPMI_ALG_HASH **ret_banks);
|
||||
int tpm2_get_good_pcr_banks_strv(Tpm2Context *c, uint32_t pcr_mask, char ***ret);
|
||||
int tpm2_get_best_pcr_bank(Tpm2Context *c, uint32_t pcr_mask, TPMI_ALG_HASH *ret);
|
||||
|
||||
int tpm2_extend_bytes(Tpm2Context *c, char **banks, unsigned pcr_index, const void *data, size_t data_size, const void *secret, size_t secret_size);
|
||||
|
||||
void tpm2_tpms_pcr_selection_to_mask(const TPMS_PCR_SELECTION *s, uint32_t *ret);
|
||||
uint32_t tpm2_tpms_pcr_selection_to_mask(const TPMS_PCR_SELECTION *s);
|
||||
void tpm2_tpms_pcr_selection_from_mask(uint32_t mask, TPMI_ALG_HASH hash, TPMS_PCR_SELECTION *ret);
|
||||
bool tpm2_tpms_pcr_selection_has_mask(const TPMS_PCR_SELECTION *s, uint32_t mask);
|
||||
void tpm2_tpms_pcr_selection_add_mask(TPMS_PCR_SELECTION *s, uint32_t mask);
|
||||
void tpm2_tpms_pcr_selection_sub_mask(TPMS_PCR_SELECTION *s, uint32_t mask);
|
||||
void tpm2_tpms_pcr_selection_add(TPMS_PCR_SELECTION *a, const TPMS_PCR_SELECTION *b);
|
||||
void tpm2_tpms_pcr_selection_sub(TPMS_PCR_SELECTION *a, const TPMS_PCR_SELECTION *b);
|
||||
void tpm2_tpms_pcr_selection_move(TPMS_PCR_SELECTION *a, TPMS_PCR_SELECTION *b);
|
||||
@@ -111,8 +116,11 @@ char *tpm2_tpms_pcr_selection_to_string(const TPMS_PCR_SELECTION *s);
|
||||
size_t tpm2_tpms_pcr_selection_weight(const TPMS_PCR_SELECTION *s);
|
||||
#define tpm2_tpms_pcr_selection_is_empty(s) (tpm2_tpms_pcr_selection_weight(s) == 0)
|
||||
|
||||
int tpm2_tpml_pcr_selection_to_mask(const TPML_PCR_SELECTION *l, TPMI_ALG_HASH hash, uint32_t *ret);
|
||||
uint32_t tpm2_tpml_pcr_selection_to_mask(const TPML_PCR_SELECTION *l, TPMI_ALG_HASH hash);
|
||||
void tpm2_tpml_pcr_selection_from_mask(uint32_t mask, TPMI_ALG_HASH hash, TPML_PCR_SELECTION *ret);
|
||||
bool tpm2_tpml_pcr_selection_has_mask(const TPML_PCR_SELECTION *l, TPMI_ALG_HASH hash, uint32_t mask);
|
||||
void tpm2_tpml_pcr_selection_add_mask(TPML_PCR_SELECTION *l, TPMI_ALG_HASH hash, uint32_t mask);
|
||||
void tpm2_tpml_pcr_selection_sub_mask(TPML_PCR_SELECTION *l, TPMI_ALG_HASH hash, uint32_t mask);
|
||||
void tpm2_tpml_pcr_selection_add_tpms_pcr_selection(TPML_PCR_SELECTION *l, const TPMS_PCR_SELECTION *s);
|
||||
void tpm2_tpml_pcr_selection_sub_tpms_pcr_selection(TPML_PCR_SELECTION *l, const TPMS_PCR_SELECTION *s);
|
||||
void tpm2_tpml_pcr_selection_add(TPML_PCR_SELECTION *a, const TPML_PCR_SELECTION *b);
|
||||
@@ -121,9 +129,106 @@ char *tpm2_tpml_pcr_selection_to_string(const TPML_PCR_SELECTION *l);
|
||||
size_t tpm2_tpml_pcr_selection_weight(const TPML_PCR_SELECTION *l);
|
||||
#define tpm2_tpml_pcr_selection_is_empty(l) (tpm2_tpml_pcr_selection_weight(l) == 0)
|
||||
|
||||
int tpm2_digest_many(TPMI_ALG_HASH alg, TPM2B_DIGEST *digest, const struct iovec data[], size_t count, bool extend);
|
||||
static inline int tpm2_digest_buffer(TPMI_ALG_HASH alg, TPM2B_DIGEST *digest, const void *data, size_t len, bool extend) {
|
||||
return tpm2_digest_many(alg, digest, &IOVEC_MAKE((void*) data, len), 1, extend);
|
||||
}
|
||||
int tpm2_digest_many_digests(TPMI_ALG_HASH alg, TPM2B_DIGEST *digest, const TPM2B_DIGEST data[], size_t count, bool extend);
|
||||
static inline int tpm2_digest_rehash(TPMI_ALG_HASH alg, TPM2B_DIGEST *digest) {
|
||||
return tpm2_digest_many(alg, digest, NULL, 0, true);
|
||||
}
|
||||
static inline int tpm2_digest_init(TPMI_ALG_HASH alg, TPM2B_DIGEST *digest) {
|
||||
return tpm2_digest_many(alg, digest, NULL, 0, false);
|
||||
}
|
||||
|
||||
void tpm2_log_debug_tpml_pcr_selection(const TPML_PCR_SELECTION *l, const char *msg);
|
||||
void tpm2_log_debug_pcr_value(const Tpm2PCRValue *pcr_value, const char *msg);
|
||||
void tpm2_log_debug_buffer(const void *buffer, size_t size, const char *msg);
|
||||
void tpm2_log_debug_digest(const TPM2B_DIGEST *digest, const char *msg);
|
||||
void tpm2_log_debug_name(const TPM2B_NAME *name, const char *msg);
|
||||
|
||||
int tpm2_pcr_read(Tpm2Context *c, const TPML_PCR_SELECTION *pcr_selection, Tpm2PCRValue **ret_pcr_values, size_t *ret_n_pcr_values);
|
||||
int tpm2_pcr_read_missing_values(Tpm2Context *c, Tpm2PCRValue *pcr_values, size_t n_pcr_values);
|
||||
|
||||
int tpm2_calculate_name(const TPMT_PUBLIC *public, TPM2B_NAME *ret_name);
|
||||
int tpm2_calculate_policy_auth_value(TPM2B_DIGEST *digest);
|
||||
int tpm2_calculate_policy_authorize(const TPM2B_PUBLIC *public, const TPM2B_DIGEST *policy_ref, TPM2B_DIGEST *digest);
|
||||
int tpm2_calculate_policy_pcr(const Tpm2PCRValue *pcr_values, size_t n_pcr_values, TPM2B_DIGEST *digest);
|
||||
int tpm2_calculate_sealing_policy(const Tpm2PCRValue *pcr_values, size_t n_pcr_values, const TPM2B_PUBLIC *public, bool use_pin, TPM2B_DIGEST *digest);
|
||||
|
||||
int tpm2_seal(Tpm2Context *c, const TPM2B_DIGEST *policy, const char *pin, void **ret_secret, size_t *ret_secret_size, void **ret_blob, size_t *ret_blob_size, uint16_t *ret_primary_alg, void **ret_srk_buf, size_t *ret_srk_buf_size);
|
||||
int tpm2_unseal(const char *device, uint32_t hash_pcr_mask, uint16_t pcr_bank, const void *pubkey, size_t pubkey_size, uint32_t pubkey_pcr_mask, JsonVariant *signature, const char *pin, uint16_t primary_alg, const void *blob, size_t blob_size, const void *policy_hash, size_t policy_hash_size, const void *srk_buf, size_t srk_buf_size, void **ret_secret, size_t *ret_secret_size);
|
||||
|
||||
#if HAVE_OPENSSL
|
||||
int tpm2_tpm2b_public_to_openssl_pkey(const TPM2B_PUBLIC *public, EVP_PKEY **ret);
|
||||
int tpm2_tpm2b_public_from_openssl_pkey(const EVP_PKEY *pkey, TPM2B_PUBLIC *ret);
|
||||
#endif
|
||||
|
||||
int tpm2_tpm2b_public_from_pem(const void *pem, size_t pem_size, TPM2B_PUBLIC *ret);
|
||||
int tpm2_tpm2b_public_to_fingerprint(const TPM2B_PUBLIC *public, void **ret_fingerprint, size_t *ret_fingerprint_size);
|
||||
|
||||
/* The tpm2-tss library has many structs that are simply a combination of an array (or object) and
|
||||
* size. These macros allow easily initializing or assigning instances of such structs from an existing
|
||||
* buffer/object and size, while also checking the size for safety with the struct buffer/object size. If the
|
||||
* provided buffer/object is NULL, the resulting struct's buffer/object will be 0s. If the provided size is
|
||||
* larger than the struct's buffer/object size, this results in assertion failure; to check the size, use one
|
||||
* of the TPM2B_*_CHECK_SIZE() macros. */
|
||||
#define TPM2B_AUTH_MAKE(b, s) TPM2B_BUF_SIZE_STRUCT_MAKE(b, s, TPM2B_AUTH, buffer, size)
|
||||
#define TPM2B_DATA_MAKE(b, s) TPM2B_BUF_SIZE_STRUCT_MAKE(b, s, TPM2B_DATA, buffer, size)
|
||||
#define TPM2B_DIGEST_MAKE(b, s) TPM2B_BUF_SIZE_STRUCT_MAKE(b, s, TPM2B_DIGEST, buffer, size)
|
||||
#define TPM2B_ECC_PARAMETER_MAKE(b, s) TPM2B_BUF_SIZE_STRUCT_MAKE(b, s, TPM2B_ECC_PARAMETER, buffer, size)
|
||||
#define TPM2B_ENCRYPTED_SECRET_MAKE(b, s) TPM2B_BUF_SIZE_STRUCT_MAKE(b, s, TPM2B_ENCRYPTED_SECRET, secret, size)
|
||||
#define TPM2B_MAX_BUFFER_MAKE(b, s) TPM2B_BUF_SIZE_STRUCT_MAKE(b, s, TPM2B_MAX_BUFFER, buffer, size)
|
||||
#define TPM2B_NAME_MAKE(b, s) TPM2B_BUF_SIZE_STRUCT_MAKE(b, s, TPM2B_NAME, name, size)
|
||||
#define TPM2B_PRIVATE_MAKE(b, s) TPM2B_BUF_SIZE_STRUCT_MAKE(b, s, TPM2B_PRIVATE, buffer, size)
|
||||
#define TPM2B_PRIVATE_KEY_RSA_MAKE(b, s) TPM2B_BUF_SIZE_STRUCT_MAKE(b, s, TPM2B_PRIVATE_KEY_RSA, buffer, size)
|
||||
#define TPM2B_PUBLIC_KEY_RSA_MAKE(b, s) TPM2B_BUF_SIZE_STRUCT_MAKE(b, s, TPM2B_PUBLIC_KEY_RSA, buffer, size)
|
||||
#define TPM2B_SENSITIVE_DATA_MAKE(b, s) TPM2B_BUF_SIZE_STRUCT_MAKE(b, s, TPM2B_SENSITIVE_DATA, buffer, size)
|
||||
#define TPM2B_BUF_SIZE_STRUCT_MAKE(buf, size, struct_type, buffer_field, size_field) \
|
||||
_TPM2B_BUF_SIZE_STRUCT_MAKE(buf, size, UNIQ, struct_type, buffer_field, size_field)
|
||||
#define _TPM2B_BUF_SIZE_STRUCT_MAKE(buf, size, uniq, struct_type, buffer_field, size_field) \
|
||||
({ \
|
||||
typeof(buf) UNIQ_T(BUF, uniq) = (buf); \
|
||||
typeof(size) UNIQ_T(SIZE, uniq) = (size); \
|
||||
struct_type UNIQ_T(STRUCT, uniq) = { .size_field = UNIQ_T(SIZE, uniq), }; \
|
||||
assert(sizeof(UNIQ_T(STRUCT, uniq).buffer_field) >= (size_t) UNIQ_T(SIZE, uniq)); \
|
||||
if (UNIQ_T(BUF, uniq)) \
|
||||
memcpy(UNIQ_T(STRUCT, uniq).buffer_field, UNIQ_T(BUF, uniq), UNIQ_T(SIZE, uniq)); \
|
||||
UNIQ_T(STRUCT, uniq); \
|
||||
})
|
||||
|
||||
/* Check if the size will fit in the TPM2B struct buffer. Returns 0 if the size will fit, otherwise this logs
|
||||
* a debug message and returns < 0. */
|
||||
#define TPM2B_AUTH_CHECK_SIZE(s) TPM2B_BUF_SIZE_STRUCT_CHECK_SIZE(s, TPM2B_AUTH, buffer)
|
||||
#define TPM2B_DATA_CHECK_SIZE(s) TPM2B_BUF_SIZE_STRUCT_CHECK_SIZE(s, TPM2B_DATA, buffer)
|
||||
#define TPM2B_DIGEST_CHECK_SIZE(s) TPM2B_BUF_SIZE_STRUCT_CHECK_SIZE(s, TPM2B_DIGEST, buffer)
|
||||
#define TPM2B_ECC_PARAMETER_CHECK_SIZE(s) TPM2B_BUF_SIZE_STRUCT_CHECK_SIZE(s, TPM2B_ECC_PARAMETER, buffer)
|
||||
#define TPM2B_ENCRYPTED_SECRET_CHECK_SIZE(s) TPM2B_BUF_SIZE_STRUCT_CHECK_SIZE(s, TPM2B_ENCRYPTED_SECRET, buffer)
|
||||
#define TPM2B_MAX_BUFFER_CHECK_SIZE(s) TPM2B_BUF_SIZE_STRUCT_CHECK_SIZE(s, TPM2B_MAX_BUFFER, buffer)
|
||||
#define TPM2B_NAME_CHECK_SIZE(s) TPM2B_BUF_SIZE_STRUCT_CHECK_SIZE(s, TPM2B_NAME, name)
|
||||
#define TPM2B_PRIVATE_CHECK_SIZE(s) TPM2B_BUF_SIZE_STRUCT_CHECK_SIZE(s, TPM2B_PRIVATE, buffer)
|
||||
#define TPM2B_PRIVATE_KEY_RSA_CHECK_SIZE(s) TPM2B_BUF_SIZE_STRUCT_CHECK_SIZE(s, TPM2B_PRIVATE_KEY_RSA, buffer)
|
||||
#define TPM2B_PUBLIC_KEY_RSA_CHECK_SIZE(s) TPM2B_BUF_SIZE_STRUCT_CHECK_SIZE(s, TPM2B_PUBLIC_KEY_RSA, buffer)
|
||||
#define TPM2B_SENSITIVE_DATA_CHECK_SIZE(s) TPM2B_BUF_SIZE_STRUCT_CHECK_SIZE(s, TPM2B_SENSITIVE_DATA, buffer)
|
||||
#define TPM2B_BUF_SIZE_STRUCT_CHECK_SIZE(size, struct_type, buffer_field) \
|
||||
_TPM2B_BUF_SIZE_STRUCT_CHECK_SIZE(size, UNIQ, struct_type, buffer_field)
|
||||
#define _TPM2B_BUF_SIZE_STRUCT_CHECK_SIZE(size, uniq, struct_type, buffer_field) \
|
||||
({ \
|
||||
size_t UNIQ_T(SIZE, uniq) = (size_t) (size); \
|
||||
size_t UNIQ_T(BUFSIZE, uniq) = sizeof_field(struct_type, buffer_field); \
|
||||
UNIQ_T(BUFSIZE, uniq) < UNIQ_T(SIZE, uniq) ? \
|
||||
log_debug_errno(SYNTHETIC_ERRNO(EINVAL), \
|
||||
"Size %zu larger than " #struct_type " buffer size %zu.", \
|
||||
UNIQ_T(SIZE, uniq), UNIQ_T(BUFSIZE, uniq)) : \
|
||||
0; \
|
||||
})
|
||||
|
||||
#else /* HAVE_TPM2 */
|
||||
typedef struct {} Tpm2Context;
|
||||
typedef struct {} Tpm2Handle;
|
||||
typedef struct {} Tpm2PCRValue;
|
||||
|
||||
#define TPM2_PCR_VALUE_MAKE(i, h, v) (Tpm2PCRValue) {}
|
||||
#endif /* HAVE_TPM2 */
|
||||
|
||||
int tpm2_list_devices(void);
|
||||
@@ -136,7 +241,8 @@ int tpm2_make_luks2_json(int keyslot, uint32_t hash_pcr_mask, uint16_t pcr_bank,
|
||||
int tpm2_parse_luks2_json(JsonVariant *v, int *ret_keyslot, uint32_t *ret_hash_pcr_mask, uint16_t *ret_pcr_bank, void **ret_pubkey, size_t *ret_pubkey_size, uint32_t *ret_pubkey_pcr_mask, uint16_t *ret_primary_alg, void **ret_blob, size_t *ret_blob_size, void **ret_policy_hash, size_t *ret_policy_hash_size, void **ret_salt, size_t *ret_salt_size, void **ret_srk_buf, size_t *ret_srk_buf_size, TPM2Flags *ret_flags);
|
||||
|
||||
/* Default to PCR 7 only */
|
||||
#define TPM2_PCR_MASK_DEFAULT (UINT32_C(1) << 7)
|
||||
#define TPM2_PCR_INDEX_DEFAULT (7)
|
||||
#define TPM2_PCR_MASK_DEFAULT INDEX_TO_MASK(uint32_t, TPM2_PCR_INDEX_DEFAULT)
|
||||
|
||||
/* We want the helpers below to work also if TPM2 libs are not available, hence define these four defines if
|
||||
* they are missing. */
|
||||
@@ -164,6 +270,8 @@ int tpm2_parse_luks2_json(JsonVariant *v, int *ret_keyslot, uint32_t *ret_hash_p
|
||||
#define TPM2_ALG_RSA 0x1
|
||||
#endif
|
||||
|
||||
int tpm2_hash_alg_to_size(uint16_t alg);
|
||||
|
||||
const char *tpm2_hash_alg_to_string(uint16_t alg);
|
||||
int tpm2_hash_alg_from_string(const char *alg);
|
||||
|
||||
@@ -171,7 +279,6 @@ const char *tpm2_asym_alg_to_string(uint16_t alg);
|
||||
int tpm2_asym_alg_from_string(const char *alg);
|
||||
|
||||
char *tpm2_pcr_mask_to_string(uint32_t mask);
|
||||
int tpm2_pcr_mask_from_string(const char *arg, uint32_t *mask);
|
||||
|
||||
typedef struct {
|
||||
uint32_t search_pcr_mask;
|
||||
@@ -220,7 +327,9 @@ enum {
|
||||
|
||||
Tpm2Support tpm2_support(void);
|
||||
|
||||
int tpm2_parse_pcr_argument(const char *arg, uint32_t *mask);
|
||||
int tpm2_parse_pcr_argument(const char *arg, Tpm2PCRValue **ret_pcr_values, size_t *ret_n_pcr_values);
|
||||
int tpm2_parse_pcr_argument_append(const char *arg, Tpm2PCRValue **ret_pcr_values, size_t *ret_n_pcr_values);
|
||||
int tpm2_parse_pcr_argument_to_mask(const char *arg, uint32_t *mask);
|
||||
|
||||
int tpm2_load_pcr_signature(const char *path, JsonVariant **ret);
|
||||
int tpm2_load_pcr_public_key(const char *path, void **ret_pubkey, size_t *ret_pubkey_size);
|
||||
|
||||
@@ -167,7 +167,6 @@ simple_tests += files(
|
||||
'test-sysctl-util.c',
|
||||
'test-terminal-util.c',
|
||||
'test-tmpfile-util.c',
|
||||
'test-tpm2.c',
|
||||
'test-udev-util.c',
|
||||
'test-uid-alloc-range.c',
|
||||
'test-uid-range.c',
|
||||
@@ -353,6 +352,11 @@ executables += [
|
||||
'dependencies' : libdl,
|
||||
'conditions' : ['ENABLE_NSS'],
|
||||
},
|
||||
test_template + {
|
||||
'sources' : files('test-openssl.c'),
|
||||
'dependencies' : libopenssl,
|
||||
'conditions' : ['HAVE_OPENSSL'],
|
||||
},
|
||||
test_template + {
|
||||
'sources' : files('test-parse-util.c'),
|
||||
'dependencies' : libm,
|
||||
@@ -415,6 +419,10 @@ executables += [
|
||||
'sources' : files('test-time-util.c'),
|
||||
'timeout' : 120,
|
||||
},
|
||||
test_template + {
|
||||
'sources' : files('test-tpm2.c'),
|
||||
'dependencies' : libopenssl,
|
||||
},
|
||||
test_template + {
|
||||
'sources' : files('test-utmp.c'),
|
||||
'conditions' : ['ENABLE_UTMP'],
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include "hexdecoct.h"
|
||||
#include "openssl-util.h"
|
||||
#include "tests.h"
|
||||
|
||||
TEST(openssl_pkey_from_pem) {
|
||||
DEFINE_HEX_PTR(key_ecc, "2d2d2d2d2d424547494e205055424c4943204b45592d2d2d2d2d0a4d466b77457759484b6f5a497a6a3043415159494b6f5a497a6a30444151634451674145726a6e4575424c73496c3972687068777976584e50686a346a426e500a44586e794a304b395579724e6764365335413532542b6f5376746b436a365a726c34685847337741515558706f426c532b7448717452714c35513d3d0a2d2d2d2d2d454e44205055424c4943204b45592d2d2d2d2d0a");
|
||||
_cleanup_(EVP_PKEY_freep) EVP_PKEY *pkey_ecc = NULL;
|
||||
assert_se(openssl_pkey_from_pem(key_ecc, key_ecc_len, &pkey_ecc) >= 0);
|
||||
|
||||
_cleanup_free_ void *x = NULL, *y = NULL;
|
||||
size_t x_len, y_len;
|
||||
int curve_id;
|
||||
assert_se(ecc_pkey_to_curve_x_y(pkey_ecc, &curve_id, &x, &x_len, &y, &y_len) >= 0);
|
||||
assert_se(curve_id == NID_X9_62_prime256v1);
|
||||
|
||||
DEFINE_HEX_PTR(expected_x, "ae39c4b812ec225f6b869870caf5cd3e18f88c19cf0d79f22742bd532acd81de");
|
||||
assert_se(x_len == expected_x_len);
|
||||
assert_se(memcmp(x, expected_x, x_len) == 0);
|
||||
|
||||
DEFINE_HEX_PTR(expected_y, "92e40e764fea12bed9028fa66b9788571b7c004145e9a01952fad1eab51a8be5");
|
||||
assert_se(y_len == expected_y_len);
|
||||
assert_se(memcmp(y, expected_y, y_len) == 0);
|
||||
|
||||
DEFINE_HEX_PTR(key_rsa, "2d2d2d2d2d424547494e205055424c4943204b45592d2d2d2d2d0a4d494942496a414e42676b71686b6947397730424151454641414f43415138414d49494243674b4341514541795639434950652f505852337a436f63787045300a6a575262546c3568585844436b472f584b79374b6d2f4439584942334b734f5a31436a5937375571372f674359363170697838697552756a73413464503165380a593445336c68556d374a332b6473766b626f4b64553243626d52494c2f6675627771694c4d587a41673342575278747234547545443533527a373634554650640a307a70304b68775231496230444c67772f344e67566f314146763378784b4d6478774d45683567676b73733038326332706c354a504e32587677426f744e6b4d0a5471526c745a4a35355244436170696e7153334577376675646c4e735851357746766c7432377a7637344b585165616d704c59433037584f6761304c676c536b0a79754774586b6a50542f735542544a705374615769674d5a6f714b7479563463515a58436b4a52684459614c47587673504233687a766d5671636e6b47654e540a65774944415141420a2d2d2d2d2d454e44205055424c4943204b45592d2d2d2d2d0a");
|
||||
_cleanup_(EVP_PKEY_freep) EVP_PKEY *pkey_rsa = NULL;
|
||||
assert_se(openssl_pkey_from_pem(key_rsa, key_rsa_len, &pkey_rsa) >= 0);
|
||||
|
||||
_cleanup_free_ void *n = NULL, *e = NULL;
|
||||
size_t n_len, e_len;
|
||||
assert_se(rsa_pkey_to_n_e(pkey_rsa, &n, &n_len, &e, &e_len) >= 0);
|
||||
|
||||
DEFINE_HEX_PTR(expected_n, "c95f4220f7bf3d7477cc2a1cc691348d645b4e5e615d70c2906fd72b2eca9bf0fd5c80772ac399d428d8efb52aeff80263ad698b1f22b91ba3b00e1d3f57bc638137961526ec9dfe76cbe46e829d53609b99120bfdfb9bc2a88b317cc0837056471b6be13b840f9dd1cfbeb85053ddd33a742a1c11d486f40cb830ff8360568d4016fdf1c4a31dc7030487982092cb34f36736a65e493cdd97bf0068b4d90c4ea465b59279e510c26a98a7a92dc4c3b7ee76536c5d0e7016f96ddbbcefef829741e6a6a4b602d3b5ce81ad0b8254a4cae1ad5e48cf4ffb140532694ad6968a0319a2a2adc95e1c4195c29094610d868b197bec3c1de1cef995a9c9e419e3537b");
|
||||
assert_se(n_len == expected_n_len);
|
||||
assert_se(memcmp(n, expected_n, n_len) == 0);
|
||||
|
||||
DEFINE_HEX_PTR(expected_e, "010001");
|
||||
assert_se(e_len == expected_e_len);
|
||||
assert_se(memcmp(e, expected_e, e_len) == 0);
|
||||
}
|
||||
|
||||
TEST(rsa_pkey_n_e) {
|
||||
DEFINE_HEX_PTR(n, "e3975a2124a7c9fe57752d106314ff62f6da731632eac221f1c0255bdcf2a34eeb21e3ab89ba8759ddad3b68be99463c7f03f3d004028a35e6f7c6596aeab2558d490f1e1c38aed2ff796bda8d6d55704eefb6ac55842dd6e606bb707f66acc02f0db2aed0dabab885bd0c850f1bdc8ac4b6bc1f74858db8ca2ab57a3d4217c091e9cd78727a2e36b8126ea629e81fecc69b0bea601000a6c0b749c5be16f53f4fa9f208a581d804234eb6526ba3fee9822d58d1ab9cac2761d7f630eb7ad6054dff0856d41aea219e1adfd87256aa1532202a070f4b1044e718d1f38bbc5a4b1fcb024f04afaafda5edeacfdf0d0bdf35c359acd059e3edb5024e588458f9b5");
|
||||
uint32_t e = htobe32(0x10001);
|
||||
|
||||
_cleanup_(EVP_PKEY_freep) EVP_PKEY *pkey = NULL;
|
||||
assert_se(rsa_pkey_from_n_e(n, n_len, &e, sizeof(e), &pkey) >= 0);
|
||||
|
||||
_cleanup_(EVP_PKEY_CTX_freep) EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new((EVP_PKEY*) pkey, NULL);
|
||||
assert_se(ctx);
|
||||
assert_se(EVP_PKEY_verify_init(ctx) == 1);
|
||||
|
||||
const char *msg = "this is a secret";
|
||||
DEFINE_HEX_PTR(sig, "14b53e0c6ad99a350c3d7811e8160f4ae03ad159815bb91bddb9735b833588df2eac221fbd3fc4ece0dd63bfaeddfdaf4ae67021e759f3638bc194836413414f54e8c4d01c9c37fa4488ea2ef772276b8a33822a53c97b1c35acfb4bc621cfb8fad88f0cf7d5491f05236886afbf9ed47f9469536482f50f74a20defa59d99676bed62a17b5eb98641df5a2f8080fa4b24f2749cc152fa65ba34c14022fcb27f1b36f52021950d7b9b6c3042c50b84cfb7d55a5f9235bfd58e1bf1f604eb93416c5fb5fd90cb68f1270dfa9daf67f52c604f62c2f2beee5e7e672b0e6e9833dd43dba99b77668540c850c9a81a5ea7aaf6297383e6135bd64572362333121fc7");
|
||||
assert_se(EVP_PKEY_verify(ctx, sig, sig_len, (unsigned char*) msg, strlen(msg)) == 1);
|
||||
|
||||
DEFINE_HEX_PTR(invalid_sig, "1234");
|
||||
assert_se(EVP_PKEY_verify(ctx, invalid_sig, invalid_sig_len, (unsigned char*) msg, strlen(msg)) != 1);
|
||||
|
||||
_cleanup_free_ void *n2 = NULL, *e2 = NULL;
|
||||
size_t n2_size, e2_size;
|
||||
assert_se(rsa_pkey_to_n_e(pkey, &n2, &n2_size, &e2, &e2_size) >= 0);
|
||||
assert_se(memcmp_nn(n, n_len, n2, n2_size) == 0);
|
||||
assert_se(e2_size <= sizeof(uint32_t));
|
||||
assert_se(memcmp(&((uint8_t*) &e)[sizeof(uint32_t) - e2_size], e2, e2_size) == 0);
|
||||
}
|
||||
|
||||
TEST(ecc_pkey_curve_x_y) {
|
||||
int curveid = NID_X9_62_prime256v1;
|
||||
DEFINE_HEX_PTR(x, "2830d2c8f65d3efbef12303b968b91692f8bd04045dcb8a9656374e4ae61d818");
|
||||
DEFINE_HEX_PTR(y, "8a80750f76729defdcc2a4bc1a91c22e60109dd6e1ffde634a650a20bab172e9");
|
||||
|
||||
_cleanup_(EVP_PKEY_freep) EVP_PKEY *pkey = NULL;
|
||||
assert_se(ecc_pkey_from_curve_x_y(curveid, x, x_len, y, y_len, &pkey) >= 0);
|
||||
|
||||
_cleanup_(EVP_PKEY_CTX_freep) EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new((EVP_PKEY*) pkey, NULL);
|
||||
assert_se(ctx);
|
||||
assert_se(EVP_PKEY_verify_init(ctx) == 1);
|
||||
|
||||
const char *msg = "this is a secret";
|
||||
DEFINE_HEX_PTR(sig, "3045022100f6ca10f7ed57a020679899b26dd5ac5a1079265885e2a6477f527b6a3f02b5ca02207b550eb3e7b69360aff977f7f6afac99c3f28266b6c5338ce373f6b59263000a");
|
||||
assert_se(EVP_PKEY_verify(ctx, sig, sig_len, (unsigned char*) msg, strlen(msg)) == 1);
|
||||
|
||||
DEFINE_HEX_PTR(invalid_sig, "1234");
|
||||
assert_se(EVP_PKEY_verify(ctx, invalid_sig, invalid_sig_len, (unsigned char*) msg, strlen(msg)) != 1);
|
||||
|
||||
_cleanup_free_ void *x2 = NULL, *y2 = NULL;
|
||||
size_t x2_size, y2_size;
|
||||
int curveid2;
|
||||
assert_se(ecc_pkey_to_curve_x_y(pkey, &curveid2, &x2, &x2_size, &y2, &y2_size) >= 0);
|
||||
assert_se(curveid == curveid2);
|
||||
assert_se(memcmp_nn(x, x_len, x2, x2_size) == 0);
|
||||
assert_se(memcmp_nn(y, y_len, y2, y2_size) == 0);
|
||||
}
|
||||
|
||||
DEFINE_TEST_MAIN(LOG_DEBUG);
|
||||
+393
-113
@@ -4,39 +4,6 @@
|
||||
#include "tpm2-util.h"
|
||||
#include "tests.h"
|
||||
|
||||
static void test_tpm2_pcr_mask_from_string_one(const char *s, uint32_t mask, int ret) {
|
||||
uint32_t m;
|
||||
|
||||
assert_se(tpm2_pcr_mask_from_string(s, &m) == ret);
|
||||
|
||||
if (ret >= 0)
|
||||
assert_se(m == mask);
|
||||
}
|
||||
|
||||
TEST(tpm2_mask_from_string) {
|
||||
test_tpm2_pcr_mask_from_string_one("", 0, 0);
|
||||
test_tpm2_pcr_mask_from_string_one("0", 1, 0);
|
||||
test_tpm2_pcr_mask_from_string_one("1", 2, 0);
|
||||
test_tpm2_pcr_mask_from_string_one("0,1", 3, 0);
|
||||
test_tpm2_pcr_mask_from_string_one("0+1", 3, 0);
|
||||
test_tpm2_pcr_mask_from_string_one("0-1", 0, -EINVAL);
|
||||
test_tpm2_pcr_mask_from_string_one("0,1,2", 7, 0);
|
||||
test_tpm2_pcr_mask_from_string_one("0+1+2", 7, 0);
|
||||
test_tpm2_pcr_mask_from_string_one("0+1,2", 7, 0);
|
||||
test_tpm2_pcr_mask_from_string_one("0,1+2", 7, 0);
|
||||
test_tpm2_pcr_mask_from_string_one("0,2", 5, 0);
|
||||
test_tpm2_pcr_mask_from_string_one("0+2", 5, 0);
|
||||
test_tpm2_pcr_mask_from_string_one("foo", 0, -EINVAL);
|
||||
test_tpm2_pcr_mask_from_string_one("7+application-support", 8388736, 0);
|
||||
test_tpm2_pcr_mask_from_string_one("8+boot-loader-code", 272, 0);
|
||||
test_tpm2_pcr_mask_from_string_one("6+boot-loader-code,44", 0, -EINVAL);
|
||||
test_tpm2_pcr_mask_from_string_one("7,shim-policy,4", 16528, 0);
|
||||
test_tpm2_pcr_mask_from_string_one("sysexts,shim-policy+kernel-boot", 26624, 0);
|
||||
test_tpm2_pcr_mask_from_string_one("sysexts,shim+kernel-boot", 0, -EINVAL);
|
||||
test_tpm2_pcr_mask_from_string_one("sysexts+17+23", 8527872, 0);
|
||||
test_tpm2_pcr_mask_from_string_one("debug+24", 0, -EINVAL);
|
||||
}
|
||||
|
||||
TEST(pcr_index_from_string) {
|
||||
assert_se(pcr_index_from_string("platform-code") == 0);
|
||||
assert_se(pcr_index_from_string("0") == 0);
|
||||
@@ -158,9 +125,7 @@ static void verify_tpms_pcr_selection(TPMS_PCR_SELECTION *s, uint32_t mask, TPMI
|
||||
assert_se(s->pcrSelect[2] == ((mask >> 16) & 0xff));
|
||||
assert_se(s->pcrSelect[3] == 0);
|
||||
|
||||
uint32_t m = POISON_U32;
|
||||
tpm2_tpms_pcr_selection_to_mask(s, &m);
|
||||
assert_se(m == mask);
|
||||
assert_se(tpm2_tpms_pcr_selection_to_mask(s) == mask);
|
||||
}
|
||||
|
||||
static void verify_tpml_pcr_selection(TPML_PCR_SELECTION *l, TPMS_PCR_SELECTION s[], size_t count) {
|
||||
@@ -168,10 +133,8 @@ static void verify_tpml_pcr_selection(TPML_PCR_SELECTION *l, TPMS_PCR_SELECTION
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
assert_tpms_pcr_selection_eq(&s[i], &l->pcrSelections[i]);
|
||||
|
||||
uint32_t mask = POISON_U32;
|
||||
TPMI_ALG_HASH hash = l->pcrSelections[i].hash;
|
||||
assert_se(tpm2_tpml_pcr_selection_to_mask(l, hash, &mask) == 0);
|
||||
verify_tpms_pcr_selection(&l->pcrSelections[i], mask, hash);
|
||||
verify_tpms_pcr_selection(&l->pcrSelections[i], tpm2_tpml_pcr_selection_to_mask(l, hash), hash);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -467,21 +430,18 @@ static bool digest_check(const TPM2B_DIGEST *digest, const char *expect) {
|
||||
h = hexmem(digest->buffer, digest->size);
|
||||
assert_se(h);
|
||||
|
||||
return streq(expect, h);
|
||||
return strcaseeq(expect, h);
|
||||
}
|
||||
|
||||
static void digest_init_sha256(TPM2B_DIGEST *digest, const char *hash) {
|
||||
_cleanup_free_ void *h = NULL;
|
||||
size_t s = 0;
|
||||
|
||||
assert_se(strlen(hash) == SHA256_DIGEST_SIZE * 2);
|
||||
static void digest_init(TPM2B_DIGEST *digest, const char *hash) {
|
||||
assert_se(strlen(hash) <= sizeof(digest->buffer) * 2);
|
||||
|
||||
assert_se(unhexmem(hash, strlen(hash), &h, &s) == 0);
|
||||
assert_se(s == SHA256_DIGEST_SIZE);
|
||||
DEFINE_HEX_PTR(h, hash);
|
||||
|
||||
memcpy_safe(digest->buffer, h, s);
|
||||
digest->size = s;
|
||||
/* Make sure the length matches a known hash algorithm */
|
||||
assert_se(IN_SET(h_len, TPM2_SHA1_DIGEST_SIZE, TPM2_SHA256_DIGEST_SIZE, TPM2_SHA384_DIGEST_SIZE, TPM2_SHA512_DIGEST_SIZE));
|
||||
|
||||
*digest = TPM2B_DIGEST_MAKE(h, h_len);
|
||||
|
||||
assert_se(digest_check(digest, hash));
|
||||
}
|
||||
@@ -489,11 +449,11 @@ static void digest_init_sha256(TPM2B_DIGEST *digest, const char *hash) {
|
||||
TEST(digest_many) {
|
||||
TPM2B_DIGEST d, d0, d1, d2, d3, d4;
|
||||
|
||||
digest_init_sha256(&d0, "0000000000000000000000000000000000000000000000000000000000000000");
|
||||
digest_init_sha256(&d1, "17b7703d9d00776310ba032e88c1a8c2a9c630ebdd799db622f6631530789175");
|
||||
digest_init_sha256(&d2, "12998c017066eb0d2a70b94e6ed3192985855ce390f321bbdb832022888bd251");
|
||||
digest_init_sha256(&d3, "c3a65887fedd3fb4f5d0047e906dff830bcbd1293160909eb4b05f485e7387ad");
|
||||
digest_init_sha256(&d4, "6491fb4bc08fc0b2ef47fc63db57e249917885e69d8c0d99667df83a59107a33");
|
||||
digest_init(&d0, "0000000000000000000000000000000000000000000000000000000000000000");
|
||||
digest_init(&d1, "17b7703d9d00776310ba032e88c1a8c2a9c630ebdd799db622f6631530789175");
|
||||
digest_init(&d2, "12998c017066eb0d2a70b94e6ed3192985855ce390f321bbdb832022888bd251");
|
||||
digest_init(&d3, "c3a65887fedd3fb4f5d0047e906dff830bcbd1293160909eb4b05f485e7387ad");
|
||||
digest_init(&d4, "6491fb4bc08fc0b2ef47fc63db57e249917885e69d8c0d99667df83a59107a33");
|
||||
|
||||
/* tpm2_digest_init, tpm2_digest_rehash */
|
||||
d = (TPM2B_DIGEST){ .size = 1, .buffer = { 2, }, };
|
||||
@@ -557,7 +517,192 @@ TEST(digest_many) {
|
||||
assert_se(digest_check(&d, "02ecb0628264235111e0053e271092981c8b15d59cd46617836bee3149a4ecb0"));
|
||||
}
|
||||
|
||||
static void tpm2b_public_init(TPM2B_PUBLIC *public) {
|
||||
static void check_parse_pcr_argument(
|
||||
const char *arg,
|
||||
const Tpm2PCRValue *prev_values,
|
||||
size_t n_prev_values,
|
||||
const Tpm2PCRValue *expected_values,
|
||||
size_t n_expected_values) {
|
||||
|
||||
_cleanup_free_ Tpm2PCRValue *values = NULL;
|
||||
size_t n_values = 0;
|
||||
|
||||
if (n_prev_values > 0) {
|
||||
assert_se(GREEDY_REALLOC_APPEND(values, n_values, prev_values, n_prev_values));
|
||||
assert_se(tpm2_parse_pcr_argument_append(arg, &values, &n_values) == 0);
|
||||
} else
|
||||
assert_se(tpm2_parse_pcr_argument(arg, &values, &n_values) == 0);
|
||||
|
||||
assert_se(n_values == n_expected_values);
|
||||
for (size_t i = 0; i < n_values; i++) {
|
||||
const Tpm2PCRValue *v = &values[i], *e = &expected_values[i];
|
||||
//tpm2_log_debug_pcr_value(e, "Expected value");
|
||||
//tpm2_log_debug_pcr_value(v, "Actual value");
|
||||
|
||||
assert_se(v->index == e->index);
|
||||
assert_se(v->hash == e->hash);
|
||||
assert_se(v->value.size == e->value.size);
|
||||
assert_se(memcmp(v->value.buffer, e->value.buffer, e->value.size) == 0);
|
||||
}
|
||||
|
||||
size_t hash_count;
|
||||
assert_se(tpm2_pcr_values_hash_count(expected_values, n_expected_values, &hash_count) == 0);
|
||||
if (hash_count == 1) {
|
||||
uint32_t mask = UINT32_MAX, expected_mask = 0;
|
||||
|
||||
if (n_prev_values > 0)
|
||||
assert_se(tpm2_pcr_values_to_mask(prev_values, n_prev_values, prev_values[0].hash, &mask) == 0);
|
||||
|
||||
assert_se(tpm2_pcr_values_to_mask(expected_values, n_expected_values, expected_values[0].hash, &expected_mask) == 0);
|
||||
|
||||
assert_se(tpm2_parse_pcr_argument_to_mask(arg, &mask) == 0);
|
||||
assert_se(mask == expected_mask);
|
||||
}
|
||||
|
||||
size_t old_n_values = n_values;
|
||||
assert_se(tpm2_parse_pcr_argument_append("", &values, &n_values) == 0);
|
||||
assert_se(values);
|
||||
assert_se(n_values == old_n_values);
|
||||
}
|
||||
|
||||
static void check_parse_pcr_argument_to_mask(const char *arg, int mask) {
|
||||
uint32_t m = 0;
|
||||
int r = tpm2_parse_pcr_argument_to_mask(arg, &m);
|
||||
|
||||
if (mask < 0)
|
||||
assert_se(mask == r);
|
||||
else
|
||||
assert_se((uint32_t) mask == m);
|
||||
}
|
||||
|
||||
TEST(parse_pcr_argument) {
|
||||
_cleanup_free_ Tpm2PCRValue *t0p = NULL;
|
||||
size_t n_t0p;
|
||||
assert_se(tpm2_parse_pcr_argument("", &t0p, &n_t0p) == 0);
|
||||
assert_se(n_t0p == 0);
|
||||
assert_se(tpm2_parse_pcr_argument_append("", &t0p, &n_t0p) == 0);
|
||||
assert_se(n_t0p == 0);
|
||||
uint32_t m0 = 0xf;
|
||||
assert_se(tpm2_parse_pcr_argument_to_mask("", &m0) == 0);
|
||||
assert_se(m0 == 0);
|
||||
assert_se(tpm2_parse_pcr_argument_to_mask("", &m0) == 0);
|
||||
assert_se(m0 == 0);
|
||||
|
||||
Tpm2PCRValue t1[] = {
|
||||
TPM2_PCR_VALUE_MAKE(0, 0, {}),
|
||||
TPM2_PCR_VALUE_MAKE(4, 0, {}),
|
||||
TPM2_PCR_VALUE_MAKE(7, 0, {}),
|
||||
TPM2_PCR_VALUE_MAKE(11, 0, {}),
|
||||
};
|
||||
check_parse_pcr_argument("0,4,7,11", NULL, 0, t1, ELEMENTSOF(t1));
|
||||
check_parse_pcr_argument("11,4,7,0", NULL, 0, t1, ELEMENTSOF(t1));
|
||||
check_parse_pcr_argument("7,4,0,11", NULL, 0, t1, ELEMENTSOF(t1));
|
||||
check_parse_pcr_argument("11,7,4,0", NULL, 0, t1, ELEMENTSOF(t1));
|
||||
check_parse_pcr_argument("0+4+7+11", NULL, 0, t1, ELEMENTSOF(t1));
|
||||
check_parse_pcr_argument("0,4+7,11", NULL, 0, t1, ELEMENTSOF(t1));
|
||||
|
||||
Tpm2PCRValue t2[] = {
|
||||
TPM2_PCR_VALUE_MAKE(0, TPM2_ALG_SHA1, {}),
|
||||
TPM2_PCR_VALUE_MAKE(4, TPM2_ALG_SHA1, {}),
|
||||
TPM2_PCR_VALUE_MAKE(7, TPM2_ALG_SHA1, {}),
|
||||
TPM2_PCR_VALUE_MAKE(11, TPM2_ALG_SHA1, {}),
|
||||
};
|
||||
check_parse_pcr_argument("0:sha1,4,7,11", NULL, 0, t2, ELEMENTSOF(t2));
|
||||
check_parse_pcr_argument("11,4,7,0:sha1", NULL, 0, t2, ELEMENTSOF(t2));
|
||||
check_parse_pcr_argument("7,4:sha1,0,11", NULL, 0, t2, ELEMENTSOF(t2));
|
||||
check_parse_pcr_argument("0:sha1,4:sha1,7:sha1,11:sha1", NULL, 0, t2, ELEMENTSOF(t2));
|
||||
check_parse_pcr_argument("0:sha1+4:sha1,11:sha1+7:sha1", NULL, 0, t2, ELEMENTSOF(t2));
|
||||
|
||||
Tpm2PCRValue t3[] = {
|
||||
TPM2_PCR_VALUE_MAKE(0, TPM2_ALG_SHA1, {}),
|
||||
TPM2_PCR_VALUE_MAKE(1, TPM2_ALG_SHA1, {}),
|
||||
TPM2_PCR_VALUE_MAKE(2, TPM2_ALG_SHA1, {}),
|
||||
TPM2_PCR_VALUE_MAKE(3, TPM2_ALG_SHA1, {}),
|
||||
TPM2_PCR_VALUE_MAKE(4, TPM2_ALG_SHA1, {}),
|
||||
TPM2_PCR_VALUE_MAKE(7, TPM2_ALG_SHA1, {}),
|
||||
TPM2_PCR_VALUE_MAKE(11, TPM2_ALG_SHA1, {}),
|
||||
TPM2_PCR_VALUE_MAKE(12, TPM2_ALG_SHA1, {}),
|
||||
};
|
||||
check_parse_pcr_argument("1,2,3,12", t2, ELEMENTSOF(t2), t3, ELEMENTSOF(t3));
|
||||
check_parse_pcr_argument("12,2,3,1", t2, ELEMENTSOF(t2), t3, ELEMENTSOF(t3));
|
||||
check_parse_pcr_argument("1,2,3,12:sha1", t1, ELEMENTSOF(t1), t3, ELEMENTSOF(t3));
|
||||
check_parse_pcr_argument("1,2,3,12:sha1", t2, ELEMENTSOF(t2), t3, ELEMENTSOF(t3));
|
||||
check_parse_pcr_argument("1:sha1,2,3,12", t1, ELEMENTSOF(t1), t3, ELEMENTSOF(t3));
|
||||
check_parse_pcr_argument("1:sha1,2,3,12", t2, ELEMENTSOF(t2), t3, ELEMENTSOF(t3));
|
||||
check_parse_pcr_argument("1:sha1,2:sha1,3:sha1,12:sha1", t1, ELEMENTSOF(t1), t3, ELEMENTSOF(t3));
|
||||
check_parse_pcr_argument("1:sha1,2:sha1,3:sha1,12:sha1", t2, ELEMENTSOF(t2), t3, ELEMENTSOF(t3));
|
||||
|
||||
TPM2B_DIGEST d4;
|
||||
digest_init(&d4, "FCE7F1083082B16CFE2B085DD7858BB11A37C09B78E36C79E5A2FD529353C4E2");
|
||||
Tpm2PCRValue t4[] = {
|
||||
TPM2_PCR_VALUE_MAKE(0, TPM2_ALG_SHA256, {}),
|
||||
TPM2_PCR_VALUE_MAKE(1, TPM2_ALG_SHA256, d4),
|
||||
TPM2_PCR_VALUE_MAKE(2, TPM2_ALG_SHA256, {}),
|
||||
TPM2_PCR_VALUE_MAKE(3, TPM2_ALG_SHA256, {}),
|
||||
TPM2_PCR_VALUE_MAKE(4, TPM2_ALG_SHA256, {}),
|
||||
TPM2_PCR_VALUE_MAKE(7, TPM2_ALG_SHA256, {}),
|
||||
TPM2_PCR_VALUE_MAKE(11, TPM2_ALG_SHA256, {}),
|
||||
TPM2_PCR_VALUE_MAKE(12, TPM2_ALG_SHA256, {}),
|
||||
};
|
||||
check_parse_pcr_argument("1:sha256=0xFCE7F1083082B16CFE2B085DD7858BB11A37C09B78E36C79E5A2FD529353C4E2,2,3,12", t1, ELEMENTSOF(t1), t4, ELEMENTSOF(t4));
|
||||
check_parse_pcr_argument("12,2,3,1:sha256=FCE7F1083082B16CFE2B085DD7858BB11A37C09B78E36C79E5A2FD529353C4E2", t1, ELEMENTSOF(t1), t4, ELEMENTSOF(t4));
|
||||
check_parse_pcr_argument("12,2,3,1:sha256=0xFCE7F1083082B16CFE2B085DD7858BB11A37C09B78E36C79E5A2FD529353C4E2", t1, ELEMENTSOF(t1), t4, ELEMENTSOF(t4));
|
||||
check_parse_pcr_argument("1:sha256=0xFCE7F1083082B16CFE2B085DD7858BB11A37C09B78E36C79E5A2FD529353C4E2,2,3,12:SHA256", t1, ELEMENTSOF(t1), t4, ELEMENTSOF(t4));
|
||||
check_parse_pcr_argument("1:sha256=0xFCE7F1083082B16CFE2B085DD7858BB11A37C09B78E36C79E5A2FD529353C4E2,2,3,12", t1, ELEMENTSOF(t1), t4, ELEMENTSOF(t4));
|
||||
check_parse_pcr_argument("1:sha256=FCE7F1083082B16CFE2B085DD7858BB11A37C09B78E36C79E5A2FD529353C4E2,2:sha256,3:sha256,12:sha256", t1, ELEMENTSOF(t1), t4, ELEMENTSOF(t4));
|
||||
check_parse_pcr_argument("1:sha256=0xFCE7F1083082B16CFE2B085DD7858BB11A37C09B78E36C79E5A2FD529353C4E2,2:sha256,3:sha256,12:sha256", t1, ELEMENTSOF(t1), t4, ELEMENTSOF(t4));
|
||||
|
||||
TPM2B_DIGEST d5;
|
||||
digest_init(&d5, "0F21EADB7F27377668E3C8069BE88D116491FBEE");
|
||||
Tpm2PCRValue t5[] = {
|
||||
TPM2_PCR_VALUE_MAKE(1, TPM2_ALG_SHA1, d5),
|
||||
TPM2_PCR_VALUE_MAKE(0, TPM2_ALG_SHA256, {}),
|
||||
TPM2_PCR_VALUE_MAKE(1, TPM2_ALG_SHA256, d4),
|
||||
TPM2_PCR_VALUE_MAKE(2, TPM2_ALG_SHA256, {}),
|
||||
TPM2_PCR_VALUE_MAKE(3, TPM2_ALG_SHA256, {}),
|
||||
TPM2_PCR_VALUE_MAKE(4, TPM2_ALG_SHA256, {}),
|
||||
TPM2_PCR_VALUE_MAKE(7, TPM2_ALG_SHA256, {}),
|
||||
TPM2_PCR_VALUE_MAKE(11, TPM2_ALG_SHA256, {}),
|
||||
TPM2_PCR_VALUE_MAKE(12, TPM2_ALG_SHA256, {}),
|
||||
TPM2_PCR_VALUE_MAKE(5, TPM2_ALG_SHA384, {}),
|
||||
TPM2_PCR_VALUE_MAKE(6, TPM2_ALG_SHA512, {}),
|
||||
};
|
||||
check_parse_pcr_argument("0,1:sha256=0xFCE7F1083082B16CFE2B085DD7858BB11A37C09B78E36C79E5A2FD529353C4E2,1:sha1=0F21EADB7F27377668E3C8069BE88D116491FBEE,2,3,4,7,11,12,5:sha384,6:sha512", NULL, 0, t5, ELEMENTSOF(t5));
|
||||
check_parse_pcr_argument("1:sha1=0F21EADB7F27377668E3C8069BE88D116491FBEE,6:sha512,5:sha384", t4, ELEMENTSOF(t4), t5, ELEMENTSOF(t5));
|
||||
|
||||
Tpm2PCRValue *v = NULL;
|
||||
size_t n_v = 0;
|
||||
assert_se(tpm2_parse_pcr_argument("1,100", &v, &n_v) < 0);
|
||||
assert_se(tpm2_parse_pcr_argument("1,2=123456abc", &v, &n_v) < 0);
|
||||
assert_se(tpm2_parse_pcr_argument("1,2:invalid", &v, &n_v) < 0);
|
||||
assert_se(tpm2_parse_pcr_argument("1:sha1=invalid", &v, &n_v) < 0);
|
||||
assert_se(v == NULL);
|
||||
assert_se(n_v == 0);
|
||||
|
||||
check_parse_pcr_argument_to_mask("", 0x0);
|
||||
check_parse_pcr_argument_to_mask("0", 0x1);
|
||||
check_parse_pcr_argument_to_mask("1", 0x2);
|
||||
check_parse_pcr_argument_to_mask("0,1", 0x3);
|
||||
check_parse_pcr_argument_to_mask("0+1", 0x3);
|
||||
check_parse_pcr_argument_to_mask("0-1", -EINVAL);
|
||||
check_parse_pcr_argument_to_mask("foo", -EINVAL);
|
||||
check_parse_pcr_argument_to_mask("0,1,2", 0x7);
|
||||
check_parse_pcr_argument_to_mask("0+1+2", 0x7);
|
||||
check_parse_pcr_argument_to_mask("0+1,2", 0x7);
|
||||
check_parse_pcr_argument_to_mask("0,1+2", 0x7);
|
||||
check_parse_pcr_argument_to_mask("0,2", 0x5);
|
||||
check_parse_pcr_argument_to_mask("0+2", 0x5);
|
||||
check_parse_pcr_argument_to_mask("7+application-support", 0x800080);
|
||||
check_parse_pcr_argument_to_mask("8+boot-loader-code", 0x110);
|
||||
check_parse_pcr_argument_to_mask("7,shim-policy,4", 0x4090);
|
||||
check_parse_pcr_argument_to_mask("sysexts,shim-policy+kernel-boot", 0x6800);
|
||||
check_parse_pcr_argument_to_mask("sysexts,shim+kernel-boot", -EINVAL);
|
||||
check_parse_pcr_argument_to_mask("sysexts+17+23", 0x822000);
|
||||
check_parse_pcr_argument_to_mask("6+boot-loader-code,44", -EINVAL);
|
||||
check_parse_pcr_argument_to_mask("debug+24", -EINVAL);
|
||||
}
|
||||
|
||||
static void tpm2b_public_rsa_init(TPM2B_PUBLIC *public, const char *rsa_n) {
|
||||
TPMT_PUBLIC tpmt = {
|
||||
.type = TPM2_ALG_RSA,
|
||||
.nameAlg = TPM2_ALG_SHA256,
|
||||
@@ -573,37 +718,155 @@ static void tpm2b_public_init(TPM2B_PUBLIC *public) {
|
||||
},
|
||||
};
|
||||
|
||||
const char *key = "9ec7341c52093ac40a1965a5df10432513c539adcf905e30577ab6ebc88ffe53cd08cef12ed9bec6125432f4fada3629b8b96d31b8f507aa35029188fe396da823fcb236027f7fbb01b0da3d87be7f999390449ced604bdf7e26c48657cc0671000f1147da195c3861c96642e54427cb7a11572e07567ec3fd6316978abc4bd92b27bb0a0e4958e599804eeb41d682b3b7fc1f960209f80a4fb8a1b64abfd96bf5d554e73cdd6ad1c8becb4fcf5e8f0c3e621d210e5e2f308f6520ad9a966779231b99f06c5989e5a23a9415c8808ab89ce81117632e2f8461cd4428bded40979236aeadafe8de3f51660a45e1dbc87694e6a36360201cca3ff9e7263e712727";
|
||||
_cleanup_free_ void *mem = NULL;
|
||||
size_t len = 0;
|
||||
assert_se(unhexmem(key, strlen(key), &mem, &len) == 0);
|
||||
assert_se(len <= sizeof(tpmt.unique.rsa.buffer));
|
||||
memcpy_safe(tpmt.unique.rsa.buffer, mem, len);
|
||||
tpmt.unique.rsa.size = len;
|
||||
DEFINE_HEX_PTR(key, rsa_n);
|
||||
tpmt.unique.rsa = TPM2B_PUBLIC_KEY_RSA_MAKE(key, key_len);
|
||||
|
||||
public->size = sizeof(tpmt);
|
||||
public->publicArea = tpmt;
|
||||
}
|
||||
|
||||
static void tpm2b_public_ecc_init(TPM2B_PUBLIC *public, TPMI_ECC_CURVE curve, const char *x, const char *y) {
|
||||
TPMT_PUBLIC tpmt = {
|
||||
.type = TPM2_ALG_ECC,
|
||||
.nameAlg = TPM2_ALG_SHA256,
|
||||
.objectAttributes = TPMA_OBJECT_RESTRICTED|TPMA_OBJECT_DECRYPT|TPMA_OBJECT_FIXEDTPM|TPMA_OBJECT_FIXEDPARENT|TPMA_OBJECT_SENSITIVEDATAORIGIN|TPMA_OBJECT_USERWITHAUTH,
|
||||
.parameters.eccDetail = {
|
||||
.symmetric = {
|
||||
.algorithm = TPM2_ALG_AES,
|
||||
.keyBits.aes = 128,
|
||||
.mode.aes = TPM2_ALG_CFB,
|
||||
},
|
||||
.scheme.scheme = TPM2_ALG_NULL,
|
||||
.curveID = curve,
|
||||
.kdf.scheme = TPM2_ALG_NULL,
|
||||
},
|
||||
};
|
||||
|
||||
DEFINE_HEX_PTR(buf_x, x);
|
||||
tpmt.unique.ecc.x = TPM2B_ECC_PARAMETER_MAKE(buf_x, buf_x_len);
|
||||
|
||||
DEFINE_HEX_PTR(buf_y, y);
|
||||
tpmt.unique.ecc.y = TPM2B_ECC_PARAMETER_MAKE(buf_y, buf_y_len);
|
||||
|
||||
public->size = sizeof(tpmt);
|
||||
public->publicArea = tpmt;
|
||||
}
|
||||
|
||||
#if HAVE_OPENSSL
|
||||
TEST(tpm2b_public_to_openssl_pkey) {
|
||||
DEFINE_HEX_PTR(msg, "edc64c6523778961fe9ba03ab7d624b27ca1dd5b01e7734cc6c891d50db04269");
|
||||
TPM2B_PUBLIC public;
|
||||
|
||||
/* RSA */
|
||||
tpm2b_public_rsa_init(&public, "d71cff5bba2173f0434a389171048e7da8cf8409b892c62946481cc383089bc754324620967fea3d00a02a717cdda4bfe1525ad957d294b88434e0a3933e86fb40f234e4935fd2ba27eb1d21da87efa466b74eb4ad18d26059904643441cf402ee933d138a2151f40459c49d87fef59e2cb822768b2d8689a9b58f82bf9a37e70693f2b2d40dfa388d365c1b1f029a14c4fc8dadb68978ef377d20ff2ca24e7078464c705eab42f531557c9c6dc0df66b506d0c26ef604f8110c64867099267453c71871e7ed22505a09daf102afc34355209ca7680eccc0ed368d148f402fa58cbb6c9d52351f535f09e4e24ad805e149f130edaa2f5e7efed3a4d2d03adb85");
|
||||
_cleanup_(EVP_PKEY_freep) EVP_PKEY *pkey_rsa = NULL;
|
||||
assert_se(tpm2_tpm2b_public_to_openssl_pkey(&public, &pkey_rsa) >= 0);
|
||||
|
||||
_cleanup_(EVP_PKEY_CTX_freep) EVP_PKEY_CTX *ctx_rsa = EVP_PKEY_CTX_new((EVP_PKEY*) pkey_rsa, NULL);
|
||||
assert_se(ctx_rsa);
|
||||
assert_se(EVP_PKEY_verify_init(ctx_rsa) == 1);
|
||||
assert_se(EVP_PKEY_CTX_set_signature_md(ctx_rsa, EVP_sha256()) > 0);
|
||||
|
||||
DEFINE_HEX_PTR(sig_rsa, "9f70a9e68911be3ec464cae91126328307bf355872127e042d6c61e0a80982872c151033bcf727abfae5fc9500c923120011e7ef4aa5fc690a59a034697b6022c141b4b209e2df6f4b282288cd9181073fbe7158ce113c79d87623423c1f3996ff931e59cc91db74f8e8656215b1436fc93ddec0f1f8fa8510826e674b250f047e6cba94c95ff98072a286baca94646b577974a1e00d56c21944e38960d8ee90511a2f938e5cf1ac7b7cc7ff8e3ac001d321254d3e4f988b90e9f6f873c26ecd0a12a626b3474833cdbb9e9f793238f6c97ee5b75a1a89bb7a7858d34ecfa6d34ac58d95085e6c4fbbebd47a4364be2725c2c6b3fa15d916f3c0b62a66fe76ae");
|
||||
assert_se(EVP_PKEY_verify(ctx_rsa, sig_rsa, sig_rsa_len, (unsigned char*) msg, msg_len) == 1);
|
||||
|
||||
/* ECC */
|
||||
tpm2b_public_ecc_init(&public, TPM2_ECC_NIST_P256, "6fc0ecf3645c673ab7e86d1ec5b315afb950257c5f68ab23296160006711fac2", "8dd2ef7a2c9ecede91493ba98c8fb3f893aff325c6a1e0f752c657b2d6ca1413");
|
||||
_cleanup_(EVP_PKEY_freep) EVP_PKEY *pkey_ecc = NULL;
|
||||
assert_se(tpm2_tpm2b_public_to_openssl_pkey(&public, &pkey_ecc) >= 0);
|
||||
|
||||
_cleanup_(EVP_PKEY_CTX_freep) EVP_PKEY_CTX *ctx_ecc = EVP_PKEY_CTX_new((EVP_PKEY*) pkey_ecc, NULL);
|
||||
assert_se(ctx_ecc);
|
||||
assert_se(EVP_PKEY_verify_init(ctx_ecc) == 1);
|
||||
|
||||
DEFINE_HEX_PTR(sig_ecc, "304602210092447ac0b5b32e90923f79bb4aba864b9c546a9900cf193a83243d35d189a2110221009a8b4df1dfa85e225eff9c606694d4d205a7a3968c9552f50bc2790209a90001");
|
||||
assert_se(EVP_PKEY_verify(ctx_ecc, sig_ecc, sig_ecc_len, (unsigned char*) msg, msg_len) == 1);
|
||||
}
|
||||
|
||||
static void get_tpm2b_public_from_pem(const void *pem, size_t pem_size, TPM2B_PUBLIC *ret) {
|
||||
_cleanup_(EVP_PKEY_freep) EVP_PKEY *pkey = NULL;
|
||||
TPM2B_PUBLIC p1 = {}, p2 = {};
|
||||
|
||||
assert(pem);
|
||||
assert(ret);
|
||||
|
||||
assert_se(openssl_pkey_from_pem(pem, pem_size, &pkey) >= 0);
|
||||
assert_se(tpm2_tpm2b_public_from_openssl_pkey(pkey, &p1) >= 0);
|
||||
assert_se(tpm2_tpm2b_public_from_pem(pem, pem_size, &p2) >= 0);
|
||||
assert_se(memcmp_nn(&p1, sizeof(p1), &p2, sizeof(p2)) == 0);
|
||||
|
||||
*ret = p1;
|
||||
}
|
||||
|
||||
static void check_tpm2b_public_fingerprint(const TPM2B_PUBLIC *public, const char *hexfp) {
|
||||
DEFINE_HEX_PTR(expected, hexfp);
|
||||
_cleanup_free_ void *fp = NULL;
|
||||
size_t fp_size;
|
||||
|
||||
assert_se(tpm2_tpm2b_public_to_fingerprint(public, &fp, &fp_size) >= 0);
|
||||
assert_se(memcmp_nn(fp, fp_size, expected, expected_len) == 0);
|
||||
}
|
||||
|
||||
TEST(tpm2b_public_from_openssl_pkey) {
|
||||
TPM2B_PUBLIC public;
|
||||
TPMT_PUBLIC *p = &public.publicArea;
|
||||
|
||||
DEFINE_HEX_PTR(key_ecc, "2d2d2d2d2d424547494e205055424c4943204b45592d2d2d2d2d0a4d466b77457759484b6f5a497a6a3043415159494b6f5a497a6a30444151634451674145726a6e4575424c73496c3972687068777976584e50686a346a426e500a44586e794a304b395579724e6764365335413532542b6f5376746b436a365a726c34685847337741515558706f426c532b7448717452714c35513d3d0a2d2d2d2d2d454e44205055424c4943204b45592d2d2d2d2d0a");
|
||||
get_tpm2b_public_from_pem(key_ecc, key_ecc_len, &public);
|
||||
|
||||
assert_se(p->type == TPM2_ALG_ECC);
|
||||
assert_se(p->parameters.eccDetail.curveID == TPM2_ECC_NIST_P256);
|
||||
|
||||
DEFINE_HEX_PTR(expected_x, "ae39c4b812ec225f6b869870caf5cd3e18f88c19cf0d79f22742bd532acd81de");
|
||||
assert_se(memcmp_nn(p->unique.ecc.x.buffer, p->unique.ecc.x.size, expected_x, expected_x_len) == 0);
|
||||
|
||||
DEFINE_HEX_PTR(expected_y, "92e40e764fea12bed9028fa66b9788571b7c004145e9a01952fad1eab51a8be5");
|
||||
assert_se(memcmp_nn(p->unique.ecc.y.buffer, p->unique.ecc.y.size, expected_y, expected_y_len) == 0);
|
||||
|
||||
check_tpm2b_public_fingerprint(&public, "cd3373293b62a52b48c12100e80ea9bfd806266ce76893a5ec31cb128052d97c");
|
||||
|
||||
DEFINE_HEX_PTR(key_rsa, "2d2d2d2d2d424547494e205055424c4943204b45592d2d2d2d2d0a4d494942496a414e42676b71686b6947397730424151454641414f43415138414d49494243674b4341514541795639434950652f505852337a436f63787045300a6a575262546c3568585844436b472f584b79374b6d2f4439584942334b734f5a31436a5937375571372f674359363170697838697552756a73413464503165380a593445336c68556d374a332b6473766b626f4b64553243626d52494c2f6675627771694c4d587a41673342575278747234547545443533527a373634554650640a307a70304b68775231496230444c67772f344e67566f314146763378784b4d6478774d45683567676b73733038326332706c354a504e32587677426f744e6b4d0a5471526c745a4a35355244436170696e7153334577376675646c4e735851357746766c7432377a7637344b585165616d704c59433037584f6761304c676c536b0a79754774586b6a50542f735542544a705374615769674d5a6f714b7479563463515a58436b4a52684459614c47587673504233687a766d5671636e6b47654e540a65774944415141420a2d2d2d2d2d454e44205055424c4943204b45592d2d2d2d2d0a");
|
||||
get_tpm2b_public_from_pem(key_rsa, key_rsa_len, &public);
|
||||
|
||||
DEFINE_HEX_PTR(expected_n, "c95f4220f7bf3d7477cc2a1cc691348d645b4e5e615d70c2906fd72b2eca9bf0fd5c80772ac399d428d8efb52aeff80263ad698b1f22b91ba3b00e1d3f57bc638137961526ec9dfe76cbe46e829d53609b99120bfdfb9bc2a88b317cc0837056471b6be13b840f9dd1cfbeb85053ddd33a742a1c11d486f40cb830ff8360568d4016fdf1c4a31dc7030487982092cb34f36736a65e493cdd97bf0068b4d90c4ea465b59279e510c26a98a7a92dc4c3b7ee76536c5d0e7016f96ddbbcefef829741e6a6a4b602d3b5ce81ad0b8254a4cae1ad5e48cf4ffb140532694ad6968a0319a2a2adc95e1c4195c29094610d868b197bec3c1de1cef995a9c9e419e3537b");
|
||||
assert_se(p->unique.rsa.size == expected_n_len);
|
||||
assert_se(memcmp(p->unique.rsa.buffer, expected_n, expected_n_len) == 0);
|
||||
|
||||
assert_se(p->parameters.rsaDetail.keyBits == expected_n_len * 8);
|
||||
|
||||
assert_se(p->parameters.rsaDetail.exponent == 0);
|
||||
|
||||
check_tpm2b_public_fingerprint(&public, "d9186d13a7fd5b3644cee05448f49ad3574e82a2942ff93cf89598d36cca78a9");
|
||||
}
|
||||
#endif
|
||||
|
||||
static void check_name(const TPM2B_NAME *name, const char *expect) {
|
||||
assert_se(name->size == SHA256_DIGEST_SIZE + 2);
|
||||
|
||||
DEFINE_HEX_PTR(e, expect);
|
||||
assert_se(name->size == e_len);
|
||||
assert_se(memcmp(name->name, e, e_len) == 0);
|
||||
}
|
||||
|
||||
TEST(calculate_name) {
|
||||
TPM2B_PUBLIC public;
|
||||
TPM2B_NAME name;
|
||||
|
||||
tpm2b_public_init(&public);
|
||||
assert_se(tpm2_calculate_name(&public.publicArea, &name) == 0);
|
||||
assert_se(name.size == SHA256_DIGEST_SIZE + 2);
|
||||
/* RSA */
|
||||
tpm2b_public_rsa_init(&public, "9ec7341c52093ac40a1965a5df10432513c539adcf905e30577ab6ebc88ffe53cd08cef12ed9bec6125432f4fada3629b8b96d31b8f507aa35029188fe396da823fcb236027f7fbb01b0da3d87be7f999390449ced604bdf7e26c48657cc0671000f1147da195c3861c96642e54427cb7a11572e07567ec3fd6316978abc4bd92b27bb0a0e4958e599804eeb41d682b3b7fc1f960209f80a4fb8a1b64abfd96bf5d554e73cdd6ad1c8becb4fcf5e8f0c3e621d210e5e2f308f6520ad9a966779231b99f06c5989e5a23a9415c8808ab89ce81117632e2f8461cd4428bded40979236aeadafe8de3f51660a45e1dbc87694e6a36360201cca3ff9e7263e712727");
|
||||
assert_se(tpm2_calculate_name(&public.publicArea, &name) >= 0);
|
||||
check_name(&name, "000be78f74a470dd92e979ca067cdb2293a35f075e8560b436bd2ccea5da21486a07");
|
||||
|
||||
const char *expect = "000be78f74a470dd92e979ca067cdb2293a35f075e8560b436bd2ccea5da21486a07";
|
||||
_cleanup_free_ char *h = hexmem(name.name, name.size);
|
||||
assert_se(h);
|
||||
|
||||
assert_se(strlen(expect) == strlen(h));
|
||||
assert_se(streq(expect, h));
|
||||
/* ECC */
|
||||
tpm2b_public_ecc_init(&public, TPM2_ECC_NIST_P256, "238e02ee4fd5598add6b502429f1815418515e4b0d6551c8e816b38cb15451d1", "70c2d491769775ec43ccd5a571c429233e9d30cf0f486c2e01acd6cb32ba93b6");
|
||||
assert_se(tpm2_calculate_name(&public.publicArea, &name) >= 0);
|
||||
check_name(&name, "000b302787187ba19c82011c987bd2dcdbb652b3a543ccc5cb0b49c33d4caae604a6");
|
||||
}
|
||||
|
||||
TEST(calculate_policy_auth_value) {
|
||||
TPM2B_DIGEST d;
|
||||
|
||||
digest_init_sha256(&d, "0000000000000000000000000000000000000000000000000000000000000000");
|
||||
digest_init(&d, "0000000000000000000000000000000000000000000000000000000000000000");
|
||||
assert_se(tpm2_calculate_policy_auth_value(&d) == 0);
|
||||
assert_se(digest_check(&d, "8fcd2169ab92694e0c633f1ab772842b8241bbc20288981fc7ac1eddc1fddb0e"));
|
||||
assert_se(tpm2_calculate_policy_auth_value(&d) == 0);
|
||||
@@ -614,59 +877,76 @@ TEST(calculate_policy_authorize) {
|
||||
TPM2B_PUBLIC public;
|
||||
TPM2B_DIGEST d;
|
||||
|
||||
tpm2b_public_init(&public);
|
||||
digest_init_sha256(&d, "0000000000000000000000000000000000000000000000000000000000000000");
|
||||
/* RSA */
|
||||
tpm2b_public_rsa_init(&public, "9ec7341c52093ac40a1965a5df10432513c539adcf905e30577ab6ebc88ffe53cd08cef12ed9bec6125432f4fada3629b8b96d31b8f507aa35029188fe396da823fcb236027f7fbb01b0da3d87be7f999390449ced604bdf7e26c48657cc0671000f1147da195c3861c96642e54427cb7a11572e07567ec3fd6316978abc4bd92b27bb0a0e4958e599804eeb41d682b3b7fc1f960209f80a4fb8a1b64abfd96bf5d554e73cdd6ad1c8becb4fcf5e8f0c3e621d210e5e2f308f6520ad9a966779231b99f06c5989e5a23a9415c8808ab89ce81117632e2f8461cd4428bded40979236aeadafe8de3f51660a45e1dbc87694e6a36360201cca3ff9e7263e712727");
|
||||
digest_init(&d, "0000000000000000000000000000000000000000000000000000000000000000");
|
||||
assert_se(tpm2_calculate_policy_authorize(&public, NULL, &d) == 0);
|
||||
assert_se(digest_check(&d, "95213a3784eaab04f427bc7e8851c2f1df0903be8e42428ec25dcefd907baff1"));
|
||||
assert_se(tpm2_calculate_policy_authorize(&public, NULL, &d) == 0);
|
||||
assert_se(digest_check(&d, "95213a3784eaab04f427bc7e8851c2f1df0903be8e42428ec25dcefd907baff1"));
|
||||
|
||||
/* ECC */
|
||||
tpm2b_public_ecc_init(&public, TPM2_ECC_NIST_P256, "423a89da6f0998f510489ab9682706e762031ef8f9faef2a185eff67065a187e", "996f73291670cef9e303d6cd9fa19ddf2c9c1fb1e283324ca9acca07c405c8d0");
|
||||
digest_init(&d, "0000000000000000000000000000000000000000000000000000000000000000");
|
||||
assert_se(tpm2_calculate_policy_authorize(&public, NULL, &d) == 0);
|
||||
assert_se(digest_check(&d, "2a5b705e83f949c27ac4d2e79e54fb5fb0a60f0b37bbd54a0ee1022ba00d3628"));
|
||||
assert_se(tpm2_calculate_policy_authorize(&public, NULL, &d) == 0);
|
||||
assert_se(digest_check(&d, "2a5b705e83f949c27ac4d2e79e54fb5fb0a60f0b37bbd54a0ee1022ba00d3628"));
|
||||
}
|
||||
|
||||
TEST(calculate_policy_pcr) {
|
||||
TPML_PCR_SELECTION pcr_selection;
|
||||
TPM2B_DIGEST pcr_values[16];
|
||||
TPM2B_DIGEST d;
|
||||
uint32_t pcr_mask;
|
||||
TPM2B_DIGEST d, dN[16];
|
||||
|
||||
digest_init_sha256(&d, "0000000000000000000000000000000000000000000000000000000000000000");
|
||||
pcr_mask = (1<<4) | (1<<7) | (1<<8);
|
||||
tpm2_tpml_pcr_selection_from_mask(pcr_mask, TPM2_ALG_SHA256, &pcr_selection);
|
||||
digest_init_sha256(&pcr_values[0], "368f85b3013041dfe203faaa364f00b07c5da7b1e5f1dbf2efb06fa6b9bd92de");
|
||||
digest_init_sha256(&pcr_values[1], "aa1154c9e0a774854ccbed4c8ce7e9b906b3d700a1a8db1772d0341a62dbe51b");
|
||||
digest_init_sha256(&pcr_values[2], "cfde439a2c06af3479ca6bdc60429b90553d65300c5cfcc40004a08c6b5ad81a");
|
||||
assert_se(tpm2_calculate_policy_pcr(&pcr_selection, pcr_values, 3, &d) == 0);
|
||||
digest_init(&dN[ 0], "2124793cbbe60c3a8637d3b84a5d054e87c351e1469a285acc04755e8b204dec");
|
||||
digest_init(&dN[ 1], "bf7592f18adcfdc549fc0b94939f5069a24697f9cff4a0dca29014767b97559d");
|
||||
digest_init(&dN[ 2], "4b00cff9dee3a364979b2dc241b34568a8ad49fcf2713df259e47dff8875feed");
|
||||
digest_init(&dN[ 3], "3d458cfe55cc03ea1f443f1562beec8df51c75e14a9fcf9a7234a13f198e7969");
|
||||
digest_init(&dN[ 4], "368f85b3013041dfe203faaa364f00b07c5da7b1e5f1dbf2efb06fa6b9bd92de");
|
||||
digest_init(&dN[ 5], "c97c40369691c8e4aa78fb3a52655cd193b780a838b8e23f5f476576919db5e5");
|
||||
digest_init(&dN[ 6], "3d458cfe55cc03ea1f443f1562beec8df51c75e14a9fcf9a7234a13f198e7969");
|
||||
digest_init(&dN[ 7], "aa1154c9e0a774854ccbed4c8ce7e9b906b3d700a1a8db1772d0341a62dbe51b");
|
||||
digest_init(&dN[ 8], "cfde439a2c06af3479ca6bdc60429b90553d65300c5cfcc40004a08c6b5ad81a");
|
||||
digest_init(&dN[ 9], "9c2bac22ef5ec84fcdb71c3ebf776cba1247e5da980e5ee08e45666a2edf0b8b");
|
||||
digest_init(&dN[10], "9885873f4d7348199ad286f8f2476d4f866940950f6f9fb9f945ed352dbdcbd2");
|
||||
digest_init(&dN[11], "42400ab950d21aa79d12cc4fdef67d1087a39ad64900619831c0974dbae54e44");
|
||||
digest_init(&dN[12], "767d064382e56ca1ad3bdcc6bc596112e6c2008b593d3570d24c2bfa64c4628c");
|
||||
digest_init(&dN[13], "30c16133175959408c9745d8dafadef5daf4b39cb2be04df0d60089bd46d3cc4");
|
||||
digest_init(&dN[14], "e3991b7ddd47be7e92726a832d6874c5349b52b789fa0db8b558c69fea29574e");
|
||||
digest_init(&dN[15], "852dae3ecb992bdeb13d6002fefeeffdd90feca8b378d56681ef2c885d0e5137");
|
||||
|
||||
digest_init(&d, "0000000000000000000000000000000000000000000000000000000000000000");
|
||||
Tpm2PCRValue v1[] = {
|
||||
TPM2_PCR_VALUE_MAKE(4, TPM2_ALG_SHA256, dN[4]),
|
||||
TPM2_PCR_VALUE_MAKE(7, TPM2_ALG_SHA256, dN[7]),
|
||||
TPM2_PCR_VALUE_MAKE(8, TPM2_ALG_SHA256, dN[8]),
|
||||
};
|
||||
assert_se(tpm2_calculate_policy_pcr(v1, ELEMENTSOF(v1), &d) == 0);
|
||||
assert_se(digest_check(&d, "76532a0e16f7e6bf6b02918c11f75d99d729fab0cc81d0df2c4284a2c4fe6e05"));
|
||||
|
||||
pcr_mask = (1<<4) | (1<<7) | (1<<8);
|
||||
tpm2_tpml_pcr_selection_from_mask(pcr_mask, TPM2_ALG_SHA256, &pcr_selection);
|
||||
digest_init_sha256(&pcr_values[0], "368f85b3013041dfe203faaa364f00b07c5da7b1e5f1dbf2efb06fa6b9bd92de");
|
||||
digest_init_sha256(&pcr_values[1], "aa1154c9e0a774854ccbed4c8ce7e9b906b3d700a1a8db1772d0341a62dbe51b");
|
||||
digest_init_sha256(&pcr_values[2], "cfde439a2c06af3479ca6bdc60429b90553d65300c5cfcc40004a08c6b5ad81a");
|
||||
assert_se(tpm2_calculate_policy_pcr(&pcr_selection, pcr_values, 3, &d) == 0);
|
||||
assert_se(tpm2_calculate_policy_pcr(v1, ELEMENTSOF(v1), &d) == 0);
|
||||
assert_se(digest_check(&d, "97e64bcabb64c1fa4b726528644926c8029f5b4458b0575c98c04fe225629a0b"));
|
||||
|
||||
digest_init_sha256(&d, "0000000000000000000000000000000000000000000000000000000000000000");
|
||||
pcr_mask = 0xffff;
|
||||
tpm2_tpml_pcr_selection_from_mask(pcr_mask, TPM2_ALG_SHA256, &pcr_selection);
|
||||
digest_init_sha256(&pcr_values[ 0], "2124793cbbe60c3a8637d3b84a5d054e87c351e1469a285acc04755e8b204dec");
|
||||
digest_init_sha256(&pcr_values[ 1], "bf7592f18adcfdc549fc0b94939f5069a24697f9cff4a0dca29014767b97559d");
|
||||
digest_init_sha256(&pcr_values[ 2], "4b00cff9dee3a364979b2dc241b34568a8ad49fcf2713df259e47dff8875feed");
|
||||
digest_init_sha256(&pcr_values[ 3], "3d458cfe55cc03ea1f443f1562beec8df51c75e14a9fcf9a7234a13f198e7969");
|
||||
digest_init_sha256(&pcr_values[ 4], "368f85b3013041dfe203faaa364f00b07c5da7b1e5f1dbf2efb06fa6b9bd92de");
|
||||
digest_init_sha256(&pcr_values[ 5], "c97c40369691c8e4aa78fb3a52655cd193b780a838b8e23f5f476576919db5e5");
|
||||
digest_init_sha256(&pcr_values[ 6], "3d458cfe55cc03ea1f443f1562beec8df51c75e14a9fcf9a7234a13f198e7969");
|
||||
digest_init_sha256(&pcr_values[ 7], "aa1154c9e0a774854ccbed4c8ce7e9b906b3d700a1a8db1772d0341a62dbe51b");
|
||||
digest_init_sha256(&pcr_values[ 8], "cfde439a2c06af3479ca6bdc60429b90553d65300c5cfcc40004a08c6b5ad81a");
|
||||
digest_init_sha256(&pcr_values[ 9], "9c2bac22ef5ec84fcdb71c3ebf776cba1247e5da980e5ee08e45666a2edf0b8b");
|
||||
digest_init_sha256(&pcr_values[10], "9885873f4d7348199ad286f8f2476d4f866940950f6f9fb9f945ed352dbdcbd2");
|
||||
digest_init_sha256(&pcr_values[11], "42400ab950d21aa79d12cc4fdef67d1087a39ad64900619831c0974dbae54e44");
|
||||
digest_init_sha256(&pcr_values[12], "767d064382e56ca1ad3bdcc6bc596112e6c2008b593d3570d24c2bfa64c4628c");
|
||||
digest_init_sha256(&pcr_values[13], "30c16133175959408c9745d8dafadef5daf4b39cb2be04df0d60089bd46d3cc4");
|
||||
digest_init_sha256(&pcr_values[14], "e3991b7ddd47be7e92726a832d6874c5349b52b789fa0db8b558c69fea29574e");
|
||||
digest_init_sha256(&pcr_values[15], "852dae3ecb992bdeb13d6002fefeeffdd90feca8b378d56681ef2c885d0e5137");
|
||||
assert_se(tpm2_calculate_policy_pcr(&pcr_selection, pcr_values, 16, &d) == 0);
|
||||
digest_init(&d, "0000000000000000000000000000000000000000000000000000000000000000");
|
||||
Tpm2PCRValue v2[] = {
|
||||
TPM2_PCR_VALUE_MAKE( 0, TPM2_ALG_SHA256, dN[ 0]),
|
||||
TPM2_PCR_VALUE_MAKE( 1, TPM2_ALG_SHA256, dN[ 1]),
|
||||
TPM2_PCR_VALUE_MAKE( 2, TPM2_ALG_SHA256, dN[ 2]),
|
||||
TPM2_PCR_VALUE_MAKE( 3, TPM2_ALG_SHA256, dN[ 3]),
|
||||
TPM2_PCR_VALUE_MAKE( 4, TPM2_ALG_SHA256, dN[ 4]),
|
||||
TPM2_PCR_VALUE_MAKE( 5, TPM2_ALG_SHA256, dN[ 5]),
|
||||
TPM2_PCR_VALUE_MAKE( 6, TPM2_ALG_SHA256, dN[ 6]),
|
||||
TPM2_PCR_VALUE_MAKE( 7, TPM2_ALG_SHA256, dN[ 7]),
|
||||
TPM2_PCR_VALUE_MAKE( 8, TPM2_ALG_SHA256, dN[ 8]),
|
||||
TPM2_PCR_VALUE_MAKE( 9, TPM2_ALG_SHA256, dN[ 9]),
|
||||
TPM2_PCR_VALUE_MAKE(10, TPM2_ALG_SHA256, dN[10]),
|
||||
TPM2_PCR_VALUE_MAKE(11, TPM2_ALG_SHA256, dN[11]),
|
||||
TPM2_PCR_VALUE_MAKE(12, TPM2_ALG_SHA256, dN[12]),
|
||||
TPM2_PCR_VALUE_MAKE(13, TPM2_ALG_SHA256, dN[13]),
|
||||
TPM2_PCR_VALUE_MAKE(14, TPM2_ALG_SHA256, dN[14]),
|
||||
TPM2_PCR_VALUE_MAKE(15, TPM2_ALG_SHA256, dN[15]),
|
||||
};
|
||||
assert_se(tpm2_calculate_policy_pcr(v2, ELEMENTSOF(v2), &d) == 0);
|
||||
assert_se(digest_check(&d, "22be4f1674f792d6345cea9427701068f0e8d9f42755dcc0e927e545a68f9c13"));
|
||||
assert_se(tpm2_calculate_policy_pcr(&pcr_selection, pcr_values, 16, &d) == 0);
|
||||
assert_se(tpm2_calculate_policy_pcr(v2, ELEMENTSOF(v2), &d) == 0);
|
||||
assert_se(digest_check(&d, "7481fd1b116078eb3ac2456e4ad542c9b46b9b8eb891335771ca8e7c8f8e4415"));
|
||||
}
|
||||
|
||||
|
||||
@@ -93,7 +93,43 @@ PASSWORD=passphrase systemd-cryptenroll --tpm2-device=auto --tpm2-pcrs=0+7 "$img
|
||||
|
||||
# Check with wrong PCR 0
|
||||
tpm2_pcrextend 0:sha256=0000000000000000000000000000000000000000000000000000000000000000
|
||||
"$SD_CRYPTSETUP" attach test-volume "$img" - tpm2-device=auto,headless=1 && exit 1
|
||||
(! "$SD_CRYPTSETUP" attach test-volume "$img" - tpm2-device=auto,headless=1)
|
||||
|
||||
if tpm_has_pcr sha256 12; then
|
||||
# Enroll using an explict PCR value (that does match current PCR value)
|
||||
systemd-cryptenroll --wipe-slot=tpm2 "$img"
|
||||
EXPECTED_PCR_VALUE=$(cat /sys/class/tpm/tpm0/pcr-sha256/12)
|
||||
PASSWORD=passphrase systemd-cryptenroll --tpm2-device=auto --tpm2-pcrs="12:sha256=$EXPECTED_PCR_VALUE" "$img"
|
||||
"$SD_CRYPTSETUP" attach test-volume "$img" - tpm2-device=auto,headless=1
|
||||
"$SD_CRYPTSETUP" detach test-volume
|
||||
|
||||
# Same as above plus more PCRs without the value or alg specified
|
||||
systemd-cryptenroll --wipe-slot=tpm2 "$img"
|
||||
EXPECTED_PCR_VALUE=$(cat /sys/class/tpm/tpm0/pcr-sha256/12)
|
||||
PASSWORD=passphrase systemd-cryptenroll --tpm2-device=auto --tpm2-pcrs="1,12:sha256=$EXPECTED_PCR_VALUE,3" "$img"
|
||||
"$SD_CRYPTSETUP" attach test-volume "$img" - tpm2-device=auto,headless=1
|
||||
"$SD_CRYPTSETUP" detach test-volume
|
||||
|
||||
# Same as above plus more PCRs with hash alg specified but hash value not specified
|
||||
systemd-cryptenroll --wipe-slot=tpm2 "$img"
|
||||
EXPECTED_PCR_VALUE=$(cat /sys/class/tpm/tpm0/pcr-sha256/12)
|
||||
PASSWORD=passphrase systemd-cryptenroll --tpm2-device=auto --tpm2-pcrs="1:sha256,12:sha256=$EXPECTED_PCR_VALUE,3" "$img"
|
||||
"$SD_CRYPTSETUP" attach test-volume "$img" - tpm2-device=auto,headless=1
|
||||
"$SD_CRYPTSETUP" detach test-volume
|
||||
|
||||
# Now the interesting part, enrolling using a hash value that doesn't match the current PCR value
|
||||
systemd-cryptenroll --wipe-slot=tpm2 "$img"
|
||||
tpm2_pcrread -Q -o /tmp/pcr.dat sha256:12
|
||||
CURRENT_PCR_VALUE=$(cat /sys/class/tpm/tpm0/pcr-sha256/12)
|
||||
EXPECTED_PCR_VALUE=$(cat /tmp/pcr.dat /tmp/pcr.dat | openssl dgst -sha256 -r | cut -d ' ' -f 1)
|
||||
PASSWORD=passphrase systemd-cryptenroll --tpm2-device=auto --tpm2-pcrs="12:sha256=$EXPECTED_PCR_VALUE" "$img"
|
||||
(! "$SD_CRYPTSETUP" attach test-volume "$img" - tpm2-device=auto,headless=1)
|
||||
tpm2_pcrextend "12:sha256=$CURRENT_PCR_VALUE"
|
||||
"$SD_CRYPTSETUP" attach test-volume "$img" - tpm2-device=auto,headless=1
|
||||
"$SD_CRYPTSETUP" detach test-volume
|
||||
|
||||
rm -f /tmp/pcr.dat
|
||||
fi
|
||||
|
||||
rm -f "${img:?}"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user