summaryrefslogtreecommitdiffstats
path: root/vespa-athenz
diff options
context:
space:
mode:
authorBjørn Christian Seime <bjorncs@oath.com>2018-06-14 12:50:12 +0200
committerBjørn Christian Seime <bjorncs@oath.com>2018-06-15 13:34:32 +0200
commitbdeeac4080ae3e36a6c1979d8fa39355f92d251c (patch)
tree0261500cdf589a3f1c464dd11ee777ad7a76c268 /vespa-athenz
parent88fd17919d10638cccd8efa71ed1916a855f88eb (diff)
Add method to ZtsClient to retrieve identity certificate
Diffstat (limited to 'vespa-athenz')
-rw-r--r--vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/DefaultZtsClient.java24
-rw-r--r--vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/Identity.java29
-rw-r--r--vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/ZtsClient.java19
-rw-r--r--vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/bindings/IdentityRefreshRequestEntity.java24
-rw-r--r--vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/bindings/IdentityResponseEntity.java40
-rw-r--r--vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/bindings/InstanceIdentityCredentials.java13
-rw-r--r--vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/bindings/InstanceRefreshInformation.java8
-rw-r--r--vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/bindings/RoleCertificateRequestEntity.java13
-rw-r--r--vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/bindings/RoleCertificateResponseEntity.java13
-rw-r--r--vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/bindings/serializers/Pkcs10CsrSerializer.java20
-rw-r--r--vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/bindings/serializers/X509CertificateDeserializer.java21
-rw-r--r--vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/bindings/serializers/X509CertificateListDeserializer.java22
-rw-r--r--vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/bindings/serializers/package-info.java8
-rw-r--r--vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/utils/IdentityCsrGenerator.java37
-rw-r--r--vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/utils/package-info.java8
-rw-r--r--vespa-athenz/src/main/java/com/yahoo/vespa/athenz/tls/X509CertificateUtils.java51
-rw-r--r--vespa-athenz/src/test/java/com/yahoo/vespa/athenz/tls/TestUtils.java5
-rw-r--r--vespa-athenz/src/test/java/com/yahoo/vespa/athenz/tls/X509CertificateUtilsTest.java25
18 files changed, 323 insertions, 57 deletions
diff --git a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/DefaultZtsClient.java b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/DefaultZtsClient.java
index dd97b20055d..f8654bbaa68 100644
--- a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/DefaultZtsClient.java
+++ b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/DefaultZtsClient.java
@@ -10,12 +10,15 @@ import com.yahoo.vespa.athenz.api.AthenzRole;
import com.yahoo.vespa.athenz.api.AthenzService;
import com.yahoo.vespa.athenz.api.NToken;
import com.yahoo.vespa.athenz.api.ZToken;
+import com.yahoo.vespa.athenz.client.zts.bindings.IdentityResponseEntity;
import com.yahoo.vespa.athenz.client.zts.bindings.InstanceIdentityCredentials;
import com.yahoo.vespa.athenz.client.zts.bindings.InstanceRefreshInformation;
+import com.yahoo.vespa.athenz.client.zts.bindings.IdentityRefreshRequestEntity;
import com.yahoo.vespa.athenz.client.zts.bindings.InstanceRegisterInformation;
import com.yahoo.vespa.athenz.client.zts.bindings.RoleCertificateRequestEntity;
import com.yahoo.vespa.athenz.client.zts.bindings.RoleCertificateResponseEntity;
import com.yahoo.vespa.athenz.client.zts.bindings.RoleTokenResponseEntity;
+import com.yahoo.vespa.athenz.client.zts.utils.IdentityCsrGenerator;
import com.yahoo.vespa.athenz.identity.ServiceIdentityProvider;
import com.yahoo.vespa.athenz.tls.Pkcs10Csr;
import com.yahoo.vespa.athenz.tls.Pkcs10CsrBuilder;
@@ -127,6 +130,27 @@ public class DefaultZtsClient implements ZtsClient {
}
@Override
+ public Identity getServiceIdentity(AthenzService identity, String keyId, Pkcs10Csr csr) {
+ URI uri = ztsUrl.resolve(String.format("instance/%s/%s/refresh", identity.getDomainName(), identity.getName()));
+ HttpUriRequest request = RequestBuilder.post()
+ .setUri(uri)
+ .setEntity(toJsonStringEntity(new IdentityRefreshRequestEntity(csr, keyId)))
+ .build();
+ return withClient(client -> {
+ try (CloseableHttpResponse response = client.execute(request)) {
+ IdentityResponseEntity entity = readEntity(response, IdentityResponseEntity.class);
+ return new Identity(entity.certificate(), entity.caCertificateBundle());
+ }
+ });
+ }
+
+ @Override
+ public Identity getServiceIdentity(AthenzService identity, String keyId, KeyPair keyPair, String dnsSuffix) {
+ Pkcs10Csr csr = new IdentityCsrGenerator(dnsSuffix).generateIdentityCsr(identity, keyPair);
+ return getServiceIdentity(identity, keyId, csr);
+ }
+
+ @Override
public ZToken getRoleToken(AthenzDomain domain) {
return getRoleToken(domain, null);
}
diff --git a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/Identity.java b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/Identity.java
new file mode 100644
index 00000000000..455f3c06d1d
--- /dev/null
+++ b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/Identity.java
@@ -0,0 +1,29 @@
+// 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.client.zts;
+
+import java.security.cert.X509Certificate;
+import java.util.List;
+
+/**
+ * The identity of a service
+ *
+ * @author bjorncs
+ */
+public class Identity {
+
+ private final X509Certificate certificate;
+ private final List<X509Certificate> caCertificates;
+
+ public Identity(X509Certificate certificate, List<X509Certificate> caCertificates) {
+ this.certificate = certificate;
+ this.caCertificates = caCertificates;
+ }
+
+ public X509Certificate certificate() {
+ return certificate;
+ }
+
+ public List<X509Certificate> caCertificates() {
+ return caCertificates;
+ }
+}
diff --git a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/ZtsClient.java b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/ZtsClient.java
index 87a204095d9..9502deca1c0 100644
--- a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/ZtsClient.java
+++ b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/ZtsClient.java
@@ -43,6 +43,25 @@ public interface ZtsClient extends AutoCloseable {
Pkcs10Csr csr);
/**
+ * Get service identity
+ *
+ * @return A x509 certificate with CA certificates
+ */
+ Identity getServiceIdentity(AthenzService identity,
+ String keyId,
+ Pkcs10Csr csr);
+
+ /**
+ * Get service identity
+ *
+ * @return A x509 certificate with CA certificates
+ */
+ Identity getServiceIdentity(AthenzService identity,
+ String keyId,
+ KeyPair keyPair,
+ String dnsSuffix);
+
+ /**
* Fetch a role token for the target domain
*
* @param domain Target domain
diff --git a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/bindings/IdentityRefreshRequestEntity.java b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/bindings/IdentityRefreshRequestEntity.java
new file mode 100644
index 00000000000..47ae9cd2d3f
--- /dev/null
+++ b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/bindings/IdentityRefreshRequestEntity.java
@@ -0,0 +1,24 @@
+// 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.client.zts.bindings;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import com.yahoo.vespa.athenz.client.zts.bindings.serializers.Pkcs10CsrSerializer;
+import com.yahoo.vespa.athenz.tls.Pkcs10Csr;
+
+/**
+ * @author bjorncs
+ */
+public class IdentityRefreshRequestEntity {
+
+ @JsonProperty("csr") @JsonSerialize(using = Pkcs10CsrSerializer.class)
+ private final Pkcs10Csr csr;
+
+ @JsonProperty("keyId")
+ private final String keyId;
+
+ public IdentityRefreshRequestEntity(Pkcs10Csr csr, String keyId) {
+ this.csr = csr;
+ this.keyId = keyId;
+ }
+}
diff --git a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/bindings/IdentityResponseEntity.java b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/bindings/IdentityResponseEntity.java
new file mode 100644
index 00000000000..7bd04362599
--- /dev/null
+++ b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/bindings/IdentityResponseEntity.java
@@ -0,0 +1,40 @@
+// 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.client.zts.bindings;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+import com.yahoo.vespa.athenz.client.zts.bindings.serializers.X509CertificateDeserializer;
+import com.yahoo.vespa.athenz.client.zts.bindings.serializers.X509CertificateListDeserializer;
+
+import java.security.cert.X509Certificate;
+import java.util.List;
+
+/**
+ * Identity response entity
+ *
+ * @author bjorncs
+ */
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class IdentityResponseEntity {
+
+ private final X509Certificate certificate;
+ private final List<X509Certificate> caCertificateBundle;
+
+ @JsonCreator
+ public IdentityResponseEntity(
+ @JsonProperty("certificate") @JsonDeserialize(using = X509CertificateDeserializer.class) X509Certificate certificate,
+ @JsonProperty("caCertBundle") @JsonDeserialize(using = X509CertificateListDeserializer.class) List<X509Certificate> caCertificateBundle) {
+ this.certificate = certificate;
+ this.caCertificateBundle = caCertificateBundle;
+ }
+
+ public X509Certificate certificate() {
+ return certificate;
+ }
+
+ public List<X509Certificate> caCertificateBundle() {
+ return caCertificateBundle;
+ }
+}
diff --git a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/bindings/InstanceIdentityCredentials.java b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/bindings/InstanceIdentityCredentials.java
index 5c265f14813..0ab697a1c4c 100644
--- a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/bindings/InstanceIdentityCredentials.java
+++ b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/bindings/InstanceIdentityCredentials.java
@@ -4,13 +4,9 @@ package com.yahoo.vespa.athenz.client.zts.bindings;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
-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 com.yahoo.vespa.athenz.client.zts.bindings.serializers.X509CertificateDeserializer;
-import java.io.IOException;
import java.security.cert.X509Certificate;
/**
@@ -39,11 +35,4 @@ public class InstanceIdentityCredentials {
return serviceToken;
}
- public static class X509CertificateDeserializer extends JsonDeserializer<X509Certificate> {
- @Override
- public X509Certificate deserialize(JsonParser parser, DeserializationContext context) throws IOException {
- return X509CertificateUtils.fromPem(parser.getValueAsString());
- }
- }
-
}
diff --git a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/bindings/InstanceRefreshInformation.java b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/bindings/InstanceRefreshInformation.java
index 6c956ddb410..b842ef43500 100644
--- a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/bindings/InstanceRefreshInformation.java
+++ b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/bindings/InstanceRefreshInformation.java
@@ -4,8 +4,9 @@ package com.yahoo.vespa.athenz.client.zts.bindings;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import com.yahoo.vespa.athenz.client.zts.bindings.serializers.Pkcs10CsrSerializer;
import com.yahoo.vespa.athenz.tls.Pkcs10Csr;
-import com.yahoo.vespa.athenz.tls.Pkcs10CsrUtils;
/**
* @author bjorncs
@@ -15,13 +16,14 @@ import com.yahoo.vespa.athenz.tls.Pkcs10CsrUtils;
public class InstanceRefreshInformation {
@JsonProperty("csr")
- private final String csr;
+ @JsonSerialize(using = Pkcs10CsrSerializer.class)
+ private final Pkcs10Csr csr;
@JsonProperty("token")
private final boolean requestServiceToken;
public InstanceRefreshInformation(Pkcs10Csr csr,
boolean requestServiceToken) {
- this.csr = Pkcs10CsrUtils.toPem(csr);
+ this.csr = csr;
this.requestServiceToken = requestServiceToken;
}
}
diff --git a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/bindings/RoleCertificateRequestEntity.java b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/bindings/RoleCertificateRequestEntity.java
index 9c56e5a60d6..f329ffbbd2c 100644
--- a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/bindings/RoleCertificateRequestEntity.java
+++ b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/bindings/RoleCertificateRequestEntity.java
@@ -8,8 +8,8 @@ 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.client.zts.bindings.serializers.Pkcs10CsrSerializer;
import com.yahoo.vespa.athenz.tls.Pkcs10Csr;
-import com.yahoo.vespa.athenz.tls.Pkcs10CsrUtils;
import java.io.IOException;
import java.time.Duration;
@@ -20,7 +20,7 @@ import java.time.Duration;
@JsonIgnoreProperties(ignoreUnknown = true)
public class RoleCertificateRequestEntity {
@JsonProperty("csr")
- @JsonSerialize(using = CsrSerializer.class)
+ @JsonSerialize(using = Pkcs10CsrSerializer.class)
public final Pkcs10Csr csr;
@JsonProperty("expiryTime")
@@ -33,15 +33,6 @@ public class RoleCertificateRequestEntity {
this.expiryTime = expiryTime;
}
- public static class CsrSerializer extends JsonSerializer<Pkcs10Csr> {
- @Override
- public void serialize(Pkcs10Csr csr,
- JsonGenerator jsonGenerator,
- SerializerProvider serializerProvider) throws IOException {
- jsonGenerator.writeString(Pkcs10CsrUtils.toPem(csr));
- }
- }
-
public static class ExpirySerializer extends JsonSerializer<Duration> {
@Override
public void serialize(Duration duration,
diff --git a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/bindings/RoleCertificateResponseEntity.java b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/bindings/RoleCertificateResponseEntity.java
index 1b4bd463392..e80f5626843 100644
--- a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/bindings/RoleCertificateResponseEntity.java
+++ b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/bindings/RoleCertificateResponseEntity.java
@@ -4,13 +4,9 @@ package com.yahoo.vespa.athenz.client.zts.bindings;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
-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 com.yahoo.vespa.athenz.client.zts.bindings.serializers.X509CertificateDeserializer;
-import java.io.IOException;
import java.security.cert.X509Certificate;
import java.time.Instant;
@@ -28,11 +24,4 @@ public class RoleCertificateResponseEntity {
this.certificate = certificate;
this.expiry = expiry;
}
-
- public static class X509CertificateDeserializer extends JsonDeserializer<X509Certificate> {
- @Override
- public X509Certificate deserialize(JsonParser parser, DeserializationContext context) throws IOException {
- return X509CertificateUtils.fromPem(parser.getValueAsString());
- }
- }
}
diff --git a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/bindings/serializers/Pkcs10CsrSerializer.java b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/bindings/serializers/Pkcs10CsrSerializer.java
new file mode 100644
index 00000000000..24825792953
--- /dev/null
+++ b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/bindings/serializers/Pkcs10CsrSerializer.java
@@ -0,0 +1,20 @@
+// 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.client.zts.bindings.serializers;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.databind.JsonSerializer;
+import com.fasterxml.jackson.databind.SerializerProvider;
+import com.yahoo.vespa.athenz.tls.Pkcs10Csr;
+import com.yahoo.vespa.athenz.tls.Pkcs10CsrUtils;
+
+import java.io.IOException;
+
+/**
+ * @author bjorncs
+ */
+public class Pkcs10CsrSerializer extends JsonSerializer<Pkcs10Csr> {
+ @Override
+ public void serialize(Pkcs10Csr csr, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
+ jsonGenerator.writeString(Pkcs10CsrUtils.toPem(csr));
+ }
+}
diff --git a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/bindings/serializers/X509CertificateDeserializer.java b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/bindings/serializers/X509CertificateDeserializer.java
new file mode 100644
index 00000000000..5dd6ceb16b4
--- /dev/null
+++ b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/bindings/serializers/X509CertificateDeserializer.java
@@ -0,0 +1,21 @@
+// 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.client.zts.bindings.serializers;
+
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.JsonDeserializer;
+import com.yahoo.vespa.athenz.tls.X509CertificateUtils;
+
+import java.io.IOException;
+import java.security.cert.X509Certificate;
+
+/**
+ * @author bjorncs
+ */
+public class X509CertificateDeserializer extends JsonDeserializer<X509Certificate> {
+ @Override
+ public X509Certificate deserialize(JsonParser parser, DeserializationContext context) throws IOException {
+ return X509CertificateUtils.fromPem(parser.getValueAsString());
+ }
+}
+
diff --git a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/bindings/serializers/X509CertificateListDeserializer.java b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/bindings/serializers/X509CertificateListDeserializer.java
new file mode 100644
index 00000000000..c496031c116
--- /dev/null
+++ b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/bindings/serializers/X509CertificateListDeserializer.java
@@ -0,0 +1,22 @@
+// 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.client.zts.bindings.serializers;
+
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.JsonDeserializer;
+import com.yahoo.vespa.athenz.tls.X509CertificateUtils;
+
+import java.io.IOException;
+import java.security.cert.X509Certificate;
+import java.util.List;
+
+/**
+ * @author bjorncs
+ */
+public class X509CertificateListDeserializer extends JsonDeserializer<List<X509Certificate>> {
+
+ @Override
+ public List<X509Certificate> deserialize(JsonParser parser, DeserializationContext ctxt) throws IOException {
+ return X509CertificateUtils.certificateListFromPem(parser.getValueAsString());
+ }
+}
diff --git a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/bindings/serializers/package-info.java b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/bindings/serializers/package-info.java
new file mode 100644
index 00000000000..4c442617494
--- /dev/null
+++ b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/bindings/serializers/package-info.java
@@ -0,0 +1,8 @@
+// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+/**
+ * @author bjorncs
+ */
+@ExportPackage
+package com.yahoo.vespa.athenz.client.zts.bindings.serializers;
+
+import com.yahoo.osgi.annotation.ExportPackage; \ No newline at end of file
diff --git a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/utils/IdentityCsrGenerator.java b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/utils/IdentityCsrGenerator.java
new file mode 100644
index 00000000000..2f152fafba8
--- /dev/null
+++ b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/utils/IdentityCsrGenerator.java
@@ -0,0 +1,37 @@
+// 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.client.zts.utils;
+
+import com.yahoo.vespa.athenz.api.AthenzService;
+import com.yahoo.vespa.athenz.client.zts.ZtsClient;
+import com.yahoo.vespa.athenz.tls.Pkcs10Csr;
+import com.yahoo.vespa.athenz.tls.Pkcs10CsrBuilder;
+
+import javax.security.auth.x500.X500Principal;
+import java.security.KeyPair;
+
+import static com.yahoo.vespa.athenz.tls.SignatureAlgorithm.SHA256_WITH_RSA;
+
+/**
+ * Generates a {@link Pkcs10Csr} instance for use with {@link ZtsClient#getServiceIdentity(AthenzService, String, Pkcs10Csr)}
+ *
+ * @author bjorncs
+ */
+public class IdentityCsrGenerator {
+
+ private final String dnsSuffix;
+
+ public IdentityCsrGenerator(String dnsSuffix) {
+ this.dnsSuffix = dnsSuffix;
+ }
+
+ public Pkcs10Csr generateIdentityCsr(AthenzService identity, KeyPair keypair) {
+ return Pkcs10CsrBuilder.fromKeypair(new X500Principal("CN=" + identity.getFullName()), keypair, SHA256_WITH_RSA)
+ .addSubjectAlternativeName(String.format(
+ "%s.%s.%s",
+ identity.getName(),
+ identity.getDomainName().replace(".", "-"),
+ dnsSuffix))
+ .build();
+ }
+
+}
diff --git a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/utils/package-info.java b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/utils/package-info.java
new file mode 100644
index 00000000000..baca71bc187
--- /dev/null
+++ b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/utils/package-info.java
@@ -0,0 +1,8 @@
+// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+/**
+ * @author bjorncs
+ */
+@ExportPackage
+package com.yahoo.vespa.athenz.client.zts.utils;
+
+import com.yahoo.osgi.annotation.ExportPackage; \ No newline at end of file
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
index 6ba094ff275..d96ed17765c 100644
--- 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
@@ -21,6 +21,7 @@ import java.io.UncheckedIOException;
import java.security.GeneralSecurityException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
+import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -36,16 +37,22 @@ public class 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);
+ return toX509Certificate(parser.readObject());
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ } catch (CertificateException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public static List<X509Certificate> certificateListFromPem(String pem) {
+ try (PEMParser parser = new PEMParser(new StringReader(pem))) {
+ List<X509Certificate> list = new ArrayList<>();
+ Object pemObject;
+ while ((pemObject = parser.readObject()) != null) {
+ list.add(toX509Certificate(pemObject));
}
- throw new IllegalArgumentException("Invalid type of PEM object: " + pemObject);
+ return list;
} catch (IOException e) {
throw new UncheckedIOException(e);
} catch (CertificateException e) {
@@ -53,6 +60,18 @@ public class X509CertificateUtils {
}
}
+ private static X509Certificate toX509Certificate(Object pemObject) throws CertificateException {
+ 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);
+ }
+
public static String toPem(X509Certificate certificate) {
try (StringWriter stringWriter = new StringWriter(); JcaPEMWriter pemWriter = new JcaPEMWriter(stringWriter)) {
pemWriter.writeObject(new PemObject("CERTIFICATE", certificate.getEncoded()));
@@ -65,6 +84,20 @@ public class X509CertificateUtils {
}
}
+ public static String toPem(List<X509Certificate> certificates) {
+ try (StringWriter stringWriter = new StringWriter(); JcaPEMWriter pemWriter = new JcaPEMWriter(stringWriter)) {
+ for (X509Certificate certificate : certificates) {
+ 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> getSubjectCommonNames(X509Certificate certificate) {
return getCommonNames(certificate.getSubjectX500Principal());
}
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..2a9b54f9e9e 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
@@ -24,7 +24,10 @@ class TestUtils {
}
static X509Certificate createCertificate(KeyPair keyPair) {
- X500Principal subject = new X500Principal("CN=mysubject");
+ return createCertificate(keyPair, new X500Principal("CN=mysubject"));
+ }
+
+ static X509Certificate createCertificate(KeyPair keyPair, X500Principal subject) {
return X509CertificateBuilder
.fromKeypair(
keyPair, subject, Instant.now(), Instant.now().plus(1, ChronoUnit.DAYS), SignatureAlgorithm.SHA256_WITH_RSA, 1)
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
index 718c0e88972..4039bf36a5f 100644
--- 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
@@ -7,6 +7,7 @@ import java.security.KeyPair;
import java.security.cert.X509Certificate;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
+import java.util.Arrays;
import java.util.List;
import static com.yahoo.vespa.athenz.tls.SubjectAlternativeName.Type.DNS_NAME;
@@ -24,15 +25,7 @@ public class X509CertificateUtilsTest {
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();
+ X509Certificate cert = TestUtils.createCertificate(keypair, subject);
assertEquals(subject, cert.getSubjectX500Principal());
String pem = X509CertificateUtils.toPem(cert);
assertThat(pem, containsString("BEGIN CERTIFICATE"));
@@ -41,6 +34,20 @@ public class X509CertificateUtilsTest {
assertEquals(subject, deserializedCert.getSubjectX500Principal());
}
+ @Test
+ public void can_deserialize_serialized_pem_certificate_list() {
+ KeyPair keypair = KeyUtils.generateKeypair(KeyAlgorithm.RSA, 2048);
+ X500Principal subject1 = new X500Principal("CN=myservice");
+ X509Certificate cert1 = TestUtils.createCertificate(keypair, subject1);
+ X500Principal subject2 = new X500Principal("CN=myservice");
+ X509Certificate cert2 = TestUtils.createCertificate(keypair, subject2);
+ List<X509Certificate> certificateList = Arrays.asList(cert1, cert2);
+ String pem = X509CertificateUtils.toPem(certificateList);
+ List<X509Certificate> deserializedCertificateList = X509CertificateUtils.certificateListFromPem(pem);
+ assertEquals(2, certificateList.size());
+ assertEquals(subject1, deserializedCertificateList.get(0).getSubjectX500Principal());
+ assertEquals(subject2, deserializedCertificateList.get(1).getSubjectX500Principal());
+ }
@Test
public void can_list_subject_alternative_names() {