Apple VAS (Value-added services) is a proprietary NFC protocol that can be used for sending data from a mobile device to an NFC terminal.
Apart from reading passes, this protocol also allows reader to send a signup URL to the device, causing a signup link notification to appear on devices that do not have an appropriate pass downloaded.
Pass data is transmitted in protected form encrypted using AES-GCM. Shared key is derived via ECDH exchange with a X963KDF and is single use only.
Depending on opreation mode, one or multiple passes can be read in a single tap.
Version 1 was current at the time of writing.
VAS can be selected using following application id (AID):
4f53452e5641532e3031
AID value is a HEX representation of ASCII string OSE.VAS.01
.
This AID is also used by Google Smart Tap:
The ususal implementation for most readers is to select OSE.VAS.01
in order to detect what wallet provider is available on device (stored in TLV tag 50
), if ApplePay
is the value, then we have a device with Apple Wallet.
Apple VAS has multiple operation modes. Mode setting affects:
Following modes are available:
00
:01
:02
:03
:VAS also has a protocol MODE flag.
00
. In this mode the reader works as a signup terminal. Tapping a device to it will display a sign-up notification on the screen.01
. Can be used for both pass redemption and URL signup advertisment.For correct operation all readers that implement VAS have to have properly configured ECP.
Otherwise, some UX/UI-related features:
VAS ECP frames are also sometimes referred to as VASUP-A, both refer to the same thing.
All known VAS frames use ECP format V1, and they differ in last byte only, depending on operation mode:
Name | Version | TCI |
---|---|---|
VAS or payment | 01 | 00 00 00 |
VAS and payment | 01 | 00 00 01 |
VAS only | 01 | 00 00 02 |
Payment only | 01 | 00 00 03 |
Payment only configuration might seem rudimentary, as phone reacts to any reader as to payment one by displaying a payment card.
But it is not the case if a chinese transit card is added to device, which this configuration helps with.
As of version 1 following commands are available:
Command name | CLA | INS | P1 | P2 | DATA | LE | RESPONSE DATA | Notes |
---|---|---|---|---|---|---|---|---|
SELECT VAS APPLET | 00 | A4 | 04 | 00 | VAS AID | 00 | BER-TLV | |
GET DATA | 80 | CA | 01 | MODE | BER-TLV | 00 | BER-TLV | Data format described below |
Commands are executed as follows:
50
.4170706c65506179
, which is a value of ApplePay
string in ASCII-encoded form, we have a device that supports Apple VAS.VAS and/or payment
modes, if you've failed to a read a pass due to connectivity issue, you shouldn't do a DESELECT and TRESET, as after that a device won't route any more requests to VAS until user preemptively ends and re-authenticates the session. CLA | INS | P1 | P2 | DATA | LE |
---|---|---|---|---|---|
00 | A4 | 04 | 00 | 4f53452e5641532e3031 |
00 |
Data contains an ASCII encoded form of "OSE.VAS.01" string;
SW1 | SW2 | DATA |
---|---|---|
90 | 00 | 6f1d50084170706c655061799f210201009f2404c05d48d09f23040000001e |
Response data example:
6f1d50084170706c655061799f210201009f2404c05d48d09f23040000001e
6f[1d]: # File Control Information Template
50[08]: # Application Label
4170706c65506179 # ASCII form of "ApplePay"
9f21[02]: # VAS version
0100 # Major version 1, minor version 0
9f24[04]: # Nonce
c05d48d0 # This number is random every time, not used
9f23[04]: # Extra information
0000001e # Meaning of this value is unknown
CLA | INS | P1 | P2 | DATA | LE |
---|---|---|---|---|---|
80 | CA | 01 | MODE | * | 00 |
P2 flag values were described in "Protocol Modes" section;
Request data: | Name | Tag | Length | Example | Notes |
---|---|---|---|---|---|
Protocol version | 9f22 |
02 |
0100 |
Always 0100 |
|
SHA256 of pass id | 9f25 |
32 |
03b57cdb3eca0984ba9abdc2fb45d86626d87b39d33c5c6dbbc313a6347a3146 |
SHA of pass type identifier, such as pass.com.passkit.pksamples.nfcdemo |
|
Capabilities mask | 9f26 |
04 |
00800002 |
More info below | |
Merchant signup URL | 9f29 |
Variable | 68747470733a2f2f6170706c652e636f6d |
URL pointing to a HTTPS signup json signed by pass certificate | |
Filter | 9f2b |
05 |
0100000000 |
Meaning unknown, mentioned in public configuration PDFs (look at References section). Values other than provided in example make pass reading fail. Value is optional, but if present MUST start with byte 01 |
|
Nonce | 9f28 |
04 |
01000000 |
Meaning unknown, could be an optional tag for mobile device nonce (see tag 9f24) |
Consists of 4 bytes, numbered 0-3 from left to right
Byte 0 - RFU
Mentioned in some public configuration PDFs, does not impact usage
07 | 06 | 05 | 04 | 03 | 02 | 01 | 00 | Notes |
---|---|---|---|---|---|---|---|---|
1 | VAS is supported | |||||||
0 | Vas is unsupported | |||||||
1 | Authentication required | |||||||
0 | Authentication not required | |||||||
X | X | X | X | RFU | ||||
X | X | Terminal type | ||||||
0 | 0 | Payment | ||||||
0 | 1 | Transit |
Byte 2 - RFU
Important for protocol operation
07 | 06 | 05 | 04 | 03 | 02 | 01 | 00 | Notes |
---|---|---|---|---|---|---|---|---|
1 | More passes will be requested in this reading session | |||||||
0 | No more passes will be requested in this reading session | |||||||
X | X | X | X | X | RFU | |||
X | X | VAS mode (like in ECP) | ||||||
0 | 0 | VAS or payment | ||||||
0 | 1 | VAS and payment | ||||||
1 | 0 | VAS only | ||||||
1 | 1 | Payment only |
Command TLV data example:
9f22[02]:
0100
9f25[20]:
03b57cdb3eca
0984ba9abdc2
fb45d86626d8
7b39d33c5c6d
bbc313a6347a
3146
9f26[04]:
00800002
9f2b[05]:
0100000000
9f28[04]:
01000000
9f29[11]:
68747470733a2f2f6170706c652e636f6d
SW1 | SW2 | DATA |
---|---|---|
XX | XX | 70549f2a009f274ebeef7375094afa4824addb8abf0a59f4c5b88f7b33cd803666cdf358dc8aa2ecea863673b7e92b8f39bc744233dda87e53f2ae346eb43415e7b20a50aa41e02de9f3d533f506e29b4ed31eaa9cfa |
Status words: | SW1 | SW2 | Notes |
---|---|---|---|
90 |
00 |
Pass data returned (full VAS) or URL was accepted (URL only) | |
6a |
83 |
Pass not selected on a screen or unavailable | |
62 |
87 |
Device not unlocked (Apple Wallet will open, pass will appear on a screen for authentication) |
Any other status word means that a command payload was built incorrectly, or that an applet was not yet selected.
Response data example:
70549f2a009f274ebeef7375094afa4824addb8abf0a59f4c5b88f7b33cd803666cdf358dc8aa2ecea863673b7e92b8f39bc744233dda87e53f2ae346eb43415e7b20a50aa41e02de9f3d533f506e29b4ed31eaa9cfa
70[54]: # EMV Proprietary Template
9f2a[00] # Unknown
9f27[4e]: # Cryptogram Information Data (VAS response)
beef7375094afa4824addb8abf0a59f4c5b88f7b33cd803666cdf358dc8aa2ec
ea863673b7e92b8f39bc744233dda87e53f2ae346eb43415e7b20a50aa41e02d
e9f3d533f506e29b4ed31eaa9cfa
Symbols [ and ] depict inclusive array indices, ( and ) depict exclusive indices. Numeration is done simillarly to Python
Cryptogram Information Data TLV tag contains following concatenated data:
After receiving the response, the next step is to decrypt it.
Due to a nature of Apple VAS protocol, decryption can be done:
In both situations, decryption is done in the following steps:
key_identifier
.shared_key
;shared_key
is used together with shared info shared_info
in X963KDF algorithm in order to get the derived key derived_key
;derived_key
is then used via AESGCM in order to decrypt pass data.
02
, 03
) to the EC public key data if you want to load it into an object representation during one of the steps.Documentation on how to generate shared information and derived keys (steps 4. 5.) is not present in this document. For that information, visit the following gist. Don't forget to thank the author.
File located at examples/implementation/decryption.py contains Python code that implements the decryption proccess.
Crypto methods are provided by cryptography library.
Correct shared info calculation is omitted, but can be reconstructed by following the link mentioned in this section before.
VAS
, vas
keywords.