tpm: add session encryption protection to tpm2_get_random()
[linux-2.6-block.git] / drivers / char / tpm / tpm2-cmd.c
index 93545be190a50d54fec136152d6ef23fa81e2be3..0cdf892ec2a7d40929787948dc146d432f74d70f 100644 (file)
@@ -216,13 +216,6 @@ out:
        return rc;
 }
 
-struct tpm2_null_auth_area {
-       __be32  handle;
-       __be16  nonce_size;
-       u8  attributes;
-       __be16  auth_size;
-} __packed;
-
 /**
  * tpm2_pcr_extend() - extend a PCR value
  *
@@ -236,24 +229,22 @@ int tpm2_pcr_extend(struct tpm_chip *chip, u32 pcr_idx,
                    struct tpm_digest *digests)
 {
        struct tpm_buf buf;
-       struct tpm2_null_auth_area auth_area;
        int rc;
        int i;
 
-       rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_PCR_EXTEND);
+       rc = tpm2_start_auth_session(chip);
        if (rc)
                return rc;
 
-       tpm_buf_append_u32(&buf, pcr_idx);
+       rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_PCR_EXTEND);
+       if (rc) {
+               tpm2_end_auth_session(chip);
+               return rc;
+       }
 
-       auth_area.handle = cpu_to_be32(TPM2_RS_PW);
-       auth_area.nonce_size = 0;
-       auth_area.attributes = 0;
-       auth_area.auth_size = 0;
+       tpm_buf_append_name(chip, &buf, pcr_idx, NULL);
+       tpm_buf_append_hmac_session(chip, &buf, 0, NULL, 0);
 
-       tpm_buf_append_u32(&buf, sizeof(struct tpm2_null_auth_area));
-       tpm_buf_append(&buf, (const unsigned char *)&auth_area,
-                      sizeof(auth_area));
        tpm_buf_append_u32(&buf, chip->nr_allocated_banks);
 
        for (i = 0; i < chip->nr_allocated_banks; i++) {
@@ -262,7 +253,9 @@ int tpm2_pcr_extend(struct tpm_chip *chip, u32 pcr_idx,
                               chip->allocated_banks[i].digest_size);
        }
 
+       tpm_buf_fill_hmac_session(chip, &buf);
        rc = tpm_transmit_cmd(chip, &buf, 0, "attempting extend a PCR value");
+       rc = tpm_buf_check_hmac_response(chip, &buf, rc);
 
        tpm_buf_destroy(&buf);
 
@@ -299,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 +
@@ -334,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;
 }
 
@@ -759,6 +765,11 @@ int tpm2_auto_startup(struct tpm_chip *chip)
                rc = 0;
        }
 
+       if (rc)
+               goto out;
+
+       rc = tpm2_sessions_init(chip);
+
 out:
        /*
         * Infineon TPM in field upgrade mode will return no data for the number