opendi4vp-offline | November 2024 | |
Yasuda, et al. | Standards Track | [Page] |
This document defines how Bluetooth Low Energy (BLE) can be used to request the presentation of verifiable credentials. It uses the request and response syntax as defined in [OpenID4VP].¶
This document enables Wallets and the Verifiers who have implemented [OpenID4VP] to request and receive verifiable presentations even if one or both of the entities do not have Internet connection by utilizing Bluetooth Low Energy (BLE). This document uses request and response syntax as defined in [OpenID4VP].¶
This draft uses the terms and definitions from [OpenID4VP], section 2.¶
The user needs to present her electronic ticket (represented by a verifiable credentioal) when entering a venue. She opens her wallet and authenticates towards the wallet. She then scans the QR code at the entrance with her wallet. The wallet determines the credential (the ticket) required by the verifier and asks for consent to share the respective credential. The credential is then transmitted to the verifier, which, after validation, allows her to enter the venue, e.g. by opening the turnstile.¶
This specification supports deployments, where the Verifier or the Wallet or both parties do not have an Internet connection or where use of an Internet connection is not desired to request and present Verifiable Credentials.¶
The protocol consists of the following steps:¶
Wallet and the Verifier MUST implement BLE according to the [Bluetooth.4.2.Core] specification.¶
The following limitations in BLE stack 4.2 need to be considerate:¶
Below is the diagram that illustrates the protocol flow:¶
Note: The arrow mark indicates a read or write by the wallet.¶
First, Verifier and the Wallet need to establish the connection. This specification defines two mechanisms to do so: BLE Advertisement initiated by the Verifier and QR code displayed by the Verifier.¶
Wallet and the Verifier MUST support LE Data Packet Length Extension according to [Bluetooth.4.2.Core] section 4.5.10.¶
Speaking in BLE terms, the Verifier takes the role of the "Peripheral GAP Role" whereas the Wallet takes the "Central GAP Role", i.e. the Verifier advertises the OpenID 4 VP service and the Wallet drives the protocol flow by reading data from and writing data to the Verifier.¶
This section describes how Verifier and the Wallet can establish a connection using Verifier-initiated BLE Advertisement. This mechanism can be used by the Verifiers when the use-case does not allow the End-Users to scan a QR code displayed on the Verifier's device, for example to ensure the safety of the Verifier.¶
The Verifier acts as the BLE server and the Verifier service MUST contain the following characteristics:¶
Verifier Service UUID MUST be 00000001-5026-444A-9E0E-D6F2450F3A77
.¶
Verifier Service UUID for SCAN_RESP MUST be 00000002-5026-444A-9E0E-D6F2450F3A77
.¶
Note: The special service UUID for the SCAN_RESP
is used to ensure support for iOS.¶
The following figure shows the message exchange.¶
+------------+ +-----------+ | |-----PDU ADV_IND------>| | | Advertiser |<----SCAN_REQ----------| Scanner | | (Verifier) |-----SCAN_RESP-------->| (Wallet) | | |<----IDENTIFY_REQ------| | +------------+ +-----------+¶
Pre-requisites: The Verifier has opened it's application and started the mode that accepts OpenID4VP.¶
PDU ADV_IND
) using the service UUID 00000001-5026-444A-9E0E-D6F2450F3A77
. The advertisment message starts with the prefix OVP
(see below) and includes the first 5 bytes of the verifier's ephemeral key.¶
SCAN_REQ
to the Verifier acknowledging the advertisment. If there is only a single Verifier sending an advertisment message with the OVP
prefix, the Wallet may automatically select this Verifier. Otherwise, if there are multiple verifiers the user is asked to choose.¶
SCAN_REQ
, the verifier sends a SCAN_RESP
to the particular Wallet using the service UUID 00000002-5026-444A-9E0E-D6F2450F3A77
. This request contains the remaining 27 byte of the Verifier's ephemeral key.¶
IDENTIFY_REQ
, see Section 5.3) and submits its public key to the verifier in plain text. The Verifier calculates the DHE secret key based on its key pair and the wallet's public key as described in Section 6.1.¶
Note: While the Verifier can be active for a long time and process multiple connections (based on the same Verifier key), it's expected that the range of the verifiers advertisement is limited based on the application's requirement. Verifiers are expected to provide the necessary controls to limit the range.¶
BLE Advertisement Packet structure is defined as follows:¶
PDU: Header: PDU type: ADV_IND Tx Address: Random Rx Address: Random Payload: (25 bytes) Adv Address: Random address Adv Data: (17 byte) Adv Type: Complete Local Name flag: "LE General Discoverable Mode", "BR/EDR Not Supported" Data: OVPSTADONENTRY_8520f00989 (3 character + 11 character identifier name + 5 bytes of the random X25519 public key)¶
The data in the Advertisement Packet contain the prefix OVP
indicating that the verifier is ready to accept connections for OpenID 4 VPs. A human readable name of the verifier is given in the next part. The rest of the data packet after the _
contains the first 5 bytes of the public key (example: `8520f00989´). (max. available size for data as defined by BLE is 20 byte).¶
The Scan Response (SCAN_RESP
) structure is defined as follows:¶
Payload: (31 bytes) Adv Address: Random address Adv Data: (31 byte) Data: 30a754748b7ddcb43ef75a0dbf3a0d26381af4eba4a98eaa9b4e6a¶
It provides the Wallet with the remaining 27 byte of the Verifier's ephemeral key.¶
This section describes how Verifier and the Wallet can establish a connection using a QR Code displayed by the Verifier.¶
The following figure shows the message exchange.¶
+------------+ +-----------+ | |-----PDU ADV_IND------>| | | Advertiser |<----Scan_QR_Code------| Scanner | | (Verifier) | | (Wallet) | | |<----IDENTIFY_REQ------| | +------------+ +-----------+¶
Pre-requisites: The Verifier has opened it's application and displays a QR Code.¶
Scan_QR_Code
) using the wallet app. The QR Code contains the name and the ephemeral public key of the Verifier. A non-normative example is shown below.¶
OPENID4VP://connect?name=STADONENTRY&key=8520f0098930a754748b7ddcb43ef75a0dbf3a0d26381af4eba4a98eaa9b4e6a¶
IDENTIFY_REQ
) and submits its public key to the verifier in plain text (see Section 5.3).¶
The URL in the QR Code starts with the custom scheme OPENID4VP
and the path is set to connect
. The URL contains the following URI query parameters:¶
name
: REQUIRED. A String containing the name of the verifier.¶
key
: REQUIRED. A String containing the Verifier's ephemeral public key in hex encoding (as defined in Section 5 of [RFC4648]).¶
A Custom URL scheme is used to enable activation of a Wallet of the End-User's choice thats capable of handling the request even if the QR Code is scanned with a camera app.¶
This request is sent by the Wallet to the Verifier to finalize the connection establishment.¶
The Verifier's UUID service MUST be 00000006-5026-444A-9E0E-D6F2450F3A77
.¶
The request carries the following parameters:¶
To calculate the session keys, the Wallet and the Verifier MUST perform ECKA-DH (Elliptic Curve Key Agreement Algorithm – Diffie-Hellman) as defined in BSI TR-03111. The Zab
output defined in BSI TR-03111 MUST be used to derive two keys.¶
The Verifier MUST derive its session key using HKDF as defined in [RFC5869] with the following parameters:¶
The Wallet MUST derive its session key using HKDF as defined in [RFC5869] with the following parameters:¶
For encryption AES-256-GCM (192) (GCM: Galois Counter Mode) as defined in NIST SP 800-38D or ChaCha20 [RFC8439] MUST be used.¶
The IV (Initialization Vector defined in NIST SP 800-38D) used for encryption MUST have the default length of 12 bytes for GCM, as specified in NIST SP 800-38D. The IV is the random nonce generated by the wallet provided in the Identify Request (see Section 5.3).¶
The encryption of the data happens before any of the request size or response size is provided. So the entire data is encrypted with AES GCM 256 bit using the derived session keys. Due to this requirement there is no message counter requirement in this design. Also because of the fact that every wallet would send a random nonce and a random ephemeral public key, it is assumed the interaction is also safe with a long term verifier key. This gives us with more probability of randomness in key derivation.¶
The AAD (Additional Authenticated Data defined in NIST SP 800-38D) used as input for the GCM function MUST be an empty string. The plaintext used as input for the GCM function MUST be Wallet request or Wallet response. The value of the data element in the session establishment and session data messages as defined in 9.1.1.4 MUST be the concatenation of the ciphertext and all 16 bytes of the authentication tag (ciphertext || authentication tag).¶
The protocol uses variable length messages to convey the presentation request and the presentation response. The design for those message exchanges uses the following pattern:¶
For every of those requests/responses, there is one dedicated characterics to obtain the messages size, e.g. for the presentation request, this is the characteristics with the service UUID 00000004-5026-444A-9E0E-D6F2450F3A77
.¶
The transmission of the actual payload is performed through another dedicated characteristics. For the presentation request, that is the service UUID 00000005-5026-444A-9E0E-D6F2450F3A77
. Depending on the MTU size, the sender splits the message into chucks and uses the transmission characteristics multiple times to transfer the chunks.
QUESTION: is there an acknowledgment, if the receiver received the data or how does the sender know when to send the next chunk?¶
In order to detect packet loss, the sender requests a transfer summary report from the receiver after it has concluded the transmission. The transfer summary always uses the same Service UUIDs:¶
Characteristic name | UUID | Type | Description |
---|---|---|---|
Transfer Summary Request | 00000009-5026-444A-9E0E-D6F2450F3A77 | Write(Wallet->Verifier) | Summary of the packets received |
Transfer Summary Report | 0000000A-5026-444A-9E0E-D6F2450F3A77 | Notify(Verifier->Wallet) | Summary of the packets received |
Note: Verifier and Wallet may have different roles with respect to the transfer summary report characteristics depending on the direction of the data flow.¶
The JSON payload is encoded using JWS Compact serialization. The request size is the number of bytes that will be sent over BLE, the size of (JWS) in bytes.¶
The actual content of the message can be a gzip [RFC1952]. In this case the size transmitted is the number of bytes of the gzip. Use the ID2 as per [RFC1952] to determine the gzip format.¶
The Request Size
characteristics is used to convey the request size.¶
Once the size of the request is obtained, the Request
characteristic is called to get the actual data. The characteristics is called repeatedly until all the requested data is received.¶
To read the complete Characteristic Value an ATT_READ_REQ PDU should be used for the first part of the value and ATT_READ_BLOB_REQ PDUs shall be used for the rest. The Value Offset parameter of each ATT_READ_BLOB_REQ PDU shall be set to the offset of the next octet within the Characteristic Value that has yet to be read. The ATT_READ_BLOB_REQ PDU is repeated until the ATT_READ_BLOB_RSP PDU’s Part Attribute Value parameter is shorter than (ATT_MTU – 1).¶
NOTE: In case the Request does not match the size then it is assumed it is corrupted and the same procedure is repeated again.¶
Using the 'Content Size' characteristics the wallet sets the size. Once it receives the confirmation about the write, the wallet starts the 'Submit VC' as a stream. 'Submit VC' is called multiple times until all the data is sent.¶
Chunk sequence no | Chunk payload | Checksum value of data |
---|---|---|
(2 bytes) | (upto MTU-4 bytes - 2 bytes) | (2 bytes) |
Chunk Sequence No: Running unsigned counter for the chunk and starts with 1 (Max 65535)¶
Chunk Payload: Chunk data.¶
Checksum: 2 bytes CRC16-CCITT-False (unsigned)¶
NOTE: Limit the max total size to ~4kb
for better performance while the protocol can handle larger size. In case the Request does not match Size then its assumed to be corrupted and the wallet is expected to send the requested chunks based on the Transfer Summary Request
.¶
In case of the CRC failure or decryption failure the Transfer summary report
would be used to resend the specifc chunks¶
The wallet would request for a Transfer Summary Request
once all the chunks are sent by the wallet. This is a write operation from the wallet.¶
When the Verifier receives the Transfer Summary Request
, the verifier MUST respond with the Transfer Summary Report
. This is a notification.¶
The following structure is used to send the summary report.¶
Chunk sequence number | Checksum |
---|---|
(2 byte each upto max MTU) | (2 bytes) |
** Chunk sequence number: ** List of chunks that are missing or failed CRC.¶
On the BLE layer, the transmission of the payload is performed as described in Section 6.2, where the following characteristics are used:¶
00000004-5026-444A-9E0E-D6F2450F3A77
: to obtain the size of the presentation request (calculation see Section 6.2.1).¶
00000005-5026-444A-9E0E-D6F2450F3A77
: to obtain the actual JSON payload constituting the presentation request.¶
The Request contains a signed request object containing the parameters as defined in [OpenID4VP].¶
The following request parameters are supported by this specification:¶
iss
: REQUIRED. MUST contain the verifier's client_id.¶
presentation_definition
: CONDITIONAL. contains the verifier's requirements regarding verifiable credentials it wants to obtain from the wallet.
MUST not be present if a 'scope' parameter is present.¶
scope
: CONDITIONAL. The scope value MUST represent a credential presentation request. This parameter MUST NOT be present if a presentation_definition
parameter is present.¶
nonce
: REQUIRED. This value is used to securely bind the verifiable presentation(s) provided by the wallet to the particular transaction.¶
aud
: OPTIONAL. This value identifies the wallet issuer (as intended recipient of the presentation request).¶
The parameters response_type
and redirect_uri
MUST NOT be present in the request.¶
The following is a non normative example of a request before signing:¶
{ "iss":"s6BhdRkqt3", "aud":"https://wallet.example.com", "nonce":"n-0S6_WzA2Mj", "presentation_definition":{ "id":"example", "input_descriptors":[ { "id":"id_credential", "format":{ "jwt_vc":{ "proof_type":[ "JsonWebSignature2020" ] } }, "constraints":{ "fields":[ { "path":[ "$.vc.type" ], "filter":{ "type":"array", "contains":{ "const":"IDCredential" } } } ] } } ] } }¶
On the BLE layer, the transmission of the payload is performed as described in Section 6.2, where the following characteristics are used:¶
The response contains the parameters as defined in Section 6 of [!@OpenID4VP] in JSON encoding.¶
The following is a non normative example of a response before signing:¶
{ "presentation_submission":{ "definition_id":"example", "id":"id_credential", "descriptor_map":[ { "id":"id_credential", "path":"$", "format":"jwt_vp", "path_nested":{ "path":"$.vp.verifiableCredential[0]", "format":"jwt_vc" } } ] }, "vp_token":"eyJhbGciOiJFUzI...XK9n2861OaHDQ" }¶
The Wallet will disconnect after providing a presentation response to the Verifier. The Verifier cannot disconnect but only timeout.¶
After data retrieval, the Wallet unsubscribes from all characteristics. Most often this is the default flow. While in certain cases the Verifier may choose to cancel in the middle of a transaction. This can be achieved by the Disconnect
. Whenever the wallet receives this notification the wallet is expected to initiate the disconnection.¶
The session MUST be terminated if at least one of the following conditions occur:¶
Termination is as per the default BLE write.¶
In case of a termination, the Wallet and Verifier MUST perform at least the following actions:¶
In case of a lost connection a full flow is conducted again.¶
The Verifier acts as the server and the Verifier service MUST contain the following characteristics:¶
Verifier Service UUID MUST be 00000001-5026-444A-9E0E-D6F2450F3A77
.¶
Verifier Service UUID for SCAN_RESP MUST be 00000002-5026-444A-9E0E-D6F2450F3A77
.¶
Characteristic name | UUID | Type | Description |
---|---|---|---|
Request Size | 00000004-5026-444A-9E0E-D6F2450F3A77 | Read(Wallet->Verifier) | Get the request size |
Request | 00000005-5026-444A-9E0E-D6F2450F3A77 | Read(Wallet->Verifier) | Get the request JSON |
Identify | 00000006-5026-444A-9E0E-D6F2450F3A77 | Write(Wallet->Verifier) | Wallet identifies as chunks |
Content Size | 00000007-5026-444A-9E0E-D6F2450F3A77 | Write(Wallet->Verifier) | Submit the content size |
Submit VC | 00000008-5026-444A-9E0E-D6F2450F3A77 | Write(Wallet->Verifier) | VC stream as chunks |
Transfer Summary Request | 00000009-5026-444A-9E0E-D6F2450F3A77 | Write(Wallet->Verifier) | Summary of the packets received |
Transfer Summary Report | 0000000A-5026-444A-9E0E-D6F2450F3A77 | Notify(Verifier->Wallet) | Summary of the packets received |
Disconnect | 0000000B-5026-444A-9E0E-D6F2450F3A77 | Notify(Verifier->Wallet) | In case verifier wants to disconnect due to unforseen error |
Both wallet and the Verifier MUST remove all the information about the session after its termination.¶
How does the wallet authenticate the Verifier? The verifier signs the presentation request.¶
How does the Verifier know a particular response is tied to a particular request? It evaluates the nonce and aud value of the presentation to match the nonce of the request and its client id.¶
[[ To be removed from the final specification ]]¶
-00¶