Extend Transit API to support Hashing and Signing Operations.

Transit API now has support to generate HMAC digests, signatures and verify signatures.

Plaintext plaintext = Plaintext.of("hello-world");

Signature signature = transitOperations.sign(keyName, plaintext);
boolean valid = transitOperations.verify(keyName, plaintext, signature);

Hmac hmac = transitOperations.getHmac(keyName, plaintext);
SignatureValidation validation = transitOperations.verify(keyName,
		VaultSignatureVerificationRequest.create(plaintext, hmac));

Original pull request: gh-162.
Closes: gh-148.
This commit is contained in:
Luander Ribeiro
2017-10-15 12:08:13 +02:00
committed by Mark Paluch
parent 438b8db745
commit 10488de17a
8 changed files with 968 additions and 0 deletions

View File

@@ -19,11 +19,16 @@ import java.util.List;
import org.springframework.lang.Nullable;
import org.springframework.vault.support.Ciphertext;
import org.springframework.vault.support.Hmac;
import org.springframework.vault.support.Plaintext;
import org.springframework.vault.support.RawTransitKey;
import org.springframework.vault.support.Signature;
import org.springframework.vault.support.TransitKeyType;
import org.springframework.vault.support.VaultDecryptionResult;
import org.springframework.vault.support.VaultEncryptionResult;
import org.springframework.vault.support.VaultHmacRequest;
import org.springframework.vault.support.VaultSignRequest;
import org.springframework.vault.support.VaultSignatureVerificationRequest;
import org.springframework.vault.support.VaultTransitContext;
import org.springframework.vault.support.VaultTransitKey;
import org.springframework.vault.support.VaultTransitKeyConfiguration;
@@ -222,4 +227,61 @@ public interface VaultTransitOperations {
* @see #rotate(String)
*/
String rewrap(String keyName, String ciphertext, VaultTransitContext transitContext);
/**
* Generate HMAC digest of given data.
*
* @param keyName must not be empty or {@literal null}.
* @param plaintext must not be empty or {@literal null}.
* @return the digest of given data using sha2-256 hash algorithm and the named key.
*/
Hmac generateHmac(String keyName, Plaintext plaintext);
/**
* Generate HMAC digest of given data.
*
* @param keyName must not be empty or {@literal null}.
* @param request {@link VaultHmacRequest} must not be empty or {@literal null}.
* @return the digest of given data using the specified hash algorithm and the named key.
*/
Hmac generateHmac(String keyName, VaultHmacRequest request);
/**
* Sign a String using a key from the vault using the SHA-256 algorithm.
*
* @param keyName must not be empty or {@literal null}.
* @param plaintext must not be empty or {@literal null}.
* @return Signature of the payload
*/
Signature sign(String keyName, Plaintext plaintext);
/**
* Sign a String using a key from the vault.
*
* @param keyName must not be empty or {@literal null}.
* @param request {@link VaultSignRequest}
* must not be empty or {@literal null}.
* @return Signature of the payload
*/
Signature sign(String keyName, VaultSignRequest request);
/**
* Verify the validity of a signature in the vault.
*
* @param keyName must not be empty or {@literal null}.
* @param plaintext must not be empty or {@literal null}.
* @param signature Signature to be verified
* @return true if the signature is valid, false otherwise
*/
boolean verify(String keyName, Plaintext plaintext, Signature signature);
/**
* Verify the validity of a signature in the vault.
*
* @param keyName must not be empty or {@literal null}.
* @param request {@link VaultSignatureVerificationRequest}
* must not be empty or {@literal null}.
* @return true if the signature is valid, false otherwise
*/
boolean verify(String keyName, VaultSignatureVerificationRequest request);
}

View File

@@ -31,13 +31,18 @@ import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import org.springframework.vault.VaultException;
import org.springframework.vault.support.Ciphertext;
import org.springframework.vault.support.Hmac;
import org.springframework.vault.support.Plaintext;
import org.springframework.vault.support.RawTransitKey;
import org.springframework.vault.support.Signature;
import org.springframework.vault.support.TransitKeyType;
import org.springframework.vault.support.VaultDecryptionResult;
import org.springframework.vault.support.VaultEncryptionResult;
import org.springframework.vault.support.VaultHmacRequest;
import org.springframework.vault.support.VaultResponse;
import org.springframework.vault.support.VaultResponseSupport;
import org.springframework.vault.support.VaultSignRequest;
import org.springframework.vault.support.VaultSignatureVerificationRequest;
import org.springframework.vault.support.VaultTransitContext;
import org.springframework.vault.support.VaultTransitKey;
import org.springframework.vault.support.VaultTransitKeyConfiguration;
@@ -49,6 +54,7 @@ import org.springframework.vault.support.VaultTransitKeyCreationRequest;
* @author Mark Paluch
* @author Sven Schürmann
* @author Praveendra Singh
* @author Luander Ribeiro
*/
public class VaultTransitTemplate implements VaultTransitOperations {
@@ -56,6 +62,8 @@ public class VaultTransitTemplate implements VaultTransitOperations {
private final String path;
private static final String DEFAULT_SIGN_ALGORITHM = "sha2-256";
public VaultTransitTemplate(VaultOperations vaultOperations, String path) {
Assert.notNull(vaultOperations, "VaultOperations must not be null");
@@ -340,6 +348,74 @@ public class VaultTransitTemplate implements VaultTransitOperations {
.getRequiredData().get("ciphertext");
}
@Override
public Hmac generateHmac(String keyName, Plaintext plaintext) {
Assert.notNull(plaintext, "Plaintext must not be null");
VaultHmacRequest request = VaultHmacRequest.ofInput(plaintext);
return generateHmac(keyName, request);
}
@Override
public Hmac generateHmac(String keyName, VaultHmacRequest hmacRequest) {
Assert.hasText(keyName, "KeyName must not be empty");
Assert.notNull(hmacRequest, "Request must not be null");
String hmac = (String) vaultOperations.
write(String.format("%s/hmac/%s", path, keyName), hmacRequest).getData()
.get("hmac");
return toHmac(hmac, hmacRequest.getContext());
}
@Override
public Signature sign(String keyName, Plaintext plaintext) {
Assert.notNull(plaintext, "Plaintext must not be null");
VaultSignRequest request = VaultSignRequest.ofInput(plaintext);
return sign(keyName, request);
}
@Override
public Signature sign(String keyName, VaultSignRequest signRequest) {
Assert.hasText(keyName, "KeyName must not be empty");
Assert.notNull(signRequest, "Plain text must not be null");
String signature = (String) vaultOperations.
write(String.format("%s/sign/%s", path, keyName), signRequest).getData()
.get("signature");
return toSignature(signature, signRequest.getContext());
}
@Override
public boolean verify(String keyName, Plaintext plainText, Signature signature) {
Assert.notNull(signature, "Signature must not be null");
Assert.notNull(plainText, "Input must not be null");
VaultSignatureVerificationRequest request =
VaultSignatureVerificationRequest.builder()
.input(plainText)
.signature(signature)
.build();
return verify(keyName, request);
}
@Override
public boolean verify(String keyName, VaultSignatureVerificationRequest request) {
Assert.notNull(request, "Request must not be null");
return (boolean) vaultOperations.
write(String.format("%s/verify/%s", path, keyName), request).getData()
.get("valid");
}
private static void applyTransitOptions(VaultTransitContext context,
Map<String, String> request) {
@@ -431,6 +507,16 @@ public class VaultTransitTemplate implements VaultTransitOperations {
.of(plaintext);
}
private static Hmac toHmac(String plaintext, VaultTransitContext context) {
return context != null ? Hmac.of(plaintext).with(context) : Hmac
.of(plaintext);
}
private static Signature toSignature(String plaintext, VaultTransitContext context) {
return context != null ? Signature.of(plaintext).with(context) : Signature
.of(plaintext);
}
@SuppressWarnings("unchecked")
private static List<Map<String, String>> getBatchData(VaultResponse vaultResponse) {
return (List<Map<String, String>>) vaultResponse.getRequiredData().get(

View File

@@ -0,0 +1,86 @@
/*
* Copyright 2016-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.vault.support;
import lombok.EqualsAndHashCode;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
import java.util.Arrays;
/**
* Value object representing Hmac digest with an optional {@link VaultTransitContext}.
*
* @author Luander Ribeiro
*/
@EqualsAndHashCode
public class Hmac {
private final String hmac;
private final VaultTransitContext context;
private Hmac(String hmac, VaultTransitContext context) {
this.hmac = hmac;
this.context = context;
}
/**
* Factory method to create {@link Hmac} from a byte sequence.
*
* @param hmac the Hmac digest, must not be {@literal null} or empty.
* @return the {@link Hmac} for {@code plaintext}.
*/
public static Hmac of(byte[] hmac) {
Assert.isTrue(!ObjectUtils.isEmpty(hmac),
"Hmac must not be null or empty");
return new Hmac(Arrays.toString(hmac), VaultTransitContext.empty());
}
/**
* Factory method to create {@link Hmac} from the given {@code hmac}.
*
* @param hmac the Hmac digest, must not be {@literal null} or empty.
* @return the {@link Hmac} for {@code hmac}.
*/
public static Hmac of(String hmac) {
Assert.hasText(hmac, "Hmac digest must not be null or empty");
return new Hmac(hmac, VaultTransitContext.empty());
}
public String getHmac() {
return hmac;
}
public VaultTransitContext getContext() {
return context;
}
/**
* Create a new {@link Hmac} object from this Hmac digest associated with the
* given {@link VaultTransitContext}.
*
* @param context transit context.
* @return the new {@link Hmac} object.
*/
public Hmac with(VaultTransitContext context) {
return new Hmac(getHmac(), context);
}
}

View File

@@ -0,0 +1,87 @@
/*
* Copyright 2016-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.vault.support;
import lombok.EqualsAndHashCode;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
import java.util.Arrays;
/**
* Value object representing Signature with an optional {@link VaultTransitContext}.
*
* @author Luander Ribeiro
*/
@EqualsAndHashCode
public class Signature {
private final String signature;
private final VaultTransitContext context;
private Signature(String signature, VaultTransitContext context) {
this.signature = signature;
this.context = context;
}
/**
* Factory method to create {@link Signature} from the given {@code signature}.
*
* @param signature the signature, must not be {@literal null} or empty.
* @return the {@link Signature} for {@code signature}.
*/
public static Signature of(byte[] signature) {
Assert.isTrue(!ObjectUtils.isEmpty(signature),
"Signature must not be null or empty");
return new Signature(Arrays.toString(signature), VaultTransitContext.empty());
}
/**
* Factory method to create {@link Signature} from the given {@code signature}.
*
* @param signature the signature, must not be {@literal null} or empty.
* @return the {@link Signature} for {@code signature}.
*/
public static Signature of(String signature) {
Assert.hasText(signature, "Signature must not be null or empty");
return new Signature(signature, VaultTransitContext.empty());
}
public String getSignature() {
return signature;
}
public VaultTransitContext getContext() {
return context;
}
/**
* Create a new {@link Signature} object from this signature associated with the
* given {@link VaultTransitContext}.
*
* @param context transit context.
* @return the new {@link Signature} object.
*/
public Signature with(VaultTransitContext context) {
return new Signature(getSignature(), context);
}
}

View File

@@ -0,0 +1,165 @@
/*
* Copyright 2016-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.vault.support;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import org.springframework.util.Assert;
import org.springframework.util.Base64Utils;
/**
* Request for a HMAC Digest.
*
* @author Luander Ribeiro
*/
public class VaultHmacRequest {
@JsonProperty("key_version")
private final int keyVersion;
private final String algorithm;
private final String input;
@JsonIgnore
private final VaultTransitContext context;
private VaultHmacRequest(int keyVersion, String algorithm,
String input, VaultTransitContext context) {
this.algorithm = algorithm;
this.input = Base64Utils.encodeToString(input.getBytes());
this.keyVersion = keyVersion;
this.context = context;
}
/**
* @return New instance of {@link VaultHmacRequest.VaultHmacRequestBuilder}
*/
public static VaultHmacRequestBuilder builder() {
return new VaultHmacRequestBuilder();
}
/**
* Create a new {@link VaultHmacRequest} specifically for an {@code input}.
* Uses {@code sha2-256} algorithm.
*
* @return a new {@link VaultHmacRequest} for the given {@code input}.
*/
public static VaultHmacRequest ofInput(Plaintext input) {
return builder().input(input).build();
}
/**
* @return Algorithm used for creating the digest.
*/
public String getAlgorithm() {
return algorithm;
}
/**
* @return plain text input used as basis to generate the digest.
*/
public String getInput() {
return input;
}
/**
* @return Version of the key used. If not set the latest version is used.
*/
public int getKeyVersion() {
return keyVersion;
}
public VaultTransitContext getContext() {
return context;
}
public static class VaultHmacRequestBuilder {
private int keyVersion;
private String algorithm = "sha2-256";
private Plaintext input;
private VaultTransitContext context;
/**
* Configure the algorithm to be used for the operation.
*
* @param algorithm Specify the algorithm to be used for the operation. If not set,
* sha2-256 is used.
* Supported algorithms are:
* sha2-224, sha2-256, sha2-384, sha2-512
* @return {@code this}
*/
public VaultHmacRequestBuilder algorithm(String algorithm) {
this.algorithm = algorithm;
return this;
}
/**
* Configure the input to be used to create the digest.
*
* @param input base input to create the digest, must not be empty or {@literal null}.
* @return {@code this}.
*/
public VaultHmacRequestBuilder input(Plaintext input) {
this.input = input;
this.context = input.getContext();
return this;
}
/**
* Configure the input to be used to create the digest.
*
* @param input base input to create the digest, must not be empty or {@literal null}.
* @return {@code this}
*/
public VaultHmacRequestBuilder input(String input) {
this.input = Plaintext.of(input);
this.context = VaultTransitContext.empty();
return this;
}
/**
* Configure the version to be used for the operation.
*
* @param version key version to be used. If not set, uses the latest version.
* @return {@code this} {@link VaultHmacRequest.VaultHmacRequestBuilder}.
*/
public VaultHmacRequestBuilder keyVersion(int version) {
this.keyVersion = version;
return this;
}
/**
* Build a new {@link VaultHmacRequest} instance. Requires
* {@link #input(String)} or {@link #input(Plaintext)} to be configured.
*
* @return a new {@link VaultHmacRequest}.
*/
public VaultHmacRequest build() {
Assert.notNull(input, "Input must not be empty");
return new VaultHmacRequest(keyVersion, algorithm, input.asString(), context);
}
}
}

View File

@@ -0,0 +1,135 @@
/*
* Copyright 2016-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.vault.support;
import com.fasterxml.jackson.annotation.JsonIgnore;
import org.springframework.util.Assert;
import org.springframework.util.Base64Utils;
/**
* Request for a signature creation request.
*
* @author Luander Ribeiro
*/
public class VaultSignRequest {
private final String algorithm;
private final String input;
@JsonIgnore
private final VaultTransitContext context;
private VaultSignRequest(String algorithm, String input, VaultTransitContext context) {
this.algorithm = algorithm;
this.input = Base64Utils.encodeToString(input.getBytes());
this.context = context;
}
/**
* @return New instance of {@link VaultSignRequest.VaultSignRequestBuilder}
*/
public static VaultSignRequestBuilder builder() {
return new VaultSignRequestBuilder();
}
/**
* Create a new {@link VaultSignRequest} specifically for an {@code input}.
* Uses {@code sha2-256} algorithm.
*
* @return a new {@link VaultSignRequest} for the given {@code input}.
*/
public static VaultSignRequest ofInput(Plaintext input) {
return builder().input(input).build();
}
/**
* @return Algorithm used for creating the digest.
*/
public String getAlgorithm() {
return algorithm;
}
/**
* @return plain text input used as basis to generate the digest.
*/
public String getInput() {
return input;
}
public VaultTransitContext getContext() {
return context;
}
public static class VaultSignRequestBuilder {
private String algorithm = "sha2-256";
private Plaintext input;
private VaultTransitContext context;
/**
* Configure the algorithm to be used for the operation.
*
* @param algorithm Specify the algorithm to be used for the operation. If not set,
* sha2-256 is used.
* Supported algorithms are:
* sha2-224, sha2-256, sha2-384, sha2-512
* @return {@code this}
*/
public VaultSignRequestBuilder algorithm(String algorithm) {
this.algorithm = algorithm;
this.context = VaultTransitContext.empty();
return this;
}
/**
* Configure the input to be used to create the digest.
*
* @param input base input to create the digest, must not be empty or {@literal null}.
* @return {@code this}.
*/
public VaultSignRequestBuilder input(Plaintext input) {
this.input = input;
this.context = input.getContext();
return this;
}
/**
* Configure the input to be used to create the digest.
*
* @param input base input to create the digest, must not be empty or {@literal null}.
* @return {@code this}
*/
public VaultSignRequestBuilder input(String input) {
this.input = Plaintext.of(input);
return this;
}
/**
* Build a new {@link VaultHmacRequest} instance. Requires
* {@link #input(String)} or {@link #input(Plaintext)} to be configured.
*
* @return a new {@link VaultHmacRequest}.
*/
public VaultSignRequest build() {
Assert.notNull(input, "Input must not be empty");
return new VaultSignRequest(algorithm, input.asString(), context);
}
}
}

View File

@@ -0,0 +1,178 @@
/*
* Copyright 2016-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.vault.support;
import org.springframework.util.Assert;
import org.springframework.util.Base64Utils;
/**
* Request for a signature verification.
*
* @author Luander Ribeiro
*/
public class VaultSignatureVerificationRequest {
private final String algorithm;
private final String input;
private final String signature;
private final String hmac;
private VaultSignatureVerificationRequest(String algorithm, String input,
String signature, String hmac) {
this.algorithm = algorithm;
this.input = Base64Utils.encodeToString(input.getBytes());
this.signature = String.valueOf(signature);
this.hmac = hmac;
}
/**
* @return New instance of
* {@link VaultSignatureVerificationRequest.VaultSignatureVerificationRequestBuilder}
*/
public static VaultSignatureVerificationRequestBuilder builder() {
return new VaultSignatureVerificationRequestBuilder();
}
/**
* Create a new {@link VaultHmacRequest} specifically for a {@code algorithm}.
*
* @param algorithm Specify the algorithm to be used for the operation. If not set,
* sha2-256 is used.
* Supported algorithms are:
* sha2-224, sha2-256, sha2-384, sha2-512
* @return a new {@link VaultHmacRequest} for the given {@code algorithm}.
*/
public VaultSignatureVerificationRequest ofAlgorithm(String algorithm) {
return builder().algorithm(algorithm).build();
}
/**
* @return Algorithm used for creating the digest.
*/
public String getAlgorithm() {
return algorithm;
}
/**
* @return plain text input used as basis to generate the digest.
*/
public String getInput() {
return input;
}
/**
* @return Signature resulting of a sign operation.
*/
public String getSignature() {
return signature;
}
/**
* @return Digest resulting of a Hmac operation.
*/
public String getHmac() {
return hmac;
}
public static class VaultSignatureVerificationRequestBuilder {
private String algorithm = "sha2-256";
private Plaintext input;
private Signature signature;
private String hmac;
/**
* Configure the algorithm to be used for the operation.
*
* @param algorithm Specify the algorithm to be used for the operation. If not set,
* sha2-256 is used.
* Supported algorithms are:
* sha2-224, sha2-256, sha2-384, sha2-512
* @return {@code this} {@link VaultHmacRequest.VaultHmacRequestBuilder}.
*/
public VaultSignatureVerificationRequestBuilder algorithm(String algorithm) {
this.algorithm = algorithm;
return this;
}
/**
* Configure the signature to be verified.
*
* @param signature to be verified.
* Either signature or hmac must not be empty of {@literal null}
* @return {@code this} {@link VaultHmacRequest.VaultHmacRequestBuilder}.
*/
public VaultSignatureVerificationRequestBuilder signature(Signature signature) {
this.signature = signature;
return this;
}
/**
* Configure the hmac to be verified.
*
* @param hmac to be verified.
* Either signature or hmac must not be empty of {@literal null}
* @return {@code this} {@link VaultHmacRequest.VaultHmacRequestBuilder}.
*/
public VaultSignatureVerificationRequestBuilder hmac(String hmac) {
this.hmac = hmac;
return this;
}
/**
* Configure the input to be used to create the digest.
*
* @param input base input to create the digest, must not be empty or {@literal null}.
* @return {@code this} {@link VaultHmacRequest.VaultHmacRequestBuilder}.
*/
public VaultSignatureVerificationRequestBuilder input(Plaintext input) {
this.input = input;
return this;
}
/**
* Configure the input to be used to create the digest.
*
* @param input base input to create the digest, must not be empty or {@literal null}.
* @return {@code this} {@link VaultHmacRequest.VaultHmacRequestBuilder}.
*/
public VaultSignatureVerificationRequestBuilder input(String input) {
this.input = Plaintext.of(input);
return this;
}
/**
* Build a new {@link VaultHmacRequest} instance. Requires
* {@link #input(String)} or {@link #input(Plaintext)} to be configured.
*
* @return a new {@link VaultHmacRequest}.
*/
public VaultSignatureVerificationRequest build() {
Assert.hasText(input.asString(), "Input must not be empty");
return new VaultSignatureVerificationRequest(algorithm,
input.asString(), signature.getSignature(), hmac);
}
}
}

View File

@@ -29,12 +29,17 @@ import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.vault.VaultException;
import org.springframework.vault.support.Ciphertext;
import org.springframework.vault.support.Hmac;
import org.springframework.vault.support.Plaintext;
import org.springframework.vault.support.RawTransitKey;
import org.springframework.vault.support.Signature;
import org.springframework.vault.support.TransitKeyType;
import org.springframework.vault.support.VaultDecryptionResult;
import org.springframework.vault.support.VaultEncryptionResult;
import org.springframework.vault.support.VaultHmacRequest;
import org.springframework.vault.support.VaultMount;
import org.springframework.vault.support.VaultSignRequest;
import org.springframework.vault.support.VaultSignatureVerificationRequest;
import org.springframework.vault.support.VaultTransitContext;
import org.springframework.vault.support.VaultTransitKey;
import org.springframework.vault.support.VaultTransitKeyConfiguration;
@@ -517,6 +522,170 @@ public class VaultTransitTemplateIntegrationTests extends IntegrationTestSupport
assertThat(decrypted.get(1).getCause()).isInstanceOf(VaultException.class);
}
@Test
public void generateHmacShouldCreateHmac() {
VaultTransitKeyCreationRequest keyCreationRequest = VaultTransitKeyCreationRequest.ofKeyType("ecdsa-p256");
transitOperations.createKey("ecdsa-key", keyCreationRequest);
Hmac hmac = transitOperations.generateHmac("ecdsa-key", Plaintext.of("hello-world"));
assertThat(hmac.getHmac()).startsWith("vault:v");
}
@Test
public void generateHmacWithCustomAlgorithmShouldCreateHmac() {
VaultTransitKeyCreationRequest keyCreationRequest = VaultTransitKeyCreationRequest.ofKeyType("ecdsa-p256");
transitOperations.createKey("ecdsa-key", keyCreationRequest);
VaultHmacRequest request = VaultHmacRequest.builder()
.input("hello-world")
.algorithm("sha2-512")
.build();
Hmac hmac = transitOperations.generateHmac("ecdsa-key", request);
assertThat(hmac.getHmac()).startsWith("vault:v");
}
@Test(expected = VaultException.class)
public void generateHmacWithInvalidAlgorithmShouldFail() {
VaultTransitKeyCreationRequest keyCreationRequest = VaultTransitKeyCreationRequest.ofKeyType("ecdsa-p256");
transitOperations.createKey("ecdsa-key", keyCreationRequest);
VaultHmacRequest request = VaultHmacRequest.builder()
.input("hello-world")
.algorithm("blah-512")
.build();
transitOperations.generateHmac("ecdsa-key", request);
}
@Test
public void signShouldCreateSignature() {
VaultTransitKeyCreationRequest keyCreationRequest = VaultTransitKeyCreationRequest.ofKeyType("ecdsa-p256");
transitOperations.createKey("ecdsa-key", keyCreationRequest);
Signature signature = transitOperations.sign("ecdsa-key", Plaintext.of("hello-world"));
assertThat(signature.getSignature()).startsWith("vault:v");
}
@Test(expected = VaultException.class)
public void signWithInvalidKeyFormatShouldFail() {
transitOperations.createKey("mykey");
transitOperations.sign("mykey", Plaintext.of("hello-world"));
}
@Test
public void signWithCustomAlgorithShouldCreateSignature() {
VaultTransitKeyCreationRequest keyCreationRequest = VaultTransitKeyCreationRequest.ofKeyType("ecdsa-p256");
transitOperations.createKey("ecdsa-key", keyCreationRequest);
VaultSignRequest request = VaultSignRequest.builder()
.input("hello-world")
.algorithm("sha2-512")
.build();
Signature signature = transitOperations.sign("ecdsa-key", request);
assertThat(signature.getSignature()).startsWith("vault:v");
}
@Test(expected = VaultException.class)
public void signWithInvalidAlgorithmShouldFail() {
VaultTransitKeyCreationRequest keyCreationRequest = VaultTransitKeyCreationRequest.ofKeyType("ecdsa-p256");
transitOperations.createKey("ecdsa-key", keyCreationRequest);
VaultSignRequest request = VaultSignRequest.builder()
.input("hello-world")
.algorithm("blah-512")
.build();
transitOperations.sign("ecdsa-key", request);
}
@Test
public void shouldVerifyValidSignature() {
VaultTransitKeyCreationRequest keyCreationRequest = VaultTransitKeyCreationRequest.ofKeyType("ecdsa-p256");
transitOperations.createKey("ecdsa-key", keyCreationRequest);
Signature signature = transitOperations.sign("ecdsa-key", Plaintext.of("hello-world"));
assertThat(signature.getSignature()).startsWith("vault:v");
boolean valid = transitOperations.verify("ecdsa-key",
Plaintext.of("hello-world"), signature);
assertThat(valid).isTrue();
}
@Test
public void shouldVerifyValidSignatureWithCustomAlgorithm() {
VaultTransitKeyCreationRequest keyCreationRequest = VaultTransitKeyCreationRequest.ofKeyType("ecdsa-p256");
transitOperations.createKey("ecdsa-key", keyCreationRequest);
VaultSignRequest request = VaultSignRequest.builder()
.input("hello-world")
.algorithm("sha2-512")
.build();
Signature signature = transitOperations.sign("ecdsa-key", request);
assertThat(signature.getSignature()).startsWith("vault:v");
VaultSignatureVerificationRequest verificationRequest =
VaultSignatureVerificationRequest.builder()
.algorithm("sha2-512")
.input("hello-world")
.signature(signature)
.build();
boolean valid = transitOperations.verify("ecdsa-key", verificationRequest);
assertThat(valid).isTrue();
}
@Test
public void shouldFailToVerifyValidSignatureWithInvalidExistingCustomAlgorithm() {
VaultTransitKeyCreationRequest keyCreationRequest = VaultTransitKeyCreationRequest.ofKeyType("ecdsa-p256");
transitOperations.createKey("ecdsa-key", keyCreationRequest);
Signature signature = transitOperations.sign("ecdsa-key", Plaintext.of("hello-world"));
assertThat(signature.getSignature()).startsWith("vault:v");
VaultSignatureVerificationRequest verificationRequest =
VaultSignatureVerificationRequest.builder()
.algorithm("sha2-512")
.input("hello-world")
.signature(signature)
.build();
boolean valid = transitOperations.verify("ecdsa-key", verificationRequest);
assertThat(valid).isFalse();
}
@Test(expected = VaultException.class)
public void shouldFailToVerifyValidSignatureWithInvalidCustomAlgorithm() {
VaultTransitKeyCreationRequest keyCreationRequest = VaultTransitKeyCreationRequest.ofKeyType("ecdsa-p256");
transitOperations.createKey("ecdsa-key", keyCreationRequest);
Signature signature = transitOperations.sign("ecdsa-key", Plaintext.of("hello-world"));
assertThat(signature.getSignature()).startsWith("vault:v");
VaultSignatureVerificationRequest verificationRequest =
VaultSignatureVerificationRequest.builder()
.algorithm("blah-512")
.input("hello-world")
.signature(signature)
.build();
transitOperations.verify("ecdsa-key", verificationRequest);
}
@Test
public void shouldCreateNewExportableKey() {