Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[rom_ext] Perform ECDSA ans SPX verification in parallel #26160

Open
wants to merge 2 commits into
base: earlgrey_1.0.0
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 26 additions & 7 deletions sw/device/silicon_creator/lib/drivers/otbn.c
Original file line number Diff line number Diff line change
Expand Up @@ -134,19 +134,23 @@ rom_error_t sc_otbn_dmem_read(size_t num_words, sc_otbn_addr_t src,
* @param error Error to return if operation fails.
* @return Result of the operation.
*/
static void sc_otbn_cmd_start(sc_otbn_cmd_t cmd) {
enum {
kIntrStateDone = (1 << OTBN_INTR_COMMON_DONE_BIT),
};
abs_mmio_write32(kBase + OTBN_INTR_STATE_REG_OFFSET, kIntrStateDone);
abs_mmio_write32(kBase + OTBN_CMD_REG_OFFSET, cmd);
}

OT_WARN_UNUSED_RESULT
static rom_error_t sc_otbn_cmd_run(sc_otbn_cmd_t cmd, rom_error_t error) {
static rom_error_t sc_otbn_cmd_finish(rom_error_t error) {
enum {
kIntrStateDone = (1 << OTBN_INTR_COMMON_DONE_BIT),
// Use a bit index that doesn't overlap with error bits.
kResDoneBit = 31,
};
static_assert((UINT32_C(1) << kResDoneBit) > kOtbnErrBitsLast,
"kResDoneBit must not overlap with OTBN error bits");

abs_mmio_write32(kBase + OTBN_INTR_STATE_REG_OFFSET, kIntrStateDone);
abs_mmio_write32(kBase + OTBN_CMD_REG_OFFSET, cmd);

rom_error_t res = kErrorOk ^ (UINT32_C(1) << kResDoneBit);
uint32_t reg = 0;
do {
Expand Down Expand Up @@ -177,7 +181,12 @@ static rom_error_t sc_otbn_cmd_run(sc_otbn_cmd_t cmd, rom_error_t error) {
return error;
}

rom_error_t sc_otbn_execute(void) {
static rom_error_t sc_otbn_cmd_run(sc_otbn_cmd_t cmd, rom_error_t error) {
sc_otbn_cmd_start(cmd);
return sc_otbn_cmd_finish(error);
}

rom_error_t sc_otbn_execute_start(void) {
// If OTBN is busy, wait for it to be done.
HARDENED_RETURN_IF_ERROR(sc_otbn_busy_wait_for_done());

Expand All @@ -187,7 +196,17 @@ rom_error_t sc_otbn_execute(void) {
sec_mmio_write32(kBase + OTBN_CTRL_REG_OFFSET,
1 << OTBN_CTRL_SOFTWARE_ERRS_FATAL_BIT);

return sc_otbn_cmd_run(kScOtbnCmdExecute, kErrorOtbnExecutionFailed);
sc_otbn_cmd_start(kScOtbnCmdExecute);
return kErrorOk;
}

rom_error_t sc_otbn_execute_finish(void) {
return sc_otbn_cmd_finish(kErrorOtbnExecutionFailed);
}

rom_error_t sc_otbn_execute(void) {
HARDENED_RETURN_IF_ERROR(sc_otbn_execute_start());
return sc_otbn_execute_finish();
}

uint32_t sc_otbn_instruction_count_get(void) {
Expand Down
23 changes: 21 additions & 2 deletions sw/device/silicon_creator/lib/drivers/otbn.h
Original file line number Diff line number Diff line change
Expand Up @@ -247,15 +247,34 @@ rom_error_t sc_otbn_dmem_read(size_t num_words, const sc_otbn_addr_t src,
uint32_t *dest);

/**
* Start the execution of the application loaded into OTBN.
* Execute the application loaded into OTBN.
*
* This function blocks until OTBN is idle.
* This function blocks until OTBN is idle and waits for the OTBN application to
* finish.
*
* @return Result of the operation.
*/
OT_WARN_UNUSED_RESULT
rom_error_t sc_otbn_execute(void);

/**
* Start execution of the application loaded into OTBN.
*
* This function blocks until OTBN is idle and then starts the OTBN application.
*
* @return Result of the operation.
*/
OT_WARN_UNUSED_RESULT
rom_error_t sc_otbn_execute_start(void);

/**
* Wait for the OTBN application to finish execution.
*
* @return Result of the operation.
*/
OT_WARN_UNUSED_RESULT
rom_error_t sc_otbn_execute_finish(void);

/**
* Blocks until OTBN is idle.
*
Expand Down
20 changes: 15 additions & 5 deletions sw/device/silicon_creator/lib/otbn_boot_services.c
Original file line number Diff line number Diff line change
Expand Up @@ -273,10 +273,9 @@ rom_error_t otbn_boot_attestation_endorse(const hmac_digest_t *digest,
return kErrorOk;
}

rom_error_t otbn_boot_sigverify(const ecdsa_p256_public_key_t *key,
const ecdsa_p256_signature_t *sig,
const hmac_digest_t *digest,
uint32_t *recovered_r) {
rom_error_t otbn_boot_sigverify_start(const ecdsa_p256_public_key_t *key,
const ecdsa_p256_signature_t *sig,
const hmac_digest_t *digest) {
// Write the mode.
uint32_t mode = kOtbnBootModeSigverify;
HARDENED_RETURN_IF_ERROR(
Expand All @@ -299,9 +298,12 @@ rom_error_t otbn_boot_sigverify(const ecdsa_p256_public_key_t *key,
sig->s, kOtbnVarBootS));

// Start the OTBN routine.
HARDENED_RETURN_IF_ERROR(sc_otbn_execute());
SEC_MMIO_WRITE_INCREMENT(kScOtbnSecMmioExecute);
return sc_otbn_execute_start();
}

rom_error_t otbn_boot_sigverify_finish(uint32_t *recovered_r) {
HARDENED_RETURN_IF_ERROR(sc_otbn_execute_finish());
// Check if the signature passed basic checks.
uint32_t ok;
HARDENED_RETURN_IF_ERROR(sc_otbn_dmem_read(1, kOtbnVarBootOk, &ok));
Expand All @@ -319,3 +321,11 @@ rom_error_t otbn_boot_sigverify(const ecdsa_p256_public_key_t *key,
return sc_otbn_dmem_read(kEcdsaP256SignatureComponentWords, kOtbnVarBootXr,
recovered_r);
}

rom_error_t otbn_boot_sigverify(const ecdsa_p256_public_key_t *key,
const ecdsa_p256_signature_t *sig,
const hmac_digest_t *digest,
uint32_t *recovered_r) {
HARDENED_RETURN_IF_ERROR(otbn_boot_sigverify_start(key, sig, digest));
return otbn_boot_sigverify_finish(recovered_r);
}
29 changes: 29 additions & 0 deletions sw/device/silicon_creator/lib/otbn_boot_services.h
Original file line number Diff line number Diff line change
Expand Up @@ -163,12 +163,41 @@ rom_error_t otbn_boot_attestation_endorse(const hmac_digest_t *digest,
* @param[out] recovered_r Buffer for the recovered `r` value.
* @return The result of the operation.
*/

OT_WARN_UNUSED_RESULT
rom_error_t otbn_boot_sigverify(const ecdsa_p256_public_key_t *key,
const ecdsa_p256_signature_t *sig,
const hmac_digest_t *digest,
uint32_t *recovered_r);

/**
* Start an ECDSA-P256 signature verify on OTBN.
*
* Expects the OTBN boot-services program to already be loaded; see
* `otbn_boot_app_load`.
*
* @param key An ECDSA-P256 public key.
* @param sig An ECDSA-P256 signature.
* @param digest Message digest to check against.
* @return The result of the operation.
*/
OT_WARN_UNUSED_RESULT
rom_error_t otbn_boot_sigverify_start(const ecdsa_p256_public_key_t *key,
const ecdsa_p256_signature_t *sig,
const hmac_digest_t *digest);

/**
* Finish an ECDSA-P256 signature verify on OTBN.
*
* Call after the `start` operation to wait for completion and collect the
* result.
*
* @param[out] recovered_r Buffer for the recovered `r` value.
* @return The result of the operation.
*/
OT_WARN_UNUSED_RESULT
rom_error_t otbn_boot_sigverify_finish(uint32_t *recovered_r);

#ifdef __cplusplus
} // extern "C"
#endif // __cplusplus
Expand Down
22 changes: 17 additions & 5 deletions sw/device/silicon_creator/lib/sigverify/ecdsa_p256_verify.c
Original file line number Diff line number Diff line change
Expand Up @@ -118,13 +118,16 @@ static rom_error_t sigverify_encoded_message_check(
return kErrorSigverifyBadEcdsaSignature;
}

rom_error_t sigverify_ecdsa_p256_verify(const ecdsa_p256_signature_t *signature,
const ecdsa_p256_public_key_t *key,
const hmac_digest_t *act_digest,
rom_error_t sigverify_ecdsa_p256_start(const ecdsa_p256_signature_t *signature,
const ecdsa_p256_public_key_t *key,
const hmac_digest_t *act_digest) {
return otbn_boot_sigverify_start(key, signature, act_digest);
}

rom_error_t sigverify_ecdsa_p256_finish(const ecdsa_p256_signature_t *signature,
uint32_t *flash_exec) {
ecdsa_p256_signature_t recovered_r;
rom_error_t error =
otbn_boot_sigverify(key, signature, act_digest, (uint32_t *)&recovered_r);
rom_error_t error = otbn_boot_sigverify_finish((uint32_t *)&recovered_r);
if (launder32(error) != kErrorOk) {
*flash_exec ^= UINT32_MAX;
return error;
Expand All @@ -133,5 +136,14 @@ rom_error_t sigverify_ecdsa_p256_verify(const ecdsa_p256_signature_t *signature,
return sigverify_encoded_message_check(&recovered_r, signature, flash_exec);
}

rom_error_t sigverify_ecdsa_p256_verify(const ecdsa_p256_signature_t *signature,
const ecdsa_p256_public_key_t *key,
const hmac_digest_t *act_digest,
uint32_t *flash_exec) {
HARDENED_RETURN_IF_ERROR(
sigverify_ecdsa_p256_start(signature, key, act_digest));
return sigverify_ecdsa_p256_finish(signature, flash_exec);
}

// Extern declarations for the inline functions in the header.
extern uint32_t sigverify_ecdsa_p256_success_to_ok(uint32_t v);
24 changes: 24 additions & 0 deletions sw/device/silicon_creator/lib/sigverify/ecdsa_p256_verify.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,30 @@ rom_error_t sigverify_ecdsa_p256_verify(const ecdsa_p256_signature_t *signature,
const hmac_digest_t *act_digest,
uint32_t *flash_exec);

/**
* Starts an ECDSA-P256 signature verification.
*
* @param signature The signature to verify, little endian.
* @param key The public key to use for verification, little endian.
* @param act_digest The actual digest of the signed message.
* @return The result of the operation.
*/
OT_WARN_UNUSED_RESULT
rom_error_t sigverify_ecdsa_p256_start(const ecdsa_p256_signature_t *signature,
const ecdsa_p256_public_key_t *key,
const hmac_digest_t *act_digest);

/**
* Finishes an ECDSA-P256 signature verification.
*
* @param signature The signature to verify, little endian.
* @param[out] flash_exec The partial value to write to the flash_ctrl EXEC
* register.
* @return The result of the operation.
*/
OT_WARN_UNUSED_RESULT
rom_error_t sigverify_ecdsa_p256_finish(const ecdsa_p256_signature_t *signature,
uint32_t *flash_exec);
/**
* Transforms `kSigverifyEcdsaSuccess` into `kErrorOk`.
*
Expand Down
17 changes: 12 additions & 5 deletions sw/device/silicon_creator/rom_ext/rom_ext.c
Original file line number Diff line number Diff line change
Expand Up @@ -520,16 +520,23 @@ static rom_error_t rom_ext_verify(const manifest_t *manifest,
} else if ((key_alg & kOwnershipKeyAlgCategoryMask) ==
kOwnershipKeyAlgCategoryHybrid) {
// Hybrid signatures check both ECDSA and SPX+ signatures.
// TODO: as a future optimization, start the ECDSA verify operation on
// OTBN and compute the SPX+ verify in parallel on Ibex.
HARDENED_RETURN_IF_ERROR(sigverify_ecdsa_p256_verify(
// Start the ECDSA verify.
HARDENED_RETURN_IF_ERROR(sigverify_ecdsa_p256_start(
&manifest->ecdsa_signature, &keyring.key[verify_key]->data.hybrid.ecdsa,
&act_digest, &flash_exec));
return rom_ext_spx_verify(
&act_digest));
// While ECDSA verify is running in OTBN, compute the SPX verify on Ibex.
rom_error_t spx = rom_ext_spx_verify(
&ext_spx_signature->signature,
&keyring.key[verify_key]->data.hybrid.spx, key_alg,
&usage_constraints_from_hw, sizeof(usage_constraints_from_hw), NULL, 0,
digest_region.start, digest_region.length, act_digest);
// ECDSA should be finished. Poll for completeion and get the result.
rom_error_t ecdsa =
sigverify_ecdsa_p256_finish(&manifest->ecdsa_signature, &flash_exec);
HARDENED_RETURN_IF_ERROR(spx);
HARDENED_RETURN_IF_ERROR(ecdsa);
// Both values should be kErrorOk. Mix them and return the result.
return (rom_error_t)((spx + ecdsa) >> 1);
} else {
// TODO: consider whether an SPX+-only verify is sufficent.
return kErrorOwnershipInvalidAlgorithm;
Expand Down
Loading