feat: Add configuration to specify public key id

This commit is contained in:
oSumAtrIX 2024-07-13 00:27:54 +02:00
parent 97a5d119ec
commit ad7d4b226f
No known key found for this signature in database
GPG Key ID: A9B3094ACDB604B4
3 changed files with 24 additions and 25 deletions

View File

@ -51,6 +51,7 @@ internal class ConfigurationRepository(
* @property assetRegex The regex matching the asset name. * @property assetRegex The regex matching the asset name.
* @property signatureAssetRegex The regex matching the signature asset name to verify the asset. * @property signatureAssetRegex The regex matching the signature asset name to verify the asset.
* @property publicKeyFile The public key file to verify the signature of the asset. * @property publicKeyFile The public key file to verify the signature of the asset.
* @property publicKeyId The ID of the public key to verify the signature of the asset.
*/ */
@Serializable @Serializable
internal class AssetConfiguration( internal class AssetConfiguration(
@ -64,6 +65,8 @@ internal class ConfigurationRepository(
@Serializable(with = FileSerializer::class) @Serializable(with = FileSerializer::class)
@SerialName("public-key-file") @SerialName("public-key-file")
val publicKeyFile: File, val publicKeyFile: File,
@SerialName("public-key-id")
val publicKeyId: Long,
) )
} }

View File

@ -92,6 +92,7 @@ internal class PatchesService(
patchesFile, patchesFile,
signatureDownloadUrl, signatureDownloadUrl,
configurationRepository.patches.publicKeyFile, configurationRepository.patches.publicKeyFile,
configurationRepository.patches.publicKeyId,
) )
) { ) {
PatchBundleLoader.Jar(patchesFile) PatchBundleLoader.Jar(patchesFile)

View File

@ -1,7 +1,6 @@
package app.revanced.api.configuration.services package app.revanced.api.configuration.services
import com.github.benmanes.caffeine.cache.Caffeine import com.github.benmanes.caffeine.cache.Caffeine
import org.bouncycastle.jce.provider.BouncyCastleProvider
import org.bouncycastle.openpgp.* import org.bouncycastle.openpgp.*
import org.bouncycastle.openpgp.operator.bc.BcKeyFingerprintCalculator import org.bouncycastle.openpgp.operator.bc.BcKeyFingerprintCalculator
import org.bouncycastle.openpgp.operator.bc.BcPGPContentVerifierBuilderProvider import org.bouncycastle.openpgp.operator.bc.BcPGPContentVerifierBuilderProvider
@ -9,7 +8,6 @@ import java.io.File
import java.io.InputStream import java.io.InputStream
import java.net.URL import java.net.URL
import java.security.MessageDigest import java.security.MessageDigest
import java.security.Security
internal class SignatureService { internal class SignatureService {
private val signatureCache = Caffeine private val signatureCache = Caffeine
@ -21,6 +19,7 @@ internal class SignatureService {
file: File, file: File,
signatureDownloadUrl: String, signatureDownloadUrl: String,
publicKeyFile: File, publicKeyFile: File,
publicKeyId: Long,
): Boolean { ): Boolean {
val fileBytes = file.readBytes() val fileBytes = file.readBytes()
@ -28,7 +27,8 @@ internal class SignatureService {
verify( verify(
fileBytes = fileBytes, fileBytes = fileBytes,
signatureInputStream = URL(signatureDownloadUrl).openStream(), signatureInputStream = URL(signatureDownloadUrl).openStream(),
publicKeyInputStream = publicKeyFile.inputStream(), publicKeyFileInputStream = publicKeyFile.inputStream(),
publicKeyId = publicKeyId,
) )
} }
} }
@ -36,37 +36,32 @@ internal class SignatureService {
private fun verify( private fun verify(
fileBytes: ByteArray, fileBytes: ByteArray,
signatureInputStream: InputStream, signatureInputStream: InputStream,
publicKeyInputStream: InputStream, publicKeyFileInputStream: InputStream,
publicKeyId: Long,
) = getSignature(signatureInputStream).apply { ) = getSignature(signatureInputStream).apply {
init(BcPGPContentVerifierBuilderProvider(), getPublicKey(publicKeyInputStream)) init(BcPGPContentVerifierBuilderProvider(), getPublicKey(publicKeyFileInputStream, publicKeyId))
update(fileBytes) update(fileBytes)
}.verify() }.verify()
private fun getPublicKey(publicKeyInputStream: InputStream): PGPPublicKey { private fun getPublicKey(
val decoderStream = PGPUtil.getDecoderStream(publicKeyInputStream) publicKeyFileInputStream: InputStream,
publicKeyId: Long,
): PGPPublicKey {
val decoderStream = PGPUtil.getDecoderStream(publicKeyFileInputStream)
val pgpPublicKeyRingCollection = PGPPublicKeyRingCollection(decoderStream, BcKeyFingerprintCalculator())
val publicKeyRing = pgpPublicKeyRingCollection.getPublicKeyRing(publicKeyId)
?: throw IllegalArgumentException("Can't find public key ring with ID $publicKeyId.")
PGPPublicKeyRingCollection(decoderStream, BcKeyFingerprintCalculator()).forEach { keyRing -> return publicKeyRing.getPublicKey(publicKeyId)
keyRing.publicKeys.forEach { publicKey -> ?: throw IllegalArgumentException("Can't find public key with ID $publicKeyId.")
if (publicKey.isEncryptionKey) {
return publicKey
}
}
}
throw IllegalArgumentException("Can't find encryption key in key ring.")
} }
private fun getSignature(inputStream: InputStream): PGPSignature { private fun getSignature(inputStream: InputStream): PGPSignature {
val decoderStream = PGPUtil.getDecoderStream(inputStream) val decoderStream = PGPUtil.getDecoderStream(inputStream)
val pgpObjectFactory = PGPObjectFactory(decoderStream, BcKeyFingerprintCalculator()) val pgpSignatureList = PGPObjectFactory(decoderStream, BcKeyFingerprintCalculator()).first {
val signatureList = pgpObjectFactory.nextObject() as PGPSignatureList it is PGPSignatureList
} as PGPSignatureList
return signatureList.first() return pgpSignatureList.first()
}
private companion object {
init {
Security.addProvider(BouncyCastleProvider())
}
} }
} }