Implemented TPM2 support for tpm_get_random().

Signed-off-by: Jarkko Sakkinen <[email protected]>
---
 drivers/char/tpm/tpm-interface.c |  6 ++++++
 drivers/char/tpm/tpm.h           | 11 ++++++++++
 drivers/char/tpm/tpm2-commands.c | 45 ++++++++++++++++++++++++++++++++++++++++
 drivers/char/tpm/tpm2.h          |  2 ++
 4 files changed, 64 insertions(+)

diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c
index ed23ba3..3d4a664 100644
--- a/drivers/char/tpm/tpm-interface.c
+++ b/drivers/char/tpm/tpm-interface.c
@@ -1002,6 +1002,12 @@ int tpm_get_random(u32 chip_num, u8 *out, size_t max)
        if (chip == NULL)
                return -ENODEV;
 
+       if (chip->tpm2) {
+               err = tpm2_get_random(chip, out, max);
+               tpm_chip_put(chip);
+               return err;
+       }
+
        do {
                tpm_cmd.header.in = tpm_getrandom_header;
                tpm_cmd.params.getrandom_in.num_bytes = cpu_to_be32(num_bytes);
diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h
index 4637342..b4c0d5d 100644
--- a/drivers/char/tpm/tpm.h
+++ b/drivers/char/tpm/tpm.h
@@ -351,6 +351,15 @@ struct tpm2_get_tpm_pt_out {
        __be32  value;
 } __packed;
 
+struct tpm2_get_random_in {
+       __be16  size;
+} __packed;
+
+struct tpm2_get_random_out {
+       __be16  size;
+       u8      buffer[TPM_MAX_RNG_DATA];
+} __packed;
+
 typedef union {
        struct  tpm_getcap_params_out getcap_out;
        struct  tpm_readpubek_params_out readpubek_out;
@@ -368,6 +377,8 @@ typedef union {
        struct  tpm2_self_test_in tpm2_selftest_in;
        struct  tpm2_get_tpm_pt_in tpm2_get_tpm_pt_in;
        struct  tpm2_get_tpm_pt_out tpm2_get_tpm_pt_out;
+       struct  tpm2_get_random_in tpm2_getrandom_in;
+       struct  tpm2_get_random_out tpm2_getrandom_out;
 } tpm_cmd_params;
 
 struct tpm_cmd_t {
diff --git a/drivers/char/tpm/tpm2-commands.c b/drivers/char/tpm/tpm2-commands.c
index b69999e..90cebb2 100644
--- a/drivers/char/tpm/tpm2-commands.c
+++ b/drivers/char/tpm/tpm2-commands.c
@@ -349,3 +349,48 @@ int tpm2_do_selftest(struct tpm_chip *chip)
 
        return rc;
 }
+
+static struct tpm_input_header tpm2_getrandom_header = {
+       .tag = cpu_to_be16(TPM2_ST_NO_SESSIONS),
+       .length = cpu_to_be32(sizeof(struct tpm_input_header) +
+                             sizeof(struct tpm2_get_random_in)),
+       .ordinal = cpu_to_be32(TPM2_CC_GET_RANDOM)
+};
+
+/**
+ * tpm2_get_random() - get random bytes from the TPM RNG
+ * @chip: TPM chip to use
+ * @out: destination buffer for the random bytes
+ * @max: the max number of bytes to write to @out
+ *
+ * Returns < 0 on error and the number of bytes read on success
+ */
+int tpm2_get_random(struct tpm_chip *chip, u8 *out, size_t max)
+{
+       struct tpm_cmd_t tpm_cmd;
+       u32 recd, num_bytes = min_t(u32, max, TPM_MAX_RNG_DATA);
+       int err, total = 0, retries = 5;
+       u8 *dest = out;
+
+       if (!out || !num_bytes || max > TPM_MAX_RNG_DATA)
+               return -EINVAL;
+
+       do {
+               tpm_cmd.header.in = tpm2_getrandom_header;
+               tpm_cmd.params.tpm2_getrandom_in.size = cpu_to_be16(num_bytes);
+
+               err = tpm_transmit_cmd(chip, &tpm_cmd, sizeof(tpm_cmd),
+                                      "attempting get random");
+               if (err)
+                       break;
+
+               recd = be16_to_cpu(tpm_cmd.params.tpm2_getrandom_out.size);
+               memcpy(dest, tpm_cmd.params.tpm2_getrandom_out.buffer, recd);
+
+               dest += recd;
+               total += recd;
+               num_bytes -= recd;
+       } while (retries-- && total < max);
+
+       return total ? total : -EIO;
+}
diff --git a/drivers/char/tpm/tpm2.h b/drivers/char/tpm/tpm2.h
index e4ed2e5..6ec84bc 100644
--- a/drivers/char/tpm/tpm2.h
+++ b/drivers/char/tpm/tpm2.h
@@ -38,6 +38,7 @@ enum tpm2_algorithms {
 enum tpm2_command_codes {
        TPM2_CC_SELF_TEST       = 0x0143,
        TPM2_CC_GET_CAPABILITY  = 0x017A,
+       TPM2_CC_GET_RANDOM      = 0x017B,
        TPM2_CC_PCR_READ        = 0x017E,
        TPM2_CC_PCR_EXTEND      = 0x0182,
 };
@@ -61,5 +62,6 @@ ssize_t tpm2_get_tpm_pt(struct device *dev, u32 property_id,  
u32* value,
 int tpm2_pcr_read_dev(struct tpm_chip *chip, int pcr_idx, u8 *res_buf);
 int tpm2_pcr_extend(struct tpm_chip *chip, int pcr_idx, const u8 *hash);
 int tpm2_do_selftest(struct tpm_chip *chip);
+int tpm2_get_random(struct tpm_chip *chip, u8 *out, size_t max);
 
 #endif /* __DRIVERS_CHAR_TPM2_H__ */
-- 
2.1.0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to