Appearance
WebSocket API v2
The WebSocket API enables live eMRTD verification with full security coverage:
- Parse the files (e.g. MRZ Info, Face Photo, ...).
- Verify the authenticity and integrity of the files (Passive Authentication).
- Detect cloned chips via Active Authentication and Chip Authentication.
The eMRTD Connector Android / eMRTD Connector iOS handle the WebSocket communication with the DocVal Server automatically.
Protocol Reference
This section describes the internal communication protocol between mobile applications and the DocVal Server. Typically, you do not need to understand this protocol to use the DocVal Server. However, being familiar with it may provide a deeper understanding of how the DocVal Server operates under the hood.
WebSocket Endpoint
Clients connect to the DocVal Server via:
wss://<server-host>/ws2/validateBy default, the DocVal Server only posts the final verification result to the configured Result Server, ensuring no sensitive eMRTD data is stored on the DocVal Server. If the client wishes to receive the finalized result as well, it must indicate this via the FINISH message (see below).
General Concept
The goal is to read an eMRTD chip as fast and securely as possible. Most of the chip access takes place locally on the client device. However, certain critical tasks (e.g., generating an Active Authentication challenge, performing Chip Authentication, and doing Passive Authentication checks) happen on the server, because the client device is not fully trusted.
On iOS, the NFC connection has a timeout (around 20 seconds), so the protocol is designed to minimize server round-trips during the NFC session. Hence, most interactions with the server occur before or after the short NFC session.
At a high level, the communication flow is:
WebSocket Connection The client opens a WebSocket connection.
Start The client sends a
STARTmessage, which includes identification and other fields.Accept The server responds with an
ACCEPTmessage containing an Active Authentication challenge.NFC Session and Data Reading
- The client opens the NFC connection to the chip.
- The client reads initial data (e.g., SOD, DG14) and may hand over Chip Authentication to the server (
CA_HANDOVER). - After the server completes Chip Authentication, it returns
CA_HANDBACK.
Complete Reading The client finishes reading the chip, closes NFC, and then sends
FINISH.Server Authentication Checks The server finalizes Passive Authentication and any other verifications.
Result
- The server posts the final passport result to the configured Result Server.
- The server will retry up to 3 times (with 3-second timeout per attempt) if the POST fails due to network/connection errors.
- HTTP error responses other than 408, 429, and 5xx are not retried.
- If the client requested it, the server also sends
RESULTback over the WebSocket.
- The server posts the final passport result to the configured Result Server.
Close The server sends a
CLOSEmessage or closes the WebSocket with the appropriate code and reason.
Active Authentication
Active Authentication (AA) ensures that an eMRTD chip is not cloned. It relies on a cryptographic challenge–response approach that proves the chip holds a private key which cannot be read or extracted from the chip. The flow is as follows:
- The server creates an 8-byte random challenge and sends it to the client in the
ACCEPTmessage. - During the NFC session, the client provides this challenge to the eMRTD chip. The chip signs the challenge using its internal private key.
- The client includes the signature it in the
FINISHmessage sent to the server. The server verifies the signature against the chip's public key.
Chip Authentication
Chip Authentication (CA) ensures that an eMRTD chip is not cloned by confirming it holds a private key known only to the chip. It uses a Diffie-Hellman key exchange to establish new secure messaging keys, then checks whether the chip can successfully communicate using those keys. The client device is considered untrusted, so the server must perform the critical CA steps.
The sequence in this protocol is:
- The client establishes NFC communication with the chip (e.g., performing Access Control) and reads Data Group 14 (
dg14), which contains security information for CA. - The client sends
dg14to the server in a binaryFILEmessage, then follows up with aCA_HANDOVERtext message, handing control of the CA process to the server. - The server generates an ephemeral Diffie-Hellman key pair and orchestrates the key exchange with the chip by sending
APDUmessages (binary) to the client, which the client relays to the chip. - The server confirms the chip can use the newly established secure messaging keys by reading Data Group 1 (
dg1). A successful read indicates that the chip holds the correct private key and is not a clone. - After verifying the chip's authenticity, the server returns
dg1in aFILEmessage and then sends aCA_HANDBACKtext message containing the newSecureMessagingInfo. This allows the client to resume reading the remaining data groups under secure messaging.
Text Messages
All text messages are sent over the WebSocket as UTF-8 JSON objects. Each message includes a type field and may contain additional message-specific fields. An example structure is:
json
{
"type": "<MESSAGE_TYPE>"
// other message-specific fields...
}Below is a description of each message type.
START (Client → Server)
The client starts the protocol by sending a START message.
| Field | Type | Description |
|---|---|---|
validationId | string | Unique identifier used to map the result to a user or session. |
clientId | string | API access key identifying the client, and used to determine the target result server. |
platform | string | Platform identifier (e.g., "android", ios). |
nfcAdapterSupportsExtendedLength | boolean | Indicates if the NFC adapter supports extended-length APDUs. |
enableDiagnostics | boolean | If true, the DocVal Server collects additional debugging information (useful for troubleshooting). |
Example
json
{
"type": "START",
"validationId": "cf847daa-a548-4509-bdeb-4edd51aee448",
"clientId": "YOUR CLIENT ID",
"platform": "android",
"nfcAdapterSupportsExtendedLength": true,
"enableDiagnostics": true
}ACCEPT (Server → Client)
Response to the START message.
| Field | Type | Description |
|---|---|---|
activeAuthenticationChallenge | string | Base64-encoded 8-byte challenge used for Active Authentication. |
Example
json
{
"type": "ACCEPT",
"activeAuthenticationChallenge": "BK69zyH/nsA="
}CA_HANDOVER (Client → Server)
Indicates that the client is handing over Chip Authentication to the server.
| Field | Type | Description |
|---|---|---|
maxTransceiveLengthForSecureMessaging | int | The maximum supported APDU length (bytes) for secure messaging. |
maxBlockSize | int | Maximum data block size that can be handled. |
secureMessagingInfo | SecureMessagingInfo | Information required for secure messaging. |
The structure for secureMessagingInfo is described below.
Example
json
{
"type": "CA_HANDOVER",
"maxTransceiveLengthForSecureMessaging": 1534,
"maxBlockSize": 4096,
"secureMessagingInfo": {
// ...
}
}CA_HANDBACK (Server → Client)
Sent by the server after completing Chip Authentication.
| Field | Type | Description |
|---|---|---|
checkResult | string | CA Result: SUCCESS, FAILED, or UNAVAILABLE |
secureMessagingInfo | SecureMessagingInfo | New secure messaging information. |
Example
json
{
"type": "CA_HANDBACK",
"checkResult": "SUCCESS",
"secureMessagingInfo": {
// ...
}
}FINISH (Client → Server)
Sent by the client to indicate that it has finished reading the eMRTD chip and has transmitted all required files.
| Field | Type | Description |
|---|---|---|
sendResult | boolean | If true, the client requests the server to also return the final result that is also sent to the result server. |
activeAuthenticationSignature | string | null | Base64-encoded signature for the challenge received in the ACCEPT message (i.e., the solved challenge). |
Example
json
{
"type": "FINISH",
"sendResult": true
}RESULT (Server → Client)
Returned by the server if sendResult in the FINISH message was true. Contains the final passport data.
| Field | Type | Description |
|---|---|---|
passport | object | The same JSON that is sent to the result server. |
Example
json
{
"type": "RESULT",
"passport": {
// ...
}
}MONITORING (Client → Server)
Can be used by the client to send monitoring messages that are then logged by the DocVal Server. Used during diagnostic sessions.
| Field | Type | Description |
|---|---|---|
message | string | The message to log. |
Example
json
{
"type": "MONITORING",
"message": "Starting PACE protocol with CAN"
}CLOSE (Server → Client)
Indicates that the server is about to close the WebSocket connection.
| Field | Type | Description |
|---|---|---|
code | int | The WebSocket close code. |
reason | string | A textual reason for the closure. |
Example
json
{
"type": "CLOSE",
"code": 1008,
"reason": "INVALID_START_MESSAGE"
}SecureMessagingInfo Object
The SecureMessagingInfo object contains data needed for performing secure messaging with the eMRTD chip. The fields are:
| Field | Type | Description |
|---|---|---|
algorithm | string | AES or DESede. |
encKey | string | Base64-encoded private encryption key. |
macKey | string | Base64-encoded private MAC key. |
ssc | int | The send sequence counter (SSC). |
json
{
"algorithm": "AES",
"encKey": "",
"macKey": "",
"ssc": 5
}Binary Messages
All binary messages have a 1-byte type identifier, followed by message type–specific data.
FILE Message
Used by both the client and the server to exchange binary files such as the SOD file or data groups (DG1, DG2, etc.).
| Field | Size |
|---|---|
| Type | 1 B |
| Name Len | 1 B |
| Name | var |
| Data | var |
- Type: Always
0x01for file messages. - Name Length: A single byte indicating the length of the file name (0–255).
- Name: UTF-8–encoded file name, matching the length stated.
- Data: The binary content of the file.
Common file names in this protocol include:
sodfor the SOD file.dg<number>for data groups (e.g.,dg1,dg2, etc.).
APDU Message (Type: 0x02)
Used for sending and receiving APDU commands and responses. The server typically sends an APDU command, which the client forwards to the chip. The client then sends back an APDU response.
| Field | Size |
|---|---|
| Type | 1 B |
| Data | var |
- Type: Always
0x02for APDU messages. - Data: The raw data to be sent to the chip or received from the chip
Connection Closure and Errors
After the process completes successfully, the server closes the WebSocket connection with code 1000 (Normal Closure). If an error occurs, the server closes the connection with a suitable RFC6455 close code and an error reason phrase.
iOS 13 & 14 Quirk
On iOS 13 and 14, an issue exists in the native URLSessionWebSocketTask where the standard close delegate is not reliably called. To ensure the client receives closure information, the server also sends a CLOSE text message (with type = "CLOSE") containing the code and reason just before closing.
Possible Error Reasons
Below are common close-reason phrases you might receive (along with an appropriate code). These phrases indicate why the server is terminating the session:
| Close-Reason-Phrase used by the DocVal Server | Description |
|---|---|
TIMEOUT_WHILE_WAITING_FOR_START_MESSAGE | No Start Message received in time. |
TIMEOUT_WHILE_WAITING_FOR_RESPONSE | No APDU Response received in time. |
INVALID_CLIENT_ID | Invalid Client ID provided. |
INVALID_START_MESSAGE | Incorrectly encoded Start Message. |
UNEXPECTED_MESSAGE | Unexpected Text Message received. |
INVALID_ACCESS_KEY_VALUES | Wrong Access Key values provided. |
ACCESS_CONTROL_FAILED | An Error occurred during Access Control. |
EMRTD_PASSPORT_READER_ERROR | An Error during the eMRTD session. |
FILE_READ_ERROR | An Error occurred while reading a file. |
COMMUNICATION_FAILED | WebSocket communication (network) failure. |
POST_TO_RESULT_SERVER_FAILED | Failed to post result to Result Server after 3 retry attempts. |
PROTOCOL_ERROR | The protocol was violated, indicating an implementation error. |
SERVER_ERROR | Server side exception occurred. |
MAX_SESSION_TIME_EXCEEDED | Session exceeded maximum time. |
MALFORMED_JSON | Client send malformed JSON. |
Appendix A: Security of Chip Authentication
This appendix details the security model behind the Chip Authentication (CA) process. It explains how the DocVal Server v2 protocol maintains robust security while offloading most of the chip communication to the client application.
The Challenge: Untrusted Clients
The primary goal of Chip Authentication is to verify that an eMRTD chip is genuine and not a clone. This is achieved through a cryptographic protocol based on a Diffie-Hellman key exchange. The server, as the trusted inspection system, must perform the security-critical steps. However, the physical NFC communication happens on the client's device, which is considered untrusted.
The challenge is to execute the CA protocol across three parties (Server, Client App, Chip) without compromising security. The protocol is designed to prevent the untrusted client app from being able to simulate a chip.
The Handover/Handback Protocol Flow
The protocol splits the Chip Authentication process into distinct phases, ensuring the server remains in control of all sensitive operations. The client acts as a simple relay for specific, encrypted APDUs during the critical exchange, and only regains the ability to communicate directly with the chip after the server has verified the chip's authenticity.
The sequence, which maps directly to the WebSocket messages, is as follows:
- Client-Side Preparation: The client application initiates the NFC session, performs Access Control, and reads the initial data required for Chip Authentication. This is primarily Data Group 14 (
dg14), which contains the chip's static public key ($PK_{IC}$). - Handover to Server:
- The client sends
dg14to the server in a binaryFILEmessage. - The client then sends a
CA_HANDOVERtext message, signaling that the server should take control.
- The client sends
- Server-Side Authentication:
- The server generates its own ephemeral Diffie-Hellman key pair and computes the shared secret, K.
- The server now needs to verify that the chip can also compute the same shared secret K, which is only possible if it possesses the corresponding private key ($SK_{IC}$). To do this, the server crafts APDU commands to complete the key exchange and test the new secure channel.
- Controlled APDU Exchange:
- The server sends these APDU commands (e.g., to deliver its public key to the chip, and then to read
dg1) to the client, encapsulated in binaryAPDUmessages. - The client forwards these APDUs to the chip.
- The chip's encrypted responses are relayed back to the server, again inside binary
APDUmessages.
- The server sends these APDU commands (e.g., to deliver its public key to the chip, and then to read
- Verification and Handback:
- The server decrypts the chip's response using the shared secret K. A successful decryption proves that the chip is genuine, as a clone would not know the private key ($SK_{IC}$) needed to generate K.
- Crucially, only after this successful verification, the server sends the
CA_HANDBACKmessage to the client. This message contains the newSecureMessagingInfo(session keys and sequence counter) derived from the shared secret K.
- Client Resumes Control: With the new session keys, the client can now resume reading the remaining Data Groups ( e.g., DG2, DG7) from the chip directly, without further server round-trips for each APDU.
- Final Server-Side Checks: After the client sends the
FINISHmessage, the server performs final security checks, including Passive Authentication, which cryptographically validates the authenticity of the chip's public key used in step 3.
Security
The server never sends the session keys (SecureMessagingInfo) to the client app until after the chip has proven possession of its private key. The client app is never privy to the chip's static private key or the server's ephemeral private key. It only acts as a temporary, blind relay for the end-to-end encrypted communication between the server and the chip. This ensures that even a malicious client cannot interfere with the authentication itself or establish a secure session with a cloned chip.