Skip to content

Instantly share code, notes, and snippets.

@gm3197
Last active April 7, 2024 10:12
Show Gist options
  • Star 23 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save gm3197/ad0959476346cef69b75ea0523214350 to your computer and use it in GitHub Desktop.
Save gm3197/ad0959476346cef69b75ea0523214350 to your computer and use it in GitHub Desktop.
Reverse Engineered Value Added Services Protocol Specification

Reverse Engineered VAS Protocol Specification

Research by Grayson Martin
Last Updated 7/8/23

Introduction

Value Added Services (VAS) is the protocol used by NFC capable passes in Apple Wallet. Access to this protocol is heavily restricted on both the device end (a special certificate issued by Apple is required to create these passes) and the reader end (NDA enforced confidentiality). As such, a desire arose to better understand the protocol in order to explore additional use cases and examine its cryptographic integrity. There are gaps in understanding in certain parts of this protocol, however this document contains the minimum necessary understanding to automatically select, read data from, and decrypt a pass.

Importantly, this specification does not enable a malicious actor to read the data from a pass for which they do not have both the reader's private key, and the pass type identifier. Impersonation of a pass is possible, however the information required to do so cannot be obtained in plaintext through this protocol, and such information must be manually extracted from the .pkpass file describing the pass.

A big thanks to the contributors of proxmark3 for the incredible research suite they've created. I hope to give back with this work and more. My implementation of this specification for the proxmark3 has been merged into that repository.

Terminology

  • Pass Type ID: A reverse-domain style string beginning with "pass." that identifies the type of pass (i.e. "pass.com.chargepoint.MobileCard" or "pass.com.panerabread.m.178")
  • VAS message: A string (length <= 64) sent from the mobile device to the reader. Often (but not necessarily) the same as the pass' serial number
  • Reader Key: A private key held in the VAS reader. All passes that the terminal can read contain a copy of the reader's public key, and use this key to encrypt the message
  • Ephemeral Key: A one-time use key generated on the mobile device to complete an Elliptic Curve Diffie Hellman routine used to derive a shared secret for encryption/decryption

Several technical protocols and specifications are mentioned and a base-level understanding of those is assumed here

Approach

This protocol was reverse engineered by observing the interactions between a compatible mobile device and an official VAS-certified reader. Additional details about the decryption algorithm and the meaning/significance of several of the otherwise mysterious bytes were obtained from public documentation and user guides of closed source and hardware implementations of the VAS protocol.

I am bound by no non-disclosure agreement that covers the following information. This work is not affiliated with nor endorsed by Apple in any way.

Javacard Applet

My original goal for this project included a Javacard Applet to enable this protocol on other devices. However the mandatory inclusion of a validated timestamp in the protocol makes implementing this specification on a device with no concept of time, such as a smartcard, impossible.

Testing

As generating an NFC pass can only be done with a certification issued by Apple, testing a pass for which you know the private key can be difficult. Thankfully, Passkit (the company, not the old name of the Apple Wallet .pkpass file protocol) has a publically available site which generates demo passes with random VAS messages, and the reader private key is published.

Enhanced Contactless Polling

To elicit a response from a mobile device when it is idle, ECP must be used. How this actually works is not well understood, and there is reason to believe that permutations of it are used in other NFC-related features of iOS including Apple Car Keys and HomeKit Keys. However, sending the bytes 6A 01 00 00 04 without an ISO 14443A select, just before the standard ISO 14443A wake-up polling begins, causes the device to respond when it otherwise would not. Not all readers support sending raw bytes without previously selecting and negotiating with a card, and as such, this aspect of the protocol is often handled by ECP-specific NFC controllers.

Commands

SELECT

A standard ISO 7816 select command, with AID equal to the ASCII encoding of "OSE.VAS.01"

Request

Byte Value
CLA 80
INS A4
P1 04
P2 00
Lᶜ Length of application identifier
Data AID of the VAS application
Lᵉ 00

Response

Tag Length Value Notes
6F 29 Response TLV See table below
Response TLV
Tag Length Value Notes
50 8 "ApplePay" ISO7816 Application Label
9F21 2 0100 Mobile Application Version
9F23 4 Mobile Capabilities See table below
9F24 4 Nonce?
Mobile Capabilities

Four bytes that indicate the capabilities and configuration of the mobile device.

Byte 1

b8 b7 b6 b5 b4 b3 b2 b1 Notes
0 0 0 0 0 0 0 0 RFU

Byte 2

b8 b7 b6 b5 b4 b3 b2 b1 Notes
0 0 0 0 0 0 0 0 RFU

Byte 3

b8 b7 b6 b5 b4 b3 b2 b1 Notes
0 0 0 0 0 0 0 0 RFU

Byte 4

b8 b7 b6 b5 b4 b3 b2 b1 Notes
0 VAS disabled
1 VAS enabled
0 0 0 1 1 1 0 Meaning unknown, additional testing required

GET VAS DATA

Allows a reader to provide a URL (handled in a similar manner to a standard NDEF tag by the OS), request the encrypted message associated with a particular pass type identifier, or both.

Request

Byte Value
CLA 80
INS CA
P1 01
P2 00 for URL only, 01 for full VAS
Lᶜ Length of request TLV
Data Request TLV, see below
Lᵉ 00
Request TLV
Tag Length Value Notes
9F22 2 0100 Terminal Application Version
9F25 32 "Merchant ID" SHA-256 hash of Pass Type ID
9F28 4 All values accepted Required, nonce maybe?
9F26 4 Terminal Capabilities See table below
9F29 Variable Merchant URL Optional
Terminal Capabilities

Four bytes that indicate the capabilities and configuration of the terminal.

Byte 1

b8 b7 b6 b5 b4 b3 b2 b1 Notes
0 0 0 0 0 0 0 0 RFU

Byte 2

b8 b7 b6 b5 b4 b3 b2 b1 Notes
0 0 0 0 0 0 0 0 RFU

Byte 3

b8 b7 b6 b5 b4 b3 b2 b1 Notes
0 0 0 0 0 0 0 0 RFU

Byte 4

b8 b7 b6 b5 b4 b3 b2 b1 Notes
0 0 0 0 0 Bits 3-7 unused, set to 0
0 No additional GET VAS DATA commands will be sent
1 One or more additional GET VAS DATA commands will be sent
0 0 Terminal supports VAS and EMV, but only one may be used in this session
0 1 Terminal supports VAS and EMV, and both may be used in this session
1 0 Terminal only supports, or is only configured for, VAS
1 1 Terminal only supports, or is only configured for, EMV

Response

An APDU status of 9000 indicates a successful response containing the following TLV:

Tag Length Value Notes
70 Variable VAS Response TLV See table below

All other APDU status codes indicate that either the device doesn't contain a pass with a matching pass type ID, or the user has been prompted for authentication and will attempt the transaction again

VAS Response TLV
Tag Length Value Notes
9F2A 0 Optional, presence indicates "Mobile Token"??
9F27 Variable Encrypted message

Decrypting VAS message

The encrypted VAS message is broken into three parts:

Start Byte End Byte Description
0 4 First 4 bytes of SHA-256 hash of raw X coordinate of the reader's EC P-256 public key
4 36 Compressed ephemeral public key used for ECDH w/ reader private key, 32 byte X coordinate. Note: when uncompressing, the Y coordinate is always even
36 End Ciphertext + 16 byte authentication tag

There are two possible encryption methods that are used, and as far as I can tell, the only way to proceed is to try both and see which one passes the GCM data integrity check.

Both methods use ECDH with ANSI X9.63 SHA 256 as the key derivation function and AES128 GCM Block Cipher. The initialization vector for GCM is always a zero-initialized 16-byte octet string. The resulting decrypted data is the concatenation of a four byte timestamp (seconds since Jan 1, 2001) and the raw VAS message.

Method 1

  • The concatenation of the byte 0x0D, the ASCII encoded strings "id-aes256-GCM" and "ApplePay encrypted VAS data", and the SHA-256 hash of the pass type identifier will serve as the "Shared Info" in the ANSI X9.63 key derivation.

Method 2

  • The string "ApplePay encrypted VAS data" will serve as the "Shared Info" in the ANSI X9.63 key derivation.

  • The SHA-256 hash of the pass type identifier will serve as the "Additional Authentication Data" in the GCM block cipher.

@KyoungsueKim
Copy link

Oh my god it blows my mind. How long did it take you to research this? This is incredible.

@DjamikTea
Copy link

Bro you are the best, this is really incredible

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment