aboutsummaryrefslogtreecommitdiffstats
path: root/vespa-athenz
diff options
context:
space:
mode:
authorBjørn Christian Seime <bjorncs@oath.com>2018-06-12 18:19:28 +0200
committerBjørn Christian Seime <bjorncs@oath.com>2018-06-12 18:19:28 +0200
commita2989608d5ddee1ce6ad870ce2aeab14495d96e9 (patch)
tree03f15ceedb5afc42092e6dd1b60fbb795cdebab3 /vespa-athenz
parentd8d316de3028e101140bff177ffa6ce66c17524e (diff)
Separate generating and validating signature to separate class
- Move signature logic to IdentityDocumentSigner - Stop using fields from deprecated IdentityDocument to generate signature
Diffstat (limited to 'vespa-athenz')
-rw-r--r--vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/client/IdentityDocumentSigner.java85
-rw-r--r--vespa-athenz/src/main/java/com/yahoo/vespa/athenz/tls/SignatureAlgorithm.java3
-rw-r--r--vespa-athenz/src/test/java/com/yahoo/vespa/athenz/identityprovider/client/IdentityDocumentSignerTest.java50
3 files changed, 137 insertions, 1 deletions
diff --git a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/client/IdentityDocumentSigner.java b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/client/IdentityDocumentSigner.java
new file mode 100644
index 00000000000..b3b5df0e68b
--- /dev/null
+++ b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/client/IdentityDocumentSigner.java
@@ -0,0 +1,85 @@
+// 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.client;
+
+import com.yahoo.vespa.athenz.api.AthenzService;
+import com.yahoo.vespa.athenz.identityprovider.api.IdentityType;
+import com.yahoo.vespa.athenz.identityprovider.api.SignedIdentityDocument;
+import com.yahoo.vespa.athenz.identityprovider.api.VespaUniqueInstanceId;
+import com.yahoo.vespa.athenz.tls.SignatureAlgorithm;
+
+import java.nio.ByteBuffer;
+import java.security.GeneralSecurityException;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.time.Instant;
+import java.util.Base64;
+import java.util.Set;
+import java.util.TreeSet;
+
+import static java.nio.charset.StandardCharsets.UTF_8;
+
+/**
+ * Generates and validates the signature for a {@link SignedIdentityDocument}
+ *
+ * @author bjorncs
+ */
+public class IdentityDocumentSigner {
+
+ public String generateSignature(VespaUniqueInstanceId providerUniqueId,
+ AthenzService providerService,
+ String configServerHostname,
+ String instanceHostname,
+ Instant createdAt,
+ Set<String> ipAddresses,
+ IdentityType identityType,
+ PrivateKey privateKey) {
+ try {
+ Signature signer = createSigner();
+ signer.initSign(privateKey);
+ writeToSigner(signer, providerUniqueId, providerService, configServerHostname, instanceHostname, createdAt, ipAddresses, identityType);
+ byte[] signature = signer.sign();
+ return Base64.getEncoder().encodeToString(signature);
+ } catch (GeneralSecurityException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public boolean hasValidSignature(SignedIdentityDocument doc, PublicKey publicKey) {
+ try {
+ Signature signer = createSigner();
+ signer.initVerify(publicKey);
+ writeToSigner(signer, doc.providerUniqueId(), doc.providerService(), doc.configServerHostname(), doc.instanceHostname(), doc.createdAt(), doc.ipAddresses(), doc.identityType());
+ return signer.verify(Base64.getDecoder().decode(doc.signature()));
+ } catch (GeneralSecurityException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private static Signature createSigner() throws NoSuchAlgorithmException {
+ return Signature.getInstance(SignatureAlgorithm.SHA512_WITH_RSA.getAlgorithmName());
+ }
+
+ private static void writeToSigner(Signature signer,
+ VespaUniqueInstanceId providerUniqueId,
+ AthenzService providerService,
+ String configServerHostname,
+ String instanceHostname,
+ Instant createdAt,
+ Set<String> ipAddresses,
+ IdentityType identityType) throws SignatureException {
+ signer.update(providerUniqueId.asDottedString().getBytes(UTF_8));
+ signer.update(providerService.getFullName().getBytes(UTF_8));
+ signer.update(configServerHostname.getBytes(UTF_8));
+ signer.update(instanceHostname.getBytes(UTF_8));
+ ByteBuffer timestampAsBuffer = ByteBuffer.allocate(Long.BYTES);
+ timestampAsBuffer.putLong(createdAt.toEpochMilli());
+ signer.update(timestampAsBuffer.array());
+ for (String ipAddress : new TreeSet<>(ipAddresses)) {
+ signer.update(ipAddress.getBytes(UTF_8));
+ }
+ signer.update(identityType.id().getBytes(UTF_8));
+ }
+}
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
index 3d85a12f714..2f3e2721751 100644
--- 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
@@ -5,7 +5,8 @@ package com.yahoo.vespa.athenz.tls;
* @author bjorncs
*/
public enum SignatureAlgorithm {
- SHA256_WITH_RSA("SHA256withRSA");
+ SHA256_WITH_RSA("SHA256withRSA"),
+ SHA512_WITH_RSA("SHA512withRSA");
private final String algorithmName;
diff --git a/vespa-athenz/src/test/java/com/yahoo/vespa/athenz/identityprovider/client/IdentityDocumentSignerTest.java b/vespa-athenz/src/test/java/com/yahoo/vespa/athenz/identityprovider/client/IdentityDocumentSignerTest.java
new file mode 100644
index 00000000000..9cc500ee241
--- /dev/null
+++ b/vespa-athenz/src/test/java/com/yahoo/vespa/athenz/identityprovider/client/IdentityDocumentSignerTest.java
@@ -0,0 +1,50 @@
+// 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.client;
+
+import com.yahoo.vespa.athenz.api.AthenzService;
+import com.yahoo.vespa.athenz.identityprovider.api.IdentityType;
+import com.yahoo.vespa.athenz.identityprovider.api.SignedIdentityDocument;
+import com.yahoo.vespa.athenz.identityprovider.api.VespaUniqueInstanceId;
+import com.yahoo.vespa.athenz.tls.KeyAlgorithm;
+import com.yahoo.vespa.athenz.tls.KeyUtils;
+import org.junit.Test;
+
+import java.net.URI;
+import java.security.KeyPair;
+import java.time.Instant;
+import java.util.Arrays;
+import java.util.HashSet;
+
+import static com.yahoo.vespa.athenz.identityprovider.api.IdentityType.TENANT;
+import static com.yahoo.vespa.athenz.identityprovider.api.SignedIdentityDocument.DEFAULT_DOCUMENT_VERSION;
+import static com.yahoo.vespa.athenz.identityprovider.api.SignedIdentityDocument.DEFAULT_KEY_VERSION;
+import static org.junit.Assert.*;
+
+/**
+ * @author bjorncs
+ */
+public class IdentityDocumentSignerTest {
+
+ @Test
+ public void generates_and_validates_signature() {
+ IdentityDocumentSigner signer = new IdentityDocumentSigner();
+ IdentityType identityType = TENANT;
+ VespaUniqueInstanceId id =
+ new VespaUniqueInstanceId(1, "cluster-id", "instance", "application", "tenant", "region", "environment", identityType);
+ AthenzService providerService = new AthenzService("vespa", "service");
+ KeyPair keyPair = KeyUtils.generateKeypair(KeyAlgorithm.RSA);
+ String configserverHostname = "configserverhostname";
+ String instanceHostname = "instancehostname";
+ Instant createdAt = Instant.EPOCH;
+ HashSet<String> ipAddresses = new HashSet<>(Arrays.asList("1.2.3.4", "::1"));
+ String signature =
+ signer.generateSignature(id, providerService, configserverHostname, instanceHostname, createdAt, ipAddresses, identityType, keyPair.getPrivate());
+
+ SignedIdentityDocument signedIdentityDocument = new SignedIdentityDocument(
+ null, signature, DEFAULT_KEY_VERSION, id, "dns-suffix", providerService, URI.create("https://zts"),
+ DEFAULT_DOCUMENT_VERSION, configserverHostname, instanceHostname, createdAt, ipAddresses, identityType);
+
+ assertTrue(signer.hasValidSignature(signedIdentityDocument, keyPair.getPublic()));
+ }
+
+} \ No newline at end of file