| /* |
| * 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. |
| * |
| * Usage: |
| * $0 [impl name] < line-by-line-input-and-expect |
| */ |
| |
| #include <ctype.h> |
| #include <stdint.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <unistd.h> |
| |
| #define LOG_TAG "ese-replay" |
| #include <ese/ese.h> |
| #include <ese/log.h> |
| |
| #include "buffer.h" |
| #include "hw.h" |
| #include "payload.h" |
| |
| const struct SupportedHardware kSupportedHardware = { |
| .len = 3, |
| .hw = |
| { |
| { |
| .name = "nq-nci", |
| .sym = "ESE_HW_NXP_PN80T_NQ_NCI_ops", |
| .lib = "libese-hw-nxp-pn80t-nq-nci.so", |
| .options = NULL, |
| }, |
| { |
| .name = "fake", |
| .sym = "ESE_HW_FAKE_ops", |
| .lib = "libese-hw-fake.so", |
| .options = NULL, |
| }, |
| { |
| .name = "echo", |
| .sym = "ESE_HW_ECHO_ops", |
| .lib = "libese-hw-echo.so", |
| .options = NULL, |
| }, |
| }, |
| }; |
| |
| int main(int argc, char **argv) { |
| if (argc != 2) { |
| printf("Usage:\n%s [hw_impl] < file_with_apdus\n\n" |
| "File format:\n" |
| " hex-apdu-to-send hex-trailing-response-bytes\\n\n" |
| "\n" |
| "For example,\n" |
| " echo -e '00A4040000 9000\\n80CA9F7F00 9000\\n' | %s nq-nci\n", |
| argv[0], argv[0]); |
| print_supported_hardware(&kSupportedHardware); |
| return 1; |
| } |
| int hw_id = find_supported_hardware(&kSupportedHardware, argv[1]); |
| if (hw_id < 0) { |
| fprintf(stderr, "Unknown hardware name: %s\n", argv[1]); |
| return 3; |
| } |
| const struct Hardware *hw = &kSupportedHardware.hw[hw_id]; |
| |
| struct EseInterface ese; |
| printf("[-] Initializing eSE\n"); |
| |
| if (!initialize_hardware(&ese, hw)) { |
| fprintf(stderr, "Could not initialize hardware\n"); |
| return 2; |
| } |
| printf("eSE implementation selected: %s\n", ese_name(&ese)); |
| if (ese_open(&ese, hw->options)) { |
| ALOGE("Cannot open hw"); |
| if (ese_error(&ese)) { |
| ALOGE("eSE error (%d): %s", ese_error_code(&ese), |
| ese_error_message(&ese)); |
| } |
| return 5; |
| } |
| printf("eSE is open\n"); |
| struct Payload payload; |
| if (!payload_init(&payload, 10 * 1024 * 1024, 1024 * 4)) { |
| ALOGE("Failed to initialize payload."); |
| return -1; |
| } |
| |
| struct Buffer reply; |
| buffer_init(&reply, 2048); |
| while (!feof(stdin) && payload_read(&payload, stdin)) { |
| payload_dump(&payload, stdout); |
| reply.len = (uint32_t)ese_transceive( |
| &ese, payload.tx.buffer, payload.tx.len, reply.buffer, reply.size); |
| if ((int)reply.len < 0 || ese_error(&ese)) { |
| printf("Transceive error. See logcat -s ese-replay\n"); |
| ALOGE("transceived returned failure: %d\n", (int)reply.len); |
| if (ese_error(&ese)) { |
| ALOGE("An error (%d) occurred: %s", ese_error_code(&ese), |
| ese_error_message(&ese)); |
| } |
| break; |
| } |
| buffer_dump(&reply, "", "Response", 240, stdout); |
| if (reply.len < payload.expected.len) { |
| printf("Received less data than expected: %u < %u\n", reply.len, |
| payload.expected.len); |
| break; |
| } |
| |
| /* Only compare the end. This allows a simple APDU success match. */ |
| if (memcmp(payload.expected.buffer, |
| (reply.buffer + reply.len) - payload.expected.len, |
| payload.expected.len)) { |
| printf("Response did not match. Aborting!\n"); |
| break; |
| } |
| } |
| buffer_free(&reply); |
| printf("Transmissions complete.\n"); |
| ese_close(&ese); |
| release_hardware(hw); |
| return 0; |
| } |