forked from mirrors/linux
		
	KEYS: trusted: Move TPM2 trusted keys code
Move TPM2 trusted keys code to trusted keys subsystem. The reason being it's better to consolidate all the trusted keys code to a single location so that it can be maintained sanely. Also, utilize existing tpm_send() exported API which wraps the internal tpm_transmit_cmd() API. Suggested-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com> Signed-off-by: Sumit Garg <sumit.garg@linaro.org> Reviewed-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com> Tested-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com> Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
This commit is contained in:
		
							parent
							
								
									47f9c27968
								
							
						
					
					
						commit
						2e19e10131
					
				
					 8 changed files with 342 additions and 394 deletions
				
			
		|  | @ -459,62 +459,6 @@ int tpm_get_random(struct tpm_chip *chip, u8 *out, size_t max) | ||||||
| } | } | ||||||
| EXPORT_SYMBOL_GPL(tpm_get_random); | EXPORT_SYMBOL_GPL(tpm_get_random); | ||||||
| 
 | 
 | ||||||
| /**
 |  | ||||||
|  * tpm_seal_trusted() - seal a trusted key payload |  | ||||||
|  * @chip:	a &struct tpm_chip instance, %NULL for the default chip |  | ||||||
|  * @options:	authentication values and other options |  | ||||||
|  * @payload:	the key data in clear and encrypted form |  | ||||||
|  * |  | ||||||
|  * Note: only TPM 2.0 chip are supported. TPM 1.x implementation is located in |  | ||||||
|  * the keyring subsystem. |  | ||||||
|  * |  | ||||||
|  * Return: same as with tpm_transmit_cmd() |  | ||||||
|  */ |  | ||||||
| int tpm_seal_trusted(struct tpm_chip *chip, struct trusted_key_payload *payload, |  | ||||||
| 		     struct trusted_key_options *options) |  | ||||||
| { |  | ||||||
| 	int rc; |  | ||||||
| 
 |  | ||||||
| 	chip = tpm_find_get_ops(chip); |  | ||||||
| 	if (!chip || !(chip->flags & TPM_CHIP_FLAG_TPM2)) |  | ||||||
| 		return -ENODEV; |  | ||||||
| 
 |  | ||||||
| 	rc = tpm2_seal_trusted(chip, payload, options); |  | ||||||
| 
 |  | ||||||
| 	tpm_put_ops(chip); |  | ||||||
| 	return rc; |  | ||||||
| } |  | ||||||
| EXPORT_SYMBOL_GPL(tpm_seal_trusted); |  | ||||||
| 
 |  | ||||||
| /**
 |  | ||||||
|  * tpm_unseal_trusted() - unseal a trusted key |  | ||||||
|  * @chip:	a &struct tpm_chip instance, %NULL for the default chip |  | ||||||
|  * @options:	authentication values and other options |  | ||||||
|  * @payload:	the key data in clear and encrypted form |  | ||||||
|  * |  | ||||||
|  * Note: only TPM 2.0 chip are supported. TPM 1.x implementation is located in |  | ||||||
|  * the keyring subsystem. |  | ||||||
|  * |  | ||||||
|  * Return: same as with tpm_transmit_cmd() |  | ||||||
|  */ |  | ||||||
| int tpm_unseal_trusted(struct tpm_chip *chip, |  | ||||||
| 		       struct trusted_key_payload *payload, |  | ||||||
| 		       struct trusted_key_options *options) |  | ||||||
| { |  | ||||||
| 	int rc; |  | ||||||
| 
 |  | ||||||
| 	chip = tpm_find_get_ops(chip); |  | ||||||
| 	if (!chip || !(chip->flags & TPM_CHIP_FLAG_TPM2)) |  | ||||||
| 		return -ENODEV; |  | ||||||
| 
 |  | ||||||
| 	rc = tpm2_unseal_trusted(chip, payload, options); |  | ||||||
| 
 |  | ||||||
| 	tpm_put_ops(chip); |  | ||||||
| 
 |  | ||||||
| 	return rc; |  | ||||||
| } |  | ||||||
| EXPORT_SYMBOL_GPL(tpm_unseal_trusted); |  | ||||||
| 
 |  | ||||||
| static int __init tpm_init(void) | static int __init tpm_init(void) | ||||||
| { | { | ||||||
| 	int rc; | 	int rc; | ||||||
|  |  | ||||||
|  | @ -212,11 +212,6 @@ static inline void tpm_add_ppi(struct tpm_chip *chip) | ||||||
| } | } | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| static inline u32 tpm2_rc_value(u32 rc) |  | ||||||
| { |  | ||||||
| 	return (rc & BIT(7)) ? rc & 0xff : rc; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| int tpm2_get_timeouts(struct tpm_chip *chip); | int tpm2_get_timeouts(struct tpm_chip *chip); | ||||||
| int tpm2_pcr_read(struct tpm_chip *chip, u32 pcr_idx, | int tpm2_pcr_read(struct tpm_chip *chip, u32 pcr_idx, | ||||||
| 		  struct tpm_digest *digest, u16 *digest_size_ptr); | 		  struct tpm_digest *digest, u16 *digest_size_ptr); | ||||||
|  | @ -224,12 +219,6 @@ int tpm2_pcr_extend(struct tpm_chip *chip, u32 pcr_idx, | ||||||
| 		    struct tpm_digest *digests); | 		    struct tpm_digest *digests); | ||||||
| int tpm2_get_random(struct tpm_chip *chip, u8 *dest, size_t max); | int tpm2_get_random(struct tpm_chip *chip, u8 *dest, size_t max); | ||||||
| void tpm2_flush_context(struct tpm_chip *chip, u32 handle); | void tpm2_flush_context(struct tpm_chip *chip, u32 handle); | ||||||
| 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, | ssize_t tpm2_get_tpm_pt(struct tpm_chip *chip, u32 property_id, | ||||||
| 			u32 *value, const char *desc); | 			u32 *value, const char *desc); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -13,20 +13,6 @@ | ||||||
| 
 | 
 | ||||||
| #include "tpm.h" | #include "tpm.h" | ||||||
| #include <crypto/hash_info.h> | #include <crypto/hash_info.h> | ||||||
| #include <keys/trusted-type.h> |  | ||||||
| 
 |  | ||||||
| enum tpm2_object_attributes { |  | ||||||
| 	TPM2_OA_USER_WITH_AUTH		= BIT(6), |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| enum tpm2_session_attributes { |  | ||||||
| 	TPM2_SA_CONTINUE_SESSION	= BIT(0), |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| struct tpm2_hash { |  | ||||||
| 	unsigned int crypto_id; |  | ||||||
| 	unsigned int tpm_id; |  | ||||||
| }; |  | ||||||
| 
 | 
 | ||||||
| static struct tpm2_hash tpm2_hash_map[] = { | static struct tpm2_hash tpm2_hash_map[] = { | ||||||
| 	{HASH_ALGO_SHA1, TPM_ALG_SHA1}, | 	{HASH_ALGO_SHA1, TPM_ALG_SHA1}, | ||||||
|  | @ -377,299 +363,6 @@ void tpm2_flush_context(struct tpm_chip *chip, u32 handle) | ||||||
| 	tpm_buf_destroy(&buf); | 	tpm_buf_destroy(&buf); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /**
 |  | ||||||
|  * tpm_buf_append_auth() - append TPMS_AUTH_COMMAND to the buffer. |  | ||||||
|  * |  | ||||||
|  * @buf: an allocated tpm_buf instance |  | ||||||
|  * @session_handle: session handle |  | ||||||
|  * @nonce: the session nonce, may be NULL if not used |  | ||||||
|  * @nonce_len: the session nonce length, may be 0 if not used |  | ||||||
|  * @attributes: the session attributes |  | ||||||
|  * @hmac: the session HMAC or password, may be NULL if not used |  | ||||||
|  * @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 the payload of a trusted key |  | ||||||
|  * |  | ||||||
|  * @chip: TPM chip to use |  | ||||||
|  * @payload: the key data in clear and encrypted form |  | ||||||
|  * @options: authentication values and other options |  | ||||||
|  * |  | ||||||
|  * Return: < 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; |  | ||||||
| 	u32 hash; |  | ||||||
| 	int i; |  | ||||||
| 	int rc; |  | ||||||
| 
 |  | ||||||
| 	for (i = 0; i < ARRAY_SIZE(tpm2_hash_map); i++) { |  | ||||||
| 		if (options->hash == tpm2_hash_map[i].crypto_id) { |  | ||||||
| 			hash = tpm2_hash_map[i].tpm_id; |  | ||||||
| 			break; |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	if (i == ARRAY_SIZE(tpm2_hash_map)) |  | ||||||
| 		return -EINVAL; |  | ||||||
| 
 |  | ||||||
| 	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 + 1); |  | ||||||
| 
 |  | ||||||
| 	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 + 1); |  | ||||||
| 	tpm_buf_append(&buf, payload->key, payload->key_len); |  | ||||||
| 	tpm_buf_append_u8(&buf, payload->migratable); |  | ||||||
| 
 |  | ||||||
| 	/* public */ |  | ||||||
| 	tpm_buf_append_u16(&buf, 14 + options->policydigest_len); |  | ||||||
| 	tpm_buf_append_u16(&buf, TPM_ALG_KEYEDHASH); |  | ||||||
| 	tpm_buf_append_u16(&buf, hash); |  | ||||||
| 
 |  | ||||||
| 	/* policy */ |  | ||||||
| 	if (options->policydigest_len) { |  | ||||||
| 		tpm_buf_append_u32(&buf, 0); |  | ||||||
| 		tpm_buf_append_u16(&buf, options->policydigest_len); |  | ||||||
| 		tpm_buf_append(&buf, options->policydigest, |  | ||||||
| 			       options->policydigest_len); |  | ||||||
| 	} else { |  | ||||||
| 		tpm_buf_append_u32(&buf, TPM2_OA_USER_WITH_AUTH); |  | ||||||
| 		tpm_buf_append_u16(&buf, 0); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	/* public parameters */ |  | ||||||
| 	tpm_buf_append_u16(&buf, TPM_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, 4, "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; |  | ||||||
| 	} |  | ||||||
| 	if (tpm_buf_length(&buf) < TPM_HEADER_SIZE + 4 + blob_len) { |  | ||||||
| 		rc = -EFAULT; |  | ||||||
| 		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) { |  | ||||||
| 		if (tpm2_rc_value(rc) == TPM2_RC_HASH) |  | ||||||
| 			rc = -EINVAL; |  | ||||||
| 		else |  | ||||||
| 			rc = -EPERM; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	return rc; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /**
 |  | ||||||
|  * tpm2_load_cmd() - execute a TPM2_Load command |  | ||||||
|  * |  | ||||||
|  * @chip: TPM chip to use |  | ||||||
|  * @payload: the key data in clear and encrypted form |  | ||||||
|  * @options: authentication values and other options |  | ||||||
|  * @blob_handle: returned blob handle |  | ||||||
|  * |  | ||||||
|  * Return: 0 on success. |  | ||||||
|  *        -E2BIG on wrong payload size. |  | ||||||
|  *        -EPERM on tpm error status. |  | ||||||
|  *        < 0 error from tpm_transmit_cmd. |  | ||||||
|  */ |  | ||||||
| static int tpm2_load_cmd(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, 4, "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; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /**
 |  | ||||||
|  * tpm2_unseal_cmd() - execute a TPM2_Unload command |  | ||||||
|  * |  | ||||||
|  * @chip: TPM chip to use |  | ||||||
|  * @payload: the key data in clear and encrypted form |  | ||||||
|  * @options: authentication values and other options |  | ||||||
|  * @blob_handle: blob handle |  | ||||||
|  * |  | ||||||
|  * Return: 0 on success |  | ||||||
|  *         -EPERM on tpm error status |  | ||||||
|  *         < 0 error from tpm_transmit_cmd |  | ||||||
|  */ |  | ||||||
| static int tpm2_unseal_cmd(struct tpm_chip *chip, |  | ||||||
| 			   struct trusted_key_payload *payload, |  | ||||||
| 			   struct trusted_key_options *options, |  | ||||||
| 			   u32 blob_handle) |  | ||||||
| { |  | ||||||
| 	struct tpm_buf buf; |  | ||||||
| 	u16 data_len; |  | ||||||
| 	u8 *data; |  | ||||||
| 	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, |  | ||||||
| 			     options->policyhandle ? |  | ||||||
| 			     options->policyhandle : TPM2_RS_PW, |  | ||||||
| 			     NULL /* nonce */, 0, |  | ||||||
| 			     TPM2_SA_CONTINUE_SESSION, |  | ||||||
| 			     options->blobauth /* hmac */, |  | ||||||
| 			     TPM_DIGEST_SIZE); |  | ||||||
| 
 |  | ||||||
| 	rc = tpm_transmit_cmd(chip, &buf, 6, "unsealing"); |  | ||||||
| 	if (rc > 0) |  | ||||||
| 		rc = -EPERM; |  | ||||||
| 
 |  | ||||||
| 	if (!rc) { |  | ||||||
| 		data_len = be16_to_cpup( |  | ||||||
| 			(__be16 *) &buf.data[TPM_HEADER_SIZE + 4]); |  | ||||||
| 		if (data_len < MIN_KEY_SIZE ||  data_len > MAX_KEY_SIZE + 1) { |  | ||||||
| 			rc = -EFAULT; |  | ||||||
| 			goto out; |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		if (tpm_buf_length(&buf) < TPM_HEADER_SIZE + 6 + data_len) { |  | ||||||
| 			rc = -EFAULT; |  | ||||||
| 			goto out; |  | ||||||
| 		} |  | ||||||
| 		data = &buf.data[TPM_HEADER_SIZE + 6]; |  | ||||||
| 
 |  | ||||||
| 		memcpy(payload->key, data, data_len - 1); |  | ||||||
| 		payload->key_len = data_len - 1; |  | ||||||
| 		payload->migratable = data[data_len - 1]; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| out: |  | ||||||
| 	tpm_buf_destroy(&buf); |  | ||||||
| 	return rc; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /**
 |  | ||||||
|  * tpm2_unseal_trusted() - unseal the payload of a trusted key |  | ||||||
|  * |  | ||||||
|  * @chip: TPM chip to use |  | ||||||
|  * @payload: the key data in clear and encrypted form |  | ||||||
|  * @options: authentication values and other options |  | ||||||
|  * |  | ||||||
|  * Return: Same as with tpm_transmit_cmd. |  | ||||||
|  */ |  | ||||||
| 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_cmd(chip, payload, options, &blob_handle); |  | ||||||
| 	if (rc) |  | ||||||
| 		return rc; |  | ||||||
| 
 |  | ||||||
| 	rc = tpm2_unseal_cmd(chip, payload, options, blob_handle); |  | ||||||
| 	tpm2_flush_context(chip, blob_handle); |  | ||||||
| 	return rc; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| struct tpm2_get_cap_out { | struct tpm2_get_cap_out { | ||||||
| 	u8 more_data; | 	u8 more_data; | ||||||
| 	__be32 subcap_id; | 	__be32 subcap_id; | ||||||
|  |  | ||||||
|  | @ -40,6 +40,13 @@ int TSS_checkhmac1(unsigned char *buffer, | ||||||
| int trusted_tpm_send(unsigned char *cmd, size_t buflen); | int trusted_tpm_send(unsigned char *cmd, size_t buflen); | ||||||
| int oiap(struct tpm_buf *tb, uint32_t *handle, unsigned char *nonce); | int oiap(struct tpm_buf *tb, uint32_t *handle, unsigned char *nonce); | ||||||
| 
 | 
 | ||||||
|  | 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); | ||||||
|  | 
 | ||||||
| #define TPM_DEBUG 0 | #define TPM_DEBUG 0 | ||||||
| 
 | 
 | ||||||
| #if TPM_DEBUG | #if TPM_DEBUG | ||||||
|  |  | ||||||
|  | @ -296,6 +296,19 @@ struct tpm_buf { | ||||||
| 	u8 *data; | 	u8 *data; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | enum tpm2_object_attributes { | ||||||
|  | 	TPM2_OA_USER_WITH_AUTH		= BIT(6), | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | enum tpm2_session_attributes { | ||||||
|  | 	TPM2_SA_CONTINUE_SESSION	= BIT(0), | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct tpm2_hash { | ||||||
|  | 	unsigned int crypto_id; | ||||||
|  | 	unsigned int tpm_id; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| static inline void tpm_buf_reset(struct tpm_buf *buf, u16 tag, u32 ordinal) | static inline void tpm_buf_reset(struct tpm_buf *buf, u16 tag, u32 ordinal) | ||||||
| { | { | ||||||
| 	struct tpm_header *head = (struct tpm_header *)buf->data; | 	struct tpm_header *head = (struct tpm_header *)buf->data; | ||||||
|  | @ -375,6 +388,11 @@ static inline void tpm_buf_append_u32(struct tpm_buf *buf, const u32 value) | ||||||
| 	tpm_buf_append(buf, (u8 *) &value2, 4); | 	tpm_buf_append(buf, (u8 *) &value2, 4); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static inline u32 tpm2_rc_value(u32 rc) | ||||||
|  | { | ||||||
|  | 	return (rc & BIT(7)) ? rc & 0xff : rc; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| #if defined(CONFIG_TCG_TPM) || defined(CONFIG_TCG_TPM_MODULE) | #if defined(CONFIG_TCG_TPM) || defined(CONFIG_TCG_TPM_MODULE) | ||||||
| 
 | 
 | ||||||
| extern int tpm_is_tpm2(struct tpm_chip *chip); | extern int tpm_is_tpm2(struct tpm_chip *chip); | ||||||
|  | @ -384,12 +402,6 @@ extern int tpm_pcr_extend(struct tpm_chip *chip, u32 pcr_idx, | ||||||
| 			  struct tpm_digest *digests); | 			  struct tpm_digest *digests); | ||||||
| extern int tpm_send(struct tpm_chip *chip, void *cmd, size_t buflen); | extern int tpm_send(struct tpm_chip *chip, void *cmd, size_t buflen); | ||||||
| extern int tpm_get_random(struct tpm_chip *chip, u8 *data, size_t max); | extern int tpm_get_random(struct tpm_chip *chip, u8 *data, size_t max); | ||||||
| extern int tpm_seal_trusted(struct tpm_chip *chip, |  | ||||||
| 			    struct trusted_key_payload *payload, |  | ||||||
| 			    struct trusted_key_options *options); |  | ||||||
| extern int tpm_unseal_trusted(struct tpm_chip *chip, |  | ||||||
| 			      struct trusted_key_payload *payload, |  | ||||||
| 			      struct trusted_key_options *options); |  | ||||||
| extern struct tpm_chip *tpm_default_chip(void); | extern struct tpm_chip *tpm_default_chip(void); | ||||||
| #else | #else | ||||||
| static inline int tpm_is_tpm2(struct tpm_chip *chip) | static inline int tpm_is_tpm2(struct tpm_chip *chip) | ||||||
|  | @ -418,18 +430,6 @@ static inline int tpm_get_random(struct tpm_chip *chip, u8 *data, size_t max) | ||||||
| 	return -ENODEV; | 	return -ENODEV; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static inline int tpm_seal_trusted(struct tpm_chip *chip, |  | ||||||
| 				   struct trusted_key_payload *payload, |  | ||||||
| 				   struct trusted_key_options *options) |  | ||||||
| { |  | ||||||
| 	return -ENODEV; |  | ||||||
| } |  | ||||||
| static inline int tpm_unseal_trusted(struct tpm_chip *chip, |  | ||||||
| 				     struct trusted_key_payload *payload, |  | ||||||
| 				     struct trusted_key_options *options) |  | ||||||
| { |  | ||||||
| 	return -ENODEV; |  | ||||||
| } |  | ||||||
| static inline struct tpm_chip *tpm_default_chip(void) | static inline struct tpm_chip *tpm_default_chip(void) | ||||||
| { | { | ||||||
| 	return NULL; | 	return NULL; | ||||||
|  |  | ||||||
|  | @ -5,3 +5,4 @@ | ||||||
| 
 | 
 | ||||||
| obj-$(CONFIG_TRUSTED_KEYS) += trusted.o | obj-$(CONFIG_TRUSTED_KEYS) += trusted.o | ||||||
| trusted-y += trusted_tpm1.o | trusted-y += trusted_tpm1.o | ||||||
|  | trusted-y += trusted_tpm2.o | ||||||
|  |  | ||||||
|  | @ -1004,7 +1004,7 @@ static int trusted_instantiate(struct key *key, | ||||||
| 	switch (key_cmd) { | 	switch (key_cmd) { | ||||||
| 	case Opt_load: | 	case Opt_load: | ||||||
| 		if (tpm2) | 		if (tpm2) | ||||||
| 			ret = tpm_unseal_trusted(chip, payload, options); | 			ret = tpm2_unseal_trusted(chip, payload, options); | ||||||
| 		else | 		else | ||||||
| 			ret = key_unseal(payload, options); | 			ret = key_unseal(payload, options); | ||||||
| 		dump_payload(payload); | 		dump_payload(payload); | ||||||
|  | @ -1020,7 +1020,7 @@ static int trusted_instantiate(struct key *key, | ||||||
| 			goto out; | 			goto out; | ||||||
| 		} | 		} | ||||||
| 		if (tpm2) | 		if (tpm2) | ||||||
| 			ret = tpm_seal_trusted(chip, payload, options); | 			ret = tpm2_seal_trusted(chip, payload, options); | ||||||
| 		else | 		else | ||||||
| 			ret = key_seal(payload, options); | 			ret = key_seal(payload, options); | ||||||
| 		if (ret < 0) | 		if (ret < 0) | ||||||
|  |  | ||||||
							
								
								
									
										314
									
								
								security/keys/trusted-keys/trusted_tpm2.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										314
									
								
								security/keys/trusted-keys/trusted_tpm2.c
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,314 @@ | ||||||
|  | // SPDX-License-Identifier: GPL-2.0-only
 | ||||||
|  | /*
 | ||||||
|  |  * Copyright (C) 2004 IBM Corporation | ||||||
|  |  * Copyright (C) 2014 Intel Corporation | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | #include <linux/string.h> | ||||||
|  | #include <linux/err.h> | ||||||
|  | #include <linux/tpm.h> | ||||||
|  | #include <linux/tpm_command.h> | ||||||
|  | 
 | ||||||
|  | #include <keys/trusted-type.h> | ||||||
|  | #include <keys/trusted_tpm.h> | ||||||
|  | 
 | ||||||
|  | static struct tpm2_hash tpm2_hash_map[] = { | ||||||
|  | 	{HASH_ALGO_SHA1, TPM_ALG_SHA1}, | ||||||
|  | 	{HASH_ALGO_SHA256, TPM_ALG_SHA256}, | ||||||
|  | 	{HASH_ALGO_SHA384, TPM_ALG_SHA384}, | ||||||
|  | 	{HASH_ALGO_SHA512, TPM_ALG_SHA512}, | ||||||
|  | 	{HASH_ALGO_SM3_256, TPM_ALG_SM3_256}, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * tpm_buf_append_auth() - append TPMS_AUTH_COMMAND to the buffer. | ||||||
|  |  * | ||||||
|  |  * @buf: an allocated tpm_buf instance | ||||||
|  |  * @session_handle: session handle | ||||||
|  |  * @nonce: the session nonce, may be NULL if not used | ||||||
|  |  * @nonce_len: the session nonce length, may be 0 if not used | ||||||
|  |  * @attributes: the session attributes | ||||||
|  |  * @hmac: the session HMAC or password, may be NULL if not used | ||||||
|  |  * @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 the payload of a trusted key | ||||||
|  |  * | ||||||
|  |  * @chip: TPM chip to use | ||||||
|  |  * @payload: the key data in clear and encrypted form | ||||||
|  |  * @options: authentication values and other options | ||||||
|  |  * | ||||||
|  |  * Return: < 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; | ||||||
|  | 	u32 hash; | ||||||
|  | 	int i; | ||||||
|  | 	int rc; | ||||||
|  | 
 | ||||||
|  | 	for (i = 0; i < ARRAY_SIZE(tpm2_hash_map); i++) { | ||||||
|  | 		if (options->hash == tpm2_hash_map[i].crypto_id) { | ||||||
|  | 			hash = tpm2_hash_map[i].tpm_id; | ||||||
|  | 			break; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if (i == ARRAY_SIZE(tpm2_hash_map)) | ||||||
|  | 		return -EINVAL; | ||||||
|  | 
 | ||||||
|  | 	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 + 1); | ||||||
|  | 
 | ||||||
|  | 	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 + 1); | ||||||
|  | 	tpm_buf_append(&buf, payload->key, payload->key_len); | ||||||
|  | 	tpm_buf_append_u8(&buf, payload->migratable); | ||||||
|  | 
 | ||||||
|  | 	/* public */ | ||||||
|  | 	tpm_buf_append_u16(&buf, 14 + options->policydigest_len); | ||||||
|  | 	tpm_buf_append_u16(&buf, TPM_ALG_KEYEDHASH); | ||||||
|  | 	tpm_buf_append_u16(&buf, hash); | ||||||
|  | 
 | ||||||
|  | 	/* policy */ | ||||||
|  | 	if (options->policydigest_len) { | ||||||
|  | 		tpm_buf_append_u32(&buf, 0); | ||||||
|  | 		tpm_buf_append_u16(&buf, options->policydigest_len); | ||||||
|  | 		tpm_buf_append(&buf, options->policydigest, | ||||||
|  | 			       options->policydigest_len); | ||||||
|  | 	} else { | ||||||
|  | 		tpm_buf_append_u32(&buf, TPM2_OA_USER_WITH_AUTH); | ||||||
|  | 		tpm_buf_append_u16(&buf, 0); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	/* public parameters */ | ||||||
|  | 	tpm_buf_append_u16(&buf, TPM_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_send(chip, buf.data, tpm_buf_length(&buf)); | ||||||
|  | 	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; | ||||||
|  | 	} | ||||||
|  | 	if (tpm_buf_length(&buf) < TPM_HEADER_SIZE + 4 + blob_len) { | ||||||
|  | 		rc = -EFAULT; | ||||||
|  | 		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) { | ||||||
|  | 		if (tpm2_rc_value(rc) == TPM2_RC_HASH) | ||||||
|  | 			rc = -EINVAL; | ||||||
|  | 		else | ||||||
|  | 			rc = -EPERM; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return rc; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * tpm2_load_cmd() - execute a TPM2_Load command | ||||||
|  |  * | ||||||
|  |  * @chip: TPM chip to use | ||||||
|  |  * @payload: the key data in clear and encrypted form | ||||||
|  |  * @options: authentication values and other options | ||||||
|  |  * @blob_handle: returned blob handle | ||||||
|  |  * | ||||||
|  |  * Return: 0 on success. | ||||||
|  |  *        -E2BIG on wrong payload size. | ||||||
|  |  *        -EPERM on tpm error status. | ||||||
|  |  *        < 0 error from tpm_send. | ||||||
|  |  */ | ||||||
|  | static int tpm2_load_cmd(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_send(chip, buf.data, tpm_buf_length(&buf)); | ||||||
|  | 	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; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * tpm2_unseal_cmd() - execute a TPM2_Unload command | ||||||
|  |  * | ||||||
|  |  * @chip: TPM chip to use | ||||||
|  |  * @payload: the key data in clear and encrypted form | ||||||
|  |  * @options: authentication values and other options | ||||||
|  |  * @blob_handle: blob handle | ||||||
|  |  * | ||||||
|  |  * Return: 0 on success | ||||||
|  |  *         -EPERM on tpm error status | ||||||
|  |  *         < 0 error from tpm_send | ||||||
|  |  */ | ||||||
|  | static int tpm2_unseal_cmd(struct tpm_chip *chip, | ||||||
|  | 			   struct trusted_key_payload *payload, | ||||||
|  | 			   struct trusted_key_options *options, | ||||||
|  | 			   u32 blob_handle) | ||||||
|  | { | ||||||
|  | 	struct tpm_buf buf; | ||||||
|  | 	u16 data_len; | ||||||
|  | 	u8 *data; | ||||||
|  | 	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, | ||||||
|  | 			     options->policyhandle ? | ||||||
|  | 			     options->policyhandle : TPM2_RS_PW, | ||||||
|  | 			     NULL /* nonce */, 0, | ||||||
|  | 			     TPM2_SA_CONTINUE_SESSION, | ||||||
|  | 			     options->blobauth /* hmac */, | ||||||
|  | 			     TPM_DIGEST_SIZE); | ||||||
|  | 
 | ||||||
|  | 	rc = tpm_send(chip, buf.data, tpm_buf_length(&buf)); | ||||||
|  | 	if (rc > 0) | ||||||
|  | 		rc = -EPERM; | ||||||
|  | 
 | ||||||
|  | 	if (!rc) { | ||||||
|  | 		data_len = be16_to_cpup( | ||||||
|  | 			(__be16 *) &buf.data[TPM_HEADER_SIZE + 4]); | ||||||
|  | 		if (data_len < MIN_KEY_SIZE ||  data_len > MAX_KEY_SIZE + 1) { | ||||||
|  | 			rc = -EFAULT; | ||||||
|  | 			goto out; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		if (tpm_buf_length(&buf) < TPM_HEADER_SIZE + 6 + data_len) { | ||||||
|  | 			rc = -EFAULT; | ||||||
|  | 			goto out; | ||||||
|  | 		} | ||||||
|  | 		data = &buf.data[TPM_HEADER_SIZE + 6]; | ||||||
|  | 
 | ||||||
|  | 		memcpy(payload->key, data, data_len - 1); | ||||||
|  | 		payload->key_len = data_len - 1; | ||||||
|  | 		payload->migratable = data[data_len - 1]; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | out: | ||||||
|  | 	tpm_buf_destroy(&buf); | ||||||
|  | 	return rc; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * tpm2_unseal_trusted() - unseal the payload of a trusted key | ||||||
|  |  * | ||||||
|  |  * @chip: TPM chip to use | ||||||
|  |  * @payload: the key data in clear and encrypted form | ||||||
|  |  * @options: authentication values and other options | ||||||
|  |  * | ||||||
|  |  * Return: Same as with tpm_send. | ||||||
|  |  */ | ||||||
|  | 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_cmd(chip, payload, options, &blob_handle); | ||||||
|  | 	if (rc) | ||||||
|  | 		return rc; | ||||||
|  | 
 | ||||||
|  | 	rc = tpm2_unseal_cmd(chip, payload, options, blob_handle); | ||||||
|  | 
 | ||||||
|  | 	return rc; | ||||||
|  | } | ||||||
		Loading…
	
		Reference in a new issue
	
	 Sumit Garg
						Sumit Garg