Skip to content

Commit

Permalink
fix expiration (#80)
Browse files Browse the repository at this point in the history
  • Loading branch information
a-trzewik committed Jun 11, 2021
1 parent 672a3e8 commit d6fc2a8
Show file tree
Hide file tree
Showing 6 changed files with 128 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,5 @@ public class DgciIdentifier {
private int algId;
private String countryCode;
private long expired;
private long expiredDuration;
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,6 @@
import ehn.techiop.hcert.data.Eudgc;
import ehn.techiop.hcert.kotlin.chain.impl.DefaultCborService;
import eu.europa.ec.dgc.issuance.config.IssuanceConfigProperties;
import eu.europa.ec.dgc.issuance.entity.GreenCertificateType;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import lombok.RequiredArgsConstructor;
import org.jetbrains.annotations.NotNull;
import org.springframework.stereotype.Service;
Expand Down Expand Up @@ -38,22 +35,12 @@ public byte[] encode(@NotNull Eudgc input) {
} catch (JsonProcessingException e) {
throw new IllegalArgumentException(e);
}
GreenCertificateType greenCertificateType;
if (input.getT() != null && !input.getT().isEmpty()) {
greenCertificateType = GreenCertificateType.Test;
} else if (input.getR() != null && !input.getR().isEmpty()) {
greenCertificateType = GreenCertificateType.Recovery;
} else {
greenCertificateType = GreenCertificateType.Vaccination;
}
long issueTime = Instant.now().getEpochSecond();
long expirationTime = issueTime
+ expirationService.expirationForType(greenCertificateType).get(ChronoUnit.SECONDS);
ExpirationService.CwtTimeFields cwtTimes = expirationService.calculateCwtExpiration(input);
CBORObject coseContainer = CBORObject.NewMap();
coseContainer.set(CBORObject.FromObject(ISSUER),
CBORObject.FromObject(issuanceConfigProperties.getCountryCode()));
coseContainer.set(CBORObject.FromObject(ISSUED_AT),CBORObject.FromObject(issueTime));
coseContainer.set(CBORObject.FromObject(EXPIRATION),CBORObject.FromObject(expirationTime));
coseContainer.set(CBORObject.FromObject(ISSUED_AT),CBORObject.FromObject(cwtTimes.getIssuedAt()));
coseContainer.set(CBORObject.FromObject(EXPIRATION),CBORObject.FromObject(cwtTimes.getExpiration()));
CBORObject hcert = CBORObject.NewMap();
hcert.set(CBORObject.FromObject(HCERT_VERSION),CBORObject.DecodeFromBytes(cbor));
coseContainer.set(CBORObject.FromObject(HCERT),hcert);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,10 @@
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.X509EncodedKeySpec;
import java.time.Duration;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.Base64;
import java.util.List;
Expand Down Expand Up @@ -113,7 +115,8 @@ public DgciIdentifier initDgci(DgciInit dgciInit) {
dgciEntity.setGreenCertificateType(dgciInit.getGreenCertificateType());

ZonedDateTime now = ZonedDateTime.now();
ZonedDateTime expiration = now.plus(expirationService.expirationForType(dgciInit.getGreenCertificateType()));
Duration expirationDuration = expirationService.expirationForType(dgciInit.getGreenCertificateType());
ZonedDateTime expiration = now.plus(expirationDuration);

dgciEntity.setExpiresAt(expiration);
dgciRepository.saveAndFlush(dgciEntity);
Expand All @@ -131,7 +134,8 @@ public DgciIdentifier initDgci(DgciInit dgciInit) {
certificateService.getKidAsBase64(),
certificateService.getAlgorithmIdentifier(),
issuanceConfigProperties.getCountryCode(),
expirationSec
expirationSec,
expirationDuration.get(ChronoUnit.SECONDS)
);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
package eu.europa.ec.dgc.issuance.service;

import ehn.techiop.hcert.data.Eudgc;
import eu.europa.ec.dgc.issuance.config.IssuanceConfigProperties;
import eu.europa.ec.dgc.issuance.entity.GreenCertificateType;
import java.time.Duration;
import java.time.Instant;
import java.time.LocalDate;
import java.time.ZoneOffset;
import java.time.temporal.ChronoUnit;
import java.util.Date;
import lombok.Data;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;

Expand Down Expand Up @@ -42,4 +48,66 @@ public Duration expirationForType(GreenCertificateType greenCertificateType) {
}
return duration;
}

/**
* calulate cbor web token expiration fields.
* It depends partly on configuration and for test and recovery also from DGC Json data
* @param eudgc json data of dgc
* @return the times
*/
public CwtTimeFields calculateCwtExpiration(Eudgc eudgc) {
CwtTimeFields result = new CwtTimeFields();
GreenCertificateType greenCertificateType;
long expirationTime;
long issueTime = Instant.now().getEpochSecond();
long expirationStartTime = issueTime;

if (eudgc.getT() != null && !eudgc.getT().isEmpty()) {
greenCertificateType = GreenCertificateType.Test;
expirationStartTime = extractTimesSec(eudgc.getT().get(0).getSc(),expirationStartTime);
expirationTime = expirationStartTime + expirationForType(greenCertificateType).get(ChronoUnit.SECONDS);
} else if (eudgc.getR() != null && !eudgc.getR().isEmpty()) {
greenCertificateType = GreenCertificateType.Recovery;
expirationTime = expirationStartTime + expirationForType(greenCertificateType).get(ChronoUnit.SECONDS);
expirationTime = extractTimesSec(eudgc.getR().get(0).getDu(),expirationTime);
} else if (eudgc.getV() != null && !eudgc.getV().isEmpty()) {
greenCertificateType = GreenCertificateType.Vaccination;
expirationStartTime = extractTimesSec(eudgc.getV().get(0).getDt(),expirationStartTime);
expirationTime = expirationStartTime + expirationForType(greenCertificateType).get(ChronoUnit.SECONDS);
} else {
// fallback
greenCertificateType = GreenCertificateType.Vaccination;
expirationTime = expirationStartTime + expirationForType(greenCertificateType).get(ChronoUnit.SECONDS);
}
result.setIssuedAt(issueTime);
result.setExpiration(expirationTime);
return result;
}

private long extractTimesSec(Date date, long defaultTimeSec) {
long timeSec;
if (date != null) {
timeSec = date.toInstant().getEpochSecond();
} else {
timeSec = defaultTimeSec;
}
return timeSec;
}

private long extractTimesSec(String dateAsString, long defaultTimeSec) {
long timeSec;
if (dateAsString != null && dateAsString.length() > 0) {
timeSec = LocalDate.parse(dateAsString).atStartOfDay().toInstant(ZoneOffset.UTC).getEpochSecond();
} else {
timeSec = defaultTimeSec;
}
return timeSec;
}


@Data
public static class CwtTimeFields {
long issuedAt;
long expiration;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package eu.europa.ec.dgc.issuance.service;

import com.fasterxml.jackson.databind.ObjectMapper;
import ehn.techiop.hcert.data.Eudgc;
import ehn.techiop.hcert.kotlin.chain.SampleData;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import static org.junit.jupiter.api.Assertions.assertNotNull;

@SpringBootTest
class ExpirationServiceTest {
@Autowired
ExpirationService expirationService;
ObjectMapper objectMapper = new ObjectMapper();

@Test
void testExpriationCalculation() throws Exception {
String vacDataJson = SampleData.Companion.getVaccination();
Eudgc eudgc = testCalculation("vactination",vacDataJson);
System.out.println(eudgc.getV().get(0).getDt());
String recoveryDataJson = SampleData.Companion.getRecovery();
eudgc = testCalculation("recovery",recoveryDataJson);
System.out.println(eudgc.getR().get(0).getDu());
String testDataJson = SampleData.Companion.getTestNaa();
eudgc = testCalculation("test",testDataJson);
System.out.println(eudgc.getT().get(0).getSc().toInstant().atOffset(ZoneOffset.UTC));
assertNotNull(eudgc);

}

private Eudgc testCalculation(String description, String vacDataJson) throws com.fasterxml.jackson.core.JsonProcessingException {
System.out.println("testing: "+description);
Eudgc eudgc = objectMapper.readValue(vacDataJson,Eudgc.class);
ExpirationService.CwtTimeFields expTime = expirationService.calculateCwtExpiration(eudgc);
LocalDateTime issuedAt = LocalDateTime.ofEpochSecond(expTime.getIssuedAt(), 0, ZoneOffset.UTC);
assertNotNull(issuedAt);
System.out.println(issuedAt);
LocalDateTime expired = LocalDateTime.ofEpochSecond(expTime.getExpiration(), 0, ZoneOffset.UTC);
System.out.println(expired);
return eudgc;
}
}
4 changes: 4 additions & 0 deletions src/test/resources/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ issuance:
privateKeyPassword: dgca
countryCode: DE
tanExpirationHours: 24
expiration:
vaccination: 365
recovery: 365
test: 3
endpoints:
frontendIssuing: true
backendIssuing: true
Expand Down

0 comments on commit d6fc2a8

Please sign in to comment.