diff --git a/src/pk/ec25519/tweetnacl.c b/src/pk/ec25519/tweetnacl.c index 37a915c57..48446ef9a 100644 --- a/src/pk/ec25519/tweetnacl.c +++ b/src/pk/ec25519/tweetnacl.c @@ -348,6 +348,16 @@ int tweetnacl_crypto_sign_keypair(prng_state *prng, int wprng, u8 *pk, u8 *sk) static const u64 L[32] = {0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10}; +static int is_canonical_s(const u8 s[32]) +{ + int i; + for (i = 31; i >= 0; --i) { + if (s[i] < L[i]) return 1; + if (s[i] > L[i]) return 0; + } + return 0; +} + sv modL(u8 *r,i64 x[64]) { i64 carry,i,j; @@ -463,6 +473,7 @@ int tweetnacl_crypto_sign_open(int *stat, u8 *m,u64 *mlen,const u8 *sm,u64 smlen if (*mlen < smlen) return CRYPT_BUFFER_OVERFLOW; *mlen = -1; if (smlen < 64) return CRYPT_INVALID_ARG; + if (!is_canonical_s(sm + 32)) return CRYPT_OK; if (unpackneg(q,pk)) return CRYPT_ERROR; diff --git a/tests/ed25519_test.c b/tests/ed25519_test.c index 45f871db9..ca1ebecd1 100644 --- a/tests/ed25519_test.c +++ b/tests/ed25519_test.c @@ -396,6 +396,43 @@ static int s_rfc_8032_7_3_test(void) return CRYPT_OK; } +static int s_signature_malleability_test(void) +{ + /* Wycheproof Ed25519 signature malleability test vectors. */ + static const struct { + int tc_id; + const char *sig; + } test_cases[] = { + { 63, "7c38e026f29e14aabd059a0f2db8b0cd783040609a8be684db12f82a27774ab067654bce3832c2d76f8f6f5dafc08d9339d4eef676573336a5c51eb6f946b31d" }, + { 64, "7c38e026f29e14aabd059a0f2db8b0cd783040609a8be684db12f82a27774ab05439412b5395d42f462c67008eba6ca839d4eef676573336a5c51eb6f946b32d" }, + { 65, "7c38e026f29e14aabd059a0f2db8b0cd783040609a8be684db12f82a27774ab02ee12ce5875bf9dff26556464bae2ad239d4eef676573336a5c51eb6f946b34d" }, + { 66, "7c38e026f29e14aabd059a0f2db8b0cd783040609a8be684db12f82a27774ab0e2300459f1e742404cd934d2c595a6253ad4eef676573336a5c51eb6f946b38d" }, + }; + const char *public_key = "7d4d0e7f6153a69b6242b522abbee685fda4420f8834b108c3bdae369ef549fa"; + const char *message = "54657374"; + unsigned long n, mlen, plen, siglen; + unsigned char msg[32], pub[32], sig[64]; + curve25519_key key; + int ret; + const int should = 0; + + plen = sizeof(pub); + DO(base16_decode(public_key, XSTRLEN(public_key), pub, &plen)); + mlen = sizeof(msg); + DO(base16_decode(message, XSTRLEN(message), msg, &mlen)); + DO(ed25519_import_raw(pub, plen, PK_PUBLIC, &key)); + + for (n = 0; n < LTC_ARRAY_SIZE(test_cases); ++n) { + siglen = sizeof(sig); + DO(base16_decode(test_cases[n].sig, XSTRLEN(test_cases[n].sig), sig, &siglen)); + DO(ed25519_verify(msg, mlen, sig, siglen, &ret, &key)); + COMPARE_TESTVECTOR(&ret, sizeof(ret), &should, sizeof(should), "Ed25519 malleability rejection", test_cases[n].tc_id); + } + + zeromem(&key, sizeof(key)); + return CRYPT_OK; +} + /** Test the ed25519 system @return CRYPT_OK if successful @@ -423,6 +460,9 @@ int ed25519_test(void) if ((ret = s_rfc_8032_7_3_test()) != CRYPT_OK) { return ret; } + if ((ret = s_signature_malleability_test()) != CRYPT_OK) { + return ret; + } return ret; }