@@ -22,7 +22,7 @@ struct trusted_key_payload {
unsigned int key_len;
unsigned int blob_len;
unsigned char migratable;
- unsigned char key[MAX_KEY_SIZE + 1];
+ unsigned char *key;
unsigned char blob[MAX_BLOB_SIZE];
};
@@ -47,6 +47,21 @@ int tpm2_unseal_trusted(struct tpm_chip *chip,
struct trusted_key_payload *payload,
struct trusted_key_options *options);
+#if defined(CONFIG_TRUSTED_KEYS) || \
+ (defined(CONFIG_TRUSTED_KEYS_MODULE) && defined(CONFIG_ENCRYPTED_KEYS_MODULE))
+void trusted_key_enable_access(void);
+void trusted_key_disable_access(void);
+#else
+static inline void trusted_key_enable_access(void)
+{
+
+}
+static inline void trusted_key_disable_access(void)
+{
+
+}
+#endif
+
#define TPM_DEBUG 0
#if TPM_DEBUG
@@ -20,6 +20,7 @@
#include <linux/err.h>
#include <keys/user-type.h>
#include <keys/trusted-type.h>
+#include <keys/trusted_tpm.h>
#include <keys/encrypted-type.h>
#include <linux/key-type.h>
#include <linux/random.h>
@@ -344,10 +345,12 @@ static int calc_hmac(u8 *digest, const u8 *key, unsigned int keylen,
}
enum derived_key_type { ENC_KEY, AUTH_KEY };
+enum master_key_type { TRUSTED_KEY, USER_KEY };
/* Derive authentication/encryption key from trusted key */
static int get_derived_key(u8 *derived_key, enum derived_key_type key_type,
- const u8 *master_key, size_t master_keylen)
+ const u8 *master_key, size_t master_keylen,
+ enum master_key_type m_key_type)
{
u8 *derived_buf;
unsigned int derived_buf_len;
@@ -366,8 +369,13 @@ static int get_derived_key(u8 *derived_key, enum derived_key_type key_type,
else
strcpy(derived_buf, "ENC_KEY");
+ if (unlikely(m_key_type == TRUSTED_KEY))
+ trusted_key_enable_access();
memcpy(derived_buf + strlen(derived_buf) + 1, master_key,
master_keylen);
+ if (unlikely(m_key_type == TRUSTED_KEY))
+ trusted_key_disable_access();
+
ret = crypto_shash_tfm_digest(hash_tfm, derived_buf, derived_buf_len,
derived_key);
kfree_sensitive(derived_buf);
@@ -408,7 +416,8 @@ static struct skcipher_request *init_skcipher_req(const u8 *key,
}
static struct key *request_master_key(struct encrypted_key_payload *epayload,
- const u8 **master_key, size_t *master_keylen)
+ const u8 **master_key, size_t *master_keylen,
+ enum master_key_type *m_key_type)
{
struct key *mkey = ERR_PTR(-EINVAL);
@@ -417,11 +426,13 @@ static struct key *request_master_key(struct encrypted_key_payload *epayload,
mkey = request_trusted_key(epayload->master_desc +
KEY_TRUSTED_PREFIX_LEN,
master_key, master_keylen);
+ *m_key_type = TRUSTED_KEY;
} else if (!strncmp(epayload->master_desc, KEY_USER_PREFIX,
KEY_USER_PREFIX_LEN)) {
mkey = request_user_key(epayload->master_desc +
KEY_USER_PREFIX_LEN,
master_key, master_keylen);
+ *m_key_type = USER_KEY;
} else
goto out;
@@ -486,13 +497,14 @@ static int derived_key_encrypt(struct encrypted_key_payload *epayload,
}
static int datablob_hmac_append(struct encrypted_key_payload *epayload,
- const u8 *master_key, size_t master_keylen)
+ const u8 *master_key, size_t master_keylen,
+ enum master_key_type m_key_type)
{
u8 derived_key[HASH_SIZE];
u8 *digest;
int ret;
- ret = get_derived_key(derived_key, AUTH_KEY, master_key, master_keylen);
+ ret = get_derived_key(derived_key, AUTH_KEY, master_key, master_keylen, m_key_type);
if (ret < 0)
goto out;
@@ -509,7 +521,7 @@ static int datablob_hmac_append(struct encrypted_key_payload *epayload,
/* verify HMAC before decrypting encrypted key */
static int datablob_hmac_verify(struct encrypted_key_payload *epayload,
const u8 *format, const u8 *master_key,
- size_t master_keylen)
+ size_t master_keylen, enum master_key_type m_key_type)
{
u8 derived_key[HASH_SIZE];
u8 digest[HASH_SIZE];
@@ -517,7 +529,7 @@ static int datablob_hmac_verify(struct encrypted_key_payload *epayload,
char *p;
unsigned short len;
- ret = get_derived_key(derived_key, AUTH_KEY, master_key, master_keylen);
+ ret = get_derived_key(derived_key, AUTH_KEY, master_key, master_keylen, m_key_type);
if (ret < 0)
goto out;
@@ -664,6 +676,7 @@ static int encrypted_key_decrypt(struct encrypted_key_payload *epayload,
size_t master_keylen;
size_t asciilen;
int ret;
+ enum master_key_type m_key_type;
encrypted_datalen = roundup(epayload->decrypted_datalen, blksize);
asciilen = (ivsize + 1 + encrypted_datalen + HASH_SIZE) * 2;
@@ -685,17 +698,17 @@ static int encrypted_key_decrypt(struct encrypted_key_payload *epayload,
if (ret < 0)
return -EINVAL;
- mkey = request_master_key(epayload, &master_key, &master_keylen);
+ mkey = request_master_key(epayload, &master_key, &master_keylen, &m_key_type);
if (IS_ERR(mkey))
return PTR_ERR(mkey);
- ret = datablob_hmac_verify(epayload, format, master_key, master_keylen);
+ ret = datablob_hmac_verify(epayload, format, master_key, master_keylen, m_key_type);
if (ret < 0) {
pr_err("encrypted_key: bad hmac (%d)\n", ret);
goto out;
}
- ret = get_derived_key(derived_key, ENC_KEY, master_key, master_keylen);
+ ret = get_derived_key(derived_key, ENC_KEY, master_key, master_keylen, m_key_type);
if (ret < 0)
goto out;
@@ -908,6 +921,7 @@ static long encrypted_read(const struct key *key, char *buffer,
char *ascii_buf;
size_t asciiblob_len;
int ret;
+ enum master_key_type m_key_type;
epayload = dereference_key_locked(key);
@@ -919,11 +933,11 @@ static long encrypted_read(const struct key *key, char *buffer,
if (!buffer || buflen < asciiblob_len)
return asciiblob_len;
- mkey = request_master_key(epayload, &master_key, &master_keylen);
+ mkey = request_master_key(epayload, &master_key, &master_keylen, &m_key_type);
if (IS_ERR(mkey))
return PTR_ERR(mkey);
- ret = get_derived_key(derived_key, ENC_KEY, master_key, master_keylen);
+ ret = get_derived_key(derived_key, ENC_KEY, master_key, master_keylen, m_key_type);
if (ret < 0)
goto out;
@@ -931,7 +945,7 @@ static long encrypted_read(const struct key *key, char *buffer,
if (ret < 0)
goto out;
- ret = datablob_hmac_append(epayload, master_key, master_keylen);
+ ret = datablob_hmac_append(epayload, master_key, master_keylen, m_key_type);
if (ret < 0)
goto out;
@@ -26,9 +26,49 @@
#include <linux/capability.h>
#include <linux/tpm.h>
#include <linux/tpm_command.h>
+#include <linux/pkeys.h>
+#include <linux/vmalloc.h>
+#include <uapi/asm-generic/mman-common.h>
#include <keys/trusted_tpm.h>
+#define PKEY_INVALID (INT_MIN)
+static int trusted_keys_pkey = PKEY_INVALID;
+
+#if defined(CONFIG_TRUSTED_KEYS) || \
+ (defined(CONFIG_TRUSTED_KEYS_MODULE) && defined(CONFIG_ENCRYPTED_KEYS_MODULE))
+void trusted_key_disable_access(void)
+{
+ if (trusted_keys_pkey == PKEY_INVALID)
+ return;
+
+ pks_mknoaccess(trusted_keys_pkey, false);
+
+}
+EXPORT_SYMBOL_GPL(trusted_key_disable_access);
+
+void trusted_key_enable_access(void)
+{
+ if (trusted_keys_pkey == PKEY_INVALID)
+ return;
+
+ pks_mkrdwr(trusted_keys_pkey, false);
+}
+EXPORT_SYMBOL_GPL(trusted_key_enable_access);
+#endif
+
+static void trusted_payload_free(struct trusted_key_payload *p)
+{
+ if (!p)
+ return;
+
+ trusted_key_enable_access();
+ memzero_explicit(p->key, MAX_KEY_SIZE + 1);
+ trusted_key_disable_access();
+ vfree(p->key);
+ kzfree(p);
+}
+
static const char hmac_alg[] = "hmac(sha1)";
static const char hash_alg[] = "sha1";
static struct tpm_chip *chip;
@@ -663,12 +703,15 @@ static int key_seal(struct trusted_key_payload *p,
if (ret)
return ret;
+ trusted_key_enable_access();
/* include migratable flag at end of sealed key */
p->key[p->key_len] = p->migratable;
ret = tpm_seal(&tb, o->keytype, o->keyhandle, o->keyauth,
p->key, p->key_len + 1, p->blob, &p->blob_len,
o->blobauth, o->pcrinfo, o->pcrinfo_len);
+ trusted_key_disable_access();
+
if (ret < 0)
pr_info("trusted_key: srkseal failed (%d)\n", ret);
@@ -689,6 +732,7 @@ static int key_unseal(struct trusted_key_payload *p,
if (ret)
return ret;
+ trusted_key_enable_access();
ret = tpm_unseal(&tb, o->keyhandle, o->keyauth, p->blob, p->blob_len,
o->blobauth, p->key, &p->key_len);
if (ret < 0)
@@ -696,6 +740,7 @@ static int key_unseal(struct trusted_key_payload *p,
else
/* pull migratable flag out of sealed key */
p->migratable = p->key[--p->key_len];
+ trusted_key_disable_access();
tpm_buf_destroy(&tb);
return ret;
@@ -928,15 +973,26 @@ static struct trusted_key_options *trusted_options_alloc(void)
static struct trusted_key_payload *trusted_payload_alloc(struct key *key)
{
- struct trusted_key_payload *p = NULL;
+ struct trusted_key_payload *p;
int ret;
ret = key_payload_reserve(key, sizeof *p);
if (ret < 0)
- return p;
+ return NULL;
p = kzalloc(sizeof *p, GFP_KERNEL);
- if (p)
+ if (p) {
p->migratable = 1; /* migratable by default */
+ if (trusted_keys_pkey == PKEY_INVALID)
+ p->key = vmalloc(MAX_KEY_SIZE + 1);
+ else
+ p->key = vmalloc_pks(MAX_KEY_SIZE + 1, trusted_keys_pkey);
+
+ if (!(p->key)) {
+ kfree(p);
+ return NULL;
+ }
+ }
+
return p;
}
@@ -1012,7 +1068,9 @@ static int trusted_instantiate(struct key *key,
break;
case Opt_new:
key_len = payload->key_len;
+ trusted_key_enable_access();
ret = tpm_get_random(chip, payload->key, key_len);
+ trusted_key_disable_access();
if (ret != key_len) {
pr_info("trusted_key: key_create failed (%d)\n", ret);
goto out;
@@ -1036,7 +1094,7 @@ static int trusted_instantiate(struct key *key,
if (!ret)
rcu_assign_keypointer(key, payload);
else
- kfree_sensitive(payload);
+ trusted_payload_free(payload);
return ret;
}
@@ -1045,7 +1103,7 @@ static void trusted_rcu_free(struct rcu_head *rcu)
struct trusted_key_payload *p;
p = container_of(rcu, struct trusted_key_payload, rcu);
- kfree_sensitive(p);
+ trusted_payload_free(p);
}
/*
@@ -1087,34 +1145,38 @@ static int trusted_update(struct key *key, struct key_preparsed_payload *prep)
ret = datablob_parse(datablob, new_p, new_o);
if (ret != Opt_update) {
ret = -EINVAL;
- kfree_sensitive(new_p);
+ trusted_payload_free(new_p);
goto out;
}
if (!new_o->keyhandle) {
ret = -EINVAL;
- kfree_sensitive(new_p);
+ trusted_payload_free(new_p);
goto out;
}
/* copy old key values, and reseal with new pcrs */
new_p->migratable = p->migratable;
new_p->key_len = p->key_len;
+
+ trusted_key_enable_access();
memcpy(new_p->key, p->key, p->key_len);
+ trusted_key_disable_access();
+
dump_payload(p);
dump_payload(new_p);
ret = key_seal(new_p, new_o);
if (ret < 0) {
pr_info("trusted_key: key_seal failed (%d)\n", ret);
- kfree_sensitive(new_p);
+ trusted_payload_free(new_p);
goto out;
}
if (new_o->pcrlock) {
ret = pcrlock(new_o->pcrlock);
if (ret < 0) {
pr_info("trusted_key: pcrlock failed (%d)\n", ret);
- kfree_sensitive(new_p);
+ trusted_payload_free(new_p);
goto out;
}
}
@@ -1219,7 +1281,7 @@ static int __init init_digests(void)
static int __init init_trusted(void)
{
- int ret;
+ int ret, key_id;
/* encrypted_keys.ko depends on successful load of this module even if
* TPM is not used.
@@ -1237,6 +1299,14 @@ static int __init init_trusted(void)
ret = register_key_type(&key_type_trusted);
if (ret < 0)
goto err_release;
+
+ /* Attempt to reserve a PKS key for protecting the trusted keys.
+ * Note the pkey is never free'ed. This is run at init time and
+ * we either get the key or we do not.
+ */
+ key_id = pks_key_alloc("Keyring Trusted Keys");
+ if (key_id >= 0)
+ trusted_keys_pkey = key_id;
return 0;
err_release:
trusted_shash_release();
@@ -8,6 +8,8 @@
#include <linux/err.h>
#include <linux/tpm.h>
#include <linux/tpm_command.h>
+#include <linux/pkeys.h>
+#include <uapi/asm-generic/mman-common.h>
#include <keys/trusted-type.h>
#include <keys/trusted_tpm.h>
@@ -96,7 +98,11 @@ int tpm2_seal_trusted(struct tpm_chip *chip,
tpm_buf_append_u16(&buf, TPM_DIGEST_SIZE);
tpm_buf_append(&buf, options->blobauth, TPM_DIGEST_SIZE);
tpm_buf_append_u16(&buf, payload->key_len + 1);
+
+ trusted_key_enable_access();
tpm_buf_append(&buf, payload->key, payload->key_len);
+ trusted_key_disable_access();
+
tpm_buf_append_u8(&buf, payload->migratable);
/* public */
@@ -278,7 +284,10 @@ static int tpm2_unseal_cmd(struct tpm_chip *chip,
}
data = &buf.data[TPM_HEADER_SIZE + 6];
+ trusted_key_enable_access();
memcpy(payload->key, data, data_len - 1);
+ trusted_key_disable_access();
+
payload->key_len = data_len - 1;
payload->migratable = data[data_len - 1];
}