by Alexander Stiefel (alexander.stiefel@t-systems.com)
This document describes the component Verification Server for the System “Corona Warn App”. In the world of the Corona Warn App the Verification Server helps to validate whether upload requests from the mobile App are valid or not. This document links the overall system architecture with the software design of the Verification Server, it links user stories with implementation inside the Verification Server. This document is intended to be read by people who want to get insights how verification works in detail, it is our guideline for implementation.
The primary scope of the component is to provide a proof whether users were tested positive for SARS-CoV-2. The secondary scope is to provide information about the status of a SARS-CoV-2 test and to provide the ability for privileged users (Health Authorities) to obtain a proof document on behalf of tested users.
The Verification Server provides proof of a positive SARS-CoV-2 test to other components of the system. In addition, it also provides information about specific SARS-CoV-2 test results. The Verification Server uses several sources to provide such proof and information.
- The Corona-Warn-App is a system which requests test result status and obtains proofs.
- The Corona-Warn-App Server is a system which needs to verify proof.
- The Portal Server is a system which creates and obtains proof and therefore acts as source for proof.
- The Test Result Server is a system which acts as trusted source for proof.
Proof is represented by a Transaction Authorization Number (TAN), which is not bound to a specific transaction.
Entity | Definition |
---|---|
GUID | Identifier for a SARS-CoV-2 Test. This component will deal only with hashed instances of the GUID. For the details of the hashing see Used cryptographic algorithms. The GUID has a length of 152 bits, it consists of a prefix of 24 bits and a main part of 128 bits. Only the main part is generated by a cryptographically reliable process. |
TAN | Is a proof that the user has a SARS-CoV-2 Test with status positive. Depending on the context the TAN has a different length. Has a default length of 128 Bit. |
teleTAN | Is a subtype of TAN with reduced length and lifetime. This TAN is handed over via phone and contains only uppercase letters and numbers, excluding 0,O and I,1,L. Length of teleTAN is 9 characters, plus 1 check character. The lifetime of a teleTAN is 1h. |
SARS-CoV-2 Test | A SARS-CoV-2 Test aggregates several probes donated by a single person to verified whether they proof an infection with the SARS-CoV-2 virus or not. A SARS-CoV-2 Test can have multiple states, “positive”, “negative”, “unknown”, “erroneous” |
Registration Token | Identifies a long term session between a mobile app and the Verification Server. The Registration Token has a length of 128 Bit. |
The Verification Server handles pseudonym data, this data needs a high level of protection. The data is protected by several measures.
ID | Measure | Comment |
---|---|---|
M1 | Not persisting IP addresses anywhere in the Verification Server | |
M2 | Early deletion of data | For all entities a deletion strategy is defined |
M3 | Make sure that application logfiles do not contain any data that is personal relatable, no hashed GUID, no GUID, no test results, no Registration Tokens | |
M4 | Persist only hashed values for personal relatable data |
The Verification Server and the Corona-Warn-App Server are operated by different people and run in different namespaces in one cloud tenant. The namespaces organize access rights of people for resources.
Primary key or pseudonymous data must not be part of a logging statement, the only exception is detected abuse cases. Logfiles are kept for 30 days.
- Diagnosis Keys upload and TAN verification is executed only a defined number of times per user and test
- The whole process of verification and upload is pseudonym not anonym
- Only one single mobile device can access the test result via GUID and only this single one device is able to upload Diagnosis Keys
- User/Patient: Person, who is tested for SARS-CoV-2, is equipped with a smartphone, Corona Warn App installed
- Test Center: Facility where the user can donate a probe to be tested for SARS-CoV-2, such as hospitals or practicing doctors
- Lab: Facility which tests the probe of the user and produces a trusted test result on SARS-CoV-2.
- Verification Server: Software service which proves that a user, who is taking part in the Corona Warn App and who is willing to file his Diagnosis Keys, has been really tested positive by an established authority
- Test Result Server: Software service, that imports the SARS-CoV-2 test results provided by the Labs and stores them for further use.
- Corona Warn App Backend: Software service, which collects the Diagnosis Keys of users, proves them to be valid, i.e. they are really from an infected person and transmits them to other users who have been exposed to the user during last two weeks.
- Hotline User: user with the role “c19hotline”
- Health Authority User: user with the role “c19healthauthority”
Note: The test result may be made available to the Test result server at any point of time through step A.
Steps:
- Scan the QR Code from the document provided by the test center/doctor - defined in User Story E07.01 – Scan QR Code with mobile App
- Create a long term Registration Token
- implemented in Use Case Create Registration Token
- Generate Registration Token
- Store Registration Token in mobile App
- Polling for result, at a regular interval the mobile app uses the Registration Token to request the result of the test
- defined in User Story E06.02 – Notify user if a test result is available
- partly implemented in Use Case Get Test Result
- The Test Result Server is queried whether a test result is available, for interface definition see [Test Result Server API]
- The Test Result Server is returning the test result, if no test is available a result with state “pending” is returned
- The result is returned to the mobile App
- The mobile app will request a TAN if a positive test result becomes available and the user has confirmed the request to upload the diagnosis keys
- defined in User Story E07.04 Upload my Diagnosis Keys
- implemented in Use Case Create TAN
- A TAN is generated by the Verification Server and the TAN is stored hashed at the Verification Server
- The TAN is delivered to the mobile App
- The App obtains the Diagnosis Keys and sends them together with the TAN string to the Corona Warn App Backend
- defined in User Story E06.04 Upload my Diagnosis Keys
- The Corona Warn App Backend verifies the upload request, by verifying the TAN at the Verification Server, to avoid false positive warnings and duplicate warnings. defined in User Story E05.01 – Avoid false positive reports
- The Verification Server verifies the TAN and returns the result of the verification
- implemented in Use Case Verify TAN
- The result is returned to the Corona-Warn-App Backend
- The Corona-Warn-App Backend processes the Diagnosis Keys.
Subsequent Diagnosis Keys upload will repeat the steps 9. until 16.
This flow is for users who can not participate in the flow based on integrated Laboratories which relies on printed GUIDs.
Precondition:
- An employee of the health authority is aware that a certain user has a positive SARS-CoV-2 Test
- The specific employee has access to the web portal run by the Portal Server Steps
- Request the creation of a teleTAN via Web Interface
- defined in User Story E06.04 – Use Call Center for Verification
- implemented in Use Cases Portal Server
-
The Portal Server requests a teleTAN
-
The Verification Server generates a teleTAN implemented in Use Case Create teleTAN
-
The Portal Server receives the teleTAN
-
The Health Authority User receives the teleTAN
-
The user is called via phone and the teleTAN is provided in case the user has the app installed on his/her phone
-
The user enters the teleTAN in the mobile app
-
The app requests a RegistrationToken based on the teleTAN
-
The RegistrationToken is generated by the Verification Server
- implemented in Use Case Create RegistrationKey based on teleTAN
- The Registration Token is returned to the mobile app
Steps 11. until 17. are the same as steps 9. until 16. in the other TAN user journey. Subsequent Diagnosis Keys upload will repeat the steps 11. until 17.
The implementation of user stories around verification involves several components, this chapter documents the mapping between Verification User Stories and Verification Server Use Cases. The user stories are detailed in [Scoping].
Implemented by
- Use Case Verify TAN
Implemented by
- Use Case Create Registration Token
Implemented by
- Use Case Get Test Result
In Verification Sever implemented by
- Use Case Create TAN
- Use Case Verify TAN
In Verification Sever implemented by
- Use Case Create teleTAN
In Verification Sever implemented by
- Use Case Create TAN based on teleTAN
In Verification Sever implemented by
- Use Case Create TAN
- Use Case Verify TAN
- Use Case Create TAN based on teleTAN
API Endpoint:
- Method: POST /testresult
- Body: { “registrationToken”: “<< registrationToken >>” }
- Authentication: none
Steps:
- Verify whether the provided RegistrationToken exists, if not exit with error HTTP 400
- Obtain hashed GUID by RegistrationToken
- Get Test status from Test Result Server
- Return Result of API Call
It is important to note, that only one Registration Token will be generated for a specific GUID or teleTAN. The use case generates Registration Tokens from hashed GUIDs xor teleTANs. This is a measure to increase data privacy.
API Endpoint:
- Method: POST /registrationToken Body: { "key": "<< key >>", "keyType": “teleTAN||hashedGUID” }
- Authentication: none
Steps
- Verify whether a registration token with the provided GUID or teleTAN already exists, if yes return error
- If a teleTAN is used for creation, verify teleTAN.
- If verification fails, return HTTP 400
- Create Registration Token
- Store entity AppSession, with hashed Registration Token. If available store hashed GUID, if available store hashed teleTAN. Mark AppSession.sourceOfTrust
- Return Registration Token.sourceOfTrust depending on which source (hashed GUID or teleTAN) was provided
- If teleTAN was provided mark teleTAN as redeemed
The use case creates a TAN. Only a specific number of TANs can be generated for a specific Registration Token, as of writing only 2 TANs can be generated.
API Endpoint:
- Method: POST /tan
- Body: { “registrationToken”: “<< registrationToken >>” }
- Authentication: none
- Verify registration token, if registration token is invalid, exit with error HTTP 400
- Verify whether the entity AppSession exists for the registration token
- If yes, check if TANcounter >= 1
- If yes, return error HTTP 400
- If no, return error HTTP 400
- If yes, check if TANcounter >= 1
- If AppSession.sourceOfTrust == “hashedGUID”
- Get test result from Test Result Sever
- Verify whether test result is positive, otherwise exit with error HTTP 400
- Generate TAN
- Generate random TAN
- Check collision with existing TANs, if yes regenerate
- Set source of trust accordingly
- Persist TAN as entity TAN
- Update entity AppSession, increment TAN counter
- Return TAN string
API Endpoint:
- Method: POST /tan/teletan
- Body: empty
- Authentication: JWT, in header, verified by cryptographic signature
- Authorization: JWT, the roles attribute contains one of the roles
- "c19hotline”
- “c19healthauthority”
- Authenticate using mTLS
- Authenticate using JWT
- Execute Use Case Rate limit requests for teleTAN creation
- Generate teleTAN (see also used cryptographic algorithms)
- use configured valid chars and configured length
- calculate check sum and append it
- persist teleTAN
- return teleTAN
API Endpoint:
- Method: POST /tan/verify
- Body: { “tan”: “<< tan >>” }
- Authentication: Client Certificate, IP range
- Verify parameter TAN for syntax constraints
- Obtain entity TAN by provided tan string
- If entity TAN does not exist, exit with error HTTP 404
- If entity TAN.redeemed is true exit with error HTTP 404
- If current time is not between entity TAN.vaildFrom and TAN.validUntil, exit with error HTTP 404
- Delete TAN
Steps:
- Delete all entities TAN older than the defined max age
- Delete all entities AppSession older than the defined max age
API Endpoint:
- Method: POST /tan Body: { "key": "<< key >>", "keyType": “teleTAN||Token” }
- Authentication: none Steps
- Verify teleTAN i. If validation fails return HTTP 400
- Generate TAN
- Mark teleTAN as redeemed
- Return teleTAN with HTTP 201
To limit the damage in case an authorized client for teleTAN creation was compromised, the number of teleTANs created per time frame is limited. The limit for the component is global and applies to all users of the API endpoint for teleTAN creation. The limit and the time window are configurable.
In addition, a specific warning message is logged when the number of created teleTANs is above 80% of the limit.
The use case is part of the teleTAN creation use case.
Steps
- Count the number of created teleTAN in the current time window
- If the number of created teleTANs is above 80% of the threshold log a specific warning message
- If the number of created teleTANs is above the threshold return http 429
Based on configuration the component must be able to switch between an internal and external mode. External mode means that only the designated public available endpoints of the API are active and the internal ones (create teleTAN, verify TAN) are not active.
To allow a client to implement Plausible Deniablity for being positivly tested the service needs to fullfill two changes acroos all API endpoints which are called by the mobile app. The use case takes the perspective of an attacking user which watches network traffic with regards to request/response size and timing.
Requirements:
- all response sizes must be equal
- response times must be similar for a time window
- allowing to execute fake requests which do not change state
Implementing those requirements makes it impossible to distinguish between "real" requests and "fake" requests and between calls to different REST endpoints.
API Endpoint:
- all Endpoints used by the app are affected
- adding a request header "cwa-fake", setting it to "1" indicates a fake request, the header is optional.
- adding an attribute "responsePadding" to the JSON response which is used to fill up the result to the fixed "equal" size
The API is REST based and the description below, is detailed by the implementation. The API endpoint provides a swagger definition. The API does not support versioning as part of the URI.
- Spring Boot
- PostgreSQL
The data model is persisted in a dedicated schema.
The entity TAN represents the authorization (sometimes referred as “proof”) that a user was SARS-CoV-2 positive tested.
Name | Not null | Type | Definition |
---|---|---|---|
(PK) TANHash | Y | String[64] | Hashed unique value of a TAN. |
validFrom | Y | Date | Timestamp when the TAN is starting to be valid |
validUntil | Y | Date | Timestamp when the TAN expires |
sourceOfTrust | Y | String [“connectedLab”, "teleTAN"] | Defines the type of the TAN |
Type | Y | String [“TAN”, “teleTAN”] | Indicates whether this tan is teleTAN or normal TAN |
createdOn | Y | Date | Date of creation |
All data is deleted after 21 days.
The entity AppSession is a hashed GUID which was used in processing to generate a TAN. The entity basically marks a GUID hash as “used”.
Name | Not null | Type | Definition |
---|---|---|---|
GUIDHash | String[64] | The hashed GUID. | |
teleTANHash | String[64] | The hashed teleTAN. | |
RegistrationTokenHash | Y | String[64] | Hash of the Registration Token. |
TANcounter | Y | Int | Contains the number of TANs generated in the session |
sourceOfTrust | Y | String [“hashedGUID”, “teleTAN”] | Defines the type of the Session |
createdON | Y | Date | Date of creation |
All data is deleted after 14 days.
Role | Authentication | Comment |
---|---|---|
Anonymous | None | the app uses no authentication for communication with Verification Server |
Corona Warn App Server | TLS Client Certificate, 2nd factor IP Range | |
Health Authority User | Signed JWT, verification of signature | |
Hotline User | Signed JWT, verification of signature |
Role | Authorization | Comment |
---|---|---|
Anonymous | None | the app uses no authorization for communication with Verification Server |
Corona Warn App Backend User | Implicit authorization | a user which is authenticated as Corona Warn App Backend User is authorized as Corona Warn App Backend User |
Health Authority User | Signed JWT, verification of signature | Signature contains role “c19healthauthority” |
Hotline User | Signed JWT | verification of signature “c19hotline” |
This chapter is still in work.
Based on STRIDE threat modelling, the threats below are anticipated:
ID | Category | Name | Definition |
---|---|---|---|
T1 | Brute Force | Brute Force teleTAN | Try to guess a teleTAN via brute force attack. |
T2 | DDoS Attack | The API is attacked by a high number of requests, leading to an outage of the service | |
T3 | Code injection | The payload and/or header contain code which is executed | |
T4 | |||
T5 | Brute force attack | By a brute force attack a client wants to guess a valid GUID to create a valid TAN | |
T6 | Steal secrets from logs |
Categories follow STRIDE:
- Spoofing
- Tampering
- Repudiation
- Information disclosure (privacy breach or data leak)
- Denial of service
- Elevation of privilege
ID | Threat | Name | Definition |
---|---|---|---|
MT1 | OTC DDoD Protection Infrastructure Level | ||
MT2 | Strong input parameter verification, with 100% code coverage and very high amount of testing | ||
MT3 | Enforcing TLS 1.2 and above | ||
MT6 | T2 | Use Open Telekom Cloud Anti-DDoS | |
MT7 | T3 | Strict validation of http headers, body content | |
MT9 | T5 | Use Throttling @ Code Level in API implementation to reduce the possible frequency of guessing attempts | |
MT10 | T5 | Detect unusual load scenario and trigger warning for operation | |
MT11 | T6 | Use only POST requests to avoid logging of secrets at infrastructure components | |
MT12 | Strict input validation, all REST input parameter are validated in a strict manner |
- Hashing of GUID: SHA-256, no salt, no pepper
- Hashing of Registration Token: SHA-256, no salt, no pepper
- Hashing of TAN: SHA-256, no salt, no pepper
- Creating of Registration Token: the JAVA UUID generation (UUID.randomUUID()) is used, which relies on Java SecureRandom (see https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/security/SecureRandom.html ) is used. this random is considered as cryptographically strong random number generator
- Creating of TAN: the JAVA UUID generation (UUID.randomUUID()) is used, which relies on Java SecureRandom (see https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/security/SecureRandom.html ) is used. this random is considered as cryptographically strong random number generator
- Creating of teleTAN: string of random chars, as random java SecureRandom (see https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/security/SecureRandom.html ) is used. this random is considered as cryptographically strong random number generator
- TAN: 128 bits
- Registration Token: 128 bits
- teleTAN: 44 bits (31 characters, length of 9)
TAN
- Lifespan of TAN is configured to 14 days
teleTAN
- Lifespan of teleTAN is configured to 1h