mirror of
https://github.com/corda/corda.git
synced 2024-12-20 21:43:14 +00:00
Add PartyAndCertificate class
Add PartyAndCertificate class for pairing proof of a party's identity with the party.
This commit is contained in:
parent
b6dbd6bbb5
commit
0e1e4042dc
@ -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))
|
||||||
}
|
}
|
@ -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)
|
@ -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)
|
||||||
|
}
|
@ -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].
|
||||||
*/
|
*/
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
@ -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>()
|
||||||
|
Loading…
Reference in New Issue
Block a user