You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
213 lines
5.9 KiB
213 lines
5.9 KiB
/*
|
|
* 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.
|
|
*
|
|
* Hack-y server to forward communication with an eSE during development.
|
|
* See README.md for more information.
|
|
*/
|
|
|
|
#include <arpa/inet.h>
|
|
#include <linux/un.h>
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <sys/socket.h>
|
|
#include <unistd.h>
|
|
|
|
#define LOG_TAG "ese-relay"
|
|
#include <ese/ese.h>
|
|
#include <ese/log.h>
|
|
|
|
extern const uint8_t *kAtr;
|
|
extern size_t kAtrLength;
|
|
extern void *kEseOpenData;
|
|
void ese_relay_init(struct EseInterface *ese);
|
|
|
|
/*
|
|
* Aligned with vpcd.h in
|
|
* https://frankmorgner.github.io/vsmartcard/virtualsmartcard
|
|
*/
|
|
#define CMD_POWER_OFF 0
|
|
#define CMD_POWER_ON 1
|
|
#define CMD_RESET 2
|
|
#define CMD_ATR 4
|
|
|
|
int setup_socket(const char *name) {
|
|
int fd;
|
|
struct sockaddr_un addr;
|
|
|
|
memset(&addr, 0, sizeof(struct sockaddr_un));
|
|
addr.sun_family = AF_UNIX;
|
|
if (strlen(name) > UNIX_PATH_MAX - 1) {
|
|
ALOGE("Abstract listener name too long.");
|
|
return -1;
|
|
}
|
|
strncpy(&addr.sun_path[1], name, strlen(name));
|
|
fd = socket(AF_UNIX, SOCK_STREAM, 0);
|
|
if (fd == -1) {
|
|
ALOGE("Could not open socket.");
|
|
return fd;
|
|
}
|
|
if (bind(fd, (struct sockaddr *)&addr,
|
|
sizeof(sa_family_t) + strlen(name) + 1) == -1) {
|
|
ALOGE("Failed to bind to abstract socket name");
|
|
close(fd);
|
|
return -1;
|
|
}
|
|
return fd;
|
|
}
|
|
|
|
int main() {
|
|
int server_fd = setup_socket(LOG_TAG);
|
|
struct EseInterface ese;
|
|
ese_relay_init(&ese);
|
|
|
|
if (listen(server_fd, 4)) {
|
|
ALOGE("Failed to listen on socket.");
|
|
close(server_fd);
|
|
return -1;
|
|
}
|
|
|
|
while (server_fd) {
|
|
struct sockaddr client_info;
|
|
socklen_t client_info_len = (socklen_t)sizeof(&client_info);
|
|
int client_fd;
|
|
uint32_t tx_len, data_read;
|
|
uint32_t rx_len;
|
|
uint16_t network_tx_len;
|
|
uint16_t network_rx_len;
|
|
uint8_t tx_buf[4096];
|
|
uint8_t rx_buf[4096];
|
|
int connected = 0;
|
|
|
|
if ((client_fd = accept(server_fd, &client_info, &client_info_len)) == -1) {
|
|
ALOGE("Fatal error accept()ing a client connection.");
|
|
return -1;
|
|
}
|
|
printf("Client connected.\n");
|
|
connected = 1;
|
|
if (ese_open(&ese, kEseOpenData)) {
|
|
ALOGE("Cannot open hw");
|
|
if (ese_error(&ese))
|
|
ALOGE("eSE error (%d): %s", ese_error_code(&ese),
|
|
ese_error_message(&ese));
|
|
return 1;
|
|
}
|
|
printf("eSE is open\n");
|
|
|
|
while (connected) {
|
|
printf("Listening for data from client\n");
|
|
if (read(client_fd, &network_tx_len, sizeof(network_tx_len)) !=
|
|
sizeof(network_tx_len)) {
|
|
ALOGE("Client disconnected.");
|
|
break;
|
|
}
|
|
tx_len = (uint32_t)ntohs(network_tx_len);
|
|
printf("tx_len: %u\n", tx_len);
|
|
if (tx_len == 0) {
|
|
ALOGE("Client had nothing to say. Goodbye.");
|
|
break;
|
|
}
|
|
if (tx_len > sizeof(tx_buf)) {
|
|
ALOGE("Client payload too large: %u", tx_len);
|
|
break;
|
|
}
|
|
for (data_read = 0; data_read < tx_len;) {
|
|
printf("Reading payload: %u of %u remaining\n", data_read, tx_len);
|
|
ssize_t bytes = read(client_fd, tx_buf + data_read, tx_len - data_read);
|
|
if (bytes < 0) {
|
|
ALOGE("Client abandoned hope during transmission.");
|
|
connected = 0;
|
|
break;
|
|
}
|
|
data_read += bytes;
|
|
}
|
|
/* Finally, we can transcieve. */
|
|
if (tx_len) {
|
|
uint32_t i;
|
|
printf("Sending %u bytes to card\n", tx_len);
|
|
printf("TX: ");
|
|
for (i = 0; i < tx_len; ++i)
|
|
printf("%.2X ", tx_buf[i]);
|
|
printf("\n");
|
|
}
|
|
|
|
if (tx_len == 1) { /* Control request */
|
|
printf("Received a control request: %x\n", tx_buf[0]);
|
|
rx_len = 0;
|
|
switch (tx_buf[0]) {
|
|
case CMD_POWER_OFF:
|
|
ese.ops->hw_reset(&ese);
|
|
break;
|
|
case CMD_POWER_ON:
|
|
break;
|
|
case CMD_RESET:
|
|
ese.ops->hw_reset(&ese);
|
|
break;
|
|
case CMD_ATR:
|
|
/* Send a dummy ATR for another JCOP card */
|
|
rx_len = kAtrLength;
|
|
printf("Filling card RX buf with fake ATR (%u)\n", rx_len);
|
|
memcpy(rx_buf, kAtr, rx_len);
|
|
printf("Sending back ATR of length %u\n", rx_len);
|
|
break;
|
|
default:
|
|
ALOGE("Unknown control byte seen: %x", tx_buf[0]);
|
|
}
|
|
if (!rx_len)
|
|
continue;
|
|
} else {
|
|
rx_len = ese_transceive(&ese, tx_buf, tx_len, rx_buf, sizeof(rx_buf));
|
|
if (ese_error(&ese)) {
|
|
ALOGE("An error (%d) occurred: %s", ese_error_code(&ese),
|
|
ese_error_message(&ese));
|
|
return -1;
|
|
}
|
|
}
|
|
if (rx_len > 0) {
|
|
uint32_t i;
|
|
printf("Read %d bytes from card\n", rx_len);
|
|
printf("RX: ");
|
|
for (i = 0; i < rx_len; ++i)
|
|
printf("%.2X ", rx_buf[i]);
|
|
printf("\n");
|
|
}
|
|
|
|
/* Send to client */
|
|
network_rx_len = htons((uint16_t)rx_len);
|
|
if (write(client_fd, &network_rx_len, sizeof(network_rx_len)) !=
|
|
sizeof(network_rx_len)) {
|
|
ALOGE("Client abandoned hope during response size.");
|
|
break;
|
|
}
|
|
|
|
for (data_read = 0; data_read < rx_len;) {
|
|
ssize_t bytes =
|
|
write(client_fd, rx_buf + data_read, rx_len - data_read);
|
|
if (bytes < 0) {
|
|
ALOGE("Client abandoned hope during response.");
|
|
connected = 0;
|
|
break;
|
|
}
|
|
data_read += bytes;
|
|
}
|
|
usleep(1000);
|
|
}
|
|
close(client_fd);
|
|
printf("Session ended\n\n");
|
|
ese_close(&ese);
|
|
}
|
|
return 0;
|
|
}
|