Skip to content

Commit

Permalink
libcaliptra: add SHA accelerator API
Browse files Browse the repository at this point in the history
Signed-off-by: Marvin Drees <marvin.drees@9elements.com>
  • Loading branch information
MDr164 committed Feb 24, 2025
1 parent d8b42bc commit 81bcf1b
Show file tree
Hide file tree
Showing 6 changed files with 288 additions and 6 deletions.
97 changes: 96 additions & 1 deletion libcaliptra/examples/generic/test.c
Original file line number Diff line number Diff line change
Expand Up @@ -596,7 +596,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;

Expand Down Expand Up @@ -708,6 +707,102 @@ int rt_test_all_commands(const test_info* info)
printf("Certify Key Extended: OK\n");
}

// SHA Engine Tests
uint32_t stream_hash[16]; // Adjust size as needed for SHA-384 or SHA-512
uint32_t stream_hash_data[4] = {116, 101, 115, 116}; // Example data "test" in ascii
uint32_t stream_hash_update_data[4] = {116, 101, 115, 116}; // Example update data "test" in ascii
uint32_t expected_stream_hash[16] = {
0xcf83e135, 0x7eefb8bd, 0xf1542850, 0xd66d8007,
0xd620e405, 0x0b5715dc, 0x83f4a921, 0xd36ce9ce,
0x47d0d13c, 0x5d85f2b0, 0xff8318d2, 0x877eec2f,
0x63b931bd, 0x47417a81, 0xa538327a, 0xf927da3e,
};

// Start SHA Stream
status = caliptra_start_sha_stream(CALIPTRA_SHA_ACCELERATOR_MODE_STREAM_384, CALIPTRA_SHA_ACCELERATOR_ENDIANESS_LITTLE, stream_hash_data, sizeof(stream_hash_data));
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(stream_hash_update_data, sizeof(stream_hash_update_data));
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(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, 16) == 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 < 16; i++) {
printf("%08x ", expected_hash[i]);
}
printf("\nReceived Hash: ");
for (int i = 0; i < 16; i++) {
printf("%08x ", hash[i]);
}
printf("\n");
failure = 1;
}
}

// Test the non-streaming mbox hash function
uint8_t mbox_hash[16]; // Adjust size as needed for SHA-384 or SHA-512
uint8_t mbox_hash_data[4] = {0x01, 0x02, 0x03, 0x04};
uint8_t expected_mbox_hash[16] = {0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0};
uint32_t mbox_start_addr = 0x1000; // Example starting address for the mailbox
uint32_t mbox_data_len = sizeof(mbox_hash_data) / sizeof(mbox_hash_data[0]);

// Write the hash data into the mailbox to be hashed
for (uint32_t i = 0; i < mbox_data_len; i++) {
caliptra_write_u32(mbox_start_addr + (i * 4), mbox_hash_data[i]);
}

// Compute MBox Hash
status = caliptra_start_mbox_hash(CALIPTRA_SHA_ACCELERATOR_MODE_384, CALIPTRA_SHA_ACCELERATOR_ENDIANESS_LITTLE, mbox_start_addr, sizeof(mbox_hash_data), mbox_hash);
if (status) {
printf("Start Non-Streaming Hash failed: 0x%x\n", status);
dump_caliptra_error_codes();
failure = 1;
} else {
printf("Start Non-Streaming Hash: OK\n");

// Verify the hash against the expected value
if (memcmp(mbox_hash, expected_mbox_hash, 16) == 0) {
printf("Non-Streaming Hash Test: Passed\n");
} else {
printf("Non-Streaming Hash Test: Failed - Hash does not match expected value\n");
printf("Expected Hash: ");
for (int i = 0; i < 16; i++) {
printf("%08x ", expected_mbox_hash[i]);
}
printf("\nReceived Hash: ");
for (int i = 0; i < 16; i++) {
printf("%08x ", mbox_hash[i]);
}
printf("\n");
failure = 1;
}
}

// FIPS_VERSION
struct caliptra_fips_version_resp version_resp;
Expand Down
12 changes: 12 additions & 0 deletions libcaliptra/inc/caliptra_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,18 @@ void caliptra_req_idev_csr_start();
// Clear IDEV CSR request.
void caliptra_req_idev_csr_complete();

// Computes the SHA hash of data inside the mailbox using the specified mode, endianess, offset and length.
int caliptra_compute_mbox_sha(int mode, int endian, uint32_t mbox_start_addr, uint32_t data_len, uint32_t* hash);

// Starts a SHA stream using the specified mode and endianess.
int caliptra_start_sha_stream(int mode, int endian, uint32_t* in_data, uint32_t data_len);

// Updates the SHA stream with additional data.
int caliptra_update_sha_stream(uint32_t* in_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
Expand Down
12 changes: 12 additions & 0 deletions libcaliptra/inc/caliptra_enums.h
Original file line number Diff line number Diff line change
Expand Up @@ -114,3 +114,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,
};
147 changes: 146 additions & 1 deletion libcaliptra/src/caliptra_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -1344,7 +1345,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;
Expand All @@ -1357,3 +1357,148 @@ bool caliptra_is_idevid_csr_ready() {

return false;
}

/**
* @brief Computes the SHA hash of data inside the mailbox using the specified mode, endianess, offset and length.
*
* @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 mbox_start_addr The mailbox start address.
* @param data_len Length of the data to hash.
* @param hash Pointer to the buffer to store the resulting hash.
* @return 0 on success, or an error code on failure.
*/
int caliptra_compute_mbox_sha(int mode, int endian, uint32_t mbox_start_addr, uint32_t data_len, uint32_t* hash) {
if (!hash || data_len < 1 || (mode != CALIPTRA_SHA_ACCELERATOR_MODE_MBOX_384 && mode != CALIPTRA_SHA_ACCELERATOR_MODE_MBOX_512) ||
(endian != CALIPTRA_SHA_ACCELERATOR_ENDIANESS_BIG && endian != CALIPTRA_SHA_ACCELERATOR_ENDIANESS_LITTLE)) {
return INVALID_PARAMS;
}

uint32_t lock_status;
caliptra_read_u32(CALIPTRA_SHA_ACCELERATOR_LOCK_ADDR, &lock_status);
if (lock_status & 0x1) {
return MBX_BUSY;
}

// 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]);
}

// Writing 1 will clear the lock
caliptra_write_u32(CALIPTRA_SHA_ACCELERATOR_LOCK_ADDR, 0x1);

return NO_ERROR;
}

/**
* @brief Starts a SHA stream using the specified mode and endianess.
*
* This function will lock the SHA accelerator and write the initial data to the SHA accelerator.
* Afterwards either call caliptra_update_sha_stream() to update the SHA stream with additional data,
* or call caliptra_finish_sha_stream() to finish the SHA stream, retrieve the resulting hash and clear the lock.
*
* @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 in_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* in_data, uint32_t data_len) {
if (!in_data || data_len < 1 || (mode != CALIPTRA_SHA_ACCELERATOR_MODE_STREAM_384 && mode != CALIPTRA_SHA_ACCELERATOR_MODE_STREAM_512) ||
(endian != CALIPTRA_SHA_ACCELERATOR_ENDIANESS_BIG && endian != CALIPTRA_SHA_ACCELERATOR_ENDIANESS_LITTLE)) {
return INVALID_PARAMS;
}

uint32_t lock_status;
// By reading the lock register we also start holding the lock if it was not already held
caliptra_read_u32(CALIPTRA_SHA_ACCELERATOR_LOCK_ADDR, &lock_status);
if (lock_status & 0x1) {
return MBX_BUSY;
}

// 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, in_data[i]);
}

return NO_ERROR;
}

/**
* @brief Updates the SHA stream with additional data.
*
* This function will write the data to the SHA accelerator and requires that caliptra_start_sha_stream()
* has been called previously.
*
* @param in_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* in_data, uint32_t data_len) {
if (!data || data_len < 1) {
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.
*
* This function will signal the SHA accelerator to finish the stream, wait for the SHA accelerator to complete,
* read out the DIGEST registers and clear the lock.
*
* @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]);
}

// Writing 1 will clear the lock
caliptra_write_u32(CALIPTRA_SHA_ACCELERATOR_LOCK_ADDR, 0x1);

return NO_ERROR;
}
8 changes: 4 additions & 4 deletions libcaliptra/src/caliptra_fuses.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}


Expand Down Expand Up @@ -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);
}


Expand Down
18 changes: 18 additions & 0 deletions libcaliptra/src/caliptra_sha.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Licensed under the Apache-2.0 license
#pragma once

#include <caliptra_top_reg.h>

// Mirrored from the top reg file

#define CALIPTRA_SHA_ACCELERATOR_BASE_ADDR CALIPTRA_TOP_REG_SHA512_ACC_CSR_BASE_ADDR
#define CALIPTRA_SHA_ACCELERATOR_LOCK_ADDR CALIPTRA_TOP_REG_SHA512_ACC_CSR_LOCK
#define CALIPTRA_SHA_ACCELERATOR_USER_ADDR CALIPTRA_TOP_REG_SHA512_ACC_CSR_USER
#define CALIPTRA_SHA_ACCELERATOR_MODE_ADDR CALIPTRA_TOP_REG_SHA512_ACC_CSR_MODE
#define CALIPTRA_SHA_ACCELERATOR_START_ADDR CALIPTRA_TOP_REG_SHA512_ACC_CSR_START_ADDRESS
#define CALIPTRA_SHA_ACCELERATOR_DLEN_ADDR CALIPTRA_TOP_REG_SHA512_ACC_CSR_DLEN
#define CALIPTRA_SHA_ACCELERATOR_DATAIN_ADDR CALIPTRA_TOP_REG_SHA512_ACC_CSR_DATAIN
#define CALIPTRA_SHA_ACCELERATOR_EXECUTE_ADDR CALIPTRA_TOP_REG_SHA512_ACC_CSR_EXECUTE
#define CALIPTRA_SHA_ACCELERATOR_STATUS_ADDR CALIPTRA_TOP_REG_SHA512_ACC_CSR_STATUS
#define CALIPTRA_SHA_ACCELERATOR_DIGEST_ADDR CALIPTRA_TOP_REG_SHA512_ACC_CSR_DIGEST_0 // TODO: This should be an array
#define CALIPTRA_SHA_ACCELERATOR_CONTROL_ADDR CALIPTRA_TOP_REG_SHA512_ACC_CSR_CONTROL

0 comments on commit 81bcf1b

Please sign in to comment.