| // SPDX-License-Identifier: GPL-2.0-only |
| /* Copyright(c) 2024-2005 Intel Corporation. All rights reserved. */ |
| |
| #define pr_fmt(x) KBUILD_MODNAME ": " x |
| |
| #include <linux/module.h> |
| #include <linux/tsm-mr.h> |
| #include <linux/miscdevice.h> |
| #include <crypto/sha2.h> |
| |
| static struct { |
| u8 static_mr[SHA384_DIGEST_SIZE]; |
| u8 config_mr[SHA512_DIGEST_SIZE]; |
| u8 rtmr0[SHA256_DIGEST_SIZE]; |
| u8 rtmr1[SHA384_DIGEST_SIZE]; |
| u8 report_digest[SHA512_DIGEST_SIZE]; |
| } sample_report = { |
| .static_mr = "static_mr", |
| .config_mr = "config_mr", |
| .rtmr0 = "rtmr0", |
| .rtmr1 = "rtmr1", |
| }; |
| |
| static int sample_report_refresh(const struct tsm_measurements *tm) |
| { |
| sha512((const u8 *)&sample_report, |
| offsetof(typeof(sample_report), report_digest), |
| sample_report.report_digest); |
| return 0; |
| } |
| |
| static int sample_report_extend_mr(const struct tsm_measurements *tm, |
| const struct tsm_measurement_register *mr, |
| const u8 *data) |
| { |
| union { |
| struct sha256_ctx sha256; |
| struct sha384_ctx sha384; |
| struct sha512_ctx sha512; |
| } ctx; |
| |
| switch (mr->mr_hash) { |
| case HASH_ALGO_SHA256: |
| sha256_init(&ctx.sha256); |
| sha256_update(&ctx.sha256, mr->mr_value, mr->mr_size); |
| sha256_update(&ctx.sha256, data, mr->mr_size); |
| sha256_final(&ctx.sha256, mr->mr_value); |
| return 0; |
| case HASH_ALGO_SHA384: |
| sha384_init(&ctx.sha384); |
| sha384_update(&ctx.sha384, mr->mr_value, mr->mr_size); |
| sha384_update(&ctx.sha384, data, mr->mr_size); |
| sha384_final(&ctx.sha384, mr->mr_value); |
| return 0; |
| case HASH_ALGO_SHA512: |
| sha512_init(&ctx.sha512); |
| sha512_update(&ctx.sha512, mr->mr_value, mr->mr_size); |
| sha512_update(&ctx.sha512, data, mr->mr_size); |
| sha512_final(&ctx.sha512, mr->mr_value); |
| return 0; |
| default: |
| pr_err("Unsupported hash algorithm: %d\n", mr->mr_hash); |
| return -EOPNOTSUPP; |
| } |
| } |
| |
| #define MR_(mr, hash) .mr_value = &sample_report.mr, TSM_MR_(mr, hash) |
| static const struct tsm_measurement_register sample_mrs[] = { |
| /* static MR, read-only */ |
| { MR_(static_mr, SHA384) }, |
| /* config MR, read-only */ |
| { MR_(config_mr, SHA512) | TSM_MR_F_NOHASH }, |
| /* RTMR, direct extension prohibited */ |
| { MR_(rtmr0, SHA256) | TSM_MR_F_LIVE }, |
| /* RTMR, direct extension allowed */ |
| { MR_(rtmr1, SHA384) | TSM_MR_F_RTMR }, |
| /* RTMR, crypto agile, alaised to rtmr0 and rtmr1, respectively */ |
| { .mr_value = &sample_report.rtmr0, |
| TSM_MR_(rtmr_crypto_agile, SHA256) | TSM_MR_F_RTMR }, |
| { .mr_value = &sample_report.rtmr1, |
| TSM_MR_(rtmr_crypto_agile, SHA384) | TSM_MR_F_RTMR }, |
| /* sha512 digest of the whole structure */ |
| { MR_(report_digest, SHA512) | TSM_MR_F_LIVE }, |
| }; |
| #undef MR_ |
| |
| static struct tsm_measurements sample_tm = { |
| .mrs = sample_mrs, |
| .nr_mrs = ARRAY_SIZE(sample_mrs), |
| .refresh = sample_report_refresh, |
| .write = sample_report_extend_mr, |
| }; |
| |
| static const struct attribute_group *sample_groups[] = { |
| NULL, |
| NULL, |
| }; |
| |
| static struct miscdevice sample_misc_dev = { |
| .name = KBUILD_MODNAME, |
| .minor = MISC_DYNAMIC_MINOR, |
| .groups = sample_groups, |
| }; |
| |
| static int __init tsm_mr_sample_init(void) |
| { |
| int rc; |
| |
| sample_groups[0] = tsm_mr_create_attribute_group(&sample_tm); |
| if (IS_ERR(sample_groups[0])) |
| return PTR_ERR(sample_groups[0]); |
| |
| rc = misc_register(&sample_misc_dev); |
| if (rc) |
| tsm_mr_free_attribute_group(sample_groups[0]); |
| return rc; |
| } |
| |
| static void __exit tsm_mr_sample_exit(void) |
| { |
| misc_deregister(&sample_misc_dev); |
| tsm_mr_free_attribute_group(sample_groups[0]); |
| } |
| |
| module_init(tsm_mr_sample_init); |
| module_exit(tsm_mr_sample_exit); |
| |
| MODULE_LICENSE("GPL"); |
| MODULE_DESCRIPTION("Sample module using tsm-mr to expose emulated MRs"); |