Path: blob/master/security/keys/trusted-keys/trusted_tpm2.c
26424 views
// SPDX-License-Identifier: GPL-2.0-only1/*2* Copyright (C) 2004 IBM Corporation3* Copyright (C) 2014 Intel Corporation4*/56#include <linux/asn1_encoder.h>7#include <linux/oid_registry.h>8#include <linux/string.h>9#include <linux/err.h>10#include <linux/tpm.h>11#include <linux/tpm_command.h>1213#include <keys/trusted-type.h>14#include <keys/trusted_tpm.h>1516#include <linux/unaligned.h>1718#include "tpm2key.asn1.h"1920static struct tpm2_hash tpm2_hash_map[] = {21{HASH_ALGO_SHA1, TPM_ALG_SHA1},22{HASH_ALGO_SHA256, TPM_ALG_SHA256},23{HASH_ALGO_SHA384, TPM_ALG_SHA384},24{HASH_ALGO_SHA512, TPM_ALG_SHA512},25{HASH_ALGO_SM3_256, TPM_ALG_SM3_256},26};2728static u32 tpm2key_oid[] = { 2, 23, 133, 10, 1, 5 };2930static int tpm2_key_encode(struct trusted_key_payload *payload,31struct trusted_key_options *options,32u8 *src, u32 len)33{34const int SCRATCH_SIZE = PAGE_SIZE;35u8 *scratch = kmalloc(SCRATCH_SIZE, GFP_KERNEL);36u8 *work = scratch, *work1;37u8 *end_work = scratch + SCRATCH_SIZE;38u8 *priv, *pub;39u16 priv_len, pub_len;40int ret;4142priv_len = get_unaligned_be16(src) + 2;43priv = src;4445src += priv_len;4647pub_len = get_unaligned_be16(src) + 2;48pub = src;4950if (!scratch)51return -ENOMEM;5253work = asn1_encode_oid(work, end_work, tpm2key_oid,54asn1_oid_len(tpm2key_oid));5556if (options->blobauth_len == 0) {57unsigned char bool[3], *w = bool;58/* tag 0 is emptyAuth */59w = asn1_encode_boolean(w, w + sizeof(bool), true);60if (WARN(IS_ERR(w), "BUG: Boolean failed to encode")) {61ret = PTR_ERR(w);62goto err;63}64work = asn1_encode_tag(work, end_work, 0, bool, w - bool);65}6667/*68* Assume both octet strings will encode to a 2 byte definite length69*70* Note: For a well behaved TPM, this warning should never71* trigger, so if it does there's something nefarious going on72*/73if (WARN(work - scratch + pub_len + priv_len + 14 > SCRATCH_SIZE,74"BUG: scratch buffer is too small")) {75ret = -EINVAL;76goto err;77}7879work = asn1_encode_integer(work, end_work, options->keyhandle);80work = asn1_encode_octet_string(work, end_work, pub, pub_len);81work = asn1_encode_octet_string(work, end_work, priv, priv_len);8283work1 = payload->blob;84work1 = asn1_encode_sequence(work1, work1 + sizeof(payload->blob),85scratch, work - scratch);86if (IS_ERR(work1)) {87ret = PTR_ERR(work1);88pr_err("BUG: ASN.1 encoder failed with %d\n", ret);89goto err;90}9192kfree(scratch);93return work1 - payload->blob;9495err:96kfree(scratch);97return ret;98}99100struct tpm2_key_context {101u32 parent;102const u8 *pub;103u32 pub_len;104const u8 *priv;105u32 priv_len;106};107108static int tpm2_key_decode(struct trusted_key_payload *payload,109struct trusted_key_options *options,110u8 **buf)111{112int ret;113struct tpm2_key_context ctx;114u8 *blob;115116memset(&ctx, 0, sizeof(ctx));117118ret = asn1_ber_decoder(&tpm2key_decoder, &ctx, payload->blob,119payload->blob_len);120if (ret < 0)121return ret;122123if (ctx.priv_len + ctx.pub_len > MAX_BLOB_SIZE)124return -EINVAL;125126blob = kmalloc(ctx.priv_len + ctx.pub_len + 4, GFP_KERNEL);127if (!blob)128return -ENOMEM;129130*buf = blob;131options->keyhandle = ctx.parent;132133memcpy(blob, ctx.priv, ctx.priv_len);134blob += ctx.priv_len;135136memcpy(blob, ctx.pub, ctx.pub_len);137138return 0;139}140141int tpm2_key_parent(void *context, size_t hdrlen,142unsigned char tag,143const void *value, size_t vlen)144{145struct tpm2_key_context *ctx = context;146const u8 *v = value;147int i;148149ctx->parent = 0;150for (i = 0; i < vlen; i++) {151ctx->parent <<= 8;152ctx->parent |= v[i];153}154155return 0;156}157158int tpm2_key_type(void *context, size_t hdrlen,159unsigned char tag,160const void *value, size_t vlen)161{162enum OID oid = look_up_OID(value, vlen);163164if (oid != OID_TPMSealedData) {165char buffer[50];166167sprint_oid(value, vlen, buffer, sizeof(buffer));168pr_debug("OID is \"%s\" which is not TPMSealedData\n",169buffer);170return -EINVAL;171}172173return 0;174}175176int tpm2_key_pub(void *context, size_t hdrlen,177unsigned char tag,178const void *value, size_t vlen)179{180struct tpm2_key_context *ctx = context;181182ctx->pub = value;183ctx->pub_len = vlen;184185return 0;186}187188int tpm2_key_priv(void *context, size_t hdrlen,189unsigned char tag,190const void *value, size_t vlen)191{192struct tpm2_key_context *ctx = context;193194ctx->priv = value;195ctx->priv_len = vlen;196197return 0;198}199200/**201* tpm2_buf_append_auth() - append TPMS_AUTH_COMMAND to the buffer.202*203* @buf: an allocated tpm_buf instance204* @session_handle: session handle205* @nonce: the session nonce, may be NULL if not used206* @nonce_len: the session nonce length, may be 0 if not used207* @attributes: the session attributes208* @hmac: the session HMAC or password, may be NULL if not used209* @hmac_len: the session HMAC or password length, maybe 0 if not used210*/211static void tpm2_buf_append_auth(struct tpm_buf *buf, u32 session_handle,212const u8 *nonce, u16 nonce_len,213u8 attributes,214const u8 *hmac, u16 hmac_len)215{216tpm_buf_append_u32(buf, 9 + nonce_len + hmac_len);217tpm_buf_append_u32(buf, session_handle);218tpm_buf_append_u16(buf, nonce_len);219220if (nonce && nonce_len)221tpm_buf_append(buf, nonce, nonce_len);222223tpm_buf_append_u8(buf, attributes);224tpm_buf_append_u16(buf, hmac_len);225226if (hmac && hmac_len)227tpm_buf_append(buf, hmac, hmac_len);228}229230/**231* tpm2_seal_trusted() - seal the payload of a trusted key232*233* @chip: TPM chip to use234* @payload: the key data in clear and encrypted form235* @options: authentication values and other options236*237* Return: < 0 on error and 0 on success.238*/239int tpm2_seal_trusted(struct tpm_chip *chip,240struct trusted_key_payload *payload,241struct trusted_key_options *options)242{243off_t offset = TPM_HEADER_SIZE;244struct tpm_buf buf, sized;245int blob_len = 0;246u32 hash;247u32 flags;248int i;249int rc;250251for (i = 0; i < ARRAY_SIZE(tpm2_hash_map); i++) {252if (options->hash == tpm2_hash_map[i].crypto_id) {253hash = tpm2_hash_map[i].tpm_id;254break;255}256}257258if (i == ARRAY_SIZE(tpm2_hash_map))259return -EINVAL;260261if (!options->keyhandle)262return -EINVAL;263264rc = tpm_try_get_ops(chip);265if (rc)266return rc;267268rc = tpm2_start_auth_session(chip);269if (rc)270goto out_put;271272rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_CREATE);273if (rc) {274tpm2_end_auth_session(chip);275goto out_put;276}277278rc = tpm_buf_init_sized(&sized);279if (rc) {280tpm_buf_destroy(&buf);281tpm2_end_auth_session(chip);282goto out_put;283}284285tpm_buf_append_name(chip, &buf, options->keyhandle, NULL);286tpm_buf_append_hmac_session(chip, &buf, TPM2_SA_DECRYPT,287options->keyauth, TPM_DIGEST_SIZE);288289/* sensitive */290tpm_buf_append_u16(&sized, options->blobauth_len);291292if (options->blobauth_len)293tpm_buf_append(&sized, options->blobauth, options->blobauth_len);294295tpm_buf_append_u16(&sized, payload->key_len);296tpm_buf_append(&sized, payload->key, payload->key_len);297tpm_buf_append(&buf, sized.data, sized.length);298299/* public */300tpm_buf_reset_sized(&sized);301tpm_buf_append_u16(&sized, TPM_ALG_KEYEDHASH);302tpm_buf_append_u16(&sized, hash);303304/* key properties */305flags = 0;306flags |= options->policydigest_len ? 0 : TPM2_OA_USER_WITH_AUTH;307flags |= payload->migratable ? 0 : (TPM2_OA_FIXED_TPM | TPM2_OA_FIXED_PARENT);308tpm_buf_append_u32(&sized, flags);309310/* policy */311tpm_buf_append_u16(&sized, options->policydigest_len);312if (options->policydigest_len)313tpm_buf_append(&sized, options->policydigest, options->policydigest_len);314315/* public parameters */316tpm_buf_append_u16(&sized, TPM_ALG_NULL);317tpm_buf_append_u16(&sized, 0);318319tpm_buf_append(&buf, sized.data, sized.length);320321/* outside info */322tpm_buf_append_u16(&buf, 0);323324/* creation PCR */325tpm_buf_append_u32(&buf, 0);326327if (buf.flags & TPM_BUF_OVERFLOW) {328rc = -E2BIG;329tpm2_end_auth_session(chip);330goto out;331}332333tpm_buf_fill_hmac_session(chip, &buf);334rc = tpm_transmit_cmd(chip, &buf, 4, "sealing data");335rc = tpm_buf_check_hmac_response(chip, &buf, rc);336if (rc)337goto out;338339blob_len = tpm_buf_read_u32(&buf, &offset);340if (blob_len > MAX_BLOB_SIZE || buf.flags & TPM_BUF_BOUNDARY_ERROR) {341rc = -E2BIG;342goto out;343}344if (buf.length - offset < blob_len) {345rc = -EFAULT;346goto out;347}348349blob_len = tpm2_key_encode(payload, options, &buf.data[offset], blob_len);350351out:352tpm_buf_destroy(&sized);353tpm_buf_destroy(&buf);354355if (rc > 0) {356if (tpm2_rc_value(rc) == TPM2_RC_HASH)357rc = -EINVAL;358else359rc = -EPERM;360}361if (blob_len < 0)362rc = blob_len;363else364payload->blob_len = blob_len;365366out_put:367tpm_put_ops(chip);368return rc;369}370371/**372* tpm2_load_cmd() - execute a TPM2_Load command373*374* @chip: TPM chip to use375* @payload: the key data in clear and encrypted form376* @options: authentication values and other options377* @blob_handle: returned blob handle378*379* Return: 0 on success.380* -E2BIG on wrong payload size.381* -EPERM on tpm error status.382* < 0 error from tpm_send.383*/384static int tpm2_load_cmd(struct tpm_chip *chip,385struct trusted_key_payload *payload,386struct trusted_key_options *options,387u32 *blob_handle)388{389struct tpm_buf buf;390unsigned int private_len;391unsigned int public_len;392unsigned int blob_len;393u8 *blob, *pub;394int rc;395u32 attrs;396397rc = tpm2_key_decode(payload, options, &blob);398if (rc) {399/* old form */400blob = payload->blob;401payload->old_format = 1;402}403404/* new format carries keyhandle but old format doesn't */405if (!options->keyhandle)406return -EINVAL;407408/* must be big enough for at least the two be16 size counts */409if (payload->blob_len < 4)410return -EINVAL;411412private_len = get_unaligned_be16(blob);413414/* must be big enough for following public_len */415if (private_len + 2 + 2 > (payload->blob_len))416return -E2BIG;417418public_len = get_unaligned_be16(blob + 2 + private_len);419if (private_len + 2 + public_len + 2 > payload->blob_len)420return -E2BIG;421422pub = blob + 2 + private_len + 2;423/* key attributes are always at offset 4 */424attrs = get_unaligned_be32(pub + 4);425426if ((attrs & (TPM2_OA_FIXED_TPM | TPM2_OA_FIXED_PARENT)) ==427(TPM2_OA_FIXED_TPM | TPM2_OA_FIXED_PARENT))428payload->migratable = 0;429else430payload->migratable = 1;431432blob_len = private_len + public_len + 4;433if (blob_len > payload->blob_len)434return -E2BIG;435436rc = tpm2_start_auth_session(chip);437if (rc)438return rc;439440rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_LOAD);441if (rc) {442tpm2_end_auth_session(chip);443return rc;444}445446tpm_buf_append_name(chip, &buf, options->keyhandle, NULL);447tpm_buf_append_hmac_session(chip, &buf, 0, options->keyauth,448TPM_DIGEST_SIZE);449450tpm_buf_append(&buf, blob, blob_len);451452if (buf.flags & TPM_BUF_OVERFLOW) {453rc = -E2BIG;454tpm2_end_auth_session(chip);455goto out;456}457458tpm_buf_fill_hmac_session(chip, &buf);459rc = tpm_transmit_cmd(chip, &buf, 4, "loading blob");460rc = tpm_buf_check_hmac_response(chip, &buf, rc);461if (!rc)462*blob_handle = be32_to_cpup(463(__be32 *) &buf.data[TPM_HEADER_SIZE]);464465out:466if (blob != payload->blob)467kfree(blob);468tpm_buf_destroy(&buf);469470if (rc > 0)471rc = -EPERM;472473return rc;474}475476/**477* tpm2_unseal_cmd() - execute a TPM2_Unload command478*479* @chip: TPM chip to use480* @payload: the key data in clear and encrypted form481* @options: authentication values and other options482* @blob_handle: blob handle483*484* Return: 0 on success485* -EPERM on tpm error status486* < 0 error from tpm_send487*/488static int tpm2_unseal_cmd(struct tpm_chip *chip,489struct trusted_key_payload *payload,490struct trusted_key_options *options,491u32 blob_handle)492{493struct tpm_buf buf;494u16 data_len;495u8 *data;496int rc;497498rc = tpm2_start_auth_session(chip);499if (rc)500return rc;501502rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_UNSEAL);503if (rc) {504tpm2_end_auth_session(chip);505return rc;506}507508tpm_buf_append_name(chip, &buf, blob_handle, NULL);509510if (!options->policyhandle) {511tpm_buf_append_hmac_session(chip, &buf, TPM2_SA_ENCRYPT,512options->blobauth,513options->blobauth_len);514} else {515/*516* FIXME: The policy session was generated outside the517* kernel so we don't known the nonce and thus can't518* calculate a HMAC on it. Therefore, the user can519* only really use TPM2_PolicyPassword and we must520* send down the plain text password, which could be521* intercepted. We can still encrypt the returned522* key, but that's small comfort since the interposer523* could repeat our actions with the exfiltrated524* password.525*/526tpm2_buf_append_auth(&buf, options->policyhandle,527NULL /* nonce */, 0, 0,528options->blobauth, options->blobauth_len);529tpm_buf_append_hmac_session_opt(chip, &buf, TPM2_SA_ENCRYPT,530NULL, 0);531}532533tpm_buf_fill_hmac_session(chip, &buf);534rc = tpm_transmit_cmd(chip, &buf, 6, "unsealing");535rc = tpm_buf_check_hmac_response(chip, &buf, rc);536if (rc > 0)537rc = -EPERM;538539if (!rc) {540data_len = be16_to_cpup(541(__be16 *) &buf.data[TPM_HEADER_SIZE + 4]);542if (data_len < MIN_KEY_SIZE || data_len > MAX_KEY_SIZE) {543rc = -EFAULT;544goto out;545}546547if (tpm_buf_length(&buf) < TPM_HEADER_SIZE + 6 + data_len) {548rc = -EFAULT;549goto out;550}551data = &buf.data[TPM_HEADER_SIZE + 6];552553if (payload->old_format) {554/* migratable flag is at the end of the key */555memcpy(payload->key, data, data_len - 1);556payload->key_len = data_len - 1;557payload->migratable = data[data_len - 1];558} else {559/*560* migratable flag already collected from key561* attributes562*/563memcpy(payload->key, data, data_len);564payload->key_len = data_len;565}566}567568out:569tpm_buf_destroy(&buf);570return rc;571}572573/**574* tpm2_unseal_trusted() - unseal the payload of a trusted key575*576* @chip: TPM chip to use577* @payload: the key data in clear and encrypted form578* @options: authentication values and other options579*580* Return: Same as with tpm_send.581*/582int tpm2_unseal_trusted(struct tpm_chip *chip,583struct trusted_key_payload *payload,584struct trusted_key_options *options)585{586u32 blob_handle;587int rc;588589rc = tpm_try_get_ops(chip);590if (rc)591return rc;592593rc = tpm2_load_cmd(chip, payload, options, &blob_handle);594if (rc)595goto out;596597rc = tpm2_unseal_cmd(chip, payload, options, blob_handle);598tpm2_flush_context(chip, blob_handle);599600out:601tpm_put_ops(chip);602603return rc;604}605606607