mirror of
https://github.com/corda/corda.git
synced 2025-02-03 09:41:10 +00:00
Add DER format encoding for CompositeKey
Add extremely rough DER format encoding for CompositeKey so that they can be used in X.509 certificates, and switch service identity generator to using the proper identity cert for signing.
This commit is contained in:
parent
155bb029da
commit
b7bec90fae
@ -1,7 +1,9 @@
|
|||||||
package net.corda.core.crypto
|
package net.corda.core.crypto
|
||||||
|
|
||||||
|
import net.corda.core.crypto.CompositeKey.NodeAndWeight
|
||||||
import net.corda.core.serialization.CordaSerializable
|
import net.corda.core.serialization.CordaSerializable
|
||||||
import net.corda.core.serialization.serialize
|
import org.bouncycastle.asn1.*
|
||||||
|
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo
|
||||||
import java.security.PublicKey
|
import java.security.PublicKey
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -35,20 +37,24 @@ class CompositeKey private constructor (val threshold: Int,
|
|||||||
* Holds node - weight pairs for a CompositeKey. Ordered first by weight, then by node's hashCode.
|
* Holds node - weight pairs for a CompositeKey. Ordered first by weight, then by node's hashCode.
|
||||||
*/
|
*/
|
||||||
@CordaSerializable
|
@CordaSerializable
|
||||||
data class NodeAndWeight(val node: PublicKey, val weight: Int): Comparable<NodeAndWeight> {
|
data class NodeAndWeight(val node: PublicKey, val weight: Int): Comparable<NodeAndWeight>, ASN1Object() {
|
||||||
override fun compareTo(other: NodeAndWeight): Int {
|
override fun compareTo(other: NodeAndWeight): Int {
|
||||||
if (weight == other.weight) {
|
if (weight == other.weight) {
|
||||||
return node.hashCode().compareTo(other.node.hashCode())
|
return node.hashCode().compareTo(other.node.hashCode())
|
||||||
}
|
}
|
||||||
else return weight.compareTo(other.weight)
|
else return weight.compareTo(other.weight)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun toASN1Primitive(): ASN1Primitive {
|
||||||
|
val vector = ASN1EncodableVector()
|
||||||
|
vector.add(DERBitString(node.encoded))
|
||||||
|
vector.add(ASN1Integer(weight.toLong()))
|
||||||
|
return DERSequence(vector)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
// TODO: Get the design standardised and from there define a recognised name
|
val ALGORITHM = CompositeSignature.ALGORITHM_IDENTIFIER.algorithm.toString()
|
||||||
val ALGORITHM = "X-Corda-CompositeKey"
|
|
||||||
// TODO: We should be using a well defined format.
|
|
||||||
val FORMAT = "X-Corda-Kryo"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -57,8 +63,17 @@ class CompositeKey private constructor (val threshold: Int,
|
|||||||
fun isFulfilledBy(key: PublicKey) = isFulfilledBy(setOf(key))
|
fun isFulfilledBy(key: PublicKey) = isFulfilledBy(setOf(key))
|
||||||
|
|
||||||
override fun getAlgorithm() = ALGORITHM
|
override fun getAlgorithm() = ALGORITHM
|
||||||
override fun getEncoded(): ByteArray = this.serialize().bytes
|
override fun getEncoded(): ByteArray {
|
||||||
override fun getFormat() = FORMAT
|
val keyVector = ASN1EncodableVector()
|
||||||
|
val childrenVector = ASN1EncodableVector()
|
||||||
|
children.forEach {
|
||||||
|
childrenVector.add(it.toASN1Primitive())
|
||||||
|
}
|
||||||
|
keyVector.add(ASN1Integer(threshold.toLong()))
|
||||||
|
keyVector.add(DERSequence(childrenVector))
|
||||||
|
return SubjectPublicKeyInfo(CompositeSignature.ALGORITHM_IDENTIFIER, DERSequence(keyVector)).encoded
|
||||||
|
}
|
||||||
|
override fun getFormat() = ASN1Encoding.DER
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function checks if the public keys corresponding to the signatures are matched against the leaves of the composite
|
* Function checks if the public keys corresponding to the signatures are matched against the leaves of the composite
|
||||||
|
@ -1,9 +1,6 @@
|
|||||||
package net.corda.node.utilities
|
package net.corda.node.utilities
|
||||||
|
|
||||||
import net.corda.core.crypto.CertificateAndKeyPair
|
import net.corda.core.crypto.*
|
||||||
import net.corda.core.crypto.CompositeKey
|
|
||||||
import net.corda.core.crypto.X509Utilities
|
|
||||||
import net.corda.core.crypto.generateKeyPair
|
|
||||||
import net.corda.core.identity.PartyAndCertificate
|
import net.corda.core.identity.PartyAndCertificate
|
||||||
import net.corda.core.serialization.serialize
|
import net.corda.core.serialization.serialize
|
||||||
import net.corda.core.serialization.storageKryo
|
import net.corda.core.serialization.storageKryo
|
||||||
@ -12,6 +9,7 @@ import net.corda.core.utilities.trace
|
|||||||
import org.bouncycastle.asn1.x500.X500Name
|
import org.bouncycastle.asn1.x500.X500Name
|
||||||
import java.nio.file.Files
|
import java.nio.file.Files
|
||||||
import java.nio.file.Path
|
import java.nio.file.Path
|
||||||
|
import java.security.cert.*
|
||||||
|
|
||||||
object ServiceIdentityGenerator {
|
object ServiceIdentityGenerator {
|
||||||
private val log = loggerFor<ServiceIdentityGenerator>()
|
private val log = loggerFor<ServiceIdentityGenerator>()
|
||||||
@ -36,15 +34,20 @@ object ServiceIdentityGenerator {
|
|||||||
log.trace { "Generating a group identity \"serviceName\" for nodes: ${dirs.joinToString()}" }
|
log.trace { "Generating a group identity \"serviceName\" for nodes: ${dirs.joinToString()}" }
|
||||||
val keyPairs = (1..dirs.size).map { generateKeyPair() }
|
val keyPairs = (1..dirs.size).map { generateKeyPair() }
|
||||||
val notaryKey = CompositeKey.Builder().addKeys(keyPairs.map { it.public }).build(threshold)
|
val notaryKey = CompositeKey.Builder().addKeys(keyPairs.map { it.public }).build(threshold)
|
||||||
// TODO: This doesn't work until we have composite keys in X.509 certificates, so we make up a certificate that nothing checks
|
val notaryCert = X509Utilities.createCertificate(CertificateType.INTERMEDIATE_CA, serviceCa.certificate,
|
||||||
// val notaryCert = X509Utilities.createCertificate(CertificateType.IDENTITY, serviceCa.certificate,
|
serviceCa.keyPair, serviceName, notaryKey)
|
||||||
// serviceCa.keyPair, serviceName, notaryKey)
|
|
||||||
val notaryCert = X509Utilities.createSelfSignedCACertificate(serviceName, generateKeyPair())
|
|
||||||
val notaryCertPath = X509Utilities.createCertificatePath(serviceCa.certificate, notaryCert, revocationEnabled = false)
|
val notaryCertPath = X509Utilities.createCertificatePath(serviceCa.certificate, notaryCert, revocationEnabled = false)
|
||||||
val notaryParty = PartyAndCertificate(serviceName, notaryKey, notaryCert, notaryCertPath)
|
val notaryParty = PartyAndCertificate(serviceName, notaryKey, notaryCert, notaryCertPath)
|
||||||
val notaryPartyBytes = notaryParty.serialize()
|
val notaryPartyBytes = notaryParty.serialize()
|
||||||
val privateKeyFile = "$serviceId-private-key"
|
val privateKeyFile = "$serviceId-private-key"
|
||||||
val publicKeyFile = "$serviceId-public"
|
val publicKeyFile = "$serviceId-public"
|
||||||
|
|
||||||
|
// Sanity check the certificate and path
|
||||||
|
val validatorParameters = PKIXParameters(setOf(TrustAnchor(serviceCa.certificate.cert, null)))
|
||||||
|
val validator = CertPathValidator.getInstance("PKIX")
|
||||||
|
validatorParameters.isRevocationEnabled = false
|
||||||
|
validator.validate(notaryCertPath, validatorParameters) as PKIXCertPathValidatorResult
|
||||||
|
|
||||||
keyPairs.zip(dirs) { keyPair, dir ->
|
keyPairs.zip(dirs) { keyPair, dir ->
|
||||||
Files.createDirectories(dir)
|
Files.createDirectories(dir)
|
||||||
notaryPartyBytes.writeToFile(dir.resolve(publicKeyFile))
|
notaryPartyBytes.writeToFile(dir.resolve(publicKeyFile))
|
||||||
|
Loading…
x
Reference in New Issue
Block a user