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:
Christian Sailer
2019-12-09 14:17:48 +00:00
committed by Rick Parker
parent 87b39bf515
commit 14050826e9
37 changed files with 468 additions and 72 deletions

View File

@ -77,7 +77,7 @@ buildscript {
ext.djvm_version = constants.getProperty("djvmVersion") ext.djvm_version = constants.getProperty("djvmVersion")
ext.deterministic_rt_version = constants.getProperty('deterministicRtVersion') ext.deterministic_rt_version = constants.getProperty('deterministicRtVersion')
ext.okhttp_version = '3.14.2' 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.typesafe_config_version = constants.getProperty("typesafeConfigVersion")
ext.fileupload_version = '1.4' ext.fileupload_version = '1.4'
// Legacy JUnit 4 version // Legacy JUnit 4 version
@ -95,10 +95,10 @@ buildscript {
ext.jansi_version = '1.18' ext.jansi_version = '1.18'
ext.hibernate_version = '5.4.3.Final' ext.hibernate_version = '5.4.3.Final'
ext.h2_version = '1.4.199' // Update docs if renamed or removed. 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.rxjava_version = '1.3.8'
ext.dokka_version = '0.9.17' 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.dependency_checker_version = '5.2.0'
ext.commons_collections_version = '4.3' ext.commons_collections_version = '4.3'
ext.beanutils_version = '1.9.3' ext.beanutils_version = '1.9.3'
@ -120,6 +120,7 @@ buildscript {
ext.class_graph_version = constants.getProperty('classgraphVersion') ext.class_graph_version = constants.getProperty('classgraphVersion')
ext.jcabi_manifests_version = '1.1' ext.jcabi_manifests_version = '1.1'
ext.picocli_version = '3.9.6' ext.picocli_version = '3.9.6'
ext.commons_lang_version = '3.9'
ext.commons_io_version = '2.6' ext.commons_io_version = '2.6'
ext.controlsfx_version = '8.40.15' ext.controlsfx_version = '8.40.15'
if (JavaVersion.current() == JavaVersion.VERSION_11) { if (JavaVersion.current() == JavaVersion.VERSION_11) {

View File

@ -58,10 +58,13 @@ task patchCore(type: Zip, dependsOn: coreJarTask) {
from(compileKotlin) from(compileKotlin)
from(processResources) from(processResources)
from(zipTree(originalJar)) { 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/internal/*ToggleField*.class'
exclude 'net/corda/core/serialization/*SerializationFactory*.class' exclude 'net/corda/core/serialization/*SerializationFactory*.class'
exclude 'net/corda/core/serialization/internal/CheckpointSerializationFactory*.class' exclude 'net/corda/core/serialization/internal/CheckpointSerializationFactory*.class'
exclude 'net/corda/core/internal/rules/*.class' exclude 'net/corda/core/internal/rules/*.class'
exclude 'net/corda/core/utilities/SgxSupport*.class'
} }
reproducibleFileOrder = true reproducibleFileOrder = true

View File

@ -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")
}
}

View File

@ -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")
}

View File

@ -0,0 +1,9 @@
package net.corda.core.utilities
import net.corda.core.KeepForDJVM
@KeepForDJVM
object SgxSupport {
@JvmStatic
val isInsideEnclave: Boolean = true
}

View File

@ -60,7 +60,7 @@ class FinalityFlowTests : WithFinality {
fun `allow use of the old API if the CorDapp target version is 3`() { fun `allow use of the old API if the CorDapp target version is 3`() {
val oldBob = createBob(cordapps = listOf(tokenOldCordapp())) val oldBob = createBob(cordapps = listOf(tokenOldCordapp()))
val stx = aliceNode.issuesCashTo(oldBob) val stx = aliceNode.issuesCashTo(oldBob)
val resultFuture = CordappResolver.withCordapp(targetPlatformVersion = 3) { val resultFuture = CordappResolver.withTestCordapp(targetPlatformVersion = 3) {
@Suppress("DEPRECATION") @Suppress("DEPRECATION")
aliceNode.startFlowAndRunNetwork(FinalityFlow(stx)).resultFuture aliceNode.startFlowAndRunNetwork(FinalityFlow(stx)).resultFuture
} }

View File

@ -59,7 +59,7 @@ dependencies {
// RxJava: observable streams of events. // RxJava: observable streams of events.
compile "io.reactivex:rxjava:$rxjava_version" 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/ // Java ed25519 implementation. See https://github.com/str4d/ed25519-java/
compile "net.i2p.crypto:eddsa:$eddsa_version" compile "net.i2p.crypto:eddsa:$eddsa_version"
@ -74,6 +74,9 @@ dependencies {
// required to use @Type annotation // required to use @Type annotation
compile "org.hibernate:hibernate-core:$hibernate_version" 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 compile group: "io.github.classgraph", name: "classgraph", version: class_graph_version
testCompile "org.ow2.asm:asm:$asm_version" testCompile "org.ow2.asm:asm:$asm_version"

View File

@ -7,6 +7,8 @@ import net.corda.core.crypto.CordaObjectIdentifier.COMPOSITE_SIGNATURE
import net.corda.core.crypto.internal.PlatformSecureRandomService import net.corda.core.crypto.internal.PlatformSecureRandomService
import org.bouncycastle.asn1.ASN1ObjectIdentifier import org.bouncycastle.asn1.ASN1ObjectIdentifier
import java.security.Provider import java.security.Provider
import java.util.*
import java.util.concurrent.ConcurrentHashMap
@KeepForDJVM @KeepForDJVM
@Suppress("DEPRECATION") // JDK11: should replace with Provider(String name, double version, String info) (since 9) @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() { private fun putPlatformSecureRandomService() {
putService(PlatformSecureRandomService(this)) 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 @KeepForDJVM

View File

@ -1,9 +1,16 @@
package net.corda.core.crypto package net.corda.core.crypto
import net.corda.core.CordaOID
import net.corda.core.DeleteForDJVM import net.corda.core.DeleteForDJVM
import net.corda.core.KeepForDJVM import net.corda.core.KeepForDJVM
import net.corda.core.StubOutForDJVM 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.corda.core.serialization.serialize
import net.i2p.crypto.eddsa.EdDSAEngine import net.i2p.crypto.eddsa.EdDSAEngine
import net.i2p.crypto.eddsa.EdDSAPrivateKey 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.EdDSAPrivateKeySpec
import net.i2p.crypto.eddsa.spec.EdDSAPublicKeySpec import net.i2p.crypto.eddsa.spec.EdDSAPublicKeySpec
import org.bouncycastle.asn1.ASN1Integer import org.bouncycastle.asn1.ASN1Integer
import org.bouncycastle.asn1.ASN1ObjectIdentifier
import org.bouncycastle.asn1.DERNull import org.bouncycastle.asn1.DERNull
import org.bouncycastle.asn1.DERUTF8String
import org.bouncycastle.asn1.DLSequence import org.bouncycastle.asn1.DLSequence
import org.bouncycastle.asn1.bc.BCObjectIdentifiers import org.bouncycastle.asn1.bc.BCObjectIdentifiers
import org.bouncycastle.asn1.nist.NISTObjectIdentifiers 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.provider.sphincs.BCSphincs256PublicKey
import org.bouncycastle.pqc.jcajce.spec.SPHINCS256KeyGenParameterSpec import org.bouncycastle.pqc.jcajce.spec.SPHINCS256KeyGenParameterSpec
import java.math.BigInteger 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.InvalidKeySpecException
import java.security.spec.PKCS8EncodedKeySpec import java.security.spec.PKCS8EncodedKeySpec
import java.security.spec.X509EncodedKeySpec import java.security.spec.X509EncodedKeySpec
@ -289,11 +306,21 @@ object Crypto {
@JvmStatic @JvmStatic
fun decodePrivateKey(encodedKey: ByteArray): PrivateKey { fun decodePrivateKey(encodedKey: ByteArray): PrivateKey {
val keyInfo = PrivateKeyInfo.getInstance(encodedKey) val keyInfo = PrivateKeyInfo.getInstance(encodedKey)
if (keyInfo.privateKeyAlgorithm.algorithm == ASN1ObjectIdentifier(CordaOID.ALIAS_PRIVATE_KEY)) {
return decodeAliasPrivateKey(keyInfo)
}
val signatureScheme = findSignatureScheme(keyInfo.privateKeyAlgorithm) val signatureScheme = findSignatureScheme(keyInfo.privateKeyAlgorithm)
val keyFactory = keyFactory(signatureScheme) val keyFactory = keyFactory(signatureScheme)
return keyFactory.generatePrivate(PKCS8EncodedKeySpec(encodedKey)) 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. * 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. * This should be used when the type key is known, e.g. during deserialisation or with key caches or key managers.
@ -436,7 +463,7 @@ object Crypto {
"Unsupported key/algorithm for schemeCodeName: ${signatureScheme.schemeCodeName}" "Unsupported key/algorithm for schemeCodeName: ${signatureScheme.schemeCodeName}"
} }
require(clearData.isNotEmpty()) { "Signing of an empty array is not permitted!" } require(clearData.isNotEmpty()) { "Signing of an empty array is not permitted!" }
val signature = Instances.getSignatureInstance(signatureScheme.signatureName, providerMap[signatureScheme.providerName]) return withSignature(signatureScheme) { signature ->
// Note that deterministic signature schemes, such as EdDSA, original SPHINCS-256 and RSA PKCS#1, do not require // 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 // 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 // SecureRandom implementation. Also, SPHINCS-256 implementation in BouncyCastle 1.60 fails with
@ -452,7 +479,8 @@ object Crypto {
signature.initSign(privateKey, newSecureRandom()) signature.initSign(privateKey, newSecureRandom())
} }
signature.update(clearData) signature.update(clearData)
return signature.sign() signature.sign()
}
} }
/** /**
@ -640,10 +668,11 @@ object Crypto {
require(isSupportedSignatureScheme(signatureScheme)) { require(isSupportedSignatureScheme(signatureScheme)) {
"Unsupported key/algorithm for schemeCodeName: ${signatureScheme.schemeCodeName}" "Unsupported key/algorithm for schemeCodeName: ${signatureScheme.schemeCodeName}"
} }
val signature = Instances.getSignatureInstance(signatureScheme.signatureName, providerMap[signatureScheme.providerName]) return withSignature(signatureScheme) { signature ->
signature.initVerify(publicKey) signature.initVerify(publicKey)
signature.update(clearData) signature.update(clearData)
return signature.verify(signatureData) signature.verify(signatureData)
}
} }
/** /**

View File

@ -1,3 +1,4 @@
@file:Suppress("MatchingDeclarationName")
@file:KeepForDJVM @file:KeepForDJVM
@file:JvmName("CryptoUtils") @file:JvmName("CryptoUtils")
@ -14,7 +15,14 @@ import net.corda.core.utilities.toBase58
import net.corda.core.utilities.toSHA256Bytes import net.corda.core.utilities.toSHA256Bytes
import java.math.BigInteger import java.math.BigInteger
import java.nio.ByteBuffer 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. * 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]. */ /** Return true if [otherKey] fulfils the requirements of this [PublicKey]. */
fun PublicKey.isFulfilledBy(otherKey: PublicKey): Boolean = isFulfilledBy(setOf(otherKey)) fun PublicKey.isFulfilledBy(otherKey: PublicKey): Boolean = isFulfilledBy(setOf(otherKey))
/** Return true if [otherKeys] fulfil the requirements of this [PublicKey]. */ /** 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) 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 // val (private, public) = keyPair
/* The [PrivateKey] of this [KeyPair]. */ /* The [PrivateKey] of this [KeyPair]. */
operator fun KeyPair.component1(): PrivateKey = this.private operator fun KeyPair.component1(): PrivateKey = this.private
/* The [PublicKey] of this [KeyPair]. */ /* The [PublicKey] of this [KeyPair]. */
operator fun KeyPair.component2(): PublicKey = this.public operator fun KeyPair.component2(): PublicKey = this.public
@ -190,6 +200,29 @@ fun KeyPair.verify(signatureData: ByteArray, clearData: ByteArray): Boolean = Cr
@Throws(NoSuchAlgorithmException::class) @Throws(NoSuchAlgorithmException::class)
fun secureRandomBytes(numOfBytes: Int): ByteArray = ByteArray(numOfBytes).apply { newSecureRandom().nextBytes(this) } 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. * 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 * 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)) * @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()) fun computeNonce(privacySalt: PrivacySalt, groupIndex: Int, internalIndex: Int) = SecureHash.sha256Twice(privacySalt.bytes + ByteBuffer.allocate(8).putInt(groupIndex).putInt(internalIndex).array())

View File

@ -1,6 +1,7 @@
@file:KeepForDJVM @file:KeepForDJVM
package net.corda.core.crypto package net.corda.core.crypto
import io.netty.util.concurrent.FastThreadLocal
import net.corda.core.DeleteForDJVM import net.corda.core.DeleteForDJVM
import net.corda.core.KeepForDJVM import net.corda.core.KeepForDJVM
import net.corda.core.serialization.CordaSerializable import net.corda.core.serialization.CordaSerializable
@ -9,6 +10,7 @@ import net.corda.core.utilities.parseAsHex
import net.corda.core.utilities.toHexString import net.corda.core.utilities.toHexString
import java.nio.ByteBuffer import java.nio.ByteBuffer
import java.security.MessageDigest import java.security.MessageDigest
import java.util.function.Supplier
/** /**
* Container for a cryptographically secure hash value. * Container for a cryptographically secure hash value.
@ -69,12 +71,14 @@ sealed class SecureHash(bytes: ByteArray) : OpaqueBytes(bytes) {
} ?: throw IllegalArgumentException("Provided string is null") } ?: throw IllegalArgumentException("Provided string is null")
} }
private val sha256MessageDigest = SHA256DigestSupplier()
/** /**
* Computes the SHA-256 hash value of the [ByteArray]. * Computes the SHA-256 hash value of the [ByteArray].
* @param bytes The [ByteArray] to hash. * @param bytes The [ByteArray] to hash.
*/ */
@JvmStatic @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. * 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) 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")
}

View File

@ -1,12 +1,73 @@
package net.corda.core.crypto.internal 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.Provider
import java.security.Signature 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 * 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. * optimise them en masse.
*/ */
object Instances { 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) {}
} }

View File

@ -2,9 +2,17 @@
@file:DeleteForDJVM @file:DeleteForDJVM
package net.corda.core.crypto.internal package net.corda.core.crypto.internal
import io.netty.util.concurrent.FastThreadLocal
import net.corda.core.DeleteForDJVM 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 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.Provider
import java.security.SecureRandom import java.security.SecureRandom
import java.security.SecureRandomSpi import java.security.SecureRandomSpi
@ -13,11 +21,13 @@ import java.security.SecureRandomSpi
* This has been migrated into a separate class so that it * This has been migrated into a separate class so that it
* is easier to delete from the core-deterministic module. * is easier to delete from the core-deterministic module.
*/ */
val platformSecureRandom: () -> SecureRandom = when { internal val platformSecureRandom: () -> SecureRandom = when {
SystemUtils.IS_OS_LINUX -> { SgxSupport.isInsideEnclave -> {
{ SecureRandom.getInstance("NativePRNGNonBlocking") } { DummySecureRandom }
}
else -> {
{ sharedSecureRandom }
} }
else -> SecureRandom::getInstanceStrong
} }
@DeleteForDJVM @DeleteForDJVM
@ -26,17 +36,65 @@ class PlatformSecureRandomService(provider: Provider)
companion object { companion object {
const val algorithm = "CordaPRNG" 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 override fun newInstance(constructorParameter: Any?) = instance
} }
@DeleteForDJVM @DeleteForDJVM
private class PlatformSecureRandomSpi : SecureRandomSpi() { 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 engineSetSeed(seed: ByteArray) = secureRandom.setSeed(seed)
override fun engineNextBytes(bytes: ByteArray) = secureRandom.nextBytes(bytes) override fun engineNextBytes(bytes: ByteArray) = secureRandom.nextBytes(bytes)
override fun engineGenerateSeed(numBytes: Int): ByteArray = secureRandom.generateSeed(numBytes) 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)
}

View File

@ -26,13 +26,19 @@ abstract class BackpressureAwareTimedFlow<ResultType> : FlowLogic<ResultType>(),
val unwrapped = wrappedResult.fromUntrustedWorld val unwrapped = wrappedResult.fromUntrustedWorld
when (unwrapped) { when (unwrapped) {
is WaitTimeUpdate -> { is WaitTimeUpdate -> {
logger.info("Counterparty [${session.counterparty}] is busy - TimedFlow $runId has been asked to wait for an additional ${unwrapped.waitTime} seconds for completion.") applyWaitTimeUpdate(session, unwrapped)
stateMachine.updateTimedFlowTimeout(unwrapped.waitTime.seconds)
} }
is ReceiveType -> @Suppress("UNCHECKED_CAST") // The compiler doesn't understand it's checked in the line above is ReceiveType -> @Suppress("UNCHECKED_CAST") // The compiler doesn't understand it's checked in the line above
return wrappedResult as UntrustworthyData<ReceiveType> 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)
}
} }

View File

@ -2,10 +2,10 @@
package net.corda.core.internal package net.corda.core.internal
import java.util.concurrent.locks.ReentrantLock
import io.github.classgraph.ClassGraph import io.github.classgraph.ClassGraph
import io.github.classgraph.ScanResult import io.github.classgraph.ScanResult
import net.corda.core.DeleteForDJVM import net.corda.core.DeleteForDJVM
import java.util.concurrent.locks.ReentrantLock
import kotlin.concurrent.withLock import kotlin.concurrent.withLock
private val pooledScanMutex = ReentrantLock() private val pooledScanMutex = ReentrantLock()

View File

@ -43,4 +43,5 @@ interface FlowStateMachine<FLOWRETURN> {
val context: InvocationContext val context: InvocationContext
val ourIdentity: Party val ourIdentity: Party
val ourSenderUUID: String? val ourSenderUUID: String?
val creationTime: Long
} }

View File

@ -27,6 +27,7 @@ import java.lang.reflect.Modifier
import java.math.BigDecimal import java.math.BigDecimal
import java.net.HttpURLConnection import java.net.HttpURLConnection
import java.net.HttpURLConnection.HTTP_OK import java.net.HttpURLConnection.HTTP_OK
import java.net.Proxy
import java.net.URI import java.net.URI
import java.net.URL import java.net.URL
import java.nio.ByteBuffer import java.nio.ByteBuffer
@ -426,15 +427,17 @@ val DEFAULT_HTTP_CONNECT_TIMEOUT = 30.seconds.toMillis()
val DEFAULT_HTTP_READ_TIMEOUT = 30.seconds.toMillis() val DEFAULT_HTTP_READ_TIMEOUT = 30.seconds.toMillis()
@DeleteForDJVM @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. // The default values are 0 which means infinite timeout.
it.connectTimeout = DEFAULT_HTTP_CONNECT_TIMEOUT.toInt() it.connectTimeout = DEFAULT_HTTP_CONNECT_TIMEOUT.toInt()
it.readTimeout = DEFAULT_HTTP_READ_TIMEOUT.toInt() it.readTimeout = DEFAULT_HTTP_READ_TIMEOUT.toInt()
} as HttpURLConnection } as HttpURLConnection
@DeleteForDJVM @DeleteForDJVM
fun URL.post(serializedData: OpaqueBytes, vararg properties: Pair<String, String>): ByteArray { fun URL.post(serializedData: OpaqueBytes, vararg properties: Pair<String, String>, proxy: Proxy? = null): ByteArray {
return openHttpConnection().run { return openHttpConnection(proxy).run {
doOutput = true doOutput = true
requestMethod = "POST" requestMethod = "POST"
properties.forEach { (key, value) -> setRequestProperty(key, value) } properties.forEach { (key, value) -> setRequestProperty(key, value) }

View File

@ -15,19 +15,52 @@ class LifeCycle<S : Enum<S>>(initial: S) {
private val lock = ReentrantReadWriteLock() private val lock = ReentrantReadWriteLock()
private var state = initial private var state = initial
/** Assert that the lifecycle in the [requiredState]. */ /**
fun requireState(requiredState: S) { * Assert that the lifecycle in the [requiredState]. Optionally runs [block], for the duration of which the
requireState({ "Required state to be $requiredState, was $it" }) { it == requiredState } * 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. */ /** 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( fun requireState(
errorMessage: (S) -> String = { "Predicate failed on state $it" }, errorMessage: (S) -> String = { "Predicate failed on state $it" },
predicate: (S) -> Boolean predicate: (S) -> Boolean
) { ) {
lock.readLock().withLock { requireState(errorMessage, predicate) {}
require(predicate(state)) { errorMessage(state) }
}
} }
/** Transition the state from [from] to [to]. */ /** Transition the state from [from] to [to]. */

View File

@ -327,6 +327,7 @@ abstract class Verifier(val ltx: LedgerTransaction, protected val transactionCla
* *
* @throws TransactionVerificationException if the constraints fail to verify * @throws TransactionVerificationException if the constraints fail to verify
*/ */
@Suppress("NestedBlockDepth", "MagicNumber")
private fun verifyConstraints(contractAttachmentsByContract: Map<ContractClassName, ContractAttachment>) { private fun verifyConstraints(contractAttachmentsByContract: Map<ContractClassName, ContractAttachment>) {
// For each contract/constraint pair check that the relevant attachment is valid. // For each contract/constraint pair check that the relevant attachment is valid.
allStates.map { it.contract to it.constraint }.toSet().forEach { (contract, constraint) -> allStates.map { it.contract to it.constraint }.toSet().forEach { (contract, constraint) ->

View File

@ -35,7 +35,8 @@ data class CordappImpl(
val notaryService: Class<out NotaryService>? = null, val notaryService: Class<out NotaryService>? = null,
/** Indicates whether the CorDapp is loaded from external sources, or generated on node startup (virtual). */ /** Indicates whether the CorDapp is loaded from external sources, or generated on node startup (virtual). */
val isLoaded: Boolean = true, val isLoaded: Boolean = true,
private val explicitCordappClasses: List<String> = emptyList() private val explicitCordappClasses: List<String> = emptyList(),
val isVirtual: Boolean = false
) : Cordapp { ) : Cordapp {
override val name: String = jarName(jarPath) override val name: String = jarName(jarPath)

View File

@ -88,20 +88,41 @@ object CordappResolver {
*/ */
val currentTargetVersion: Int get() = currentCordapp?.targetPlatformVersion ?: 1 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. * Temporarily apply a fake CorDapp with the given parameters. For use in testing.
*/ */
@Synchronized @Synchronized
@VisibleForTesting @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 val currentResolver = cordappResolver
cordappResolver = { cordappResolver = {
CordappImpl.TEST_INSTANCE.copy(minimumPlatformVersion = minimumPlatformVersion, targetPlatformVersion = targetPlatformVersion) CordappImpl.TEST_INSTANCE.copy(minimumPlatformVersion = minimumPlatformVersion, targetPlatformVersion = targetPlatformVersion)
} }
extraCordappsForTesting = listOf(cordappResolver()!!) + extraApps
try { try {
return block() return block()
} finally { } finally {
cordappResolver = currentResolver cordappResolver = currentResolver
extraCordappsForTesting = listOf()
} }
} }

View File

@ -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()
}

View File

@ -5,7 +5,10 @@ import net.corda.core.DoNotImplement
import net.corda.core.contracts.* import net.corda.core.contracts.*
import net.corda.core.cordapp.CordappContext import net.corda.core.cordapp.CordappContext
import net.corda.core.cordapp.CordappProvider 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.flows.ContractUpgradeFlow
import net.corda.core.node.services.* import net.corda.core.node.services.*
import net.corda.core.serialization.SerializeAsToken import net.corda.core.serialization.SerializeAsToken

View File

@ -7,7 +7,6 @@ import net.corda.core.crypto.DigitalSignature
import net.corda.core.crypto.SignableData import net.corda.core.crypto.SignableData
import net.corda.core.crypto.TransactionSignature import net.corda.core.crypto.TransactionSignature
import net.corda.core.identity.PartyAndCertificate import net.corda.core.identity.PartyAndCertificate
import net.corda.core.node.ServiceHub
import java.security.KeyPair import java.security.KeyPair
import java.security.PrivateKey import java.security.PrivateKey
import java.security.PublicKey import java.security.PublicKey

View File

@ -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.ColumnPredicate.*
import net.corda.core.node.services.vault.EqualityComparisonOperator.* import net.corda.core.node.services.vault.EqualityComparisonOperator.*
import net.corda.core.node.services.vault.LikenessOperator.* import net.corda.core.node.services.vault.LikenessOperator.*
import net.corda.core.schemas.PersistentState
import net.corda.core.schemas.StatePersistable import net.corda.core.schemas.StatePersistable
import net.corda.core.serialization.CordaSerializable import net.corda.core.serialization.CordaSerializable
import java.lang.reflect.Field import java.lang.reflect.Field

View File

@ -22,7 +22,8 @@ import net.corda.core.utilities.contextLogger
import java.security.PublicKey import java.security.PublicKey
import java.time.Duration import java.time.Duration
import java.time.Instant import java.time.Instant
import java.util.* import java.util.ArrayDeque
import java.util.UUID
import java.util.regex.Pattern import java.util.regex.Pattern
import kotlin.collections.ArrayList import kotlin.collections.ArrayList
import kotlin.collections.component1 import kotlin.collections.component1

View File

@ -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) 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. */ /** When called from a companion object, returns the logger for the enclosing class. */
fun Any.contextLogger(): Logger = LoggerFactory.getLogger(javaClass.enclosingClass) fun Any.contextLogger(): Logger = LoggerFactory.getLogger(javaClass.enclosingClass)

View File

@ -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)")
}
}

View 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"))
}
}

View File

@ -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)
}
}
}
}

View File

@ -28,7 +28,7 @@ class CordappResolverTest {
assertEquals(defaultTargetVersion, CordappResolver.currentTargetVersion) assertEquals(defaultTargetVersion, CordappResolver.currentTargetVersion)
val expectedTargetVersion = 555 val expectedTargetVersion = 555
CordappResolver.withCordapp(targetPlatformVersion = expectedTargetVersion) { CordappResolver.withTestCordapp(targetPlatformVersion = expectedTargetVersion) {
val actualTargetVersion = CordappResolver.currentTargetVersion val actualTargetVersion = CordappResolver.currentTargetVersion
assertEquals(expectedTargetVersion, actualTargetVersion) assertEquals(expectedTargetVersion, actualTargetVersion)
} }

View File

@ -4,8 +4,8 @@ import net.corda.core.contracts.StateRef
import net.corda.core.crypto.SecureHash import net.corda.core.crypto.SecureHash
import net.corda.core.internal.declaredField import net.corda.core.internal.declaredField
import org.assertj.core.api.Assertions.catchThrowable import org.assertj.core.api.Assertions.catchThrowable
import org.junit.Assert
import org.junit.Assert.assertSame import org.junit.Assert.assertSame
import org.junit.Assert.assertTrue
import org.junit.Test import org.junit.Test
import java.nio.ByteBuffer import java.nio.ByteBuffer
import java.nio.ReadOnlyBufferException import java.nio.ReadOnlyBufferException
@ -52,10 +52,10 @@ class ByteArraysTest {
val privacySalt = net.corda.core.contracts.PrivacySalt() val privacySalt = net.corda.core.contracts.PrivacySalt()
val privacySaltAsHexString = privacySalt.bytes.toHexString() val privacySaltAsHexString = privacySalt.bytes.toHexString()
Assert.assertTrue(privacySaltAsHexString.matches(HEX_REGEX)) assertTrue(privacySaltAsHexString.matches(HEX_REGEX))
val stateRef = StateRef(SecureHash.randomSHA256(), 0) val stateRef = StateRef(SecureHash.randomSHA256(), 0)
val txhashAsHexString = stateRef.txhash.bytes.toHexString() val txhashAsHexString = stateRef.txhash.bytes.toHexString()
Assert.assertTrue(txhashAsHexString.matches(HEX_REGEX)) assertTrue(txhashAsHexString.matches(HEX_REGEX))
} }
} }

View File

@ -2,7 +2,6 @@ package net.corda.nodeapi.internal.crypto
import net.corda.core.crypto.internal.AliasPrivateKey import net.corda.core.crypto.internal.AliasPrivateKey
import net.corda.testing.internal.stubs.CertificateStoreStubs import net.corda.testing.internal.stubs.CertificateStoreStubs
import org.assertj.core.api.Assertions.assertThatIllegalArgumentException
import org.junit.Rule import org.junit.Rule
import org.junit.Test import org.junit.Test
import org.junit.rules.TemporaryFolder import org.junit.rules.TemporaryFolder
@ -20,15 +19,18 @@ class AliasPrivateKeyTest {
val alias = "01234567890" val alias = "01234567890"
val aliasPrivateKey = AliasPrivateKey(alias) val aliasPrivateKey = AliasPrivateKey(alias)
val certificatesDirectory = tempFolder.root.toPath() val certificatesDirectory = tempFolder.root.toPath()
val signingCertStore = CertificateStoreStubs.Signing.withCertificatesDirectory(certificatesDirectory, "keystorepass").get(createNew = true) val signingCertStore = CertificateStoreStubs.Signing.withCertificatesDirectory(
signingCertStore.query { setPrivateKey(alias, aliasPrivateKey, listOf(NOT_YET_REGISTERED_MARKER_KEYS_AND_CERTS.ECDSAR1_CERT), "entrypassword") } 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. // We can retrieve the certificate.
assertTrue { signingCertStore.contains(alias) } assertTrue { signingCertStore.contains(alias) }
// We can retrieve the certificate. // We can retrieve the certificate.
assertEquals(NOT_YET_REGISTERED_MARKER_KEYS_AND_CERTS.ECDSAR1_CERT, signingCertStore[alias]) 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. // Although we can store an AliasPrivateKey, we cannot retrieve it. But, it's fine as we use certStore for storing/handling certs
assertThatIllegalArgumentException().isThrownBy { // only.
signingCertStore.query { getPrivateKey(alias, "entrypassword") } assertEquals(aliasPrivateKey, signingCertStore.query { getPrivateKey(alias, "entrypassword") })
}.withMessage("Unrecognised algorithm: 1.3.6.1.4.1.50530.1.2")
} }
} }

View File

@ -45,7 +45,8 @@ class TransientReference<out A>(@Transient val value: A)
class FlowStateMachineImpl<R>(override val id: StateMachineRunId, class FlowStateMachineImpl<R>(override val id: StateMachineRunId,
override val logic: FlowLogic<R>, override val logic: FlowLogic<R>,
scheduler: FiberScheduler scheduler: FiberScheduler,
override val creationTime: Long = System.currentTimeMillis()
) : Fiber<Unit>(id.toString(), scheduler), FlowStateMachine<R>, FlowFiber { ) : Fiber<Unit>(id.toString(), scheduler), FlowStateMachine<R>, FlowFiber {
companion object { companion object {
/** /**

View File

@ -82,7 +82,7 @@ class FinalityHandlerTest {
} }
private fun TestStartedNode.finaliseWithOldApi(stx: SignedTransaction): CordaFuture<SignedTransaction> { private fun TestStartedNode.finaliseWithOldApi(stx: SignedTransaction): CordaFuture<SignedTransaction> {
return CordappResolver.withCordapp(targetPlatformVersion = 3) { return CordappResolver.withTestCordapp(targetPlatformVersion = 3) {
@Suppress("DEPRECATION") @Suppress("DEPRECATION")
services.startFlow(FinalityFlow(stx)).resultFuture.apply { services.startFlow(FinalityFlow(stx)).resultFuture.apply {
mockNet.runNetwork() mockNet.runNetwork()

View File

@ -897,7 +897,7 @@ class NodeVaultServiceTest {
fun List<StateAndRef<DummyState>>.getNumbers() = map { it.state.data.magicNumber }.toSet() 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(1, megaCorp.party)))
services.recordTransactions(StatesToRecord.ONLY_RELEVANT, listOf(createTx(2, miniCorp.party))) services.recordTransactions(StatesToRecord.ONLY_RELEVANT, listOf(createTx(2, miniCorp.party)))
services.recordTransactions(StatesToRecord.ONLY_RELEVANT, listOf(createTx(3, miniCorp.party, megaCorp.party))) services.recordTransactions(StatesToRecord.ONLY_RELEVANT, listOf(createTx(3, miniCorp.party, megaCorp.party)))

View File

@ -4,7 +4,6 @@ import com.google.common.reflect.TypeToken
import net.corda.core.KeepForDJVM import net.corda.core.KeepForDJVM
import net.corda.core.internal.isPublic import net.corda.core.internal.isPublic
import net.corda.core.serialization.SerializableCalculatedProperty import net.corda.core.serialization.SerializableCalculatedProperty
import net.corda.core.utilities.contextLogger
import net.corda.serialization.internal.amqp.MethodClassifier.* import net.corda.serialization.internal.amqp.MethodClassifier.*
import java.lang.reflect.Field import java.lang.reflect.Field
import java.lang.reflect.Method import java.lang.reflect.Method