int ima_calc_field_array_hash(struct ima_field_data *field_data,
                              struct ima_template_entry *entry)
 {
-       int rc;
+       u16 alg_id;
+       int rc, i;
 
        rc = ima_calc_field_array_hash_tfm(field_data, entry, ima_sha1_idx);
+       if (rc)
+               return rc;
+
+       entry->digests[ima_sha1_idx].alg_id = TPM_ALG_SHA1;
+
+       for (i = 0; i < NR_BANKS(ima_tpm_chip) + ima_extra_slots; i++) {
+               if (i == ima_sha1_idx)
+                       continue;
+
+               if (i < NR_BANKS(ima_tpm_chip)) {
+                       alg_id = ima_tpm_chip->allocated_banks[i].alg_id;
+                       entry->digests[i].alg_id = alg_id;
+               }
+
+               /* for unmapped TPM algorithms digest is still a padded SHA1 */
+               if (!ima_algo_array[i].tfm) {
+                       memcpy(entry->digests[i].digest,
+                              entry->digests[ima_sha1_idx].digest,
+                              TPM_DIGEST_SIZE);
+                       continue;
+               }
+
+               rc = ima_calc_field_array_hash_tfm(field_data, entry, i);
+               if (rc)
+                       return rc;
+       }
        return rc;
 }
 
 
                return binary_runtime_size + sizeof(struct ima_kexec_hdr);
 };
 
-static int ima_pcr_extend(const u8 *hash, int pcr)
+static int ima_pcr_extend(struct tpm_digest *digests_arg, int pcr)
 {
        int result = 0;
-       int i;
 
        if (!ima_tpm_chip)
                return result;
 
-       for (i = 0; i < ima_tpm_chip->nr_allocated_banks; i++)
-               memcpy(digests[i].digest, hash, TPM_DIGEST_SIZE);
-
-       result = tpm_pcr_extend(ima_tpm_chip, pcr, digests);
+       result = tpm_pcr_extend(ima_tpm_chip, pcr, digests_arg);
        if (result != 0)
                pr_err("Error Communicating to TPM chip, result: %d\n", result);
        return result;
                           const char *op, struct inode *inode,
                           const unsigned char *filename)
 {
-       u8 digest[TPM_DIGEST_SIZE];
+       u8 *digest = entry->digests[ima_sha1_idx].digest;
+       struct tpm_digest *digests_arg = entry->digests;
        const char *audit_cause = "hash_added";
        char tpm_audit_cause[AUDIT_CAUSE_LEN_MAX];
        int audit_info = 1;
 
        mutex_lock(&ima_extend_list_mutex);
        if (!violation) {
-               memcpy(digest, entry->digests[ima_sha1_idx].digest,
-                      sizeof(digest));
                if (ima_lookup_digest_entry(digest, entry->pcr)) {
                        audit_cause = "hash_exists";
                        result = -EEXIST;
        }
 
        if (violation)          /* invalidate pcr */
-               memset(digest, 0xff, sizeof(digest));
+               digests_arg = digests;
 
-       tpmresult = ima_pcr_extend(digest, entry->pcr);
+       tpmresult = ima_pcr_extend(digests_arg, entry->pcr);
        if (tpmresult != 0) {
                snprintf(tpm_audit_cause, AUDIT_CAUSE_LEN_MAX, "TPM_error(%d)",
                         tpmresult);
 
 int __init ima_init_digests(void)
 {
+       u16 digest_size;
+       u16 crypto_id;
        int i;
 
        if (!ima_tpm_chip)
        if (!digests)
                return -ENOMEM;
 
-       for (i = 0; i < ima_tpm_chip->nr_allocated_banks; i++)
+       for (i = 0; i < ima_tpm_chip->nr_allocated_banks; i++) {
                digests[i].alg_id = ima_tpm_chip->allocated_banks[i].alg_id;
+               digest_size = ima_tpm_chip->allocated_banks[i].digest_size;
+               crypto_id = ima_tpm_chip->allocated_banks[i].crypto_id;
+
+               /* for unmapped TPM algorithms digest is still a padded SHA1 */
+               if (crypto_id == HASH_ALGO__LAST)
+                       digest_size = SHA1_DIGEST_SIZE;
+
+               memset(digests[i].digest, 0xff, digest_size);
+       }
 
        return 0;
 }
 
 int ima_restore_measurement_list(loff_t size, void *buf)
 {
        char template_name[MAX_TEMPLATE_NAME_LEN];
+       unsigned char zero[TPM_DIGEST_SIZE] = { 0 };
 
        struct ima_kexec_hdr *khdr = buf;
        struct ima_field_data hdr[HDR__LAST] = {
                if (ret < 0)
                        break;
 
-               memcpy(entry->digests[ima_sha1_idx].digest,
-                      hdr[HDR_DIGEST].data, hdr[HDR_DIGEST].len);
+               if (memcmp(hdr[HDR_DIGEST].data, zero, sizeof(zero))) {
+                       ret = ima_calc_field_array_hash(
+                                               &entry->template_data[0],
+                                               entry);
+                       if (ret < 0) {
+                               pr_err("cannot calculate template digest\n");
+                               ret = -EINVAL;
+                               break;
+                       }
+               }
+
                entry->pcr = !ima_canonical_fmt ? *(hdr[HDR_PCR].data) :
                             le32_to_cpu(*(hdr[HDR_PCR].data));
                ret = ima_restore_measurement_entry(entry);