/* * 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 #include #include #include #include #include #include #define LOG_TAG "ese-relay" #include #include 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; }