diff --git a/platform-sdk/swirlds-platform-core/src/main/java/com/swirlds/platform/crypto/CryptoStatic.java b/platform-sdk/swirlds-platform-core/src/main/java/com/swirlds/platform/crypto/CryptoStatic.java index 9e10d66ed653..47e83641f986 100644 --- a/platform-sdk/swirlds-platform-core/src/main/java/com/swirlds/platform/crypto/CryptoStatic.java +++ b/platform-sdk/swirlds-platform-core/src/main/java/com/swirlds/platform/crypto/CryptoStatic.java @@ -455,15 +455,8 @@ static void copyPublicKeys(final PublicStores publicStores, final AddressBook ad final Address add = addressBook.getAddress(nodeId); final String name = nameToAlias(add.getSelfName()); final X509Certificate sigCert = publicStores.getCertificate(SIGNING, name); - try { - final X509Certificate agrCert = publicStores.getCertificate(KeyCertPurpose.AGREEMENT, name); - addressBook.add( - addressBook.getAddress(nodeId).copySetSigCert(sigCert).copySetAgreeCert(agrCert)); - } catch (final KeyLoadingException e) { - // the agreement key is allowed to be absent and is never used from the address book anymore. - addressBook.add( - addressBook.getAddress(nodeId).copySetSigCert(sigCert).copySetAgreeCert(null)); - } + // the agreement key is never used from the address book anymore and is left null. + addressBook.add(addressBook.getAddress(nodeId).copySetSigCert(sigCert)); } } diff --git a/platform-sdk/swirlds-platform-core/src/main/java/com/swirlds/platform/crypto/EnhancedKeyStoreLoader.java b/platform-sdk/swirlds-platform-core/src/main/java/com/swirlds/platform/crypto/EnhancedKeyStoreLoader.java index c623993eff66..8d5c668dd46b 100644 --- a/platform-sdk/swirlds-platform-core/src/main/java/com/swirlds/platform/crypto/EnhancedKeyStoreLoader.java +++ b/platform-sdk/swirlds-platform-core/src/main/java/com/swirlds/platform/crypto/EnhancedKeyStoreLoader.java @@ -319,6 +319,12 @@ public EnhancedKeyStoreLoader generateIfNecessary() for (final NodeId node : localNodes) { if (!agrPrivateKeys.containsKey(node)) { + final String alias = nameToAlias(addressBook.getAddress(node).getSelfName()); + logger.info( + STARTUP.getMarker(), + "Generating agreement key pair for local node {} [ alias = {} ]", + node, + alias); // Generate a new agreement key since it does not exist final KeyPair agrKeyPair = KeysAndCerts.generateAgreementKeyPair(); agrPrivateKeys.put(node, agrKeyPair.getPrivate()); @@ -330,8 +336,7 @@ public EnhancedKeyStoreLoader generateIfNecessary() final KeyPair signingKeyPair = new KeyPair(publicSigningKey, privateSigningKey); // generate the agreement certificate - final String dnA = CryptoStatic.distinguishedName(KeyCertPurpose.AGREEMENT.storeName( - nameToAlias(addressBook.getAddress(node).getSelfName()))); + final String dnA = CryptoStatic.distinguishedName(KeyCertPurpose.AGREEMENT.storeName(alias)); final X509Certificate agrCert = CryptoStatic.generateCertificate( dnA, agrKeyPair, @@ -391,17 +396,18 @@ public EnhancedKeyStoreLoader verify(@NonNull final AddressBook validatingBook) throw new KeyLoadingException("No private key found for node %s [ alias = %s, purpose = %s ]" .formatted(nodeId, nodeAlias, KeyCertPurpose.AGREEMENT)); } + + // the agreement certificate must be present for local nodes + if (!agrCertificates.containsKey(nodeId)) { + throw new KeyLoadingException("No certificate found for node %s [ alias = %s, purpose = %s ]" + .formatted(nodeId, nodeAlias, KeyCertPurpose.AGREEMENT)); + } } if (!sigCertificates.containsKey(nodeId)) { throw new KeyLoadingException("No certificate found for node %s [ alias = %s, purpose = %s ]" .formatted(nodeId, nodeAlias, KeyCertPurpose.SIGNING)); } - - if (!agrCertificates.containsKey(nodeId)) { - throw new KeyLoadingException("No certificate found for node %s [ alias = %s, purpose = %s ]" - .formatted(nodeId, nodeAlias, KeyCertPurpose.AGREEMENT)); - } }); return this; @@ -441,19 +447,14 @@ public Map keysAndCerts(@NonNull final AddressBook validat iterateAddressBook(validatingBook, (i, nodeId, address, nodeAlias) -> { final X509Certificate sigCert = publicStores.getCertificate(KeyCertPurpose.SIGNING, nodeAlias); - final X509Certificate agrCert = publicStores.getCertificate(KeyCertPurpose.AGREEMENT, nodeAlias); if (sigCert == null) { throw new KeyLoadingException( "No signing certificate found for node %s [ alias = %s ]".formatted(nodeId, nodeAlias)); } - if (agrCert == null) { - throw new KeyLoadingException( - "No agreement certificate found for node %s [ alias = %s ]".formatted(nodeId, nodeAlias)); - } - if (localNodes.contains(nodeId)) { + final X509Certificate agrCert = publicStores.getCertificate(KeyCertPurpose.AGREEMENT, nodeAlias); final PrivateKey sigPrivateKey = sigPrivateKeys.get(nodeId); final PrivateKey agrPrivateKey = agrPrivateKeys.get(nodeId); @@ -467,6 +468,12 @@ public Map keysAndCerts(@NonNull final AddressBook validat "No agreement private key found for node %s [ alias = %s ]".formatted(nodeId, nodeAlias)); } + // the agreement certificate must be present for local nodes + if (agrCert == null) { + throw new KeyLoadingException( + "No agreement certificate found for node %s [ alias = %s ]".formatted(nodeId, nodeAlias)); + } + final KeyPair sigKeyPair = new KeyPair(sigCert.getPublicKey(), sigPrivateKey); final KeyPair agrKeyPair = new KeyPair(agrCert.getPublicKey(), agrPrivateKey); @@ -550,14 +557,22 @@ public PublicStores publicStores(@NonNull final AddressBook validatingBook) .formatted(nodeId, nodeAlias, KeyCertPurpose.SIGNING)); } - if (!(agrCert instanceof X509Certificate)) { - throw new KeyLoadingException( - "Illegal agreement certificate type for node %s [ alias = %s, purpose = %s ]" - .formatted(nodeId, nodeAlias, KeyCertPurpose.AGREEMENT)); + if (isLocal(address)) { + // The agreement certificate is loaded by the local nodes and provided to peers through mTLS handshaking + logger.trace( + STARTUP.getMarker(), + "Injecting agreement certificate for local node {} [ alias = {} ] into public stores", + nodeId, + nodeAlias); + if (!(agrCert instanceof X509Certificate)) { + throw new KeyLoadingException( + "Illegal agreement certificate type for node %s [ alias = %s, purpose = %s ]" + .formatted(nodeId, nodeAlias, KeyCertPurpose.AGREEMENT)); + } + publicStores.setCertificate(KeyCertPurpose.AGREEMENT, (X509Certificate) agrCert, nodeAlias); } publicStores.setCertificate(KeyCertPurpose.SIGNING, (X509Certificate) sigCert, nodeAlias); - publicStores.setCertificate(KeyCertPurpose.AGREEMENT, (X509Certificate) agrCert, nodeAlias); }); return publicStores; diff --git a/platform-sdk/swirlds-platform-core/src/main/java/com/swirlds/platform/state/service/PbjConverter.java b/platform-sdk/swirlds-platform-core/src/main/java/com/swirlds/platform/state/service/PbjConverter.java index 6905d7ed5a27..2e7137ebed27 100644 --- a/platform-sdk/swirlds-platform-core/src/main/java/com/swirlds/platform/state/service/PbjConverter.java +++ b/platform-sdk/swirlds-platform-core/src/main/java/com/swirlds/platform/state/service/PbjConverter.java @@ -328,9 +328,12 @@ private static com.hedera.hapi.platform.state.MinimumJudgeInfo toPbjMinimumJudge return new com.hedera.hapi.platform.state.MinimumJudgeInfo(v.round(), v.minimumJudgeAncientThreshold()); } - @NonNull - private static SerializableX509Certificate fromPbjX509Certificate(@NonNull final Bytes bytes) { - requireNonNull(bytes); + @Nullable + private static SerializableX509Certificate fromPbjX509Certificate(@Nullable final Bytes bytes) { + if (bytes == null || bytes.length() == 0) { + // as of release 0.55.0, future address books in state will not have the agreement key serialized. + return null; + } final byte[] encoded = bytes.toByteArray(); try { return new SerializableX509Certificate((X509Certificate) diff --git a/platform-sdk/swirlds-platform-core/src/test/java/com/swirlds/platform/crypto/EnhancedKeyStoreLoaderTest.java b/platform-sdk/swirlds-platform-core/src/test/java/com/swirlds/platform/crypto/EnhancedKeyStoreLoaderTest.java index 27384a5881e8..4cbb9d556c71 100644 --- a/platform-sdk/swirlds-platform-core/src/test/java/com/swirlds/platform/crypto/EnhancedKeyStoreLoaderTest.java +++ b/platform-sdk/swirlds-platform-core/src/test/java/com/swirlds/platform/crypto/EnhancedKeyStoreLoaderTest.java @@ -136,8 +136,8 @@ void keyStoreLoaderPositiveTest(final String directoryName) assertThat(keysAndCerts.sigKeyPair()).isNotNull(); } - assertThat(addr.getAgreePublicKey()).isNotNull(); assertThat(addr.getSigPublicKey()).isNotNull(); + assertThat(addr.getAgreePublicKey()).isNull(); } } diff --git a/platform-sdk/swirlds-platform-core/src/test/resources/com/swirlds/platform/crypto/EnhancedKeyStoreLoader/config.txt b/platform-sdk/swirlds-platform-core/src/test/resources/com/swirlds/platform/crypto/EnhancedKeyStoreLoader/config.txt index 564dab6ba104..9f4f9f9504a9 100644 --- a/platform-sdk/swirlds-platform-core/src/test/resources/com/swirlds/platform/crypto/EnhancedKeyStoreLoader/config.txt +++ b/platform-sdk/swirlds-platform-core/src/test/resources/com/swirlds/platform/crypto/EnhancedKeyStoreLoader/config.txt @@ -6,6 +6,6 @@ swirld, 123 address, 0, A, Alice, 1, 127.0.0.1, 15301, 127.0.0.1, 15301 address, 1, B, Bob, 1, 127.0.0.1, 15302, 127.0.0.1, 15302 - address, 2, C, Carol, 1, 127.0.0.1, 15303, 127.0.0.1, 15303 + address, 2, C, Carol, 1, 8.8.8.8, 15303, 127.0.0.1, 15303 nextNodeId, 3