mirror of
https://github.com/corda/corda.git
synced 2025-03-23 04:25:19 +00:00
ENT-4595 harmonize core and serialization (#5792)
* Harmonize serialization/core and deterministic counterparts * Fix test for changed private alias key behaviour * Detekt errors * roll back project.xml
This commit is contained in:
parent
87b39bf515
commit
14050826e9
@ -77,7 +77,7 @@ buildscript {
|
||||
ext.djvm_version = constants.getProperty("djvmVersion")
|
||||
ext.deterministic_rt_version = constants.getProperty('deterministicRtVersion')
|
||||
ext.okhttp_version = '3.14.2'
|
||||
ext.netty_version = '4.1.22.Final'
|
||||
ext.netty_version = '4.1.29.Final'
|
||||
ext.typesafe_config_version = constants.getProperty("typesafeConfigVersion")
|
||||
ext.fileupload_version = '1.4'
|
||||
// Legacy JUnit 4 version
|
||||
@ -95,10 +95,10 @@ buildscript {
|
||||
ext.jansi_version = '1.18'
|
||||
ext.hibernate_version = '5.4.3.Final'
|
||||
ext.h2_version = '1.4.199' // Update docs if renamed or removed.
|
||||
ext.postgresql_version = '42.2.5'
|
||||
ext.postgresql_version = '42.2.8'
|
||||
ext.rxjava_version = '1.3.8'
|
||||
ext.dokka_version = '0.9.17'
|
||||
ext.eddsa_version = '0.2.0'
|
||||
ext.eddsa_version = '0.3.0'
|
||||
ext.dependency_checker_version = '5.2.0'
|
||||
ext.commons_collections_version = '4.3'
|
||||
ext.beanutils_version = '1.9.3'
|
||||
@ -120,6 +120,7 @@ buildscript {
|
||||
ext.class_graph_version = constants.getProperty('classgraphVersion')
|
||||
ext.jcabi_manifests_version = '1.1'
|
||||
ext.picocli_version = '3.9.6'
|
||||
ext.commons_lang_version = '3.9'
|
||||
ext.commons_io_version = '2.6'
|
||||
ext.controlsfx_version = '8.40.15'
|
||||
if (JavaVersion.current() == JavaVersion.VERSION_11) {
|
||||
|
@ -58,10 +58,13 @@ task patchCore(type: Zip, dependsOn: coreJarTask) {
|
||||
from(compileKotlin)
|
||||
from(processResources)
|
||||
from(zipTree(originalJar)) {
|
||||
exclude 'net/corda/core/crypto/DelegatingSecureRandomService*.class'
|
||||
exclude 'net/corda/core/crypto/SHA256DigestSupplier.class'
|
||||
exclude 'net/corda/core/internal/*ToggleField*.class'
|
||||
exclude 'net/corda/core/serialization/*SerializationFactory*.class'
|
||||
exclude 'net/corda/core/serialization/internal/CheckpointSerializationFactory*.class'
|
||||
exclude 'net/corda/core/internal/rules/*.class'
|
||||
exclude 'net/corda/core/utilities/SgxSupport*.class'
|
||||
}
|
||||
|
||||
reproducibleFileOrder = true
|
||||
|
@ -0,0 +1,19 @@
|
||||
package net.corda.core.crypto
|
||||
|
||||
import java.security.Provider
|
||||
import java.security.SecureRandomSpi
|
||||
|
||||
@Suppress("unused")
|
||||
class DelegatingSecureRandomService(provider: CordaSecurityProvider)
|
||||
: Provider.Service(provider, "SecureRandom", "dummy-algorithm", UnsupportedSecureRandomSpi::javaClass.name, null, null) {
|
||||
private val instance: SecureRandomSpi = UnsupportedSecureRandomSpi(algorithm)
|
||||
override fun newInstance(param: Any?) = instance
|
||||
|
||||
private class UnsupportedSecureRandomSpi(private val algorithm: String) : SecureRandomSpi() {
|
||||
override fun engineSetSeed(seed: ByteArray) = unsupported()
|
||||
override fun engineNextBytes(bytes: ByteArray) = unsupported()
|
||||
override fun engineGenerateSeed(numBytes: Int) = unsupported()
|
||||
|
||||
private fun unsupported(): Nothing = throw UnsupportedOperationException("$algorithm not supported")
|
||||
}
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
package net.corda.core.crypto
|
||||
|
||||
import java.security.MessageDigest
|
||||
import java.util.function.Supplier
|
||||
|
||||
@Suppress("unused")
|
||||
private class SHA256DigestSupplier : Supplier<MessageDigest> {
|
||||
override fun get(): MessageDigest = MessageDigest.getInstance("SHA-256")
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
package net.corda.core.utilities
|
||||
|
||||
import net.corda.core.KeepForDJVM
|
||||
|
||||
@KeepForDJVM
|
||||
object SgxSupport {
|
||||
@JvmStatic
|
||||
val isInsideEnclave: Boolean = true
|
||||
}
|
@ -60,7 +60,7 @@ class FinalityFlowTests : WithFinality {
|
||||
fun `allow use of the old API if the CorDapp target version is 3`() {
|
||||
val oldBob = createBob(cordapps = listOf(tokenOldCordapp()))
|
||||
val stx = aliceNode.issuesCashTo(oldBob)
|
||||
val resultFuture = CordappResolver.withCordapp(targetPlatformVersion = 3) {
|
||||
val resultFuture = CordappResolver.withTestCordapp(targetPlatformVersion = 3) {
|
||||
@Suppress("DEPRECATION")
|
||||
aliceNode.startFlowAndRunNetwork(FinalityFlow(stx)).resultFuture
|
||||
}
|
||||
|
@ -59,7 +59,7 @@ dependencies {
|
||||
// RxJava: observable streams of events.
|
||||
compile "io.reactivex:rxjava:$rxjava_version"
|
||||
|
||||
compile "org.apache.commons:commons-lang3:3.9"
|
||||
compile "org.apache.commons:commons-lang3:$commons_lang_version"
|
||||
|
||||
// Java ed25519 implementation. See https://github.com/str4d/ed25519-java/
|
||||
compile "net.i2p.crypto:eddsa:$eddsa_version"
|
||||
@ -74,6 +74,9 @@ dependencies {
|
||||
// required to use @Type annotation
|
||||
compile "org.hibernate:hibernate-core:$hibernate_version"
|
||||
|
||||
// FastThreadLocal
|
||||
compile "io.netty:netty-common:$netty_version"
|
||||
|
||||
compile group: "io.github.classgraph", name: "classgraph", version: class_graph_version
|
||||
|
||||
testCompile "org.ow2.asm:asm:$asm_version"
|
||||
|
@ -7,6 +7,8 @@ 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.concurrent.ConcurrentHashMap
|
||||
|
||||
@KeepForDJVM
|
||||
@Suppress("DEPRECATION") // JDK11: should replace with Provider(String name, double version, String info) (since 9)
|
||||
@ -29,6 +31,40 @@ class CordaSecurityProvider : Provider(PROVIDER_NAME, 0.1, "$PROVIDER_NAME secur
|
||||
private fun putPlatformSecureRandomService() {
|
||||
putService(PlatformSecureRandomService(this))
|
||||
}
|
||||
|
||||
override fun getService(type: String, algorithm: String): Service? = serviceFactory(type, algorithm)
|
||||
|
||||
// Used to work around banning of ConcurrentHashMap in DJVM
|
||||
@Suppress("TooGenericExceptionCaught")
|
||||
private val serviceFactory: (String, String) -> Service? = try {
|
||||
// Will throw UnsupportedOperationException in DJVM
|
||||
makeCachingFactory()
|
||||
} catch (e: Exception) {
|
||||
makeFactory()
|
||||
}
|
||||
|
||||
private fun superGetService(type: String, algorithm: String): Service? = super.getService(type, algorithm)
|
||||
|
||||
@StubOutForDJVM
|
||||
private fun makeCachingFactory(): Function2<String, String, Service?> {
|
||||
return object : Function2<String, String, Service?> {
|
||||
private val services = ConcurrentHashMap<Pair<String, String>, Optional<Service>>()
|
||||
|
||||
override fun invoke(type: String, algorithm: String): Service? {
|
||||
return services.getOrPut(Pair(type, algorithm)) {
|
||||
Optional.ofNullable(superGetService(type, algorithm))
|
||||
}.orElse(null)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun makeFactory(): Function2<String, String, Service?> {
|
||||
return object : Function2<String, String, Service?> {
|
||||
override fun invoke(type: String, algorithm: String): Service? {
|
||||
return superGetService(type, algorithm)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@KeepForDJVM
|
||||
|
@ -1,9 +1,16 @@
|
||||
package net.corda.core.crypto
|
||||
|
||||
import net.corda.core.CordaOID
|
||||
import net.corda.core.DeleteForDJVM
|
||||
import net.corda.core.KeepForDJVM
|
||||
import net.corda.core.StubOutForDJVM
|
||||
import net.corda.core.crypto.internal.*
|
||||
import net.corda.core.crypto.internal.AliasPrivateKey
|
||||
import net.corda.core.crypto.internal.Instances.withSignature
|
||||
import net.corda.core.crypto.internal.`id-Curve25519ph`
|
||||
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.providerMap
|
||||
import net.corda.core.serialization.serialize
|
||||
import net.i2p.crypto.eddsa.EdDSAEngine
|
||||
import net.i2p.crypto.eddsa.EdDSAPrivateKey
|
||||
@ -14,7 +21,9 @@ 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.nist.NISTObjectIdentifiers
|
||||
@ -42,7 +51,15 @@ 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.*
|
||||
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.SignatureException
|
||||
import java.security.spec.InvalidKeySpecException
|
||||
import java.security.spec.PKCS8EncodedKeySpec
|
||||
import java.security.spec.X509EncodedKeySpec
|
||||
@ -289,11 +306,21 @@ object Crypto {
|
||||
@JvmStatic
|
||||
fun decodePrivateKey(encodedKey: ByteArray): PrivateKey {
|
||||
val keyInfo = PrivateKeyInfo.getInstance(encodedKey)
|
||||
if (keyInfo.privateKeyAlgorithm.algorithm == ASN1ObjectIdentifier(CordaOID.ALIAS_PRIVATE_KEY)) {
|
||||
return decodeAliasPrivateKey(keyInfo)
|
||||
}
|
||||
val signatureScheme = findSignatureScheme(keyInfo.privateKeyAlgorithm)
|
||||
val keyFactory = keyFactory(signatureScheme)
|
||||
return keyFactory.generatePrivate(PKCS8EncodedKeySpec(encodedKey))
|
||||
}
|
||||
|
||||
private fun decodeAliasPrivateKey(keyInfo: PrivateKeyInfo): PrivateKey {
|
||||
val encodable = keyInfo.parsePrivateKey() as DLSequence
|
||||
val derutF8String = encodable.getObjectAt(0)
|
||||
val alias = (derutF8String as DERUTF8String).string
|
||||
return AliasPrivateKey(alias)
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode a PKCS8 encoded key to its [PrivateKey] object based on the input scheme code name.
|
||||
* This should be used when the type key is known, e.g. during deserialisation or with key caches or key managers.
|
||||
@ -436,23 +463,24 @@ object Crypto {
|
||||
"Unsupported key/algorithm for schemeCodeName: ${signatureScheme.schemeCodeName}"
|
||||
}
|
||||
require(clearData.isNotEmpty()) { "Signing of an empty array is not permitted!" }
|
||||
val signature = Instances.getSignatureInstance(signatureScheme.signatureName, providerMap[signatureScheme.providerName])
|
||||
// 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) {
|
||||
signature.initSign(privateKey)
|
||||
} else {
|
||||
// The rest of the algorithms will require a SecureRandom input (i.e., ECDSA or any new algorithm for which
|
||||
// we don't know if it's deterministic).
|
||||
signature.initSign(privateKey, newSecureRandom())
|
||||
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) {
|
||||
signature.initSign(privateKey)
|
||||
} else {
|
||||
// The rest of the algorithms will require a SecureRandom input (i.e., ECDSA or any new algorithm for which
|
||||
// we don't know if it's deterministic).
|
||||
signature.initSign(privateKey, newSecureRandom())
|
||||
}
|
||||
signature.update(clearData)
|
||||
signature.sign()
|
||||
}
|
||||
signature.update(clearData)
|
||||
return signature.sign()
|
||||
}
|
||||
|
||||
/**
|
||||
@ -640,10 +668,11 @@ object Crypto {
|
||||
require(isSupportedSignatureScheme(signatureScheme)) {
|
||||
"Unsupported key/algorithm for schemeCodeName: ${signatureScheme.schemeCodeName}"
|
||||
}
|
||||
val signature = Instances.getSignatureInstance(signatureScheme.signatureName, providerMap[signatureScheme.providerName])
|
||||
signature.initVerify(publicKey)
|
||||
signature.update(clearData)
|
||||
return signature.verify(signatureData)
|
||||
return withSignature(signatureScheme) { signature ->
|
||||
signature.initVerify(publicKey)
|
||||
signature.update(clearData)
|
||||
signature.verify(signatureData)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,3 +1,4 @@
|
||||
@file:Suppress("MatchingDeclarationName")
|
||||
@file:KeepForDJVM
|
||||
@file:JvmName("CryptoUtils")
|
||||
|
||||
@ -14,7 +15,14 @@ import net.corda.core.utilities.toBase58
|
||||
import net.corda.core.utilities.toSHA256Bytes
|
||||
import java.math.BigInteger
|
||||
import java.nio.ByteBuffer
|
||||
import java.security.*
|
||||
import java.security.InvalidKeyException
|
||||
import java.security.KeyPair
|
||||
import java.security.NoSuchAlgorithmException
|
||||
import java.security.PrivateKey
|
||||
import java.security.PublicKey
|
||||
import java.security.SecureRandom
|
||||
import java.security.SecureRandomSpi
|
||||
import java.security.SignatureException
|
||||
|
||||
/**
|
||||
* Utility to simplify the act of signing a byte array.
|
||||
@ -116,6 +124,7 @@ val PublicKey.keys: Set<PublicKey> get() = (this as? CompositeKey)?.leafKeys ?:
|
||||
|
||||
/** Return true if [otherKey] fulfils the requirements of this [PublicKey]. */
|
||||
fun PublicKey.isFulfilledBy(otherKey: PublicKey): Boolean = isFulfilledBy(setOf(otherKey))
|
||||
|
||||
/** Return true if [otherKeys] fulfil the requirements of this [PublicKey]. */
|
||||
fun PublicKey.isFulfilledBy(otherKeys: Iterable<PublicKey>): Boolean = (this as? CompositeKey)?.isFulfilledBy(otherKeys) ?: (this in otherKeys)
|
||||
|
||||
@ -137,6 +146,7 @@ fun Iterable<TransactionSignature>.byKeys() = map { it.by }.toSet()
|
||||
// val (private, public) = keyPair
|
||||
/* The [PrivateKey] of this [KeyPair]. */
|
||||
operator fun KeyPair.component1(): PrivateKey = this.private
|
||||
|
||||
/* The [PublicKey] of this [KeyPair]. */
|
||||
operator fun KeyPair.component2(): PublicKey = this.public
|
||||
|
||||
@ -190,6 +200,29 @@ fun KeyPair.verify(signatureData: ByteArray, clearData: ByteArray): Boolean = Cr
|
||||
@Throws(NoSuchAlgorithmException::class)
|
||||
fun secureRandomBytes(numOfBytes: Int): ByteArray = ByteArray(numOfBytes).apply { newSecureRandom().nextBytes(this) }
|
||||
|
||||
/**
|
||||
* This is a hack added because during deserialisation when no-param constructors are called sometimes default values
|
||||
* generate random numbers, which fail in SGX.
|
||||
* TODO remove this once deserialisation is figured out.
|
||||
*/
|
||||
private class DummySecureRandomSpi : SecureRandomSpi() {
|
||||
override fun engineSetSeed(bytes: ByteArray?) {
|
||||
Exception("DummySecureRandomSpi.engineSetSeed called").printStackTrace(System.out)
|
||||
}
|
||||
|
||||
override fun engineNextBytes(bytes: ByteArray?) {
|
||||
Exception("DummySecureRandomSpi.engineNextBytes called").printStackTrace(System.out)
|
||||
bytes?.fill(0)
|
||||
}
|
||||
|
||||
override fun engineGenerateSeed(numberOfBytes: Int): ByteArray {
|
||||
Exception("DummySecureRandomSpi.engineGenerateSeed called").printStackTrace(System.out)
|
||||
return ByteArray(numberOfBytes)
|
||||
}
|
||||
}
|
||||
|
||||
object DummySecureRandom : SecureRandom(DummySecureRandomSpi(), null)
|
||||
|
||||
/**
|
||||
* Get an instance of [SecureRandom] to avoid blocking, due to waiting for additional entropy, when possible.
|
||||
* In this version, the NativePRNGNonBlocking is exclusively used on Linux OS to utilize dev/urandom because in high traffic
|
||||
@ -254,3 +287,4 @@ fun <T : Any> serializedHash(x: T): SecureHash = x.serialize(context = Serializa
|
||||
* @return SHA256(SHA256(privacySalt || groupIndex || internalIndex))
|
||||
*/
|
||||
fun computeNonce(privacySalt: PrivacySalt, groupIndex: Int, internalIndex: Int) = SecureHash.sha256Twice(privacySalt.bytes + ByteBuffer.allocate(8).putInt(groupIndex).putInt(internalIndex).array())
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
@file:KeepForDJVM
|
||||
package net.corda.core.crypto
|
||||
|
||||
import io.netty.util.concurrent.FastThreadLocal
|
||||
import net.corda.core.DeleteForDJVM
|
||||
import net.corda.core.KeepForDJVM
|
||||
import net.corda.core.serialization.CordaSerializable
|
||||
@ -9,6 +10,7 @@ import net.corda.core.utilities.parseAsHex
|
||||
import net.corda.core.utilities.toHexString
|
||||
import java.nio.ByteBuffer
|
||||
import java.security.MessageDigest
|
||||
import java.util.function.Supplier
|
||||
|
||||
/**
|
||||
* Container for a cryptographically secure hash value.
|
||||
@ -69,12 +71,14 @@ sealed class SecureHash(bytes: ByteArray) : OpaqueBytes(bytes) {
|
||||
} ?: throw IllegalArgumentException("Provided string is null")
|
||||
}
|
||||
|
||||
private val sha256MessageDigest = SHA256DigestSupplier()
|
||||
|
||||
/**
|
||||
* Computes the SHA-256 hash value of the [ByteArray].
|
||||
* @param bytes The [ByteArray] to hash.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun sha256(bytes: ByteArray) = SHA256(MessageDigest.getInstance("SHA-256").digest(bytes))
|
||||
fun sha256(bytes: ByteArray) = SHA256(sha256MessageDigest.get().digest(bytes))
|
||||
|
||||
/**
|
||||
* Computes the SHA-256 hash of the [ByteArray], and then computes the SHA-256 hash of the hash.
|
||||
@ -139,4 +143,17 @@ fun ByteArray.sha256(): SecureHash.SHA256 = SecureHash.sha256(this)
|
||||
*/
|
||||
fun OpaqueBytes.sha256(): SecureHash.SHA256 = SecureHash.sha256(this.bytes)
|
||||
|
||||
/**
|
||||
* Hide the [FastThreadLocal] class behind a [Supplier] interface
|
||||
* so that we can remove it for core-deterministic.
|
||||
*/
|
||||
private class SHA256DigestSupplier : Supplier<MessageDigest> {
|
||||
private val threadLocalSha256MessageDigest = LocalSHA256Digest()
|
||||
override fun get(): MessageDigest = threadLocalSha256MessageDigest.get()
|
||||
}
|
||||
|
||||
// Declaring this as "object : FastThreadLocal<>" would have
|
||||
// created an extra public class in the API definition.
|
||||
private class LocalSHA256Digest : FastThreadLocal<MessageDigest>() {
|
||||
override fun initialValue(): MessageDigest = MessageDigest.getInstance("SHA-256")
|
||||
}
|
||||
|
@ -1,12 +1,73 @@
|
||||
package net.corda.core.crypto.internal
|
||||
|
||||
import net.corda.core.DeleteForDJVM
|
||||
import net.corda.core.StubOutForDJVM
|
||||
import net.corda.core.crypto.SignatureScheme
|
||||
import net.corda.core.internal.LazyPool
|
||||
import java.security.Provider
|
||||
import java.security.Signature
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
|
||||
/**
|
||||
* This is a collection of crypto related getInstance methods that tend to be quite inefficient and we want to be able to
|
||||
* optimise them en masse.
|
||||
*/
|
||||
object Instances {
|
||||
fun getSignatureInstance(algorithm: String, provider: Provider?) = Signature.getInstance(algorithm, provider)
|
||||
}
|
||||
fun <A> withSignature(signatureScheme: SignatureScheme, func: (signature: Signature) -> A): A {
|
||||
val signature = getSignatureInstance(signatureScheme.signatureName, providerMap[signatureScheme.providerName])
|
||||
try {
|
||||
return func(signature)
|
||||
} finally {
|
||||
releaseSignatureInstance(signature)
|
||||
}
|
||||
}
|
||||
|
||||
fun getSignatureInstance(algorithm: String, provider: Provider?) = signatureFactory.borrow(algorithm, provider)
|
||||
fun releaseSignatureInstance(sig: Signature) = signatureFactory.release(sig)
|
||||
|
||||
// Used to work around banning of ConcurrentHashMap in DJVM
|
||||
private val signatureFactory: SignatureFactory = try {
|
||||
makeCachingFactory()
|
||||
} catch (e: UnsupportedOperationException) {
|
||||
// Thrown by DJVM for method stubbed out below.
|
||||
makeFactory()
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
@StubOutForDJVM
|
||||
private fun makeCachingFactory(): SignatureFactory {
|
||||
return CachingSignatureFactory()
|
||||
}
|
||||
|
||||
@DeleteForDJVM
|
||||
private class CachingSignatureFactory : SignatureFactory {
|
||||
private val signatureInstances = ConcurrentHashMap<SignatureKey, LazyPool<Signature>>()
|
||||
|
||||
override fun borrow(algorithm: String, provider: Provider?): Signature {
|
||||
return signatureInstances.getOrPut(SignatureKey(algorithm, provider)) {
|
||||
LazyPool(newInstance = { Signature.getInstance(algorithm, provider) })
|
||||
}.borrow()
|
||||
}
|
||||
|
||||
override fun release(sig: Signature): Unit =
|
||||
signatureInstances[SignatureKey(sig.algorithm, sig.provider)]?.release(sig)!!
|
||||
}
|
||||
|
||||
private fun makeFactory(): SignatureFactory {
|
||||
return object : SignatureFactory {
|
||||
override fun borrow(algorithm: String, provider: Provider?): Signature {
|
||||
return Signature.getInstance(algorithm, provider)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
interface SignatureFactory {
|
||||
fun borrow(algorithm: String, provider: Provider?): Signature
|
||||
fun release(sig: Signature) {}
|
||||
}
|
||||
|
@ -2,9 +2,17 @@
|
||||
@file:DeleteForDJVM
|
||||
package net.corda.core.crypto.internal
|
||||
|
||||
import io.netty.util.concurrent.FastThreadLocal
|
||||
import net.corda.core.DeleteForDJVM
|
||||
import net.corda.core.crypto.newSecureRandom
|
||||
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
|
||||
import java.io.File
|
||||
import java.io.FileInputStream
|
||||
import java.io.IOException
|
||||
import java.io.InputStream
|
||||
import java.security.Provider
|
||||
import java.security.SecureRandom
|
||||
import java.security.SecureRandomSpi
|
||||
@ -13,11 +21,13 @@ import java.security.SecureRandomSpi
|
||||
* This has been migrated into a separate class so that it
|
||||
* is easier to delete from the core-deterministic module.
|
||||
*/
|
||||
val platformSecureRandom: () -> SecureRandom = when {
|
||||
SystemUtils.IS_OS_LINUX -> {
|
||||
{ SecureRandom.getInstance("NativePRNGNonBlocking") }
|
||||
internal val platformSecureRandom: () -> SecureRandom = when {
|
||||
SgxSupport.isInsideEnclave -> {
|
||||
{ DummySecureRandom }
|
||||
}
|
||||
else -> {
|
||||
{ sharedSecureRandom }
|
||||
}
|
||||
else -> SecureRandom::getInstanceStrong
|
||||
}
|
||||
|
||||
@DeleteForDJVM
|
||||
@ -26,17 +36,65 @@ class PlatformSecureRandomService(provider: Provider)
|
||||
|
||||
companion object {
|
||||
const val algorithm = "CordaPRNG"
|
||||
private val logger = loggerFor<PlatformSecureRandomService>()
|
||||
}
|
||||
|
||||
private val instance: SecureRandomSpi = if (SystemUtils.IS_OS_LINUX) tryAndUseLinuxSecureRandomSpi() else PlatformSecureRandomSpi()
|
||||
|
||||
@Suppress("TooGenericExceptionCaught", "TooGenericExceptionThrown")
|
||||
private fun tryAndUseLinuxSecureRandomSpi(): SecureRandomSpi = try {
|
||||
LinuxSecureRandomSpi()
|
||||
} catch (e: Exception) {
|
||||
logger.error("Unable to initialise LinuxSecureRandomSpi. The exception logged with this message might assist with diagnosis." +
|
||||
" The process will now exit.", e)
|
||||
System.exit(1)
|
||||
throw RuntimeException("Never reached, but calms the compiler.")
|
||||
}
|
||||
|
||||
private val instance: SecureRandomSpi = PlatformSecureRandomSpi()
|
||||
override fun newInstance(constructorParameter: Any?) = instance
|
||||
}
|
||||
|
||||
@DeleteForDJVM
|
||||
private class PlatformSecureRandomSpi : SecureRandomSpi() {
|
||||
private val secureRandom: SecureRandom = newSecureRandom()
|
||||
private val threadLocalSecureRandom = object : FastThreadLocal<SecureRandom>() {
|
||||
override fun initialValue() = SecureRandom.getInstanceStrong()
|
||||
}
|
||||
|
||||
private val secureRandom: SecureRandom get() = threadLocalSecureRandom.get()
|
||||
|
||||
override fun engineSetSeed(seed: ByteArray) = secureRandom.setSeed(seed)
|
||||
override fun engineNextBytes(bytes: ByteArray) = secureRandom.nextBytes(bytes)
|
||||
override fun engineGenerateSeed(numBytes: Int): ByteArray = secureRandom.generateSeed(numBytes)
|
||||
}
|
||||
|
||||
@DeleteForDJVM
|
||||
@Suppress("TooGenericExceptionCaught", "TooGenericExceptionThrown")
|
||||
private class LinuxSecureRandomSpi : SecureRandomSpi() {
|
||||
private fun openURandom(): InputStream {
|
||||
try {
|
||||
val file = File("/dev/urandom")
|
||||
val stream = FileInputStream(file)
|
||||
if (stream.read() == -1)
|
||||
throw RuntimeException("/dev/urandom not readable?")
|
||||
return stream
|
||||
} catch (e: Exception) {
|
||||
throw RuntimeException(e)
|
||||
}
|
||||
}
|
||||
|
||||
private var urandom = DataInputStream(openURandom())
|
||||
|
||||
override fun engineSetSeed(seed: ByteArray) {}
|
||||
override fun engineNextBytes(bytes: ByteArray) = try {
|
||||
urandom.readFully(bytes)
|
||||
} catch (e: IOException) {
|
||||
throw RuntimeException(e)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
@ -26,13 +26,19 @@ abstract class BackpressureAwareTimedFlow<ResultType> : FlowLogic<ResultType>(),
|
||||
val unwrapped = wrappedResult.fromUntrustedWorld
|
||||
when (unwrapped) {
|
||||
is WaitTimeUpdate -> {
|
||||
logger.info("Counterparty [${session.counterparty}] is busy - TimedFlow $runId has been asked to wait for an additional ${unwrapped.waitTime} seconds for completion.")
|
||||
stateMachine.updateTimedFlowTimeout(unwrapped.waitTime.seconds)
|
||||
applyWaitTimeUpdate(session, unwrapped)
|
||||
}
|
||||
is ReceiveType -> @Suppress("UNCHECKED_CAST") // The compiler doesn't understand it's checked in the line above
|
||||
return wrappedResult as UntrustworthyData<ReceiveType>
|
||||
else -> throw throw IllegalArgumentException("We were expecting a ${ReceiveType::class.java.name} or WaitTimeUpdate but we instead got a ${unwrapped.javaClass.name} ($unwrapped)")
|
||||
else -> throw throw IllegalArgumentException("We were expecting a ${ReceiveType::class.java.name} or WaitTimeUpdate but " +
|
||||
"we instead got a ${unwrapped.javaClass.name} ($unwrapped)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
open fun applyWaitTimeUpdate(session: FlowSession, update: WaitTimeUpdate) {
|
||||
logger.info("Counterparty [${session.counterparty}] is busy - TimedFlow $runId has been asked to wait for an additional " +
|
||||
"${update.waitTime} for completion.")
|
||||
stateMachine.updateTimedFlowTimeout(update.waitTime.seconds)
|
||||
}
|
||||
}
|
||||
|
@ -2,10 +2,10 @@
|
||||
|
||||
package net.corda.core.internal
|
||||
|
||||
import java.util.concurrent.locks.ReentrantLock
|
||||
import io.github.classgraph.ClassGraph
|
||||
import io.github.classgraph.ScanResult
|
||||
import net.corda.core.DeleteForDJVM
|
||||
import java.util.concurrent.locks.ReentrantLock
|
||||
import kotlin.concurrent.withLock
|
||||
|
||||
private val pooledScanMutex = ReentrantLock()
|
||||
|
@ -43,4 +43,5 @@ interface FlowStateMachine<FLOWRETURN> {
|
||||
val context: InvocationContext
|
||||
val ourIdentity: Party
|
||||
val ourSenderUUID: String?
|
||||
val creationTime: Long
|
||||
}
|
||||
|
@ -27,6 +27,7 @@ import java.lang.reflect.Modifier
|
||||
import java.math.BigDecimal
|
||||
import java.net.HttpURLConnection
|
||||
import java.net.HttpURLConnection.HTTP_OK
|
||||
import java.net.Proxy
|
||||
import java.net.URI
|
||||
import java.net.URL
|
||||
import java.nio.ByteBuffer
|
||||
@ -426,15 +427,17 @@ val DEFAULT_HTTP_CONNECT_TIMEOUT = 30.seconds.toMillis()
|
||||
val DEFAULT_HTTP_READ_TIMEOUT = 30.seconds.toMillis()
|
||||
|
||||
@DeleteForDJVM
|
||||
fun URL.openHttpConnection(): HttpURLConnection = openConnection().also {
|
||||
fun URL.openHttpConnection(proxy: Proxy? = null): HttpURLConnection = (
|
||||
if (proxy == null) openConnection()
|
||||
else openConnection(proxy)).also {
|
||||
// The default values are 0 which means infinite timeout.
|
||||
it.connectTimeout = DEFAULT_HTTP_CONNECT_TIMEOUT.toInt()
|
||||
it.readTimeout = DEFAULT_HTTP_READ_TIMEOUT.toInt()
|
||||
} as HttpURLConnection
|
||||
|
||||
@DeleteForDJVM
|
||||
fun URL.post(serializedData: OpaqueBytes, vararg properties: Pair<String, String>): ByteArray {
|
||||
return openHttpConnection().run {
|
||||
fun URL.post(serializedData: OpaqueBytes, vararg properties: Pair<String, String>, proxy: Proxy? = null): ByteArray {
|
||||
return openHttpConnection(proxy).run {
|
||||
doOutput = true
|
||||
requestMethod = "POST"
|
||||
properties.forEach { (key, value) -> setRequestProperty(key, value) }
|
||||
|
@ -15,19 +15,52 @@ class LifeCycle<S : Enum<S>>(initial: S) {
|
||||
private val lock = ReentrantReadWriteLock()
|
||||
private var state = initial
|
||||
|
||||
/** Assert that the lifecycle in the [requiredState]. */
|
||||
fun requireState(requiredState: S) {
|
||||
requireState({ "Required state to be $requiredState, was $it" }) { it == requiredState }
|
||||
/**
|
||||
* Assert that the lifecycle in the [requiredState]. Optionally runs [block], for the duration of which the
|
||||
* lifecycle is guaranteed to stay in [requiredState].
|
||||
*/
|
||||
fun <A> requireState(
|
||||
requiredState: S,
|
||||
block: () -> A
|
||||
): A {
|
||||
return requireState(
|
||||
errorMessage = { "Required state to be $requiredState, was $it" },
|
||||
predicate = { it == requiredState },
|
||||
block = block
|
||||
)
|
||||
}
|
||||
|
||||
fun requireState(requiredState: S) = requireState(requiredState) {}
|
||||
|
||||
fun <A> requireState(
|
||||
requiredState: S,
|
||||
throwable: Throwable,
|
||||
block: () -> A
|
||||
): A {
|
||||
return lock.readLock().withLock {
|
||||
if (requiredState != state) {
|
||||
throw throwable
|
||||
}
|
||||
block()
|
||||
}
|
||||
}
|
||||
|
||||
/** Assert something about the current state atomically. */
|
||||
fun <A> requireState(
|
||||
errorMessage: (S) -> String,
|
||||
predicate: (S) -> Boolean,
|
||||
block: () -> A
|
||||
): A {
|
||||
return lock.readLock().withLock {
|
||||
require(predicate(state)) { errorMessage(state) }
|
||||
block()
|
||||
}
|
||||
}
|
||||
fun requireState(
|
||||
errorMessage: (S) -> String = { "Predicate failed on state $it" },
|
||||
predicate: (S) -> Boolean
|
||||
) {
|
||||
lock.readLock().withLock {
|
||||
require(predicate(state)) { errorMessage(state) }
|
||||
}
|
||||
requireState(errorMessage, predicate) {}
|
||||
}
|
||||
|
||||
/** Transition the state from [from] to [to]. */
|
||||
|
@ -327,6 +327,7 @@ abstract class Verifier(val ltx: LedgerTransaction, protected val transactionCla
|
||||
*
|
||||
* @throws TransactionVerificationException if the constraints fail to verify
|
||||
*/
|
||||
@Suppress("NestedBlockDepth", "MagicNumber")
|
||||
private fun verifyConstraints(contractAttachmentsByContract: Map<ContractClassName, ContractAttachment>) {
|
||||
// For each contract/constraint pair check that the relevant attachment is valid.
|
||||
allStates.map { it.contract to it.constraint }.toSet().forEach { (contract, constraint) ->
|
||||
|
@ -35,7 +35,8 @@ data class CordappImpl(
|
||||
val notaryService: Class<out NotaryService>? = null,
|
||||
/** Indicates whether the CorDapp is loaded from external sources, or generated on node startup (virtual). */
|
||||
val isLoaded: Boolean = true,
|
||||
private val explicitCordappClasses: List<String> = emptyList()
|
||||
private val explicitCordappClasses: List<String> = emptyList(),
|
||||
val isVirtual: Boolean = false
|
||||
) : Cordapp {
|
||||
override val name: String = jarName(jarPath)
|
||||
|
||||
|
@ -88,20 +88,41 @@ object CordappResolver {
|
||||
*/
|
||||
val currentTargetVersion: Int get() = currentCordapp?.targetPlatformVersion ?: 1
|
||||
|
||||
// A list of extra CorDapps added to the current CorDapps list for testing purposes.
|
||||
private var extraCordappsForTesting = listOf<Cordapp>()
|
||||
|
||||
/**
|
||||
* Return all the CorDapps that were involved in the call stack at the point the provided exception was generated.
|
||||
*
|
||||
* This is provided to allow splitting the cost of generating the exception and retrieving the CorDapps involved.
|
||||
*/
|
||||
fun cordappsFromException(exception: Exception): List<Cordapp> {
|
||||
val apps = exception.stackTrace
|
||||
.mapNotNull { cordappClasses[it.className] }
|
||||
.flatten()
|
||||
.distinct()
|
||||
return (apps + extraCordappsForTesting)
|
||||
}
|
||||
|
||||
/**
|
||||
* Temporarily apply a fake CorDapp with the given parameters. For use in testing.
|
||||
*/
|
||||
@Synchronized
|
||||
@VisibleForTesting
|
||||
fun <T> withCordapp(minimumPlatformVersion: Int = 1, targetPlatformVersion: Int = PLATFORM_VERSION, block: () -> T): T {
|
||||
fun <T> withTestCordapp(minimumPlatformVersion: Int = 1,
|
||||
targetPlatformVersion: Int = PLATFORM_VERSION,
|
||||
extraApps: List<CordappImpl> = listOf(),
|
||||
block: () -> T): T {
|
||||
val currentResolver = cordappResolver
|
||||
cordappResolver = {
|
||||
CordappImpl.TEST_INSTANCE.copy(minimumPlatformVersion = minimumPlatformVersion, targetPlatformVersion = targetPlatformVersion)
|
||||
}
|
||||
extraCordappsForTesting = listOf(cordappResolver()!!) + extraApps
|
||||
try {
|
||||
return block()
|
||||
} finally {
|
||||
cordappResolver = currentResolver
|
||||
extraCordappsForTesting = listOf()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,8 @@
|
||||
package net.corda.core.internal.utilities
|
||||
|
||||
import java.util.concurrent.TimeUnit
|
||||
import kotlin.system.measureNanoTime
|
||||
|
||||
fun measureMilliAndNanoTime(block: () -> Unit): Double {
|
||||
return measureNanoTime(block).toDouble() / TimeUnit.MILLISECONDS.toNanos(1).toDouble()
|
||||
}
|
@ -5,7 +5,10 @@ import net.corda.core.DoNotImplement
|
||||
import net.corda.core.contracts.*
|
||||
import net.corda.core.cordapp.CordappContext
|
||||
import net.corda.core.cordapp.CordappProvider
|
||||
import net.corda.core.crypto.*
|
||||
import net.corda.core.crypto.Crypto
|
||||
import net.corda.core.crypto.SignableData
|
||||
import net.corda.core.crypto.SignatureMetadata
|
||||
import net.corda.core.crypto.TransactionSignature
|
||||
import net.corda.core.flows.ContractUpgradeFlow
|
||||
import net.corda.core.node.services.*
|
||||
import net.corda.core.serialization.SerializeAsToken
|
||||
|
@ -7,7 +7,6 @@ import net.corda.core.crypto.DigitalSignature
|
||||
import net.corda.core.crypto.SignableData
|
||||
import net.corda.core.crypto.TransactionSignature
|
||||
import net.corda.core.identity.PartyAndCertificate
|
||||
import net.corda.core.node.ServiceHub
|
||||
import java.security.KeyPair
|
||||
import java.security.PrivateKey
|
||||
import java.security.PublicKey
|
||||
|
@ -9,7 +9,6 @@ import net.corda.core.node.services.vault.CollectionOperator.*
|
||||
import net.corda.core.node.services.vault.ColumnPredicate.*
|
||||
import net.corda.core.node.services.vault.EqualityComparisonOperator.*
|
||||
import net.corda.core.node.services.vault.LikenessOperator.*
|
||||
import net.corda.core.schemas.PersistentState
|
||||
import net.corda.core.schemas.StatePersistable
|
||||
import net.corda.core.serialization.CordaSerializable
|
||||
import java.lang.reflect.Field
|
||||
|
@ -22,7 +22,8 @@ import net.corda.core.utilities.contextLogger
|
||||
import java.security.PublicKey
|
||||
import java.time.Duration
|
||||
import java.time.Instant
|
||||
import java.util.*
|
||||
import java.util.ArrayDeque
|
||||
import java.util.UUID
|
||||
import java.util.regex.Pattern
|
||||
import kotlin.collections.ArrayList
|
||||
import kotlin.collections.component1
|
||||
|
@ -38,6 +38,9 @@ infix fun Long.exactAdd(b: Long): Long = Math.addExact(this, b)
|
||||
*/
|
||||
inline fun <reified T : Any> loggerFor(): Logger = LoggerFactory.getLogger(T::class.java)
|
||||
|
||||
/** Returns the logger used for detailed logging. */
|
||||
fun detailedLogger(): Logger = LoggerFactory.getLogger("DetailedInfo")
|
||||
|
||||
/** When called from a companion object, returns the logger for the enclosing class. */
|
||||
fun Any.contextLogger(): Logger = LoggerFactory.getLogger(javaClass.enclosingClass)
|
||||
|
||||
|
@ -0,0 +1,8 @@
|
||||
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)")
|
||||
}
|
||||
}
|
11
core/src/test/kotlin/net/corda/core/crypto/SecureHashTest.kt
Normal file
11
core/src/test/kotlin/net/corda/core/crypto/SecureHashTest.kt
Normal file
@ -0,0 +1,11 @@
|
||||
package net.corda.core.crypto
|
||||
|
||||
import org.junit.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
class SecureHashTest {
|
||||
@Test
|
||||
fun `sha256 does not retain state between same-thread invocations`() {
|
||||
assertEquals(SecureHash.sha256("abc"), SecureHash.sha256("abc"))
|
||||
}
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
package net.corda.core.crypto
|
||||
|
||||
import org.junit.Test
|
||||
import java.security.SecureRandom
|
||||
|
||||
class SecureRandomTest {
|
||||
@Test(timeout = 1000)
|
||||
fun `regular SecureRandom does not spend a lot of time seeding itself`() {
|
||||
val bytes = ByteArray(1000)
|
||||
repeat(10) {
|
||||
val sr = SecureRandom()
|
||||
repeat(100) {
|
||||
sr.nextBytes(bytes)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -28,7 +28,7 @@ class CordappResolverTest {
|
||||
assertEquals(defaultTargetVersion, CordappResolver.currentTargetVersion)
|
||||
|
||||
val expectedTargetVersion = 555
|
||||
CordappResolver.withCordapp(targetPlatformVersion = expectedTargetVersion) {
|
||||
CordappResolver.withTestCordapp(targetPlatformVersion = expectedTargetVersion) {
|
||||
val actualTargetVersion = CordappResolver.currentTargetVersion
|
||||
assertEquals(expectedTargetVersion, actualTargetVersion)
|
||||
}
|
||||
|
@ -4,8 +4,8 @@ import net.corda.core.contracts.StateRef
|
||||
import net.corda.core.crypto.SecureHash
|
||||
import net.corda.core.internal.declaredField
|
||||
import org.assertj.core.api.Assertions.catchThrowable
|
||||
import org.junit.Assert
|
||||
import org.junit.Assert.assertSame
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Test
|
||||
import java.nio.ByteBuffer
|
||||
import java.nio.ReadOnlyBufferException
|
||||
@ -52,10 +52,10 @@ class ByteArraysTest {
|
||||
|
||||
val privacySalt = net.corda.core.contracts.PrivacySalt()
|
||||
val privacySaltAsHexString = privacySalt.bytes.toHexString()
|
||||
Assert.assertTrue(privacySaltAsHexString.matches(HEX_REGEX))
|
||||
assertTrue(privacySaltAsHexString.matches(HEX_REGEX))
|
||||
|
||||
val stateRef = StateRef(SecureHash.randomSHA256(), 0)
|
||||
val txhashAsHexString = stateRef.txhash.bytes.toHexString()
|
||||
Assert.assertTrue(txhashAsHexString.matches(HEX_REGEX))
|
||||
assertTrue(txhashAsHexString.matches(HEX_REGEX))
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,6 @@ package net.corda.nodeapi.internal.crypto
|
||||
|
||||
import net.corda.core.crypto.internal.AliasPrivateKey
|
||||
import net.corda.testing.internal.stubs.CertificateStoreStubs
|
||||
import org.assertj.core.api.Assertions.assertThatIllegalArgumentException
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.rules.TemporaryFolder
|
||||
@ -20,15 +19,18 @@ class AliasPrivateKeyTest {
|
||||
val alias = "01234567890"
|
||||
val aliasPrivateKey = AliasPrivateKey(alias)
|
||||
val certificatesDirectory = tempFolder.root.toPath()
|
||||
val signingCertStore = CertificateStoreStubs.Signing.withCertificatesDirectory(certificatesDirectory, "keystorepass").get(createNew = true)
|
||||
signingCertStore.query { setPrivateKey(alias, aliasPrivateKey, listOf(NOT_YET_REGISTERED_MARKER_KEYS_AND_CERTS.ECDSAR1_CERT), "entrypassword") }
|
||||
val signingCertStore = CertificateStoreStubs.Signing.withCertificatesDirectory(
|
||||
certificatesDirectory,
|
||||
"keystorepass").get(createNew = true)
|
||||
signingCertStore.query {
|
||||
setPrivateKey(alias, aliasPrivateKey, listOf(NOT_YET_REGISTERED_MARKER_KEYS_AND_CERTS.ECDSAR1_CERT), "entrypassword")
|
||||
}
|
||||
// We can retrieve the certificate.
|
||||
assertTrue { signingCertStore.contains(alias) }
|
||||
// We can retrieve the certificate.
|
||||
assertEquals(NOT_YET_REGISTERED_MARKER_KEYS_AND_CERTS.ECDSAR1_CERT, signingCertStore[alias])
|
||||
// Although we can store an AliasPrivateKey, we cannot retrieve it. But, it's fine as we use certStore for storing/handling certs only.
|
||||
assertThatIllegalArgumentException().isThrownBy {
|
||||
signingCertStore.query { getPrivateKey(alias, "entrypassword") }
|
||||
}.withMessage("Unrecognised algorithm: 1.3.6.1.4.1.50530.1.2")
|
||||
// Although we can store an AliasPrivateKey, we cannot retrieve it. But, it's fine as we use certStore for storing/handling certs
|
||||
// only.
|
||||
assertEquals(aliasPrivateKey, signingCertStore.query { getPrivateKey(alias, "entrypassword") })
|
||||
}
|
||||
}
|
||||
|
@ -45,7 +45,8 @@ class TransientReference<out A>(@Transient val value: A)
|
||||
|
||||
class FlowStateMachineImpl<R>(override val id: StateMachineRunId,
|
||||
override val logic: FlowLogic<R>,
|
||||
scheduler: FiberScheduler
|
||||
scheduler: FiberScheduler,
|
||||
override val creationTime: Long = System.currentTimeMillis()
|
||||
) : Fiber<Unit>(id.toString(), scheduler), FlowStateMachine<R>, FlowFiber {
|
||||
companion object {
|
||||
/**
|
||||
|
@ -82,7 +82,7 @@ class FinalityHandlerTest {
|
||||
}
|
||||
|
||||
private fun TestStartedNode.finaliseWithOldApi(stx: SignedTransaction): CordaFuture<SignedTransaction> {
|
||||
return CordappResolver.withCordapp(targetPlatformVersion = 3) {
|
||||
return CordappResolver.withTestCordapp(targetPlatformVersion = 3) {
|
||||
@Suppress("DEPRECATION")
|
||||
services.startFlow(FinalityFlow(stx)).resultFuture.apply {
|
||||
mockNet.runNetwork()
|
||||
|
@ -897,7 +897,7 @@ class NodeVaultServiceTest {
|
||||
|
||||
fun List<StateAndRef<DummyState>>.getNumbers() = map { it.state.data.magicNumber }.toSet()
|
||||
|
||||
CordappResolver.withCordapp(targetPlatformVersion = 3) {
|
||||
CordappResolver.withTestCordapp(targetPlatformVersion = 3) {
|
||||
services.recordTransactions(StatesToRecord.ONLY_RELEVANT, listOf(createTx(1, megaCorp.party)))
|
||||
services.recordTransactions(StatesToRecord.ONLY_RELEVANT, listOf(createTx(2, miniCorp.party)))
|
||||
services.recordTransactions(StatesToRecord.ONLY_RELEVANT, listOf(createTx(3, miniCorp.party, megaCorp.party)))
|
||||
|
@ -4,7 +4,6 @@ import com.google.common.reflect.TypeToken
|
||||
import net.corda.core.KeepForDJVM
|
||||
import net.corda.core.internal.isPublic
|
||||
import net.corda.core.serialization.SerializableCalculatedProperty
|
||||
import net.corda.core.utilities.contextLogger
|
||||
import net.corda.serialization.internal.amqp.MethodClassifier.*
|
||||
import java.lang.reflect.Field
|
||||
import java.lang.reflect.Method
|
||||
|
Loading…
x
Reference in New Issue
Block a user