/// Non-maskable interrupt handler void nmi_handler(void) { // Look for the clock instability interrupt. This is a security measure // that helps prevent clock glitching. if ((RCC_CIR & RCC_CIR_CSSF) != 0) { layout_warning_static("Clock instability detected. Reboot Device!"); shutdown(); } }
static void promptRegister(bool request, const U2F_REGISTER_REQ *req) { #if 0 // Users find it confusing when a Ledger and a KeepKey are plugged in // at the same time. To avoid that, we elect not to show a message in // this case. if (0 == memcmp(req->appId, BOGUS_APPID, U2F_APPID_SIZE)) { layoutU2FDialog(request, "U2f Register", "Another U2F device was used to register in this application."); } else { #else { #endif const char *appname = ""; bool readable = getReadableAppId(req->appId, &appname); layoutU2FDialog(request, "U2F Register", readable ? "Do you want to register with %s?" : "Do you want to register with this U2F application?\n\n%s", appname); } } void u2f_register(const APDU *a) { static U2F_REGISTER_REQ last_req; const U2F_REGISTER_REQ *req = (U2F_REGISTER_REQ *)a->data; if (!storage_isInitialized()) { layout_warning_static("Cannot register u2f: not initialized"); send_u2f_error(U2F_SW_CONDITIONS_NOT_SATISFIED); delay_ms(3000); return; } // Validate basic request parameters debugLog(0, "", "u2f register"); if (APDU_LEN(*a) != sizeof(U2F_REGISTER_REQ)) { debugLog(0, "", "u2f register - badlen"); send_u2f_error(U2F_SW_WRONG_LENGTH); return; } // If this request is different from last request, reset state machine if (memcmp(&last_req, req, sizeof(last_req)) != 0) { memcpy(&last_req, req, sizeof(last_req)); last_req_state = INIT; } // First Time request, return not present and display request dialog if (last_req_state == INIT) { // error: testof-user-presence is required //buttonUpdate(); promptRegister(true, req); last_req_state = REG; } // Still awaiting Keypress if (last_req_state == REG) { // error: testof-user-presence is required send_u2f_error(U2F_SW_CONDITIONS_NOT_SATISFIED); dialog_timeout = U2F_TIMEOUT; return; } // Buttons said yes if (last_req_state == REG_PASS) { uint8_t data[sizeof(U2F_REGISTER_RESP) + 2]; U2F_REGISTER_RESP *resp = (U2F_REGISTER_RESP *)&data; memzero(data, sizeof(data)); resp->registerId = U2F_REGISTER_ID; resp->keyHandleLen = KEY_HANDLE_LEN; // Generate keypair for this appId const HDNode *node = generateKeyHandle(req->appId, (uint8_t*)&resp->keyHandleCertSig); if (!node) { debugLog(0, "", "getDerivedNode Fail"); send_u2f_error(U2F_SW_WRONG_DATA); // error:bad key handle return; } ecdsa_get_public_key65(node->curve->params, node->private_key, (uint8_t *)&resp->pubKey); memcpy(resp->keyHandleCertSig + resp->keyHandleLen, U2F_ATT_CERT, sizeof(U2F_ATT_CERT)); uint8_t sig[64]; U2F_REGISTER_SIG_STR sig_base; sig_base.reserved = 0; memcpy(sig_base.appId, req->appId, U2F_APPID_SIZE); memcpy(sig_base.chal, req->chal, U2F_CHAL_SIZE); memcpy(sig_base.keyHandle, &resp->keyHandleCertSig, KEY_HANDLE_LEN); memcpy(sig_base.pubKey, &resp->pubKey, U2F_PUBKEY_LEN); if (ecdsa_sign(&nist256p1, HASHER_SHA2, U2F_ATT_PRIV_KEY, (uint8_t *)&sig_base, sizeof(sig_base), sig, NULL, NULL) != 0) { send_u2f_error(U2F_SW_WRONG_DATA); return; } // Where to write the signature in the response uint8_t *resp_sig = resp->keyHandleCertSig + resp->keyHandleLen + sizeof(U2F_ATT_CERT); // Convert to der for the response const uint8_t sig_len = ecdsa_sig_to_der(sig, resp_sig); // Append success bytes memcpy(resp->keyHandleCertSig + resp->keyHandleLen + sizeof(U2F_ATT_CERT) + sig_len, "\x90\x00", 2); int l = 1 /* registerId */ + U2F_PUBKEY_LEN + 1 /* keyhandleLen */ + resp->keyHandleLen + sizeof(U2F_ATT_CERT) + sig_len + 2; last_req_state = INIT; dialog_timeout = 0; send_u2f_msg(data, l); promptRegister(false, req); return; } // Didnt expect to get here dialog_timeout = 0; } static void promptAuthenticate(bool request, const U2F_AUTHENTICATE_REQ *req) { const char *appname = ""; bool readable = getReadableAppId(req->appId, &appname); layoutU2FDialog(request, "U2F Authenticate", readable ? "Log in to %s?" : "Do you want to log in?\n\n%s", appname); } void u2f_authenticate(const APDU *a) { const U2F_AUTHENTICATE_REQ *req = (U2F_AUTHENTICATE_REQ *)a->data; static U2F_AUTHENTICATE_REQ last_req; if (!storage_isInitialized()) { layout_warning_static("Cannot authenticate u2f: not initialized"); send_u2f_error(U2F_SW_CONDITIONS_NOT_SATISFIED); delay_ms(3000); return; } if (APDU_LEN(*a) < 64) { /// FIXME: decent value debugLog(0, "", "u2f authenticate - badlen"); send_u2f_error(U2F_SW_WRONG_LENGTH); return; } if (req->keyHandleLen != KEY_HANDLE_LEN) { debugLog(0, "", "u2f auth - bad keyhandle len"); send_u2f_error(U2F_SW_WRONG_DATA); // error:bad key handle return; } const HDNode *node = validateKeyHandle(req->appId, req->keyHandle); if (!node) { debugLog(0, "", "u2f auth - bad keyhandle len"); send_u2f_error(U2F_SW_WRONG_DATA); // error:bad key handle return; } if (a->p1 == U2F_AUTH_CHECK_ONLY) { debugLog(0, "", "u2f authenticate check"); // This is a success for a good keyhandle // A failed check would have happened earlier // error: testof-user-presence is required send_u2f_error(U2F_SW_CONDITIONS_NOT_SATISFIED); return; } if (a->p1 != U2F_AUTH_ENFORCE) { debugLog(0, "", "u2f authenticate unknown"); // error:bad key handle send_u2f_error(U2F_SW_WRONG_DATA); return; } debugLog(0, "", "u2f authenticate enforce"); if (memcmp(&last_req, req, sizeof(last_req)) != 0) { memcpy(&last_req, req, sizeof(last_req)); last_req_state = INIT; } if (last_req_state == INIT) { // error: testof-user-presence is required //buttonUpdate(); // Clear button state promptAuthenticate(true, req); last_req_state = AUTH; } // Awaiting Keypress if (last_req_state == AUTH) { // error: testof-user-presence is required send_u2f_error(U2F_SW_CONDITIONS_NOT_SATISFIED); dialog_timeout = U2F_TIMEOUT; return; } // Buttons said yes if (last_req_state == AUTH_PASS) { uint8_t buf[sizeof(U2F_AUTHENTICATE_RESP) + 2]; U2F_AUTHENTICATE_RESP *resp = (U2F_AUTHENTICATE_RESP *)&buf; const uint32_t ctr = storage_nextU2FCounter(); resp->flags = U2F_AUTH_FLAG_TUP; resp->ctr[0] = ctr >> 24 & 0xff; resp->ctr[1] = ctr >> 16 & 0xff; resp->ctr[2] = ctr >> 8 & 0xff; resp->ctr[3] = ctr & 0xff; // Build and sign response U2F_AUTHENTICATE_SIG_STR sig_base; uint8_t sig[64]; memcpy(sig_base.appId, req->appId, U2F_APPID_SIZE); sig_base.flags = resp->flags; memcpy(sig_base.ctr, resp->ctr, 4); memcpy(sig_base.chal, req->chal, U2F_CHAL_SIZE); if (ecdsa_sign(&nist256p1, HASHER_SHA2, node->private_key, (uint8_t *)&sig_base, sizeof(sig_base), sig, NULL, NULL) != 0) { send_u2f_error(U2F_SW_WRONG_DATA); return; } // Copy DER encoded signature into response const uint8_t sig_len = ecdsa_sig_to_der(sig, resp->sig); // Append OK memcpy(buf + sizeof(U2F_AUTHENTICATE_RESP) - U2F_MAX_EC_SIG_SIZE + sig_len, "\x90\x00", 2); last_req_state = INIT; dialog_timeout = 0; send_u2f_msg(buf, sizeof(U2F_AUTHENTICATE_RESP) - U2F_MAX_EC_SIG_SIZE + sig_len + 2); promptAuthenticate(false, req); } }
/* * __stack_chk_fail() - Stack smashing protector (SSP) call back funcation * for -fstack-protector-all GCC option * * INPUT * none * OUTPUT * none */ __attribute__((noreturn)) void __stack_chk_fail(void) { layout_warning_static("Error Detected. Reboot Device!"); shutdown(); }
/* * storage_commit() - Write content of configuration in shadow memory to * storage partion in flash * * INPUT * none * OUTPUT * none */ void storage_commit(void) { uint32_t shadow_ram_crc32, shadow_flash_crc32, retries; memcpy((void *)&shadow_config, STORAGE_MAGIC_STR, STORAGE_MAGIC_LEN); for(retries = 0; retries < STORAGE_RETRIES; retries++) { /* Capture CRC for verification at restore */ shadow_ram_crc32 = calc_crc32((uint32_t *)&shadow_config, sizeof(shadow_config) / sizeof(uint32_t)); if(shadow_ram_crc32 == 0) { continue; /* Retry */ } /* Make sure flash is in good state before proceeding */ if(!flash_chk_status()) { flash_clear_status_flags(); continue; /* Retry */ } /* Make sure storage sector is valid before proceeding */ if(storage_location < FLASH_STORAGE1 && storage_location > FLASH_STORAGE3) { /* Let it exhaust the retries and error out */ continue; } flash_unlock(); flash_erase_word(storage_location); wear_leveling_shift(); flash_erase_word(storage_location); /* Load storage data first before loading storage magic */ if(flash_write_word(storage_location, STORAGE_MAGIC_LEN, sizeof(shadow_config) - STORAGE_MAGIC_LEN, (uint8_t *)&shadow_config + STORAGE_MAGIC_LEN)) { if(!flash_write_word(storage_location, 0, STORAGE_MAGIC_LEN, (uint8_t *)&shadow_config)) { continue; /* Retry */ } } else { continue; /* Retry */ } /* Flash write completed successfully. Verify CRC */ shadow_flash_crc32 = calc_crc32((uint32_t *)flash_write_helper( storage_location), sizeof(shadow_config) / sizeof(uint32_t)); if(shadow_flash_crc32 == shadow_ram_crc32) { /* Commit successful, break to exit */ break; } else { continue; /* Retry */ } } flash_lock(); if(retries >= STORAGE_RETRIES) { layout_warning_static("Error Detected. Reboot Device!"); system_halt(); } }
static void update_bootloader(void) { layout_warning_static("Please update your bootloader."); shutdown(); }
static void unknown_bootloader(void) { layout_warning_static("Unknown bootloader. Contact support."); shutdown(); }