exposure-notifications-verification-server

module
v0.2.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 5, 2020 License: Apache-2.0

README

Exposure Notifications Verification System | Reference Server

As part of the broader Google Exposure Notification reference server efforts, this repository contains the reference implementation for a verification server.

About the Server

Following the high level flow for the verification system, this server:

  1. Handles human user authorization using Firebase Authentication
  2. Provides a Web interface for a case investigation epidemiologist (epi) to enter test parameters (status + test date) and issue a verification code
    • Verification codes are 8 numeric digits so that they can be easily read over a phone call or send via SMS text message.
    • Verification codes are valid for a short duration (1 hour)
  3. Provides a JSON-over-HTTP API for exchanging the verification code for a verification token.
    • Verification tokens are signed JWTs that are valid for 24 hours (configurable)
  4. Provides a JSON-over-HTTP API for exchanging the verification token for a verification certificate. This API call also requires an HMAC of the Temporary Exposure Key (TEK) data+metatata. This HMAC value is signed by the verification server to be later accepted by an exposure notifications server. This same TEK data used to generate the HMAC here, must be passed to the exposure notifications server, otherwise the request will be rejected.
    • Please see the documentation for the HMAC Calculation
    • The Verification Certificate is also a JWT

Verification Flow

Architecture details

  • 4 services combine to make this application. All servers are intended to be deployed in an autoscaled serverless environment.
    • cmd/server - Web UI for creating verification codes
    • cmd/apiserver - Server for mobile device applications to do verification
    • cmd/adminapi - Server for connecting existing PHA applications to the verification system. [Optional component]
    • cmd/cleanup - Server for cleaning up old data. Required in order to recycle and reuse verification codes over a longer period of time.
  • PostgreSQL database for shared state
    • This codebase utilizes GORM, so it is possible to easily switch to another supported SQL database.
  • Redis cache used for distributed rate limiting.
  • Relies on Firebase Authentication for handling of identity / login
  • As is, this project is configured to use username/password based login, but can easily be configured to use any firebase supported identity provider.

Configuring your Development Environment for Running Locally

gcloud auth login && gcloud auth application-default login

Create a key ring and two signing keys

gcloud kms keyrings create --location=us signing
gcloud kms keys create token-signing --location=us --keyring=signing --purpose=asymmetric-signing --default-algorithm=ec-sign-p256-sha256
gcloud kms keys create certificate-signing --location=us --keyring=signing --purpose=asymmetric-signing --default-algorithm=ec-sign-p256-sha256

To get the resource name(s)

gcloud kms keys describe token-signing --keyring=signing --location=us
gcloud kms keys describe certificate-signing --keyring=signing --location=us

Finish setup and run the server.

gcloud auth login && gcloud auth application-default login

# In case you have this set, unset it to rely on gcloud.
unset GOOGLE_APPLICATION_CREDENTIALS

# Initialize Dev Settings
eval $(./scripts/dev init)
./scripts/dev dbstart

# Configure These settings to your firebase application
export FIREBASE_API_KEY="YOUR API KEY"
export FIREBASE_PROJECT_ID="YOUR-PROJECT-123456"
export FIREBASE_MESSAGE_SENDER_ID="789123456"
export FIREBASE_APP_ID="1:123456:web:abcd1234"
export FIREBASE_MEASUREMENT_ID="G-J12345C"

export FIREBASE_AUTH_DOMAIN="${FIREBASE_PROJECT_ID}.firebaseapp.com"
export FIREBASE_DATABASE_URL="https://${FIREBASE_PROJECT_ID}.firebaseio.com"
export FIREBASE_STORAGE_BUCKET="${FIREBASE_PROJECT_ID}.appspot.com"

export TOKEN_SIGNING_KEY="<Token Key Resource ID from Above>"
export CERTIFICATE_SIGNING_KEY="<Certificate Key Resource ID from Above>"


# D/L SA from Firebase https://console.firebase.google.com/project/project-name-123456/settings/serviceaccounts/adminsdk
export GOOGLE_APPLICATION_CREDENTIALS=/Users/USERNAME/Documents/project-name-123456-firebase-adminsdk-ab3-4cde56f78g.json

# Configure CSRF_AUTH_KEY. This is a 32 byte string base64 encoded.
# Create your own with `openssl rand -base64 32 | tr -d '\n'`
export CSRF_AUTH_KEY="aGVsbG9oZWxsb2hlbGxvaGVsbG9oZWxsb2hlbGxvaGk="

# Configure cookie encryption, the first is 64 bytes, the second is 32.
# Create your own with `openssl rand -base64 NUM | tr -d '\n'` where NUM is 32 or 64
export COOKIE_KEYS="M+yP18fJL7e/afWNdvDrHXPRq7BC1T0zlQPHAwNbeEJmp35y7dSTxvhARKLGYzH6DuIUe0uFqsK5XQtGMl8SuQ==,3PBCfkE6aFzq9UQbtzXUOJ4rta5RsYjxtrMz4j41xiE="

# Enable dev mode
export DEV_MODE=1

# Migrate DB
./scripts/dev dbmigrate


# OPTIONAL: You can create a realm (one should be created as part of migration)
# and note the return number in the output.
go run ./cmd/add-realm --name "my-custom-realm"


# create a user for whatever email address you want to use
go run ./cmd/add-users --email YOUR-NAME@DOMAIN.com --name "First Last" --admin --realm 1 --admin-realm 1

go run ./cmd/server

API Access

Access to the APIs is controlled through API keys. Users with Admin access are able to issue API keys and API keys have one of two levels of access: DEVICE or ADMIN.

  • DEVICE - Intended for a mobile application to call the cmd/apiserver to to the two step verification protocol to exchange verification codes for verification tokens, and verification tokens for verification certificates.

  • ADMIN - Intended for public health authority internal applications to integrate with this server. Additional protection is recommended, i.e. service mesh or external authentication.

API Guide for App Developers

The following APIs exist for the API server (cmd/apiserver). All APIs are JSON over HTTPS, only use POST, and require that the API key be passed in the HTTP header X-API-Key.

In addition to "real" requests, the server also accept chaff (fake) requests. These can be used to obfuscate real traffic from a network observer or server operator. To initiate a chaff request, set the X-Chaff header on your request. The client should still send a real request with a real request body (the body will not be processed). The server will respond with a fake response that your client MUST NOT process. Client's should sporadically issue chaff requests.

  1. /api/verify - Exchange a verification code for a long term verification token.

    VerifyCodeRequest:

    {
      "code": "<the code>"
    }
    

    VerifyCodeResponse:

    {
      "TestType": "<test type string>",
      "SymptomDate": "YYYY-MM-DD",
      "VerificationToken": "<JWT verification token>",
      "Error": ""
    }
    
  2. /api/certificate - Exchange a verification token for a verification certificate (for key server)

    VerificationCertificateRequest:

    {
      "VerificationToken": "token from verifyCodeResponse",
      "ekeyhmac": "hmac of exposure keys"
    }
    

    VerificationCertificateResponse:

    {
      "Certificate": "<JWT verification certificate>",
      "Error": ""
    }
    
Test Utilities

Using an Admin API key, one can request verification codes using cmd/get-token.

go run ./cmd/get-code --type="confirmed" --onset="2020-07-14" --apikey="<ADMIN API KEY>"

From there, there are two tools that can be used to complete the code->token->certificate exchange. To exchange the verification code for the verification token.

go run ./cmd/get-token --apikey="<DEVICE API KEY>" --code="<verificationCode>"

And to exchange the token for a verification certificate.

go run ./cmd/get-certificate --apikey="<DEVICE API KEY>" --token="<TOKEN FROM ABOVE>" --hmac="<HMAC TEKs to Certify>"

A complete end to end example:

exposure-notifications-verification-server on 🌱 readme [$!] via 🐹 v1.14.2
❯ go run ./cmd/get-code --apikey="BXlIlWxg3zgwDRPIVKF9QVshUbibOHI4cVsmXzxtJVx5FsBsr4/BNVSqzdaHXhEyAGf0X+xRp3rah9qipPB2kg" --type="likely" --onset="2020-07-10"
2020/07/16 13:56:51 Sending: {TestType:likely SymptomDate:2020-07-10}
2020/07/16 13:56:51 Result:
{VerificationCode:14404755 ExpiresAt:Thu, 16 Jul 2020 14:56:51 PDT Error:}

exposure-notifications-verification-server on 🌱 readme [$!] via 🐹 v1.14.2
❯ go run ./cmd/get-token --apikey="i9UhDG3kYj3eW0CslXMXujPJfbzJ0mJlLDN8zdFYiiDR6hrOrTm0UFSE6JSbW5qb9Af3/B+U+3nkmIxeopoMXA" --code="14404755"
2020/07/16 13:57:40 Sending: {VerificationCode:14404755}
2020/07/16 13:57:41 Result:
{TestType:likely SymptomDate:2020-07-10 VerificationToken:eyJhbGciOiJFUzI1NiIsImtpZCI6InYxIiwidHlwIjoiSldUIn0.eyJhdWQiOiJkaWFnbm9zaXMtdmVyaWZpY2F0aW9uLWV4YW1wbGUiLCJleHAiOjE1OTUwMTk0NjEsImp0aSI6Im5BbVdJKzVnZDRuSG0wcnJiOGRGWUVwUExDdFpaK2dMOXZ5YjVCcDJIdmVHTndmeHV5ZS9rU2x2Q2NhSGovWEwrelh5K1U1L3JpdFh1SGt1eGtvc3dLam13ZlJ0ZUpRQWpqeEdYazV5cFpPeENySGM2Z1ZVZTdxdVVNZFVkRkpBIiwiaWF0IjoxNTk0OTMzMDYxLCJpc3MiOiJkaWFnbm9zaXMtdmVyaWZpY2F0aW9uLWV4YW1wbGUiLCJzdWIiOiJsaWtlbHkuMjAyMC0wNy0xMCJ9.mxMsCwRUc6AtHNNjf_xjlxT4xJrwK2b1OkOvyWDmSKxJunaOBO_j9s4SCG_b3TbZn2eAPeqG8zNSu_YUzS5GYw Error:}

exposure-notifications-verification-server on 🌱 readme [$!] via 🐹 v1.14.2
❯ go run ./cmd/get-certificate --apikey="i9UhDG3kYj3eW0CslXMXujPJfbzJ0mJlLDN8zdFYiiDR6hrOrTm0UFSE6JSbW5qb9Af3/B+U+3nkmIxeopoMXA" --token="eyJhbGciOiJFUzI1NiIsImtpZCI6InYxIiwidHlwIjoiSldUIn0.eyJhdWQiOiJkaWFnbm9zaXMtdmVyaWZpY2F0aW9uLWV4YW1wbGUiLCJleHAiOjE1OTUwMTk0NjEsImp0aSI6Im5BbVdJKzVnZDRuSG0wcnJiOGRGWUVwUExDdFpaK2dMOXZ5YjVCcDJIdmVHTndmeHV5ZS9rU2x2Q2NhSGovWEwrelh5K1U1L3JpdFh1SGt1eGtvc3dLam13ZlJ0ZUpRQWpqeEdYazV5cFpPeENySGM2Z1ZVZTdxdVVNZFVkRkpBIiwiaWF0IjoxNTk0OTMzMDYxLCJpc3MiOiJkaWFnbm9zaXMtdmVyaWZpY2F0aW9uLWV4YW1wbGUiLCJzdWIiOiJsaWtlbHkuMjAyMC0wNy0xMCJ9.mxMsCwRUc6AtHNNjf_xjlxT4xJrwK2b1OkOvyWDmSKxJunaOBO_j9s4SCG_b3TbZn2eAPeqG8zNSu_YUzS5GYw" --hmac="2u1nHt5WWurJytFLF3xitNzM99oNrad2y4YGOL53AeY="
2020/07/16 13:59:24 Sending: {VerificationToken:eyJhbGciOiJFUzI1NiIsImtpZCI6InYxIiwidHlwIjoiSldUIn0.eyJhdWQiOiJkaWFnbm9zaXMtdmVyaWZpY2F0aW9uLWV4YW1wbGUiLCJleHAiOjE1OTUwMTk0NjEsImp0aSI6Im5BbVdJKzVnZDRuSG0wcnJiOGRGWUVwUExDdFpaK2dMOXZ5YjVCcDJIdmVHTndmeHV5ZS9rU2x2Q2NhSGovWEwrelh5K1U1L3JpdFh1SGt1eGtvc3dLam13ZlJ0ZUpRQWpqeEdYazV5cFpPeENySGM2Z1ZVZTdxdVVNZFVkRkpBIiwiaWF0IjoxNTk0OTMzMDYxLCJpc3MiOiJkaWFnbm9zaXMtdmVyaWZpY2F0aW9uLWV4YW1wbGUiLCJzdWIiOiJsaWtlbHkuMjAyMC0wNy0xMCJ9.mxMsCwRUc6AtHNNjf_xjlxT4xJrwK2b1OkOvyWDmSKxJunaOBO_j9s4SCG_b3TbZn2eAPeqG8zNSu_YUzS5GYw ExposureKeyHMAC:2u1nHt5WWurJytFLF3xitNzM99oNrad2y4YGOL53AeY=}
2020/07/16 13:59:24 Result:
{Certificate:eyJhbGciOiJFUzI1NiIsImtpZCI6InYxIiwidHlwIjoiSldUIn0.eyJyZXBvcnRUeXBlIjoibGlrZWx5Iiwic3ltcHRvbU9uc2V0SW50ZXJ2YWwiOjI2NTcyMzIsInRyaXNrIjpbXSwidGVrbWFjIjoiMnUxbkh0NVdXdXJKeXRGTEYzeGl0TnpNOTlvTnJhZDJ5NFlHT0w1M0FlWT0iLCJhdWQiOiJleHBvc3VyZS1ub3RpZmljYXRpb25zLXNlcnZlciIsImV4cCI6MTU5NDkzNDA2NCwiaWF0IjoxNTk0OTMzMTY0LCJpc3MiOiJkaWFnbm9zaXMtdmVyaWZpY2F0aW9uLWV4YW1wbGUiLCJuYmYiOjE1OTQ5MzMxNjN9.gmIzjVUNLtmGHCEybx7NXw8NjTCKDBszUHeE3hnY9u15HISjtjpH2zE_5ZXk2nlRQT9OFQnIkogO8Bz4zLbf_A Error:}

A Walkthrough of the Service

Login Create Users Issue Verification Code Verification Code Issued

Directories

Path Synopsis
cmd
add-realm
Adds a new realm.
Adds a new realm.
add-sms-config
Adds an SMS configuration to a realm.
Adds an SMS configuration to a realm.
add-users
Adds a user or enables that user if they record already exists
Adds a user or enables that user if they record already exists
adminapi
This server implements the device facing APIs for exchaning verification codes for tokens and tokens for certificates.
This server implements the device facing APIs for exchaning verification codes for tokens and tokens for certificates.
apiserver
This server implements the device facing APIs for exchaning verification codes for tokens and tokens for certificates.
This server implements the device facing APIs for exchaning verification codes for tokens and tokens for certificates.
cleanup
This server implements the database cleanup.
This server implements the database cleanup.
get-certificate
Exchanges a verification token for a verification certificate (step 2).
Exchanges a verification token for a verification certificate (step 2).
get-code
Exchanges a verification code for a verification token.
Exchanges a verification code for a verification token.
get-token
Exchanges a verification code for a verification token.
Exchanges a verification code for a verification token.
migrate
A binary for running database migrations
A binary for running database migrations
docs
pkg
api
Package api defines the JSON-RPC API between the browser and the server as well as between mobile devices and the server.
Package api defines the JSON-RPC API between the browser and the server as well as between mobile devices and the server.
clients
Package clients provides functions for invoking the APIs of the verification server
Package clients provides functions for invoking the APIs of the verification server
config
Package config defines the environment baased configuration for this project.
Package config defines the environment baased configuration for this project.
controller
Package controller defines common utilities used by web and API controllers.
Package controller defines common utilities used by web and API controllers.
controller/apikey
Package apikey contains web controllers for listing and adding API Keys.
Package apikey contains web controllers for listing and adding API Keys.
controller/certapi
Package certapi implements the token + TEK verification API.
Package certapi implements the token + TEK verification API.
controller/cleanup
Package cleanup implements periodic data deletion.
Package cleanup implements periodic data deletion.
controller/flash
Package flash implements flash messages.
Package flash implements flash messages.
controller/home
Package home defines a web controller for the home page of the verification server.
Package home defines a web controller for the home page of the verification server.
controller/index
Package index defines the controller for the index/landing page.
Package index defines the controller for the index/landing page.
controller/issueapi
Package issueapi implements the API handler for taking a code requst, assigning an OTP, saving it to the database and returning the result.
Package issueapi implements the API handler for taking a code requst, assigning an OTP, saving it to the database and returning the result.
controller/middleware
Package middleware contains application specific gin middleware functions.
Package middleware contains application specific gin middleware functions.
controller/realm
Package realm contains web controllers for selecting the effective realm.
Package realm contains web controllers for selecting the effective realm.
controller/realmadmin
Package realmadmin contains web controllers for changing realm settings.
Package realmadmin contains web controllers for changing realm settings.
controller/session
Package session contains the controller that exchanges firebase auth tokens for server side session tokens.
Package session contains the controller that exchanges firebase auth tokens for server side session tokens.
controller/user
Package user contains web controllers for listing and adding users.
Package user contains web controllers for listing and adding users.
controller/verifyapi
Package verifyapi implements the exchange of the verification code (short term token) for a long term token that can be used to get a verification certification to send to the key server.
Package verifyapi implements the exchange of the verification code (short term token) for a long term token that can be used to get a verification certification to send to the key server.
database
Package database manages database connections and ORM integration.
Package database manages database connections and ORM integration.
gcpkms
Package gcpkms implements cryptographic signing using Google Cloud Key Management Service.
Package gcpkms implements cryptographic signing using Google Cloud Key Management Service.
jsonclient
Package jsonclient is a simple JSON over HTTP Client.
Package jsonclient is a simple JSON over HTTP Client.
jwthelper
Package jwthelper implements some common methods on top of the JWT library.
Package jwthelper implements some common methods on top of the JWT library.
logging
Package logging sets up and configures logging.
Package logging sets up and configures logging.
otp
Package otp contains the implementation of the issuance of verification codes.
Package otp contains the implementation of the issuance of verification codes.
ratelimit
Package ratelimit defines common rate limiting logic and config.
Package ratelimit defines common rate limiting logic and config.
render
Package render defines rendering functionality.
Package render defines rendering functionality.
signer
Package signer defines the interface for signing.
Package signer defines the interface for signing.
sms
Package sms defines interfaces for sending SMS text messages.
Package sms defines interfaces for sending SMS text messages.
tools
e2e-test
Command line test that exercises the verification and key server, simulating a mobile device uploading TEKs.
Command line test that exercises the verification and key server, simulating a mobile device uploading TEKs.
gen-secret
Small uiliity to generate random bytes and store them as secrets in Google Secret Manager.
Small uiliity to generate random bytes and store them as secrets in Google Secret Manager.
seed
Package main provides a utility that bootstraps the initial database with users and realms.
Package main provides a utility that bootstraps the initial database with users and realms.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL