diff --git a/sw/lib/sw/device/silicon_creator/BUILD b/sw/lib/sw/device/silicon_creator/BUILD index ae85b613a7213..ecb7a66c4629e 100644 --- a/sw/lib/sw/device/silicon_creator/BUILD +++ b/sw/lib/sw/device/silicon_creator/BUILD @@ -107,6 +107,7 @@ cc_library( "//sw/lib/sw/device/base:hardened_memory", "//sw/lib/sw/device/base:macros", "//sw/lib/sw/device/base:multibits", + "//sw/lib/sw/device/silicon_creator:otbn_boot_services", "//sw/lib/sw/device/silicon_creator:dbg_print", "//sw/lib/sw/device/silicon_creator/sigverify", ], @@ -140,6 +141,27 @@ dual_cc_library( ), ) +cc_library( + name = "attestation", + hdrs = ["attestation.h"], +) + +cc_library( + name = "otbn_boot_services", + srcs = ["otbn_boot_services.c"], + hdrs = ["otbn_boot_services.h"], + # This target uses OTBN pointers internally, so it cannot work host-side. + target_compatible_with = [OPENTITAN_CPU], + deps = [ + ":attestation", + "//sw/lib/sw/device/base:macros", + "//sw/device/silicon_creator/lib/drivers:hmac", + "//sw/device/silicon_creator/lib/drivers:otbn", + "//sw/otbn/crypto:boot", + "//sw/lib/sw/device/silicon_creator:dbg_print", + ], +) + exports_files([ "boot_data.h", "boot_data.c", @@ -155,6 +177,7 @@ exports_files([ "mock_boot_data.h", "mock_manifest.h", "mock_shutdown.h", + "otbn_boot_services_functest.c", "rom_patch.c", "rom_patch.h", "shutdown.c", diff --git a/sw/lib/sw/device/silicon_creator/attestation.h b/sw/lib/sw/device/silicon_creator/attestation.h new file mode 100644 index 0000000000000..556ba33a4cbdd --- /dev/null +++ b/sw/lib/sw/device/silicon_creator/attestation.h @@ -0,0 +1,118 @@ +// Copyright lowRISC contributors (OpenTitan project). +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +#ifndef OPENTITAN_SW_LIB_SW_DEVICE_SILICON_CREATOR_ATTESTATION_H_ +#define OPENTITAN_SW_LIB_SW_DEVICE_SILICON_CREATOR_ATTESTATION_H_ + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +enum { + /** + * Size of the additional seed for attestation key generation in bits. + */ + kAttestationSeedBits = 320, + /** + * Size of the additional seed for attestation key generation in bytes. + */ + kAttestationSeedBytes = kAttestationSeedBits / 8, + /** + * Size of the additional seed for attestation key generation in 32b words. + */ + kAttestationSeedWords = kAttestationSeedBytes / sizeof(uint32_t), + /** + * Size of a coordinate for an attestation public key in bits. + */ + kAttestationPublicKeyCoordBits = 256, + /** + * Size of a coordinate for an attestation public key in bytes. + */ + kAttestationPublicKeyCoordBytes = kAttestationPublicKeyCoordBits / 8, + /** + * Size of a coordinate for an attestation public key in 32b words. + */ + kAttestationPublicKeyCoordWords = + kAttestationPublicKeyCoordBytes / sizeof(uint32_t), + /** + * Size of an attestation signature component in bits. + */ + kAttestationSignatureComponentBits = 256, + /** + * Size of an attestation signature component in bytes. + */ + kAttestationSignatureComponentBytes = kAttestationSignatureComponentBits / 8, + /** + * Size of an attestation signature component in 32b words. + */ + kAttestationSignatureComponentWords = + kAttestationSignatureComponentBytes / sizeof(uint32_t), + /** + * Size of an attestation signature in bits. + */ + kAttestationSignatureBits = kAttestationSignatureComponentBits * 2, + /** + * Size of an attestation signature in bytes. + */ + kAttestationSignatureBytes = kAttestationSignatureBits / 8, + /** + * Size of an attestation signature in 32b words. + */ + kAttestationSignatureWords = kAttestationSignatureBytes / sizeof(uint32_t), +}; + +typedef enum { + /** + * The UDS attestation key seed. + */ + kUdsAttestationKeySeed = 0, + /** + * The CDI_0 attestation key seed. + */ + kCdi0AttestationKeySeed = 1, + /** + * The CDI_1 attestation key seed. + */ + kCdi1AttestationKeySeed = 2, + /** + * The TPM EK attestation key seed. + */ + kTpmEkAttestationKeySeed = 3, + /** + * The TPM CEK attestation key seed. + */ + kTpmCekAttestationKeySeed = 4, + /** + * The TPM CIK attestation key seed. + */ + kTpmCikAttestationKeySeed = 5, +} attestation_key_seed_t; + +/** + * Holds an attestation public key (ECDSA-P256). + */ +typedef struct attestation_public_key { + /** + * Affine x-coordinate of the point. + */ + uint32_t x[kAttestationPublicKeyCoordWords]; + /** + * Affine y-coordinate of the point. + */ + uint32_t y[kAttestationPublicKeyCoordWords]; +} attestation_public_key_t; + +/** + * Holds an attestation signature (ECDSA-P256). + */ +typedef struct attestation_signature { + uint32_t r[kAttestationSignatureComponentWords]; + uint32_t s[kAttestationSignatureComponentWords]; +} attestation_signature_t; + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus + +#endif // OPENTITAN_SW_LIB_SW_DEVICE_SILICON_CREATOR_ATTESTATION_H_ diff --git a/sw/lib/sw/device/silicon_creator/error.h b/sw/lib/sw/device/silicon_creator/error.h index 51a933e585652..6d543c8d22a79 100644 --- a/sw/lib/sw/device/silicon_creator/error.h +++ b/sw/lib/sw/device/silicon_creator/error.h @@ -81,6 +81,9 @@ enum module_ { X(kErrorSigverifyBadRsaKey, ERROR_(4, kModuleSigverify, kInvalidArgument)), \ X(kErrorSigverifyBadSpxKey, ERROR_(5, kModuleSigverify, kInvalidArgument)), \ X(kErrorSigverifyLargeRsaSignature, ERROR_(6, kModuleSigverify, kInvalidArgument)), \ + X(kErrorSigverifyBadEcdsaSignature, ERROR_(7, kModuleSigverify, kInvalidArgument)), \ + X(kErrorSigverifyBadAuthPartition, ERROR_(8, kModuleSigverify, kInvalidArgument)), \ + X(kErrorSigverifyBadEcdsaKey, ERROR_(9, kModuleSigverify, kInvalidArgument)), \ \ X(kErrorKeymgrInternal, ERROR_(1, kModuleKeymgr, kInternal)), \ \ diff --git a/sw/lib/sw/device/silicon_creator/otbn_boot_services.c b/sw/lib/sw/device/silicon_creator/otbn_boot_services.c new file mode 100644 index 0000000000000..26a82f4c45a2c --- /dev/null +++ b/sw/lib/sw/device/silicon_creator/otbn_boot_services.c @@ -0,0 +1,95 @@ +// Copyright lowRISC contributors (OpenTitan project). +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +#include "sw/lib/sw/device/silicon_creator/otbn_boot_services.h" + +#include "sw/device/silicon_creator/lib/drivers/hmac.h" +#include "sw/device/silicon_creator/lib/drivers/otbn.h" +#include "sw/lib/sw/device/silicon_creator/attestation.h" +#include "sw/lib/sw/device/silicon_creator/base/sec_mmio.h" +#include "sw/lib/sw/device/silicon_creator/dbg_print.h" + +#include "otbn_regs.h" // Generated. + +OTBN_DECLARE_APP_SYMBOLS(boot); // The OTBN boot-services app. +OTBN_DECLARE_SYMBOL_ADDR(boot, mode); // Application mode. +OTBN_DECLARE_SYMBOL_ADDR(boot, msg); // ECDSA message digest. +OTBN_DECLARE_SYMBOL_ADDR(boot, x); // ECDSA public key x-coordinate. +OTBN_DECLARE_SYMBOL_ADDR(boot, y); // ECDSA public key y-coordinate. +OTBN_DECLARE_SYMBOL_ADDR(boot, r); // ECDSA signature component r. +OTBN_DECLARE_SYMBOL_ADDR(boot, s); // ECDSA signature component s. +OTBN_DECLARE_SYMBOL_ADDR(boot, x_r); // ECDSA verification result. +OTBN_DECLARE_SYMBOL_ADDR(boot, ok); // ECDSA verification status. + +static const sc_otbn_app_t kOtbnAppBoot = OTBN_APP_T_INIT(boot); +static const sc_otbn_addr_t kOtbnVarBootMode = OTBN_ADDR_T_INIT(boot, mode); +static const sc_otbn_addr_t kOtbnVarBootMsg = OTBN_ADDR_T_INIT(boot, msg); +static const sc_otbn_addr_t kOtbnVarBootX = OTBN_ADDR_T_INIT(boot, x); +static const sc_otbn_addr_t kOtbnVarBootY = OTBN_ADDR_T_INIT(boot, y); +static const sc_otbn_addr_t kOtbnVarBootR = OTBN_ADDR_T_INIT(boot, r); +static const sc_otbn_addr_t kOtbnVarBootS = OTBN_ADDR_T_INIT(boot, s); +static const sc_otbn_addr_t kOtbnVarBootXr = OTBN_ADDR_T_INIT(boot, x_r); +static const sc_otbn_addr_t kOtbnVarBootOk = OTBN_ADDR_T_INIT(boot, ok); + +enum { + /* + * Mode is represented by a single word. + */ + kOtbnBootModeWords = 1, + /* + * Mode to run signature verification. + * + * Value taken from `boot.s`. + */ + kOtbnBootModeSigverify = 0x7d3, +}; + +rom_error_t otbn_boot_app_load(void) { return sc_otbn_load_app(kOtbnAppBoot); } + +rom_error_t otbn_boot_sigverify(const attestation_public_key_t *key, + const attestation_signature_t *sig, + const hmac_digest_t *digest, + uint32_t *recovered_r) { + // Write the mode. + uint32_t mode = kOtbnBootModeSigverify; + HARDENED_RETURN_IF_ERROR( + sc_otbn_dmem_write(kOtbnBootModeWords, &mode, kOtbnVarBootMode)); + + // Write the public key. + HARDENED_RETURN_IF_ERROR(sc_otbn_dmem_write(kAttestationPublicKeyCoordWords, + key->x, kOtbnVarBootX)); + HARDENED_RETURN_IF_ERROR(sc_otbn_dmem_write(kAttestationPublicKeyCoordWords, + key->y, kOtbnVarBootY)); + + // Write the message digest. + HARDENED_RETURN_IF_ERROR( + sc_otbn_dmem_write(kHmacDigestNumWords, digest->digest, kOtbnVarBootMsg)); + + // Write the signature. + HARDENED_RETURN_IF_ERROR(sc_otbn_dmem_write( + kAttestationSignatureComponentWords, sig->r, kOtbnVarBootR)); + HARDENED_RETURN_IF_ERROR(sc_otbn_dmem_write( + kAttestationSignatureComponentWords, sig->s, kOtbnVarBootS)); + + // Start the OTBN routine. + HARDENED_RETURN_IF_ERROR(sc_otbn_execute()); + SEC_MMIO_WRITE_INCREMENT(kScOtbnSecMmioExecute); + + // Check if the signature passed basic checks. + uint32_t ok; + HARDENED_RETURN_IF_ERROR(sc_otbn_dmem_read(1, kOtbnVarBootOk, &ok)); + if (launder32(ok) != kHardenedBoolTrue) { + return kErrorSigverifyBadEcdsaSignature; + } + + // Read the status value again as an extra hardening measure. + HARDENED_RETURN_IF_ERROR(sc_otbn_dmem_read(1, kOtbnVarBootOk, &ok)); + HARDENED_CHECK_EQ(ok, kHardenedBoolTrue); + + // TODO(#20023): Check the instruction count register (see `mod_exp_otbn`). + + // Read the recovered `r` value from DMEM. + return sc_otbn_dmem_read(kAttestationSignatureComponentWords, kOtbnVarBootXr, + recovered_r); +} diff --git a/sw/lib/sw/device/silicon_creator/otbn_boot_services.h b/sw/lib/sw/device/silicon_creator/otbn_boot_services.h new file mode 100644 index 0000000000000..82778aeee4cce --- /dev/null +++ b/sw/lib/sw/device/silicon_creator/otbn_boot_services.h @@ -0,0 +1,57 @@ +// Copyright lowRISC contributors (OpenTitan project). +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +#ifndef OPENTITAN_SW_LIB_SW_DEVICE_SILICON_CREATOR_LIB_OTBN_BOOT_SERVICES_H_ +#define OPENTITAN_SW_LIB_SW_DEVICE_SILICON_CREATOR_LIB_OTBN_BOOT_SERVICES_H_ + +#include +#include + +#include "sw/device/silicon_creator/lib/drivers/hmac.h" +#include "sw/lib/sw/device/silicon_creator/attestation.h" + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +/** + * Loads the OTBN boot-services application. + * + * Loads the OTBN program that runs attestation and code-signature + * verification. The program can later be cleared by wiping OTBN's IMEM and + * DMEM, or by loading a diffierent OTBN application. + * + * @return The result of the operation. + */ +OT_WARN_UNUSED_RESULT +rom_error_t otbn_boot_app_load(void); + +/** + * Computes an ECDSA-P256 signature verification on OTBN. + * + * May be used for code signatures as well as attestation signatures. Returns + * the recovered `r` value in `result`. The signature is valid if this `r` + * value matches the `r` component of the signature, but the caller is + * responsible for the final comparison. + * + * 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. + * @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 attestation_public_key_t *key, + const attestation_signature_t *sig, + const hmac_digest_t *digest, + uint32_t *recovered_r); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus + +#endif // OPENTITAN_SW_LIB_SW_DEVICE_SILICON_CREATOR_LIB_OTBN_BOOT_SERVICES_H_ diff --git a/sw/lib/sw/device/silicon_creator/otbn_boot_services_functest.c b/sw/lib/sw/device/silicon_creator/otbn_boot_services_functest.c new file mode 100644 index 0000000000000..89b5f6e349e37 --- /dev/null +++ b/sw/lib/sw/device/silicon_creator/otbn_boot_services_functest.c @@ -0,0 +1,60 @@ +// Copyright lowRISC contributors (OpenTitan project). +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +#include "sw/device/lib/testing/test_framework/check.h" +#include "sw/device/lib/testing/test_framework/ottf_main.h" +#include "sw/device/lib/testing/test_framework/status.h" +#include "sw/device/silicon_creator/lib/drivers/hmac.h" +#include "sw/lib/sw/device/silicon_creator/otbn_boot_services.h" + +#include "hw/top_darjeeling/sw/autogen/top_darjeeling.h" // Generated. + +OTTF_DEFINE_TEST_CONFIG(); + +// Message value for signature generation/verification tests. +const char kTestMessage[] = "Test message."; +const size_t kTestMessageLen = sizeof(kTestMessage) - 1; + +// Valid ECDSA-P256 public key. +static const attestation_public_key_t kEcdsaKey = { + .x = {0x1ceb402b, 0x9dc600d1, 0x182ec21b, 0x5ede3640, 0x3566bdac, + 0x1debf94b, 0x1a286a75, 0x8904d749}, + .y = {0x63eab6dc, 0x0c53bf99, 0x086d3ee7, 0x1076efa6, 0x8dd8ece2, + 0xbfececf0, 0x9b94e34d, 0x59b12f3c}, +}; + +// Valid ECDSA-P256 signature for `kTestMessage`. +static const attestation_signature_t kEcdsaSignature = { + .r = {0x4811545a, 0x088d927b, 0x5d8624b5, 0x2ef1f329, 0x184ba14a, + 0xf655eede, 0xaaed0d54, 0xa20e1ac7}, + .s = {0x729b945d, 0x181dc116, 0x1025dba4, 0xb99828a0, 0xe7225df3, + 0x0e200e9b, 0x785690b4, 0xf47efe98}}; + +rom_error_t sigverify_test(void) { + // Hash the test message. + hmac_digest_t digest; + + hmac_sha256_init(); + hmac_sha256_update(kTestMessage, kTestMessageLen); + hmac_sha256_final(&digest); + + // The recovered `r` value from sigverify should be equal to the signature + // `r` value. + uint32_t recovered_r[kAttestationSignatureComponentWords]; + RETURN_IF_ERROR( + otbn_boot_sigverify(&kEcdsaKey, &kEcdsaSignature, &digest, recovered_r)); + CHECK_ARRAYS_EQ(recovered_r, kEcdsaSignature.r, ARRAYSIZE(kEcdsaSignature.r)); + return kErrorOk; +} + +bool test_main(void) { + status_t result = OK_STATUS(); + + // Load the boot services OTBN app. + CHECK(otbn_boot_app_load() == kErrorOk); + + EXECUTE_TEST(result, sigverify_test); + + return status_ok(result); +} diff --git a/sw/top_darjeeling/sw/device/silicon_creator/BUILD b/sw/top_darjeeling/sw/device/silicon_creator/BUILD index fc35092428a06..8eb1b3a182cdb 100644 --- a/sw/top_darjeeling/sw/device/silicon_creator/BUILD +++ b/sw/top_darjeeling/sw/device/silicon_creator/BUILD @@ -333,3 +333,24 @@ opentitan_functest( "//sw/top_darjeeling/sw/device/runtime:print", ], ) + +opentitan_functest( + name = "otbn_boot_services_functest", + srcs = ["//sw/lib/sw/device/silicon_creator:otbn_boot_services_functest.c"], + targets = [ + "dv", + "verilator", + ], + test_in_second_rom = True, + deps = [ + "//sw/device/lib/testing/test_framework:check", + "//sw/device/lib/testing/test_framework:ottf_main", + "//sw/device/lib/testing/test_framework:ottf_test_config", + "//sw/device/lib/testing/test_framework:status", + "//sw/device/lib/testing/test_rom:second_rom_linker_script", + "//sw/device/lib/testing/test_rom:test_second_rom_lib", + "//sw/device/silicon_creator/lib/drivers:hmac", + "//sw/lib/sw/device/silicon_creator:otbn_boot_services", + "//hw/top_darjeeling/sw/autogen:top_darjeeling", + ], +)