Line data Source code
1 : #include <string.h> 2 : #include <openenclave/enclave.h> 3 : 4 : #include "hal/constants.h" 5 : #include "hal/communication.h" 6 : #include "hal/seed.h" 7 : #include "hal/access.h" 8 : #include "hal/endorsement.h" 9 : #include "hal/nvmem.h" 10 : #include "hal/exceptions.h" 11 : #include "hal/log.h" 12 : 13 : #include "secret_store.h" 14 : #include "hsm.h" 15 : #include "apdu.h" 16 : #include "instructions.h" 17 : #include "modes.h" 18 : #include "bc_state.h" 19 : #include "err.h" 20 : #include "bc_err.h" 21 : #include "upgrade.h" 22 : #include "evidence.h" 23 : #include "meta_bc.h" 24 : 25 : /** 26 : * APDU buffer (host pointer and local enclave copy) 27 : */ 28 : #define APDU_BUFFER_SIZE (2048 + 5) 29 : 30 : static unsigned char* host_apdu_buffer; 31 : static unsigned char apdu_buffer[APDU_BUFFER_SIZE]; 32 : 33 2 : static void wipe_system() { 34 2 : seed_wipe(); 35 2 : access_wipe(); 36 2 : } 37 : 38 0 : static void on_access_wiped() { 39 0 : if (!seed_wipe()) { 40 : LOG("Error wiping seed module\n"); 41 : } 42 : LOG("Seed wiped\n"); 43 0 : } 44 : 45 5 : static unsigned int do_onboard(unsigned int rx) { 46 : // Validations 47 5 : if (seed_available()) { 48 1 : THROW(ERR_DEVICE_ONBOARDED); 49 : } 50 : 51 : // Require seed plus a nonblank password 52 4 : if (APDU_DATA_SIZE(rx) < SEED_LENGTH + 1) { 53 1 : THROW(ERR_INVALID_DATA_SIZE); 54 : } 55 : 56 : // Onboarding 57 : uint8_t tmp_buffer[sizeof(apdu_buffer)]; 58 3 : memcpy(tmp_buffer, APDU_DATA_PTR, SEED_LENGTH); 59 3 : if (!seed_generate(tmp_buffer, SEED_LENGTH)) { 60 1 : wipe_system(); 61 1 : THROW(ERR_ONBOARDING); 62 : } 63 : 64 2 : size_t password_length = APDU_DATA_SIZE(rx) - SEED_LENGTH; 65 2 : memcpy(tmp_buffer, APDU_DATA_PTR + SEED_LENGTH, password_length); 66 2 : if (!access_set_password((char*)tmp_buffer, password_length)) { 67 1 : wipe_system(); 68 1 : THROW(ERR_ONBOARDING); 69 : } 70 : 71 1 : SET_APDU_OP(1); 72 1 : return TX_NO_DATA(); 73 : } 74 : 75 3 : static unsigned int do_change_password(unsigned int rx) { 76 : // Require a nonblank password 77 3 : if (APDU_DATA_SIZE(rx) < 1) { 78 1 : THROW(ERR_INVALID_DATA_SIZE); 79 : } 80 : 81 : // Password change 82 : uint8_t tmp_buffer[sizeof(apdu_buffer)]; 83 2 : size_t password_length = APDU_DATA_SIZE(rx); 84 2 : memcpy(tmp_buffer, APDU_DATA_PTR, password_length); 85 2 : if (!access_set_password((char*)tmp_buffer, password_length)) { 86 1 : THROW(ERR_PASSWORD_CHANGE); 87 : } 88 : 89 1 : SET_APDU_OP(1); 90 1 : return TX_NO_DATA(); 91 : } 92 : 93 3 : static unsigned int do_unlock(unsigned int rx) { 94 3 : if (!access_is_locked()) { 95 1 : SET_APDU_OP(1); 96 1 : return TX_NO_DATA(); 97 : } 98 : 99 2 : if (APDU_DATA_SIZE(rx) == 0) { 100 1 : THROW(ERR_INVALID_DATA_SIZE); 101 : } 102 : 103 1 : SET_APDU_OP(access_unlock((char*)APDU_DATA_PTR, APDU_DATA_SIZE(rx)) ? 1 104 : : 0); 105 1 : return TX_NO_DATA(); 106 : } 107 : 108 1 : static unsigned int do_echo(unsigned int rx) { 109 1 : return rx; 110 : } 111 : 112 : static unsigned char curr_cmd; 113 : 114 35 : static void reset_unless_cmd_is(unsigned char cmd) { 115 35 : if (cmd != curr_cmd) { 116 : // Reset all modules' contexts 117 27 : hsm_reset_if_starting(cmd); 118 27 : upgrade_reset(); 119 27 : curr_cmd = cmd; 120 : } 121 35 : } 122 : 123 41 : static external_processor_result_t system_do_process_apdu(unsigned int rx) { 124 41 : external_processor_result_t result = { 125 : .handled = true, 126 : .tx = 0, 127 : }; 128 : 129 41 : switch (APDU_CMD()) { 130 : // Reports the bootloader mode only if the device is locked 131 : // Otherwise command is ignored and the powHSM handler will 132 : // take over instead. 133 2 : case RSK_MODE_CMD: 134 2 : if (access_is_locked()) { 135 1 : reset_unless_cmd_is(RSK_MODE_CMD); 136 1 : SET_APDU_CMD(APP_MODE_BOOTLOADER); 137 1 : result.tx = 2; 138 1 : break; 139 : } 140 1 : result.handled = false; 141 1 : break; 142 5 : case SGX_ONBOARD: 143 5 : reset_unless_cmd_is(SGX_ONBOARD); 144 5 : result.tx = do_onboard(rx); 145 1 : break; 146 4 : case SGX_IS_LOCKED: 147 4 : REQUIRE_ONBOARDED(); 148 4 : reset_unless_cmd_is(SGX_IS_LOCKED); 149 4 : SET_APDU_OP(access_is_locked() ? 1 : 0); 150 4 : result.tx = TX_NO_DATA(); 151 4 : break; 152 1 : case SGX_RETRIES: 153 1 : REQUIRE_ONBOARDED(); 154 1 : reset_unless_cmd_is(SGX_RETRIES); 155 1 : SET_APDU_OP(access_get_retries()); 156 1 : result.tx = TX_NO_DATA(); 157 1 : break; 158 3 : case SGX_UNLOCK: 159 3 : REQUIRE_ONBOARDED(); 160 3 : reset_unless_cmd_is(SGX_UNLOCK); 161 3 : result.tx = do_unlock(rx); 162 2 : break; 163 1 : case SGX_ECHO: 164 1 : reset_unless_cmd_is(SGX_ECHO); 165 1 : result.tx = do_echo(rx); 166 1 : break; 167 3 : case SGX_CHANGE_PASSWORD: 168 3 : REQUIRE_ONBOARDED(); 169 3 : REQUIRE_UNLOCKED(); 170 3 : reset_unless_cmd_is(SGX_CHANGE_PASSWORD); 171 3 : result.tx = do_change_password(rx); 172 1 : break; 173 5 : case SGX_UPGRADE: 174 5 : reset_unless_cmd_is(SGX_UPGRADE); 175 5 : result.tx = upgrade_process_apdu(rx); 176 5 : break; 177 1 : case INS_HEARTBEAT: 178 : // For now, we don't support heartbeat in SGX 179 1 : THROW(ERR_INS_NOT_SUPPORTED); 180 : break; 181 : // Override the default hsm module handlers for these 182 : // commands 183 14 : case INS_ADVANCE: 184 : case INS_UPD_ANCESTOR: 185 14 : REQUIRE_UNLOCKED(); 186 12 : REQUIRE_ONBOARDED(); 187 10 : reset_unless_cmd_is(APDU_CMD()); 188 10 : result.tx = do_meta_advupd(rx); 189 10 : break; 190 2 : default: 191 2 : reset_unless_cmd_is(0); 192 2 : result.handled = false; 193 : } 194 : 195 29 : return result; 196 : } 197 : 198 41 : unsigned int system_process_apdu(unsigned int rx) { 199 : // Copy host APDU => enclave APDU 200 41 : memcpy(apdu_buffer, host_apdu_buffer, sizeof(apdu_buffer)); 201 41 : unsigned int tx = hsm_process_apdu(rx); 202 : // Copy enclave APDU => host APDU 203 29 : memcpy(host_apdu_buffer, apdu_buffer, sizeof(apdu_buffer)); 204 29 : return tx; 205 : } 206 : 207 44 : bool system_init(unsigned char* msg_buffer, size_t msg_buffer_size) { 208 : // Validate that host and enclave APDU buffers have the same size 209 44 : if (msg_buffer_size != sizeof(apdu_buffer)) { 210 : LOG("Expected APDU buffer size to be %lu but got %lu\n", 211 : sizeof(apdu_buffer), 212 : msg_buffer_size); 213 1 : return false; 214 : } 215 : 216 : // Validate that the host APDU buffer is entirely outside the enclave 217 : // memory space 218 43 : if (!oe_is_outside_enclave(msg_buffer, msg_buffer_size)) { 219 : LOG("APDU buffer memory area not outside the enclave\n"); 220 1 : return false; 221 : } 222 : 223 : // Set the pointer to the host APDU buffer 224 42 : host_apdu_buffer = msg_buffer; 225 : 226 : // Initialize modules 227 : LOG("Initializing modules...\n"); 228 42 : if (!sest_init()) { 229 : LOG("Error initializing secret store module\n"); 230 1 : return false; 231 : } 232 : 233 41 : if (!access_init(on_access_wiped)) { 234 : LOG("Error initializing access module\n"); 235 1 : return false; 236 : } 237 : 238 40 : if (!seed_init()) { 239 : LOG("Error initializing seed module\n"); 240 1 : return false; 241 : } 242 : 243 : // Make sure both access and seed are in the same state 244 39 : if (!seed_available() ^ access_is_wiped()) { 245 : LOG("Inconsistent system state detected\n"); 246 33 : if (!access_wipe() || !seed_wipe()) { 247 : LOG("System wipe failed\n"); 248 2 : return false; 249 : } 250 : LOG("System wiped\n"); 251 : } 252 : 253 37 : if (!communication_init(apdu_buffer, sizeof(apdu_buffer))) { 254 : LOG("Error initializing communication module\n"); 255 1 : return false; 256 : } 257 : 258 36 : if (!evidence_init()) { 259 : LOG("Error initializing evidence module\n"); 260 1 : return false; 261 : } 262 : 263 35 : if (!endorsement_init()) { 264 : LOG("Error initializing endorsement module\n"); 265 1 : return false; 266 : } 267 : 268 34 : nvmem_init(); 269 34 : if (!nvmem_register_block( 270 : "bcstate", &N_bc_state_var, sizeof(N_bc_state_var))) { 271 : LOG("Error registering bcstate block\n"); 272 1 : return false; 273 : } 274 33 : if (!nvmem_register_block("bcstate_updating", 275 : &N_bc_state_updating_backup_var, 276 : sizeof(N_bc_state_updating_backup_var))) { 277 : LOG("Error registering bcstate_updating block\n"); 278 1 : return false; 279 : } 280 : 281 32 : if (!nvmem_load()) { 282 : LOG("Error loading nvmem\n"); 283 1 : return false; 284 : } 285 : 286 31 : upgrade_init(); 287 : 288 : LOG("Modules initialized\n"); 289 : 290 : LOG("Initializing powHSM...\n"); 291 31 : hsm_init(); 292 31 : hsm_set_external_processor(system_do_process_apdu); 293 31 : curr_cmd = 0; 294 : LOG("powHSM initialized\n"); 295 : 296 31 : return true; 297 : } 298 : 299 0 : void system_finalise() { 300 : // Finalise modules 301 0 : endorsement_finalise(); 302 0 : evidence_finalise(); 303 0 : }