mirror of
https://github.com/corda/corda.git
synced 2024-12-21 13:57:54 +00:00
Add support for X509Certificate and CertPath serialization
This commit is contained in:
parent
b8755ccdb2
commit
36a091dd6a
@ -188,15 +188,15 @@ object X509Utilities {
|
|||||||
* @param revocationEnabled whether revocation of certificates in the path should be checked.
|
* @param revocationEnabled whether revocation of certificates in the path should be checked.
|
||||||
*/
|
*/
|
||||||
fun createCertificatePath(rootCertAndKey: CertificateAndKeyPair,
|
fun createCertificatePath(rootCertAndKey: CertificateAndKeyPair,
|
||||||
targetCertAndKey: CertificateAndKeyPair,
|
targetCertAndKey: X509Certificate,
|
||||||
revocationEnabled: Boolean): CertPathBuilderResult {
|
revocationEnabled: Boolean): CertPathBuilderResult {
|
||||||
val intermediateCertificates = setOf(targetCertAndKey.certificate)
|
val intermediateCertificates = setOf(targetCertAndKey)
|
||||||
val certStore = CertStore.getInstance("Collection", CollectionCertStoreParameters(intermediateCertificates))
|
val certStore = CertStore.getInstance("Collection", CollectionCertStoreParameters(intermediateCertificates))
|
||||||
val certPathFactory = CertPathBuilder.getInstance("PKIX")
|
val certPathFactory = CertPathBuilder.getInstance("PKIX")
|
||||||
val trustAnchor = TrustAnchor(rootCertAndKey.certificate, null)
|
val trustAnchor = TrustAnchor(rootCertAndKey.certificate, null)
|
||||||
val certPathParameters = try {
|
val certPathParameters = try {
|
||||||
PKIXBuilderParameters(setOf(trustAnchor), X509CertSelector().apply {
|
PKIXBuilderParameters(setOf(trustAnchor), X509CertSelector().apply {
|
||||||
certificate = targetCertAndKey.certificate
|
certificate = targetCertAndKey
|
||||||
})
|
})
|
||||||
} catch (ex: InvalidAlgorithmParameterException) {
|
} catch (ex: InvalidAlgorithmParameterException) {
|
||||||
throw RuntimeException(ex)
|
throw RuntimeException(ex)
|
||||||
|
@ -26,9 +26,12 @@ import org.bouncycastle.pqc.jcajce.provider.sphincs.BCSphincs256PrivateKey
|
|||||||
import org.bouncycastle.pqc.jcajce.provider.sphincs.BCSphincs256PublicKey
|
import org.bouncycastle.pqc.jcajce.provider.sphincs.BCSphincs256PublicKey
|
||||||
import org.objenesis.strategy.StdInstantiatorStrategy
|
import org.objenesis.strategy.StdInstantiatorStrategy
|
||||||
import org.slf4j.Logger
|
import org.slf4j.Logger
|
||||||
|
import sun.security.provider.certpath.X509CertPath
|
||||||
import java.io.BufferedInputStream
|
import java.io.BufferedInputStream
|
||||||
import java.io.FileInputStream
|
import java.io.FileInputStream
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
|
import java.security.cert.CertPath
|
||||||
|
import java.security.cert.X509Certificate
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
object DefaultKryoCustomizer {
|
object DefaultKryoCustomizer {
|
||||||
@ -97,6 +100,12 @@ object DefaultKryoCustomizer {
|
|||||||
// Note that return type should be specifically set to InputStream, otherwise it may not work, i.e. val aStream : InputStream = HashCheckingStream(...).
|
// Note that return type should be specifically set to InputStream, otherwise it may not work, i.e. val aStream : InputStream = HashCheckingStream(...).
|
||||||
addDefaultSerializer(InputStream::class.java, InputStreamSerializer)
|
addDefaultSerializer(InputStream::class.java, InputStreamSerializer)
|
||||||
|
|
||||||
|
register(CertPath::class.java, CertPathSerializer)
|
||||||
|
register(X509CertPath::class.java, CertPathSerializer)
|
||||||
|
// TODO: We shouldn't need to serialize raw certificates, and if we do then we need a cleaner solution
|
||||||
|
// than this mess.
|
||||||
|
val x509CertObjectClazz = Class.forName("org.bouncycastle.jcajce.provider.asymmetric.x509.X509CertificateObject")
|
||||||
|
register(x509CertObjectClazz, X509CertificateSerializer)
|
||||||
register(X500Name::class.java, X500NameSerializer)
|
register(X500Name::class.java, X500NameSerializer)
|
||||||
|
|
||||||
register(BCECPrivateKey::class.java, PrivateKeySerializer)
|
register(BCECPrivateKey::class.java, PrivateKeySerializer)
|
||||||
|
@ -30,6 +30,9 @@ import java.nio.file.Files
|
|||||||
import java.nio.file.Path
|
import java.nio.file.Path
|
||||||
import java.security.PrivateKey
|
import java.security.PrivateKey
|
||||||
import java.security.PublicKey
|
import java.security.PublicKey
|
||||||
|
import java.security.cert.CertPath
|
||||||
|
import java.security.cert.CertificateFactory
|
||||||
|
import java.security.cert.X509Certificate
|
||||||
import java.security.spec.InvalidKeySpecException
|
import java.security.spec.InvalidKeySpecException
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
import java.util.*
|
import java.util.*
|
||||||
@ -613,6 +616,36 @@ object X500NameSerializer : Serializer<X500Name>() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For serialising an [CertPath] in an X.500 standard format.
|
||||||
|
*/
|
||||||
|
@ThreadSafe
|
||||||
|
object CertPathSerializer : Serializer<CertPath>() {
|
||||||
|
val factory = CertificateFactory.getInstance("X.509")
|
||||||
|
override fun read(kryo: Kryo, input: Input, type: Class<CertPath>): CertPath {
|
||||||
|
return factory.generateCertPath(input)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun write(kryo: Kryo, output: Output, obj: CertPath) {
|
||||||
|
output.writeBytes(obj.encoded)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For serialising an [CX509Certificate] in an X.500 standard format.
|
||||||
|
*/
|
||||||
|
@ThreadSafe
|
||||||
|
object X509CertificateSerializer : Serializer<X509Certificate>() {
|
||||||
|
val factory = CertificateFactory.getInstance("X.509")
|
||||||
|
override fun read(kryo: Kryo, input: Input, type: Class<X509Certificate>): X509Certificate {
|
||||||
|
return factory.generateCertificate(input) as X509Certificate
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun write(kryo: Kryo, output: Output, obj: X509Certificate) {
|
||||||
|
output.writeBytes(obj.encoded)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class KryoPoolWithContext(val baseKryoPool: KryoPool, val contextKey: Any, val context: Any) : KryoPool {
|
class KryoPoolWithContext(val baseKryoPool: KryoPool, val contextKey: Any, val context: Any) : KryoPool {
|
||||||
override fun <T : Any?> run(callback: KryoCallback<T>): T {
|
override fun <T : Any?> run(callback: KryoCallback<T>): T {
|
||||||
val kryo = borrow()
|
val kryo = borrow()
|
||||||
|
@ -3,8 +3,11 @@ package net.corda.core.serialization
|
|||||||
import com.esotericsoftware.kryo.Kryo
|
import com.esotericsoftware.kryo.Kryo
|
||||||
import com.google.common.primitives.Ints
|
import com.google.common.primitives.Ints
|
||||||
import net.corda.core.crypto.*
|
import net.corda.core.crypto.*
|
||||||
|
import net.corda.core.utilities.ALICE
|
||||||
|
import net.corda.core.utilities.BOB
|
||||||
import net.corda.node.services.messaging.Ack
|
import net.corda.node.services.messaging.Ack
|
||||||
import net.corda.node.services.persistence.NodeAttachmentService
|
import net.corda.node.services.persistence.NodeAttachmentService
|
||||||
|
import net.corda.testing.BOB_PUBKEY
|
||||||
import org.assertj.core.api.Assertions.assertThat
|
import org.assertj.core.api.Assertions.assertThat
|
||||||
import org.assertj.core.api.Assertions.assertThatThrownBy
|
import org.assertj.core.api.Assertions.assertThatThrownBy
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
@ -12,6 +15,8 @@ import org.junit.Test
|
|||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
import java.io.ByteArrayInputStream
|
import java.io.ByteArrayInputStream
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
|
import java.security.cert.CertPath
|
||||||
|
import java.security.cert.X509Certificate
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
@ -136,6 +141,24 @@ class KryoTests {
|
|||||||
assertEquals(-1, readRubbishStream.read())
|
assertEquals(-1, readRubbishStream.read())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `serialize - deserialize X509Certififcate`() {
|
||||||
|
val expected = X509Utilities.createSelfSignedCACert(ALICE.name).certificate
|
||||||
|
val serialized = expected.serialize(kryo).bytes
|
||||||
|
val actual: X509Certificate = serialized.deserialize(kryo)
|
||||||
|
assertEquals(expected, actual)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `serialize - deserialize X509CertPath`() {
|
||||||
|
val rootCA = X509Utilities.createSelfSignedCACert(ALICE.name)
|
||||||
|
val certificate = X509Utilities.createTlsServerCert(BOB.name, BOB_PUBKEY, rootCA, emptyList(), emptyList())
|
||||||
|
val expected = X509Utilities.createCertificatePath(rootCA, certificate, false).certPath
|
||||||
|
val serialized = expected.serialize(kryo).bytes
|
||||||
|
val actual: CertPath = serialized.deserialize(kryo)
|
||||||
|
assertEquals(expected, actual)
|
||||||
|
}
|
||||||
|
|
||||||
@CordaSerializable
|
@CordaSerializable
|
||||||
private data class Person(val name: String, val birthday: Instant?)
|
private data class Person(val name: String, val birthday: Instant?)
|
||||||
|
|
||||||
|
@ -87,10 +87,10 @@ class InMemoryIdentityServiceTests {
|
|||||||
fun `assert ownership`() {
|
fun `assert ownership`() {
|
||||||
val aliceRootCertAndKey = X509Utilities.createSelfSignedCACert(ALICE.name)
|
val aliceRootCertAndKey = X509Utilities.createSelfSignedCACert(ALICE.name)
|
||||||
val aliceTxCertAndKey = X509Utilities.createIntermediateCert(ALICE.name, aliceRootCertAndKey)
|
val aliceTxCertAndKey = X509Utilities.createIntermediateCert(ALICE.name, aliceRootCertAndKey)
|
||||||
val aliceCertPath = X509Utilities.createCertificatePath(aliceRootCertAndKey, aliceTxCertAndKey, false).certPath
|
val aliceCertPath = X509Utilities.createCertificatePath(aliceRootCertAndKey, aliceTxCertAndKey.certificate, false).certPath
|
||||||
val bobRootCertAndKey = X509Utilities.createSelfSignedCACert(BOB.name)
|
val bobRootCertAndKey = X509Utilities.createSelfSignedCACert(BOB.name)
|
||||||
val bobTxCertAndKey = X509Utilities.createIntermediateCert(BOB.name, bobRootCertAndKey)
|
val bobTxCertAndKey = X509Utilities.createIntermediateCert(BOB.name, bobRootCertAndKey)
|
||||||
val bobCertPath = X509Utilities.createCertificatePath(bobRootCertAndKey, bobTxCertAndKey, false).certPath
|
val bobCertPath = X509Utilities.createCertificatePath(bobRootCertAndKey, bobTxCertAndKey.certificate, false).certPath
|
||||||
val service = InMemoryIdentityService()
|
val service = InMemoryIdentityService()
|
||||||
val alice = Party(aliceRootCertAndKey)
|
val alice = Party(aliceRootCertAndKey)
|
||||||
val anonymousAlice = AnonymousParty(aliceTxCertAndKey.keyPair.public)
|
val anonymousAlice = AnonymousParty(aliceTxCertAndKey.keyPair.public)
|
||||||
|
Loading…
Reference in New Issue
Block a user