mirror of
git://git.yoctoproject.org/linux-yocto.git
synced 2025-08-21 16:31:14 +02:00
tpm: Address !chip->auth in tpm_buf_append_hmac_session*()
Unless tpm_chip_bootstrap() was called by the driver, !chip->auth can
cause a null derefence in tpm_buf_hmac_session*(). Thus, address
!chip->auth in tpm_buf_hmac_session*() and remove the fallback
implementation for !TCG_TPM2_HMAC.
Cc: stable@vger.kernel.org # v6.9+
Reported-by: Stefan Berger <stefanb@linux.ibm.com>
Closes: https://lore.kernel.org/linux-integrity/20240617193408.1234365-1-stefanb@linux.ibm.com/
Fixes: 1085b8276b
("tpm: Add the rest of the session HMAC API")
Tested-by: Michael Ellerman <mpe@ellerman.id.au> # ppc
Signed-off-by: Jarkko Sakkinen <jarkko@kernel.org>
This commit is contained in:
parent
a61809a332
commit
7ca110f267
|
@ -272,6 +272,110 @@ void tpm_buf_append_name(struct tpm_chip *chip, struct tpm_buf *buf,
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(tpm_buf_append_name);
|
EXPORT_SYMBOL_GPL(tpm_buf_append_name);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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)
|
||||||
|
{
|
||||||
|
#ifdef CONFIG_TCG_TPM2_HMAC
|
||||||
|
u8 nonce[SHA256_DIGEST_SIZE];
|
||||||
|
struct tpm2_auth *auth;
|
||||||
|
u32 len;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (!tpm2_chip_auth(chip)) {
|
||||||
|
/* offset tells us where the sessions area begins */
|
||||||
|
int offset = buf->handles * 4 + TPM_HEADER_SIZE;
|
||||||
|
u32 len = 9 + passphrase_len;
|
||||||
|
|
||||||
|
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, passphrase_len);
|
||||||
|
tpm_buf_append(buf, passphrase, passphrase_len);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_TCG_TPM2_HMAC
|
||||||
|
/*
|
||||||
|
* The Architecture Guide requires us to strip trailing zeros
|
||||||
|
* before computing the HMAC
|
||||||
|
*/
|
||||||
|
while (passphrase && passphrase_len > 0 && passphrase[passphrase_len - 1] == '\0')
|
||||||
|
passphrase_len--;
|
||||||
|
|
||||||
|
auth = chip->auth;
|
||||||
|
auth->attrs = attributes;
|
||||||
|
auth->passphrase_len = passphrase_len;
|
||||||
|
if (passphrase_len)
|
||||||
|
memcpy(auth->passphrase, passphrase, passphrase_len);
|
||||||
|
|
||||||
|
if (auth->session != tpm_buf_length(buf)) {
|
||||||
|
/* we're not the first session */
|
||||||
|
len = get_unaligned_be32(&buf->data[auth->session]);
|
||||||
|
if (4 + len + auth->session != tpm_buf_length(buf)) {
|
||||||
|
WARN(1, "session length mismatch, cannot append");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* add our new session */
|
||||||
|
len += 9 + 2 * SHA256_DIGEST_SIZE;
|
||||||
|
put_unaligned_be32(len, &buf->data[auth->session]);
|
||||||
|
} else {
|
||||||
|
tpm_buf_append_u32(buf, 9 + 2 * SHA256_DIGEST_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* random number for our nonce */
|
||||||
|
get_random_bytes(nonce, sizeof(nonce));
|
||||||
|
memcpy(auth->our_nonce, nonce, sizeof(nonce));
|
||||||
|
tpm_buf_append_u32(buf, auth->handle);
|
||||||
|
/* our new nonce */
|
||||||
|
tpm_buf_append_u16(buf, SHA256_DIGEST_SIZE);
|
||||||
|
tpm_buf_append(buf, nonce, SHA256_DIGEST_SIZE);
|
||||||
|
tpm_buf_append_u8(buf, auth->attrs);
|
||||||
|
/* and put a placeholder for the hmac */
|
||||||
|
tpm_buf_append_u16(buf, SHA256_DIGEST_SIZE);
|
||||||
|
tpm_buf_append(buf, nonce, SHA256_DIGEST_SIZE);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(tpm_buf_append_hmac_session);
|
||||||
|
|
||||||
#ifdef CONFIG_TCG_TPM2_HMAC
|
#ifdef CONFIG_TCG_TPM2_HMAC
|
||||||
|
|
||||||
static int tpm2_create_primary(struct tpm_chip *chip, u32 hierarchy,
|
static int tpm2_create_primary(struct tpm_chip *chip, u32 hierarchy,
|
||||||
|
@ -457,82 +561,6 @@ static void tpm_buf_append_salt(struct tpm_buf *buf, struct tpm_chip *chip)
|
||||||
crypto_free_kpp(kpp);
|
crypto_free_kpp(kpp);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 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)
|
|
||||||
{
|
|
||||||
u8 nonce[SHA256_DIGEST_SIZE];
|
|
||||||
u32 len;
|
|
||||||
struct tpm2_auth *auth = chip->auth;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The Architecture Guide requires us to strip trailing zeros
|
|
||||||
* before computing the HMAC
|
|
||||||
*/
|
|
||||||
while (passphrase && passphrase_len > 0
|
|
||||||
&& passphrase[passphrase_len - 1] == '\0')
|
|
||||||
passphrase_len--;
|
|
||||||
|
|
||||||
auth->attrs = attributes;
|
|
||||||
auth->passphrase_len = passphrase_len;
|
|
||||||
if (passphrase_len)
|
|
||||||
memcpy(auth->passphrase, passphrase, passphrase_len);
|
|
||||||
|
|
||||||
if (auth->session != tpm_buf_length(buf)) {
|
|
||||||
/* we're not the first session */
|
|
||||||
len = get_unaligned_be32(&buf->data[auth->session]);
|
|
||||||
if (4 + len + auth->session != tpm_buf_length(buf)) {
|
|
||||||
WARN(1, "session length mismatch, cannot append");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* add our new session */
|
|
||||||
len += 9 + 2 * SHA256_DIGEST_SIZE;
|
|
||||||
put_unaligned_be32(len, &buf->data[auth->session]);
|
|
||||||
} else {
|
|
||||||
tpm_buf_append_u32(buf, 9 + 2 * SHA256_DIGEST_SIZE);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* random number for our nonce */
|
|
||||||
get_random_bytes(nonce, sizeof(nonce));
|
|
||||||
memcpy(auth->our_nonce, nonce, sizeof(nonce));
|
|
||||||
tpm_buf_append_u32(buf, auth->handle);
|
|
||||||
/* our new nonce */
|
|
||||||
tpm_buf_append_u16(buf, SHA256_DIGEST_SIZE);
|
|
||||||
tpm_buf_append(buf, nonce, SHA256_DIGEST_SIZE);
|
|
||||||
tpm_buf_append_u8(buf, auth->attrs);
|
|
||||||
/* and put a placeholder for the hmac */
|
|
||||||
tpm_buf_append_u16(buf, SHA256_DIGEST_SIZE);
|
|
||||||
tpm_buf_append(buf, nonce, SHA256_DIGEST_SIZE);
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL(tpm_buf_append_hmac_session);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* tpm_buf_fill_hmac_session() - finalize the session HMAC
|
* tpm_buf_fill_hmac_session() - finalize the session HMAC
|
||||||
* @chip: the TPM chip structure
|
* @chip: the TPM chip structure
|
||||||
|
@ -563,6 +591,9 @@ void tpm_buf_fill_hmac_session(struct tpm_chip *chip, struct tpm_buf *buf)
|
||||||
u8 cphash[SHA256_DIGEST_SIZE];
|
u8 cphash[SHA256_DIGEST_SIZE];
|
||||||
struct sha256_state sctx;
|
struct sha256_state sctx;
|
||||||
|
|
||||||
|
if (!auth)
|
||||||
|
return;
|
||||||
|
|
||||||
/* save the command code in BE format */
|
/* save the command code in BE format */
|
||||||
auth->ordinal = head->ordinal;
|
auth->ordinal = head->ordinal;
|
||||||
|
|
||||||
|
@ -721,6 +752,9 @@ int tpm_buf_check_hmac_response(struct tpm_chip *chip, struct tpm_buf *buf,
|
||||||
u32 cc = be32_to_cpu(auth->ordinal);
|
u32 cc = be32_to_cpu(auth->ordinal);
|
||||||
int parm_len, len, i, handles;
|
int parm_len, len, i, handles;
|
||||||
|
|
||||||
|
if (!auth)
|
||||||
|
return rc;
|
||||||
|
|
||||||
if (auth->session >= TPM_HEADER_SIZE) {
|
if (auth->session >= TPM_HEADER_SIZE) {
|
||||||
WARN(1, "tpm session not filled correctly\n");
|
WARN(1, "tpm session not filled correctly\n");
|
||||||
goto out;
|
goto out;
|
||||||
|
|
|
@ -502,10 +502,6 @@ static inline struct tpm2_auth *tpm2_chip_auth(struct tpm_chip *chip)
|
||||||
|
|
||||||
void tpm_buf_append_name(struct tpm_chip *chip, struct tpm_buf *buf,
|
void tpm_buf_append_name(struct tpm_chip *chip, struct tpm_buf *buf,
|
||||||
u32 handle, u8 *name);
|
u32 handle, u8 *name);
|
||||||
|
|
||||||
#ifdef CONFIG_TCG_TPM2_HMAC
|
|
||||||
|
|
||||||
int tpm2_start_auth_session(struct tpm_chip *chip);
|
|
||||||
void tpm_buf_append_hmac_session(struct tpm_chip *chip, struct tpm_buf *buf,
|
void tpm_buf_append_hmac_session(struct tpm_chip *chip, struct tpm_buf *buf,
|
||||||
u8 attributes, u8 *passphrase,
|
u8 attributes, u8 *passphrase,
|
||||||
int passphraselen);
|
int passphraselen);
|
||||||
|
@ -515,9 +511,27 @@ static inline void tpm_buf_append_hmac_session_opt(struct tpm_chip *chip,
|
||||||
u8 *passphrase,
|
u8 *passphrase,
|
||||||
int passphraselen)
|
int passphraselen)
|
||||||
{
|
{
|
||||||
tpm_buf_append_hmac_session(chip, buf, attributes, passphrase,
|
struct tpm_header *head;
|
||||||
passphraselen);
|
int offset;
|
||||||
|
|
||||||
|
if (tpm2_chip_auth(chip)) {
|
||||||
|
tpm_buf_append_hmac_session(chip, buf, attributes, passphrase, passphraselen);
|
||||||
|
} else {
|
||||||
|
offset = buf->handles * 4 + TPM_HEADER_SIZE;
|
||||||
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_TCG_TPM2_HMAC
|
||||||
|
|
||||||
|
int tpm2_start_auth_session(struct tpm_chip *chip);
|
||||||
void tpm_buf_fill_hmac_session(struct tpm_chip *chip, struct tpm_buf *buf);
|
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 tpm_buf_check_hmac_response(struct tpm_chip *chip, struct tpm_buf *buf,
|
||||||
int rc);
|
int rc);
|
||||||
|
@ -532,48 +546,6 @@ static inline int tpm2_start_auth_session(struct tpm_chip *chip)
|
||||||
static inline void tpm2_end_auth_session(struct tpm_chip *chip)
|
static inline void tpm2_end_auth_session(struct tpm_chip *chip)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
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,
|
static inline void tpm_buf_fill_hmac_session(struct tpm_chip *chip,
|
||||||
struct tpm_buf *buf)
|
struct tpm_buf *buf)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue
Block a user