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