diff --git a/pom.xml b/pom.xml
index de68716..5fffcbc 100644
--- a/pom.xml
+++ b/pom.xml
@@ -31,12 +31,13 @@
UTF-8
1.3.1
- 6.5.3
- 2.6.8
- 5.3.19
+ 7.1.1
+ 2.7.1
+ 2021.0.3
+ 5.3.22
5.7.1
5.6.5.Final
- 1.18.22
+ 1.18.24
4.9.1
1.2.0
1.6.21
@@ -106,6 +107,13 @@
pom
import
+
+ org.springframework.cloud
+ spring-cloud-dependencies
+ ${spring.cloud.version}
+ pom
+ import
+
org.projectlombok
lombok
@@ -185,6 +193,14 @@
org.liquibase
liquibase-core
+
+ org.springframework.cloud
+ spring-cloud-starter-bootstrap
+
+
+ org.springframework.cloud
+ spring-cloud-starter-vault-config
+
org.junit.jupiter
junit-jupiter-api
diff --git a/src/main/java/eu/europa/ec/dgc/issuance/service/impl/SigningServiceImpl.java b/src/main/java/eu/europa/ec/dgc/issuance/service/impl/SigningServiceImpl.java
index ef4922d..4c440b8 100644
--- a/src/main/java/eu/europa/ec/dgc/issuance/service/impl/SigningServiceImpl.java
+++ b/src/main/java/eu/europa/ec/dgc/issuance/service/impl/SigningServiceImpl.java
@@ -15,9 +15,12 @@
import org.bouncycastle.crypto.signers.PSSSigner;
import org.bouncycastle.jcajce.provider.asymmetric.util.EC5Util;
import org.bouncycastle.jce.spec.ECParameterSpec;
-import org.springframework.stereotype.Component;
+import org.springframework.context.annotation.Profile;
+import org.springframework.stereotype.Service;
-@Component
+
+@Service
+@Profile("!vault")
public class SigningServiceImpl implements SigningService {
@Override
public byte[] signHash(byte[] hashBytes, PrivateKey privateKey) {
diff --git a/src/main/java/eu/europa/ec/dgc/issuance/service/impl/VaultSigningServiceImpl.java b/src/main/java/eu/europa/ec/dgc/issuance/service/impl/VaultSigningServiceImpl.java
new file mode 100644
index 0000000..e68e177
--- /dev/null
+++ b/src/main/java/eu/europa/ec/dgc/issuance/service/impl/VaultSigningServiceImpl.java
@@ -0,0 +1,48 @@
+package eu.europa.ec.dgc.issuance.service.impl;
+
+import eu.europa.ec.dgc.issuance.service.SigningService;
+import java.math.BigInteger;
+import java.nio.charset.StandardCharsets;
+import java.security.PrivateKey;
+import java.security.interfaces.RSAPrivateCrtKey;
+import java.util.Base64;
+import lombok.RequiredArgsConstructor;
+import org.bouncycastle.crypto.CryptoException;
+import org.bouncycastle.crypto.Digest;
+import org.bouncycastle.crypto.digests.SHA256Digest;
+import org.bouncycastle.crypto.engines.RSABlindedEngine;
+import org.bouncycastle.crypto.params.ECDomainParameters;
+import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
+import org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters;
+import org.bouncycastle.crypto.signers.ECDSASigner;
+import org.bouncycastle.crypto.signers.PSSSigner;
+import org.bouncycastle.jcajce.provider.asymmetric.util.EC5Util;
+import org.bouncycastle.jce.spec.ECParameterSpec;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Profile;
+import org.springframework.stereotype.Service;
+import org.springframework.vault.core.VaultTemplate;
+import org.springframework.vault.support.Plaintext;
+
+
+@Service
+@RequiredArgsConstructor
+@Profile("vault")
+public class VaultSigningServiceImpl implements SigningService {
+
+ private final VaultTemplate vaultTemplate;
+
+ @Value("${dgc.signKey:issuer-key}")
+ private String signKey;
+
+ @Override
+ public byte[] signHash(byte[] hash, PrivateKey privateKey) {
+ String hashBase64 = Base64.getEncoder().encodeToString(hash);
+
+ String signature = vaultTemplate.opsForTransit().sign(signKey, Plaintext.of(hashBase64)).getSignature();
+ if (signature.startsWith("vault:v1:")) {
+ signature = signature.substring(9);
+ }
+ return Base64.getDecoder().decode(signature);
+ }
+}
diff --git a/src/main/resources/bootstrap-cloud.yaml b/src/main/resources/bootstrap-cloud.yaml
new file mode 100644
index 0000000..de153fc
--- /dev/null
+++ b/src/main/resources/bootstrap-cloud.yaml
@@ -0,0 +1,23 @@
+---
+spring:
+ application:
+ name: cwa-dcc-rules
+ cloud:
+ vault:
+ ssl:
+ trust-store: file:${SSL_VAULT_TRUSTSTORE_PATH}
+ trust-store-password: ${SSL_VAULT_TRUSTSTORE_PASSWORD}
+ enabled: true
+ generic:
+ enabled: false
+ fail-fast: true
+ authentication: KUBERNETES
+ kubernetes:
+ role: ${VAULT_ROLE}
+ kubernetes-path: kubernetes
+ service-account-token-file: /var/run/secrets/kubernetes.io/serviceaccount/token
+ uri: ${VAULT_URI}
+ connection-timeout: 5000
+ read-timeout: 15000
+ config:
+ order: -10
diff --git a/src/main/resources/bootstrap-vaultlocal.yaml b/src/main/resources/bootstrap-vaultlocal.yaml
new file mode 100644
index 0000000..300bd62
--- /dev/null
+++ b/src/main/resources/bootstrap-vaultlocal.yaml
@@ -0,0 +1,14 @@
+spring:
+ cloud:
+ vault:
+ enabled: true
+ # use for local vault transit test (change the access token)
+ token: hvs.s4nIVAiASHG6FNETWBFevasa
+ scheme: http
+ fail-fast: true
+ # use for local vault transit test (change the uri)
+ uri: http://127.0.0.1:8200
+ connection-timeout: 5000
+ read-timeout: 15000
+ config:
+ order: -10
diff --git a/src/main/resources/bootstrap.yaml b/src/main/resources/bootstrap.yaml
new file mode 100644
index 0000000..4eed0ce
--- /dev/null
+++ b/src/main/resources/bootstrap.yaml
@@ -0,0 +1,5 @@
+---
+spring:
+ cloud:
+ vault:
+ enabled: false
diff --git a/src/test/java/eu/europa/ec/dgc/issuance/service/impl/VaultSigningServiceImplTest.java b/src/test/java/eu/europa/ec/dgc/issuance/service/impl/VaultSigningServiceImplTest.java
new file mode 100644
index 0000000..8b0e8be
--- /dev/null
+++ b/src/test/java/eu/europa/ec/dgc/issuance/service/impl/VaultSigningServiceImplTest.java
@@ -0,0 +1,56 @@
+package eu.europa.ec.dgc.issuance.service.impl;
+
+import java.util.Base64;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.mock.mockito.MockBean;
+import org.springframework.context.annotation.Profile;
+import org.springframework.test.context.ActiveProfiles;
+import org.springframework.vault.core.VaultTemplate;
+import org.springframework.vault.core.VaultTransitOperations;
+import org.springframework.vault.support.Plaintext;
+import org.springframework.vault.support.Signature;
+
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+@SpringBootTest
+@ActiveProfiles("vault")
+class VaultSigningServiceImplTest {
+
+ @Autowired
+ private VaultSigningServiceImpl vaultSigningService;
+ @MockBean
+ private VaultTemplate vaultTemplate;
+
+ @Test
+ void signHash() {
+ byte[] hash = Base64.getDecoder().decode("dGVzdA==");
+
+ VaultTransitOperations vaultTransitOperation = mock(VaultTransitOperations.class);
+ when(vaultTemplate.opsForTransit()).thenReturn(vaultTransitOperation);
+ when(vaultTransitOperation.sign("issuer-key", Plaintext.of("dGVzdA==")))
+ .thenReturn(Signature.of("vault:v1:dGVzdA=="));
+
+ byte[] result = vaultSigningService.signHash(hash, null);
+ assertNotNull(result);
+ }
+
+ @Test
+ void signHash_noVaultPrefix() {
+ byte[] hash = Base64.getDecoder().decode("dGVzdA==");
+
+ VaultTransitOperations vaultTransitOperation = mock(VaultTransitOperations.class);
+ when(vaultTemplate.opsForTransit()).thenReturn(vaultTransitOperation);
+ when(vaultTransitOperation.sign("issuer-key", Plaintext.of("dGVzdA==")))
+ .thenReturn(Signature.of("dGVzdA=="));
+
+ byte[] result = vaultSigningService.signHash(hash, null);
+ assertNotNull(result);
+ }
+
+}