From 86ab97cfd8dd7e1628c128bb54c7c1946c8155c4 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 | 59 +++++++++++- libcaliptra/inc/caliptra_api.h | 12 +++ libcaliptra/inc/caliptra_enums.h | 12 +++ libcaliptra/src/caliptra_api.c | 141 +++++++++++++++++++++++++++- libcaliptra/src/caliptra_fuses.h | 8 +- libcaliptra/src/caliptra_sha.h | 14 +++ 6 files changed, 240 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 bdd421e7e2..0b89c5de53 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,64 @@ 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] = {116, 101, 115, 116}; // Example data "test" in ascii + uint32_t update_data[4] = {116, 101, 115, 116}; // Example update data "test" in ascii + uint32_t expected_hash[48] = { + 0xcb, 0xcd, 0x01, 0x73, 0x2c, 0xe9, 0x66, 0xfc, + 0x58, 0xf5, 0xca, 0x38, 0xd1, 0xbf, 0xc6, 0xb7, + 0xbf, 0x9c, 0x00, 0xd7, 0x2a, 0xbf, 0xbe, 0x83, + 0xd6, 0x00, 0x12, 0x18, 0xbf, 0x34, 0x09, 0xc6, + 0xcd, 0x15, 0xd0, 0x05, 0xe3, 0xe7, 0x62, 0x77, + 0x45, 0x0b, 0x16, 0xc3, 0x0c, 0x5b, 0x9c, 0x25 + }; + + // 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, 4); + 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"); + + // Verify the hash against the expected value + if (memcmp(hash, expected_hash, sizeof(expected_hash)) == 0) { + printf("SHA Stream Test: Passed\n"); + } else { + printf("SHA Stream Test: Failed - Hash does not match expected value\n"); + printf("Expected Hash: "); + for (int i = 0; i < sizeof(expected_hash) / sizeof(expected_hash[0]); i++) { + printf("%08x ", expected_hash[i]); + } + printf("\nReceived Hash: "); + for (int i = 0; i < sizeof(hash) / sizeof(hash[0]); i++) { + printf("%08x ", hash[i]); + } + printf("\n"); + failure = 1; + } // FIPS_VERSION struct caliptra_fips_version_resp version_resp; diff --git a/libcaliptra/inc/caliptra_api.h b/libcaliptra/inc/caliptra_api.h index 8992dad882..1ceb3a33d3 100644 --- a/libcaliptra/inc/caliptra_api.h +++ b/libcaliptra/inc/caliptra_api.h @@ -205,6 +205,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 cf8d4b9924..90679ce905 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) @@ -1266,7 +1267,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; @@ -1279,3 +1279,142 @@ 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) { + uint32_t lock_status; + caliptra_read_u32(CALIPTRA_SHA_ACCELERATOR_LOCK_ADDR, &lock_status); + if (lock_status & 0x1) { + return MBX_BUSY; + } + + // 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 NO_ERROR; + } 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) { + uint32_t lock_status; + caliptra_read_u32(CALIPTRA_SHA_ACCELERATOR_LOCK_ADDR, &lock_status); + if (lock_status & 0x1) { + return MBX_BUSY; + } + + // 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 NO_ERROR; + } 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 NO_ERROR; +} + +/** + * @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 NO_ERROR; +} 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)