Skip to content

Commit 9c1bac8

Browse files
committed
Corrected according to dgc-java
1 parent 8695b47 commit 9c1bac8

File tree

6 files changed

+142
-17
lines changed

6 files changed

+142
-17
lines changed

pom.xml

+21-1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,12 @@
2626
<maven.compiler.source>1.8</maven.compiler.source>
2727
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
2828
</properties>
29+
<repositories>
30+
<repository>
31+
<id>staging</id>
32+
<url>https://s01.oss.sonatype.org/content/groups/staging</url>
33+
</repository>
34+
</repositories>
2935
<distributionManagement>
3036
<repository>
3137
<id>github</id>
@@ -75,6 +81,14 @@
7581
<version>2.12.2</version>
7682
</dependency>
7783

84+
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.datatype/jackson-datatype-jsr310 -->
85+
<dependency>
86+
<groupId>com.fasterxml.jackson.datatype</groupId>
87+
<artifactId>jackson-datatype-jsr310</artifactId>
88+
<version>2.12.2</version>
89+
</dependency>
90+
91+
7892
<dependency>
7993
<groupId>org.junit.jupiter</groupId>
8094
<artifactId>junit-jupiter-engine</artifactId>
@@ -90,6 +104,12 @@
90104
<scope>test</scope>
91105
</dependency>
92106

107+
<dependency>
108+
<groupId>se.digg.dgc</groupId>
109+
<artifactId>dgc-create-validate</artifactId>
110+
<version>0.9.0</version>
111+
<scope>test</scope>
112+
</dependency>
93113

94114
<dependency>
95115
<groupId>com.fasterxml.jackson.core</groupId>
@@ -115,7 +135,7 @@
115135
<sourceType>yamlschema</sourceType>
116136
<formatDates>true</formatDates>
117137
<generateBuilders>true</generateBuilders>
118-
<inclusionLevel>NON_EMPTY</inclusionLevel>
138+
<!--<inclusionLevel>NON_EMPTY</inclusionLevel>-->
119139
<includeJsr303Annotations>true</includeJsr303Annotations>
120140
<includeConstructors>true</includeConstructors>
121141
<useTitleAsClassname>true</useTitleAsClassname>

src/main/java/ehn/techiop/hcert/CertificateProvider.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,5 @@
55
import java.security.PublicKey;
66

77
public interface CertificateProvider {
8-
PublicKey provideKey(String kid, String issuer) throws CoseException;
8+
PublicKey provideKey(byte[] kid, String issuer) throws CoseException;
99
}

src/main/java/ehn/techiop/hcert/GreenCertificateDecoder.java

+5-1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
import COSE.*;
66
import com.fasterxml.jackson.databind.ObjectMapper;
7+
import com.fasterxml.jackson.databind.SerializationFeature;
8+
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
79
import com.upokecenter.cbor.CBORObject;
810

911
import java.io.ByteArrayInputStream;
@@ -55,7 +57,7 @@ public String decode(String base45String) throws CompressorException, IOExceptio
5557
private String toJsonPayload(byte[] coseBytes) throws CoseException, IOException {
5658
Sign1Message msg = (Sign1Message) Message.DecodeFromBytes(coseBytes, MessageTag.Sign1);
5759

58-
String kid = msg.getProtectedAttributes().get(HeaderKeys.KID.AsCBOR()).AsString();
60+
byte[] kid = msg.getProtectedAttributes().get(HeaderKeys.KID.AsCBOR()).GetByteString();
5961

6062
CBORObject cborObject = CBORObject.DecodeFromBytes(msg.GetContent());
6163
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
@@ -64,6 +66,8 @@ private String toJsonPayload(byte[] coseBytes) throws CoseException, IOException
6466
String json = byteArrayOutputStream.toString("UTF-8");
6567

6668
ObjectMapper objectMapper = new ObjectMapper();
69+
objectMapper.registerModule(new JavaTimeModule());
70+
objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
6771
CertificatePayload certificatePayload = objectMapper.readValue(json, CertificatePayload.class);
6872
String issuer = certificatePayload.getIss();
6973

src/main/java/ehn/techiop/hcert/GreenCertificateEncoder.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,14 @@
1919
public class GreenCertificateEncoder {
2020

2121
private final OneKey privateKey;
22-
private final String kid;
22+
private final byte[] kid;
2323
private final String prefix;
2424

25-
public GreenCertificateEncoder(OneKey privateKey, String kid) {
25+
public GreenCertificateEncoder(OneKey privateKey, byte[] kid) {
2626
this(privateKey, kid, "HC1");
2727
}
2828

29-
public GreenCertificateEncoder(OneKey privateKey, String kid, String prefix) {
29+
public GreenCertificateEncoder(OneKey privateKey, byte[] kid, String prefix) {
3030
this.privateKey = privateKey;
3131
this.kid = kid;
3232
this.prefix = prefix;

src/test/java/ehn/techiop/hcert/CertificateTest.java

+66-11
Original file line numberDiff line numberDiff line change
@@ -4,22 +4,30 @@
44
import COSE.CoseException;
55
import COSE.OneKey;
66
import com.fasterxml.jackson.databind.ObjectMapper;
7+
import com.fasterxml.jackson.databind.SerializationFeature;
8+
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
79
import ehn.techiop.hcert.model.CertificatePayload;
810
import ehn.techiop.hcert.model.HealthCertificate;
911
import org.apache.commons.compress.compressors.CompressorException;
1012
import org.bouncycastle.jce.provider.BouncyCastleProvider;
13+
import org.bouncycastle.x509.X509V1CertificateGenerator;
1114
import org.junit.jupiter.api.BeforeAll;
1215
import org.junit.jupiter.api.Test;
16+
import se.digg.dgc.payload.v1.DGCSchemaException;
17+
import se.digg.dgc.service.impl.DefaultDGCEncoder;
18+
import se.digg.dgc.signatures.impl.DefaultDGCSigner;
1319

20+
import javax.security.auth.x500.X500Principal;
1421
import java.io.IOException;
15-
import java.security.NoSuchAlgorithmException;
16-
import java.security.Security;
22+
import java.math.BigInteger;
23+
import java.nio.charset.StandardCharsets;
24+
import java.security.*;
25+
import java.security.cert.Certificate;
26+
import java.security.cert.CertificateException;
27+
import java.security.cert.X509Certificate;
1728
import java.time.LocalDateTime;
1829
import java.time.ZoneOffset;
19-
import java.util.ArrayList;
20-
import java.util.Date;
21-
import java.util.List;
22-
import java.util.UUID;
30+
import java.util.*;
2331

2432
import static org.junit.jupiter.api.Assertions.assertEquals;
2533
import static org.junit.jupiter.api.Assertions.assertThrows;
@@ -79,7 +87,7 @@ static void beforeAll() throws Exception {
7987
@Test
8088
void roundtrip() throws CompressorException, CoseException, IOException {
8189

82-
String encoded = new GreenCertificateEncoder(cborPrivateKey, UUID.randomUUID().toString()).encode(json);
90+
String encoded = new GreenCertificateEncoder(cborPrivateKey, UUID.randomUUID().toString().getBytes(StandardCharsets.UTF_8)).encode(json);
8391
String result = new GreenCertificateDecoder((kid, issuer) -> cborPublicKey.AsPublicKey()).decode(encoded);
8492

8593
ObjectMapper mapper = new ObjectMapper();
@@ -92,7 +100,7 @@ void wrongPublicKey() throws CompressorException, CoseException, IOException {
92100

93101
OneKey anotherPublicKey = OneKey.generateKey(AlgorithmID.ECDSA_256).PublicKey();
94102

95-
String encoded = new GreenCertificateEncoder(cborPrivateKey, UUID.randomUUID().toString()).encode(json);
103+
String encoded = new GreenCertificateEncoder(cborPrivateKey, UUID.randomUUID().toString().getBytes(StandardCharsets.UTF_8)).encode(json);
96104

97105
Exception exception = assertThrows(RuntimeException.class,
98106
() -> new GreenCertificateDecoder((kid, issuer) -> anotherPublicKey.AsPublicKey()).decode(encoded));
@@ -107,7 +115,7 @@ void rsaKeys() throws CompressorException, CoseException, IOException, NoSuchAlg
107115

108116
OneKey keys = OneKey.generateKey(AlgorithmID.RSA_PSS_256);
109117

110-
String encoded = new GreenCertificateEncoder(keys, UUID.randomUUID().toString()).encode(json);
118+
String encoded = new GreenCertificateEncoder(keys, UUID.randomUUID().toString().getBytes(StandardCharsets.UTF_8)).encode(json);
111119
String result = new GreenCertificateDecoder((kid, issuer) -> keys.AsPublicKey()).decode(encoded);
112120
ObjectMapper mapper = new ObjectMapper();
113121
assertEquals(mapper.readTree(json), mapper.readTree(result));
@@ -170,7 +178,7 @@ void rsaKeys() throws CompressorException, CoseException, IOException, NoSuchAlg
170178
.build();
171179

172180
CertificatePayload test_0405870109 = new CertificateDSL()
173-
.withSubject("Judy", "Jensen")
181+
.withSubject("Øjvind", "Ørn")
174182
.withExpiredVaccine()
175183
.withExpiredTestResult()
176184
.withRecovery()
@@ -181,11 +189,58 @@ void testSetDKExample() throws IOException, CompressorException, CoseException {
181189

182190
String input = new ObjectMapper().writeValueAsString(test_0405870101);
183191

184-
String encoded = new GreenCertificateEncoder(cborPrivateKey, UUID.randomUUID().toString()).encode(input);
192+
String encoded = new GreenCertificateEncoder(cborPrivateKey, UUID.randomUUID().toString().getBytes(StandardCharsets.UTF_8)).encode(input);
185193
String result = new GreenCertificateDecoder((kid, issuer) -> cborPublicKey.AsPublicKey()).decode(encoded);
186194

187195
ObjectMapper mapper = new ObjectMapper();
188196
assertEquals(mapper.readTree(input), mapper.readTree(result));
189197
}
190198

199+
@Test
200+
void testAgainstDGCJava() throws CertificateException, IOException, NoSuchAlgorithmException, DGCSchemaException, SignatureException, CompressorException, CoseException, NoSuchProviderException, InvalidKeyException {
201+
202+
Security.insertProviderAt(new BouncyCastleProvider(), 1);
203+
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA", "BC");
204+
keyPairGenerator.initialize(2048, new SecureRandom());
205+
206+
KeyPair keyPair = keyPairGenerator.generateKeyPair();
207+
Certificate certificate = generateCertificate(keyPair);
208+
209+
210+
se.digg.dgc.payload.v1.DigitalGreenCertificate testData = DefaultDGCExample.getTestDGC();
211+
DefaultDGCEncoder encoder = new DefaultDGCEncoder(new DefaultDGCSigner(keyPair.getPrivate(), (X509Certificate) certificate));
212+
String bytes = encoder.encode(testData, LocalDateTime.now().toInstant(ZoneOffset.UTC));
213+
String result = new GreenCertificateDecoder((kid, issuer) -> certificate.getPublicKey()).decode(bytes);
214+
215+
216+
ObjectMapper mapper = new ObjectMapper();
217+
mapper.registerModule(new JavaTimeModule());
218+
219+
mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
220+
221+
222+
DigitalGreenCertificate dgcResult = mapper.readValue(result, CertificatePayload.class).getHcert().getDigitalGreenCertificate();
223+
assertEquals( mapper.valueToTree(testData), mapper.valueToTree(dgcResult));
224+
}
225+
226+
227+
228+
public static Certificate generateCertificate(KeyPair keyPair) throws CertificateException, NoSuchAlgorithmException, SignatureException, NoSuchProviderException, InvalidKeyException {
229+
// yesterday
230+
Date validityBeginDate = new Date(System.currentTimeMillis() - 24 * 60 * 60 * 1000);
231+
// in 2 years
232+
Date validityEndDate = new Date(System.currentTimeMillis() + 2 * 365 * 24 * 60 * 60 * 1000);
233+
234+
X509V1CertificateGenerator certGen = new X509V1CertificateGenerator();
235+
X500Principal dnName = new X500Principal("CN=John Doe, C=DK");
236+
certGen.setSerialNumber(BigInteger.valueOf(System.currentTimeMillis()));
237+
certGen.setSubjectDN(dnName);
238+
certGen.setIssuerDN(dnName); // use the same
239+
certGen.setNotBefore(validityBeginDate);
240+
certGen.setNotAfter(validityEndDate);
241+
certGen.setPublicKey(keyPair.getPublic());
242+
certGen.setSignatureAlgorithm("SHA256WithRSAEncryption");
243+
return certGen.generate(keyPair.getPrivate(), "BC");
244+
245+
}
191246
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package ehn.techiop.hcert;
2+
3+
import se.digg.dgc.payload.v1.DigitalGreenCertificate;
4+
import se.digg.dgc.payload.v1.Id;
5+
import se.digg.dgc.payload.v1.Sub;
6+
import se.digg.dgc.payload.v1.Vac;
7+
8+
import java.time.LocalDate;
9+
import java.util.Arrays;
10+
11+
public class DefaultDGCExample {
12+
13+
public static se.digg.dgc.payload.v1.DigitalGreenCertificate getTestDGC() {
14+
se.digg.dgc.payload.v1.DigitalGreenCertificate dgc = new DigitalGreenCertificate();
15+
16+
se.digg.dgc.payload.v1.Sub sub = new Sub();
17+
sub
18+
.withGn("Martin")
19+
.withFn("Lindström")
20+
.withDob(LocalDate.parse("1969-11-29"))
21+
.withGen("male");
22+
23+
se.digg.dgc.payload.v1.Id pnr = new se.digg.dgc.payload.v1.Id();
24+
pnr.withI("NN").withT("196911292932");
25+
se.digg.dgc.payload.v1.Id passport = new Id();
26+
passport.withI("PPN").withT("56987413");
27+
sub.withId(Arrays.asList(pnr, passport));
28+
29+
dgc.setSub(sub);
30+
31+
se.digg.dgc.payload.v1.Vac vac = new Vac();
32+
vac
33+
.withDis("Covid-19")
34+
.withVap("vap-value")
35+
.withMep("mep-value")
36+
.withAut("aut-value")
37+
.withSeq(Integer.valueOf(1))
38+
.withTot(Integer.valueOf(2))
39+
.withDat(LocalDate.parse("2021-04-02"))
40+
.withCou("SE");
41+
42+
dgc.setVac(Arrays.asList(vac));
43+
44+
return dgc;
45+
}
46+
}

0 commit comments

Comments
 (0)