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()
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
/**
* 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))
}

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
import net.corda.core.crypto.*
import net.corda.core.identity.Party
import net.corda.core.identity.PartyAndCertificate
import org.bouncycastle.asn1.x500.X500Name
import java.math.BigInteger
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)) }
/** 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)) }
/** 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)) }
/** 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)) }
/** 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)) }
/** 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)) }
/** 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)) }
/** 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)) }
/** 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)) }
/** 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 com.zaxxer.hikari.HikariConfig
import com.zaxxer.hikari.HikariDataSource
import net.corda.core.crypto.CompositeKey
import net.corda.core.crypto.SecureHash
import net.corda.core.crypto.parsePublicKeyBase58
import net.corda.core.crypto.toBase58String
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.transactions.TransactionInterface
import org.jetbrains.exposed.sql.transactions.TransactionManager
@ -16,8 +17,12 @@ import rx.Subscriber
import rx.subjects.PublishSubject
import rx.subjects.Subject
import rx.subjects.UnicastSubject
import java.io.ByteArrayInputStream
import java.io.Closeable
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.time.Instant
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.
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 TxnNoteColumns(val txId: Column<SecureHash>, val note: Column<String>)
/**
* [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.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.localDate(name: String) = this.registerColumn<LocalDate>(name, LocalDateColumnType)
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.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].
*/

View File

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

View File

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