mirror of
https://github.com/corda/corda.git
synced 2024-12-26 16:11:12 +00:00
Merge remote-tracking branch 'open/master' into os-merge-1b37cef
This commit is contained in:
commit
a97abbc8c0
@ -13,6 +13,7 @@ package net.corda.core.flows
|
|||||||
import co.paralleluniverse.fibers.Suspendable
|
import co.paralleluniverse.fibers.Suspendable
|
||||||
import net.corda.core.contracts.StateAndRef
|
import net.corda.core.contracts.StateAndRef
|
||||||
import net.corda.core.internal.FetchDataFlow
|
import net.corda.core.internal.FetchDataFlow
|
||||||
|
import net.corda.core.internal.readFully
|
||||||
import net.corda.core.transactions.SignedTransaction
|
import net.corda.core.transactions.SignedTransaction
|
||||||
import net.corda.core.utilities.unwrap
|
import net.corda.core.utilities.unwrap
|
||||||
|
|
||||||
@ -70,7 +71,7 @@ open class DataVendingFlow(val otherSideSession: FlowSession, val payload: Any)
|
|||||||
serviceHub.validatedTransactions.getTransaction(it) ?: throw FetchDataFlow.HashNotFound(it)
|
serviceHub.validatedTransactions.getTransaction(it) ?: throw FetchDataFlow.HashNotFound(it)
|
||||||
}
|
}
|
||||||
FetchDataFlow.DataType.ATTACHMENT -> dataRequest.hashes.map {
|
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -38,7 +38,7 @@ abstract class AbstractAttachment(dataLoader: () -> ByteArray) : Attachment {
|
|||||||
fun SerializeAsTokenContext.attachmentDataLoader(id: SecureHash): () -> ByteArray {
|
fun SerializeAsTokenContext.attachmentDataLoader(id: SecureHash): () -> ByteArray {
|
||||||
return {
|
return {
|
||||||
val a = serviceHub.attachments.openAttachment(id) ?: throw MissingAttachmentsException(listOf(id))
|
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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,6 +12,8 @@
|
|||||||
|
|
||||||
package net.corda.core.internal
|
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.Cordapp
|
||||||
import net.corda.core.cordapp.CordappConfig
|
import net.corda.core.cordapp.CordappConfig
|
||||||
import net.corda.core.cordapp.CordappContext
|
import net.corda.core.cordapp.CordappContext
|
||||||
@ -50,6 +52,7 @@ import java.nio.file.attribute.FileAttribute
|
|||||||
import java.nio.file.attribute.FileTime
|
import java.nio.file.attribute.FileTime
|
||||||
import java.security.KeyPair
|
import java.security.KeyPair
|
||||||
import java.security.PrivateKey
|
import java.security.PrivateKey
|
||||||
|
import java.security.PublicKey
|
||||||
import java.security.cert.X509Certificate
|
import java.security.cert.X509Certificate
|
||||||
import java.time.Duration
|
import java.time.Duration
|
||||||
import java.time.temporal.Temporal
|
import java.time.temporal.Temporal
|
||||||
@ -160,8 +163,31 @@ fun Path.writeLines(lines: Iterable<CharSequence>, charset: Charset = UTF_8, var
|
|||||||
|
|
||||||
inline fun <reified T : Any> Path.readObject(): T = readAll().deserialize()
|
inline fun <reified T : Any> 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)
|
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 <reified T : Any> 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) + "…"
|
fun String.abbreviate(maxWidth: Int): String = if (length <= maxWidth) this else take(maxWidth - 1) + "…"
|
||||||
|
|
||||||
/** Return the sum of an Iterable of [BigDecimal]s. */
|
/** Return the sum of an Iterable of [BigDecimal]s. */
|
||||||
@ -215,7 +241,7 @@ fun <T> logElapsedTime(label: String, logger: Logger? = null, body: () -> T): T
|
|||||||
/** Convert a [ByteArrayOutputStream] to [InputStreamAndHash]. */
|
/** Convert a [ByteArrayOutputStream] to [InputStreamAndHash]. */
|
||||||
fun ByteArrayOutputStream.toInputStreamAndHash(): InputStreamAndHash {
|
fun ByteArrayOutputStream.toInputStreamAndHash(): InputStreamAndHash {
|
||||||
val bytes = toByteArray()
|
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) {
|
data class InputStreamAndHash(val inputStream: InputStream, val sha256: SecureHash.SHA256) {
|
||||||
@ -343,7 +369,7 @@ fun URL.post(serializedData: OpaqueBytes): ByteArray {
|
|||||||
setRequestProperty("Content-Type", "application/octet-stream")
|
setRequestProperty("Content-Type", "application/octet-stream")
|
||||||
outputStream.use { serializedData.open().copyTo(it) }
|
outputStream.use { serializedData.open().copyTo(it) }
|
||||||
checkOkResponse()
|
checkOkResponse()
|
||||||
inputStream.use { it.readBytes() }
|
inputStream.readFully()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -356,7 +382,7 @@ fun HttpURLConnection.checkOkResponse() {
|
|||||||
|
|
||||||
inline fun <reified T : Any> HttpURLConnection.responseAs(): T {
|
inline fun <reified T : Any> HttpURLConnection.responseAs(): T {
|
||||||
checkOkResponse()
|
checkOkResponse()
|
||||||
return inputStream.use { it.readBytes() }.deserialize()
|
return inputStream.readObject()
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Analogous to [Thread.join]. */
|
/** Analogous to [Thread.join]. */
|
||||||
@ -427,3 +453,5 @@ fun NotarisationRequest.generateSignature(serviceHub: ServiceHub): NotarisationR
|
|||||||
}
|
}
|
||||||
return NotarisationRequestSignature(signature, serviceHub.myInfo.platformVersion)
|
return NotarisationRequestSignature(signature, serviceHub.myInfo.platformVersion)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val PublicKey.hash: SecureHash get() = encoded.sha256()
|
||||||
|
@ -14,7 +14,7 @@ package net.corda.core.utilities
|
|||||||
|
|
||||||
import net.corda.core.crypto.Base58
|
import net.corda.core.crypto.Base58
|
||||||
import net.corda.core.crypto.Crypto
|
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.nio.charset.Charset
|
||||||
import java.security.PublicKey
|
import java.security.PublicKey
|
||||||
import java.util.*
|
import java.util.*
|
||||||
@ -95,4 +95,4 @@ fun parsePublicKeyBase58(base58String: String): PublicKey = Crypto.decodePublicK
|
|||||||
fun PublicKey.toBase58String(): String = this.encoded.toBase58()
|
fun PublicKey.toBase58String(): String = this.encoded.toBase58()
|
||||||
|
|
||||||
/** Return the bytes of the SHA-256 output for this public key. */
|
/** 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
|
||||||
|
@ -17,6 +17,7 @@ import net.corda.core.crypto.sha256
|
|||||||
import net.corda.core.identity.Party
|
import net.corda.core.identity.Party
|
||||||
import net.corda.core.internal.FetchAttachmentsFlow
|
import net.corda.core.internal.FetchAttachmentsFlow
|
||||||
import net.corda.core.internal.FetchDataFlow
|
import net.corda.core.internal.FetchDataFlow
|
||||||
|
import net.corda.core.internal.hash
|
||||||
import net.corda.core.utilities.getOrThrow
|
import net.corda.core.utilities.getOrThrow
|
||||||
import net.corda.node.internal.StartedNode
|
import net.corda.node.internal.StartedNode
|
||||||
import net.corda.node.services.persistence.NodeAttachmentService
|
import net.corda.node.services.persistence.NodeAttachmentService
|
||||||
@ -29,7 +30,6 @@ import net.corda.testing.node.internal.startFlow
|
|||||||
import org.junit.After
|
import org.junit.After
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import java.io.ByteArrayInputStream
|
|
||||||
import java.io.ByteArrayOutputStream
|
import java.io.ByteArrayOutputStream
|
||||||
import java.util.jar.JarOutputStream
|
import java.util.jar.JarOutputStream
|
||||||
import java.util.zip.ZipEntry
|
import java.util.zip.ZipEntry
|
||||||
@ -68,7 +68,7 @@ class AttachmentTests {
|
|||||||
bobNode.registerInitiatedFlow(FetchAttachmentsResponse::class.java)
|
bobNode.registerInitiatedFlow(FetchAttachmentsResponse::class.java)
|
||||||
// Insert an attachment into node zero's store directly.
|
// Insert an attachment into node zero's store directly.
|
||||||
val id = aliceNode.database.transaction {
|
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.
|
// Get node one to run a flow to fetch it and insert it.
|
||||||
@ -82,7 +82,7 @@ class AttachmentTests {
|
|||||||
bobNode.attachments.openAttachment(id)!!
|
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.
|
// Shut down node zero and ensure node one can still resolve the attachment.
|
||||||
aliceNode.dispose()
|
aliceNode.dispose()
|
||||||
@ -121,7 +121,7 @@ class AttachmentTests {
|
|||||||
val attachment = fakeAttachment()
|
val attachment = fakeAttachment()
|
||||||
// Insert an attachment into node zero's store directly.
|
// Insert an attachment into node zero's store directly.
|
||||||
val id = aliceNode.database.transaction {
|
val id = aliceNode.database.transaction {
|
||||||
aliceNode.attachments.importAttachment(ByteArrayInputStream(attachment))
|
aliceNode.attachments.importAttachment(attachment.inputStream())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Corrupt its store.
|
// Corrupt its store.
|
||||||
|
@ -15,13 +15,10 @@ import com.esotericsoftware.kryo.Kryo
|
|||||||
import com.esotericsoftware.kryo.io.Output
|
import com.esotericsoftware.kryo.io.Output
|
||||||
import javassist.ClassPool
|
import javassist.ClassPool
|
||||||
import javassist.CtClass
|
import javassist.CtClass
|
||||||
import java.io.ByteArrayInputStream
|
|
||||||
import java.lang.StringBuilder
|
|
||||||
import java.lang.instrument.ClassFileTransformer
|
import java.lang.instrument.ClassFileTransformer
|
||||||
import java.lang.instrument.Instrumentation
|
import java.lang.instrument.Instrumentation
|
||||||
import java.security.ProtectionDomain
|
import java.security.ProtectionDomain
|
||||||
import java.util.concurrent.ConcurrentHashMap
|
import java.util.concurrent.ConcurrentHashMap
|
||||||
import java.util.concurrent.atomic.AtomicInteger
|
|
||||||
|
|
||||||
class KryoHookAgent {
|
class KryoHookAgent {
|
||||||
companion object {
|
companion object {
|
||||||
@ -79,7 +76,7 @@ object KryoHook : ClassFileTransformer {
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
return try {
|
return try {
|
||||||
val clazz = classPool.makeClass(ByteArrayInputStream(classfileBuffer))
|
val clazz = classPool.makeClass(classfileBuffer.inputStream())
|
||||||
instrumentClass(clazz)?.toBytecode()
|
instrumentClass(clazz)?.toBytecode()
|
||||||
} catch (throwable: Throwable) {
|
} catch (throwable: Throwable) {
|
||||||
println("SOMETHING WENT WRONG")
|
println("SOMETHING WENT WRONG")
|
||||||
|
@ -12,7 +12,6 @@ package net.corda.quasarhook
|
|||||||
|
|
||||||
import javassist.ClassPool
|
import javassist.ClassPool
|
||||||
import javassist.CtClass
|
import javassist.CtClass
|
||||||
import java.io.ByteArrayInputStream
|
|
||||||
import java.lang.instrument.ClassFileTransformer
|
import java.lang.instrument.ClassFileTransformer
|
||||||
import java.lang.instrument.Instrumentation
|
import java.lang.instrument.Instrumentation
|
||||||
import java.security.ProtectionDomain
|
import java.security.ProtectionDomain
|
||||||
@ -193,9 +192,9 @@ object QuasarInstrumentationHook : ClassFileTransformer {
|
|||||||
classfileBuffer: ByteArray
|
classfileBuffer: ByteArray
|
||||||
): ByteArray {
|
): ByteArray {
|
||||||
return try {
|
return try {
|
||||||
val instrument = instrumentMap.get(className)
|
val instrument = instrumentMap[className]
|
||||||
return instrument?.let {
|
return instrument?.let {
|
||||||
val clazz = classPool.makeClass(ByteArrayInputStream(classfileBuffer))
|
val clazz = classPool.makeClass(classfileBuffer.inputStream())
|
||||||
it(clazz)
|
it(clazz)
|
||||||
clazz.toBytecode()
|
clazz.toBytecode()
|
||||||
} ?: classfileBuffer
|
} ?: classfileBuffer
|
||||||
|
@ -15,7 +15,6 @@ import net.corda.core.contracts.ContractAttachment
|
|||||||
import net.corda.core.crypto.SecureHash
|
import net.corda.core.crypto.SecureHash
|
||||||
import net.corda.core.internal.isUploaderTrusted
|
import net.corda.core.internal.isUploaderTrusted
|
||||||
import net.corda.core.serialization.CordaSerializable
|
import net.corda.core.serialization.CordaSerializable
|
||||||
import java.io.ByteArrayInputStream
|
|
||||||
import java.io.ByteArrayOutputStream
|
import java.io.ByteArrayOutputStream
|
||||||
import java.io.FileNotFoundException
|
import java.io.FileNotFoundException
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
@ -111,12 +110,12 @@ class AttachmentsClassLoader(attachments: List<Attachment>, parent: ClassLoader
|
|||||||
if (url.protocol != "attachment") return null
|
if (url.protocol != "attachment") return null
|
||||||
val attachment = idsToAttachments[SecureHash.parse(url.host)] ?: return null
|
val attachment = idsToAttachments[SecureHash.parse(url.host)] ?: return null
|
||||||
val path = url.path?.substring(1) ?: return null // Chop off the leading slash.
|
val path = url.path?.substring(1) ?: return null // Chop off the leading slash.
|
||||||
try {
|
return try {
|
||||||
val stream = ByteArrayOutputStream()
|
val stream = ByteArrayOutputStream()
|
||||||
attachment.extractFile(path, stream)
|
attachment.extractFile(path, stream)
|
||||||
return ByteArrayInputStream(stream.toByteArray())
|
stream.toByteArray().inputStream()
|
||||||
} catch (e: FileNotFoundException) {
|
} catch (e: FileNotFoundException) {
|
||||||
return null
|
null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,12 +18,14 @@ import net.corda.core.internal.*
|
|||||||
import net.corda.core.utilities.days
|
import net.corda.core.utilities.days
|
||||||
import net.corda.core.utilities.millis
|
import net.corda.core.utilities.millis
|
||||||
import org.bouncycastle.asn1.*
|
import org.bouncycastle.asn1.*
|
||||||
|
import org.bouncycastle.asn1.x500.X500Name
|
||||||
import org.bouncycastle.asn1.x500.style.BCStyle
|
import org.bouncycastle.asn1.x500.style.BCStyle
|
||||||
import org.bouncycastle.asn1.x509.*
|
import org.bouncycastle.asn1.x509.*
|
||||||
import org.bouncycastle.asn1.x509.Extension
|
import org.bouncycastle.asn1.x509.Extension
|
||||||
import org.bouncycastle.cert.X509CertificateHolder
|
import org.bouncycastle.cert.X509CertificateHolder
|
||||||
import org.bouncycastle.cert.X509v3CertificateBuilder
|
import org.bouncycastle.cert.X509v3CertificateBuilder
|
||||||
import org.bouncycastle.cert.bc.BcX509ExtensionUtils
|
import org.bouncycastle.cert.bc.BcX509ExtensionUtils
|
||||||
|
import org.bouncycastle.cert.jcajce.JcaX509ExtensionUtils
|
||||||
import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder
|
import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder
|
||||||
import org.bouncycastle.openssl.jcajce.JcaPEMWriter
|
import org.bouncycastle.openssl.jcajce.JcaPEMWriter
|
||||||
import org.bouncycastle.operator.ContentSigner
|
import org.bouncycastle.operator.ContentSigner
|
||||||
@ -159,18 +161,25 @@ $trustedRoot""", e, certPath, e.index)
|
|||||||
/**
|
/**
|
||||||
* Build a partial X.509 certificate ready for signing.
|
* Build a partial X.509 certificate ready for signing.
|
||||||
*
|
*
|
||||||
|
* @param certificateType type of the certificate.
|
||||||
* @param issuer name of the issuing entity.
|
* @param issuer name of the issuing entity.
|
||||||
|
* @param issuerPublicKey public key of the issuing entity.
|
||||||
* @param subject name of the certificate subject.
|
* @param subject name of the certificate subject.
|
||||||
* @param subjectPublicKey public key of the certificate subject.
|
* @param subjectPublicKey public key of the certificate subject.
|
||||||
* @param validityWindow the time period the certificate is valid for.
|
* @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 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,
|
issuer: X500Principal,
|
||||||
|
issuerPublicKey: PublicKey,
|
||||||
subject: X500Principal,
|
subject: X500Principal,
|
||||||
subjectPublicKey: PublicKey,
|
subjectPublicKey: PublicKey,
|
||||||
validityWindow: Pair<Date, Date>,
|
validityWindow: Pair<Date, Date>,
|
||||||
nameConstraints: NameConstraints? = null): X509v3CertificateBuilder {
|
nameConstraints: NameConstraints? = null,
|
||||||
|
crlDistPoint: String? = null,
|
||||||
|
crlIssuer: X500Name? = null): X509v3CertificateBuilder {
|
||||||
val serial = BigInteger.valueOf(random63BitValue())
|
val serial = BigInteger.valueOf(random63BitValue())
|
||||||
val keyPurposes = DERSequence(ASN1EncodableVector().apply { certificateType.purposes.forEach { add(it) } })
|
val keyPurposes = DERSequence(ASN1EncodableVector().apply { certificateType.purposes.forEach { add(it) } })
|
||||||
val subjectPublicKeyInfo = SubjectPublicKeyInfo.getInstance(ASN1Sequence.getInstance(subjectPublicKey.encoded))
|
val subjectPublicKeyInfo = SubjectPublicKeyInfo.getInstance(ASN1Sequence.getInstance(subjectPublicKey.encoded))
|
||||||
@ -181,10 +190,12 @@ $trustedRoot""", e, certPath, e.index)
|
|||||||
.addExtension(Extension.basicConstraints, true, BasicConstraints(certificateType.isCA))
|
.addExtension(Extension.basicConstraints, true, BasicConstraints(certificateType.isCA))
|
||||||
.addExtension(Extension.keyUsage, false, certificateType.keyUsage)
|
.addExtension(Extension.keyUsage, false, certificateType.keyUsage)
|
||||||
.addExtension(Extension.extendedKeyUsage, false, keyPurposes)
|
.addExtension(Extension.extendedKeyUsage, false, keyPurposes)
|
||||||
|
.addExtension(Extension.authorityKeyIdentifier, false, JcaX509ExtensionUtils().createAuthorityKeyIdentifier(issuerPublicKey))
|
||||||
|
|
||||||
if (role != null) {
|
if (role != null) {
|
||||||
builder.addExtension(ASN1ObjectIdentifier(CordaOID.X509_EXTENSION_CORDA_ROLE), false, role)
|
builder.addExtension(ASN1ObjectIdentifier(CordaOID.X509_EXTENSION_CORDA_ROLE), false, role)
|
||||||
}
|
}
|
||||||
|
addCrlInfo(builder, crlDistPoint, crlIssuer)
|
||||||
if (nameConstraints != null) {
|
if (nameConstraints != null) {
|
||||||
builder.addExtension(Extension.nameConstraints, true, nameConstraints)
|
builder.addExtension(Extension.nameConstraints, true, nameConstraints)
|
||||||
}
|
}
|
||||||
@ -195,11 +206,15 @@ $trustedRoot""", e, certPath, e.index)
|
|||||||
/**
|
/**
|
||||||
* Create a X509 v3 certificate using the given issuer certificate and key pair.
|
* 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 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 issuerKeyPair The KeyPair of the root CA above this used to sign it.
|
||||||
* @param subject subject of the generated certificate.
|
* @param subject subject of the generated certificate.
|
||||||
* @param subjectPublicKey subject's public key.
|
* @param subjectPublicKey subject's public key.
|
||||||
* @param validityWindow The certificate's validity window. Default to [DEFAULT_VALIDITY_WINDOW] if not provided.
|
* @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.
|
* @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.
|
* Note the generated certificate tree is capped at max depth of 1 below this to be in line with commercially available certificates.
|
||||||
*/
|
*/
|
||||||
@ -210,7 +225,9 @@ $trustedRoot""", e, certPath, e.index)
|
|||||||
subject: X500Principal,
|
subject: X500Principal,
|
||||||
subjectPublicKey: PublicKey,
|
subjectPublicKey: PublicKey,
|
||||||
validityWindow: Pair<Duration, Duration> = DEFAULT_VALIDITY_WINDOW,
|
validityWindow: Pair<Duration, Duration> = 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)
|
val window = getCertificateValidityWindow(validityWindow.first, validityWindow.second, issuerCertificate)
|
||||||
return createCertificate(
|
return createCertificate(
|
||||||
certificateType,
|
certificateType,
|
||||||
@ -219,28 +236,36 @@ $trustedRoot""", e, certPath, e.index)
|
|||||||
subject,
|
subject,
|
||||||
subjectPublicKey,
|
subjectPublicKey,
|
||||||
window,
|
window,
|
||||||
nameConstraints
|
nameConstraints,
|
||||||
|
crlDistPoint,
|
||||||
|
crlIssuer
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Build and sign an X.509 certificate with the given signer.
|
* 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 issuer name of the issuing entity.
|
||||||
* @param issuerSigner content signer to sign the certificate with.
|
* @param issuerSigner content signer to sign the certificate with.
|
||||||
* @param subject name of the certificate subject.
|
* @param subject name of the certificate subject.
|
||||||
* @param subjectPublicKey public key of the certificate subject.
|
* @param subjectPublicKey public key of the certificate subject.
|
||||||
* @param validityWindow the time period the certificate is valid for.
|
* @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 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,
|
fun createCertificate(certificateType: CertificateType,
|
||||||
issuer: X500Principal,
|
issuer: X500Principal,
|
||||||
|
issuerPublicKey: PublicKey,
|
||||||
issuerSigner: ContentSigner,
|
issuerSigner: ContentSigner,
|
||||||
subject: X500Principal,
|
subject: X500Principal,
|
||||||
subjectPublicKey: PublicKey,
|
subjectPublicKey: PublicKey,
|
||||||
validityWindow: Pair<Date, Date>,
|
validityWindow: Pair<Date, Date>,
|
||||||
nameConstraints: NameConstraints? = null): X509Certificate {
|
nameConstraints: NameConstraints? = null,
|
||||||
val builder = createPartialCertificate(certificateType, issuer, subject, subjectPublicKey, validityWindow, nameConstraints)
|
crlDistPoint: String? = null,
|
||||||
|
crlIssuer: X500Name? = null): X509Certificate {
|
||||||
|
val builder = createPartialCertificate(certificateType, issuer, issuerPublicKey, subject, subjectPublicKey, validityWindow, nameConstraints, crlDistPoint, crlIssuer)
|
||||||
return builder.build(issuerSigner).run {
|
return builder.build(issuerSigner).run {
|
||||||
require(isValidOn(Date()))
|
require(isValidOn(Date()))
|
||||||
toJca()
|
toJca()
|
||||||
@ -250,6 +275,7 @@ $trustedRoot""", e, certPath, e.index)
|
|||||||
/**
|
/**
|
||||||
* Build and sign an X.509 certificate with CA cert private key.
|
* 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 issuer name of the issuing entity.
|
||||||
* @param issuerKeyPair the public & private key to sign the certificate with.
|
* @param issuerKeyPair the public & private key to sign the certificate with.
|
||||||
* @param subject name of the certificate subject.
|
* @param subject name of the certificate subject.
|
||||||
@ -263,11 +289,21 @@ $trustedRoot""", e, certPath, e.index)
|
|||||||
subject: X500Principal,
|
subject: X500Principal,
|
||||||
subjectPublicKey: PublicKey,
|
subjectPublicKey: PublicKey,
|
||||||
validityWindow: Pair<Date, Date>,
|
validityWindow: Pair<Date, Date>,
|
||||||
nameConstraints: NameConstraints? = null): X509Certificate {
|
nameConstraints: NameConstraints? = null,
|
||||||
|
crlDistPoint: String? = null,
|
||||||
|
crlIssuer: X500Name? = null): X509Certificate {
|
||||||
val signatureScheme = Crypto.findSignatureScheme(issuerKeyPair.private)
|
val signatureScheme = Crypto.findSignatureScheme(issuerKeyPair.private)
|
||||||
val provider = Crypto.findProvider(signatureScheme.providerName)
|
val provider = Crypto.findProvider(signatureScheme.providerName)
|
||||||
val signer = ContentSignerBuilder.build(signatureScheme, issuerKeyPair.private, provider)
|
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 {
|
return builder.build(signer).run {
|
||||||
require(isValidOn(Date()))
|
require(isValidOn(Date()))
|
||||||
require(isSignatureValid(JcaContentVerifierProviderBuilder().build(issuerKeyPair.public)))
|
require(isSignatureValid(JcaContentVerifierProviderBuilder().build(issuerKeyPair.public)))
|
||||||
@ -312,6 +348,21 @@ $trustedRoot""", e, certPath, e.index)
|
|||||||
fun buildCertPath(certificates: List<X509Certificate>): CertPath {
|
fun buildCertPath(certificates: List<X509Certificate>): CertPath {
|
||||||
return X509CertificateFactory().generateCertPath(certificates)
|
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
|
// Assuming cert type to role is 1:1
|
||||||
|
@ -10,12 +10,8 @@
|
|||||||
|
|
||||||
package net.corda.nodeapi.internal.network
|
package net.corda.nodeapi.internal.network
|
||||||
|
|
||||||
import com.google.common.hash.Hashing
|
|
||||||
import com.google.common.hash.HashingInputStream
|
|
||||||
import com.typesafe.config.ConfigFactory
|
import com.typesafe.config.ConfigFactory
|
||||||
import net.corda.cordform.CordformNode
|
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.crypto.SecureHash.Companion.parse
|
||||||
import net.corda.core.identity.Party
|
import net.corda.core.identity.Party
|
||||||
import net.corda.core.internal.*
|
import net.corda.core.internal.*
|
||||||
@ -37,7 +33,6 @@ import net.corda.nodeapi.internal.serialization.SerializationFactoryImpl
|
|||||||
import net.corda.nodeapi.internal.serialization.amqp.AMQPServerSerializationScheme
|
import net.corda.nodeapi.internal.serialization.amqp.AMQPServerSerializationScheme
|
||||||
import net.corda.nodeapi.internal.serialization.kryo.AbstractKryoSerializationScheme
|
import net.corda.nodeapi.internal.serialization.kryo.AbstractKryoSerializationScheme
|
||||||
import net.corda.nodeapi.internal.serialization.kryo.kryoMagic
|
import net.corda.nodeapi.internal.serialization.kryo.kryoMagic
|
||||||
import java.io.File
|
|
||||||
import java.io.PrintStream
|
import java.io.PrintStream
|
||||||
import java.nio.file.Files
|
import java.nio.file.Files
|
||||||
import java.nio.file.Path
|
import java.nio.file.Path
|
||||||
@ -201,7 +196,7 @@ class NetworkBootstrapper {
|
|||||||
private fun generateWhitelist(whitelistFile: Path, excludeWhitelistFile: Path, cordapps: List<String>?): Map<String, List<AttachmentId>> {
|
private fun generateWhitelist(whitelistFile: Path, excludeWhitelistFile: Path, cordapps: List<String>?): Map<String, List<AttachmentId>> {
|
||||||
val existingWhitelist = if (whitelistFile.exists()) readContractWhitelist(whitelistFile) else emptyMap()
|
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()
|
val excludeContracts = if (excludeWhitelistFile.exists()) readExcludeWhitelist(excludeWhitelistFile) else emptyList()
|
||||||
if (excludeContracts.isNotEmpty()) {
|
if (excludeContracts.isNotEmpty()) {
|
||||||
@ -209,7 +204,7 @@ class NetworkBootstrapper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
val newWhiteList = cordapps?.flatMap { cordappJarPath ->
|
val newWhiteList = cordapps?.flatMap { cordappJarPath ->
|
||||||
val jarHash = getJarHash(cordappJarPath)
|
val jarHash = Paths.get(cordappJarPath).hash
|
||||||
scanJarForContracts(cordappJarPath).map { contract ->
|
scanJarForContracts(cordappJarPath).map { contract ->
|
||||||
contract to jarHash
|
contract to jarHash
|
||||||
}
|
}
|
||||||
@ -223,30 +218,26 @@ class NetworkBootstrapper {
|
|||||||
contractClassName to (if (newHash == null || newHash in existing) existing else existing + newHash)
|
contractClassName to (if (newHash == null || newHash in existing) existing else existing + newHash)
|
||||||
}.toMap()
|
}.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
|
return merged
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun overwriteWhitelist(whitelistFile: Path, mergedWhiteList: Map<String, List<AttachmentId>>) {
|
private fun overwriteWhitelist(whitelistFile: Path, mergedWhiteList: Map<String, List<AttachmentId>>) {
|
||||||
PrintStream(whitelistFile.toFile().outputStream()).use { out ->
|
PrintStream(whitelistFile.toFile().outputStream()).use { out ->
|
||||||
mergedWhiteList.forEach { (contract, attachments) ->
|
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 ->
|
private fun readContractWhitelist(file: Path): Map<String, List<AttachmentId>> {
|
||||||
val hs = HashingInputStream(Hashing.sha256(), jar)
|
return file.readAllLines()
|
||||||
hs.readBytes()
|
.map { line -> line.split(":") }
|
||||||
SecureHash.SHA256(hs.hash().asBytes())
|
.map { (contract, attachmentIds) ->
|
||||||
|
contract to (attachmentIds.split(",").map(::parse))
|
||||||
|
}.toMap()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun readContractWhitelist(file: Path): Map<String, List<AttachmentId>> = file.readAllLines()
|
|
||||||
.map { line -> line.split(":") }
|
|
||||||
.map { (contract, attachmentIds) ->
|
|
||||||
contract to (attachmentIds.split(",").map(::parse))
|
|
||||||
}.toMap()
|
|
||||||
|
|
||||||
private fun readExcludeWhitelist(file: Path): List<String> = file.readAllLines().map(String::trim)
|
private fun readExcludeWhitelist(file: Path): List<String> = file.readAllLines().map(String::trim)
|
||||||
|
|
||||||
private fun NotaryInfo.prettyPrint(): String = "${identity.name} (${if (validating) "" else "non-"}validating)"
|
private fun NotaryInfo.prettyPrint(): String = "${identity.name} (${if (validating) "" else "non-"}validating)"
|
||||||
|
@ -13,6 +13,7 @@ package net.corda.nodeapi.internal.serialization.amqp.custom
|
|||||||
import net.corda.core.contracts.Attachment
|
import net.corda.core.contracts.Attachment
|
||||||
import net.corda.core.contracts.ContractAttachment
|
import net.corda.core.contracts.ContractAttachment
|
||||||
import net.corda.core.contracts.ContractClassName
|
import net.corda.core.contracts.ContractClassName
|
||||||
|
import net.corda.core.internal.readFully
|
||||||
import net.corda.core.serialization.MissingAttachmentsException
|
import net.corda.core.serialization.MissingAttachmentsException
|
||||||
import net.corda.nodeapi.internal.serialization.GeneratedAttachment
|
import net.corda.nodeapi.internal.serialization.GeneratedAttachment
|
||||||
import net.corda.nodeapi.internal.serialization.amqp.CustomSerializer
|
import net.corda.nodeapi.internal.serialization.amqp.CustomSerializer
|
||||||
@ -27,7 +28,7 @@ class ContractAttachmentSerializer(factory: SerializerFactory) : CustomSerialize
|
|||||||
ContractAttachmentProxy::class.java, factory) {
|
ContractAttachmentProxy::class.java, factory) {
|
||||||
override fun toProxy(obj: ContractAttachment): ContractAttachmentProxy {
|
override fun toProxy(obj: ContractAttachment): ContractAttachmentProxy {
|
||||||
val bytes = try {
|
val bytes = try {
|
||||||
obj.attachment.open().readBytes()
|
obj.attachment.open().readFully()
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
throw MissingAttachmentsException(listOf(obj.id))
|
throw MissingAttachmentsException(listOf(obj.id))
|
||||||
}
|
}
|
||||||
|
@ -46,6 +46,6 @@ object InputStreamSerializer : CustomSerializer.Implements<InputStream>(InputStr
|
|||||||
|
|
||||||
override fun readObject(obj: Any, schemas: SerializationSchemas, input: DeserializationInput): InputStream {
|
override fun readObject(obj: Any, schemas: SerializationSchemas, input: DeserializationInput): InputStream {
|
||||||
val bits = input.readObject(obj, schemas, ByteArray::class.java) as ByteArray
|
val bits = input.readObject(obj, schemas, ByteArray::class.java) as ByteArray
|
||||||
return ByteArrayInputStream(bits)
|
return bits.inputStream()
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -28,6 +28,7 @@ import net.corda.core.crypto.CompositeKey
|
|||||||
import net.corda.core.crypto.SecureHash
|
import net.corda.core.crypto.SecureHash
|
||||||
import net.corda.core.identity.PartyAndCertificate
|
import net.corda.core.identity.PartyAndCertificate
|
||||||
import net.corda.core.internal.AbstractAttachment
|
import net.corda.core.internal.AbstractAttachment
|
||||||
|
import net.corda.core.internal.readFully
|
||||||
import net.corda.core.serialization.MissingAttachmentsException
|
import net.corda.core.serialization.MissingAttachmentsException
|
||||||
import net.corda.core.serialization.SerializationWhitelist
|
import net.corda.core.serialization.SerializationWhitelist
|
||||||
import net.corda.core.serialization.SerializeAsToken
|
import net.corda.core.serialization.SerializeAsToken
|
||||||
@ -233,7 +234,7 @@ object DefaultKryoCustomizer {
|
|||||||
val lazyAttachment = object : AbstractAttachment({
|
val lazyAttachment = object : AbstractAttachment({
|
||||||
val attachment = attachmentStorage.openAttachment(attachmentHash)
|
val attachment = attachmentStorage.openAttachment(attachmentHash)
|
||||||
?: throw MissingAttachmentsException(listOf(attachmentHash))
|
?: throw MissingAttachmentsException(listOf(attachmentHash))
|
||||||
attachment.open().readBytes()
|
attachment.open().readFully()
|
||||||
}) {
|
}) {
|
||||||
override val id = attachmentHash
|
override val id = attachmentHash
|
||||||
}
|
}
|
||||||
|
@ -39,7 +39,6 @@ import net.corda.nodeapi.internal.serialization.serializationContextKey
|
|||||||
import org.slf4j.Logger
|
import org.slf4j.Logger
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
import rx.Observable
|
import rx.Observable
|
||||||
import java.io.ByteArrayInputStream
|
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
import java.lang.reflect.InvocationTargetException
|
import java.lang.reflect.InvocationTargetException
|
||||||
import java.security.PrivateKey
|
import java.security.PrivateKey
|
||||||
@ -222,7 +221,7 @@ object InputStreamSerializer : Serializer<InputStream>() {
|
|||||||
System.arraycopy(chunk, 0, flattened, offset, chunk.size)
|
System.arraycopy(chunk, 0, flattened, offset, chunk.size)
|
||||||
offset += chunk.size
|
offset += chunk.size
|
||||||
}
|
}
|
||||||
return ByteArrayInputStream(flattened)
|
return flattened.inputStream()
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -76,5 +76,5 @@ internal fun Output.substitute(transform: (OutputStream) -> OutputStream) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
internal fun Input.substitute(transform: (InputStream) -> InputStream) {
|
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))
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,8 @@ package net.corda.nodeapi.internal
|
|||||||
|
|
||||||
import com.nhaarman.mockito_kotlin.doReturn
|
import com.nhaarman.mockito_kotlin.doReturn
|
||||||
import com.nhaarman.mockito_kotlin.whenever
|
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.crypto.SecureHash
|
||||||
import net.corda.core.identity.CordaX500Name
|
import net.corda.core.identity.CordaX500Name
|
||||||
import net.corda.core.internal.declaredField
|
import net.corda.core.internal.declaredField
|
||||||
@ -32,9 +33,9 @@ import net.corda.testing.common.internal.testNetworkParameters
|
|||||||
import net.corda.testing.core.DUMMY_NOTARY_NAME
|
import net.corda.testing.core.DUMMY_NOTARY_NAME
|
||||||
import net.corda.testing.core.SerializationEnvironmentRule
|
import net.corda.testing.core.SerializationEnvironmentRule
|
||||||
import net.corda.testing.core.TestIdentity
|
import net.corda.testing.core.TestIdentity
|
||||||
|
import net.corda.testing.internal.MockCordappConfigProvider
|
||||||
import net.corda.testing.internal.kryoSpecific
|
import net.corda.testing.internal.kryoSpecific
|
||||||
import net.corda.testing.internal.rigorousMock
|
import net.corda.testing.internal.rigorousMock
|
||||||
import net.corda.testing.internal.MockCordappConfigProvider
|
|
||||||
import net.corda.testing.services.MockAttachmentStorage
|
import net.corda.testing.services.MockAttachmentStorage
|
||||||
import org.apache.commons.io.IOUtils
|
import org.apache.commons.io.IOUtils
|
||||||
import org.junit.Assert.*
|
import org.junit.Assert.*
|
||||||
@ -137,8 +138,8 @@ class AttachmentsClassLoaderTests {
|
|||||||
fun `test overlapping file exception`() {
|
fun `test overlapping file exception`() {
|
||||||
val storage = attachments
|
val storage = attachments
|
||||||
val att0 = attachmentId
|
val att0 = attachmentId
|
||||||
val att1 = storage.importAttachment(ByteArrayInputStream(fakeAttachment("file.txt", "some data")))
|
val att1 = storage.importAttachment(fakeAttachment("file.txt", "some data").inputStream())
|
||||||
val att2 = storage.importAttachment(ByteArrayInputStream(fakeAttachment("file.txt", "some other data")))
|
val att2 = storage.importAttachment(fakeAttachment("file.txt", "some other data").inputStream())
|
||||||
|
|
||||||
assertFailsWith(AttachmentsClassLoader.OverlappingAttachments::class) {
|
assertFailsWith(AttachmentsClassLoader.OverlappingAttachments::class) {
|
||||||
AttachmentsClassLoader(arrayOf(att0, att1, att2).map { storage.openAttachment(it)!! })
|
AttachmentsClassLoader(arrayOf(att0, att1, att2).map { storage.openAttachment(it)!! })
|
||||||
@ -149,8 +150,8 @@ class AttachmentsClassLoaderTests {
|
|||||||
fun `basic`() {
|
fun `basic`() {
|
||||||
val storage = attachments
|
val storage = attachments
|
||||||
val att0 = attachmentId
|
val att0 = attachmentId
|
||||||
val att1 = storage.importAttachment(ByteArrayInputStream(fakeAttachment("file1.txt", "some data")))
|
val att1 = storage.importAttachment(fakeAttachment("file1.txt", "some data").inputStream())
|
||||||
val att2 = storage.importAttachment(ByteArrayInputStream(fakeAttachment("file2.txt", "some other data")))
|
val att2 = storage.importAttachment(fakeAttachment("file2.txt", "some other data").inputStream())
|
||||||
|
|
||||||
val cl = AttachmentsClassLoader(arrayOf(att0, att1, att2).map { storage.openAttachment(it)!! })
|
val cl = AttachmentsClassLoader(arrayOf(att0, att1, att2).map { storage.openAttachment(it)!! })
|
||||||
val txt = IOUtils.toString(cl.getResourceAsStream("file1.txt"), Charsets.UTF_8.name())
|
val txt = IOUtils.toString(cl.getResourceAsStream("file1.txt"), Charsets.UTF_8.name())
|
||||||
@ -161,8 +162,8 @@ class AttachmentsClassLoaderTests {
|
|||||||
fun `Check platform independent path handling in attachment jars`() {
|
fun `Check platform independent path handling in attachment jars`() {
|
||||||
val storage = MockAttachmentStorage()
|
val storage = MockAttachmentStorage()
|
||||||
|
|
||||||
val att1 = storage.importAttachment(ByteArrayInputStream(fakeAttachment("/folder1/foldera/file1.txt", "some data")))
|
val att1 = storage.importAttachment(fakeAttachment("/folder1/foldera/file1.txt", "some data").inputStream())
|
||||||
val att2 = storage.importAttachment(ByteArrayInputStream(fakeAttachment("\\folder1\\folderb\\file2.txt", "some other data")))
|
val att2 = storage.importAttachment(fakeAttachment("\\folder1\\folderb\\file2.txt", "some other data").inputStream())
|
||||||
|
|
||||||
val data1a = readAttachment(storage.openAttachment(att1)!!, "/folder1/foldera/file1.txt")
|
val data1a = readAttachment(storage.openAttachment(att1)!!, "/folder1/foldera/file1.txt")
|
||||||
assertArrayEquals("some data".toByteArray(), data1a)
|
assertArrayEquals("some data".toByteArray(), data1a)
|
||||||
@ -181,8 +182,8 @@ class AttachmentsClassLoaderTests {
|
|||||||
fun `loading class AnotherDummyContract`() {
|
fun `loading class AnotherDummyContract`() {
|
||||||
val storage = attachments
|
val storage = attachments
|
||||||
val att0 = attachmentId
|
val att0 = attachmentId
|
||||||
val att1 = storage.importAttachment(ByteArrayInputStream(fakeAttachment("file1.txt", "some data")))
|
val att1 = storage.importAttachment(fakeAttachment("file1.txt", "some data").inputStream())
|
||||||
val att2 = storage.importAttachment(ByteArrayInputStream(fakeAttachment("file2.txt", "some other data")))
|
val att2 = storage.importAttachment(fakeAttachment("file2.txt", "some other data").inputStream())
|
||||||
|
|
||||||
val cl = AttachmentsClassLoader(arrayOf(att0, att1, att2).map { storage.openAttachment(it)!! }, FilteringClassLoader)
|
val cl = AttachmentsClassLoader(arrayOf(att0, att1, att2).map { storage.openAttachment(it)!! }, FilteringClassLoader)
|
||||||
val contractClass = Class.forName(ISOLATED_CONTRACT_CLASS_NAME, true, cl)
|
val contractClass = Class.forName(ISOLATED_CONTRACT_CLASS_NAME, true, cl)
|
||||||
@ -205,8 +206,8 @@ class AttachmentsClassLoaderTests {
|
|||||||
val bytes = contract.serialize()
|
val bytes = contract.serialize()
|
||||||
val storage = attachments
|
val storage = attachments
|
||||||
val att0 = attachmentId
|
val att0 = attachmentId
|
||||||
val att1 = storage.importAttachment(ByteArrayInputStream(fakeAttachment("file1.txt", "some data")))
|
val att1 = storage.importAttachment(fakeAttachment("file1.txt", "some data").inputStream())
|
||||||
val att2 = storage.importAttachment(ByteArrayInputStream(fakeAttachment("file2.txt", "some other data")))
|
val att2 = storage.importAttachment(fakeAttachment("file2.txt", "some other data").inputStream())
|
||||||
|
|
||||||
val cl = AttachmentsClassLoader(arrayOf(att0, att1, att2).map { storage.openAttachment(it)!! }, FilteringClassLoader)
|
val cl = AttachmentsClassLoader(arrayOf(att0, att1, att2).map { storage.openAttachment(it)!! }, FilteringClassLoader)
|
||||||
|
|
||||||
@ -231,8 +232,8 @@ class AttachmentsClassLoaderTests {
|
|||||||
val bytes = data.serialize(context = context2)
|
val bytes = data.serialize(context = context2)
|
||||||
val storage = attachments
|
val storage = attachments
|
||||||
val att0 = attachmentId
|
val att0 = attachmentId
|
||||||
val att1 = storage.importAttachment(ByteArrayInputStream(fakeAttachment("file1.txt", "some data")))
|
val att1 = storage.importAttachment(fakeAttachment("file1.txt", "some data").inputStream())
|
||||||
val att2 = storage.importAttachment(ByteArrayInputStream(fakeAttachment("file2.txt", "some other data")))
|
val att2 = storage.importAttachment(fakeAttachment("file2.txt", "some other data").inputStream())
|
||||||
|
|
||||||
val cl = AttachmentsClassLoader(arrayOf(att0, att1, att2).map { storage.openAttachment(it)!! }, FilteringClassLoader)
|
val cl = AttachmentsClassLoader(arrayOf(att0, att1, att2).map { storage.openAttachment(it)!! }, FilteringClassLoader)
|
||||||
|
|
||||||
|
@ -30,9 +30,7 @@ import net.corda.testing.core.BOB_NAME
|
|||||||
import net.corda.testing.core.TestIdentity
|
import net.corda.testing.core.TestIdentity
|
||||||
import net.corda.testing.internal.createDevIntermediateCaCertPath
|
import net.corda.testing.internal.createDevIntermediateCaCertPath
|
||||||
import org.assertj.core.api.Assertions.assertThat
|
import org.assertj.core.api.Assertions.assertThat
|
||||||
import org.bouncycastle.asn1.x509.BasicConstraints
|
import org.bouncycastle.asn1.x509.*
|
||||||
import org.bouncycastle.asn1.x509.Extension
|
|
||||||
import org.bouncycastle.asn1.x509.KeyUsage
|
|
||||||
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
|
||||||
@ -113,6 +111,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
|
@Test
|
||||||
fun `storing EdDSA key in java keystore`() {
|
fun `storing EdDSA key in java keystore`() {
|
||||||
val tmpKeyStore = tempFile("keystore.jks")
|
val tmpKeyStore = tempFile("keystore.jks")
|
||||||
|
@ -53,7 +53,6 @@ import org.junit.Test
|
|||||||
import org.junit.runner.RunWith
|
import org.junit.runner.RunWith
|
||||||
import org.junit.runners.Parameterized
|
import org.junit.runners.Parameterized
|
||||||
import org.junit.runners.Parameterized.Parameters
|
import org.junit.runners.Parameterized.Parameters
|
||||||
import java.io.ByteArrayInputStream
|
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.io.NotSerializableException
|
import java.io.NotSerializableException
|
||||||
import java.math.BigDecimal
|
import java.math.BigDecimal
|
||||||
@ -1093,9 +1092,9 @@ class SerializationOutputTests(private val compression: CordaSerializationEncodi
|
|||||||
val factory2 = SerializerFactory(AllWhitelist, ClassLoader.getSystemClassLoader())
|
val factory2 = SerializerFactory(AllWhitelist, ClassLoader.getSystemClassLoader())
|
||||||
factory2.register(net.corda.nodeapi.internal.serialization.amqp.custom.InputStreamSerializer)
|
factory2.register(net.corda.nodeapi.internal.serialization.amqp.custom.InputStreamSerializer)
|
||||||
val bytes = ByteArray(10) { it.toByte() }
|
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 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.available(), obj2.available())
|
||||||
assertEquals(obj3.read(), obj2.read())
|
assertEquals(obj3.read(), obj2.read())
|
||||||
}
|
}
|
||||||
|
@ -39,7 +39,6 @@ import org.junit.runner.RunWith
|
|||||||
import org.junit.runners.Parameterized
|
import org.junit.runners.Parameterized
|
||||||
import org.junit.runners.Parameterized.Parameters
|
import org.junit.runners.Parameterized.Parameters
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
import java.io.ByteArrayInputStream
|
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
import java.util.*
|
import java.util.*
|
||||||
@ -200,7 +199,11 @@ class KryoTests(private val compression: CordaSerializationEncoding?) {
|
|||||||
@Test
|
@Test
|
||||||
fun `HashCheckingStream (de)serialize`() {
|
fun `HashCheckingStream (de)serialize`() {
|
||||||
val rubbish = ByteArray(12345, { (it * it * 0.12345).toByte() })
|
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) {
|
for (i in 0..12344) {
|
||||||
assertEquals(rubbish[i], readRubbishStream.read().toByte())
|
assertEquals(rubbish[i], readRubbishStream.read().toByte())
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,7 @@ package net.corda.node.utilities.registration
|
|||||||
import net.corda.core.identity.CordaX500Name
|
import net.corda.core.identity.CordaX500Name
|
||||||
import net.corda.core.internal.concurrent.transpose
|
import net.corda.core.internal.concurrent.transpose
|
||||||
import net.corda.core.internal.logElapsedTime
|
import net.corda.core.internal.logElapsedTime
|
||||||
|
import net.corda.core.internal.readFully
|
||||||
import net.corda.core.messaging.startFlow
|
import net.corda.core.messaging.startFlow
|
||||||
import net.corda.core.utilities.*
|
import net.corda.core.utilities.*
|
||||||
import net.corda.finance.DOLLARS
|
import net.corda.finance.DOLLARS
|
||||||
@ -143,7 +144,7 @@ class RegistrationHandler(private val rootCertAndKeyPair: CertificateAndKeyPair)
|
|||||||
@Produces(MediaType.TEXT_PLAIN)
|
@Produces(MediaType.TEXT_PLAIN)
|
||||||
fun registration(input: InputStream): Response {
|
fun registration(input: InputStream): Response {
|
||||||
return log.logElapsedTime("Registration") {
|
return log.logElapsedTime("Registration") {
|
||||||
val certificationRequest = input.use { JcaPKCS10CertificationRequest(it.readBytes()) }
|
val certificationRequest = JcaPKCS10CertificationRequest(input.readFully())
|
||||||
val (certPath, name) = createSignedClientCertificate(
|
val (certPath, name) = createSignedClientCertificate(
|
||||||
certificationRequest,
|
certificationRequest,
|
||||||
rootCertAndKeyPair.keyPair,
|
rootCertAndKeyPair.keyPair,
|
||||||
|
@ -15,6 +15,7 @@ import net.corda.core.crypto.SecureHash
|
|||||||
import net.corda.core.crypto.toStringShort
|
import net.corda.core.crypto.toStringShort
|
||||||
import net.corda.core.identity.*
|
import net.corda.core.identity.*
|
||||||
import net.corda.core.internal.CertRole
|
import net.corda.core.internal.CertRole
|
||||||
|
import net.corda.core.internal.hash
|
||||||
import net.corda.core.node.services.UnknownAnonymousPartyException
|
import net.corda.core.node.services.UnknownAnonymousPartyException
|
||||||
import net.corda.core.serialization.SingletonSerializeAsToken
|
import net.corda.core.serialization.SingletonSerializeAsToken
|
||||||
import net.corda.core.utilities.MAX_HASH_HEX_SIZE
|
import net.corda.core.utilities.MAX_HASH_HEX_SIZE
|
||||||
@ -72,7 +73,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)
|
private fun mapToKey(party: PartyAndCertificate) = mapToKey(party.owningKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,6 +50,7 @@ fun freshCertificate(identityService: IdentityService,
|
|||||||
val ourCertificate = X509Utilities.createCertificate(
|
val ourCertificate = X509Utilities.createCertificate(
|
||||||
CertificateType.CONFIDENTIAL_LEGAL_IDENTITY,
|
CertificateType.CONFIDENTIAL_LEGAL_IDENTITY,
|
||||||
issuerCert.subjectX500Principal,
|
issuerCert.subjectX500Principal,
|
||||||
|
issuerCert.publicKey,
|
||||||
issuerSigner,
|
issuerSigner,
|
||||||
issuer.name.x500Principal,
|
issuer.name.x500Principal,
|
||||||
subjectPublicKey,
|
subjectPublicKey,
|
||||||
|
@ -21,9 +21,11 @@ import net.corda.core.contracts.Attachment
|
|||||||
import net.corda.core.contracts.ContractAttachment
|
import net.corda.core.contracts.ContractAttachment
|
||||||
import net.corda.core.contracts.ContractClassName
|
import net.corda.core.contracts.ContractClassName
|
||||||
import net.corda.core.crypto.SecureHash
|
import net.corda.core.crypto.SecureHash
|
||||||
|
import net.corda.core.crypto.sha256
|
||||||
import net.corda.core.internal.AbstractAttachment
|
import net.corda.core.internal.AbstractAttachment
|
||||||
import net.corda.core.internal.UNKNOWN_UPLOADER
|
import net.corda.core.internal.UNKNOWN_UPLOADER
|
||||||
import net.corda.core.internal.VisibleForTesting
|
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.AttachmentId
|
||||||
import net.corda.core.node.services.AttachmentStorage
|
import net.corda.core.node.services.AttachmentStorage
|
||||||
import net.corda.core.node.services.vault.AttachmentQueryCriteria
|
import net.corda.core.node.services.vault.AttachmentQueryCriteria
|
||||||
@ -37,7 +39,10 @@ import net.corda.node.utilities.NonInvalidatingWeightBasedCache
|
|||||||
import net.corda.nodeapi.internal.persistence.NODE_DATABASE_PREFIX
|
import net.corda.nodeapi.internal.persistence.NODE_DATABASE_PREFIX
|
||||||
import net.corda.nodeapi.internal.persistence.currentDBSession
|
import net.corda.nodeapi.internal.persistence.currentDBSession
|
||||||
import net.corda.nodeapi.internal.withContractsInJar
|
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.nio.file.Paths
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
import java.util.*
|
import java.util.*
|
||||||
@ -272,14 +277,6 @@ class NodeAttachmentService(
|
|||||||
return import(jar, uploader, filename)
|
return import(jar, uploader, filename)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getAttachmentIdAndBytes(jar: InputStream): Pair<AttachmentId, ByteArray> {
|
|
||||||
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 =
|
override fun hasAttachment(attachmentId: AttachmentId): Boolean =
|
||||||
currentDBSession().find(NodeAttachmentService.DBAttachment::class.java, attachmentId.toString()) != null
|
currentDBSession().find(NodeAttachmentService.DBAttachment::class.java, attachmentId.toString()) != null
|
||||||
|
|
||||||
@ -288,15 +285,16 @@ class NodeAttachmentService(
|
|||||||
return withContractsInJar(jar) { contractClassNames, inputStream ->
|
return withContractsInJar(jar) { contractClassNames, inputStream ->
|
||||||
require(inputStream !is JarInputStream)
|
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.
|
// 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
|
// 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
|
// 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.
|
// 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)) {
|
if (!hasAttachment(id)) {
|
||||||
checkIsAValidJAR(ByteArrayInputStream(bytes))
|
checkIsAValidJAR(bytes.inputStream())
|
||||||
val session = currentDBSession()
|
val session = currentDBSession()
|
||||||
val attachment = NodeAttachmentService.DBAttachment(attId = id.toString(), content = bytes, uploader = uploader, filename = filename, contractClassNames = contractClassNames)
|
val attachment = NodeAttachmentService.DBAttachment(attId = id.toString(), content = bytes, uploader = uploader, filename = filename, contractClassNames = contractClassNames)
|
||||||
session.save(attachment)
|
session.save(attachment)
|
||||||
|
@ -45,24 +45,26 @@ import net.corda.finance.contracts.asset.Cash
|
|||||||
import net.corda.finance.flows.TwoPartyTradeFlow.Buyer
|
import net.corda.finance.flows.TwoPartyTradeFlow.Buyer
|
||||||
import net.corda.finance.flows.TwoPartyTradeFlow.Seller
|
import net.corda.finance.flows.TwoPartyTradeFlow.Seller
|
||||||
import net.corda.node.internal.StartedNode
|
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.IdentityServiceInternal
|
||||||
|
import net.corda.node.services.api.WritableTransactionStorage
|
||||||
import net.corda.node.services.persistence.DBTransactionStorage
|
import net.corda.node.services.persistence.DBTransactionStorage
|
||||||
import net.corda.node.services.persistence.checkpoints
|
import net.corda.node.services.persistence.checkpoints
|
||||||
import net.corda.nodeapi.internal.persistence.CordaPersistence
|
import net.corda.nodeapi.internal.persistence.CordaPersistence
|
||||||
import net.corda.testing.core.*
|
import net.corda.testing.core.*
|
||||||
import net.corda.testing.internal.LogHelper
|
|
||||||
import net.corda.testing.dsl.LedgerDSL
|
import net.corda.testing.dsl.LedgerDSL
|
||||||
import net.corda.testing.dsl.TestLedgerDSLInterpreter
|
import net.corda.testing.dsl.TestLedgerDSLInterpreter
|
||||||
import net.corda.testing.dsl.TestTransactionDSLInterpreter
|
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.TEST_TX_TIME
|
||||||
import net.corda.testing.internal.rigorousMock
|
import net.corda.testing.internal.rigorousMock
|
||||||
import net.corda.testing.internal.vault.VaultFiller
|
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.InternalMockNetwork
|
||||||
import net.corda.testing.node.internal.InternalMockNodeParameters
|
import net.corda.testing.node.internal.InternalMockNodeParameters
|
||||||
import net.corda.testing.node.internal.pumpReceive
|
import net.corda.testing.node.internal.pumpReceive
|
||||||
import net.corda.testing.node.internal.startFlow
|
import net.corda.testing.node.internal.startFlow
|
||||||
|
import net.corda.testing.node.ledger
|
||||||
import org.assertj.core.api.Assertions.assertThat
|
import org.assertj.core.api.Assertions.assertThat
|
||||||
import org.junit.After
|
import org.junit.After
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
@ -70,7 +72,6 @@ import org.junit.Test
|
|||||||
import org.junit.runner.RunWith
|
import org.junit.runner.RunWith
|
||||||
import org.junit.runners.Parameterized
|
import org.junit.runners.Parameterized
|
||||||
import rx.Observable
|
import rx.Observable
|
||||||
import java.io.ByteArrayInputStream
|
|
||||||
import java.io.ByteArrayOutputStream
|
import java.io.ByteArrayOutputStream
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import java.util.jar.JarOutputStream
|
import java.util.jar.JarOutputStream
|
||||||
@ -357,7 +358,7 @@ class TwoPartyTradeFlowTests(private val anonymous: Boolean) {
|
|||||||
it.closeEntry()
|
it.closeEntry()
|
||||||
}
|
}
|
||||||
val attachmentID = aliceNode.database.transaction {
|
val attachmentID = aliceNode.database.transaction {
|
||||||
attachment(ByteArrayInputStream(stream.toByteArray()))
|
attachment(stream.toByteArray().inputStream())
|
||||||
}
|
}
|
||||||
|
|
||||||
val bobsFakeCash = bobNode.database.transaction {
|
val bobsFakeCash = bobNode.database.transaction {
|
||||||
@ -461,7 +462,7 @@ class TwoPartyTradeFlowTests(private val anonymous: Boolean) {
|
|||||||
it.closeEntry()
|
it.closeEntry()
|
||||||
}
|
}
|
||||||
val attachmentID = aliceNode.database.transaction {
|
val attachmentID = aliceNode.database.transaction {
|
||||||
attachment(ByteArrayInputStream(stream.toByteArray()))
|
attachment(stream.toByteArray().inputStream())
|
||||||
}
|
}
|
||||||
|
|
||||||
val bobsKey = bobNode.services.keyManagementService.keys.single()
|
val bobsKey = bobNode.services.keyManagementService.keys.single()
|
||||||
|
@ -15,10 +15,7 @@ import com.google.common.jimfs.Configuration
|
|||||||
import com.google.common.jimfs.Jimfs
|
import com.google.common.jimfs.Jimfs
|
||||||
import net.corda.core.crypto.SecureHash
|
import net.corda.core.crypto.SecureHash
|
||||||
import net.corda.core.crypto.sha256
|
import net.corda.core.crypto.sha256
|
||||||
import net.corda.core.internal.read
|
import net.corda.core.internal.*
|
||||||
import net.corda.core.internal.readAll
|
|
||||||
import net.corda.core.internal.write
|
|
||||||
import net.corda.core.internal.writeLines
|
|
||||||
import net.corda.core.node.services.vault.AttachmentQueryCriteria
|
import net.corda.core.node.services.vault.AttachmentQueryCriteria
|
||||||
import net.corda.core.node.services.vault.AttachmentSort
|
import net.corda.core.node.services.vault.AttachmentSort
|
||||||
import net.corda.core.node.services.vault.Builder
|
import net.corda.core.node.services.vault.Builder
|
||||||
@ -240,7 +237,7 @@ class NodeAttachmentStorageTest {
|
|||||||
database.transaction {
|
database.transaction {
|
||||||
val storage = NodeAttachmentService(MetricRegistry())
|
val storage = NodeAttachmentService(MetricRegistry())
|
||||||
val e = assertFailsWith<NodeAttachmentService.HashMismatchException> {
|
val e = assertFailsWith<NodeAttachmentService.HashMismatchException> {
|
||||||
storage.openAttachment(id)!!.open().use { it.readBytes() }
|
storage.openAttachment(id)!!.open().readFully()
|
||||||
}
|
}
|
||||||
assertEquals(e.expected, id)
|
assertEquals(e.expected, id)
|
||||||
|
|
||||||
|
@ -12,14 +12,14 @@ package net.corda.testing.node.internal.network
|
|||||||
|
|
||||||
import net.corda.core.crypto.SecureHash
|
import net.corda.core.crypto.SecureHash
|
||||||
import net.corda.core.crypto.SignedData
|
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.node.NodeInfo
|
||||||
import net.corda.core.serialization.deserialize
|
|
||||||
import net.corda.core.serialization.serialize
|
import net.corda.core.serialization.serialize
|
||||||
import net.corda.core.utilities.NetworkHostAndPort
|
import net.corda.core.utilities.NetworkHostAndPort
|
||||||
import net.corda.nodeapi.internal.SignedNodeInfo
|
import net.corda.nodeapi.internal.SignedNodeInfo
|
||||||
import net.corda.nodeapi.internal.createDevNetworkMapCa
|
import net.corda.nodeapi.internal.createDevNetworkMapCa
|
||||||
import net.corda.nodeapi.internal.crypto.CertificateAndKeyPair
|
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.NetworkMap
|
||||||
import net.corda.nodeapi.internal.network.ParametersUpdate
|
import net.corda.nodeapi.internal.network.ParametersUpdate
|
||||||
import org.eclipse.jetty.server.Server
|
import org.eclipse.jetty.server.Server
|
||||||
@ -120,7 +120,7 @@ class NetworkMapServer(private val pollInterval: Duration,
|
|||||||
@Consumes(MediaType.APPLICATION_OCTET_STREAM)
|
@Consumes(MediaType.APPLICATION_OCTET_STREAM)
|
||||||
fun publishNodeInfo(input: InputStream): Response {
|
fun publishNodeInfo(input: InputStream): Response {
|
||||||
return try {
|
return try {
|
||||||
val signedNodeInfo = input.readBytes().deserialize<SignedNodeInfo>()
|
val signedNodeInfo = input.readObject<SignedNodeInfo>()
|
||||||
signedNodeInfo.verified()
|
signedNodeInfo.verified()
|
||||||
nodeInfoMap[signedNodeInfo.raw.hash] = signedNodeInfo
|
nodeInfoMap[signedNodeInfo.raw.hash] = signedNodeInfo
|
||||||
ok()
|
ok()
|
||||||
@ -136,7 +136,7 @@ class NetworkMapServer(private val pollInterval: Duration,
|
|||||||
@Path("ack-parameters")
|
@Path("ack-parameters")
|
||||||
@Consumes(MediaType.APPLICATION_OCTET_STREAM)
|
@Consumes(MediaType.APPLICATION_OCTET_STREAM)
|
||||||
fun ackNetworkParameters(input: InputStream): Response {
|
fun ackNetworkParameters(input: InputStream): Response {
|
||||||
val signedParametersHash = input.readBytes().deserialize<SignedData<SecureHash>>()
|
val signedParametersHash = input.readObject<SignedData<SecureHash>>()
|
||||||
val hash = signedParametersHash.verified()
|
val hash = signedParametersHash.verified()
|
||||||
latestAcceptedParametersMap[signedParametersHash.sig.by] = hash
|
latestAcceptedParametersMap[signedParametersHash.sig.by] = hash
|
||||||
return ok().build()
|
return ok().build()
|
||||||
|
@ -17,13 +17,13 @@ import net.corda.core.crypto.SecureHash
|
|||||||
import net.corda.core.crypto.sha256
|
import net.corda.core.crypto.sha256
|
||||||
import net.corda.core.internal.AbstractAttachment
|
import net.corda.core.internal.AbstractAttachment
|
||||||
import net.corda.core.internal.UNKNOWN_UPLOADER
|
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.AttachmentId
|
||||||
import net.corda.core.node.services.AttachmentStorage
|
import net.corda.core.node.services.AttachmentStorage
|
||||||
import net.corda.core.node.services.vault.AttachmentQueryCriteria
|
import net.corda.core.node.services.vault.AttachmentQueryCriteria
|
||||||
import net.corda.core.node.services.vault.AttachmentSort
|
import net.corda.core.node.services.vault.AttachmentSort
|
||||||
import net.corda.core.serialization.SingletonSerializeAsToken
|
import net.corda.core.serialization.SingletonSerializeAsToken
|
||||||
import net.corda.nodeapi.internal.withContractsInJar
|
import net.corda.nodeapi.internal.withContractsInJar
|
||||||
import java.io.ByteArrayOutputStream
|
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import java.util.jar.JarInputStream
|
import java.util.jar.JarInputStream
|
||||||
@ -63,7 +63,7 @@ class MockAttachmentStorage : AttachmentStorage, SingletonSerializeAsToken() {
|
|||||||
|
|
||||||
fun importContractAttachment(contractClassNames: List<ContractClassName>, uploader: String, jar: InputStream): AttachmentId = importAttachmentInternal(jar, uploader, null, contractClassNames)
|
fun importContractAttachment(contractClassNames: List<ContractClassName>, uploader: String, jar: InputStream): AttachmentId = importAttachmentInternal(jar, uploader, null, contractClassNames)
|
||||||
|
|
||||||
fun getAttachmentIdAndBytes(jar: InputStream): Pair<AttachmentId, ByteArray> = jar.readBytes().let { bytes -> Pair(bytes.sha256(), bytes) }
|
fun getAttachmentIdAndBytes(jar: InputStream): Pair<AttachmentId, ByteArray> = jar.readFully().let { bytes -> Pair(bytes.sha256(), bytes) }
|
||||||
|
|
||||||
private class MockAttachment(dataLoader: () -> ByteArray, override val id: SecureHash) : AbstractAttachment(dataLoader)
|
private class MockAttachment(dataLoader: () -> ByteArray, override val id: SecureHash) : AbstractAttachment(dataLoader)
|
||||||
|
|
||||||
@ -71,7 +71,7 @@ class MockAttachmentStorage : AttachmentStorage, SingletonSerializeAsToken() {
|
|||||||
// JIS makes read()/readBytes() return bytes of the current file, but we want to hash the entire container here.
|
// JIS makes read()/readBytes() return bytes of the current file, but we want to hash the entire container here.
|
||||||
require(jar !is JarInputStream)
|
require(jar !is JarInputStream)
|
||||||
|
|
||||||
val bytes = jar.readBytes()
|
val bytes = jar.readFully()
|
||||||
|
|
||||||
val sha256 = bytes.sha256()
|
val sha256 = bytes.sha256()
|
||||||
if (sha256 !in files.keys) {
|
if (sha256 !in files.keys) {
|
||||||
|
Loading…
Reference in New Issue
Block a user