summaryrefslogtreecommitdiffstats
path: root/athenz-identity-provider-service/src
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 /athenz-identity-provider-service/src
parenta4a3147111bc427f2af081e8572b5618e3e05e7d (diff)
Revert "Bjorncs/certificate builder"
Diffstat (limited to 'athenz-identity-provider-service/src')
-rw-r--r--athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/AthenzSslTrustStoreConfigurator.java56
-rw-r--r--athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/ca/CertificateSerializedPayload.java13
-rw-r--r--athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/ca/CertificateSigner.java102
-rw-r--r--athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/ca/CertificateSignerResource.java4
-rw-r--r--athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/ca/CsrSerializedPayload.java17
-rw-r--r--athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/impl/AthenzCertificateClient.java4
-rw-r--r--athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/impl/CkmsKeyProvider.java7
-rw-r--r--athenz-identity-provider-service/src/test/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/ca/CertificateSignerTest.java76
8 files changed, 194 insertions, 85 deletions
diff --git a/athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/AthenzSslTrustStoreConfigurator.java b/athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/AthenzSslTrustStoreConfigurator.java
index 3091321c47a..376dd2ed4ac 100644
--- a/athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/AthenzSslTrustStoreConfigurator.java
+++ b/athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/AthenzSslTrustStoreConfigurator.java
@@ -8,18 +8,32 @@ import com.yahoo.jdisc.http.ssl.SslTrustStoreContext;
import com.yahoo.log.LogLevel;
import com.yahoo.vespa.athenz.tls.KeyStoreBuilder;
import com.yahoo.vespa.athenz.tls.KeyStoreType;
-import com.yahoo.vespa.athenz.tls.SignatureAlgorithm;
-import com.yahoo.vespa.athenz.tls.X509CertificateBuilder;
import com.yahoo.vespa.hosted.athenz.instanceproviderservice.config.AthenzProviderServiceConfig;
+import org.bouncycastle.asn1.x500.X500Name;
+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.X509v3CertificateBuilder;
+import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
+import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.bouncycastle.operator.ContentSigner;
+import org.bouncycastle.operator.OperatorCreationException;
+import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
-import javax.security.auth.x500.X500Principal;
import java.io.File;
+import java.io.IOException;
+import java.math.BigInteger;
import java.security.KeyPair;
import java.security.KeyStore;
import java.security.KeyStoreException;
+import java.security.Provider;
+import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.time.Duration;
import java.time.Instant;
+import java.util.Date;
import java.util.logging.Logger;
/**
@@ -30,6 +44,7 @@ public class AthenzSslTrustStoreConfigurator implements SslTrustStoreConfigurato
private static final Logger log = Logger.getLogger(AthenzSslTrustStoreConfigurator.class.getName());
private static final String CERTIFICATE_ALIAS = "cfgselfsigned";
+ private static final Provider provider = new BouncyCastleProvider();
private final KeyStore trustStore;
@Inject
@@ -74,20 +89,29 @@ public class AthenzSslTrustStoreConfigurator implements SslTrustStoreConfigurato
return keyProvider.getKeyPair(zoneConfig.secretVersion());
}
- private static X509Certificate createSelfSignedCertificate(KeyPair keyPair, ConfigserverConfig config) {
- X500Principal subject = new X500Principal("CN="+ config.loadBalancerAddress());
+ private static X509Certificate createSelfSignedCertificate(KeyPair keyPair, ConfigserverConfig config)
+ throws IOException, CertificateException, OperatorCreationException {
+ ContentSigner contentSigner = new JcaContentSignerBuilder("SHA256WithRSA").build(keyPair.getPrivate());
+ X500Name x500Name = new X500Name("CN="+ config.loadBalancerAddress());
Instant now = Instant.now();
- X509CertificateBuilder builder = X509CertificateBuilder
- .fromKeypair(
- keyPair,
- subject,
- now,
- now.plus(Duration.ofDays(30)),
- SignatureAlgorithm.SHA256_WITH_RSA,
- now.toEpochMilli())
- .setBasicConstraints(true, true);
- config.zookeeperserver().forEach(server -> builder.addSubjectAlternativeName(server.hostname()));
- return builder.build();
+ Date notBefore = Date.from(now);
+ Date notAfter = Date.from(now.plus(Duration.ofDays(30)));
+
+ GeneralNames generalNames = new GeneralNames(
+ config.zookeeperserver().stream()
+ .map(server -> new GeneralName(GeneralName.dNSName, server.hostname()))
+ .toArray(GeneralName[]::new));
+
+ X509v3CertificateBuilder certificateBuilder =
+ new JcaX509v3CertificateBuilder(
+ x500Name, BigInteger.valueOf(now.toEpochMilli()), notBefore, notAfter, x500Name, keyPair.getPublic()
+ )
+ .addExtension(Extension.basicConstraints, true, new BasicConstraints(true))
+ .addExtension(Extension.subjectAlternativeName, false, generalNames);
+
+ return new JcaX509CertificateConverter()
+ .setProvider(provider)
+ .getCertificate(certificateBuilder.build(contentSigner));
}
}
diff --git a/athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/ca/CertificateSerializedPayload.java b/athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/ca/CertificateSerializedPayload.java
index cfef2bc0e33..25733bf0075 100644
--- a/athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/ca/CertificateSerializedPayload.java
+++ b/athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/ca/CertificateSerializedPayload.java
@@ -7,9 +7,12 @@ import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
-import com.yahoo.vespa.athenz.tls.X509CertificateUtils;
+import org.bouncycastle.openssl.jcajce.JcaPEMWriter;
+import org.bouncycastle.util.io.pem.PemObject;
import java.io.IOException;
+import java.io.StringWriter;
+import java.security.cert.CertificateEncodingException;
import java.security.cert.X509Certificate;
/**
@@ -53,7 +56,13 @@ public class CertificateSerializedPayload {
@Override
public void serialize(
X509Certificate certificate, JsonGenerator gen, SerializerProvider serializers) throws IOException {
- gen.writeString(X509CertificateUtils.toPem(certificate));
+ try (StringWriter stringWriter = new StringWriter(); JcaPEMWriter pemWriter = new JcaPEMWriter(stringWriter)) {
+ pemWriter.writeObject(new PemObject("CERTIFICATE", certificate.getEncoded()));
+ pemWriter.flush();
+ gen.writeString(stringWriter.toString());
+ } catch (CertificateEncodingException e) {
+ throw new RuntimeException("Failed to encode X509Certificate", e);
+ }
}
}
}
diff --git a/athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/ca/CertificateSigner.java b/athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/ca/CertificateSigner.java
index 7b4a599d5dd..f6f6bb1dbca 100644
--- a/athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/ca/CertificateSigner.java
+++ b/athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/ca/CertificateSigner.java
@@ -6,23 +6,41 @@ import com.google.inject.Inject;
import com.yahoo.cloud.config.ConfigserverConfig;
import com.yahoo.config.provision.Zone;
import com.yahoo.log.LogLevel;
-import com.yahoo.vespa.athenz.tls.Extension;
-import com.yahoo.vespa.athenz.tls.Pkcs10Csr;
-import com.yahoo.vespa.athenz.tls.SignatureAlgorithm;
-import com.yahoo.vespa.athenz.tls.X509CertificateBuilder;
-import com.yahoo.vespa.athenz.tls.X509CertificateUtils;
import com.yahoo.vespa.hosted.athenz.instanceproviderservice.KeyProvider;
import com.yahoo.vespa.hosted.athenz.instanceproviderservice.config.AthenzProviderServiceConfig;
-
-import javax.security.auth.x500.X500Principal;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.DERUTF8String;
+import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.bouncycastle.asn1.x500.AttributeTypeAndValue;
+import org.bouncycastle.asn1.x500.X500Name;
+import org.bouncycastle.asn1.x500.style.BCStyle;
+import org.bouncycastle.asn1.x509.BasicConstraints;
+import org.bouncycastle.asn1.x509.Extension;
+import org.bouncycastle.asn1.x509.Extensions;
+import org.bouncycastle.cert.X509v3CertificateBuilder;
+import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
+import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.bouncycastle.operator.ContentSigner;
+import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
+import org.bouncycastle.pkcs.PKCS10CertificationRequest;
+import org.bouncycastle.pkcs.jcajce.JcaPKCS10CertificationRequest;
+
+import java.math.BigInteger;
import java.security.PrivateKey;
+import java.security.Provider;
+import java.security.PublicKey;
import java.security.cert.X509Certificate;
import java.time.Clock;
import java.time.Duration;
-import java.time.Instant;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Date;
+import java.util.Enumeration;
import java.util.List;
import java.util.logging.Logger;
import java.util.stream.Collectors;
+import java.util.stream.Stream;
import static com.yahoo.vespa.hosted.athenz.instanceproviderservice.impl.Utils.getZoneConfig;
@@ -38,13 +56,16 @@ public class CertificateSigner {
private static final Logger log = Logger.getLogger(CertificateSigner.class.getName());
- static final SignatureAlgorithm SIGNER_ALGORITHM = SignatureAlgorithm.SHA256_WITH_RSA;
+ static final String SIGNER_ALGORITHM = "SHA256withRSA";
static final Duration CERTIFICATE_EXPIRATION = Duration.ofDays(30);
- private static final List<Extension> ILLEGAL_EXTENSIONS = ImmutableList.of(
- Extension.BASIC_CONSTRAINS, Extension.SUBJECT_ALTERNATIVE_NAMES);
+ private static final List<ASN1ObjectIdentifier> ILLEGAL_EXTENSIONS = ImmutableList.of(
+ Extension.basicConstraints, Extension.subjectAlternativeName);
+
+ private final JcaX509CertificateConverter certificateConverter = new JcaX509CertificateConverter();
+ private final Provider provider = new BouncyCastleProvider();
private final PrivateKey caPrivateKey;
- private final X500Principal issuer;
+ private final X500Name issuer;
private final Clock clock;
@Inject
@@ -57,7 +78,7 @@ public class CertificateSigner {
CertificateSigner(PrivateKey caPrivateKey, String loadBalancerAddress, Clock clock) {
this.caPrivateKey = caPrivateKey;
- this.issuer = new X500Principal("CN=" + loadBalancerAddress);
+ this.issuer = new X500Name("CN=" + loadBalancerAddress);
this.clock = clock;
}
@@ -68,28 +89,46 @@ public class CertificateSigner {
* <li>CSR does not contain any any of the extensions in {@code ILLEGAL_EXTENSIONS}</li>
* </ul>
*/
- X509Certificate generateX509Certificate(Pkcs10Csr csr, String remoteHostname) {
- verifyCertificateCommonName(csr.getSubject(), remoteHostname);
- verifyCertificateExtensions(csr);
+ X509Certificate generateX509Certificate(PKCS10CertificationRequest certReq, String remoteHostname) {
+ verifyCertificateCommonName(certReq.getSubject(), remoteHostname);
+ verifyCertificateExtensions(certReq);
+
+ Date notBefore = Date.from(clock.instant());
+ Date notAfter = Date.from(clock.instant().plus(CERTIFICATE_EXPIRATION));
- Instant now = clock.instant();
try {
- return X509CertificateBuilder.fromCsr(csr, issuer, now, now.plus(CERTIFICATE_EXPIRATION), caPrivateKey, SIGNER_ALGORITHM, now.toEpochMilli())
- .setBasicConstraints(true, false)
- .build();
+ PublicKey publicKey = new JcaPKCS10CertificationRequest(certReq).getPublicKey();
+ X509v3CertificateBuilder caBuilder = new JcaX509v3CertificateBuilder(
+ issuer, BigInteger.valueOf(clock.millis()), notBefore, notAfter, certReq.getSubject(), publicKey)
+
+ // Set Basic Constraints to false
+ .addExtension(Extension.basicConstraints, true, new BasicConstraints(false));
+
+ ContentSigner caSigner = new JcaContentSignerBuilder(SIGNER_ALGORITHM)
+ .setProvider(provider)
+ .build(caPrivateKey);
+
+ return certificateConverter
+ .setProvider(provider)
+ .getCertificate(caBuilder.build(caSigner));
} catch (Exception ex) {
log.log(LogLevel.ERROR, "Failed to generate X509 Certificate", ex);
- throw new RuntimeException("Failed to generate X509 Certificate", ex);
+ throw new RuntimeException("Failed to generate X509 Certificate");
}
}
- static void verifyCertificateCommonName(X500Principal subject, String remoteHostname) {
- List<String> commonNames = X509CertificateUtils.getCommonNames(subject);
- if (commonNames.size() != 1) {
+ static void verifyCertificateCommonName(X500Name subject, String remoteHostname) {
+ List<AttributeTypeAndValue> attributesAndValues = Arrays.stream(subject.getRDNs())
+ .flatMap(rdn -> rdn.isMultiValued() ?
+ Stream.of(rdn.getTypesAndValues()) : Stream.of(rdn.getFirst()))
+ .filter(attr -> attr.getType() == BCStyle.CN)
+ .collect(Collectors.toList());
+
+ if (attributesAndValues.size() != 1) {
throw new IllegalArgumentException("Only 1 common name should be set");
}
- String actualCommonName = commonNames.get(0);
+ String actualCommonName = DERUTF8String.getInstance(attributesAndValues.get(0).getValue()).getString();
if (! actualCommonName.equals(remoteHostname)) {
throw new IllegalArgumentException("Remote hostname " + remoteHostname +
" does not match common name " + actualCommonName);
@@ -97,12 +136,15 @@ public class CertificateSigner {
}
@SuppressWarnings("unchecked")
- static void verifyCertificateExtensions(Pkcs10Csr csr) {
- List<String> extensionOIds = csr.getExtensionOIds();
- List<String> illegalExt = ILLEGAL_EXTENSIONS.stream()
- .map(Extension::getOId)
- .filter(extensionOIds::contains)
+ static void verifyCertificateExtensions(PKCS10CertificationRequest request) {
+ List<String> illegalExt = Arrays
+ .stream(request.getAttributes(PKCSObjectIdentifiers.pkcs_9_at_extensionRequest))
+ .map(attribute -> Extensions.getInstance(attribute.getAttrValues().getObjectAt(0)))
+ .flatMap(ext -> Collections.list((Enumeration<ASN1ObjectIdentifier>) ext.oids()).stream())
+ .filter(ILLEGAL_EXTENSIONS::contains)
+ .map(ASN1ObjectIdentifier::getId)
.collect(Collectors.toList());
+
if (! illegalExt.isEmpty()) {
throw new IllegalArgumentException("CSR contains illegal extensions: " + String.join(", ", illegalExt));
}
diff --git a/athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/ca/CertificateSignerResource.java b/athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/ca/CertificateSignerResource.java
index 1dd452866a5..0c6199efdcb 100644
--- a/athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/ca/CertificateSignerResource.java
+++ b/athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/ca/CertificateSignerResource.java
@@ -4,7 +4,7 @@ package com.yahoo.vespa.hosted.athenz.instanceproviderservice.ca;
import com.google.inject.Inject;
import com.yahoo.container.jaxrs.annotation.Component;
import com.yahoo.log.LogLevel;
-import com.yahoo.vespa.athenz.tls.Pkcs10Csr;
+import org.bouncycastle.pkcs.PKCS10CertificationRequest;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.BadRequestException;
@@ -45,7 +45,7 @@ public class CertificateSignerResource {
try {
InetAddress addr = InetAddress.getByName(req.getRemoteAddr());
String remoteHostname = addr.getHostName();
- Pkcs10Csr csr = csrPayload.csr;
+ PKCS10CertificationRequest csr = csrPayload.csr;
log.log(LogLevel.DEBUG, "Certification request from " + remoteHostname + ": " + csr);
X509Certificate certificate = certificateSigner.generateX509Certificate(csr, remoteHostname);
return new CertificateSerializedPayload(certificate);
diff --git a/athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/ca/CsrSerializedPayload.java b/athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/ca/CsrSerializedPayload.java
index 375a4c3e17d..f56214513aa 100644
--- a/athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/ca/CsrSerializedPayload.java
+++ b/athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/ca/CsrSerializedPayload.java
@@ -7,10 +7,11 @@ 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.Pkcs10Csr;
-import com.yahoo.vespa.athenz.tls.Pkcs10CsrUtils;
+import org.bouncycastle.openssl.PEMParser;
+import org.bouncycastle.pkcs.PKCS10CertificationRequest;
import java.io.IOException;
+import java.io.StringReader;
/**
* Contains PEM formatted Certificate Signing Request (CSR)
@@ -19,11 +20,11 @@ import java.io.IOException;
*/
public class CsrSerializedPayload {
- @JsonProperty("csr") public final Pkcs10Csr csr;
+ @JsonProperty("csr") public final PKCS10CertificationRequest csr;
@JsonCreator
public CsrSerializedPayload(@JsonProperty("csr") @JsonDeserialize(using = CertificateRequestDeserializer.class)
- Pkcs10Csr csr) {
+ PKCS10CertificationRequest csr) {
this.csr = csr;
}
@@ -49,11 +50,13 @@ public class CsrSerializedPayload {
'}';
}
- public static class CertificateRequestDeserializer extends JsonDeserializer<Pkcs10Csr> {
+ public static class CertificateRequestDeserializer extends JsonDeserializer<PKCS10CertificationRequest> {
@Override
- public Pkcs10Csr deserialize(
+ public PKCS10CertificationRequest deserialize(
JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException {
- return Pkcs10CsrUtils.fromPem(jsonParser.getValueAsString());
+ try (PEMParser pemParser = new PEMParser(new StringReader(jsonParser.getValueAsString()))) {
+ return (PKCS10CertificationRequest) pemParser.readObject();
+ }
}
}
}
diff --git a/athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/impl/AthenzCertificateClient.java b/athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/impl/AthenzCertificateClient.java
index 35b483affae..ca5c776bf3c 100644
--- a/athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/impl/AthenzCertificateClient.java
+++ b/athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/impl/AthenzCertificateClient.java
@@ -1,10 +1,10 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.hosted.athenz.instanceproviderservice.impl;
+import com.yahoo.athenz.auth.util.Crypto;
import com.yahoo.athenz.zts.InstanceRefreshRequest;
import com.yahoo.athenz.zts.ZTSClient;
import com.yahoo.container.jdisc.athenz.AthenzIdentityProvider;
-import com.yahoo.vespa.athenz.tls.X509CertificateUtils;
import com.yahoo.vespa.hosted.athenz.instanceproviderservice.config.AthenzProviderServiceConfig;
import javax.net.ssl.SSLContext;
@@ -34,7 +34,7 @@ public class AthenzCertificateClient {
req.setKeyId(Integer.toString(zoneConfig.secretVersion()));
String pemEncoded = ztsClient.postInstanceRefreshRequest(zoneConfig.domain(), zoneConfig.serviceName(), req)
.getCertificate();
- return X509CertificateUtils.fromPem(pemEncoded);
+ return Crypto.loadX509Certificate(pemEncoded);
}
}
diff --git a/athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/impl/CkmsKeyProvider.java b/athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/impl/CkmsKeyProvider.java
index 41aee29d761..2f2cd5a8495 100644
--- a/athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/impl/CkmsKeyProvider.java
+++ b/athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/impl/CkmsKeyProvider.java
@@ -2,9 +2,9 @@
package com.yahoo.vespa.hosted.athenz.instanceproviderservice.impl;
import com.google.inject.Inject;
+import com.yahoo.athenz.auth.util.Crypto;
import com.yahoo.config.provision.Zone;
import com.yahoo.container.jdisc.Ckms;
-import com.yahoo.vespa.athenz.tls.KeyUtils;
import com.yahoo.vespa.hosted.athenz.instanceproviderservice.KeyProvider;
import com.yahoo.vespa.hosted.athenz.instanceproviderservice.config.AthenzProviderServiceConfig;
@@ -58,9 +58,10 @@ public class CkmsKeyProvider implements KeyProvider {
}
}
+ // TODO: Consider moving to cryptoutils
private KeyPair readKeyPair(int version) {
- PrivateKey privateKey = KeyUtils.fromPemEncodedPrivateKey(ckms.getSecret(secretName, version));
- PublicKey publicKey = KeyUtils.extractPublicKey(privateKey);
+ PrivateKey privateKey = Crypto.loadPrivateKey(ckms.getSecret(secretName, version));
+ PublicKey publicKey = Crypto.extractPublicKey(privateKey);
return new KeyPair(publicKey, privateKey);
}
}
diff --git a/athenz-identity-provider-service/src/test/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/ca/CertificateSignerTest.java b/athenz-identity-provider-service/src/test/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/ca/CertificateSignerTest.java
index 6c624eb1da0..594bbf77fce 100644
--- a/athenz-identity-provider-service/src/test/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/ca/CertificateSignerTest.java
+++ b/athenz-identity-provider-service/src/test/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/ca/CertificateSignerTest.java
@@ -2,16 +2,23 @@
package com.yahoo.vespa.hosted.athenz.instanceproviderservice.ca;
import com.yahoo.test.ManualClock;
-import com.yahoo.vespa.athenz.tls.Extension;
-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 org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.bouncycastle.asn1.x500.X500Name;
+import org.bouncycastle.asn1.x509.Extension;
+import org.bouncycastle.asn1.x509.Extensions;
+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.jcajce.JcaContentSignerBuilder;
+import org.bouncycastle.pkcs.PKCS10CertificationRequest;
+import org.bouncycastle.pkcs.PKCS10CertificationRequestBuilder;
+import org.bouncycastle.pkcs.jcajce.JcaPKCS10CertificationRequestBuilder;
import org.junit.Test;
-import javax.security.auth.x500.X500Principal;
import java.math.BigInteger;
import java.security.KeyPair;
+import java.security.KeyPairGenerator;
import java.security.cert.X509Certificate;
import java.time.Instant;
import java.util.Collection;
@@ -28,6 +35,8 @@ import static org.junit.Assert.fail;
*/
public class CertificateSignerTest {
+ private final KeyPair clientKeyPair = getKeyPair();
+
private final long startTime = 1234567890000L;
private final KeyPair caKeyPair = getKeyPair();
private final String cfgServerHostname = "cfg1.us-north-1.vespa.domain.tld";
@@ -38,21 +47,22 @@ public class CertificateSignerTest {
@Test
public void test_signing() throws Exception {
- String subject = String.format("CN=%s,OU=Vespa,C=NO", requestersHostname);
- Pkcs10Csr csr = createCsrBuilder(subject).build();
+ ExtensionsGenerator extGen = new ExtensionsGenerator();
+ String subject = "C=NO,OU=Vespa,CN=" + requestersHostname;
+ PKCS10CertificationRequest request = makeRequest(subject, extGen.generate());
- X509Certificate certificate = signer.generateX509Certificate(csr, requestersHostname);
- assertCertificate(certificate, subject, Collections.singleton(Extension.BASIC_CONSTRAINS.getOId()));
+ X509Certificate certificate = signer.generateX509Certificate(request, requestersHostname);
+ assertCertificate(certificate, subject, Collections.singleton(Extension.basicConstraints.getId()));
}
@Test
public void common_name_test() throws Exception {
CertificateSigner.verifyCertificateCommonName(
- new X500Principal("CN=" + requestersHostname), requestersHostname);
+ new X500Name("CN=" + requestersHostname), requestersHostname);
CertificateSigner.verifyCertificateCommonName(
- new X500Principal("C=NO,OU=Vespa,CN=" + requestersHostname), requestersHostname);
+ new X500Name("C=NO,OU=Vespa,CN=" + requestersHostname), requestersHostname);
CertificateSigner.verifyCertificateCommonName(
- new X500Principal("C=NO+OU=org,CN=" + requestersHostname), requestersHostname);
+ new X500Name("C=NO+OU=org,CN=" + requestersHostname), requestersHostname);
assertCertificateCommonNameException("C=NO", "Only 1 common name should be set");
assertCertificateCommonNameException("C=US+CN=abc123.domain.tld,C=NO+CN=" + requestersHostname, "Only 1 common name should be set");
@@ -62,15 +72,26 @@ public class CertificateSignerTest {
@Test(expected = IllegalArgumentException.class)
public void extensions_test_subject_alternative_names() throws Exception {
- Pkcs10Csr csr = createCsrBuilder("OU=Vespa")
- .addSubjectAlternativeName("some.other.domain.tld")
- .build();
- CertificateSigner.verifyCertificateExtensions(csr);
+ ExtensionsGenerator extGen = new ExtensionsGenerator();
+ extGen.addExtension(Extension.subjectAlternativeName, false, new GeneralNames(new GeneralName[] {
+ new GeneralName(GeneralName.dNSName, "some.other.domain.tld")}));
+ PKCS10CertificationRequest request = makeRequest("OU=Vespa", extGen.generate());
+
+ CertificateSigner.verifyCertificateExtensions(request);
+ }
+
+ @Test
+ public void extensions_allowed() throws Exception {
+ ExtensionsGenerator extGen = new ExtensionsGenerator();
+ extGen.addExtension(Extension.certificateIssuer, true, new byte[0]);
+ PKCS10CertificationRequest request = makeRequest("OU=Vespa", extGen.generate());
+
+ CertificateSigner.verifyCertificateExtensions(request);
}
private void assertCertificateCommonNameException(String subject, String expectedMessage) {
try {
- CertificateSigner.verifyCertificateCommonName(new X500Principal(subject), requestersHostname);
+ CertificateSigner.verifyCertificateCommonName(new X500Name(subject), requestersHostname);
fail("Expected to fail");
} catch (IllegalArgumentException e) {
assertEquals(expectedMessage, e.getMessage());
@@ -82,8 +103,8 @@ public class CertificateSignerTest {
assertEquals(BigInteger.valueOf(startTime), certificate.getSerialNumber());
assertEquals(startTime, certificate.getNotBefore().getTime());
assertEquals(startTime + CertificateSigner.CERTIFICATE_EXPIRATION.toMillis(), certificate.getNotAfter().getTime());
- assertEquals(CertificateSigner.SIGNER_ALGORITHM.getAlgorithmName(), certificate.getSigAlgName());
- assertEquals(new X500Principal(expectedSubjectName), certificate.getSubjectX500Principal());
+ assertEquals(CertificateSigner.SIGNER_ALGORITHM, certificate.getSigAlgName());
+ assertEquals(expectedSubjectName, certificate.getSubjectDN().getName());
assertEquals("CN=" + cfgServerHostname, certificate.getIssuerX500Principal().getName());
Set<String> extensions = Stream.of(certificate.getNonCriticalExtensionOIDs(),
@@ -95,11 +116,20 @@ public class CertificateSignerTest {
certificate.verify(caKeyPair.getPublic());
}
- private Pkcs10CsrBuilder createCsrBuilder(String subject) {
- return Pkcs10CsrBuilder.fromKeypair(new X500Principal(subject), caKeyPair, CertificateSigner.SIGNER_ALGORITHM);
+ private PKCS10CertificationRequest makeRequest(String subject, Extensions extensions) throws Exception {
+ PKCS10CertificationRequestBuilder builder = new JcaPKCS10CertificationRequestBuilder(
+ new X500Name(subject), clientKeyPair.getPublic());
+ builder.addAttribute(PKCSObjectIdentifiers.pkcs_9_at_extensionRequest, extensions);
+
+ ContentSigner signGen = new JcaContentSignerBuilder(CertificateSigner.SIGNER_ALGORITHM).build(caKeyPair.getPrivate());
+ return builder.build(signGen);
}
private static KeyPair getKeyPair() {
- return KeyUtils.generateKeypair(KeyAlgorithm.RSA);
+ try {
+ return KeyPairGenerator.getInstance("RSA").genKeyPair();
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
}
}