From 2d3495c8c24f014d8e51d7878d2d1ab97373b6e2 Mon Sep 17 00:00:00 2001 From: Yecheng Zhao Date: Fri, 10 Mar 2023 21:09:37 +0000 Subject: [PATCH] pw_crypto: Handle micro-ecc native little endian Adjust input into little endian order when micro-ecc is configured with uECC_VLI_NATIVE_LITTLE_ENDIAN=1. Bug: b/271895100 Change-Id: Id8e24a38b97f76725d11b0b0f0b74216bf159aee Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/133475 Commit-Queue: Yecheng Zhao Reviewed-by: Ali Zhang --- pw_crypto/ecdsa_uecc.cc | 62 ++++++++++++++++++++++++++++++----------- 1 file changed, 45 insertions(+), 17 deletions(-) diff --git a/pw_crypto/ecdsa_uecc.cc b/pw_crypto/ecdsa_uecc.cc index 937d79d567..cbb7af565a 100644 --- a/pw_crypto/ecdsa_uecc.cc +++ b/pw_crypto/ecdsa_uecc.cc @@ -14,6 +14,8 @@ #define PW_LOG_MODULE_NAME "ECDSA-UECC" #define PW_LOG_LEVEL PW_LOG_LEVEL_WARN +#include + #include "pw_crypto/ecdsa.h" #include "pw_log/log.h" #include "uECC.h" @@ -21,33 +23,59 @@ namespace pw::crypto::ecdsa { constexpr size_t kP256CurveOrderBytes = 32; +constexpr size_t kP256PublicKeySize = 2 * kP256CurveOrderBytes + 1; +constexpr size_t kP256SignatureSize = kP256CurveOrderBytes * 2; Status VerifyP256Signature(ConstByteSpan public_key, ConstByteSpan digest, ConstByteSpan signature) { - const uint8_t* public_key_bytes = - reinterpret_cast(public_key.data()); - const uint8_t* digest_bytes = reinterpret_cast(digest.data()); - const uint8_t* signature_bytes = - reinterpret_cast(signature.data()); - - uECC_Curve curve = uECC_secp256r1(); + // Signature expected in raw format (r||s) + if (signature.size() != kP256SignatureSize) { + PW_LOG_DEBUG("Bad signature format"); + return Status::InvalidArgument(); + } // Supports SEC 1 uncompressed form (04||X||Y) only. - if (public_key.size() != (2 * kP256CurveOrderBytes + 1) || - public_key_bytes[0] != 0x04) { + if (public_key.size() != kP256PublicKeySize || + std::to_integer(public_key.data()[0]) != 0x04) { PW_LOG_DEBUG("Bad public key format"); return Status::InvalidArgument(); } - // Make sure the public key is on the curve. - if (!uECC_valid_public_key(public_key_bytes + 1, curve)) { - 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)))); + 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 - // Signature expected in raw format (r||s) - if (signature.size() != kP256CurveOrderBytes * 2) { - PW_LOG_DEBUG("Bad signature format"); + uint8_t public_key_bytes[kP256PublicKeySize - 1] + __attribute__((__aligned__(sizeof(uint64_t)))); + 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)))); + memcpy(digest_bytes, digest.data(), sizeof(digest_bytes)); + std::reverse(digest_bytes, digest_bytes + sizeof(digest_bytes)); +#else + const uint8_t* public_key_bytes = + reinterpret_cast(public_key.data()) + 1; + const uint8_t* digest_bytes = reinterpret_cast(digest.data()); + const uint8_t* signature_bytes = + reinterpret_cast(signature.data()); +#endif + + uECC_Curve curve = uECC_secp256r1(); + // Make sure the public key is on the curve. + if (!uECC_valid_public_key(public_key_bytes, curve)) { + PW_LOG_DEBUG("Bad public key curve"); return Status::InvalidArgument(); } @@ -59,7 +87,7 @@ Status VerifyP256Signature(ConstByteSpan public_key, } // Verify the signature. - if (!uECC_verify(public_key_bytes + 1, + if (!uECC_verify(public_key_bytes, digest_bytes, digest.size(), signature_bytes,