From 83011b2e29586cc68dde54042e69b02ca2484eda Mon Sep 17 00:00:00 2001 From: DeckerSU Date: Wed, 2 Oct 2024 16:34:05 +0200 Subject: [PATCH 1/4] cc: fix ed25519 signatures malleability MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - https://github.com/KomodoPlatform/komodo/issues/630 - https://soatok.blog/2024/08/14/security-issues-in-matrixs-olm-library/#vuln-ed25519 Actually, the current CC code doesn’t use Ed25519 signatures, so `CVE-2024-45193` has no impact on Komodo (KMD) or any existing assetchains. However, since CC could potentially use these types of signatures in the future (e.g., for newly developed CCs), we’ve added a `0 <= s < L` check to prevent signature malleability. --- .../src/include/ed25519/src/verify.c | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/cryptoconditions/src/include/ed25519/src/verify.c b/src/cryptoconditions/src/include/ed25519/src/verify.c index 32f988edc8b..55ce97785d4 100644 --- a/src/cryptoconditions/src/include/ed25519/src/verify.c +++ b/src/cryptoconditions/src/include/ed25519/src/verify.c @@ -3,6 +3,14 @@ #include "ge.h" #include "sc.h" +/* L = 2^252+27742317777372353535851937790883648493 in little-endian form */ +const unsigned char curve25519_order[32] = { + 0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, + 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10 +}; + static int consttime_equal(const unsigned char *x, const unsigned char *y) { unsigned char r = 0; @@ -59,6 +67,21 @@ int ed25519_verify(const unsigned char *signature, const unsigned char *message, return 0; } + /* make sure 0 <= s < L, as per RFC 8032, section 5.1.7 to prevent signature + * malleability. Due to the three-bit check above (forces s < 2^253) there + * is not that much room, but adding L once works with most signatures */ + for (size_t i = 31; ; i--) + { + if (signature[i+32] < curve25519_order[i]) + { + break; + } + else if (signature[i+32] > curve25519_order[i] || i == 0) + { + return 0; + } + } + sha512_init(&hash); sha512_update(&hash, signature, 32); sha512_update(&hash, public_key, 32); From afcb471fbf5bb7a9ef0c5435cbee06c4738404bd Mon Sep 17 00:00:00 2001 From: DeckerSU Date: Wed, 2 Oct 2024 16:51:08 +0200 Subject: [PATCH 2/4] add ed25519 signature malleability test --- .../src/include/ed25519/test.c | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/src/cryptoconditions/src/include/ed25519/test.c b/src/cryptoconditions/src/include/ed25519/test.c index e2159a9af82..363575c18bd 100644 --- a/src/cryptoconditions/src/include/ed25519/test.c +++ b/src/cryptoconditions/src/include/ed25519/test.c @@ -9,6 +9,17 @@ #include "src/ge.h" #include "src/sc.h" +void print_signature(unsigned char signature[64], char *msg) { + printf("%s\n", msg); + for (int i = 0; i < 64; i++) { + printf("%02x", signature[i]); + if ((i + 1) % 8 != 0) { + printf(" "); + } else { + printf("\n"); + } + } +} int main() { unsigned char public_key[32], private_key[64], seed[32], scalar[32]; @@ -146,5 +157,41 @@ int main() { printf("%fus per shared secret\n", ((double) ((end - start) * 1000)) / CLOCKS_PER_SEC / i * 1000); + /* ed25519 signature malleability test */ + + printf("testing signature malleability\n"); + + const unsigned char curve25519_order[32] = { + 0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, + 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10 + }; + + ed25519_create_seed(seed); + ed25519_create_keypair(public_key, private_key, seed); + ed25519_sign(signature, message, message_len, public_key, private_key); + + print_signature(signature, "Signature:"); + if (ed25519_verify(signature, message, message_len, public_key)) { + printf("valid signature\n"); + } else { + printf("invalid signature\n"); + } + + // add L to S, which starts at sig[32] + unsigned int s = 0; + for (size_t i = 0; i < 32; i++) { + s = signature[32 + i] + curve25519_order[i] + (s >> 8); + signature[32 + i] = s & 0xff; + } + + print_signature(signature,"Modified signature:"); + if (ed25519_verify(signature, message, message_len, public_key)) { + printf("valid signature\n"); + } else { + printf("invalid signature\n"); + } + return 0; } From e2451761c670a9b4e615b10e5b1c34cf155188ce Mon Sep 17 00:00:00 2001 From: DeckerSU Date: Wed, 2 Oct 2024 17:12:42 +0200 Subject: [PATCH 3/4] use int instead of size_t in 0 <= s < L check loop using a signed integer type (int) is preferable here, to avoid potential issues with unsigned underflow. --- src/cryptoconditions/src/include/ed25519/src/verify.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cryptoconditions/src/include/ed25519/src/verify.c b/src/cryptoconditions/src/include/ed25519/src/verify.c index 55ce97785d4..c749d9b9919 100644 --- a/src/cryptoconditions/src/include/ed25519/src/verify.c +++ b/src/cryptoconditions/src/include/ed25519/src/verify.c @@ -70,7 +70,7 @@ int ed25519_verify(const unsigned char *signature, const unsigned char *message, /* make sure 0 <= s < L, as per RFC 8032, section 5.1.7 to prevent signature * malleability. Due to the three-bit check above (forces s < 2^253) there * is not that much room, but adding L once works with most signatures */ - for (size_t i = 31; ; i--) + for (int i = 31; ; i--) { if (signature[i+32] < curve25519_order[i]) { From b29198e2d7b0f4366124affd9bcdcf9eb1d6c1d4 Mon Sep 17 00:00:00 2001 From: DeckerSU Date: Wed, 2 Oct 2024 18:15:52 +0200 Subject: [PATCH 4/4] cc: test, update pytest ver. requirement addressed in https://github.com/KomodoPlatform/komodo/issues/631 --- src/cryptoconditions/test-requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cryptoconditions/test-requirements.txt b/src/cryptoconditions/test-requirements.txt index 3e7a933b91c..8dd61a78cf6 100644 --- a/src/cryptoconditions/test-requirements.txt +++ b/src/cryptoconditions/test-requirements.txt @@ -1,3 +1,3 @@ base58==0.2.5 secp256k1 -pytest +pytest>=8.0.0