Add PartyAndCertificate class

Add PartyAndCertificate class for pairing proof of a party's identity with the party.
This commit is contained in:
Ross Nicoll 2017-05-31 09:45:40 +01:00 committed by GitHub
parent b6dbd6bbb5
commit 0e1e4042dc
6 changed files with 104 additions and 17 deletions

View File

@ -18,6 +18,15 @@ abstract class AbstractParty(val owningKey: PublicKey) {
override fun hashCode(): Int = owningKey.hashCode() override fun hashCode(): Int = owningKey.hashCode()
abstract fun nameOrNull(): X500Name? abstract fun nameOrNull(): X500Name?
/**
* Build a reference to something being stored or issued by a party e.g. in a vault or (more likely) on their normal
* ledger.
*/
abstract fun ref(bytes: OpaqueBytes): PartyAndReference abstract fun ref(bytes: OpaqueBytes): PartyAndReference
/**
* Build a reference to something being stored or issued by a party e.g. in a vault or (more likely) on their normal
* ledger.
*/
fun ref(vararg bytes: Byte) = ref(OpaqueBytes.of(*bytes)) fun ref(vararg bytes: Byte) = ref(OpaqueBytes.of(*bytes))
} }

View File

@ -0,0 +1,16 @@
package net.corda.core.identity
import net.corda.core.contracts.PartyAndReference
import net.corda.core.serialization.OpaqueBytes
import org.bouncycastle.asn1.x500.X500Name
import org.bouncycastle.cert.X509CertificateHolder
import java.security.PublicKey
import java.security.cert.CertPath
import java.security.cert.X509Certificate
/**
* A full party plus the X.509 certificate and path linking the party back to a trust root.
*/
class PartyAndCertificate(name: X500Name, owningKey: PublicKey,
val certificate: X509CertificateHolder,
val certPath: CertPath) : Party(name, owningKey)

View File

@ -3,7 +3,7 @@
package net.corda.core.utilities package net.corda.core.utilities
import net.corda.core.crypto.* import net.corda.core.crypto.*
import net.corda.core.identity.Party import net.corda.core.identity.PartyAndCertificate
import org.bouncycastle.asn1.x500.X500Name import org.bouncycastle.asn1.x500.X500Name
import java.math.BigInteger import java.math.BigInteger
import java.security.KeyPair import java.security.KeyPair
@ -21,36 +21,52 @@ val DUMMY_KEY_2: KeyPair by lazy { generateKeyPair() }
val DUMMY_NOTARY_KEY: KeyPair by lazy { entropyToKeyPair(BigInteger.valueOf(20)) } val DUMMY_NOTARY_KEY: KeyPair by lazy { entropyToKeyPair(BigInteger.valueOf(20)) }
/** Dummy notary identity for tests and simulations */ /** Dummy notary identity for tests and simulations */
val DUMMY_NOTARY: Party get() = Party(X500Name("CN=Notary Service,O=R3,OU=corda,L=Zurich,C=CH"), DUMMY_NOTARY_KEY.public) val DUMMY_NOTARY: PartyAndCertificate get() = getTestPartyAndCertificate(X500Name("CN=Notary Service,O=R3,OU=corda,L=Zurich,C=CH"), DUMMY_NOTARY_KEY.public)
val DUMMY_MAP_KEY: KeyPair by lazy { entropyToKeyPair(BigInteger.valueOf(30)) } val DUMMY_MAP_KEY: KeyPair by lazy { entropyToKeyPair(BigInteger.valueOf(30)) }
/** Dummy network map service identity for tests and simulations */ /** Dummy network map service identity for tests and simulations */
val DUMMY_MAP: Party get() = Party(X500Name("CN=Network Map Service,O=R3,OU=corda,L=Amsterdam,C=NL"), DUMMY_MAP_KEY.public) val DUMMY_MAP: PartyAndCertificate get() = getTestPartyAndCertificate(X500Name("CN=Network Map Service,O=R3,OU=corda,L=Amsterdam,C=NL"), DUMMY_MAP_KEY.public)
val DUMMY_BANK_A_KEY: KeyPair by lazy { entropyToKeyPair(BigInteger.valueOf(40)) } val DUMMY_BANK_A_KEY: KeyPair by lazy { entropyToKeyPair(BigInteger.valueOf(40)) }
/** Dummy bank identity for tests and simulations */ /** Dummy bank identity for tests and simulations */
val DUMMY_BANK_A: Party get() = Party(X500Name("CN=Bank A,O=Bank A,L=London,C=UK"), DUMMY_BANK_A_KEY.public) val DUMMY_BANK_A: PartyAndCertificate get() = getTestPartyAndCertificate(X500Name("CN=Bank A,O=Bank A,L=London,C=UK"), DUMMY_BANK_A_KEY.public)
val DUMMY_BANK_B_KEY: KeyPair by lazy { entropyToKeyPair(BigInteger.valueOf(50)) } val DUMMY_BANK_B_KEY: KeyPair by lazy { entropyToKeyPair(BigInteger.valueOf(50)) }
/** Dummy bank identity for tests and simulations */ /** Dummy bank identity for tests and simulations */
val DUMMY_BANK_B: Party get() = Party(X500Name("CN=Bank B,O=Bank B,L=New York,C=US"), DUMMY_BANK_B_KEY.public) val DUMMY_BANK_B: PartyAndCertificate get() = getTestPartyAndCertificate(X500Name("CN=Bank B,O=Bank B,L=New York,C=US"), DUMMY_BANK_B_KEY.public)
val DUMMY_BANK_C_KEY: KeyPair by lazy { entropyToKeyPair(BigInteger.valueOf(60)) } val DUMMY_BANK_C_KEY: KeyPair by lazy { entropyToKeyPair(BigInteger.valueOf(60)) }
/** Dummy bank identity for tests and simulations */ /** Dummy bank identity for tests and simulations */
val DUMMY_BANK_C: Party get() = Party(X500Name("CN=Bank C,O=Bank C,L=Tokyo,C=JP"), DUMMY_BANK_C_KEY.public) val DUMMY_BANK_C: PartyAndCertificate get() = getTestPartyAndCertificate(X500Name("CN=Bank C,O=Bank C,L=Tokyo,C=JP"), DUMMY_BANK_C_KEY.public)
val ALICE_KEY: KeyPair by lazy { entropyToKeyPair(BigInteger.valueOf(70)) } val ALICE_KEY: KeyPair by lazy { entropyToKeyPair(BigInteger.valueOf(70)) }
/** Dummy individual identity for tests and simulations */ /** Dummy individual identity for tests and simulations */
val ALICE: Party get() = Party(X500Name("CN=Alice Corp,O=Alice Corp,L=London,C=UK"), ALICE_KEY.public) val ALICE: PartyAndCertificate get() = getTestPartyAndCertificate(X500Name("CN=Alice Corp,O=Alice Corp,L=London,C=UK"), ALICE_KEY.public)
val BOB_KEY: KeyPair by lazy { entropyToKeyPair(BigInteger.valueOf(80)) } val BOB_KEY: KeyPair by lazy { entropyToKeyPair(BigInteger.valueOf(80)) }
/** Dummy individual identity for tests and simulations */ /** Dummy individual identity for tests and simulations */
val BOB: Party get() = Party(X500Name("CN=Bob Plc,O=Bob Plc,L=London,C=UK"), BOB_KEY.public) val BOB: PartyAndCertificate get() = getTestPartyAndCertificate(X500Name("CN=Bob Plc,O=Bob Plc,L=London,C=UK"), BOB_KEY.public)
val CHARLIE_KEY: KeyPair by lazy { entropyToKeyPair(BigInteger.valueOf(90)) } val CHARLIE_KEY: KeyPair by lazy { entropyToKeyPair(BigInteger.valueOf(90)) }
/** Dummy individual identity for tests and simulations */ /** Dummy individual identity for tests and simulations */
val CHARLIE: Party get() = Party(X500Name("CN=Charlie Ltd,O=Charlie Ltd,L=London,C=UK"), CHARLIE_KEY.public) val CHARLIE: PartyAndCertificate get() = getTestPartyAndCertificate(X500Name("CN=Charlie Ltd,O=Charlie Ltd,L=London,C=UK"), CHARLIE_KEY.public)
val DUMMY_REGULATOR_KEY: KeyPair by lazy { entropyToKeyPair(BigInteger.valueOf(100)) } val DUMMY_REGULATOR_KEY: KeyPair by lazy { entropyToKeyPair(BigInteger.valueOf(100)) }
/** Dummy regulator for tests and simulations */ /** Dummy regulator for tests and simulations */
val DUMMY_REGULATOR: Party get() = Party(X500Name("CN=Regulator A,OU=Corda,O=AMF,L=Paris,C=FR"), DUMMY_REGULATOR_KEY.public) val DUMMY_REGULATOR: PartyAndCertificate get() = getTestPartyAndCertificate(X500Name("CN=Regulator A,OU=Corda,O=AMF,L=Paris,C=FR"), DUMMY_REGULATOR_KEY.public)
val DUMMY_CA_KEY: KeyPair by lazy { entropyToKeyPair(BigInteger.valueOf(110)) }
val DUMMY_CA: CertificateAndKeyPair by lazy {
// TODO: Should be identity scheme
val cert = X509Utilities.createSelfSignedCACertificate(X500Name("CN=Dummy CA,OU=Corda,O=R3 Ltd,L=London,C=UK"), DUMMY_CA_KEY)
CertificateAndKeyPair(cert, DUMMY_CA_KEY)
}
/**
* Build a test party with a nonsense certificate authority for testing purposes.
*/
fun getTestPartyAndCertificate(name: X500Name, publicKey: PublicKey): PartyAndCertificate {
val cert = X509Utilities.createCertificate(CertificateType.IDENTITY, DUMMY_CA.certificate, DUMMY_CA.keyPair, name, publicKey)
val certPath = X509Utilities.createCertificatePath(DUMMY_CA.certificate, cert, revocationEnabled = false)
return PartyAndCertificate(name, publicKey, cert, certPath)
}

View File

@ -3,11 +3,12 @@ package net.corda.node.utilities
import co.paralleluniverse.strands.Strand import co.paralleluniverse.strands.Strand
import com.zaxxer.hikari.HikariConfig import com.zaxxer.hikari.HikariConfig
import com.zaxxer.hikari.HikariDataSource import com.zaxxer.hikari.HikariDataSource
import net.corda.core.crypto.CompositeKey
import net.corda.core.crypto.SecureHash import net.corda.core.crypto.SecureHash
import net.corda.core.crypto.parsePublicKeyBase58 import net.corda.core.crypto.parsePublicKeyBase58
import net.corda.core.crypto.toBase58String import net.corda.core.crypto.toBase58String
import net.corda.node.utilities.StrandLocalTransactionManager.Boundary import net.corda.node.utilities.StrandLocalTransactionManager.Boundary
import org.bouncycastle.cert.X509CertificateHolder
import org.h2.jdbc.JdbcBlob
import org.jetbrains.exposed.sql.* import org.jetbrains.exposed.sql.*
import org.jetbrains.exposed.sql.transactions.TransactionInterface import org.jetbrains.exposed.sql.transactions.TransactionInterface
import org.jetbrains.exposed.sql.transactions.TransactionManager import org.jetbrains.exposed.sql.transactions.TransactionManager
@ -16,8 +17,12 @@ import rx.Subscriber
import rx.subjects.PublishSubject import rx.subjects.PublishSubject
import rx.subjects.Subject import rx.subjects.Subject
import rx.subjects.UnicastSubject import rx.subjects.UnicastSubject
import java.io.ByteArrayInputStream
import java.io.Closeable import java.io.Closeable
import java.security.PublicKey import java.security.PublicKey
import java.security.cert.CertPath
import java.security.cert.CertificateFactory
import java.security.cert.X509Certificate
import java.sql.Connection import java.sql.Connection
import java.time.Instant import java.time.Instant
import java.time.LocalDate import java.time.LocalDate
@ -264,15 +269,25 @@ fun <T : Any> rx.Observable<T>.wrapWithDatabaseTransaction(db: Database? = null)
// Composite columns for use with below Exposed helpers. // Composite columns for use with below Exposed helpers.
data class PartyColumns(val name: Column<String>, val owningKey: Column<PublicKey>) data class PartyColumns(val name: Column<String>, val owningKey: Column<PublicKey>)
data class PartyAndCertificateColumns(val name: Column<String>, val owningKey: Column<PublicKey>,
val certificate: Column<X509CertificateHolder>, val certPath: Column<CertPath>)
data class StateRefColumns(val txId: Column<SecureHash>, val index: Column<Int>) data class StateRefColumns(val txId: Column<SecureHash>, val index: Column<Int>)
data class TxnNoteColumns(val txId: Column<SecureHash>, val note: Column<String>) data class TxnNoteColumns(val txId: Column<SecureHash>, val note: Column<String>)
/** /**
* [Table] column helpers for use with Exposed, as per [varchar] etc. * [Table] column helpers for use with Exposed, as per [varchar] etc.
*/ */
fun Table.certificate(name: String) = this.registerColumn<X509CertificateHolder>(name, X509CertificateColumnType)
fun Table.certificatePath(name: String) = this.registerColumn<CertPath>(name, CertPathColumnType)
fun Table.publicKey(name: String) = this.registerColumn<PublicKey>(name, PublicKeyColumnType) fun Table.publicKey(name: String) = this.registerColumn<PublicKey>(name, PublicKeyColumnType)
fun Table.secureHash(name: String) = this.registerColumn<SecureHash>(name, SecureHashColumnType) fun Table.secureHash(name: String) = this.registerColumn<SecureHash>(name, SecureHashColumnType)
fun Table.party(nameColumnName: String, keyColumnName: String) = PartyColumns(this.varchar(nameColumnName, length = 255), this.publicKey(keyColumnName)) fun Table.party(nameColumnName: String,
keyColumnName: String) = PartyColumns(this.varchar(nameColumnName, length = 255), this.publicKey(keyColumnName))
fun Table.partyAndCertificate(nameColumnName: String,
keyColumnName: String,
certificateColumnName: String,
pathColumnName: String) = PartyAndCertificateColumns(this.varchar(nameColumnName, length = 255), this.publicKey(keyColumnName),
this.certificate(certificateColumnName), this.certificatePath(pathColumnName))
fun Table.uuidString(name: String) = this.registerColumn<UUID>(name, UUIDStringColumnType) fun Table.uuidString(name: String) = this.registerColumn<UUID>(name, UUIDStringColumnType)
fun Table.localDate(name: String) = this.registerColumn<LocalDate>(name, LocalDateColumnType) fun Table.localDate(name: String) = this.registerColumn<LocalDate>(name, LocalDateColumnType)
fun Table.localDateTime(name: String) = this.registerColumn<LocalDateTime>(name, LocalDateTimeColumnType) fun Table.localDateTime(name: String) = this.registerColumn<LocalDateTime>(name, LocalDateTimeColumnType)
@ -280,6 +295,35 @@ fun Table.instant(name: String) = this.registerColumn<Instant>(name, InstantColu
fun Table.stateRef(txIdColumnName: String, indexColumnName: String) = StateRefColumns(this.secureHash(txIdColumnName), this.integer(indexColumnName)) fun Table.stateRef(txIdColumnName: String, indexColumnName: String) = StateRefColumns(this.secureHash(txIdColumnName), this.integer(indexColumnName))
fun Table.txnNote(txIdColumnName: String, txnNoteColumnName: String) = TxnNoteColumns(this.secureHash(txIdColumnName), this.text(txnNoteColumnName)) fun Table.txnNote(txIdColumnName: String, txnNoteColumnName: String) = TxnNoteColumns(this.secureHash(txIdColumnName), this.text(txnNoteColumnName))
/**
* [ColumnType] for marshalling to/from database on behalf of [X509CertificateHolder].
*/
object X509CertificateColumnType : ColumnType() {
override fun sqlType(): String = "BLOB"
override fun valueFromDB(value: Any): Any {
val blob = value as JdbcBlob
return X509CertificateHolder(blob.getBytes(0, blob.length().toInt()))
}
override fun notNullValueToDB(value: Any): Any = (value as X509CertificateHolder).encoded
}
/**
* [ColumnType] for marshalling to/from database on behalf of [CertPath].
*/
object CertPathColumnType : ColumnType() {
private val factory = CertificateFactory.getInstance("X.509")
override fun sqlType(): String = "BLOB"
override fun valueFromDB(value: Any): Any {
val blob = value as JdbcBlob
return factory.generateCertPath(ByteArrayInputStream(blob.getBytes(0, blob.length().toInt())))
}
override fun notNullValueToDB(value: Any): Any = (value as CertPath).encoded
}
/** /**
* [ColumnType] for marshalling to/from database on behalf of [PublicKey]. * [ColumnType] for marshalling to/from database on behalf of [PublicKey].
*/ */

View File

@ -24,13 +24,13 @@ class InMemoryIdentityServiceTests {
val service = InMemoryIdentityService() val service = InMemoryIdentityService()
assertNull(service.getAllIdentities().firstOrNull()) assertNull(service.getAllIdentities().firstOrNull())
service.registerIdentity(ALICE) service.registerIdentity(ALICE)
var expected = setOf(ALICE) var expected = setOf<Party>(ALICE)
var actual = service.getAllIdentities().toHashSet() var actual = service.getAllIdentities().toHashSet()
assertEquals(expected, actual) assertEquals(expected, actual)
// Add a second party and check we get both back // Add a second party and check we get both back
service.registerIdentity(BOB) service.registerIdentity(BOB)
expected = setOf(ALICE, BOB) expected = setOf<Party>(ALICE, BOB)
actual = service.getAllIdentities().toHashSet() actual = service.getAllIdentities().toHashSet()
assertEquals(expected, actual) assertEquals(expected, actual)
} }

View File

@ -1,24 +1,26 @@
package net.corda.testing.node package net.corda.testing.node
import co.paralleluniverse.common.util.VisibleForTesting import co.paralleluniverse.common.util.VisibleForTesting
import net.corda.core.crypto.DummyPublicKey import net.corda.core.crypto.entropyToKeyPair
import net.corda.core.identity.Party import net.corda.core.identity.Party
import net.corda.core.messaging.SingleMessageRecipient import net.corda.core.messaging.SingleMessageRecipient
import net.corda.core.node.NodeInfo import net.corda.core.node.NodeInfo
import net.corda.core.node.services.NetworkMapCache import net.corda.core.node.services.NetworkMapCache
import net.corda.core.utilities.getTestPartyAndCertificate
import net.corda.node.services.network.InMemoryNetworkMapCache import net.corda.node.services.network.InMemoryNetworkMapCache
import net.corda.testing.MOCK_VERSION_INFO import net.corda.testing.MOCK_VERSION_INFO
import net.corda.testing.getTestX509Name import net.corda.testing.getTestX509Name
import rx.Observable import rx.Observable
import rx.subjects.PublishSubject import rx.subjects.PublishSubject
import java.math.BigInteger
/** /**
* Network map cache with no backing map service. * Network map cache with no backing map service.
*/ */
class MockNetworkMapCache : InMemoryNetworkMapCache() { class MockNetworkMapCache : InMemoryNetworkMapCache() {
private companion object { private companion object {
val BANK_C = Party(getTestX509Name("Bank C"), DummyPublicKey("Bank C")) val BANK_C = getTestPartyAndCertificate(getTestX509Name("Bank C"), entropyToKeyPair(BigInteger.valueOf(1000)).public)
val BANK_D = Party(getTestX509Name("Bank D"), DummyPublicKey("Bank D")) val BANK_D = getTestPartyAndCertificate(getTestX509Name("Bank D"), entropyToKeyPair(BigInteger.valueOf(2000)).public)
} }
override val changed: Observable<NetworkMapCache.MapChange> = PublishSubject.create<NetworkMapCache.MapChange>() override val changed: Observable<NetworkMapCache.MapChange> = PublishSubject.create<NetworkMapCache.MapChange>()