@@ -22,6 +22,12 @@ static struct tpm_digest known_digest = { .alg_id = TPM_ALG_SHA256,
0xf1, 0x22, 0x38, 0x6c, 0x33, 0xb1, 0x14, 0xb7, 0xec, 0x05,
0x5f, 0x49}};
+/* sha256(sha256(empty_pcr | known_digest)) */
+static const char expected_digest[] = {0x2f, 0x96, 0xf2, 0x1b, 0x70, 0xa9, 0xe8,
+ 0x42, 0x25, 0x8e, 0x66, 0x07, 0xbe, 0xbc, 0xe3, 0x1f, 0x2c, 0x84, 0x4a,
+ 0x3f, 0x85, 0x17, 0x31, 0x47, 0x9a, 0xa5, 0x53, 0xbb, 0x23, 0x0c, 0x32,
+ 0xf3};
+
/* Derive a key from the kernel and user keys for data encryption. */
static int snapshot_use_user_key(struct snapshot_data *data)
{
@@ -491,7 +497,7 @@ static int snapshot_setup_encryption_common(struct snapshot_data *data)
static int snapshot_create_kernel_key(struct snapshot_data *data)
{
/* Create a key sealed by the SRK. */
- char *keyinfo = "new\t32\tkeyhandle=0x81000000";
+ char *keyinfo = "new\t32\tkeyhandle=0x81000000\tcreationpcrs=0x00800000";
const struct cred *cred = current_cred();
struct tpm_digest *digests = NULL;
struct key *key = NULL;
@@ -612,17 +618,57 @@ int snapshot_get_encryption_key(struct snapshot_data *data,
return rc;
}
+/* Currently only PCR23 is included in the creation data. */
+#define SNAPSHOT_KEY_PCR_COUNT 1
+
+/* The standard set of 24 PCRs takes 3 bytes to represent as a bitmask. */
+#define SNAPSHOT_KEY_PCR_SELECTION_BYTES 3
+
+/*
+ * The TPM loves to return variable length structures. This is the form of
+ * TPM2B_CREATION_DATA expected and verified for the snapshot key.
+ */
+struct snapshot_key_creation_data {
+ __be16 size;
+ /* TPMS_CREATION_DATA, the hashed portion */
+ struct {
+ /* TPML_PCR_SELECTION */
+ struct {
+ __be32 count;
+ /* TPMS_PCR_SELECTION */
+ struct {
+ __be16 hash_algo;
+ u8 size;
+ u8 select[SNAPSHOT_KEY_PCR_SELECTION_BYTES];
+ } __packed pcr_selections;
+ } __packed pcr_select;
+
+ /* TPM2B_DIGEST */
+ struct {
+ __be16 size;
+ u8 digest[SHA256_DIGEST_SIZE];
+ } __packed pcr_digest[SNAPSHOT_KEY_PCR_COUNT];
+
+ /* ... additional fields not verified ... */
+ } creation;
+} __packed;
+
static int snapshot_load_kernel_key(struct snapshot_data *data,
struct uswsusp_key_blob *blob)
{
char *keytemplate = "load\t%s\tkeyhandle=0x81000000";
+ struct snapshot_key_creation_data *creation;
const struct cred *cred = current_cred();
+ struct trusted_key_payload *payload;
+ char certhash[SHA256_DIGEST_SIZE];
struct tpm_digest *digests = NULL;
+ unsigned int creation_hash_length;
char *blobstring = NULL;
struct key *key = NULL;
struct tpm_chip *chip;
char *keyinfo = NULL;
+ u32 pcr_selection = 0;
int i, ret;
chip = tpm_default_chip();
@@ -640,8 +686,10 @@ static int snapshot_load_kernel_key(struct snapshot_data *data,
digests = kcalloc(chip->nr_allocated_banks, sizeof(struct tpm_digest),
GFP_KERNEL);
- if (!digests)
+ if (!digests) {
+ ret = -ENOMEM;
goto out;
+ }
for (i = 0; i < chip->nr_allocated_banks; i++) {
digests[i].alg_id = chip->allocated_banks[i].alg_id;
@@ -681,6 +729,76 @@ static int snapshot_load_kernel_key(struct snapshot_data *data,
if (ret != 0)
goto out;
+ /* Verify the creation hash matches the creation data. */
+ payload = key->payload.data[0];
+ creation = (struct snapshot_key_creation_data *)payload->creation;
+ if (!creation || !payload->creation_hash ||
+ (payload->creation_len < sizeof(*creation)) ||
+ (payload->creation_hash_len - 2 != SHA256_DIGEST_SIZE)) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ creation_hash_length =
+ payload->creation_len -
+ offsetof(struct snapshot_key_creation_data, creation);
+
+ sha256((const u8 *)&creation->creation, creation_hash_length, certhash);
+ if (memcmp(payload->creation_hash + sizeof(__be16), certhash, SHA256_DIGEST_SIZE) != 0) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /* We now know that the creation data is authentic - parse it */
+
+ /* Verify TPML_PCR_SELECTION.count */
+ if (be32_to_cpu(creation->creation.pcr_select.count) !=
+ SNAPSHOT_KEY_PCR_COUNT) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /* Verify the PCRs are SHA256. */
+ if (be16_to_cpu(creation->creation.pcr_select.pcr_selections.hash_algo) !=
+ TPM_ALG_SHA256) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /* Gather the PCR selection bitmask. */
+ if (creation->creation.pcr_select.pcr_selections.size !=
+ SNAPSHOT_KEY_PCR_SELECTION_BYTES) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ for (i = SNAPSHOT_KEY_PCR_SELECTION_BYTES - 1; i >= 0; i--) {
+ pcr_selection <<= 8;
+ pcr_selection |=
+ creation->creation.pcr_select.pcr_selections.select[i];
+ }
+
+ /* Verify PCR 23 is selected. */
+ if (pcr_selection != (1 << 23)) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /* Verify the first and only PCR hash is the expected size. */
+ if (be16_to_cpu(creation->creation.pcr_digest[0].size) !=
+ SHA256_DIGEST_SIZE) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /* Verify PCR 23 contained the expected value when the key was created. */
+ if (memcmp(&creation->creation.pcr_digest[0].digest, expected_digest,
+ SHA256_DIGEST_SIZE) != 0) {
+
+ ret = -EINVAL;
+ goto out;
+ }
+
data->key = key;
key = NULL;