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 Dec 11, 2024
1 parent 2f8f19b commit 3eef2a0
Show file tree
Hide file tree
Showing 6 changed files with 240 additions and 6 deletions.
59 changes: 58 additions & 1 deletion libcaliptra/examples/generic/test.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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[4] = {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, 4);
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;
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 @@ -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
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 @@ -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,
};
141 changes: 140 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 @@ -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;
Expand All @@ -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;
}
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
14 changes: 14 additions & 0 deletions libcaliptra/src/caliptra_sha.h
Original file line number Diff line number Diff line change
@@ -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)

0 comments on commit 3eef2a0

Please sign in to comment.