CORDA-2031 put "AlgorithmParameters.SHA256WITHECDSA" to BC (#3997)

This commit is contained in:
Konstantinos Chalkias 2018-09-27 15:21:12 +01:00 committed by GitHub
parent adcd0d45df
commit e92ad538cf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 73 additions and 29 deletions

View File

@ -11,6 +11,7 @@ import net.i2p.crypto.eddsa.EdDSASecurityProvider
import org.bouncycastle.asn1.ASN1ObjectIdentifier import org.bouncycastle.asn1.ASN1ObjectIdentifier
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo import org.bouncycastle.asn1.pkcs.PrivateKeyInfo
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo
import org.bouncycastle.jcajce.provider.asymmetric.ec.AlgorithmParametersSpi
import org.bouncycastle.jcajce.provider.util.AsymmetricKeyInfoConverter import org.bouncycastle.jcajce.provider.util.AsymmetricKeyInfoConverter
import org.bouncycastle.jce.provider.BouncyCastleProvider import org.bouncycastle.jce.provider.BouncyCastleProvider
import org.bouncycastle.pqc.jcajce.provider.BouncyCastlePQCProvider import org.bouncycastle.pqc.jcajce.provider.BouncyCastlePQCProvider
@ -30,6 +31,8 @@ internal val cordaBouncyCastleProvider = BouncyCastleProvider().apply {
override fun generatePublic(keyInfo: SubjectPublicKeyInfo) = decodePublicKey(EDDSA_ED25519_SHA512, keyInfo.encoded) override fun generatePublic(keyInfo: SubjectPublicKeyInfo) = decodePublicKey(EDDSA_ED25519_SHA512, keyInfo.encoded)
override fun generatePrivate(keyInfo: PrivateKeyInfo) = decodePrivateKey(EDDSA_ED25519_SHA512, keyInfo.encoded) override fun generatePrivate(keyInfo: PrivateKeyInfo) = decodePrivateKey(EDDSA_ED25519_SHA512, keyInfo.encoded)
}) })
// Required due to [X509CRL].verify() reported issues in network-services after BC 1.60 update.
put("AlgorithmParameters.SHA256WITHECDSA", AlgorithmParametersSpi::class.java.name)
}.also { }.also {
// This registration is needed for reading back EdDSA key from java keystore. // This registration is needed for reading back EdDSA key from java keystore.
// TODO: Find a way to make JKS work with bouncy castle provider or implement our own provide so we don't have to register bouncy castle provider. // TODO: Find a way to make JKS work with bouncy castle provider or implement our own provide so we don't have to register bouncy castle provider.

View File

@ -25,10 +25,10 @@ import net.corda.testing.core.BOB_NAME
import net.corda.testing.core.CHARLIE_NAME import net.corda.testing.core.CHARLIE_NAME
import net.corda.testing.core.MAX_MESSAGE_SIZE import net.corda.testing.core.MAX_MESSAGE_SIZE
import net.corda.testing.driver.PortAllocation import net.corda.testing.driver.PortAllocation
import net.corda.testing.internal.stubs.CertificateStoreStubs
import net.corda.testing.internal.DEV_INTERMEDIATE_CA import net.corda.testing.internal.DEV_INTERMEDIATE_CA
import net.corda.testing.internal.DEV_ROOT_CA import net.corda.testing.internal.DEV_ROOT_CA
import net.corda.testing.internal.rigorousMock import net.corda.testing.internal.rigorousMock
import net.corda.testing.internal.stubs.CertificateStoreStubs
import org.bouncycastle.asn1.x500.X500Name import org.bouncycastle.asn1.x500.X500Name
import org.bouncycastle.asn1.x509.* import org.bouncycastle.asn1.x509.*
import org.bouncycastle.cert.jcajce.JcaX509CRLConverter import org.bouncycastle.cert.jcajce.JcaX509CRLConverter
@ -62,6 +62,7 @@ import javax.ws.rs.Path
import javax.ws.rs.Produces import javax.ws.rs.Produces
import javax.ws.rs.core.Response import javax.ws.rs.core.Response
import kotlin.test.assertEquals import kotlin.test.assertEquals
import kotlin.test.assertFailsWith
class CertificateRevocationListNodeTests { class CertificateRevocationListNodeTests {
@Rule @Rule
@ -81,6 +82,32 @@ class CertificateRevocationListNodeTests {
private abstract class AbstractNodeConfiguration : NodeConfiguration private abstract class AbstractNodeConfiguration : NodeConfiguration
companion object {
fun createRevocationList(clrServer: CrlServer, signatureAlgorithm: String, caCertificate: X509Certificate,
caPrivateKey: PrivateKey,
endpoint: String,
indirect: Boolean,
vararg serialNumbers: BigInteger): X509CRL {
println("Generating CRL for $endpoint")
val builder = JcaX509v2CRLBuilder(caCertificate.subjectX500Principal, Date(System.currentTimeMillis() - 1.minutes.toMillis()))
val extensionUtils = JcaX509ExtensionUtils()
builder.addExtension(Extension.authorityKeyIdentifier,
false, extensionUtils.createAuthorityKeyIdentifier(caCertificate))
val issuingDistPointName = GeneralName(
GeneralName.uniformResourceIdentifier,
"http://${clrServer.hostAndPort.host}:${clrServer.hostAndPort.port}/crl/$endpoint")
// This is required and needs to match the certificate settings with respect to being indirect
val issuingDistPoint = IssuingDistributionPoint(DistributionPointName(GeneralNames(issuingDistPointName)), indirect, false)
builder.addExtension(Extension.issuingDistributionPoint, true, issuingDistPoint)
builder.setNextUpdate(Date(System.currentTimeMillis() + 1.seconds.toMillis()))
serialNumbers.forEach {
builder.addCRLEntry(it, Date(System.currentTimeMillis() - 10.minutes.toMillis()), ReasonFlags.certificateHold)
}
val signer = JcaContentSignerBuilder(signatureAlgorithm).setProvider(Crypto.findProvider("BC")).build(caPrivateKey)
return JcaX509CRLConverter().setProvider(Crypto.findProvider("BC")).getCRL(builder.build(signer))
}
}
@Before @Before
fun setUp() { fun setUp() {
Security.addProvider(BouncyCastleProvider()) Security.addProvider(BouncyCastleProvider())
@ -455,12 +482,15 @@ class CertificateRevocationListNodeTests {
@Path("node.crl") @Path("node.crl")
@Produces("application/pkcs7-crl") @Produces("application/pkcs7-crl")
fun getNodeCRL(): Response { fun getNodeCRL(): Response {
return Response.ok(createRevocationList( return Response.ok(CertificateRevocationListNodeTests.createRevocationList(
server,
SIGNATURE_ALGORITHM,
INTERMEDIATE_CA.certificate, INTERMEDIATE_CA.certificate,
INTERMEDIATE_CA.keyPair.private, INTERMEDIATE_CA.keyPair.private,
NODE_CRL, NODE_CRL,
false, false,
*revokedNodeCerts.toTypedArray()).encoded).build() *revokedNodeCerts.toTypedArray()).encoded)
.build()
} }
@GET @GET
@ -468,11 +498,14 @@ class CertificateRevocationListNodeTests {
@Produces("application/pkcs7-crl") @Produces("application/pkcs7-crl")
fun getIntermediateCRL(): Response { fun getIntermediateCRL(): Response {
return Response.ok(createRevocationList( return Response.ok(createRevocationList(
server,
SIGNATURE_ALGORITHM,
ROOT_CA.certificate, ROOT_CA.certificate,
ROOT_CA.keyPair.private, ROOT_CA.keyPair.private,
INTEMEDIATE_CRL, INTEMEDIATE_CRL,
false, false,
*revokedIntermediateCerts.toTypedArray()).encoded).build() *revokedIntermediateCerts.toTypedArray()).encoded)
.build()
} }
@GET @GET
@ -480,33 +513,13 @@ class CertificateRevocationListNodeTests {
@Produces("application/pkcs7-crl") @Produces("application/pkcs7-crl")
fun getEmptyCRL(): Response { fun getEmptyCRL(): Response {
return Response.ok(createRevocationList( return Response.ok(createRevocationList(
server,
SIGNATURE_ALGORITHM,
ROOT_CA.certificate, ROOT_CA.certificate,
ROOT_CA.keyPair.private, ROOT_CA.keyPair.private,
EMPTY_CRL, true).encoded).build() EMPTY_CRL,
} true).encoded)
.build()
private fun createRevocationList(caCertificate: X509Certificate,
caPrivateKey: PrivateKey,
endpoint: String,
indirect: Boolean,
vararg serialNumbers: BigInteger): X509CRL {
println("Generating CRL for $endpoint")
val builder = JcaX509v2CRLBuilder(caCertificate.subjectX500Principal, Date(System.currentTimeMillis() - 1.minutes.toMillis()))
val extensionUtils = JcaX509ExtensionUtils()
builder.addExtension(Extension.authorityKeyIdentifier,
false, extensionUtils.createAuthorityKeyIdentifier(caCertificate))
val issuingDistPointName = GeneralName(
GeneralName.uniformResourceIdentifier,
"http://${server.hostAndPort.host}:${server.hostAndPort.port}/crl/$endpoint")
// This is required and needs to match the certificate settings with respect to being indirect
val issuingDistPoint = IssuingDistributionPoint(DistributionPointName(GeneralNames(issuingDistPointName)), indirect, false)
builder.addExtension(Extension.issuingDistributionPoint, true, issuingDistPoint)
builder.setNextUpdate(Date(System.currentTimeMillis() + 1.seconds.toMillis()))
serialNumbers.forEach {
builder.addCRLEntry(it, Date(System.currentTimeMillis() - 10.minutes.toMillis()), ReasonFlags.certificateHold)
}
val signer = JcaContentSignerBuilder(SIGNATURE_ALGORITHM).setProvider(BouncyCastleProvider.PROVIDER_NAME).build(caPrivateKey)
return JcaX509CRLConverter().setProvider(BouncyCastleProvider.PROVIDER_NAME).getCRL(builder.build(signer))
} }
} }
@ -546,4 +559,32 @@ class CertificateRevocationListNodeTests {
} }
} }
} }
@Test
fun `verify CRL algorithms`() {
val ECDSA_ALGORITHM = "SHA256withECDSA"
val EC_ALGORITHM = "EC"
val EMPTY_CRL = "empty.crl"
val crl = createRevocationList(
server,
ECDSA_ALGORITHM,
ROOT_CA.certificate,
ROOT_CA.keyPair.private,
EMPTY_CRL,
true)
// This should pass.
crl.verify(ROOT_CA.keyPair.public)
// Try changing the algorithm to EC will fail.
assertFailsWith<IllegalArgumentException>("Unknown signature type requested: EC") {
createRevocationList(
server,
EC_ALGORITHM,
ROOT_CA.certificate,
ROOT_CA.keyPair.private,
EMPTY_CRL,
true)
}
}
} }