mirror of
https://github.com/corda/corda.git
synced 2025-01-18 02:39:51 +00:00
CORDA-579: Add EdDSA engine that understands X.509 keys (#1540)
* Add EdDSA engine that understands X.509 keys * Add test for Certificate serialization * Address PR comments from Kostas
This commit is contained in:
parent
1d6bd85f8a
commit
49a70cdbd6
@ -1,10 +1,7 @@
|
||||
package net.corda.core.crypto
|
||||
|
||||
import net.corda.core.serialization.serialize
|
||||
import net.i2p.crypto.eddsa.EdDSAEngine
|
||||
import net.i2p.crypto.eddsa.EdDSAPrivateKey
|
||||
import net.i2p.crypto.eddsa.EdDSAPublicKey
|
||||
import net.i2p.crypto.eddsa.EdDSASecurityProvider
|
||||
import net.i2p.crypto.eddsa.*
|
||||
import net.i2p.crypto.eddsa.math.GroupElement
|
||||
import net.i2p.crypto.eddsa.spec.EdDSANamedCurveSpec
|
||||
import net.i2p.crypto.eddsa.spec.EdDSANamedCurveTable
|
||||
@ -41,6 +38,8 @@ import org.bouncycastle.pqc.jcajce.provider.sphincs.BCSphincs256PublicKey
|
||||
import org.bouncycastle.pqc.jcajce.spec.SPHINCS256KeyGenParameterSpec
|
||||
import java.math.BigInteger
|
||||
import java.security.*
|
||||
import java.security.KeyFactory
|
||||
import java.security.KeyPairGenerator
|
||||
import java.security.spec.InvalidKeySpecException
|
||||
import java.security.spec.PKCS8EncodedKeySpec
|
||||
import java.security.spec.X509EncodedKeySpec
|
||||
@ -200,6 +199,8 @@ object Crypto {
|
||||
|
||||
private fun getBouncyCastleProvider() = BouncyCastleProvider().apply {
|
||||
putAll(EdDSASecurityProvider())
|
||||
// Override the normal EdDSA engine with one which can handle X509 keys.
|
||||
put("Signature.${EdDSAEngine.SIGNATURE_ALGORITHM}", X509EdDSAEngine::class.qualifiedName)
|
||||
addKeyInfoConverter(EDDSA_ED25519_SHA512.signatureOID.algorithm, KeyInfoConverter(EDDSA_ED25519_SHA512))
|
||||
}
|
||||
|
||||
|
48
core/src/main/kotlin/net/i2p/crypto/eddsa/X509EdDSAEngine.kt
Normal file
48
core/src/main/kotlin/net/i2p/crypto/eddsa/X509EdDSAEngine.kt
Normal file
@ -0,0 +1,48 @@
|
||||
package net.i2p.crypto.eddsa
|
||||
|
||||
import java.security.*
|
||||
import java.security.spec.AlgorithmParameterSpec
|
||||
import java.security.spec.X509EncodedKeySpec
|
||||
|
||||
/**
|
||||
* Wrapper around [EdDSAEngine] which can intelligently rewrite X509Keys to a [EdDSAPublicKey]. This is a temporary
|
||||
* solution until this is integrated upstream and/or a custom certificate factory implemented to force the correct
|
||||
* key type. Only intercepts public keys passed into [engineInitVerify], as there is no equivalent issue with private
|
||||
* keys.
|
||||
*/
|
||||
class X509EdDSAEngine : Signature {
|
||||
private val engine: EdDSAEngine
|
||||
|
||||
constructor() : super(EdDSAEngine.SIGNATURE_ALGORITHM) {
|
||||
engine = EdDSAEngine()
|
||||
}
|
||||
constructor(digest: MessageDigest) : super(EdDSAEngine.SIGNATURE_ALGORITHM) {
|
||||
engine = EdDSAEngine(digest)
|
||||
}
|
||||
|
||||
override fun engineInitSign(privateKey: PrivateKey) = engine.engineInitSign(privateKey)
|
||||
override fun engineInitVerify(publicKey: PublicKey) {
|
||||
val parsedKey = if (publicKey is sun.security.x509.X509Key) {
|
||||
EdDSAPublicKey(X509EncodedKeySpec(publicKey.encoded))
|
||||
} else {
|
||||
publicKey
|
||||
}
|
||||
engine.engineInitVerify(parsedKey)
|
||||
}
|
||||
|
||||
override fun engineVerify(sigBytes: ByteArray): Boolean = engine.engineVerify(sigBytes)
|
||||
override fun engineSign(): ByteArray = engine.engineSign()
|
||||
override fun engineUpdate(b: Byte) = engine.engineUpdate(b)
|
||||
override fun engineUpdate(b: ByteArray, off: Int, len: Int) = engine.engineUpdate(b, off, len)
|
||||
override fun engineGetParameters(): AlgorithmParameters {
|
||||
val method = engine.javaClass.getMethod("engineGetParameters")
|
||||
return method.invoke(engine) as AlgorithmParameters
|
||||
}
|
||||
override fun engineSetParameter(params: AlgorithmParameterSpec) = engine.setParameter(params)
|
||||
override fun engineGetParameter(param: String): Any = engine.engineGetParameter(param)
|
||||
override fun engineSetParameter(param: String, value: Any?) = engine.engineSetParameter(param, value)
|
||||
override fun engineInitSign(privateKey: PrivateKey, random: SecureRandom) {
|
||||
val method = engine.javaClass.getMethod("engineInitSign", PrivateKey::class.java, SecureRandom::class.java)
|
||||
method.invoke(engine, privateKey, random)
|
||||
}
|
||||
}
|
@ -1,13 +1,18 @@
|
||||
package net.corda.core.identity
|
||||
|
||||
import net.corda.core.crypto.entropyToKeyPair
|
||||
import net.corda.core.internal.read
|
||||
import net.corda.core.serialization.deserialize
|
||||
import net.corda.core.serialization.serialize
|
||||
import net.corda.node.utilities.KEYSTORE_TYPE
|
||||
import net.corda.node.utilities.save
|
||||
import net.corda.testing.getTestPartyAndCertificate
|
||||
import net.corda.testing.withTestSerialization
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.junit.Test
|
||||
import java.io.File
|
||||
import java.math.BigInteger
|
||||
import java.security.KeyStore
|
||||
|
||||
class PartyAndCertificateTest {
|
||||
@Test
|
||||
@ -22,4 +27,26 @@ class PartyAndCertificateTest {
|
||||
assertThat(copy.certificate).isEqualTo(original.certificate)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `jdk serialization`() {
|
||||
withTestSerialization {
|
||||
val identity = getTestPartyAndCertificate(Party(
|
||||
CordaX500Name(organisation = "Test Corp", locality = "Madrid", country = "ES"),
|
||||
entropyToKeyPair(BigInteger.valueOf(83)).public))
|
||||
val original = identity.certificate
|
||||
val storePassword = "test"
|
||||
val keyStoreFilePath = File.createTempFile("serialization_test", "jks").toPath()
|
||||
var keyStore = KeyStore.getInstance(KEYSTORE_TYPE)
|
||||
keyStore.load(null, storePassword.toCharArray())
|
||||
keyStore.setCertificateEntry(identity.name.toString(), original)
|
||||
keyStore.save(keyStoreFilePath, storePassword)
|
||||
|
||||
// Load the key store back in again
|
||||
keyStore = KeyStore.getInstance(KEYSTORE_TYPE)
|
||||
keyStoreFilePath.read { keyStore.load(it, storePassword.toCharArray()) }
|
||||
val copy = keyStore.getCertificate(identity.name.toString())
|
||||
assertThat(copy).isEqualTo(original) // .isNotSameAs(original)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user