apdu_runner.c 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. #include "apdu_runner.h"
  2. #define TAG "APDU_Runner"
  3. // Max length of firmware upgrade: 731 bytes
  4. #define SEADER_APDU_MAX_LEN 732
  5. void seader_apdu_runner_cleanup(Seader* seader, SeaderWorkerEvent event) {
  6. SeaderWorker* seader_worker = seader->worker;
  7. seader_worker_change_state(seader_worker, SeaderWorkerStateReady);
  8. apdu_log_free(seader->apdu_log);
  9. seader->apdu_log = NULL;
  10. if(seader_worker->callback) {
  11. seader_worker->callback(event, seader_worker->context);
  12. }
  13. }
  14. bool seader_apdu_runner_send_next_line(Seader* seader) {
  15. SeaderWorker* seader_worker = seader->worker;
  16. SeaderUartBridge* seader_uart = seader_worker->uart;
  17. SeaderAPDURunnerContext* apdu_runner_ctx = &(seader->apdu_runner_ctx);
  18. FuriString* line = furi_string_alloc();
  19. apdu_log_get_next_log_str(seader->apdu_log, line);
  20. size_t len = furi_string_size(line) / 2; // String is in HEX, divide by 2 for bytes
  21. uint8_t* apdu = malloc(len);
  22. if(apdu == NULL) {
  23. FURI_LOG_E(TAG, "Failed to allocate memory for APDU");
  24. seader_apdu_runner_cleanup(seader, SeaderWorkerEventAPDURunnerError);
  25. return false;
  26. }
  27. if(len > SEADER_UART_RX_BUF_SIZE) {
  28. FURI_LOG_E(TAG, "APDU length is too long");
  29. seader_apdu_runner_cleanup(seader, SeaderWorkerEventAPDURunnerError);
  30. free(apdu);
  31. return false;
  32. }
  33. if(!hex_chars_to_uint8(furi_string_get_cstr(line), apdu)) {
  34. FURI_LOG_E(TAG, "Failed to convert line to number");
  35. seader_apdu_runner_cleanup(seader, SeaderWorkerEventAPDURunnerError);
  36. free(apdu);
  37. return false;
  38. }
  39. FURI_LOG_I(
  40. TAG,
  41. "APDU Runner => (%d/%d): %s",
  42. apdu_runner_ctx->current_line,
  43. apdu_runner_ctx->total_lines,
  44. furi_string_get_cstr(line));
  45. if(seader_worker->callback) {
  46. seader_worker->callback(SeaderWorkerEventAPDURunnerUpdate, seader_worker->context);
  47. }
  48. apdu_runner_ctx->current_line++;
  49. if(seader_uart->T == 1) {
  50. seader_send_t1(seader_uart, apdu, len);
  51. } else {
  52. seader_ccid_XfrBlock(seader_uart, apdu, len);
  53. }
  54. furi_string_free(line);
  55. free(apdu);
  56. return true;
  57. }
  58. void seader_apdu_runner_init(Seader* seader) {
  59. SeaderAPDURunnerContext* apdu_runner_ctx = &(seader->apdu_runner_ctx);
  60. if(apdu_log_check_presence(SEADER_APDU_RUNNER_FILE_NAME)) {
  61. FURI_LOG_I(TAG, "APDU log file exists");
  62. } else {
  63. FURI_LOG_W(TAG, "APDU log file does not exist");
  64. return;
  65. }
  66. seader->apdu_log = apdu_log_alloc(SEADER_APDU_RUNNER_FILE_NAME, APDULogModeOpenExisting);
  67. apdu_runner_ctx->current_line = 0;
  68. apdu_runner_ctx->total_lines = apdu_log_get_total_lines(seader->apdu_log);
  69. FURI_LOG_I(TAG, "APDU log lines: %d", apdu_runner_ctx->total_lines);
  70. seader_apdu_runner_send_next_line(seader);
  71. }
  72. bool seader_apdu_runner_response(Seader* seader, uint8_t* r_apdu, size_t r_len) {
  73. SeaderUartBridge* seader_uart = seader->worker->uart;
  74. SeaderAPDURunnerContext* apdu_runner_ctx = &(seader->apdu_runner_ctx);
  75. uint8_t GET_RESPONSE[] = {0x00, 0xc0, 0x00, 0x00, 0xff};
  76. uint8_t SW1 = r_apdu[r_len - 2];
  77. uint8_t SW2 = r_apdu[r_len - 1];
  78. switch(SW1) {
  79. case 0x61:
  80. //FURI_LOG_D(TAG, "Request %d bytes", SW2);
  81. GET_RESPONSE[4] = SW2;
  82. seader_ccid_XfrBlock(seader_uart, GET_RESPONSE, sizeof(GET_RESPONSE));
  83. return true;
  84. }
  85. if(r_len < SEADER_UART_RX_BUF_SIZE) {
  86. char* display = malloc(r_len * 2 + 1);
  87. if(display == NULL) {
  88. FURI_LOG_E(TAG, "Failed to allocate memory for display");
  89. seader_apdu_runner_cleanup(seader, SeaderWorkerEventAPDURunnerError);
  90. return false;
  91. }
  92. memset(display, 0, r_len * 2 + 1);
  93. for(uint8_t i = 0; i < r_len; i++) {
  94. snprintf(display + (i * 2), sizeof(display), "%02x", r_apdu[i]);
  95. }
  96. FURI_LOG_I(
  97. TAG,
  98. "APDU Runner <=: (%d/%d): %s",
  99. apdu_runner_ctx->current_line,
  100. apdu_runner_ctx->total_lines,
  101. display);
  102. free(display);
  103. } else {
  104. FURI_LOG_I(TAG, "APDU Runner <=: Response too long to display");
  105. }
  106. /** Compare last two bytes to expected line **/
  107. FuriString* line = furi_string_alloc();
  108. apdu_log_get_next_log_str(seader->apdu_log, line);
  109. if(furi_string_size(line) % 2 == 1) {
  110. FURI_LOG_E(TAG, "APDU log file has odd number of characters");
  111. seader_apdu_runner_cleanup(seader, SeaderWorkerEventAPDURunnerError);
  112. return false;
  113. }
  114. size_t len = furi_string_size(line) / 2; // String is in HEX, divide by 2 for bytes
  115. uint8_t* apdu = malloc(len);
  116. if(apdu == NULL) {
  117. FURI_LOG_E(TAG, "Failed to allocate memory for APDU");
  118. seader_apdu_runner_cleanup(seader, SeaderWorkerEventAPDURunnerError);
  119. return false;
  120. }
  121. if(!hex_chars_to_uint8(furi_string_get_cstr(line), apdu)) {
  122. FURI_LOG_E(TAG, "Failed to convert line to byte array");
  123. seader_apdu_runner_cleanup(seader, SeaderWorkerEventAPDURunnerError);
  124. free(apdu);
  125. // TODO: Send failed event
  126. return false;
  127. }
  128. apdu_runner_ctx->current_line++;
  129. furi_string_free(line);
  130. if(memcmp(r_apdu + r_len - 2, apdu + len - 2, 2) != 0) {
  131. FURI_LOG_W(
  132. TAG,
  133. "APDU runner response does not match. Response %02x%02x != expected %02x%02x",
  134. r_apdu[r_len - 2],
  135. r_apdu[r_len - 1],
  136. apdu[len - 2],
  137. apdu[len - 1]);
  138. seader_apdu_runner_cleanup(seader, SeaderWorkerEventAPDURunnerError);
  139. free(apdu);
  140. return false;
  141. }
  142. free(apdu);
  143. // Check if we are at the end of the log
  144. if(apdu_runner_ctx->current_line >= apdu_runner_ctx->total_lines) {
  145. FURI_LOG_I(TAG, "APDU runner finished");
  146. seader_apdu_runner_cleanup(seader, SeaderWorkerEventAPDURunnerSuccess);
  147. return false;
  148. }
  149. // Send next line
  150. return seader_apdu_runner_send_next_line(seader);
  151. }