Skip to content
This repository has been archived by the owner on Apr 14, 2021. It is now read-only.

Possible forgery of Check-In QR-Codes #35

Open
rmsk2 opened this issue Apr 4, 2021 · 4 comments
Open

Possible forgery of Check-In QR-Codes #35

rmsk2 opened this issue Apr 4, 2021 · 4 comments

Comments

@rmsk2
Copy link

rmsk2 commented Apr 4, 2021

Overview

Relying only the information contained in this repository it seems to be the case that it is possible for a malicious user to generate a forged check-in QR code in such a way that the forgery is not detectable by the venue or the Luca backend. If I am correct this would allow a malicious user to successfully check into a venue without disclosing any information necessary for contact tracing.

Introduction

https://github.com/lucaapp/security-concept/blob/main/content/processes/guest_app_checkin.md describes the data which is encoded in the QR code generated by the Luca app which is intended to be scanned by the venue:

  • version (QR code protocol version)
  • device_type
  • key_id (ID of the daily keypair used for this Check-In)
  • timestamp
  • trace_id
  • enc_data
  • ephemeral_keys.public
  • verification_tag
  • checksum

where

timestamp        = UNIX timestamp rounded down to the last full minute (little endian encoding)
trace_id         = HMAC-SHA256(user_id || timestamp, tracing_secret)  # truncated to 16 bytes
ephemeral_keys   = a new secp256r1 key pair (for DLIES with the daily public key)
dh_key           = ECDH(ephemeral_keys.private, daily_keypair.public)
enc_key          = SHA256(dh_key || 0x01)  # truncated to 16 bytes
iv               = ephemeral_keys.public   # truncated to 16 bytes
enc_data         = AES-128-CTR(userId || data_secret, enc_key, iv)
verification_tag = HMAC-SHA256(timestamp || enc_data, data_authentication_key)

and the tracing_secret, the data_secret and the data_authentication key are neither known by the venue, nor by the attacker nor by the Luca backend. Additionally it is assumed that daily_keypair.public, key_id, version and device_type are public information.

Description of the attack

In order to perform the attack a maliciuous user has to generate a QR code containing the information mentioned above which is accepted by the scanning venue and the Luca backend. So let's have a look at all elements of the QR code:

version

Public information

device_type

Public information

key_id

Public information

timestamp

Public information

trace_id

For an honest user the trace_id is calculated as follows:

HMAC-SHA256(user_id || timestamp, tracing_secret)  # truncated to 16 bytes

The attacker does not know the tracing_secret but neither do the venue nor the Luca backend. This in turn means that any 16 byte random information has to be accepted by the venue and the Luca backend, because they can not verify it.

enc_data

For an honest user this value is calculated as

ephemeral_keys   = a new secp256r1 key pair (for DLIES with the daily public key)
dh_key           = ECDH(ephemeral_keys.private, daily_keypair.public)
enc_key          = SHA256(dh_key || 0x01)  # truncated to 16 bytes
iv               = ephemeral_keys.public   # truncated to 16 bytes
enc_data         = AES-128-CTR(userId || data_secret, enc_key, iv)

It has to be noted that none of the involved parties knows the data_secret but the other information can be generated by the attacker. If the attacker performs the calculations above using a random value (of correct length) for the data_secret and the user_id the results have to be accepted by the backend and the venue because neither of them holds the private daily_key and therefore can not perform the decryption operation which would be necessary in order to detect the forgery.

ephemeral_keys.public

Can be generated by the attacker.

verification_tag

For an honest user this value is caclulated as follows:

verification_tag = HMAC-SHA256(timestamp || enc_data, data_authentication_key)

For this calculation the data_authentication_key is needed. This key is not known to the attacker, the venue and the Luca backend. This again means that any random 8 (the HMAC is truncated to 8 bytes according to this documentation) byte value has to be accepted by the venue as well as the backend because they have no means to verify it.

checksum

Checksum is the SHA-256 hash truncated to 4 bytes of the previously described data and can be easily generated by an attacker.

Conclusion

If I have not missed a central piece of information an attacker can easily create a QR code which can be used to check in to a venue but is unusable for contact tracing and does not disclose the identity of the attacker.

@rmsk2
Copy link
Author

rmsk2 commented Apr 4, 2021

Here it is said that:

In the conventional Check-In process this data would now be encoded into a QR code and presented to a 
Scanner  Frontend to finish up the Check-In and upload it to the Luca Server. Instead, the Guest App re-
encrypts the generated data for the venue keypair, associates it with the scanner ID and uploads the 
finalized Check-In to the Luca Server itself.

The resulting Check-In is equivalent to a Check-In performed by the Scanner Frontend.

If there is no separate authentication process which allows the Luca backend to authenticate a legitimate app installation then the observation made in this issue also applies to a check in where the user scans a QR code provided by the venue.

@rmsk2
Copy link
Author

rmsk2 commented Apr 5, 2021

Given the Security Objectives O1, O2 and O3 it may be impossible to prevent dishonest users from creating fake check ins as described above.

@reneme
Copy link
Contributor

reneme commented Apr 7, 2021

Given the Security Objectives O1, O2 and O3 it may be impossible to prevent dishonest users from creating fake check ins as described above.

Yes, that's exactly the point: If the Luca server were able to verify your identity during check-in (i.e. that you have registered a User ID) it would contradict O2. With a different implementation strategy (i.e. handing out verifiable tokens after registration) multiple check-ins of a single user could be linked (contradicting O3).

Note, however, that it is not possible for such an adversary to generate check-ins in the name of other existing User IDs as they do not possess the user's verification_secret. Hence, the health authority would notice this forgery via the verification_tag.

@rmsk2
Copy link
Author

rmsk2 commented Apr 7, 2021

I understand that there exists a tradeoff between different goals, i.e. your security objectives and the wish to improve the quality of contact tracing Information when compared to the current situation where quite a few people give fake names on contact tracing forms.

Using the approach outlined above anyone who does not wish to be traced can continue to not being traced even when using (or being forced to use) the Luca App.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants