From 54fa208c7da9c9a789c3a6d1cd5f4126753645b0 Mon Sep 17 00:00:00 2001 From: Pierre-Marie Padiou Date: Tue, 31 Aug 2021 15:28:40 +0200 Subject: [PATCH] Add validation on the recid in `verifymessage` (#1928) We offset the `recid` by `31` for compatibility with `lnd` [1] but we should also support normal values (0-3), and also add boundary checks. [1] https://twitter.com/rusty_twit/status/1182102005914800128 --- .../src/main/scala/fr/acinq/eclair/Eclair.scala | 6 +++++- .../test/scala/fr/acinq/eclair/EclairImplSpec.scala | 10 ++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/Eclair.scala b/eclair-core/src/main/scala/fr/acinq/eclair/Eclair.scala index f335d9824..bc650d75e 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/Eclair.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/Eclair.scala @@ -458,7 +458,11 @@ class EclairImpl(appKit: Kit) extends Eclair with Logging { override def verifyMessage(message: ByteVector, recoverableSignature: ByteVector): VerifiedMessage = { val signedBytes = SignedMessage.signedBytes(message) val signature = ByteVector64(recoverableSignature.tail) - val recoveryId = recoverableSignature.head.toInt - 31 + val recoveryId = recoverableSignature.head.toInt match { + case lndFormat if (lndFormat - 31) >= 0 && (lndFormat - 31) <= 3 => lndFormat - 31 + case normalFormat if normalFormat >= 0 && normalFormat <= 3 => normalFormat + case invalidFormat => throw new RuntimeException(s"invalid recid prefix $invalidFormat") + } val pubKeyFromSignature = Crypto.recoverPublicKey(signature, signedBytes, recoveryId) VerifiedMessage(valid = true, pubKeyFromSignature) } diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/EclairImplSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/EclairImplSpec.scala index ac4221c74..a02314e17 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/EclairImplSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/EclairImplSpec.scala @@ -469,6 +469,16 @@ class EclairImplSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with I assert(verifiedMessage.publicKey !== kit.nodeParams.nodeId) } + test("verify a signature with different recid formats") { f => + import f._ + val eclair = new EclairImpl(kit) + + val bytesMsg = ByteVector("hello, world".getBytes) + val sig = hex"730dce842c31b692dc041c2d0f00423d2a2a67b0c63c1a905d500f09652a5b1a036763a1603333fa589ae92d1f7963428ff170e976d0966a113f4b9f9d0efc7f" + assert(eclair.verifyMessage(bytesMsg, hex"1f" ++ sig).valid) // 0x1f = 31, format used by lnd (spec: https://twitter.com/rusty_twit/status/1182102005914800128) + assert(eclair.verifyMessage(bytesMsg, hex"00" ++ sig).valid) + } + test("ensure that an invalid recoveryId cause the signature verification to fail") { f => import f._