// SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2018 [email protected] * * Cryptographic helper routines for handling TPM2 sessions for * authorization HMAC and request response encryption. * * The idea is to ensure that every TPM command is HMAC protected by a * session, meaning in-flight tampering would be detected and in * addition all sensitive inputs and responses should be encrypted. * * The basic way this works is to use a TPM feature called salted * sessions where a random secret used in session construction is * encrypted to the public part of a known TPM key. The problem is we * have no known keys, so initially a primary Elliptic Curve key is * derived from the NULL seed (we use EC because most TPMs generate * these keys much faster than RSA ones). The curve used is NIST_P256 * because that's now mandated to be present in 'TCG TPM v2.0 * Provisioning Guidance' * * Threat problems: the initial TPM2_CreatePrimary is not (and cannot * be) session protected, so a clever Man in the Middle could return a * public key they control to this command and from there intercept * and decode all subsequent session based transactions. The kernel * cannot mitigate this threat but, after boot, userspace can get * proof this has not happened by asking the TPM to certify the NULL * key. This certification would chain back to the TPM Endorsement * Certificate and prove the NULL seed primary had not been tampered * with and thus all sessions must have been cryptographically secure. * To assist with this, the initial NULL seed public key name is made * available in a sysfs file. * * Use of these functions: * * The design is all the crypto, hash and hmac gunk is confined in this * file and never needs to be seen even by the kernel internal user. To * the user there's an init function tpm2_sessions_init() that needs to * be called once per TPM which generates the NULL seed primary key. * * These are the usage functions: * * tpm2_start_auth_session() which allocates the opaque auth structure * and gets a session from the TPM. This must be called before * any of the following functions. The session is protected by a * session_key which is derived from a random salt value * encrypted to the NULL seed. * tpm2_end_auth_session() kills the session and frees the resources. * Under normal operation this function is done by * tpm_buf_check_hmac_response(), so this is only to be used on * error legs where the latter is not executed. * tpm_buf_append_name() to add a handle to the buffer. This must be * used in place of the usual tpm_buf_append_u32() for adding * handles because handles have to be processed specially when * calculating the HMAC. In particular, for NV, volatile and * permanent objects you now need to provide the name. * tpm_buf_append_hmac_session() which appends the hmac session to the * buf in the same way tpm_buf_append_auth does(). * tpm_buf_fill_hmac_session() This calculates the correct hash and * places it in the buffer. It must be called after the complete * command buffer is finalized so it can fill in the correct HMAC * based on the parameters. * tpm_buf_check_hmac_response() which checks the session response in * the buffer and calculates what it should be. If there's a * mismatch it will log a warning and return an error. If * tpm_buf_append_hmac_session() did not specify * TPM_SA_CONTINUE_SESSION then the session will be closed (if it * hasn't been consumed) and the auth structure freed. */ #include "tpm.h" #include <linux/random.h> #include <linux/scatterlist.h> #include <linux/unaligned.h> #include <crypto/kpp.h> #include <crypto/ecdh.h> #include <crypto/hash.h> #include <crypto/hmac.h> /* maximum number of names the TPM must remember for authorization */ #define AUTH_MAX_NAMES … #define AES_KEY_BYTES … #define AES_KEY_BITS … /* * This is the structure that carries all the auth information (like * session handle, nonces, session key and auth) from use to use it is * designed to be opaque to anything outside. */ struct tpm2_auth { … }; #ifdef CONFIG_TCG_TPM2_HMAC /* * Name Size based on TPM algorithm (assumes no hash bigger than 255) */ static u8 name_size(const u8 *name) { … } static int tpm2_parse_read_public(char *name, struct tpm_buf *buf) { … } static int tpm2_read_public(struct tpm_chip *chip, u32 handle, char *name) { … } #endif /* CONFIG_TCG_TPM2_HMAC */ /** * tpm_buf_append_name() - add a handle area to the buffer * @chip: the TPM chip structure * @buf: The buffer to be appended * @handle: The handle to be appended * @name: The name of the handle (may be NULL) * * In order to compute session HMACs, we need to know the names of the * objects pointed to by the handles. For most objects, this is simply * the actual 4 byte handle or an empty buf (in these cases @name * should be NULL) but for volatile objects, permanent objects and NV * areas, the name is defined as the hash (according to the name * algorithm which should be set to sha256) of the public area to * which the two byte algorithm id has been appended. For these * objects, the @name pointer should point to this. If a name is * required but @name is NULL, then TPM2_ReadPublic() will be called * on the handle to obtain the name. * * As with most tpm_buf operations, success is assumed because failure * will be caused by an incorrect programming model and indicated by a * kernel message. */ void tpm_buf_append_name(struct tpm_chip *chip, struct tpm_buf *buf, u32 handle, u8 *name) { … } EXPORT_SYMBOL_GPL(…); /** * tpm_buf_append_hmac_session() - Append a TPM session element * @chip: the TPM chip structure * @buf: The buffer to be appended * @attributes: The session attributes * @passphrase: The session authority (NULL if none) * @passphrase_len: The length of the session authority (0 if none) * * This fills in a session structure in the TPM command buffer, except * for the HMAC which cannot be computed until the command buffer is * complete. The type of session is controlled by the @attributes, * the main ones of which are TPM2_SA_CONTINUE_SESSION which means the * session won't terminate after tpm_buf_check_hmac_response(), * TPM2_SA_DECRYPT which means this buffers first parameter should be * encrypted with a session key and TPM2_SA_ENCRYPT, which means the * response buffer's first parameter needs to be decrypted (confusing, * but the defines are written from the point of view of the TPM). * * Any session appended by this command must be finalized by calling * tpm_buf_fill_hmac_session() otherwise the HMAC will be incorrect * and the TPM will reject the command. * * As with most tpm_buf operations, success is assumed because failure * will be caused by an incorrect programming model and indicated by a * kernel message. */ void tpm_buf_append_hmac_session(struct tpm_chip *chip, struct tpm_buf *buf, u8 attributes, u8 *passphrase, int passphrase_len) { … } EXPORT_SYMBOL_GPL(…); #ifdef CONFIG_TCG_TPM2_HMAC static int tpm2_create_primary(struct tpm_chip *chip, u32 hierarchy, u32 *handle, u8 *name); /* * It turns out the crypto hmac(sha256) is hard for us to consume * because it assumes a fixed key and the TPM seems to change the key * on every operation, so we weld the hmac init and final functions in * here to give it the same usage characteristics as a regular hash */ static void tpm2_hmac_init(struct sha256_state *sctx, u8 *key, u32 key_len) { … } static void tpm2_hmac_final(struct sha256_state *sctx, u8 *key, u32 key_len, u8 *out) { … } /* * assume hash sha256 and nonces u, v of size SHA256_DIGEST_SIZE but * otherwise standard tpm2_KDFa. Note output is in bytes not bits. */ static void tpm2_KDFa(u8 *key, u32 key_len, const char *label, u8 *u, u8 *v, u32 bytes, u8 *out) { … } /* * Somewhat of a bastardization of the real KDFe. We're assuming * we're working with known point sizes for the input parameters and * the hash algorithm is fixed at sha256. Because we know that the * point size is 32 bytes like the hash size, there's no need to loop * in this KDF. */ static void tpm2_KDFe(u8 z[EC_PT_SZ], const char *str, u8 *pt_u, u8 *pt_v, u8 *out) { … } static void tpm_buf_append_salt(struct tpm_buf *buf, struct tpm_chip *chip, struct tpm2_auth *auth) { … } /** * tpm_buf_fill_hmac_session() - finalize the session HMAC * @chip: the TPM chip structure * @buf: The buffer to be appended * * This command must not be called until all of the parameters have * been appended to @buf otherwise the computed HMAC will be * incorrect. * * This function computes and fills in the session HMAC using the * session key and, if TPM2_SA_DECRYPT was specified, computes the * encryption key and encrypts the first parameter of the command * buffer with it. * * As with most tpm_buf operations, success is assumed because failure * will be caused by an incorrect programming model and indicated by a * kernel message. */ void tpm_buf_fill_hmac_session(struct tpm_chip *chip, struct tpm_buf *buf) { … } EXPORT_SYMBOL(…); /** * tpm_buf_check_hmac_response() - check the TPM return HMAC for correctness * @chip: the TPM chip structure * @buf: the original command buffer (which now contains the response) * @rc: the return code from tpm_transmit_cmd * * If @rc is non zero, @buf may not contain an actual return, so @rc * is passed through as the return and the session cleaned up and * de-allocated if required (this is required if * TPM2_SA_CONTINUE_SESSION was not specified as a session flag). * * If @rc is zero, the response HMAC is computed against the returned * @buf and matched to the TPM one in the session area. If there is a * mismatch, an error is logged and -EINVAL returned. * * The reason for this is that the command issue and HMAC check * sequence should look like: * * rc = tpm_transmit_cmd(...); * rc = tpm_buf_check_hmac_response(&buf, auth, rc); * if (rc) * ... * * Which is easily layered into the current contrl flow. * * Returns: 0 on success or an error. */ int tpm_buf_check_hmac_response(struct tpm_chip *chip, struct tpm_buf *buf, int rc) { … } EXPORT_SYMBOL(…); /** * tpm2_end_auth_session() - kill the allocated auth session * @chip: the TPM chip structure * * ends the session started by tpm2_start_auth_session and frees all * the resources. Under normal conditions, * tpm_buf_check_hmac_response() will correctly end the session if * required, so this function is only for use in error legs that will * bypass the normal invocation of tpm_buf_check_hmac_response(). */ void tpm2_end_auth_session(struct tpm_chip *chip) { … } EXPORT_SYMBOL(…); static int tpm2_parse_start_auth_session(struct tpm2_auth *auth, struct tpm_buf *buf) { … } static int tpm2_load_null(struct tpm_chip *chip, u32 *null_key) { … } /** * tpm2_start_auth_session() - create a HMAC authentication session with the TPM * @chip: the TPM chip structure to create the session with * * This function loads the NULL seed from its saved context and starts * an authentication session on the null seed, fills in the * @chip->auth structure to contain all the session details necessary * for performing the HMAC, encrypt and decrypt operations and * returns. The NULL seed is flushed before this function returns. * * Return: zero on success or actual error encountered. */ int tpm2_start_auth_session(struct tpm_chip *chip) { … } EXPORT_SYMBOL(…); /* * A mask containing the object attributes for the kernel held null primary key * used in HMAC encryption. For more information on specific attributes look up * to "8.3 TPMA_OBJECT (Object Attributes)". */ #define TPM2_OA_NULL_KEY … /** * tpm2_parse_create_primary() - parse the data returned from TPM_CC_CREATE_PRIMARY * * @chip: The TPM the primary was created under * @buf: The response buffer from the chip * @handle: pointer to be filled in with the return handle of the primary * @hierarchy: The hierarchy the primary was created for * @name: pointer to be filled in with the primary key name * * Return: * * 0 - OK * * -errno - A system error * * TPM_RC - A TPM error */ static int tpm2_parse_create_primary(struct tpm_chip *chip, struct tpm_buf *buf, u32 *handle, u32 hierarchy, u8 *name) { … } /** * tpm2_create_primary() - create a primary key using a fixed P-256 template * * @chip: the TPM chip to create under * @hierarchy: The hierarchy handle to create under * @handle: The returned volatile handle on success * @name: The name of the returned key * * For platforms that might not have a persistent primary, this can be * used to create one quickly on the fly (it uses Elliptic Curve not * RSA, so even slow TPMs can create one fast). The template uses the * TCG mandated H one for non-endorsement ECC primaries, i.e. P-256 * elliptic curve (the only current one all TPM2s are required to * have) a sha256 name hash and no policy. * * Return: * * 0 - OK * * -errno - A system error * * TPM_RC - A TPM error */ static int tpm2_create_primary(struct tpm_chip *chip, u32 hierarchy, u32 *handle, u8 *name) { … } static int tpm2_create_null_primary(struct tpm_chip *chip) { … } /** * tpm2_sessions_init() - start of day initialization for the sessions code * @chip: TPM chip * * Derive and context save the null primary and allocate memory in the * struct tpm_chip for the authorizations. * * Return: * * 0 - OK * * -errno - A system error * * TPM_RC - A TPM error */ int tpm2_sessions_init(struct tpm_chip *chip) { … } EXPORT_SYMBOL(…); #endif /* CONFIG_TCG_TPM2_HMAC */