|
@@ -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;
|
|
@@ -380,6 +385,249 @@ static const struct tpm_input_header tpm2_get_tpm_pt_header = {
|
|
|
.ordinal = cpu_to_be32(TPM2_CC_GET_CAPABILITY)
|
|
|
};
|
|
|
|
|
|
+/**
|
|
|
+ * 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.
|