Skip to content

Commit

Permalink
Introduce Gaen V2.
Browse files Browse the repository at this point in the history
  • Loading branch information
martinalig committed Oct 13, 2020
1 parent e58a7e7 commit e9337ca
Show file tree
Hide file tree
Showing 12 changed files with 686 additions and 25 deletions.
1 change: 1 addition & 0 deletions dpppt-backend-sdk/dpppt-backend-sdk-data/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>42.2.14</version>
</dependency>
<dependency>
<groupId>org.hsqldb</groupId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,4 +56,13 @@ List<GaenKey> getSortedExposedForKeyDate(
* @param retentionPeriod in milliseconds
*/
void cleanDB(Duration retentionPeriod);

/**
* Returns all exposed keys since keySince.
*
* @param keysSince
* @param now
* @return
*/
List<GaenKey> getSortedExposedSince(UTCInstant keysSince, UTCInstant now);
}
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,53 @@ public List<GaenKey> getSortedExposedForKeyDate(
return jt.query(sql, params, new GaenKeyRowMapper());
}

@Override
@Transactional(readOnly = true)
public List<GaenKey> getSortedExposedSince(UTCInstant keysSince, UTCInstant now) {
MapSqlParameterSource params = new MapSqlParameterSource();
params.addValue("since", keysSince.getDate());
params.addValue("maxBucket", now.roundToBucketStart(releaseBucketDuration).getDate());
params.addValue("timeSkewSeconds", timeSkew.toSeconds());

// Select keys since the given date. We need to make sure, only keys are returned
// that are allowed to be published.
// For this, we calculate the expiry for each key in a sub query. The expiry is then used for
// the where clause:
// - if expiry <= received_at: the key was ready to publish when we received it. Release this
// key, if received_at in [since, maxBucket)
// - if expiry > received_at: we have to wait until expiry till we can release this key. This
// means we only release the key if expiry in [since, maxBucket)
// This problem arises, because we only want key with received_at after since, but we need to
// ensure that we relase ALL keys meaning keys which were still valid when they were received

// we need to add the time skew to calculate the expiry timestamp of a key:
// TO_TIMESTAMP((rolling_start_number + rolling_period) * 10 * 60 + :timeSkewSeconds

String sql =
"select keys.pk_exposed_id, keys.key, keys.rolling_start_number, keys.rolling_period,"
+ " keys.transmission_risk_level from (select pk_exposed_id, key,"
+ " rolling_start_number, rolling_period, transmission_risk_level, received_at, "
+ getSQLExpressionForExpiry()
+ " as expiry from t_gaen_exposed)"
+ " as keys where ((keys.received_at >= :since AND"
+ " keys.received_at < :maxBucket AND keys.expiry <= keys.received_at) OR (keys.expiry"
+ " >= :since AND keys.expiry < :maxBucket AND keys.expiry > keys.received_at))";

sql += " order by keys.pk_exposed_id desc";

return jt.query(sql, params, new GaenKeyRowMapper());
}

private String getSQLExpressionForExpiry() {
if (this.dbType.equals(PGSQL)) {
return "TO_TIMESTAMP((rolling_start_number + rolling_period) * 10 * 60 +"
+ " :timeSkewSeconds)";
} else {
return "TIMESTAMP_WITH_ZONE((rolling_start_number + rolling_period) * 10 * 60 +"
+ " :timeSkewSeconds)";
}
}

@Override
@Transactional(readOnly = false)
public void cleanDB(Duration retentionPeriod) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package org.dpppt.backend.sdk.model.gaen;

import ch.ubique.openapi.docannotations.Documentation;
import java.util.List;
import javax.validation.Valid;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;

public class GaenV2UploadKeysRequest {

@NotNull
@NotEmpty
@Valid
@Size(min = 30, max = 30)
@Documentation(
description = "30 Temporary Exposure Keys - zero or more of them might be fake keys.")
private List<GaenKey> gaenKeys;

public List<GaenKey> getGaenKeys() {
return this.gaenKeys;
}

public void setGaenKeys(List<GaenKey> gaenKeys) {
this.gaenKeys = gaenKeys;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
syntax = "proto2";
package org.dpppt.backend.sdk.model.gaen.proto.v2;
option java_package = "org.dpppt.backend.sdk.model.gaen.proto.v2";

message TemporaryExposureKeyExport {
// Time window of keys in the file, based on arrival
// at the server, in UTC seconds.
optional fixed64 start_timestamp = 1;
optional fixed64 end_timestamp = 2;

// The region from which these keys came
optional string region = 3;

// Reserved for future use. Both batch_num and batch_size
// must be set to a value of 1.
optional int32 batch_num = 4;
optional int32 batch_size = 5;

// Information about associated signatures
repeated SignatureInfo signature_infos = 6;

// Exposure keys that are new.
repeated TemporaryExposureKey keys = 7;

// Keys that have changed status from previous key archives,
// including keys that are being revoked.
repeated TemporaryExposureKey revised_keys = 8;
}
message SignatureInfo {
// The first two fields have been deprecated.
// reserved 1, 2;
// reserved "app_bundle_id", "android_package";
optional string app_bundle_id = 1;
optional string android_package = 2;

// Key version in case the key server signing key is rotated. (e.g. "v1")
// A PHA can only have one active public key at a time, so they must rotate
// keys on all devices and servers at the same time to avoid problems.
optional string verification_key_version = 3;

// Implementation-specific string that can be used in key verification.
// Valid character in this string are all alphanumeric characters,
// underscores, and periods.
optional string verification_key_id = 4;

// All keys must be signed using the SHA-256 with ECDSA algorithm.
// This field must contain the string "1.2.840.10045.4.3.2".
optional string signature_algorithm = 5;
}
message TemporaryExposureKey {
// Temporary exposure key for an infected user.
optional bytes key_data = 1;

// Varying risk associated with a key depending on diagnosis method.
// Deprecated and no longer used.
optional int32 transmission_risk_level = 2 [deprecated = true];

// The interval number since epoch for which a key starts
optional int32 rolling_start_interval_number = 3;

// How long this key is valid, specified in increments of 10 minutes
optional int32 rolling_period = 4
[default = 144]; // defaults to 24 hours

// Data type that represents why this key was published.
enum ReportType {
UNKNOWN = 0; // Never returned by the client API.
CONFIRMED_TEST = 1;
CONFIRMED_CLINICAL_DIAGNOSIS = 2;
SELF_REPORT = 3;
RECURSIVE = 4; // Reserved for future use.
REVOKED = 5; // Used to revoke a key, never returned by client API.
}

// Type of diagnosis associated with a key.
optional ReportType report_type = 5;

// Number of days elapsed between symptom onset and the TEK being used.
// E.g. 2 means TEK is from 2 days after onset of symptoms.
// Valid values range is from -14 to 14.
optional sint32 days_since_onset_of_symptoms = 6;
}
message TEKSignatureList {
// Information about associated signatures
repeated TEKSignature signatures = 1;
}

message TEKSignature {
// Information to uniquely identify the public key associated
// with the key server's signing key.
optional SignatureInfo signature_info = 1;

// Reserved for future use. Both batch_num and batch_size
// must be set to a value of 1.
optional int32 batch_num = 2;
optional int32 batch_size = 3;

// Signature in X9.62 format (ASN.1 SEQUENCE of two INTEGER fields).
optional bytes signature = 4;
}
48 changes: 25 additions & 23 deletions dpppt-backend-sdk/dpppt-backend-sdk-ws/pom.xml
Original file line number Diff line number Diff line change
@@ -1,12 +1,8 @@
<!--
~ Copyright (c) 2020 Ubique Innovation AG <https://www.ubique.ch>
~
~ This Source Code Form is subject to the terms of the Mozilla Public
~ License, v. 2.0. If a copy of the MPL was not distributed with this
~ file, You can obtain one at https://mozilla.org/MPL/2.0/.
~
~ SPDX-License-Identifier: MPL-2.0
-->
<!-- ~ Copyright (c) 2020 Ubique Innovation AG <https://www.ubique.ch> ~
~ This Source Code Form is subject to the terms of the Mozilla Public ~ License,
v. 2.0. If a copy of the MPL was not distributed with this ~ file, You can
obtain one at https://mozilla.org/MPL/2.0/. ~ ~ SPDX-License-Identifier:
MPL-2.0 -->

<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
Expand Down Expand Up @@ -71,6 +67,12 @@
<artifactId>spring-security-oauth2</artifactId>
</dependency>

<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>42.2.14</version>
</dependency>

<!-- dp3t models -->
<dependency>
<groupId>org.dpppt</groupId>
Expand Down Expand Up @@ -123,27 +125,27 @@
</executions>
</plugin>
<plugin>
<groupId>ch.ubique.openapi</groupId>
<artifactId>springboot-swagger-3</artifactId>
<configuration>
<apiVersion>1.0-gapple</apiVersion>
<basePackages>org.dpppt.backend.sdk.model</basePackages>
<groupId>ch.ubique.openapi</groupId>
<artifactId>springboot-swagger-3</artifactId>
<configuration>
<apiVersion>1.0-gapple</apiVersion>
<basePackages>org.dpppt.backend.sdk.model</basePackages>
<blackListedPackages>
<blackListedPackage>com.google.protobuf</blackListedPackage>
</blackListedPackages>
<ignoredTypes>
<ignoredType>byte</ignoredType>
</ignoredTypes>
<controllers>
<controllers>
<controller>org.dpppt.backend.sdk.ws.controller.GaenController</controller>
</controllers>
<description>DP3T API</description>
<apiUrls>
<apiUrl>https://demo.dpppt.org</apiUrl>
</apiUrls>
<title>DP3T API</title>
</configuration>
</plugin>
</controllers>
<description>DP3T API</description>
<apiUrls>
<apiUrl>https://demo.dpppt.org</apiUrl>
</apiUrls>
<title>DP3T API</title>
</configuration>
</plugin>
</plugins>
</build>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import org.dpppt.backend.sdk.data.gaen.GAENDataService;
import org.dpppt.backend.sdk.data.gaen.JDBCGAENDataServiceImpl;
import org.dpppt.backend.sdk.ws.controller.GaenController;
import org.dpppt.backend.sdk.ws.controller.GaenV2Controller;
import org.dpppt.backend.sdk.ws.filter.ResponseWrapperFilter;
import org.dpppt.backend.sdk.ws.insertmanager.InsertManager;
import org.dpppt.backend.sdk.ws.insertmanager.insertionfilters.AssertKeyFormat;
Expand All @@ -43,6 +44,7 @@
import org.dpppt.backend.sdk.ws.insertmanager.insertionmodifier.OldAndroid0RPModifier;
import org.dpppt.backend.sdk.ws.interceptor.HeaderInjector;
import org.dpppt.backend.sdk.ws.security.KeyVault;
import org.dpppt.backend.sdk.ws.security.NoValidateRequest;
import org.dpppt.backend.sdk.ws.security.ValidateRequest;
import org.dpppt.backend.sdk.ws.security.signature.ProtoSignature;
import org.dpppt.backend.sdk.ws.util.ValidationUtils;
Expand Down Expand Up @@ -277,6 +279,9 @@ public ValidationUtils gaenValidationUtils() {
@Bean
public GaenController gaenController() {
ValidateRequest theValidator = gaenRequestValidator;
if (theValidator == null) {
theValidator = backupValidator();
}
return new GaenController(
insertManagerExposed(),
insertManagerExposedNextDay(),
Expand All @@ -291,6 +296,25 @@ public GaenController gaenController() {
keyVault.get("nextDayJWT").getPrivate());
}

@Bean
public GaenV2Controller gaenV2Controller() {
ValidateRequest theValidator = gaenRequestValidator;
if (theValidator == null) {
theValidator = backupValidator();
}
return new GaenV2Controller(
insertManagerExposed(),
theValidator,
gaenValidationUtils(),
fakeKeyService(),
gaenSigner(),
gaenDataService(),
Duration.ofMillis(releaseBucketDuration),
Duration.ofMillis(requestTime),
Duration.ofMillis(exposedListCacheControl),
Duration.ofDays(retentionDays));
}

@Bean
public GAENDataService gaenDataService() {
return new JDBCGAENDataServiceImpl(
Expand All @@ -302,6 +326,11 @@ public RedeemDataService redeemDataService() {
return new JDBCRedeemDataServiceImpl(dataSource());
}

@Bean
ValidateRequest backupValidator() {
return new NoValidateRequest();
}

@Bean
public MappingJackson2HttpMessageConverter converter() {
ObjectMapper mapper =
Expand Down
Loading

0 comments on commit e9337ca

Please sign in to comment.