From 35e483cde7a1188ca6fc08d655036854e0b0add8 Mon Sep 17 00:00:00 2001 From: Bjørn Christian Seime Date: Tue, 20 Mar 2018 14:28:54 +0100 Subject: Replace BouncyCastle use in node-admin with vespa-athenz equivalents --- .../admin/configserver/SslConfigServerApiImpl.java | 4 -- .../certificate/CertificateSerializedPayload.java | 13 +----- .../certificate/ConfigServerKeyStoreRefresher.java | 51 ++++++++-------------- .../certificate/CsrSerializedPayload.java | 21 +++------ .../ConfigServerKeyStoreRefresherTest.java | 36 +++++---------- 5 files changed, 39 insertions(+), 86 deletions(-) (limited to 'node-admin') diff --git a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/configserver/SslConfigServerApiImpl.java b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/configserver/SslConfigServerApiImpl.java index 110dbe9c9b3..bdd4a8c0b9d 100644 --- a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/configserver/SslConfigServerApiImpl.java +++ b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/configserver/SslConfigServerApiImpl.java @@ -7,11 +7,9 @@ import com.yahoo.vespa.hosted.node.admin.component.Environment; import com.yahoo.vespa.hosted.node.admin.configserver.certificate.ConfigServerKeyStoreRefresher; import com.yahoo.vespa.hosted.node.admin.util.KeyStoreOptions; import org.apache.http.conn.ssl.SSLConnectionSocketFactory; -import org.bouncycastle.jce.provider.BouncyCastleProvider; import javax.net.ssl.HostnameVerifier; import javax.net.ssl.SSLContext; -import java.security.Security; import java.util.Collections; import java.util.Optional; @@ -28,8 +26,6 @@ public class SslConfigServerApiImpl implements ConfigServerApi { private final Optional keyStoreRefresher; public SslConfigServerApiImpl(Environment environment) { - Security.addProvider(new BouncyCastleProvider()); - this.environment = environment; // At this point we don't know the state of the keystore, it may not exist at all, or the keystore diff --git a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/configserver/certificate/CertificateSerializedPayload.java b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/configserver/certificate/CertificateSerializedPayload.java index e7148754fde..94bff3c9633 100644 --- a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/configserver/certificate/CertificateSerializedPayload.java +++ b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/configserver/certificate/CertificateSerializedPayload.java @@ -7,13 +7,9 @@ import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.JsonDeserializer; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import org.bouncycastle.cert.X509CertificateHolder; -import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter; -import org.bouncycastle.openssl.PEMParser; +import com.yahoo.vespa.athenz.tls.X509CertificateUtils; import java.io.IOException; -import java.io.StringReader; -import java.security.cert.CertificateException; import java.security.cert.X509Certificate; /** @@ -58,12 +54,7 @@ public class CertificateSerializedPayload { @Override public X509Certificate deserialize( JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException { - try (PEMParser pemParser = new PEMParser(new StringReader(jsonParser.getValueAsString()))) { - X509CertificateHolder x509CertificateHolder = (X509CertificateHolder) pemParser.readObject(); - return new JcaX509CertificateConverter().getCertificate(x509CertificateHolder); - } catch (CertificateException e) { - throw new RuntimeException("Failed to deserialize X509Certificate", e); - } + return X509CertificateUtils.fromPem(jsonParser.getValueAsString()); } } } diff --git a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/configserver/certificate/ConfigServerKeyStoreRefresher.java b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/configserver/certificate/ConfigServerKeyStoreRefresher.java index a9db96c2a77..beb1acd9e5a 100644 --- a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/configserver/certificate/ConfigServerKeyStoreRefresher.java +++ b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/configserver/certificate/ConfigServerKeyStoreRefresher.java @@ -3,24 +3,19 @@ package com.yahoo.vespa.hosted.node.admin.configserver.certificate; import com.yahoo.log.LogLevel; import com.yahoo.net.HostName; +import com.yahoo.vespa.athenz.tls.KeyAlgorithm; import com.yahoo.vespa.athenz.tls.KeyStoreBuilder; +import com.yahoo.vespa.athenz.tls.KeyUtils; +import com.yahoo.vespa.athenz.tls.Pkcs10Csr; +import com.yahoo.vespa.athenz.tls.Pkcs10CsrBuilder; +import com.yahoo.vespa.athenz.tls.SignatureAlgorithm; import com.yahoo.vespa.hosted.node.admin.configserver.ConfigServerApi; import com.yahoo.vespa.hosted.node.admin.util.KeyStoreOptions; -import org.bouncycastle.asn1.x500.X500Name; -import org.bouncycastle.operator.ContentSigner; -import org.bouncycastle.operator.OperatorCreationException; -import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder; -import org.bouncycastle.pkcs.PKCS10CertificationRequest; -import org.bouncycastle.pkcs.jcajce.JcaPKCS10CertificationRequestBuilder; - -import java.io.IOException; + +import javax.security.auth.x500.X500Principal; import java.security.KeyPair; -import java.security.KeyPairGenerator; import java.security.KeyStore; import java.security.KeyStoreException; -import java.security.NoSuchAlgorithmException; -import java.security.NoSuchProviderException; -import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import java.time.Clock; import java.util.concurrent.Executors; @@ -40,7 +35,7 @@ public class ConfigServerKeyStoreRefresher { private static final Logger logger = Logger.getLogger(ConfigServerKeyStoreRefresher.class.getName()); private static final String KEY_STORE_ALIAS = "alias"; static final long MINIMUM_SECONDS_BETWEEN_REFRESH_RETRY = 3600; - static final String SIGNER_ALGORITHM = "SHA256withRSA"; + static final SignatureAlgorithm SIGNER_ALGORITHM = SignatureAlgorithm.SHA256_WITH_RSA; static final String CONFIG_SERVER_CERTIFICATE_SIGNING_PATH = "/athenz/v1/provider/sign"; private final ScheduledExecutorService executor; @@ -101,12 +96,11 @@ public class ConfigServerKeyStoreRefresher { } while (!executor.isTerminated()); } - public boolean refreshKeyStoreIfNeeded() throws - IOException, NoSuchAlgorithmException, OperatorCreationException, CertificateException, KeyStoreException, NoSuchProviderException { + public boolean refreshKeyStoreIfNeeded() { if (!shouldRefreshCertificate()) return false; KeyPair keyPair = generateKeyPair(); - PKCS10CertificationRequest csr = generateCsr(keyPair, hostname); + Pkcs10Csr csr = generateCsr(keyPair, hostname); X509Certificate certificate = sendCsr(csr); storeCertificate(keyPair, certificate); @@ -141,8 +135,7 @@ public class ConfigServerKeyStoreRefresher { * well before the certificate actually expires so that we have enough time to retry without * overloading config server. */ - private long getSecondsUntilCertificateShouldBeRefreshed() - throws NoSuchAlgorithmException, CertificateException, NoSuchProviderException, KeyStoreException, IOException { + private long getSecondsUntilCertificateShouldBeRefreshed() throws KeyStoreException{ X509Certificate cert = getConfigServerCertificate(); long notBefore = cert.getNotBefore().getTime() / 1000; long notAfter = cert.getNotAfter().getTime() / 1000; @@ -152,12 +145,11 @@ public class ConfigServerKeyStoreRefresher { return Math.max(0, notBefore + thirdOfLifetime - now); } - X509Certificate getConfigServerCertificate() throws NoSuchAlgorithmException, CertificateException, NoSuchProviderException, KeyStoreException, IOException { + X509Certificate getConfigServerCertificate() throws KeyStoreException { return (X509Certificate) keyStoreOptions.loadKeyStore().getCertificate(KEY_STORE_ALIAS); } - private void storeCertificate(KeyPair keyPair, X509Certificate certificate) - throws KeyStoreException, CertificateException, NoSuchAlgorithmException, IOException, NoSuchProviderException { + private void storeCertificate(KeyPair keyPair, X509Certificate certificate) { keyStoreOptions.path.getParent().toFile().mkdirs(); KeyStore keyStore = KeyStoreBuilder.withType(keyStoreOptions.keyStoreType) @@ -167,7 +159,7 @@ public class ConfigServerKeyStoreRefresher { keyStoreOptions.storeKeyStore(keyStore); } - private X509Certificate sendCsr(PKCS10CertificationRequest csr) { + private X509Certificate sendCsr(Pkcs10Csr csr) { CertificateSerializedPayload certificateSerializedPayload = configServerApi.post( CONFIG_SERVER_CERTIFICATE_SIGNING_PATH, new CsrSerializedPayload(csr), @@ -176,17 +168,12 @@ public class ConfigServerKeyStoreRefresher { return certificateSerializedPayload.certificate; } - static KeyPair generateKeyPair() throws NoSuchAlgorithmException { - KeyPairGenerator rsa = KeyPairGenerator.getInstance("RSA"); - rsa.initialize(2048); - return rsa.genKeyPair(); + static KeyPair generateKeyPair() { + return KeyUtils.generateKeypair(KeyAlgorithm.RSA, 2048); } - private static PKCS10CertificationRequest generateCsr(KeyPair keyPair, String commonName) - throws NoSuchAlgorithmException, OperatorCreationException { - ContentSigner signer = new JcaContentSignerBuilder(SIGNER_ALGORITHM).build(keyPair.getPrivate()); - - return new JcaPKCS10CertificationRequestBuilder(new X500Name("CN=" + commonName), keyPair.getPublic()) - .build(signer); + private static Pkcs10Csr generateCsr(KeyPair keyPair, String commonName) { + return Pkcs10CsrBuilder.fromKeypair(new X500Principal("CN=" + commonName), keyPair, SIGNER_ALGORITHM) + .build(); } } diff --git a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/configserver/certificate/CsrSerializedPayload.java b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/configserver/certificate/CsrSerializedPayload.java index aa83fdc9e22..34b190b546c 100644 --- a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/configserver/certificate/CsrSerializedPayload.java +++ b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/configserver/certificate/CsrSerializedPayload.java @@ -7,12 +7,10 @@ import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.databind.JsonSerializer; import com.fasterxml.jackson.databind.SerializerProvider; import com.fasterxml.jackson.databind.annotation.JsonSerialize; -import org.bouncycastle.openssl.jcajce.JcaPEMWriter; -import org.bouncycastle.pkcs.PKCS10CertificationRequest; -import org.bouncycastle.util.io.pem.PemObject; +import com.yahoo.vespa.athenz.tls.Pkcs10Csr; +import com.yahoo.vespa.athenz.tls.Pkcs10CsrUtils; import java.io.IOException; -import java.io.StringWriter; /** * Contains PEM formatted Certificate Signing Request (CSR) @@ -23,10 +21,10 @@ import java.io.StringWriter; public class CsrSerializedPayload { @JsonProperty("csr") @JsonSerialize(using = CertificateRequestSerializer.class) - public final PKCS10CertificationRequest csr; + public final Pkcs10Csr csr; @JsonCreator - public CsrSerializedPayload(@JsonProperty("csr") PKCS10CertificationRequest csr) { + public CsrSerializedPayload(@JsonProperty("csr") Pkcs10Csr csr) { this.csr = csr; } @@ -52,15 +50,10 @@ public class CsrSerializedPayload { '}'; } - public static class CertificateRequestSerializer extends JsonSerializer { + public static class CertificateRequestSerializer extends JsonSerializer { @Override - public void serialize( - PKCS10CertificationRequest csr, JsonGenerator gen, SerializerProvider serializers) throws IOException { - try (StringWriter stringWriter = new StringWriter(); JcaPEMWriter pemWriter = new JcaPEMWriter(stringWriter)) { - pemWriter.writeObject(new PemObject("CERTIFICATE REQUEST", csr.getEncoded())); - pemWriter.flush(); - gen.writeString(stringWriter.toString()); - } + public void serialize(Pkcs10Csr csr, JsonGenerator gen, SerializerProvider serializers) throws IOException { + gen.writeString(Pkcs10CsrUtils.toPem(csr)); } } } diff --git a/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/configserver/certificate/ConfigServerKeyStoreRefresherTest.java b/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/configserver/certificate/ConfigServerKeyStoreRefresherTest.java index 85684ea3bd4..69aaad210a4 100644 --- a/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/configserver/certificate/ConfigServerKeyStoreRefresherTest.java +++ b/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/configserver/certificate/ConfigServerKeyStoreRefresherTest.java @@ -2,24 +2,19 @@ package com.yahoo.vespa.hosted.node.admin.configserver.certificate; import com.yahoo.test.ManualClock; +import com.yahoo.vespa.athenz.tls.X509CertificateBuilder; import com.yahoo.vespa.hosted.node.admin.configserver.ConfigServerApi; import com.yahoo.vespa.hosted.node.admin.util.KeyStoreOptions; -import org.bouncycastle.asn1.x500.X500Name; -import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter; -import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder; -import org.bouncycastle.jce.provider.BouncyCastleProvider; -import org.bouncycastle.operator.ContentSigner; -import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; -import java.math.BigInteger; +import javax.security.auth.x500.X500Principal; import java.security.KeyPair; import java.security.cert.X509Certificate; import java.time.Duration; -import java.util.Date; +import java.time.Instant; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; @@ -141,22 +136,13 @@ public class ConfigServerKeyStoreRefresherTest { .thenThrow(exception); } - private X509Certificate makeCertificate(int serial) throws Exception { - try { - KeyPair keyPair = ConfigServerKeyStoreRefresher.generateKeyPair(); - X500Name subject = new X500Name("CN=" + commonName); - Date notBefore = Date.from(clock.instant()); - Date notAfter = Date.from(clock.instant().plus(certificateExpiration)); - - JcaX509v3CertificateBuilder certGen = new JcaX509v3CertificateBuilder(subject, - BigInteger.valueOf(serial), notBefore, notAfter, subject, keyPair.getPublic()); - ContentSigner sigGen = new JcaContentSignerBuilder(ConfigServerKeyStoreRefresher.SIGNER_ALGORITHM) - .build(keyPair.getPrivate()); - return new JcaX509CertificateConverter() - .setProvider(new BouncyCastleProvider()) - .getCertificate(certGen.build(sigGen)); - } catch (Exception e) { - throw new RuntimeException(e); - } + private X509Certificate makeCertificate(int serial) { + KeyPair keyPair = ConfigServerKeyStoreRefresher.generateKeyPair(); + X500Principal subject = new X500Principal("CN=" + commonName); + Instant notBefore = clock.instant(); + Instant notAfter = clock.instant().plus(certificateExpiration); + + return X509CertificateBuilder.fromKeypair(keyPair, subject, notBefore, notAfter, ConfigServerKeyStoreRefresher.SIGNER_ALGORITHM, serial) + .build(); } } \ No newline at end of file -- cgit v1.2.3