From a645807d446a9997b8bca720cc4e6dcacc9e2310 Mon Sep 17 00:00:00 2001 From: Gus Narea Date: Tue, 28 Jul 2020 18:52:59 +0100 Subject: [PATCH] fix(handshake): Use RSA-PSS when signing nonces (#24) Counterpart on the server: https://github.com/relaycorp/relaynet-gateway-android/pull/65 --- .../tech/relaycorp/poweb/CryptoUtils.kt | 7 +++++++ .../relaycorp/poweb/handshake/NonceSigner.kt | 4 +++- .../relaycorp/poweb/handshake/CMSUtils.kt | 9 ++++++--- .../poweb/handshake/NonceSignerTest.kt | 20 ++++++++++++++++--- 4 files changed, 33 insertions(+), 7 deletions(-) create mode 100644 src/main/kotlin/tech/relaycorp/poweb/CryptoUtils.kt diff --git a/src/main/kotlin/tech/relaycorp/poweb/CryptoUtils.kt b/src/main/kotlin/tech/relaycorp/poweb/CryptoUtils.kt new file mode 100644 index 0000000..3600254 --- /dev/null +++ b/src/main/kotlin/tech/relaycorp/poweb/CryptoUtils.kt @@ -0,0 +1,7 @@ +package tech.relaycorp.poweb + +import org.bouncycastle.jce.provider.BouncyCastleProvider + +object CryptoUtils { + val BC_PROVIDER = BouncyCastleProvider() +} diff --git a/src/main/kotlin/tech/relaycorp/poweb/handshake/NonceSigner.kt b/src/main/kotlin/tech/relaycorp/poweb/handshake/NonceSigner.kt index a249311..91af059 100644 --- a/src/main/kotlin/tech/relaycorp/poweb/handshake/NonceSigner.kt +++ b/src/main/kotlin/tech/relaycorp/poweb/handshake/NonceSigner.kt @@ -7,6 +7,7 @@ import org.bouncycastle.cms.jcajce.JcaSignerInfoGeneratorBuilder import org.bouncycastle.operator.ContentSigner import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder import org.bouncycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder +import tech.relaycorp.poweb.CryptoUtils import tech.relaycorp.relaynet.wrappers.x509.Certificate import java.security.PrivateKey @@ -14,7 +15,8 @@ class NonceSigner(internal val certificate: Certificate, private val privateKey: fun sign(nonce: ByteArray): ByteArray { val signedDataGenerator = CMSSignedDataGenerator() - val signerBuilder = JcaContentSignerBuilder("SHA256withRSA") + val signerBuilder = JcaContentSignerBuilder("SHA256WITHRSAANDMGF1") + .setProvider(CryptoUtils.BC_PROVIDER) val contentSigner: ContentSigner = signerBuilder.build(privateKey) val signerInfoGenerator = JcaSignerInfoGeneratorBuilder( JcaDigestCalculatorProviderBuilder() diff --git a/src/test/kotlin/tech/relaycorp/poweb/handshake/CMSUtils.kt b/src/test/kotlin/tech/relaycorp/poweb/handshake/CMSUtils.kt index b946df2..22e73db 100644 --- a/src/test/kotlin/tech/relaycorp/poweb/handshake/CMSUtils.kt +++ b/src/test/kotlin/tech/relaycorp/poweb/handshake/CMSUtils.kt @@ -9,6 +9,7 @@ import org.bouncycastle.cms.CMSSignedData import org.bouncycastle.cms.SignerInformation import org.bouncycastle.cms.jcajce.JcaSimpleSignerInfoVerifierBuilder import org.bouncycastle.util.Selector +import tech.relaycorp.poweb.CryptoUtils import tech.relaycorp.relaynet.wrappers.x509.Certificate object CMSUtils { @@ -20,8 +21,8 @@ object CMSUtils { val signerInfo = getSignerInfoFromSignedData(signedData) - // We shouldn't have to force this type cast but this is the only way I could get the code to work and, based on - // what I found online, that's what others have had to do as well + // We shouldn't have to force this type cast but this is the only way I could get the code + // to work and, based on what I found online, that's what others have had to do as well @Suppress("UNCHECKED_CAST") val signerCertSelector = X509CertificateHolderSelector( signerInfo.sid.issuer, signerInfo.sid.serialNumber @@ -29,7 +30,9 @@ object CMSUtils { val signerCertMatches = signedData.certificates.getMatches(signerCertSelector) val signerCertificateHolder = signerCertMatches.first() - val verifier = JcaSimpleSignerInfoVerifierBuilder().build(signerCertificateHolder) + val verifier = JcaSimpleSignerInfoVerifierBuilder() + .setProvider(CryptoUtils.BC_PROVIDER) + .build(signerCertificateHolder) signerInfo.verify(verifier) diff --git a/src/test/kotlin/tech/relaycorp/poweb/handshake/NonceSignerTest.kt b/src/test/kotlin/tech/relaycorp/poweb/handshake/NonceSignerTest.kt index e37b65d..93ae4c0 100644 --- a/src/test/kotlin/tech/relaycorp/poweb/handshake/NonceSignerTest.kt +++ b/src/test/kotlin/tech/relaycorp/poweb/handshake/NonceSignerTest.kt @@ -6,6 +6,8 @@ import org.bouncycastle.asn1.ASN1Primitive import org.bouncycastle.asn1.DEROctetString import org.bouncycastle.asn1.cms.Attribute import org.bouncycastle.asn1.cms.ContentInfo +import org.bouncycastle.asn1.nist.NISTObjectIdentifiers +import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers import org.bouncycastle.cms.CMSSignedData import org.bouncycastle.util.CollectionStore import org.junit.jupiter.api.Nested @@ -159,6 +161,16 @@ class NonceSignerTest { assertEquals(certificate.certificateHolder, attachedCerts[0]) } + @Test + fun `Signature algorithm should be RSA-PSS`() { + val serialization = signer.sign(nonce) + + val cmsSignedData = parseCmsSignedData(serialization) + + val signerInfo = cmsSignedData.signerInfos.first() + assertEquals(PKCSObjectIdentifiers.id_RSASSA_PSS.id, signerInfo.encryptionAlgOID) + } + @Test fun `SHA-256 should be used`() { val serialization = signer.sign(nonce) @@ -166,12 +178,14 @@ class NonceSignerTest { val cmsSignedData = parseCmsSignedData(serialization) assertEquals(1, cmsSignedData.digestAlgorithmIDs.size) - val sha256Oid = ASN1ObjectIdentifier("2.16.840.1.101.3.4.2.1") - assertEquals(sha256Oid, cmsSignedData.digestAlgorithmIDs.first().algorithm) + assertEquals( + NISTObjectIdentifiers.id_sha256, + cmsSignedData.digestAlgorithmIDs.first().algorithm + ) val signerInfo = cmsSignedData.signerInfos.first() - assertEquals(sha256Oid, signerInfo.digestAlgorithmID.algorithm) + assertEquals(NISTObjectIdentifiers.id_sha256, signerInfo.digestAlgorithmID.algorithm) } @Test