diff --git a/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt b/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt index 3414e53b48..e613b6dfb4 100644 --- a/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt +++ b/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt @@ -869,11 +869,14 @@ abstract class AbstractNode(val configuration: NodeConfiguration, private fun obtainIdentity(): Pair { val legalIdentityPrivateKeyAlias = "$NODE_IDENTITY_ALIAS_PREFIX-private-key" - if (!cryptoService.containsKey(legalIdentityPrivateKeyAlias)) { + var signingCertificateStore = configuration.signingCertificateStore.get() + if (!cryptoService.containsKey(legalIdentityPrivateKeyAlias) && !signingCertificateStore.contains(legalIdentityPrivateKeyAlias)) { log.info("$legalIdentityPrivateKeyAlias not found in key store, generating fresh key!") - storeLegalIdentity(legalIdentityPrivateKeyAlias) + createAndStoreLegalIdentity(legalIdentityPrivateKeyAlias) + signingCertificateStore = configuration.signingCertificateStore.get() // We need to resync after [createAndStoreLegalIdentity]. + } else { + checkAliasMismatch(legalIdentityPrivateKeyAlias, signingCertificateStore) } - val signingCertificateStore = configuration.signingCertificateStore.get() val x509Cert = signingCertificateStore.query { getCertificate(legalIdentityPrivateKeyAlias) } // TODO: Use configuration to indicate composite key should be used instead of public key for the identity. @@ -891,22 +894,36 @@ abstract class AbstractNode(val configuration: NodeConfiguration, return getPartyAndCertificatePlusAliasKeyPair(certificates, legalIdentityPrivateKeyAlias) } + // Check if a key alias exists only in one of the cryptoService and certSigningStore. + private fun checkAliasMismatch(alias: String, certificateStore: CertificateStore) { + if (cryptoService.containsKey(alias) != certificateStore.contains(alias)) { + val keyExistsIn: String = if (cryptoService.containsKey(alias)) "CryptoService" else "signingCertificateStore" + throw IllegalStateException("CryptoService and signingCertificateStore are not aligned, the entry for key-alias: $alias is only found in $keyExistsIn") + } + } + /** Loads pre-generated notary service cluster identity. */ private fun loadNotaryClusterIdentity(serviceLegalName: CordaX500Name): Pair { val privateKeyAlias = "$DISTRIBUTED_NOTARY_ALIAS_PREFIX-private-key" val compositeKeyAlias = "$DISTRIBUTED_NOTARY_ALIAS_PREFIX-composite-key" val signingCertificateStore = configuration.signingCertificateStore.get() + val privateKeyAliasCertChain = try { + signingCertificateStore.query { getCertificateChain(privateKeyAlias) } + } catch (e: Exception) { + throw IllegalStateException("Certificate-chain for $privateKeyAlias cannot be found", e) + } // A composite key is only required for BFT notaries. - val certificates = if (cryptoService.containsKey(compositeKeyAlias)) { + val certificates = if (cryptoService.containsKey(compositeKeyAlias) && signingCertificateStore.contains(compositeKeyAlias)) { val certificate = signingCertificateStore[compositeKeyAlias] // We have to create the certificate chain for the composite key manually, this is because we don't have a keystore // provider that understand compositeKey-privateKey combo. The cert chain is created using the composite key certificate + // the tail of the private key certificates, as they are both signed by the same certificate chain. - listOf(certificate) + signingCertificateStore.query { getCertificateChain(privateKeyAlias) }.drop(1) + listOf(certificate) + privateKeyAliasCertChain.drop(1) } else { - // We assume the notary is CFT, and each cluster member shares the same notary key pair. - signingCertificateStore.query { getCertificateChain(privateKeyAlias) } + checkAliasMismatch(compositeKeyAlias, signingCertificateStore) + // If [compositeKeyAlias] does not exist, we assume the notary is CFT, and each cluster member shares the same notary key pair. + privateKeyAliasCertChain } val subject = CordaX500Name.build(certificates.first().subjectX500Principal) @@ -924,12 +941,12 @@ abstract class AbstractNode(val configuration: NodeConfiguration, return Pair(PartyAndCertificate(certPath), keyPair) } - private fun storeLegalIdentity(alias: String): PartyAndCertificate { + private fun createAndStoreLegalIdentity(alias: String): PartyAndCertificate { val legalIdentityPublicKey = generateKeyPair(alias) val signingCertificateStore = configuration.signingCertificateStore.get() val nodeCaCertPath = signingCertificateStore.value.getCertificateChain(X509Utilities.CORDA_CLIENT_CA) - val nodeCaCert = nodeCaCertPath[0] // This should be the same with signingCertificateStore[alias] + val nodeCaCert = nodeCaCertPath[0] // This should be the same with signingCertificateStore[alias]. val identityCert = X509Utilities.createCertificate( CertificateType.LEGAL_IDENTITY, diff --git a/node/src/main/kotlin/net/corda/node/services/config/NodeConfigurationImpl.kt b/node/src/main/kotlin/net/corda/node/services/config/NodeConfigurationImpl.kt index d2c4745e1c..12a2b0fc4d 100644 --- a/node/src/main/kotlin/net/corda/node/services/config/NodeConfigurationImpl.kt +++ b/node/src/main/kotlin/net/corda/node/services/config/NodeConfigurationImpl.kt @@ -274,6 +274,9 @@ data class NodeConfigurationImpl( if (cryptoServiceName == null && cryptoServiceConf != null) { errors += "'cryptoServiceName' is mandatory when 'cryptoServiceConf' is specified" } + if (notary != null && !(cryptoServiceName == null || cryptoServiceName == SupportedCryptoServices.BC_SIMPLE)) { + errors += "Notary node with a non supported 'cryptoServiceName' has been detected" + } return errors }