From 0966349d1a98dbcb057e450c39b2d0f7c6b33e82 Mon Sep 17 00:00:00 2001 From: Alva Swanson Date: Mon, 22 Jul 2024 17:07:01 +0000 Subject: [PATCH] build-logic: Support m out of n signature verification In Electrum all developers sign the binaries, but in Bitcoin Core a subset of its developers sign the binaries. Our existing signature verification code fails if not all developers have signed the binaries. This change enforces that all provided signatures are signed by its developers, i.e., if we have 20 hard-coded public keys and a binary has 10 signatures we ensure that the public keys of those 10 signatures belong to the hard-coded developers and all signatures are valid. --- .../tasks/signature/SignatureVerifier.kt | 24 ++++++++++++------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/build-logic/gradle-tasks/src/main/kotlin/bisq/gradle/tasks/signature/SignatureVerifier.kt b/build-logic/gradle-tasks/src/main/kotlin/bisq/gradle/tasks/signature/SignatureVerifier.kt index 6c0a31a59a..7dea031019 100644 --- a/build-logic/gradle-tasks/src/main/kotlin/bisq/gradle/tasks/signature/SignatureVerifier.kt +++ b/build-logic/gradle-tasks/src/main/kotlin/bisq/gradle/tasks/signature/SignatureVerifier.kt @@ -22,21 +22,27 @@ class SignatureVerifier( ): Boolean { Security.addProvider(BouncyCastleProvider()) - var isSuccess = true + val signatureFileInBytes = readSignatureFromFile(signatureFile) + val pgpObjectFactory = JcaPGPObjectFactory(signatureFileInBytes) + val signatureList: PGPSignatureList = pgpObjectFactory.nextObject() as PGPSignatureList + + val signatureVerificationResult = mutableListOf() pgpFingerprintToKeyUrl.forEach { (fingerprint, keyUrl) -> val ppgPublicKeyParser = PpgPublicKeyParser(fingerprint, keyUrl) ppgPublicKeyParser.parse() val isSignedByAnyKey = verifyDetachedSignature( potentialSigningKeys = ppgPublicKeyParser.keyById, - pgpSignatureByteArray = readSignatureFromFile(signatureFile), + signatureList = signatureList, data = fileToVerify.readBytes() ) - isSuccess = isSuccess && isSignedByAnyKey + signatureVerificationResult.add(isSignedByAnyKey) } - return isSuccess + val numberOfSuccessfulVerifications = signatureVerificationResult.filter { isSuccess -> isSuccess } + .count() + return numberOfSuccessfulVerifications == signatureList.size() } private fun readSignatureFromFile(signatureFile: File): ByteArray { @@ -48,12 +54,9 @@ class SignatureVerifier( private fun verifyDetachedSignature( potentialSigningKeys: Map, - pgpSignatureByteArray: ByteArray, + signatureList: PGPSignatureList, data: ByteArray ): Boolean { - val pgpObjectFactory = JcaPGPObjectFactory(pgpSignatureByteArray) - val signatureList: PGPSignatureList = pgpObjectFactory.nextObject() as PGPSignatureList - var pgpSignature: PGPSignature? = null var signingKey: PGPPublicKey? = null @@ -65,7 +68,10 @@ class SignatureVerifier( } } - checkNotNull(signingKey) { "signingKey not found" } + if (signingKey == null) { + return false + } + checkNotNull(pgpSignature) { "signature for key not found" } pgpSignature.init(