aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAli Zhang <alizhang@google.com>2023-03-17 17:34:13 +0000
committerCQ Bot Account <pigweed-scoped@luci-project-accounts.iam.gserviceaccount.com>2023-03-17 17:34:13 +0000
commit8ee6f0ab813ca6ee8f005fa68c1d54539825f951 (patch)
tree2f214796143182d64295b878a1d3763f9fc875a1
parentf847251047345efb8956abd33371f17bc8f1e4be (diff)
downloadpigweed-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.gn24
-rw-r--r--pw_crypto/docs.rst18
-rw-r--r--pw_crypto/ecdsa_uecc.cc25
-rw-r--r--third_party/micro_ecc/BUILD.gn33
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" ]
}