/* * Copyright (C) 2017 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Test program to select the CardManager and request the card production * lifcycle data (CPLC). */ #include <stdint.h> #include <stdio.h> #include <unistd.h> #include <ese/ese.h> ESE_INCLUDE_HW(ESE_HW_NXP_PN80T_NQ_NCI); /* APDU: CLA INS P1-P2 Lc Data Le */ struct Apdu { uint32_t length; const uint8_t *bytes; const char *desc; }; struct ApduSession { uint32_t count; const char *desc; const struct Apdu *apdus[]; }; const uint8_t kSelectCardManagerBytes[] = {0x00, 0xA4, 0x04, 0x00, 0x00}; /* Implicitly selects the ISD at A0 00 00 01 51 00 00 */ const struct Apdu kSelectCardManager = { .length = sizeof(kSelectCardManagerBytes), .bytes = &kSelectCardManagerBytes[0], .desc = "SELECT CARD MANAGER", }; const uint8_t kGetCplcBytes[] = {0x80, 0xCA, 0x9F, 0x7F, 0x00}; const struct Apdu kGetCplc = { .length = sizeof(kGetCplcBytes), .bytes = &kGetCplcBytes[0], .desc = "GET CPLC", }; const struct ApduSession kGetCplcSession = { .count = 2, .desc = "GET-CPLC", .apdus = { &kSelectCardManager, &kGetCplc, }, }; const struct ApduSession kEmptySession = { .count = 0, .desc = "Empty session (hw close only)", .apdus = {}, }; /* Define the loader service sessions here! */ const uint8_t kSelectJcopIdentifyBytes[] = { 0x00, 0xA4, 0x04, 0x00, 0x09, 0xA0, 0x00, 0x00, 0x01, 0x67, 0x41, 0x30, 0x00, 0xFF, }; const struct Apdu kSelectJcopIdentify = { .length = sizeof(kSelectJcopIdentifyBytes), .bytes = &kSelectJcopIdentifyBytes[0], .desc = "SELECT JCOP IDENTIFY", }; const struct ApduSession *kSessions[] = { &kGetCplcSession, &kEmptySession, }; int main() { struct EseInterface ese = ESE_INITIALIZER(ESE_HW_NXP_PN80T_NQ_NCI); void *ese_hw_open_data = NULL; size_t s = 0; for (; s < sizeof(kSessions) / sizeof(kSessions[0]); ++s) { int recvd; uint32_t apdu_index = 0; uint8_t rx_buf[1024]; if (ese_open(&ese, ese_hw_open_data) < 0) { printf("Cannot open hw\n"); if (ese_error(&ese)) printf("eSE error (%d): %s\n", ese_error_code(&ese), ese_error_message(&ese)); return 1; } printf("Running session %s\n", kSessions[s]->desc); for (; apdu_index < kSessions[s]->count; ++apdu_index) { uint32_t i; const struct Apdu *apdu = kSessions[s]->apdus[apdu_index]; printf("Sending APDU %u: %s\n", apdu_index, apdu->desc); printf("Sending %u bytes to card\n", apdu->length); printf("TX: "); for (i = 0; i < apdu->length; ++i) printf("%.2X ", apdu->bytes[i]); printf("\n"); recvd = ese_transceive(&ese, (uint8_t *)apdu->bytes, apdu->length, rx_buf, sizeof(rx_buf)); if (ese_error(&ese)) { printf("An error (%d) occurred: %s", ese_error_code(&ese), ese_error_message(&ese)); return -1; } if (recvd > 0) { int i; printf("Read %d bytes from card\n", recvd); printf("RX: "); for (i = 0; i < recvd; ++i) printf("%.2X ", rx_buf[i]); printf("\n"); } usleep(1000); } printf("Session completed\n\n"); ese_close(&ese); } return 0; }