Skip to content

Commit

Permalink
Add support for export cdi crypto api and sign with exported
Browse files Browse the repository at this point in the history
  • Loading branch information
clundin25 committed Jan 30, 2025
1 parent 77e61bd commit 0410cb0
Show file tree
Hide file tree
Showing 27 changed files with 792 additions and 152 deletions.
70 changes: 70 additions & 0 deletions api/src/mailbox.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@ impl CommandId {

// The get IDevID CSR command.
pub const GET_IDEV_CSR: Self = Self(0x4944_4352); // "IDCR"

// The sign with exported ecdsa command.
pub const SIGN_WITH_EXPORTED_ECDSA: Self = Self(0x5357_4545); // "SWEE"
}

impl From<u32> for CommandId {
Expand Down Expand Up @@ -153,6 +156,7 @@ pub enum MailboxResp {
CertifyKeyExtended(CertifyKeyExtendedResp),
AuthorizeAndStash(AuthorizeAndStashResp),
GetIdevCsr(GetIdevCsrResp),
SignWithExportedEcdsa(SignWithExportedEcdsaResp),
}

impl MailboxResp {
Expand All @@ -174,6 +178,7 @@ impl MailboxResp {
MailboxResp::CertifyKeyExtended(resp) => Ok(resp.as_bytes()),
MailboxResp::AuthorizeAndStash(resp) => Ok(resp.as_bytes()),
MailboxResp::GetIdevCsr(resp) => Ok(resp.as_bytes()),
MailboxResp::SignWithExportedEcdsa(resp) => Ok(resp.as_bytes()),
}
}

Expand All @@ -195,6 +200,7 @@ impl MailboxResp {
MailboxResp::CertifyKeyExtended(resp) => Ok(resp.as_mut_bytes()),
MailboxResp::AuthorizeAndStash(resp) => Ok(resp.as_mut_bytes()),
MailboxResp::GetIdevCsr(resp) => Ok(resp.as_mut_bytes()),
MailboxResp::SignWithExportedEcdsa(resp) => Ok(resp.as_mut_bytes()),
}
}

Expand Down Expand Up @@ -253,6 +259,7 @@ pub enum MailboxReq {
CertifyKeyExtended(CertifyKeyExtendedReq),
SetAuthManifest(SetAuthManifestReq),
AuthorizeAndStash(AuthorizeAndStashReq),
SignWithExportedEcdsa(SignWithExportedEcdsaReq),
}

impl MailboxReq {
Expand All @@ -278,6 +285,7 @@ impl MailboxReq {
MailboxReq::CertifyKeyExtended(req) => Ok(req.as_bytes()),
MailboxReq::SetAuthManifest(req) => Ok(req.as_bytes()),
MailboxReq::AuthorizeAndStash(req) => Ok(req.as_bytes()),
MailboxReq::SignWithExportedEcdsa(req) => Ok(req.as_bytes()),
}
}

Expand All @@ -303,6 +311,7 @@ impl MailboxReq {
MailboxReq::CertifyKeyExtended(req) => Ok(req.as_mut_bytes()),
MailboxReq::SetAuthManifest(req) => Ok(req.as_mut_bytes()),
MailboxReq::AuthorizeAndStash(req) => Ok(req.as_mut_bytes()),
MailboxReq::SignWithExportedEcdsa(req) => Ok(req.as_mut_bytes()),
}
}

Expand All @@ -328,6 +337,7 @@ impl MailboxReq {
MailboxReq::CertifyKeyExtended(_) => CommandId::CERTIFY_KEY_EXTENDED,
MailboxReq::SetAuthManifest(_) => CommandId::SET_AUTH_MANIFEST,
MailboxReq::AuthorizeAndStash(_) => CommandId::AUTHORIZE_AND_STASH,
MailboxReq::SignWithExportedEcdsa(_) => CommandId::SIGN_WITH_EXPORTED_ECDSA,
}
}

Expand Down Expand Up @@ -1010,6 +1020,66 @@ impl Default for GetIdevCsrResp {
}
}

// SIGN_WITH_EXPORTED_ECDSA
#[repr(C)]
#[derive(Debug, IntoBytes, FromBytes, KnownLayout, Immutable, PartialEq, Eq)]
pub struct SignWithExportedEcdsaReq {
pub hdr: MailboxReqHeader,
pub exported_cdi_handle: [u8; Self::EXPORTED_CDI_MAX_SIZE],
pub tbs: [u8; Self::MAX_DIGEST_SIZE],
}

impl Default for SignWithExportedEcdsaReq {
fn default() -> Self {
Self {
hdr: MailboxReqHeader::default(),
exported_cdi_handle: [0u8; Self::EXPORTED_CDI_MAX_SIZE],
tbs: [0u8; Self::MAX_DIGEST_SIZE],
}
}
}

impl SignWithExportedEcdsaReq {
pub const EXPORTED_CDI_MAX_SIZE: usize = 32;
pub const MAX_DIGEST_SIZE: usize = 48;
}

impl Request for SignWithExportedEcdsaReq {
const ID: CommandId = CommandId::SIGN_WITH_EXPORTED_ECDSA;
type Resp = SignWithExportedEcdsaResp;
}

#[repr(C)]
#[derive(Debug, IntoBytes, FromBytes, KnownLayout, Immutable, PartialEq, Eq)]
pub struct SignWithExportedEcdsaResp {
pub hdr: MailboxRespHeader,
pub derived_pubkey_x: [u8; Self::X_SIZE],
pub derived_pubkey_y: [u8; Self::Y_SIZE],
pub signature_r: [u8; Self::R_SIZE],
pub signature_s: [u8; Self::S_SIZE],
}

impl SignWithExportedEcdsaResp {
pub const X_SIZE: usize = 48;
pub const Y_SIZE: usize = 48;
pub const R_SIZE: usize = 48;
pub const S_SIZE: usize = 48;
}

impl ResponseVarSize for SignWithExportedEcdsaResp {}

impl Default for SignWithExportedEcdsaResp {
fn default() -> Self {
Self {
hdr: MailboxRespHeader::default(),
signature_r: [0u8; Self::R_SIZE],
signature_s: [0u8; Self::S_SIZE],
derived_pubkey_x: [0u8; Self::X_SIZE],
derived_pubkey_y: [0u8; Self::Y_SIZE],
}
}
}

#[repr(u32)]
#[derive(Debug, PartialEq, Eq)]
pub enum ImageHashSource {
Expand Down
2 changes: 2 additions & 0 deletions common/src/keyids.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,5 +33,7 @@ pub const KEY_ID_RT_PRIV_KEY: KeyId = KeyId::KeyId5;
pub const KEY_ID_DPE_CDI: KeyId = KeyId::KeyId8;
#[cfg(feature = "runtime")]
pub const KEY_ID_DPE_PRIV_KEY: KeyId = KeyId::KeyId9;
#[cfg(feature = "runtime")]
pub const KEY_ID_EXPORTED_DPE_CDI: KeyId = KeyId::KeyId10;

pub const KEY_ID_TMP: KeyId = KeyId::KeyId3;
8 changes: 8 additions & 0 deletions error/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -449,6 +449,14 @@ impl CaliptraError {
CaliptraError::new_const(0x000E0052);
pub const RUNTIME_AUTH_MANIFEST_IMAGE_METADATA_LIST_DUPLICATE_FIRMWARE_ID: CaliptraError =
CaliptraError::new_const(0x000E0053);
pub const RUNTIME_SIGN_WITH_EXPORTED_ECDSA_KEY_DERIVIATION_FAILED: CaliptraError =
CaliptraError::new_const(0x000E0054);
pub const RUNTIME_SIGN_WITH_EXPORTED_ECDSA_SIGNATURE_FAILED: CaliptraError =
CaliptraError::new_const(0x000E0055);
pub const RUNTIME_SIGN_WITH_EXPORTED_ECDSA_INVALID_DIGEST: CaliptraError =
CaliptraError::new_const(0x000E0056);
pub const RUNTIME_SIGN_WITH_EXPORTED_ECDSA_INVALID_SIGNATURE: CaliptraError =
CaliptraError::new_const(0x000E0057);

/// FMC Errors
pub const FMC_GLOBAL_NMI: CaliptraError = CaliptraError::new_const(0x000F0001);
Expand Down
146 changes: 146 additions & 0 deletions libcaliptra/examples/generic/test.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@
#include "caliptra_types.h"
#include "idev_csr_array.h"

#include <openssl/asn1.h>
#include <openssl/bn.h>
#include <openssl/bio.h>
#include <openssl/ec.h>
#include <openssl/x509.h>

// Arbitrary example only - values must be customized/tuned for the SoC
static const uint64_t wdt_timeout = 0xA0000000; // approximately 5s for 500MHz clock
// Arbitrary example only - values must be customized/tuned for the SoC
Expand Down Expand Up @@ -50,6 +56,71 @@ static void caliptra_wait_for_csr_ready(void)
}
}

/*
* caliptra_verify_signature
*
* Uses OpenSSL to verify that the signature returned by `SignWithExportedEcdsa`
* matches the public key in the certificate vended by `DeriveContext`
*
* @return bool True if the signature passes verification, false otherwise
*/
static bool caliptra_verify_ecdsa_signature(struct dpe_derive_context_exported_cdi_response* dpe_resp, struct caliptra_sign_with_exported_ecdsa_resp* sign_resp, uint8_t* tbs, size_t tbs_size)
{
BIO* cert_ptr = BIO_new_mem_buf(dpe_resp->new_certificate, dpe_resp->certificate_size);
X509* x509 = d2i_X509_bio(cert_ptr, NULL);

if (x509 == NULL) {
printf("Error parsing certificate.\n");
return false;
}

EVP_PKEY *pkey = X509_get_pubkey(x509);
if (pkey == NULL) {
printf("Error getting public key.\n");
X509_free(x509);
return false;
}

EC_KEY* ec_pub_key = EVP_PKEY_get1_EC_KEY(pkey);
if (ec_pub_key == NULL) {
printf("Error converting pub key to EC pub key.\n");
return false;
}

BIGNUM* r = BN_bin2bn(sign_resp->signature_r, 48, NULL);
if (r == NULL) {
printf("Error creating ECDSA R.\n");
return false;
}

BIGNUM* s = BN_bin2bn(sign_resp->signature_s, 48, NULL);
if (s == NULL) {
printf("Error creating ECDSA S.\n");
return false;
}

ECDSA_SIG *signature = ECDSA_SIG_new();
if (signature == NULL) {
printf("Error creating signature.\n");
return false;
}
ECDSA_SIG_set0(signature, r, s);

uint8_t *dersig = NULL;
int size = i2d_ECDSA_SIG(signature, &dersig);

if (ECDSA_verify(0, (const unsigned char *)&tbs, sizeof(tbs), dersig, size, ec_pub_key) != 1) {
return false;
}

free(dersig);
ECDSA_SIG_free(signature);
X509_free(x509);
BIO_free(cert_ptr);

return true;
}

void dump_caliptra_error_codes()
{
printf("Caliptra FW error non-fatal code is 0x%x\n", caliptra_read_fw_non_fatal_error());
Expand Down Expand Up @@ -690,6 +761,80 @@ int rom_test_devid_csr(const test_info* info)
return failure;
}

// Verify signing with an exported cdi
int sign_with_exported_ecdsa_cdi(const test_info* info)
{
int failure = 0;
int status = boot_to_ready_for_fw(info, false);

if (status){
dump_caliptra_error_codes();
failure = 1;
}

status = caliptra_upload_fw(&info->image_bundle, false);

if (status)
{
printf("FW Load Failed: 0x%x\n", status);
dump_caliptra_error_codes();
failure = 1;
}

struct dpe_derive_context_cmd derive_context_cmd = { 0 };
derive_context_cmd.cmd_hdr.magic = DPE_MAGIC;
derive_context_cmd.cmd_hdr.cmd_id = DPE_DERIVE_CONTEXT;
derive_context_cmd.cmd_hdr.profile = 0x4;
derive_context_cmd.flags = DPE_DERIVE_CONTEXT_FLAG_EXPORT_CDI | DPE_DERIVE_CONTEXT_FLAG_CREATE_CERTIFICATE;

struct caliptra_invoke_dpe_req dpe_req = { 0 };
dpe_req.derive_context_cmd = derive_context_cmd;
dpe_req.data_size = sizeof(struct dpe_derive_context_cmd);

struct caliptra_invoke_dpe_resp dpe_resp = { 0 };
status = caliptra_invoke_dpe_command(&dpe_req, &dpe_resp, false);

if (status) {
printf("DPE Command failed: 0x%x\n", status);
dump_caliptra_error_codes();
failure = 1;
} else {
printf("DPE Command: OK\n");
}

struct dpe_derive_context_exported_cdi_response* exported_resp = &dpe_resp.derive_context_exported_cdi_resp;

// SHA384 of a 48 bytes of 0s
uint8_t tbs[] = {
0x8f, 0x0d, 0x14, 0x5c, 0x03, 0x68, 0xad, 0x6b, 0x70, 0xbe,
0x22, 0xe4, 0x1c, 0x40, 0x0e, 0xea, 0x91, 0xb9, 0x71, 0xd9,
0x6b, 0xa2, 0x20, 0xfe, 0xc9, 0xfa, 0xe2, 0x5a, 0x58, 0xdf,
0xfd, 0xaa, 0xf7, 0x2d, 0xbe, 0x8f, 0x67, 0x83, 0xd5, 0x51,
0x28, 0xc9, 0xdf, 0x4e, 0xfa, 0xf6, 0xf8, 0xa7
};

struct caliptra_sign_with_exported_ecdsa_req sign_req = { 0 };
memcpy(&sign_req.exported_cdi, exported_resp->exported_cdi, sizeof(uint8_t) * 32);
memcpy(&sign_req.digest, &tbs, sizeof(uint8_t) * 48);

struct caliptra_sign_with_exported_ecdsa_resp sign_resp = { 0 };
status = caliptra_sign_with_exported_ecdsa(&sign_req, &sign_resp, false);

if (status) {
printf("Sign with exported Ecdsa failed: 0x%x\n", status);
return 1;
}

if (caliptra_verify_ecdsa_signature(exported_resp, &sign_resp, tbs, sizeof(tbs))) {
printf("Sign with exported Ecdsa: OK\n");
} else {
printf("Error invalid signature.\n");
failure = 1;
}

return failure;
}

// Issue FW load commands repeatedly
// Coverage for piecewise FW load and runtime FW updates
int upload_fw_piecewise(const test_info* info)
Expand Down Expand Up @@ -820,6 +965,7 @@ int run_tests(const test_info* info)
run_test(rt_test_all_commands, info, "Test all Runtime commmands");
run_test(rom_test_devid_csr, info, "Test IDEV CSR GEN");
run_test(upload_fw_piecewise, info, "Test Piecewise FW Load");
run_test(sign_with_exported_ecdsa_cdi, info, "Test Sign with Exported ECDSA");

if (global_test_result) {
printf("\t\tlibcaliptra test failures reported\n");
Expand Down
2 changes: 1 addition & 1 deletion libcaliptra/examples/hwmodel/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ HWMODEL_DIR = $(OUTPUT_DIR)
HWMODEL_HEADER_DIR = ../../../hw-model/c-binding/out
HWMODEL_INCLUDE = -I$(HWMODEL_HEADER_DIR)
HWMODEL_LIB = -Wl,-L$(HWMODEL_DIR) -lcaliptra_hw_model_c_binding
HWMODEL_FLAGS = -lpthread -lstdc++ -ldl -lrt -lm
HWMODEL_FLAGS = -lpthread -lstdc++ -ldl -lrt -lm -lcrypto
HWMODEL_HEADER = $(HWMODEL_HEADER_DIR)/caliptra_model.h
HWMODEL_BINDING_LIB_OBJ = $(HWMODEL_DIR)/libcaliptra_hw_model_c_binding.a

Expand Down
3 changes: 3 additions & 0 deletions libcaliptra/inc/caliptra_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,9 @@ int caliptra_fips_version(struct caliptra_fips_version_resp *resp, bool async);
// Get IDev CSR
int caliptra_get_idev_csr(struct caliptra_get_idev_csr_resp *resp, bool async);

// Sign with Exported Ecdsa
int caliptra_sign_with_exported_ecdsa(struct caliptra_sign_with_exported_ecdsa_req *req, struct caliptra_sign_with_exported_ecdsa_resp *resp, bool async);

// Self test start
int caliptra_self_test_start(bool async);

Expand Down
5 changes: 5 additions & 0 deletions libcaliptra/inc/caliptra_enums.h
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,11 @@ enum dpe_error_codes {
DPE_RAND_ERROR = 0x1007,
};

enum dpe_derive_context_cmd_flags {
DPE_DERIVE_CONTEXT_FLAG_EXPORT_CDI = ( 1UL << 23),
DPE_DERIVE_CONTEXT_FLAG_CREATE_CERTIFICATE = ( 1UL << 22),
};

#define DPE_PROFILE_256 3
#define DPE_PROFILE_384 4

Expand Down
Loading

0 comments on commit 0410cb0

Please sign in to comment.