Merge pull request #3 from corda/feature/ENT-2506/change_signers_type

ENT-2506 Changes signers field type
This commit is contained in:
Tudor Malene 2018-09-19 11:07:29 +01:00 committed by GitHub
commit 7902d758bd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 47 additions and 37 deletions

View File

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

View File

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

View File

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

View File

@ -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.

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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