Received: by 2002:ab2:23c8:0:b0:1f2:fdbc:cb93 with SMTP id a8csp151938lqe; Wed, 27 Mar 2024 01:27:19 -0700 (PDT) X-Forwarded-Encrypted: i=3; AJvYcCVI3p9eJ2N5Pehjv1r3XVv2SMC0oANeSo0tgZ3Ka2UZx1OHxVJbjPn11i3NetSY1eg82LbfU8/avVorL5nZjOBtOrnNZuk91wnWBA4aLg== X-Google-Smtp-Source: AGHT+IHm6+YayNAy0AVIj35wBrgwjupqSfu7tWqWo4rs0wZxwpzyUo4HSS77WuaSGQPyDiJidv40 X-Received: by 2002:a05:620a:3882:b0:78a:3ad0:9920 with SMTP id qp2-20020a05620a388200b0078a3ad09920mr2083263qkn.34.1711528039253; Wed, 27 Mar 2024 01:27:19 -0700 (PDT) ARC-Seal: i=2; a=rsa-sha256; t=1711528039; cv=pass; d=google.com; s=arc-20160816; b=Dfl/nLBWNLQZX+tTwPDoSbjKHt7Cb7yFSiZQPVzYOex8b8JVVG/XnKwJtxBAOLkQYV 3gu6TU66pW4ljVXjYbZwTxjjwV9Wnv3Dv4NGk/AotJegP6lH8UckxQHK66eCiMPRWBQ7 EG9QVopFvPBjc0kZK3ZmWcHLGxEGUXGDUhlXRTONUnOSGEN8xZoyrdIGpcwGDn1v06OR 1LENxPY7CgBxfY5EpCwYO768ebVbBz0crxcCvFUVeNdPqvZor/0C1HL8M94AbWwJYfYm BDM9wbJogmSdOFXHMVyQrf87lGItS+hZC6nDCzrWqScsVSX/pSYboR89dDa1offgnlAR eobQ== ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=content-transfer-encoding:mime-version:list-unsubscribe :list-subscribe:list-id:precedence:references:in-reply-to:message-id :date:subject:cc:to:from:dkim-signature; bh=Jk3bunkUZB3eJdbTI0pWomxdZHb/buVMZM8Xz7Iwzes=; fh=X4Qzk8qX4/yR9bvF/fdKtqplUsEm+9Wc7C8J5LmpSSQ=; b=gzybeMVEClEtwyRlRrT1UX6Z3O5vbZ3dX7Qb8KiyLkWHhwbHg34fjsJgjr3Ve78Irf ohiRhQpIkcFooOLEu8yRO4a92nPkertMDxgJX6Z0wXFspLHOXYO09a7in45FrjBYyB1z /+8TQwFZeURQjVvzuH7EhXTUl84jPqtTc960KHhN3DH3RxqhpNAxR114sh4XuRMvR15w Y77For2HtW23JqilncD5VKGjp2SxXf3KxIFovY5oo1xptqtPnPXg5bmh6nRGDqfG+L4v ik0hiJmQW5MfN0J4Jl6BD+xp5MSDXVsNZnpCCKAOZMJUAoKWDtDLDp4ZxGQcF+Wq24Ti NZzA==; dara=google.com ARC-Authentication-Results: i=2; mx.google.com; dkim=pass header.i=@sigma-star.at header.s=google header.b=A5BARKQg; arc=pass (i=1 spf=pass spfdomain=sigma-star.at dkim=pass dkdomain=sigma-star.at dmarc=pass fromdomain=sigma-star.at); spf=pass (google.com: domain of linux-crypto+bounces-2932-linux.lists.archive=gmail.com@vger.kernel.org designates 147.75.199.223 as permitted sender) smtp.mailfrom="linux-crypto+bounces-2932-linux.lists.archive=gmail.com@vger.kernel.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=sigma-star.at Return-Path: Received: from ny.mirrors.kernel.org (ny.mirrors.kernel.org. [147.75.199.223]) by mx.google.com with ESMTPS id b14-20020a05620a04ee00b00789e907f565si9431251qkh.291.2024.03.27.01.27.19 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 27 Mar 2024 01:27:19 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-crypto+bounces-2932-linux.lists.archive=gmail.com@vger.kernel.org designates 147.75.199.223 as permitted sender) client-ip=147.75.199.223; Authentication-Results: mx.google.com; dkim=pass header.i=@sigma-star.at header.s=google header.b=A5BARKQg; arc=pass (i=1 spf=pass spfdomain=sigma-star.at dkim=pass dkdomain=sigma-star.at dmarc=pass fromdomain=sigma-star.at); spf=pass (google.com: domain of linux-crypto+bounces-2932-linux.lists.archive=gmail.com@vger.kernel.org designates 147.75.199.223 as permitted sender) smtp.mailfrom="linux-crypto+bounces-2932-linux.lists.archive=gmail.com@vger.kernel.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=sigma-star.at Received: from smtp.subspace.kernel.org (wormhole.subspace.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ny.mirrors.kernel.org (Postfix) with ESMTPS id B855A1C271B5 for ; Wed, 27 Mar 2024 08:26:56 +0000 (UTC) Received: from localhost.localdomain (localhost.localdomain [127.0.0.1]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 1D28746B8E; Wed, 27 Mar 2024 08:25:24 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=sigma-star.at header.i=@sigma-star.at header.b="A5BARKQg" X-Original-To: linux-crypto@vger.kernel.org Received: from mail-lj1-f175.google.com (mail-lj1-f175.google.com [209.85.208.175]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id E55343A1D7 for ; Wed, 27 Mar 2024 08:25:20 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.208.175 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1711527923; cv=none; b=uB0brUrEgcIzPdip3a2ypxrfYDzafyxUO6IVlP0L0PRjJxiA767/A1J3qcCtNSi/1Jw/HG3Ik9sd6LVSPX6KxejKFFsdN8aDyBz0MiShAM0QXbUw4Sk94tg6JOmT6FbsjO7Ejb6kABnMmwBoGRmV4IBxmEQrijrqvwLPZ3gMdpE= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1711527923; c=relaxed/simple; bh=Xr7SHlqReVMUGU8MnJMNHJB/GT7lVWiG8UM22EKgLlw=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=NV+5gXBWEHp+vb/8aeIhKTNmHnl5haofEWmI4Xu0M1n1cQBoI3aTdobW72/bd/HCL2hwdOlCXYZD1Q8Z6c2+F9gebFJdXchElH2WjVX+/HrsHQBIRDfZgrmHg7atdafpM9BBEaUx76E8Ped5N+X/afzpI3xc3SWGtLwQEku6DkY= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=sigma-star.at; spf=pass smtp.mailfrom=sigma-star.at; dkim=pass (2048-bit key) header.d=sigma-star.at header.i=@sigma-star.at header.b=A5BARKQg; arc=none smtp.client-ip=209.85.208.175 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=sigma-star.at Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=sigma-star.at Received: by mail-lj1-f175.google.com with SMTP id 38308e7fff4ca-2d6fd3cfaa6so2152081fa.2 for ; Wed, 27 Mar 2024 01:25:20 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sigma-star.at; s=google; t=1711527919; x=1712132719; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=Jk3bunkUZB3eJdbTI0pWomxdZHb/buVMZM8Xz7Iwzes=; b=A5BARKQgTei/91/sZMnVVEqUYH4kxpFwqoMhs/rjCAqaq8zaxpZAXGq7jIO2N0lL7X ISVn2v5+/OVJ5TjGnaBkpRwvJSAhdGXrPQwGq0tVTCHt0a4xYL4WxWo7+ZKuhkUz1kd3 0rLVVbDHdgSQJ83kl1+RSt/3RyNRs2xKvrXKOjpyvGjY8jAhXa4fOzgJK+9uZkfEzC/7 MpuUmeaCBJ9ObZxLo5zGLSvsiFMSUcrGTQXWCagEtDhGWbaGfNqKHvLPujFVpuaG1fyP bT6wrzop1bWzVCNr3qkEQC8UoQryPPalUMwWNTWk06MWQdBUMo/swruUXmC8oaIzwQHh T9fg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1711527919; x=1712132719; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=Jk3bunkUZB3eJdbTI0pWomxdZHb/buVMZM8Xz7Iwzes=; b=eqdHEnEGaTTFOGjea5Spj526rR3XZkcNv6jEtIGAxaK7zNX9xx62kpKrfeN00M1tgP a+MerDPduKEf5w+JJVruqS6lPS85OvZBgXsMYeMtkZhp2p+vOr24UMhSldZ0xRhuMOF9 uWeTXSqln6DGOfsYs7I4U/BjTeCSJyT3FXXJuyQr5ue+UQizZn/sM2pqH6le3e1cFtfN Cu/JlYoBZy/C/Ov9MliJHFyjssEDNprWWPdS0zo5uoSt0+gN9vXlSne7Fek+fDMnHCvT 7uZ9vNcUSlXxkWW3BxEwh22PaXFRhTIeIwD7PBehNGNvtdjz2ClUnhUX1cjf5Fqr/NxJ CXnQ== X-Forwarded-Encrypted: i=1; AJvYcCV2TIl0gupVDRpEQHNvPdyju5b1FA5TsfphSUK3aW+mtwI71Spqwu2UuT4uRMptaZL7ywXlio/vmgC+EMLyoqfyA9JUwkkGT666zWwt X-Gm-Message-State: AOJu0YzwB6MxJ+DpejlZylet/VItcqcNMo7A2YHxtNAzl1lNJP6J9Bwn Z9itH7LYpiC4svAam2QyTWDQBUSa2YINP2G7Q++npLknjcuHT3mXCKmRnGltdMs= X-Received: by 2002:a05:651c:a04:b0:2d6:a7a1:17ad with SMTP id k4-20020a05651c0a0400b002d6a7a117admr2472680ljq.51.1711527919170; Wed, 27 Mar 2024 01:25:19 -0700 (PDT) Received: from localhost ([82.150.214.1]) by smtp.gmail.com with UTF8SMTPSA id c9-20020a7bc2a9000000b0041493615585sm1376019wmk.39.2024.03.27.01.25.17 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Wed, 27 Mar 2024 01:25:18 -0700 (PDT) From: David Gstir To: Mimi Zohar , James Bottomley , Jarkko Sakkinen , Herbert Xu , "David S. Miller" Cc: David Gstir , Shawn Guo , Jonathan Corbet , Sascha Hauer , Pengutronix Kernel Team , Fabio Estevam , NXP Linux Team , Ahmad Fatoum , sigma star Kernel Team , David Howells , Li Yang , Paul Moore , James Morris , "Serge E. Hallyn" , "Paul E. McKenney" , Randy Dunlap , Catalin Marinas , "Rafael J. Wysocki" , Tejun Heo , "Steven Rostedt (Google)" , linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, linux-integrity@vger.kernel.org, keyrings@vger.kernel.org, linux-crypto@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linuxppc-dev@lists.ozlabs.org, linux-security-module@vger.kernel.org, Richard Weinberger , David Oberhollenzer Subject: [PATCH v7 3/6] KEYS: trusted: Introduce NXP DCP-backed trusted keys Date: Wed, 27 Mar 2024 09:24:49 +0100 Message-ID: <20240327082454.13729-4-david@sigma-star.at> X-Mailer: git-send-email 2.44.0 In-Reply-To: <20240327082454.13729-1-david@sigma-star.at> References: <20240327082454.13729-1-david@sigma-star.at> Precedence: bulk X-Mailing-List: linux-crypto@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit DCP (Data Co-Processor) is the little brother of NXP's CAAM IP. Beside of accelerated crypto operations, it also offers support for hardware-bound keys. Using this feature it is possible to implement a blob mechanism similar to what CAAM offers. Unlike on CAAM, constructing and parsing the blob has to happen in software (i.e. the kernel). The software-based blob format used by DCP trusted keys encrypts the payload using AES-128-GCM with a freshly generated random key and nonce. The random key itself is AES-128-ECB encrypted using the DCP unique or OTP key. The DCP trusted key blob format is: /* * struct dcp_blob_fmt - DCP BLOB format. * * @fmt_version: Format version, currently being %1 * @blob_key: Random AES 128 key which is used to encrypt @payload, * @blob_key itself is encrypted with OTP or UNIQUE device key in * AES-128-ECB mode by DCP. * @nonce: Random nonce used for @payload encryption. * @payload_len: Length of the plain text @payload. * @payload: The payload itself, encrypted using AES-128-GCM and @blob_key, * GCM auth tag of size AES_BLOCK_SIZE is attached at the end of it. * * The total size of a DCP BLOB is sizeof(struct dcp_blob_fmt) + @payload_len + * AES_BLOCK_SIZE. */ struct dcp_blob_fmt { __u8 fmt_version; __u8 blob_key[AES_KEYSIZE_128]; __u8 nonce[AES_KEYSIZE_128]; __le32 payload_len; __u8 payload[]; } __packed; By default the unique key is used. It is also possible to use the OTP key. While the unique key should be unique it is not documented how this key is derived. Therefore selection the OTP key is supported as well via the use_otp_key module parameter. Co-developed-by: Richard Weinberger Signed-off-by: Richard Weinberger Co-developed-by: David Oberhollenzer Signed-off-by: David Oberhollenzer Signed-off-by: David Gstir Reviewed-by: Jarkko Sakkinen --- include/keys/trusted_dcp.h | 11 + security/keys/trusted-keys/Kconfig | 8 + security/keys/trusted-keys/Makefile | 2 + security/keys/trusted-keys/trusted_core.c | 6 +- security/keys/trusted-keys/trusted_dcp.c | 313 ++++++++++++++++++++++ 5 files changed, 339 insertions(+), 1 deletion(-) create mode 100644 include/keys/trusted_dcp.h create mode 100644 security/keys/trusted-keys/trusted_dcp.c diff --git a/include/keys/trusted_dcp.h b/include/keys/trusted_dcp.h new file mode 100644 index 000000000000..9aaa42075b40 --- /dev/null +++ b/include/keys/trusted_dcp.h @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2021 sigma star gmbh + */ + +#ifndef TRUSTED_DCP_H +#define TRUSTED_DCP_H + +extern struct trusted_key_ops dcp_trusted_key_ops; + +#endif diff --git a/security/keys/trusted-keys/Kconfig b/security/keys/trusted-keys/Kconfig index 553dc117f385..1fb8aa001995 100644 --- a/security/keys/trusted-keys/Kconfig +++ b/security/keys/trusted-keys/Kconfig @@ -39,6 +39,14 @@ config TRUSTED_KEYS_CAAM Enable use of NXP's Cryptographic Accelerator and Assurance Module (CAAM) as trusted key backend. +config TRUSTED_KEYS_DCP + bool "DCP-based trusted keys" + depends on CRYPTO_DEV_MXS_DCP >= TRUSTED_KEYS + default y + select HAVE_TRUSTED_KEYS + help + Enable use of NXP's DCP (Data Co-Processor) as trusted key backend. + if !HAVE_TRUSTED_KEYS comment "No trust source selected!" endif diff --git a/security/keys/trusted-keys/Makefile b/security/keys/trusted-keys/Makefile index 735aa0bc08ef..f0f3b27f688b 100644 --- a/security/keys/trusted-keys/Makefile +++ b/security/keys/trusted-keys/Makefile @@ -14,3 +14,5 @@ trusted-$(CONFIG_TRUSTED_KEYS_TPM) += tpm2key.asn1.o trusted-$(CONFIG_TRUSTED_KEYS_TEE) += trusted_tee.o trusted-$(CONFIG_TRUSTED_KEYS_CAAM) += trusted_caam.o + +trusted-$(CONFIG_TRUSTED_KEYS_DCP) += trusted_dcp.o diff --git a/security/keys/trusted-keys/trusted_core.c b/security/keys/trusted-keys/trusted_core.c index fee1ab2c734d..5113aeae5628 100644 --- a/security/keys/trusted-keys/trusted_core.c +++ b/security/keys/trusted-keys/trusted_core.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -30,7 +31,7 @@ MODULE_PARM_DESC(rng, "Select trusted key RNG"); static char *trusted_key_source; module_param_named(source, trusted_key_source, charp, 0); -MODULE_PARM_DESC(source, "Select trusted keys source (tpm, tee or caam)"); +MODULE_PARM_DESC(source, "Select trusted keys source (tpm, tee, caam or dcp)"); static const struct trusted_key_source trusted_key_sources[] = { #if defined(CONFIG_TRUSTED_KEYS_TPM) @@ -42,6 +43,9 @@ static const struct trusted_key_source trusted_key_sources[] = { #if defined(CONFIG_TRUSTED_KEYS_CAAM) { "caam", &trusted_key_caam_ops }, #endif +#if defined(CONFIG_TRUSTED_KEYS_DCP) + { "dcp", &dcp_trusted_key_ops }, +#endif }; DEFINE_STATIC_CALL_NULL(trusted_key_seal, *trusted_key_sources[0].ops->seal); diff --git a/security/keys/trusted-keys/trusted_dcp.c b/security/keys/trusted-keys/trusted_dcp.c new file mode 100644 index 000000000000..16c44aafeab3 --- /dev/null +++ b/security/keys/trusted-keys/trusted_dcp.c @@ -0,0 +1,313 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2021 sigma star gmbh + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DCP_BLOB_VERSION 1 +#define DCP_BLOB_AUTHLEN 16 + +/** + * struct dcp_blob_fmt - DCP BLOB format. + * + * @fmt_version: Format version, currently being %1. + * @blob_key: Random AES 128 key which is used to encrypt @payload, + * @blob_key itself is encrypted with OTP or UNIQUE device key in + * AES-128-ECB mode by DCP. + * @nonce: Random nonce used for @payload encryption. + * @payload_len: Length of the plain text @payload. + * @payload: The payload itself, encrypted using AES-128-GCM and @blob_key, + * GCM auth tag of size DCP_BLOB_AUTHLEN is attached at the end of it. + * + * The total size of a DCP BLOB is sizeof(struct dcp_blob_fmt) + @payload_len + + * DCP_BLOB_AUTHLEN. + */ +struct dcp_blob_fmt { + __u8 fmt_version; + __u8 blob_key[AES_KEYSIZE_128]; + __u8 nonce[AES_KEYSIZE_128]; + __le32 payload_len; + __u8 payload[]; +} __packed; + +static bool use_otp_key; +module_param_named(dcp_use_otp_key, use_otp_key, bool, 0); +MODULE_PARM_DESC(dcp_use_otp_key, "Use OTP instead of UNIQUE key for sealing"); + +static bool skip_zk_test; +module_param_named(dcp_skip_zk_test, skip_zk_test, bool, 0); +MODULE_PARM_DESC(dcp_skip_zk_test, "Don't test whether device keys are zero'ed"); + +static unsigned int calc_blob_len(unsigned int payload_len) +{ + return sizeof(struct dcp_blob_fmt) + payload_len + DCP_BLOB_AUTHLEN; +} + +static int do_dcp_crypto(u8 *in, u8 *out, bool do_encrypt) +{ + struct skcipher_request *req = NULL; + struct scatterlist src_sg, dst_sg; + struct crypto_skcipher *tfm; + u8 paes_key[DCP_PAES_KEYSIZE]; + DECLARE_CRYPTO_WAIT(wait); + int res = 0; + + if (use_otp_key) + paes_key[0] = DCP_PAES_KEY_OTP; + else + paes_key[0] = DCP_PAES_KEY_UNIQUE; + + tfm = crypto_alloc_skcipher("ecb-paes-dcp", CRYPTO_ALG_INTERNAL, + CRYPTO_ALG_INTERNAL); + if (IS_ERR(tfm)) { + res = PTR_ERR(tfm); + tfm = NULL; + goto out; + } + + req = skcipher_request_alloc(tfm, GFP_NOFS); + if (!req) { + res = -ENOMEM; + goto out; + } + + skcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG | + CRYPTO_TFM_REQ_MAY_SLEEP, + crypto_req_done, &wait); + res = crypto_skcipher_setkey(tfm, paes_key, sizeof(paes_key)); + if (res < 0) + goto out; + + sg_init_one(&src_sg, in, AES_KEYSIZE_128); + sg_init_one(&dst_sg, out, AES_KEYSIZE_128); + skcipher_request_set_crypt(req, &src_sg, &dst_sg, AES_KEYSIZE_128, + NULL); + + if (do_encrypt) + res = crypto_wait_req(crypto_skcipher_encrypt(req), &wait); + else + res = crypto_wait_req(crypto_skcipher_decrypt(req), &wait); + +out: + skcipher_request_free(req); + crypto_free_skcipher(tfm); + + return res; +} + +static int do_aead_crypto(u8 *in, u8 *out, size_t len, u8 *key, u8 *nonce, + bool do_encrypt) +{ + struct aead_request *aead_req = NULL; + struct scatterlist src_sg, dst_sg; + struct crypto_aead *aead; + int ret; + + aead = crypto_alloc_aead("gcm(aes)", 0, CRYPTO_ALG_ASYNC); + if (IS_ERR(aead)) { + ret = PTR_ERR(aead); + goto out; + } + + ret = crypto_aead_setauthsize(aead, DCP_BLOB_AUTHLEN); + if (ret < 0) { + pr_err("Can't set crypto auth tag len: %d\n", ret); + goto free_aead; + } + + aead_req = aead_request_alloc(aead, GFP_KERNEL); + if (!aead_req) { + ret = -ENOMEM; + goto free_aead; + } + + sg_init_one(&src_sg, in, len); + if (do_encrypt) { + /* + * If we encrypt our buffer has extra space for the auth tag. + */ + sg_init_one(&dst_sg, out, len + DCP_BLOB_AUTHLEN); + } else { + sg_init_one(&dst_sg, out, len); + } + + aead_request_set_crypt(aead_req, &src_sg, &dst_sg, len, nonce); + aead_request_set_callback(aead_req, CRYPTO_TFM_REQ_MAY_SLEEP, NULL, + NULL); + aead_request_set_ad(aead_req, 0); + + if (crypto_aead_setkey(aead, key, AES_KEYSIZE_128)) { + pr_err("Can't set crypto AEAD key\n"); + ret = -EINVAL; + goto free_req; + } + + if (do_encrypt) + ret = crypto_aead_encrypt(aead_req); + else + ret = crypto_aead_decrypt(aead_req); + +free_req: + aead_request_free(aead_req); +free_aead: + crypto_free_aead(aead); +out: + return ret; +} + +static int decrypt_blob_key(u8 *key) +{ + return do_dcp_crypto(key, key, false); +} + +static int encrypt_blob_key(u8 *key) +{ + return do_dcp_crypto(key, key, true); +} + +static int trusted_dcp_seal(struct trusted_key_payload *p, char *datablob) +{ + struct dcp_blob_fmt *b = (struct dcp_blob_fmt *)p->blob; + int blen, ret; + + blen = calc_blob_len(p->key_len); + if (blen > MAX_BLOB_SIZE) + return -E2BIG; + + b->fmt_version = DCP_BLOB_VERSION; + get_random_bytes(b->nonce, AES_KEYSIZE_128); + get_random_bytes(b->blob_key, AES_KEYSIZE_128); + + ret = do_aead_crypto(p->key, b->payload, p->key_len, b->blob_key, + b->nonce, true); + if (ret) { + pr_err("Unable to encrypt blob payload: %i\n", ret); + return ret; + } + + ret = encrypt_blob_key(b->blob_key); + if (ret) { + pr_err("Unable to encrypt blob key: %i\n", ret); + return ret; + } + + b->payload_len = get_unaligned_le32(&p->key_len); + p->blob_len = blen; + return 0; +} + +static int trusted_dcp_unseal(struct trusted_key_payload *p, char *datablob) +{ + struct dcp_blob_fmt *b = (struct dcp_blob_fmt *)p->blob; + int blen, ret; + + if (b->fmt_version != DCP_BLOB_VERSION) { + pr_err("DCP blob has bad version: %i, expected %i\n", + b->fmt_version, DCP_BLOB_VERSION); + ret = -EINVAL; + goto out; + } + + p->key_len = le32_to_cpu(b->payload_len); + blen = calc_blob_len(p->key_len); + if (blen != p->blob_len) { + pr_err("DCP blob has bad length: %i != %i\n", blen, + p->blob_len); + ret = -EINVAL; + goto out; + } + + ret = decrypt_blob_key(b->blob_key); + if (ret) { + pr_err("Unable to decrypt blob key: %i\n", ret); + goto out; + } + + ret = do_aead_crypto(b->payload, p->key, p->key_len + DCP_BLOB_AUTHLEN, + b->blob_key, b->nonce, false); + if (ret) { + pr_err("Unwrap of DCP payload failed: %i\n", ret); + goto out; + } + + ret = 0; +out: + return ret; +} + +static int test_for_zero_key(void) +{ + /* + * Encrypting a plaintext of all 0x55 bytes will yield + * this ciphertext in case the DCP test key is used. + */ + static const u8 bad[] = {0x9a, 0xda, 0xe0, 0x54, 0xf6, 0x3d, 0xfa, 0xff, + 0x5e, 0xa1, 0x8e, 0x45, 0xed, 0xf6, 0xea, 0x6f}; + void *buf = NULL; + int ret = 0; + + if (skip_zk_test) + goto out; + + buf = kmalloc(AES_BLOCK_SIZE, GFP_KERNEL); + if (!buf) { + ret = -ENOMEM; + goto out; + } + + memset(buf, 0x55, AES_BLOCK_SIZE); + + ret = do_dcp_crypto(buf, buf, true); + if (ret) + goto out; + + if (memcmp(buf, bad, AES_BLOCK_SIZE) == 0) { + pr_warn("Device neither in secure nor trusted mode!\n"); + ret = -EINVAL; + } +out: + kfree(buf); + return ret; +} + +static int trusted_dcp_init(void) +{ + int ret; + + if (use_otp_key) + pr_info("Using DCP OTP key\n"); + + ret = test_for_zero_key(); + if (ret) { + pr_warn("Test for zero'ed keys failed: %i\n", ret); + + return -EINVAL; + } + + return register_key_type(&key_type_trusted); +} + +static void trusted_dcp_exit(void) +{ + unregister_key_type(&key_type_trusted); +} + +struct trusted_key_ops dcp_trusted_key_ops = { + .exit = trusted_dcp_exit, + .init = trusted_dcp_init, + .seal = trusted_dcp_seal, + .unseal = trusted_dcp_unseal, + .migratable = 0, +}; -- 2.35.3