mirror of
https://github.com/corda/corda.git
synced 2025-02-03 01:31:24 +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
|
||||
|
||||
import net.corda.core.crypto.CompositeKey.NodeAndWeight
|
||||
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
|
||||
|
||||
/**
|
||||
@ -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.
|
||||
*/
|
||||
@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 {
|
||||
if (weight == other.weight) {
|
||||
return node.hashCode().compareTo(other.node.hashCode())
|
||||
}
|
||||
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 {
|
||||
// TODO: Get the design standardised and from there define a recognised name
|
||||
val ALGORITHM = "X-Corda-CompositeKey"
|
||||
// TODO: We should be using a well defined format.
|
||||
val FORMAT = "X-Corda-Kryo"
|
||||
val ALGORITHM = CompositeSignature.ALGORITHM_IDENTIFIER.algorithm.toString()
|
||||
}
|
||||
|
||||
/**
|
||||
@ -57,8 +63,17 @@ class CompositeKey private constructor (val threshold: Int,
|
||||
fun isFulfilledBy(key: PublicKey) = isFulfilledBy(setOf(key))
|
||||
|
||||
override fun getAlgorithm() = ALGORITHM
|
||||
override fun getEncoded(): ByteArray = this.serialize().bytes
|
||||
override fun getFormat() = FORMAT
|
||||
override fun getEncoded(): ByteArray {
|
||||
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
|
||||
|
@ -1,9 +1,6 @@
|
||||
package net.corda.node.utilities
|
||||
|
||||
import net.corda.core.crypto.CertificateAndKeyPair
|
||||
import net.corda.core.crypto.CompositeKey
|
||||
import net.corda.core.crypto.X509Utilities
|
||||
import net.corda.core.crypto.generateKeyPair
|
||||
import net.corda.core.crypto.*
|
||||
import net.corda.core.identity.PartyAndCertificate
|
||||
import net.corda.core.serialization.serialize
|
||||
import net.corda.core.serialization.storageKryo
|
||||
@ -12,6 +9,7 @@ import net.corda.core.utilities.trace
|
||||
import org.bouncycastle.asn1.x500.X500Name
|
||||
import java.nio.file.Files
|
||||
import java.nio.file.Path
|
||||
import java.security.cert.*
|
||||
|
||||
object ServiceIdentityGenerator {
|
||||
private val log = loggerFor<ServiceIdentityGenerator>()
|
||||
@ -36,15 +34,20 @@ object ServiceIdentityGenerator {
|
||||
log.trace { "Generating a group identity \"serviceName\" for nodes: ${dirs.joinToString()}" }
|
||||
val keyPairs = (1..dirs.size).map { generateKeyPair() }
|
||||
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.IDENTITY, serviceCa.certificate,
|
||||
// serviceCa.keyPair, serviceName, notaryKey)
|
||||
val notaryCert = X509Utilities.createSelfSignedCACertificate(serviceName, generateKeyPair())
|
||||
val notaryCert = X509Utilities.createCertificate(CertificateType.INTERMEDIATE_CA, serviceCa.certificate,
|
||||
serviceCa.keyPair, serviceName, notaryKey)
|
||||
val notaryCertPath = X509Utilities.createCertificatePath(serviceCa.certificate, notaryCert, revocationEnabled = false)
|
||||
val notaryParty = PartyAndCertificate(serviceName, notaryKey, notaryCert, notaryCertPath)
|
||||
val notaryPartyBytes = notaryParty.serialize()
|
||||
val privateKeyFile = "$serviceId-private-key"
|
||||
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 ->
|
||||
Files.createDirectories(dir)
|
||||
notaryPartyBytes.writeToFile(dir.resolve(publicKeyFile))
|
||||
|
Loading…
x
Reference in New Issue
Block a user