Example #1
0
void fsm_msgInitialize(Initialize *msg)
{
	(void)msg;
	recovery_abort();
	signing_abort();
	RESP_INIT(Features);
	resp->has_vendor = true;         strlcpy(resp->vendor, "bitcointrezor.com", sizeof(resp->vendor));
	resp->has_major_version = true;  resp->major_version = VERSION_MAJOR;
	resp->has_minor_version = true;  resp->minor_version = VERSION_MINOR;
	resp->has_patch_version = true;  resp->patch_version = VERSION_PATCH;
	resp->has_device_id = true;      strlcpy(resp->device_id, storage_uuid_str, sizeof(resp->device_id));
	resp->has_pin_protection = true; resp->pin_protection = storage.has_pin;
	resp->has_passphrase_protection = true; resp->passphrase_protection = storage.has_passphrase_protection && storage.passphrase_protection;
#ifdef SCM_REVISION
	int len = sizeof(SCM_REVISION) - 1;
	resp->has_revision = true; memcpy(resp->revision.bytes, SCM_REVISION, len); resp->revision.size = len;
#endif
	resp->has_bootloader_hash = true; resp->bootloader_hash.size = memory_bootloader_hash(resp->bootloader_hash.bytes);
	if (storage.has_language) {
		resp->has_language = true;
		strlcpy(resp->language, storage.language, sizeof(resp->language));
	}
	if (storage.has_label) {
		resp->has_label = true;
		strlcpy(resp->label, storage.label, sizeof(resp->label));
	}
	resp->coins_count = COINS_COUNT;
	memcpy(resp->coins, coins, COINS_COUNT * sizeof(CoinType));
	resp->has_initialized = true; resp->initialized = storage_isInitialized();
	resp->has_imported = true; resp->imported = storage.has_imported && storage.imported;
	msg_write(MessageType_MessageType_Features, resp);
}
Example #2
0
void fsm_msgLoadDevice(LoadDevice *msg)
{
	if (storage_isInitialized()) {
		fsm_sendFailure(FailureType_Failure_UnexpectedMessage, "Device is already initialized. Use Wipe first.");
		return;
	}

	layoutDialogSwipe(DIALOG_ICON_QUESTION, "Cancel", "I take the risk", NULL, "Loading private seed", "is not recommended.", "Continue only if you", "know what you are", "doing!", NULL);
	if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) {
		fsm_sendFailure(FailureType_Failure_ActionCancelled, "Load cancelled");
		layoutHome();
		return;
	}

	if (msg->has_mnemonic && !(msg->has_skip_checksum && msg->skip_checksum) ) {
		if (!mnemonic_check(msg->mnemonic)) {
			fsm_sendFailure(FailureType_Failure_ActionCancelled, "Mnemonic with wrong checksum provided");
			layoutHome();
			return;
		}
	}

	storage_loadDevice(msg);
	storage_commit();
	fsm_sendSuccess("Device loaded");
	layoutHome();
}
Example #3
0
int main(void)
{
    _buttonusr_isr = (void *)&buttonisr_usr;
    _timerusr_isr = (void *)&timerisr_usr;
    _mmhusr_isr = (void *)&mmhisr;

    /* Drop privileges */
    drop_privs();

    /* Init board */
    kk_board_init();

    /* Program the model into OTP, if we're not in screen-test mode, and it's
     * not already there
     */
    (void)flash_programModel();

    /* Init for safeguard against stack overflow (-fstack-protector-all) */
    __stack_chk_guard = (uintptr_t)random32();

    /* Bootloader Verification */
    check_bootloader();

    led_func(SET_RED_LED);
    dbg_print("Application Version %d.%d.%d\n\r", MAJOR_VERSION, MINOR_VERSION,
              PATCH_VERSION);

    /* Init storage */
    storage_init();

    /* Init protcol buffer message map and usb msg callback */
    fsm_init();

    led_func(SET_GREEN_LED);

    usbInit();
    u2fInit();
    led_func(CLR_RED_LED);

    reset_idle_time();

    if (is_mfg_mode())
        layout_screen_test();
    else if (!storage_isInitialized())
        layout_standard_notification("Welcome", "keepkey.com/get-started",
                                     NOTIFICATION_LOGO);
    else
        layoutHomeForced();

    while (1) {
        delay_ms_with_callback(ONE_SEC, &exec, 1);
        increment_idle_time(ONE_SEC);
        toggle_screensaver();
    }

    return 0;
}
Example #4
0
void fsm_msgRecoveryDevice(RecoveryDevice *msg)
{
	if (storage_isInitialized()) {
		fsm_sendFailure(FailureType_Failure_UnexpectedMessage, "Device is already initialized. Use Wipe first.");
		return;
	}
	recovery_init(
		msg->has_word_count ? msg->word_count : 12,
		msg->has_passphrase_protection && msg->passphrase_protection,
		msg->has_pin_protection && msg->pin_protection,
		msg->has_language ? msg->language : 0,
		msg->has_label ? msg->label : 0,
		msg->has_enforce_wordlist ? msg->enforce_wordlist : false
	);
}
Example #5
0
void fsm_msgResetDevice(ResetDevice *msg)
{
	if (storage_isInitialized()) {
		fsm_sendFailure(FailureType_Failure_UnexpectedMessage, "Device is already initialized. Use Wipe first.");
		return;
	}

	reset_init(
		msg->has_display_random && msg->display_random,
		msg->has_strength ? msg->strength : 128,
		msg->has_passphrase_protection && msg->passphrase_protection,
		msg->has_pin_protection && msg->pin_protection,
		msg->has_language ? msg->language : 0,
		msg->has_label ? msg->label : 0
	);
}
Example #6
0
void layoutHome(void)
{
	if (layoutLast == layoutHome || layoutLast == layoutScreensaver) {
		oledClear();
	} else {
		layoutSwipe();
	}
	layoutLast = layoutHome;
	const char *label = storage_isInitialized() ? storage_getLabel() : _("Go to trezor.io/start");
	const uint8_t *homescreen = storage_getHomescreen();
	if (homescreen) {
		BITMAP b;
		b.width = 128;
		b.height = 64;
		b.data = homescreen;
		oledDrawBitmap(0, 0, &b);
	} else {
		if (label && strlen(label) > 0) {
			oledDrawBitmap(44, 4, &bmp_logo48);
			oledDrawStringCenter(OLED_HEIGHT - 8, label, FONT_STANDARD);
		} else {
			oledDrawBitmap(40, 0, &bmp_logo64);
		}
	}
	if (storage_noBackup()) {
		oledBox(0, 0, 127, 8, false);
		oledDrawStringCenter(0, "SEEDLESS", FONT_STANDARD);
	} else
	if (storage_unfinishedBackup()) {
		oledBox(0, 0, 127, 8, false);
		oledDrawStringCenter(0, "BACKUP FAILED!", FONT_STANDARD);
	} else
	if (storage_needsBackup()) {
		oledBox(0, 0, 127, 8, false);
		oledDrawStringCenter(0, "NEEDS BACKUP!", FONT_STANDARD);
	}
	oledRefresh();

	// Reset lock screen timeout
	system_millis_lock_start = timer_ms();
}
Example #7
0
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);
	}
}