mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-11 04:18:39 +08:00
KEYS: trusted: dcp: fix leak of blob encryption key
Trusted keys unseal the key blob on load, but keep the sealed payload in
the blob field so that every subsequent read (export) will simply
convert this field to hex and send it to userspace.
With DCP-based trusted keys, we decrypt the blob encryption key (BEK)
in the Kernel due hardware limitations and then decrypt the blob payload.
BEK decryption is done in-place which means that the trusted key blob
field is modified and it consequently holds the BEK in plain text.
Every subsequent read of that key thus send the plain text BEK instead
of the encrypted BEK to userspace.
This issue only occurs when importing a trusted DCP-based key and
then exporting it again. This should rarely happen as the common use cases
are to either create a new trusted key and export it, or import a key
blob and then just use it without exporting it again.
Fix this by performing BEK decryption and encryption in a dedicated
buffer. Further always wipe the plain text BEK buffer to prevent leaking
the key via uninitialized memory.
Cc: stable@vger.kernel.org # v6.10+
Fixes: 2e8a0f40a3
("KEYS: trusted: Introduce NXP DCP-backed trusted keys")
Signed-off-by: David Gstir <david@sigma-star.at>
Reviewed-by: Jarkko Sakkinen <jarkko@kernel.org>
Signed-off-by: Jarkko Sakkinen <jarkko@kernel.org>
This commit is contained in:
parent
6486cad00a
commit
0e28bf61a5
@ -186,20 +186,21 @@ out:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int decrypt_blob_key(u8 *key)
|
static int decrypt_blob_key(u8 *encrypted_key, u8 *plain_key)
|
||||||
{
|
{
|
||||||
return do_dcp_crypto(key, key, false);
|
return do_dcp_crypto(encrypted_key, plain_key, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int encrypt_blob_key(u8 *key)
|
static int encrypt_blob_key(u8 *plain_key, u8 *encrypted_key)
|
||||||
{
|
{
|
||||||
return do_dcp_crypto(key, key, true);
|
return do_dcp_crypto(plain_key, encrypted_key, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int trusted_dcp_seal(struct trusted_key_payload *p, char *datablob)
|
static int trusted_dcp_seal(struct trusted_key_payload *p, char *datablob)
|
||||||
{
|
{
|
||||||
struct dcp_blob_fmt *b = (struct dcp_blob_fmt *)p->blob;
|
struct dcp_blob_fmt *b = (struct dcp_blob_fmt *)p->blob;
|
||||||
int blen, ret;
|
int blen, ret;
|
||||||
|
u8 plain_blob_key[AES_KEYSIZE_128];
|
||||||
|
|
||||||
blen = calc_blob_len(p->key_len);
|
blen = calc_blob_len(p->key_len);
|
||||||
if (blen > MAX_BLOB_SIZE)
|
if (blen > MAX_BLOB_SIZE)
|
||||||
@ -207,30 +208,36 @@ static int trusted_dcp_seal(struct trusted_key_payload *p, char *datablob)
|
|||||||
|
|
||||||
b->fmt_version = DCP_BLOB_VERSION;
|
b->fmt_version = DCP_BLOB_VERSION;
|
||||||
get_random_bytes(b->nonce, AES_KEYSIZE_128);
|
get_random_bytes(b->nonce, AES_KEYSIZE_128);
|
||||||
get_random_bytes(b->blob_key, AES_KEYSIZE_128);
|
get_random_bytes(plain_blob_key, AES_KEYSIZE_128);
|
||||||
|
|
||||||
ret = do_aead_crypto(p->key, b->payload, p->key_len, b->blob_key,
|
ret = do_aead_crypto(p->key, b->payload, p->key_len, plain_blob_key,
|
||||||
b->nonce, true);
|
b->nonce, true);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
pr_err("Unable to encrypt blob payload: %i\n", ret);
|
pr_err("Unable to encrypt blob payload: %i\n", ret);
|
||||||
return ret;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = encrypt_blob_key(b->blob_key);
|
ret = encrypt_blob_key(plain_blob_key, b->blob_key);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
pr_err("Unable to encrypt blob key: %i\n", ret);
|
pr_err("Unable to encrypt blob key: %i\n", ret);
|
||||||
return ret;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
put_unaligned_le32(p->key_len, &b->payload_len);
|
put_unaligned_le32(p->key_len, &b->payload_len);
|
||||||
p->blob_len = blen;
|
p->blob_len = blen;
|
||||||
return 0;
|
ret = 0;
|
||||||
|
|
||||||
|
out:
|
||||||
|
memzero_explicit(plain_blob_key, sizeof(plain_blob_key));
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int trusted_dcp_unseal(struct trusted_key_payload *p, char *datablob)
|
static int trusted_dcp_unseal(struct trusted_key_payload *p, char *datablob)
|
||||||
{
|
{
|
||||||
struct dcp_blob_fmt *b = (struct dcp_blob_fmt *)p->blob;
|
struct dcp_blob_fmt *b = (struct dcp_blob_fmt *)p->blob;
|
||||||
int blen, ret;
|
int blen, ret;
|
||||||
|
u8 plain_blob_key[AES_KEYSIZE_128];
|
||||||
|
|
||||||
if (b->fmt_version != DCP_BLOB_VERSION) {
|
if (b->fmt_version != DCP_BLOB_VERSION) {
|
||||||
pr_err("DCP blob has bad version: %i, expected %i\n",
|
pr_err("DCP blob has bad version: %i, expected %i\n",
|
||||||
@ -248,14 +255,14 @@ static int trusted_dcp_unseal(struct trusted_key_payload *p, char *datablob)
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = decrypt_blob_key(b->blob_key);
|
ret = decrypt_blob_key(b->blob_key, plain_blob_key);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
pr_err("Unable to decrypt blob key: %i\n", ret);
|
pr_err("Unable to decrypt blob key: %i\n", ret);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = do_aead_crypto(b->payload, p->key, p->key_len + DCP_BLOB_AUTHLEN,
|
ret = do_aead_crypto(b->payload, p->key, p->key_len + DCP_BLOB_AUTHLEN,
|
||||||
b->blob_key, b->nonce, false);
|
plain_blob_key, b->nonce, false);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
pr_err("Unwrap of DCP payload failed: %i\n", ret);
|
pr_err("Unwrap of DCP payload failed: %i\n", ret);
|
||||||
goto out;
|
goto out;
|
||||||
@ -263,6 +270,8 @@ static int trusted_dcp_unseal(struct trusted_key_payload *p, char *datablob)
|
|||||||
|
|
||||||
ret = 0;
|
ret = 0;
|
||||||
out:
|
out:
|
||||||
|
memzero_explicit(plain_blob_key, sizeof(plain_blob_key));
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user