Skip to content

Commit 529b465

Browse files
feat: refactor with new certificate (#12)
* feat: refactor with new certificate Signed-off-by: Christoffer Killander <extern.christoffer.killander@digg.se> * feat: add x509 to response header Signed-off-by: Christoffer Killander <extern.christoffer.killander@digg.se>
1 parent fb11ff2 commit 529b465

File tree

8 files changed

+66
-32
lines changed

8 files changed

+66
-32
lines changed

src/main/java/se/digg/wallet/provider/application/config/WuaKeystoreProperties.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,12 @@
77
import java.security.KeyStore;
88
import java.security.PrivateKey;
99
import java.security.cert.Certificate;
10+
import java.security.cert.X509Certificate;
1011
import java.security.interfaces.ECPrivateKey;
1112
import java.security.interfaces.ECPublicKey;
13+
import java.util.Arrays;
14+
import java.util.List;
15+
import java.util.stream.Collectors;
1216
import org.springframework.boot.context.properties.ConfigurationProperties;
1317
import org.springframework.core.io.Resource;
1418

@@ -45,4 +49,16 @@ public ECPublicKey getPublicKey() {
4549
throw new RuntimeException("Failed to load public key from filesystem", e);
4650
}
4751
}
52+
53+
public List<X509Certificate> getCertificateChain() {
54+
try {
55+
KeyStore keyStore = KeyStore.getInstance(type());
56+
keyStore.load(location().getInputStream(), password().toCharArray());
57+
return Arrays.stream(keyStore.getCertificateChain(alias()))
58+
.map(c -> (X509Certificate) c)
59+
.collect(Collectors.toList());
60+
} catch (Exception e) {
61+
throw new RuntimeException("Failed to load certificate chain from filesystem", e);
62+
}
63+
}
4864
}

src/main/java/se/digg/wallet/provider/application/service/WalletUnitAttestationService.java

Lines changed: 30 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,17 @@
77
import com.fasterxml.jackson.core.JsonProcessingException;
88
import com.fasterxml.jackson.core.type.TypeReference;
99
import com.fasterxml.jackson.databind.ObjectMapper;
10-
import com.nimbusds.jose.JOSEException;
1110
import com.nimbusds.jose.JOSEObjectType;
1211
import com.nimbusds.jose.JWSAlgorithm;
1312
import com.nimbusds.jose.JWSHeader;
1413
import com.nimbusds.jose.JWSSigner;
1514
import com.nimbusds.jose.crypto.ECDSASigner;
1615
import com.nimbusds.jose.jwk.ECKey;
16+
import com.nimbusds.jose.util.Base64;
1717
import com.nimbusds.jwt.JWTClaimsSet;
1818
import com.nimbusds.jwt.SignedJWT;
19+
import java.security.cert.CertificateEncodingException;
20+
import java.security.cert.X509Certificate;
1921
import java.security.interfaces.ECPrivateKey;
2022
import java.time.Duration;
2123
import java.time.Instant;
@@ -33,8 +35,7 @@ public class WalletUnitAttestationService {
3335
private final ObjectMapper objectMapper;
3436

3537
public WalletUnitAttestationService(
36-
WuaKeystoreProperties keystoreProperties,
37-
ObjectMapper objectMapper) {
38+
WuaKeystoreProperties keystoreProperties, ObjectMapper objectMapper) {
3839
this.keystoreProperties = keystoreProperties;
3940
this.objectMapper = objectMapper;
4041
}
@@ -48,30 +49,12 @@ public SignedJWT createWalletUnitAttestation(String walletPublicKeyJwk) throws E
4849
claims.put("status", getStatus());
4950
claims.put("attested_keys", attestedKeys);
5051

51-
return createSignedJwt(
52-
keystoreProperties.getSigningKey(),
53-
keystoreProperties.alias(),
54-
keystoreProperties.issuer(),
55-
Duration.ofHours(keystoreProperties.validityHours()),
56-
claims);
57-
}
58-
59-
private Map<String, Object> getStatus() throws JsonProcessingException {
60-
return objectMapper.readValue(keystoreProperties.status(), new TypeReference<>() {});
61-
}
62-
63-
private Map<String, Object> getEudiWalletInfo() throws JsonProcessingException {
64-
return objectMapper.readValue(
65-
keystoreProperties.eudiWalletInfo(), new TypeReference<>() {});
66-
}
52+
ECPrivateKey signingKey = keystoreProperties.getSigningKey();
53+
String keyId = keystoreProperties.alias();
54+
List<X509Certificate> certificateChain = keystoreProperties.getCertificateChain();
55+
String issuer = keystoreProperties.issuer();
56+
Duration validity = Duration.ofHours(keystoreProperties.validityHours());
6757

68-
private SignedJWT createSignedJwt(
69-
ECPrivateKey signingKey,
70-
String keyId,
71-
String issuer,
72-
Duration validity,
73-
Map<String, Object> claims)
74-
throws JOSEException {
7558
Instant now = Instant.now();
7659

7760
JWTClaimsSet.Builder claimsBuilder =
@@ -86,10 +69,23 @@ private SignedJWT createSignedJwt(
8669

8770
JWTClaimsSet claimsSet = claimsBuilder.build();
8871

72+
List<Base64> x5c =
73+
certificateChain.stream()
74+
.map(
75+
c -> {
76+
try {
77+
return Base64.encode(c.getEncoded());
78+
} catch (CertificateEncodingException e) {
79+
throw new RuntimeException(e);
80+
}
81+
})
82+
.toList();
83+
8984
JWSHeader header =
9085
new JWSHeader.Builder(JWSAlgorithm.ES256)
9186
.keyID(keyId)
9287
.type(new JOSEObjectType("keyattestation+jwt"))
88+
.x509CertChain(x5c)
9389
.build();
9490

9591
SignedJWT signedJwt = new SignedJWT(header, claimsSet);
@@ -99,4 +95,12 @@ private SignedJWT createSignedJwt(
9995

10096
return signedJwt;
10197
}
98+
99+
private Map<String, Object> getStatus() throws JsonProcessingException {
100+
return objectMapper.readValue(keystoreProperties.status(), new TypeReference<>() {});
101+
}
102+
103+
private Map<String, Object> getEudiWalletInfo() throws JsonProcessingException {
104+
return objectMapper.readValue(keystoreProperties.eudiWalletInfo(), new TypeReference<>() {});
105+
}
102106
}

src/main/resources/application-dev.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
wua:
55
keystore:
6-
location: file:src/test/resources/dev/wua-signing.p12
7-
password: Test1234
8-
alias: wua-signing
6+
location: file:src/test/resources/certificates/wallet-provider.p12
7+
password: secret
8+
alias: wallet-provider
99
type: PKCS12

src/test/java/se/digg/wallet/provider/application/service/WalletUnitAttestationServiceTest.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
package se.digg.wallet.provider.application.service;
66

77
import static org.junit.jupiter.api.Assertions.assertEquals;
8+
import static org.junit.jupiter.api.Assertions.assertFalse;
89
import static org.junit.jupiter.api.Assertions.assertNotNull;
910
import static org.junit.jupiter.api.Assertions.assertTrue;
1011

@@ -85,6 +86,19 @@ void assertThatCreateWalletUnitAttestation_givenValidJwk_shouldSucceed() throws
8586
verifyJwtSignature(jwt, keystoreProperties.getPublicKey());
8687
}
8788

89+
@Test
90+
void assertThatCreateWalletUnitAttestation_hasX5cHeader() throws Exception {
91+
KeyPairGenerator gen = KeyPairGenerator.getInstance("EC");
92+
gen.initialize(Curve.P_256.toECParameterSpec());
93+
KeyPair keyPair = gen.generateKeyPair();
94+
ECKey jwk = new ECKey.Builder(Curve.P_256, (ECPublicKey) keyPair.getPublic()).build();
95+
96+
SignedJWT jwt = service.createWalletUnitAttestation(jwk.toString());
97+
98+
assertNotNull(jwt.getHeader().getX509CertChain());
99+
assertFalse(jwt.getHeader().getX509CertChain().isEmpty());
100+
}
101+
88102
private void verifyJwtSignature(SignedJWT jwt, ECPublicKey publicKey) throws JOSEException {
89103
assertTrue(jwt.verify(new ECDSAVerifier(publicKey)));
90104
}

src/test/resources/application.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@ spring:
88

99
wua:
1010
keystore:
11-
location: classpath:dev/wua-signing.p12
12-
password: Test1234
13-
alias: wua-signing
11+
location: classpath:certificates/wallet-provider.p12
12+
password: secret
13+
alias: wallet-provider
1414
type: PKCS12
1515
issuer: "Digg"
1616
validity-hours: 24
1.89 KB
Binary file not shown.
File renamed without changes.
-1.09 KB
Binary file not shown.

0 commit comments

Comments
 (0)