Path: blob/master/security/keys/trusted-keys/trusted_dcp.c
26424 views
// SPDX-License-Identifier: GPL-2.0-only1/*2* Copyright (C) 2021 sigma star gmbh3*/45#include <crypto/aead.h>6#include <crypto/aes.h>7#include <crypto/algapi.h>8#include <crypto/gcm.h>9#include <crypto/skcipher.h>10#include <keys/trusted-type.h>11#include <linux/key-type.h>12#include <linux/module.h>13#include <linux/printk.h>14#include <linux/random.h>15#include <linux/scatterlist.h>16#include <soc/fsl/dcp.h>1718#define DCP_BLOB_VERSION 119#define DCP_BLOB_AUTHLEN 162021/**22* DOC: dcp blob format23*24* The Data Co-Processor (DCP) provides hardware-bound AES keys using its25* AES encryption engine only. It does not provide direct key sealing/unsealing.26* To make DCP hardware encryption keys usable as trust source, we define27* our own custom format that uses a hardware-bound key to secure the sealing28* key stored in the key blob.29*30* Whenever a new trusted key using DCP is generated, we generate a random 128-bit31* blob encryption key (BEK) and 128-bit nonce. The BEK and nonce are used to32* encrypt the trusted key payload using AES-128-GCM.33*34* The BEK itself is encrypted using the hardware-bound key using the DCP's AES35* encryption engine with AES-128-ECB. The encrypted BEK, generated nonce,36* BEK-encrypted payload and authentication tag make up the blob format together37* with a version number, payload length and authentication tag.38*/3940/**41* struct dcp_blob_fmt - DCP BLOB format.42*43* @fmt_version: Format version, currently being %1.44* @blob_key: Random AES 128 key which is used to encrypt @payload,45* @blob_key itself is encrypted with OTP or UNIQUE device key in46* AES-128-ECB mode by DCP.47* @nonce: Random nonce used for @payload encryption.48* @payload_len: Length of the plain text @payload.49* @payload: The payload itself, encrypted using AES-128-GCM and @blob_key,50* GCM auth tag of size DCP_BLOB_AUTHLEN is attached at the end of it.51*52* The total size of a DCP BLOB is sizeof(struct dcp_blob_fmt) + @payload_len +53* DCP_BLOB_AUTHLEN.54*/55struct dcp_blob_fmt {56__u8 fmt_version;57__u8 blob_key[AES_KEYSIZE_128];58__u8 nonce[AES_KEYSIZE_128];59__le32 payload_len;60__u8 payload[];61} __packed;6263static bool use_otp_key;64module_param_named(dcp_use_otp_key, use_otp_key, bool, 0);65MODULE_PARM_DESC(dcp_use_otp_key, "Use OTP instead of UNIQUE key for sealing");6667static bool skip_zk_test;68module_param_named(dcp_skip_zk_test, skip_zk_test, bool, 0);69MODULE_PARM_DESC(dcp_skip_zk_test, "Don't test whether device keys are zero'ed");7071static unsigned int calc_blob_len(unsigned int payload_len)72{73return sizeof(struct dcp_blob_fmt) + payload_len + DCP_BLOB_AUTHLEN;74}7576static int do_dcp_crypto(u8 *in, u8 *out, bool do_encrypt)77{78struct skcipher_request *req = NULL;79struct scatterlist src_sg, dst_sg;80struct crypto_skcipher *tfm;81u8 paes_key[DCP_PAES_KEYSIZE];82DECLARE_CRYPTO_WAIT(wait);83int res = 0;8485if (use_otp_key)86paes_key[0] = DCP_PAES_KEY_OTP;87else88paes_key[0] = DCP_PAES_KEY_UNIQUE;8990tfm = crypto_alloc_skcipher("ecb-paes-dcp", CRYPTO_ALG_INTERNAL,91CRYPTO_ALG_INTERNAL);92if (IS_ERR(tfm)) {93res = PTR_ERR(tfm);94tfm = NULL;95goto out;96}9798req = skcipher_request_alloc(tfm, GFP_NOFS);99if (!req) {100res = -ENOMEM;101goto out;102}103104skcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG |105CRYPTO_TFM_REQ_MAY_SLEEP,106crypto_req_done, &wait);107res = crypto_skcipher_setkey(tfm, paes_key, sizeof(paes_key));108if (res < 0)109goto out;110111sg_init_one(&src_sg, in, AES_KEYSIZE_128);112sg_init_one(&dst_sg, out, AES_KEYSIZE_128);113skcipher_request_set_crypt(req, &src_sg, &dst_sg, AES_KEYSIZE_128,114NULL);115116if (do_encrypt)117res = crypto_wait_req(crypto_skcipher_encrypt(req), &wait);118else119res = crypto_wait_req(crypto_skcipher_decrypt(req), &wait);120121out:122skcipher_request_free(req);123crypto_free_skcipher(tfm);124125return res;126}127128static int do_aead_crypto(u8 *in, u8 *out, size_t len, u8 *key, u8 *nonce,129bool do_encrypt)130{131struct aead_request *aead_req = NULL;132struct scatterlist src_sg, dst_sg;133struct crypto_aead *aead;134int ret;135DECLARE_CRYPTO_WAIT(wait);136137aead = crypto_alloc_aead("gcm(aes)", 0, CRYPTO_ALG_ASYNC);138if (IS_ERR(aead)) {139ret = PTR_ERR(aead);140goto out;141}142143ret = crypto_aead_setauthsize(aead, DCP_BLOB_AUTHLEN);144if (ret < 0) {145pr_err("Can't set crypto auth tag len: %d\n", ret);146goto free_aead;147}148149aead_req = aead_request_alloc(aead, GFP_KERNEL);150if (!aead_req) {151ret = -ENOMEM;152goto free_aead;153}154155sg_init_one(&src_sg, in, len);156if (do_encrypt) {157/*158* If we encrypt our buffer has extra space for the auth tag.159*/160sg_init_one(&dst_sg, out, len + DCP_BLOB_AUTHLEN);161} else {162sg_init_one(&dst_sg, out, len);163}164165aead_request_set_crypt(aead_req, &src_sg, &dst_sg, len, nonce);166aead_request_set_callback(aead_req, CRYPTO_TFM_REQ_MAY_SLEEP,167crypto_req_done, &wait);168aead_request_set_ad(aead_req, 0);169170if (crypto_aead_setkey(aead, key, AES_KEYSIZE_128)) {171pr_err("Can't set crypto AEAD key\n");172ret = -EINVAL;173goto free_req;174}175176if (do_encrypt)177ret = crypto_wait_req(crypto_aead_encrypt(aead_req), &wait);178else179ret = crypto_wait_req(crypto_aead_decrypt(aead_req), &wait);180181free_req:182aead_request_free(aead_req);183free_aead:184crypto_free_aead(aead);185out:186return ret;187}188189static int decrypt_blob_key(u8 *encrypted_key, u8 *plain_key)190{191return do_dcp_crypto(encrypted_key, plain_key, false);192}193194static int encrypt_blob_key(u8 *plain_key, u8 *encrypted_key)195{196return do_dcp_crypto(plain_key, encrypted_key, true);197}198199static int trusted_dcp_seal(struct trusted_key_payload *p, char *datablob)200{201struct dcp_blob_fmt *b = (struct dcp_blob_fmt *)p->blob;202int blen, ret;203u8 *plain_blob_key;204205blen = calc_blob_len(p->key_len);206if (blen > MAX_BLOB_SIZE)207return -E2BIG;208209plain_blob_key = kmalloc(AES_KEYSIZE_128, GFP_KERNEL);210if (!plain_blob_key)211return -ENOMEM;212213b->fmt_version = DCP_BLOB_VERSION;214get_random_bytes(b->nonce, AES_KEYSIZE_128);215get_random_bytes(plain_blob_key, AES_KEYSIZE_128);216217ret = do_aead_crypto(p->key, b->payload, p->key_len, plain_blob_key,218b->nonce, true);219if (ret) {220pr_err("Unable to encrypt blob payload: %i\n", ret);221goto out;222}223224ret = encrypt_blob_key(plain_blob_key, b->blob_key);225if (ret) {226pr_err("Unable to encrypt blob key: %i\n", ret);227goto out;228}229230put_unaligned_le32(p->key_len, &b->payload_len);231p->blob_len = blen;232ret = 0;233234out:235memzero_explicit(plain_blob_key, AES_KEYSIZE_128);236kfree(plain_blob_key);237238return ret;239}240241static int trusted_dcp_unseal(struct trusted_key_payload *p, char *datablob)242{243struct dcp_blob_fmt *b = (struct dcp_blob_fmt *)p->blob;244int blen, ret;245u8 *plain_blob_key = NULL;246247if (b->fmt_version != DCP_BLOB_VERSION) {248pr_err("DCP blob has bad version: %i, expected %i\n",249b->fmt_version, DCP_BLOB_VERSION);250ret = -EINVAL;251goto out;252}253254p->key_len = le32_to_cpu(b->payload_len);255blen = calc_blob_len(p->key_len);256if (blen != p->blob_len) {257pr_err("DCP blob has bad length: %i != %i\n", blen,258p->blob_len);259ret = -EINVAL;260goto out;261}262263plain_blob_key = kmalloc(AES_KEYSIZE_128, GFP_KERNEL);264if (!plain_blob_key) {265ret = -ENOMEM;266goto out;267}268269ret = decrypt_blob_key(b->blob_key, plain_blob_key);270if (ret) {271pr_err("Unable to decrypt blob key: %i\n", ret);272goto out;273}274275ret = do_aead_crypto(b->payload, p->key, p->key_len + DCP_BLOB_AUTHLEN,276plain_blob_key, b->nonce, false);277if (ret) {278pr_err("Unwrap of DCP payload failed: %i\n", ret);279goto out;280}281282ret = 0;283out:284if (plain_blob_key) {285memzero_explicit(plain_blob_key, AES_KEYSIZE_128);286kfree(plain_blob_key);287}288289return ret;290}291292static int test_for_zero_key(void)293{294/*295* Encrypting a plaintext of all 0x55 bytes will yield296* this ciphertext in case the DCP test key is used.297*/298static const u8 bad[] = {0x9a, 0xda, 0xe0, 0x54, 0xf6, 0x3d, 0xfa, 0xff,2990x5e, 0xa1, 0x8e, 0x45, 0xed, 0xf6, 0xea, 0x6f};300void *buf = NULL;301int ret = 0;302303if (skip_zk_test)304goto out;305306buf = kmalloc(AES_BLOCK_SIZE, GFP_KERNEL);307if (!buf) {308ret = -ENOMEM;309goto out;310}311312memset(buf, 0x55, AES_BLOCK_SIZE);313314ret = do_dcp_crypto(buf, buf, true);315if (ret)316goto out;317318if (memcmp(buf, bad, AES_BLOCK_SIZE) == 0) {319pr_warn("Device neither in secure nor trusted mode!\n");320ret = -EINVAL;321}322out:323kfree(buf);324return ret;325}326327static int trusted_dcp_init(void)328{329int ret;330331if (use_otp_key)332pr_info("Using DCP OTP key\n");333334ret = test_for_zero_key();335if (ret) {336pr_warn("Test for zero'ed keys failed: %i\n", ret);337338return -EINVAL;339}340341return register_key_type(&key_type_trusted);342}343344static void trusted_dcp_exit(void)345{346unregister_key_type(&key_type_trusted);347}348349struct trusted_key_ops dcp_trusted_key_ops = {350.exit = trusted_dcp_exit,351.init = trusted_dcp_init,352.seal = trusted_dcp_seal,353.unseal = trusted_dcp_unseal,354.migratable = 0,355};356357358