From patchwork Fri Oct 2 08:38:17 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jarkko Sakkinen X-Patchwork-Id: 7314111 Return-Path: X-Original-To: patchwork-tpmdd-devel@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 0AC299F1D5 for ; Fri, 2 Oct 2015 08:38:59 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 80FA7208B4 for ; Fri, 2 Oct 2015 08:38:57 +0000 (UTC) Received: from lists.sourceforge.net (lists.sourceforge.net [216.34.181.88]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id F3F67207A9 for ; Fri, 2 Oct 2015 08:38:55 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=sfs-ml-4.v29.ch3.sourceforge.com) by sfs-ml-4.v29.ch3.sourceforge.com with esmtp (Exim 4.76) (envelope-from ) id 1Zhvri-0005DI-Gu; Fri, 02 Oct 2015 08:38:54 +0000 Received: from sog-mx-1.v43.ch3.sourceforge.com ([172.29.43.191] helo=mx.sourceforge.net) by sfs-ml-4.v29.ch3.sourceforge.com with esmtp (Exim 4.76) (envelope-from ) id 1Zhvrg-0005DD-Pp for tpmdd-devel@lists.sourceforge.net; Fri, 02 Oct 2015 08:38:52 +0000 X-ACL-Warn: Received: from mga09.intel.com ([134.134.136.24]) by sog-mx-1.v43.ch3.sourceforge.com with esmtp (Exim 4.76) id 1Zhvra-0001Yf-N9 for tpmdd-devel@lists.sourceforge.net; Fri, 02 Oct 2015 08:38:52 +0000 Received: from orsmga001.jf.intel.com ([10.7.209.18]) by orsmga102.jf.intel.com with ESMTP; 02 Oct 2015 01:38:47 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.17,622,1437462000"; d="scan'208";a="782596085" Received: from dybugrov-mobl3.ccr.corp.intel.com (HELO localhost) ([10.252.8.88]) by orsmga001.jf.intel.com with ESMTP; 02 Oct 2015 01:38:43 -0700 From: Jarkko Sakkinen To: tpmdd-devel@lists.sourceforge.net, linux-kernel@vger.kernel.org Date: Fri, 2 Oct 2015 11:38:17 +0300 Message-Id: <1443775102-9727-4-git-send-email-jarkko.sakkinen@linux.intel.com> X-Mailer: git-send-email 2.5.0 In-Reply-To: <1443775102-9727-1-git-send-email-jarkko.sakkinen@linux.intel.com> References: <1443775102-9727-1-git-send-email-jarkko.sakkinen@linux.intel.com> X-Spam-Score: -0.0 (/) X-Headers-End: 1Zhvra-0001Yf-N9 Cc: David Howells , gregkh@linuxfoundation.org, "open list:KEYS-TRUSTED" , "open list:KEYS-TRUSTED" , David Safford , akpm@linux-foundation.org Subject: [tpmdd-devel] [PATCH 3/4] tpm: seal/unseal for TPM 2.0 X-BeenThere: tpmdd-devel@lists.sourceforge.net X-Mailman-Version: 2.1.9 Precedence: list List-Id: Tpm Device Driver maintainance List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: tpmdd-devel-bounces@lists.sourceforge.net X-Spam-Status: No, score=-6.9 required=5.0 tests=BAYES_00, HK_RANDOM_ENVFROM, RCVD_IN_DNSWL_HI, T_RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Added tpm_trusted_seal() and tpm_trusted_unseal() API for sealing trusted keys. This patch implements basic sealing and unsealing functionality for TPM 2.0: * Seal with a parent key using a 20 byte auth value. * Unseal with a parent key using a 20 byte auth value. Signed-off-by: Jarkko Sakkinen --- drivers/char/tpm/tpm-interface.c | 75 ++++++++++++++++ drivers/char/tpm/tpm.h | 14 +++ drivers/char/tpm/tpm2-cmd.c | 184 +++++++++++++++++++++++++++++++++++++++ include/keys/trusted-type.h | 2 +- include/linux/tpm.h | 26 ++++++ 5 files changed, 300 insertions(+), 1 deletion(-) diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c index e85d341..6dd4c74 100644 --- a/drivers/char/tpm/tpm-interface.c +++ b/drivers/char/tpm/tpm-interface.c @@ -666,6 +666,29 @@ int tpm_pcr_read_dev(struct tpm_chip *chip, int pcr_idx, u8 *res_buf) } /** + * tpm_is_tpm2 - is the chip a TPM2 chip? + * @chip_num: tpm idx # or ANY + * + * Returns 1 if the chip is a TPM2 chip. + */ +int tpm_is_tpm2(u32 chip_num) +{ + struct tpm_chip *chip; + int rc; + + chip = tpm_chip_find_get(chip_num); + if (chip == NULL) + return -ENODEV; + + rc = (chip->flags & TPM_CHIP_FLAG_TPM2) != 0; + + tpm_chip_put(chip); + + return rc; +} +EXPORT_SYMBOL_GPL(tpm_is_tpm2); + +/** * tpm_pcr_read - read a pcr value * @chip_num: tpm idx # or ANY * @pcr_idx: pcr idx to retrieve @@ -1021,6 +1044,58 @@ int tpm_get_random(u32 chip_num, u8 *out, size_t max) } EXPORT_SYMBOL_GPL(tpm_get_random); +/** + * tpm_seal_trusted() - seal a trusted key + * @chip_num: A specific chip number for the request or TPM_ANY_NUM + * @options: authentication values and other options + * @payload: the key data in clear and encrypted form + * + * Returns < 0 on error and 0 on success. At the moment, only TPM 2.0 chips + * are supported. + */ +int tpm_seal_trusted(u32 chip_num, struct trusted_key_payload *payload, + struct trusted_key_options *options) +{ + struct tpm_chip *chip; + int rc; + + chip = tpm_chip_find_get(chip_num); + if (chip == NULL || !(chip->flags & TPM_CHIP_FLAG_TPM2)) + return -ENODEV; + + rc = tpm2_seal_trusted(chip, payload, options); + + tpm_chip_put(chip); + return rc; +} +EXPORT_SYMBOL_GPL(tpm_seal_trusted); + +/** + * tpm_unseal_trusted() - unseal a trusted key + * @chip_num: A specific chip number for the request or TPM_ANY_NUM + * @options: authentication values and other options + * @payload: the key data in clear and encrypted form + * + * Returns < 0 on error and 0 on success. At the moment, only TPM 2.0 chips + * are supported. + */ +int tpm_unseal_trusted(u32 chip_num, struct trusted_key_payload *payload, + struct trusted_key_options *options) +{ + struct tpm_chip *chip; + int rc; + + chip = tpm_chip_find_get(chip_num); + if (chip == NULL || !(chip->flags & TPM_CHIP_FLAG_TPM2)) + return -ENODEV; + + rc = tpm2_unseal_trusted(chip, payload, options); + + tpm_chip_put(chip); + return rc; +} +EXPORT_SYMBOL_GPL(tpm_unseal_trusted); + static int __init tpm_init(void) { int rc; diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h index f04afb7..2d79939 100644 --- a/drivers/char/tpm/tpm.h +++ b/drivers/char/tpm/tpm.h @@ -88,6 +88,9 @@ enum tpm2_return_codes { enum tpm2_algorithms { TPM2_ALG_SHA1 = 0x0004, + TPM2_ALG_KEYEDHASH = 0x0008, + TPM2_ALG_SHA256 = 0x000B, + TPM2_ALG_NULL = 0x0010 }; enum tpm2_command_codes { @@ -95,6 +98,10 @@ enum tpm2_command_codes { TPM2_CC_SELF_TEST = 0x0143, TPM2_CC_STARTUP = 0x0144, TPM2_CC_SHUTDOWN = 0x0145, + TPM2_CC_CREATE = 0x0153, + TPM2_CC_LOAD = 0x0157, + TPM2_CC_UNSEAL = 0x015E, + TPM2_CC_FLUSH_CONTEXT = 0x0165, TPM2_CC_GET_CAPABILITY = 0x017A, TPM2_CC_GET_RANDOM = 0x017B, TPM2_CC_PCR_READ = 0x017E, @@ -492,6 +499,13 @@ static inline void tpm_remove_ppi(struct tpm_chip *chip) int tpm2_pcr_read(struct tpm_chip *chip, int pcr_idx, u8 *res_buf); int tpm2_pcr_extend(struct tpm_chip *chip, int pcr_idx, const u8 *hash); int tpm2_get_random(struct tpm_chip *chip, u8 *out, size_t max); +int tpm2_seal_trusted(struct tpm_chip *chip, + struct trusted_key_payload *payload, + struct trusted_key_options *options); +int tpm2_unseal_trusted(struct tpm_chip *chip, + struct trusted_key_payload *payload, + struct trusted_key_options *options); + ssize_t tpm2_get_tpm_pt(struct tpm_chip *chip, u32 property_id, u32 *value, const char *desc); diff --git a/drivers/char/tpm/tpm2-cmd.c b/drivers/char/tpm/tpm2-cmd.c index 0d55674..0986c96 100644 --- a/drivers/char/tpm/tpm2-cmd.c +++ b/drivers/char/tpm/tpm2-cmd.c @@ -16,6 +16,11 @@ */ #include "tpm.h" +#include + +enum tpm2_object_attributes { + TPM2_ATTR_USER_WITH_AUTH = BIT(6), +}; struct tpm2_pcr_read_in { __be32 pcr_selects_cnt; @@ -322,6 +327,185 @@ int tpm2_get_random(struct tpm_chip *chip, u8 *res_buf, size_t max) } /** + * tpm2_seal_trusted() - seal a trusted key + * @chip_num: A specific chip number for the request or TPM_ANY_NUM + * @options: authentication values and other options + * @payload: the key data in clear and encrypted form + * + * Returns < 0 on error and 0 on success. + */ +int tpm2_seal_trusted(struct tpm_chip *chip, + struct trusted_key_payload *payload, + struct trusted_key_options *options) +{ + unsigned int blob_len; + struct tpm_buf buf; + int rc; + + tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_CREATE); + tpm_buf_append_u32(&buf, options->keyhandle); + tpm2_buf_append_auth(&buf, TPM2_RS_PW, + NULL /* nonce */, 0, + 0 /* session_attributes */, + options->keyauth /* hmac */, + TPM_DIGEST_SIZE); + + /* sensitive */ + tpm_buf_append_u16(&buf, 4 + TPM_DIGEST_SIZE + payload->key_len); + + 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); + tpm_buf_append(&buf, payload->key, payload->key_len); + + /* public */ + tpm_buf_append_u16(&buf, 14); + + tpm_buf_append_u16(&buf, TPM2_ALG_KEYEDHASH); + tpm_buf_append_u16(&buf, TPM2_ALG_SHA256); + tpm_buf_append_u32(&buf, TPM2_ATTR_USER_WITH_AUTH); + tpm_buf_append_u16(&buf, 0); /* policy digest size */ + tpm_buf_append_u16(&buf, TPM2_ALG_NULL); + tpm_buf_append_u16(&buf, 0); + + /* outside info */ + tpm_buf_append_u16(&buf, 0); + + /* creation PCR */ + tpm_buf_append_u32(&buf, 0); + + rc = tpm_transmit_cmd(chip, buf.data, TPM_BUF_SIZE, "sealing data"); + if (rc) + goto out; + + blob_len = be32_to_cpup((__be32 *) &buf.data[TPM_HEADER_SIZE]); + if (blob_len > MAX_BLOB_SIZE) { + rc = -E2BIG; + goto out; + } + + memcpy(payload->blob, &buf.data[TPM_HEADER_SIZE + 4], blob_len); + payload->blob_len = blob_len; + +out: + if (rc > 0) + rc = -EPERM; + + return rc; +} + +static int tpm2_load(struct tpm_chip *chip, + struct trusted_key_payload *payload, + struct trusted_key_options *options, + u32 *blob_handle) +{ + struct tpm_buf buf; + unsigned int private_len; + unsigned int public_len; + unsigned int blob_len; + int rc; + + private_len = be16_to_cpup((__be16 *) &payload->blob[0]); + if (private_len > (payload->blob_len - 2)) + return -E2BIG; + + public_len = be16_to_cpup((__be16 *) &payload->blob[2 + private_len]); + blob_len = private_len + public_len + 4; + if (blob_len > payload->blob_len) + return -E2BIG; + + tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_LOAD); + tpm_buf_append_u32(&buf, options->keyhandle); + tpm2_buf_append_auth(&buf, TPM2_RS_PW, + NULL /* nonce */, 0, + 0 /* session_attributes */, + options->keyauth /* hmac */, + TPM_DIGEST_SIZE); + + tpm_buf_append(&buf, payload->blob, payload->blob_len); + + rc = tpm_transmit_cmd(chip, buf.data, TPM_BUF_SIZE, "loading blob"); + if (!rc) + *blob_handle = be32_to_cpup( + (__be32 *) &buf.data[TPM_HEADER_SIZE]); + + if (rc > 0) + rc = -EPERM; + + return rc; +} + +static void tpm2_flush_context(struct tpm_chip *chip, u32 handle) +{ + struct tpm_buf buf; + int rc; + + tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_FLUSH_CONTEXT); + tpm_buf_append_u32(&buf, handle); + + rc = tpm_transmit_cmd(chip, buf.data, TPM_BUF_SIZE, "flushing context"); + if (rc) + dev_warn(chip->pdev, "0x%08x was not flushed\n", handle); +} + +static int tpm2_unseal(struct tpm_chip *chip, + struct trusted_key_payload *payload, + struct trusted_key_options *options, + u32 blob_handle) +{ + struct tpm_buf buf; + int rc; + + tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_UNSEAL); + tpm_buf_append_u32(&buf, blob_handle); + tpm2_buf_append_auth(&buf, TPM2_RS_PW, + NULL /* nonce */, 0, + 0 /* session_attributes */, + options->blobauth /* hmac */, + TPM_DIGEST_SIZE); + + rc = tpm_transmit_cmd(chip, buf.data, TPM_BUF_SIZE, "unsealing"); + if (rc > 0) + rc = -EPERM; + + if (!rc) { + payload->key_len = be16_to_cpup( + (__be16 *) &buf.data[TPM_HEADER_SIZE + 4]); + + memcpy(payload->key, &buf.data[TPM_HEADER_SIZE + 6], + payload->key_len); + } + + return rc; +} + +/** + * tpm_unseal_trusted() - unseal a trusted key + * @chip_num: A specific chip number for the request or TPM_ANY_NUM + * @options: authentication values and other options + * @payload: the key data in clear and encrypted form + * + * Returns < 0 on error and 0 on success. + */ +int tpm2_unseal_trusted(struct tpm_chip *chip, + struct trusted_key_payload *payload, + struct trusted_key_options *options) +{ + u32 blob_handle; + int rc; + + rc = tpm2_load(chip, payload, options, &blob_handle); + if (rc) + return rc; + + rc = tpm2_unseal(chip, payload, options, blob_handle); + + tpm2_flush_context(chip, blob_handle); + + return rc; +} + +/** * tpm2_get_tpm_pt() - get value of a TPM_CAP_TPM_PROPERTIES type property * @chip: TPM chip to use. * @property_id: property ID. diff --git a/include/keys/trusted-type.h b/include/keys/trusted-type.h index 9a2c626..0224b21 100644 --- a/include/keys/trusted-type.h +++ b/include/keys/trusted-type.h @@ -16,7 +16,7 @@ #define MIN_KEY_SIZE 32 #define MAX_KEY_SIZE 128 -#define MAX_BLOB_SIZE 320 +#define MAX_BLOB_SIZE 512 #define MAX_PCRINFO_SIZE 64 struct trusted_key_payload { diff --git a/include/linux/tpm.h b/include/linux/tpm.h index 8350c53..706e63e 100644 --- a/include/linux/tpm.h +++ b/include/linux/tpm.h @@ -30,6 +30,8 @@ #define TPM_ANY_NUM 0xFFFF struct tpm_chip; +struct trusted_key_payload; +struct trusted_key_options; struct tpm_class_ops { const u8 req_complete_mask; @@ -46,11 +48,22 @@ struct tpm_class_ops { #if defined(CONFIG_TCG_TPM) || defined(CONFIG_TCG_TPM_MODULE) +extern int tpm_is_tpm2(u32 chip_num); extern int tpm_pcr_read(u32 chip_num, int pcr_idx, u8 *res_buf); extern int tpm_pcr_extend(u32 chip_num, int pcr_idx, const u8 *hash); extern int tpm_send(u32 chip_num, void *cmd, size_t buflen); extern int tpm_get_random(u32 chip_num, u8 *data, size_t max); +extern int tpm_seal_trusted(u32 chip_num, + struct trusted_key_payload *payload, + struct trusted_key_options *options); +extern int tpm_unseal_trusted(u32 chip_num, + struct trusted_key_payload *payload, + struct trusted_key_options *options); #else +static inline int tpm_is_tpm2(u32 chip_num) +{ + return -ENODEV; +} static inline int tpm_pcr_read(u32 chip_num, int pcr_idx, u8 *res_buf) { return -ENODEV; } @@ -63,5 +76,18 @@ static inline int tpm_send(u32 chip_num, void *cmd, size_t buflen) { static inline int tpm_get_random(u32 chip_num, u8 *data, size_t max) { return -ENODEV; } + +static inline int tpm_seal_trusted(u32 chip_num, + struct trusted_key_payload *payload, + struct trusted_key_options *options) +{ + return -ENODEV; +} +static inline int tpm_unseal_trusted(u32 chip_num, + struct trusted_key_payload *payload, + struct trusted_key_options *options) +{ + return -ENODEV; +} #endif #endif