mirror of
https://github.com/corda/corda.git
synced 2025-02-21 09:51:57 +00:00
CORDA-2009 update to BC 1.60 (security fixes) (#3974)
* update to BC 1.60 (security fixes) * adding key combination keystore/cert tests
This commit is contained in:
parent
6775ffa2e6
commit
38c85d1711
@ -5,7 +5,7 @@ kotlinVersion=1.2.51
|
|||||||
platformVersion=4
|
platformVersion=4
|
||||||
guavaVersion=25.1-jre
|
guavaVersion=25.1-jre
|
||||||
proguardVersion=6.0.3
|
proguardVersion=6.0.3
|
||||||
bouncycastleVersion=1.57
|
bouncycastleVersion=1.60
|
||||||
typesafeConfigVersion=1.3.1
|
typesafeConfigVersion=1.3.1
|
||||||
jsr305Version=3.0.2
|
jsr305Version=3.0.2
|
||||||
artifactoryPluginVersion=4.7.3
|
artifactoryPluginVersion=4.7.3
|
||||||
|
@ -1,9 +1,13 @@
|
|||||||
package net.corda.nodeapi.internal.crypto
|
package net.corda.nodeapi.internal.crypto
|
||||||
|
|
||||||
import net.corda.core.crypto.Crypto
|
import net.corda.core.crypto.*
|
||||||
|
import net.corda.core.crypto.Crypto.COMPOSITE_KEY
|
||||||
|
import net.corda.core.crypto.Crypto.ECDSA_SECP256K1_SHA256
|
||||||
|
import net.corda.core.crypto.Crypto.ECDSA_SECP256R1_SHA256
|
||||||
import net.corda.core.crypto.Crypto.EDDSA_ED25519_SHA512
|
import net.corda.core.crypto.Crypto.EDDSA_ED25519_SHA512
|
||||||
|
import net.corda.core.crypto.Crypto.RSA_SHA256
|
||||||
|
import net.corda.core.crypto.Crypto.SPHINCS256_SHA256
|
||||||
import net.corda.core.crypto.Crypto.generateKeyPair
|
import net.corda.core.crypto.Crypto.generateKeyPair
|
||||||
import net.corda.core.crypto.newSecureRandom
|
|
||||||
import net.corda.core.identity.CordaX500Name
|
import net.corda.core.identity.CordaX500Name
|
||||||
import net.corda.core.internal.div
|
import net.corda.core.internal.div
|
||||||
import net.corda.core.serialization.SerializationContext
|
import net.corda.core.serialization.SerializationContext
|
||||||
@ -12,6 +16,8 @@ import net.corda.core.serialization.serialize
|
|||||||
import net.corda.node.serialization.amqp.AMQPServerSerializationScheme
|
import net.corda.node.serialization.amqp.AMQPServerSerializationScheme
|
||||||
import net.corda.nodeapi.internal.config.MutualSslConfiguration
|
import net.corda.nodeapi.internal.config.MutualSslConfiguration
|
||||||
import net.corda.nodeapi.internal.createDevNodeCa
|
import net.corda.nodeapi.internal.createDevNodeCa
|
||||||
|
import net.corda.nodeapi.internal.crypto.X509Utilities.DEFAULT_IDENTITY_SIGNATURE_SCHEME
|
||||||
|
import net.corda.nodeapi.internal.crypto.X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME
|
||||||
import net.corda.nodeapi.internal.protonwrapper.netty.init
|
import net.corda.nodeapi.internal.protonwrapper.netty.init
|
||||||
import net.corda.nodeapi.internal.registerDevP2pCertificates
|
import net.corda.nodeapi.internal.registerDevP2pCertificates
|
||||||
import net.corda.nodeapi.internal.registerDevSigningCertificates
|
import net.corda.nodeapi.internal.registerDevSigningCertificates
|
||||||
@ -24,17 +30,24 @@ import net.corda.testing.core.BOB_NAME
|
|||||||
import net.corda.testing.core.TestIdentity
|
import net.corda.testing.core.TestIdentity
|
||||||
import net.corda.testing.internal.stubs.CertificateStoreStubs
|
import net.corda.testing.internal.stubs.CertificateStoreStubs
|
||||||
import net.corda.testing.internal.createDevIntermediateCaCertPath
|
import net.corda.testing.internal.createDevIntermediateCaCertPath
|
||||||
|
import net.i2p.crypto.eddsa.EdDSAPrivateKey
|
||||||
import org.assertj.core.api.Assertions.assertThat
|
import org.assertj.core.api.Assertions.assertThat
|
||||||
import org.bouncycastle.asn1.x509.*
|
import org.bouncycastle.asn1.x509.*
|
||||||
|
import org.bouncycastle.jcajce.provider.asymmetric.rsa.BCRSAPrivateCrtKey
|
||||||
|
import org.bouncycastle.pqc.jcajce.provider.sphincs.BCSphincs256PrivateKey
|
||||||
import org.junit.Rule
|
import org.junit.Rule
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.rules.TemporaryFolder
|
import org.junit.rules.TemporaryFolder
|
||||||
|
import sun.security.rsa.RSAPrivateCrtKeyImpl
|
||||||
import java.io.DataInputStream
|
import java.io.DataInputStream
|
||||||
import java.io.DataOutputStream
|
import java.io.DataOutputStream
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.net.InetAddress
|
import java.net.InetAddress
|
||||||
import java.net.InetSocketAddress
|
import java.net.InetSocketAddress
|
||||||
import java.nio.file.Path
|
import java.nio.file.Path
|
||||||
|
import java.security.Key
|
||||||
|
import java.security.KeyPair
|
||||||
|
import java.security.PrivateKey
|
||||||
import java.security.cert.CertPath
|
import java.security.cert.CertPath
|
||||||
import java.security.cert.X509Certificate
|
import java.security.cert.X509Certificate
|
||||||
import java.util.*
|
import java.util.*
|
||||||
@ -53,6 +66,28 @@ class X509UtilitiesTest {
|
|||||||
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
|
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
|
||||||
"TLS_DHE_RSA_WITH_AES_128_GCM_SHA256"
|
"TLS_DHE_RSA_WITH_AES_128_GCM_SHA256"
|
||||||
)
|
)
|
||||||
|
// We ensure that all of the algorithms are both used (at least once) as first and second in the following [Pair]s.
|
||||||
|
// We also add [DEFAULT_TLS_SIGNATURE_SCHEME] and [DEFAULT_IDENTITY_SIGNATURE_SCHEME] combinations for consistency.
|
||||||
|
val certChainSchemeCombinations = listOf(
|
||||||
|
Pair(DEFAULT_TLS_SIGNATURE_SCHEME, DEFAULT_TLS_SIGNATURE_SCHEME),
|
||||||
|
Pair(DEFAULT_IDENTITY_SIGNATURE_SCHEME, DEFAULT_IDENTITY_SIGNATURE_SCHEME),
|
||||||
|
Pair(DEFAULT_TLS_SIGNATURE_SCHEME, DEFAULT_IDENTITY_SIGNATURE_SCHEME),
|
||||||
|
Pair(ECDSA_SECP256R1_SHA256, SPHINCS256_SHA256),
|
||||||
|
Pair(ECDSA_SECP256K1_SHA256, RSA_SHA256),
|
||||||
|
Pair(EDDSA_ED25519_SHA512, ECDSA_SECP256K1_SHA256),
|
||||||
|
Pair(RSA_SHA256, EDDSA_ED25519_SHA512),
|
||||||
|
Pair(SPHINCS256_SHA256, ECDSA_SECP256R1_SHA256)
|
||||||
|
)
|
||||||
|
|
||||||
|
val schemeToKeyTypes = listOf(
|
||||||
|
// By default, JKS returns SUN EC key.
|
||||||
|
Triple(ECDSA_SECP256R1_SHA256,java.security.interfaces.ECPrivateKey::class.java, org.bouncycastle.jce.interfaces.ECPrivateKey::class.java),
|
||||||
|
Triple(ECDSA_SECP256K1_SHA256,java.security.interfaces.ECPrivateKey::class.java, org.bouncycastle.jce.interfaces.ECPrivateKey::class.java),
|
||||||
|
Triple(EDDSA_ED25519_SHA512, EdDSAPrivateKey::class.java, EdDSAPrivateKey::class.java),
|
||||||
|
// By default, JKS returns SUN RSA key.
|
||||||
|
Triple(RSA_SHA256, RSAPrivateCrtKeyImpl::class.java, BCRSAPrivateCrtKey::class.java),
|
||||||
|
Triple(SPHINCS256_SHA256, BCSphincs256PrivateKey::class.java, BCSphincs256PrivateKey::class.java)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Rule
|
@Rule
|
||||||
@ -61,7 +96,11 @@ class X509UtilitiesTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `create valid self-signed CA certificate`() {
|
fun `create valid self-signed CA certificate`() {
|
||||||
val caKey = generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
|
Crypto.supportedSignatureSchemes().filter { it != COMPOSITE_KEY }.forEach { validSelfSignedCertificate(it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun validSelfSignedCertificate(signatureScheme: SignatureScheme) {
|
||||||
|
val caKey = generateKeyPair(signatureScheme)
|
||||||
val subject = X500Principal("CN=Test Cert,O=R3 Ltd,L=London,C=GB")
|
val subject = X500Principal("CN=Test Cert,O=R3 Ltd,L=London,C=GB")
|
||||||
val caCert = X509Utilities.createSelfSignedCACertificate(subject, caKey)
|
val caCert = X509Utilities.createSelfSignedCACertificate(subject, caKey)
|
||||||
assertEquals(subject, caCert.subjectX500Principal) // using our subject common name
|
assertEquals(subject, caCert.subjectX500Principal) // using our subject common name
|
||||||
@ -78,8 +117,12 @@ class X509UtilitiesTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `load and save a PEM file certificate`() {
|
fun `load and save a PEM file certificate`() {
|
||||||
|
Crypto.supportedSignatureSchemes().filter { it != COMPOSITE_KEY }.forEach { loadSavePEMCert(it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun loadSavePEMCert(signatureScheme: SignatureScheme) {
|
||||||
val tmpCertificateFile = tempFile("cacert.pem")
|
val tmpCertificateFile = tempFile("cacert.pem")
|
||||||
val caKey = generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
|
val caKey = generateKeyPair(signatureScheme)
|
||||||
val caCert = X509Utilities.createSelfSignedCACertificate(X500Principal("CN=Test Cert,O=R3 Ltd,L=London,C=GB"), caKey)
|
val caCert = X509Utilities.createSelfSignedCACertificate(X500Principal("CN=Test Cert,O=R3 Ltd,L=London,C=GB"), caKey)
|
||||||
X509Utilities.saveCertificateAsPEMFile(caCert, tmpCertificateFile)
|
X509Utilities.saveCertificateAsPEMFile(caCert, tmpCertificateFile)
|
||||||
val readCertificate = X509Utilities.loadCertificateFromPEMFile(tmpCertificateFile)
|
val readCertificate = X509Utilities.loadCertificateFromPEMFile(tmpCertificateFile)
|
||||||
@ -88,29 +131,52 @@ class X509UtilitiesTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `create valid server certificate chain`() {
|
fun `create valid server certificate chain`() {
|
||||||
val caKey = generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
|
certChainSchemeCombinations.forEach { createValidServerCertChain(it.first, it.second) }
|
||||||
val caCert = X509Utilities.createSelfSignedCACertificate(X500Principal("CN=Test CA Cert,O=R3 Ltd,L=London,C=GB"), caKey)
|
}
|
||||||
val subject = X500Principal("CN=Server Cert,O=R3 Ltd,L=London,C=GB")
|
|
||||||
val keyPair = generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
|
private fun createValidServerCertChain(signatureSchemeRoot: SignatureScheme, signatureSchemeChild: SignatureScheme) {
|
||||||
val serverCert = X509Utilities.createCertificate(CertificateType.TLS, caCert, caKey, subject, keyPair.public)
|
val (caKeyPair, caCert, _, childCert, _, childSubject)
|
||||||
assertEquals(subject, serverCert.subjectX500Principal) // using our subject common name
|
= genCaAndChildKeysCertsAndSubjects(signatureSchemeRoot, signatureSchemeChild)
|
||||||
assertEquals(caCert.issuerX500Principal, serverCert.issuerX500Principal) // Issued by our CA cert
|
assertEquals(childSubject, childCert.subjectX500Principal) // Using our subject common name.
|
||||||
serverCert.checkValidity(Date()) // throws on verification problems
|
assertEquals(caCert.issuerX500Principal, childCert.issuerX500Principal) // Issued by our CA cert.
|
||||||
serverCert.verify(caKey.public) // throws on verification problems
|
childCert.checkValidity(Date()) // Throws on verification problems.
|
||||||
serverCert.toBc().run {
|
childCert.verify(caKeyPair.public) // Throws on verification problems.
|
||||||
|
childCert.toBc().run {
|
||||||
val basicConstraints = BasicConstraints.getInstance(getExtension(Extension.basicConstraints).parsedValue)
|
val basicConstraints = BasicConstraints.getInstance(getExtension(Extension.basicConstraints).parsedValue)
|
||||||
val keyUsage = KeyUsage.getInstance(getExtension(Extension.keyUsage).parsedValue)
|
val keyUsage = KeyUsage.getInstance(getExtension(Extension.keyUsage).parsedValue)
|
||||||
assertFalse { keyUsage.hasUsages(5) } // Bit 5 == keyCertSign according to ASN.1 spec (see full comment on KeyUsage property)
|
assertFalse { keyUsage.hasUsages(5) } // Bit 5 == keyCertSign according to ASN.1 spec (see full comment on KeyUsage property).
|
||||||
assertNull(basicConstraints.pathLenConstraint) // Non-CA certificate
|
assertNull(basicConstraints.pathLenConstraint) // Non-CA certificate.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private data class CaAndChildKeysCertsAndSubjects(val caKeyPair: KeyPair,
|
||||||
|
val caCert: X509Certificate,
|
||||||
|
val childKeyPair: KeyPair,
|
||||||
|
val childCert: X509Certificate,
|
||||||
|
val caSubject: X500Principal,
|
||||||
|
val childSubject: X500Principal)
|
||||||
|
|
||||||
|
private fun genCaAndChildKeysCertsAndSubjects(signatureSchemeRoot: SignatureScheme,
|
||||||
|
signatureSchemeChild: SignatureScheme,
|
||||||
|
rootSubject: X500Principal = X500Principal("CN=Test CA Cert,O=R3 Ltd,L=London,C=GB"),
|
||||||
|
childSubject: X500Principal = X500Principal("CN=Test Child Cert,O=R3 Ltd,L=London,C=GB")): CaAndChildKeysCertsAndSubjects {
|
||||||
|
val caKeyPair = generateKeyPair(signatureSchemeRoot)
|
||||||
|
val caCert = X509Utilities.createSelfSignedCACertificate(rootSubject, caKeyPair)
|
||||||
|
val childKeyPair = generateKeyPair(signatureSchemeChild)
|
||||||
|
val childCert = X509Utilities.createCertificate(CertificateType.TLS, caCert, caKeyPair, childSubject, childKeyPair.public)
|
||||||
|
return CaAndChildKeysCertsAndSubjects(caKeyPair, caCert, childKeyPair, childCert, rootSubject, childSubject)
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `create valid server certificate chain includes CRL info`() {
|
fun `create valid server certificate chain includes CRL info`() {
|
||||||
val caKey = generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
|
certChainSchemeCombinations.forEach { createValidServerCertIncludeCRL(it.first, it.second) }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createValidServerCertIncludeCRL(signatureSchemeRoot: SignatureScheme, signatureSchemeChild: SignatureScheme) {
|
||||||
|
val caKey = generateKeyPair(signatureSchemeRoot)
|
||||||
val caCert = X509Utilities.createSelfSignedCACertificate(X500Principal("CN=Test CA Cert,O=R3 Ltd,L=London,C=GB"), caKey)
|
val caCert = X509Utilities.createSelfSignedCACertificate(X500Principal("CN=Test CA Cert,O=R3 Ltd,L=London,C=GB"), caKey)
|
||||||
val caSubjectKeyIdentifier = SubjectKeyIdentifier.getInstance(caCert.toBc().getExtension(Extension.subjectKeyIdentifier).parsedValue)
|
val caSubjectKeyIdentifier = SubjectKeyIdentifier.getInstance(caCert.toBc().getExtension(Extension.subjectKeyIdentifier).parsedValue)
|
||||||
val keyPair = generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
|
val keyPair = generateKeyPair(signatureSchemeChild)
|
||||||
val crlDistPoint = "http://test.com"
|
val crlDistPoint = "http://test.com"
|
||||||
val serverCert = X509Utilities.createCertificate(
|
val serverCert = X509Utilities.createCertificate(
|
||||||
CertificateType.TLS,
|
CertificateType.TLS,
|
||||||
@ -128,57 +194,33 @@ class X509UtilitiesTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `storing EdDSA key in java keystore`() {
|
fun `storing all supported key types in java keystore`() {
|
||||||
|
Crypto.supportedSignatureSchemes().filter { it != COMPOSITE_KEY }.forEach { storeKeyToKeystore(it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun storeKeyToKeystore(signatureScheme: SignatureScheme) {
|
||||||
val tmpKeyStore = tempFile("keystore.jks")
|
val tmpKeyStore = tempFile("keystore.jks")
|
||||||
|
|
||||||
val keyPair = generateKeyPair(EDDSA_ED25519_SHA512)
|
val keyPair = generateKeyPair(signatureScheme)
|
||||||
val testName = X500Principal("CN=Test,O=R3 Ltd,L=London,C=GB")
|
val testName = X500Principal("CN=Test,O=R3 Ltd,L=London,C=GB")
|
||||||
val selfSignCert = X509Utilities.createSelfSignedCACertificate(testName, keyPair)
|
val selfSignCert = X509Utilities.createSelfSignedCACertificate(testName, keyPair)
|
||||||
|
|
||||||
assertTrue(Arrays.equals(selfSignCert.publicKey.encoded, keyPair.public.encoded))
|
assertTrue(Arrays.equals(selfSignCert.publicKey.encoded, keyPair.public.encoded))
|
||||||
|
|
||||||
// Save the EdDSA private key with self sign cert in the keystore.
|
// Save the private key with self sign cert in the keystore.
|
||||||
val keyStore = loadOrCreateKeyStore(tmpKeyStore, "keystorepass")
|
val keyStore = loadOrCreateKeyStore(tmpKeyStore, "keystorepass")
|
||||||
keyStore.setKeyEntry("Key", keyPair.private, "password".toCharArray(), arrayOf(selfSignCert))
|
keyStore.setKeyEntry("Key", keyPair.private, "password".toCharArray(), arrayOf(selfSignCert))
|
||||||
keyStore.save(tmpKeyStore, "keystorepass")
|
keyStore.save(tmpKeyStore, "keystorepass")
|
||||||
|
|
||||||
// Load the keystore from file and make sure keys are intact.
|
// Load the keystore from file and make sure keys are intact.
|
||||||
val keyStore2 = loadOrCreateKeyStore(tmpKeyStore, "keystorepass")
|
val reloadedKeystore = loadOrCreateKeyStore(tmpKeyStore, "keystorepass")
|
||||||
val privateKey = keyStore2.getKey("Key", "password".toCharArray())
|
val reloadedPrivateKey = reloadedKeystore.getKey("Key", "password".toCharArray())
|
||||||
val pubKey = keyStore2.getCertificate("Key").publicKey
|
val reloadedPublicKey = reloadedKeystore.getCertificate("Key").publicKey
|
||||||
|
|
||||||
assertNotNull(pubKey)
|
assertNotNull(reloadedPublicKey)
|
||||||
assertNotNull(privateKey)
|
assertNotNull(reloadedPrivateKey)
|
||||||
assertEquals(keyPair.public, pubKey)
|
assertEquals(keyPair.public, reloadedPublicKey)
|
||||||
assertEquals(keyPair.private, privateKey)
|
assertEquals(keyPair.private, reloadedPrivateKey)
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `signing EdDSA key with EcDSA certificate`() {
|
|
||||||
val tmpKeyStore = tempFile("keystore.jks")
|
|
||||||
val ecDSAKey = generateKeyPair(Crypto.ECDSA_SECP256R1_SHA256)
|
|
||||||
val testName = X500Principal("CN=Test,O=R3 Ltd,L=London,C=GB")
|
|
||||||
val ecDSACert = X509Utilities.createSelfSignedCACertificate(testName, ecDSAKey)
|
|
||||||
val edDSAKeypair = generateKeyPair(EDDSA_ED25519_SHA512)
|
|
||||||
val edDSACert = X509Utilities.createCertificate(CertificateType.TLS, ecDSACert, ecDSAKey, BOB.name.x500Principal, edDSAKeypair.public)
|
|
||||||
|
|
||||||
// Save the EdDSA private key with cert chains.
|
|
||||||
val keyStore = loadOrCreateKeyStore(tmpKeyStore, "keystorepass")
|
|
||||||
keyStore.setKeyEntry("Key", edDSAKeypair.private, "password".toCharArray(), arrayOf(ecDSACert, edDSACert))
|
|
||||||
keyStore.save(tmpKeyStore, "keystorepass")
|
|
||||||
|
|
||||||
// Load the keystore from file and make sure keys are intact.
|
|
||||||
val keyStore2 = loadOrCreateKeyStore(tmpKeyStore, "keystorepass")
|
|
||||||
val privateKey = keyStore2.getKey("Key", "password".toCharArray())
|
|
||||||
val certs = keyStore2.getCertificateChain("Key")
|
|
||||||
|
|
||||||
val pubKey = certs.last().publicKey
|
|
||||||
|
|
||||||
assertEquals(2, certs.size)
|
|
||||||
assertNotNull(pubKey)
|
|
||||||
assertNotNull(privateKey)
|
|
||||||
assertEquals(edDSAKeypair.public, pubKey)
|
|
||||||
assertEquals(edDSAKeypair.private, privateKey)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -316,7 +358,17 @@ class X509UtilitiesTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `get correct private key type from Keystore`() {
|
fun `get correct private key type from Keystore`() {
|
||||||
val keyPair = generateKeyPair(Crypto.ECDSA_SECP256R1_SHA256)
|
schemeToKeyTypes.forEach { getCorrectKeyFromKeystore(it.first, it.second, it.third) }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun <U, C> getCorrectKeyFromKeystore(signatureScheme: SignatureScheme, uncastedClass: Class<U>, castedClass: Class<C>) {
|
||||||
|
val keyPair = generateKeyPair(signatureScheme)
|
||||||
|
val (keyFromKeystore, keyFromKeystoreCasted) = storeAndGetKeysFromKeystore(keyPair)
|
||||||
|
assertThat(keyFromKeystore).isInstanceOf(uncastedClass)
|
||||||
|
assertThat(keyFromKeystoreCasted).isInstanceOf(castedClass)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun storeAndGetKeysFromKeystore(keyPair: KeyPair): Pair<Key, PrivateKey> {
|
||||||
val testName = X500Principal("CN=Test,O=R3 Ltd,L=London,C=GB")
|
val testName = X500Principal("CN=Test,O=R3 Ltd,L=London,C=GB")
|
||||||
val selfSignCert = X509Utilities.createSelfSignedCACertificate(testName, keyPair)
|
val selfSignCert = X509Utilities.createSelfSignedCACertificate(testName, keyPair)
|
||||||
val keyStore = loadOrCreateKeyStore(tempFile("testKeystore.jks"), "keystorepassword")
|
val keyStore = loadOrCreateKeyStore(tempFile("testKeystore.jks"), "keystorepassword")
|
||||||
@ -324,13 +376,15 @@ class X509UtilitiesTest {
|
|||||||
|
|
||||||
val keyFromKeystore = keyStore.getKey("Key", "keypassword".toCharArray())
|
val keyFromKeystore = keyStore.getKey("Key", "keypassword".toCharArray())
|
||||||
val keyFromKeystoreCasted = keyStore.getSupportedKey("Key", "keypassword")
|
val keyFromKeystoreCasted = keyStore.getSupportedKey("Key", "keypassword")
|
||||||
|
return Pair(keyFromKeystore, keyFromKeystoreCasted)
|
||||||
assertTrue(keyFromKeystore is java.security.interfaces.ECPrivateKey) // by default JKS returns SUN EC key
|
|
||||||
assertTrue(keyFromKeystoreCasted is org.bouncycastle.jce.interfaces.ECPrivateKey)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `serialize - deserialize X509Certififcate`() {
|
fun `serialize - deserialize X509Certificate`() {
|
||||||
|
Crypto.supportedSignatureSchemes().filter { it != COMPOSITE_KEY }.forEach { serializeDeserializeX509Cert(it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun serializeDeserializeX509Cert(signatureScheme: SignatureScheme) {
|
||||||
val factory = SerializationFactoryImpl().apply { registerScheme(AMQPServerSerializationScheme()) }
|
val factory = SerializationFactoryImpl().apply { registerScheme(AMQPServerSerializationScheme()) }
|
||||||
val context = SerializationContextImpl(amqpMagic,
|
val context = SerializationContextImpl(amqpMagic,
|
||||||
javaClass.classLoader,
|
javaClass.classLoader,
|
||||||
@ -339,7 +393,7 @@ class X509UtilitiesTest {
|
|||||||
true,
|
true,
|
||||||
SerializationContext.UseCase.P2P,
|
SerializationContext.UseCase.P2P,
|
||||||
null)
|
null)
|
||||||
val expected = X509Utilities.createSelfSignedCACertificate(ALICE.name.x500Principal, Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME))
|
val expected = X509Utilities.createSelfSignedCACertificate(ALICE.name.x500Principal, generateKeyPair(signatureScheme))
|
||||||
val serialized = expected.serialize(factory, context).bytes
|
val serialized = expected.serialize(factory, context).bytes
|
||||||
val actual = serialized.deserialize<X509Certificate>(factory, context)
|
val actual = serialized.deserialize<X509Certificate>(factory, context)
|
||||||
assertEquals(expected, actual)
|
assertEquals(expected, actual)
|
||||||
@ -347,6 +401,10 @@ class X509UtilitiesTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `serialize - deserialize X509CertPath`() {
|
fun `serialize - deserialize X509CertPath`() {
|
||||||
|
Crypto.supportedSignatureSchemes().filter { it != COMPOSITE_KEY }.forEach { serializeDeserializeX509CertPath(it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun serializeDeserializeX509CertPath(signatureScheme: SignatureScheme) {
|
||||||
val factory = SerializationFactoryImpl().apply { registerScheme(AMQPServerSerializationScheme()) }
|
val factory = SerializationFactoryImpl().apply { registerScheme(AMQPServerSerializationScheme()) }
|
||||||
val context = SerializationContextImpl(
|
val context = SerializationContextImpl(
|
||||||
amqpMagic,
|
amqpMagic,
|
||||||
@ -357,7 +415,7 @@ class X509UtilitiesTest {
|
|||||||
SerializationContext.UseCase.P2P,
|
SerializationContext.UseCase.P2P,
|
||||||
null
|
null
|
||||||
)
|
)
|
||||||
val rootCAKey = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
|
val rootCAKey = generateKeyPair(signatureScheme)
|
||||||
val rootCACert = X509Utilities.createSelfSignedCACertificate(ALICE_NAME.x500Principal, rootCAKey)
|
val rootCACert = X509Utilities.createSelfSignedCACertificate(ALICE_NAME.x500Principal, rootCAKey)
|
||||||
val certificate = X509Utilities.createCertificate(CertificateType.TLS, rootCACert, rootCAKey, BOB_NAME.x500Principal, BOB.publicKey)
|
val certificate = X509Utilities.createCertificate(CertificateType.TLS, rootCACert, rootCAKey, BOB_NAME.x500Principal, BOB.publicKey)
|
||||||
val expected = X509Utilities.buildCertPath(certificate, rootCACert)
|
val expected = X509Utilities.buildCertPath(certificate, rootCACert)
|
||||||
@ -365,4 +423,33 @@ class X509UtilitiesTest {
|
|||||||
val actual: CertPath = serialized.deserialize(factory, context)
|
val actual: CertPath = serialized.deserialize(factory, context)
|
||||||
assertEquals(expected, actual)
|
assertEquals(expected, actual)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `signing a key type with another key type certificate then store and reload correctly from keystore`() {
|
||||||
|
certChainSchemeCombinations.forEach { signCertWithOtherKeyTypeAndTestKeystoreReload(it.first, it.second) }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun signCertWithOtherKeyTypeAndTestKeystoreReload(signatureSchemeRoot: SignatureScheme, signatureSchemeChild: SignatureScheme) {
|
||||||
|
val tmpKeyStore = tempFile("keystore.jks")
|
||||||
|
|
||||||
|
val (_, caCert, childKeyPair, childCert) = genCaAndChildKeysCertsAndSubjects(signatureSchemeRoot, signatureSchemeChild)
|
||||||
|
|
||||||
|
// Save the child private key with cert chains.
|
||||||
|
val keyStore = loadOrCreateKeyStore(tmpKeyStore, "keystorepass")
|
||||||
|
keyStore.setKeyEntry("Key", childKeyPair.private, "password".toCharArray(), arrayOf(caCert, childCert))
|
||||||
|
keyStore.save(tmpKeyStore, "keystorepass")
|
||||||
|
|
||||||
|
// Load the keystore from file and make sure keys are intact.
|
||||||
|
val reloadedKeystore = loadOrCreateKeyStore(tmpKeyStore, "keystorepass")
|
||||||
|
val reloadedPrivateKey = reloadedKeystore.getKey("Key", "password".toCharArray())
|
||||||
|
val reloadedCerts = reloadedKeystore.getCertificateChain("Key")
|
||||||
|
|
||||||
|
val reloadedPublicKey = reloadedCerts.last().publicKey
|
||||||
|
|
||||||
|
assertEquals(2, reloadedCerts.size)
|
||||||
|
assertNotNull(reloadedPublicKey)
|
||||||
|
assertNotNull(reloadedPrivateKey)
|
||||||
|
assertEquals(childKeyPair.public, reloadedPublicKey)
|
||||||
|
assertEquals(childKeyPair.private, reloadedPrivateKey)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user