1/* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 * 16 * Usage: 17 * $0 [impl name] < line-by-line-input-and-expect 18 */ 19 20#include <ctype.h> 21#include <stdint.h> 22#include <stdio.h> 23#include <stdlib.h> 24#include <string.h> 25#include <unistd.h> 26 27#define LOG_TAG "ese-replay" 28#include <ese/ese.h> 29#include <ese/log.h> 30 31#include "buffer.h" 32#include "hw.h" 33#include "payload.h" 34 35const struct SupportedHardware kSupportedHardware = { 36 .len = 3, 37 .hw = 38 { 39 { 40 .name = "nq-nci", 41 .sym = "ESE_HW_NXP_PN80T_NQ_NCI_ops", 42 .lib = "libese-hw-nxp-pn80t-nq-nci.so", 43 .options = NULL, 44 }, 45 { 46 .name = "fake", 47 .sym = "ESE_HW_FAKE_ops", 48 .lib = "libese-hw-fake.so", 49 .options = NULL, 50 }, 51 { 52 .name = "echo", 53 .sym = "ESE_HW_ECHO_ops", 54 .lib = "libese-hw-echo.so", 55 .options = NULL, 56 }, 57 }, 58}; 59 60int main(int argc, char **argv) { 61 if (argc != 2) { 62 printf("Usage:\n%s [hw_impl] < file_with_apdus\n\n" 63 "File format:\n" 64 " hex-apdu-to-send hex-trailing-response-bytes\\n\n" 65 "\n" 66 "For example,\n" 67 " echo -e '00A4040000 9000\\n80CA9F7F00 9000\\n' | %s nq-nci\n", 68 argv[0], argv[0]); 69 print_supported_hardware(&kSupportedHardware); 70 return 1; 71 } 72 int hw_id = find_supported_hardware(&kSupportedHardware, argv[1]); 73 if (hw_id < 0) { 74 fprintf(stderr, "Unknown hardware name: %s\n", argv[1]); 75 return 3; 76 } 77 const struct Hardware *hw = &kSupportedHardware.hw[hw_id]; 78 79 struct EseInterface ese; 80 printf("[-] Initializing eSE\n"); 81 82 if (!initialize_hardware(&ese, hw)) { 83 fprintf(stderr, "Could not initialize hardware\n"); 84 return 2; 85 } 86 printf("eSE implementation selected: %s\n", ese_name(&ese)); 87 if (ese_open(&ese, hw->options)) { 88 ALOGE("Cannot open hw"); 89 if (ese_error(&ese)) { 90 ALOGE("eSE error (%d): %s", ese_error_code(&ese), 91 ese_error_message(&ese)); 92 } 93 return 5; 94 } 95 printf("eSE is open\n"); 96 struct Payload payload; 97 if (!payload_init(&payload, 10 * 1024 * 1024, 1024 * 4)) { 98 ALOGE("Failed to initialize payload."); 99 return -1; 100 } 101 102 struct Buffer reply; 103 buffer_init(&reply, 2048); 104 while (!feof(stdin) && payload_read(&payload, stdin)) { 105 payload_dump(&payload, stdout); 106 reply.len = (uint32_t)ese_transceive( 107 &ese, payload.tx.buffer, payload.tx.len, reply.buffer, reply.size); 108 if ((int)reply.len < 0 || ese_error(&ese)) { 109 printf("Transceive error. See logcat -s ese-replay\n"); 110 ALOGE("transceived returned failure: %d\n", (int)reply.len); 111 if (ese_error(&ese)) { 112 ALOGE("An error (%d) occurred: %s", ese_error_code(&ese), 113 ese_error_message(&ese)); 114 } 115 break; 116 } 117 buffer_dump(&reply, "", "Response", 240, stdout); 118 if (reply.len < payload.expected.len) { 119 printf("Received less data than expected: %u < %u\n", reply.len, 120 payload.expected.len); 121 break; 122 } 123 124 /* Only compare the end. This allows a simple APDU success match. */ 125 if (memcmp(payload.expected.buffer, 126 (reply.buffer + reply.len) - payload.expected.len, 127 payload.expected.len)) { 128 printf("Response did not match. Aborting!\n"); 129 break; 130 } 131 } 132 buffer_free(&reply); 133 printf("Transmissions complete.\n"); 134 ese_close(&ese); 135 release_hardware(hw); 136 return 0; 137} 138