linux/security/keys/trusted-keys/trusted_tpm2.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Copyright (C) 2004 IBM Corporation
   4 * Copyright (C) 2014 Intel Corporation
   5 */
   6
   7#include <linux/string.h>
   8#include <linux/err.h>
   9#include <linux/tpm.h>
  10#include <linux/tpm_command.h>
  11
  12#include <keys/trusted-type.h>
  13#include <keys/trusted_tpm.h>
  14
  15static struct tpm2_hash tpm2_hash_map[] = {
  16        {HASH_ALGO_SHA1, TPM_ALG_SHA1},
  17        {HASH_ALGO_SHA256, TPM_ALG_SHA256},
  18        {HASH_ALGO_SHA384, TPM_ALG_SHA384},
  19        {HASH_ALGO_SHA512, TPM_ALG_SHA512},
  20        {HASH_ALGO_SM3_256, TPM_ALG_SM3_256},
  21};
  22
  23/**
  24 * tpm_buf_append_auth() - append TPMS_AUTH_COMMAND to the buffer.
  25 *
  26 * @buf: an allocated tpm_buf instance
  27 * @session_handle: session handle
  28 * @nonce: the session nonce, may be NULL if not used
  29 * @nonce_len: the session nonce length, may be 0 if not used
  30 * @attributes: the session attributes
  31 * @hmac: the session HMAC or password, may be NULL if not used
  32 * @hmac_len: the session HMAC or password length, maybe 0 if not used
  33 */
  34static void tpm2_buf_append_auth(struct tpm_buf *buf, u32 session_handle,
  35                                 const u8 *nonce, u16 nonce_len,
  36                                 u8 attributes,
  37                                 const u8 *hmac, u16 hmac_len)
  38{
  39        tpm_buf_append_u32(buf, 9 + nonce_len + hmac_len);
  40        tpm_buf_append_u32(buf, session_handle);
  41        tpm_buf_append_u16(buf, nonce_len);
  42
  43        if (nonce && nonce_len)
  44                tpm_buf_append(buf, nonce, nonce_len);
  45
  46        tpm_buf_append_u8(buf, attributes);
  47        tpm_buf_append_u16(buf, hmac_len);
  48
  49        if (hmac && hmac_len)
  50                tpm_buf_append(buf, hmac, hmac_len);
  51}
  52
  53/**
  54 * tpm2_seal_trusted() - seal the payload of a trusted key
  55 *
  56 * @chip: TPM chip to use
  57 * @payload: the key data in clear and encrypted form
  58 * @options: authentication values and other options
  59 *
  60 * Return: < 0 on error and 0 on success.
  61 */
  62int tpm2_seal_trusted(struct tpm_chip *chip,
  63                      struct trusted_key_payload *payload,
  64                      struct trusted_key_options *options)
  65{
  66        unsigned int blob_len;
  67        struct tpm_buf buf;
  68        u32 hash;
  69        int i;
  70        int rc;
  71
  72        for (i = 0; i < ARRAY_SIZE(tpm2_hash_map); i++) {
  73                if (options->hash == tpm2_hash_map[i].crypto_id) {
  74                        hash = tpm2_hash_map[i].tpm_id;
  75                        break;
  76                }
  77        }
  78
  79        if (i == ARRAY_SIZE(tpm2_hash_map))
  80                return -EINVAL;
  81
  82        rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_CREATE);
  83        if (rc)
  84                return rc;
  85
  86        tpm_buf_append_u32(&buf, options->keyhandle);
  87        tpm2_buf_append_auth(&buf, TPM2_RS_PW,
  88                             NULL /* nonce */, 0,
  89                             0 /* session_attributes */,
  90                             options->keyauth /* hmac */,
  91                             TPM_DIGEST_SIZE);
  92
  93        /* sensitive */
  94        tpm_buf_append_u16(&buf, 4 + TPM_DIGEST_SIZE + payload->key_len + 1);
  95
  96        tpm_buf_append_u16(&buf, TPM_DIGEST_SIZE);
  97        tpm_buf_append(&buf, options->blobauth, TPM_DIGEST_SIZE);
  98        tpm_buf_append_u16(&buf, payload->key_len + 1);
  99        tpm_buf_append(&buf, payload->key, payload->key_len);
 100        tpm_buf_append_u8(&buf, payload->migratable);
 101
 102        /* public */
 103        tpm_buf_append_u16(&buf, 14 + options->policydigest_len);
 104        tpm_buf_append_u16(&buf, TPM_ALG_KEYEDHASH);
 105        tpm_buf_append_u16(&buf, hash);
 106
 107        /* policy */
 108        if (options->policydigest_len) {
 109                tpm_buf_append_u32(&buf, 0);
 110                tpm_buf_append_u16(&buf, options->policydigest_len);
 111                tpm_buf_append(&buf, options->policydigest,
 112                               options->policydigest_len);
 113        } else {
 114                tpm_buf_append_u32(&buf, TPM2_OA_USER_WITH_AUTH);
 115                tpm_buf_append_u16(&buf, 0);
 116        }
 117
 118        /* public parameters */
 119        tpm_buf_append_u16(&buf, TPM_ALG_NULL);
 120        tpm_buf_append_u16(&buf, 0);
 121
 122        /* outside info */
 123        tpm_buf_append_u16(&buf, 0);
 124
 125        /* creation PCR */
 126        tpm_buf_append_u32(&buf, 0);
 127
 128        if (buf.flags & TPM_BUF_OVERFLOW) {
 129                rc = -E2BIG;
 130                goto out;
 131        }
 132
 133        rc = tpm_send(chip, buf.data, tpm_buf_length(&buf));
 134        if (rc)
 135                goto out;
 136
 137        blob_len = be32_to_cpup((__be32 *) &buf.data[TPM_HEADER_SIZE]);
 138        if (blob_len > MAX_BLOB_SIZE) {
 139                rc = -E2BIG;
 140                goto out;
 141        }
 142        if (tpm_buf_length(&buf) < TPM_HEADER_SIZE + 4 + blob_len) {
 143                rc = -EFAULT;
 144                goto out;
 145        }
 146
 147        memcpy(payload->blob, &buf.data[TPM_HEADER_SIZE + 4], blob_len);
 148        payload->blob_len = blob_len;
 149
 150out:
 151        tpm_buf_destroy(&buf);
 152
 153        if (rc > 0) {
 154                if (tpm2_rc_value(rc) == TPM2_RC_HASH)
 155                        rc = -EINVAL;
 156                else
 157                        rc = -EPERM;
 158        }
 159
 160        return rc;
 161}
 162
 163/**
 164 * tpm2_load_cmd() - execute a TPM2_Load command
 165 *
 166 * @chip: TPM chip to use
 167 * @payload: the key data in clear and encrypted form
 168 * @options: authentication values and other options
 169 * @blob_handle: returned blob handle
 170 *
 171 * Return: 0 on success.
 172 *        -E2BIG on wrong payload size.
 173 *        -EPERM on tpm error status.
 174 *        < 0 error from tpm_send.
 175 */
 176static int tpm2_load_cmd(struct tpm_chip *chip,
 177                         struct trusted_key_payload *payload,
 178                         struct trusted_key_options *options,
 179                         u32 *blob_handle)
 180{
 181        struct tpm_buf buf;
 182        unsigned int private_len;
 183        unsigned int public_len;
 184        unsigned int blob_len;
 185        int rc;
 186
 187        private_len = be16_to_cpup((__be16 *) &payload->blob[0]);
 188        if (private_len > (payload->blob_len - 2))
 189                return -E2BIG;
 190
 191        public_len = be16_to_cpup((__be16 *) &payload->blob[2 + private_len]);
 192        blob_len = private_len + public_len + 4;
 193        if (blob_len > payload->blob_len)
 194                return -E2BIG;
 195
 196        rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_LOAD);
 197        if (rc)
 198                return rc;
 199
 200        tpm_buf_append_u32(&buf, options->keyhandle);
 201        tpm2_buf_append_auth(&buf, TPM2_RS_PW,
 202                             NULL /* nonce */, 0,
 203                             0 /* session_attributes */,
 204                             options->keyauth /* hmac */,
 205                             TPM_DIGEST_SIZE);
 206
 207        tpm_buf_append(&buf, payload->blob, blob_len);
 208
 209        if (buf.flags & TPM_BUF_OVERFLOW) {
 210                rc = -E2BIG;
 211                goto out;
 212        }
 213
 214        rc = tpm_send(chip, buf.data, tpm_buf_length(&buf));
 215        if (!rc)
 216                *blob_handle = be32_to_cpup(
 217                        (__be32 *) &buf.data[TPM_HEADER_SIZE]);
 218
 219out:
 220        tpm_buf_destroy(&buf);
 221
 222        if (rc > 0)
 223                rc = -EPERM;
 224
 225        return rc;
 226}
 227
 228/**
 229 * tpm2_unseal_cmd() - execute a TPM2_Unload command
 230 *
 231 * @chip: TPM chip to use
 232 * @payload: the key data in clear and encrypted form
 233 * @options: authentication values and other options
 234 * @blob_handle: blob handle
 235 *
 236 * Return: 0 on success
 237 *         -EPERM on tpm error status
 238 *         < 0 error from tpm_send
 239 */
 240static int tpm2_unseal_cmd(struct tpm_chip *chip,
 241                           struct trusted_key_payload *payload,
 242                           struct trusted_key_options *options,
 243                           u32 blob_handle)
 244{
 245        struct tpm_buf buf;
 246        u16 data_len;
 247        u8 *data;
 248        int rc;
 249
 250        rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_UNSEAL);
 251        if (rc)
 252                return rc;
 253
 254        tpm_buf_append_u32(&buf, blob_handle);
 255        tpm2_buf_append_auth(&buf,
 256                             options->policyhandle ?
 257                             options->policyhandle : TPM2_RS_PW,
 258                             NULL /* nonce */, 0,
 259                             TPM2_SA_CONTINUE_SESSION,
 260                             options->blobauth /* hmac */,
 261                             TPM_DIGEST_SIZE);
 262
 263        rc = tpm_send(chip, buf.data, tpm_buf_length(&buf));
 264        if (rc > 0)
 265                rc = -EPERM;
 266
 267        if (!rc) {
 268                data_len = be16_to_cpup(
 269                        (__be16 *) &buf.data[TPM_HEADER_SIZE + 4]);
 270                if (data_len < MIN_KEY_SIZE ||  data_len > MAX_KEY_SIZE + 1) {
 271                        rc = -EFAULT;
 272                        goto out;
 273                }
 274
 275                if (tpm_buf_length(&buf) < TPM_HEADER_SIZE + 6 + data_len) {
 276                        rc = -EFAULT;
 277                        goto out;
 278                }
 279                data = &buf.data[TPM_HEADER_SIZE + 6];
 280
 281                memcpy(payload->key, data, data_len - 1);
 282                payload->key_len = data_len - 1;
 283                payload->migratable = data[data_len - 1];
 284        }
 285
 286out:
 287        tpm_buf_destroy(&buf);
 288        return rc;
 289}
 290
 291/**
 292 * tpm2_unseal_trusted() - unseal the payload of a trusted key
 293 *
 294 * @chip: TPM chip to use
 295 * @payload: the key data in clear and encrypted form
 296 * @options: authentication values and other options
 297 *
 298 * Return: Same as with tpm_send.
 299 */
 300int tpm2_unseal_trusted(struct tpm_chip *chip,
 301                        struct trusted_key_payload *payload,
 302                        struct trusted_key_options *options)
 303{
 304        u32 blob_handle;
 305        int rc;
 306
 307        rc = tpm2_load_cmd(chip, payload, options, &blob_handle);
 308        if (rc)
 309                return rc;
 310
 311        rc = tpm2_unseal_cmd(chip, payload, options, blob_handle);
 312        tpm2_flush_context(chip, blob_handle);
 313
 314        return rc;
 315}
 316