Skip to content

Commit

Permalink
Verification claims adjustments (google#700)
Browse files Browse the repository at this point in the history
* remove free form pha claims
* introduce v1.5 fields to verification claims
* clairfy naming
* mark transmission risk overrides as deprecated, but still used

Part of google#680
Part of google#663
  • Loading branch information
mikehelmick authored and krazykid committed Jul 13, 2020
1 parent 5b59334 commit 9cd1ad1
Show file tree
Hide file tree
Showing 5 changed files with 75 additions and 34 deletions.
4 changes: 2 additions & 2 deletions internal/publish/model/exposure_model.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ func ApplyTransmissionRiskOverrides(p *verifyapi.Publish, overrides verifyapi.Tr
// Advance the overrideIdx until the current key is covered or we exhaust the
// override index.
for overrideIdx < len(overrides) &&
eKey.IntervalNumber+eKey.IntervalCount <= overrides[overrideIdx].SinceRollingPeriod {
eKey.IntervalNumber+eKey.IntervalCount <= overrides[overrideIdx].SinceRollingInterval {
overrideIdx++
}

Expand All @@ -59,7 +59,7 @@ func ApplyTransmissionRiskOverrides(p *verifyapi.Publish, overrides verifyapi.Tr

// Check to see if this key is in the current override.
// If the key was EVERY valid during the SinceRollingPeriod then the override applies.
if eKey.IntervalNumber+eKey.IntervalCount >= overrides[overrideIdx].SinceRollingPeriod {
if eKey.IntervalNumber+eKey.IntervalCount >= overrides[overrideIdx].SinceRollingInterval {
p.Keys[i].TransmissionRisk = overrides[overrideIdx].TranismissionRisk
// don't advance overrideIdx, there might be additional keys in this override.
}
Expand Down
24 changes: 12 additions & 12 deletions internal/publish/model/exposure_model_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -578,16 +578,16 @@ func TestApplyOverrides(t *testing.T) {
},
Overrides: []verifyapi.TransmissionRiskOverride{
{
SinceRollingPeriod: 5,
TranismissionRisk: 5,
SinceRollingInterval: 5,
TranismissionRisk: 5,
},
{
SinceRollingPeriod: 3,
TranismissionRisk: 3,
SinceRollingInterval: 3,
TranismissionRisk: 3,
},
{
SinceRollingPeriod: 0,
TranismissionRisk: 0,
SinceRollingInterval: 0,
TranismissionRisk: 0,
},
},
Want: []verifyapi.ExposureKey{
Expand Down Expand Up @@ -637,12 +637,12 @@ func TestApplyOverrides(t *testing.T) {
},
Overrides: []verifyapi.TransmissionRiskOverride{
{
SinceRollingPeriod: 4,
TranismissionRisk: 5, // anything effective at time >= 4 gets TR 5.
SinceRollingInterval: 4,
TranismissionRisk: 5, // anything effective at time >= 4 gets TR 5.
},
{
SinceRollingPeriod: 0,
TranismissionRisk: 2, // 2 since beginning of time.
SinceRollingInterval: 0,
TranismissionRisk: 2, // 2 since beginning of time.
},
},
Want: []verifyapi.ExposureKey{
Expand Down Expand Up @@ -680,8 +680,8 @@ func TestApplyOverrides(t *testing.T) {
},
Overrides: []verifyapi.TransmissionRiskOverride{
{
SinceRollingPeriod: 4,
TranismissionRisk: 5, // anything effective at time >= 4 gets TR 5.
SinceRollingInterval: 4,
TranismissionRisk: 5, // anything effective at time >= 4 gets TR 5.
},
},
Want: []verifyapi.ExposureKey{
Expand Down
4 changes: 2 additions & 2 deletions internal/publish/publish_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -266,8 +266,8 @@ func TestPublishWithBypass(t *testing.T) {
},
Overrides: []verifyapi.TransmissionRiskOverride{
{
TranismissionRisk: 8,
SinceRollingPeriod: 0,
TranismissionRisk: 8,
SinceRollingInterval: 0,
},
},
WantTRAdjustment: []int{8, 8}, // 2 entries, both override to 8
Expand Down
50 changes: 41 additions & 9 deletions pkg/api/v1alpha1/verification_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,27 @@ import (
)

const (
ExposureKeyHMACClaim = "tekmac"
HealthAuthorityDataClaim = "phadata"
// ExposureKeyHMACClaim is the JWT claim key for the HMAC of the TEKs
ExposureKeyHMACClaim = "tekmac"
// TransmissionRiskOverrideClaim is the JWT Claim key for transmission risk overrides
TransmissionRiskOverrideClaim = "trisk"
KeyIDHeader = "kid"
// ReportTypeClaim is the JWT claim for the report type (confirmed|likely|negative)
ReportTypeClaim = "reportType"
// SymptomOnsetIntervalClaim is the JWT claim for the interval representing the symptom onset.
SymptomOnsetIntervalClaim = "symptomOnsetInterval"
// TestDateIntervalClaim is the JWT claim for the interval representing the test date
TestDateIntervalClaim = "testDateInterval"
// KeyIDHeader is the standard JWT key ID header name.
KeyIDHeader = "kid"

// ReportType strings that correspond to what is defined in internal/pb/export/export.proto

// ReportTypeConfirmed indicates to set ReportType.CONFIRMED_TEST
ReportTypeConfirmed = "confirmed"
// ReportTypeClinical indicates to set ReportType.CONFIRMED_CLINICAL_DIAGNOSIS
ReportTypeClinical = "likely"
// ReportTypeNegative is allowed by the verification flow. These keys are not saved in the system.
ReportTypeNegative = "negative"
)

// TransmissionRiskVector is an additional set of claims that can be
Expand All @@ -40,8 +57,8 @@ var _ sort.Interface = TransmissionRiskVector{}

// TransmissionRiskOverride is an indvidual transmission risk override.
type TransmissionRiskOverride struct {
TranismissionRisk int `json:"tr"`
SinceRollingPeriod int32 `json:"sinceRollingPeriod"`
TranismissionRisk int `json:"tr"`
SinceRollingInterval int32 `json:"sinceRollingInterval"`
}

func (a TransmissionRiskVector) Len() int {
Expand All @@ -51,23 +68,38 @@ func (a TransmissionRiskVector) Len() int {
// Less sorts the TransmissionRiskVector vector with the largest SinceRollingPeriod
// value first. Descending sort.
func (a TransmissionRiskVector) Less(i, j int) bool {
return a[i].SinceRollingPeriod > a[j].SinceRollingPeriod
return a[i].SinceRollingInterval > a[j].SinceRollingInterval
}

func (a TransmissionRiskVector) Swap(i, j int) {
a[i], a[j] = a[j], a[i]
}

// VerificationClaims represents the accepted Claims portion of the verification certificate JWT.
// This data is used to set data on the uploaded TEKs and will be reflected on export. See the export file format:
// https:/google/exposure-notifications-server/blob/main/internal/pb/export/export.proto#L73
type VerificationClaims struct {
PHAClaims map[string]string `json:"phadata"`
ReportType string `json:"reportType"`
// SymptomOnsetInterval uses the same 10 minute interval timing as TEKs use. If an interval is provided that isn not the
// start of a UTC day, then it will be rounded down to the beginning of that UTC day. And from there the days +/- symptom
// onset will be calculated.
SymptomOnsetInterval uint32 `json:"symptomOnsetInterval"`
// TestDateInterval also uses the 10 mninute intervals and has the same rounding
// rules as SymptomOnsetInterval
TestDateInterval uint32 `json:"testDateInterval"`

// Deprecated, but not scheduled for removal.
// TransmissionRisks will continue to be supported. On newer versions of the device software,
// the ReportType and days +/- symptom onset will be used.
TransmissionRisks TransmissionRiskVector `json:"trisk"`
SignedMAC string `json:"tekmac"`

SignedMAC string `json:"tekmac"`
jwt.StandardClaims
}

// NewVerificationClaims initializes a new VerificationClaims struct.
func NewVerificationClaims() *VerificationClaims {
return &VerificationClaims{
PHAClaims: make(map[string]string),
TransmissionRisks: []TransmissionRiskOverride{},
}
}
27 changes: 18 additions & 9 deletions tools/example-verification-signing/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,14 @@
// See the License for the specific language governing permissions and
// limitations under the License.

// This package implements a sample server that implements the public health authority
// This package implements a sample server that implements a piece of the public health authority
// verification protocol: https:/google/exposure-notifications-server/blob/main/docs/design/verification_protocol.md
//
// To call this server using curl:
// curl -d '{"verificationCode":"fakeCode","tekhmac":"replace w/ tek hmac"}' -H "Content-Type: application/json" -X POST http://localhost:8080/
//
// The FULL protocol is implemented by
// https:/google/exposure-notifications-verification-server/
package main

import (
Expand All @@ -31,6 +34,7 @@ import (
"strings"
"time"

"github.com/google/exposure-notifications-server/internal/publish/model"
"github.com/google/exposure-notifications-server/internal/setup"
"github.com/google/exposure-notifications-server/pkg/api/v1alpha1"
"github.com/google/exposure-notifications-server/pkg/keys"
Expand All @@ -40,6 +44,7 @@ import (
)

// VerifyRequest is the JSON structure the server accepts in order to issue a certificate.
// This is a simplified example and doesn't represent the full capabilities.
type VerifyRequest struct {
VerificationCode string `json:"verificationCode"`
HMAC string `json:"tekhmac"`
Expand Down Expand Up @@ -68,6 +73,8 @@ func (c *config) KeyManagerConfig() *keys.Config {
}

func main() {
oneDay := 24 * time.Hour

ctx := context.Background()
var cfg config
env, err := setup.Setup(ctx, &cfg)
Expand All @@ -94,18 +101,20 @@ func main() {

now := time.Now().UTC()

// Normally - you would verify the verificationCode against a database and optionally
// assign transmission risk overrides.

// Here - we simply sign the claims and assume the verificationCode is valid.
// Here - we simply sign the claims and do not to any code or token verification.
// The full verification flow reference implementation is available at:
// https:/google/exposure-notifications-verification-server/

// Build a JWT that contains the Standard and Extended claims as defined in
// pkg/api/v1alpha1/verification_types.go
claims := v1alpha1.NewVerificationClaims()
// PHAClaims is a key-value map that can be used to send information from the verification
// server to the app and/or the key server.
// The reference key server ignores anything in PHAClaims.
claims.PHAClaims["testkit"] = "55-HH-A7"

// Here, we show an example of a confirmed lab test, conducted yesterday (-1 day),
// with symptom onset occurring 2 days before the test (-3 days from now).
claims.ReportType = v1alpha1.ReportTypeConfirmed
claims.TestDateInterval = uint32(model.IntervalNumber(now.Add(-1 * oneDay).Truncate(oneDay)))
claims.SymptomOnsetInterval = uint32(model.IntervalNumber(now.Add(-3 * oneDay).Truncate(oneDay)))

// optionally add transmission risks
claims.SignedMAC = request.HMAC
// Add in the standard claims.
Expand Down

0 comments on commit 9cd1ad1

Please sign in to comment.