mirror of
https://github.com/corda/corda.git
synced 2025-04-07 19:34:41 +00:00
ENT-5219: Synchronize BCCryptoService between OS and ENT (#6178)
This commit is contained in:
parent
73d5fc4db6
commit
824c01daad
@ -143,4 +143,4 @@ enum class WrappingMode {
|
||||
WRAPPED
|
||||
}
|
||||
|
||||
class WrappedPrivateKey(val keyMaterial: ByteArray, val signatureScheme: SignatureScheme)
|
||||
class WrappedPrivateKey(val keyMaterial: ByteArray, val signatureScheme: SignatureScheme, val encodingVersion: Int? = null)
|
@ -162,20 +162,30 @@ class BCCryptoService(private val legalName: X500Principal,
|
||||
wrappingKeyStore.save(wrappingKeyStorePath!!, certificateStore.password)
|
||||
}
|
||||
|
||||
/**
|
||||
* Using "AESWRAPPAD" cipher spec for key wrapping defined by [RFC 5649](https://tools.ietf.org/html/rfc5649).
|
||||
* "AESWRAPPAD" (same as "AESKWP" or "AESRFC5649WRAP") is implemented in [org.bouncycastle.jcajce.provider.symmetric.AES.WrapPad] using
|
||||
* [org.bouncycastle.crypto.engines.RFC5649WrapEngine]. See:
|
||||
* - https://www.bouncycastle.org/docs/docs1.5on/org/bouncycastle/crypto/engines/AESWrapPadEngine.html
|
||||
* - https://www.bouncycastle.org/docs/docs1.5on/org/bouncycastle/crypto/engines/RFC5649WrapEngine.html
|
||||
*
|
||||
* Keys encoded with "AESWRAPPAD" are stored with encodingVersion = 1. Previously used cipher spec ("AES" == "AES/ECB/PKCS5Padding")
|
||||
* corresponds to encodingVersion = null.
|
||||
*/
|
||||
override fun generateWrappedKeyPair(masterKeyAlias: String, childKeyScheme: SignatureScheme): Pair<PublicKey, WrappedPrivateKey> {
|
||||
if (!wrappingKeyStore.containsAlias(masterKeyAlias)) {
|
||||
throw IllegalStateException("There is no master key under the alias: $masterKeyAlias")
|
||||
}
|
||||
|
||||
val wrappingKey = wrappingKeyStore.getKey(masterKeyAlias, certificateStore.entryPassword.toCharArray())
|
||||
val cipher = Cipher.getInstance("AES", cordaBouncyCastleProvider)
|
||||
val cipher = Cipher.getInstance("AESWRAPPAD", cordaBouncyCastleProvider)
|
||||
cipher.init(Cipher.WRAP_MODE, wrappingKey)
|
||||
|
||||
val keyPairGenerator = keyPairGeneratorFromScheme(childKeyScheme)
|
||||
val keyPair = keyPairGenerator.generateKeyPair()
|
||||
val privateKeyMaterialWrapped = cipher.wrap(keyPair.private)
|
||||
|
||||
return Pair(keyPair.public, WrappedPrivateKey(privateKeyMaterialWrapped, childKeyScheme))
|
||||
return Pair(keyPair.public, WrappedPrivateKey(privateKeyMaterialWrapped, childKeyScheme, encodingVersion = 1))
|
||||
}
|
||||
|
||||
override fun sign(masterKeyAlias: String, wrappedPrivateKey: WrappedPrivateKey, payloadToSign: ByteArray): ByteArray {
|
||||
@ -184,7 +194,12 @@ class BCCryptoService(private val legalName: X500Principal,
|
||||
}
|
||||
|
||||
val wrappingKey = wrappingKeyStore.getKey(masterKeyAlias, certificateStore.entryPassword.toCharArray())
|
||||
val cipher = Cipher.getInstance("AES", cordaBouncyCastleProvider)
|
||||
// Keeping backwards compatibility with previous encoding algorithms
|
||||
val algorithm = when(wrappedPrivateKey.encodingVersion) {
|
||||
1 -> "AESWRAPPAD"
|
||||
else -> "AES"
|
||||
}
|
||||
val cipher = Cipher.getInstance(algorithm, cordaBouncyCastleProvider)
|
||||
cipher.init(Cipher.UNWRAP_MODE, wrappingKey)
|
||||
|
||||
val privateKey = cipher.unwrap(wrappedPrivateKey.keyMaterial, keyAlgorithmFromScheme(wrappedPrivateKey.signatureScheme), Cipher.PRIVATE_KEY) as PrivateKey
|
||||
|
@ -2,6 +2,7 @@ package net.corda.nodeapi.internal.cryptoservice.bouncycastle
|
||||
|
||||
import net.corda.core.crypto.Crypto
|
||||
import net.corda.core.crypto.SignatureScheme
|
||||
import net.corda.core.crypto.internal.cordaBouncyCastleProvider
|
||||
import net.corda.core.internal.div
|
||||
import net.corda.core.utilities.days
|
||||
import net.corda.nodeapi.internal.config.CertificateStoreSupplier
|
||||
@ -13,6 +14,7 @@ import net.corda.nodeapi.internal.cryptoservice.WrappedPrivateKey
|
||||
import net.corda.nodeapi.internal.cryptoservice.WrappingMode
|
||||
import net.corda.testing.core.ALICE_NAME
|
||||
import net.corda.coretesting.internal.stubs.CertificateStoreStubs
|
||||
import net.corda.nodeapi.internal.crypto.loadOrCreateKeyStore
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.assertj.core.api.Assertions.assertThatThrownBy
|
||||
import org.bouncycastle.jce.provider.BouncyCastleProvider
|
||||
@ -23,8 +25,10 @@ import org.junit.rules.TemporaryFolder
|
||||
import java.io.FileOutputStream
|
||||
import java.nio.file.Path
|
||||
import java.security.*
|
||||
import java.security.spec.ECGenParameterSpec
|
||||
import java.time.Duration
|
||||
import java.util.*
|
||||
import javax.crypto.Cipher
|
||||
import javax.security.auth.x500.X500Principal
|
||||
import kotlin.test.assertFailsWith
|
||||
import kotlin.test.assertFalse
|
||||
@ -253,4 +257,27 @@ class BCCryptoServiceTests {
|
||||
|
||||
Crypto.doVerify(publicKey, signature, data)
|
||||
}
|
||||
|
||||
@Test(timeout=300_000)
|
||||
fun `cryptoService can sign with previously encoded version of wrapped key`() {
|
||||
val cryptoService = BCCryptoService(ALICE_NAME.x500Principal, signingCertificateStore, wrappingKeyStorePath)
|
||||
|
||||
val wrappingKeyAlias = UUID.randomUUID().toString()
|
||||
cryptoService.createWrappingKey(wrappingKeyAlias)
|
||||
|
||||
val wrappingKeyStore = loadOrCreateKeyStore(wrappingKeyStorePath, cryptoService.certificateStore.password, "PKCS12")
|
||||
val wrappingKey = wrappingKeyStore.getKey(wrappingKeyAlias, cryptoService.certificateStore.entryPassword.toCharArray())
|
||||
val cipher = Cipher.getInstance("AES", cordaBouncyCastleProvider)
|
||||
cipher.init(Cipher.WRAP_MODE, wrappingKey)
|
||||
|
||||
val keyPairGenerator = KeyPairGenerator.getInstance("EC", cordaBouncyCastleProvider)
|
||||
keyPairGenerator.initialize(ECGenParameterSpec("secp256r1"))
|
||||
val keyPair = keyPairGenerator.generateKeyPair()
|
||||
val privateKeyMaterialWrapped = cipher.wrap(keyPair.private)
|
||||
val wrappedPrivateKey = WrappedPrivateKey(privateKeyMaterialWrapped, Crypto.ECDSA_SECP256R1_SHA256, encodingVersion = null)
|
||||
|
||||
val data = "data".toByteArray()
|
||||
val signature = cryptoService.sign(wrappingKeyAlias, wrappedPrivateKey, data)
|
||||
Crypto.doVerify(keyPair.public, signature, data)
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user