基于C语言解析EMV卡GPO响应获取各卡AFL的技术问询
Alright, let's tackle parsing the AFL (Access File Locator) from GET PROCESSING OPTIONS (GPO) responses in C—since you don't have Java tools to lean on, we'll build a straightforward, card-agnostic parser that handles those three card types you mentioned.
First, a quick recap: GPO responses use BER-TLV formatting. The AFL is always stored under the 0x94 TLV tag. The response might be wrapped in a container tag: either 0x77 (Response Message Template Format 2, like your HelloBank/PayPal examples) or 0x80 (Response Message Template Format 1, like your PostePay example). Our goal is to drill down through these containers to extract the 0x94 tag's value.
Step 1: Core TLV Parsing Function
We'll start with a reusable function to hunt for a specific TLV tag, including recursive parsing of container tags (0x77/0x80):
#include <stdint.h> #include <string.h> /** * Finds a target TLV tag in BER-TLV formatted data * @param data: Pointer to raw TLV data * @param data_len: Length of the raw data * @param target_tag: Tag to search for (e.g., 0x94 for AFL) * @param value: Output pointer to the tag's value * @param value_len: Output length of the tag's value * @return 0 on success, -1 if tag not found */ int find_tlv_tag(const uint8_t *data, size_t data_len, uint8_t target_tag, const uint8_t **value, size_t *value_len) { size_t offset = 0; while (offset < data_len) { // Parse single-byte tag (covers 0x80, 0x77, 0x94 which we care about) uint8_t current_tag = data[offset++]; // Parse length (handle single and multi-byte lengths) size_t len = data[offset++]; if (len & 0x80) { int num_len_bytes = len & 0x7F; len = 0; for (int i = 0; i < num_len_bytes; i++) { len = (len << 8) | data[offset++]; } } // Check if we found our target tag if (current_tag == target_tag) { *value = &data[offset]; *value_len = len; return 0; } // If this is a container tag, recursively search its contents if (current_tag == 0x77 || current_tag == 0x80) { int ret = find_tlv_tag(&data[offset], len, target_tag, value, value_len); if (ret == 0) return 0; } // Skip past the current tag's value to move to the next TLV element offset += len; } return -1; }
Step 2: GPO-Specific AFL Extraction
Next, wrap the core function to handle GPO responses (we'll strip the trailing success status word 90 00 first):
/** * Extracts AFL from a raw GPO response * @param gpo_response: Raw GPO response bytes (including status word) * @param response_len: Total length of the GPO response * @param afl_data: Output pointer to the AFL bytes * @param afl_len: Output length of the AFL data * @return 0 on success, -1 on error */ int parse_gpo_afl(const uint8_t *gpo_response, size_t response_len, const uint8_t **afl_data, size_t *afl_len) { // Validate response length (needs at least status word + some data) if (response_len < 2) return -1; // Strip trailing status word (90 00 is standard success for GPO) const uint8_t *tlv_data = gpo_response; size_t tlv_len = response_len - 2; // Search for the 0x94 tag (AFL) return find_tlv_tag(tlv_data, tlv_len, 0x94, afl_data, afl_len); }
Testing with Your Card Examples
Let's verify with your three cases:
A) HelloBank Response
Raw response (full with status word):77 12 82 02 38 00 94 0C 10 02 04 01 18 01 01 00 20 01 01 00 90 00
parse_gpo_aflwill find the0x94tag with length0xC(12 bytes).- AFL data:
10 02 04 01 18 01 01 00 20 01 01 00
B) PayPal Response
Raw response (full with status word):77 12 82 02 39 00 94 0C 18 01 01 00 20 01 01 00 28 01 03 01 90 00
0x94tag length is0xC(12 bytes).- AFL data:
18 01 01 00 20 01 01 00 28 01 03 01
C) PostePay Response (Starts with 0x80)
Even though the response starts with 0x80 (Template Format 1), the recursive parsing in find_tlv_tag will drill into the 0x80 container and locate the 0x94 tag just like the other cases.
Edge Case Notes
- Multi-byte Tags: The current code handles single-byte tags (which covers all tags we need for AFL extraction). If you encounter cards with extended multi-byte tags later, you can expand the tag parsing logic.
- Non-Standard Status Words: Some cards might return alternative success status words. If needed, adjust the
parse_gpo_aflfunction to check for valid status words before stripping them. - Variable AFL Length: AFL length is defined by the
0x94tag's length field—our code automatically adapts to whatever length the card returns.
内容的提问来源于stack exchange,提问作者Valerio Colonnese

