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  * Hack-y server to forward communication with an eSE during development.
17  * See README.md for more information.
18  */
19 
20 #include <arpa/inet.h>
21 #include <linux/un.h>
22 #include <stdint.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include <sys/socket.h>
26 #include <unistd.h>
27 
28 #define LOG_TAG "ese-relay"
29 #include <ese/ese.h>
30 #include <ese/log.h>
31 
32 extern const uint8_t *kAtr;
33 extern size_t kAtrLength;
34 extern void *kEseOpenData;
35 void ese_relay_init(struct EseInterface *ese);
36 
37 /*
38  * Aligned with vpcd.h in
39  * https://frankmorgner.github.io/vsmartcard/virtualsmartcard
40  */
41 #define CMD_POWER_OFF 0
42 #define CMD_POWER_ON 1
43 #define CMD_RESET 2
44 #define CMD_ATR 4
45 
setup_socket(const char * name)46 int setup_socket(const char *name) {
47   int fd;
48   struct sockaddr_un addr;
49 
50   memset(&addr, 0, sizeof(struct sockaddr_un));
51   addr.sun_family = AF_UNIX;
52   if (strlen(name) > UNIX_PATH_MAX - 1) {
53     ALOGE("Abstract listener name too long.");
54     return -1;
55   }
56   strncpy(&addr.sun_path[1], name, strlen(name));
57   fd = socket(AF_UNIX, SOCK_STREAM, 0);
58   if (fd == -1) {
59     ALOGE("Could not open socket.");
60     return fd;
61   }
62   if (bind(fd, (struct sockaddr *)&addr,
63            sizeof(sa_family_t) + strlen(name) + 1) == -1) {
64     ALOGE("Failed to bind to abstract socket name");
65     close(fd);
66     return -1;
67   }
68   return fd;
69 }
70 
main()71 int main() {
72   int server_fd = setup_socket(LOG_TAG);
73   struct EseInterface ese;
74   ese_relay_init(&ese);
75 
76   if (listen(server_fd, 4)) {
77     ALOGE("Failed to listen on socket.");
78     close(server_fd);
79     return -1;
80   }
81 
82   while (server_fd) {
83     struct sockaddr client_info;
84     socklen_t client_info_len = (socklen_t)sizeof(&client_info);
85     int client_fd;
86     uint32_t tx_len, data_read;
87     uint32_t rx_len;
88     uint16_t network_tx_len;
89     uint16_t network_rx_len;
90     uint8_t tx_buf[4096];
91     uint8_t rx_buf[4096];
92     int connected = 0;
93 
94     if ((client_fd = accept(server_fd, &client_info, &client_info_len)) == -1) {
95       ALOGE("Fatal error accept()ing a client connection.");
96       return -1;
97     }
98     printf("Client connected.\n");
99     connected = 1;
100     if (ese_open(&ese, kEseOpenData)) {
101       ALOGE("Cannot open hw");
102       if (ese_error(&ese))
103         ALOGE("eSE error (%d): %s", ese_error_code(&ese),
104               ese_error_message(&ese));
105       return 1;
106     }
107     printf("eSE is open\n");
108 
109     while (connected) {
110       printf("Listening for data from client\n");
111       if (read(client_fd, &network_tx_len, sizeof(network_tx_len)) !=
112           sizeof(network_tx_len)) {
113         ALOGE("Client disconnected.");
114         break;
115       }
116       tx_len = (uint32_t)ntohs(network_tx_len);
117       printf("tx_len: %u\n", tx_len);
118       if (tx_len == 0) {
119         ALOGE("Client had nothing to say. Goodbye.");
120         break;
121       }
122       if (tx_len > sizeof(tx_buf)) {
123         ALOGE("Client payload too large: %u", tx_len);
124         break;
125       }
126       for (data_read = 0; data_read < tx_len;) {
127         printf("Reading payload: %u of %u remaining\n", data_read, tx_len);
128         ssize_t bytes = read(client_fd, tx_buf + data_read, tx_len - data_read);
129         if (bytes < 0) {
130           ALOGE("Client abandoned hope during transmission.");
131           connected = 0;
132           break;
133         }
134         data_read += bytes;
135       }
136       /* Finally, we can transcieve. */
137       if (tx_len) {
138         uint32_t i;
139         printf("Sending %u bytes to card\n", tx_len);
140         printf("TX: ");
141         for (i = 0; i < tx_len; ++i)
142           printf("%.2X ", tx_buf[i]);
143         printf("\n");
144       }
145 
146       if (tx_len == 1) { /* Control request */
147         printf("Received a control request: %x\n", tx_buf[0]);
148         rx_len = 0;
149         switch (tx_buf[0]) {
150         case CMD_POWER_OFF:
151           ese.ops->hw_reset(&ese);
152           break;
153         case CMD_POWER_ON:
154           break;
155         case CMD_RESET:
156           ese.ops->hw_reset(&ese);
157           break;
158         case CMD_ATR:
159           /* Send a dummy ATR for another JCOP card */
160           rx_len = kAtrLength;
161           printf("Filling card RX buf with fake ATR (%u)\n", rx_len);
162           memcpy(rx_buf, kAtr, rx_len);
163           printf("Sending back ATR of length %u\n", rx_len);
164           break;
165         default:
166           ALOGE("Unknown control byte seen: %x", tx_buf[0]);
167         }
168         if (!rx_len)
169           continue;
170       } else {
171         rx_len = ese_transceive(&ese, tx_buf, tx_len, rx_buf, sizeof(rx_buf));
172         if (ese_error(&ese)) {
173           ALOGE("An error (%d) occurred: %s", ese_error_code(&ese),
174                 ese_error_message(&ese));
175           return -1;
176         }
177       }
178       if (rx_len > 0) {
179         uint32_t i;
180         printf("Read %d bytes from card\n", rx_len);
181         printf("RX: ");
182         for (i = 0; i < rx_len; ++i)
183           printf("%.2X ", rx_buf[i]);
184         printf("\n");
185       }
186 
187       /* Send to client */
188       network_rx_len = htons((uint16_t)rx_len);
189       if (write(client_fd, &network_rx_len, sizeof(network_rx_len)) !=
190           sizeof(network_rx_len)) {
191         ALOGE("Client abandoned hope during response size.");
192         break;
193       }
194 
195       for (data_read = 0; data_read < rx_len;) {
196         ssize_t bytes =
197             write(client_fd, rx_buf + data_read, rx_len - data_read);
198         if (bytes < 0) {
199           ALOGE("Client abandoned hope during response.");
200           connected = 0;
201           break;
202         }
203         data_read += bytes;
204       }
205       usleep(1000);
206     }
207     close(client_fd);
208     printf("Session ended\n\n");
209     ese_close(&ese);
210   }
211   return 0;
212 }
213