tpm: add session encryption protection to tpm2_get_random()
authorJames Bottomley <James.Bottomley@HansenPartnership.com>
Mon, 29 Apr 2024 20:28:07 +0000 (16:28 -0400)
committerJarkko Sakkinen <jarkko@kernel.org>
Thu, 9 May 2024 19:30:51 +0000 (22:30 +0300)
If some entity is snooping the TPM bus, they can see the random
numbers we're extracting from the TPM and do prediction attacks
against their consumers.  Foil this attack by using response
encryption to prevent the attacker from seeing the random sequence.

Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
Reviewed-by: Jarkko Sakkinen <jarkko@kernel.org>
Tested-by: Jarkko Sakkinen <jarkko@kernel.org>
Signed-off-by: Jarkko Sakkinen <jarkko@kernel.org>
drivers/char/tpm/tpm2-cmd.c

index a53a843294ed14f3207db65c6b7efebad1d0021f..0cdf892ec2a7d40929787948dc146d432f74d70f 100644 (file)
@@ -292,25 +292,35 @@ int tpm2_get_random(struct tpm_chip *chip, u8 *dest, size_t max)
        if (!num_bytes || max > TPM_MAX_RNG_DATA)
                return -EINVAL;
 
-       err = tpm_buf_init(&buf, 0, 0);
+       err = tpm2_start_auth_session(chip);
        if (err)
                return err;
 
+       err = tpm_buf_init(&buf, 0, 0);
+       if (err) {
+               tpm2_end_auth_session(chip);
+               return err;
+       }
+
        do {
-               tpm_buf_reset(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_GET_RANDOM);
+               tpm_buf_reset(&buf, TPM2_ST_SESSIONS, TPM2_CC_GET_RANDOM);
+               tpm_buf_append_hmac_session_opt(chip, &buf, TPM2_SA_ENCRYPT
+                                               | TPM2_SA_CONTINUE_SESSION,
+                                               NULL, 0);
                tpm_buf_append_u16(&buf, num_bytes);
+               tpm_buf_fill_hmac_session(chip, &buf);
                err = tpm_transmit_cmd(chip, &buf,
                                       offsetof(struct tpm2_get_random_out,
                                                buffer),
                                       "attempting get random");
+               err = tpm_buf_check_hmac_response(chip, &buf, err);
                if (err) {
                        if (err > 0)
                                err = -EIO;
                        goto out;
                }
 
-               out = (struct tpm2_get_random_out *)
-                       &buf.data[TPM_HEADER_SIZE];
+               out = (struct tpm2_get_random_out *)tpm_buf_parameters(&buf);
                recd = min_t(u32, be16_to_cpu(out->size), num_bytes);
                if (tpm_buf_length(&buf) <
                    TPM_HEADER_SIZE +
@@ -327,9 +337,12 @@ int tpm2_get_random(struct tpm_chip *chip, u8 *dest, size_t max)
        } while (retries-- && total < max);
 
        tpm_buf_destroy(&buf);
+       tpm2_end_auth_session(chip);
+
        return total ? total : -EIO;
 out:
        tpm_buf_destroy(&buf);
+       tpm2_end_auth_session(chip);
        return err;
 }