summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--config-model-api/src/main/java/com/yahoo/config/model/api/EndpointCertificateMetadata.java9
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/tenant/EndpointCertificateRetriever.java19
-rw-r--r--security-utils/src/main/java/com/yahoo/security/X509CertificateUtils.java21
-rw-r--r--security-utils/src/test/java/com/yahoo/security/X509CertificateUtilsTest.java16
4 files changed, 65 insertions, 0 deletions
diff --git a/config-model-api/src/main/java/com/yahoo/config/model/api/EndpointCertificateMetadata.java b/config-model-api/src/main/java/com/yahoo/config/model/api/EndpointCertificateMetadata.java
index 9ed6056f184..a1fae9bb148 100644
--- a/config-model-api/src/main/java/com/yahoo/config/model/api/EndpointCertificateMetadata.java
+++ b/config-model-api/src/main/java/com/yahoo/config/model/api/EndpointCertificateMetadata.java
@@ -23,4 +23,13 @@ public class EndpointCertificateMetadata {
public int version() {
return version;
}
+
+ @Override
+ public String toString() {
+ return "EndpointCertificateMetadata{" +
+ "keyName='" + keyName + '\'' +
+ ", certName='" + certName + '\'' +
+ ", version=" + version +
+ '}';
+ }
}
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/tenant/EndpointCertificateRetriever.java b/configserver/src/main/java/com/yahoo/vespa/config/server/tenant/EndpointCertificateRetriever.java
index cc757ef7036..5f40e5e1411 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/tenant/EndpointCertificateRetriever.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/tenant/EndpointCertificateRetriever.java
@@ -4,7 +4,12 @@ package com.yahoo.vespa.config.server.tenant;
import com.yahoo.config.model.api.EndpointCertificateMetadata;
import com.yahoo.config.model.api.EndpointCertificateSecrets;
import com.yahoo.container.jdisc.secretstore.SecretStore;
+import com.yahoo.security.KeyUtils;
+import com.yahoo.security.X509CertificateUtils;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.cert.X509Certificate;
import java.util.Optional;
/**
@@ -28,10 +33,24 @@ public class EndpointCertificateRetriever {
try {
String cert = secretStore.getSecret(endpointCertificateMetadata.certName(), endpointCertificateMetadata.version());
String key = secretStore.getSecret(endpointCertificateMetadata.keyName(), endpointCertificateMetadata.version());
+
+ verifyKeyMatchesCertificate(endpointCertificateMetadata, cert, key);
+
return new EndpointCertificateSecrets(cert, key);
} catch (RuntimeException e) {
// Assume not ready yet
return EndpointCertificateSecrets.MISSING;
}
}
+
+ private void verifyKeyMatchesCertificate(EndpointCertificateMetadata endpointCertificateMetadata, String cert, String key) {
+ X509Certificate x509Certificate = X509CertificateUtils.fromPem(cert);
+
+ PrivateKey privateKey = KeyUtils.fromPemEncodedPrivateKey(key);
+ PublicKey publicKey = x509Certificate.getPublicKey();
+
+ if(!X509CertificateUtils.privateKeyMatchesPublicKey(privateKey, publicKey)) {
+ throw new IllegalArgumentException("Failed to retrieve endpoint secrets: Certificate and key data do not match for " + endpointCertificateMetadata);
+ }
+ }
}
diff --git a/security-utils/src/main/java/com/yahoo/security/X509CertificateUtils.java b/security-utils/src/main/java/com/yahoo/security/X509CertificateUtils.java
index 97b6cc344e1..cefa8ab2f51 100644
--- a/security-utils/src/main/java/com/yahoo/security/X509CertificateUtils.java
+++ b/security-utils/src/main/java/com/yahoo/security/X509CertificateUtils.java
@@ -19,11 +19,16 @@ import java.io.StringReader;
import java.io.StringWriter;
import java.io.UncheckedIOException;
import java.security.GeneralSecurityException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.Signature;
+import java.security.SignatureException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
+import java.util.Random;
import static com.yahoo.security.Extension.SUBJECT_ALTERNATIVE_NAMES;
import static java.util.stream.Collectors.toList;
@@ -140,4 +145,20 @@ public class X509CertificateUtils {
}
}
+ public static boolean privateKeyMatchesPublicKey(PrivateKey privateKey, PublicKey publicKey) {
+ byte[] someRandomData = new byte[64];
+ new Random().nextBytes(someRandomData);
+
+ Signature signer = SignatureUtils.createSigner(privateKey);
+ Signature verifier = SignatureUtils.createVerifier(publicKey);
+ try {
+ signer.update(someRandomData);
+ verifier.update(someRandomData);
+ byte[] signature = signer.sign();
+ return verifier.verify(signature);
+ } catch (SignatureException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
}
diff --git a/security-utils/src/test/java/com/yahoo/security/X509CertificateUtilsTest.java b/security-utils/src/test/java/com/yahoo/security/X509CertificateUtilsTest.java
index 76a93028efe..b4eca8328c1 100644
--- a/security-utils/src/test/java/com/yahoo/security/X509CertificateUtilsTest.java
+++ b/security-utils/src/test/java/com/yahoo/security/X509CertificateUtilsTest.java
@@ -17,7 +17,9 @@ import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
/**
* @author bjorncs
@@ -71,4 +73,18 @@ public class X509CertificateUtilsTest {
assertThat(sans.size(), is(1));
assertThat(sans.get(0), equalTo(san));
}
+
+ @Test
+ public void verifies_matching_cert_and_key() {
+ KeyPair ecKeypairA = KeyUtils.generateKeypair(KeyAlgorithm.EC, 256);
+ KeyPair ecKeypairB = KeyUtils.generateKeypair(KeyAlgorithm.EC, 256);
+ KeyPair rsaKeypairA = KeyUtils.generateKeypair(KeyAlgorithm.RSA, 1024);
+ KeyPair rsaKeypairB = KeyUtils.generateKeypair(KeyAlgorithm.RSA, 1024);
+
+ assertTrue(X509CertificateUtils.privateKeyMatchesPublicKey(ecKeypairA.getPrivate(), ecKeypairA.getPublic()));
+ assertTrue(X509CertificateUtils.privateKeyMatchesPublicKey(rsaKeypairA.getPrivate(), rsaKeypairA.getPublic()));
+
+ assertFalse(X509CertificateUtils.privateKeyMatchesPublicKey(ecKeypairA.getPrivate(), ecKeypairB.getPublic()));
+ assertFalse(X509CertificateUtils.privateKeyMatchesPublicKey(rsaKeypairA.getPrivate(), rsaKeypairB.getPublic()));
+ }
} \ No newline at end of file