diff options
author | Ali Zhang <alizhang@google.com> | 2023-03-17 17:34:13 +0000 |
---|---|---|
committer | CQ Bot Account <pigweed-scoped@luci-project-accounts.iam.gserviceaccount.com> | 2023-03-17 17:34:13 +0000 |
commit | 8ee6f0ab813ca6ee8f005fa68c1d54539825f951 (patch) | |
tree | 2f214796143182d64295b878a1d3763f9fc875a1 | |
parent | f847251047345efb8956abd33371f17bc8f1e4be (diff) | |
download | pigweed-8ee6f0ab813ca6ee8f005fa68c1d54539825f951.tar.gz |
pw_crypto: Support little-endian uECC backend
Add support for specifying a little-endian version of the micro-ecc
backend via:
`pw_crypto_ECDSA_BACKEND="//pw_crypto:ecdsa_uecc_little_endian"`
Add a dedicated test against this backend.
Bug: b/273608430
Change-Id: I5db1f6be00edd3e7ae8c8624454b40a11c3f1070
Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/134219
Commit-Queue: Ali Zhang <alizhang@google.com>
Reviewed-by: Yecheng Zhao <zyecheng@google.com>
-rw-r--r-- | pw_crypto/BUILD.gn | 24 | ||||
-rw-r--r-- | pw_crypto/docs.rst | 18 | ||||
-rw-r--r-- | pw_crypto/ecdsa_uecc.cc | 25 | ||||
-rw-r--r-- | third_party/micro_ecc/BUILD.gn | 33 |
4 files changed, 83 insertions, 17 deletions
diff --git a/pw_crypto/BUILD.gn b/pw_crypto/BUILD.gn index 9787100ee..d10cecfe3 100644 --- a/pw_crypto/BUILD.gn +++ b/pw_crypto/BUILD.gn @@ -19,6 +19,7 @@ import("$dir_pw_build/facade.gni") import("$dir_pw_build/target_types.gni") import("$dir_pw_crypto/backend.gni") import("$dir_pw_docgen/docs.gni") +import("$dir_pw_third_party/micro_ecc/micro_ecc.gni") import("$dir_pw_unit_test/test.gni") config("default_config") { @@ -83,6 +84,7 @@ pw_test_group("tests") { ":sha256_test", ":sha256_mock_test", ":ecdsa_test", + ":ecdsa_uecc_little_endian_test", ] } @@ -188,13 +190,33 @@ pw_source_set("ecdsa_uecc") { sources = [ "ecdsa_uecc.cc" ] deps = [ "$dir_pw_log", - "$dir_pw_third_party/micro_ecc", + "$dir_pw_third_party/micro_ecc:micro_ecc_big_endian", ] public_deps = [ ":ecdsa.facade" ] } +pw_source_set("ecdsa_uecc_little_endian") { + sources = [ "ecdsa_uecc.cc" ] + deps = [ + "$dir_pw_log", + "$dir_pw_third_party/micro_ecc:micro_ecc_little_endian", + ] + public_deps = [ ":ecdsa.facade" ] +} + +# This test targets the specific backend pointed to by +# pw_crypto_ECDSA_BACKEND. pw_test("ecdsa_test") { enable_if = pw_crypto_ECDSA_BACKEND != "" deps = [ ":ecdsa" ] sources = [ "ecdsa_test.cc" ] } + +# This test targets the micro_ecc little endian backend specifically. +# +# TODO(b/273819841) deduplicate all backend tests. +pw_test("ecdsa_uecc_little_endian_test") { + enable_if = dir_pw_third_party_micro_ecc != "" + sources = [ "ecdsa_test.cc" ] + deps = [ ":ecdsa_uecc_little_endian" ] +} diff --git a/pw_crypto/docs.rst b/pw_crypto/docs.rst index 601952869..1230cd35d 100644 --- a/pw_crypto/docs.rst +++ b/pw_crypto/docs.rst @@ -99,7 +99,9 @@ configured. # Install and configure MbedTLS pw package install mbedtls gn gen out --args=' - dir_pw_third_party_mbedtls=pw_env_setup_PACKAGE_ROOT + "/mbedtls" + import("//build_overrides/pigweed_environment.gni") + + dir_pw_third_party_mbedtls=pw_env_setup_PACKAGE_ROOT+"/mbedtls" pw_crypto_SHA256_BACKEND="//pw_crypto:sha256_mbedtls" pw_crypto_ECDSA_BACKEND="//pw_crypto:ecdsa_mbedtls" ' @@ -145,7 +147,9 @@ configured. # Install and configure BoringSSL pw package install boringssl gn gen out --args=' - dir_pw_third_party_boringssl=pw_env_setup_PACKAGE_ROOT + "/boringssl" + import("//build_overrides/pigweed_environment.gni") + + dir_pw_third_party_boringssl=pw_env_setup_PACKAGE_ROOT+"/boringssl" pw_crypto_SHA256_BACKEND="//pw_crypto:sha256_boringssl" pw_crypto_ECDSA_BACKEND="//pw_crypto:ecdsa_boringssl" ' @@ -165,10 +169,18 @@ To select Micro ECC, the library needs to be installed and configured. # Install and configure Micro ECC pw package install micro-ecc gn gen out --args=' - dir_pw_third_party_micro_ecc=pw_env_setup_PACKAGE_ROOT + "//micro-ecc" + import("//build_overrides/pigweed_environment.gni") + + dir_pw_third_party_micro_ecc=pw_env_setup_PACKAGE_ROOT+"/micro-ecc" pw_crypto_ECDSA_BACKEND="//pw_crypto:ecdsa_uecc" ' +The default micro-ecc backend uses big endian as is standard practice. It also +has a little-endian configuration which can be used to slightly reduce call +stack frame use and/or when non pw_crypto clients use the same micro-ecc +with a little-endian configuration. The little-endian version of micro-ecc +can be selected with ``pw_crypto_ECDSA_BACKEND="//pw_crypto:ecdsa_uecc_little_endian"`` + Note Micro-ECC does not implement any hashing functions, so you will need to use other backends for SHA256 functionality if needed. Size Reports diff --git a/pw_crypto/ecdsa_uecc.cc b/pw_crypto/ecdsa_uecc.cc index cbb7af565..912a28b44 100644 --- a/pw_crypto/ecdsa_uecc.cc +++ b/pw_crypto/ecdsa_uecc.cc @@ -42,26 +42,29 @@ Status VerifyP256Signature(ConstByteSpan public_key, return Status::InvalidArgument(); } -#if uECC_VLI_NATIVE_LITTLE_ENDIAN - // VerifyP256Signature always assume big endian input. If the library is - // configured to expect native little endian, we need to convert the input - // into little endian. - uint8_t signature_bytes[kP256SignatureSize] - __attribute__((__aligned__(sizeof(uint64_t)))); +#if defined(uECC_VLI_NATIVE_LITTLE_ENDIAN) && uECC_VLI_NATIVE_LITTLE_ENDIAN + // uECC_VLI_NATIVE_LITTLE_ENDIAN is defined with a non-zero value when + // pw_crypto_ECDSA_BACKEND is set to "//pw_crypto:ecdsa_uecc_little_endian". + // + // Since pw_crypto APIs are big endian only (standard practice), here we + // need to convert input parameters to little endian. + // + // Additionally uECC requires these little endian buffers to be word aligned + // in case unaligned accesses are not supported by the hardware. We choose + // the maximum 8-byte alignment to avoid referrencing internal uECC headers. + alignas(8) uint8_t signature_bytes[kP256SignatureSize]; memcpy(signature_bytes, signature.data(), sizeof(signature_bytes)); std::reverse(signature_bytes, signature_bytes + kP256CurveOrderBytes); // r std::reverse(signature_bytes + kP256CurveOrderBytes, signature_bytes + sizeof(signature_bytes)); // s - uint8_t public_key_bytes[kP256PublicKeySize - 1] - __attribute__((__aligned__(sizeof(uint64_t)))); + alignas(8) uint8_t public_key_bytes[kP256PublicKeySize - 1]; memcpy(public_key_bytes, public_key.data() + 1, sizeof(public_key_bytes)); std::reverse(public_key_bytes, public_key_bytes + kP256CurveOrderBytes); // X std::reverse(public_key_bytes + kP256CurveOrderBytes, public_key_bytes + sizeof(public_key_bytes)); // Y - uint8_t digest_bytes[kP256CurveOrderBytes] - __attribute__((__aligned__(sizeof(uint64_t)))); + alignas(8) uint8_t digest_bytes[kP256CurveOrderBytes]; memcpy(digest_bytes, digest.data(), sizeof(digest_bytes)); std::reverse(digest_bytes, digest_bytes + sizeof(digest_bytes)); #else @@ -70,7 +73,7 @@ Status VerifyP256Signature(ConstByteSpan public_key, const uint8_t* digest_bytes = reinterpret_cast<const uint8_t*>(digest.data()); const uint8_t* signature_bytes = reinterpret_cast<const uint8_t*>(signature.data()); -#endif +#endif // uECC_VLI_NATIVE_LITTLE_ENDIAN uECC_Curve curve = uECC_secp256r1(); // Make sure the public key is on the curve. diff --git a/third_party/micro_ecc/BUILD.gn b/third_party/micro_ecc/BUILD.gn index 4ead9fd64..6db2acc8f 100644 --- a/third_party/micro_ecc/BUILD.gn +++ b/third_party/micro_ecc/BUILD.gn @@ -29,8 +29,37 @@ if (dir_pw_third_party_micro_ecc != "") { defines = [ "uECC_SUPPORT_COMPRESSED_POINT=0" ] } - pw_source_set("micro_ecc") { - public_configs = [ ":public_config" ] + # Endianess is a public configuration for uECC as it determines how large + # integers are interpreted in uECC public APIs. + # + # Big endian is a lot more common and thus is recommended unless you are + # really resource-constrained or another uECC client expects little + # endian. + config("big_endian_config") { + defines = [ "uECC_VLI_NATIVE_LITTLE_ENDIAN=0" ] + } + + # Little endian can reduce call stack usage in native little endian + # execution environments (as determined by processor state, memory + # access config etc.) + config("little_endian_config") { + defines = [ "uECC_VLI_NATIVE_LITTLE_ENDIAN=1" ] + } + + pw_source_set("micro_ecc_big_endian") { + public_configs = [ + ":big_endian_config", + ":public_config", + ] + configs = [ ":internal_config" ] + sources = [ "$dir_pw_third_party_micro_ecc/uECC.c" ] + } + + pw_source_set("micro_ecc_little_endian") { + public_configs = [ + ":little_endian_config", + ":public_config", + ] configs = [ ":internal_config" ] sources = [ "$dir_pw_third_party_micro_ecc/uECC.c" ] } |