mirror of
https://github.com/corda/corda.git
synced 2024-12-24 07:06:44 +00:00
Merge pull request #3 from corda/feature/ENT-2506/change_signers_type
ENT-2506 Changes signers field type
This commit is contained in:
commit
7902d758bd
@ -429,7 +429,7 @@ public static final class net.corda.core.contracts.AmountTransfer$Companion exte
|
||||
public interface net.corda.core.contracts.Attachment extends net.corda.core.contracts.NamedByHash
|
||||
public void extractFile(String, java.io.OutputStream)
|
||||
@NotNull
|
||||
public abstract java.util.List<net.corda.core.identity.Party> getSigners()
|
||||
public abstract java.util.List<java.security.PublicKey> getSigners()
|
||||
public abstract int getSize()
|
||||
@NotNull
|
||||
public abstract java.io.InputStream open()
|
||||
@ -540,7 +540,7 @@ public final class net.corda.core.contracts.ContractAttachment extends java.lang
|
||||
@NotNull
|
||||
public net.corda.core.crypto.SecureHash getId()
|
||||
@NotNull
|
||||
public java.util.List<net.corda.core.identity.Party> getSigners()
|
||||
public java.util.List<java.security.PublicKey> getSigners()
|
||||
public int getSize()
|
||||
@Nullable
|
||||
public final String getUploader()
|
||||
|
@ -3,13 +3,13 @@ package net.corda.deterministic.common
|
||||
import net.corda.core.contracts.Attachment
|
||||
import net.corda.core.contracts.ContractClassName
|
||||
import net.corda.core.crypto.SecureHash
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.serialization.CordaSerializable
|
||||
import java.io.ByteArrayInputStream
|
||||
import java.io.InputStream
|
||||
import java.security.PublicKey
|
||||
|
||||
@CordaSerializable
|
||||
class MockContractAttachment(override val id: SecureHash = SecureHash.zeroHash, val contract: ContractClassName, override val signers: List<Party> = ArrayList()) : Attachment {
|
||||
class MockContractAttachment(override val id: SecureHash = SecureHash.zeroHash, val contract: ContractClassName, override val signers: List<PublicKey> = emptyList()) : Attachment {
|
||||
override fun open(): InputStream = ByteArrayInputStream(id.bytes)
|
||||
override val size = id.size
|
||||
}
|
||||
|
@ -42,8 +42,8 @@ class AttachmentTest {
|
||||
attachment = object : Attachment {
|
||||
override val id: SecureHash
|
||||
get() = SecureHash.allOnesHash
|
||||
override val signers: List<Party>
|
||||
get() = listOf(ALICE)
|
||||
override val signers: List<PublicKey>
|
||||
get() = listOf(ALICE_KEY)
|
||||
override val size: Int
|
||||
get() = jarData.size
|
||||
|
||||
|
@ -7,6 +7,7 @@ import net.corda.core.serialization.CordaSerializable
|
||||
import java.io.FileNotFoundException
|
||||
import java.io.InputStream
|
||||
import java.io.OutputStream
|
||||
import java.security.PublicKey
|
||||
import java.util.jar.JarInputStream
|
||||
|
||||
/**
|
||||
@ -51,10 +52,10 @@ interface Attachment : NamedByHash {
|
||||
fun extractFile(path: String, outputTo: OutputStream) = openAsJAR().use { it.extractFile(path, outputTo) }
|
||||
|
||||
/**
|
||||
* The parties that have correctly signed the whole attachment.
|
||||
* The keys that have correctly signed the whole attachment.
|
||||
* Can be empty, for example non-contract attachments won't be necessarily be signed.
|
||||
*/
|
||||
val signers: List<Party>
|
||||
val signers: List<PublicKey>
|
||||
|
||||
/**
|
||||
* Attachment size in bytes.
|
||||
|
@ -82,5 +82,5 @@ data class SignatureAttachmentConstraint(
|
||||
val key: PublicKey
|
||||
) : AttachmentConstraint {
|
||||
override fun isSatisfiedBy(attachment: Attachment): Boolean =
|
||||
key.isFulfilledBy(attachment.signers.map { it.owningKey })
|
||||
key.isFulfilledBy(attachment.signers.map { it })
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
@file:KeepForDJVM
|
||||
|
||||
package net.corda.core.internal
|
||||
|
||||
import net.corda.core.DeleteForDJVM
|
||||
@ -11,6 +12,7 @@ import java.io.FileNotFoundException
|
||||
import java.io.IOException
|
||||
import java.io.InputStream
|
||||
import java.io.OutputStream
|
||||
import java.security.PublicKey
|
||||
import java.util.jar.JarInputStream
|
||||
|
||||
const val DEPLOYED_CORDAPP_UPLOADER = "app"
|
||||
@ -40,8 +42,8 @@ abstract class AbstractAttachment(dataLoader: () -> ByteArray) : Attachment {
|
||||
override val size: Int get() = attachmentData.size
|
||||
|
||||
override fun open(): InputStream = attachmentData.inputStream()
|
||||
override val signers by lazy {
|
||||
openAsJAR().use(JarSignatureCollector::collectSigningParties)
|
||||
override val signers: List<PublicKey> by lazy {
|
||||
openAsJAR().use(JarSignatureCollector::collectSigners)
|
||||
}
|
||||
|
||||
override fun equals(other: Any?) = other === this || other is Attachment && other.id == this.id
|
||||
|
@ -2,6 +2,7 @@ package net.corda.core.internal
|
||||
|
||||
import net.corda.core.identity.Party
|
||||
import java.security.CodeSigner
|
||||
import java.security.PublicKey
|
||||
import java.security.cert.X509Certificate
|
||||
import java.util.jar.JarEntry
|
||||
import java.util.jar.JarInputStream
|
||||
@ -20,7 +21,7 @@ object JarSignatureCollector {
|
||||
* @param jar The open [JarInputStream] to collect signing parties from.
|
||||
* @throws InvalidJarSignersException If the signer sets for any two signable items are different from each other.
|
||||
*/
|
||||
fun collectSigningParties(jar: JarInputStream): List<Party> {
|
||||
fun collectSigners(jar: JarInputStream): List<PublicKey> {
|
||||
val signerSets = jar.fileSignerSets
|
||||
if (signerSets.isEmpty()) return emptyList()
|
||||
|
||||
@ -28,14 +29,14 @@ object JarSignatureCollector {
|
||||
for ((otherFile, otherSignerSet) in signerSets.subList(1, signerSets.size)) {
|
||||
if (otherSignerSet != firstSignerSet) throw InvalidJarSignersException(
|
||||
"""
|
||||
Mismatch between signers ${firstSignerSet.toPartiesOrderedByName()} for file $firstFile
|
||||
and signers ${otherSignerSet.toPartiesOrderedByName()} for file ${otherFile}.
|
||||
Mismatch between signers ${firstSignerSet.toOrderedPublicKeys()} for file $firstFile
|
||||
and signers ${otherSignerSet.toOrderedPublicKeys()} for file ${otherFile}.
|
||||
See https://docs.corda.net/design/data-model-upgrades/signature-constraints.html for details of the
|
||||
constraints applied to attachment signatures.
|
||||
""".trimIndent().replace('\n', ' '))
|
||||
}
|
||||
|
||||
return firstSignerSet.toPartiesOrderedByName()
|
||||
return firstSignerSet.toOrderedPublicKeys()
|
||||
}
|
||||
|
||||
private val JarInputStream.fileSignerSets: List<Pair<String, Set<CodeSigner>>> get() =
|
||||
@ -56,9 +57,9 @@ object JarSignatureCollector {
|
||||
private fun Sequence<JarEntry>.toFileSignerSet(): Sequence<Pair<String, Set<CodeSigner>>> =
|
||||
map { entry -> entry.name to (entry.codeSigners?.toSet() ?: emptySet()) }
|
||||
|
||||
private fun Set<CodeSigner>.toPartiesOrderedByName(): List<Party> = map {
|
||||
Party(it.signerCertPath.certificates[0] as X509Certificate)
|
||||
}.sortedBy { it.name.toString() } // Sorted for determinism.
|
||||
private fun Set<CodeSigner>.toOrderedPublicKeys(): List<PublicKey> = map {
|
||||
(it.signerCertPath.certificates[0] as X509Certificate).publicKey
|
||||
}.sortedBy { it.hash} // Sorted for determinism.
|
||||
|
||||
private val JarInputStream.entries get(): Sequence<JarEntry> = generateSequence(nextJarEntry) { nextJarEntry }
|
||||
}
|
||||
|
@ -163,8 +163,8 @@ open class TransactionBuilder @JvmOverloads constructor(
|
||||
}
|
||||
}
|
||||
|
||||
private fun makeSignatureAttachmentConstraint(attachmentSigners: List<Party>) =
|
||||
SignatureAttachmentConstraint(CompositeKey.Builder().addKeys(attachmentSigners.map { it.owningKey }).build())
|
||||
private fun makeSignatureAttachmentConstraint(attachmentSigners: List<PublicKey>) =
|
||||
SignatureAttachmentConstraint(CompositeKey.Builder().addKeys(attachmentSigners.map { it }).build())
|
||||
|
||||
private fun useWhitelistedByZoneAttachmentConstraint(contractClassName: ContractClassName, networkParameters: NetworkParameters) =
|
||||
contractClassName in networkParameters.whitelistedContractImplementations.keys
|
||||
|
@ -2,6 +2,7 @@ package net.corda.core.internal
|
||||
|
||||
import net.corda.core.identity.CordaX500Name
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.nodeapi.internal.crypto.loadKeyStore
|
||||
import net.corda.testing.core.ALICE_NAME
|
||||
import net.corda.testing.core.BOB_NAME
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
@ -13,6 +14,7 @@ import java.io.FileInputStream
|
||||
import java.nio.file.Files
|
||||
import java.nio.file.Path
|
||||
import java.nio.file.Paths
|
||||
import java.security.PublicKey
|
||||
import java.util.jar.JarInputStream
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertFailsWith
|
||||
@ -60,7 +62,7 @@ class JarSignatureCollectorTest {
|
||||
}
|
||||
}
|
||||
|
||||
private val List<Party>.names get() = map { it.name }
|
||||
private val List<Party>.keys get() = map { it.owningKey }
|
||||
|
||||
@After
|
||||
fun tearDown() {
|
||||
@ -92,33 +94,33 @@ class JarSignatureCollectorTest {
|
||||
@Test
|
||||
fun `one signer`() {
|
||||
createJar("_signable1", "_signable2")
|
||||
signAsAlice()
|
||||
assertEquals(listOf(ALICE_NAME), getJarSigners().names) // We only reused ALICE's distinguished name, so the keys will be different.
|
||||
val key = signAsAlice()
|
||||
assertEquals(listOf(key), getJarSigners())
|
||||
|
||||
(dir / "my-dir").createDirectory()
|
||||
updateJar("my-dir")
|
||||
assertEquals(listOf(ALICE_NAME), getJarSigners().names) // Unsigned directory is irrelevant.
|
||||
assertEquals(listOf(key), getJarSigners()) // Unsigned directory is irrelevant.
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `two signers`() {
|
||||
createJar("_signable1", "_signable2")
|
||||
signAsAlice()
|
||||
signAsBob()
|
||||
val key1 = signAsAlice()
|
||||
val key2 = signAsBob()
|
||||
|
||||
assertEquals(listOf(ALICE_NAME, BOB_NAME), getJarSigners().names)
|
||||
assertEquals(setOf(key1, key2), getJarSigners().toSet())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `all files must be signed by the same set of signers`() {
|
||||
createJar("_signable1")
|
||||
signAsAlice()
|
||||
assertEquals(listOf(ALICE_NAME), getJarSigners().names)
|
||||
val key1 = signAsAlice()
|
||||
assertEquals(listOf(key1), getJarSigners())
|
||||
|
||||
updateJar("_signable2")
|
||||
signAsBob()
|
||||
assertFailsWith<InvalidJarSignersException>(
|
||||
"""
|
||||
"""
|
||||
Mismatch between signers [O=Alice Corp, L=Madrid, C=ES, O=Bob Plc, L=Rome, C=IT] for file _signable1
|
||||
and signers [O=Bob Plc, L=Rome, C=IT] for file _signable2.
|
||||
See https://docs.corda.net/design/data-model-upgrades/signature-constraints.html for details of the
|
||||
@ -131,8 +133,8 @@ class JarSignatureCollectorTest {
|
||||
fun `bad signature is caught even if the party would not qualify as a signer`() {
|
||||
(dir / "volatile").writeLines(listOf("volatile"))
|
||||
createJar("volatile")
|
||||
signAsAlice()
|
||||
assertEquals(listOf(ALICE_NAME), getJarSigners().names)
|
||||
val key1 = signAsAlice()
|
||||
assertEquals(listOf(key1), getJarSigners())
|
||||
|
||||
(dir / "volatile").writeLines(listOf("garbage"))
|
||||
updateJar("volatile", "_signable1") // ALICE's signature on volatile is now bad.
|
||||
@ -148,14 +150,17 @@ class JarSignatureCollectorTest {
|
||||
private fun updateJar(vararg contents: String) =
|
||||
execute(*(arrayOf("jar", "uvf", FILENAME) + contents))
|
||||
|
||||
private fun signJar(alias: String, password: String) =
|
||||
execute("jarsigner", "-keystore", "_teststore", "-storepass", "storepass", "-keypass", password, FILENAME, alias)
|
||||
private fun signJar(alias: String, password: String): PublicKey {
|
||||
execute("jarsigner", "-keystore", "_teststore", "-storepass", "storepass", "-keypass", password, FILENAME, alias)
|
||||
val ks = loadKeyStore(dir.resolve("_teststore"), "storepass")
|
||||
return ks.getCertificate(alias).publicKey
|
||||
}
|
||||
|
||||
private fun signAsAlice() = signJar(ALICE, ALICE_PASS)
|
||||
private fun signAsBob() = signJar(BOB, BOB_PASS)
|
||||
|
||||
private fun getJarSigners() =
|
||||
JarInputStream(FileInputStream((dir / FILENAME).toFile())).use(JarSignatureCollector::collectSigningParties)
|
||||
JarInputStream(FileInputStream((dir / FILENAME).toFile())).use(JarSignatureCollector::collectSigners)
|
||||
//endregion
|
||||
|
||||
}
|
||||
|
@ -23,6 +23,7 @@ import org.junit.Assert.assertTrue
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import java.security.PublicKey
|
||||
|
||||
class TransactionBuilderTest {
|
||||
@Rule
|
||||
@ -119,12 +120,12 @@ class TransactionBuilderTest {
|
||||
private val unsignedAttachment = object : AbstractAttachment({ byteArrayOf() }) {
|
||||
override val id: SecureHash get() = throw UnsupportedOperationException()
|
||||
|
||||
override val signers: List<Party> get() = emptyList()
|
||||
override val signers: List<PublicKey> get() = emptyList()
|
||||
}
|
||||
|
||||
private fun signedAttachment(vararg parties: Party) = object : AbstractAttachment({ byteArrayOf() }) {
|
||||
override val id: SecureHash get() = throw UnsupportedOperationException()
|
||||
|
||||
override val signers: List<Party> get() = parties.toList()
|
||||
override val signers: List<PublicKey> get() = parties.map { it.owningKey }
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user