diff --git a/Android.mk b/Android.mk index d79ce9b18..6081b3003 100644 --- a/Android.mk +++ b/Android.mk @@ -255,7 +255,6 @@ LOCAL_SRC_FILES := \ src/core/crypto/aes_ecb.cpp \ src/core/crypto/crypto_platform.cpp \ src/core/crypto/ecdsa.cpp \ - src/core/crypto/ecdsa_tinycrypt.cpp \ src/core/crypto/hkdf_sha256.cpp \ src/core/crypto/hmac_sha256.cpp \ src/core/crypto/mbedtls.cpp \ diff --git a/include/openthread/crypto.h b/include/openthread/crypto.h index 3be657bca..a3c06d8d6 100644 --- a/include/openthread/crypto.h +++ b/include/openthread/crypto.h @@ -55,25 +55,13 @@ extern "C" { * */ -#define OT_CRYPTO_SHA256_HASH_SIZE 32 ///< Length of SHA256 hash (in bytes). - /** * @struct otCryptoSha256Hash * * This structure represents a SHA-256 hash. * */ -OT_TOOL_PACKED_BEGIN -struct otCryptoSha256Hash -{ - uint8_t m8[OT_CRYPTO_SHA256_HASH_SIZE]; ///< Hash bytes. -} OT_TOOL_PACKED_END; - -/** - * This structure represents a SHA-256 hash. - * - */ -typedef struct otCryptoSha256Hash otCryptoSha256Hash; +typedef otPlatCryptoSha256Hash otCryptoSha256Hash; /** * This function performs HMAC computation. diff --git a/include/openthread/instance.h b/include/openthread/instance.h index e5aa5c752..8d403ff4d 100644 --- a/include/openthread/instance.h +++ b/include/openthread/instance.h @@ -53,7 +53,7 @@ extern "C" { * @note This number versions both OpenThread platform and user APIs. * */ -#define OPENTHREAD_API_VERSION (258) +#define OPENTHREAD_API_VERSION (259) /** * @addtogroup api-instance diff --git a/include/openthread/platform/crypto.h b/include/openthread/platform/crypto.h index 7cadc8e79..258dd59ca 100644 --- a/include/openthread/platform/crypto.h +++ b/include/openthread/platform/crypto.h @@ -130,6 +130,95 @@ typedef struct otCryptoContext uint16_t mContextSize; ///< The length of the context in bytes. } otCryptoContext; +/** + * Length of SHA256 hash (in bytes). + * + */ +#define OT_CRYPTO_SHA256_HASH_SIZE 32 + +/** + * @struct otPlatCryptoSha256Hash + * + * This structure represents a SHA-256 hash. + * + */ +OT_TOOL_PACKED_BEGIN +struct otPlatCryptoSha256Hash +{ + uint8_t m8[OT_CRYPTO_SHA256_HASH_SIZE]; ///< Hash bytes. +} OT_TOOL_PACKED_END; + +/** + * This structure represents a SHA-256 hash. + * + */ +typedef struct otPlatCryptoSha256Hash otPlatCryptoSha256Hash; + +/** + * Max buffer size (in bytes) for representing the EDCSA key-pair in DER format. + * + */ +#define OT_CRYPTO_ECDSA_MAX_DER_SIZE 125 + +/** + * @struct otPlatCryptoEcdsaKeyPair + * + * This structure represents an ECDSA key pair (public and private keys). + * + * The key pair is stored using Distinguished Encoding Rules (DER) format (per RFC 5915). + * + */ +typedef struct otPlatCryptoEcdsaKeyPair +{ + uint8_t mDerBytes[OT_CRYPTO_ECDSA_MAX_DER_SIZE]; + uint8_t mDerLength; +} otPlatCryptoEcdsaKeyPair; + +/** + * Buffer size (in bytes) for representing the EDCSA public key. + * + */ +#define OT_CRYPTO_ECDSA_PUBLIC_KEY_SIZE 64 + +/** + * @struct otPlatCryptoEcdsaPublicKey + * + * This struct represents a ECDSA public key. + * + * The public key is stored as a byte sequence representation of an uncompressed curve point (RFC 6605 - sec 4). + * + */ +OT_TOOL_PACKED_BEGIN +struct otPlatCryptoEcdsaPublicKey +{ + uint8_t m8[OT_CRYPTO_ECDSA_PUBLIC_KEY_SIZE]; +} OT_TOOL_PACKED_END; + +typedef struct otPlatCryptoEcdsaPublicKey otPlatCryptoEcdsaPublicKey; + +/** + * Buffer size (in bytes) for representing the EDCSA signature. + * + */ +#define OT_CRYPTO_ECDSA_SIGNATURE_SIZE 64 + +/** + * @struct otPlatCryptoEcdsaSignature + * + * This struct represents an ECDSA signature. + * + * The signature is encoded as the concatenated binary representation of two MPIs `r` and `s` which are calculated + * during signing (RFC 6605 - section 4). + * + */ +OT_TOOL_PACKED_BEGIN +struct otPlatCryptoEcdsaSignature +{ + uint8_t m8[OT_CRYPTO_ECDSA_SIGNATURE_SIZE]; +} OT_TOOL_PACKED_END; + +typedef struct otPlatCryptoEcdsaSignature otPlatCryptoEcdsaSignature; + /** * Initialize the Crypto module. * @@ -480,15 +569,81 @@ void otPlatCryptoRandomDeinit(void); /** * Fills a given buffer with cryptographically secure random bytes. * - * @param[out] aBuffer A pointer to a buffer to fill with the random bytes. - * @param[in] aSize Size of buffer (number of bytes to fill). + * @param[out] aBuffer A pointer to a buffer to fill with the random bytes. + * @param[in] aSize Size of buffer (number of bytes to fill). * - * @retval OT_ERROR_NONE Successfully filled buffer with random values. - * @retval OT_ERROR_FAILED Operation failed. + * @retval OT_ERROR_NONE Successfully filled buffer with random values. + * @retval OT_ERROR_FAILED Operation failed. * */ otError otPlatCryptoRandomGet(uint8_t *aBuffer, uint16_t aSize); +/** + * Generate and populate the output buffer with a new ECDSA key-pair. + * + * @param[out] aKeyPair A pointer to an ECDSA key-pair structure to store the generated key-pair. + * + * @retval OT_ERROR_NONE A new key-pair was generated successfully. + * @retval OT_ERROR_NO_BUFS Failed to allocate buffer for key generation. + * @retval OT_ERROR_NOT_CAPABLE Feature not supported. + * @retval OT_ERROR_FAILED Failed to generate key-pair. + * + */ +otError otPlatCryptoEcdsaGenerateKey(otPlatCryptoEcdsaKeyPair *aKeyPair); + +/** + * Get the associated public key from the input context. + * + * @param[in] aKeyPair A pointer to an ECDSA key-pair structure where the key-pair is stored. + * @param[out] aPublicKey A pointer to an ECDSA public key structure to store the public key. + * + * @retval OT_ERROR_NONE Public key was retrieved successfully, and @p aBuffer is updated. + * @retval OT_ERROR_PARSE The key-pair DER format could not be parsed (invalid format). + * @retval OT_ERROR_INVALID_ARGS The @p aContext is NULL. + * + */ +otError otPlatCryptoEcdsaGetPublicKey(const otPlatCryptoEcdsaKeyPair *aKeyPair, otPlatCryptoEcdsaPublicKey *aPublicKey); + +/** + * Calculate the ECDSA signature for a hashed message using the private key from the input context. + * + * This method uses the deterministic digital signature generation procedure from RFC 6979. + * + * @param[in] aKeyPair A pointer to an ECDSA key-pair structure where the key-pair is stored. + * @param[in] aHash A pointer to a SHA-256 hash structure where the hash value for signature calculation + * is stored. + * @param[out] aSignature A pointer to an ECDSA signature structure to output the calculated signature. + * + * @retval OT_ERROR_NONE The signature was calculated successfully, @p aSignature was updated. + * @retval OT_ERROR_PARSE The key-pair DER format could not be parsed (invalid format). + * @retval OT_ERROR_NO_BUFS Failed to allocate buffer for signature calculation. + * @retval OT_ERROR_INVALID_ARGS The @p aContext is NULL. + * + */ +otError otPlatCryptoEcdsaSign(const otPlatCryptoEcdsaKeyPair *aKeyPair, + const otPlatCryptoSha256Hash * aHash, + otPlatCryptoEcdsaSignature * aSignature); + +/** + * Use the key from the input context to verify the ECDSA signature of a hashed message. + * + * @param[in] aPublicKey A pointer to an ECDSA public key structure where the public key for signature + * verification is stored. + * @param[in] aHash A pointer to a SHA-256 hash structure where the hash value for signature verification + * is stored. + * @param[in] aSignature A pointer to an ECDSA signature structure where the signature value to be verified is + * stored. + * + * @retval OT_ERROR_NONE The signature was verified successfully. + * @retval OT_ERROR_SECURITY The signature is invalid. + * @retval OT_ERROR_INVALID_ARGS The key or hash is invalid. + * @retval OT_ERROR_NO_BUFS Failed to allocate buffer for signature verification. + * + */ +otError otPlatCryptoEcdsaVerify(const otPlatCryptoEcdsaPublicKey *aPublicKey, + const otPlatCryptoSha256Hash * aHash, + const otPlatCryptoEcdsaSignature *aSignature); + /** * @} * diff --git a/src/core/BUILD.gn b/src/core/BUILD.gn index c625335a1..baf337056 100644 --- a/src/core/BUILD.gn +++ b/src/core/BUILD.gn @@ -463,7 +463,6 @@ openthread_core_files = [ "crypto/crypto_platform.cpp", "crypto/ecdsa.cpp", "crypto/ecdsa.hpp", - "crypto/ecdsa_tinycrypt.cpp", "crypto/hkdf_sha256.cpp", "crypto/hkdf_sha256.hpp", "crypto/hmac_sha256.cpp", diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 230783357..e0de03c5a 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -121,7 +121,6 @@ set(COMMON_SOURCES crypto/aes_ecb.cpp crypto/crypto_platform.cpp crypto/ecdsa.cpp - crypto/ecdsa_tinycrypt.cpp crypto/hkdf_sha256.cpp crypto/hmac_sha256.cpp crypto/mbedtls.cpp diff --git a/src/core/Makefile.am b/src/core/Makefile.am index 309a82975..7062dea02 100644 --- a/src/core/Makefile.am +++ b/src/core/Makefile.am @@ -211,7 +211,6 @@ SOURCES_COMMON = \ crypto/aes_ecb.cpp \ crypto/crypto_platform.cpp \ crypto/ecdsa.cpp \ - crypto/ecdsa_tinycrypt.cpp \ crypto/hkdf_sha256.cpp \ crypto/hmac_sha256.cpp \ crypto/mbedtls.cpp \ diff --git a/src/core/crypto/crypto_platform.cpp b/src/core/crypto/crypto_platform.cpp index 7b3a77070..19373fe46 100644 --- a/src/core/crypto/crypto_platform.cpp +++ b/src/core/crypto/crypto_platform.cpp @@ -34,9 +34,12 @@ #include #include +#include #include #include +#include #include +#include #include #include @@ -48,6 +51,7 @@ #include "common/instance.hpp" #include "common/new.hpp" #include "config/crypto.h" +#include "crypto/ecdsa.hpp" #include "crypto/hmac_sha256.hpp" #include "crypto/storage.hpp" @@ -484,6 +488,175 @@ OT_TOOL_WEAK otError otPlatCryptoRandomGet(uint8_t *aBuffer, uint16_t aSize) mbedtls_ctr_drbg_random(&sCtrDrbgContext, static_cast(aBuffer), static_cast(aSize))); } +#if OPENTHREAD_CONFIG_ECDSA_ENABLE + +OT_TOOL_WEAK otError otPlatCryptoEcdsaGenerateKey(otPlatCryptoEcdsaKeyPair *aKeyPair) +{ + mbedtls_pk_context pk; + int ret; + + mbedtls_pk_init(&pk); + + ret = mbedtls_pk_setup(&pk, mbedtls_pk_info_from_type(MBEDTLS_PK_ECKEY)); + VerifyOrExit(ret == 0); + + ret = mbedtls_ecp_gen_key(MBEDTLS_ECP_DP_SECP256R1, mbedtls_pk_ec(pk), MbedTls::CryptoSecurePrng, nullptr); + VerifyOrExit(ret == 0); + + ret = mbedtls_pk_write_key_der(&pk, aKeyPair->mDerBytes, OT_CRYPTO_ECDSA_MAX_DER_SIZE); + VerifyOrExit(ret > 0); + + aKeyPair->mDerLength = static_cast(ret); + + memmove(aKeyPair->mDerBytes, aKeyPair->mDerBytes + OT_CRYPTO_ECDSA_MAX_DER_SIZE - aKeyPair->mDerLength, + aKeyPair->mDerLength); + +exit: + mbedtls_pk_free(&pk); + + return (ret >= 0) ? kErrorNone : MbedTls::MapError(ret); +} + +OT_TOOL_WEAK otError otPlatCryptoEcdsaGetPublicKey(const otPlatCryptoEcdsaKeyPair *aKeyPair, + otPlatCryptoEcdsaPublicKey * aPublicKey) +{ + Error error = kErrorNone; + mbedtls_pk_context pk; + mbedtls_ecp_keypair *keyPair; + int ret; + + mbedtls_pk_init(&pk); + + VerifyOrExit(mbedtls_pk_setup(&pk, mbedtls_pk_info_from_type(MBEDTLS_PK_ECKEY)) == 0, error = kErrorFailed); + +#if (MBEDTLS_VERSION_NUMBER >= 0x03000000) + VerifyOrExit(mbedtls_pk_parse_key(&pk, aKeyPair->mDerBytes, aKeyPair->mDerLength, nullptr, 0, + MbedTls::CryptoSecurePrng, nullptr) == 0, + error = kErrorParse); +#else + VerifyOrExit(mbedtls_pk_parse_key(&pk, aKeyPair->mDerBytes, aKeyPair->mDerLength, nullptr, 0) == 0, + error = kErrorParse); +#endif + + keyPair = mbedtls_pk_ec(pk); + + ret = mbedtls_mpi_write_binary(&keyPair->MBEDTLS_PRIVATE(Q).MBEDTLS_PRIVATE(X), aPublicKey->m8, + Ecdsa::P256::kMpiSize); + VerifyOrExit(ret == 0, error = MbedTls::MapError(ret)); + + ret = mbedtls_mpi_write_binary(&keyPair->MBEDTLS_PRIVATE(Q).MBEDTLS_PRIVATE(Y), + aPublicKey->m8 + Ecdsa::P256::kMpiSize, Ecdsa::P256::kMpiSize); + VerifyOrExit(ret == 0, error = MbedTls::MapError(ret)); + +exit: + mbedtls_pk_free(&pk); + return error; +} + +OT_TOOL_WEAK otError otPlatCryptoEcdsaSign(const otPlatCryptoEcdsaKeyPair *aKeyPair, + const otPlatCryptoSha256Hash * aHash, + otPlatCryptoEcdsaSignature * aSignature) +{ + Error error = kErrorNone; + mbedtls_pk_context pk; + mbedtls_ecp_keypair * keypair; + mbedtls_ecdsa_context ecdsa; + mbedtls_mpi r; + mbedtls_mpi s; + int ret; + + mbedtls_pk_init(&pk); + mbedtls_ecdsa_init(&ecdsa); + mbedtls_mpi_init(&r); + mbedtls_mpi_init(&s); + + VerifyOrExit(mbedtls_pk_setup(&pk, mbedtls_pk_info_from_type(MBEDTLS_PK_ECKEY)) == 0, error = kErrorFailed); + +#if (MBEDTLS_VERSION_NUMBER >= 0x03000000) + VerifyOrExit(mbedtls_pk_parse_key(&pk, aKeyPair->mDerBytes, aKeyPair->mDerLength, nullptr, 0, + MbedTls::CryptoSecurePrng, nullptr) == 0, + error = kErrorParse); +#else + VerifyOrExit(mbedtls_pk_parse_key(&pk, aKeyPair->mDerBytes, aKeyPair->mDerLength, nullptr, 0) == 0, + error = kErrorParse); +#endif + + keypair = mbedtls_pk_ec(pk); + + ret = mbedtls_ecdsa_from_keypair(&ecdsa, keypair); + VerifyOrExit(ret == 0, error = MbedTls::MapError(ret)); + +#if (MBEDTLS_VERSION_NUMBER >= 0x02130000) + ret = mbedtls_ecdsa_sign_det_ext(&ecdsa.MBEDTLS_PRIVATE(grp), &r, &s, &ecdsa.MBEDTLS_PRIVATE(d), aHash->m8, + Sha256::Hash::kSize, MBEDTLS_MD_SHA256, MbedTls::CryptoSecurePrng, nullptr); +#else + ret = mbedtls_ecdsa_sign_det(&ecdsa.MBEDTLS_PRIVATE(grp), &r, &s, &ecdsa.MBEDTLS_PRIVATE(d), aHash->m8, + Sha256::Hash::kSize, MBEDTLS_MD_SHA256); +#endif + VerifyOrExit(ret == 0, error = MbedTls::MapError(ret)); + + OT_ASSERT(mbedtls_mpi_size(&r) <= Ecdsa::P256::kMpiSize); + + ret = mbedtls_mpi_write_binary(&r, aSignature->m8, Ecdsa::P256::kMpiSize); + VerifyOrExit(ret == 0, error = MbedTls::MapError(ret)); + + ret = mbedtls_mpi_write_binary(&s, aSignature->m8 + Ecdsa::P256::kMpiSize, Ecdsa::P256::kMpiSize); + VerifyOrExit(ret == 0, error = MbedTls::MapError(ret)); + +exit: + mbedtls_pk_free(&pk); + mbedtls_mpi_free(&s); + mbedtls_mpi_free(&r); + mbedtls_ecdsa_free(&ecdsa); + + return error; +} + +OT_TOOL_WEAK otError otPlatCryptoEcdsaVerify(const otPlatCryptoEcdsaPublicKey *aPublicKey, + const otPlatCryptoSha256Hash * aHash, + const otPlatCryptoEcdsaSignature *aSignature) +{ + Error error = kErrorNone; + mbedtls_ecdsa_context ecdsa; + mbedtls_mpi r; + mbedtls_mpi s; + int ret; + + mbedtls_ecdsa_init(&ecdsa); + mbedtls_mpi_init(&r); + mbedtls_mpi_init(&s); + + ret = mbedtls_ecp_group_load(&ecdsa.MBEDTLS_PRIVATE(grp), MBEDTLS_ECP_DP_SECP256R1); + VerifyOrExit(ret == 0, error = MbedTls::MapError(ret)); + + ret = mbedtls_mpi_read_binary(&ecdsa.MBEDTLS_PRIVATE(Q).MBEDTLS_PRIVATE(X), aPublicKey->m8, Ecdsa::P256::kMpiSize); + VerifyOrExit(ret == 0, error = MbedTls::MapError(ret)); + ret = mbedtls_mpi_read_binary(&ecdsa.MBEDTLS_PRIVATE(Q).MBEDTLS_PRIVATE(Y), aPublicKey->m8 + Ecdsa::P256::kMpiSize, + Ecdsa::P256::kMpiSize); + VerifyOrExit(ret == 0, error = MbedTls::MapError(ret)); + ret = mbedtls_mpi_lset(&ecdsa.MBEDTLS_PRIVATE(Q).MBEDTLS_PRIVATE(Z), 1); + VerifyOrExit(ret == 0, error = MbedTls::MapError(ret)); + + ret = mbedtls_mpi_read_binary(&r, aSignature->m8, Ecdsa::P256::kMpiSize); + VerifyOrExit(ret == 0, error = MbedTls::MapError(ret)); + + ret = mbedtls_mpi_read_binary(&s, aSignature->m8 + Ecdsa::P256::kMpiSize, Ecdsa::P256::kMpiSize); + VerifyOrExit(ret == 0, error = MbedTls::MapError(ret)); + + ret = mbedtls_ecdsa_verify(&ecdsa.MBEDTLS_PRIVATE(grp), aHash->m8, Sha256::Hash::kSize, &ecdsa.MBEDTLS_PRIVATE(Q), + &r, &s); + VerifyOrExit(ret == 0, error = kErrorSecurity); + +exit: + mbedtls_mpi_free(&s); + mbedtls_mpi_free(&r); + mbedtls_ecdsa_free(&ecdsa); + + return error; +} + +#endif // #if OPENTHREAD_CONFIG_ECDSA_ENABLE + #endif // #if !OPENTHREAD_RADIO #endif // #if OPENTHREAD_CONFIG_CRYPTO_LIB == OPENTHREAD_CONFIG_CRYPTO_LIB_MBEDTLS diff --git a/src/core/crypto/ecdsa.cpp b/src/core/crypto/ecdsa.cpp index 4500d828f..cd71dc887 100644 --- a/src/core/crypto/ecdsa.cpp +++ b/src/core/crypto/ecdsa.cpp @@ -35,8 +35,6 @@ #if OPENTHREAD_CONFIG_ECDSA_ENABLE -#ifndef MBEDTLS_USE_TINYCRYPT - #include #include @@ -53,166 +51,6 @@ namespace ot { namespace Crypto { namespace Ecdsa { -Error P256::KeyPair::Generate(void) -{ - mbedtls_pk_context pk; - int ret; - - mbedtls_pk_init(&pk); - - ret = mbedtls_pk_setup(&pk, mbedtls_pk_info_from_type(MBEDTLS_PK_ECKEY)); - VerifyOrExit(ret == 0); - - ret = mbedtls_ecp_gen_key(MBEDTLS_ECP_DP_SECP256R1, mbedtls_pk_ec(pk), MbedTls::CryptoSecurePrng, nullptr); - VerifyOrExit(ret == 0); - - ret = mbedtls_pk_write_key_der(&pk, mDerBytes, sizeof(mDerBytes)); - VerifyOrExit(ret > 0); - - mDerLength = static_cast(ret); - - memmove(mDerBytes, mDerBytes + sizeof(mDerBytes) - mDerLength, mDerLength); - -exit: - mbedtls_pk_free(&pk); - - return (ret >= 0) ? kErrorNone : MbedTls::MapError(ret); -} - -Error P256::KeyPair::Parse(void *aContext) const -{ - Error error = kErrorNone; - mbedtls_pk_context *pk = reinterpret_cast(aContext); - - mbedtls_pk_init(pk); - - VerifyOrExit(mbedtls_pk_setup(pk, mbedtls_pk_info_from_type(MBEDTLS_PK_ECKEY)) == 0, error = kErrorFailed); -#if (MBEDTLS_VERSION_NUMBER >= 0x03000000) - VerifyOrExit(mbedtls_pk_parse_key(pk, mDerBytes, mDerLength, nullptr, 0, MbedTls::CryptoSecurePrng, nullptr) == 0, - error = kErrorParse); -#else - VerifyOrExit(mbedtls_pk_parse_key(pk, mDerBytes, mDerLength, nullptr, 0) == 0, error = kErrorParse); -#endif - -exit: - return error; -} - -Error P256::KeyPair::GetPublicKey(PublicKey &aPublicKey) const -{ - Error error; - mbedtls_pk_context pk; - mbedtls_ecp_keypair *keyPair; - int ret; - - SuccessOrExit(error = Parse(&pk)); - - keyPair = mbedtls_pk_ec(pk); - - ret = mbedtls_mpi_write_binary(&keyPair->MBEDTLS_PRIVATE(Q).MBEDTLS_PRIVATE(X), aPublicKey.mData, kMpiSize); - VerifyOrExit(ret == 0, error = MbedTls::MapError(ret)); - - ret = mbedtls_mpi_write_binary(&keyPair->MBEDTLS_PRIVATE(Q).MBEDTLS_PRIVATE(Y), aPublicKey.mData + kMpiSize, - kMpiSize); - VerifyOrExit(ret == 0, error = MbedTls::MapError(ret)); - -exit: - mbedtls_pk_free(&pk); - return error; -} - -Error P256::KeyPair::Sign(const Sha256::Hash &aHash, Signature &aSignature) const -{ - Error error; - mbedtls_pk_context pk; - mbedtls_ecp_keypair * keypair; - mbedtls_ecdsa_context ecdsa; - mbedtls_mpi r; - mbedtls_mpi s; - int ret; - - mbedtls_ecdsa_init(&ecdsa); - mbedtls_mpi_init(&r); - mbedtls_mpi_init(&s); - - SuccessOrExit(error = Parse(&pk)); - - keypair = mbedtls_pk_ec(pk); - - ret = mbedtls_ecdsa_from_keypair(&ecdsa, keypair); - VerifyOrExit(ret == 0, error = MbedTls::MapError(ret)); - -#if OPENTHREAD_CONFIG_DETERMINISTIC_ECDSA_ENABLE -#if (MBEDTLS_VERSION_NUMBER >= 0x02130000) - ret = mbedtls_ecdsa_sign_det_ext(&ecdsa.MBEDTLS_PRIVATE(grp), &r, &s, &ecdsa.MBEDTLS_PRIVATE(d), aHash.GetBytes(), - Sha256::Hash::kSize, MBEDTLS_MD_SHA256, MbedTls::CryptoSecurePrng, nullptr); -#else - ret = mbedtls_ecdsa_sign_det(&ecdsa.MBEDTLS_PRIVATE(grp), &r, &s, &ecdsa.MBEDTLS_PRIVATE(d), aHash.GetBytes(), - Sha256::Hash::kSize, MBEDTLS_MD_SHA256); -#endif -#else - ret = mbedtls_ecdsa_sign(&ecdsa.MBEDTLS_PRIVATE(grp), &r, &s, &ecdsa.MBEDTLS_PRIVATE(d), aHash.GetBytes(), - Sha256::Hash::kSize, MbedTls::CryptoSecurePrng, nullptr); -#endif - VerifyOrExit(ret == 0, error = MbedTls::MapError(ret)); - - OT_ASSERT(mbedtls_mpi_size(&r) <= kMpiSize); - - ret = mbedtls_mpi_write_binary(&r, aSignature.mShared.mMpis.mR, kMpiSize); - VerifyOrExit(ret == 0, error = MbedTls::MapError(ret)); - - ret = mbedtls_mpi_write_binary(&s, aSignature.mShared.mMpis.mS, kMpiSize); - VerifyOrExit(ret == 0, error = MbedTls::MapError(ret)); - -exit: - mbedtls_pk_free(&pk); - mbedtls_mpi_free(&s); - mbedtls_mpi_free(&r); - mbedtls_ecdsa_free(&ecdsa); - - return error; -} - -Error P256::PublicKey::Verify(const Sha256::Hash &aHash, const Signature &aSignature) const -{ - Error error = kErrorNone; - mbedtls_ecdsa_context ecdsa; - mbedtls_mpi r; - mbedtls_mpi s; - int ret; - - mbedtls_ecdsa_init(&ecdsa); - mbedtls_mpi_init(&r); - mbedtls_mpi_init(&s); - - ret = mbedtls_ecp_group_load(&ecdsa.MBEDTLS_PRIVATE(grp), MBEDTLS_ECP_DP_SECP256R1); - VerifyOrExit(ret == 0, error = MbedTls::MapError(ret)); - - ret = mbedtls_mpi_read_binary(&ecdsa.MBEDTLS_PRIVATE(Q).MBEDTLS_PRIVATE(X), GetBytes(), kMpiSize); - VerifyOrExit(ret == 0, error = MbedTls::MapError(ret)); - ret = mbedtls_mpi_read_binary(&ecdsa.MBEDTLS_PRIVATE(Q).MBEDTLS_PRIVATE(Y), GetBytes() + kMpiSize, kMpiSize); - VerifyOrExit(ret == 0, error = MbedTls::MapError(ret)); - ret = mbedtls_mpi_lset(&ecdsa.MBEDTLS_PRIVATE(Q).MBEDTLS_PRIVATE(Z), 1); - VerifyOrExit(ret == 0, error = MbedTls::MapError(ret)); - - ret = mbedtls_mpi_read_binary(&r, aSignature.mShared.mMpis.mR, kMpiSize); - VerifyOrExit(ret == 0, error = MbedTls::MapError(ret)); - - ret = mbedtls_mpi_read_binary(&s, aSignature.mShared.mMpis.mS, kMpiSize); - VerifyOrExit(ret == 0, error = MbedTls::MapError(ret)); - - ret = mbedtls_ecdsa_verify(&ecdsa.MBEDTLS_PRIVATE(grp), aHash.GetBytes(), Sha256::Hash::kSize, - &ecdsa.MBEDTLS_PRIVATE(Q), &r, &s); - VerifyOrExit(ret == 0, error = kErrorSecurity); - -exit: - mbedtls_mpi_free(&s); - mbedtls_mpi_free(&r); - mbedtls_ecdsa_free(&ecdsa); - - return error; -} - Error Sign(uint8_t * aOutput, uint16_t & aOutputLength, const uint8_t *aInputHash, @@ -286,5 +124,4 @@ exit: } // namespace Crypto } // namespace ot -#endif // MBEDTLS_USE_TINYCRYPT #endif // OPENTHREAD_CONFIG_ECDSA_ENABLE diff --git a/src/core/crypto/ecdsa.hpp b/src/core/crypto/ecdsa.hpp index 98b439b81..56376e7d7 100644 --- a/src/core/crypto/ecdsa.hpp +++ b/src/core/crypto/ecdsa.hpp @@ -41,6 +41,9 @@ #include #include +#include +#include + #include "common/error.hpp" #include "crypto/sha256.hpp" @@ -83,13 +86,13 @@ public: * */ OT_TOOL_PACKED_BEGIN - class Signature + class Signature : public otPlatCryptoEcdsaSignature { friend class KeyPair; friend class PublicKey; public: - static constexpr uint8_t kSize = 2 * kMpiSize; ///< Signature size in bytes (two times the curve MPI size). + static constexpr uint8_t kSize = OT_CRYPTO_ECDSA_SIGNATURE_SIZE; ///< Signature size in bytes. /** * This method returns the signature as a byte array. @@ -97,21 +100,7 @@ public: * @returns A pointer to the byte array containing the signature. * */ - const uint8_t *GetBytes(void) const { return mShared.mKey; } - - private: - OT_TOOL_PACKED_BEGIN - struct Mpis - { - uint8_t mR[kMpiSize]; - uint8_t mS[kMpiSize]; - } OT_TOOL_PACKED_END; - - union OT_TOOL_PACKED_FIELD - { - Mpis mMpis; - uint8_t mKey[kSize]; - } mShared; + const uint8_t *GetBytes(void) const { return m8; } } OT_TOOL_PACKED_END; /** @@ -120,23 +109,20 @@ public: * The key pair is stored using Distinguished Encoding Rules (DER) format (per RFC 5915). * */ - class KeyPair + class KeyPair : public otPlatCryptoEcdsaKeyPair { public: /** * Max buffer size (in bytes) for representing the key-pair in DER format. * */ - static constexpr uint8_t kMaxDerSize = 125; + static constexpr uint8_t kMaxDerSize = OT_CRYPTO_ECDSA_MAX_DER_SIZE; /** * This constructor initializes a `KeyPair` as empty (no key). * */ - KeyPair(void) - : mDerLength(0) - { - } + KeyPair(void) { mDerLength = 0; } /** * This method generates and populates the `KeyPair` with a new public/private keys. @@ -147,7 +133,7 @@ public: * @retval kErrorFailed Failed to generate key. * */ - Error Generate(void); + Error Generate(void) { return otPlatCryptoEcdsaGenerateKey(this); } /** * This method gets the associated public key from the `KeyPair`. @@ -158,7 +144,7 @@ public: * @retval kErrorParse The key-pair DER format could not be parsed (invalid format). * */ - Error GetPublicKey(PublicKey &aPublicKey) const; + Error GetPublicKey(PublicKey &aPublicKey) const { return otPlatCryptoEcdsaGetPublicKey(this, &aPublicKey); } /** * This method gets the pointer to start of the buffer containing the key-pair info in DER format. @@ -212,13 +198,10 @@ public: * @retval kErrorNoBufs Failed to allocate buffer for signature calculation. * */ - Error Sign(const Sha256::Hash &aHash, Signature &aSignature) const; - - private: - Error Parse(void *aContext) const; - - uint8_t mDerBytes[kMaxDerSize]; - uint8_t mDerLength; + Error Sign(const Sha256::Hash &aHash, Signature &aSignature) const + { + return otPlatCryptoEcdsaSign(this, &aHash, &aSignature); + } }; /** @@ -228,12 +211,12 @@ public: * */ OT_TOOL_PACKED_BEGIN - class PublicKey : public Equatable + class PublicKey : public otPlatCryptoEcdsaPublicKey, public Equatable { friend class KeyPair; public: - static constexpr uint8_t kSize = kMpiSize * 2; ///< Size of the public key in bytes. + static constexpr uint8_t kSize = OT_CRYPTO_ECDSA_PUBLIC_KEY_SIZE; ///< Size of the public key in bytes. /** * This method gets the pointer to the buffer containing the public key (as an uncompressed curve point). @@ -241,7 +224,7 @@ public: * @return The pointer to the buffer containing the public key (with `kSize` bytes). * */ - const uint8_t *GetBytes(void) const { return mData; } + const uint8_t *GetBytes(void) const { return m8; } /** * This method uses the `PublicKey` to verify the ECDSA signature of a hashed message. @@ -255,10 +238,10 @@ public: * @retval kErrorNoBufs Failed to allocate buffer for signature verification * */ - Error Verify(const Sha256::Hash &aHash, const Signature &aSignature) const; - - private: - uint8_t mData[kSize]; + Error Verify(const Sha256::Hash &aHash, const Signature &aSignature) const + { + return otPlatCryptoEcdsaVerify(this, &aHash, &aSignature); + } } OT_TOOL_PACKED_END; }; @@ -292,6 +275,11 @@ Error Sign(uint8_t * aOutput, } // namespace Ecdsa } // namespace Crypto + +DefineCoreType(otPlatCryptoEcdsaSignature, Crypto::Ecdsa::P256::Signature); +DefineCoreType(otPlatCryptoEcdsaKeyPair, Crypto::Ecdsa::P256::KeyPair); +DefineCoreType(otPlatCryptoEcdsaPublicKey, Crypto::Ecdsa::P256::PublicKey); + } // namespace ot #endif // OPENTHREAD_CONFIG_ECDSA_ENABLE diff --git a/src/core/crypto/ecdsa_tinycrypt.cpp b/src/core/crypto/ecdsa_tinycrypt.cpp deleted file mode 100644 index 852cb40e7..000000000 --- a/src/core/crypto/ecdsa_tinycrypt.cpp +++ /dev/null @@ -1,215 +0,0 @@ -/* - * Copyright (c) 2022, The OpenThread Authors. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the copyright holder nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * @file - * This file implements ECDSA signing using TinyCrypt library. - */ - -#include "ecdsa.hpp" - -#if OPENTHREAD_CONFIG_ECDSA_ENABLE - -#ifdef MBEDTLS_USE_TINYCRYPT - -#if OPENTHREAD_CONFIG_DETERMINISTIC_ECDSA_ENABLE -#warning "tinycrypt does not support generating deterministic ECDSA signatures" -#endif - -#include - -#include -#include - -#include -#include -#include - -#include "common/code_utils.hpp" -#include "common/debug.hpp" -#include "common/random.hpp" -#include "crypto/mbedtls.hpp" - -namespace ot { -namespace Crypto { -namespace Ecdsa { - -Error P256::KeyPair::Generate(void) -{ - mbedtls_pk_context pk; - mbedtls_uecc_keypair *keypair; - int ret; - - mbedtls_pk_init(&pk); - - ret = mbedtls_pk_setup(&pk, mbedtls_pk_info_from_type(MBEDTLS_PK_ECKEY)); - VerifyOrExit(ret == 0); - - keypair = mbedtls_pk_uecc(pk); - - ret = uECC_make_key(keypair->public_key, keypair->private_key); - VerifyOrExit(ret == UECC_SUCCESS); - - ret = mbedtls_pk_write_key_der(&pk, mDerBytes, sizeof(mDerBytes)); - VerifyOrExit(ret > 0); - - mDerLength = static_cast(ret); - - memmove(mDerBytes, mDerBytes + sizeof(mDerBytes) - mDerLength, mDerLength); - -exit: - mbedtls_pk_free(&pk); - - return (ret >= 0) ? kErrorNone : MbedTls::MapError(ret); -} - -Error P256::KeyPair::Parse(void *aContext) const -{ - Error error = kErrorNone; - mbedtls_pk_context *pk = reinterpret_cast(aContext); - - mbedtls_pk_init(pk); - - VerifyOrExit(mbedtls_pk_setup(pk, mbedtls_pk_info_from_type(MBEDTLS_PK_ECKEY)) == 0, error = kErrorFailed); -#if (MBEDTLS_VERSION_NUMBER >= 0x03000000) - VerifyOrExit(mbedtls_pk_parse_key(pk, mDerBytes, mDerLength, nullptr, 0, MbedTls::CryptoSecurePrng, nullptr) == 0, - error = kErrorParse); -#else - VerifyOrExit(mbedtls_pk_parse_key(pk, mDerBytes, mDerLength, nullptr, 0) == 0, error = kErrorParse); -#endif - -exit: - return error; -} - -Error P256::KeyPair::GetPublicKey(PublicKey &aPublicKey) const -{ - Error error; - mbedtls_pk_context pk; - mbedtls_uecc_keypair *keyPair; - int ret; - - SuccessOrExit(error = Parse(&pk)); - - keyPair = mbedtls_pk_uecc(pk); - - memcpy(aPublicKey.mData, keyPair->public_key, kMpiSize); - memcpy(aPublicKey.mData + kMpiSize, keyPair->public_key + kMpiSize, kMpiSize); - -exit: - mbedtls_pk_free(&pk); - - return error; -} - -Error P256::KeyPair::Sign(const Sha256::Hash &aHash, Signature &aSignature) const -{ - Error error; - mbedtls_pk_context pk; - mbedtls_uecc_keypair *keypair; - int ret; - uint8_t sig[2 * kMpiSize]; - - SuccessOrExit(error = Parse(&pk)); - - keypair = mbedtls_pk_uecc(pk); - - ret = uECC_sign(keypair->private_key, aHash.GetBytes(), Sha256::Hash::kSize, sig); - VerifyOrExit(ret == UECC_SUCCESS, error = MbedTls::MapError(ret)); - - memcpy(aSignature.mShared.mMpis.mR, sig, kMpiSize); - memcpy(aSignature.mShared.mMpis.mS, sig + kMpiSize, kMpiSize); - -exit: - mbedtls_pk_free(&pk); - - return error; -} - -Error P256::PublicKey::Verify(const Sha256::Hash &aHash, const Signature &aSignature) const -{ - Error error = kErrorNone; - int ret; - uint8_t public_key[2 * kMpiSize]; - uint8_t sig[2 * kMpiSize]; - - memcpy(public_key, GetBytes(), 2 * kMpiSize); - - memcpy(sig, aSignature.mShared.mMpis.mR, kMpiSize); - memcpy(sig + kMpiSize, aSignature.mShared.mMpis.mS, kMpiSize); - - ret = uECC_verify(public_key, aHash.GetBytes(), Sha256::Hash::kSize, sig); - VerifyOrExit(ret == UECC_SUCCESS, error = kErrorSecurity); - -exit: - return error; -} - -Error Sign(uint8_t * aOutput, - uint16_t & aOutputLength, - const uint8_t *aInputHash, - uint16_t aInputHashLength, - const uint8_t *aPrivateKey, - uint16_t aPrivateKeyLength) -{ - Error error = kErrorNone; - mbedtls_pk_context pkCtx; - mbedtls_uecc_keypair *keypair; - uint8_t sig[2 * NUM_ECC_BYTES]; - - mbedtls_pk_init(&pkCtx); - - // Parse a private key in PEM format. - VerifyOrExit(mbedtls_pk_parse_key(&pkCtx, aPrivateKey, aPrivateKeyLength, nullptr, 0) == 0, - error = kErrorInvalidArgs); - VerifyOrExit(mbedtls_pk_get_type(&pkCtx) == MBEDTLS_PK_ECKEY, error = kErrorInvalidArgs); - - keypair = mbedtls_pk_uecc(pkCtx); - OT_ASSERT(keypair != nullptr); - - // Sign using ECDSA. - VerifyOrExit(uECC_sign(keypair->private_key, aInputHash, aInputHashLength, sig) == UECC_SUCCESS, - error = kErrorFailed); - VerifyOrExit(2 * NUM_ECC_BYTES <= aOutputLength, error = kErrorNoBufs); - - // Concatenate the two octet sequences in the order R and then S. - memcpy(aOutput, sig, 2 * NUM_ECC_BYTES); - aOutputLength = 2 * NUM_ECC_BYTES; - -exit: - mbedtls_pk_free(&pkCtx); - - return error; -} - -} // namespace Ecdsa -} // namespace Crypto -} // namespace ot - -#endif // MBEDTLS_USE_TINYCRYPT -#endif // OPENTHREAD_CONFIG_ECDSA_ENABLE