diff --git a/sw/device/lib/crypto/impl/BUILD b/sw/device/lib/crypto/impl/BUILD index 66e85ca8880fa..19335a649e528 100644 --- a/sw/device/lib/crypto/impl/BUILD +++ b/sw/device/lib/crypto/impl/BUILD @@ -51,9 +51,8 @@ cc_library( ":keyblob", "//sw/device/lib/crypto/drivers:entropy", "//sw/device/lib/crypto/drivers:hmac", - "//sw/device/lib/crypto/impl/ecc:ecdh_p384", - "//sw/device/lib/crypto/impl/ecc:ecdsa_p384", "//sw/device/lib/crypto/impl/ecc:p256", + "//sw/device/lib/crypto/impl/ecc:p384", "//sw/device/lib/crypto/include:datatypes", ], ) diff --git a/sw/device/lib/crypto/impl/ecc.c b/sw/device/lib/crypto/impl/ecc.c index de185f1d096f2..e7f491e5c82d7 100644 --- a/sw/device/lib/crypto/impl/ecc.c +++ b/sw/device/lib/crypto/impl/ecc.c @@ -6,9 +6,8 @@ #include "sw/device/lib/crypto/drivers/entropy.h" #include "sw/device/lib/crypto/drivers/hmac.h" -#include "sw/device/lib/crypto/impl/ecc/ecdh_p384.h" -#include "sw/device/lib/crypto/impl/ecc/ecdsa_p384.h" #include "sw/device/lib/crypto/impl/ecc/p256.h" +#include "sw/device/lib/crypto/impl/ecc/p384.h" #include "sw/device/lib/crypto/impl/integrity.h" #include "sw/device/lib/crypto/impl/keyblob.h" #include "sw/device/lib/crypto/include/datatypes.h" @@ -155,11 +154,11 @@ otcrypto_status_t otcrypto_ecdsa_keygen_async_start( if (launder32(private_key->config.hw_backed) == kHardenedBoolTrue) { HARDENED_CHECK_EQ(private_key->config.hw_backed, kHardenedBoolTrue); HARDENED_TRY(sideload_key_seed(private_key)); - return ecdsa_p384_sideload_keygen_start(); + return p384_sideload_keygen_start(); } else if (launder32(private_key->config.hw_backed) == kHardenedBoolFalse) { HARDENED_CHECK_EQ(private_key->config.hw_backed, kHardenedBoolFalse); - return ecdsa_p384_keygen_start(); + return p384_keygen_start(); } else { return OTCRYPTO_BAD_ARGS; } @@ -369,18 +368,19 @@ static status_t internal_p256_keygen_finalize( } /** - * Finalize an ECDSA key generation operation for curve P-384. + * Finalize a keypair generation operation for curve P-384. * * This function assumes that space is already allocated for all key material * and that the length parameters on the structs are set accordingly, in the - * same way as for `otcrypto_ecdsa_keygen_async_finalize`. + * same way as for `otcrypto_ecdh_keygen_async_finalize` and + * `otcrypto_ecdsa_keygen_async_finalize`. * * @param[out] private_key Private key to populate. * @param[out] public_key Public key to populate. * @return OK or error. */ OT_WARN_UNUSED_RESULT -static status_t internal_ecdsa_p384_keygen_finalize( +static status_t internal_p384_keygen_finalize( otcrypto_blinded_key_t *private_key, otcrypto_unblinded_key_t *public_key) { // Check the lengths of caller-allocated buffers. HARDENED_TRY(p384_private_key_length_check(private_key)); @@ -395,7 +395,7 @@ static status_t internal_ecdsa_p384_keygen_finalize( // be the last potentially error-causing line before returning to the // caller. HARDENED_CHECK_EQ(private_key->config.hw_backed, kHardenedBoolTrue); - HARDENED_TRY(ecdsa_p384_sideload_keygen_finalize(pk)); + HARDENED_TRY(p384_sideload_keygen_finalize(pk)); } else if (launder32(private_key->config.hw_backed) == kHardenedBoolFalse) { p384_masked_scalar_t *sk = (p384_masked_scalar_t *)private_key->keyblob; // Note: This operation wipes DMEM after retrieving the keys, so if an error @@ -403,7 +403,7 @@ static status_t internal_ecdsa_p384_keygen_finalize( // be the last potentially error-causing line before returning to the // caller. HARDENED_CHECK_EQ(private_key->config.hw_backed, kHardenedBoolFalse); - HARDENED_TRY(ecdsa_p384_keygen_finalize(sk, pk)); + HARDENED_TRY(p384_keygen_finalize(sk, pk)); private_key->checksum = integrity_blinded_checksum(private_key); } else { return OTCRYPTO_BAD_ARGS; @@ -440,8 +440,7 @@ otcrypto_status_t otcrypto_ecdsa_keygen_async_finalize( case kOtcryptoEccCurveTypeNistP384: HARDENED_CHECK_EQ(elliptic_curve->curve_type, kOtcryptoEccCurveTypeNistP384); - HARDENED_TRY( - internal_ecdsa_p384_keygen_finalize(private_key, public_key)); + HARDENED_TRY(internal_p384_keygen_finalize(private_key, public_key)); break; case kEccCurveTypeBrainpoolP256R1: OT_FALLTHROUGH_INTENDED; @@ -516,12 +515,12 @@ static status_t internal_ecdsa_p384_sign_start( // Start the asynchronous signature-generation routine. HARDENED_CHECK_EQ(private_key->config.hw_backed, kHardenedBoolFalse); p384_masked_scalar_t *sk = (p384_masked_scalar_t *)private_key->keyblob; - return ecdsa_p384_sign_start(message_digest.data, sk); + return p384_ecdsa_sign_start(message_digest.data, sk); } else if (launder32(private_key->config.hw_backed) == kHardenedBoolTrue) { // Load the key and start in sideloaded-key mode. HARDENED_CHECK_EQ(private_key->config.hw_backed, kHardenedBoolTrue); HARDENED_TRY(sideload_key_seed(private_key)); - return ecdsa_p384_sideload_sign_start(message_digest.data); + return p384_ecdsa_sideload_sign_start(message_digest.data); } // Invalid value for private_key->hw_backed. @@ -604,7 +603,7 @@ static status_t p256_signature_length_check(size_t len) { * Check the length of a signature buffer for ECDSA with P-384. * * If this check passes on `signature.len`, it is safe to interpret - * `signature.data` as `ecdsa_p384_signature_t *`. + * `signature.data` as `p384_ecdsa_signature_t *`. * * @param len Length to check. * @return OK if the lengths are correct or BAD_ARGS otherwise. @@ -612,10 +611,10 @@ static status_t p256_signature_length_check(size_t len) { OT_WARN_UNUSED_RESULT static status_t p384_signature_length_check(size_t len) { if (launder32(len) > UINT32_MAX / sizeof(uint32_t) || - launder32(len) * sizeof(uint32_t) != sizeof(ecdsa_p384_signature_t)) { + launder32(len) * sizeof(uint32_t) != sizeof(p384_ecdsa_signature_t)) { return OTCRYPTO_BAD_ARGS; } - HARDENED_CHECK_EQ(len * sizeof(uint32_t), sizeof(ecdsa_p384_signature_t)); + HARDENED_CHECK_EQ(len * sizeof(uint32_t), sizeof(p384_ecdsa_signature_t)); return OTCRYPTO_OK; } @@ -644,12 +643,12 @@ otcrypto_status_t otcrypto_ecdsa_sign_async_finalize( HARDENED_CHECK_EQ(elliptic_curve->curve_type, kOtcryptoEccCurveTypeNistP384); HARDENED_TRY(p384_signature_length_check(signature.len)); - ecdsa_p384_signature_t *sig_p384 = - (ecdsa_p384_signature_t *)signature.data; + p384_ecdsa_signature_t *sig_p384 = + (p384_ecdsa_signature_t *)signature.data; // Note: This operation wipes DMEM, so if an error occurs after this // point then the signature would be unrecoverable. This should be the // last potentially error-causing line before returning to the caller. - HARDENED_TRY(ecdsa_p384_sign_finalize(sig_p384)); + HARDENED_TRY(p384_ecdsa_sign_finalize(sig_p384)); break; case kEccCurveTypeBrainpoolP256R1: OT_FALLTHROUGH_INTENDED; @@ -720,10 +719,10 @@ static status_t internal_ecdsa_p384_verify_start( // Check the signature lengths. HARDENED_TRY(p384_signature_length_check(signature.len)); - ecdsa_p384_signature_t *sig = (ecdsa_p384_signature_t *)signature.data; + p384_ecdsa_signature_t *sig = (p384_ecdsa_signature_t *)signature.data; // Start the asynchronous signature-verification routine. - return ecdsa_p384_verify_start(sig, message_digest.data, pk); + return p384_ecdsa_verify_start(sig, message_digest.data, pk); } otcrypto_status_t otcrypto_ecdsa_verify_async_start( @@ -799,9 +798,9 @@ otcrypto_status_t otcrypto_ecdsa_verify_async_finalize( HARDENED_CHECK_EQ(elliptic_curve->curve_type, kOtcryptoEccCurveTypeNistP384); HARDENED_TRY(p384_signature_length_check(signature.len)); - ecdsa_p384_signature_t *sig_p384 = - (ecdsa_p384_signature_t *)signature.data; - return ecdsa_p384_verify_finalize(sig_p384, verification_result); + p384_ecdsa_signature_t *sig_p384 = + (p384_ecdsa_signature_t *)signature.data; + return p384_ecdsa_verify_finalize(sig_p384, verification_result); case kEccCurveTypeBrainpoolP256R1: OT_FALLTHROUGH_INTENDED; case kOtcryptoEccCurveTypeCustom: @@ -853,11 +852,11 @@ otcrypto_status_t otcrypto_ecdh_keygen_async_start( if (launder32(private_key->config.hw_backed) == kHardenedBoolTrue) { HARDENED_CHECK_EQ(private_key->config.hw_backed, kHardenedBoolTrue); HARDENED_TRY(sideload_key_seed(private_key)); - return ecdh_p384_sideload_keypair_start(); + return p384_sideload_keygen_start(); } else if (launder32(private_key->config.hw_backed) == kHardenedBoolFalse) { HARDENED_CHECK_EQ(private_key->config.hw_backed, kHardenedBoolFalse); - return ecdh_p384_keypair_start(); + return p384_keygen_start(); } return OTCRYPTO_BAD_ARGS; case kEccCurveTypeBrainpoolP256R1: @@ -874,49 +873,6 @@ otcrypto_status_t otcrypto_ecdh_keygen_async_start( return OTCRYPTO_FATAL_ERR; } -/** - * Finalize an ECDH keypair generation operation for curve P-384. - * - * This function assumes that space is already allocated for all key material - * and that the length parameters on the structs are set accordingly, in the - * same way as for `otcrypto_ecdh_keygen_async_finalize`. - * - * @param[out] private_key Private key to populate. - * @param[out] public_key Public key to populate. - * @return OK or error. - */ -OT_WARN_UNUSED_RESULT -static status_t internal_ecdh_p384_keygen_finalize( - otcrypto_blinded_key_t *private_key, otcrypto_unblinded_key_t *public_key) { - // Check the lengths of caller-allocated buffers. - HARDENED_TRY(p384_private_key_length_check(private_key)); - HARDENED_TRY(p384_public_key_length_check(public_key)); - p384_point_t *pk = (p384_point_t *)public_key->key; - - // Note: The `finalize` operations wipe DMEM after retrieving the keys, so if - // an error occurs after this point then the keys would be unrecoverable. - // The `finalize` call should be the last potentially error-causing line - // before returning to the caller. - - if (launder32(private_key->config.hw_backed) == kHardenedBoolTrue) { - HARDENED_CHECK_EQ(private_key->config.hw_backed, kHardenedBoolTrue); - HARDENED_TRY(ecdh_p384_sideload_keypair_finalize(pk)); - } else if (launder32(private_key->config.hw_backed) == kHardenedBoolFalse) { - HARDENED_CHECK_EQ(private_key->config.hw_backed, kHardenedBoolFalse); - p384_masked_scalar_t *sk = (p384_masked_scalar_t *)private_key->keyblob; - HARDENED_TRY(ecdh_p384_keypair_finalize(sk, pk)); - private_key->checksum = integrity_blinded_checksum(private_key); - } else { - return OTCRYPTO_BAD_ARGS; - } - - // Prepare the public key. - public_key->checksum = integrity_unblinded_checksum(public_key); - - // Clear the OTBN sideload slot (in case the seed was sideloaded). - return keymgr_sideload_clear_otbn(); -} - otcrypto_status_t otcrypto_ecdh_keygen_async_finalize( const otcrypto_ecc_curve_t *elliptic_curve, otcrypto_blinded_key_t *private_key, otcrypto_unblinded_key_t *public_key) { @@ -944,7 +900,7 @@ otcrypto_status_t otcrypto_ecdh_keygen_async_finalize( case kOtcryptoEccCurveTypeNistP384: HARDENED_CHECK_EQ(elliptic_curve->curve_type, kOtcryptoEccCurveTypeNistP384); - HARDENED_TRY(internal_ecdh_p384_keygen_finalize(private_key, public_key)); + HARDENED_TRY(internal_p384_keygen_finalize(private_key, public_key)); break; case kEccCurveTypeBrainpoolP256R1: OT_FALLTHROUGH_INTENDED; @@ -1006,11 +962,11 @@ static status_t internal_ecdh_p384_start( if (launder32(private_key->config.hw_backed) == kHardenedBoolTrue) { HARDENED_CHECK_EQ(private_key->config.hw_backed, kHardenedBoolTrue); HARDENED_TRY(sideload_key_seed(private_key)); - return ecdh_p384_sideload_shared_key_start(pk); + return p384_sideload_ecdh_start(pk); } else if (launder32(private_key->config.hw_backed) == kHardenedBoolFalse) { HARDENED_CHECK_EQ(private_key->config.hw_backed, kHardenedBoolFalse); p384_masked_scalar_t *sk = (p384_masked_scalar_t *)private_key->keyblob; - return ecdh_p384_shared_key_start(sk, pk); + return p384_ecdh_start(sk, pk); } // Invalid value for `hw_backed`. @@ -1155,8 +1111,8 @@ static status_t internal_ecdh_p384_finalize( // Note: This operation wipes DMEM after retrieving the keys, so if an error // occurs after this point then the keys would be unrecoverable. This should // be the last potentially error-causing line before returning to the caller. - ecdh_p384_shared_key_t ss; - HARDENED_TRY(ecdh_p384_shared_key_finalize(&ss)); + p384_ecdh_shared_key_t ss; + HARDENED_TRY(p384_ecdh_finalize(&ss)); keyblob_from_shares(ss.share0, ss.share1, shared_secret->config, shared_secret->keyblob); diff --git a/sw/device/lib/crypto/impl/ecc/BUILD b/sw/device/lib/crypto/impl/ecc/BUILD index bb0b3f7553282..5d6dd36e12780 100644 --- a/sw/device/lib/crypto/impl/ecc/BUILD +++ b/sw/device/lib/crypto/impl/ecc/BUILD @@ -21,78 +21,15 @@ cc_library( ) cc_library( - name = "ecdh_p384", - srcs = ["ecdh_p384.c"], - hdrs = ["ecdh_p384.h"], + name = "p384", + srcs = ["p384.c"], + hdrs = ["p384.h"], target_compatible_with = [OPENTITAN_CPU], deps = [ - ":p384_common", "//sw/device/lib/base:hardened", "//sw/device/lib/base:hardened_memory", - "//sw/device/lib/crypto/drivers:otbn", - "//sw/otbn/crypto:p384_ecdh", - ], -) - -cc_library( - name = "ecdsa_p384", - hdrs = ["ecdsa_p384.h"], - target_compatible_with = [OPENTITAN_CPU], - deps = [ - ":ecdsa_p384_keygen", - ":ecdsa_p384_sign", - ":ecdsa_p384_verify", - ], -) - -cc_library( - name = "ecdsa_p384_keygen", - srcs = ["ecdsa_p384_keygen.c"], - hdrs = ["ecdsa_p384_keygen.h"], - target_compatible_with = [OPENTITAN_CPU], - deps = [ - ":p384_common", - "//sw/device/lib/base:hardened", - "//sw/device/lib/base:hardened_memory", - "//sw/device/lib/crypto/drivers:otbn", - "//sw/otbn/crypto:p384_ecdsa_keygen", - ], -) - -cc_library( - name = "ecdsa_p384_sign", - srcs = ["ecdsa_p384_sign.c"], - hdrs = ["ecdsa_p384_sign.h"], - target_compatible_with = [OPENTITAN_CPU], - deps = [ - ":p384_common", - "//sw/device/lib/base:hardened", - "//sw/device/lib/base:hardened_memory", - "//sw/device/lib/crypto/drivers:otbn", - "//sw/otbn/crypto:p384_ecdsa_sign", - ], -) - -cc_library( - name = "ecdsa_p384_verify", - srcs = ["ecdsa_p384_verify.c"], - hdrs = ["ecdsa_p384_verify.h"], - target_compatible_with = [OPENTITAN_CPU], - deps = [ - ":p384_common", - "//sw/device/lib/base:hardened", - "//sw/device/lib/base:hardened_memory", - "//sw/device/lib/crypto/drivers:otbn", - "//sw/otbn/crypto:p384_ecdsa_verify", - ], -) - -cc_library( - name = "p384_common", - srcs = ["p384_common.c"], - hdrs = ["p384_common.h"], - deps = [ "//sw/device/lib/crypto/drivers:otbn", "//sw/device/lib/crypto/impl:status", + "//sw/otbn/crypto:run_p384", ], ) diff --git a/sw/device/lib/crypto/impl/ecc/ecdh_p384.c b/sw/device/lib/crypto/impl/ecc/ecdh_p384.c deleted file mode 100644 index 70773675275b4..0000000000000 --- a/sw/device/lib/crypto/impl/ecc/ecdh_p384.c +++ /dev/null @@ -1,180 +0,0 @@ -// 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/crypto/impl/ecc/ecdh_p384.h" - -#include "sw/device/lib/base/hardened.h" -#include "sw/device/lib/base/hardened_memory.h" -#include "sw/device/lib/crypto/drivers/otbn.h" - -#include "hw/top_earlgrey/sw/autogen/top_earlgrey.h" - -// Module ID for status codes. -#define MODULE_ID MAKE_MODULE_ID('p', '3', 'x') - -OTBN_DECLARE_APP_SYMBOLS(p384_ecdh); // The OTBN ECDSH/P-384 app. -OTBN_DECLARE_SYMBOL_ADDR(p384_ecdh, mode); // ECDH application mode. -OTBN_DECLARE_SYMBOL_ADDR(p384_ecdh, x); // The public key x-coordinate. -OTBN_DECLARE_SYMBOL_ADDR(p384_ecdh, y); // The public key y-coordinate. -OTBN_DECLARE_SYMBOL_ADDR(p384_ecdh, - d0); // The private key scalar d (share 0). -OTBN_DECLARE_SYMBOL_ADDR(p384_ecdh, - d1); // The private key scalar d (share 1). -OTBN_DECLARE_SYMBOL_ADDR(p384_ecdh, ok); // Status code. - -static const otbn_app_t kOtbnAppEcdh = OTBN_APP_T_INIT(p384_ecdh); -static const otbn_addr_t kOtbnVarEcdhMode = OTBN_ADDR_T_INIT(p384_ecdh, mode); -static const otbn_addr_t kOtbnVarEcdhX = OTBN_ADDR_T_INIT(p384_ecdh, x); -static const otbn_addr_t kOtbnVarEcdhY = OTBN_ADDR_T_INIT(p384_ecdh, y); -static const otbn_addr_t kOtbnVarEcdhD0 = OTBN_ADDR_T_INIT(p384_ecdh, d0); -static const otbn_addr_t kOtbnVarEcdhD1 = OTBN_ADDR_T_INIT(p384_ecdh, d1); -static const otbn_addr_t kOtbnVarEcdhOk = OTBN_ADDR_T_INIT(p384_ecdh, ok); - -enum { - /* - * Mode is represented by a single word. - */ - kOtbnEcdhModeWords = 1, - /* - * Mode to generate a new random keypair. - */ - kOtbnEcdhModeKeypairRandom = 0x3f1, - /* - * Mode to generate a new shared key. - */ - kOtbnEcdhModeSharedKey = 0x5ec, - /* - * Mode to generate a new sideloaded keypair. - */ - kOtbnEcdhModeKeypairFromSeed = 0x29f, - /* - * Mode to generate a new sideloaded shared key. - */ - kOtbnEcdhModeSharedKeyFromSeed = 0x74b, -}; - -status_t ecdh_p384_keypair_start(void) { - // Load the ECDH/P-384 app. Fails if OTBN is non-idle. - HARDENED_TRY(otbn_load_app(kOtbnAppEcdh)); - - // Set mode so start() will jump into keygen. - uint32_t mode = kOtbnEcdhModeKeypairRandom; - HARDENED_TRY(otbn_dmem_write(kOtbnEcdhModeWords, &mode, kOtbnVarEcdhMode)); - - // Start the OTBN routine. - return otbn_execute(); -} - -status_t ecdh_p384_keypair_finalize(p384_masked_scalar_t *private_key, - p384_point_t *public_key) { - // Spin here waiting for OTBN to complete. - HARDENED_TRY(otbn_busy_wait_for_done()); - - // Read the masked private key from OTBN dmem. - HARDENED_TRY(otbn_dmem_read(kP384MaskedScalarShareWords, kOtbnVarEcdhD0, - private_key->share0)); - HARDENED_TRY(otbn_dmem_read(kP384MaskedScalarShareWords, kOtbnVarEcdhD1, - private_key->share1)); - - // Read the public key from OTBN dmem. - HARDENED_TRY(otbn_dmem_read(kP384CoordWords, kOtbnVarEcdhX, public_key->x)); - HARDENED_TRY(otbn_dmem_read(kP384CoordWords, kOtbnVarEcdhY, public_key->y)); - - // Wipe DMEM. - HARDENED_TRY(otbn_dmem_sec_wipe()); - - return OTCRYPTO_OK; -} - -status_t ecdh_p384_shared_key_start(const p384_masked_scalar_t *private_key, - const p384_point_t *public_key) { - // Load the ECDH/P-384 app. Fails if OTBN is non-idle. - HARDENED_TRY(otbn_load_app(kOtbnAppEcdh)); - - // Set mode so start() will jump into shared-key generation. - uint32_t mode = kOtbnEcdhModeSharedKey; - HARDENED_TRY(otbn_dmem_write(kOtbnEcdhModeWords, &mode, kOtbnVarEcdhMode)); - - // Set the private key shares. - HARDENED_TRY( - p384_masked_scalar_write(private_key, kOtbnVarEcdhD0, kOtbnVarEcdhD1)); - - // Set the public key x coordinate. - HARDENED_TRY(otbn_dmem_write(kP384CoordWords, public_key->x, kOtbnVarEcdhX)); - - // Set the public key y coordinate. - HARDENED_TRY(otbn_dmem_write(kP384CoordWords, public_key->y, kOtbnVarEcdhY)); - - // Start the OTBN routine. - return otbn_execute(); -} - -status_t ecdh_p384_shared_key_finalize(ecdh_p384_shared_key_t *shared_key) { - // Spin here waiting for OTBN to complete. - HARDENED_TRY(otbn_busy_wait_for_done()); - - // Read the status code out of DMEM (false if basic checks on the validity of - // the public key failed). - uint32_t ok; - HARDENED_TRY(otbn_dmem_read(1, kOtbnVarEcdhOk, &ok)); - if (launder32(ok) != kHardenedBoolTrue) { - return OTCRYPTO_BAD_ARGS; - } - HARDENED_CHECK_EQ(ok, kHardenedBoolTrue); - - // Read the shares of the key from OTBN dmem (at vars x and y). - HARDENED_TRY( - otbn_dmem_read(kP384CoordWords, kOtbnVarEcdhX, shared_key->share0)); - HARDENED_TRY( - otbn_dmem_read(kP384CoordWords, kOtbnVarEcdhY, shared_key->share1)); - - // Wipe DMEM. - HARDENED_TRY(otbn_dmem_sec_wipe()); - - return OTCRYPTO_OK; -} - -status_t ecdh_p384_sideload_keypair_start(void) { - // Load the ECDH/P-384 app. Fails if OTBN is non-idle. - HARDENED_TRY(otbn_load_app(kOtbnAppEcdh)); - - // Set mode so start() will jump into keygen. - uint32_t mode = kOtbnEcdhModeKeypairFromSeed; - HARDENED_TRY(otbn_dmem_write(kOtbnEcdhModeWords, &mode, kOtbnVarEcdhMode)); - - // Start the OTBN routine. - return otbn_execute(); -} - -status_t ecdh_p384_sideload_keypair_finalize(p384_point_t *public_key) { - // Spin here waiting for OTBN to complete. - HARDENED_TRY(otbn_busy_wait_for_done()); - - // Read the public key from OTBN dmem. - HARDENED_TRY(otbn_dmem_read(kP384CoordWords, kOtbnVarEcdhX, public_key->x)); - HARDENED_TRY(otbn_dmem_read(kP384CoordWords, kOtbnVarEcdhY, public_key->y)); - - // Wipe DMEM. - HARDENED_TRY(otbn_dmem_sec_wipe()); - - return OTCRYPTO_OK; -} - -status_t ecdh_p384_sideload_shared_key_start(const p384_point_t *public_key) { - // Load the ECDH/P-384 app. Fails if OTBN is non-idle. - HARDENED_TRY(otbn_load_app(kOtbnAppEcdh)); - - // Set mode so start() will jump into shared-key generation. - uint32_t mode = kOtbnEcdhModeSharedKeyFromSeed; - HARDENED_TRY(otbn_dmem_write(kOtbnEcdhModeWords, &mode, kOtbnVarEcdhMode)); - - // Set the public key x coordinate. - HARDENED_TRY(otbn_dmem_write(kP384CoordWords, public_key->x, kOtbnVarEcdhX)); - - // Set the public key y coordinate. - HARDENED_TRY(otbn_dmem_write(kP384CoordWords, public_key->y, kOtbnVarEcdhY)); - - // Start the OTBN routine. - return otbn_execute(); -} diff --git a/sw/device/lib/crypto/impl/ecc/ecdh_p384.h b/sw/device/lib/crypto/impl/ecc/ecdh_p384.h deleted file mode 100644 index 61fb586b84692..0000000000000 --- a/sw/device/lib/crypto/impl/ecc/ecdh_p384.h +++ /dev/null @@ -1,120 +0,0 @@ -// 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_DEVICE_LIB_CRYPTO_IMPL_ECC_ECDH_P384_H_ -#define OPENTITAN_SW_DEVICE_LIB_CRYPTO_IMPL_ECC_ECDH_P384_H_ - -#include -#include - -#include "sw/device/lib/base/hardened.h" -#include "sw/device/lib/crypto/drivers/otbn.h" -#include "sw/device/lib/crypto/impl/ecc/p384_common.h" - -#ifdef __cplusplus -extern "C" { -#endif // __cplusplus - -/** - * A type that holds a blinded ECDH shared secret key. - * - * The key is boolean-masked (XOR of the two shares). - */ -typedef struct ecdh_p384_shared_key { - uint32_t share0[kP384CoordWords]; - uint32_t share1[kP384CoordWords]; -} ecdh_p384_shared_key_t; - -/** - * Start an async ECDH/P-384 keypair generation operation on OTBN. - * - * Returns an `OTCRYPTO_ASYNC_INCOMPLETE` error if OTBN is busy. - * - * @return Result of the operation (OK or error). - */ -OT_WARN_UNUSED_RESULT -status_t ecdh_p384_keypair_start(void); - -/** - * Finish an async ECDH/P-384 keypair generation operation on OTBN. - * - * Blocks until OTBN is idle. - * - * @param[out] private_key Generated private key. - * @param[out] public_key Generated public key. - * @return Result of the operation (OK or error). - */ -OT_WARN_UNUSED_RESULT -status_t ecdh_p384_keypair_finalize(p384_masked_scalar_t *private_key, - p384_point_t *public_key); - -/** - * Start an async ECDH/P-384 shared key generation operation on OTBN. - * - * Returns an `OTCRYPTO_ASYNC_INCOMPLETE` error if OTBN is busy. - * - * @param private_key Private key (d). - * @param public_key Public key (Q). - * @return Result of the operation (OK or error). - */ -OT_WARN_UNUSED_RESULT -status_t ecdh_p384_shared_key_start(const p384_masked_scalar_t *private_key, - const p384_point_t *public_key); - -/** - * Finish an async ECDH/P-384 shared key generation operation on OTBN. - * - * Blocks until OTBN is idle. May be used after either - * `ecdh_p384_shared_key_start` or `ecdh_p384_sideload_shared_key_start`; the - * operation is the same. - * - * @param[out] shared_key Shared secret key (x-coordinate of d*Q). - * @return Result of the operation (OK or error). - */ -OT_WARN_UNUSED_RESULT -status_t ecdh_p384_shared_key_finalize(ecdh_p384_shared_key_t *shared_key); - -/** - * Start an async ECDH/P-384 sideloaded keypair generation operation on OTBN. - * - * Generates the keypair from a key manager seed. The key manager should - * already have sideloaded the key into OTBN before this operation is called. - * - * Returns an `OTCRYPTO_ASYNC_INCOMPLETE` error if OTBN is busy. - * - * @return Result of the operation (OK or error). - */ -OT_WARN_UNUSED_RESULT -status_t ecdh_p384_sideload_keypair_start(void); - -/** - * Finish an async ECDH/P-384 sideloaded keypair generation operation on OTBN. - * - * Blocks until OTBN is idle. Returns only the public key. - * - * @param[out] public_key Generated public key. - * @return Result of the operation (OK or error). - */ -OT_WARN_UNUSED_RESULT -status_t ecdh_p384_sideload_keypair_finalize(p384_point_t *public_key); - -/** - * Start an async ECDH/P-384 shared key generation operation on OTBN. - * - * Uses a private key generated from a key manager seed. The key manager should - * already have sideloaded the key into OTBN before this operation is called. - * - * Returns an `OTCRYPTO_ASYNC_INCOMPLETE` error if OTBN is busy. - * - * @param public_key Public key (Q). - * @return Result of the operation (OK or error). - */ -OT_WARN_UNUSED_RESULT -status_t ecdh_p384_sideload_shared_key_start(const p384_point_t *public_key); - -#ifdef __cplusplus -} // extern "C" -#endif // __cplusplus - -#endif // OPENTITAN_SW_DEVICE_LIB_CRYPTO_IMPL_ECC_ECDH_P384_H_ diff --git a/sw/device/lib/crypto/impl/ecc/ecdsa_p384.h b/sw/device/lib/crypto/impl/ecc/ecdsa_p384.h deleted file mode 100644 index 2d0d560e10048..0000000000000 --- a/sw/device/lib/crypto/impl/ecc/ecdsa_p384.h +++ /dev/null @@ -1,25 +0,0 @@ -// 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_DEVICE_LIB_CRYPTO_IMPL_ECC_ECDSA_P384_H_ -#define OPENTITAN_SW_DEVICE_LIB_CRYPTO_IMPL_ECC_ECDSA_P384_H_ - -#include "sw/device/lib/crypto/impl/ecc/ecdsa_p384_keygen.h" -#include "sw/device/lib/crypto/impl/ecc/ecdsa_p384_sign.h" -#include "sw/device/lib/crypto/impl/ecc/ecdsa_p384_verify.h" - -/** - * @file - * @brief Unified header file that includes all P-384 ECDSA operations. - */ - -#ifdef __cplusplus -extern "C" { -#endif // __cplusplus - -#ifdef __cplusplus -} // extern "C" -#endif // __cplusplus - -#endif // OPENTITAN_SW_DEVICE_LIB_CRYPTO_IMPL_ECC_ECDSA_P384_H_ diff --git a/sw/device/lib/crypto/impl/ecc/ecdsa_p384_keygen.c b/sw/device/lib/crypto/impl/ecc/ecdsa_p384_keygen.c deleted file mode 100644 index 46f98defb8468..0000000000000 --- a/sw/device/lib/crypto/impl/ecc/ecdsa_p384_keygen.c +++ /dev/null @@ -1,113 +0,0 @@ -// 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/crypto/impl/ecc/ecdsa_p384_keygen.h" - -#include "sw/device/lib/base/hardened.h" -#include "sw/device/lib/base/hardened_memory.h" -#include "sw/device/lib/crypto/drivers/otbn.h" - -#include "hw/top_earlgrey/sw/autogen/top_earlgrey.h" - -// Module ID for status codes. -#define MODULE_ID MAKE_MODULE_ID('p', '3', 'k') - -OTBN_DECLARE_APP_SYMBOLS(p384_ecdsa_keygen); // The OTBN ECDSA/P-384 app. -OTBN_DECLARE_SYMBOL_ADDR(p384_ecdsa_keygen, - mode); // ECDSA keygen application mode. -OTBN_DECLARE_SYMBOL_ADDR(p384_ecdsa_keygen, d0); // Private key first share. -OTBN_DECLARE_SYMBOL_ADDR(p384_ecdsa_keygen, d1); // Private key second share. -OTBN_DECLARE_SYMBOL_ADDR(p384_ecdsa_keygen, x); // x-coordinate. -OTBN_DECLARE_SYMBOL_ADDR(p384_ecdsa_keygen, y); // y-coordinate. - -static const otbn_app_t kOtbnAppEcdsaKeygen = - OTBN_APP_T_INIT(p384_ecdsa_keygen); -static const otbn_addr_t kOtbnVarEcdsaMode = - OTBN_ADDR_T_INIT(p384_ecdsa_keygen, mode); -static const otbn_addr_t kOtbnVarEcdsaX = - OTBN_ADDR_T_INIT(p384_ecdsa_keygen, x); -static const otbn_addr_t kOtbnVarEcdsaY = - OTBN_ADDR_T_INIT(p384_ecdsa_keygen, y); -static const otbn_addr_t kOtbnVarEcdsaD0 = - OTBN_ADDR_T_INIT(p384_ecdsa_keygen, d0); -static const otbn_addr_t kOtbnVarEcdsaD1 = - OTBN_ADDR_T_INIT(p384_ecdsa_keygen, d1); - -enum { - /* - * Mode is represented by a single word. - */ - kOtbnEcdsaModeWords = 1, - /* - * Mode to generate a new random keypair. - * - * Value taken from `p384_ecdsa_keygen.s`. - */ - kOtbnEcdsaModeKeygen = 0x3d4, - /* - * Mode to generate a sideloaded key. - * - * Value taken from `p384_ecdsa_keygen.s`. - */ - kOtbnEcdsaModeSideloadKeygen = 0x5e8, -}; - -status_t ecdsa_p384_keygen_start(void) { - // Load the ECDSA/P-384 app. Fails if OTBN is non-idle. - HARDENED_TRY(otbn_load_app(kOtbnAppEcdsaKeygen)); - - // Set mode so start() will jump into sideload-keygen. - uint32_t mode = kOtbnEcdsaModeKeygen; - HARDENED_TRY(otbn_dmem_write(kOtbnEcdsaModeWords, &mode, kOtbnVarEcdsaMode)); - - // Start the OTBN routine. - return otbn_execute(); -} - -status_t ecdsa_p384_sideload_keygen_start(void) { - // Load the ECDSA/P-384 app. Fails if OTBN is non-idle. - HARDENED_TRY(otbn_load_app(kOtbnAppEcdsaKeygen)); - - // Set mode so start() will jump into sideload-keygen. - uint32_t mode = kOtbnEcdsaModeSideloadKeygen; - HARDENED_TRY(otbn_dmem_write(kOtbnEcdsaModeWords, &mode, kOtbnVarEcdsaMode)); - - // Start the OTBN routine. - return otbn_execute(); -} - -status_t ecdsa_p384_keygen_finalize(p384_masked_scalar_t *private_key, - p384_point_t *public_key) { - // Spin here waiting for OTBN to complete. - HARDENED_TRY(otbn_busy_wait_for_done()); - - // Read the masked private key from OTBN dmem. - HARDENED_TRY(otbn_dmem_read(kP384MaskedScalarShareWords, kOtbnVarEcdsaD0, - private_key->share0)); - HARDENED_TRY(otbn_dmem_read(kP384MaskedScalarShareWords, kOtbnVarEcdsaD1, - private_key->share1)); - - // Read the public key from OTBN dmem. - HARDENED_TRY(otbn_dmem_read(kP384CoordWords, kOtbnVarEcdsaX, public_key->x)); - HARDENED_TRY(otbn_dmem_read(kP384CoordWords, kOtbnVarEcdsaY, public_key->y)); - - // Wipe DMEM. - HARDENED_TRY(otbn_dmem_sec_wipe()); - - return OTCRYPTO_OK; -} - -status_t ecdsa_p384_sideload_keygen_finalize(p384_point_t *public_key) { - // Spin here waiting for OTBN to complete. - HARDENED_TRY(otbn_busy_wait_for_done()); - - // Read the public key from OTBN dmem. - HARDENED_TRY(otbn_dmem_read(kP384CoordWords, kOtbnVarEcdsaX, public_key->x)); - HARDENED_TRY(otbn_dmem_read(kP384CoordWords, kOtbnVarEcdsaY, public_key->y)); - - // Wipe DMEM. - HARDENED_TRY(otbn_dmem_sec_wipe()); - - return OTCRYPTO_OK; -} diff --git a/sw/device/lib/crypto/impl/ecc/ecdsa_p384_keygen.h b/sw/device/lib/crypto/impl/ecc/ecdsa_p384_keygen.h deleted file mode 100644 index 6b6f153590226..0000000000000 --- a/sw/device/lib/crypto/impl/ecc/ecdsa_p384_keygen.h +++ /dev/null @@ -1,70 +0,0 @@ -// 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_DEVICE_LIB_CRYPTO_IMPL_ECC_ECDSA_P384_KEYGEN_H_ -#define OPENTITAN_SW_DEVICE_LIB_CRYPTO_IMPL_ECC_ECDSA_P384_KEYGEN_H_ - -#include -#include - -#include "sw/device/lib/base/hardened.h" -#include "sw/device/lib/crypto/drivers/otbn.h" -#include "sw/device/lib/crypto/impl/ecc/p384_common.h" - -#ifdef __cplusplus -extern "C" { -#endif // __cplusplus - -/** - * Start an async ECDSA/P-384 keypair generation operation on OTBN. - * - * Returns an `OTCRYPTO_ASYNC_INCOMPLETE` error if OTBN is busy. - * - * @return Result of the operation (OK or error). - */ -OT_WARN_UNUSED_RESULT -status_t ecdsa_p384_keygen_start(void); - -/** - * Start an async ECDSA/P-384 sideloaded keypair generation operation on OTBN. - * - * Expects a sideloaded key from keymgr to be already loaded on OTBN. Returns - * an `OTCRYPTO_ASYNC_INCOMPLETE` error if OTBN is busy. - * - * @return Result of the operation (OK or error). - */ -OT_WARN_UNUSED_RESULT -status_t ecdsa_p384_sideload_keygen_start(void); - -/** - * Finish an async ECDSA/P-384 keypair generation operation on OTBN. - * - * Blocks until OTBN is idle. - * - * @param[out] private_key Generated private key. - * @param[out] public_key Generated public key. - * @return Result of the operation (OK or error). - */ -OT_WARN_UNUSED_RESULT -status_t ecdsa_p384_keygen_finalize(p384_masked_scalar_t *private_key, - p384_point_t *public_key); - -/** - * Start an async ECDSA/P-384 sideloaded keypair generation operation on OTBN. - * - * This routine will only read back the public key, instead of both public and - * private as with `ecdsa_p384_keygen_finalize`. Blocks until OTBN is idle. - * - * @param[out] public_key Public key. - * @return Result of the operation (OK or error). - */ -OT_WARN_UNUSED_RESULT -status_t ecdsa_p384_sideload_keygen_finalize(p384_point_t *public_key); - -#ifdef __cplusplus -} -"C" -#endif // __cplusplus - -#endif // OPENTITAN_SW_DEVICE_LIB_CRYPTO_IMPL_ECC_ECDSA_P384_KEYGEN_H_ diff --git a/sw/device/lib/crypto/impl/ecc/ecdsa_p384_sign.c b/sw/device/lib/crypto/impl/ecc/ecdsa_p384_sign.c deleted file mode 100644 index 30247a6523104..0000000000000 --- a/sw/device/lib/crypto/impl/ecc/ecdsa_p384_sign.c +++ /dev/null @@ -1,106 +0,0 @@ -// 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/crypto/impl/ecc/ecdsa_p384_sign.h" - -#include "sw/device/lib/base/hardened.h" -#include "sw/device/lib/base/hardened_memory.h" -#include "sw/device/lib/crypto/drivers/otbn.h" - -#include "hw/top_earlgrey/sw/autogen/top_earlgrey.h" - -// Module ID for status codes. -#define MODULE_ID MAKE_MODULE_ID('p', '3', 's') - -OTBN_DECLARE_APP_SYMBOLS(p384_ecdsa_sign); // The OTBN ECDSA/P-384 app. -OTBN_DECLARE_SYMBOL_ADDR(p384_ecdsa_sign, - mode); // ECDSA sign application mode. -OTBN_DECLARE_SYMBOL_ADDR(p384_ecdsa_sign, d0); // private key first share -OTBN_DECLARE_SYMBOL_ADDR(p384_ecdsa_sign, d1); // private key second share -OTBN_DECLARE_SYMBOL_ADDR(p384_ecdsa_sign, msg); // hash message to sign/verify -OTBN_DECLARE_SYMBOL_ADDR(p384_ecdsa_sign, r); // r part of signature -OTBN_DECLARE_SYMBOL_ADDR(p384_ecdsa_sign, s); // s part of signature - -static const otbn_app_t kOtbnAppEcdsaSign = OTBN_APP_T_INIT(p384_ecdsa_sign); -static const otbn_addr_t kOtbnVarEcdsaMode = - OTBN_ADDR_T_INIT(p384_ecdsa_sign, mode); -static const otbn_addr_t kOtbnVarEcdsaD0 = - OTBN_ADDR_T_INIT(p384_ecdsa_sign, d0); -static const otbn_addr_t kOtbnVarEcdsaD1 = - OTBN_ADDR_T_INIT(p384_ecdsa_sign, d1); -static const otbn_addr_t kOtbnVarEcdsaMsg = - OTBN_ADDR_T_INIT(p384_ecdsa_sign, msg); -static const otbn_addr_t kOtbnVarEcdsaR = OTBN_ADDR_T_INIT(p384_ecdsa_sign, r); -static const otbn_addr_t kOtbnVarEcdsaS = OTBN_ADDR_T_INIT(p384_ecdsa_sign, s); - -enum { - /* - * Mode is represented by a single word. - */ - kOtbnEcdsaModeWords = 1, - /* - * Mode to generate a signature. - * - * Value taken from `p384_ecdsa.s`. - */ - kOtbnEcdsaModeSign = 0x15b, - /* - * Mode to sign with a sideloaded key. - * - * Value taken from `p384_ecdsa.s`. - */ - kOtbnEcdsaModeSideloadSign = 0x49e, -}; - -status_t ecdsa_p384_sign_start(const uint32_t digest[kP384ScalarWords], - const p384_masked_scalar_t *private_key) { - // Load the ECDSA/P-384 app. Fails if OTBN is non-idle. - HARDENED_TRY(otbn_load_app(kOtbnAppEcdsaSign)); - - // Set mode so start() will jump into sideloaded signing. - uint32_t mode = kOtbnEcdsaModeSign; - HARDENED_TRY(otbn_dmem_write(kOtbnEcdsaModeWords, &mode, kOtbnVarEcdsaMode)); - - // Set the message digest. - HARDENED_TRY(set_message_digest(digest, kOtbnVarEcdsaMsg)); - - // Set the private key shares. - HARDENED_TRY( - p384_masked_scalar_write(private_key, kOtbnVarEcdsaD0, kOtbnVarEcdsaD1)); - - // Start the OTBN routine. - return otbn_execute(); -} - -status_t ecdsa_p384_sideload_sign_start( - const uint32_t digest[kP384ScalarWords]) { - // Load the ECDSA/P-384 app. Fails if OTBN is non-idle. - HARDENED_TRY(otbn_load_app(kOtbnAppEcdsaSign)); - - // Set mode so start() will jump into sideloaded signing. - uint32_t mode = kOtbnEcdsaModeSideloadSign; - HARDENED_TRY(otbn_dmem_write(kOtbnEcdsaModeWords, &mode, kOtbnVarEcdsaMode)); - - // Set the message digest. - HARDENED_TRY(set_message_digest(digest, kOtbnVarEcdsaMsg)); - - // Start the OTBN routine. - return otbn_execute(); -} - -status_t ecdsa_p384_sign_finalize(ecdsa_p384_signature_t *result) { - // Spin here waiting for OTBN to complete. - HARDENED_TRY(otbn_busy_wait_for_done()); - - // Read signature R out of OTBN dmem. - HARDENED_TRY(otbn_dmem_read(kP384ScalarWords, kOtbnVarEcdsaR, result->r)); - - // Read signature S out of OTBN dmem. - HARDENED_TRY(otbn_dmem_read(kP384ScalarWords, kOtbnVarEcdsaS, result->s)); - - // Wipe DMEM. - HARDENED_TRY(otbn_dmem_sec_wipe()); - - return OTCRYPTO_OK; -} diff --git a/sw/device/lib/crypto/impl/ecc/ecdsa_p384_sign.h b/sw/device/lib/crypto/impl/ecc/ecdsa_p384_sign.h deleted file mode 100644 index dcd960e2e5a25..0000000000000 --- a/sw/device/lib/crypto/impl/ecc/ecdsa_p384_sign.h +++ /dev/null @@ -1,62 +0,0 @@ -// 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_DEVICE_LIB_CRYPTO_IMPL_ECC_ECDSA_P384_SIGN_H_ -#define OPENTITAN_SW_DEVICE_LIB_CRYPTO_IMPL_ECC_ECDSA_P384_SIGN_H_ - -#include -#include - -#include "sw/device/lib/base/hardened.h" -#include "sw/device/lib/crypto/drivers/otbn.h" -#include "sw/device/lib/crypto/impl/ecc/p384_common.h" - -#ifdef __cplusplus -extern "C" { -#endif // __cplusplus - -/** - * Start an async ECDSA/P-384 signature generation operation on OTBN. - * - * Returns an `OTCRYPTO_ASYNC_INCOMPLETE` error if OTBN is busy. - * - * @param digest Digest of the message to sign. - * @param private_key Secret key to sign the message with. - * @return Result of the operation (OK or error). - */ -OT_WARN_UNUSED_RESULT -status_t ecdsa_p384_sign_start(const uint32_t digest[kP384ScalarWords], - const p384_masked_scalar_t *private_key); - -/** - * Start an async ECDSA/P-384 signature generation operation on OTBN. - * - * Expects a sideloaded key from keymgr to be already loaded on OTBN. Returns - * an `OTCRYPTO_ASYNC_INCOMPLETE` error if OTBN is busy. - * - * @param digest Digest of the message to sign. - * @return Result of the operation (OK or error). - */ -OT_WARN_UNUSED_RESULT -status_t ecdsa_p384_sideload_sign_start( - const uint32_t digest[kP384ScalarWords]); - -/** - * Finish an async ECDSA/P-384 signature generation operation on OTBN. - * - * See the documentation of `ecdsa_p384_sign` for details. - * - * Blocks until OTBN is idle. - * - * @param[out] result Buffer in which to store the generated signature. - * @return Result of the operation (OK or error). - */ -OT_WARN_UNUSED_RESULT -status_t ecdsa_p384_sign_finalize(ecdsa_p384_signature_t *result); - -#ifdef __cplusplus -} // extern "C" -#endif // __cplusplus - -#endif // OPENTITAN_SW_DEVICE_LIB_CRYPTO_IMPL_ECC_ECDSA_P384_SIGN_H_ diff --git a/sw/device/lib/crypto/impl/ecc/ecdsa_p384_verify.c b/sw/device/lib/crypto/impl/ecc/ecdsa_p384_verify.c deleted file mode 100644 index 947ec8eacaf00..0000000000000 --- a/sw/device/lib/crypto/impl/ecc/ecdsa_p384_verify.c +++ /dev/null @@ -1,93 +0,0 @@ -// 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/crypto/impl/ecc/ecdsa_p384_verify.h" - -#include "sw/device/lib/base/hardened.h" -#include "sw/device/lib/base/hardened_memory.h" -#include "sw/device/lib/crypto/drivers/otbn.h" - -#include "hw/top_earlgrey/sw/autogen/top_earlgrey.h" - -// Module ID for status codes. -#define MODULE_ID MAKE_MODULE_ID('p', '3', 'v') - -OTBN_DECLARE_APP_SYMBOLS(p384_ecdsa_verify); // The OTBN ECDSA/P-384 app. -OTBN_DECLARE_SYMBOL_ADDR(p384_ecdsa_verify, x); // Public key x-coordinate. -OTBN_DECLARE_SYMBOL_ADDR(p384_ecdsa_verify, y); // Public key y-coordinate. -OTBN_DECLARE_SYMBOL_ADDR(p384_ecdsa_verify, - x_r); // result of verify (x1 coordinate) -OTBN_DECLARE_SYMBOL_ADDR(p384_ecdsa_verify, - msg); // hash message to sign/verify -OTBN_DECLARE_SYMBOL_ADDR(p384_ecdsa_verify, r); // r part of signature -OTBN_DECLARE_SYMBOL_ADDR(p384_ecdsa_verify, s); // s part of signature -OTBN_DECLARE_SYMBOL_ADDR(p384_ecdsa_verify, ok); // Status code. - -static const otbn_app_t kOtbnAppEcdsaVerify = - OTBN_APP_T_INIT(p384_ecdsa_verify); -static const otbn_addr_t kOtbnVarEcdsaX = - OTBN_ADDR_T_INIT(p384_ecdsa_verify, x); -static const otbn_addr_t kOtbnVarEcdsaY = - OTBN_ADDR_T_INIT(p384_ecdsa_verify, y); -static const otbn_addr_t kOtbnVarEcdsaMsg = - OTBN_ADDR_T_INIT(p384_ecdsa_verify, msg); -static const otbn_addr_t kOtbnVarEcdsaR = - OTBN_ADDR_T_INIT(p384_ecdsa_verify, r); -static const otbn_addr_t kOtbnVarEcdsaS = - OTBN_ADDR_T_INIT(p384_ecdsa_verify, s); -static const otbn_addr_t kOtbnVarEcdsaRnd = - OTBN_ADDR_T_INIT(p384_ecdsa_verify, x_r); -static const otbn_addr_t kOtbnVarEcdsaOk = - OTBN_ADDR_T_INIT(p384_ecdsa_verify, ok); - -status_t ecdsa_p384_verify_start(const ecdsa_p384_signature_t *signature, - const uint32_t digest[kP384ScalarWords], - const p384_point_t *public_key) { - // Load the ECDSA/P-384 app - HARDENED_TRY(otbn_load_app(kOtbnAppEcdsaVerify)); - - // Set the message digest. - HARDENED_TRY(set_message_digest(digest, kOtbnVarEcdsaMsg)); - - // Set the signature R. - HARDENED_TRY(otbn_dmem_write(kP384ScalarWords, signature->r, kOtbnVarEcdsaR)); - - // Set the signature S. - HARDENED_TRY(otbn_dmem_write(kP384ScalarWords, signature->s, kOtbnVarEcdsaS)); - - // Set the public key x coordinate. - HARDENED_TRY(otbn_dmem_write(kP384CoordWords, public_key->x, kOtbnVarEcdsaX)); - - // Set the public key y coordinate. - HARDENED_TRY(otbn_dmem_write(kP384CoordWords, public_key->y, kOtbnVarEcdsaY)); - - // Start the OTBN routine. - return otbn_execute(); -} - -status_t ecdsa_p384_verify_finalize(const ecdsa_p384_signature_t *signature, - hardened_bool_t *result) { - // Spin here waiting for OTBN to complete. - HARDENED_TRY(otbn_busy_wait_for_done()); - - // Read the status code out of DMEM (false if basic checks on the validity of - // the signature and public key failed). - uint32_t ok; - HARDENED_TRY(otbn_dmem_read(1, kOtbnVarEcdsaOk, &ok)); - if (launder32(ok) != kHardenedBoolTrue) { - return OTCRYPTO_BAD_ARGS; - } - HARDENED_CHECK_EQ(ok, kHardenedBoolTrue); - - // Read x_r (recovered R) out of OTBN dmem. - uint32_t x_r[kP384ScalarWords]; - HARDENED_TRY(otbn_dmem_read(kP384ScalarWords, kOtbnVarEcdsaRnd, x_r)); - - *result = hardened_memeq(x_r, signature->r, kP384ScalarWords); - - // Wipe DMEM. - HARDENED_TRY(otbn_dmem_sec_wipe()); - - return OTCRYPTO_OK; -} diff --git a/sw/device/lib/crypto/impl/ecc/ecdsa_p384_verify.h b/sw/device/lib/crypto/impl/ecc/ecdsa_p384_verify.h deleted file mode 100644 index ca60ee29c5372..0000000000000 --- a/sw/device/lib/crypto/impl/ecc/ecdsa_p384_verify.h +++ /dev/null @@ -1,64 +0,0 @@ -// 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_DEVICE_LIB_CRYPTO_IMPL_ECC_ECDSA_P384_VERIFY_H_ -#define OPENTITAN_SW_DEVICE_LIB_CRYPTO_IMPL_ECC_ECDSA_P384_VERIFY_H_ - -#include -#include - -#include "sw/device/lib/base/hardened.h" -#include "sw/device/lib/crypto/drivers/otbn.h" -#include "sw/device/lib/crypto/impl/ecc/p384_common.h" - -#ifdef __cplusplus -extern "C" { -#endif // __cplusplus - -/** - * Start an async ECDSA/P-384 signature verification operation on OTBN. - * - * See the documentation of `ecdsa_p384_verify` for details. - * - * Returns an `OTCRYPTO_ASYNC_INCOMPLETE` error if OTBN is busy. - * - * @param signature Signature to be verified. - * @param digest Digest of the message to check the signature against. - * @param public_key Key to check the signature against. - * @return Result of the operation (OK or error). - */ -OT_WARN_UNUSED_RESULT -status_t ecdsa_p384_verify_start(const ecdsa_p384_signature_t *signature, - const uint32_t digest[kP384ScalarWords], - const p384_point_t *public_key); - -/** - * Finish an async ECDSA/P-384 signature verification operation on OTBN. - * - * See the documentation of `ecdsa_p384_verify` for details. - * - * Blocks until OTBN is idle. - * - * If the signature is valid, writes `kHardenedBoolTrue` to `result`; - * otherwise, writes `kHardenedBoolFalse`. - * - * Note: the caller must check the `result` buffer in order to determine if a - * signature passed verification. If a signature is invalid, but nothing goes - * wrong during computation (e.g. hardware errors, failed preconditions), the - * status will be OK but `result` will be `kHardenedBoolFalse`. - * - * @param signature Signature to be verified. - * @param[out] result Output buffer (true if signature is valid, false - * otherwise) - * @return Result of the operation (OK or error). - */ -OT_WARN_UNUSED_RESULT -status_t ecdsa_p384_verify_finalize(const ecdsa_p384_signature_t *signature, - hardened_bool_t *result); - -#ifdef __cplusplus -} // extern "C" -#endif // __cplusplus - -#endif // OPENTITAN_SW_DEVICE_LIB_CRYPTO_IMPL_ECC_ECDSA_P384_VERIFY_H_ diff --git a/sw/device/lib/crypto/impl/ecc/p384.c b/sw/device/lib/crypto/impl/ecc/p384.c new file mode 100644 index 0000000000000..00bc2e9c1b5a3 --- /dev/null +++ b/sw/device/lib/crypto/impl/ecc/p384.c @@ -0,0 +1,341 @@ +// 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/crypto/impl/ecc/p384.h" + +#include "sw/device/lib/base/hardened.h" +#include "sw/device/lib/base/hardened_memory.h" +#include "sw/device/lib/crypto/drivers/otbn.h" + +#include "hw/top_earlgrey/sw/autogen/top_earlgrey.h" + +// Module ID for status codes. +#define MODULE_ID MAKE_MODULE_ID('p', '3', 'r') + +// Declare the OTBN app. +OTBN_DECLARE_APP_SYMBOLS(run_p384); +static const otbn_app_t kOtbnAppP384 = OTBN_APP_T_INIT(run_p384); + +// Declare offsets for input and output buffers. +OTBN_DECLARE_SYMBOL_ADDR(run_p384, mode); // Mode of operation. +OTBN_DECLARE_SYMBOL_ADDR(run_p384, msg); // ECDSA message digest. +OTBN_DECLARE_SYMBOL_ADDR(run_p384, r); // ECDSA signature scalar R. +OTBN_DECLARE_SYMBOL_ADDR(run_p384, s); // ECDSA signature scalar S. +OTBN_DECLARE_SYMBOL_ADDR(run_p384, x); // Public key x-coordinate. +OTBN_DECLARE_SYMBOL_ADDR(run_p384, y); // Public key y-coordinate. +OTBN_DECLARE_SYMBOL_ADDR(run_p384, d0); // Private key scalar d (share 0). +OTBN_DECLARE_SYMBOL_ADDR(run_p384, d1); // Private key scalar d (share 1). +OTBN_DECLARE_SYMBOL_ADDR(run_p384, x_r); // ECDSA verification result. +OTBN_DECLARE_SYMBOL_ADDR(run_p384, ok); // Status code. + +static const otbn_addr_t kOtbnVarMode = OTBN_ADDR_T_INIT(run_p384, mode); +static const otbn_addr_t kOtbnVarMsg = OTBN_ADDR_T_INIT(run_p384, msg); +static const otbn_addr_t kOtbnVarR = OTBN_ADDR_T_INIT(run_p384, r); +static const otbn_addr_t kOtbnVarS = OTBN_ADDR_T_INIT(run_p384, s); +static const otbn_addr_t kOtbnVarX = OTBN_ADDR_T_INIT(run_p384, x); +static const otbn_addr_t kOtbnVarY = OTBN_ADDR_T_INIT(run_p384, y); +static const otbn_addr_t kOtbnVarD0 = OTBN_ADDR_T_INIT(run_p384, d0); +static const otbn_addr_t kOtbnVarD1 = OTBN_ADDR_T_INIT(run_p384, d1); +static const otbn_addr_t kOtbnVarXr = OTBN_ADDR_T_INIT(run_p384, x_r); +static const otbn_addr_t kOtbnVarOk = OTBN_ADDR_T_INIT(run_p384, ok); + +// Declare mode constants. +OTBN_DECLARE_SYMBOL_ADDR(run_p384, MODE_KEYGEN); +OTBN_DECLARE_SYMBOL_ADDR(run_p384, MODE_SIGN); +OTBN_DECLARE_SYMBOL_ADDR(run_p384, MODE_VERIFY); +OTBN_DECLARE_SYMBOL_ADDR(run_p384, MODE_ECDH); +OTBN_DECLARE_SYMBOL_ADDR(run_p384, MODE_SIDELOAD_KEYGEN); +OTBN_DECLARE_SYMBOL_ADDR(run_p384, MODE_SIDELOAD_SIGN); +OTBN_DECLARE_SYMBOL_ADDR(run_p384, MODE_SIDELOAD_ECDH); +static const uint32_t kP384ModeKeygen = OTBN_ADDR_T_INIT(run_p384, MODE_KEYGEN); +static const uint32_t kP384ModeSign = OTBN_ADDR_T_INIT(run_p384, MODE_SIGN); +static const uint32_t kP384ModeVerify = OTBN_ADDR_T_INIT(run_p384, MODE_VERIFY); +static const uint32_t kP384ModeEcdh = OTBN_ADDR_T_INIT(run_p384, MODE_ECDH); +static const uint32_t kP384ModeSideloadKeygen = + OTBN_ADDR_T_INIT(run_p384, MODE_SIDELOAD_KEYGEN); +static const uint32_t kP384ModeSideloadSign = + OTBN_ADDR_T_INIT(run_p384, MODE_SIDELOAD_SIGN); +static const uint32_t kP384ModeSideloadEcdh = + OTBN_ADDR_T_INIT(run_p384, MODE_SIDELOAD_ECDH); + +enum { + /* + * Mode is represented by a single word. + */ + kP384ModeWords = 1, + /** + * Number of extra padding words needed for masked scalar shares. + * + * Where W is the word size and S is the share size, the padding needed is: + * (W - (S % W)) % W + * + * The extra outer "% W" ensures that the padding is 0 if (S % W) is 0. + */ + kMaskedScalarPaddingWords = + (kOtbnWideWordNumWords - + (kP384MaskedScalarShareWords % kOtbnWideWordNumWords)) % + kOtbnWideWordNumWords, +}; + +static status_t p384_masked_scalar_write(const p384_masked_scalar_t *src, + const otbn_addr_t share0_addr, + const otbn_addr_t share1_addr) { + HARDENED_TRY( + otbn_dmem_write(kP384MaskedScalarShareWords, src->share0, share0_addr)); + HARDENED_TRY( + otbn_dmem_write(kP384MaskedScalarShareWords, src->share1, share1_addr)); + + // Write trailing 0s so that OTBN's 384-bit read of the second share does not + // cause an error. + HARDENED_TRY(otbn_dmem_set(kMaskedScalarPaddingWords, 0, + share0_addr + kP384MaskedScalarShareBytes)); + HARDENED_TRY(otbn_dmem_set(kMaskedScalarPaddingWords, 0, + share1_addr + kP384MaskedScalarShareBytes)); + + return OTCRYPTO_OK; +} + +static status_t set_message_digest(const uint32_t digest[kP384ScalarWords], + const otbn_addr_t dst) { + // Set the message digest. We swap all the bytes so that OTBN can interpret + // the digest as a little-endian integer, which is a more natural fit for the + // architecture than the big-endian form requested by the specification (FIPS + // 186-5, section B.2.1). + uint32_t digest_little_endian[kP384ScalarWords]; + size_t i = 0; + for (; launder32(i) < kP384ScalarWords; i++) { + digest_little_endian[i] = + __builtin_bswap32(digest[kP384ScalarWords - 1 - i]); + } + HARDENED_CHECK_EQ(i, kP384ScalarWords); + return otbn_dmem_write(kP384ScalarWords, digest_little_endian, dst); +} + +status_t p384_keygen_start(void) { + // Load the ECDH/P-384 app. Fails if OTBN is non-idle. + HARDENED_TRY(otbn_load_app(kOtbnAppP384)); + + // Set mode so start() will jump into keygen. + uint32_t mode = kP384ModeKeygen; + HARDENED_TRY(otbn_dmem_write(kP384ModeWords, &mode, kOtbnVarMode)); + + // Start the OTBN routine. + return otbn_execute(); +} + +status_t p384_keygen_finalize(p384_masked_scalar_t *private_key, + p384_point_t *public_key) { + // Spin here waiting for OTBN to complete. + HARDENED_TRY(otbn_busy_wait_for_done()); + + // Read the masked private key from OTBN dmem. + HARDENED_TRY(otbn_dmem_read(kP384MaskedScalarShareWords, kOtbnVarD0, + private_key->share0)); + HARDENED_TRY(otbn_dmem_read(kP384MaskedScalarShareWords, kOtbnVarD1, + private_key->share1)); + + // Read the public key from OTBN dmem. + HARDENED_TRY(otbn_dmem_read(kP384CoordWords, kOtbnVarX, public_key->x)); + HARDENED_TRY(otbn_dmem_read(kP384CoordWords, kOtbnVarY, public_key->y)); + + // Wipe DMEM. + HARDENED_TRY(otbn_dmem_sec_wipe()); + + return OTCRYPTO_OK; +} + +status_t p384_sideload_keygen_start(void) { + // Load the ECDH/P-384 app. Fails if OTBN is non-idle. + HARDENED_TRY(otbn_load_app(kOtbnAppP384)); + + // Set mode so start() will jump into keygen. + uint32_t mode = kP384ModeSideloadKeygen; + HARDENED_TRY(otbn_dmem_write(kP384ModeWords, &mode, kOtbnVarMode)); + + // Start the OTBN routine. + return otbn_execute(); +} + +status_t p384_sideload_keygen_finalize(p384_point_t *public_key) { + // Spin here waiting for OTBN to complete. + HARDENED_TRY(otbn_busy_wait_for_done()); + + // Read the public key from OTBN dmem. + HARDENED_TRY(otbn_dmem_read(kP384CoordWords, kOtbnVarX, public_key->x)); + HARDENED_TRY(otbn_dmem_read(kP384CoordWords, kOtbnVarY, public_key->y)); + + // Wipe DMEM. + HARDENED_TRY(otbn_dmem_sec_wipe()); + + return OTCRYPTO_OK; +} + +status_t p384_ecdsa_sign_start(const uint32_t digest[kP384ScalarWords], + const p384_masked_scalar_t *private_key) { + // Load the ECDSA/P-384 app. Fails if OTBN is non-idle. + HARDENED_TRY(otbn_load_app(kOtbnAppP384)); + + // Set mode so start() will jump into sideloaded signing. + uint32_t mode = kP384ModeSign; + HARDENED_TRY(otbn_dmem_write(kP384ModeWords, &mode, kOtbnVarMode)); + + // Set the message digest. + HARDENED_TRY(set_message_digest(digest, kOtbnVarMsg)); + + // Set the private key shares. + HARDENED_TRY(p384_masked_scalar_write(private_key, kOtbnVarD0, kOtbnVarD1)); + + // Start the OTBN routine. + return otbn_execute(); +} + +status_t p384_ecdsa_sideload_sign_start( + const uint32_t digest[kP384ScalarWords]) { + // Load the ECDSA/P-384 app. Fails if OTBN is non-idle. + HARDENED_TRY(otbn_load_app(kOtbnAppP384)); + + // Set mode so start() will jump into sideloaded signing. + uint32_t mode = kP384ModeSideloadSign; + HARDENED_TRY(otbn_dmem_write(kP384ModeWords, &mode, kOtbnVarMode)); + + // Set the message digest. + HARDENED_TRY(set_message_digest(digest, kOtbnVarMsg)); + + // Start the OTBN routine. + return otbn_execute(); +} + +status_t p384_ecdsa_sign_finalize(p384_ecdsa_signature_t *result) { + // Spin here waiting for OTBN to complete. + HARDENED_TRY(otbn_busy_wait_for_done()); + + // Read signature R out of OTBN dmem. + HARDENED_TRY(otbn_dmem_read(kP384ScalarWords, kOtbnVarR, result->r)); + + // Read signature S out of OTBN dmem. + HARDENED_TRY(otbn_dmem_read(kP384ScalarWords, kOtbnVarS, result->s)); + + // Wipe DMEM. + HARDENED_TRY(otbn_dmem_sec_wipe()); + + return OTCRYPTO_OK; +} + +status_t p384_ecdsa_verify_start(const p384_ecdsa_signature_t *signature, + const uint32_t digest[kP384ScalarWords], + const p384_point_t *public_key) { + // Load the ECDSA/P-384 app + HARDENED_TRY(otbn_load_app(kOtbnAppP384)); + + // Set mode so start() will jump into ECDSA verify. + uint32_t mode = kP384ModeVerify; + HARDENED_TRY(otbn_dmem_write(kP384ModeWords, &mode, kOtbnVarMode)); + + // Set the message digest. + HARDENED_TRY(set_message_digest(digest, kOtbnVarMsg)); + + // Set the signature R. + HARDENED_TRY(otbn_dmem_write(kP384ScalarWords, signature->r, kOtbnVarR)); + + // Set the signature S. + HARDENED_TRY(otbn_dmem_write(kP384ScalarWords, signature->s, kOtbnVarS)); + + // Set the public key x coordinate. + HARDENED_TRY(otbn_dmem_write(kP384CoordWords, public_key->x, kOtbnVarX)); + + // Set the public key y coordinate. + HARDENED_TRY(otbn_dmem_write(kP384CoordWords, public_key->y, kOtbnVarY)); + + // Start the OTBN routine. + return otbn_execute(); +} + +status_t p384_ecdsa_verify_finalize(const p384_ecdsa_signature_t *signature, + hardened_bool_t *result) { + // Spin here waiting for OTBN to complete. + HARDENED_TRY(otbn_busy_wait_for_done()); + + // Read the status code out of DMEM (false if basic checks on the validity of + // the signature and public key failed). + uint32_t ok; + HARDENED_TRY(otbn_dmem_read(1, kOtbnVarOk, &ok)); + if (launder32(ok) != kHardenedBoolTrue) { + return OTCRYPTO_BAD_ARGS; + } + HARDENED_CHECK_EQ(ok, kHardenedBoolTrue); + + // Read x_r (recovered R) out of OTBN dmem. + uint32_t x_r[kP384ScalarWords]; + HARDENED_TRY(otbn_dmem_read(kP384ScalarWords, kOtbnVarXr, x_r)); + + *result = hardened_memeq(x_r, signature->r, kP384ScalarWords); + + // Wipe DMEM. + HARDENED_TRY(otbn_dmem_sec_wipe()); + + return OTCRYPTO_OK; +} + +status_t p384_ecdh_start(const p384_masked_scalar_t *private_key, + const p384_point_t *public_key) { + // Load the ECDH/P-384 app. Fails if OTBN is non-idle. + HARDENED_TRY(otbn_load_app(kOtbnAppP384)); + + // Set mode so start() will jump into shared-key generation. + uint32_t mode = kP384ModeEcdh; + HARDENED_TRY(otbn_dmem_write(kP384ModeWords, &mode, kOtbnVarMode)); + + // Set the private key shares. + HARDENED_TRY(p384_masked_scalar_write(private_key, kOtbnVarD0, kOtbnVarD1)); + + // Set the public key x coordinate. + HARDENED_TRY(otbn_dmem_write(kP384CoordWords, public_key->x, kOtbnVarX)); + + // Set the public key y coordinate. + HARDENED_TRY(otbn_dmem_write(kP384CoordWords, public_key->y, kOtbnVarY)); + + // Start the OTBN routine. + return otbn_execute(); +} + +status_t p384_ecdh_finalize(p384_ecdh_shared_key_t *shared_key) { + // Spin here waiting for OTBN to complete. + HARDENED_TRY(otbn_busy_wait_for_done()); + + // Read the status code out of DMEM (false if basic checks on the validity of + // the signature and public key failed). + uint32_t ok; + HARDENED_TRY(otbn_dmem_read(1, kOtbnVarOk, &ok)); + if (launder32(ok) != kHardenedBoolTrue) { + return OTCRYPTO_BAD_ARGS; + } + HARDENED_CHECK_EQ(ok, kHardenedBoolTrue); + + // Read the shares of the key from OTBN dmem (at vars x and y). + HARDENED_TRY(otbn_dmem_read(kP384CoordWords, kOtbnVarX, shared_key->share0)); + HARDENED_TRY(otbn_dmem_read(kP384CoordWords, kOtbnVarY, shared_key->share1)); + + // Wipe DMEM. + HARDENED_TRY(otbn_dmem_sec_wipe()); + + return OTCRYPTO_OK; +} + +status_t p384_sideload_ecdh_start(const p384_point_t *public_key) { + // Load the ECDH/P-384 app. Fails if OTBN is non-idle. + HARDENED_TRY(otbn_load_app(kOtbnAppP384)); + + // Set mode so start() will jump into shared-key generation. + uint32_t mode = kP384ModeSideloadEcdh; + HARDENED_TRY(otbn_dmem_write(kP384ModeWords, &mode, kOtbnVarMode)); + + // Set the public key x coordinate. + HARDENED_TRY(otbn_dmem_write(kP384CoordWords, public_key->x, kOtbnVarX)); + + // Set the public key y coordinate. + HARDENED_TRY(otbn_dmem_write(kP384CoordWords, public_key->y, kOtbnVarY)); + + // Start the OTBN routine. + return otbn_execute(); +} diff --git a/sw/device/lib/crypto/impl/ecc/p384.h b/sw/device/lib/crypto/impl/ecc/p384.h new file mode 100644 index 0000000000000..613d775e61bb6 --- /dev/null +++ b/sw/device/lib/crypto/impl/ecc/p384.h @@ -0,0 +1,285 @@ +// 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_DEVICE_LIB_CRYPTO_IMPL_ECC_P384_H_ +#define OPENTITAN_SW_DEVICE_LIB_CRYPTO_IMPL_ECC_P384_H_ + +#include +#include + +#include "sw/device/lib/base/hardened.h" +#include "sw/device/lib/crypto/drivers/otbn.h" + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +enum { + /** + * Length of a P-384 curve point coordinate in bits (modulo p). + */ + kP384CoordBits = 384, + /** + * Length of a P-384 curve point coordinate in bytes. + */ + kP384CoordBytes = kP384CoordBits / 8, + /** + * Length of a P-384 curve point coordinate in words. + */ + kP384CoordWords = kP384CoordBytes / sizeof(uint32_t), + /** + * Length of an element in the P-384 scalar field (modulo the curve order n). + */ + kP384ScalarBits = 384, + /** + * Length of a secret scalar share in bytes. + */ + kP384ScalarBytes = kP384ScalarBits / 8, + /** + * Length of secret scalar share in words. + */ + kP384ScalarWords = kP384ScalarBytes / sizeof(uint32_t), + /** + * Length of a masked secret scalar share. + * + * This implementation uses extra redundant bits for side-channel protection. + */ + kP384MaskedScalarShareBits = kP384ScalarBits + 64, + /** + * Length of a masked secret scalar share in bytes. + */ + kP384MaskedScalarShareBytes = kP384MaskedScalarShareBits / 8, + /** + * Length of masked secret scalar share in words. + */ + kP384MaskedScalarShareWords = kP384MaskedScalarShareBytes / sizeof(uint32_t), +}; + +/** + * A type that holds a masked value from the P-384 scalar field. + * + * This struct is used to represent secret keys, which are integers modulo n. + * The key d is represented in two 320-bit shares, d0 and d1, such that d = (d0 + * + d1) mod n. Mathematically, d0 and d1 could also be reduced modulo n, but + * the extra bits provide side-channel protection. + */ +typedef struct p384_masked_scalar { + /** + * First share of the secret scalar. + */ + uint32_t share0[kP384MaskedScalarShareWords]; + /** + * Second share of the secret scalar. + */ + uint32_t share1[kP384MaskedScalarShareWords]; +} p384_masked_scalar_t; + +/** + * A type that holds a P-384 curve point. + */ +typedef struct p384_point { + /** + * Affine x-coordinate. + */ + uint32_t x[kP384CoordWords]; + /** + * Affine y-coordinate. + */ + uint32_t y[kP384CoordWords]; +} p384_point_t; + +/** + * A type that holds an ECDSA/P-384 signature. + * + * The signature consists of two integers r and s, computed modulo n. + */ +typedef struct p384_ecdsa_signature_t { + uint32_t r[kP384ScalarWords]; + uint32_t s[kP384ScalarWords]; +} p384_ecdsa_signature_t; + +/** + * A type that holds a blinded ECDH shared secret key. + * + * The key is boolean-masked (XOR of the two shares). + */ +typedef struct p384_ecdh_shared_key { + uint32_t share0[kP384CoordWords]; + uint32_t share1[kP384CoordWords]; +} p384_ecdh_shared_key_t; + +/** + * Start an async P-384 keypair generation operation on OTBN. + * + * Appropriate for both ECDSA and ECDH; the key-generation process is the same. + * + * Returns an `OTCRYPTO_ASYNC_INCOMPLETE` error if OTBN is busy. + * + * @return Result of the operation (OK or error). + */ +OT_WARN_UNUSED_RESULT +status_t p384_keygen_start(void); + +/** + * Finish an async P-384 keypair generation operation on OTBN. + * + * Blocks until OTBN is idle. + * + * @param[out] private_key Generated private key. + * @param[out] public_key Generated public key. + * @return Result of the operation (OK or error). + */ +OT_WARN_UNUSED_RESULT +status_t p384_keygen_finalize(p384_masked_scalar_t *private_key, + p384_point_t *public_key); + +/** + * Start an async P-384 sideloaded keypair generation operation on OTBN. + * + * Appropriate for both ECDSA and ECDH; the key-generation process is the same. + * + * Expects a sideloaded key from keymgr to be already loaded on OTBN. Returns + * an `OTCRYPTO_ASYNC_INCOMPLETE` error if OTBN is busy. + * + * @return Result of the operation (OK or error). + */ +OT_WARN_UNUSED_RESULT +status_t p384_sideload_keygen_start(void); + +/** + * Finish an async P-384 sideloaded keypair generation operation on OTBN. + * + * This routine will only read back the public key, instead of both public and + * private as with `p384_ecdsa_keygen_finalize`. Blocks until OTBN is idle. + * + * @param[out] public_key Public key. + * @return Result of the operation (OK or error). + */ +OT_WARN_UNUSED_RESULT +status_t p384_sideload_keygen_finalize(p384_point_t *public_key); + +/** + * Start an async ECDSA/P-384 signature generation operation on OTBN. + * + * Returns an `OTCRYPTO_ASYNC_INCOMPLETE` error if OTBN is busy. + * + * @param digest Digest of the message to sign. + * @param private_key Secret key to sign the message with. + * @return Result of the operation (OK or error). + */ +OT_WARN_UNUSED_RESULT +status_t p384_ecdsa_sign_start(const uint32_t digest[kP384ScalarWords], + const p384_masked_scalar_t *private_key); + +/** + * Start an async ECDSA/P-384 signature generation operation on OTBN. + * + * Expects a sideloaded key from keymgr to be already loaded on OTBN. Returns + * an `OTCRYPTO_ASYNC_INCOMPLETE` error if OTBN is busy. + * + * @param digest Digest of the message to sign. + * @return Result of the operation (OK or error). + */ +OT_WARN_UNUSED_RESULT +status_t p384_ecdsa_sideload_sign_start( + const uint32_t digest[kP384ScalarWords]); + +/** + * Finish an async ECDSA/P-384 signature generation operation on OTBN. + * + * See the documentation of `p384_ecdsa_sign` for details. + * + * Blocks until OTBN is idle. + * + * @param[out] result Buffer in which to store the generated signature. + * @return Result of the operation (OK or error). + */ +OT_WARN_UNUSED_RESULT +status_t p384_ecdsa_sign_finalize(p384_ecdsa_signature_t *result); + +/** + * Start an async ECDSA/P-384 signature verification operation on OTBN. + * + * See the documentation of `p384_ecdsa_verify` for details. + * + * Returns an `OTCRYPTO_ASYNC_INCOMPLETE` error if OTBN is busy. + * + * @param signature Signature to be verified. + * @param digest Digest of the message to check the signature against. + * @param public_key Key to check the signature against. + * @return Result of the operation (OK or error). + */ +OT_WARN_UNUSED_RESULT +status_t p384_ecdsa_verify_start(const p384_ecdsa_signature_t *signature, + const uint32_t digest[kP384ScalarWords], + const p384_point_t *public_key); + +/** + * Finish an async ECDSA/P-384 signature verification operation on OTBN. + * + * See the documentation of `p384_ecdsa_verify` for details. + * + * Blocks until OTBN is idle. + * + * If the signature is valid, writes `kHardenedBoolTrue` to `result`; + * otherwise, writes `kHardenedBoolFalse`. + * + * Note: the caller must check the `result` buffer in order to determine if a + * signature passed verification. If a signature is invalid, but nothing goes + * wrong during computation (e.g. hardware errors, failed preconditions), the + * status will be OK but `result` will be `kHardenedBoolFalse`. + * + * @param signature Signature to be verified. + * @param[out] result Output buffer (true if signature is valid, false + * otherwise) + * @return Result of the operation (OK or error). + */ +OT_WARN_UNUSED_RESULT +status_t p384_ecdsa_verify_finalize(const p384_ecdsa_signature_t *signature, + hardened_bool_t *result); + +/** + * Start an async ECDH/P-384 shared key generation operation on OTBN. + * + * Returns an `OTCRYPTO_ASYNC_INCOMPLETE` error if OTBN is busy. + * + * @param private_key Private key (d). + * @param public_key Public key (Q). + * @return Result of the operation (OK or error). + */ +OT_WARN_UNUSED_RESULT +status_t p384_ecdh_start(const p384_masked_scalar_t *private_key, + const p384_point_t *public_key); + +/** + * Finish an async ECDH/P-384 shared key generation operation on OTBN. + * + * Blocks until OTBN is idle. May be used after either `p384_ecdh_start` or + * `p384_sideload_ecdh_start`; the operation is the same. + * + * @param[out] shared_key Shared secret key (x-coordinate of d*Q). + * @return Result of the operation (OK or error). + */ +OT_WARN_UNUSED_RESULT +status_t p384_ecdh_finalize(p384_ecdh_shared_key_t *shared_key); + +/** + * Start an async ECDH/P-384 shared key generation operation on OTBN. + * + * Uses a private key generated from a key manager seed. The key manager should + * already have sideloaded the key into OTBN before this operation is called. + * + * Returns an `OTCRYPTO_ASYNC_INCOMPLETE` error if OTBN is busy. + * + * @param public_key Public key (Q). + * @return Result of the operation (OK or error). + */ +OT_WARN_UNUSED_RESULT +status_t p384_sideload_ecdh_start(const p384_point_t *public_key); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus + +#endif // OPENTITAN_SW_DEVICE_LIB_CRYPTO_IMPL_ECC_P384_H_ diff --git a/sw/device/lib/crypto/impl/ecc/p384_common.c b/sw/device/lib/crypto/impl/ecc/p384_common.c deleted file mode 100644 index 95983910ed936..0000000000000 --- a/sw/device/lib/crypto/impl/ecc/p384_common.c +++ /dev/null @@ -1,58 +0,0 @@ -// 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/crypto/impl/ecc/p384_common.h" - -#include "sw/device/lib/crypto/drivers/otbn.h" -#include "sw/device/lib/crypto/impl/status.h" - -enum { - /** - * Number of extra padding words needed for masked scalar shares. - * - * Where W is the word size and S is the share size, the padding needed is: - * (W - (S % W)) % W - * - * The extra outer "% W" ensures that the padding is 0 if (S % W) is 0. - */ - kMaskedScalarPaddingWords = - (kOtbnWideWordNumWords - - (kP384MaskedScalarShareWords % kOtbnWideWordNumWords)) % - kOtbnWideWordNumWords, -}; - -status_t p384_masked_scalar_write(const p384_masked_scalar_t *src, - const otbn_addr_t share0_addr, - const otbn_addr_t share1_addr) { - HARDENED_TRY( - otbn_dmem_write(kP384MaskedScalarShareWords, src->share0, share0_addr)); - HARDENED_TRY( - otbn_dmem_write(kP384MaskedScalarShareWords, src->share1, share1_addr)); - - // Write trailing 0s so that OTBN's 384-bit read of the second share does not - // cause an error. - HARDENED_TRY(otbn_dmem_set(kMaskedScalarPaddingWords, 0, - share0_addr + kP384MaskedScalarShareBytes)); - HARDENED_TRY(otbn_dmem_set(kMaskedScalarPaddingWords, 0, - share1_addr + kP384MaskedScalarShareBytes)); - - return OTCRYPTO_OK; -} - -status_t set_message_digest(const uint32_t digest[kP384ScalarWords], - const otbn_addr_t kOtbnVarEcdsaMsg) { - // Set the message digest. We swap all the bytes so that OTBN can interpret - // the digest as a little-endian integer, which is a more natural fit for the - // architecture than the big-endian form requested by the specification (FIPS - // 186-5, section B.2.1). - uint32_t digest_little_endian[kP384ScalarWords]; - size_t i = 0; - for (; launder32(i) < kP384ScalarWords; i++) { - digest_little_endian[i] = - __builtin_bswap32(digest[kP384ScalarWords - 1 - i]); - } - HARDENED_CHECK_EQ(i, kP384ScalarWords); - return otbn_dmem_write(kP384ScalarWords, digest_little_endian, - kOtbnVarEcdsaMsg); -} diff --git a/sw/device/lib/crypto/impl/ecc/p384_common.h b/sw/device/lib/crypto/impl/ecc/p384_common.h deleted file mode 100644 index d8244767839df..0000000000000 --- a/sw/device/lib/crypto/impl/ecc/p384_common.h +++ /dev/null @@ -1,136 +0,0 @@ -// 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_DEVICE_LIB_CRYPTO_IMPL_ECC_P384_COMMON_H_ -#define OPENTITAN_SW_DEVICE_LIB_CRYPTO_IMPL_ECC_P384_COMMON_H_ - -#include -#include - -#include "sw/device/lib/crypto/drivers/otbn.h" -#include "sw/device/lib/crypto/impl/status.h" - -#ifdef __cplusplus -extern "C" { -#endif // __cplusplus - -enum { - /** - * Length of a P-384 curve point coordinate in bits (modulo p). - */ - kP384CoordBits = 384, - /** - * Length of a P-384 curve point coordinate in bytes. - */ - kP384CoordBytes = kP384CoordBits / 8, - /** - * Length of a P-384 curve point coordinate in words. - */ - kP384CoordWords = kP384CoordBytes / sizeof(uint32_t), - /** - * Length of an element in the P-384 scalar field (modulo the curve order n). - */ - kP384ScalarBits = 384, - /** - * Length of a secret scalar share in bytes. - */ - kP384ScalarBytes = kP384ScalarBits / 8, - /** - * Length of secret scalar share in words. - */ - kP384ScalarWords = kP384ScalarBytes / sizeof(uint32_t), - /** - * Length of a masked secret scalar share. - * - * This implementation uses extra redundant bits for side-channel protection. - */ - kP384MaskedScalarShareBits = kP384ScalarBits + 64, - /** - * Length of a masked secret scalar share in bytes. - */ - kP384MaskedScalarShareBytes = kP384MaskedScalarShareBits / 8, - /** - * Length of masked secret scalar share in words. - */ - kP384MaskedScalarShareWords = kP384MaskedScalarShareBytes / sizeof(uint32_t), -}; - -/** - * A type that holds a masked value from the P-384 scalar field. - * - * This struct is used to represent secret keys, which are integers modulo n. - * The key d is represented in two 320-bit shares, d0 and d1, such that d = (d0 - * + d1) mod n. Mathematically, d0 and d1 could also be reduced modulo n, but - * the extra bits provide side-channel protection. - */ -typedef struct p384_masked_scalar { - /** - * First share of the secret scalar. - */ - uint32_t share0[kP384MaskedScalarShareWords]; - /** - * Second share of the secret scalar. - */ - uint32_t share1[kP384MaskedScalarShareWords]; -} p384_masked_scalar_t; - -/** - * A type that holds a P-384 curve point. - */ -typedef struct p384_point { - /** - * Affine x-coordinate. - */ - uint32_t x[kP384CoordWords]; - /** - * Affine y-coordinate. - */ - uint32_t y[kP384CoordWords]; -} p384_point_t; - -/** - * A type that holds an ECDSA/P-384 signature. - * - * The signature consists of two integers r and s, computed modulo n. - */ -typedef struct ecdsa_p384_signature_t { - uint32_t r[kP384ScalarWords]; - uint32_t s[kP384ScalarWords]; -} ecdsa_p384_signature_t; - -/** - * Write a masked P-384 scalar to OTBN's data memory. - * - * OTBN actually requires that 512 bits be written, even though only 320 are - * used; the others are ignored but must be set to avoid an error when OTBN - * attempts to read uninitialized memory. - * - * @param src Masked scalar to write. - * @param share0_addr DMEM address of the first share. - * @param share1_addr DMEM address of the second share. - * @return Result of the operation. - */ -OT_WARN_UNUSED_RESULT -status_t p384_masked_scalar_write(const p384_masked_scalar_t *src, - const otbn_addr_t share0_addr, - const otbn_addr_t share1_addr); - -/** - * Set the message digest for signature generation or verification. - * - * OTBN requires the digest in little-endian form, so this routine flips the - * bytes. - * - * @param digest Digest to set (big-endian). - * @return OK or error. - */ -OT_WARN_UNUSED_RESULT -status_t set_message_digest(const uint32_t digest[kP384ScalarWords], - const otbn_addr_t kOtbnVarEcdsaMsg); - -#ifdef __cplusplus -} // extern "C" -#endif // __cplusplus - -#endif // OPENTITAN_SW_DEVICE_LIB_CRYPTO_IMPL_ECC_P384_COMMON_H_ diff --git a/sw/otbn/crypto/BUILD b/sw/otbn/crypto/BUILD index e931cfb2322c1..e5b53dca750a3 100644 --- a/sw/otbn/crypto/BUILD +++ b/sw/otbn/crypto/BUILD @@ -365,9 +365,9 @@ otbn_binary( ) otbn_binary( - name = "p384_ecdh", + name = "run_p384", srcs = [ - "p384_ecdh.s", + "run_p384.s", ], deps = [ ":p384_a2b", @@ -378,53 +378,9 @@ otbn_binary( ":p384_isoncurve", ":p384_keygen", ":p384_keygen_from_seed", - ":p384_scalar_mult", - ], -) - -otbn_binary( - name = "p384_ecdsa_keygen", - srcs = [ - "p384_ecdsa_keygen.s", - ], - deps = [ - ":p384_b2a", - ":p384_base", - ":p384_base_mult", - ":p384_internal_mult", - ":p384_keygen", - ":p384_keygen_from_seed", - ], -) - -otbn_binary( - name = "p384_ecdsa_sign", - srcs = [ - "p384_ecdsa_sign.s", - ], - deps = [ - ":p384_b2a", - ":p384_base", - ":p384_base_mult", - ":p384_internal_mult", - ":p384_keygen", - ":p384_keygen_from_seed", ":p384_modinv", + ":p384_scalar_mult", ":p384_sign", - ], -) - -otbn_binary( - name = "p384_ecdsa_verify", - srcs = [ - "p384_ecdsa_verify.s", - ], - deps = [ - ":p384_base", - ":p384_base_mult", - ":p384_internal_mult", - ":p384_isoncurve", - ":p384_modinv", ":p384_verify", ], ) diff --git a/sw/otbn/crypto/p384_curve_point_valid.s b/sw/otbn/crypto/p384_curve_point_valid.s new file mode 100644 index 0000000000000..f73add4fd0be0 --- /dev/null +++ b/sw/otbn/crypto/p384_curve_point_valid.s @@ -0,0 +1,46 @@ +/* Copyright lowRISC contributors (OpenTitan project). */ +/* Licensed under the Apache License, Version 2.0, see LICENSE for details. */ +/* SPDX-License-Identifier: Apache-2.0 */ + +/** + * Curve point validation for curve P-384. + * + * Checks if a given curve point (e.g. public key for ECDH shared key + * generation) is a valid curve point on the P-384 curve. + * + * The check is successful when the binary execution completes without + * error. In case of an unvalid point, a software error is raised and execution + * is halted. + */ + +.section .text.start +start: + /* Init all-zero register. */ + bn.xor w31, w31, w31 + + jal x1, validate_point + + /* Unsupported mode; fail. */ + unimp + unimp + unimp + +validate_point: + /* Call curve point validation function */ + jal x1, p384_curve_point_valid + + ecall + +.data + +/* Public key x-coordinate. */ +.globl x +.balign 32 +x: + .zero 64 + +/* Public key y-coordinate. */ +.globl y +.balign 32 +y: + .zero 64 diff --git a/sw/otbn/crypto/p384_ecdsa_keygen.s b/sw/otbn/crypto/p384_ecdsa_keygen.s deleted file mode 100644 index a25b9dacb795f..0000000000000 --- a/sw/otbn/crypto/p384_ecdsa_keygen.s +++ /dev/null @@ -1,154 +0,0 @@ -/* Copyright lowRISC contributors (OpenTitan project). */ -/* Licensed under the Apache License, Version 2.0, see LICENSE for details. */ -/* SPDX-License-Identifier: Apache-2.0 */ - -/** - * Entrypoint for P-384 ECDSA key generation operations. - * - * This binary generates a new keypair. - * - * This binary has the following modes of operation: - * 1. MODE_KEYGEN_RANDOM: generate a random keypair - * 2. MODE_KEYGEN_FROM_SEED: generate a keypair from a sideloaded seed - */ - -.equ MODE_KEYGEN_RANDOM, 0x3d4 -.equ MODE_KEYGEN_FROM_SEED, 0x5e8 - -.section .text.start -.globl start -start: - /* Init all-zero register. */ - bn.xor w31, w31, w31 - - /* Read the mode and tail-call the requested operation. */ - la x2, mode - lw x2, 0(x2) - - addi x3, x0, MODE_KEYGEN_RANDOM - beq x2, x3, keypair_random - - addi x3, x0, MODE_KEYGEN_FROM_SEED - beq x2, x3, keypair_from_seed - - /* Unsupported mode; fail. */ - unimp - unimp - unimp - -/** - * Generate a fresh random keypair. - * - * Returns secret key d in 448-bit shares d0, d1. - * Returns public key Q = d*G in affine coordinates (x, y). - * - * @param[in] w31: all-zero - * @param[out] dmem[d0]: 1st private key share d0 - * @param[out] dmem[d1]: 2nd private key share d1 - * @param[out] dmem[x]: Public key x-coordinate - * @param[out] dmem[y]: Public key y-coordinate - - */ -keypair_random: - /* Generate secret key d in shares. - dmem[d0] <= d0 - dmem[d1] <= d1 */ - jal x1, p384_generate_random_key - - /* Generate public key d*G. - dmem[x] <= (d*G).x - dmem[y] <= (d*G).y */ - jal x1, p384_base_mult - - ecall - -/** - * Generate a fresh random keypair from a sideloaded seed. - * - * Returns secret key d in 384-bit shares d0, d1. - * - * Returns public key Q = d*G in affine coordinates (x, y). - * - * This routine runs in constant time (except potentially waiting for entropy - * from RND). - * - * @param[in] w31: all-zero - * @param[out] dmem[d0]: 1st private key share d0 - * @param[out] dmem[d1]: 2nd private key share d1 - * @param[out] dmem[x]: Public key x-coordinate - * @param[out] dmem[y]: Public key y-coordinate - * - * clobbered registers: x2, x3, x9 to x13, x18 to x21, x26 to x30, w0 to w30 - * clobbered flag groups: FG0 - */ -keypair_from_seed: - /* Load keymgr seeds from WSRs. - w20,w21 <= seed0 - w10,w11 <= seed1 */ - bn.wsrr w20, KEY_S0_L - bn.wsrr w21, KEY_S0_H - bn.wsrr w10, KEY_S1_L - bn.wsrr w11, KEY_S1_H - - /* Generate secret key d in shares. - dmem[d0] <= d0 - dmem[d1] <= d1 */ - jal x1, p384_key_from_seed - - /* Generate public key d*G. - dmem[x] <= (d*G).x - dmem[y] <= (d*G).y */ - jal x1, p384_base_mult - - ecall - -.bss - -/* Operational mode. */ -.globl mode -.balign 4 -mode: - .zero 4 - -/* random scalar first share */ -.globl k0 -.balign 32 -k0: - .zero 64 - -/* random scalar second share */ -.globl k1 -.balign 32 -k1: - .zero 64 - -/* private key first share */ -.globl d0 -.balign 32 -d0: - .zero 64 - -/* private key second share */ -.globl d1 -.balign 32 -d1: - .zero 64 - -/* x-coordinate. */ -.globl x -.balign 32 -x: - .zero 64 - -/* y-coordinate. */ -.globl y -.balign 32 -y: - .zero 64 - -/* 704 bytes of scratchpad memory - defined globally to save dmem */ -.balign 32 -.globl scratchpad -scratchpad: - .zero 704 diff --git a/sw/otbn/crypto/p384_ecdsa_sign.s b/sw/otbn/crypto/p384_ecdsa_sign.s deleted file mode 100644 index e3f0c49941842..0000000000000 --- a/sw/otbn/crypto/p384_ecdsa_sign.s +++ /dev/null @@ -1,169 +0,0 @@ -/* Copyright lowRISC contributors (OpenTitan project). */ -/* Licensed under the Apache License, Version 2.0, see LICENSE for details. */ -/* SPDX-License-Identifier: Apache-2.0 */ - -/** - * Entrypoint for P-384 ECDSA signing operations. - * - * This binary generates a signature using a caller-provided secret key. - * - * This binary has the following modes of operation: - * 1. MODE_SIGN: generate signature using caller-provided secret key - * 2. MODE_SIDELOAD_SIGN: generate signature using sideloaded secret key/seed - */ - - /** - * Mode magic values, generated with - * $ ./util/design/sparse-fsm-encode.py -d 6 -m 5 -n 11 \ - * --avoid-zero -s 2205231843 - * - * Call the same utility with the same arguments and a higher -m to generate - * additional value(s) without changing the others or sacrificing mutual HD. - * - * TODO(#17727): in some places the OTBN assembler support for .equ directives - * is lacking, so they cannot be used in bignum instructions or pseudo-ops such - * as `li`. If support is added, we could use 32-bit values here instead of - * 11-bit. - */ -.equ MODE_SIGN, 0x15b -.equ MODE_SIDELOAD_SIGN, 0x49e - -.section .text.start -.globl start -start: - /* Init all-zero register. */ - bn.xor w31, w31, w31 - - /* Read the mode and tail-call the requested operation. */ - la x2, mode - lw x2, 0(x2) - - addi x3, x0, MODE_SIGN - beq x2, x3, ecdsa_sign - - addi x3, x0, MODE_SIDELOAD_SIGN - beq x2, x3, ecdsa_sign_sideload - - /* Invalid mode; fail. */ - unimp - unimp - unimp - -/** - * P-384 ECDSA signature generation. - * Generate the secret scalar k from a random seed. - * - * @param[in] dmem[msg]: message to be signed in dmem - * @param[in] dmem[d0]: 1st private key share d0 - * @param[in] dmem[d1]: 2nd private key share d1 - * @param[out] dmem[r]: r component of signature - * @param[out] dmem[s]: s component of signature - */ -ecdsa_sign: - /* Generate a fresh random scalar for signing. - dmem[k0] <= first share of k - dmem[k1] <= second share of k */ - jal x1, p384_generate_k - - /* Generate the signature. */ - jal x1, p384_sign - - ecall - -/** - * P-384 ECDSA side-loaded signature generation. - * Generate a signature using a private key from a - * sideloaded seed. - * - * @param[in] dmem[msg]: message to be signed in dmem - * @param[out] dmem[r]: r component of signature - * @param[out] dmem[s]: s component of signature - */ -ecdsa_sign_sideload: - /* Load keymgr seeds from WSRs. - w20,w21 <= seed0 - w10,w11 <= seed1 */ - bn.wsrr w20, KEY_S0_L - bn.wsrr w21, KEY_S0_H - bn.wsrr w10, KEY_S1_L - bn.wsrr w11, KEY_S1_H - - /* Generate secret key d in shares. - dmem[d0] <= d0 - dmem[d1] <= d1 */ - jal x1, p384_key_from_seed - - /* Tail-call signature-generation routine. */ - jal x0, ecdsa_sign - - -.bss - -/* Operational mode. */ -.globl mode -.balign 4 -mode: - .zero 4 - -/* x-coordinate. */ -.globl x -.balign 32 -x: - .zero 64 - -/* y-coordinate. */ -.globl y -.balign 32 -y: - .zero 64 - -/* random scalar first share */ -.globl k0 -.balign 32 -k0: - .zero 64 - -/* random scalar second share */ -.globl k1 -.balign 32 -k1: - .zero 64 - -/* r part of signature */ -.globl r -.balign 32 -r: - .zero 64 - -/* s part of signature */ -.globl s -.balign 32 -s: - .zero 64 - -.data - -/* private key first share */ -.globl d0 -.balign 32 -d0: - .zero 64 - -/* private key second share */ -.globl d1 -.balign 32 -d1: - .zero 64 - -/* hash message to sign/verify */ -.globl msg -.balign 32 -msg: - .zero 64 - -/* 704 bytes of scratchpad memory - defined globally to save dmem */ -.balign 32 -.globl scratchpad -scratchpad: - .zero 704 diff --git a/sw/otbn/crypto/p384_ecdsa_verify.s b/sw/otbn/crypto/p384_ecdsa_verify.s deleted file mode 100644 index 59cc817703017..0000000000000 --- a/sw/otbn/crypto/p384_ecdsa_verify.s +++ /dev/null @@ -1,104 +0,0 @@ -/* Copyright lowRISC contributors (OpenTitan project). */ -/* Licensed under the Apache License, Version 2.0, see LICENSE for details. */ -/* SPDX-License-Identifier: Apache-2.0 */ - -/** - * Entrypoint for P-384 ECDSA verifying operations. - * - * This binary verifies a signature. - !!! Attention !!! - before - * signature verification p384_curve_point_valid - * binary has to be executed to check if the provided - * public key is valid. - */ - -.section .text.start -.globl start -start: - /* Init all-zero register. */ - bn.xor w31, w31, w31 - - jal x1, ecdsa_verify - - /* Invalid mode; fail. */ - unimp - unimp - unimp - - -/** - * P-384 ECDSA signature verification - * - * The routine computes the x1 coordinate and places it in dmem. x1 will be - * reduced (mod n), however, the final comparison has to be performed on the - * host side. The signature is valid if x1 == r. - * This routine runs in variable time. - * - * @param[in] dmem[msg]: message to be verified - * @param[in] dmem[r]: r part of signature - * @param[in] dmem[s]: s part of signature - * @param[in] dmem[x]: x-coordinate of public key - * @param[in] dmem[y]: y-coordinate of public key - * @param[out] dmem[x_r]: x1 coordinate to be compared to rs - */ -ecdsa_verify: - /* Call curve point validation function */ - jal x1, p384_check_public_key - - /* Verify the signature (compute x1). */ - jal x1, p384_verify - - ecall - -.bss - -/* Success code for basic validity checks on the public key and signature. - Should be HARDENED_BOOL_TRUE or HARDENED_BOOL_FALSE. */ -.balign 4 -.globl ok -ok: - .zero 4 - -/* result of verify (x1 coordinate) */ -.globl x_r -.balign 32 -x_r: - .zero 64 - -.data - -/* Public key x-coordinate. */ -.globl x -.balign 32 -x: - .zero 64 - -/* Public key y-coordinate. */ -.globl y -.balign 32 -y: - .zero 64 - -/* hash message to sign/verify */ -.globl msg -.balign 32 -msg: - .zero 64 - -/* r part of signature */ -.globl r -.balign 32 -r: - .zero 64 - -/* s part of signature */ -.globl s -.balign 32 -s: - .zero 64 - -/* 896 bytes of scratchpad memory - defined globally to save dmem. */ -.balign 32 -.globl scratchpad -scratchpad: - .zero 896 diff --git a/sw/otbn/crypto/p384_scalar_mult.s b/sw/otbn/crypto/p384_scalar_mult.s index f476438b85bc2..ec22a3507fbc1 100644 --- a/sw/otbn/crypto/p384_scalar_mult.s +++ b/sw/otbn/crypto/p384_scalar_mult.s @@ -10,9 +10,9 @@ /** * Externally callable wrapper for P-384 scalar point multiplication * - * Calculates R = k*P = k*(x_p, y_p) + * Calculates R = d*P = d*(x_p, y_p) * where R, P are valid P-384 curve points in affine coordinates, - * k is a 384-bit scalar. + * d is a 384-bit scalar. * The x coordinate of R is arithmetically masked. * Returns the masked x coordinate of R and the corresponding mask. * @@ -21,8 +21,8 @@ * * @param[in] dmem[x]: affine x-coordinate in dmem * @param[in] dmem[y]: affine y-coordinate in dmem - * @param[in] dmem[k0]: 1st scalar share k0 in dmem - * @param[in] dmem[k1]: 2nd scalar share k1 in dmem + * @param[in] dmem[d0]: 1st scalar share d0 in dmem + * @param[in] dmem[d1]: 2nd scalar share d1 in dmem * @param[out] dmem[x]: masked x coordinate of R * @param[out] dmem[y]: corresponding mask * @@ -54,11 +54,11 @@ p384_scalar_mult: /* set dmem pointer to point to y-coordinate */ la x21, y - /* set dmem pointer to point to 1st scalar share k0 */ - la x17, k0 + /* set dmem pointer to point to 1st scalar share d0 */ + la x17, d0 - /* set dmem pointer to point to 2nd scalar share k1 */ - la x19, k1 + /* set dmem pointer to point to 2nd scalar share d1 */ + la x19, d1 /* load domain parameter p (modulus) [w13, w12] = p = dmem[p384_p] */ @@ -178,15 +178,15 @@ p384_scalar_mult: .balign 32 /* 1st scalar share d0 */ -.globl k0 -.weak k0 -k0: +.globl d0 +.weak d0 +d0: .zero 64 /* 2nd scalar share d1 */ -.globl k1 -.weak k1 -k1: +.globl d1 +.weak d1 +d1: .zero 64 /* x-coordinate */ diff --git a/sw/otbn/crypto/p384_verify.s b/sw/otbn/crypto/p384_verify.s index b3c5e1e699925..9db74bbf04bc3 100644 --- a/sw/otbn/crypto/p384_verify.s +++ b/sw/otbn/crypto/p384_verify.s @@ -384,7 +384,7 @@ p384_verify: addi x12, x26, 0 jal x1, store_proj - /* Increment counter. */ + /* increment counter */ addi x15, x15, 1 /* load domain parameter p (order of finite field) diff --git a/sw/otbn/crypto/p384_ecdh.s b/sw/otbn/crypto/run_p384.s similarity index 59% rename from sw/otbn/crypto/p384_ecdh.s rename to sw/otbn/crypto/run_p384.s index 32fca0faa1c7e..5c570a6f0a123 100644 --- a/sw/otbn/crypto/p384_ecdh.s +++ b/sw/otbn/crypto/run_p384.s @@ -3,19 +3,21 @@ /* SPDX-License-Identifier: Apache-2.0 */ /** - * Elliptic-curve Diffie-Hellman (ECDH) on curve P-384. + * Entrypoint for P-384 ECDH and ECDSA operations. * * This binary has the following modes of operation: - * 1. MODE_KEYGEN_RANDOM: generate a random keypair - * 2. MODE_SHARED_KEYGEN: compute shared key - * 3. MODE_KEYGEN_FROM_SEED: generate keypair from a sideloaded seed - * 4. MODE_SHARED_KEYGEN_FROM_SEED: compute shared key using sideloaded seed + * 1. MODE_KEYGEN: generate a new keypair + * 2. MODE_SIGN: generate an ECDSA signature using caller-provided secret key + * 3. MODE_VERIFY: verify an ECDSA signature + * 4. MODE_ECDH: ECDH key exchange using a caller-provided secret key + * 5. MODE_SIDELOAD_KEYGEN: generate a keypair from a sideloaded seed + * 6. MODE_SIDELOAD_SIGN: generate an ECDSA signature using sideloaded secret key/seed + * 7. MODE_SIDELOAD_ECDH: ECDH key exchange using a secret key from a sideloaded seed */ /** * Mode magic values generated with - * $ ./util/design/sparse-fsm-encode.py -d 6 -m 4 -n 11 \ - * --avoid-zero -s 3660400884 + * $ ./util/design/sparse-fsm-encode.py -d 6 -m 4 -n 11 --avoid-zero -s 1654842154 * * Call the same utility with the same arguments and a higher -m to generate * additional value(s) without changing the others or sacrificing mutual HD. @@ -25,18 +27,24 @@ * as `li`. If support is added, we could use 32-bit values here instead of * 11-bit. */ -.equ MODE_SHARED_KEY, 0x5ec -.equ MODE_KEYPAIR_RANDOM, 0x3f1 -.equ MODE_KEYPAIR_FROM_SEED, 0x29f -.equ MODE_SHARED_KEY_FROM_SEED, 0x74b +.equ MODE_KEYGEN, 0x0e7 +.equ MODE_SIGN, 0x633 +.equ MODE_VERIFY, 0x54d +.equ MODE_ECDH, 0x3bd +.equ MODE_SIDELOAD_KEYGEN, 0x4da +.equ MODE_SIDELOAD_SIGN, 0x786 +.equ MODE_SIDELOAD_ECDH, 0x36a /** * Make the mode constants visible to Ibex. */ -.globl MODE_SHARED_KEY -.globl MODE_KEYPAIR_RANDOM -.globl MODE_KEYPAIR_FROM_SEED -.globl MODE_SHARED_KEY_FROM_SEED +.globl MODE_KEYGEN +.globl MODE_SIGN +.globl MODE_VERIFY +.globl MODE_ECDH +.globl MODE_SIDELOAD_KEYGEN +.globl MODE_SIDELOAD_SIGN +.globl MODE_SIDELOAD_ECDH /** * Hardened boolean values. @@ -47,27 +55,34 @@ .equ HARDENED_BOOL_FALSE, 0x1d4 .section .text.start +.globl start start: - /* Init all-zero register. */ - bn.xor w31, w31, w31 - /* Read the mode and tail-call the requested operation. */ - la x2, mode - lw x2, 0(x2) + la x2, mode + lw x2, 0(x2) + + addi x3, x0, MODE_KEYGEN + beq x2, x3, keypair_random + + addi x3, x0, MODE_SIGN + beq x2, x3, ecdsa_sign - addi x3, x0, MODE_KEYPAIR_RANDOM - beq x2, x3, keypair_random + addi x3, x0, MODE_VERIFY + beq x2, x3, ecdsa_verify - addi x3, x0, MODE_SHARED_KEY - beq x2, x3, shared_key + addi x3, x0, MODE_ECDH + beq x2, x3, shared_key - addi x3, x0, MODE_KEYPAIR_FROM_SEED - beq x2, x3, keypair_from_seed + addi x3, x0, MODE_SIDELOAD_KEYGEN + beq x2, x3, keypair_from_seed - addi x3, x0, MODE_SHARED_KEY_FROM_SEED - beq x2, x3, shared_key_from_seed + addi x3, x0, MODE_SIDELOAD_SIGN + beq x2, x3, ecdsa_sign_sideloaded - /* Unsupported mode; fail. */ + addi x3, x0, MODE_SIDELOAD_ECDH + beq x2, x3, shared_key_from_seed + + /* Invalid mode; fail. */ unimp unimp unimp @@ -104,6 +119,79 @@ keypair_random: ecall +/** + * P-384 ECDSA signature generation. + * Generate the secret scalar k from a random seed. + * + * @param[in] dmem[msg]: message to be signed in dmem + * @param[in] dmem[d0]: 1st private key share d0 + * @param[in] dmem[d1]: 2nd private key share d1 + * @param[out] dmem[r]: r component of signature + * @param[out] dmem[s]: s component of signature + */ +ecdsa_sign: + /* Generate a fresh random scalar for signing. + dmem[k0] <= first share of k + dmem[k1] <= second share of k */ + jal x1, p384_generate_k + + /* Generate the signature. */ + jal x1, p384_sign + + ecall + +/** + * P-384 ECDSA side-loaded signature generation. + * + * Generate a signature using a private key from a + * sideloaded seed. + * + * @param[in] dmem[msg]: message to be signed in dmem + * @param[out] dmem[r]: r component of signature + * @param[out] dmem[s]: s component of signature + */ +ecdsa_sign_sideloaded: + /* Load keymgr seeds from WSRs. + w20,w21 <= seed0 + w10,w11 <= seed1 */ + bn.wsrr w20, KEY_S0_L + bn.wsrr w21, KEY_S0_H + bn.wsrr w10, KEY_S1_L + bn.wsrr w11, KEY_S1_H + + /* Generate secret key d in shares. + dmem[d0] <= d0 + dmem[d1] <= d1 */ + jal x1, p384_key_from_seed + + /* Tail-call signature-generation routine. */ + jal x0, ecdsa_sign + +/** + * P-384 ECDSA signature verification + * + * The routine computes the x1 coordinate and places it in dmem. x1 will be + * reduced (mod n), however, the final comparison has to be performed on the + * host side. The signature is valid if x1 == r. + * This routine runs in variable time. + * + * @param[in] dmem[msg]: message to be verified + * @param[in] dmem[r]: r part of signature + * @param[in] dmem[s]: s part of signature + * @param[in] dmem[x]: x-coordinate of public key + * @param[in] dmem[y]: y-coordinate of public key + * @param[out] dmem[x_r]: x1 coordinate to be compared to rs + */ +ecdsa_verify: + /* Validate the public key (ends the program on failure). */ + jal x1, p384_check_public_key + + /* Verify the signature (compute x1). */ + jal x1, p384_verify + + ecall + + /** * Generate a shared key from a secret and public key. * @@ -114,8 +202,8 @@ keypair_random: * This routine runs in constant time. * * @param[in] w31: all-zero - * @param[in] dmem[k0]: 1st private key share d0/k0 - * @param[in] dmem[k1]: 2nd private key share d1/k0 + * @param[in] dmem[d0]: 1st private key share d0 + * @param[in] dmem[d1]: 2nd private key share d1 * @param[in] dmem[x]: x-coordinate of public key * @param[in] dmem[y]: y-coordinate of public key * @param[out] dmem[x]: x0, first share of shared key. @@ -254,13 +342,30 @@ shared_key_from_seed: mode: .zero 4 -/* Success code for basic validity checks on the public key and signature. - Should be HARDENED_BOOL_TRUE or HARDENED_BOOL_FALSE. */ +/* Success code for basic validity checks on the public key and signature. */ .globl ok .balign 4 ok: .zero 4 +/* Message digest. */ +.globl msg +.balign 32 +msg: + .zero 64 + +/* Signature R. */ +.globl r +.balign 32 +r: + .zero 64 + +/* Signature S. */ +.globl s +.balign 32 +s: + .zero 64 + /* Public key x-coordinate. */ .globl x .balign 32 @@ -273,22 +378,31 @@ x: y: .zero 64 -/* Secret key (d) in two shares: d = (d0 + d1) mod n. +/* Private key (d) in two shares: d = (d0 + d1) mod n. */ +.globl d0 +.balign 32 +d0: + .zero 64 +.globl d1 +.balign 32 +d1: + .zero 64 + +/* Verification result x_r (aka x_1). */ +.globl x_r +.balign 32 +x_r: + .zero 64 - Note: This is also labeled k0, k1 because the `p384_scalar_mult` algorithm - requires k0 and k1 as labels for the scalar; in the case of ECDH, the - scalar in `p384_scalar_mult` is always the private key (d). */ +.section .scratchpad -.globl d0 +/* Secret scalar (k) in two shares: k = (k0 + k1) mod n */ .globl k0 .balign 32 -d0: k0: .zero 64 -.globl d1 .globl k1 .balign 32 -d1: k1: .zero 64 diff --git a/sw/otbn/crypto/tests/BUILD b/sw/otbn/crypto/tests/BUILD index 12b691ac9cc81..4cdaf2375fba6 100644 --- a/sw/otbn/crypto/tests/BUILD +++ b/sw/otbn/crypto/tests/BUILD @@ -456,6 +456,7 @@ otbn_sim_test( srcs = [ "p384_ecdsa_verify_test.s", ], + dexp = "p384_ecdsa_verify_test.dexp", exp = "p384_ecdsa_verify_test.exp", deps = [ "//sw/otbn/crypto:p384_base", diff --git a/sw/otbn/crypto/tests/p384_ecdh_shared_key_test.s b/sw/otbn/crypto/tests/p384_ecdh_shared_key_test.s index a38cd975acee9..81c5901f9486a 100644 --- a/sw/otbn/crypto/tests/p384_ecdh_shared_key_test.s +++ b/sw/otbn/crypto/tests/p384_ecdh_shared_key_test.s @@ -100,9 +100,9 @@ y: .word 0x841e4949 .zero 16 -/* 1st scalar share k0 (448-bit) */ -.globl k0 -k0: +/* 1st scalar share d0 (448-bit) */ +.globl d0 +d0: .word 0x5c832a51 .word 0x3eb17c27 .word 0x9a0c1b76 @@ -119,9 +119,9 @@ k0: .word 0x32f9e2b0 .zero 8 -/* 2nd scalar share k1 (448-bit) */ -.globl k1 -k1: +/* 2nd scalar share d1 (448-bit) */ +.globl d1 +d1: .word 0x33eae098 .word 0xd31b18d5 .word 0x507568cd @@ -138,7 +138,7 @@ k1: .word 0x9e5dc598 .zero 8 -/* scalar k = (k0 + k1) mod n (384-bit)*/ +/* scalar d = (d0 + d1) mod n (384-bit)*/ scalar: .word 0xe8791ba3 .word 0xf549e1f7 diff --git a/sw/otbn/crypto/tests/p384_ecdsa_verify_test.s b/sw/otbn/crypto/tests/p384_ecdsa_verify_test.s index a18ba3229ec1e..8570b399ae3cf 100644 --- a/sw/otbn/crypto/tests/p384_ecdsa_verify_test.s +++ b/sw/otbn/crypto/tests/p384_ecdsa_verify_test.s @@ -33,10 +33,9 @@ p384_ecdsa_verify_test: ok: .word 0x000000739 -.balign 32 - /* message */ .globl msg +.balign 32 msg: .word 0x55555555 .word 0x55555555 @@ -54,6 +53,7 @@ msg: /* signature R */ .globl r +.balign 32 r: .word 0xb68c28d8 .word 0x2b23ce3a @@ -71,6 +71,7 @@ r: /* signature S */ .globl s +.balign 32 s: .word 0x24bc1bf9 .word 0x752042f5 @@ -88,6 +89,7 @@ s: /* public key x-coordinate */ .globl x +.balign 32 x: .word 0x4877f3d1 .word 0x7b829460 @@ -105,6 +107,7 @@ x: /* public key y-coordinate */ .globl y +.balign 32 y: .word 0xc181f90f .word 0xc31ef079 @@ -122,5 +125,6 @@ y: /* signature verification result x_res (x_r) */ .globl x_r +.balign 32 x_r: .zero 64 diff --git a/sw/otbn/crypto/tests/p384_scalar_mult_test.s b/sw/otbn/crypto/tests/p384_scalar_mult_test.s index 9b1805258e29b..11fec0f525e04 100644 --- a/sw/otbn/crypto/tests/p384_scalar_mult_test.s +++ b/sw/otbn/crypto/tests/p384_scalar_mult_test.s @@ -91,9 +91,9 @@ y: .word 0x841e4949 .zero 16 -/* 1st scalar share k0 (448-bit) */ -.globl k0 -k0: +/* 1st scalar share d0 (448-bit) */ +.globl d0 +d0: .word 0x5c832a51 .word 0x3eb17c27 .word 0x9a0c1b76 @@ -110,9 +110,9 @@ k0: .word 0x32f9e2b0 .zero 8 -/* 2nd scalar share k1 (448-bit) */ -.globl k1 -k1: +/* 2nd scalar share d1 (448-bit) */ +.globl d1 +d1: .word 0x33eae098 .word 0xd31b18d5 .word 0x507568cd @@ -129,7 +129,7 @@ k1: .word 0x9e5dc598 .zero 8 -/* scalar k = (k0 + k1) mod n (384-bit)*/ +/* scalar d = (d0 + d1) mod n (384-bit)*/ scalar: .word 0xe8791ba3 .word 0xf549e1f7