diff options
author | Linus Torvalds | 2024-05-13 10:40:15 -0700 |
---|---|---|
committer | Linus Torvalds | 2024-05-13 10:40:15 -0700 |
commit | b19239143e393d4b52b3b9a17c7ac07138f2cfd4 (patch) | |
tree | 61bf41aa899dae5e2e8ba3cdbe98a9a011220c90 /include | |
parent | c024814828f72b1ae9cc2c338997b2d9826c80f6 (diff) | |
parent | 1d479e3cd6520085832a6b432d521eeead2691ba (diff) |
Merge tag 'tpmdd-next-6.10-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/jarkko/linux-tpmdd
Pull TPM updates from Jarkko Sakkinen:
"These are the changes for the TPM driver with a single major new
feature: TPM bus encryption and integrity protection. The key pair on
TPM side is generated from so called null random seed per power on of
the machine [1]. This supports the TPM encryption of the hard drive by
adding layer of protection against bus interposer attacks.
Other than that, a few minor fixes and documentation for tpm_tis to
clarify basics of TPM localities for future patch review discussions
(will be extended and refined over times, just a seed)"
Link: https://lore.kernel.org/linux-integrity/20240429202811.13643-1-James.Bottomley@HansenPartnership.com/ [1]
* tag 'tpmdd-next-6.10-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/jarkko/linux-tpmdd: (28 commits)
Documentation: tpm: Add TPM security docs toctree entry
tpm: disable the TPM if NULL name changes
Documentation: add tpm-security.rst
tpm: add the null key name as a sysfs export
KEYS: trusted: Add session encryption protection to the seal/unseal path
tpm: add session encryption protection to tpm2_get_random()
tpm: add hmac checks to tpm2_pcr_extend()
tpm: Add the rest of the session HMAC API
tpm: Add HMAC session name/handle append
tpm: Add HMAC session start and end functions
tpm: Add TCG mandated Key Derivation Functions (KDFs)
tpm: Add NULL primary creation
tpm: export the context save and load commands
tpm: add buffer function to point to returned parameters
crypto: lib - implement library version of AES in CFB mode
KEYS: trusted: tpm2: Use struct tpm_buf for sized buffers
tpm: Add tpm_buf_read_{u8,u16,u32}
tpm: TPM2B formatted buffers
tpm: Store the length of the tpm_buf data separately.
tpm: Update struct tpm_buf documentation comments
...
Diffstat (limited to 'include')
-rw-r--r-- | include/crypto/aes.h | 5 | ||||
-rw-r--r-- | include/keys/trusted_tpm.h | 2 | ||||
-rw-r--r-- | include/linux/tpm.h | 316 |
3 files changed, 231 insertions, 92 deletions
diff --git a/include/crypto/aes.h b/include/crypto/aes.h index 2090729701ab..9339da7c20a8 100644 --- a/include/crypto/aes.h +++ b/include/crypto/aes.h @@ -87,4 +87,9 @@ void aes_decrypt(const struct crypto_aes_ctx *ctx, u8 *out, const u8 *in); extern const u8 crypto_aes_sbox[]; extern const u8 crypto_aes_inv_sbox[]; +void aescfb_encrypt(const struct crypto_aes_ctx *ctx, u8 *dst, const u8 *src, + int len, const u8 iv[AES_BLOCK_SIZE]); +void aescfb_decrypt(const struct crypto_aes_ctx *ctx, u8 *dst, const u8 *src, + int len, const u8 iv[AES_BLOCK_SIZE]); + #endif diff --git a/include/keys/trusted_tpm.h b/include/keys/trusted_tpm.h index 7769b726863a..a088b33fd0e3 100644 --- a/include/keys/trusted_tpm.h +++ b/include/keys/trusted_tpm.h @@ -6,8 +6,6 @@ #include <linux/tpm_command.h> /* implementation specific TPM constants */ -#define MAX_BUF_SIZE 1024 -#define TPM_GETRANDOM_SIZE 14 #define TPM_SIZE_OFFSET 2 #define TPM_RETURN_OFFSET 6 #define TPM_DATA_OFFSET 10 diff --git a/include/linux/tpm.h b/include/linux/tpm.h index 4ee9d13749ad..c17e4efbb2e5 100644 --- a/include/linux/tpm.h +++ b/include/linux/tpm.h @@ -23,6 +23,7 @@ #include <linux/fs.h> #include <linux/highmem.h> #include <crypto/hash_info.h> +#include <crypto/aes.h> #define TPM_DIGEST_SIZE 20 /* Max TPM v1.2 PCR size */ #define TPM_MAX_DIGEST_SIZE SHA512_DIGEST_SIZE @@ -30,17 +31,28 @@ struct tpm_chip; struct trusted_key_payload; struct trusted_key_options; +/* opaque structure, holds auth session parameters like the session key */ +struct tpm2_auth; + +enum tpm2_session_types { + TPM2_SE_HMAC = 0x00, + TPM2_SE_POLICY = 0x01, + TPM2_SE_TRIAL = 0x02, +}; /* if you add a new hash to this, increment TPM_MAX_HASHES below */ enum tpm_algorithms { TPM_ALG_ERROR = 0x0000, TPM_ALG_SHA1 = 0x0004, + TPM_ALG_AES = 0x0006, TPM_ALG_KEYEDHASH = 0x0008, TPM_ALG_SHA256 = 0x000B, TPM_ALG_SHA384 = 0x000C, TPM_ALG_SHA512 = 0x000D, TPM_ALG_NULL = 0x0010, TPM_ALG_SM3_256 = 0x0012, + TPM_ALG_ECC = 0x0023, + TPM_ALG_CFB = 0x0043, }; /* @@ -49,6 +61,11 @@ enum tpm_algorithms { */ #define TPM_MAX_HASHES 5 +enum tpm2_curves { + TPM2_ECC_NONE = 0x0000, + TPM2_ECC_NIST_P256 = 0x0003, +}; + struct tpm_digest { u16 alg_id; u8 digest[TPM_MAX_DIGEST_SIZE]; @@ -116,6 +133,20 @@ struct tpm_chip_seqops { const struct seq_operations *seqops; }; +/* fixed define for the curve we use which is NIST_P256 */ +#define EC_PT_SZ 32 + +/* + * fixed define for the size of a name. This is actually HASHALG size + * plus 2, so 32 for SHA256 + */ +#define TPM2_NAME_SIZE 34 + +/* + * The maximum size for an object context + */ +#define TPM2_MAX_CONTEXT_SIZE 4096 + struct tpm_chip { struct device dev; struct device devs; @@ -170,6 +201,18 @@ struct tpm_chip { /* active locality */ int locality; + +#ifdef CONFIG_TCG_TPM2_HMAC + /* details for communication security via sessions */ + + /* saved context for NULL seed */ + u8 null_key_context[TPM2_MAX_CONTEXT_SIZE]; + /* name of NULL seed */ + u8 null_key_name[TPM2_NAME_SIZE]; + u8 null_ec_key_x[EC_PT_SZ]; + u8 null_ec_key_y[EC_PT_SZ]; + struct tpm2_auth *auth; +#endif }; #define TPM_HEADER_SIZE 10 @@ -194,6 +237,7 @@ enum tpm2_timeouts { enum tpm2_structures { TPM2_ST_NO_SESSIONS = 0x8001, TPM2_ST_SESSIONS = 0x8002, + TPM2_ST_CREATION = 0x8021, }; /* Indicates from what layer of the software stack the error comes from */ @@ -204,6 +248,7 @@ enum tpm2_return_codes { TPM2_RC_SUCCESS = 0x0000, TPM2_RC_HASH = 0x0083, /* RC_FMT1 */ TPM2_RC_HANDLE = 0x008B, + TPM2_RC_INTEGRITY = 0x009F, TPM2_RC_INITIALIZE = 0x0100, /* RC_VER1 */ TPM2_RC_FAILURE = 0x0101, TPM2_RC_DISABLED = 0x0120, @@ -231,6 +276,8 @@ enum tpm2_command_codes { TPM2_CC_CONTEXT_LOAD = 0x0161, TPM2_CC_CONTEXT_SAVE = 0x0162, TPM2_CC_FLUSH_CONTEXT = 0x0165, + TPM2_CC_READ_PUBLIC = 0x0173, + TPM2_CC_START_AUTH_SESS = 0x0176, TPM2_CC_VERIFY_SIGNATURE = 0x0177, TPM2_CC_GET_CAPABILITY = 0x017A, TPM2_CC_GET_RANDOM = 0x017B, @@ -243,9 +290,25 @@ enum tpm2_command_codes { }; enum tpm2_permanent_handles { + TPM2_RH_NULL = 0x40000007, TPM2_RS_PW = 0x40000009, }; +/* Most Significant Octet for key types */ +enum tpm2_mso_type { + TPM2_MSO_NVRAM = 0x01, + TPM2_MSO_SESSION = 0x02, + TPM2_MSO_POLICY = 0x03, + TPM2_MSO_PERMANENT = 0x40, + TPM2_MSO_VOLATILE = 0x80, + TPM2_MSO_PERSISTENT = 0x81, +}; + +static inline enum tpm2_mso_type tpm2_handle_mso(u32 handle) +{ + return handle >> 24; +} + enum tpm2_capabilities { TPM2_CAP_HANDLES = 1, TPM2_CAP_COMMANDS = 2, @@ -284,6 +347,7 @@ enum tpm_chip_flags { TPM_CHIP_FLAG_FIRMWARE_UPGRADE = BIT(7), TPM_CHIP_FLAG_SUSPENDED = BIT(8), TPM_CHIP_FLAG_HWRNG_DISABLED = BIT(9), + TPM_CHIP_FLAG_DISABLE = BIT(10), }; #define to_tpm_chip(d) container_of(d, struct tpm_chip, dev) @@ -297,28 +361,61 @@ struct tpm_header { }; } __packed; -/* A string buffer type for constructing TPM commands. This is based on the - * ideas of string buffer code in security/keys/trusted.h but is heap based - * in order to keep the stack usage minimal. - */ - enum tpm_buf_flags { + /* the capacity exceeded: */ TPM_BUF_OVERFLOW = BIT(0), + /* TPM2B format: */ + TPM_BUF_TPM2B = BIT(1), + /* read out of boundary: */ + TPM_BUF_BOUNDARY_ERROR = BIT(2), }; +/* + * A string buffer type for constructing TPM commands. + */ struct tpm_buf { - unsigned int flags; + u32 flags; + u32 length; u8 *data; + u8 handles; }; enum tpm2_object_attributes { TPM2_OA_FIXED_TPM = BIT(1), + TPM2_OA_ST_CLEAR = BIT(2), TPM2_OA_FIXED_PARENT = BIT(4), + TPM2_OA_SENSITIVE_DATA_ORIGIN = BIT(5), TPM2_OA_USER_WITH_AUTH = BIT(6), + TPM2_OA_ADMIN_WITH_POLICY = BIT(7), + TPM2_OA_NO_DA = BIT(10), + TPM2_OA_ENCRYPTED_DUPLICATION = BIT(11), + TPM2_OA_RESTRICTED = BIT(16), + TPM2_OA_DECRYPT = BIT(17), + TPM2_OA_SIGN = BIT(18), }; +/* + * definitions for the canonical template. These are mandated + * by the TCG key template documents + */ + +#define AES_KEY_BYTES AES_KEYSIZE_128 +#define AES_KEY_BITS (AES_KEY_BYTES*8) +#define TPM2_OA_TMPL (TPM2_OA_NO_DA | \ + TPM2_OA_FIXED_TPM | \ + TPM2_OA_FIXED_PARENT | \ + TPM2_OA_SENSITIVE_DATA_ORIGIN | \ + TPM2_OA_USER_WITH_AUTH | \ + TPM2_OA_DECRYPT | \ + TPM2_OA_RESTRICTED) + enum tpm2_session_attributes { TPM2_SA_CONTINUE_SESSION = BIT(0), + TPM2_SA_AUDIT_EXCLUSIVE = BIT(1), + TPM2_SA_AUDIT_RESET = BIT(3), + TPM2_SA_DECRYPT = BIT(5), + TPM2_SA_ENCRYPT = BIT(6), + TPM2_SA_AUDIT = BIT(7), }; struct tpm2_hash { @@ -326,84 +423,21 @@ struct tpm2_hash { unsigned int tpm_id; }; -static inline void tpm_buf_reset(struct tpm_buf *buf, u16 tag, u32 ordinal) -{ - struct tpm_header *head = (struct tpm_header *)buf->data; - - head->tag = cpu_to_be16(tag); - head->length = cpu_to_be32(sizeof(*head)); - head->ordinal = cpu_to_be32(ordinal); -} - -static inline int tpm_buf_init(struct tpm_buf *buf, u16 tag, u32 ordinal) -{ - buf->data = (u8 *)__get_free_page(GFP_KERNEL); - if (!buf->data) - return -ENOMEM; - - buf->flags = 0; - tpm_buf_reset(buf, tag, ordinal); - return 0; -} - -static inline void tpm_buf_destroy(struct tpm_buf *buf) -{ - free_page((unsigned long)buf->data); -} - -static inline u32 tpm_buf_length(struct tpm_buf *buf) -{ - struct tpm_header *head = (struct tpm_header *)buf->data; - - return be32_to_cpu(head->length); -} - -static inline u16 tpm_buf_tag(struct tpm_buf *buf) -{ - struct tpm_header *head = (struct tpm_header *)buf->data; - - return be16_to_cpu(head->tag); -} - -static inline void tpm_buf_append(struct tpm_buf *buf, - const unsigned char *new_data, - unsigned int new_len) -{ - struct tpm_header *head = (struct tpm_header *)buf->data; - u32 len = tpm_buf_length(buf); - - /* Return silently if overflow has already happened. */ - if (buf->flags & TPM_BUF_OVERFLOW) - return; - - if ((len + new_len) > PAGE_SIZE) { - WARN(1, "tpm_buf: overflow\n"); - buf->flags |= TPM_BUF_OVERFLOW; - return; - } - - memcpy(&buf->data[len], new_data, new_len); - head->length = cpu_to_be32(len + new_len); -} - -static inline void tpm_buf_append_u8(struct tpm_buf *buf, const u8 value) -{ - tpm_buf_append(buf, &value, 1); -} - -static inline void tpm_buf_append_u16(struct tpm_buf *buf, const u16 value) -{ - __be16 value2 = cpu_to_be16(value); - - tpm_buf_append(buf, (u8 *) &value2, 2); -} - -static inline void tpm_buf_append_u32(struct tpm_buf *buf, const u32 value) -{ - __be32 value2 = cpu_to_be32(value); - - tpm_buf_append(buf, (u8 *) &value2, 4); -} +int tpm_buf_init(struct tpm_buf *buf, u16 tag, u32 ordinal); +void tpm_buf_reset(struct tpm_buf *buf, u16 tag, u32 ordinal); +int tpm_buf_init_sized(struct tpm_buf *buf); +void tpm_buf_reset_sized(struct tpm_buf *buf); +void tpm_buf_destroy(struct tpm_buf *buf); +u32 tpm_buf_length(struct tpm_buf *buf); +void tpm_buf_append(struct tpm_buf *buf, const u8 *new_data, u16 new_length); +void tpm_buf_append_u8(struct tpm_buf *buf, const u8 value); +void tpm_buf_append_u16(struct tpm_buf *buf, const u16 value); +void tpm_buf_append_u32(struct tpm_buf *buf, const u32 value); +u8 tpm_buf_read_u8(struct tpm_buf *buf, off_t *offset); +u16 tpm_buf_read_u16(struct tpm_buf *buf, off_t *offset); +u32 tpm_buf_read_u32(struct tpm_buf *buf, off_t *offset); + +u8 *tpm_buf_parameters(struct tpm_buf *buf); /* * Check if TPM device is in the firmware upgrade mode. @@ -415,7 +449,7 @@ static inline bool tpm_is_firmware_upgrade(struct tpm_chip *chip) static inline u32 tpm2_rc_value(u32 rc) { - return (rc & BIT(7)) ? rc & 0xff : rc; + return (rc & BIT(7)) ? rc & 0xbf : rc; } #if defined(CONFIG_TCG_TPM) || defined(CONFIG_TCG_TPM_MODULE) @@ -429,10 +463,19 @@ extern int tpm_pcr_read(struct tpm_chip *chip, u32 pcr_idx, struct tpm_digest *digest); extern int tpm_pcr_extend(struct tpm_chip *chip, u32 pcr_idx, struct tpm_digest *digests); -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 struct tpm_chip *tpm_default_chip(void); void tpm2_flush_context(struct tpm_chip *chip, u32 handle); + +static inline void tpm_buf_append_empty_auth(struct tpm_buf *buf, u32 handle) +{ + /* simple authorization for empty auth */ + tpm_buf_append_u32(buf, 9); /* total length of auth */ + tpm_buf_append_u32(buf, handle); + tpm_buf_append_u16(buf, 0); /* nonce len */ + tpm_buf_append_u8(buf, 0); /* attributes */ + tpm_buf_append_u16(buf, 0); /* hmac len */ +} #else static inline int tpm_is_tpm2(struct tpm_chip *chip) { @@ -450,10 +493,6 @@ static inline int tpm_pcr_extend(struct tpm_chip *chip, u32 pcr_idx, return -ENODEV; } -static inline int tpm_send(struct tpm_chip *chip, void *cmd, size_t buflen) -{ - return -ENODEV; -} static inline int tpm_get_random(struct tpm_chip *chip, u8 *data, size_t max) { return -ENODEV; @@ -463,5 +502,102 @@ static inline struct tpm_chip *tpm_default_chip(void) { return NULL; } + +static inline void tpm_buf_append_empty_auth(struct tpm_buf *buf, u32 handle) +{ +} #endif +#ifdef CONFIG_TCG_TPM2_HMAC + +int tpm2_start_auth_session(struct tpm_chip *chip); +void tpm_buf_append_name(struct tpm_chip *chip, struct tpm_buf *buf, + u32 handle, u8 *name); +void tpm_buf_append_hmac_session(struct tpm_chip *chip, struct tpm_buf *buf, + u8 attributes, u8 *passphrase, + int passphraselen); +static inline void tpm_buf_append_hmac_session_opt(struct tpm_chip *chip, + struct tpm_buf *buf, + u8 attributes, + u8 *passphrase, + int passphraselen) +{ + tpm_buf_append_hmac_session(chip, buf, attributes, passphrase, + passphraselen); +} +void tpm_buf_fill_hmac_session(struct tpm_chip *chip, struct tpm_buf *buf); +int tpm_buf_check_hmac_response(struct tpm_chip *chip, struct tpm_buf *buf, + int rc); +void tpm2_end_auth_session(struct tpm_chip *chip); +#else +#include <asm/unaligned.h> + +static inline int tpm2_start_auth_session(struct tpm_chip *chip) +{ + return 0; +} +static inline void tpm2_end_auth_session(struct tpm_chip *chip) +{ +} +static inline void tpm_buf_append_name(struct tpm_chip *chip, + struct tpm_buf *buf, + u32 handle, u8 *name) +{ + tpm_buf_append_u32(buf, handle); + /* count the number of handles in the upper bits of flags */ + buf->handles++; +} +static inline void tpm_buf_append_hmac_session(struct tpm_chip *chip, + struct tpm_buf *buf, + u8 attributes, u8 *passphrase, + int passphraselen) +{ + /* offset tells us where the sessions area begins */ + int offset = buf->handles * 4 + TPM_HEADER_SIZE; + u32 len = 9 + passphraselen; + + if (tpm_buf_length(buf) != offset) { + /* not the first session so update the existing length */ + len += get_unaligned_be32(&buf->data[offset]); + put_unaligned_be32(len, &buf->data[offset]); + } else { + tpm_buf_append_u32(buf, len); + } + /* auth handle */ + tpm_buf_append_u32(buf, TPM2_RS_PW); + /* nonce */ + tpm_buf_append_u16(buf, 0); + /* attributes */ + tpm_buf_append_u8(buf, 0); + /* passphrase */ + tpm_buf_append_u16(buf, passphraselen); + tpm_buf_append(buf, passphrase, passphraselen); +} +static inline void tpm_buf_append_hmac_session_opt(struct tpm_chip *chip, + struct tpm_buf *buf, + u8 attributes, + u8 *passphrase, + int passphraselen) +{ + int offset = buf->handles * 4 + TPM_HEADER_SIZE; + struct tpm_header *head = (struct tpm_header *) buf->data; + + /* + * if the only sessions are optional, the command tag + * must change to TPM2_ST_NO_SESSIONS + */ + if (tpm_buf_length(buf) == offset) + head->tag = cpu_to_be16(TPM2_ST_NO_SESSIONS); +} +static inline void tpm_buf_fill_hmac_session(struct tpm_chip *chip, + struct tpm_buf *buf) +{ +} +static inline int tpm_buf_check_hmac_response(struct tpm_chip *chip, + struct tpm_buf *buf, + int rc) +{ + return rc; +} +#endif /* CONFIG_TCG_TPM2_HMAC */ + #endif |