lkml.org 
[lkml]   [2015]   [Oct]   [16]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 08/10] tpm: seal/unseal for TPM 2.0
    Date
    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 <jarkko.sakkinen@linux.intel.com>
    ---
    drivers/char/tpm/tpm-interface.c | 76 ++++++++++++
    drivers/char/tpm/tpm.h | 15 ++-
    drivers/char/tpm/tpm2-cmd.c | 250 ++++++++++++++++++++++++++++++++++++++-
    include/keys/trusted-type.h | 2 +-
    include/linux/tpm.h | 26 ++++
    5 files changed, 366 insertions(+), 3 deletions(-)

    diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c
    index e85d341..c50637d 100644
    --- a/drivers/char/tpm/tpm-interface.c
    +++ b/drivers/char/tpm/tpm-interface.c
    @@ -666,6 +666,30 @@ 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 < 0 on error, and 1 or 0 on success depending whether 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 +1045,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 cb46f62..a4257a3 100644
    --- a/drivers/char/tpm/tpm.h
    +++ b/drivers/char/tpm/tpm.h
    @@ -90,6 +90,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 {
    @@ -97,6 +100,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,
    @@ -407,7 +414,7 @@ struct tpm_buf {
    u8 *data;
    };

    -static inline void tpm_buf_init(struct tpm_buf *buf, u16 tag, u32 ordinal)
    +static inline int tpm_buf_init(struct tpm_buf *buf, u16 tag, u32 ordinal)
    {
    struct tpm_input_header *head;

    @@ -527,6 +534,12 @@ static inline void tpm_add_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 011909a..bd7039f 100644
    --- a/drivers/char/tpm/tpm2-cmd.c
    +++ b/drivers/char/tpm/tpm2-cmd.c
    @@ -1,5 +1,5 @@
    /*
    - * Copyright (C) 2014 Intel Corporation
    + * Copyright (C) 2014, 2015 Intel Corporation
    *
    * Authors:
    * Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
    @@ -16,6 +16,11 @@
    */

    #include "tpm.h"
    +#include <keys/trusted-type.h>
    +
    +enum tpm2_object_attributes {
    + TPM2_ATTR_USER_WITH_AUTH = BIT(6),
    +};

    struct tpm2_startup_in {
    __be16 startup_type;
    @@ -381,6 +386,249 @@ static const struct tpm_input_header tpm2_get_tpm_pt_header = {
    };

    /**
    + * Append TPMS_AUTH_COMMAND to the buffer. The buffer must be allocated with
    + * tpm_buf_alloc().
    + *
    + * @param buf: an allocated tpm_buf instance
    + * @param nonce: the session nonce, may be NULL if not used
    + * @param nonce_len: the session nonce length, may be 0 if not used
    + * @param attributes: the session attributes
    + * @param hmac: the session HMAC or password, may be NULL if not used
    + * @param hmac_len: the session HMAC or password length, maybe 0 if not used
    + */
    +static void tpm2_buf_append_auth(struct tpm_buf *buf, u32 session_handle,
    + const u8 *nonce, u16 nonce_len,
    + u8 attributes,
    + const u8 *hmac, u16 hmac_len)
    +{
    + tpm_buf_append_u32(buf, 9 + nonce_len + hmac_len);
    + tpm_buf_append_u32(buf, session_handle);
    + tpm_buf_append_u16(buf, nonce_len);
    +
    + if (nonce && nonce_len)
    + tpm_buf_append(buf, nonce, nonce_len);
    +
    + tpm_buf_append_u8(buf, attributes);
    + tpm_buf_append_u16(buf, hmac_len);
    +
    + if (hmac && hmac_len)
    + tpm_buf_append(buf, hmac, hmac_len);
    +}
    +
    +/**
    + * 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;
    +
    + rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_CREATE);
    + if (rc)
    + return rc;
    +
    + 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);
    +
    + if (buf.flags & TPM_BUF_OVERFLOW) {
    + rc = -E2BIG;
    + goto out;
    + }
    +
    + rc = tpm_transmit_cmd(chip, buf.data, PAGE_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:
    + tpm_buf_destroy(&buf);
    +
    + 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;
    +
    + rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_LOAD);
    + if (rc)
    + return rc;
    +
    + 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, blob_len);
    +
    + if (buf.flags & TPM_BUF_OVERFLOW) {
    + rc = -E2BIG;
    + goto out;
    + }
    +
    + rc = tpm_transmit_cmd(chip, buf.data, PAGE_SIZE, "loading blob");
    + if (!rc)
    + *blob_handle = be32_to_cpup(
    + (__be32 *) &buf.data[TPM_HEADER_SIZE]);
    +
    +out:
    + tpm_buf_destroy(&buf);
    +
    + if (rc > 0)
    + rc = -EPERM;
    +
    + return rc;
    +}
    +
    +static void tpm2_flush_context(struct tpm_chip *chip, u32 handle)
    +{
    + struct tpm_buf buf;
    + int rc;
    +
    + rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_FLUSH_CONTEXT);
    + if (rc) {
    + dev_warn(chip->pdev, "0x%08x was not flushed, out of memory\n",
    + handle);
    + return;
    + }
    +
    + tpm_buf_append_u32(&buf, handle);
    +
    + rc = tpm_transmit_cmd(chip, buf.data, PAGE_SIZE, "flushing context");
    + if (rc)
    + dev_warn(chip->pdev, "0x%08x was not flushed, rc=%d\n", handle,
    + rc);
    +
    + tpm_buf_destroy(&buf);
    +}
    +
    +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;
    +
    + rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_UNSEAL);
    + if (rc)
    + return rc;
    +
    + 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, PAGE_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);
    + }
    +
    + tpm_buf_destroy(&buf);
    + 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 c91651f..f91ecd9 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
    --
    2.5.0


    \
     
     \ /
      Last update: 2015-10-16 21:01    [W:4.230 / U:0.152 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site