Skip to content

Commit 5b700ad

Browse files
committed
Modified to fit newest version of schemata
Modified verification signature algorithm
1 parent a8fe2c8 commit 5b700ad

File tree

10 files changed

+290
-283
lines changed

10 files changed

+290
-283
lines changed

pom.xml

+22-42
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,13 @@
4242
<version>1.1.0</version>
4343
</dependency>
4444

45+
<dependency>
46+
<groupId>com.upokecenter</groupId>
47+
<artifactId>cbor</artifactId>
48+
<version>4.3.0</version>
49+
</dependency>
50+
51+
4552
<dependency>
4653
<groupId>org.apache.commons</groupId>
4754
<artifactId>commons-compress</artifactId>
@@ -54,11 +61,18 @@
5461
<version>0.0.3</version>
5562
</dependency>
5663

64+
<!-- https://mvnrepository.com/artifact/javax.validation/validation-api -->
65+
<dependency>
66+
<groupId>javax.validation</groupId>
67+
<artifactId>validation-api</artifactId>
68+
<version>2.0.1.Final</version>
69+
</dependency>
70+
71+
5772
<dependency>
5873
<groupId>com.fasterxml.jackson.core</groupId>
5974
<artifactId>jackson-databind</artifactId>
6075
<version>2.12.2</version>
61-
<scope>test</scope>
6276
</dependency>
6377

6478
<dependency>
@@ -88,59 +102,25 @@
88102

89103
<plugins>
90104

91-
<plugin>
92-
<artifactId>maven-antrun-plugin</artifactId>
93-
<version>1.8</version>
94-
<executions>
95-
<execution>
96-
<phase>initialize</phase>
97-
<configuration>
98-
<target>
99-
<mkdir dir="${basedir}/src/main/resources/schema" />
100-
</target>
101-
</configuration>
102-
<goals>
103-
<goal>run</goal>
104-
</goals>
105-
</execution>
106-
</executions>
107-
</plugin>
108105

109-
<plugin>
110-
<groupId>com.googlecode.maven-download-plugin</groupId>
111-
<artifactId>download-maven-plugin</artifactId>
112-
<version>1.6.1</version>
113-
<executions>
114-
<execution>
115-
<id>get-schema-yml</id>
116-
<phase>generate-sources</phase>
117-
<goals>
118-
<goal>wget</goal>
119-
</goals>
120-
121-
</execution>
122-
</executions>
123-
<configuration>
124-
<url>
125-
https://raw.githubusercontent.com/ehn-digital-green-development/hcert-schema/main/eu_hcert_v1_schema.yaml
126-
</url>
127-
<outputDirectory>${basedir}/src/main/resources/schema</outputDirectory>
128-
</configuration>
129-
</plugin>
130106

131107
<plugin>
132108
<groupId>org.jsonschema2pojo</groupId>
133109
<artifactId>jsonschema2pojo-maven-plugin</artifactId>
134110
<version>1.1.0</version>
135111
<configuration>
136-
<sourceDirectory>${basedir}/src/main/resources</sourceDirectory>
137-
<targetPackage>ehn.techiop.hcert</targetPackage>
112+
<sourceDirectory>${basedir}/src/main/resources/schema</sourceDirectory>
113+
<includeAdditionalProperties>false</includeAdditionalProperties>
114+
<targetPackage>ehn.techiop.healthCertificate</targetPackage>
138115
<sourceType>yamlschema</sourceType>
139116
<formatDates>true</formatDates>
140117
<generateBuilders>true</generateBuilders>
141118
<inclusionLevel>NON_EMPTY</inclusionLevel>
142-
119+
<includeJsr303Annotations>true</includeJsr303Annotations>
120+
<includeConstructors>true</includeConstructors>
121+
<useTitleAsClassname>true</useTitleAsClassname>
143122
</configuration>
123+
144124
<executions>
145125
<execution>
146126
<phase>generate-sources</phase>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package ehn.techiop.hcert;
2+
3+
import COSE.CoseException;
4+
5+
import java.security.PublicKey;
6+
7+
public interface CertificateProvider {
8+
PublicKey provideKey(String kid, String issuer) throws CoseException;
9+
}

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

+55-46
Original file line numberDiff line numberDiff line change
@@ -2,76 +2,85 @@
22

33
import static org.apache.commons.compress.utils.IOUtils.toByteArray;
44

5-
import COSE.CoseException;
6-
import COSE.Message;
7-
import COSE.MessageTag;
8-
import COSE.OneKey;
9-
import COSE.Sign1Message;
5+
import COSE.*;
6+
import com.fasterxml.jackson.databind.ObjectMapper;
107
import com.upokecenter.cbor.CBORObject;
8+
119
import java.io.ByteArrayInputStream;
1210
import java.io.ByteArrayOutputStream;
1311
import java.io.IOException;
12+
13+
import ehn.techiop.hcert.model.CertificatePayload;
1414
import nl.minvws.encoding.Base45;
1515
import org.apache.commons.compress.compressors.CompressorException;
1616
import org.apache.commons.compress.compressors.CompressorInputStream;
1717
import org.apache.commons.compress.compressors.CompressorStreamFactory;
1818

1919
public class GreenCertificateDecoder {
2020

21-
private final OneKey publicKey;
21+
private final CertificateProvider certificateProvider;
22+
private final String prefix;
2223

23-
public GreenCertificateDecoder(OneKey publicKey) {
24-
this.publicKey = publicKey;
25-
}
24+
public GreenCertificateDecoder(CertificateProvider certificateProvider) {
25+
this(certificateProvider, "HC1");
26+
}
2627

28+
public GreenCertificateDecoder(CertificateProvider certificateProvider, String prefix) {
29+
this.certificateProvider = certificateProvider;
30+
this.prefix = prefix;
31+
}
2732

2833

29-
/**
30-
* Decodes base45 encoded string -> Deflate -> COSE -> CBOR -> arbitrary Json String
31-
*
32-
* @param base45String
33-
* @return
34-
* @throws CompressorException
35-
* @throws IOException
36-
* @throws CoseException
37-
*/
38-
public String decode(String base45String) throws CompressorException, IOException, CoseException {
39-
if(!base45String.startsWith("HC1"))
40-
throw new RuntimeException("Base45 string not valid according to specification");
34+
/**
35+
* Decodes base45 encoded string -> Deflate -> COSE -> CBOR -> arbitrary Json String
36+
*
37+
* @param base45String
38+
* @return
39+
* @throws CompressorException
40+
* @throws IOException
41+
* @throws CoseException
42+
*/
43+
public String decode(String base45String) throws CompressorException, IOException, CoseException {
44+
if (!base45String.startsWith(prefix))
45+
throw new RuntimeException("Base45 string not valid according to specification");
4146

42-
base45String = base45String.substring(3);
43-
byte[] decodedBytes = Base45.getDecoder().decode(base45String);
47+
base45String = base45String.substring(3);
48+
byte[] decodedBytes = Base45.getDecoder().decode(base45String);
4449

45-
byte[] coseBytes = getCoseBytes(decodedBytes);
50+
byte[] coseBytes = decompress(decodedBytes);
4651

47-
byte[] cborBytes = getCborBytes(coseBytes);
52+
return toJsonPayload(coseBytes);
53+
}
4854

49-
return getJsonString(cborBytes);
50-
}
55+
private String toJsonPayload(byte[] coseBytes) throws CoseException, IOException {
56+
Sign1Message msg = (Sign1Message) Message.DecodeFromBytes(coseBytes, MessageTag.Sign1);
5157

52-
private String getJsonString(byte[] cborBytes) throws IOException {
53-
CBORObject cborObject = CBORObject.DecodeFromBytes(cborBytes);
54-
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
55-
cborObject.WriteJSONTo(byteArrayOutputStream);
58+
String kid = msg.getProtectedAttributes().get(HeaderKeys.KID.AsCBOR()).AsString();
5659

57-
return byteArrayOutputStream.toString("UTF-8");
58-
}
60+
CBORObject cborObject = CBORObject.DecodeFromBytes(msg.GetContent());
61+
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
62+
cborObject.WriteJSONTo(byteArrayOutputStream);
5963

60-
private byte[] getCborBytes(byte[] coseBytes) throws CoseException {
61-
Sign1Message msg = (Sign1Message) Message.DecodeFromBytes(coseBytes, MessageTag.Sign1);
62-
if (!msg.validate(publicKey)) {
63-
throw new RuntimeException("Could not verify COSE signature");
64-
}
64+
String json = byteArrayOutputStream.toString("UTF-8");
6565

66-
return msg.GetContent();
67-
}
66+
ObjectMapper objectMapper = new ObjectMapper();
67+
CertificatePayload certificatePayload = objectMapper.readValue(json, CertificatePayload.class);
68+
String issuer = certificatePayload.getIss();
6869

69-
private byte[] getCoseBytes(byte[] decodedBytes) throws CompressorException, IOException {
7070

71-
CompressorInputStream compressedStream = new CompressorStreamFactory()
72-
.createCompressorInputStream(CompressorStreamFactory.DEFLATE,
73-
new ByteArrayInputStream(decodedBytes));
71+
if (!msg.validate(new OneKey(certificateProvider.provideKey(kid, issuer), null))) {
72+
throw new RuntimeException("Could not verify COSE signature");
73+
}
7474

75-
return toByteArray(compressedStream);
76-
}
75+
return json;
76+
}
77+
78+
private byte[] decompress(byte[] decodedBytes) throws CompressorException, IOException {
79+
80+
CompressorInputStream compressedStream = new CompressorStreamFactory()
81+
.createCompressorInputStream(CompressorStreamFactory.DEFLATE,
82+
new ByteArrayInputStream(decodedBytes));
83+
84+
return toByteArray(compressedStream);
85+
}
7786
}

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

+13-11
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,35 @@
11
package ehn.techiop.hcert;
22

33
import COSE.Attribute;
4-
import COSE.AlgorithmID;
54
import COSE.CoseException;
65
import COSE.HeaderKeys;
76
import COSE.KeyKeys;
87
import COSE.OneKey;
98
import COSE.Sign1Message;
109
import com.upokecenter.cbor.CBORObject;
11-
import java.security.PrivateKey;
12-
import java.security.interfaces.RSAPrivateCrtKey;
1310
import org.apache.commons.compress.compressors.CompressorException;
1411
import org.apache.commons.compress.compressors.CompressorOutputStream;
1512
import org.apache.commons.compress.compressors.CompressorStreamFactory;
1613

1714
import nl.minvws.encoding.Base45;
15+
1816
import java.io.ByteArrayOutputStream;
1917
import java.io.IOException;
20-
import java.util.UUID;
2118

2219
public class GreenCertificateEncoder {
2320

2421
private final OneKey privateKey;
25-
private String kid;
22+
private final String kid;
23+
private final String prefix;
2624

2725
public GreenCertificateEncoder(OneKey privateKey, String kid) {
26+
this(privateKey, kid, "HC1");
27+
}
28+
29+
public GreenCertificateEncoder(OneKey privateKey, String kid, String prefix) {
2830
this.privateKey = privateKey;
2931
this.kid = kid;
32+
this.prefix = prefix;
3033
}
3134

3235
/**
@@ -40,21 +43,21 @@ public GreenCertificateEncoder(OneKey privateKey, String kid) {
4043
*/
4144
public String encode(String json) throws CoseException, CompressorException, IOException {
4245

43-
byte[] cborBytes = getCborBytes(json);
46+
byte[] cborBytes = toCBORbytes(json);
4447

4548
byte[] coseBytes = getCOSEBytes(cborBytes);
4649

47-
byte[] deflateBytes = getDeflateBytes(coseBytes);
50+
byte[] deflateBytes = compress(coseBytes);
4851

4952
return getBase45(deflateBytes);
5053
}
5154

5255
private String getBase45(byte[] deflateBytes) {
5356

54-
return "HC1" + Base45.getEncoder().encodeToString(deflateBytes);
57+
return prefix + Base45.getEncoder().encodeToString(deflateBytes);
5558
}
5659

57-
private byte[] getDeflateBytes(byte[] messageBytes) throws CompressorException, IOException {
60+
private byte[] compress(byte[] messageBytes) throws CompressorException, IOException {
5861
ByteArrayOutputStream deflateOutputStream = new ByteArrayOutputStream();
5962
try (CompressorOutputStream deflateOut = new CompressorStreamFactory()
6063
.createCompressorOutputStream(CompressorStreamFactory.DEFLATE, deflateOutputStream)) {
@@ -75,9 +78,8 @@ private byte[] getCOSEBytes(byte[] cborBytes) throws CoseException {
7578
return msg.EncodeToBytes();
7679
}
7780

78-
private byte[] getCborBytes(String json) {
81+
private byte[] toCBORbytes(String json) {
7982
CBORObject cborObject = CBORObject.FromJSONString(json);
80-
8183
return cborObject.EncodeToBytes();
8284
}
8385
}

src/main/java/ehn/techiop/hcert/model/CertificatePayload.java

+5-5
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ public class CertificatePayload {
1414
private long exp;
1515

1616
@JsonProperty("-260")
17-
private Hcert hcert;
17+
private HealthCertificate healthCertificate;
1818

1919

2020
public String getIss() {
@@ -41,12 +41,12 @@ public void setExp(long exp) {
4141
this.exp = exp;
4242
}
4343

44-
public Hcert getHcert() {
45-
return hcert;
44+
public HealthCertificate getHcert() {
45+
return healthCertificate;
4646
}
4747

48-
public void setHcert(Hcert hcert) {
49-
this.hcert = hcert;
48+
public void setHcert(HealthCertificate healthCertificate) {
49+
this.healthCertificate = healthCertificate;
5050
}
5151

5252
}

src/main/java/ehn/techiop/hcert/model/Hcert.java

-19
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package ehn.techiop.hcert.model;
2+
3+
import com.fasterxml.jackson.annotation.JsonProperty;
4+
import ehn.techiop.hcert.DigitalGreenCertificate;
5+
6+
public class HealthCertificate {
7+
8+
@JsonProperty("1")
9+
private DigitalGreenCertificate digitalGreenCertificate;
10+
11+
public DigitalGreenCertificate getDigitalGreenCertificate() {
12+
return digitalGreenCertificate;
13+
}
14+
15+
public void setDigitalGreenCertificate(DigitalGreenCertificate digitalGreenCertificate) {
16+
this.digitalGreenCertificate = digitalGreenCertificate;
17+
}
18+
}

0 commit comments

Comments
 (0)