From 9406df0701e050b8428cb0ce03cda9a275e4cd97 Mon Sep 17 00:00:00 2001 From: Harald Musum Date: Wed, 21 Mar 2018 15:20:54 +0100 Subject: Revert "Bjorncs/certificate builder" --- .../vespa/athenz/identity/SiaIdentityProvider.java | 29 ++--- .../identityprovider/AthenzCredentialsService.java | 54 +++----- .../vespa/athenz/identityprovider/CryptoUtils.java | 113 ++++++++++++++++ .../athenz/identityprovider/InstanceIdentity.java | 3 +- .../athenz/tls/BasicConstraintsExtension.java | 14 -- .../athenz/tls/BouncyCastleProviderHolder.java | 14 -- .../java/com/yahoo/vespa/athenz/tls/Extension.java | 22 ---- .../com/yahoo/vespa/athenz/tls/KeyAlgorithm.java | 19 --- .../com/yahoo/vespa/athenz/tls/KeyStoreType.java | 4 +- .../java/com/yahoo/vespa/athenz/tls/KeyUtils.java | 41 ------ .../java/com/yahoo/vespa/athenz/tls/Pkcs10Csr.java | 90 ------------- .../yahoo/vespa/athenz/tls/Pkcs10CsrBuilder.java | 89 ------------- .../com/yahoo/vespa/athenz/tls/Pkcs10CsrUtils.java | 38 ------ .../yahoo/vespa/athenz/tls/SignatureAlgorithm.java | 19 --- .../vespa/athenz/tls/X509CertificateBuilder.java | 145 --------------------- .../vespa/athenz/tls/X509CertificateUtils.java | 78 ----------- .../yahoo/vespa/athenz/utils/AthenzIdentities.java | 18 ++- .../athenz/identityprovider/CryptoUtilsTest.java | 28 ++++ .../athenz/tls/AthenzSslContextBuilderTest.java | 3 +- .../vespa/athenz/tls/KeyStoreBuilderTest.java | 3 +- .../com/yahoo/vespa/athenz/tls/KeyUtilsTest.java | 22 ---- .../vespa/athenz/tls/Pkcs10CsrBuilderTest.java | 27 ---- .../com/yahoo/vespa/athenz/tls/Pkcs10CsrTest.java | 55 -------- .../yahoo/vespa/athenz/tls/Pkcs10CsrUtilsTest.java | 29 ----- .../java/com/yahoo/vespa/athenz/tls/TestUtils.java | 50 ++++--- .../athenz/tls/X509CertificateBuilderTest.java | 58 --------- .../vespa/athenz/tls/X509CertificateUtilsTest.java | 36 ----- 27 files changed, 218 insertions(+), 883 deletions(-) create mode 100644 vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/CryptoUtils.java delete mode 100644 vespa-athenz/src/main/java/com/yahoo/vespa/athenz/tls/BasicConstraintsExtension.java delete mode 100644 vespa-athenz/src/main/java/com/yahoo/vespa/athenz/tls/BouncyCastleProviderHolder.java delete mode 100644 vespa-athenz/src/main/java/com/yahoo/vespa/athenz/tls/Extension.java delete mode 100644 vespa-athenz/src/main/java/com/yahoo/vespa/athenz/tls/KeyAlgorithm.java delete mode 100644 vespa-athenz/src/main/java/com/yahoo/vespa/athenz/tls/KeyUtils.java delete mode 100644 vespa-athenz/src/main/java/com/yahoo/vespa/athenz/tls/Pkcs10Csr.java delete mode 100644 vespa-athenz/src/main/java/com/yahoo/vespa/athenz/tls/Pkcs10CsrBuilder.java delete mode 100644 vespa-athenz/src/main/java/com/yahoo/vespa/athenz/tls/Pkcs10CsrUtils.java delete mode 100644 vespa-athenz/src/main/java/com/yahoo/vespa/athenz/tls/SignatureAlgorithm.java delete mode 100644 vespa-athenz/src/main/java/com/yahoo/vespa/athenz/tls/X509CertificateBuilder.java delete mode 100644 vespa-athenz/src/main/java/com/yahoo/vespa/athenz/tls/X509CertificateUtils.java create mode 100644 vespa-athenz/src/test/java/com/yahoo/vespa/athenz/identityprovider/CryptoUtilsTest.java delete mode 100644 vespa-athenz/src/test/java/com/yahoo/vespa/athenz/tls/KeyUtilsTest.java delete mode 100644 vespa-athenz/src/test/java/com/yahoo/vespa/athenz/tls/Pkcs10CsrBuilderTest.java delete mode 100644 vespa-athenz/src/test/java/com/yahoo/vespa/athenz/tls/Pkcs10CsrTest.java delete mode 100644 vespa-athenz/src/test/java/com/yahoo/vespa/athenz/tls/Pkcs10CsrUtilsTest.java delete mode 100644 vespa-athenz/src/test/java/com/yahoo/vespa/athenz/tls/X509CertificateBuilderTest.java delete mode 100644 vespa-athenz/src/test/java/com/yahoo/vespa/athenz/tls/X509CertificateUtilsTest.java (limited to 'vespa-athenz') 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 .. - // and SAN dnsname .instanceid.athenz. - 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 .. + // and SAN dnsname .instanceid.athenz. + 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 { @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 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 getBasicConstraints() { - return getExtensions() - .map(BasicConstraints::fromExtensions) - .map(BasicConstraints::isCA); - } - - public List getExtensionOIds() { - return getExtensions() - .map(extensions -> Arrays.stream(extensions.getExtensionOIDs()) - .map(ASN1ObjectIdentifier::getId) - .collect(toList())) - .orElse(emptyList()); - - } - - private Optional 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 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 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 getCommonNames(X509Certificate certificate) { - return getCommonNames(certificate.getSubjectX500Principal()); - } - - public static List 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 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 expected = Arrays.asList(Extension.BASIC_CONSTRAINS.getOId(), Extension.SUBJECT_ALTERNATIVE_NAMES.getOId()); - List 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 -- cgit v1.2.3