diff --git a/sw/device/tests/crypto/cryptotest/firmware/BUILD b/sw/device/tests/crypto/cryptotest/firmware/BUILD index 4887aaaba906c8..889c9dbd78b68f 100644 --- a/sw/device/tests/crypto/cryptotest/firmware/BUILD +++ b/sw/device/tests/crypto/cryptotest/firmware/BUILD @@ -125,6 +125,24 @@ cc_library( ], ) +cc_library( + name = "sphincsplus", + srcs = ["sphincsplus.c"], + hdrs = ["sphincsplus.h"], + deps = [ + "//sw/device/lib/base:memory", + "//sw/device/lib/base:status", + "//sw/device/lib/crypto/impl:integrity", + "//sw/device/lib/crypto/impl:keyblob", + "//sw/device/lib/crypto/include:datatypes", + "//sw/device/lib/runtime:log", + "//sw/device/lib/testing/test_framework:ujson_ottf", + "//sw/device/lib/ujson", + "//sw/device/silicon_creator/lib/sigverify/sphincsplus:verify", + "//sw/device/tests/crypto/cryptotest/json:sphincsplus_commands", + ], +) + cc_library( name = "aes_sca", srcs = ["aes_sca.c"], @@ -251,6 +269,7 @@ opentitan_binary( ":kmac_sca", ":prng_sca", ":sha3_sca", + ":sphincsplus", ":trigger_sca", "//sw/device/lib/base:status", "//sw/device/lib/crypto/drivers:entropy", @@ -290,6 +309,7 @@ opentitan_test( ":kmac_sca", ":prng_sca", ":sha3_sca", + ":sphincsplus", ":trigger_sca", "//sw/device/lib/base:status", "//sw/device/lib/crypto/drivers:entropy", @@ -305,5 +325,6 @@ opentitan_test( "//sw/device/tests/crypto/cryptotest/json:hash_commands", "//sw/device/tests/crypto/cryptotest/json:hmac_commands", "//sw/device/tests/crypto/cryptotest/json:ibex_fi_commands", + "//sw/device/tests/crypto/cryptotest/json:sphincsplus_commands", ], ) diff --git a/sw/device/tests/crypto/cryptotest/firmware/firmware.c b/sw/device/tests/crypto/cryptotest/firmware/firmware.c index 72aae987b7a398..3146495f9df285 100644 --- a/sw/device/tests/crypto/cryptotest/firmware/firmware.c +++ b/sw/device/tests/crypto/cryptotest/firmware/firmware.c @@ -23,6 +23,7 @@ #include "sw/device/tests/crypto/cryptotest/json/kmac_sca_commands.h" #include "sw/device/tests/crypto/cryptotest/json/prng_sca_commands.h" #include "sw/device/tests/crypto/cryptotest/json/sha3_sca_commands.h" +#include "sw/device/tests/crypto/cryptotest/json/sphincsplus_commands.h" #include "sw/device/tests/crypto/cryptotest/json/trigger_sca_commands.h" // Include handlers @@ -37,6 +38,7 @@ #include "kmac_sca.h" #include "prng_sca.h" #include "sha3_sca.h" +#include "sphincsplus.h" #include "trigger_sca.h" OTTF_DEFINE_TEST_CONFIG(.enable_uart_flow_control = true); @@ -64,6 +66,9 @@ status_t process_cmd(ujson_t *uj) { case kCryptotestCommandHmac: RESP_ERR(uj, handle_hmac(uj)); break; + case kCryptotestCommandSphincsPlus: + RESP_ERR(uj, handle_sphincsplus(uj)); + break; case kCryptotestCommandAesSca: RESP_ERR(uj, handle_aes_sca(uj)); break; diff --git a/sw/device/tests/crypto/cryptotest/firmware/sphincsplus.c b/sw/device/tests/crypto/cryptotest/firmware/sphincsplus.c new file mode 100644 index 00000000000000..2a1c01b3fdd4a9 --- /dev/null +++ b/sw/device/tests/crypto/cryptotest/firmware/sphincsplus.c @@ -0,0 +1,100 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +#include "sw/device/lib/base/memory.h" +#include "sw/device/lib/base/status.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" +#include "sw/device/lib/runtime/log.h" +#include "sw/device/lib/testing/test_framework/ujson_ottf.h" +#include "sw/device/lib/ujson/ujson.h" +#include "sw/device/silicon_creator/lib/sigverify/sphincsplus/verify.h" +#include "sw/device/tests/crypto/cryptotest/json/sphincsplus_commands.h" + +status_t handle_sphincsplus_verify(ujson_t *uj) { + // Declare SPHINCS+ parameter ujson deserializer types + cryptotest_sphincsplus_hash_alg_t uj_hash_alg; + cryptotest_sphincsplus_public_key_t uj_public_key; + cryptotest_sphincsplus_message_t uj_message; + cryptotest_sphincsplus_signature_t uj_signature; + + // Deserialize ujson byte stream into SPHINCS+ parameters + TRY(ujson_deserialize_cryptotest_sphincsplus_hash_alg_t(uj, &uj_hash_alg)); + TRY(ujson_deserialize_cryptotest_sphincsplus_public_key_t(uj, + &uj_public_key)); + TRY(ujson_deserialize_cryptotest_sphincsplus_message_t(uj, &uj_message)); + TRY(ujson_deserialize_cryptotest_sphincsplus_signature_t(uj, &uj_signature)); + + if (uj_public_key.public_len != kSpxVerifyPkBytes) { + LOG_ERROR("Incorrect public key length: (expected = %d, got = %d)", + kSpxVerifyPkBytes, uj_public_key.public_len); + return INVALID_ARGUMENT(); + } + if (uj_signature.signature_len != kSpxVerifySigBytes) { + LOG_ERROR("Incorrect signature length: (expected = %d, got = %d)", + kSpxVerifySigBytes, uj_signature.signature_len); + return INVALID_ARGUMENT(); + } + + switch (uj_hash_alg) { + case kCryptotestSphincsPlusHashAlgSha256: + LOG_ERROR("SPHINCS+ SHA-256 is not supported yet."); + return INVALID_ARGUMENT(); + break; + case kCryptotestSphincsPlusHashAlgShake256: + break; + default: + LOG_ERROR("Unrecognized SPHINCS+ hash mode: %d", uj_hash_alg); + return INVALID_ARGUMENT(); + } + uint32_t exp_root[kSpxVerifyRootNumWords]; + spx_public_key_root((uint32_t *)uj_public_key.public, exp_root); + uint32_t act_root[kSpxVerifyRootNumWords]; + rom_error_t error = + spx_verify((uint32_t *)uj_signature.signature, NULL, 0, NULL, 0, + (uint8_t *)uj_message.message, uj_message.message_len, + (uint32_t *)uj_public_key.public, act_root); + cryptotest_sphincsplus_verify_output_t uj_output; + switch (error) { + case kErrorOk: + uj_output = kCryptotestSphincsPlusVerifyOutputSuccess; + for (size_t i = 0; i < kSpxVerifyRootNumWords; i++) { + if (exp_root[i] != act_root[i]) { + uj_output = kCryptotestSphincsPlusVerifyOutputFailure; + break; + } + } + RESP_OK(ujson_serialize_cryptotest_sphincsplus_verify_output_t, uj, + &uj_output); + break; + case kErrorSigverifyBadSpxSignature: + OT_FALLTHROUGH_INTENDED; + case kErrorSigverifyBadSpxKey: + uj_output = kCryptotestSphincsPlusVerifyOutputFailure; + // Respond "failure" if the IUT reports an invalid argument + RESP_OK(ujson_serialize_cryptotest_sphincsplus_verify_output_t, uj, + &uj_output); + break; + default: + LOG_ERROR( + "Unexpected error value returned from spx_verify: " + "0x%x", + error); + return INTERNAL(); + } + return OK_STATUS(0); +} + +status_t handle_sphincsplus(ujson_t *uj) { + cryptotest_sphincsplus_operation_t uj_op; + TRY(ujson_deserialize_cryptotest_sphincsplus_operation_t(uj, &uj_op)); + switch (uj_op) { + case kCryptotestSphincsPlusOperationVerify: + return handle_sphincsplus_verify(uj); + default: + LOG_ERROR("Unsupported SPHINCS+ operation: %d", uj_op); + return INVALID_ARGUMENT(); + } +} diff --git a/sw/device/tests/crypto/cryptotest/firmware/sphincsplus.h b/sw/device/tests/crypto/cryptotest/firmware/sphincsplus.h new file mode 100644 index 00000000000000..d1b68051fa5fc3 --- /dev/null +++ b/sw/device/tests/crypto/cryptotest/firmware/sphincsplus.h @@ -0,0 +1,13 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +#ifndef OPENTITAN_SW_DEVICE_TESTS_CRYPTO_CRYPTOTEST_FIRMWARE_SPHINCSPLUS_H_ +#define OPENTITAN_SW_DEVICE_TESTS_CRYPTO_CRYPTOTEST_FIRMWARE_SPHINCSPLUS_H_ + +#include "sw/device/lib/base/status.h" +#include "sw/device/lib/ujson/ujson.h" + +status_t handle_sphincsplus(ujson_t *uj); + +#endif // OPENTITAN_SW_DEVICE_TESTS_CRYPTO_CRYPTOTEST_FIRMWARE_SPHINCSPLUS_H_