From d3d0220c2cd65b39e2d96a1f247d73b15a48c6b1 Mon Sep 17 00:00:00 2001 From: Marvin Drees Date: Wed, 14 Aug 2024 18:13:03 +0200 Subject: [PATCH] libcaliptra: add SHA accelerator API Signed-off-by: Marvin Drees --- libcaliptra/examples/generic/test.c | 35 +++++++- libcaliptra/inc/caliptra_api.h | 12 +++ libcaliptra/inc/caliptra_enums.h | 12 +++ libcaliptra/src/caliptra_api.c | 129 +++++++++++++++++++++++++++- libcaliptra/src/caliptra_fuses.h | 8 +- libcaliptra/src/caliptra_sha.h | 14 +++ 6 files changed, 204 insertions(+), 6 deletions(-) create mode 100644 libcaliptra/src/caliptra_sha.h diff --git a/libcaliptra/examples/generic/test.c b/libcaliptra/examples/generic/test.c index 7f7daeeffa..18ce50f5e7 100644 --- a/libcaliptra/examples/generic/test.c +++ b/libcaliptra/examples/generic/test.c @@ -438,7 +438,6 @@ int rt_test_all_commands(const test_info* info) printf("DPE Command: OK\n"); } - // FW_INFO struct caliptra_fw_info_resp fw_info_resp; @@ -550,6 +549,40 @@ int rt_test_all_commands(const test_info* info) printf("Certify Key Extended: OK\n"); } + // SHA Engine Tests + uint32_t hash[12]; // Adjust size as needed for SHA-384 or SHA-512 + uint32_t data[16] = {0}; // Example data, adjust size as needed + uint32_t update_data[8] = {1}; // Example update data, adjust size as needed + + // Start SHA Stream + status = caliptra_start_sha_stream(CALIPTRA_SHA_ACCELERATOR_MODE_STREAM_384, CALIPTRA_SHA_ACCELERATOR_ENDIANESS_LITTLE, data, 16); + if (status) { + printf("Start SHA Stream failed: 0x%x\n", status); + dump_caliptra_error_codes(); + failure = 1; + } else { + printf("Start SHA Stream: OK\n"); + } + + // Update SHA Stream + status = caliptra_update_sha_stream(update_data, 8); + if (status) { + printf("Update SHA Stream failed: 0x%x\n", status); + dump_caliptra_error_codes(); + failure = 1; + } else { + printf("Update SHA Stream: OK\n"); + } + + // Finish SHA Stream + status = caliptra_finish_sha_stream(hash); + if (status) { + printf("Finish SHA Stream failed: 0x%x\n", status); + dump_caliptra_error_codes(); + failure = 1; + } else { + printf("Finish SHA Stream: OK\n"); + } // FIPS_VERSION struct caliptra_fips_version_resp version_resp; diff --git a/libcaliptra/inc/caliptra_api.h b/libcaliptra/inc/caliptra_api.h index a5fbeefd68..99991b8bc0 100644 --- a/libcaliptra/inc/caliptra_api.h +++ b/libcaliptra/inc/caliptra_api.h @@ -202,6 +202,18 @@ void caliptra_req_idev_csr_start(); // Clear IDEV CSR request. void caliptra_req_idev_csr_complete(); +// Computes the SHA hash using the specified mode and endianess. +int caliptra_compute_sha(int mode, int endian, uint32_t* data, uint32_t data_len, uint32_t* hash, uint32_t mbox_start_addr); + +// Starts a SHA stream using the specified mode and endianess. +int caliptra_start_sha_stream(int mode, int endian, uint32_t* data, uint32_t data_len); + +// Updates the SHA stream with additional data. +int caliptra_update_sha_stream(uint32_t* data, uint32_t data_len); + +// Finishes the SHA stream and retrieves the resulting hash. +int caliptra_finish_sha_stream(uint32_t* hash); + #ifdef __cplusplus } #endif diff --git a/libcaliptra/inc/caliptra_enums.h b/libcaliptra/inc/caliptra_enums.h index 7351234cdc..d7aec32341 100644 --- a/libcaliptra/inc/caliptra_enums.h +++ b/libcaliptra/inc/caliptra_enums.h @@ -110,3 +110,15 @@ enum dpe_profile { P256Sha256 = DPE_PROFILE_256, P384Sha384 = DPE_PROFILE_384, }; + +enum caliptra_sha_accelerator_endianess { + CALIPTRA_SHA_ACCELERATOR_ENDIANESS_BIG = 0, + CALIPTRA_SHA_ACCELERATOR_ENDIANESS_LITTLE = 1, +}; + +enum caliptra_sha_accelerator_mode { + CALIPTRA_SHA_ACCELERATOR_MODE_STREAM_384 = 0, + CALIPTRA_SHA_ACCELERATOR_MODE_STREAM_512 = 1, + CALIPTRA_SHA_ACCELERATOR_MODE_MBOX_384 = 2, + CALIPTRA_SHA_ACCELERATOR_MODE_MBOX_512 = 3, +}; diff --git a/libcaliptra/src/caliptra_api.c b/libcaliptra/src/caliptra_api.c index 5bac11a39e..6dbaf78930 100644 --- a/libcaliptra/src/caliptra_api.c +++ b/libcaliptra/src/caliptra_api.c @@ -11,6 +11,7 @@ #include "caliptra_types.h" #include "caliptra_fuses.h" #include "caliptra_mbox.h" +#include "caliptra_sha.h" #define CALIPTRA_STATUS_NOT_READY (0) #define CALIPTRA_REG_BASE (CALIPTRA_TOP_REG_MBOX_CSR_BASE_ADDR) @@ -1251,7 +1252,6 @@ void caliptra_req_idev_csr_complete() caliptra_write_u32(CALIPTRA_TOP_REG_GENERIC_AND_FUSE_REG_CPTRA_DBG_MANUF_SERVICE_REG, dbg_manuf_serv_req & ~0x01); } - // Check if IDEV CSR is ready. bool caliptra_is_idevid_csr_ready() { uint32_t status; @@ -1264,3 +1264,130 @@ bool caliptra_is_idevid_csr_ready() { return false; } + +/** + * @brief Computes the SHA hash using the specified mode and endianess. + * + * @param mode The SHA mode to use (e.g., CALIPTRA_SHA_ACCELERATOR_MODE_MBOX_384). + * @param endian The endianess to use (e.g., CALIPTRA_SHA_ACCELERATOR_ENDIANESS_BIG). + * @param data Pointer to the data to hash. + * @param data_len Length of the data to hash. + * @param hash Pointer to the buffer to store the resulting hash. + * @param mbox_start_addr The mailbox start address. + * @return 0 on success, or an error code on failure. + */ +int caliptra_compute_sha(int mode, int endian, uint32_t* data, uint32_t data_len, uint32_t* hash, uint32_t mbox_start_addr) { + if (!data || !hash) { + return INVALID_PARAMS; + } + + if (mode == CALIPTRA_SHA_ACCELERATOR_MODE_MBOX_384 || mode == CALIPTRA_SHA_ACCELERATOR_MODE_MBOX_512) { + // Writing 1 will clear the lock + caliptra_write_u32(CALIPTRA_SHA_ACCELERATOR_LOCK_ADDR, 0x1); + // Zeroize engine registers to start fresh + caliptra_write_u32(CALIPTRA_SHA_ACCELERATOR_CONTROL_ADDR, 0x1); + // Set mode and endianess accordingly + uint32_t control_value = (mode & 0xFFFF) | ((endian & 0xFF) << 16); + caliptra_write_u32(CALIPTRA_SHA_ACCELERATOR_CONTROL_ADDR, control_value); + // Write data to the SHA accelerator + caliptra_write_u32(CALIPTRA_SHA_ACCELERATOR_START_ADDR, mbox_start_addr); + caliptra_write_u32(CALIPTRA_SHA_ACCELERATOR_DLEN_ADDR, data_len); + // Let engine read out mbox addr + caliptra_write_u32(CALIPTRA_SHA_ACCELERATOR_EXECUTE_ADDR, 0x1); + // Wait for the SHA accelerator to complete + uint32_t status; + do { + caliptra_read_u32(CALIPTRA_SHA_ACCELERATOR_STATUS_ADDR, &status); + } while ((status & 0x1) == 0); + // Read out the DIGEST registers and place into hash struct + for (int i = 0; i < 16; i++) { + caliptra_read_u32(CALIPTRA_SHA_ACCELERATOR_DIGEST_ADDR + (i * 4), &hash[i]); + } + + return 0; + } else { + return INVALID_PARAMS; + } +} + +/** + * @brief Starts a SHA stream using the specified mode and endianess. + * + * @param mode The SHA mode to use (e.g., CALIPTRA_SHA_ACCELERATOR_MODE_STREAM_384). + * @param endian The endianess to use (e.g., CALIPTRA_SHA_ACCELERATOR_ENDIANESS_BIG). + * @param data Pointer to the initial data to hash. + * @param data_len Length of the initial data to hash. + * @return 0 on success, or an error code on failure. + */ +int caliptra_start_sha_stream(int mode, int endian, uint32_t* data, uint32_t data_len) { + if (!data) { + return INVALID_PARAMS; + } + + if (mode == CALIPTRA_SHA_ACCELERATOR_MODE_STREAM_384 || mode == CALIPTRA_SHA_ACCELERATOR_MODE_STREAM_512) { + // Writing 1 will clear the lock + caliptra_write_u32(CALIPTRA_SHA_ACCELERATOR_LOCK_ADDR, 0x1); + // Zeroize engine registers to start fresh + caliptra_write_u32(CALIPTRA_SHA_ACCELERATOR_CONTROL_ADDR, 0x1); + // Set mode and endianess accordingly + uint32_t control_value = (mode & 0xFFFF) | ((endian & 0xFF) << 16); + caliptra_write_u32(CALIPTRA_SHA_ACCELERATOR_CONTROL_ADDR, control_value); + + // Write initial data to the SHA accelerator + for (uint32_t i = 0; i < data_len; i++) { + caliptra_write_u32(CALIPTRA_SHA_ACCELERATOR_DATAIN_ADDR, data[i]); + } + + return 0; + } else { + return INVALID_PARAMS; + } +} + +/** + * @brief Updates the SHA stream with additional data. + * + * @param data Pointer to the data to hash. + * @param data_len Length of the data to hash. + * @return 0 on success, or an error code on failure. + */ +int caliptra_update_sha_stream(uint32_t* data, uint32_t data_len) { + if (!data) { + return INVALID_PARAMS; + } + + // Write data to the SHA accelerator + for (uint32_t i = 0; i < data_len; i++) { + caliptra_write_u32(CALIPTRA_SHA_ACCELERATOR_DATAIN_ADDR, data[i]); + } + + return 0; +} + +/** + * @brief Finishes the SHA stream and retrieves the resulting hash. + * + * @param hash Pointer to the buffer to store the resulting hash. + * @return 0 on success, or an error code on failure. + */ +int caliptra_finish_sha_stream(uint32_t* hash) { + if (!hash) { + return INVALID_PARAMS; + } + + // Signal the SHA accelerator to finish the stream + caliptra_write_u32(CALIPTRA_SHA_ACCELERATOR_EXECUTE_ADDR, 0x1); + + // Wait for the SHA accelerator to complete + uint32_t status; + do { + caliptra_read_u32(CALIPTRA_SHA_ACCELERATOR_STATUS_ADDR, &status); + } while ((status & 0x1) == 0); + + // Read out the DIGEST registers and place into hash struct + for (int i = 0; i < 16; i++) { + caliptra_read_u32(CALIPTRA_SHA_ACCELERATOR_DIGEST_ADDR + (i * 4), &hash[i]); + } + + return 0; +} diff --git a/libcaliptra/src/caliptra_fuses.h b/libcaliptra/src/caliptra_fuses.h index 184d987864..d6e424173a 100644 --- a/libcaliptra/src/caliptra_fuses.h +++ b/libcaliptra/src/caliptra_fuses.h @@ -48,9 +48,9 @@ static inline uint32_t caliptra_read_fw_error_fatal(void) return caliptra_generic_and_fuse_read(GENERIC_AND_FUSE_REG_CPTRA_FW_ERROR_FATAL); } -static inline uint32_t caliptra_read_dbg_manuf_serv() +static inline uint32_t caliptra_read_dbg_manuf_serv() { - return caliptra_generic_and_fuse_read(GENERIC_AND_FUSE_REG_CPTRA_DBG_MANUF_SERVICE_REG); + return caliptra_generic_and_fuse_read(GENERIC_AND_FUSE_REG_CPTRA_DBG_MANUF_SERVICE_REG); } @@ -119,10 +119,10 @@ static inline void caliptra_write_fuse_valid_pauser(uint32_t data) caliptra_generic_and_fuse_write(GENERIC_AND_FUSE_REG_CPTRA_FUSE_VALID_PAUSER, data); } -static inline void caliptra_write_dbg_manuf_serv(uint32_t data) +static inline void caliptra_write_dbg_manuf_serv(uint32_t data) { // Set Manuf service reg - caliptra_generic_and_fuse_write(GENERIC_AND_FUSE_REG_CPTRA_DBG_MANUF_SERVICE_REG, data); + caliptra_generic_and_fuse_write(GENERIC_AND_FUSE_REG_CPTRA_DBG_MANUF_SERVICE_REG, data); } diff --git a/libcaliptra/src/caliptra_sha.h b/libcaliptra/src/caliptra_sha.h new file mode 100644 index 0000000000..d164e19944 --- /dev/null +++ b/libcaliptra/src/caliptra_sha.h @@ -0,0 +1,14 @@ +// Licensed under the Apache-2.0 license +#pragma once + +#define CALIPTRA_SHA_ACCELERATOR_BASE_ADDR 0x30021000 +#define CALIPTRA_SHA_ACCELERATOR_LOCK_ADDR (CALIPTRA_SHA_ACCELERATOR_BASE_ADDR + 0x00) +#define CALIPTRA_SHA_ACCELERATOR_USER_ADDR (CALIPTRA_SHA_ACCELERATOR_BASE_ADDR + 0x04) +#define CALIPTRA_SHA_ACCELERATOR_MODE_ADDR (CALIPTRA_SHA_ACCELERATOR_BASE_ADDR + 0x08) +#define CALIPTRA_SHA_ACCELERATOR_START_ADDR (CALIPTRA_SHA_ACCELERATOR_BASE_ADDR + 0x0c) +#define CALIPTRA_SHA_ACCELERATOR_DLEN_ADDR (CALIPTRA_SHA_ACCELERATOR_BASE_ADDR + 0x10) +#define CALIPTRA_SHA_ACCELERATOR_DATAIN_ADDR (CALIPTRA_SHA_ACCELERATOR_BASE_ADDR + 0x14) +#define CALIPTRA_SHA_ACCELERATOR_EXECUTE_ADDR (CALIPTRA_SHA_ACCELERATOR_BASE_ADDR + 0x18) +#define CALIPTRA_SHA_ACCELERATOR_STATUS_ADDR (CALIPTRA_SHA_ACCELERATOR_BASE_ADDR + 0x1c) +#define CALIPTRA_SHA_ACCELERATOR_DIGEST_ADDR (CALIPTRA_SHA_ACCELERATOR_BASE_ADDR + 0x20) +#define CALIPTRA_SHA_ACCELERATOR_CONTROL_ADDR (CALIPTRA_SHA_ACCELERATOR_BASE_ADDR + 0x60)