From 53a0aae48989288903c52e3c849567aa2b9ce5d6 Mon Sep 17 00:00:00 2001 From: Shams Asari Date: Thu, 5 Apr 2018 14:27:42 +0100 Subject: [PATCH 1/3] Introduced a few helper methods around InputStream.readBytes (#2928) --- .../corda/core/flows/SendTransactionFlow.kt | 3 +- .../corda/core/internal/AbstractAttachment.kt | 2 +- .../net/corda/core/internal/InternalUtils.kt | 29 +++++++++++++++++-- .../net/corda/core/flows/AttachmentTests.kt | 3 +- .../internal/network/NetworkBootstrapper.kt | 29 +++++++------------ .../custom/ContractAttachmentSerializer.kt | 3 +- .../kryo/DefaultKryoCustomizer.kt | 3 +- .../registration/NodeRegistrationTest.kt | 3 +- .../persistence/NodeAttachmentService.kt | 22 +++++++------- .../persistence/NodeAttachmentStorageTest.kt | 7 ++--- .../node/internal/network/NetworkMapServer.kt | 8 ++--- .../testing/services/MockAttachmentStorage.kt | 6 ++-- 12 files changed, 67 insertions(+), 51 deletions(-) diff --git a/core/src/main/kotlin/net/corda/core/flows/SendTransactionFlow.kt b/core/src/main/kotlin/net/corda/core/flows/SendTransactionFlow.kt index 16f402c486..46271ab3c3 100644 --- a/core/src/main/kotlin/net/corda/core/flows/SendTransactionFlow.kt +++ b/core/src/main/kotlin/net/corda/core/flows/SendTransactionFlow.kt @@ -3,6 +3,7 @@ package net.corda.core.flows import co.paralleluniverse.fibers.Suspendable import net.corda.core.contracts.StateAndRef import net.corda.core.internal.FetchDataFlow +import net.corda.core.internal.readFully import net.corda.core.transactions.SignedTransaction import net.corda.core.utilities.unwrap @@ -60,7 +61,7 @@ open class DataVendingFlow(val otherSideSession: FlowSession, val payload: Any) serviceHub.validatedTransactions.getTransaction(it) ?: throw FetchDataFlow.HashNotFound(it) } FetchDataFlow.DataType.ATTACHMENT -> dataRequest.hashes.map { - serviceHub.attachments.openAttachment(it)?.open()?.readBytes() ?: throw FetchDataFlow.HashNotFound(it) + serviceHub.attachments.openAttachment(it)?.open()?.readFully() ?: throw FetchDataFlow.HashNotFound(it) } } } diff --git a/core/src/main/kotlin/net/corda/core/internal/AbstractAttachment.kt b/core/src/main/kotlin/net/corda/core/internal/AbstractAttachment.kt index 6281f79795..1e05c8c4c2 100644 --- a/core/src/main/kotlin/net/corda/core/internal/AbstractAttachment.kt +++ b/core/src/main/kotlin/net/corda/core/internal/AbstractAttachment.kt @@ -28,7 +28,7 @@ abstract class AbstractAttachment(dataLoader: () -> ByteArray) : Attachment { fun SerializeAsTokenContext.attachmentDataLoader(id: SecureHash): () -> ByteArray { return { val a = serviceHub.attachments.openAttachment(id) ?: throw MissingAttachmentsException(listOf(id)) - (a as? AbstractAttachment)?.attachmentData ?: a.open().use { it.readBytes() } + (a as? AbstractAttachment)?.attachmentData ?: a.open().readFully() } } diff --git a/core/src/main/kotlin/net/corda/core/internal/InternalUtils.kt b/core/src/main/kotlin/net/corda/core/internal/InternalUtils.kt index 97ef208514..7f53da869f 100644 --- a/core/src/main/kotlin/net/corda/core/internal/InternalUtils.kt +++ b/core/src/main/kotlin/net/corda/core/internal/InternalUtils.kt @@ -2,6 +2,8 @@ package net.corda.core.internal +import com.google.common.hash.Hashing +import com.google.common.hash.HashingInputStream import net.corda.core.cordapp.Cordapp import net.corda.core.cordapp.CordappConfig import net.corda.core.cordapp.CordappContext @@ -150,8 +152,31 @@ fun Path.writeLines(lines: Iterable, charset: Charset = UTF_8, var inline fun Path.readObject(): T = readAll().deserialize() +/** Calculate the hash of the contents of this file. */ +val Path.hash: SecureHash get() = read { it.hash() } + fun InputStream.copyTo(target: Path, vararg options: CopyOption): Long = Files.copy(this, target, *options) +/** Same as [InputStream.readBytes] but also closes the stream. */ +fun InputStream.readFully(): ByteArray = use { it.readBytes() } + +/** Calculate the hash of the remaining bytes in this input stream. The stream is closed at the end. */ +fun InputStream.hash(): SecureHash { + return use { + val his = HashingInputStream(Hashing.sha256(), it) + his.copyTo(NullOutputStream) // To avoid reading in the entire stream into memory just write out the bytes to /dev/null + SecureHash.SHA256(his.hash().asBytes()) + } +} + +inline fun InputStream.readObject(): T = readFully().deserialize() + +object NullOutputStream : OutputStream() { + override fun write(b: Int) = Unit + override fun write(b: ByteArray) = Unit + override fun write(b: ByteArray, off: Int, len: Int) = Unit +} + fun String.abbreviate(maxWidth: Int): String = if (length <= maxWidth) this else take(maxWidth - 1) + "…" /** Return the sum of an Iterable of [BigDecimal]s. */ @@ -333,7 +358,7 @@ fun URL.post(serializedData: OpaqueBytes): ByteArray { setRequestProperty("Content-Type", "application/octet-stream") outputStream.use { serializedData.open().copyTo(it) } checkOkResponse() - inputStream.use { it.readBytes() } + inputStream.readFully() } } @@ -346,7 +371,7 @@ fun HttpURLConnection.checkOkResponse() { inline fun HttpURLConnection.responseAs(): T { checkOkResponse() - return inputStream.use { it.readBytes() }.deserialize() + return inputStream.readObject() } /** Analogous to [Thread.join]. */ diff --git a/core/src/test/kotlin/net/corda/core/flows/AttachmentTests.kt b/core/src/test/kotlin/net/corda/core/flows/AttachmentTests.kt index d7bf7ce049..5047a18655 100644 --- a/core/src/test/kotlin/net/corda/core/flows/AttachmentTests.kt +++ b/core/src/test/kotlin/net/corda/core/flows/AttachmentTests.kt @@ -7,6 +7,7 @@ import net.corda.core.crypto.sha256 import net.corda.core.identity.Party import net.corda.core.internal.FetchAttachmentsFlow import net.corda.core.internal.FetchDataFlow +import net.corda.core.internal.hash import net.corda.core.utilities.getOrThrow import net.corda.node.internal.StartedNode import net.corda.node.services.persistence.NodeAttachmentService @@ -72,7 +73,7 @@ class AttachmentTests { bobNode.attachments.openAttachment(id)!! } - assertEquals(id, attachment.open().readBytes().sha256()) + assertEquals(id, attachment.open().hash()) // Shut down node zero and ensure node one can still resolve the attachment. aliceNode.dispose() diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/internal/network/NetworkBootstrapper.kt b/node-api/src/main/kotlin/net/corda/nodeapi/internal/network/NetworkBootstrapper.kt index b554ed9c50..671a3a086d 100644 --- a/node-api/src/main/kotlin/net/corda/nodeapi/internal/network/NetworkBootstrapper.kt +++ b/node-api/src/main/kotlin/net/corda/nodeapi/internal/network/NetworkBootstrapper.kt @@ -1,11 +1,7 @@ package net.corda.nodeapi.internal.network -import com.google.common.hash.Hashing -import com.google.common.hash.HashingInputStream import com.typesafe.config.ConfigFactory import net.corda.cordform.CordformNode -import net.corda.core.contracts.ContractClassName -import net.corda.core.crypto.SecureHash import net.corda.core.crypto.SecureHash.Companion.parse import net.corda.core.identity.Party import net.corda.core.internal.* @@ -27,7 +23,6 @@ import net.corda.nodeapi.internal.serialization.SerializationFactoryImpl import net.corda.nodeapi.internal.serialization.amqp.AMQPServerSerializationScheme import net.corda.nodeapi.internal.serialization.kryo.AbstractKryoSerializationScheme import net.corda.nodeapi.internal.serialization.kryo.kryoMagic -import java.io.File import java.io.PrintStream import java.nio.file.Files import java.nio.file.Path @@ -191,7 +186,7 @@ class NetworkBootstrapper { private fun generateWhitelist(whitelistFile: Path, excludeWhitelistFile: Path, cordapps: List?): Map> { val existingWhitelist = if (whitelistFile.exists()) readContractWhitelist(whitelistFile) else emptyMap() - println(if (existingWhitelist.isEmpty()) "No existing whitelist file found." else "Found existing whitelist: ${whitelistFile}") + println(if (existingWhitelist.isEmpty()) "No existing whitelist file found." else "Found existing whitelist: $whitelistFile") val excludeContracts = if (excludeWhitelistFile.exists()) readExcludeWhitelist(excludeWhitelistFile) else emptyList() if (excludeContracts.isNotEmpty()) { @@ -199,7 +194,7 @@ class NetworkBootstrapper { } val newWhiteList = cordapps?.flatMap { cordappJarPath -> - val jarHash = getJarHash(cordappJarPath) + val jarHash = Paths.get(cordappJarPath).hash scanJarForContracts(cordappJarPath).map { contract -> contract to jarHash } @@ -213,30 +208,26 @@ class NetworkBootstrapper { contractClassName to (if (newHash == null || newHash in existing) existing else existing + newHash) }.toMap() - println("CorDapp whitelist " + (if (existingWhitelist.isEmpty()) "generated" else "updated") + " in ${whitelistFile}") + println("CorDapp whitelist " + (if (existingWhitelist.isEmpty()) "generated" else "updated") + " in $whitelistFile") return merged } private fun overwriteWhitelist(whitelistFile: Path, mergedWhiteList: Map>) { PrintStream(whitelistFile.toFile().outputStream()).use { out -> mergedWhiteList.forEach { (contract, attachments) -> - out.println("${contract}:${attachments.joinToString(",")}") + out.println("$contract:${attachments.joinToString(",")}") } } } - private fun getJarHash(cordappPath: String): AttachmentId = File(cordappPath).inputStream().use { jar -> - val hs = HashingInputStream(Hashing.sha256(), jar) - hs.readBytes() - SecureHash.SHA256(hs.hash().asBytes()) + private fun readContractWhitelist(file: Path): Map> { + return file.readAllLines() + .map { line -> line.split(":") } + .map { (contract, attachmentIds) -> + contract to (attachmentIds.split(",").map(::parse)) + }.toMap() } - private fun readContractWhitelist(file: Path): Map> = file.readAllLines() - .map { line -> line.split(":") } - .map { (contract, attachmentIds) -> - contract to (attachmentIds.split(",").map(::parse)) - }.toMap() - private fun readExcludeWhitelist(file: Path): List = file.readAllLines().map(String::trim) private fun NotaryInfo.prettyPrint(): String = "${identity.name} (${if (validating) "" else "non-"}validating)" diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/custom/ContractAttachmentSerializer.kt b/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/custom/ContractAttachmentSerializer.kt index 917057f428..2faa5b4abf 100644 --- a/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/custom/ContractAttachmentSerializer.kt +++ b/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/custom/ContractAttachmentSerializer.kt @@ -3,6 +3,7 @@ package net.corda.nodeapi.internal.serialization.amqp.custom import net.corda.core.contracts.Attachment import net.corda.core.contracts.ContractAttachment import net.corda.core.contracts.ContractClassName +import net.corda.core.internal.readFully import net.corda.core.serialization.MissingAttachmentsException import net.corda.nodeapi.internal.serialization.GeneratedAttachment import net.corda.nodeapi.internal.serialization.amqp.CustomSerializer @@ -17,7 +18,7 @@ class ContractAttachmentSerializer(factory: SerializerFactory) : CustomSerialize ContractAttachmentProxy::class.java, factory) { override fun toProxy(obj: ContractAttachment): ContractAttachmentProxy { val bytes = try { - obj.attachment.open().readBytes() + obj.attachment.open().readFully() } catch (e: Exception) { throw MissingAttachmentsException(listOf(obj.id)) } diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/kryo/DefaultKryoCustomizer.kt b/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/kryo/DefaultKryoCustomizer.kt index 9bb6b81142..d41e526855 100644 --- a/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/kryo/DefaultKryoCustomizer.kt +++ b/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/kryo/DefaultKryoCustomizer.kt @@ -18,6 +18,7 @@ import net.corda.core.crypto.CompositeKey import net.corda.core.crypto.SecureHash import net.corda.core.identity.PartyAndCertificate import net.corda.core.internal.AbstractAttachment +import net.corda.core.internal.readFully import net.corda.core.serialization.MissingAttachmentsException import net.corda.core.serialization.SerializationWhitelist import net.corda.core.serialization.SerializeAsToken @@ -223,7 +224,7 @@ object DefaultKryoCustomizer { val lazyAttachment = object : AbstractAttachment({ val attachment = attachmentStorage.openAttachment(attachmentHash) ?: throw MissingAttachmentsException(listOf(attachmentHash)) - attachment.open().readBytes() + attachment.open().readFully() }) { override val id = attachmentHash } diff --git a/node/src/integration-test/kotlin/net/corda/node/utilities/registration/NodeRegistrationTest.kt b/node/src/integration-test/kotlin/net/corda/node/utilities/registration/NodeRegistrationTest.kt index 21592b7870..eb691ea415 100644 --- a/node/src/integration-test/kotlin/net/corda/node/utilities/registration/NodeRegistrationTest.kt +++ b/node/src/integration-test/kotlin/net/corda/node/utilities/registration/NodeRegistrationTest.kt @@ -3,6 +3,7 @@ package net.corda.node.utilities.registration import net.corda.core.identity.CordaX500Name import net.corda.core.internal.concurrent.transpose import net.corda.core.internal.logElapsedTime +import net.corda.core.internal.readFully import net.corda.core.messaging.startFlow import net.corda.core.utilities.* import net.corda.finance.DOLLARS @@ -130,7 +131,7 @@ class RegistrationHandler(private val rootCertAndKeyPair: CertificateAndKeyPair) @Produces(MediaType.TEXT_PLAIN) fun registration(input: InputStream): Response { return log.logElapsedTime("Registration") { - val certificationRequest = input.use { JcaPKCS10CertificationRequest(it.readBytes()) } + val certificationRequest = JcaPKCS10CertificationRequest(input.readFully()) val (certPath, name) = createSignedClientCertificate( certificationRequest, rootCertAndKeyPair.keyPair, diff --git a/node/src/main/kotlin/net/corda/node/services/persistence/NodeAttachmentService.kt b/node/src/main/kotlin/net/corda/node/services/persistence/NodeAttachmentService.kt index e4ea68a1e6..6ae49ca276 100644 --- a/node/src/main/kotlin/net/corda/node/services/persistence/NodeAttachmentService.kt +++ b/node/src/main/kotlin/net/corda/node/services/persistence/NodeAttachmentService.kt @@ -11,9 +11,11 @@ import net.corda.core.contracts.Attachment import net.corda.core.contracts.ContractAttachment import net.corda.core.contracts.ContractClassName import net.corda.core.crypto.SecureHash +import net.corda.core.crypto.sha256 import net.corda.core.internal.AbstractAttachment import net.corda.core.internal.UNKNOWN_UPLOADER import net.corda.core.internal.VisibleForTesting +import net.corda.core.internal.readFully import net.corda.core.node.services.AttachmentId import net.corda.core.node.services.AttachmentStorage import net.corda.core.node.services.vault.AttachmentQueryCriteria @@ -27,7 +29,10 @@ import net.corda.node.utilities.NonInvalidatingWeightBasedCache import net.corda.nodeapi.internal.persistence.NODE_DATABASE_PREFIX import net.corda.nodeapi.internal.persistence.currentDBSession import net.corda.nodeapi.internal.withContractsInJar -import java.io.* +import java.io.FilterInputStream +import java.io.IOException +import java.io.InputStream +import java.io.Serializable import java.nio.file.Paths import java.time.Instant import java.util.* @@ -262,14 +267,6 @@ class NodeAttachmentService( return import(jar, uploader, filename) } - fun getAttachmentIdAndBytes(jar: InputStream): Pair { - val hs = HashingInputStream(Hashing.sha256(), jar) - val bytes = hs.readBytes() - checkIsAValidJAR(ByteArrayInputStream(bytes)) - val id = SecureHash.SHA256(hs.hash().asBytes()) - return Pair(id, bytes) - } - override fun hasAttachment(attachmentId: AttachmentId): Boolean = currentDBSession().find(NodeAttachmentService.DBAttachment::class.java, attachmentId.toString()) != null @@ -278,15 +275,16 @@ class NodeAttachmentService( return withContractsInJar(jar) { contractClassNames, inputStream -> require(inputStream !is JarInputStream) - // Read the file into RAM, hashing it to find the ID as we go. The attachment must fit into memory. + // Read the file into RAM and then calculate its hash. The attachment must fit into memory. // TODO: Switch to a two-phase insert so we can handle attachments larger than RAM. // To do this we must pipe stream into the database without knowing its hash, which we will learn only once // the insert/upload is complete. We can then query to see if it's a duplicate and if so, erase, and if not // set the hash field of the new attachment record. - val (id, bytes) = getAttachmentIdAndBytes(inputStream) + val bytes = inputStream.readFully() + val id = bytes.sha256() if (!hasAttachment(id)) { - checkIsAValidJAR(ByteArrayInputStream(bytes)) + checkIsAValidJAR(bytes.inputStream()) val session = currentDBSession() val attachment = NodeAttachmentService.DBAttachment(attId = id.toString(), content = bytes, uploader = uploader, filename = filename, contractClassNames = contractClassNames) session.save(attachment) diff --git a/node/src/test/kotlin/net/corda/node/services/persistence/NodeAttachmentStorageTest.kt b/node/src/test/kotlin/net/corda/node/services/persistence/NodeAttachmentStorageTest.kt index 861a324e78..a15e18ff27 100644 --- a/node/src/test/kotlin/net/corda/node/services/persistence/NodeAttachmentStorageTest.kt +++ b/node/src/test/kotlin/net/corda/node/services/persistence/NodeAttachmentStorageTest.kt @@ -5,10 +5,7 @@ import com.google.common.jimfs.Configuration import com.google.common.jimfs.Jimfs import net.corda.core.crypto.SecureHash import net.corda.core.crypto.sha256 -import net.corda.core.internal.read -import net.corda.core.internal.readAll -import net.corda.core.internal.write -import net.corda.core.internal.writeLines +import net.corda.core.internal.* import net.corda.core.node.services.vault.AttachmentQueryCriteria import net.corda.core.node.services.vault.AttachmentSort import net.corda.core.node.services.vault.Builder @@ -230,7 +227,7 @@ class NodeAttachmentStorageTest { database.transaction { val storage = NodeAttachmentService(MetricRegistry()) val e = assertFailsWith { - storage.openAttachment(id)!!.open().use { it.readBytes() } + storage.openAttachment(id)!!.open().readFully() } assertEquals(e.expected, id) diff --git a/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/network/NetworkMapServer.kt b/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/network/NetworkMapServer.kt index ba8522d9c3..b9f620c9fb 100644 --- a/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/network/NetworkMapServer.kt +++ b/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/network/NetworkMapServer.kt @@ -2,14 +2,14 @@ package net.corda.testing.node.internal.network import net.corda.core.crypto.SecureHash import net.corda.core.crypto.SignedData +import net.corda.core.internal.readObject +import net.corda.core.node.NetworkParameters import net.corda.core.node.NodeInfo -import net.corda.core.serialization.deserialize import net.corda.core.serialization.serialize import net.corda.core.utilities.NetworkHostAndPort import net.corda.nodeapi.internal.SignedNodeInfo import net.corda.nodeapi.internal.createDevNetworkMapCa import net.corda.nodeapi.internal.crypto.CertificateAndKeyPair -import net.corda.core.node.NetworkParameters import net.corda.nodeapi.internal.network.NetworkMap import net.corda.nodeapi.internal.network.ParametersUpdate import org.eclipse.jetty.server.Server @@ -110,7 +110,7 @@ class NetworkMapServer(private val pollInterval: Duration, @Consumes(MediaType.APPLICATION_OCTET_STREAM) fun publishNodeInfo(input: InputStream): Response { return try { - val signedNodeInfo = input.readBytes().deserialize() + val signedNodeInfo = input.readObject() signedNodeInfo.verified() nodeInfoMap[signedNodeInfo.raw.hash] = signedNodeInfo ok() @@ -126,7 +126,7 @@ class NetworkMapServer(private val pollInterval: Duration, @Path("ack-parameters") @Consumes(MediaType.APPLICATION_OCTET_STREAM) fun ackNetworkParameters(input: InputStream): Response { - val signedParametersHash = input.readBytes().deserialize>() + val signedParametersHash = input.readObject>() val hash = signedParametersHash.verified() latestAcceptedParametersMap[signedParametersHash.sig.by] = hash return ok().build() diff --git a/testing/test-utils/src/main/kotlin/net/corda/testing/services/MockAttachmentStorage.kt b/testing/test-utils/src/main/kotlin/net/corda/testing/services/MockAttachmentStorage.kt index d51b7a543c..e4fb2f5716 100644 --- a/testing/test-utils/src/main/kotlin/net/corda/testing/services/MockAttachmentStorage.kt +++ b/testing/test-utils/src/main/kotlin/net/corda/testing/services/MockAttachmentStorage.kt @@ -7,13 +7,13 @@ import net.corda.core.crypto.SecureHash import net.corda.core.crypto.sha256 import net.corda.core.internal.AbstractAttachment import net.corda.core.internal.UNKNOWN_UPLOADER +import net.corda.core.internal.readFully import net.corda.core.node.services.AttachmentId import net.corda.core.node.services.AttachmentStorage import net.corda.core.node.services.vault.AttachmentQueryCriteria import net.corda.core.node.services.vault.AttachmentSort import net.corda.core.serialization.SingletonSerializeAsToken import net.corda.nodeapi.internal.withContractsInJar -import java.io.ByteArrayOutputStream import java.io.InputStream import java.util.* import java.util.jar.JarInputStream @@ -53,7 +53,7 @@ class MockAttachmentStorage : AttachmentStorage, SingletonSerializeAsToken() { fun importContractAttachment(contractClassNames: List, uploader: String, jar: InputStream): AttachmentId = importAttachmentInternal(jar, uploader, null, contractClassNames) - fun getAttachmentIdAndBytes(jar: InputStream): Pair = jar.readBytes().let { bytes -> Pair(bytes.sha256(), bytes) } + fun getAttachmentIdAndBytes(jar: InputStream): Pair = jar.readFully().let { bytes -> Pair(bytes.sha256(), bytes) } private class MockAttachment(dataLoader: () -> ByteArray, override val id: SecureHash) : AbstractAttachment(dataLoader) @@ -61,7 +61,7 @@ class MockAttachmentStorage : AttachmentStorage, SingletonSerializeAsToken() { // JIS makes read()/readBytes() return bytes of the current file, but we want to hash the entire container here. require(jar !is JarInputStream) - val bytes = jar.readBytes() + val bytes = jar.readFully() val sha256 = bytes.sha256() if (sha256 !in files.keys) { From c8b58a601ff7c2263e6217c5b9a1ffd90c07914c Mon Sep 17 00:00:00 2001 From: Michal Kit Date: Thu, 5 Apr 2018 16:39:41 +0100 Subject: [PATCH 2/3] Adding CRL support in the generated certificates. (#2932) --- .../nodeapi/internal/crypto/X509Utilities.kt | 67 ++++++++++++++++--- .../internal/crypto/X509UtilitiesTest.kt | 26 ++++++- .../net/corda/node/services/keys/KMSUtils.kt | 1 + 3 files changed, 83 insertions(+), 11 deletions(-) diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/internal/crypto/X509Utilities.kt b/node-api/src/main/kotlin/net/corda/nodeapi/internal/crypto/X509Utilities.kt index 6866074d47..245263768f 100644 --- a/node-api/src/main/kotlin/net/corda/nodeapi/internal/crypto/X509Utilities.kt +++ b/node-api/src/main/kotlin/net/corda/nodeapi/internal/crypto/X509Utilities.kt @@ -8,12 +8,14 @@ import net.corda.core.internal.* import net.corda.core.utilities.days import net.corda.core.utilities.millis import org.bouncycastle.asn1.* +import org.bouncycastle.asn1.x500.X500Name import org.bouncycastle.asn1.x500.style.BCStyle import org.bouncycastle.asn1.x509.* import org.bouncycastle.asn1.x509.Extension import org.bouncycastle.cert.X509CertificateHolder import org.bouncycastle.cert.X509v3CertificateBuilder import org.bouncycastle.cert.bc.BcX509ExtensionUtils +import org.bouncycastle.cert.jcajce.JcaX509ExtensionUtils import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder import org.bouncycastle.openssl.jcajce.JcaPEMWriter import org.bouncycastle.operator.ContentSigner @@ -149,18 +151,25 @@ $trustedRoot""", e, certPath, e.index) /** * Build a partial X.509 certificate ready for signing. * + * @param certificateType type of the certificate. * @param issuer name of the issuing entity. + * @param issuerPublicKey public key of the issuing entity. * @param subject name of the certificate subject. * @param subjectPublicKey public key of the certificate subject. * @param validityWindow the time period the certificate is valid for. * @param nameConstraints any name constraints to impose on certificates signed by the generated certificate. + * @param crlDistPoint CRL distribution point. + * @param crlIssuer X500Name of the CRL issuer. */ - fun createPartialCertificate(certificateType: CertificateType, + private fun createPartialCertificate(certificateType: CertificateType, issuer: X500Principal, + issuerPublicKey: PublicKey, subject: X500Principal, subjectPublicKey: PublicKey, validityWindow: Pair, - nameConstraints: NameConstraints? = null): X509v3CertificateBuilder { + nameConstraints: NameConstraints? = null, + crlDistPoint: String? = null, + crlIssuer: X500Name? = null): X509v3CertificateBuilder { val serial = BigInteger.valueOf(random63BitValue()) val keyPurposes = DERSequence(ASN1EncodableVector().apply { certificateType.purposes.forEach { add(it) } }) val subjectPublicKeyInfo = SubjectPublicKeyInfo.getInstance(ASN1Sequence.getInstance(subjectPublicKey.encoded)) @@ -171,10 +180,12 @@ $trustedRoot""", e, certPath, e.index) .addExtension(Extension.basicConstraints, true, BasicConstraints(certificateType.isCA)) .addExtension(Extension.keyUsage, false, certificateType.keyUsage) .addExtension(Extension.extendedKeyUsage, false, keyPurposes) + .addExtension(Extension.authorityKeyIdentifier, false, JcaX509ExtensionUtils().createAuthorityKeyIdentifier(issuerPublicKey)) if (role != null) { builder.addExtension(ASN1ObjectIdentifier(CordaOID.X509_EXTENSION_CORDA_ROLE), false, role) } + addCrlInfo(builder, crlDistPoint, crlIssuer) if (nameConstraints != null) { builder.addExtension(Extension.nameConstraints, true, nameConstraints) } @@ -185,11 +196,15 @@ $trustedRoot""", e, certPath, e.index) /** * Create a X509 v3 certificate using the given issuer certificate and key pair. * + * @param certificateType type of the certificate. * @param issuerCertificate The Public certificate of the root CA above this used to sign it. * @param issuerKeyPair The KeyPair of the root CA above this used to sign it. * @param subject subject of the generated certificate. * @param subjectPublicKey subject's public key. * @param validityWindow The certificate's validity window. Default to [DEFAULT_VALIDITY_WINDOW] if not provided. + * @param nameConstraints any name constraints to impose on certificates signed by the generated certificate. + * @param crlDistPoint CRL distribution point. + * @param crlIssuer X500Name of the CRL issuer. * @return A data class is returned containing the new intermediate CA Cert and its KeyPair for signing downstream certificates. * Note the generated certificate tree is capped at max depth of 1 below this to be in line with commercially available certificates. */ @@ -200,7 +215,9 @@ $trustedRoot""", e, certPath, e.index) subject: X500Principal, subjectPublicKey: PublicKey, validityWindow: Pair = DEFAULT_VALIDITY_WINDOW, - nameConstraints: NameConstraints? = null): X509Certificate { + nameConstraints: NameConstraints? = null, + crlDistPoint: String? = null, + crlIssuer: X500Name? = null): X509Certificate { val window = getCertificateValidityWindow(validityWindow.first, validityWindow.second, issuerCertificate) return createCertificate( certificateType, @@ -209,28 +226,36 @@ $trustedRoot""", e, certPath, e.index) subject, subjectPublicKey, window, - nameConstraints + nameConstraints, + crlDistPoint, + crlIssuer ) } /** * Build and sign an X.509 certificate with the given signer. * + * @param certificateType type of the certificate. * @param issuer name of the issuing entity. * @param issuerSigner content signer to sign the certificate with. * @param subject name of the certificate subject. * @param subjectPublicKey public key of the certificate subject. * @param validityWindow the time period the certificate is valid for. * @param nameConstraints any name constraints to impose on certificates signed by the generated certificate. + * @param crlDistPoint CRL distribution point. + * @param crlIssuer X500Name of the CRL issuer. */ fun createCertificate(certificateType: CertificateType, issuer: X500Principal, + issuerPublicKey: PublicKey, issuerSigner: ContentSigner, subject: X500Principal, subjectPublicKey: PublicKey, validityWindow: Pair, - nameConstraints: NameConstraints? = null): X509Certificate { - val builder = createPartialCertificate(certificateType, issuer, subject, subjectPublicKey, validityWindow, nameConstraints) + nameConstraints: NameConstraints? = null, + crlDistPoint: String? = null, + crlIssuer: X500Name? = null): X509Certificate { + val builder = createPartialCertificate(certificateType, issuer, issuerPublicKey, subject, subjectPublicKey, validityWindow, nameConstraints, crlDistPoint, crlIssuer) return builder.build(issuerSigner).run { require(isValidOn(Date())) toJca() @@ -240,6 +265,7 @@ $trustedRoot""", e, certPath, e.index) /** * Build and sign an X.509 certificate with CA cert private key. * + * @param certificateType type of the certificate. * @param issuer name of the issuing entity. * @param issuerKeyPair the public & private key to sign the certificate with. * @param subject name of the certificate subject. @@ -253,11 +279,21 @@ $trustedRoot""", e, certPath, e.index) subject: X500Principal, subjectPublicKey: PublicKey, validityWindow: Pair, - nameConstraints: NameConstraints? = null): X509Certificate { + nameConstraints: NameConstraints? = null, + crlDistPoint: String? = null, + crlIssuer: X500Name? = null): X509Certificate { val signatureScheme = Crypto.findSignatureScheme(issuerKeyPair.private) val provider = Crypto.findProvider(signatureScheme.providerName) val signer = ContentSignerBuilder.build(signatureScheme, issuerKeyPair.private, provider) - val builder = createPartialCertificate(certificateType, issuer, subject, subjectPublicKey, validityWindow, nameConstraints) + val builder = createPartialCertificate( + certificateType, + issuer, + issuerKeyPair.public, + subject, subjectPublicKey, + validityWindow, + nameConstraints, + crlDistPoint, + crlIssuer) return builder.build(signer).run { require(isValidOn(Date())) require(isSignatureValid(JcaContentVerifierProviderBuilder().build(issuerKeyPair.public))) @@ -302,6 +338,21 @@ $trustedRoot""", e, certPath, e.index) fun buildCertPath(certificates: List): CertPath { return X509CertificateFactory().generateCertPath(certificates) } + + private fun addCrlInfo(builder: X509v3CertificateBuilder, crlDistPoint: String?, crlIssuer: X500Name?) { + if (crlDistPoint != null) { + val distPointName = DistributionPointName(GeneralNames(GeneralName(GeneralName.uniformResourceIdentifier, crlDistPoint))) + val crlIssuerGeneralNames = crlIssuer?.let { + GeneralNames(GeneralName(crlIssuer)) + } + // The second argument is flag that allows you to define what reason of certificate revocation is served by this distribution point see [ReasonFlags]. + // The idea is that you have different revocation per revocation reason. Since we won't go into such a granularity, we can skip that parameter. + // The third argument allows you to specify the name of the CRL issuer, it needs to be consistent with the crl (IssuingDistributionPoint) extension and the idp argument. + // If idp == true, set it, if idp == false, leave it null as done here. + val distPoint = DistributionPoint(distPointName, null, crlIssuerGeneralNames) + builder.addExtension(Extension.cRLDistributionPoints, false, CRLDistPoint(arrayOf(distPoint))) + } + } } // Assuming cert type to role is 1:1 diff --git a/node-api/src/test/kotlin/net/corda/nodeapi/internal/crypto/X509UtilitiesTest.kt b/node-api/src/test/kotlin/net/corda/nodeapi/internal/crypto/X509UtilitiesTest.kt index 8e5aa1c776..1fbd9e1dad 100644 --- a/node-api/src/test/kotlin/net/corda/nodeapi/internal/crypto/X509UtilitiesTest.kt +++ b/node-api/src/test/kotlin/net/corda/nodeapi/internal/crypto/X509UtilitiesTest.kt @@ -20,9 +20,7 @@ import net.corda.testing.core.BOB_NAME import net.corda.testing.core.TestIdentity import net.corda.testing.internal.createDevIntermediateCaCertPath import org.assertj.core.api.Assertions.assertThat -import org.bouncycastle.asn1.x509.BasicConstraints -import org.bouncycastle.asn1.x509.Extension -import org.bouncycastle.asn1.x509.KeyUsage +import org.bouncycastle.asn1.x509.* import org.junit.Rule import org.junit.Test import org.junit.rules.TemporaryFolder @@ -103,6 +101,28 @@ class X509UtilitiesTest { } } + @Test + fun `create valid server certificate chain includes CRL info`() { + val caKey = generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME) + val caCert = X509Utilities.createSelfSignedCACertificate(X500Principal("CN=Test CA Cert,O=R3 Ltd,L=London,C=GB"), caKey) + val caSubjectKeyIdentifier = SubjectKeyIdentifier.getInstance(caCert.toBc().getExtension(Extension.subjectKeyIdentifier).parsedValue) + val keyPair = generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME) + val crlDistPoint = "http://test.com" + val serverCert = X509Utilities.createCertificate( + CertificateType.TLS, + caCert, + caKey, + X500Principal("CN=Server Cert,O=R3 Ltd,L=London,C=GB"), + keyPair.public, + crlDistPoint = crlDistPoint) + serverCert.toBc().run { + val certCrlDistPoint = CRLDistPoint.getInstance(getExtension(Extension.cRLDistributionPoints).parsedValue) + assertTrue(certCrlDistPoint.distributionPoints.first().distributionPoint.toString().contains(crlDistPoint)) + val certCaAuthorityKeyIdentifier = AuthorityKeyIdentifier.getInstance(getExtension(Extension.authorityKeyIdentifier).parsedValue) + assertTrue(Arrays.equals(caSubjectKeyIdentifier.keyIdentifier, certCaAuthorityKeyIdentifier.keyIdentifier)) + } + } + @Test fun `storing EdDSA key in java keystore`() { val tmpKeyStore = tempFile("keystore.jks") diff --git a/node/src/main/kotlin/net/corda/node/services/keys/KMSUtils.kt b/node/src/main/kotlin/net/corda/node/services/keys/KMSUtils.kt index 1db8b49e02..6cef78b051 100644 --- a/node/src/main/kotlin/net/corda/node/services/keys/KMSUtils.kt +++ b/node/src/main/kotlin/net/corda/node/services/keys/KMSUtils.kt @@ -40,6 +40,7 @@ fun freshCertificate(identityService: IdentityService, val ourCertificate = X509Utilities.createCertificate( CertificateType.CONFIDENTIAL_LEGAL_IDENTITY, issuerCert.subjectX500Principal, + issuerCert.publicKey, issuerSigner, issuer.name.x500Principal, subjectPublicKey, From 1b37cef82222ee5128fcd90264cf0ba51fe942ff Mon Sep 17 00:00:00 2001 From: Shams Asari Date: Thu, 5 Apr 2018 17:18:27 +0100 Subject: [PATCH 3/3] Minor: use of ByteArray.inputStream() and introduced PublicKey.hash (#2931) --- .../net/corda/core/internal/InternalUtils.kt | 5 +++- .../net/corda/core/utilities/EncodingUtils.kt | 4 +-- .../net/corda/core/flows/AttachmentTests.kt | 5 ++-- .../kotlin/net/corda/kryohook/KryoHook.kt | 5 +--- .../quasarhook/QuasarInstrumentationHook.kt | 5 ++-- .../internal/AttachmentsClassLoader.kt | 7 ++--- .../amqp/custom/InputStreamSerializer.kt | 2 +- .../internal/serialization/kryo/Kryo.kt | 3 +- .../serialization/kryo/KryoStreams.kt | 2 +- .../internal/AttachmentsClassLoaderTests.kt | 29 ++++++++++--------- .../amqp/SerializationOutputTests.kt | 5 ++-- .../internal/serialization/kryo/KryoTests.kt | 7 +++-- .../identity/PersistentIdentityService.kt | 3 +- .../node/messaging/TwoPartyTradeFlowTests.kt | 13 +++++---- 14 files changed, 48 insertions(+), 47 deletions(-) diff --git a/core/src/main/kotlin/net/corda/core/internal/InternalUtils.kt b/core/src/main/kotlin/net/corda/core/internal/InternalUtils.kt index 7f53da869f..a7aa8624c4 100644 --- a/core/src/main/kotlin/net/corda/core/internal/InternalUtils.kt +++ b/core/src/main/kotlin/net/corda/core/internal/InternalUtils.kt @@ -42,6 +42,7 @@ import java.nio.file.attribute.FileAttribute import java.nio.file.attribute.FileTime import java.security.KeyPair import java.security.PrivateKey +import java.security.PublicKey import java.security.cert.X509Certificate import java.time.Duration import java.time.temporal.Temporal @@ -230,7 +231,7 @@ fun logElapsedTime(label: String, logger: Logger? = null, body: () -> T): T /** Convert a [ByteArrayOutputStream] to [InputStreamAndHash]. */ fun ByteArrayOutputStream.toInputStreamAndHash(): InputStreamAndHash { val bytes = toByteArray() - return InputStreamAndHash(ByteArrayInputStream(bytes), bytes.sha256()) + return InputStreamAndHash(bytes.inputStream(), bytes.sha256()) } data class InputStreamAndHash(val inputStream: InputStream, val sha256: SecureHash.SHA256) { @@ -442,3 +443,5 @@ fun NotarisationRequest.generateSignature(serviceHub: ServiceHub): NotarisationR } return NotarisationRequestSignature(signature, serviceHub.myInfo.platformVersion) } + +val PublicKey.hash: SecureHash get() = encoded.sha256() diff --git a/core/src/main/kotlin/net/corda/core/utilities/EncodingUtils.kt b/core/src/main/kotlin/net/corda/core/utilities/EncodingUtils.kt index f4fdca5196..c7d5d75810 100644 --- a/core/src/main/kotlin/net/corda/core/utilities/EncodingUtils.kt +++ b/core/src/main/kotlin/net/corda/core/utilities/EncodingUtils.kt @@ -4,7 +4,7 @@ package net.corda.core.utilities import net.corda.core.crypto.Base58 import net.corda.core.crypto.Crypto -import net.corda.core.crypto.sha256 +import net.corda.core.internal.hash import java.nio.charset.Charset import java.security.PublicKey import java.util.* @@ -85,4 +85,4 @@ fun parsePublicKeyBase58(base58String: String): PublicKey = Crypto.decodePublicK fun PublicKey.toBase58String(): String = this.encoded.toBase58() /** Return the bytes of the SHA-256 output for this public key. */ -fun PublicKey.toSHA256Bytes(): ByteArray = this.encoded.sha256().bytes +fun PublicKey.toSHA256Bytes(): ByteArray = this.hash.bytes diff --git a/core/src/test/kotlin/net/corda/core/flows/AttachmentTests.kt b/core/src/test/kotlin/net/corda/core/flows/AttachmentTests.kt index 5047a18655..74414e47b1 100644 --- a/core/src/test/kotlin/net/corda/core/flows/AttachmentTests.kt +++ b/core/src/test/kotlin/net/corda/core/flows/AttachmentTests.kt @@ -20,7 +20,6 @@ import net.corda.testing.node.internal.startFlow import org.junit.After import org.junit.Before import org.junit.Test -import java.io.ByteArrayInputStream import java.io.ByteArrayOutputStream import java.util.jar.JarOutputStream import java.util.zip.ZipEntry @@ -59,7 +58,7 @@ class AttachmentTests { bobNode.registerInitiatedFlow(FetchAttachmentsResponse::class.java) // Insert an attachment into node zero's store directly. val id = aliceNode.database.transaction { - aliceNode.attachments.importAttachment(ByteArrayInputStream(fakeAttachment())) + aliceNode.attachments.importAttachment(fakeAttachment().inputStream()) } // Get node one to run a flow to fetch it and insert it. @@ -112,7 +111,7 @@ class AttachmentTests { val attachment = fakeAttachment() // Insert an attachment into node zero's store directly. val id = aliceNode.database.transaction { - aliceNode.attachments.importAttachment(ByteArrayInputStream(attachment)) + aliceNode.attachments.importAttachment(attachment.inputStream()) } // Corrupt its store. diff --git a/experimental/kryo-hook/src/main/kotlin/net/corda/kryohook/KryoHook.kt b/experimental/kryo-hook/src/main/kotlin/net/corda/kryohook/KryoHook.kt index 5afbd0e4ff..f08bdd52e9 100644 --- a/experimental/kryo-hook/src/main/kotlin/net/corda/kryohook/KryoHook.kt +++ b/experimental/kryo-hook/src/main/kotlin/net/corda/kryohook/KryoHook.kt @@ -5,13 +5,10 @@ import com.esotericsoftware.kryo.Kryo import com.esotericsoftware.kryo.io.Output import javassist.ClassPool import javassist.CtClass -import java.io.ByteArrayInputStream -import java.lang.StringBuilder import java.lang.instrument.ClassFileTransformer import java.lang.instrument.Instrumentation import java.security.ProtectionDomain import java.util.concurrent.ConcurrentHashMap -import java.util.concurrent.atomic.AtomicInteger class KryoHookAgent { companion object { @@ -69,7 +66,7 @@ object KryoHook : ClassFileTransformer { return null } return try { - val clazz = classPool.makeClass(ByteArrayInputStream(classfileBuffer)) + val clazz = classPool.makeClass(classfileBuffer.inputStream()) instrumentClass(clazz)?.toBytecode() } catch (throwable: Throwable) { println("SOMETHING WENT WRONG") diff --git a/experimental/quasar-hook/src/main/kotlin/net/corda/quasarhook/QuasarInstrumentationHook.kt b/experimental/quasar-hook/src/main/kotlin/net/corda/quasarhook/QuasarInstrumentationHook.kt index acd586fa31..1cc522206e 100644 --- a/experimental/quasar-hook/src/main/kotlin/net/corda/quasarhook/QuasarInstrumentationHook.kt +++ b/experimental/quasar-hook/src/main/kotlin/net/corda/quasarhook/QuasarInstrumentationHook.kt @@ -2,7 +2,6 @@ package net.corda.quasarhook import javassist.ClassPool import javassist.CtClass -import java.io.ByteArrayInputStream import java.lang.instrument.ClassFileTransformer import java.lang.instrument.Instrumentation import java.security.ProtectionDomain @@ -183,9 +182,9 @@ object QuasarInstrumentationHook : ClassFileTransformer { classfileBuffer: ByteArray ): ByteArray { return try { - val instrument = instrumentMap.get(className) + val instrument = instrumentMap[className] return instrument?.let { - val clazz = classPool.makeClass(ByteArrayInputStream(classfileBuffer)) + val clazz = classPool.makeClass(classfileBuffer.inputStream()) it(clazz) clazz.toBytecode() } ?: classfileBuffer diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/internal/AttachmentsClassLoader.kt b/node-api/src/main/kotlin/net/corda/nodeapi/internal/AttachmentsClassLoader.kt index 6117670407..5b53279f9f 100644 --- a/node-api/src/main/kotlin/net/corda/nodeapi/internal/AttachmentsClassLoader.kt +++ b/node-api/src/main/kotlin/net/corda/nodeapi/internal/AttachmentsClassLoader.kt @@ -5,7 +5,6 @@ import net.corda.core.contracts.ContractAttachment import net.corda.core.crypto.SecureHash import net.corda.core.internal.isUploaderTrusted import net.corda.core.serialization.CordaSerializable -import java.io.ByteArrayInputStream import java.io.ByteArrayOutputStream import java.io.FileNotFoundException import java.io.InputStream @@ -101,12 +100,12 @@ class AttachmentsClassLoader(attachments: List, parent: ClassLoader if (url.protocol != "attachment") return null val attachment = idsToAttachments[SecureHash.parse(url.host)] ?: return null val path = url.path?.substring(1) ?: return null // Chop off the leading slash. - try { + return try { val stream = ByteArrayOutputStream() attachment.extractFile(path, stream) - return ByteArrayInputStream(stream.toByteArray()) + stream.toByteArray().inputStream() } catch (e: FileNotFoundException) { - return null + null } } } diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/custom/InputStreamSerializer.kt b/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/custom/InputStreamSerializer.kt index 47c5f0b539..ff2439bab9 100644 --- a/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/custom/InputStreamSerializer.kt +++ b/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/custom/InputStreamSerializer.kt @@ -36,6 +36,6 @@ object InputStreamSerializer : CustomSerializer.Implements(InputStr override fun readObject(obj: Any, schemas: SerializationSchemas, input: DeserializationInput): InputStream { val bits = input.readObject(obj, schemas, ByteArray::class.java) as ByteArray - return ByteArrayInputStream(bits) + return bits.inputStream() } } \ No newline at end of file diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/kryo/Kryo.kt b/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/kryo/Kryo.kt index e161768f65..86316cc006 100644 --- a/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/kryo/Kryo.kt +++ b/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/kryo/Kryo.kt @@ -28,7 +28,6 @@ import net.corda.nodeapi.internal.serialization.serializationContextKey import org.slf4j.Logger import org.slf4j.LoggerFactory import rx.Observable -import java.io.ByteArrayInputStream import java.io.InputStream import java.lang.reflect.InvocationTargetException import java.security.PrivateKey @@ -208,7 +207,7 @@ object InputStreamSerializer : Serializer() { System.arraycopy(chunk, 0, flattened, offset, chunk.size) offset += chunk.size } - return ByteArrayInputStream(flattened) + return flattened.inputStream() } } diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/kryo/KryoStreams.kt b/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/kryo/KryoStreams.kt index b1274223cc..1d26ba2703 100644 --- a/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/kryo/KryoStreams.kt +++ b/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/kryo/KryoStreams.kt @@ -66,5 +66,5 @@ internal fun Output.substitute(transform: (OutputStream) -> OutputStream) { } internal fun Input.substitute(transform: (InputStream) -> InputStream) { - inputStream = transform(SequenceInputStream(ByteArrayInputStream(buffer.copyOfRange(position(), limit())), inputStream)) + inputStream = transform(SequenceInputStream(buffer.copyOfRange(position(), limit()).inputStream(), inputStream)) } diff --git a/node-api/src/test/kotlin/net/corda/nodeapi/internal/AttachmentsClassLoaderTests.kt b/node-api/src/test/kotlin/net/corda/nodeapi/internal/AttachmentsClassLoaderTests.kt index eeafa28630..7ac2ca9d4b 100644 --- a/node-api/src/test/kotlin/net/corda/nodeapi/internal/AttachmentsClassLoaderTests.kt +++ b/node-api/src/test/kotlin/net/corda/nodeapi/internal/AttachmentsClassLoaderTests.kt @@ -2,7 +2,8 @@ package net.corda.nodeapi.internal import com.nhaarman.mockito_kotlin.doReturn import com.nhaarman.mockito_kotlin.whenever -import net.corda.core.contracts.* +import net.corda.core.contracts.Attachment +import net.corda.core.contracts.Contract import net.corda.core.crypto.SecureHash import net.corda.core.identity.CordaX500Name import net.corda.core.internal.declaredField @@ -22,9 +23,9 @@ import net.corda.testing.common.internal.testNetworkParameters import net.corda.testing.core.DUMMY_NOTARY_NAME import net.corda.testing.core.SerializationEnvironmentRule import net.corda.testing.core.TestIdentity +import net.corda.testing.internal.MockCordappConfigProvider import net.corda.testing.internal.kryoSpecific import net.corda.testing.internal.rigorousMock -import net.corda.testing.internal.MockCordappConfigProvider import net.corda.testing.services.MockAttachmentStorage import org.apache.commons.io.IOUtils import org.junit.Assert.* @@ -127,8 +128,8 @@ class AttachmentsClassLoaderTests { fun `test overlapping file exception`() { val storage = attachments val att0 = attachmentId - val att1 = storage.importAttachment(ByteArrayInputStream(fakeAttachment("file.txt", "some data"))) - val att2 = storage.importAttachment(ByteArrayInputStream(fakeAttachment("file.txt", "some other data"))) + val att1 = storage.importAttachment(fakeAttachment("file.txt", "some data").inputStream()) + val att2 = storage.importAttachment(fakeAttachment("file.txt", "some other data").inputStream()) assertFailsWith(AttachmentsClassLoader.OverlappingAttachments::class) { AttachmentsClassLoader(arrayOf(att0, att1, att2).map { storage.openAttachment(it)!! }) @@ -139,8 +140,8 @@ class AttachmentsClassLoaderTests { fun `basic`() { val storage = attachments val att0 = attachmentId - val att1 = storage.importAttachment(ByteArrayInputStream(fakeAttachment("file1.txt", "some data"))) - val att2 = storage.importAttachment(ByteArrayInputStream(fakeAttachment("file2.txt", "some other data"))) + val att1 = storage.importAttachment(fakeAttachment("file1.txt", "some data").inputStream()) + val att2 = storage.importAttachment(fakeAttachment("file2.txt", "some other data").inputStream()) val cl = AttachmentsClassLoader(arrayOf(att0, att1, att2).map { storage.openAttachment(it)!! }) val txt = IOUtils.toString(cl.getResourceAsStream("file1.txt"), Charsets.UTF_8.name()) @@ -151,8 +152,8 @@ class AttachmentsClassLoaderTests { fun `Check platform independent path handling in attachment jars`() { val storage = MockAttachmentStorage() - val att1 = storage.importAttachment(ByteArrayInputStream(fakeAttachment("/folder1/foldera/file1.txt", "some data"))) - val att2 = storage.importAttachment(ByteArrayInputStream(fakeAttachment("\\folder1\\folderb\\file2.txt", "some other data"))) + val att1 = storage.importAttachment(fakeAttachment("/folder1/foldera/file1.txt", "some data").inputStream()) + val att2 = storage.importAttachment(fakeAttachment("\\folder1\\folderb\\file2.txt", "some other data").inputStream()) val data1a = readAttachment(storage.openAttachment(att1)!!, "/folder1/foldera/file1.txt") assertArrayEquals("some data".toByteArray(), data1a) @@ -171,8 +172,8 @@ class AttachmentsClassLoaderTests { fun `loading class AnotherDummyContract`() { val storage = attachments val att0 = attachmentId - val att1 = storage.importAttachment(ByteArrayInputStream(fakeAttachment("file1.txt", "some data"))) - val att2 = storage.importAttachment(ByteArrayInputStream(fakeAttachment("file2.txt", "some other data"))) + val att1 = storage.importAttachment(fakeAttachment("file1.txt", "some data").inputStream()) + val att2 = storage.importAttachment(fakeAttachment("file2.txt", "some other data").inputStream()) val cl = AttachmentsClassLoader(arrayOf(att0, att1, att2).map { storage.openAttachment(it)!! }, FilteringClassLoader) val contractClass = Class.forName(ISOLATED_CONTRACT_CLASS_NAME, true, cl) @@ -195,8 +196,8 @@ class AttachmentsClassLoaderTests { val bytes = contract.serialize() val storage = attachments val att0 = attachmentId - val att1 = storage.importAttachment(ByteArrayInputStream(fakeAttachment("file1.txt", "some data"))) - val att2 = storage.importAttachment(ByteArrayInputStream(fakeAttachment("file2.txt", "some other data"))) + val att1 = storage.importAttachment(fakeAttachment("file1.txt", "some data").inputStream()) + val att2 = storage.importAttachment(fakeAttachment("file2.txt", "some other data").inputStream()) val cl = AttachmentsClassLoader(arrayOf(att0, att1, att2).map { storage.openAttachment(it)!! }, FilteringClassLoader) @@ -221,8 +222,8 @@ class AttachmentsClassLoaderTests { val bytes = data.serialize(context = context2) val storage = attachments val att0 = attachmentId - val att1 = storage.importAttachment(ByteArrayInputStream(fakeAttachment("file1.txt", "some data"))) - val att2 = storage.importAttachment(ByteArrayInputStream(fakeAttachment("file2.txt", "some other data"))) + val att1 = storage.importAttachment(fakeAttachment("file1.txt", "some data").inputStream()) + val att2 = storage.importAttachment(fakeAttachment("file2.txt", "some other data").inputStream()) val cl = AttachmentsClassLoader(arrayOf(att0, att1, att2).map { storage.openAttachment(it)!! }, FilteringClassLoader) diff --git a/node-api/src/test/kotlin/net/corda/nodeapi/internal/serialization/amqp/SerializationOutputTests.kt b/node-api/src/test/kotlin/net/corda/nodeapi/internal/serialization/amqp/SerializationOutputTests.kt index 822bf86396..a41f5b33c0 100644 --- a/node-api/src/test/kotlin/net/corda/nodeapi/internal/serialization/amqp/SerializationOutputTests.kt +++ b/node-api/src/test/kotlin/net/corda/nodeapi/internal/serialization/amqp/SerializationOutputTests.kt @@ -43,7 +43,6 @@ import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.Parameterized import org.junit.runners.Parameterized.Parameters -import java.io.ByteArrayInputStream import java.io.IOException import java.io.NotSerializableException import java.math.BigDecimal @@ -1083,9 +1082,9 @@ class SerializationOutputTests(private val compression: CordaSerializationEncodi val factory2 = SerializerFactory(AllWhitelist, ClassLoader.getSystemClassLoader()) factory2.register(net.corda.nodeapi.internal.serialization.amqp.custom.InputStreamSerializer) val bytes = ByteArray(10) { it.toByte() } - val obj = ByteArrayInputStream(bytes) + val obj = bytes.inputStream() val obj2 = serdes(obj, factory, factory2, expectedEqual = false, expectDeserializedEqual = false) - val obj3 = ByteArrayInputStream(bytes) // Can't use original since the stream pointer has moved. + val obj3 = bytes.inputStream() // Can't use original since the stream pointer has moved. assertEquals(obj3.available(), obj2.available()) assertEquals(obj3.read(), obj2.read()) } diff --git a/node-api/src/test/kotlin/net/corda/nodeapi/internal/serialization/kryo/KryoTests.kt b/node-api/src/test/kotlin/net/corda/nodeapi/internal/serialization/kryo/KryoTests.kt index da045ce633..d7acb47e7f 100644 --- a/node-api/src/test/kotlin/net/corda/nodeapi/internal/serialization/kryo/KryoTests.kt +++ b/node-api/src/test/kotlin/net/corda/nodeapi/internal/serialization/kryo/KryoTests.kt @@ -29,7 +29,6 @@ import org.junit.runner.RunWith import org.junit.runners.Parameterized import org.junit.runners.Parameterized.Parameters import org.slf4j.LoggerFactory -import java.io.ByteArrayInputStream import java.io.InputStream import java.time.Instant import java.util.* @@ -190,7 +189,11 @@ class KryoTests(private val compression: CordaSerializationEncoding?) { @Test fun `HashCheckingStream (de)serialize`() { val rubbish = ByteArray(12345, { (it * it * 0.12345).toByte() }) - val readRubbishStream: InputStream = NodeAttachmentService.HashCheckingStream(SecureHash.sha256(rubbish), rubbish.size, ByteArrayInputStream(rubbish)).serialize(factory, context).deserialize(factory, context) + val readRubbishStream: InputStream = NodeAttachmentService.HashCheckingStream( + SecureHash.sha256(rubbish), + rubbish.size, + rubbish.inputStream() + ).serialize(factory, context).deserialize(factory, context) for (i in 0..12344) { assertEquals(rubbish[i], readRubbishStream.read().toByte()) } diff --git a/node/src/main/kotlin/net/corda/node/services/identity/PersistentIdentityService.kt b/node/src/main/kotlin/net/corda/node/services/identity/PersistentIdentityService.kt index c5784c0bd0..a8ff0525e0 100644 --- a/node/src/main/kotlin/net/corda/node/services/identity/PersistentIdentityService.kt +++ b/node/src/main/kotlin/net/corda/node/services/identity/PersistentIdentityService.kt @@ -5,6 +5,7 @@ import net.corda.core.crypto.SecureHash import net.corda.core.crypto.toStringShort import net.corda.core.identity.* import net.corda.core.internal.CertRole +import net.corda.core.internal.hash import net.corda.core.node.services.UnknownAnonymousPartyException import net.corda.core.serialization.SingletonSerializeAsToken import net.corda.core.utilities.MAX_HASH_HEX_SIZE @@ -62,7 +63,7 @@ class PersistentIdentityService(override val trustRoot: X509Certificate, ) } - private fun mapToKey(owningKey: PublicKey) = SecureHash.sha256(owningKey.encoded) + private fun mapToKey(owningKey: PublicKey) = owningKey.hash private fun mapToKey(party: PartyAndCertificate) = mapToKey(party.owningKey) } diff --git a/node/src/test/kotlin/net/corda/node/messaging/TwoPartyTradeFlowTests.kt b/node/src/test/kotlin/net/corda/node/messaging/TwoPartyTradeFlowTests.kt index 4bd1dddbc0..604eca0f7a 100644 --- a/node/src/test/kotlin/net/corda/node/messaging/TwoPartyTradeFlowTests.kt +++ b/node/src/test/kotlin/net/corda/node/messaging/TwoPartyTradeFlowTests.kt @@ -35,24 +35,26 @@ import net.corda.finance.contracts.asset.Cash import net.corda.finance.flows.TwoPartyTradeFlow.Buyer import net.corda.finance.flows.TwoPartyTradeFlow.Seller import net.corda.node.internal.StartedNode -import net.corda.node.services.api.WritableTransactionStorage import net.corda.node.services.api.IdentityServiceInternal +import net.corda.node.services.api.WritableTransactionStorage import net.corda.node.services.persistence.DBTransactionStorage import net.corda.node.services.persistence.checkpoints import net.corda.nodeapi.internal.persistence.CordaPersistence import net.corda.testing.core.* -import net.corda.testing.internal.LogHelper import net.corda.testing.dsl.LedgerDSL import net.corda.testing.dsl.TestLedgerDSLInterpreter import net.corda.testing.dsl.TestTransactionDSLInterpreter +import net.corda.testing.internal.LogHelper import net.corda.testing.internal.TEST_TX_TIME import net.corda.testing.internal.rigorousMock import net.corda.testing.internal.vault.VaultFiller -import net.corda.testing.node.* +import net.corda.testing.node.InMemoryMessagingNetwork +import net.corda.testing.node.MockServices import net.corda.testing.node.internal.InternalMockNetwork import net.corda.testing.node.internal.InternalMockNodeParameters import net.corda.testing.node.internal.pumpReceive import net.corda.testing.node.internal.startFlow +import net.corda.testing.node.ledger import org.assertj.core.api.Assertions.assertThat import org.junit.After import org.junit.Before @@ -60,7 +62,6 @@ import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.Parameterized import rx.Observable -import java.io.ByteArrayInputStream import java.io.ByteArrayOutputStream import java.util.* import java.util.jar.JarOutputStream @@ -347,7 +348,7 @@ class TwoPartyTradeFlowTests(private val anonymous: Boolean) { it.closeEntry() } val attachmentID = aliceNode.database.transaction { - attachment(ByteArrayInputStream(stream.toByteArray())) + attachment(stream.toByteArray().inputStream()) } val bobsFakeCash = bobNode.database.transaction { @@ -451,7 +452,7 @@ class TwoPartyTradeFlowTests(private val anonymous: Boolean) { it.closeEntry() } val attachmentID = aliceNode.database.transaction { - attachment(ByteArrayInputStream(stream.toByteArray())) + attachment(stream.toByteArray().inputStream()) } val bobsKey = bobNode.services.keyManagementService.keys.single()