aboutsummaryrefslogtreecommitdiffstats
path: root/vespa-athenz
diff options
context:
space:
mode:
authorHarald Musum <musum@oath.com>2018-03-21 15:20:54 +0100
committerGitHub <noreply@github.com>2018-03-21 15:20:54 +0100
commit9406df0701e050b8428cb0ce03cda9a275e4cd97 (patch)
tree5ea1d3c0e31286ea9b6adc1d1a7f1edbb70346a9 /vespa-athenz
parenta4a3147111bc427f2af081e8572b5618e3e05e7d (diff)
Revert "Bjorncs/certificate builder"
Diffstat (limited to 'vespa-athenz')
-rw-r--r--vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identity/SiaIdentityProvider.java29
-rw-r--r--vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/AthenzCredentialsService.java54
-rw-r--r--vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/CryptoUtils.java113
-rw-r--r--vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/InstanceIdentity.java3
-rw-r--r--vespa-athenz/src/main/java/com/yahoo/vespa/athenz/tls/BasicConstraintsExtension.java14
-rw-r--r--vespa-athenz/src/main/java/com/yahoo/vespa/athenz/tls/BouncyCastleProviderHolder.java14
-rw-r--r--vespa-athenz/src/main/java/com/yahoo/vespa/athenz/tls/Extension.java22
-rw-r--r--vespa-athenz/src/main/java/com/yahoo/vespa/athenz/tls/KeyAlgorithm.java19
-rw-r--r--vespa-athenz/src/main/java/com/yahoo/vespa/athenz/tls/KeyStoreType.java4
-rw-r--r--vespa-athenz/src/main/java/com/yahoo/vespa/athenz/tls/KeyUtils.java41
-rw-r--r--vespa-athenz/src/main/java/com/yahoo/vespa/athenz/tls/Pkcs10Csr.java90
-rw-r--r--vespa-athenz/src/main/java/com/yahoo/vespa/athenz/tls/Pkcs10CsrBuilder.java89
-rw-r--r--vespa-athenz/src/main/java/com/yahoo/vespa/athenz/tls/Pkcs10CsrUtils.java38
-rw-r--r--vespa-athenz/src/main/java/com/yahoo/vespa/athenz/tls/SignatureAlgorithm.java19
-rw-r--r--vespa-athenz/src/main/java/com/yahoo/vespa/athenz/tls/X509CertificateBuilder.java145
-rw-r--r--vespa-athenz/src/main/java/com/yahoo/vespa/athenz/tls/X509CertificateUtils.java78
-rw-r--r--vespa-athenz/src/main/java/com/yahoo/vespa/athenz/utils/AthenzIdentities.java18
-rw-r--r--vespa-athenz/src/test/java/com/yahoo/vespa/athenz/identityprovider/CryptoUtilsTest.java28
-rw-r--r--vespa-athenz/src/test/java/com/yahoo/vespa/athenz/tls/AthenzSslContextBuilderTest.java3
-rw-r--r--vespa-athenz/src/test/java/com/yahoo/vespa/athenz/tls/KeyStoreBuilderTest.java3
-rw-r--r--vespa-athenz/src/test/java/com/yahoo/vespa/athenz/tls/KeyUtilsTest.java22
-rw-r--r--vespa-athenz/src/test/java/com/yahoo/vespa/athenz/tls/Pkcs10CsrBuilderTest.java27
-rw-r--r--vespa-athenz/src/test/java/com/yahoo/vespa/athenz/tls/Pkcs10CsrTest.java55
-rw-r--r--vespa-athenz/src/test/java/com/yahoo/vespa/athenz/tls/Pkcs10CsrUtilsTest.java29
-rw-r--r--vespa-athenz/src/test/java/com/yahoo/vespa/athenz/tls/TestUtils.java50
-rw-r--r--vespa-athenz/src/test/java/com/yahoo/vespa/athenz/tls/X509CertificateBuilderTest.java58
-rw-r--r--vespa-athenz/src/test/java/com/yahoo/vespa/athenz/tls/X509CertificateUtilsTest.java36
27 files changed, 218 insertions, 883 deletions
diff --git a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identity/SiaIdentityProvider.java b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identity/SiaIdentityProvider.java
index 62ac722759a..892a4f266ae 100644
--- a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identity/SiaIdentityProvider.java
+++ b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identity/SiaIdentityProvider.java
@@ -1,6 +1,7 @@
// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.athenz.identity;
+import com.yahoo.athenz.auth.util.Crypto;
import com.yahoo.component.AbstractComponent;
import com.yahoo.container.jdisc.athenz.AthenzIdentityProvider;
import com.yahoo.vespa.athenz.api.AthenzDomain;
@@ -8,25 +9,19 @@ import com.yahoo.vespa.athenz.api.AthenzIdentityCertificate;
import com.yahoo.vespa.athenz.api.AthenzService;
import com.yahoo.vespa.athenz.tls.AthenzSslContextBuilder;
import com.yahoo.vespa.athenz.tls.KeyStoreType;
-import com.yahoo.vespa.athenz.tls.KeyUtils;
-import com.yahoo.vespa.athenz.tls.X509CertificateUtils;
import javax.net.ssl.SSLContext;
import java.io.File;
-import java.io.IOException;
-import java.io.UncheckedIOException;
-import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.PrivateKey;
import java.security.cert.X509Certificate;
import java.time.Duration;
import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
-import static java.util.stream.Collectors.joining;
-
/**
* @author mortent
*/
@@ -68,21 +63,13 @@ public class SiaIdentityProvider extends AbstractComponent implements AthenzIden
}
private SSLContext createIdentitySslContext() {
- try {
- String certPem = Files.lines(Paths.get(path, "certs", String.format("%s.%s.cert.pem", getDomain(), getService())))
- .collect(joining());
- X509Certificate certificate = X509CertificateUtils.fromPem(certPem);
- String keyPem = Files.lines(Paths.get(path, "keys", String.format("%s.%s.key.pem", getDomain(), getService())))
- .collect(joining());
- PrivateKey privateKey = KeyUtils.fromPemEncodedPrivateKey(keyPem);
+ X509Certificate certificate = Crypto.loadX509Certificate(Paths.get(path, "certs", String.format("%s.%s.cert.pem", getDomain(),getService())).toFile());
+ PrivateKey privateKey = Crypto.loadPrivateKey(Paths.get(path, "keys", String.format("%s.%s.key.pem", getDomain(),getService())).toFile());
- return new AthenzSslContextBuilder()
- .withTrustStore(new File(trustStorePath), KeyStoreType.JKS)
- .withIdentityCertificate(new AthenzIdentityCertificate(certificate, privateKey))
- .build();
- } catch (IOException e) {
- throw new UncheckedIOException(e);
- }
+ return new AthenzSslContextBuilder()
+ .withTrustStore(new File(trustStorePath), KeyStoreType.JKS)
+ .withIdentityCertificate(new AthenzIdentityCertificate(certificate, privateKey))
+ .build();
}
private void reloadSslContext() {
diff --git a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/AthenzCredentialsService.java b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/AthenzCredentialsService.java
index e73cd2f2bdd..b9fb7e94782 100644
--- a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/AthenzCredentialsService.java
+++ b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/AthenzCredentialsService.java
@@ -3,14 +3,8 @@ package com.yahoo.vespa.athenz.identityprovider;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.yahoo.container.core.identity.IdentityConfig;
-import com.yahoo.vespa.athenz.tls.KeyAlgorithm;
-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.Pkcs10CsrUtils;
-import com.yahoo.vespa.athenz.tls.SignatureAlgorithm;
+import org.bouncycastle.pkcs.PKCS10CertificationRequest;
-import javax.security.auth.x500.X500Principal;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.security.KeyPair;
@@ -40,20 +34,20 @@ class AthenzCredentialsService {
}
AthenzCredentials registerInstance() {
- KeyPair keyPair = KeyUtils.generateKeypair(KeyAlgorithm.RSA);
+ KeyPair keyPair = CryptoUtils.createKeyPair();
String rawDocument = identityDocumentService.getSignedIdentityDocument();
SignedIdentityDocument document = parseSignedIdentityDocument(rawDocument);
- Pkcs10Csr csr = createCSR(identityConfig.domain(),
- identityConfig.service(),
- document.dnsSuffix,
- document.providerUniqueId,
- keyPair);
+ PKCS10CertificationRequest csr = CryptoUtils.createCSR(identityConfig.domain(),
+ identityConfig.service(),
+ document.dnsSuffix,
+ document.providerUniqueId,
+ keyPair);
InstanceRegisterInformation instanceRegisterInformation =
new InstanceRegisterInformation(document.providerService,
identityConfig.domain(),
identityConfig.service(),
rawDocument,
- Pkcs10CsrUtils.toPem(csr));
+ CryptoUtils.toPem(csr));
InstanceIdentity instanceIdentity = athenzService.sendInstanceRegisterRequest(instanceRegisterInformation,
document.ztsEndpoint);
return toAthenzCredentials(instanceIdentity, keyPair, document);
@@ -61,13 +55,13 @@ class AthenzCredentialsService {
AthenzCredentials updateCredentials(AthenzCredentials currentCredentials) {
SignedIdentityDocument document = currentCredentials.getIdentityDocument();
- KeyPair newKeyPair = KeyUtils.generateKeypair(KeyAlgorithm.RSA);
- Pkcs10Csr csr = createCSR(identityConfig.domain(),
- identityConfig.service(),
- document.dnsSuffix,
- document.providerUniqueId,
- newKeyPair);
- InstanceRefreshInformation refreshInfo = new InstanceRefreshInformation(Pkcs10CsrUtils.toPem(csr));
+ KeyPair newKeyPair = CryptoUtils.createKeyPair();
+ PKCS10CertificationRequest csr = CryptoUtils.createCSR(identityConfig.domain(),
+ identityConfig.service(),
+ document.dnsSuffix,
+ document.providerUniqueId,
+ newKeyPair);
+ InstanceRefreshInformation refreshInfo = new InstanceRefreshInformation(CryptoUtils.toPem(csr));
InstanceIdentity instanceIdentity =
athenzService.sendInstanceRefreshRequest(document.providerService,
identityConfig.domain(),
@@ -96,22 +90,4 @@ class AthenzCredentialsService {
}
}
- private static Pkcs10Csr createCSR(String identityDomain,
- String identityService,
- String dnsSuffix,
- String providerUniqueId,
- KeyPair keyPair) {
- X500Principal subject = new X500Principal(String.format("CN=%s.%s", identityDomain, identityService));
- // Add SAN dnsname <service>.<domain-with-dashes>.<provider-dnsname-suffix>
- // and SAN dnsname <provider-unique-instance-id>.instanceid.athenz.<provider-dnsname-suffix>
- return Pkcs10CsrBuilder.fromKeypair(subject, keyPair, SignatureAlgorithm.SHA256_WITH_RSA)
- .addSubjectAlternativeName(String.format("%s.%s.%s",
- identityService,
- identityDomain.replace(".", "-"),
- dnsSuffix))
- .addSubjectAlternativeName(String.format("%s.instanceid.athenz.%s",
- providerUniqueId,
- dnsSuffix))
- .build();
- }
}
diff --git a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/CryptoUtils.java b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/CryptoUtils.java
new file mode 100644
index 00000000000..6e74d3bc8b1
--- /dev/null
+++ b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/CryptoUtils.java
@@ -0,0 +1,113 @@
+// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.athenz.identityprovider;
+
+import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.bouncycastle.asn1.x509.Extension;
+import org.bouncycastle.asn1.x509.ExtensionsGenerator;
+import org.bouncycastle.asn1.x509.GeneralName;
+import org.bouncycastle.asn1.x509.GeneralNames;
+import org.bouncycastle.cert.X509CertificateHolder;
+import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.bouncycastle.openssl.PEMParser;
+import org.bouncycastle.openssl.jcajce.JcaPEMWriter;
+import org.bouncycastle.operator.OperatorCreationException;
+import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
+import org.bouncycastle.pkcs.PKCS10CertificationRequest;
+import org.bouncycastle.pkcs.PKCS10CertificationRequestBuilder;
+import org.bouncycastle.pkcs.jcajce.JcaPKCS10CertificationRequestBuilder;
+import org.bouncycastle.util.io.pem.PemObject;
+
+import javax.security.auth.x500.X500Principal;
+import java.io.IOException;
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.io.UncheckedIOException;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+
+/**
+ * @author bjorncs
+ */
+class CryptoUtils {
+
+ private static final BouncyCastleProvider bouncyCastleProvider = new BouncyCastleProvider();
+
+ private CryptoUtils() {}
+
+ static KeyPair createKeyPair() {
+ try {
+ KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
+ return kpg.generateKeyPair();
+ } catch (NoSuchAlgorithmException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ static PKCS10CertificationRequest createCSR(String identityDomain,
+ String identityService,
+ String dnsSuffix,
+ String providerUniqueId,
+ KeyPair keyPair) {
+ try {
+ // Add SAN dnsname <service>.<domain-with-dashes>.<provider-dnsname-suffix>
+ // and SAN dnsname <provider-unique-instance-id>.instanceid.athenz.<provider-dnsname-suffix>
+ GeneralNames subjectAltNames = new GeneralNames(new GeneralName[]{
+ new GeneralName(GeneralName.dNSName, String.format("%s.%s.%s",
+ identityService,
+ identityDomain.replace(".", "-"),
+ dnsSuffix)),
+ new GeneralName(GeneralName.dNSName, String.format("%s.instanceid.athenz.%s",
+ providerUniqueId,
+ dnsSuffix))
+ });
+
+ ExtensionsGenerator extGen = new ExtensionsGenerator();
+ extGen.addExtension(Extension.subjectAlternativeName, false, subjectAltNames);
+
+ X500Principal subject = new X500Principal(
+ String.format("CN=%s.%s", identityDomain, identityService));
+
+ PKCS10CertificationRequestBuilder requestBuilder =
+ new JcaPKCS10CertificationRequestBuilder(subject, keyPair.getPublic());
+ requestBuilder.addAttribute(PKCSObjectIdentifiers.pkcs_9_at_extensionRequest, extGen.generate());
+ return requestBuilder.build(new JcaContentSignerBuilder("SHA256withRSA").build(keyPair.getPrivate()));
+ } catch (OperatorCreationException e) {
+ throw new RuntimeException(e);
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ }
+
+ static String toPem(PKCS10CertificationRequest csr) {
+ try (StringWriter stringWriter = new StringWriter(); JcaPEMWriter pemWriter = new JcaPEMWriter(stringWriter)) {
+ pemWriter.writeObject(new PemObject("CERTIFICATE REQUEST", csr.getEncoded()));
+ pemWriter.flush();
+ return stringWriter.toString();
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ }
+
+ static X509Certificate parseCertificate(String pemEncodedCertificate) {
+ try (PEMParser parser = new PEMParser(new StringReader(pemEncodedCertificate))) {
+ Object pemObject = parser.readObject();
+ if (pemObject instanceof X509Certificate) {
+ return (X509Certificate) pemObject;
+ }
+ if (pemObject instanceof X509CertificateHolder) {
+ return new JcaX509CertificateConverter()
+ .setProvider(bouncyCastleProvider)
+ .getCertificate((X509CertificateHolder) pemObject);
+ }
+ throw new IllegalArgumentException("Invalid type of PEM object: " + pemObject);
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ } catch (CertificateException e) {
+ throw new RuntimeException(e);
+ }
+ }
+}
diff --git a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/InstanceIdentity.java b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/InstanceIdentity.java
index 899ff7a95d7..b90ce56ca7e 100644
--- a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/InstanceIdentity.java
+++ b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/InstanceIdentity.java
@@ -8,7 +8,6 @@ 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 com.yahoo.vespa.athenz.tls.X509CertificateUtils;
import java.io.IOException;
import java.security.cert.X509Certificate;
@@ -42,7 +41,7 @@ public class InstanceIdentity {
public static class X509CertificateDeserializer extends JsonDeserializer<X509Certificate> {
@Override
public X509Certificate deserialize(JsonParser parser, DeserializationContext context) throws IOException {
- return X509CertificateUtils.fromPem(parser.getValueAsString());
+ return CryptoUtils.parseCertificate(parser.getValueAsString());
}
}
diff --git a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/tls/BasicConstraintsExtension.java b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/tls/BasicConstraintsExtension.java
deleted file mode 100644
index 008268dbfe0..00000000000
--- a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/tls/BasicConstraintsExtension.java
+++ /dev/null
@@ -1,14 +0,0 @@
-// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.vespa.athenz.tls;
-
-/**
- * @author bjorncs
- */
-class BasicConstraintsExtension {
- final boolean isCritical, isCertAuthorityCertificate;
-
- BasicConstraintsExtension(boolean isCritical, boolean isCertAuthorityCertificate) {
- this.isCritical = isCritical;
- this.isCertAuthorityCertificate = isCertAuthorityCertificate;
- }
-}
diff --git a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/tls/BouncyCastleProviderHolder.java b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/tls/BouncyCastleProviderHolder.java
deleted file mode 100644
index 03049961dc0..00000000000
--- a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/tls/BouncyCastleProviderHolder.java
+++ /dev/null
@@ -1,14 +0,0 @@
-// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.vespa.athenz.tls;
-
-import org.bouncycastle.jce.provider.BouncyCastleProvider;
-
-/**
- * @author bjorncs
- */
-class BouncyCastleProviderHolder {
-
- private static final BouncyCastleProvider bcProvider = new BouncyCastleProvider();
-
- static BouncyCastleProvider getInstance() { return bcProvider; }
-}
diff --git a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/tls/Extension.java b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/tls/Extension.java
deleted file mode 100644
index 18403669c4d..00000000000
--- a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/tls/Extension.java
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.vespa.athenz.tls;
-
-import org.bouncycastle.asn1.ASN1ObjectIdentifier;
-
-/**
- * @author bjorncs
- */
-public enum Extension {
- BASIC_CONSTRAINS(org.bouncycastle.asn1.x509.Extension.basicConstraints),
- SUBJECT_ALTERNATIVE_NAMES(org.bouncycastle.asn1.x509.Extension.subjectAlternativeName);
-
- final ASN1ObjectIdentifier extensionOId;
-
- Extension(ASN1ObjectIdentifier extensionOId) {
- this.extensionOId = extensionOId;
- }
-
- public String getOId() {
- return extensionOId.getId();
- }
-}
diff --git a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/tls/KeyAlgorithm.java b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/tls/KeyAlgorithm.java
deleted file mode 100644
index 4c4198adaac..00000000000
--- a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/tls/KeyAlgorithm.java
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.vespa.athenz.tls;
-
-/**
- * @author bjorncs
- */
-public enum KeyAlgorithm {
- RSA("RSA");
-
- private final String algorithmName;
-
- KeyAlgorithm(String algorithmName) {
- this.algorithmName = algorithmName;
- }
-
- String getAlgorithmName() {
- return algorithmName;
- }
-}
diff --git a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/tls/KeyStoreType.java b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/tls/KeyStoreType.java
index 6c08a60ff5b..a5c35549540 100644
--- a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/tls/KeyStoreType.java
+++ b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/tls/KeyStoreType.java
@@ -17,8 +17,10 @@ public enum KeyStoreType {
}
},
PKCS12 {
+ private final BouncyCastleProvider bouncyCastleProvider = new BouncyCastleProvider();
+
KeyStore createKeystore() throws KeyStoreException {
- return KeyStore.getInstance("PKCS12", BouncyCastleProviderHolder.getInstance());
+ return KeyStore.getInstance("PKCS12", bouncyCastleProvider);
}
};
abstract KeyStore createKeystore() throws GeneralSecurityException;
diff --git a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/tls/KeyUtils.java b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/tls/KeyUtils.java
deleted file mode 100644
index f49e1324ba5..00000000000
--- a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/tls/KeyUtils.java
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.vespa.athenz.tls;
-
-import com.yahoo.athenz.auth.util.Crypto;
-
-import java.security.GeneralSecurityException;
-import java.security.KeyPair;
-import java.security.KeyPairGenerator;
-import java.security.PrivateKey;
-import java.security.PublicKey;
-
-/**
- * @author bjorncs
- */
-public class KeyUtils {
- private KeyUtils() {}
-
- public static KeyPair generateKeypair(KeyAlgorithm algorithm, int keySize) {
- try {
- KeyPairGenerator keyGen = KeyPairGenerator.getInstance(algorithm.getAlgorithmName());
- if (keySize != -1) {
- keyGen.initialize(keySize);
- }
- return keyGen.genKeyPair();
- } catch (GeneralSecurityException e) {
- throw new RuntimeException(e);
- }
- }
-
- public static KeyPair generateKeypair(KeyAlgorithm algorithm) {
- return generateKeypair(algorithm, -1);
- }
-
- public static PublicKey extractPublicKey(PrivateKey privateKey) {
- return Crypto.extractPublicKey(privateKey);
- }
-
- public static PrivateKey fromPemEncodedPrivateKey(String pem) {
- return Crypto.loadPrivateKey(pem);
- }
-}
diff --git a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/tls/Pkcs10Csr.java b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/tls/Pkcs10Csr.java
deleted file mode 100644
index d9cd3141f19..00000000000
--- a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/tls/Pkcs10Csr.java
+++ /dev/null
@@ -1,90 +0,0 @@
-// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.vespa.athenz.tls;
-
-import org.bouncycastle.asn1.ASN1Encodable;
-import org.bouncycastle.asn1.ASN1ObjectIdentifier;
-import org.bouncycastle.asn1.DERIA5String;
-import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
-import org.bouncycastle.asn1.x500.X500Name;
-import org.bouncycastle.asn1.x509.BasicConstraints;
-import org.bouncycastle.asn1.x509.Extension;
-import org.bouncycastle.asn1.x509.Extensions;
-import org.bouncycastle.asn1.x509.GeneralName;
-import org.bouncycastle.asn1.x509.GeneralNames;
-import org.bouncycastle.pkcs.PKCS10CertificationRequest;
-
-import javax.security.auth.x500.X500Principal;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Optional;
-
-import static java.util.Collections.emptyList;
-import static java.util.stream.Collectors.toList;
-
-/**
- * @author bjorncs
- */
-public class Pkcs10Csr {
-
- private final PKCS10CertificationRequest csr;
-
- Pkcs10Csr(PKCS10CertificationRequest csr) {
- this.csr = csr;
- }
-
- PKCS10CertificationRequest getBcCsr() {
- return csr;
- }
-
- public X500Principal getSubject() {
- return new X500Principal(csr.getSubject().toString());
- }
-
- public List<String> getSubjectAlternativeNames() {
- return getExtensions()
- .map(extensions -> GeneralNames.fromExtensions(extensions, Extension.subjectAlternativeName))
- .map(generalNames -> Arrays.stream(generalNames.getNames())
- .map(Pkcs10Csr::toString)
- .collect(toList()))
- .orElse(emptyList());
- }
-
- /**
- * @return If basic constraints extension is present: returns true if CA cert, false otherwise. Returns empty if the extension is not present.
- */
- public Optional<Boolean> getBasicConstraints() {
- return getExtensions()
- .map(BasicConstraints::fromExtensions)
- .map(BasicConstraints::isCA);
- }
-
- public List<String> getExtensionOIds() {
- return getExtensions()
- .map(extensions -> Arrays.stream(extensions.getExtensionOIDs())
- .map(ASN1ObjectIdentifier::getId)
- .collect(toList()))
- .orElse(emptyList());
-
- }
-
- private Optional<Extensions> getExtensions() {
- return Optional.of(csr.getAttributes(PKCSObjectIdentifiers.pkcs_9_at_extensionRequest))
- .filter(attributes -> attributes.length > 0)
- .map(attributes -> attributes[0])
- .map(attribute -> Extensions.getInstance(attribute.getAttrValues().getObjectAt(0)));
- }
-
- private static String toString(GeneralName generalName) {
- ASN1Encodable name = generalName.getName();
- switch (generalName.getTagNo()) {
- case GeneralName.rfc822Name:
- case GeneralName.dNSName:
- case GeneralName.uniformResourceIdentifier:
- return DERIA5String.getInstance(name).getString();
- case GeneralName.directoryName:
- return X500Name.getInstance(name).toString();
- default:
- return name.toString();
- }
- }
-}
diff --git a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/tls/Pkcs10CsrBuilder.java b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/tls/Pkcs10CsrBuilder.java
deleted file mode 100644
index 9c2cd9d4d9f..00000000000
--- a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/tls/Pkcs10CsrBuilder.java
+++ /dev/null
@@ -1,89 +0,0 @@
-// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.vespa.athenz.tls;
-
-import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
-import org.bouncycastle.asn1.x509.BasicConstraints;
-import org.bouncycastle.asn1.x509.Extension;
-import org.bouncycastle.asn1.x509.ExtensionsGenerator;
-import org.bouncycastle.asn1.x509.GeneralName;
-import org.bouncycastle.asn1.x509.GeneralNames;
-import org.bouncycastle.operator.ContentSigner;
-import org.bouncycastle.operator.OperatorCreationException;
-import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
-import org.bouncycastle.pkcs.PKCS10CertificationRequestBuilder;
-import org.bouncycastle.pkcs.jcajce.JcaPKCS10CertificationRequestBuilder;
-
-import javax.security.auth.x500.X500Principal;
-import java.io.IOException;
-import java.io.UncheckedIOException;
-import java.security.KeyPair;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * @author bjorncs
- */
-public class Pkcs10CsrBuilder {
-
- private final X500Principal subject;
- private final KeyPair keyPair;
- private final List<String> subjectAlternativeNames = new ArrayList<>();
- private final SignatureAlgorithm signatureAlgorithm;
- private BasicConstraintsExtension basicConstraintsExtension;
-
- private Pkcs10CsrBuilder(X500Principal subject,
- KeyPair keyPair,
- SignatureAlgorithm signatureAlgorithm) {
- this.subject = subject;
- this.keyPair = keyPair;
- this.signatureAlgorithm = signatureAlgorithm;
- }
-
- public static Pkcs10CsrBuilder fromKeypair(X500Principal subject,
- KeyPair keyPair,
- SignatureAlgorithm signatureAlgorithm) {
- return new Pkcs10CsrBuilder(subject, keyPair, signatureAlgorithm);
- }
-
- public Pkcs10CsrBuilder addSubjectAlternativeName(String san) {
- this.subjectAlternativeNames.add(san);
- return this;
- }
-
- public Pkcs10CsrBuilder setBasicConstraints(boolean isCritical, boolean isCertAuthorityCertificate) {
- this.basicConstraintsExtension = new BasicConstraintsExtension(isCritical, isCertAuthorityCertificate);
- return this;
- }
-
- public Pkcs10Csr build() {
- try {
- PKCS10CertificationRequestBuilder requestBuilder =
- new JcaPKCS10CertificationRequestBuilder(subject, keyPair.getPublic());
- ExtensionsGenerator extGen = new ExtensionsGenerator();
- if (basicConstraintsExtension != null) {
- extGen.addExtension(
- Extension.basicConstraints,
- basicConstraintsExtension.isCritical,
- new BasicConstraints(basicConstraintsExtension.isCertAuthorityCertificate));
- }
- if (!subjectAlternativeNames.isEmpty()) {
- GeneralNames generalNames = new GeneralNames(
- subjectAlternativeNames.stream()
- .map(san -> new GeneralName(GeneralName.dNSName, san))
- .toArray(GeneralName[]::new));
- extGen.addExtension(Extension.subjectAlternativeName, false, generalNames);
- }
- requestBuilder.addAttribute(PKCSObjectIdentifiers.pkcs_9_at_extensionRequest, extGen.generate());
- ContentSigner contentSigner = new JcaContentSignerBuilder(signatureAlgorithm.getAlgorithmName())
- .setProvider(BouncyCastleProviderHolder.getInstance())
- .build(keyPair.getPrivate());
- return new Pkcs10Csr(requestBuilder.build(contentSigner));
- } catch (OperatorCreationException e) {
- throw new RuntimeException(e);
- } catch (IOException e) {
- throw new UncheckedIOException(e);
- }
-
- }
-
-}
diff --git a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/tls/Pkcs10CsrUtils.java b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/tls/Pkcs10CsrUtils.java
deleted file mode 100644
index 2289c9ac0ee..00000000000
--- a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/tls/Pkcs10CsrUtils.java
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.vespa.athenz.tls;
-
-import org.bouncycastle.openssl.PEMParser;
-import org.bouncycastle.openssl.jcajce.JcaPEMWriter;
-import org.bouncycastle.pkcs.PKCS10CertificationRequest;
-import org.bouncycastle.util.io.pem.PemObject;
-
-import java.io.IOException;
-import java.io.StringReader;
-import java.io.StringWriter;
-import java.io.UncheckedIOException;
-
-/**
- * @author bjorncs
- */
-public class Pkcs10CsrUtils {
-
- private Pkcs10CsrUtils() {}
-
- public static Pkcs10Csr fromPem(String pem) {
- try (PEMParser pemParser = new PEMParser(new StringReader(pem))) {
- return new Pkcs10Csr((PKCS10CertificationRequest) pemParser.readObject());
- } catch (IOException e) {
- throw new UncheckedIOException(e);
- }
- }
-
- public static String toPem(Pkcs10Csr csr) {
- try (StringWriter stringWriter = new StringWriter(); JcaPEMWriter pemWriter = new JcaPEMWriter(stringWriter)) {
- pemWriter.writeObject(new PemObject("CERTIFICATE REQUEST", csr.getBcCsr().getEncoded()));
- pemWriter.flush();
- return stringWriter.toString();
- } catch (IOException e) {
- throw new UncheckedIOException(e);
- }
- }
-}
diff --git a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/tls/SignatureAlgorithm.java b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/tls/SignatureAlgorithm.java
deleted file mode 100644
index 3d85a12f714..00000000000
--- a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/tls/SignatureAlgorithm.java
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.vespa.athenz.tls;
-
-/**
- * @author bjorncs
- */
-public enum SignatureAlgorithm {
- SHA256_WITH_RSA("SHA256withRSA");
-
- private final String algorithmName;
-
- SignatureAlgorithm(String algorithmName) {
- this.algorithmName = algorithmName;
- }
-
- public String getAlgorithmName() {
- return algorithmName;
- }
-}
diff --git a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/tls/X509CertificateBuilder.java b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/tls/X509CertificateBuilder.java
deleted file mode 100644
index ba22af13fd2..00000000000
--- a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/tls/X509CertificateBuilder.java
+++ /dev/null
@@ -1,145 +0,0 @@
-// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.vespa.athenz.tls;
-
-import org.bouncycastle.asn1.x509.BasicConstraints;
-import org.bouncycastle.asn1.x509.Extension;
-import org.bouncycastle.asn1.x509.GeneralName;
-import org.bouncycastle.asn1.x509.GeneralNames;
-import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
-import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder;
-import org.bouncycastle.operator.ContentSigner;
-import org.bouncycastle.operator.OperatorException;
-import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
-import org.bouncycastle.pkcs.PKCS10CertificationRequest;
-import org.bouncycastle.pkcs.jcajce.JcaPKCS10CertificationRequest;
-
-import javax.security.auth.x500.X500Principal;
-import java.io.IOException;
-import java.io.UncheckedIOException;
-import java.math.BigInteger;
-import java.security.GeneralSecurityException;
-import java.security.KeyPair;
-import java.security.PrivateKey;
-import java.security.PublicKey;
-import java.security.cert.X509Certificate;
-import java.sql.Date;
-import java.time.Instant;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * @author bjorncs
- */
-public class X509CertificateBuilder {
-
- private final long serialNumber;
- private final SignatureAlgorithm signingAlgorithm;
- private final PrivateKey caPrivateKey;
- private final Instant notBefore;
- private final Instant notAfter;
- private final List<String> subjectAlternativeNames = new ArrayList<>();
- private final X500Principal issuer;
- private final X500Principal subject;
- private final PublicKey certPublicKey;
- private BasicConstraintsExtension basicConstraintsExtension;
-
- private X509CertificateBuilder(X500Principal issuer,
- X500Principal subject,
- Instant notBefore,
- Instant notAfter,
- PublicKey certPublicKey,
- PrivateKey caPrivateKey,
- SignatureAlgorithm signingAlgorithm,
- long serialNumber) {
- this.issuer = issuer;
- this.subject = subject;
- this.notBefore = notBefore;
- this.notAfter = notAfter;
- this.certPublicKey = certPublicKey;
- this.caPrivateKey = caPrivateKey;
- this.signingAlgorithm = signingAlgorithm;
- this.serialNumber = serialNumber;
- }
-
- public static X509CertificateBuilder fromCsr(Pkcs10Csr csr,
- X500Principal caIssuer,
- Instant notBefore,
- Instant notAfter,
- PrivateKey caPrivateKey,
- SignatureAlgorithm signingAlgorithm,
- long serialNumber) {
- try {
- PKCS10CertificationRequest bcCsr = csr.getBcCsr();
- PublicKey publicKey = new JcaPKCS10CertificationRequest(bcCsr).getPublicKey();
- return new X509CertificateBuilder(caIssuer,
- new X500Principal(bcCsr.getSubject().getEncoded()),
- notBefore,
- notAfter,
- publicKey,
- caPrivateKey,
- signingAlgorithm,
- serialNumber);
- } catch (GeneralSecurityException e) {
- throw new RuntimeException(e);
- } catch (IOException e) {
- throw new UncheckedIOException(e);
- }
- }
-
- public static X509CertificateBuilder fromKeypair(KeyPair keyPair,
- X500Principal subject,
- Instant notBefore,
- Instant notAfter,
- SignatureAlgorithm signingAlgorithm,
- long serialNumber) {
- return new X509CertificateBuilder(subject,
- subject,
- notBefore,
- notAfter,
- keyPair.getPublic(),
- keyPair.getPrivate(),
- signingAlgorithm,
- serialNumber);
- }
-
- public X509CertificateBuilder addSubjectAlternativeName(String san) {
- this.subjectAlternativeNames.add(san);
- return this;
- }
-
- public X509CertificateBuilder setBasicConstraints(boolean isCritical, boolean isCertAuthorityCertificate) {
- this.basicConstraintsExtension = new BasicConstraintsExtension(isCritical, isCertAuthorityCertificate);
- return this;
- }
-
- public X509Certificate build() {
- try {
- JcaX509v3CertificateBuilder jcaCertBuilder = new JcaX509v3CertificateBuilder(
- issuer, BigInteger.valueOf(serialNumber), Date.from(notBefore), Date.from(notAfter), subject, certPublicKey);
- if (basicConstraintsExtension != null) {
- jcaCertBuilder.addExtension(
- Extension.basicConstraints,
- basicConstraintsExtension.isCritical,
- new BasicConstraints(basicConstraintsExtension.isCertAuthorityCertificate));
- }
- if (!subjectAlternativeNames.isEmpty()) {
- GeneralNames generalNames = new GeneralNames(
- subjectAlternativeNames.stream()
- .map(san -> new GeneralName(GeneralName.dNSName, san))
- .toArray(GeneralName[]::new));
- jcaCertBuilder.addExtension(Extension.subjectAlternativeName, false, generalNames);
- }
- ContentSigner contentSigner = new JcaContentSignerBuilder(signingAlgorithm.getAlgorithmName())
- .setProvider(BouncyCastleProviderHolder.getInstance())
- .build(caPrivateKey);
- return new JcaX509CertificateConverter()
- .setProvider(BouncyCastleProviderHolder.getInstance())
- .getCertificate(jcaCertBuilder.build(contentSigner));
- } catch (OperatorException | GeneralSecurityException e) {
- throw new RuntimeException(e);
- } catch (IOException e) {
- throw new UncheckedIOException(e);
- }
- }
-
-}
diff --git a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/tls/X509CertificateUtils.java b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/tls/X509CertificateUtils.java
deleted file mode 100644
index 3e1bd3eb31c..00000000000
--- a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/tls/X509CertificateUtils.java
+++ /dev/null
@@ -1,78 +0,0 @@
-// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.vespa.athenz.tls;
-
-import org.bouncycastle.cert.X509CertificateHolder;
-import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
-import org.bouncycastle.openssl.PEMParser;
-import org.bouncycastle.openssl.jcajce.JcaPEMWriter;
-import org.bouncycastle.util.io.pem.PemObject;
-
-import javax.naming.NamingException;
-import javax.naming.ldap.LdapName;
-import javax.security.auth.x500.X500Principal;
-import java.io.IOException;
-import java.io.StringReader;
-import java.io.StringWriter;
-import java.io.UncheckedIOException;
-import java.security.GeneralSecurityException;
-import java.security.cert.CertificateException;
-import java.security.cert.X509Certificate;
-import java.util.List;
-
-import static java.util.stream.Collectors.toList;
-
-/**
- * @author bjorncs
- */
-public class X509CertificateUtils {
-
- private X509CertificateUtils() {}
-
- public static X509Certificate fromPem(String pem) {
- try (PEMParser parser = new PEMParser(new StringReader(pem))) {
- Object pemObject = parser.readObject();
- if (pemObject instanceof X509Certificate) {
- return (X509Certificate) pemObject;
- }
- if (pemObject instanceof X509CertificateHolder) {
- return new JcaX509CertificateConverter()
- .setProvider(BouncyCastleProviderHolder.getInstance())
- .getCertificate((X509CertificateHolder) pemObject);
- }
- throw new IllegalArgumentException("Invalid type of PEM object: " + pemObject);
- } catch (IOException e) {
- throw new UncheckedIOException(e);
- } catch (CertificateException e) {
- throw new RuntimeException(e);
- }
- }
-
- public static String toPem(X509Certificate certificate) {
- try (StringWriter stringWriter = new StringWriter(); JcaPEMWriter pemWriter = new JcaPEMWriter(stringWriter)) {
- pemWriter.writeObject(new PemObject("CERTIFICATE", certificate.getEncoded()));
- pemWriter.flush();
- return stringWriter.toString();
- } catch (GeneralSecurityException e) {
- throw new RuntimeException(e);
- } catch (IOException e) {
- throw new UncheckedIOException(e);
- }
- }
-
- public static List<String> getCommonNames(X509Certificate certificate) {
- return getCommonNames(certificate.getSubjectX500Principal());
- }
-
- public static List<String> getCommonNames(X500Principal subject) {
- try {
- String subjectPrincipal = subject.getName();
- return new LdapName(subjectPrincipal).getRdns().stream()
- .filter(rdn -> rdn.getType().equalsIgnoreCase("cn"))
- .map(rdn -> rdn.getValue().toString())
- .collect(toList());
- } catch (NamingException e) {
- throw new IllegalArgumentException("Invalid CN: " + e, e);
- }
-
- }
-}
diff --git a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/utils/AthenzIdentities.java b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/utils/AthenzIdentities.java
index ad2428cc292..fd34263e387 100644
--- a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/utils/AthenzIdentities.java
+++ b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/utils/AthenzIdentities.java
@@ -5,10 +5,10 @@ import com.yahoo.vespa.athenz.api.AthenzDomain;
import com.yahoo.vespa.athenz.api.AthenzIdentity;
import com.yahoo.vespa.athenz.api.AthenzService;
import com.yahoo.vespa.athenz.api.AthenzUser;
-import com.yahoo.vespa.athenz.tls.X509CertificateUtils;
+import javax.naming.NamingException;
+import javax.naming.ldap.LdapName;
import java.security.cert.X509Certificate;
-import java.util.List;
/**
* @author bjorncs
@@ -53,11 +53,15 @@ public class AthenzIdentities {
}
private static String getCommonName(X509Certificate certificate) {
- List<String> commonNames = X509CertificateUtils.getCommonNames(certificate);
- if (commonNames.size() != 1) {
- String subjectName = certificate.getSubjectX500Principal().getName();
- throw new IllegalArgumentException("Expected single CN in certificate's subject: " + subjectName);
+ try {
+ String subjectPrincipal = certificate.getSubjectX500Principal().getName();
+ return new LdapName(subjectPrincipal).getRdns().stream()
+ .filter(rdn -> rdn.getType().equalsIgnoreCase("cn"))
+ .map(rdn -> rdn.getValue().toString())
+ .findFirst()
+ .orElseThrow(() -> new IllegalArgumentException("Could not find CN in certificate: " + subjectPrincipal));
+ } catch (NamingException e) {
+ throw new IllegalArgumentException("Invalid CN: " + e, e);
}
- return commonNames.get(0);
}
}
diff --git a/vespa-athenz/src/test/java/com/yahoo/vespa/athenz/identityprovider/CryptoUtilsTest.java b/vespa-athenz/src/test/java/com/yahoo/vespa/athenz/identityprovider/CryptoUtilsTest.java
new file mode 100644
index 00000000000..353c5d3c504
--- /dev/null
+++ b/vespa-athenz/src/test/java/com/yahoo/vespa/athenz/identityprovider/CryptoUtilsTest.java
@@ -0,0 +1,28 @@
+// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.athenz.identityprovider;
+
+import org.bouncycastle.pkcs.PKCS10CertificationRequest;
+import org.junit.Test;
+
+import java.io.IOException;
+import java.security.KeyPair;
+
+import static org.hamcrest.CoreMatchers.containsString;
+import static org.junit.Assert.assertThat;
+
+/**
+ * @author bjorncs
+ */
+public class CryptoUtilsTest {
+
+ @Test
+ public void certificate_signing_request_is_correct_and_can_be_serialized_to_pem() throws IOException {
+ KeyPair keyPair = CryptoUtils.createKeyPair();
+ PKCS10CertificationRequest csr = CryptoUtils.createCSR(
+ "identity-domain", "identity-service", "vespa.cloud.com", "unique.instance.id", keyPair);
+ String pem = CryptoUtils.toPem(csr);
+ assertThat(pem, containsString("BEGIN CERTIFICATE REQUEST"));
+ assertThat(pem, containsString("END CERTIFICATE REQUEST"));
+ }
+
+}
diff --git a/vespa-athenz/src/test/java/com/yahoo/vespa/athenz/tls/AthenzSslContextBuilderTest.java b/vespa-athenz/src/test/java/com/yahoo/vespa/athenz/tls/AthenzSslContextBuilderTest.java
index cf1b2168dc8..20ac8791863 100644
--- a/vespa-athenz/src/test/java/com/yahoo/vespa/athenz/tls/AthenzSslContextBuilderTest.java
+++ b/vespa-athenz/src/test/java/com/yahoo/vespa/athenz/tls/AthenzSslContextBuilderTest.java
@@ -10,6 +10,7 @@ import java.security.KeyPair;
import java.security.cert.X509Certificate;
import static com.yahoo.vespa.athenz.tls.TestUtils.createCertificate;
+import static com.yahoo.vespa.athenz.tls.TestUtils.createKeyPair;
import static com.yahoo.vespa.athenz.tls.TestUtils.createKeystore;
import static com.yahoo.vespa.athenz.tls.TestUtils.createKeystoreFile;
@@ -47,7 +48,7 @@ public class AthenzSslContextBuilderTest {
@Test
public void can_build_sslcontext_with_keystore_from_private_key_and_certificate() throws Exception {
- KeyPair keyPair = KeyUtils.generateKeypair(KeyAlgorithm.RSA, 2048);
+ KeyPair keyPair = createKeyPair();
X509Certificate certificate = createCertificate(keyPair);
new AthenzSslContextBuilder()
.withKeyStore(keyPair.getPrivate(), certificate)
diff --git a/vespa-athenz/src/test/java/com/yahoo/vespa/athenz/tls/KeyStoreBuilderTest.java b/vespa-athenz/src/test/java/com/yahoo/vespa/athenz/tls/KeyStoreBuilderTest.java
index 6060f6f3521..1b6fa8bcbf1 100644
--- a/vespa-athenz/src/test/java/com/yahoo/vespa/athenz/tls/KeyStoreBuilderTest.java
+++ b/vespa-athenz/src/test/java/com/yahoo/vespa/athenz/tls/KeyStoreBuilderTest.java
@@ -9,6 +9,7 @@ import java.security.KeyPair;
import java.security.cert.X509Certificate;
import static com.yahoo.vespa.athenz.tls.TestUtils.createCertificate;
+import static com.yahoo.vespa.athenz.tls.TestUtils.createKeyPair;
import static com.yahoo.vespa.athenz.tls.TestUtils.createKeystoreFile;
/**
@@ -23,7 +24,7 @@ public class KeyStoreBuilderTest {
@Test
public void can_create_jks_keystore_from_privatekey_and_certificate() throws Exception {
- KeyPair keyPair = KeyUtils.generateKeypair(KeyAlgorithm.RSA, 4096);
+ KeyPair keyPair = createKeyPair();
X509Certificate certificate = createCertificate(keyPair);
KeyStoreBuilder.withType(KeyStoreType.JKS)
.withKeyEntry("key", keyPair.getPrivate(), certificate)
diff --git a/vespa-athenz/src/test/java/com/yahoo/vespa/athenz/tls/KeyUtilsTest.java b/vespa-athenz/src/test/java/com/yahoo/vespa/athenz/tls/KeyUtilsTest.java
deleted file mode 100644
index a8730a31838..00000000000
--- a/vespa-athenz/src/test/java/com/yahoo/vespa/athenz/tls/KeyUtilsTest.java
+++ /dev/null
@@ -1,22 +0,0 @@
-package com.yahoo.vespa.athenz.tls;
-
-import org.junit.Test;
-
-import java.security.KeyPair;
-import java.security.PublicKey;
-
-import static org.junit.Assert.assertNotNull;
-
-/**
- * @author bjorncs
- */
-public class KeyUtilsTest {
-
- @Test
- public void can_extract_public_key_from_private() {
- KeyPair keyPair = KeyUtils.generateKeypair(KeyAlgorithm.RSA);
- PublicKey publicKey = KeyUtils.extractPublicKey(keyPair.getPrivate());
- assertNotNull(publicKey);
- }
-
-} \ No newline at end of file
diff --git a/vespa-athenz/src/test/java/com/yahoo/vespa/athenz/tls/Pkcs10CsrBuilderTest.java b/vespa-athenz/src/test/java/com/yahoo/vespa/athenz/tls/Pkcs10CsrBuilderTest.java
deleted file mode 100644
index e3aaba66efe..00000000000
--- a/vespa-athenz/src/test/java/com/yahoo/vespa/athenz/tls/Pkcs10CsrBuilderTest.java
+++ /dev/null
@@ -1,27 +0,0 @@
-package com.yahoo.vespa.athenz.tls;
-
-import org.junit.Test;
-
-import javax.security.auth.x500.X500Principal;
-
-import java.security.KeyPair;
-
-import static org.junit.Assert.*;
-
-/**
- * @author bjorncs
- */
-public class Pkcs10CsrBuilderTest {
-
- @Test
- public void can_build_csr_with_sans() {
- X500Principal subject = new X500Principal("CN=subject");
- KeyPair keypair = KeyUtils.generateKeypair(KeyAlgorithm.RSA, 2048);
- Pkcs10Csr csr = Pkcs10CsrBuilder.fromKeypair(subject, keypair, SignatureAlgorithm.SHA256_WITH_RSA)
- .addSubjectAlternativeName("san1.com")
- .addSubjectAlternativeName("san2.com")
- .build();
- assertEquals(subject, csr.getSubject());
- }
-
-} \ No newline at end of file
diff --git a/vespa-athenz/src/test/java/com/yahoo/vespa/athenz/tls/Pkcs10CsrTest.java b/vespa-athenz/src/test/java/com/yahoo/vespa/athenz/tls/Pkcs10CsrTest.java
deleted file mode 100644
index bb2e80ba705..00000000000
--- a/vespa-athenz/src/test/java/com/yahoo/vespa/athenz/tls/Pkcs10CsrTest.java
+++ /dev/null
@@ -1,55 +0,0 @@
-package com.yahoo.vespa.athenz.tls;
-
-import org.junit.Test;
-
-import javax.security.auth.x500.X500Principal;
-import java.security.KeyPair;
-import java.util.Arrays;
-import java.util.List;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
-/**
- * @author bjorncs
- */
-public class Pkcs10CsrTest {
-
- @Test
- public void can_read_subject_alternative_names() {
- X500Principal subject = new X500Principal("CN=subject");
- KeyPair keypair = KeyUtils.generateKeypair(KeyAlgorithm.RSA, 2048);
- String san1 = "san1.com";
- String san2 = "san2.com";
- Pkcs10Csr csr = Pkcs10CsrBuilder.fromKeypair(subject, keypair, SignatureAlgorithm.SHA256_WITH_RSA)
- .addSubjectAlternativeName(san1)
- .addSubjectAlternativeName(san2)
- .build();
- assertEquals(Arrays.asList(san1, san2), csr.getSubjectAlternativeNames());
- }
-
- @Test
- public void can_read_basic_constraints() {
- X500Principal subject = new X500Principal("CN=subject");
- KeyPair keypair = KeyUtils.generateKeypair(KeyAlgorithm.RSA, 2048);
- Pkcs10Csr csr = Pkcs10CsrBuilder.fromKeypair(subject, keypair, SignatureAlgorithm.SHA256_WITH_RSA)
- .setBasicConstraints(true, true)
- .build();
- assertTrue(csr.getBasicConstraints().isPresent());
- assertTrue(csr.getBasicConstraints().get());
- }
-
- @Test
- public void can_read_extensions() {
- X500Principal subject = new X500Principal("CN=subject");
- KeyPair keypair = KeyUtils.generateKeypair(KeyAlgorithm.RSA, 2048);
- Pkcs10Csr csr = Pkcs10CsrBuilder.fromKeypair(subject, keypair, SignatureAlgorithm.SHA256_WITH_RSA)
- .addSubjectAlternativeName("san")
- .setBasicConstraints(true, true)
- .build();
- List<String> expected = Arrays.asList(Extension.BASIC_CONSTRAINS.getOId(), Extension.SUBJECT_ALTERNATIVE_NAMES.getOId());
- List<String> actual = csr.getExtensionOIds();
- assertEquals(expected, actual);
- }
-
-} \ No newline at end of file
diff --git a/vespa-athenz/src/test/java/com/yahoo/vespa/athenz/tls/Pkcs10CsrUtilsTest.java b/vespa-athenz/src/test/java/com/yahoo/vespa/athenz/tls/Pkcs10CsrUtilsTest.java
deleted file mode 100644
index 5b5a57f1fcc..00000000000
--- a/vespa-athenz/src/test/java/com/yahoo/vespa/athenz/tls/Pkcs10CsrUtilsTest.java
+++ /dev/null
@@ -1,29 +0,0 @@
-package com.yahoo.vespa.athenz.tls;
-
-import org.junit.Test;
-
-import javax.security.auth.x500.X500Principal;
-import java.security.KeyPair;
-
-import static org.hamcrest.CoreMatchers.containsString;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertThat;
-
-/**
- * @author bjorncs
- */
-public class Pkcs10CsrUtilsTest {
-
- @Test
- public void can_deserialize_serialized_pem_csr() {
- X500Principal subject = new X500Principal("CN=subject");
- KeyPair keypair = KeyUtils.generateKeypair(KeyAlgorithm.RSA, 2048);
- Pkcs10Csr csr = Pkcs10CsrBuilder.fromKeypair(subject, keypair, SignatureAlgorithm.SHA256_WITH_RSA).build();
- String pem = Pkcs10CsrUtils.toPem(csr);
- Pkcs10Csr deserializedCsr = Pkcs10CsrUtils.fromPem(pem);
- assertThat(pem, containsString("BEGIN CERTIFICATE REQUEST"));
- assertThat(pem, containsString("END CERTIFICATE REQUEST"));
- assertEquals(subject, deserializedCsr.getSubject());
- }
-
-} \ No newline at end of file
diff --git a/vespa-athenz/src/test/java/com/yahoo/vespa/athenz/tls/TestUtils.java b/vespa-athenz/src/test/java/com/yahoo/vespa/athenz/tls/TestUtils.java
index 64f15408313..54601c04514 100644
--- a/vespa-athenz/src/test/java/com/yahoo/vespa/athenz/tls/TestUtils.java
+++ b/vespa-athenz/src/test/java/com/yahoo/vespa/athenz/tls/TestUtils.java
@@ -1,13 +1,23 @@
// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.athenz.tls;
-import javax.security.auth.x500.X500Principal;
+import com.yahoo.athenz.auth.util.Crypto;
+import org.bouncycastle.asn1.x500.X500Name;
+import org.bouncycastle.operator.OperatorCreationException;
+import org.bouncycastle.pkcs.PKCS10CertificationRequest;
+
+import java.io.BufferedOutputStream;
import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.security.GeneralSecurityException;
import java.security.KeyPair;
+import java.security.KeyPairGenerator;
import java.security.KeyStore;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
-import java.time.Instant;
-import java.time.temporal.ChronoUnit;
import static com.yahoo.vespa.athenz.tls.KeyStoreUtils.writeKeyStoreToFile;
@@ -16,22 +26,32 @@ import static com.yahoo.vespa.athenz.tls.KeyStoreUtils.writeKeyStoreToFile;
*/
class TestUtils {
- static KeyStore createKeystore(KeyStoreType type, char[] password) {
- KeyPair keyPair = KeyUtils.generateKeypair(KeyAlgorithm.RSA, 4096);
- return KeyStoreBuilder.withType(type)
- .withKeyEntry("entry-name", keyPair.getPrivate(), password, createCertificate(keyPair))
- .build();
+ static KeyStore createKeystore(KeyStoreType type, char[] password)
+ throws GeneralSecurityException, IOException, OperatorCreationException {
+ KeyPair keyPair = createKeyPair();
+ KeyStore keystore = type.createKeystore();
+ keystore.load(null);
+ keystore.setKeyEntry("entry-name", keyPair.getPrivate(), password, new Certificate[]{createCertificate(keyPair)});
+ return keystore;
+ }
+
+ static X509Certificate createCertificate(KeyPair keyPair)
+ throws OperatorCreationException, IOException {
+ String x500Principal = "CN=mysubject";
+ PKCS10CertificationRequest csr =
+ Crypto.getPKCS10CertRequest(
+ Crypto.generateX509CSR(keyPair.getPrivate(), x500Principal, null));
+ return Crypto.generateX509Certificate(csr, keyPair.getPrivate(), new X500Name(x500Principal), 3600, false);
}
- static X509Certificate createCertificate(KeyPair keyPair) {
- X500Principal subject = new X500Principal("CN=mysubject");
- return X509CertificateBuilder
- .fromKeypair(
- keyPair, subject, Instant.now(), Instant.now().plus(1, ChronoUnit.DAYS), SignatureAlgorithm.SHA256_WITH_RSA, 1)
- .build();
+ static KeyPair createKeyPair() throws NoSuchAlgorithmException {
+ KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
+ keyGen.initialize(4096);
+ return keyGen.genKeyPair();
}
- static void createKeystoreFile(File file, KeyStoreType type, char[] password) {
+ static void createKeystoreFile(File file, KeyStoreType type, char[] password)
+ throws IOException, GeneralSecurityException, OperatorCreationException {
writeKeyStoreToFile(createKeystore(type, password), file, password);
}
}
diff --git a/vespa-athenz/src/test/java/com/yahoo/vespa/athenz/tls/X509CertificateBuilderTest.java b/vespa-athenz/src/test/java/com/yahoo/vespa/athenz/tls/X509CertificateBuilderTest.java
deleted file mode 100644
index 81ff4fdb208..00000000000
--- a/vespa-athenz/src/test/java/com/yahoo/vespa/athenz/tls/X509CertificateBuilderTest.java
+++ /dev/null
@@ -1,58 +0,0 @@
-package com.yahoo.vespa.athenz.tls;
-
-import org.junit.Test;
-
-import javax.security.auth.x500.X500Principal;
-import java.security.KeyPair;
-import java.security.NoSuchAlgorithmException;
-import java.security.cert.X509Certificate;
-import java.time.Instant;
-import java.time.temporal.ChronoUnit;
-
-import static org.junit.Assert.assertEquals;
-
-/**
- * @author bjorncs
- */
-public class X509CertificateBuilderTest {
-
- @Test
- public void can_build_self_signed_certificate() throws NoSuchAlgorithmException {
- KeyPair keyPair = KeyUtils.generateKeypair(KeyAlgorithm.RSA, 2048);
- X500Principal subject = new X500Principal("CN=myservice");
- X509Certificate cert =
- X509CertificateBuilder.fromKeypair(
- keyPair,
- subject,
- Instant.now(),
- Instant.now().plus(1, ChronoUnit.DAYS),
- SignatureAlgorithm.SHA256_WITH_RSA,
- 1)
- .setBasicConstraints(true, true)
- .build();
- assertEquals(subject, cert.getSubjectX500Principal());
- }
-
- @Test
- public void can_build_certificate_from_csr() {
- X500Principal subject = new X500Principal("CN=subject");
- X500Principal issuer = new X500Principal("CN=issuer");
- KeyPair csrKeypair = KeyUtils.generateKeypair(KeyAlgorithm.RSA, 2048);
- Pkcs10Csr csr = Pkcs10CsrBuilder.fromKeypair(subject, csrKeypair, SignatureAlgorithm.SHA256_WITH_RSA).build();
- KeyPair caKeypair = KeyUtils.generateKeypair(KeyAlgorithm.RSA, 2048);
- X509Certificate cert = X509CertificateBuilder
- .fromCsr(
- csr,
- issuer,
- Instant.now(),
- Instant.now().plus(1, ChronoUnit.DAYS),
- caKeypair.getPrivate(),
- SignatureAlgorithm.SHA256_WITH_RSA,
- 1)
- .addSubjectAlternativeName("subject1.alt")
- .addSubjectAlternativeName("subject2.alt")
- .build();
- assertEquals(subject, cert.getSubjectX500Principal());
- }
-
-} \ No newline at end of file
diff --git a/vespa-athenz/src/test/java/com/yahoo/vespa/athenz/tls/X509CertificateUtilsTest.java b/vespa-athenz/src/test/java/com/yahoo/vespa/athenz/tls/X509CertificateUtilsTest.java
deleted file mode 100644
index 3ba011b1efb..00000000000
--- a/vespa-athenz/src/test/java/com/yahoo/vespa/athenz/tls/X509CertificateUtilsTest.java
+++ /dev/null
@@ -1,36 +0,0 @@
-package com.yahoo.vespa.athenz.tls;
-
-import org.junit.Test;
-
-import javax.security.auth.x500.X500Principal;
-import java.security.KeyPair;
-import java.security.cert.X509Certificate;
-import java.time.Instant;
-import java.time.temporal.ChronoUnit;
-
-import static org.junit.Assert.assertEquals;
-
-/**
- * @author bjorncs
- */
-public class X509CertificateUtilsTest {
- @Test
- public void can_deserialize_serialized_pem_certificate() {
- KeyPair keypair = KeyUtils.generateKeypair(KeyAlgorithm.RSA, 2048);
- X500Principal subject = new X500Principal("CN=myservice");
- X509Certificate cert = X509CertificateBuilder
- .fromKeypair(
- keypair,
- subject,
- Instant.now(),
- Instant.now().plus(1, ChronoUnit.DAYS),
- SignatureAlgorithm.SHA256_WITH_RSA,
- 1)
- .build();
- assertEquals(subject, cert.getSubjectX500Principal());
- X509Certificate deserializedCert = X509CertificateUtils.fromPem(X509CertificateUtils.toPem(cert));
- assertEquals(subject, deserializedCert.getSubjectX500Principal());
- }
-
-
-} \ No newline at end of file