Line data Source code
1 : /** 2 : * The MIT License (MIT) 3 : * 4 : * Copyright (c) 2021 RSK Labs Ltd 5 : * 6 : * Permission is hereby granted, free of charge, to any person obtaining a copy 7 : * of this software and associated documentation files (the "Software"), to 8 : * deal in the Software without restriction, including without limitation the 9 : * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 10 : * sell copies of the Software, and to permit persons to whom the Software is 11 : * furnished to do so, subject to the following conditions: 12 : * 13 : * The above copyright notice and this permission notice shall be included in 14 : * all copies or substantial portions of the Software. 15 : * 16 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 : * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 : * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 22 : * IN THE SOFTWARE. 23 : */ 24 : 25 : #ifndef __TRUSTED_META_BC_H 26 : #define __TRUSTED_META_BC_H 27 : 28 : #include <stdlib.h> 29 : #include <stdint.h> 30 : #include <string.h> 31 : 32 : #include "meta_bc.h" 33 : 34 : #include "hal/exceptions.h" 35 : #include "hal/log.h" 36 : 37 : #include "apdu.h" 38 : #include "instructions.h" 39 : #include "err.h" 40 : 41 : #include "bc_advance.h" 42 : #include "bc_ancestor.h" 43 : #include "bc_err.h" 44 : 45 : #define MAX_CHUNK_SIZE 80 46 : #define CHUNK_OVERHEAD 5 47 : 48 26 : unsigned int do_meta_advupd(unsigned int rx) { 49 : uint8_t cmd; 50 : uint8_t internal_buffer[MAX_CHUNK_SIZE + CHUNK_OVERHEAD]; 51 : uint8_t* old_buffer; 52 : size_t old_buffer_size; 53 : 54 26 : cmd = APDU_CMD(); 55 : 56 : // Backup message buffer spec 57 26 : old_buffer = communication_get_msg_buffer(); 58 26 : old_buffer_size = communication_get_msg_buffer_size(); 59 : 60 : // Set new buffer 61 26 : communication_set_msg_buffer(internal_buffer, sizeof(internal_buffer)); 62 : 63 : // Send data in chunks 64 26 : unsigned int total_data = APDU_DATA_SIZE(rx); 65 26 : unsigned int data_offset = 0; 66 26 : unsigned int chunk_size = 67 : total_data < MAX_CHUNK_SIZE ? total_data : MAX_CHUNK_SIZE; 68 26 : unsigned int irx = 0; 69 : 70 : BEGIN_TRY { 71 26 : TRY { 72 : // Initialize internal buffer for soundness 73 26 : memcpy(internal_buffer, old_buffer, rx < DATA ? rx : DATA); 74 26 : if (rx < DATA) 75 1 : SET_APDU_OP(0); 76 : 77 59 : while (data_offset < total_data) { 78 50 : SET_APDU_CLA(); 79 50 : SET_APDU_CMD(cmd); 80 50 : SET_APDU_OP(old_buffer[OP]); 81 50 : if (chunk_size == 0 || chunk_size > APDU_TOTAL_DATA_SIZE) { 82 : // This shouldn't happen 83 2 : THROW(ERR_INTERNAL); 84 : } 85 48 : if (chunk_size > total_data - data_offset) { 86 : // Not enough data 87 1 : THROW(PROT_INVALID); 88 : } 89 94 : memcpy( 90 47 : APDU_DATA_PTR, &old_buffer[DATA + data_offset], chunk_size); 91 47 : irx = TX_FOR_DATA_SIZE(chunk_size); 92 : LOG_HEX("ITX >", internal_buffer, irx); 93 47 : switch (cmd) { 94 23 : case INS_ADVANCE: 95 23 : irx = bc_advance(irx); 96 22 : break; 97 23 : case INS_UPD_ANCESTOR: 98 23 : irx = bc_upd_ancestor(irx); 99 22 : break; 100 1 : default: 101 : // We should never reach this point 102 1 : THROW(ERR_INTERNAL); 103 : } 104 : LOG_HEX("ITX <", internal_buffer, irx); 105 : // Validate response 106 44 : if (irx != TX_FOR_TXLEN() && irx != TX_NO_DATA()) { 107 : LOG("Unexpected response size\n"); 108 1 : THROW(ERR_INTERNAL); 109 : } 110 43 : if (APDU_CLA() != CLA || APDU_CMD() != cmd) { 111 : LOG("Unexpected response command\n"); 112 2 : THROW(ERR_INTERNAL); 113 : } 114 : // Done? 115 41 : if (APDU_OP() != old_buffer[OP]) { 116 8 : break; 117 : } 118 33 : data_offset += chunk_size; 119 33 : chunk_size = APDU_TXLEN(); 120 : } 121 : 122 : // Restore message buffer 123 17 : communication_set_msg_buffer(old_buffer, old_buffer_size); 124 : 125 : // Response 126 17 : SET_APDU_OP(internal_buffer[OP]); 127 17 : if (irx == TX_FOR_DATA_SIZE(1)) { 128 8 : SET_APDU_TXLEN(internal_buffer[DATA]); 129 17 : return TX_FOR_TXLEN(); 130 : } else { 131 9 : return TX_NO_DATA(); 132 : } 133 : } 134 9 : CATCH_OTHER(e) { 135 : // Restore message buffer 136 9 : communication_set_msg_buffer(old_buffer, old_buffer_size); 137 : // Forward 138 9 : THROW(e); 139 : } 140 : FINALLY { 141 : } 142 : } 143 : END_TRY; 144 : } 145 : 146 : #endif // __TRUSTED_META_BC_H