mirror of
https://github.com/corda/corda.git
synced 2024-12-18 12:46:29 +00:00
Merge pull request #7675 from corda/shams-remove-i2p
ENT-11101: Fix all crypto issues introduced by Java 17 upgrade
This commit is contained in:
commit
6bdad94236
@ -8290,11 +8290,6 @@ public static final class net.corda.core.utilities.ProgressTracker$UNSTARTED ext
|
||||
public interface net.corda.core.utilities.PropertyDelegate
|
||||
public abstract T getValue(Object, kotlin.reflect.KProperty)
|
||||
##
|
||||
public final class net.corda.core.utilities.SgxSupport extends java.lang.Object
|
||||
public static final boolean isInsideEnclave()
|
||||
@NotNull
|
||||
public static final net.corda.core.utilities.SgxSupport INSTANCE
|
||||
##
|
||||
public final class net.corda.core.utilities.ThreadDumpUtilsKt extends java.lang.Object
|
||||
@NotNull
|
||||
public static final String asString(management.ThreadInfo, int)
|
||||
|
@ -90,7 +90,6 @@ buildscript {
|
||||
ext.h2_version = constants.getProperty("h2Version")
|
||||
ext.rxjava_version = constants.getProperty("rxjavaVersion")
|
||||
ext.dokka_version = constants.getProperty("dokkaVersion")
|
||||
ext.eddsa_version = constants.getProperty("eddsaVersion")
|
||||
ext.dependency_checker_version = constants.getProperty("dependencyCheckerVersion")
|
||||
ext.commons_collections_version = constants.getProperty("commonsCollectionsVersion")
|
||||
ext.beanutils_version = constants.getProperty("beanutilsVersion")
|
||||
@ -178,7 +177,6 @@ buildscript {
|
||||
classpath "com.guardsquare:proguard-gradle:$proguard_version"
|
||||
classpath 'com.github.ben-manes:gradle-versions-plugin:0.15.0'
|
||||
classpath "org.jetbrains.dokka:dokka-base:$dokka_version"
|
||||
classpath "net.i2p.crypto:eddsa:$eddsa_version" // Needed for ServiceIdentityGenerator in the build environment.
|
||||
classpath "org.owasp:dependency-check-gradle:$dependency_checker_version"
|
||||
classpath "org.jfrog.buildinfo:build-info-extractor-gradle:$artifactory_plugin_version"
|
||||
// Capsule gradle plugin forked and maintained locally to support Gradle 5.x
|
||||
|
@ -21,7 +21,7 @@ guavaVersion=28.0-jre
|
||||
quasarVersion=0.9.0_r3
|
||||
dockerJavaVersion=3.2.5
|
||||
proguardVersion=7.3.1
|
||||
// bouncy castle version must not be changed on a patch release. Needs a full release test cycle to flush out any issues.
|
||||
# Bouncy Castle version must not be changed on a patch release. Needs a full release test cycle to flush out any issues.
|
||||
bouncycastleVersion=1.75
|
||||
classgraphVersion=4.8.135
|
||||
disruptorVersion=3.4.2
|
||||
@ -79,7 +79,6 @@ hibernateVersion=5.6.14.Final
|
||||
h2Version=2.2.224
|
||||
rxjavaVersion=1.3.8
|
||||
dokkaVersion=1.8.20
|
||||
eddsaVersion=0.3.0
|
||||
dependencyCheckerVersion=5.2.0
|
||||
commonsCollectionsVersion=4.3
|
||||
beanutilsVersion=1.9.4
|
||||
|
@ -184,7 +184,6 @@ quasar {
|
||||
"io.github.classgraph**",
|
||||
"io.netty*",
|
||||
"liquibase**",
|
||||
"net.i2p.crypto.**",
|
||||
"nonapi.io.github.classgraph.**",
|
||||
"org.apiguardian.**",
|
||||
"org.bouncycastle**",
|
||||
|
@ -36,8 +36,6 @@ dependencies {
|
||||
// For caches rather than guava
|
||||
implementation "com.github.ben-manes.caffeine:caffeine:$caffeine_version"
|
||||
implementation "org.apache.commons:commons-lang3:$commons_lang3_version"
|
||||
// Java ed25519 implementation. See https://github.com/str4d/ed25519-java/
|
||||
implementation "net.i2p.crypto:eddsa:$eddsa_version"
|
||||
// Bouncy castle support needed for X509 certificate manipulation
|
||||
implementation "org.bouncycastle:bcprov-jdk18on:${bouncycastle_version}"
|
||||
// required to use @Type annotation
|
||||
@ -93,19 +91,7 @@ processTestResources {
|
||||
}
|
||||
}
|
||||
|
||||
compileTestJava {
|
||||
options.compilerArgs += [
|
||||
'--add-exports', 'java.base/sun.security.util=ALL-UNNAMED',
|
||||
'--add-exports', 'java.base/sun.security.x509=ALL-UNNAMED'
|
||||
]
|
||||
}
|
||||
|
||||
test {
|
||||
// TODO This obscures whether any Corda client APIs need these JVM flags as well (which they shouldn't do)
|
||||
jvmArgs += [
|
||||
'--add-exports', 'java.base/sun.security.util=ALL-UNNAMED',
|
||||
'--add-exports', 'java.base/sun.security.x509=ALL-UNNAMED'
|
||||
]
|
||||
maxParallelForks = (System.env.CORDA_CORE_TESTING_FORKS == null) ? 1 : "$System.env.CORDA_CORE_TESTING_FORKS".toInteger()
|
||||
}
|
||||
|
||||
@ -129,7 +115,6 @@ quasar {
|
||||
"io.github.classgraph**",
|
||||
"io.netty*",
|
||||
"liquibase**",
|
||||
"net.i2p.crypto.**",
|
||||
"nonapi.io.github.classgraph.**",
|
||||
"org.apiguardian.**",
|
||||
"org.bouncycastle**",
|
||||
|
@ -5,11 +5,10 @@ import net.corda.core.crypto.CordaObjectIdentifier.COMPOSITE_SIGNATURE
|
||||
import net.corda.core.crypto.internal.PlatformSecureRandomService
|
||||
import org.bouncycastle.asn1.ASN1ObjectIdentifier
|
||||
import java.security.Provider
|
||||
import java.util.*
|
||||
import java.util.Optional
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
|
||||
@Suppress("DEPRECATION") // JDK11: should replace with Provider(String name, double version, String info) (since 9)
|
||||
class CordaSecurityProvider : Provider(PROVIDER_NAME, 0.1, "$PROVIDER_NAME security provider wrapper") {
|
||||
class CordaSecurityProvider : Provider(PROVIDER_NAME, "0.2", "$PROVIDER_NAME security provider") {
|
||||
companion object {
|
||||
const val PROVIDER_NAME = "Corda"
|
||||
}
|
||||
@ -17,21 +16,8 @@ class CordaSecurityProvider : Provider(PROVIDER_NAME, 0.1, "$PROVIDER_NAME secur
|
||||
private val services = ConcurrentHashMap<Pair<String, String>, Optional<Service>>()
|
||||
|
||||
init {
|
||||
put("KeyFactory.${CompositeKey.KEY_ALGORITHM}", CompositeKeyFactory::class.java.name)
|
||||
put("Alg.Alias.KeyFactory.$COMPOSITE_KEY", CompositeKey.KEY_ALGORITHM)
|
||||
put("Alg.Alias.KeyFactory.OID.$COMPOSITE_KEY", CompositeKey.KEY_ALGORITHM)
|
||||
put("Signature.${CompositeSignature.SIGNATURE_ALGORITHM}", CompositeSignature::class.java.name)
|
||||
put("Alg.Alias.Signature.$COMPOSITE_SIGNATURE", CompositeSignature.SIGNATURE_ALGORITHM)
|
||||
put("Alg.Alias.Signature.OID.$COMPOSITE_SIGNATURE", CompositeSignature.SIGNATURE_ALGORITHM)
|
||||
putPlatformSecureRandomService()
|
||||
|
||||
// JDK11+ - Hack to set Provider#legacyChanged to false, without this SecureRandom will not
|
||||
// pickup our random implementation (even if our provider is the first provider in
|
||||
// the chain).
|
||||
super.getService("UNDEFINED", "UNDEFINED")
|
||||
}
|
||||
|
||||
private fun putPlatformSecureRandomService() {
|
||||
putService(Service(this, "KeyFactory", CompositeKey.KEY_ALGORITHM, CompositeKeyFactory::class.java.name, listOf("$COMPOSITE_KEY", "OID.$COMPOSITE_KEY"), null))
|
||||
putService(Service(this, "Signature", CompositeSignature.SIGNATURE_ALGORITHM, CompositeSignature::class.java.name, listOf("$COMPOSITE_SIGNATURE", "OID.$COMPOSITE_SIGNATURE"), null))
|
||||
putService(PlatformSecureRandomService(this))
|
||||
}
|
||||
|
||||
|
@ -1,31 +1,26 @@
|
||||
package net.corda.core.crypto
|
||||
|
||||
import net.corda.core.CordaOID
|
||||
import net.corda.core.crypto.Crypto.EDDSA_ED25519_SHA512
|
||||
import net.corda.core.crypto.internal.AliasPrivateKey
|
||||
import net.corda.core.crypto.internal.Curve25519.isOnCurve25519
|
||||
import net.corda.core.crypto.internal.Instances.withSignature
|
||||
import net.corda.core.crypto.internal.PublicKeyCache
|
||||
import net.corda.core.crypto.internal.bouncyCastlePQCProvider
|
||||
import net.corda.core.crypto.internal.cordaBouncyCastleProvider
|
||||
import net.corda.core.crypto.internal.cordaSecurityProvider
|
||||
import net.corda.core.crypto.internal.`id-Curve25519ph`
|
||||
import net.corda.core.crypto.internal.providerMap
|
||||
import net.corda.core.crypto.internal.sunEcProvider
|
||||
import net.corda.core.internal.utilities.PrivateInterner
|
||||
import net.corda.core.serialization.serialize
|
||||
import net.corda.core.utilities.ByteSequence
|
||||
import net.i2p.crypto.eddsa.EdDSAEngine
|
||||
import net.i2p.crypto.eddsa.EdDSAPrivateKey
|
||||
import net.i2p.crypto.eddsa.EdDSAPublicKey
|
||||
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.DERUTF8String
|
||||
import org.bouncycastle.asn1.DLSequence
|
||||
import org.bouncycastle.asn1.bc.BCObjectIdentifiers
|
||||
import org.bouncycastle.asn1.edec.EdECObjectIdentifiers
|
||||
import org.bouncycastle.asn1.nist.NISTObjectIdentifiers
|
||||
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers
|
||||
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo
|
||||
@ -34,6 +29,9 @@ import org.bouncycastle.asn1.x509.AlgorithmIdentifier
|
||||
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo
|
||||
import org.bouncycastle.asn1.x9.X9ObjectIdentifiers
|
||||
import org.bouncycastle.crypto.CryptoServicesRegistrar
|
||||
import org.bouncycastle.crypto.params.Ed25519PrivateKeyParameters
|
||||
import org.bouncycastle.crypto.util.PrivateKeyInfoFactory
|
||||
import org.bouncycastle.crypto.util.SubjectPublicKeyInfoFactory
|
||||
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPrivateKey
|
||||
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey
|
||||
import org.bouncycastle.jcajce.provider.asymmetric.edec.BCEdDSAPrivateKey
|
||||
@ -49,20 +47,24 @@ 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.math.ec.rfc8032.Ed25519
|
||||
import org.bouncycastle.pqc.jcajce.provider.sphincs.BCSphincs256PrivateKey
|
||||
import org.bouncycastle.pqc.jcajce.provider.sphincs.BCSphincs256PublicKey
|
||||
import org.bouncycastle.pqc.jcajce.spec.SPHINCS256KeyGenParameterSpec
|
||||
import java.math.BigInteger
|
||||
import java.security.InvalidKeyException
|
||||
import java.security.Key
|
||||
import java.security.KeyFactory
|
||||
import java.security.KeyPair
|
||||
import java.security.KeyPairGenerator
|
||||
import java.security.PrivateKey
|
||||
import java.security.Provider
|
||||
import java.security.PublicKey
|
||||
import java.security.Signature
|
||||
import java.security.SignatureException
|
||||
import java.security.interfaces.EdECPrivateKey
|
||||
import java.security.interfaces.EdECPublicKey
|
||||
import java.security.spec.InvalidKeySpecException
|
||||
import java.security.spec.NamedParameterSpec
|
||||
import java.security.spec.PKCS8EncodedKeySpec
|
||||
import java.security.spec.X509EncodedKeySpec
|
||||
import javax.crypto.Mac
|
||||
@ -77,7 +79,7 @@ import javax.crypto.spec.SecretKeySpec
|
||||
* <li>RSA_SHA256 (RSA PKCS#1 using SHA256 as hash algorithm).
|
||||
* <li>ECDSA_SECP256K1_SHA256 (ECDSA using the secp256k1 Koblitz curve and SHA256 as hash algorithm).
|
||||
* <li>ECDSA_SECP256R1_SHA256 (ECDSA using the secp256r1 (NIST P-256) curve and SHA256 as hash algorithm).
|
||||
* <li>EDDSA_ED25519_SHA512 (EdDSA using the ed255519 twisted Edwards curve and SHA512 as hash algorithm).
|
||||
* <li>EDDSA_ED25519_SHA512 (EdDSA using the ed25519 twisted Edwards curve and SHA512 as hash algorithm).
|
||||
* <li>SPHINCS256_SHA512 (SPHINCS-256 hash-based signature scheme using SHA512 as hash algorithm).
|
||||
* </ul>
|
||||
*/
|
||||
@ -95,7 +97,7 @@ object Crypto {
|
||||
listOf(AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption, null)),
|
||||
cordaBouncyCastleProvider.name,
|
||||
"RSA",
|
||||
"SHA256WITHRSA",
|
||||
"SHA256withRSA",
|
||||
null,
|
||||
3072,
|
||||
"RSA_SHA256 signature scheme using SHA256 as hash algorithm."
|
||||
@ -140,13 +142,12 @@ object Crypto {
|
||||
val EDDSA_ED25519_SHA512: SignatureScheme = SignatureScheme(
|
||||
4,
|
||||
"EDDSA_ED25519_SHA512",
|
||||
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.
|
||||
cordaBouncyCastleProvider.name,
|
||||
"1.3.101.112",
|
||||
EdDSAEngine.SIGNATURE_ALGORITHM,
|
||||
EdDSANamedCurveTable.getByName("ED25519"),
|
||||
AlgorithmIdentifier(EdECObjectIdentifiers.id_Ed25519, null),
|
||||
emptyList(), // Both keys and the signature scheme use the same OID.
|
||||
sunEcProvider.name,
|
||||
"Ed25519",
|
||||
"Ed25519",
|
||||
NamedParameterSpec.ED25519,
|
||||
256,
|
||||
"EdDSA signature scheme using the ed25519 twisted Edwards curve."
|
||||
)
|
||||
@ -164,11 +165,11 @@ object Crypto {
|
||||
val SPHINCS256_SHA256 = SignatureScheme(
|
||||
5,
|
||||
"SPHINCS-256_SHA512",
|
||||
AlgorithmIdentifier(BCObjectIdentifiers.sphincs256_with_SHA512, DLSequence(arrayOf(ASN1Integer(0), SHA512_256))),
|
||||
AlgorithmIdentifier(BCObjectIdentifiers.sphincs256_with_SHA512, null),
|
||||
listOf(AlgorithmIdentifier(BCObjectIdentifiers.sphincs256, DLSequence(arrayOf(ASN1Integer(0), SHA512_256)))),
|
||||
bouncyCastlePQCProvider.name,
|
||||
"SPHINCS256",
|
||||
"SHA512WITHSPHINCS256",
|
||||
"SHA512withSPHINCS256",
|
||||
SPHINCS256KeyGenParameterSpec(SPHINCS256KeyGenParameterSpec.SHA512_256),
|
||||
256,
|
||||
"SPHINCS-256 hash-based signature scheme. It provides 128bit security against post-quantum attackers " +
|
||||
@ -244,8 +245,9 @@ object Crypto {
|
||||
|
||||
@JvmStatic
|
||||
fun findSignatureScheme(algorithm: AlgorithmIdentifier): SignatureScheme {
|
||||
return algorithmMap[normaliseAlgorithmIdentifier(algorithm)]
|
||||
?: throw IllegalArgumentException("Unrecognised algorithm: ${algorithm.algorithm.id}")
|
||||
return requireNotNull(algorithmMap[normaliseAlgorithmIdentifier(algorithm)]) {
|
||||
"Unrecognised algorithm identifier: ${algorithm.algorithm} ${algorithm.parameters}"
|
||||
}
|
||||
}
|
||||
|
||||
/** Find [SignatureScheme] by platform specific schemeNumberID. */
|
||||
@ -307,12 +309,11 @@ object Crypto {
|
||||
@JvmStatic
|
||||
fun decodePrivateKey(encodedKey: ByteArray): PrivateKey {
|
||||
val keyInfo = PrivateKeyInfo.getInstance(encodedKey)
|
||||
if (keyInfo.privateKeyAlgorithm.algorithm == ASN1ObjectIdentifier(CordaOID.ALIAS_PRIVATE_KEY)) {
|
||||
return convertIfBCEdDSAPrivateKey(decodeAliasPrivateKey(keyInfo))
|
||||
return if (keyInfo.privateKeyAlgorithm.algorithm == ASN1ObjectIdentifier(CordaOID.ALIAS_PRIVATE_KEY)) {
|
||||
decodeAliasPrivateKey(keyInfo)
|
||||
} else {
|
||||
findSignatureScheme(keyInfo.privateKeyAlgorithm).keyFactory.generatePrivate(PKCS8EncodedKeySpec(encodedKey))
|
||||
}
|
||||
val signatureScheme = findSignatureScheme(keyInfo.privateKeyAlgorithm)
|
||||
val keyFactory = keyFactory(signatureScheme)
|
||||
return convertIfBCEdDSAPrivateKey(keyFactory.generatePrivate(PKCS8EncodedKeySpec(encodedKey)))
|
||||
}
|
||||
|
||||
private fun decodeAliasPrivateKey(keyInfo: PrivateKeyInfo): PrivateKey {
|
||||
@ -351,8 +352,7 @@ object Crypto {
|
||||
"Unsupported key/algorithm for schemeCodeName: ${signatureScheme.schemeCodeName}"
|
||||
}
|
||||
try {
|
||||
val keyFactory = keyFactory(signatureScheme)
|
||||
return convertIfBCEdDSAPrivateKey(keyFactory.generatePrivate(PKCS8EncodedKeySpec(encodedKey)))
|
||||
return signatureScheme.keyFactory.generatePrivate(PKCS8EncodedKeySpec(encodedKey))
|
||||
} catch (ikse: InvalidKeySpecException) {
|
||||
throw InvalidKeySpecException("This private key cannot be decoded, please ensure it is PKCS8 encoded and that " +
|
||||
"it corresponds to the input scheme's code name.", ikse)
|
||||
@ -368,12 +368,11 @@ object Crypto {
|
||||
*/
|
||||
@JvmStatic
|
||||
fun decodePublicKey(encodedKey: ByteArray): PublicKey {
|
||||
return PublicKeyCache.publicKeyForCachedBytes(ByteSequence.of(encodedKey)) ?: {
|
||||
return PublicKeyCache.publicKeyForCachedBytes(ByteSequence.of(encodedKey)) ?: run {
|
||||
val subjectPublicKeyInfo = SubjectPublicKeyInfo.getInstance(encodedKey)
|
||||
val signatureScheme = findSignatureScheme(subjectPublicKeyInfo.algorithm)
|
||||
val keyFactory = keyFactory(signatureScheme)
|
||||
convertIfBCEdDSAPublicKey(keyFactory.generatePublic(X509EncodedKeySpec(encodedKey)))
|
||||
}()
|
||||
internPublicKey(signatureScheme.keyFactory.generatePublic(X509EncodedKeySpec(encodedKey)))
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
@ -412,8 +411,7 @@ object Crypto {
|
||||
"Unsupported key/algorithm for schemeCodeName: ${signatureScheme.schemeCodeName}"
|
||||
}
|
||||
try {
|
||||
val keyFactory = keyFactory(signatureScheme)
|
||||
return convertIfBCEdDSAPublicKey(keyFactory.generatePublic(X509EncodedKeySpec(encodedKey)))
|
||||
return signatureScheme.keyFactory.generatePublic(X509EncodedKeySpec(encodedKey))
|
||||
} catch (ikse: InvalidKeySpecException) {
|
||||
throw InvalidKeySpecException("This public key cannot be decoded, please ensure it is X509 encoded and " +
|
||||
"that it corresponds to the input scheme's code name.", ikse)
|
||||
@ -471,12 +469,8 @@ object Crypto {
|
||||
return withSignature(signatureScheme) { signature ->
|
||||
// Note that deterministic signature schemes, such as EdDSA, original SPHINCS-256 and RSA PKCS#1, do not require
|
||||
// extra randomness, but we have to ensure that non-deterministic algorithms (i.e., ECDSA) use non-blocking
|
||||
// SecureRandom implementation. Also, SPHINCS-256 implementation in BouncyCastle 1.60 fails with
|
||||
// ClassCastException if we invoke initSign with a SecureRandom as an input.
|
||||
// TODO Although we handle the above issue here, consider updating to BC 1.61+ which provides a fix.
|
||||
if (signatureScheme == EDDSA_ED25519_SHA512
|
||||
|| signatureScheme == SPHINCS256_SHA256
|
||||
|| signatureScheme == RSA_SHA256) {
|
||||
// SecureRandom implementation.
|
||||
if (signatureScheme == EDDSA_ED25519_SHA512 || signatureScheme == SPHINCS256_SHA256 || signatureScheme == RSA_SHA256) {
|
||||
signature.initSign(privateKey)
|
||||
} else {
|
||||
// The rest of the algorithms will require a SecureRandom input (i.e., ECDSA or any new algorithm for which
|
||||
@ -716,8 +710,7 @@ object Crypto {
|
||||
* This operation is currently supported for ECDSA secp256r1 (NIST P-256), ECDSA secp256k1 and EdDSA ed25519.
|
||||
*
|
||||
* Similarly to BIP32, the implemented algorithm uses an HMAC function based on SHA512 and it is actually
|
||||
* an implementation the HKDF rfc - Step 1: Extract function,
|
||||
* @see <a href="https://tools.ietf.org/html/rfc5869">HKDF</a>
|
||||
* an implementation of the [HKDF rfc - Step 1: Extract function](https://tools.ietf.org/html/rfc5869),
|
||||
* which is practically a variation of the private-parent-key -> private-child-key hardened key generation of BIP32.
|
||||
*
|
||||
* Unlike BIP32, where both private and public keys are extended to prevent deterministically
|
||||
@ -725,8 +718,8 @@ object Crypto {
|
||||
* without a chain-code and the generated key relies solely on the security of the private key.
|
||||
*
|
||||
* Although without a chain-code we lose the aforementioned property of not depending solely on the key,
|
||||
* it should be mentioned that the cryptographic strength of the HMAC depends upon the size of the secret key.
|
||||
* @see <a href="https://en.wikipedia.org/wiki/Hash-based_message_authentication_code#Security">HMAC Security</a>
|
||||
* it should be mentioned that the cryptographic strength of the HMAC depends upon the size of the secret key
|
||||
* (see [HMAC Security](https://en.wikipedia.org/wiki/Hash-based_message_authentication_code#Security)).
|
||||
* Thus, as long as the master key is kept secret and has enough entropy (~256 bits for EC-schemes), the system
|
||||
* is considered secure.
|
||||
*
|
||||
@ -743,9 +736,9 @@ object Crypto {
|
||||
* <li>salt values should not be chosen by an attacker.
|
||||
* </ul></p>
|
||||
*
|
||||
* Regarding the last requirement, according to Krawczyk's HKDF scheme: <i>While there is no need to keep the salt secret,
|
||||
* it is assumed that salt values are independent of the input keying material</i>.
|
||||
* @see <a href="http://eprint.iacr.org/2010/264.pdf">Cryptographic Extraction and Key Derivation - The HKDF Scheme</a>.
|
||||
* Regarding the last requirement, according to Krawczyk's HKDF scheme: _While there is no need to keep the salt secret,
|
||||
* it is assumed that salt values are independent of the input keying material_
|
||||
* (see [Cryptographic Extraction and Key Derivation - The HKDF Scheme](http://eprint.iacr.org/2010/264.pdf)).
|
||||
*
|
||||
* There are also protocols that require an authenticated nonce (e.g. when a DH derived key is used as a seed) and thus
|
||||
* we need to make sure that nonces come from legitimate parties rather than selected by an attacker.
|
||||
@ -845,13 +838,7 @@ object Crypto {
|
||||
private fun deriveKeyPairEdDSA(privateKey: PrivateKey, seed: ByteArray): KeyPair {
|
||||
// Compute HMAC(privateKey, seed).
|
||||
val macBytes = deriveHMAC(privateKey, seed)
|
||||
|
||||
// Calculate key pair.
|
||||
val params = EDDSA_ED25519_SHA512.algSpec as EdDSANamedCurveSpec
|
||||
val bytes = macBytes.copyOf(params.curve.field.getb() / 8) // Need to pad the entropy to the valid seed length.
|
||||
val privateKeyD = EdDSAPrivateKeySpec(bytes, params)
|
||||
val publicKeyD = EdDSAPublicKeySpec(privateKeyD.a, params)
|
||||
return KeyPair(internPublicKey(EdDSAPublicKey(publicKeyD)), EdDSAPrivateKey(privateKeyD))
|
||||
return deriveEdDSAKeyPair(macBytes)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -882,15 +869,20 @@ object Crypto {
|
||||
fun deriveKeyPairFromEntropy(entropy: BigInteger): KeyPair = deriveKeyPairFromEntropy(DEFAULT_SIGNATURE_SCHEME, entropy)
|
||||
|
||||
// Custom key pair generator from entropy.
|
||||
// The BigIntenger.toByteArray() uses the two's-complement representation.
|
||||
// The BigInteger.toByteArray() uses the two's-complement representation.
|
||||
// The entropy is transformed to a byte array in big-endian byte-order and
|
||||
// only the first ed25519.field.getb() / 8 bytes are used.
|
||||
private fun deriveEdDSAKeyPairFromEntropy(entropy: BigInteger): KeyPair {
|
||||
val params = EDDSA_ED25519_SHA512.algSpec as EdDSANamedCurveSpec
|
||||
val bytes = entropy.toByteArray().copyOf(params.curve.field.getb() / 8) // Need to pad the entropy to the valid seed length.
|
||||
val priv = EdDSAPrivateKeySpec(bytes, params)
|
||||
val pub = EdDSAPublicKeySpec(priv.a, params)
|
||||
return KeyPair(internPublicKey(EdDSAPublicKey(pub)), EdDSAPrivateKey(priv))
|
||||
return deriveEdDSAKeyPair(entropy.toByteArray().copyOf(Ed25519.PUBLIC_KEY_SIZE))
|
||||
}
|
||||
|
||||
private fun deriveEdDSAKeyPair(bytes: ByteArray): KeyPair {
|
||||
val privateKeyParams = Ed25519PrivateKeyParameters(bytes, 0) // This will copy the first 256 bits
|
||||
val encodedPrivateKey = PrivateKeyInfoFactory.createPrivateKeyInfo(privateKeyParams).encoded
|
||||
val privateKey = EDDSA_ED25519_SHA512.keyFactory.generatePrivate(PKCS8EncodedKeySpec(encodedPrivateKey))
|
||||
val encodedPublicKey = SubjectPublicKeyInfoFactory.createSubjectPublicKeyInfo(privateKeyParams.generatePublicKey()).encoded
|
||||
val publicKey = EDDSA_ED25519_SHA512.keyFactory.generatePublic(X509EncodedKeySpec(encodedPublicKey))
|
||||
return KeyPair(internPublicKey(publicKey), privateKey)
|
||||
}
|
||||
|
||||
// Custom key pair generator from an entropy required for various tests. It is similar to deriveKeyPairECDSA,
|
||||
@ -925,7 +917,7 @@ object Crypto {
|
||||
val mac = Mac.getInstance("HmacSHA512", cordaBouncyCastleProvider)
|
||||
val keyData = when (privateKey) {
|
||||
is BCECPrivateKey -> privateKey.d.toByteArray()
|
||||
is EdDSAPrivateKey -> privateKey.geta()
|
||||
is EdECPrivateKey -> privateKey.bytes.get()
|
||||
else -> throw InvalidKeyException("Key type ${privateKey.algorithm} is not supported for deterministic key derivation")
|
||||
}
|
||||
val key = SecretKeySpec(keyData, "HmacSHA512")
|
||||
@ -936,12 +928,12 @@ object Crypto {
|
||||
/**
|
||||
* 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.
|
||||
* @see <a href="https://safecurves.cr.yp.to/twist.html">Small subgroup and invalid-curve attacks</a> for a more descriptive explanation on such attacks.
|
||||
* See [Small subgroup and invalid-curve attacks](https://safecurves.cr.yp.to/twist.html) for a more descriptive explanation on such attacks.
|
||||
* We use this function on [validatePublicKey], which is currently used for signature verification only.
|
||||
* Thus, as these attacks are mostly not relevant to signature verification, we should note that
|
||||
* we are doing it out of an abundance of caution and specifically to proactively protect developers
|
||||
* against using these points as part of a DH key agreement or for use cases as yet unimagined.
|
||||
* This method currently applies to BouncyCastle's ECDSA (both R1 and K1 curves) and I2P's EdDSA (ed25519 curve).
|
||||
* This method currently applies to BouncyCastle's ECDSA (both R1 and K1 curves) and JCA EdDSA (ed25519 curve).
|
||||
* @param publicKey a [PublicKey], usually used to validate a signer's public key in on the Curve.
|
||||
* @param signatureScheme a [SignatureScheme] object, retrieved from supported signature schemes, see [Crypto].
|
||||
* @return true if the point lies on the curve or false if it doesn't.
|
||||
@ -954,17 +946,11 @@ object Crypto {
|
||||
}
|
||||
return when (publicKey) {
|
||||
is BCECPublicKey -> publicKey.parameters == signatureScheme.algSpec && !publicKey.q.isInfinity && publicKey.q.isValid
|
||||
is EdDSAPublicKey -> publicKey.params == signatureScheme.algSpec && !isEdDSAPointAtInfinity(publicKey) && publicKey.a.isOnCurve
|
||||
is EdECPublicKey -> signatureScheme == EDDSA_ED25519_SHA512 && publicKey.params.name.equals("Ed25519", ignoreCase = true) && publicKey.point.isOnCurve25519
|
||||
else -> throw IllegalArgumentException("Unsupported key type: ${publicKey::class}")
|
||||
}
|
||||
}
|
||||
|
||||
// Return true if EdDSA publicKey is point at infinity.
|
||||
// For EdDSA a custom function is required as it is not supported by the I2P implementation.
|
||||
private fun isEdDSAPointAtInfinity(publicKey: EdDSAPublicKey): Boolean {
|
||||
return publicKey.a.toP3() == (EDDSA_ED25519_SHA512.algSpec as EdDSANamedCurveSpec).curve.getZero(GroupElement.Representation.P3)
|
||||
}
|
||||
|
||||
/** Check if the requested [SignatureScheme] is supported by the system. */
|
||||
@JvmStatic
|
||||
fun isSupportedSignatureScheme(signatureScheme: SignatureScheme): Boolean {
|
||||
@ -981,7 +967,7 @@ object Crypto {
|
||||
// Check if a public key satisfies algorithm specs (for ECC: key should lie on the curve and not being point-at-infinity).
|
||||
private fun validatePublicKey(signatureScheme: SignatureScheme, key: PublicKey): Boolean {
|
||||
return when (key) {
|
||||
is BCECPublicKey, is EdDSAPublicKey -> publicKeyOnCurve(signatureScheme, key)
|
||||
is BCECPublicKey, is EdECPublicKey -> publicKeyOnCurve(signatureScheme, key)
|
||||
is BCRSAPublicKey -> key.modulus.bitLength() >= 2048 // Although the recommended RSA key size is 3072, we accept any key >= 2048bits.
|
||||
is BCSphincs256PublicKey -> true
|
||||
else -> throw IllegalArgumentException("Unsupported key type: ${key::class}")
|
||||
@ -991,21 +977,6 @@ object Crypto {
|
||||
private val interner = PrivateInterner<PublicKey>()
|
||||
private fun internPublicKey(key: PublicKey): PublicKey = PublicKeyCache.cachePublicKey(interner.intern(key))
|
||||
|
||||
|
||||
private fun convertIfBCEdDSAPublicKey(key: PublicKey): PublicKey {
|
||||
return internPublicKey(when (key) {
|
||||
is BCEdDSAPublicKey -> EdDSAPublicKey(X509EncodedKeySpec(key.encoded))
|
||||
else -> key
|
||||
})
|
||||
}
|
||||
|
||||
private fun convertIfBCEdDSAPrivateKey(key: PrivateKey): PrivateKey {
|
||||
return when (key) {
|
||||
is BCEdDSAPrivateKey -> EdDSAPrivateKey(PKCS8EncodedKeySpec(key.encoded))
|
||||
else -> key
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a public key to a supported implementation.
|
||||
* @param key a public key.
|
||||
@ -1031,9 +1002,9 @@ object Crypto {
|
||||
is BCECPublicKey -> internPublicKey(key)
|
||||
is BCRSAPublicKey -> internPublicKey(key)
|
||||
is BCSphincs256PublicKey -> internPublicKey(key)
|
||||
is EdDSAPublicKey -> internPublicKey(key)
|
||||
is EdECPublicKey -> internPublicKey(key)
|
||||
is CompositeKey -> internPublicKey(key)
|
||||
is BCEdDSAPublicKey -> convertIfBCEdDSAPublicKey(key)
|
||||
is BCEdDSAPublicKey -> internPublicKey(key)
|
||||
else -> decodePublicKey(key.encoded)
|
||||
}
|
||||
}
|
||||
@ -1052,8 +1023,8 @@ object Crypto {
|
||||
is BCECPrivateKey -> key
|
||||
is BCRSAPrivateKey -> key
|
||||
is BCSphincs256PrivateKey -> key
|
||||
is EdDSAPrivateKey -> key
|
||||
is BCEdDSAPrivateKey -> convertIfBCEdDSAPrivateKey(key)
|
||||
is EdECPrivateKey -> key
|
||||
is BCEdDSAPrivateKey -> key
|
||||
else -> decodePrivateKey(key.encoded)
|
||||
}
|
||||
}
|
||||
@ -1095,8 +1066,4 @@ object Crypto {
|
||||
private fun setBouncyCastleRNG() {
|
||||
CryptoServicesRegistrar.setSecureRandom(newSecureRandom())
|
||||
}
|
||||
|
||||
private fun keyFactory(signatureScheme: SignatureScheme) = signatureScheme.getKeyFactory {
|
||||
KeyFactory.getInstance(signatureScheme.algorithmName, providerMap[signatureScheme.providerName])
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,8 @@
|
||||
package net.corda.core.crypto
|
||||
|
||||
import net.corda.core.contracts.PrivacySalt
|
||||
import net.corda.core.crypto.internal.platformSecureRandomFactory
|
||||
import net.corda.core.crypto.internal.PlatformSecureRandomService
|
||||
import net.corda.core.crypto.internal.cordaSecurityProvider
|
||||
import net.corda.core.serialization.SerializationDefaults
|
||||
import net.corda.core.serialization.serialize
|
||||
import net.corda.core.utilities.OpaqueBytes
|
||||
@ -19,6 +20,7 @@ import java.security.PublicKey
|
||||
import java.security.SecureRandom
|
||||
import java.security.SecureRandomSpi
|
||||
import java.security.SignatureException
|
||||
import kotlin.math.abs
|
||||
|
||||
/**
|
||||
* Utility to simplify the act of signing a byte array.
|
||||
@ -231,7 +233,12 @@ object DummySecureRandom : SecureRandom(DummySecureRandomSpi(), null)
|
||||
* which should never happen and suggests an unusual JVM or non-standard Java library.
|
||||
*/
|
||||
@Throws(NoSuchAlgorithmException::class)
|
||||
fun newSecureRandom(): SecureRandom = platformSecureRandomFactory()
|
||||
fun newSecureRandom(): SecureRandom = sharedSecureRandom
|
||||
|
||||
// This is safe to share because of the underlying implementation of SecureRandomSpi
|
||||
private val sharedSecureRandom: SecureRandom by lazy(LazyThreadSafetyMode.PUBLICATION) {
|
||||
SecureRandom.getInstance(PlatformSecureRandomService.ALGORITHM, cordaSecurityProvider)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a random positive non-zero long generated using a secure RNG. This function sacrifies a bit of entropy in order
|
||||
@ -239,7 +246,7 @@ fun newSecureRandom(): SecureRandom = platformSecureRandomFactory()
|
||||
*/
|
||||
fun random63BitValue(): Long {
|
||||
while (true) {
|
||||
val candidate = Math.abs(newSecureRandom().nextLong())
|
||||
val candidate = abs(newSecureRandom().nextLong())
|
||||
// No need to check for -0L
|
||||
if (candidate != 0L && candidate != Long.MIN_VALUE) {
|
||||
return candidate
|
||||
|
@ -1,5 +1,6 @@
|
||||
package net.corda.core.crypto
|
||||
|
||||
import net.corda.core.crypto.internal.providerMap
|
||||
import org.bouncycastle.asn1.x509.AlgorithmIdentifier
|
||||
import java.security.KeyFactory
|
||||
import java.security.Signature
|
||||
@ -36,11 +37,6 @@ data class SignatureScheme(
|
||||
@Volatile
|
||||
private var memoizedKeyFactory: KeyFactory? = null
|
||||
|
||||
internal fun getKeyFactory(factoryFactory: () -> KeyFactory): KeyFactory {
|
||||
return memoizedKeyFactory ?: run {
|
||||
val newFactory = factoryFactory()
|
||||
memoizedKeyFactory = newFactory
|
||||
newFactory
|
||||
}
|
||||
}
|
||||
internal val keyFactory: KeyFactory
|
||||
get() = memoizedKeyFactory ?: KeyFactory.getInstance(algorithmName, providerMap[providerName]).also { memoizedKeyFactory = it }
|
||||
}
|
||||
|
@ -0,0 +1,46 @@
|
||||
|
||||
package net.corda.core.crypto.internal
|
||||
|
||||
import java.math.BigInteger
|
||||
import java.math.BigInteger.TWO
|
||||
import java.security.spec.EdECPoint
|
||||
|
||||
/**
|
||||
* Parameters for Curve25519, as defined in https://www.rfc-editor.org/rfc/rfc7748#section-4.1.
|
||||
*/
|
||||
@Suppress("MagicNumber")
|
||||
object Curve25519 {
|
||||
val p = TWO.pow(255) - 19.toBigInteger() // 2^255 - 19
|
||||
val d = ModP(BigInteger("37095705934669439343138083508754565189542113879843219016388785533085940283555"))
|
||||
|
||||
val EdECPoint.isOnCurve25519: Boolean
|
||||
// https://www.rfc-editor.org/rfc/rfc8032.html#section-5.1.3
|
||||
get() {
|
||||
if (y >= p) return false
|
||||
val ySquared = ModP(y).pow(TWO)
|
||||
val u = ySquared - 1 // y^2 - 1 (mod p)
|
||||
val v = d * ySquared + 1 // dy^2 + 1 (mod p)
|
||||
val x = (u / v).pow((p + 3.toBigInteger()).shiftRight(3)) // (u/v)^((p+3)/8) (mod p)
|
||||
val vxSquared = v * x.pow(TWO)
|
||||
return vxSquared == u || vxSquared == -u
|
||||
}
|
||||
|
||||
fun BigInteger.modP(): ModP = ModP(mod(p))
|
||||
|
||||
private fun BigInteger.additiveInverse(): BigInteger = p - this
|
||||
|
||||
data class ModP(val value: BigInteger) : Comparable<ModP> {
|
||||
fun pow(exponent: BigInteger): ModP = ModP(value.modPow(exponent, p))
|
||||
|
||||
operator fun unaryMinus(): ModP = ModP(value.additiveInverse())
|
||||
operator fun plus(other: ModP): ModP = (this.value + other.value).modP()
|
||||
operator fun plus(other: Int): ModP = (this.value + other.toBigInteger()).modP()
|
||||
operator fun minus(other: ModP): ModP = (this.value + other.value.additiveInverse()).modP()
|
||||
operator fun minus(other: Int): ModP = (this.value + other.toBigInteger().additiveInverse()).modP()
|
||||
operator fun times(other: ModP): ModP = (this.value * other.value).modP()
|
||||
operator fun div(other: ModP): ModP = (this.value * other.value.modInverse(p)).modP()
|
||||
|
||||
override fun compareTo(other: ModP): Int = this.value.compareTo(other.value)
|
||||
override fun toString(): String = "$value (mod Curve25519 p)"
|
||||
}
|
||||
}
|
@ -26,9 +26,8 @@ object Instances {
|
||||
private val signatureFactory: SignatureFactory = CachingSignatureFactory()
|
||||
|
||||
// The provider itself is a very bad key class as hashCode() is expensive and contended. So use name and version instead.
|
||||
private data class SignatureKey(val algorithm: String, val providerName: String?, val providerVersion: Double?) {
|
||||
constructor(algorithm: String, provider: Provider?) : this(algorithm, provider?.name,
|
||||
@Suppress("DEPRECATION") provider?.version) // JDK11: should replace with getVersionStr() (since 9)
|
||||
private data class SignatureKey(val algorithm: String, val providerName: String?, val providerVersion: String?) {
|
||||
constructor(algorithm: String, provider: Provider?) : this(algorithm, provider?.name, provider?.versionStr)
|
||||
}
|
||||
|
||||
private class CachingSignatureFactory : SignatureFactory {
|
||||
|
@ -2,8 +2,6 @@
|
||||
package net.corda.core.crypto.internal
|
||||
|
||||
import io.netty.util.concurrent.FastThreadLocal
|
||||
import net.corda.core.crypto.DummySecureRandom
|
||||
import net.corda.core.utilities.SgxSupport
|
||||
import net.corda.core.utilities.loggerFor
|
||||
import org.apache.commons.lang3.SystemUtils
|
||||
import java.io.DataInputStream
|
||||
@ -16,21 +14,8 @@ import java.security.SecureRandom
|
||||
import java.security.SecureRandomSpi
|
||||
import kotlin.system.exitProcess
|
||||
|
||||
/**
|
||||
* This has been migrated into a separate class so that it
|
||||
* is easier to delete from the core-deterministic module.
|
||||
*/
|
||||
val platformSecureRandom: () -> SecureRandom = when {
|
||||
SgxSupport.isInsideEnclave -> {
|
||||
{ DummySecureRandom }
|
||||
}
|
||||
else -> {
|
||||
{ sharedSecureRandom }
|
||||
}
|
||||
}
|
||||
|
||||
class PlatformSecureRandomService(provider: Provider)
|
||||
: Provider.Service(provider, "SecureRandom", ALGORITHM, PlatformSecureRandomSpi::javaClass.name, null, null) {
|
||||
: Provider.Service(provider, "SecureRandom", ALGORITHM, PlatformSecureRandomSpi::class.java.name, null, null) {
|
||||
|
||||
companion object {
|
||||
const val ALGORITHM = "CordaPRNG"
|
||||
@ -88,8 +73,3 @@ private class LinuxSecureRandomSpi : SecureRandomSpi() {
|
||||
|
||||
override fun engineGenerateSeed(numBytes: Int): ByteArray = ByteArray(numBytes).apply { engineNextBytes(this) }
|
||||
}
|
||||
|
||||
// This is safe to share because of the underlying implementation of SecureRandomSpi
|
||||
private val sharedSecureRandom: SecureRandom by lazy(LazyThreadSafetyMode.PUBLICATION) {
|
||||
SecureRandom.getInstance(PlatformSecureRandomService.ALGORITHM)
|
||||
}
|
||||
|
@ -1,24 +1,17 @@
|
||||
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.internal.X509EdDSAEngine
|
||||
import net.i2p.crypto.eddsa.EdDSAEngine
|
||||
import net.i2p.crypto.eddsa.EdDSASecurityProvider
|
||||
import org.bouncycastle.asn1.ASN1ObjectIdentifier
|
||||
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo
|
||||
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo
|
||||
import org.bouncycastle.jcajce.provider.asymmetric.ec.AlgorithmParametersSpi
|
||||
import org.bouncycastle.jcajce.provider.util.AsymmetricKeyInfoConverter
|
||||
import org.bouncycastle.jce.provider.BouncyCastleProvider
|
||||
import org.bouncycastle.pqc.jcajce.provider.BouncyCastlePQCProvider
|
||||
import java.security.Provider
|
||||
import java.security.SecureRandom
|
||||
import java.security.Security
|
||||
import java.util.Collections.unmodifiableMap
|
||||
|
||||
val sunEcProvider = checkNotNull(Security.getProvider("SunEC")).also {
|
||||
// Insert Secp256k1SupportProvider just in-front of SunEC for adding back support for secp256k1
|
||||
Security.insertProviderAt(Secp256k1SupportProvider(), Security.getProviders().indexOf(it))
|
||||
}
|
||||
|
||||
val cordaSecurityProvider = CordaSecurityProvider().also {
|
||||
// Among the others, we should register [CordaSecurityProvider] as the first provider, to ensure that when invoking [SecureRandom()]
|
||||
// the [platformSecureRandom] is returned (which is registered in CordaSecurityProvider).
|
||||
@ -29,40 +22,8 @@ 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
|
||||
val `id-Curve25519ph` = ASN1ObjectIdentifier("1.3.101.112")
|
||||
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)
|
||||
put("Signature.Ed25519", 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)
|
||||
})
|
||||
// Required due to [X509CRL].verify() reported issues in network-services after BC 1.60 update.
|
||||
put("AlgorithmParameters.SHA256WITHECDSA", AlgorithmParametersSpi::class.java.name)
|
||||
}.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.
|
||||
val cordaBouncyCastleProvider = BouncyCastleProvider().also {
|
||||
Security.addProvider(it)
|
||||
|
||||
// Remove providers that class with bouncy castle
|
||||
val bcProviders = it.keys
|
||||
|
||||
// JDK 17: Add SunEC provider as lowest priority, as we use Bouncycastle for EDDSA
|
||||
// and remove amy algorithms that conflict with Bouncycastle
|
||||
val sunEC = Security.getProvider("SunEC")
|
||||
if (sunEC != null) {
|
||||
Security.removeProvider("SunEC")
|
||||
Security.addProvider(sunEC)
|
||||
|
||||
for(alg in sunEC.keys) {
|
||||
if (bcProviders.contains(alg)) {
|
||||
sunEC.remove(alg)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val bouncyCastlePQCProvider = BouncyCastlePQCProvider().apply {
|
||||
@ -75,8 +36,6 @@ val bouncyCastlePQCProvider = BouncyCastlePQCProvider().apply {
|
||||
// i.e. if someone removes a Provider and then he/she adds a new one with the same name.
|
||||
// The val is immutable to avoid any harmful state changes.
|
||||
internal val providerMap: Map<String, Provider> = unmodifiableMap(
|
||||
listOf(cordaBouncyCastleProvider, cordaSecurityProvider, bouncyCastlePQCProvider)
|
||||
listOf(sunEcProvider, cordaBouncyCastleProvider, cordaSecurityProvider, bouncyCastlePQCProvider)
|
||||
.associateByTo(LinkedHashMap(), Provider::getName)
|
||||
)
|
||||
|
||||
fun platformSecureRandomFactory(): SecureRandom = platformSecureRandom() // To minimise diff of CryptoUtils against open-source.
|
||||
|
@ -0,0 +1,188 @@
|
||||
@file:Suppress("MagicNumber")
|
||||
|
||||
package net.corda.core.crypto.internal
|
||||
|
||||
import org.bouncycastle.jce.provider.BouncyCastleProvider
|
||||
import java.math.BigInteger
|
||||
import java.math.BigInteger.ZERO
|
||||
import java.security.AlgorithmParameters
|
||||
import java.security.KeyPair
|
||||
import java.security.KeyPairGeneratorSpi
|
||||
import java.security.PrivateKey
|
||||
import java.security.Provider
|
||||
import java.security.PublicKey
|
||||
import java.security.SecureRandom
|
||||
import java.security.Signature
|
||||
import java.security.SignatureSpi
|
||||
import java.security.interfaces.ECPrivateKey
|
||||
import java.security.interfaces.ECPublicKey
|
||||
import java.security.spec.AlgorithmParameterSpec
|
||||
import java.security.spec.ECFieldFp
|
||||
import java.security.spec.ECParameterSpec
|
||||
import java.security.spec.ECPoint
|
||||
import java.security.spec.EllipticCurve
|
||||
import java.security.spec.NamedParameterSpec
|
||||
|
||||
/**
|
||||
* Augment the SunEC provider with secp256k1 curve support by delegating to [BouncyCastleProvider] when secp256k1 keys or params are
|
||||
* requested. Otherwise delegates to SunEC.
|
||||
*/
|
||||
class Secp256k1SupportProvider : Provider("Secp256k1Support", "1.0", "Augmenting SunEC with support for the secp256k1 curve via BC") {
|
||||
init {
|
||||
put("Signature.SHA256withECDSA", Secp256k1SupportSignatureSpi::class.java.name)
|
||||
put("KeyPairGenerator.EC", Secp256k1SupportKeyPairGeneratorSpi::class.java.name)
|
||||
put("AlgorithmParameters.EC", "sun.security.util.ECParameters")
|
||||
put("KeyFactory.EC", "sun.security.ec.ECKeyFactory")
|
||||
}
|
||||
|
||||
class Secp256k1SupportSignatureSpi : SignatureSpi() {
|
||||
private lateinit var sunEc: Signature
|
||||
private lateinit var bc: Signature
|
||||
private lateinit var selected: Signature
|
||||
|
||||
override fun engineInitVerify(publicKey: PublicKey?) {
|
||||
selectProvider((publicKey as? ECPublicKey)?.params)
|
||||
selected.initVerify(publicKey)
|
||||
}
|
||||
|
||||
override fun engineInitSign(privateKey: PrivateKey?) {
|
||||
selectProvider((privateKey as? ECPrivateKey)?.params)
|
||||
selected.initSign(privateKey)
|
||||
}
|
||||
|
||||
override fun engineSetParameter(params: AlgorithmParameterSpec?) {
|
||||
selectProvider(params)
|
||||
// The BC implementation throws UnsupportedOperationException, so we just avoid calling it.
|
||||
if (selected !== bc) {
|
||||
selected.setParameter(params)
|
||||
}
|
||||
}
|
||||
|
||||
private fun selectProvider(params: AlgorithmParameterSpec?) {
|
||||
if (params.isSecp256k1) {
|
||||
if (!::bc.isInitialized) {
|
||||
bc = Signature.getInstance("SHA256withECDSA", cordaBouncyCastleProvider)
|
||||
}
|
||||
selected = bc
|
||||
} else {
|
||||
selectSunEc()
|
||||
}
|
||||
}
|
||||
|
||||
private fun selectSunEc() {
|
||||
if (!::sunEc.isInitialized) {
|
||||
sunEc = Signature.getInstance("SHA256withECDSA", sunEcProvider)
|
||||
}
|
||||
selected = sunEc
|
||||
}
|
||||
|
||||
override fun engineUpdate(b: Byte) {
|
||||
defaultToSunEc()
|
||||
selected.update(b)
|
||||
}
|
||||
|
||||
override fun engineUpdate(b: ByteArray?, off: Int, len: Int) {
|
||||
defaultToSunEc()
|
||||
selected.update(b, off, len)
|
||||
}
|
||||
|
||||
override fun engineSign(): ByteArray {
|
||||
defaultToSunEc()
|
||||
return selected.sign()
|
||||
}
|
||||
|
||||
override fun engineVerify(sigBytes: ByteArray?): Boolean {
|
||||
defaultToSunEc()
|
||||
return selected.verify(sigBytes)
|
||||
}
|
||||
|
||||
override fun engineGetParameters(): AlgorithmParameters {
|
||||
defaultToSunEc()
|
||||
return selected.parameters
|
||||
}
|
||||
|
||||
@Deprecated("Deprecated in Java")
|
||||
@Suppress("DEPRECATION")
|
||||
override fun engineSetParameter(param: String?, value: Any?) {
|
||||
defaultToSunEc()
|
||||
selected.setParameter(param, value)
|
||||
}
|
||||
|
||||
@Deprecated("Deprecated in Java")
|
||||
@Suppress("DEPRECATION")
|
||||
override fun engineGetParameter(param: String?): Any {
|
||||
defaultToSunEc()
|
||||
return selected.getParameter(param)
|
||||
}
|
||||
|
||||
private fun defaultToSunEc() {
|
||||
// Even though it's probably a bug to start using the Signature object without first calling one of the intialize methods,
|
||||
// default it to SunEC provider anyway and let it deal with the issue.
|
||||
if (!::selected.isInitialized) {
|
||||
selectSunEc()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class Secp256k1SupportKeyPairGeneratorSpi : KeyPairGeneratorSpi() {
|
||||
// The methods in KeyPairGeneratorSpi are public, which allows us to directly call them. This is not the case with SignatureSpi (above).
|
||||
private lateinit var sunEc: KeyPairGeneratorSpi
|
||||
private lateinit var bc: KeyPairGeneratorSpi
|
||||
private lateinit var selected: KeyPairGeneratorSpi
|
||||
|
||||
override fun initialize(keysize: Int, random: SecureRandom?) {
|
||||
selectSunEc()
|
||||
selected.initialize(keysize, random)
|
||||
}
|
||||
|
||||
override fun initialize(params: AlgorithmParameterSpec?, random: SecureRandom?) {
|
||||
if (params.isSecp256k1) {
|
||||
if (!::bc.isInitialized) {
|
||||
bc = org.bouncycastle.jcajce.provider.asymmetric.ec.KeyPairGeneratorSpi.EC()
|
||||
}
|
||||
selected = bc
|
||||
} else {
|
||||
selectSunEc()
|
||||
}
|
||||
selected.initialize(params, random)
|
||||
}
|
||||
|
||||
private fun selectSunEc() {
|
||||
if (!::sunEc.isInitialized) {
|
||||
sunEc = sunEcProvider.getService("KeyPairGenerator", "EC").newInstance(null) as KeyPairGeneratorSpi
|
||||
}
|
||||
selected = sunEc
|
||||
}
|
||||
|
||||
override fun generateKeyPair(): KeyPair {
|
||||
if (!::selected.isInitialized) {
|
||||
// In-case initialize wasn't first called, default to SunEC
|
||||
selectSunEc()
|
||||
}
|
||||
return selected.generateKeyPair()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parameters for the secp256k1 curve
|
||||
*/
|
||||
private object Secp256k1 {
|
||||
val n = BigInteger("fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141", 16)
|
||||
val g = ECPoint(
|
||||
BigInteger("79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798", 16),
|
||||
BigInteger("483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8", 16)
|
||||
)
|
||||
val curve = EllipticCurve(
|
||||
ECFieldFp(BigInteger("fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f", 16)),
|
||||
ZERO,
|
||||
7.toBigInteger()
|
||||
)
|
||||
}
|
||||
|
||||
val AlgorithmParameterSpec?.isSecp256k1: Boolean
|
||||
get() = when (this) {
|
||||
is ECParameterSpec -> cofactor == 1 && order == Secp256k1.n && curve == Secp256k1.curve && generator == Secp256k1.g
|
||||
is NamedParameterSpec -> name.equals("secp256k1", ignoreCase = true)
|
||||
else -> false
|
||||
}
|
@ -13,7 +13,7 @@ import java.util.*
|
||||
class StatePointerSearch(val state: ContractState) {
|
||||
private companion object {
|
||||
// Classes in these packages should not be part of a search.
|
||||
private val blackListedPackages = setOf("java.", "javax.", "org.bouncycastle.", "net.i2p.crypto.")
|
||||
private val blackListedPackages = setOf("java.", "javax.", "org.bouncycastle.")
|
||||
}
|
||||
|
||||
// Type required for traversal.
|
||||
|
@ -1,59 +0,0 @@
|
||||
package net.corda.core.internal
|
||||
|
||||
import net.corda.core.crypto.Crypto
|
||||
import net.i2p.crypto.eddsa.EdDSAEngine
|
||||
import net.i2p.crypto.eddsa.EdDSAPublicKey
|
||||
import java.security.AlgorithmParameters
|
||||
import java.security.InvalidKeyException
|
||||
import java.security.MessageDigest
|
||||
import java.security.PrivateKey
|
||||
import java.security.PublicKey
|
||||
import java.security.SecureRandom
|
||||
import java.security.Signature
|
||||
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.initSign(privateKey)
|
||||
|
||||
override fun engineInitSign(privateKey: PrivateKey, random: SecureRandom) = engine.initSign(privateKey, random)
|
||||
|
||||
override fun engineInitVerify(publicKey: PublicKey) {
|
||||
val parsedKey = try {
|
||||
publicKey as? EdDSAPublicKey ?: EdDSAPublicKey(X509EncodedKeySpec(Crypto.encodePublicKey(publicKey)))
|
||||
} catch (e: Exception) {
|
||||
throw (InvalidKeyException(e.message))
|
||||
}
|
||||
engine.initVerify(parsedKey)
|
||||
}
|
||||
|
||||
override fun engineSign(): ByteArray = engine.sign()
|
||||
override fun engineVerify(sigBytes: ByteArray): Boolean = engine.verify(sigBytes)
|
||||
|
||||
override fun engineUpdate(b: Byte) = engine.update(b)
|
||||
override fun engineUpdate(b: ByteArray, off: Int, len: Int) = engine.update(b, off, len)
|
||||
|
||||
override fun engineGetParameters(): AlgorithmParameters = engine.parameters
|
||||
override fun engineSetParameter(params: AlgorithmParameterSpec) = engine.setParameter(params)
|
||||
@Suppress("DEPRECATION", "OverridingDeprecatedMember")
|
||||
override fun engineGetParameter(param: String): Any = engine.getParameter(param)
|
||||
|
||||
@Suppress("DEPRECATION", "OverridingDeprecatedMember")
|
||||
override fun engineSetParameter(param: String, value: Any?) = engine.setParameter(param, value)
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
package net.corda.core.utilities
|
||||
|
||||
object SgxSupport {
|
||||
@JvmStatic
|
||||
val isInsideEnclave: Boolean by lazy {
|
||||
(System.getProperty("os.name") == "Linux") && (System.getProperty("java.vm.name") == "Avian (Corda)")
|
||||
}
|
||||
}
|
@ -1,135 +0,0 @@
|
||||
package net.corda.core.internal;
|
||||
|
||||
import net.corda.core.crypto.Crypto;
|
||||
import net.i2p.crypto.eddsa.EdDSAEngine;
|
||||
import net.i2p.crypto.eddsa.EdDSAPublicKey;
|
||||
import org.junit.Test;
|
||||
import sun.security.util.BitArray;
|
||||
import sun.security.util.ObjectIdentifier;
|
||||
import sun.security.x509.AlgorithmId;
|
||||
import sun.security.x509.X509Key;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.math.BigInteger;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.KeyPair;
|
||||
import java.security.SignatureException;
|
||||
import java.util.Random;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* JDK11 upgrade: rewritten in Java to gain access to private internal JDK classes via module directives (not available to Kotlin compiler):
|
||||
* import sun.security.util.BitArray;
|
||||
* import sun.security.util.ObjectIdentifier;
|
||||
* import sun.security.x509.AlgorithmId;
|
||||
* import sun.security.x509.X509Key;
|
||||
*/
|
||||
public class X509EdDSAEngineTest {
|
||||
private static final long SEED = 20170920L;
|
||||
private static final int TEST_DATA_SIZE = 2000;
|
||||
|
||||
// offset into an EdDSA header indicating where the key header and actual key start
|
||||
// in the underlying byte array
|
||||
private static final int KEY_HEADER_START = 9;
|
||||
private static final int KEY_START = 12;
|
||||
|
||||
private X509Key toX509Key(EdDSAPublicKey publicKey) throws IOException, InvalidKeyException {
|
||||
byte[] internals = publicKey.getEncoded();
|
||||
|
||||
// key size in the header includes the count unused bits at the end of the key
|
||||
// [keyHeaderStart + 2] but NOT the key header ID [keyHeaderStart] so the
|
||||
// actual length of the key blob is size - 1
|
||||
int keySize = (internals[KEY_HEADER_START + 1]) - 1;
|
||||
|
||||
byte[] key = new byte[keySize];
|
||||
System.arraycopy(internals, KEY_START, key, 0, keySize);
|
||||
|
||||
// 1.3.101.102 is the EdDSA OID
|
||||
return new TestX509Key(new AlgorithmId(ObjectIdentifier.of("1.3.101.112")), new BitArray(keySize * 8, key));
|
||||
}
|
||||
|
||||
private static class TestX509Key extends X509Key {
|
||||
TestX509Key(AlgorithmId algorithmId, BitArray key) throws InvalidKeyException {
|
||||
this.algid = algorithmId;
|
||||
this.setKey(key);
|
||||
this.encode();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Put the X509EdDSA engine through basic tests to verify that the functions are hooked up correctly.
|
||||
*/
|
||||
@Test
|
||||
public void SignAndVerify() throws InvalidKeyException, SignatureException {
|
||||
X509EdDSAEngine engine = new X509EdDSAEngine();
|
||||
KeyPair keyPair = Crypto.deriveKeyPairFromEntropy(Crypto.EDDSA_ED25519_SHA512, BigInteger.valueOf(SEED));
|
||||
EdDSAPublicKey publicKey = (EdDSAPublicKey) keyPair.getPublic();
|
||||
byte[] randomBytes = new byte[TEST_DATA_SIZE];
|
||||
new Random(SEED).nextBytes(randomBytes);
|
||||
engine.initSign(keyPair.getPrivate());
|
||||
engine.update(randomBytes[0]);
|
||||
engine.update(randomBytes, 1, randomBytes.length - 1);
|
||||
|
||||
// Now verify the signature
|
||||
byte[] signature = engine.sign();
|
||||
|
||||
engine.initVerify(publicKey);
|
||||
engine.update(randomBytes);
|
||||
assertTrue(engine.verify(signature));
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that signing with an X509Key wrapped EdDSA key works.
|
||||
*/
|
||||
@Test
|
||||
public void SignAndVerifyWithX509Key() throws InvalidKeyException, SignatureException, IOException {
|
||||
X509EdDSAEngine engine = new X509EdDSAEngine();
|
||||
KeyPair keyPair = Crypto.deriveKeyPairFromEntropy(Crypto.EDDSA_ED25519_SHA512, BigInteger.valueOf(SEED + 1));
|
||||
X509Key publicKey = toX509Key((EdDSAPublicKey) keyPair.getPublic());
|
||||
byte[] randomBytes = new byte[TEST_DATA_SIZE];
|
||||
new Random(SEED + 1).nextBytes(randomBytes);
|
||||
engine.initSign(keyPair.getPrivate());
|
||||
engine.update(randomBytes[0]);
|
||||
engine.update(randomBytes, 1, randomBytes.length - 1);
|
||||
|
||||
// Now verify the signature
|
||||
byte[] signature = engine.sign();
|
||||
|
||||
engine.initVerify(publicKey);
|
||||
engine.update(randomBytes);
|
||||
assertTrue(engine.verify(signature));
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that signing with an X509Key wrapped EdDSA key succeeds when using the underlying EdDSAEngine.
|
||||
*/
|
||||
@Test
|
||||
public void SignAndVerifyWithX509KeyAndOldEngineFails() throws InvalidKeyException, SignatureException, IOException {
|
||||
X509EdDSAEngine engine = new X509EdDSAEngine();
|
||||
KeyPair keyPair = Crypto.deriveKeyPairFromEntropy(Crypto.EDDSA_ED25519_SHA512, BigInteger.valueOf(SEED + 1));
|
||||
X509Key publicKey = toX509Key((EdDSAPublicKey) keyPair.getPublic());
|
||||
byte[] randomBytes = new byte[TEST_DATA_SIZE];
|
||||
new Random(SEED + 1).nextBytes(randomBytes);
|
||||
engine.initSign(keyPair.getPrivate());
|
||||
engine.update(randomBytes[0]);
|
||||
engine.update(randomBytes, 1, randomBytes.length - 1);
|
||||
|
||||
// Now verify the signature
|
||||
byte[] signature = engine.sign();
|
||||
engine.initVerify(publicKey);
|
||||
engine.update(randomBytes);
|
||||
engine.verify(signature);
|
||||
}
|
||||
|
||||
/** Verify will fail if the input public key cannot be converted to EdDSA public key. */
|
||||
@Test
|
||||
public void verifyWithNonSupportedKeyTypeFails() {
|
||||
EdDSAEngine engine = new EdDSAEngine();
|
||||
KeyPair keyPair = Crypto.deriveKeyPairFromEntropy(Crypto.ECDSA_SECP256K1_SHA256, BigInteger.valueOf(SEED));
|
||||
assertThatExceptionOfType(InvalidKeyException.class).isThrownBy(() ->
|
||||
engine.initVerify(keyPair.getPublic())
|
||||
);
|
||||
}
|
||||
}
|
@ -8,15 +8,10 @@ import net.corda.core.crypto.Crypto.RSA_SHA256
|
||||
import net.corda.core.crypto.Crypto.SPHINCS256_SHA256
|
||||
import net.corda.core.crypto.internal.PlatformSecureRandomService
|
||||
import net.corda.core.utilities.OpaqueBytes
|
||||
import net.i2p.crypto.eddsa.EdDSAKey
|
||||
import net.i2p.crypto.eddsa.EdDSAPrivateKey
|
||||
import net.i2p.crypto.eddsa.EdDSAPublicKey
|
||||
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.EdDSAPublicKeySpec
|
||||
import org.apache.commons.lang3.ArrayUtils.EMPTY_BYTE_ARRAY
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.assertj.core.api.Assertions.assertThatIllegalArgumentException
|
||||
import org.assertj.core.api.Assertions.assertThatThrownBy
|
||||
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo
|
||||
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo
|
||||
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPrivateKey
|
||||
@ -24,15 +19,18 @@ import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey
|
||||
import org.bouncycastle.jce.ECNamedCurveTable
|
||||
import org.bouncycastle.jce.interfaces.ECKey
|
||||
import org.bouncycastle.jce.spec.ECNamedCurveParameterSpec
|
||||
import org.bouncycastle.math.ec.rfc8032.Ed25519
|
||||
import org.bouncycastle.pqc.jcajce.provider.sphincs.BCSphincs256PrivateKey
|
||||
import org.bouncycastle.pqc.jcajce.provider.sphincs.BCSphincs256PublicKey
|
||||
import org.junit.Assert.assertNotEquals
|
||||
import org.junit.Ignore
|
||||
import org.junit.Test
|
||||
import java.math.BigInteger
|
||||
import java.security.KeyPairGenerator
|
||||
import java.security.SecureRandom
|
||||
import java.security.Security
|
||||
import java.security.interfaces.EdECPrivateKey
|
||||
import java.security.interfaces.EdECPublicKey
|
||||
import java.security.spec.NamedParameterSpec
|
||||
import java.util.Random
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertFalse
|
||||
@ -132,11 +130,8 @@ class CryptoUtilsTest {
|
||||
|
||||
// test on malformed signatures (even if they change for 1 bit)
|
||||
signedData[0] = signedData[0].inc()
|
||||
try {
|
||||
assertThatThrownBy {
|
||||
Crypto.doVerify(pubKey, signedData, testBytes)
|
||||
fail()
|
||||
} catch (e: Exception) {
|
||||
// expected
|
||||
}
|
||||
}
|
||||
|
||||
@ -498,9 +493,9 @@ class CryptoUtilsTest {
|
||||
val (privEd, pubEd) = keyPairEd
|
||||
|
||||
assertEquals(privEd.algorithm, "EdDSA")
|
||||
assertEquals((privEd as EdDSAKey).params, EdDSANamedCurveTable.getByName("ED25519"))
|
||||
assertEquals((privEd as EdECPrivateKey).params.name, NamedParameterSpec.ED25519.name)
|
||||
assertEquals(pubEd.algorithm, "EdDSA")
|
||||
assertEquals((pubEd as EdDSAKey).params, EdDSANamedCurveTable.getByName("ED25519"))
|
||||
assertEquals((pubEd as EdECPublicKey).params.name, NamedParameterSpec.ED25519.name)
|
||||
}
|
||||
|
||||
@Test(timeout=300_000)
|
||||
@ -659,18 +654,23 @@ class CryptoUtilsTest {
|
||||
|
||||
@Test(timeout=300_000)
|
||||
fun `Check EdDSA public key on curve`() {
|
||||
val keyPairEdDSA = Crypto.generateKeyPair(EDDSA_ED25519_SHA512)
|
||||
val pubEdDSA = keyPairEdDSA.public
|
||||
assertTrue(Crypto.publicKeyOnCurve(EDDSA_ED25519_SHA512, pubEdDSA))
|
||||
// Use R1 curve for check.
|
||||
assertFalse(Crypto.publicKeyOnCurve(ECDSA_SECP256R1_SHA256, pubEdDSA))
|
||||
// Check for point at infinity.
|
||||
val pubKeySpec = EdDSAPublicKeySpec((EDDSA_ED25519_SHA512.algSpec as EdDSANamedCurveSpec).curve.getZero(GroupElement.Representation.P3), EDDSA_ED25519_SHA512.algSpec as EdDSANamedCurveSpec)
|
||||
assertFalse(Crypto.publicKeyOnCurve(EDDSA_ED25519_SHA512, EdDSAPublicKey(pubKeySpec)))
|
||||
repeat(100) {
|
||||
val keyPairEdDSA = Crypto.generateKeyPair(EDDSA_ED25519_SHA512)
|
||||
val pubEdDSA = keyPairEdDSA.public
|
||||
assertTrue(Crypto.publicKeyOnCurve(EDDSA_ED25519_SHA512, pubEdDSA))
|
||||
// Use R1 curve for check.
|
||||
assertFalse(Crypto.publicKeyOnCurve(ECDSA_SECP256R1_SHA256, pubEdDSA))
|
||||
}
|
||||
val invalidKey = run {
|
||||
val bytes = ByteArray(Ed25519.PUBLIC_KEY_SIZE).also { it[0] = 2 }
|
||||
val encoded = SubjectPublicKeyInfo(EDDSA_ED25519_SHA512.signatureOID, bytes).encoded
|
||||
Crypto.decodePublicKey(encoded)
|
||||
}
|
||||
assertThat(invalidKey).isInstanceOf(EdECPublicKey::class.java)
|
||||
assertThat(Crypto.publicKeyOnCurve(EDDSA_ED25519_SHA512, invalidKey)).isFalse()
|
||||
}
|
||||
|
||||
@Test(timeout = 300_000)
|
||||
@Ignore("TODO JDK17: Fixme")
|
||||
fun `Unsupported EC public key type on curve`() {
|
||||
val keyGen = KeyPairGenerator.getInstance("EC") // sun.security.ec.ECPublicKeyImpl
|
||||
keyGen.initialize(256, newSecureRandom())
|
||||
@ -772,10 +772,8 @@ class CryptoUtilsTest {
|
||||
// Check scheme.
|
||||
assertEquals(priv.algorithm, dpriv.algorithm)
|
||||
assertEquals(pub.algorithm, dpub.algorithm)
|
||||
assertTrue(dpriv is EdDSAPrivateKey)
|
||||
assertTrue(dpub is EdDSAPublicKey)
|
||||
assertEquals((dpriv as EdDSAKey).params, EdDSANamedCurveTable.getByName("ED25519"))
|
||||
assertEquals((dpub as EdDSAKey).params, EdDSANamedCurveTable.getByName("ED25519"))
|
||||
assertEquals((dpriv as EdECPrivateKey).params.name, NamedParameterSpec.ED25519.name)
|
||||
assertEquals((dpub as EdECPublicKey).params.name, NamedParameterSpec.ED25519.name)
|
||||
assertEquals(Crypto.findSignatureScheme(dpriv), EDDSA_ED25519_SHA512)
|
||||
assertEquals(Crypto.findSignatureScheme(dpub), EDDSA_ED25519_SHA512)
|
||||
|
||||
|
@ -1,17 +1,16 @@
|
||||
package net.corda.core.crypto
|
||||
|
||||
import net.corda.core.crypto.Crypto.EDDSA_ED25519_SHA512
|
||||
import net.corda.core.crypto.internal.Instances.withSignature
|
||||
import net.corda.core.utilities.hexToByteArray
|
||||
import net.corda.core.utilities.toHex
|
||||
import net.i2p.crypto.eddsa.EdDSAPrivateKey
|
||||
import net.i2p.crypto.eddsa.EdDSASecurityProvider
|
||||
import net.i2p.crypto.eddsa.spec.EdDSANamedCurveSpec
|
||||
import net.i2p.crypto.eddsa.spec.EdDSAPrivateKeySpec
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo
|
||||
import org.junit.Test
|
||||
import java.security.PrivateKey
|
||||
import java.security.Signature
|
||||
import java.util.Locale
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertNotEquals
|
||||
import java.security.spec.EdECPrivateKeySpec
|
||||
import java.security.spec.NamedParameterSpec
|
||||
import java.security.spec.X509EncodedKeySpec
|
||||
|
||||
/**
|
||||
* Testing PureEdDSA Ed25519 using test vectors from https://tools.ietf.org/html/rfc8032#section-7.1
|
||||
@ -19,8 +18,6 @@ import kotlin.test.assertNotEquals
|
||||
class EdDSATests {
|
||||
@Test(timeout=300_000)
|
||||
fun `PureEdDSA Ed25519 test vectors`() {
|
||||
val edParams = Crypto.EDDSA_ED25519_SHA512.algSpec as EdDSANamedCurveSpec
|
||||
|
||||
// MESSAGE (length 0 bytes).
|
||||
val testVector1 = SignatureTestVector(
|
||||
"9d61b19deffd5a60ba844af492ec2cc4" +
|
||||
@ -152,11 +149,24 @@ class EdDSATests {
|
||||
"3dca179c138ac17ad9bef1177331a704"
|
||||
)
|
||||
|
||||
val keyFactory = EDDSA_ED25519_SHA512.keyFactory
|
||||
|
||||
val testVectors = listOf(testVector1, testVector2, testVector3, testVector1024, testVectorSHAabc)
|
||||
testVectors.forEach {
|
||||
val privateKey = EdDSAPrivateKey(EdDSAPrivateKeySpec(it.privateKeyHex.hexToByteArray(), edParams))
|
||||
assertEquals(it.signatureOutputHex, doSign(privateKey, it.messageToSignHex.hexToByteArray()).toHex()
|
||||
.lowercase(Locale.getDefault()))
|
||||
testVectors.forEach { testVector ->
|
||||
val messageBytes = testVector.messageToSignHex.hexToByteArray()
|
||||
val signatureBytes = testVector.signatureOutputHex.hexToByteArray()
|
||||
// Check the private key produces the expected signature
|
||||
val privateKey = keyFactory.generatePrivate(EdECPrivateKeySpec(NamedParameterSpec.ED25519, testVector.privateKeyHex.hexToByteArray()))
|
||||
assertThat(doSign(privateKey, messageBytes)).isEqualTo(signatureBytes)
|
||||
// Check the public key verifies the signature
|
||||
val result = withSignature(EDDSA_ED25519_SHA512) { signature ->
|
||||
val publicKeyInfo = SubjectPublicKeyInfo(EDDSA_ED25519_SHA512.signatureOID, testVector.publicKeyHex.hexToByteArray())
|
||||
val publicKey = keyFactory.generatePublic(X509EncodedKeySpec(publicKeyInfo.encoded))
|
||||
signature.initVerify(publicKey)
|
||||
signature.update(messageBytes)
|
||||
signature.verify(signatureBytes)
|
||||
}
|
||||
assertThat(result).isTrue()
|
||||
}
|
||||
|
||||
// Test vector for the variant Ed25519ctx, expected to fail.
|
||||
@ -172,9 +182,8 @@ class EdDSATests {
|
||||
"5a5ca2df6668346291c2043d4eb3e90d"
|
||||
)
|
||||
|
||||
val privateKey = EdDSAPrivateKey(EdDSAPrivateKeySpec(testVectorEd25519ctx.privateKeyHex.hexToByteArray(), edParams))
|
||||
assertNotEquals(testVectorEd25519ctx.signatureOutputHex, doSign(privateKey, testVectorEd25519ctx.messageToSignHex.hexToByteArray()).toHex()
|
||||
.lowercase(Locale.getDefault()))
|
||||
val privateKey = keyFactory.generatePrivate(EdECPrivateKeySpec(NamedParameterSpec.ED25519, testVectorEd25519ctx.privateKeyHex.hexToByteArray()))
|
||||
assertThat(doSign(privateKey, testVectorEd25519ctx.messageToSignHex.hexToByteArray()).toHex().lowercase()).isNotEqualTo(testVectorEd25519ctx.signatureOutputHex)
|
||||
}
|
||||
|
||||
/** A test vector object for digital signature schemes. */
|
||||
@ -185,9 +194,10 @@ class EdDSATests {
|
||||
|
||||
// Required to implement a custom doSign function, because Corda's Crypto.doSign does not allow empty messages (testVector1).
|
||||
private fun doSign(privateKey: PrivateKey, clearData: ByteArray): ByteArray {
|
||||
val signature = Signature.getInstance(Crypto.EDDSA_ED25519_SHA512.signatureName, EdDSASecurityProvider())
|
||||
signature.initSign(privateKey)
|
||||
signature.update(clearData)
|
||||
return signature.sign()
|
||||
return withSignature(EDDSA_ED25519_SHA512) { signature ->
|
||||
signature.initSign(privateKey)
|
||||
signature.update(clearData)
|
||||
signature.sign()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1426,7 +1426,6 @@
|
||||
<ID>TooManyFunctions:ActionExecutorImpl.kt$ActionExecutorImpl : ActionExecutor</ID>
|
||||
<ID>TooManyFunctions:AppendOnlyPersistentMap.kt$AppendOnlyPersistentMapBase<K, V, E, out EK></ID>
|
||||
<ID>TooManyFunctions:ArtemisTcpTransport.kt$ArtemisTcpTransport$Companion</ID>
|
||||
<ID>TooManyFunctions:BCCryptoService.kt$BCCryptoService : CryptoService</ID>
|
||||
<ID>TooManyFunctions:BFTSmart.kt$BFTSmart$Replica : DefaultRecoverable</ID>
|
||||
<ID>TooManyFunctions:BaseTransaction.kt$BaseTransaction : NamedByHash</ID>
|
||||
<ID>TooManyFunctions:ClassCarpenter.kt$ClassCarpenterImpl : ClassCarpenter</ID>
|
||||
@ -1669,9 +1668,6 @@
|
||||
<ID>WildcardImport:AttachmentsClassLoader.kt$import net.corda.core.serialization.*</ID>
|
||||
<ID>WildcardImport:AttachmentsClassLoaderStaticContractTests.kt$import net.corda.core.contracts.*</ID>
|
||||
<ID>WildcardImport:AutoOfferFlow.kt$import net.corda.core.flows.*</ID>
|
||||
<ID>WildcardImport:BCCryptoService.kt$import java.security.*</ID>
|
||||
<ID>WildcardImport:BCCryptoService.kt$import net.corda.nodeapi.internal.cryptoservice.*</ID>
|
||||
<ID>WildcardImport:BCCryptoServiceTests.kt$import java.security.*</ID>
|
||||
<ID>WildcardImport:BFTNotaryServiceTests.kt$import net.corda.core.crypto.*</ID>
|
||||
<ID>WildcardImport:BFTNotaryServiceTests.kt$import net.corda.testing.node.internal.*</ID>
|
||||
<ID>WildcardImport:BFTSmart.kt$import net.corda.core.crypto.*</ID>
|
||||
|
@ -15,7 +15,6 @@ dependencies {
|
||||
testImplementation "org.junit.jupiter:junit-jupiter-api:${junit_jupiter_version}"
|
||||
testImplementation "junit:junit:$junit_version"
|
||||
testImplementation "org.mockito.kotlin:mockito-kotlin:$mockito_kotlin_version"
|
||||
testImplementation "net.i2p.crypto:eddsa:$eddsa_version"
|
||||
testImplementation "com.typesafe:config:$typesafe_config_version"
|
||||
testImplementation "io.dropwizard.metrics:metrics-core:$metrics_version"
|
||||
testImplementation "co.paralleluniverse:quasar-core:$quasar_version"
|
||||
|
@ -1,6 +1,5 @@
|
||||
package net.corda.nodeapitests.internal.crypto
|
||||
|
||||
|
||||
import io.netty.handler.ssl.ClientAuth
|
||||
import io.netty.handler.ssl.SslContextBuilder
|
||||
import io.netty.handler.ssl.SslProvider
|
||||
@ -52,7 +51,6 @@ import net.corda.testing.core.BOB_NAME
|
||||
import net.corda.testing.core.TestIdentity
|
||||
import net.corda.testing.driver.internal.incrementalPortAllocation
|
||||
import net.corda.testing.internal.createDevIntermediateCaCertPath
|
||||
import net.i2p.crypto.eddsa.EdDSAPrivateKey
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.bouncycastle.asn1.x509.AuthorityKeyIdentifier
|
||||
import org.bouncycastle.asn1.x509.BasicConstraints
|
||||
@ -60,9 +58,7 @@ import org.bouncycastle.asn1.x509.CRLDistPoint
|
||||
import org.bouncycastle.asn1.x509.Extension
|
||||
import org.bouncycastle.asn1.x509.KeyUsage
|
||||
import org.bouncycastle.asn1.x509.SubjectKeyIdentifier
|
||||
import org.bouncycastle.jcajce.provider.asymmetric.edec.BCEdDSAPrivateKey
|
||||
import org.bouncycastle.pqc.jcajce.provider.sphincs.BCSphincs256PrivateKey
|
||||
import org.junit.Ignore
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.rules.TemporaryFolder
|
||||
@ -77,7 +73,8 @@ import java.security.KeyPair
|
||||
import java.security.PrivateKey
|
||||
import java.security.cert.CertPath
|
||||
import java.security.cert.X509Certificate
|
||||
import java.util.*
|
||||
import java.security.interfaces.EdECPrivateKey
|
||||
import java.util.Date
|
||||
import javax.net.ssl.SSLContext
|
||||
import javax.net.ssl.SSLParameters
|
||||
import javax.net.ssl.SSLServerSocket
|
||||
@ -93,7 +90,6 @@ import kotlin.test.assertNull
|
||||
import kotlin.test.assertTrue
|
||||
import kotlin.test.fail
|
||||
|
||||
@Ignore("TODO JDK17: Fixme")
|
||||
class X509UtilitiesTest {
|
||||
private companion object {
|
||||
val ALICE = TestIdentity(ALICE_NAME, 70).party
|
||||
@ -122,9 +118,9 @@ class X509UtilitiesTest {
|
||||
|
||||
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),
|
||||
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, EdECPrivateKey::class.java, EdECPrivateKey::class.java),
|
||||
// By default, JKS returns SUN RSA key.
|
||||
Triple(SPHINCS256_SHA256, BCSphincs256PrivateKey::class.java, BCSphincs256PrivateKey::class.java)
|
||||
)
|
||||
@ -136,8 +132,7 @@ class X509UtilitiesTest {
|
||||
|
||||
@Test(timeout=300_000)
|
||||
fun `create valid self-signed CA certificate`() {
|
||||
Crypto.supportedSignatureSchemes().filter { it != COMPOSITE_KEY
|
||||
&& ( it != SPHINCS256_SHA256)}.forEach { validSelfSignedCertificate(it) }
|
||||
Crypto.supportedSignatureSchemes().filter { it != COMPOSITE_KEY }.forEach { validSelfSignedCertificate(it) }
|
||||
}
|
||||
|
||||
private fun validSelfSignedCertificate(signatureScheme: SignatureScheme) {
|
||||
@ -158,7 +153,7 @@ class X509UtilitiesTest {
|
||||
|
||||
@Test(timeout=300_000)
|
||||
fun `load and save a PEM file certificate`() {
|
||||
Crypto.supportedSignatureSchemes().filter { it != COMPOSITE_KEY }.forEach { loadSavePEMCert(it) }
|
||||
Crypto.supportedSignatureSchemes().filter { it != COMPOSITE_KEY }.forEach(::loadSavePEMCert)
|
||||
}
|
||||
|
||||
private fun loadSavePEMCert(signatureScheme: SignatureScheme) {
|
||||
@ -172,8 +167,7 @@ class X509UtilitiesTest {
|
||||
|
||||
@Test(timeout=300_000)
|
||||
fun `create valid server certificate chain`() {
|
||||
certChainSchemeCombinations.filter{ it.first != SPHINCS256_SHA256 }
|
||||
.forEach { createValidServerCertChain(it.first, it.second) }
|
||||
certChainSchemeCombinations.forEach { createValidServerCertChain(it.first, it.second) }
|
||||
}
|
||||
|
||||
private fun createValidServerCertChain(signatureSchemeRoot: SignatureScheme, signatureSchemeChild: SignatureScheme) {
|
||||
@ -451,13 +445,11 @@ class X509UtilitiesTest {
|
||||
schemeToKeyTypes.forEach { getCorrectKeyFromKeystore(it.first, it.second, it.third) }
|
||||
}
|
||||
|
||||
private fun <U, C> getCorrectKeyFromKeystore(signatureScheme: SignatureScheme, uncastedClass: Class<U>, castedClass: Class<C>) {
|
||||
private fun <R, S> getCorrectKeyFromKeystore(signatureScheme: SignatureScheme, rawClass: Class<R>, supportedClass: Class<S>) {
|
||||
val keyPair = generateKeyPair(signatureScheme)
|
||||
val (keyFromKeystore, keyFromKeystoreCasted) = storeAndGetKeysFromKeystore(keyPair)
|
||||
if (uncastedClass == EdDSAPrivateKey::class.java && keyFromKeystore !is BCEdDSAPrivateKey) {
|
||||
assertThat(keyFromKeystore).isInstanceOf(uncastedClass)
|
||||
}
|
||||
assertThat(keyFromKeystoreCasted).isInstanceOf(castedClass)
|
||||
val (rawKey, supportedKey) = storeAndGetKeysFromKeystore(keyPair)
|
||||
assertThat(rawKey).isInstanceOf(rawClass)
|
||||
assertThat(supportedKey).isInstanceOf(supportedClass)
|
||||
}
|
||||
|
||||
private fun storeAndGetKeysFromKeystore(keyPair: KeyPair): Pair<Key, PrivateKey> {
|
||||
@ -466,9 +458,9 @@ class X509UtilitiesTest {
|
||||
val keyStore = loadOrCreateKeyStore(tempFile("testKeystore.jks"), "keystorepassword")
|
||||
keyStore.setKeyEntry("Key", keyPair.private, "keypassword".toCharArray(), arrayOf(selfSignCert))
|
||||
|
||||
val keyFromKeystore = keyStore.getKey("Key", "keypassword".toCharArray())
|
||||
val keyFromKeystoreCasted = keyStore.getSupportedKey("Key", "keypassword")
|
||||
return Pair(keyFromKeystore, keyFromKeystoreCasted)
|
||||
val rawKey = keyStore.getKey("Key", "keypassword".toCharArray())
|
||||
val supportedKey = keyStore.getSupportedKey("Key", "keypassword")
|
||||
return Pair(rawKey, supportedKey)
|
||||
}
|
||||
|
||||
@Test(timeout=300_000)
|
||||
|
@ -57,7 +57,6 @@ dependencies {
|
||||
implementation "io.reactivex:rxjava:$rxjava_version"
|
||||
implementation "javax.persistence:javax.persistence-api:2.2"
|
||||
implementation "org.hibernate:hibernate-core:$hibernate_version"
|
||||
implementation "net.i2p.crypto:eddsa:$eddsa_version"
|
||||
implementation "co.paralleluniverse:quasar-osgi-annotations:$quasar_version"
|
||||
|
||||
runtimeOnly 'com.mattbertolini:liquibase-slf4j:2.0.0'
|
||||
|
@ -78,7 +78,7 @@ interface CertificateStore : Iterable<Pair<String, X509Certificate>> {
|
||||
}
|
||||
|
||||
fun setCertPathOnly(alias: String, certificates: List<X509Certificate>) {
|
||||
// In case CryptoService and CertificateStore share the same KeyStore (i.e., when BCCryptoService is used),
|
||||
// In case CryptoService and CertificateStore share the same KeyStore (i.e., when DefaultCryptoService is used),
|
||||
// extract the existing key from the Keystore and store it again along with the new certificate chain.
|
||||
// This is because KeyStores do not support updateKeyEntry and thus we cannot update the certificate chain
|
||||
// without overriding the key entry.
|
||||
|
@ -1,6 +1,5 @@
|
||||
package net.corda.nodeapi.internal.crypto
|
||||
|
||||
import net.corda.core.crypto.Crypto.SPHINCS256_SHA256
|
||||
import net.corda.core.crypto.SignatureScheme
|
||||
import net.corda.core.crypto.internal.Instances
|
||||
import org.bouncycastle.asn1.x509.AlgorithmIdentifier
|
||||
@ -27,9 +26,7 @@ object ContentSignerBuilder {
|
||||
|
||||
val sig = try {
|
||||
signatureInstance.apply {
|
||||
// TODO special handling for Sphincs due to a known BouncyCastle's Sphincs bug we reported.
|
||||
// It is fixed in BC 161b12, so consider updating the below if-statement after updating BouncyCastle.
|
||||
if (random != null && signatureScheme != SPHINCS256_SHA256) {
|
||||
if (random != null) {
|
||||
initSign(privateKey, random)
|
||||
} else {
|
||||
initSign(privateKey)
|
||||
@ -48,7 +45,7 @@ object ContentSignerBuilder {
|
||||
|
||||
private class SignatureOutputStream(private val sig: Signature, private val optimised: Boolean) : OutputStream() {
|
||||
private var alreadySigned = false
|
||||
internal val signature: ByteArray by lazy {
|
||||
val signature: ByteArray by lazy {
|
||||
try {
|
||||
alreadySigned = true
|
||||
sig.sign()
|
||||
|
@ -69,7 +69,7 @@ import kotlin.io.path.reader
|
||||
import kotlin.io.path.writer
|
||||
|
||||
object X509Utilities {
|
||||
// Note that this default value only applies to BCCryptoService. Other implementations of CryptoService may have to use different
|
||||
// Note that this default value only applies to DefaultCryptoService. Other implementations of CryptoService may have to use different
|
||||
// schemes (for instance `UtimacoCryptoService.DEFAULT_IDENTITY_SIGNATURE_SCHEME`).
|
||||
val DEFAULT_IDENTITY_SIGNATURE_SCHEME = Crypto.EDDSA_ED25519_SHA512
|
||||
val DEFAULT_TLS_SIGNATURE_SCHEME = Crypto.ECDSA_SECP256R1_SHA256
|
||||
@ -303,10 +303,10 @@ object X509Utilities {
|
||||
crlDistPoint: String? = null,
|
||||
crlIssuer: X500Name? = null): X509Certificate {
|
||||
val builder = createPartialCertificate(certificateType, issuer, issuerPublicKey, subject, subjectPublicKey, validityWindow, nameConstraints, crlDistPoint, crlIssuer)
|
||||
return builder.build(issuerSigner).run {
|
||||
require(isValidOn(Date())){"Certificate is not valid at instant now"}
|
||||
toJca()
|
||||
}
|
||||
val certificate = builder.build(issuerSigner).toJca()
|
||||
certificate.checkValidity(Date())
|
||||
certificate.verify(issuerPublicKey)
|
||||
return certificate
|
||||
}
|
||||
|
||||
/**
|
||||
@ -340,18 +340,22 @@ object X509Utilities {
|
||||
validityWindow,
|
||||
nameConstraints,
|
||||
crlDistPoint,
|
||||
crlIssuer)
|
||||
return builder.build(signer).run {
|
||||
require(isValidOn(Date())){"Certificate is not valid at instant now"}
|
||||
require(isSignatureValid(JcaContentVerifierProviderBuilder().build(issuerKeyPair.public))){"Invalid signature"}
|
||||
toJca()
|
||||
}
|
||||
crlIssuer
|
||||
)
|
||||
val certificate = builder.build(signer).toJca()
|
||||
certificate.checkValidity(Date())
|
||||
certificate.verify(issuerKeyPair.public)
|
||||
return certificate
|
||||
}
|
||||
|
||||
/**
|
||||
* Create certificate signing request using provided information.
|
||||
*/
|
||||
fun createCertificateSigningRequest(subject: X500Principal, email: String, publicKey: PublicKey, contentSigner: ContentSigner, certRole: CertRole = CertRole.NODE_CA): PKCS10CertificationRequest {
|
||||
fun createCertificateSigningRequest(subject: X500Principal,
|
||||
email: String,
|
||||
publicKey: PublicKey,
|
||||
contentSigner: ContentSigner,
|
||||
certRole: CertRole = CertRole.NODE_CA): PKCS10CertificationRequest {
|
||||
return JcaPKCS10CertificationRequestBuilder(subject, publicKey)
|
||||
.addAttribute(BCStyle.E, DERUTF8String(email))
|
||||
.addAttribute(ASN1ObjectIdentifier(CordaOID.X509_EXTENSION_CORDA_ROLE), certRole)
|
||||
@ -410,7 +414,7 @@ object X509Utilities {
|
||||
}
|
||||
|
||||
// Assuming cert type to role is 1:1
|
||||
val CertRole.certificateType: CertificateType get() = CertificateType.values().first { it.role == this }
|
||||
val CertRole.certificateType: CertificateType get() = CertificateType.entries.first { it.role == this }
|
||||
|
||||
/**
|
||||
* Convert a [X509Certificate] into BouncyCastle's [X509CertificateHolder].
|
||||
|
@ -1,9 +1,8 @@
|
||||
package net.corda.nodeapi.internal.cryptoservice.bouncycastle
|
||||
package net.corda.nodeapi.internal.cryptoservice
|
||||
|
||||
import net.corda.core.crypto.Crypto
|
||||
import net.corda.core.crypto.SignatureScheme
|
||||
import net.corda.core.crypto.internal.Instances.getSignatureInstance
|
||||
import net.corda.core.crypto.internal.cordaBouncyCastleProvider
|
||||
import net.corda.core.crypto.internal.Instances.withSignature
|
||||
import net.corda.core.crypto.newSecureRandom
|
||||
import net.corda.core.crypto.sha256
|
||||
import net.corda.core.utilities.detailedLogger
|
||||
@ -14,27 +13,30 @@ import net.corda.nodeapi.internal.crypto.ContentSignerBuilder
|
||||
import net.corda.nodeapi.internal.crypto.X509Utilities
|
||||
import net.corda.nodeapi.internal.crypto.loadOrCreateKeyStore
|
||||
import net.corda.nodeapi.internal.crypto.save
|
||||
import net.corda.nodeapi.internal.cryptoservice.*
|
||||
import net.corda.nodeapi.internal.cryptoservice.CryptoService
|
||||
import net.corda.nodeapi.internal.cryptoservice.CryptoServiceException
|
||||
import org.bouncycastle.operator.ContentSigner
|
||||
import java.nio.file.Path
|
||||
import java.security.*
|
||||
import java.security.KeyPair
|
||||
import java.security.KeyPairGenerator
|
||||
import java.security.KeyStore
|
||||
import java.security.PrivateKey
|
||||
import java.security.Provider
|
||||
import java.security.PublicKey
|
||||
import java.security.Signature
|
||||
import java.security.spec.ECGenParameterSpec
|
||||
import javax.crypto.Cipher
|
||||
import javax.crypto.KeyGenerator
|
||||
import javax.security.auth.x500.X500Principal
|
||||
|
||||
/**
|
||||
* Basic implementation of a [CryptoService] that uses BouncyCastle for cryptographic operations
|
||||
* Basic implementation of a [CryptoService] which uses Corda's [Provider]s for cryptographic operations
|
||||
* and a Java KeyStore in the form of [CertificateStore] to store private keys.
|
||||
* This service reuses the [NodeConfiguration.signingCertificateStore] to store keys.
|
||||
*
|
||||
* The [wrappingKeyStorePath] must be provided in order to execute any wrapping operations (e.g. [createWrappingKey], [generateWrappedKeyPair])
|
||||
*/
|
||||
class BCCryptoService(private val legalName: X500Principal,
|
||||
private val certificateStoreSupplier: CertificateStoreSupplier,
|
||||
private val wrappingKeyStorePath: Path? = null) : CryptoService {
|
||||
@Suppress("TooManyFunctions")
|
||||
class DefaultCryptoService(private val legalName: X500Principal,
|
||||
private val certificateStoreSupplier: CertificateStoreSupplier,
|
||||
private val wrappingKeyStorePath: Path? = null) : CryptoService {
|
||||
|
||||
private companion object {
|
||||
val detailedLogger = detailedLogger()
|
||||
@ -97,7 +99,7 @@ class BCCryptoService(private val legalName: X500Principal,
|
||||
|
||||
private fun signWithAlgorithm(alias: String, data: ByteArray, signAlgorithm: String): ByteArray {
|
||||
val privateKey = certificateStore.query { getPrivateKey(alias, certificateStore.entryPassword) }
|
||||
val signature = Signature.getInstance(signAlgorithm, cordaBouncyCastleProvider)
|
||||
val signature = Signature.getInstance(signAlgorithm)
|
||||
detailedLogger.trace { "CryptoService(action=signing_start;alias=$alias;algorithm=$signAlgorithm)" }
|
||||
signature.initSign(privateKey, newSecureRandom())
|
||||
signature.update(data)
|
||||
@ -126,7 +128,7 @@ class BCCryptoService(private val legalName: X500Principal,
|
||||
|
||||
/**
|
||||
* If a node is running in [NodeConfiguration.devMode] and for backwards compatibility purposes, the same [KeyStore]
|
||||
* is reused outside [BCCryptoService] to update certificate paths. [resyncKeystore] will sync [BCCryptoService]'s
|
||||
* is reused outside [DefaultCryptoService] to update certificate paths. [resyncKeystore] will sync [DefaultCryptoService]'s
|
||||
* loaded [certificateStore] in memory with the contents of the corresponding [KeyStore] file.
|
||||
*/
|
||||
fun resyncKeystore() {
|
||||
@ -178,7 +180,7 @@ class BCCryptoService(private val legalName: X500Principal,
|
||||
}
|
||||
|
||||
val wrappingKey = wrappingKeyStore.getKey(masterKeyAlias, certificateStore.entryPassword.toCharArray())
|
||||
val cipher = Cipher.getInstance("AESWRAPPAD", cordaBouncyCastleProvider)
|
||||
val cipher = Cipher.getInstance("AESWRAPPAD")
|
||||
cipher.init(Cipher.WRAP_MODE, wrappingKey)
|
||||
|
||||
val keyPairGenerator = keyPairGeneratorFromScheme(childKeyScheme)
|
||||
@ -199,22 +201,23 @@ class BCCryptoService(private val legalName: X500Principal,
|
||||
1 -> "AESWRAPPAD"
|
||||
else -> "AES"
|
||||
}
|
||||
val cipher = Cipher.getInstance(algorithm, cordaBouncyCastleProvider)
|
||||
val cipher = Cipher.getInstance(algorithm)
|
||||
cipher.init(Cipher.UNWRAP_MODE, wrappingKey)
|
||||
|
||||
val privateKey = cipher.unwrap(wrappedPrivateKey.keyMaterial, keyAlgorithmFromScheme(wrappedPrivateKey.signatureScheme), Cipher.PRIVATE_KEY) as PrivateKey
|
||||
|
||||
val signature = getSignatureInstance(wrappedPrivateKey.signatureScheme.signatureName, cordaBouncyCastleProvider)
|
||||
signature.initSign(privateKey, newSecureRandom())
|
||||
signature.update(payloadToSign)
|
||||
return signature.sign()
|
||||
return withSignature(wrappedPrivateKey.signatureScheme) { signature ->
|
||||
signature.initSign(privateKey, newSecureRandom())
|
||||
signature.update(payloadToSign)
|
||||
signature.sign()
|
||||
}
|
||||
}
|
||||
|
||||
override fun getWrappingMode(): WrappingMode? = WrappingMode.DEGRADED_WRAPPED
|
||||
override fun getWrappingMode(): WrappingMode = WrappingMode.DEGRADED_WRAPPED
|
||||
|
||||
private fun keyPairGeneratorFromScheme(scheme: SignatureScheme): KeyPairGenerator {
|
||||
val algorithm = keyAlgorithmFromScheme(scheme)
|
||||
val keyPairGenerator = KeyPairGenerator.getInstance(algorithm, cordaBouncyCastleProvider)
|
||||
val keyPairGenerator = KeyPairGenerator.getInstance(algorithm)
|
||||
when (scheme) {
|
||||
Crypto.ECDSA_SECP256R1_SHA256 -> keyPairGenerator.initialize(ECGenParameterSpec("secp256r1"))
|
||||
Crypto.ECDSA_SECP256K1_SHA256 -> keyPairGenerator.initialize(ECGenParameterSpec("secp256k1"))
|
@ -20,7 +20,6 @@ import de.javakaffee.kryoserializers.guava.ImmutableSortedSetSerializer
|
||||
import net.corda.core.contracts.ContractAttachment
|
||||
import net.corda.core.contracts.ContractClassName
|
||||
import net.corda.core.contracts.PrivacySalt
|
||||
import net.corda.core.crypto.CompositeKey
|
||||
import net.corda.core.crypto.SecureHash
|
||||
import net.corda.core.identity.PartyAndCertificate
|
||||
import net.corda.core.internal.AbstractAttachment
|
||||
@ -40,14 +39,6 @@ import net.corda.core.utilities.toNonEmptySet
|
||||
import net.corda.serialization.internal.DefaultWhitelist
|
||||
import net.corda.serialization.internal.GeneratedAttachment
|
||||
import net.corda.serialization.internal.MutableClassWhitelist
|
||||
import net.i2p.crypto.eddsa.EdDSAPrivateKey
|
||||
import net.i2p.crypto.eddsa.EdDSAPublicKey
|
||||
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPrivateKey
|
||||
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey
|
||||
import org.bouncycastle.jcajce.provider.asymmetric.rsa.BCRSAPrivateCrtKey
|
||||
import org.bouncycastle.jcajce.provider.asymmetric.rsa.BCRSAPublicKey
|
||||
import org.bouncycastle.pqc.jcajce.provider.sphincs.BCSphincs256PrivateKey
|
||||
import org.bouncycastle.pqc.jcajce.provider.sphincs.BCSphincs256PublicKey
|
||||
import org.objenesis.instantiator.ObjectInstantiator
|
||||
import org.objenesis.strategy.InstantiatorStrategy
|
||||
import org.objenesis.strategy.StdInstantiatorStrategy
|
||||
@ -62,14 +53,13 @@ import java.security.PublicKey
|
||||
import java.security.cert.CertPath
|
||||
import java.security.cert.X509Certificate
|
||||
import java.util.*
|
||||
import kotlin.collections.ArrayList
|
||||
|
||||
object DefaultKryoCustomizer {
|
||||
private val serializationWhitelists: List<SerializationWhitelist> by lazy {
|
||||
ServiceLoader.load(SerializationWhitelist::class.java, this.javaClass.classLoader).toList() + DefaultWhitelist
|
||||
}
|
||||
|
||||
fun customize(kryo: Kryo, publicKeySerializer: Serializer<PublicKey> = PublicKeySerializer): Kryo {
|
||||
fun customize(kryo: Kryo): Kryo {
|
||||
return kryo.apply {
|
||||
isRegistrationRequired = false
|
||||
references = true
|
||||
@ -110,6 +100,8 @@ object DefaultKryoCustomizer {
|
||||
// Please add any new registrations to the end.
|
||||
|
||||
addDefaultSerializer(LinkedHashMapIteratorSerializer.getIterator()::class.java.superclass, LinkedHashMapIteratorSerializer)
|
||||
addDefaultSerializer(PublicKey::class.java, PublicKeySerializer)
|
||||
addDefaultSerializer(PrivateKey::class.java, PrivateKeySerializer)
|
||||
register(LinkedHashMapEntrySerializer.getEntry()::class.java, LinkedHashMapEntrySerializer)
|
||||
register(LinkedListItrSerializer.getListItr()::class.java, LinkedListItrSerializer)
|
||||
register(Arrays.asList("").javaClass, ArraysAsListSerializer())
|
||||
@ -126,11 +118,6 @@ object DefaultKryoCustomizer {
|
||||
// InputStream subclasses whitelisting, required for attachments.
|
||||
register(BufferedInputStream::class.java, InputStreamSerializer)
|
||||
register(Class.forName("sun.net.www.protocol.jar.JarURLConnection\$JarURLInputStream"), InputStreamSerializer)
|
||||
register(PublicKey::class.java, publicKeySerializer)
|
||||
register(PrivateKey::class.java, PrivateKeySerializer)
|
||||
register(EdDSAPublicKey::class.java, publicKeySerializer)
|
||||
register(EdDSAPrivateKey::class.java, PrivateKeySerializer)
|
||||
register(CompositeKey::class.java, publicKeySerializer) // Using a custom serializer for compactness
|
||||
// Exceptions. We don't bother sending the stack traces as the client will fill in its own anyway.
|
||||
register(Array<StackTraceElement>::class, read = { _, _ -> emptyArray() }, write = { _, _, _ -> })
|
||||
// This ensures a NonEmptySetSerializer is constructed with an initial value.
|
||||
@ -139,12 +126,6 @@ object DefaultKryoCustomizer {
|
||||
register(Class::class.java, ClassSerializer)
|
||||
register(FileInputStream::class.java, InputStreamSerializer)
|
||||
register(CertPath::class.java, CertPathSerializer)
|
||||
register(BCECPrivateKey::class.java, PrivateKeySerializer)
|
||||
register(BCECPublicKey::class.java, publicKeySerializer)
|
||||
register(BCRSAPrivateCrtKey::class.java, PrivateKeySerializer)
|
||||
register(BCRSAPublicKey::class.java, publicKeySerializer)
|
||||
register(BCSphincs256PrivateKey::class.java, PrivateKeySerializer)
|
||||
register(BCSphincs256PublicKey::class.java, publicKeySerializer)
|
||||
register(NotaryChangeWireTransaction::class.java, NotaryChangeWireTransactionSerializer)
|
||||
register(PartyAndCertificate::class.java, PartyAndCertificateSerializer)
|
||||
|
||||
|
@ -28,7 +28,6 @@ import net.corda.core.transactions.NotaryChangeWireTransaction
|
||||
import net.corda.core.transactions.SignedTransaction
|
||||
import net.corda.core.transactions.WireTransaction
|
||||
import net.corda.core.utilities.OpaqueBytes
|
||||
import net.corda.core.utilities.SgxSupport
|
||||
import net.corda.serialization.internal.serializationContextKey
|
||||
import org.slf4j.Logger
|
||||
import org.slf4j.LoggerFactory
|
||||
@ -83,11 +82,8 @@ class ImmutableClassSerializer<T : Any>(val klass: KClass<T>) : Serializer<T>()
|
||||
|
||||
init {
|
||||
// Verify that this class is immutable (all properties are final).
|
||||
// We disable this check inside SGX as the reflection blows up.
|
||||
if (!SgxSupport.isInsideEnclave) {
|
||||
props.forEach {
|
||||
require(it !is KMutableProperty<*>) { "$it mutable property of class: ${klass} is unsupported" }
|
||||
}
|
||||
props.forEach {
|
||||
require(it !is KMutableProperty<*>) { "$it mutable property of class: $klass is unsupported" }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6,16 +6,15 @@ import net.corda.core.identity.CordaX500Name
|
||||
import net.corda.core.identity.PartyAndCertificate
|
||||
import net.corda.core.node.NodeInfo
|
||||
import net.corda.core.utilities.NetworkHostAndPort
|
||||
import net.corda.coretesting.internal.TestNodeInfoBuilder
|
||||
import net.corda.coretesting.internal.signWith
|
||||
import net.corda.nodeapi.internal.crypto.CertificateType
|
||||
import net.corda.nodeapi.internal.crypto.X509Utilities
|
||||
import net.corda.testing.core.ALICE_NAME
|
||||
import net.corda.testing.core.BOB_NAME
|
||||
import net.corda.testing.core.SerializationEnvironmentRule
|
||||
import net.corda.coretesting.internal.TestNodeInfoBuilder
|
||||
import net.corda.coretesting.internal.signWith
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.assertj.core.api.Assertions.assertThatThrownBy
|
||||
import org.junit.Ignore
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import java.security.KeyPair
|
||||
@ -56,7 +55,6 @@ class SignedNodeInfoTest {
|
||||
}
|
||||
|
||||
@Test(timeout=300_000)
|
||||
@Ignore("TODO JDK17: Fixme")
|
||||
fun `verifying composite keys only`() {
|
||||
val aliceKeyPair = generateKeyPair()
|
||||
val bobKeyPair = generateKeyPair()
|
||||
|
@ -28,6 +28,6 @@ class ContentSignerBuilderTest {
|
||||
.isThrownBy {
|
||||
ContentSignerBuilder.build(signatureScheme, issuerKeyPair.private, provider)
|
||||
}
|
||||
.withMessage("Incorrect key type EC for signature scheme NONEwithEdDSA")
|
||||
.withMessage("Incorrect key type EC for signature scheme Ed25519")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,33 +1,32 @@
|
||||
package net.corda.nodeapi.internal.cryptoservice.bouncycastle
|
||||
package net.corda.nodeapi.internal.cryptoservice
|
||||
|
||||
import net.corda.core.crypto.Crypto
|
||||
import net.corda.core.crypto.SignatureScheme
|
||||
import net.corda.core.crypto.internal.cordaBouncyCastleProvider
|
||||
import net.corda.core.utilities.days
|
||||
import net.corda.coretesting.internal.stubs.CertificateStoreStubs
|
||||
import net.corda.nodeapi.internal.config.CertificateStoreSupplier
|
||||
import net.corda.nodeapi.internal.crypto.CertificateType
|
||||
import net.corda.nodeapi.internal.crypto.X509Utilities
|
||||
import net.corda.nodeapi.internal.cryptoservice.CryptoService
|
||||
import net.corda.nodeapi.internal.cryptoservice.CryptoServiceException
|
||||
import net.corda.nodeapi.internal.cryptoservice.WrappedPrivateKey
|
||||
import net.corda.nodeapi.internal.cryptoservice.WrappingMode
|
||||
import net.corda.testing.core.ALICE_NAME
|
||||
import net.corda.coretesting.internal.stubs.CertificateStoreStubs
|
||||
import net.corda.nodeapi.internal.crypto.loadOrCreateKeyStore
|
||||
import net.corda.testing.core.ALICE_NAME
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.assertj.core.api.Assertions.assertThatThrownBy
|
||||
import org.bouncycastle.jce.provider.BouncyCastleProvider
|
||||
import org.junit.Before
|
||||
import org.junit.Ignore
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.rules.TemporaryFolder
|
||||
import java.io.FileOutputStream
|
||||
import java.nio.file.Path
|
||||
import java.security.*
|
||||
import java.security.KeyPair
|
||||
import java.security.KeyPairGenerator
|
||||
import java.security.KeyStore
|
||||
import java.security.PublicKey
|
||||
import java.security.Signature
|
||||
import java.security.spec.ECGenParameterSpec
|
||||
import java.time.Duration
|
||||
import java.util.*
|
||||
import java.util.UUID
|
||||
import javax.crypto.Cipher
|
||||
import javax.security.auth.x500.X500Principal
|
||||
import kotlin.io.path.div
|
||||
@ -35,7 +34,7 @@ import kotlin.test.assertFailsWith
|
||||
import kotlin.test.assertFalse
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
class BCCryptoServiceTests {
|
||||
class DefaultCryptoServiceTests {
|
||||
companion object {
|
||||
val clearData = "data".toByteArray()
|
||||
}
|
||||
@ -61,15 +60,13 @@ class BCCryptoServiceTests {
|
||||
}
|
||||
|
||||
@Test(timeout=300_000)
|
||||
@Ignore("TODO JDK17: Fixme")
|
||||
fun `BCCryptoService generate key pair and sign both data and cert`() {
|
||||
val cryptoService = BCCryptoService(ALICE_NAME.x500Principal, signingCertificateStore, wrappingKeyStorePath)
|
||||
fun `cryptoService generate key pair and sign both data and cert`() {
|
||||
val cryptoService = DefaultCryptoService(ALICE_NAME.x500Principal, signingCertificateStore, wrappingKeyStorePath)
|
||||
// Testing every supported scheme.
|
||||
Crypto.supportedSignatureSchemes().filter { it != Crypto.COMPOSITE_KEY
|
||||
&& it.signatureName != "SHA512WITHSPHINCS256"}.forEach { generateKeyAndSignForScheme(cryptoService, it) }
|
||||
Crypto.supportedSignatureSchemes().filter { it != Crypto.COMPOSITE_KEY }.forEach { generateKeyAndSignForScheme(cryptoService, it) }
|
||||
}
|
||||
|
||||
private fun generateKeyAndSignForScheme(cryptoService: BCCryptoService, signatureScheme: SignatureScheme) {
|
||||
private fun generateKeyAndSignForScheme(cryptoService: DefaultCryptoService, signatureScheme: SignatureScheme) {
|
||||
val alias = "signature${signatureScheme.schemeNumberID}"
|
||||
val pubKey = cryptoService.generateKeyPair(alias, signatureScheme)
|
||||
assertTrue { cryptoService.containsKey(alias) }
|
||||
@ -95,12 +92,10 @@ class BCCryptoServiceTests {
|
||||
}
|
||||
|
||||
@Test(timeout=300_000)
|
||||
@Ignore("TODO JDK17: Fixme")
|
||||
fun `BCCryptoService generate key pair and sign with existing schemes`() {
|
||||
val cryptoService = BCCryptoService(ALICE_NAME.x500Principal, signingCertificateStore, wrappingKeyStorePath)
|
||||
fun `cryptoService generate key pair and sign with existing schemes`() {
|
||||
val cryptoService = DefaultCryptoService(ALICE_NAME.x500Principal, signingCertificateStore, wrappingKeyStorePath)
|
||||
// Testing every supported scheme.
|
||||
Crypto.supportedSignatureSchemes().filter { it != Crypto.COMPOSITE_KEY
|
||||
&& it.signatureName != "SHA512WITHSPHINCS256"}.forEach {
|
||||
Crypto.supportedSignatureSchemes().filter { it != Crypto.COMPOSITE_KEY }.forEach {
|
||||
val alias = "signature${it.schemeNumberID}"
|
||||
val pubKey = cryptoService.generateKeyPair(alias, it)
|
||||
assertTrue { cryptoService.containsKey(alias) }
|
||||
@ -110,9 +105,7 @@ class BCCryptoServiceTests {
|
||||
}
|
||||
|
||||
@Test(timeout=300_000)
|
||||
@Ignore("TODO JDK17: Fixme")
|
||||
fun `BCCryptoService generate key pair and sign with passed signing algorithm`() {
|
||||
|
||||
fun `cryptoService generate key pair and sign with passed signing algorithm`() {
|
||||
assertTrue{signAndVerify(signAlgo = "NONEwithRSA", alias = "myKeyAlias", keyTypeAlgo = "RSA")}
|
||||
assertTrue{signAndVerify(signAlgo = "MD2withRSA", alias = "myKeyAlias", keyTypeAlgo = "RSA")}
|
||||
assertTrue{signAndVerify(signAlgo = "MD5withRSA", alias = "myKeyAlias", keyTypeAlgo = "RSA")}
|
||||
@ -132,7 +125,7 @@ class BCCryptoServiceTests {
|
||||
private fun signAndVerify(signAlgo: String, alias: String, keyTypeAlgo: String): Boolean {
|
||||
val keyPairGenerator = KeyPairGenerator.getInstance(keyTypeAlgo)
|
||||
val keyPair = keyPairGenerator.genKeyPair()
|
||||
val cryptoService = BCCryptoService(ALICE_NAME.x500Principal, createKeystore(alias, keyPair), wrappingKeyStorePath)
|
||||
val cryptoService = DefaultCryptoService(ALICE_NAME.x500Principal, createKeystore(alias, keyPair), wrappingKeyStorePath)
|
||||
assertTrue { cryptoService.containsKey(alias) }
|
||||
val signatureData = cryptoService.sign(alias, clearData, signAlgo)
|
||||
return verify(signAlgo, cryptoService.getPublicKey(alias), signatureData, clearData)
|
||||
@ -175,7 +168,7 @@ class BCCryptoServiceTests {
|
||||
@Test(timeout=300_000)
|
||||
fun `When key does not exist getPublicKey, sign and getSigner should throw`() {
|
||||
val nonExistingAlias = "nonExistingAlias"
|
||||
val cryptoService = BCCryptoService(ALICE_NAME.x500Principal, signingCertificateStore, wrappingKeyStorePath)
|
||||
val cryptoService = DefaultCryptoService(ALICE_NAME.x500Principal, signingCertificateStore, wrappingKeyStorePath)
|
||||
assertFalse { cryptoService.containsKey(nonExistingAlias) }
|
||||
assertFailsWith<CryptoServiceException> { cryptoService.getPublicKey(nonExistingAlias) }
|
||||
assertFailsWith<CryptoServiceException> { cryptoService.sign(nonExistingAlias, clearData) }
|
||||
@ -184,7 +177,7 @@ class BCCryptoServiceTests {
|
||||
|
||||
@Test(timeout=300_000)
|
||||
fun `cryptoService supports degraded mode of wrapping`() {
|
||||
val cryptoService = BCCryptoService(ALICE_NAME.x500Principal, signingCertificateStore, wrappingKeyStorePath)
|
||||
val cryptoService = DefaultCryptoService(ALICE_NAME.x500Principal, signingCertificateStore, wrappingKeyStorePath)
|
||||
val supportedMode = cryptoService.getWrappingMode()
|
||||
|
||||
assertThat(supportedMode).isEqualTo(WrappingMode.DEGRADED_WRAPPED)
|
||||
@ -192,7 +185,7 @@ class BCCryptoServiceTests {
|
||||
|
||||
@Test(timeout=300_000)
|
||||
fun `cryptoService does not fail when requested to create same wrapping key twice with failIfExists is false`() {
|
||||
val cryptoService = BCCryptoService(ALICE_NAME.x500Principal, signingCertificateStore, wrappingKeyStorePath)
|
||||
val cryptoService = DefaultCryptoService(ALICE_NAME.x500Principal, signingCertificateStore, wrappingKeyStorePath)
|
||||
|
||||
val keyAlias = UUID.randomUUID().toString()
|
||||
cryptoService.createWrappingKey(keyAlias)
|
||||
@ -201,7 +194,7 @@ class BCCryptoServiceTests {
|
||||
|
||||
@Test(timeout=300_000)
|
||||
fun `cryptoService does fail when requested to create same wrapping key twice with failIfExists is true`() {
|
||||
val cryptoService = BCCryptoService(ALICE_NAME.x500Principal, signingCertificateStore, wrappingKeyStorePath)
|
||||
val cryptoService = DefaultCryptoService(ALICE_NAME.x500Principal, signingCertificateStore, wrappingKeyStorePath)
|
||||
|
||||
val keyAlias = UUID.randomUUID().toString()
|
||||
cryptoService.createWrappingKey(keyAlias)
|
||||
@ -213,7 +206,7 @@ class BCCryptoServiceTests {
|
||||
|
||||
@Test(timeout=300_000)
|
||||
fun `cryptoService fails when asked to generate wrapped key pair or sign, but the master key specified does not exist`() {
|
||||
val cryptoService = BCCryptoService(ALICE_NAME.x500Principal, signingCertificateStore, wrappingKeyStorePath)
|
||||
val cryptoService = DefaultCryptoService(ALICE_NAME.x500Principal, signingCertificateStore, wrappingKeyStorePath)
|
||||
|
||||
val wrappingKeyAlias = UUID.randomUUID().toString()
|
||||
|
||||
@ -230,7 +223,7 @@ class BCCryptoServiceTests {
|
||||
|
||||
@Test(timeout=300_000)
|
||||
fun `cryptoService can generate wrapped key pair and sign with the private key successfully, using default algorithm`() {
|
||||
val cryptoService = BCCryptoService(ALICE_NAME.x500Principal, signingCertificateStore, wrappingKeyStorePath)
|
||||
val cryptoService = DefaultCryptoService(ALICE_NAME.x500Principal, signingCertificateStore, wrappingKeyStorePath)
|
||||
|
||||
val wrappingKeyAlias = UUID.randomUUID().toString()
|
||||
cryptoService.createWrappingKey(wrappingKeyAlias)
|
||||
@ -239,7 +232,7 @@ class BCCryptoServiceTests {
|
||||
|
||||
@Test(timeout=300_000)
|
||||
fun `cryptoService can generate wrapped key pair and sign with the private key successfully`() {
|
||||
val cryptoService = BCCryptoService(ALICE_NAME.x500Principal, signingCertificateStore, wrappingKeyStorePath)
|
||||
val cryptoService = DefaultCryptoService(ALICE_NAME.x500Principal, signingCertificateStore, wrappingKeyStorePath)
|
||||
|
||||
val wrappingKeyAlias = UUID.randomUUID().toString()
|
||||
cryptoService.createWrappingKey(wrappingKeyAlias)
|
||||
@ -264,7 +257,7 @@ class BCCryptoServiceTests {
|
||||
|
||||
@Test(timeout=300_000)
|
||||
fun `cryptoService can sign with previously encoded version of wrapped key`() {
|
||||
val cryptoService = BCCryptoService(ALICE_NAME.x500Principal, signingCertificateStore, wrappingKeyStorePath)
|
||||
val cryptoService = DefaultCryptoService(ALICE_NAME.x500Principal, signingCertificateStore, wrappingKeyStorePath)
|
||||
|
||||
val wrappingKeyAlias = UUID.randomUUID().toString()
|
||||
cryptoService.createWrappingKey(wrappingKeyAlias)
|
@ -139,7 +139,12 @@ class KryoTests(private val compression: CordaSerializationEncoding?) {
|
||||
|
||||
@Test(timeout=300_000)
|
||||
fun `deserialised key pair functions the same as serialised one`() {
|
||||
val keyPair = generateKeyPair()
|
||||
// The default signature scheme, EDDSA_ED25519_SHA512, generates public keys which have a writeReplace method (EdDSAPublicKeyImpl).
|
||||
// This is picked up by Quasar's custom ReplaceableObjectKryo, which will *always* use the writeReplace for serialisation, ignoring
|
||||
// any Kryo serialisers that might have been configured. This thus means the deserialisation path does not go via
|
||||
// Cryto.decodePublicKey, which interns the materialised PublicKey. To avoid all of this, and test the last assertion, we use
|
||||
// ECDSA keys, whose implementation doesn't have a writeReplace method.
|
||||
val keyPair = Crypto.generateKeyPair(Crypto.ECDSA_SECP256R1_SHA256)
|
||||
val bitsToSign: ByteArray = Ints.toByteArray(0x01234567)
|
||||
val wrongBits: ByteArray = Ints.toByteArray(0x76543210)
|
||||
val signature = keyPair.sign(bitsToSign)
|
||||
|
@ -223,7 +223,6 @@ dependencies {
|
||||
integrationTestImplementation "junit:junit:$junit_version"
|
||||
integrationTestImplementation "org.assertj:assertj-core:${assertj_version}"
|
||||
integrationTestImplementation "org.apache.qpid:qpid-jms-client:${protonj_version}"
|
||||
integrationTestImplementation "net.i2p.crypto:eddsa:$eddsa_version"
|
||||
|
||||
// used by FinalityFlowErrorHandlingTest
|
||||
slowIntegrationTestImplementation project(':testing:cordapps:cashobservers')
|
||||
@ -276,7 +275,6 @@ quasar {
|
||||
"io.github.classgraph**",
|
||||
"io.netty*",
|
||||
"liquibase**",
|
||||
"net.i2p.crypto.**",
|
||||
"nonapi.io.github.classgraph.**",
|
||||
"org.apiguardian.**",
|
||||
"org.bouncycastle**",
|
||||
|
@ -65,7 +65,7 @@ tasks.register('buildCordaJAR', FatCapsule) {
|
||||
applicationVersion = corda_release_version
|
||||
applicationId = "net.corda.node.Corda"
|
||||
// See experimental/quasar-hook/README.md for how to generate.
|
||||
def quasarExcludeExpression = "x(antlr**;bftsmart**;co.paralleluniverse**;com.codahale**;com.esotericsoftware**;com.fasterxml**;com.google**;com.ibm**;com.intellij**;com.jcabi**;org.mockito**;com.opengamma**;com.typesafe**;com.zaxxer**;de.javakaffee**;groovy**;groovyjarjarantlr**;groovyjarjarasm**;io.atomix**;io.github**;io.netty**;jdk**;kotlin**;net.bytebuddy**;net.i2p**;org.apache**;org.bouncycastle**;org.codehaus**;org.crsh**;org.dom4j**;org.fusesource**;org.h2**;org.hibernate**;org.jboss**;org.jcp**;org.joda**;org.objectweb**;org.objenesis**;org.slf4j**;org.w3c**;org.xml**;org.yaml**;reflectasm**;rx**;org.jolokia**;com.lmax**;picocli**;liquibase**;com.github.benmanes**;org.json**;org.postgresql**;nonapi.io.github.classgraph**;io.opentelemetry**)"
|
||||
def quasarExcludeExpression = "x(antlr**;bftsmart**;co.paralleluniverse**;com.codahale**;com.esotericsoftware**;com.fasterxml**;com.google**;com.ibm**;com.intellij**;com.jcabi**;org.mockito**;com.opengamma**;com.typesafe**;com.zaxxer**;de.javakaffee**;groovy**;groovyjarjarantlr**;groovyjarjarasm**;io.atomix**;io.github**;io.netty**;jdk**;kotlin**;net.bytebuddy**;org.apache**;org.bouncycastle**;org.codehaus**;org.crsh**;org.dom4j**;org.fusesource**;org.h2**;org.hibernate**;org.jboss**;org.jcp**;org.joda**;org.objectweb**;org.objenesis**;org.slf4j**;org.w3c**;org.xml**;org.yaml**;reflectasm**;rx**;org.jolokia**;com.lmax**;picocli**;liquibase**;com.github.benmanes**;org.json**;org.postgresql**;nonapi.io.github.classgraph**;io.opentelemetry**)"
|
||||
def quasarClassLoaderExclusion = "l(net.corda.core.serialization.internal.**)"
|
||||
def quasarOptions = "m"
|
||||
javaAgents = quasar_classifier ? ["quasar-core-${quasar_version}-${quasar_classifier}.jar=${quasarOptions}${quasarExcludeExpression}${quasarClassLoaderExclusion}"] : ["quasar-core-${quasar_version}.jar=${quasarExcludeExpression}${quasarClassLoaderExclusion}"]
|
||||
|
@ -3,7 +3,12 @@
|
||||
--add-opens=java.base/java.nio=ALL-UNNAMED
|
||||
--add-opens=java.base/java.security=ALL-UNNAMED
|
||||
--add-opens=java.base/java.security.cert=ALL-UNNAMED
|
||||
--add-opens=java.base/java.security.spec=ALL-UNNAMED
|
||||
--add-opens=java.base/java.time=ALL-UNNAMED
|
||||
--add-opens=java.base/java.util=ALL-UNNAMED
|
||||
--add-opens=java.base/java.util.concurrent=ALL-UNNAMED
|
||||
--add-opens=java.base/sun.security.pkcs=ALL-UNNAMED
|
||||
--add-opens=java.base/sun.security.util=ALL-UNNAMED
|
||||
--add-opens=java.base/sun.security.x509=ALL-UNNAMED
|
||||
--add-opens=java.sql/java.sql=ALL-UNNAMED
|
||||
--add-opens=jdk.crypto.ec/sun.security.ec.ed=ALL-UNNAMED
|
||||
|
@ -7,7 +7,6 @@ import net.corda.core.flows.StartableByRPC
|
||||
import net.corda.core.serialization.CheckpointCustomSerializer
|
||||
import net.corda.testing.node.internal.CustomCordapp
|
||||
import net.corda.testing.node.internal.enclosedCordapp
|
||||
import net.i2p.crypto.eddsa.EdDSAPublicKey
|
||||
import org.assertj.core.api.Assertions
|
||||
import java.security.PublicKey
|
||||
import java.time.Duration
|
||||
@ -198,17 +197,4 @@ class TestCorDapp {
|
||||
throw FlowException("Broken on purpose")
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("unused")
|
||||
class BrokenEdDSAPublicKeySerializer :
|
||||
CheckpointCustomSerializer<EdDSAPublicKey, String> {
|
||||
override fun toProxy(obj: EdDSAPublicKey): String {
|
||||
throw FlowException("Broken on purpose")
|
||||
}
|
||||
|
||||
override fun fromProxy(proxy: String): EdDSAPublicKey {
|
||||
throw FlowException("Broken on purpose")
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -150,7 +150,7 @@ import net.corda.nodeapi.internal.SignedNodeInfo
|
||||
import net.corda.nodeapi.internal.cordapp.CordappLoader
|
||||
import net.corda.nodeapi.internal.cordapp.cordappSchemas
|
||||
import net.corda.nodeapi.internal.cryptoservice.CryptoService
|
||||
import net.corda.nodeapi.internal.cryptoservice.bouncycastle.BCCryptoService
|
||||
import net.corda.nodeapi.internal.cryptoservice.DefaultCryptoService
|
||||
import net.corda.nodeapi.internal.lifecycle.NodeLifecycleEvent
|
||||
import net.corda.nodeapi.internal.lifecycle.NodeLifecycleEventsDistributor
|
||||
import net.corda.nodeapi.internal.lifecycle.NodeServicesContext
|
||||
@ -1061,7 +1061,7 @@ abstract class AbstractNode<S>(val configuration: NodeConfiguration,
|
||||
}
|
||||
|
||||
protected open fun makeCryptoService(): CryptoService {
|
||||
return BCCryptoService(configuration.myLegalName.x500Principal, configuration.signingCertificateStore)
|
||||
return DefaultCryptoService(configuration.myLegalName.x500Principal, configuration.signingCertificateStore)
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
|
@ -16,7 +16,7 @@ import net.corda.nodeapi.internal.crypto.X509Utilities.DISTRIBUTED_NOTARY_KEY_AL
|
||||
import net.corda.nodeapi.internal.crypto.X509Utilities.NODE_IDENTITY_KEY_ALIAS
|
||||
import net.corda.nodeapi.internal.crypto.checkValidity
|
||||
import net.corda.nodeapi.internal.cryptoservice.CryptoService
|
||||
import net.corda.nodeapi.internal.cryptoservice.bouncycastle.BCCryptoService
|
||||
import net.corda.nodeapi.internal.cryptoservice.DefaultCryptoService
|
||||
import java.io.IOException
|
||||
import java.math.BigInteger
|
||||
import java.nio.file.NoSuchFileException
|
||||
@ -54,8 +54,8 @@ class KeyStoreHandler(private val configuration: NodeConfiguration, private val
|
||||
if (configuration.devMode) {
|
||||
configuration.configureWithDevSSLCertificate(cryptoService, devModeKeyEntropy)
|
||||
// configureWithDevSSLCertificate is a devMode process that writes directly to keystore files, so
|
||||
// we should re-synchronise BCCryptoService with the updated keystore file.
|
||||
if (cryptoService is BCCryptoService) {
|
||||
// we should re-synchronise DefaultCryptoService with the updated keystore file.
|
||||
if (cryptoService is DefaultCryptoService) {
|
||||
cryptoService.resyncKeystore()
|
||||
}
|
||||
}
|
||||
|
@ -17,7 +17,7 @@ import net.corda.nodeapi.internal.config.toProperties
|
||||
import net.corda.nodeapi.internal.crypto.X509KeyStore
|
||||
import net.corda.nodeapi.internal.crypto.X509Utilities
|
||||
import net.corda.nodeapi.internal.cryptoservice.CryptoService
|
||||
import net.corda.nodeapi.internal.cryptoservice.bouncycastle.BCCryptoService
|
||||
import net.corda.nodeapi.internal.cryptoservice.DefaultCryptoService
|
||||
import net.corda.nodeapi.internal.installDevNodeCaCertPath
|
||||
import net.corda.nodeapi.internal.loadDevCaTrustStore
|
||||
import net.corda.nodeapi.internal.registerDevP2pCertificates
|
||||
@ -195,7 +195,7 @@ fun MutualSslConfiguration.configureDevKeyAndTrustStores(myLegalName: CordaX500N
|
||||
FileBasedCertificateStoreSupplier(keyStore.path, keyStore.storePassword, keyStore.entryPassword).get(true)
|
||||
.also { it.registerDevP2pCertificates(myLegalName) }
|
||||
when (cryptoService) {
|
||||
is BCCryptoService, null -> {
|
||||
is DefaultCryptoService, null -> {
|
||||
val signingKeyStore = FileBasedCertificateStoreSupplier(signingCertificateStore.path, signingCertificateStore.storePassword, signingCertificateStore.entryPassword).get(true)
|
||||
.also {
|
||||
it.installDevNodeCaCertPath(myLegalName)
|
||||
|
@ -77,7 +77,7 @@ interface NodeConfiguration : ConfigurationWithOptionsContainer {
|
||||
val baseDirectory: Path
|
||||
val certificatesDirectory: Path
|
||||
// signingCertificateStore is used to store certificate chains.
|
||||
// However, BCCryptoService is reusing this to store keys as well.
|
||||
// However, DefaultCryptoService is reusing this to store keys as well.
|
||||
val signingCertificateStore: FileBasedCertificateStoreSupplier
|
||||
val p2pSslOptions: MutualSslConfiguration
|
||||
|
||||
|
@ -22,7 +22,7 @@ import net.corda.nodeapi.internal.crypto.X509Utilities.CORDA_ROOT_CA
|
||||
import net.corda.nodeapi.internal.crypto.X509Utilities.DEFAULT_VALIDITY_WINDOW
|
||||
import net.corda.nodeapi.internal.crypto.x509
|
||||
import net.corda.nodeapi.internal.cryptoservice.CryptoService
|
||||
import net.corda.nodeapi.internal.cryptoservice.bouncycastle.BCCryptoService
|
||||
import net.corda.nodeapi.internal.cryptoservice.DefaultCryptoService
|
||||
import org.bouncycastle.asn1.x500.X500Name
|
||||
import org.bouncycastle.openssl.jcajce.JcaPEMWriter
|
||||
import org.bouncycastle.operator.ContentSigner
|
||||
@ -98,7 +98,7 @@ open class NetworkRegistrationHelper(
|
||||
certificatesDirectory.safeSymbolicRead().createDirectories()
|
||||
// We need this in case cryptoService and certificateStore share the same KeyStore (for backwards compatibility purposes).
|
||||
// If we didn't, then an update to cryptoService wouldn't be reflected to certificateStore that is already loaded in memory.
|
||||
val certStore: CertificateStore = if (cryptoService is BCCryptoService) cryptoService.certificateStore else certificateStore
|
||||
val certStore: CertificateStore = if (cryptoService is DefaultCryptoService) cryptoService.certificateStore else certificateStore
|
||||
|
||||
// SELF_SIGNED_PRIVATE_KEY is used as progress indicator.
|
||||
if (certStore.contains(nodeCaKeyAlias) && !certStore.contains(SELF_SIGNED_PRIVATE_KEY)) {
|
||||
@ -169,7 +169,7 @@ open class NetworkRegistrationHelper(
|
||||
certificatesDirectory.safeSymbolicRead().createDirectories()
|
||||
// We need this in case cryptoService and certificateStore share the same KeyStore (for backwards compatibility purposes).
|
||||
// If we didn't, then an update to cryptoService wouldn't be reflected to certificateStore that is already loaded in memory.
|
||||
val certStore: CertificateStore = if (cryptoService is BCCryptoService) cryptoService.certificateStore else certificateStore
|
||||
val certStore: CertificateStore = if (cryptoService is DefaultCryptoService) cryptoService.certificateStore else certificateStore
|
||||
|
||||
if (!certStore.contains(nodeCaKeyAlias)) {
|
||||
logProgress("Node CA key doesn't exist, program will now terminate...")
|
||||
@ -374,7 +374,7 @@ class NodeRegistrationConfiguration(
|
||||
tlsCertCrlDistPoint = config.tlsCertCrlDistPoint,
|
||||
certificatesDirectory = config.certificatesDirectory,
|
||||
emailAddress = config.emailAddress,
|
||||
cryptoService = BCCryptoService(config.myLegalName.x500Principal, config.signingCertificateStore),
|
||||
cryptoService = DefaultCryptoService(config.myLegalName.x500Principal, config.signingCertificateStore),
|
||||
certificateStore = config.signingCertificateStore.get(true),
|
||||
notaryServiceConfig = config.notary?.let {
|
||||
// Validation of the presence of the notary service legal name is only done here and not in the top level configuration
|
||||
|
@ -23,13 +23,12 @@ import net.corda.nodeapi.internal.crypto.X509Utilities.DISTRIBUTED_NOTARY_COMPOS
|
||||
import net.corda.nodeapi.internal.crypto.X509Utilities.DISTRIBUTED_NOTARY_KEY_ALIAS
|
||||
import net.corda.nodeapi.internal.crypto.X509Utilities.NODE_IDENTITY_KEY_ALIAS
|
||||
import net.corda.nodeapi.internal.cryptoservice.CryptoService
|
||||
import net.corda.nodeapi.internal.cryptoservice.bouncycastle.BCCryptoService
|
||||
import net.corda.nodeapi.internal.cryptoservice.DefaultCryptoService
|
||||
import net.corda.testing.core.ALICE_NAME
|
||||
import net.corda.testing.core.BOB_NAME
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.assertj.core.api.Assertions.assertThatThrownBy
|
||||
import org.junit.Before
|
||||
import org.junit.Ignore
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.rules.TemporaryFolder
|
||||
@ -37,7 +36,6 @@ import java.security.KeyPair
|
||||
import java.security.PublicKey
|
||||
import kotlin.io.path.div
|
||||
|
||||
@Ignore("TODO JDK17: Fixme")
|
||||
class KeyStoreHandlerTest {
|
||||
@Rule
|
||||
@JvmField
|
||||
@ -49,7 +47,7 @@ class KeyStoreHandlerTest {
|
||||
|
||||
private val keyStore get() = config.signingCertificateStore.get()
|
||||
|
||||
private lateinit var cryptoService: BCCryptoService
|
||||
private lateinit var cryptoService: DefaultCryptoService
|
||||
|
||||
private lateinit var keyStoreHandler: KeyStoreHandler
|
||||
|
||||
@ -66,7 +64,7 @@ class KeyStoreHandlerTest {
|
||||
doReturn(ALICE_NAME).whenever(it).myLegalName
|
||||
doReturn(null).whenever(it).notary
|
||||
}
|
||||
cryptoService = BCCryptoService(ALICE_NAME.x500Principal, signingCertificateStore)
|
||||
cryptoService = DefaultCryptoService(ALICE_NAME.x500Principal, signingCertificateStore)
|
||||
keyStoreHandler = KeyStoreHandler(config, cryptoService)
|
||||
}
|
||||
|
||||
@ -192,7 +190,7 @@ class KeyStoreHandlerTest {
|
||||
val devCertificateDir = tempFolder.root.toPath() / "certificates-dev"
|
||||
val signingCertificateStore = CertificateStoreStubs.Signing.withCertificatesDirectory(devCertificateDir)
|
||||
val p2pSslOptions = CertificateStoreStubs.P2P.withCertificatesDirectory(devCertificateDir)
|
||||
val devCryptoService = BCCryptoService(config.myLegalName.x500Principal, signingCertificateStore)
|
||||
val devCryptoService = DefaultCryptoService(config.myLegalName.x500Principal, signingCertificateStore)
|
||||
|
||||
doReturn(true).whenever(config).devMode
|
||||
doReturn(signingCertificateStore).whenever(config).signingCertificateStore
|
||||
|
@ -955,8 +955,7 @@ class DriverDSLImpl(
|
||||
val excludePackagePattern = "x(antlr**;bftsmart**;ch**;co.paralleluniverse**;com.codahale**;com.esotericsoftware**;" +
|
||||
"com.fasterxml**;com.google**;com.ibm**;com.intellij**;com.jcabi**;com.nhaarman**;com.opengamma**;" +
|
||||
"com.typesafe**;com.zaxxer**;de.javakaffee**;groovy**;groovyjarjarantlr**;groovyjarjarasm**;io.atomix**;" +
|
||||
"io.github**;io.netty**;jdk**;joptsimple**;junit**;kotlin**;net.bytebuddy**;" +
|
||||
"net.i2p**;org.apache**;" +
|
||||
"io.github**;io.netty**;jdk**;joptsimple**;junit**;kotlin**;net.bytebuddy**;org.apache**;" +
|
||||
"org.assertj**;org.bouncycastle**;org.codehaus**;org.crsh**;org.dom4j**;org.fusesource**;org.h2**;" +
|
||||
"org.hamcrest**;org.hibernate**;org.jboss**;org.jcp**;org.joda**;org.junit**;org.mockito**;org.objectweb**;" +
|
||||
"org.objenesis**;org.slf4j**;org.w3c**;org.xml**;org.yaml**;reflectasm**;rx**;org.jolokia**;" +
|
||||
|
Loading…
Reference in New Issue
Block a user