mirror of
https://github.com/corda/corda.git
synced 2024-12-27 08:22:35 +00:00
Merge pull request #549 from corda/andr3ej-provider-setup-ent
ENT-1439 Refactor Provider setup
This commit is contained in:
commit
ca586eda18
@ -10,9 +10,9 @@
|
||||
|
||||
package net.corda.core.crypto
|
||||
|
||||
import net.corda.core.crypto.CordaObjectIdentifier.COMPOSITE_KEY
|
||||
import net.corda.core.crypto.CordaObjectIdentifier.COMPOSITE_SIGNATURE
|
||||
import org.bouncycastle.asn1.ASN1ObjectIdentifier
|
||||
import java.security.AccessController
|
||||
import java.security.PrivilegedAction
|
||||
import java.security.Provider
|
||||
|
||||
class CordaSecurityProvider : Provider(PROVIDER_NAME, 0.1, "$PROVIDER_NAME security provider wrapper") {
|
||||
@ -21,20 +21,12 @@ class CordaSecurityProvider : Provider(PROVIDER_NAME, 0.1, "$PROVIDER_NAME secur
|
||||
}
|
||||
|
||||
init {
|
||||
AccessController.doPrivileged(PrivilegedAction<Unit> { setup() })
|
||||
}
|
||||
|
||||
private fun setup() {
|
||||
put("KeyFactory.${CompositeKey.KEY_ALGORITHM}", "net.corda.core.crypto.CompositeKeyFactory")
|
||||
put("Signature.${CompositeSignature.SIGNATURE_ALGORITHM}", "net.corda.core.crypto.CompositeSignature")
|
||||
|
||||
val compositeKeyOID = CordaObjectIdentifier.COMPOSITE_KEY.id
|
||||
put("Alg.Alias.KeyFactory.$compositeKeyOID", CompositeKey.KEY_ALGORITHM)
|
||||
put("Alg.Alias.KeyFactory.OID.$compositeKeyOID", CompositeKey.KEY_ALGORITHM)
|
||||
|
||||
val compositeSignatureOID = CordaObjectIdentifier.COMPOSITE_SIGNATURE.id
|
||||
put("Alg.Alias.Signature.$compositeSignatureOID", CompositeSignature.SIGNATURE_ALGORITHM)
|
||||
put("Alg.Alias.Signature.OID.$compositeSignatureOID", CompositeSignature.SIGNATURE_ALGORITHM)
|
||||
put("KeyFactory.${CompositeKey.KEY_ALGORITHM}", CompositeKeyFactory::class.java.name)
|
||||
put("Signature.${CompositeSignature.SIGNATURE_ALGORITHM}", CompositeSignature::class.java.name)
|
||||
put("Alg.Alias.KeyFactory.$COMPOSITE_KEY", CompositeKey.KEY_ALGORITHM)
|
||||
put("Alg.Alias.KeyFactory.OID.$COMPOSITE_KEY", CompositeKey.KEY_ALGORITHM)
|
||||
put("Alg.Alias.Signature.$COMPOSITE_SIGNATURE", CompositeSignature.SIGNATURE_ALGORITHM)
|
||||
put("Alg.Alias.Signature.OID.$COMPOSITE_SIGNATURE", CompositeSignature.SIGNATURE_ALGORITHM)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -10,19 +10,17 @@
|
||||
|
||||
package net.corda.core.crypto
|
||||
|
||||
import net.corda.core.internal.X509EdDSAEngine
|
||||
import net.corda.core.crypto.internal.*
|
||||
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.math.GroupElement
|
||||
import net.i2p.crypto.eddsa.spec.EdDSANamedCurveSpec
|
||||
import net.i2p.crypto.eddsa.spec.EdDSANamedCurveTable
|
||||
import net.i2p.crypto.eddsa.spec.EdDSAPrivateKeySpec
|
||||
import net.i2p.crypto.eddsa.spec.EdDSAPublicKeySpec
|
||||
import org.bouncycastle.asn1.ASN1Integer
|
||||
import org.bouncycastle.asn1.ASN1ObjectIdentifier
|
||||
import org.bouncycastle.asn1.DERNull
|
||||
import org.bouncycastle.asn1.DLSequence
|
||||
import org.bouncycastle.asn1.bc.BCObjectIdentifiers
|
||||
@ -37,7 +35,6 @@ import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPrivateKey
|
||||
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey
|
||||
import org.bouncycastle.jcajce.provider.asymmetric.rsa.BCRSAPrivateKey
|
||||
import org.bouncycastle.jcajce.provider.asymmetric.rsa.BCRSAPublicKey
|
||||
import org.bouncycastle.jcajce.provider.util.AsymmetricKeyInfoConverter
|
||||
import org.bouncycastle.jce.ECNamedCurveTable
|
||||
import org.bouncycastle.jce.provider.BouncyCastleProvider
|
||||
import org.bouncycastle.jce.spec.ECNamedCurveParameterSpec
|
||||
@ -47,7 +44,6 @@ import org.bouncycastle.jce.spec.ECPublicKeySpec
|
||||
import org.bouncycastle.math.ec.ECConstants
|
||||
import org.bouncycastle.math.ec.FixedPointCombMultiplier
|
||||
import org.bouncycastle.math.ec.WNafUtil
|
||||
import org.bouncycastle.pqc.jcajce.provider.BouncyCastlePQCProvider
|
||||
import org.bouncycastle.pqc.jcajce.provider.sphincs.BCSphincs256PrivateKey
|
||||
import org.bouncycastle.pqc.jcajce.provider.sphincs.BCSphincs256PublicKey
|
||||
import org.bouncycastle.pqc.jcajce.spec.SPHINCS256KeyGenParameterSpec
|
||||
@ -84,7 +80,7 @@ object Crypto {
|
||||
"RSA_SHA256",
|
||||
AlgorithmIdentifier(PKCSObjectIdentifiers.sha256WithRSAEncryption, null),
|
||||
listOf(AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption, null)),
|
||||
BouncyCastleProvider.PROVIDER_NAME,
|
||||
cordaBouncyCastleProvider.name,
|
||||
"RSA",
|
||||
"SHA256WITHRSA",
|
||||
null,
|
||||
@ -99,7 +95,7 @@ object Crypto {
|
||||
"ECDSA_SECP256K1_SHA256",
|
||||
AlgorithmIdentifier(X9ObjectIdentifiers.ecdsa_with_SHA256, SECObjectIdentifiers.secp256k1),
|
||||
listOf(AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, SECObjectIdentifiers.secp256k1)),
|
||||
BouncyCastleProvider.PROVIDER_NAME,
|
||||
cordaBouncyCastleProvider.name,
|
||||
"ECDSA",
|
||||
"SHA256withECDSA",
|
||||
ECNamedCurveTable.getParameterSpec("secp256k1"),
|
||||
@ -114,7 +110,7 @@ object Crypto {
|
||||
"ECDSA_SECP256R1_SHA256",
|
||||
AlgorithmIdentifier(X9ObjectIdentifiers.ecdsa_with_SHA256, SECObjectIdentifiers.secp256r1),
|
||||
listOf(AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, SECObjectIdentifiers.secp256r1)),
|
||||
BouncyCastleProvider.PROVIDER_NAME,
|
||||
cordaBouncyCastleProvider.name,
|
||||
"ECDSA",
|
||||
"SHA256withECDSA",
|
||||
ECNamedCurveTable.getParameterSpec("secp256r1"),
|
||||
@ -128,14 +124,13 @@ object Crypto {
|
||||
* Not to be confused with the EdDSA variants, Ed25519ctx and Ed25519ph.
|
||||
*/
|
||||
@JvmField
|
||||
val EDDSA_ED25519_SHA512 = SignatureScheme(
|
||||
val EDDSA_ED25519_SHA512: SignatureScheme = SignatureScheme(
|
||||
4,
|
||||
"EDDSA_ED25519_SHA512",
|
||||
// OID taken from https://tools.ietf.org/html/draft-ietf-curdle-pkix-00
|
||||
AlgorithmIdentifier(ASN1ObjectIdentifier("1.3.101.112"), null),
|
||||
AlgorithmIdentifier(`id-Curve25519ph`, null),
|
||||
emptyList(), // Both keys and the signature scheme use the same OID in i2p library.
|
||||
// We added EdDSA to bouncy castle for certificate signing.
|
||||
BouncyCastleProvider.PROVIDER_NAME,
|
||||
cordaBouncyCastleProvider.name,
|
||||
"1.3.101.112",
|
||||
EdDSAEngine.SIGNATURE_ALGORITHM,
|
||||
EdDSANamedCurveTable.getByName("ED25519"),
|
||||
@ -158,7 +153,7 @@ object Crypto {
|
||||
"SPHINCS-256_SHA512",
|
||||
AlgorithmIdentifier(BCObjectIdentifiers.sphincs256_with_SHA512, DLSequence(arrayOf(ASN1Integer(0), SHA512_256))),
|
||||
listOf(AlgorithmIdentifier(BCObjectIdentifiers.sphincs256, DLSequence(arrayOf(ASN1Integer(0), SHA512_256)))),
|
||||
"BCPQC",
|
||||
bouncyCastlePQCProvider.name,
|
||||
"SPHINCS256",
|
||||
"SHA512WITHSPHINCS256",
|
||||
SPHINCS256KeyGenParameterSpec(SPHINCS256KeyGenParameterSpec.SHA512_256),
|
||||
@ -175,7 +170,7 @@ object Crypto {
|
||||
"COMPOSITE",
|
||||
AlgorithmIdentifier(CordaObjectIdentifier.COMPOSITE_KEY),
|
||||
emptyList(),
|
||||
CordaSecurityProvider.PROVIDER_NAME,
|
||||
cordaSecurityProvider.name,
|
||||
CompositeKey.KEY_ALGORITHM,
|
||||
CompositeSignature.SIGNATURE_ALGORITHM,
|
||||
null,
|
||||
@ -209,22 +204,6 @@ object Crypto {
|
||||
+ signatureSchemeMap.values.map { Pair(it.signatureOID, it) })
|
||||
.toMap()
|
||||
|
||||
// This map is required to defend against users that forcibly call Security.addProvider / Security.removeProvider
|
||||
// that could cause unexpected and suspicious behaviour.
|
||||
// i.e. if someone removes a Provider and then he/she adds a new one with the same name.
|
||||
// The val is private to avoid any harmful state changes.
|
||||
private val providerMap: Map<String, Provider> = mapOf(
|
||||
BouncyCastleProvider.PROVIDER_NAME to getBouncyCastleProvider(),
|
||||
CordaSecurityProvider.PROVIDER_NAME to CordaSecurityProvider(),
|
||||
"BCPQC" to BouncyCastlePQCProvider()) // Unfortunately, provider's name is not final in BouncyCastlePQCProvider, so we explicitly set it.
|
||||
|
||||
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))
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun supportedSignatureSchemes(): List<SignatureScheme> = ArrayList(signatureSchemeMap.values)
|
||||
|
||||
@ -233,13 +212,6 @@ object Crypto {
|
||||
return providerMap[name] ?: throw IllegalArgumentException("Unrecognised provider: $name")
|
||||
}
|
||||
|
||||
init {
|
||||
// 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.
|
||||
Security.addProvider(getBouncyCastleProvider())
|
||||
Security.addProvider(CordaSecurityProvider())
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalise an algorithm identifier by converting [DERNull] parameters into a Kotlin null value.
|
||||
*/
|
||||
@ -886,7 +858,7 @@ object Crypto {
|
||||
// Compute the HMAC-SHA512 using a privateKey as the MAC_key and a seed ByteArray.
|
||||
private fun deriveHMAC(privateKey: PrivateKey, seed: ByteArray): ByteArray {
|
||||
// Compute hmac(privateKey, seed).
|
||||
val mac = Mac.getInstance("HmacSHA512", providerMap[BouncyCastleProvider.PROVIDER_NAME])
|
||||
val mac = Mac.getInstance("HmacSHA512", cordaBouncyCastleProvider)
|
||||
val keyData = when (privateKey) {
|
||||
is BCECPrivateKey -> privateKey.d.toByteArray()
|
||||
is EdDSAPrivateKey -> privateKey.geta()
|
||||
@ -897,16 +869,6 @@ object Crypto {
|
||||
return mac.doFinal(seed)
|
||||
}
|
||||
|
||||
private class KeyInfoConverter(val signatureScheme: SignatureScheme) : AsymmetricKeyInfoConverter {
|
||||
override fun generatePublic(keyInfo: SubjectPublicKeyInfo?): PublicKey? {
|
||||
return keyInfo?.let { decodePublicKey(signatureScheme, it.encoded) }
|
||||
}
|
||||
|
||||
override fun generatePrivate(keyInfo: PrivateKeyInfo?): PrivateKey? {
|
||||
return keyInfo?.let { decodePrivateKey(signatureScheme, it.encoded) }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a point's coordinates are on the expected curve to avoid certain types of ECC attacks.
|
||||
* Point-at-infinity is not permitted as well.
|
||||
|
@ -13,13 +13,13 @@
|
||||
package net.corda.core.crypto
|
||||
|
||||
import net.corda.core.contracts.PrivacySalt
|
||||
import net.corda.core.crypto.internal.platformSecureRandomFactory
|
||||
import net.corda.core.serialization.SerializationDefaults
|
||||
import net.corda.core.serialization.serialize
|
||||
import net.corda.core.utilities.OpaqueBytes
|
||||
import net.corda.core.utilities.toBase58
|
||||
import net.corda.core.utilities.toSHA256Bytes
|
||||
import java.math.BigInteger
|
||||
import net.corda.core.utilities.SgxSupport
|
||||
import java.nio.ByteBuffer
|
||||
import java.security.*
|
||||
|
||||
@ -203,14 +203,6 @@ private class DummySecureRandomSpi : SecureRandomSpi() {
|
||||
}
|
||||
object DummySecureRandom : SecureRandom(DummySecureRandomSpi(), null)
|
||||
|
||||
private val _newSecureRandom: () -> SecureRandom by lazy {
|
||||
when {
|
||||
SgxSupport.isInsideEnclave -> { { DummySecureRandom } }
|
||||
System.getProperty("os.name") == "Linux" -> { { SecureRandom.getInstance("NativePRNGNonBlocking") } }
|
||||
else -> { { SecureRandom.getInstanceStrong() } }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an instance of [SecureRandom] to avoid blocking, due to waiting for additional entropy, when possible.
|
||||
* In this version, the NativePRNGNonBlocking is exclusively used on Linux OS to utilize dev/urandom because in high traffic
|
||||
@ -230,7 +222,7 @@ private val _newSecureRandom: () -> SecureRandom by lazy {
|
||||
* which should never happen and suggests an unusual JVM or non-standard Java library.
|
||||
*/
|
||||
@Throws(NoSuchAlgorithmException::class)
|
||||
fun newSecureRandom(): SecureRandom = _newSecureRandom()
|
||||
fun newSecureRandom(): SecureRandom = platformSecureRandomFactory()
|
||||
|
||||
/**
|
||||
* Returns a random positive non-zero long generated using a secure RNG. This function sacrifies a bit of entropy in order
|
||||
|
@ -0,0 +1,56 @@
|
||||
package net.corda.core.crypto.internal
|
||||
|
||||
import net.corda.core.crypto.CordaSecurityProvider
|
||||
import net.corda.core.crypto.Crypto.EDDSA_ED25519_SHA512
|
||||
import net.corda.core.crypto.Crypto.decodePrivateKey
|
||||
import net.corda.core.crypto.Crypto.decodePublicKey
|
||||
import net.corda.core.crypto.DummySecureRandom
|
||||
import net.corda.core.internal.X509EdDSAEngine
|
||||
import net.corda.core.utilities.SgxSupport
|
||||
import net.i2p.crypto.eddsa.EdDSAEngine
|
||||
import net.i2p.crypto.eddsa.EdDSASecurityProvider
|
||||
import org.apache.commons.lang.SystemUtils
|
||||
import org.bouncycastle.asn1.ASN1ObjectIdentifier
|
||||
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo
|
||||
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo
|
||||
import org.bouncycastle.jcajce.provider.util.AsymmetricKeyInfoConverter
|
||||
import org.bouncycastle.jce.provider.BouncyCastleProvider
|
||||
import org.bouncycastle.pqc.jcajce.provider.BouncyCastlePQCProvider
|
||||
import java.security.SecureRandom
|
||||
import java.security.Security
|
||||
|
||||
internal val cordaSecurityProvider = CordaSecurityProvider().also {
|
||||
Security.insertProviderAt(it, 1) // The position is 1-based.
|
||||
}
|
||||
// OID taken from https://tools.ietf.org/html/draft-ietf-curdle-pkix-00
|
||||
internal val `id-Curve25519ph` = ASN1ObjectIdentifier("1.3.101.112")
|
||||
internal val cordaBouncyCastleProvider = BouncyCastleProvider().apply {
|
||||
putAll(EdDSASecurityProvider())
|
||||
// Override the normal EdDSA engine with one which can handle X509 keys.
|
||||
put("Signature.${EdDSAEngine.SIGNATURE_ALGORITHM}", X509EdDSAEngine::class.java.name)
|
||||
addKeyInfoConverter(`id-Curve25519ph`, object : AsymmetricKeyInfoConverter {
|
||||
override fun generatePublic(keyInfo: SubjectPublicKeyInfo) = decodePublicKey(EDDSA_ED25519_SHA512, keyInfo.encoded)
|
||||
override fun generatePrivate(keyInfo: PrivateKeyInfo) = decodePrivateKey(EDDSA_ED25519_SHA512, keyInfo.encoded)
|
||||
})
|
||||
}.also {
|
||||
// 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.
|
||||
Security.addProvider(it)
|
||||
}
|
||||
internal val bouncyCastlePQCProvider = BouncyCastlePQCProvider().apply {
|
||||
require(name == "BCPQC") // The constant it comes from is not final.
|
||||
}
|
||||
// This map is required to defend against users that forcibly call Security.addProvider / Security.removeProvider
|
||||
// that could cause unexpected and suspicious behaviour.
|
||||
// i.e. if someone removes a Provider and then he/she adds a new one with the same name.
|
||||
// The val is private to avoid any harmful state changes.
|
||||
internal val providerMap = listOf(cordaBouncyCastleProvider, cordaSecurityProvider, bouncyCastlePQCProvider).map { it.name to it }.toMap()
|
||||
internal val platformSecureRandomFactory: () -> SecureRandom = when {
|
||||
SgxSupport.isInsideEnclave -> {
|
||||
{ DummySecureRandom }
|
||||
}
|
||||
SystemUtils.IS_OS_LINUX -> {
|
||||
{ SecureRandom.getInstance("NativePRNGNonBlocking") }
|
||||
}
|
||||
else -> SecureRandom::getInstanceStrong
|
||||
}
|
@ -13,10 +13,13 @@
|
||||
|
||||
package net.corda.node
|
||||
|
||||
import net.corda.core.crypto.CordaSecurityProvider
|
||||
import net.corda.core.crypto.Crypto
|
||||
import kotlin.system.exitProcess
|
||||
import net.corda.node.internal.EnterpriseNode
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
Crypto.findProvider(CordaSecurityProvider.PROVIDER_NAME) // Install our SecureRandom before e.g. UUID asks for one.
|
||||
// Pass the arguments to the Node factory. In the Enterprise edition, this line is modified to point to a subclass.
|
||||
// It will exit the process in case of startup failure and is not intended to be used by embedders. If you want
|
||||
// to embed Node in your own container, instantiate it directly and set up the configuration objects yourself.
|
||||
|
Loading…
Reference in New Issue
Block a user