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_msgPing(Ping *msg)
{
	RESP_INIT(Success);

	if (msg->has_button_protection && msg->button_protection) {
		layoutDialogSwipe(DIALOG_ICON_QUESTION, "Cancel", "Confirm", NULL, "Do you really want to", "answer to ping?", NULL, NULL, NULL, NULL);
		if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) {
			fsm_sendFailure(FailureType_Failure_ActionCancelled, "Ping cancelled");
			layoutHome();
			return;
		}
	}

	if (msg->has_pin_protection && msg->pin_protection) {
		if (!protectPin(true)) {
			layoutHome();
			return;
		}
	}

	if (msg->has_passphrase_protection && msg->passphrase_protection) {
		if (!protectPassphrase()) {
			fsm_sendFailure(FailureType_Failure_ActionCancelled, "Ping cancelled");
			return;
		}
	}

	if (msg->has_message) {
		resp->has_message = true;
		memcpy(&(resp->message), &(msg->message), sizeof(resp->message));
	}
	msg_write(MessageType_MessageType_Success, resp);
	layoutHome();
}
Example #3
0
void fsm_msgGetAddress(GetAddress *msg)
{
	RESP_INIT(Address);

	HDNode *node = fsm_getRootNode();
	if (!node) return;
	const CoinType *coin = coinByName(msg->coin_name);
	if (!coin) {
		fsm_sendFailure(FailureType_Failure_Other, "Invalid coin name");
		layoutHome();
		return;
	}

	fsm_deriveKey(node, msg->address_n, msg->address_n_count);

	ecdsa_get_address(node->public_key, coin->address_type, resp->address);

	if (msg->has_show_display && msg->show_display) {
		layoutAddress(resp->address);
		if (!protectButton(ButtonRequestType_ButtonRequest_Address, true)) {
			fsm_sendFailure(FailureType_Failure_ActionCancelled, "Show address cancelled");
			layoutHome();
			return;
		}
	}

	msg_write(MessageType_MessageType_Address, resp);
	layoutHome();
}
Example #4
0
void fsm_msgEstimateTxSize(EstimateTxSize *msg)
{
	RESP_INIT(TxSize);
	resp->has_tx_size = true;
	resp->tx_size = transactionEstimateSize(msg->inputs_count, msg->outputs_count);
	msg_write(MessageType_MessageType_TxSize, resp);
}
Example #5
0
void fsm_msgSignMessage(SignMessage *msg)
{
	RESP_INIT(MessageSignature);

	layoutSignMessage(msg->message.bytes, msg->message.size);
	if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) {
		fsm_sendFailure(FailureType_Failure_ActionCancelled, "Sign message cancelled");
		layoutHome();
		return;
	}

	if (!protectPin(true)) {
		layoutHome();
		return;
	}

	const CoinType *coin = fsm_getCoin(msg->coin_name);
	if (!coin) return;
	const HDNode *node = fsm_getDerivedNode(msg->address_n, msg->address_n_count);
	if (!node) return;

	layoutProgressSwipe("Signing", 0);
	if (cryptoMessageSign(msg->message.bytes, msg->message.size, node->private_key, resp->signature.bytes) == 0) {
		resp->has_address = true;
		uint8_t addr_raw[21];
		ecdsa_get_address_raw(node->public_key, coin->address_type, addr_raw);
		base58_encode_check(addr_raw, 21, resp->address, sizeof(resp->address));
		resp->has_signature = true;
		resp->signature.size = 65;
		msg_write(MessageType_MessageType_MessageSignature, resp);
	} else {
		fsm_sendFailure(FailureType_Failure_Other, "Error signing message");
	}
	layoutHome();
}
Example #6
0
void fsm_msgGetPublicKey(GetPublicKey *msg)
{
    RESP_INIT(PublicKey);

    if (!storage_is_initialized()) 
    {
        fsm_sendFailure(FailureType_Failure_NotInitialized, "Device not initialized");
        return;
    }

    if(!pin_protect_cached())
    {
        go_home();
        return;
    }

    const HDNode *node = fsm_getDerivedNode(msg->address_n, msg->address_n_count);

    if(!node) { return; }

    uint8_t public_key[33];  // copy public key to temporary buffer
    memcpy(public_key, node->public_key, sizeof(public_key));

    if(msg->has_ecdsa_curve_name)
    {
        const ecdsa_curve *curve = get_curve_by_name(msg->ecdsa_curve_name);

        if(curve)
        {
            // correct public key (since fsm_getDerivedNode uses secp256k1 curve)
            ecdsa_get_public_key33(curve, node->private_key, public_key);
        }
    }

    resp->node.depth = node->depth;
    resp->node.fingerprint = node->fingerprint;
    resp->node.child_num = node->child_num;
    resp->node.chain_code.size = 32;
    memcpy(resp->node.chain_code.bytes, node->chain_code, 32);
    resp->node.has_private_key = false;
    resp->node.has_public_key = true;
    resp->node.public_key.size = 33;
    memcpy(resp->node.public_key.bytes, public_key, 33);
    resp->has_xpub = true;
    hdnode_serialize_public(node, resp->xpub, sizeof(resp->xpub));

    if(msg->has_show_display && msg->show_display)
    {
        if(!confirm_xpub(resp->xpub))
        {
            fsm_sendFailure(FailureType_Failure_ActionCancelled, "Show extended public key cancelled");
            go_home();
            return;
        }
    }

    msg_write(MessageType_MessageType_PublicKey, resp);
    go_home();
}
Example #7
0
void fsm_msgGetAddress(GetAddress *msg)
{
	RESP_INIT(Address);

	if (!protectPin(true)) {
		layoutHome();
		return;
	}

	const CoinType *coin = fsm_getCoin(msg->coin_name);
	if (!coin) return;
	const HDNode *node = fsm_getDerivedNode(msg->address_n, msg->address_n_count);
	if (!node) return;

	if (msg->has_multisig) {
		layoutProgressSwipe("Preparing", 0);
		if (cryptoMultisigPubkeyIndex(&(msg->multisig), node->public_key) < 0) {
			fsm_sendFailure(FailureType_Failure_Other, "Pubkey not found in multisig script");
			layoutHome();
			return;
		}
		uint8_t buf[32];
		if (compile_script_multisig_hash(&(msg->multisig), buf) == 0) {
			fsm_sendFailure(FailureType_Failure_Other, "Invalid multisig script");
			layoutHome();
			return;
		}
		ripemd160(buf, 32, buf + 1);
		buf[0] = coin->address_type_p2sh; // multisig cointype
		base58_encode_check(buf, 21, resp->address, sizeof(resp->address));
	} else {
		ecdsa_get_address(node->public_key, coin->address_type, resp->address, sizeof(resp->address));
	}

	if (msg->has_show_display && msg->show_display) {
		char desc[16];
		if (msg->has_multisig) {
			strlcpy(desc, "Msig __ of __:", sizeof(desc));
			const uint32_t m = msg->multisig.m;
			const uint32_t n = msg->multisig.pubkeys_count;
			desc[5] = (m < 10) ? ' ': ('0' + (m / 10));
			desc[6] = '0' + (m % 10);
			desc[11] = (n < 10) ? ' ': ('0' + (n / 10));
			desc[12] = '0' + (n % 10);
		} else {
			strlcpy(desc, "Address:", sizeof(desc));
		}
		layoutAddress(resp->address, desc);
		if (!protectButton(ButtonRequestType_ButtonRequest_Address, true)) {
			fsm_sendFailure(FailureType_Failure_ActionCancelled, "Show address cancelled");
			layoutHome();
			return;
		}
	}

	msg_write(MessageType_MessageType_Address, resp);
	layoutHome();
}
Example #8
0
void fsm_sendSuccess(const char *text)
{
	RESP_INIT(Success);
	if (text) {
		resp->has_message = true;
		strlcpy(resp->message, text, sizeof(resp->message));
	}
	msg_write(MessageType_MessageType_Success, resp);
}
Example #9
0
void fsm_msgCipherKeyValue(CipherKeyValue *msg)
{
	if (!msg->has_key) {
		fsm_sendFailure(FailureType_Failure_SyntaxError, "No key provided");
		return;
	}
	if (!msg->has_value) {
		fsm_sendFailure(FailureType_Failure_SyntaxError, "No value provided");
		return;
	}
	if (msg->value.size % 16) {
		fsm_sendFailure(FailureType_Failure_SyntaxError, "Value length must be a multiple of 16");
		return;
	}
	if (!protectPin(true)) {
		layoutHome();
		return;
	}
	HDNode *node = fsm_getRootNode();
	if (!node) return;
	fsm_deriveKey(node, msg->address_n, msg->address_n_count);

	bool encrypt = msg->has_encrypt && msg->encrypt;
	bool ask_on_encrypt = msg->has_ask_on_encrypt && msg->ask_on_encrypt;
	bool ask_on_decrypt = msg->has_ask_on_decrypt && msg->ask_on_decrypt;
	if ((encrypt && ask_on_encrypt) || (!encrypt && ask_on_decrypt)) {
		layoutCipherKeyValue(encrypt, msg->key);
		if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) {
			fsm_sendFailure(FailureType_Failure_ActionCancelled, "CipherKeyValue cancelled");
			layoutHome();
			return;
		}
	}

	uint8_t data[256 + 4];
	strlcpy((char *)data, msg->key, sizeof(data));
	strlcat((char *)data, ask_on_encrypt ? "E1" : "E0", sizeof(data));
	strlcat((char *)data, ask_on_decrypt ? "D1" : "D0", sizeof(data));

	hmac_sha512(node->private_key, 32, data, strlen((char *)data), data);

	RESP_INIT(Success);
	if (encrypt) {
		aes_encrypt_ctx ctx;
		aes_encrypt_key256(data, &ctx);
		aes_cbc_encrypt(msg->value.bytes, resp->payload.bytes, msg->value.size, data + 32, &ctx);
	} else {
		aes_decrypt_ctx ctx;
		aes_decrypt_key256(data, &ctx);
		aes_cbc_decrypt(msg->value.bytes, resp->payload.bytes, msg->value.size, data + 32, &ctx);
	}
	resp->has_payload = true;
	resp->payload.size = msg->value.size;
	msg_write(MessageType_MessageType_Success, resp);
	layoutHome();
}
Example #10
0
void fsm_msgEncryptMessage(EncryptMessage *msg)
{
	if (!msg->has_pubkey) {
		fsm_sendFailure(FailureType_Failure_SyntaxError, "No public key provided");
		return;
	}
	if (!msg->has_message) {
		fsm_sendFailure(FailureType_Failure_SyntaxError, "No message provided");
		return;
	}
	curve_point pubkey;
	if (msg->pubkey.size != 33 || ecdsa_read_pubkey(&secp256k1, msg->pubkey.bytes, &pubkey) == 0) {
		fsm_sendFailure(FailureType_Failure_SyntaxError, "Invalid public key provided");
		return;
	}
	bool display_only = msg->has_display_only && msg->display_only;
	bool signing = msg->address_n_count > 0;
	RESP_INIT(EncryptedMessage);
	const CoinType *coin = 0;
	const HDNode *node = 0;
	uint8_t address_raw[21];
	if (signing) {
		coin = coinByName(msg->coin_name);
		if (!coin) {
			fsm_sendFailure(FailureType_Failure_Other, "Invalid coin name");
			return;
		}
		if (!protectPin(true)) {
			layoutHome();
			return;
		}
		node = fsm_getDerivedNode(msg->address_n, msg->address_n_count);
		if (!node) return;
		uint8_t public_key[33];
		ecdsa_get_public_key33(&secp256k1, node->private_key, public_key);
		ecdsa_get_address_raw(public_key, coin->address_type, address_raw);
	}
	layoutEncryptMessage(msg->message.bytes, msg->message.size, signing);
	if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) {
		fsm_sendFailure(FailureType_Failure_ActionCancelled, "Encrypt message cancelled");
		layoutHome();
		return;
	}
	layoutProgressSwipe("Encrypting", 0);
	if (cryptoMessageEncrypt(&pubkey, msg->message.bytes, msg->message.size, display_only, resp->nonce.bytes, &(resp->nonce.size), resp->message.bytes, &(resp->message.size), resp->hmac.bytes, &(resp->hmac.size), signing ? node->private_key : 0, signing ? address_raw : 0) != 0) {
		fsm_sendFailure(FailureType_Failure_ActionCancelled, "Error encrypting message");
		layoutHome();
		return;
	}
	resp->has_nonce = true;
	resp->has_message = true;
	resp->has_hmac = true;
	msg_write(MessageType_MessageType_EncryptedMessage, resp);
	layoutHome();
}
Example #11
0
void fsm_msgDecryptMessage(DecryptMessage *msg)
{
	if (!msg->has_nonce) {
		fsm_sendFailure(FailureType_Failure_SyntaxError, "No nonce provided");
		return;
	}
	if (!msg->has_message) {
		fsm_sendFailure(FailureType_Failure_SyntaxError, "No message provided");
		return;
	}
	if (!msg->has_hmac) {
		fsm_sendFailure(FailureType_Failure_SyntaxError, "No message hmac provided");
		return;
	}
	curve_point nonce_pubkey;
	if (msg->nonce.size != 33 || ecdsa_read_pubkey(&secp256k1, msg->nonce.bytes, &nonce_pubkey) == 0) {
		fsm_sendFailure(FailureType_Failure_SyntaxError, "Invalid nonce provided");
		return;
	}
	if (!protectPin(true)) {
		layoutHome();
		return;
	}
	const HDNode *node = fsm_getDerivedNode(msg->address_n, msg->address_n_count);
	if (!node) return;

	layoutProgressSwipe("Decrypting", 0);
	RESP_INIT(DecryptedMessage);
	bool display_only = false;
	bool signing = false;
	uint8_t address_raw[21];
	if (cryptoMessageDecrypt(&nonce_pubkey, msg->message.bytes, msg->message.size, msg->hmac.bytes, msg->hmac.size, node->private_key, resp->message.bytes, &(resp->message.size), &display_only, &signing, address_raw) != 0) {
		fsm_sendFailure(FailureType_Failure_ActionCancelled, "Error decrypting message");
		layoutHome();
		return;
	}
	if (signing) {
		base58_encode_check(address_raw, 21, resp->address, sizeof(resp->address));
	}
	layoutDecryptMessage(resp->message.bytes, resp->message.size, signing ? resp->address : 0);
	protectButton(ButtonRequestType_ButtonRequest_Other, true);
	if (display_only) {
		resp->has_address = false;
		resp->has_message = false;
		memset(resp->address, 0, sizeof(resp->address));
		memset(&(resp->message), 0, sizeof(resp->message));
	} else {
		resp->has_address = signing;
		resp->has_message = true;
	}
	msg_write(MessageType_MessageType_DecryptedMessage, resp);
	layoutHome();
}
Example #12
0
void fsm_msgSignMessage(SignMessage *msg)
{
    RESP_INIT(MessageSignature);

	if (!storage_is_initialized()) 
    {
		fsm_sendFailure(FailureType_Failure_NotInitialized, "Device not initialized");
		return;
	}

    if(!confirm(ButtonRequestType_ButtonRequest_SignMessage, "Sign Message",
                (char *)msg->message.bytes))
    {
        fsm_sendFailure(FailureType_Failure_ActionCancelled, "Sign message cancelled");
        go_home();
        return;
    }

    if(!pin_protect_cached())
    {
        go_home();
        return;
    }

    const CoinType *coin = fsm_getCoin(msg->coin_name);

    if(!coin) { return; }

    const HDNode *node = fsm_getDerivedNode(msg->address_n, msg->address_n_count);

    if(!node) { return; }

    if(cryptoMessageSign(coin, msg->message.bytes, msg->message.size, node->private_key,
                         resp->signature.bytes) == 0)
    {
        resp->has_address = true;
        uint8_t addr_raw[21];
        ecdsa_get_address_raw(node->public_key, coin->address_type, addr_raw);
        base58_encode_check(addr_raw, 21, resp->address, sizeof(resp->address));
        resp->has_signature = true;
        resp->signature.size = 65;
        msg_write(MessageType_MessageType_MessageSignature, resp);
    }
    else
    {
        fsm_sendFailure(FailureType_Failure_Other, "Error signing message");
    }

    go_home();
}
Example #13
0
void fsm_sendFailure(FailureType code, const char *text)
{
	if (protectAbortedByInitialize) {
		fsm_msgInitialize((Initialize *)0);
		protectAbortedByInitialize = false;
		return;
	}
	RESP_INIT(Failure);
	resp->has_code = true;
	resp->code = code;
	if (text) {
		resp->has_message = true;
		strlcpy(resp->message, text, sizeof(resp->message));
	}
	msg_write(MessageType_MessageType_Failure, resp);
}
Example #14
0
void fsm_msgGetEntropy(GetEntropy *msg)
{
	layoutDialogSwipe(DIALOG_ICON_QUESTION, "Cancel", "Confirm", NULL, "Do you really want to", "send entropy?", NULL, NULL, NULL, NULL);
	if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) {
		fsm_sendFailure(FailureType_Failure_ActionCancelled, "Entropy cancelled");
		layoutHome();
		return;
	}
	RESP_INIT(Entropy);
	uint32_t len = msg->size;
	if (len > 1024) {
		len = 1024;
	}
	resp->entropy.size = len;
	random_buffer(resp->entropy.bytes, len);
	msg_write(MessageType_MessageType_Entropy, resp);
	layoutHome();
}
Example #15
0
void fsm_msgDebugLinkGetState(DebugLinkGetState *msg)
{
	(void)msg;
	RESP_INIT(DebugLinkState);

	resp->has_layout = true;
	resp->layout.size = OLED_BUFSIZE;
	memcpy(resp->layout.bytes, oledGetBuffer(), OLED_BUFSIZE);

	if (storage.has_pin) {
		resp->has_pin = true;
		strlcpy(resp->pin, storage.pin, sizeof(resp->pin));
	}

	resp->has_matrix = true;
	strlcpy(resp->matrix, pinmatrix_get(), sizeof(resp->matrix));

	resp->has_reset_entropy = true;
	resp->reset_entropy.size = reset_get_int_entropy(resp->reset_entropy.bytes);

	resp->has_reset_word = true;
	strlcpy(resp->reset_word, reset_get_word(), sizeof(resp->reset_word));

	resp->has_recovery_fake_word = true;
	strlcpy(resp->recovery_fake_word, recovery_get_fake_word(), sizeof(resp->recovery_fake_word));

	resp->has_recovery_word_pos = true;
	resp->recovery_word_pos = recovery_get_word_pos();

	if (storage.has_mnemonic) {
		resp->has_mnemonic = true;
		strlcpy(resp->mnemonic, storage.mnemonic, sizeof(resp->mnemonic));
	}

	if (storage.has_node) {
		resp->has_node = true;
		memcpy(&(resp->node), &(storage.node), sizeof(HDNode));
	}

	resp->has_passphrase_protection = true;
	resp->passphrase_protection = storage.has_passphrase_protection && storage.passphrase_protection;

	msg_debug_write(MessageType_MessageType_DebugLinkState, resp);
}
Example #16
0
void fsm_sendSuccess(const char *text)
{
    if(reset_msg_stack)
    {
        fsm_msgInitialize((Initialize *)0);
        reset_msg_stack = false;
        return;
    }

    RESP_INIT(Success);

    if(text)
    {
        resp->has_message = true;
        strlcpy(resp->message, text, sizeof(resp->message));
    }

    msg_write(MessageType_MessageType_Success, resp);
}
Example #17
0
void fsm_msgPing(Ping *msg)
{
    RESP_INIT(Success);

    if(msg->has_button_protection && msg->button_protection)
        if(!confirm(ButtonRequestType_ButtonRequest_Ping, "Ping", msg->message))
        {
            fsm_sendFailure(FailureType_Failure_ActionCancelled, "Ping cancelled");
            go_home();
            return;
        }

    if(msg->has_pin_protection && msg->pin_protection)
    {
        if(!pin_protect_cached())
        {
            go_home();
            return;
        }
    }

    if(msg->has_passphrase_protection && msg->passphrase_protection)
    {
        if(!passphrase_protect())
        {
            fsm_sendFailure(FailureType_Failure_ActionCancelled, "Ping cancelled");
            go_home();
            return;
        }
    }

    if(msg->has_message)
    {
        resp->has_message = true;
        memcpy(&(resp->message), &(msg->message), sizeof(resp->message));
    }

    msg_write(MessageType_MessageType_Success, resp);
    go_home();
}
Example #18
0
void fsm_msgSignMessage(SignMessage *msg)
{
	RESP_INIT(MessageSignature);

	layoutSignMessage(msg->message.bytes, msg->message.size);
	if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) {
		fsm_sendFailure(FailureType_Failure_ActionCancelled, "Sign message cancelled");
		layoutHome();
		return;
	}

	if (!protectPin(true)) {
		layoutHome();
		return;
	}

	HDNode *node = fsm_getRootNode();
	if (!node) return;
	const CoinType *coin = coinByName(msg->coin_name);
	if (!coin) {
		fsm_sendFailure(FailureType_Failure_Other, "Invalid coin name");
		layoutHome();
		return;
	}

	fsm_deriveKey(node, msg->address_n, msg->address_n_count);

	ecdsa_get_address(node->public_key, coin->address_type, resp->address);
	layoutProgressSwipe("Signing", 0, 0);
	if (transactionMessageSign(msg->message.bytes, msg->message.size, node->private_key, resp->address, resp->signature.bytes)) {
		resp->has_address = true;
		resp->has_signature = true;
		resp->signature.size = 65;
		msg_write(MessageType_MessageType_MessageSignature, resp);
	} else {
		fsm_sendFailure(FailureType_Failure_Other, "Error signing message");
	}
	layoutHome();
}
Example #19
0
void fsm_msgGetPublicKey(GetPublicKey *msg)
{
	RESP_INIT(PublicKey);

	HDNode *node = fsm_getRootNode();
	if (!node) return;

	fsm_deriveKey(node, msg->address_n, msg->address_n_count);

	resp->node.depth = node->depth;
	resp->node.fingerprint = node->fingerprint;
	resp->node.child_num = node->child_num;
	resp->node.chain_code.size = 32;
	memcpy(resp->node.chain_code.bytes, node->chain_code, 32);
	resp->node.has_private_key = false;
	resp->node.has_public_key = true;
	resp->node.public_key.size = 33;
	memcpy(resp->node.public_key.bytes, node->public_key, 33);
	resp->has_xpub = true;
	hdnode_serialize_public(node, resp->xpub);
	msg_write(MessageType_MessageType_PublicKey, resp);
	layoutHome();
}
Example #20
0
void fsm_msgGetPublicKey(GetPublicKey *msg)
{
	RESP_INIT(PublicKey);

	if (!protectPin(true)) {
		layoutHome();
		return;
	}

	const HDNode *node = fsm_getDerivedNode(msg->address_n, msg->address_n_count);
	if (!node) return;

	uint8_t public_key[33];  // copy public key to temporary buffer
	memcpy(public_key, node->public_key, sizeof(public_key));

	if (msg->has_ecdsa_curve_name) {
		const ecdsa_curve *curve = get_curve_by_name(msg->ecdsa_curve_name);
		if (curve) {
			// correct public key (since fsm_getDerivedNode uses secp256k1 curve)
			ecdsa_get_public_key33(curve, node->private_key, public_key);
		}
	}

	resp->node.depth = node->depth;
	resp->node.fingerprint = node->fingerprint;
	resp->node.child_num = node->child_num;
	resp->node.chain_code.size = 32;
	memcpy(resp->node.chain_code.bytes, node->chain_code, 32);
	resp->node.has_private_key = false;
	resp->node.has_public_key = true;
	resp->node.public_key.size = 33;
	memcpy(resp->node.public_key.bytes, public_key, 33);
	resp->has_xpub = true;
	hdnode_serialize_public(node, resp->xpub, sizeof(resp->xpub));
	msg_write(MessageType_MessageType_PublicKey, resp);
	layoutHome();
}
Example #21
0
void fsm_msgGetEntropy(GetEntropy *msg)
{
    if(!confirm(ButtonRequestType_ButtonRequest_GetEntropy,
                "Generate Entropy",
                "Do you want to generate and return entropy using the hardware RNG?"))
    {
        fsm_sendFailure(FailureType_Failure_ActionCancelled, "Entropy cancelled");
        go_home();
        return;
    }

    RESP_INIT(Entropy);
    uint32_t len = msg->size;

    if(len > ENTROPY_BUF)
    {
        len = ENTROPY_BUF;
    }

    resp->entropy.size = len;
    random_buffer(resp->entropy.bytes, len);
    msg_write(MessageType_MessageType_Entropy, resp);
    go_home();
}
Example #22
0
void fsm_msgSignIdentity(SignIdentity *msg)
{
	RESP_INIT(SignedIdentity);

	layoutSignIdentity(&(msg->identity), msg->has_challenge_visual ? msg->challenge_visual : 0);
	if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) {
		fsm_sendFailure(FailureType_Failure_ActionCancelled, "Sign identity cancelled");
		layoutHome();
		return;
	}

	if (!protectPin(true)) {
		layoutHome();
		return;
	}

	uint8_t hash[32];
	if (!msg->has_identity || cryptoIdentityFingerprint(&(msg->identity), hash) == 0) {
		fsm_sendFailure(FailureType_Failure_Other, "Invalid identity");
		layoutHome();
		return;
	}

	uint32_t address_n[5];
	address_n[0] = 0x80000000 | 13;
	address_n[1] = 0x80000000 | hash[ 0] | (hash[ 1] << 8) | (hash[ 2] << 16) | (hash[ 3] << 24);
	address_n[2] = 0x80000000 | hash[ 4] | (hash[ 5] << 8) | (hash[ 6] << 16) | (hash[ 7] << 24);
	address_n[3] = 0x80000000 | hash[ 8] | (hash[ 9] << 8) | (hash[10] << 16) | (hash[11] << 24);
	address_n[4] = 0x80000000 | hash[12] | (hash[13] << 8) | (hash[14] << 16) | (hash[15] << 24);

	const HDNode *node = fsm_getDerivedNode(address_n, 5);
	if (!node) return;

	uint8_t public_key[33];  // copy public key to temporary buffer
	memcpy(public_key, node->public_key, sizeof(public_key));

	if (msg->has_ecdsa_curve_name) {
		const ecdsa_curve *curve = get_curve_by_name(msg->ecdsa_curve_name);
		if (curve) {
			// correct public key (since fsm_getDerivedNode uses secp256k1 curve)
			ecdsa_get_public_key33(curve, node->private_key, public_key);
		}
	}

	bool sign_ssh = msg->identity.has_proto && (strcmp(msg->identity.proto, "ssh") == 0);

	int result = 0;
	layoutProgressSwipe("Signing", 0);
	if (sign_ssh) { // SSH does not sign visual challenge
		result = sshMessageSign(msg->challenge_hidden.bytes, msg->challenge_hidden.size, node->private_key, resp->signature.bytes);
	} else {
		uint8_t digest[64];
		sha256_Raw(msg->challenge_hidden.bytes, msg->challenge_hidden.size, digest);
		sha256_Raw((const uint8_t *)msg->challenge_visual, strlen(msg->challenge_visual), digest + 32);
		result = cryptoMessageSign(digest, 64, node->private_key, resp->signature.bytes);
	}

	if (result == 0) {
		if (sign_ssh) {
			resp->has_address = false;
		} else {
			resp->has_address = true;
			uint8_t addr_raw[21];
			ecdsa_get_address_raw(node->public_key, 0x00, addr_raw); // hardcoded Bitcoin address type
			base58_encode_check(addr_raw, 21, resp->address, sizeof(resp->address));
		}
		resp->has_public_key = true;
		resp->public_key.size = 33;
		memcpy(resp->public_key.bytes, public_key, 33);
		resp->has_signature = true;
		resp->signature.size = 65;
		msg_write(MessageType_MessageType_SignedIdentity, resp);
	} else {
		fsm_sendFailure(FailureType_Failure_Other, "Error signing identity");
	}
	layoutHome();
}
Example #23
0
void fsm_msgGetFeatures(GetFeatures *msg)
{
    (void)msg;
    RESP_INIT(Features);

    /* Vendor */
    resp->has_vendor = true;
    strlcpy(resp->vendor, "keepkey.com", sizeof(resp->vendor));

    /* Version */
    resp->has_major_version = true;  resp->major_version = MAJOR_VERSION;
    resp->has_minor_version = true;  resp->minor_version = MINOR_VERSION;
    resp->has_patch_version = true;  resp->patch_version = PATCH_VERSION;

    /* Device ID */
    resp->has_device_id = true;
    strlcpy(resp->device_id, storage_get_uuid_str(), sizeof(resp->device_id));

    /* Security settings */
    resp->has_pin_protection = true; resp->pin_protection = storage_has_pin();
    resp->has_passphrase_protection = true;
    resp->passphrase_protection = storage_get_passphrase_protected();

#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

    /* Bootloader hash */
    resp->has_bootloader_hash = true;
    resp->bootloader_hash.size = memory_bootloader_hash(
                                     resp->bootloader_hash.bytes);

    /* Settings for device */
    if(storage_get_language())
    {
        resp->has_language = true;
        strlcpy(resp->language, storage_get_language(), sizeof(resp->language));
    }

    if(storage_get_label())
    {
        resp->has_label = true;
        strlcpy(resp->label, storage_get_label(), sizeof(resp->label));
    }

    /* Coin type support */
    resp->coins_count = COINS_COUNT;
    memcpy(resp->coins, coins, COINS_COUNT * sizeof(CoinType));

    /* Is device initialized? */
    resp->has_initialized = true;  resp->initialized = storage_is_initialized();

    /* Are private keys imported */
    resp->has_imported = true; resp->imported = storage_get_imported();

    /* Cached pin and passphrase status */
    resp->has_pin_cached = true; resp->pin_cached = session_is_pin_cached();
    resp->has_passphrase_cached = true;
    resp->passphrase_cached = session_is_passphrase_cached();

    msg_write(MessageType_MessageType_Features, resp);
}
Example #24
0
void fsm_msgCipherKeyValue(CipherKeyValue *msg)
{

	if (!storage_is_initialized()) 
    {
		fsm_sendFailure(FailureType_Failure_NotInitialized, "Device not initialized");
		return;
	}

    if(!msg->has_key)
    {
        fsm_sendFailure(FailureType_Failure_SyntaxError, "No key provided");
        return;
    }

    if(!msg->has_value)
    {
        fsm_sendFailure(FailureType_Failure_SyntaxError, "No value provided");
        return;
    }

    if(msg->value.size % 16)
    {
        fsm_sendFailure(FailureType_Failure_SyntaxError,
                        "Value length must be a multiple of 16");
        return;
    }

    if(!pin_protect_cached())
    {
        go_home();
        return;
    }

    const HDNode *node = fsm_getDerivedNode(msg->address_n, msg->address_n_count);

    if(!node) { return; }

    bool encrypt = msg->has_encrypt && msg->encrypt;
    bool ask_on_encrypt = msg->has_ask_on_encrypt && msg->ask_on_encrypt;
    bool ask_on_decrypt = msg->has_ask_on_decrypt && msg->ask_on_decrypt;

    if((encrypt && ask_on_encrypt) || (!encrypt && ask_on_decrypt))
    {
        if(!confirm_cipher(encrypt, msg->key))
        {
            fsm_sendFailure(FailureType_Failure_ActionCancelled,
                            "CipherKeyValue cancelled");
            go_home();
            return;
        }
    }

    uint8_t data[256 + 4];
    strlcpy((char *)data, msg->key, sizeof(data));
    strlcat((char *)data, ask_on_encrypt ? "E1" : "E0", sizeof(data));
    strlcat((char *)data, ask_on_decrypt ? "D1" : "D0", sizeof(data));

    hmac_sha512(node->private_key, 32, data, strlen((char *)data), data);

    RESP_INIT(CipheredKeyValue);

    if(encrypt)
    {
        aes_encrypt_ctx ctx;
        aes_encrypt_key256(data, &ctx);
        aes_cbc_encrypt(msg->value.bytes, resp->value.bytes, msg->value.size,
                        ((msg->iv.size == 16) ? (msg->iv.bytes) : (data + 32)), &ctx);
    }
    else
    {
        aes_decrypt_ctx ctx;
        aes_decrypt_key256(data, &ctx);
        aes_cbc_decrypt(msg->value.bytes, resp->value.bytes, msg->value.size,
                        ((msg->iv.size == 16) ? (msg->iv.bytes) : (data + 32)), &ctx);
    }

    resp->has_value = true;
    resp->value.size = msg->value.size;
    msg_write(MessageType_MessageType_CipheredKeyValue, resp);
    go_home();
}
Example #25
0
void fsm_msgGetAddress(GetAddress *msg)
{
    RESP_INIT(Address);

    if (!storage_is_initialized()) 
    {
        fsm_sendFailure(FailureType_Failure_NotInitialized, "Device not initialized");
        return;
    }

    if(!pin_protect_cached())
    {
        go_home();
        return;
    }

    const CoinType *coin = fsm_getCoin(msg->coin_name);

    if(!coin) { return; }

    const HDNode *node = fsm_getDerivedNode(msg->address_n, msg->address_n_count);

    if(!node) { return; }

    if(msg->has_multisig)
    {

        if(cryptoMultisigPubkeyIndex(&(msg->multisig), node->public_key) < 0)
        {
            fsm_sendFailure(FailureType_Failure_Other,
                            "Pubkey not found in multisig script");
            go_home();
            return;
        }

        uint8_t buf[32];

        if(compile_script_multisig_hash(&(msg->multisig), buf) == 0)
        {
            fsm_sendFailure(FailureType_Failure_Other, "Invalid multisig script");
            go_home();
            return;
        }

        ripemd160(buf, 32, buf + 1);
        buf[0] = coin->address_type_p2sh; // multisig cointype
        base58_encode_check(buf, 21, resp->address, sizeof(resp->address));
    }
    else
    {
        ecdsa_get_address(node->public_key, coin->address_type, resp->address,
                          sizeof(resp->address));
    }

    if(msg->has_show_display && msg->show_display)
    {
        char desc[MEDIUM_STR_BUF] = "";

        if(msg->has_multisig)
        {
            const uint32_t m = msg->multisig.m;
            const uint32_t n = msg->multisig.pubkeys_count;

            /* snprintf: 22 + 10 (%lu) + 10 (%lu) + 1 (NULL) = 43 */
            snprintf(desc, MEDIUM_STR_BUF, "(Multi-Signature %lu of %lu)", (unsigned long)m,
                     (unsigned long)n);
        }

        if(!confirm_address(desc, resp->address))
        {
            fsm_sendFailure(FailureType_Failure_ActionCancelled, "Show address cancelled");
            go_home();
            return;
        }
    }

    msg_write(MessageType_MessageType_Address, resp);
    go_home();
}
Example #26
0
void fsm_msgDecryptMessage(DecryptMessage *msg)
{

    if (!storage_is_initialized()) 
    {
        fsm_sendFailure(FailureType_Failure_NotInitialized, "Device not initialized");
        return;
    }

    if(!msg->has_nonce)
    {
        fsm_sendFailure(FailureType_Failure_SyntaxError, "No nonce provided");
        return;
    }

    if(!msg->has_message)
    {
        fsm_sendFailure(FailureType_Failure_SyntaxError, "No message provided");
        return;
    }

    if(!msg->has_hmac)
    {
        fsm_sendFailure(FailureType_Failure_SyntaxError, "No message hmac provided");
        return;
    }

    curve_point nonce_pubkey;

    if(msg->nonce.size != 33 ||
            ecdsa_read_pubkey(&secp256k1, msg->nonce.bytes, &nonce_pubkey) == 0)
    {
        fsm_sendFailure(FailureType_Failure_SyntaxError, "Invalid nonce provided");
        return;
    }

    if(!pin_protect_cached())
    {
        go_home();
        return;
    }

    const HDNode *node = fsm_getDerivedNode(msg->address_n, msg->address_n_count);

    if(!node) { return; }

    layout_simple_message("Decrypting Message...");

    RESP_INIT(DecryptedMessage);
    bool display_only = false;
    bool signing = false;
    uint8_t address_raw[21];

    if(cryptoMessageDecrypt(&nonce_pubkey, msg->message.bytes, msg->message.size,
                            msg->hmac.bytes, msg->hmac.size, node->private_key, resp->message.bytes,
                            &(resp->message.size), &display_only, &signing, address_raw) != 0)
    {
        fsm_sendFailure(FailureType_Failure_ActionCancelled,
                        "Error decrypting message");
        go_home();
        return;
    }

    if(signing)
    {
        base58_encode_check(address_raw, 21, resp->address, sizeof(resp->address));
    }

    if(!confirm_decrypt_msg((char *)resp->message.bytes,
                            signing ? resp->address : 0))
    {
        fsm_sendFailure(FailureType_Failure_ActionCancelled,
                        "Decrypt message cancelled");
        go_home();
        return;
    }

    if(display_only)
    {
        resp->has_address = false;
        resp->has_message = false;
        memset(resp->address, 0, sizeof(resp->address));
        memset(&(resp->message), 0, sizeof(resp->message));
    }
    else
    {
        resp->has_address = signing;
        resp->has_message = true;
    }

    msg_write(MessageType_MessageType_DecryptedMessage, resp);
    go_home();
}
Example #27
0
void fsm_sendFailure(Failure_FailureType code, const char *text)
#endif
{
	if (protectAbortedByCancel) {
		protectAbortedByCancel = false;
	}
	if (protectAbortedByInitialize) {
		fsm_msgInitialize((Initialize *)0);
		protectAbortedByInitialize = false;
		return;
	}
	RESP_INIT(Failure);
	resp->has_code = true;
	resp->code = code;
	if (!text) {
		switch (code) {
			case Failure_FailureType_Failure_UnexpectedMessage:
				text = _("Unexpected message");
				break;
			case Failure_FailureType_Failure_ButtonExpected:
				text = _("Button expected");
				break;
			case Failure_FailureType_Failure_DataError:
				text = _("Data error");
				break;
			case Failure_FailureType_Failure_ActionCancelled:
				text = _("Action cancelled by user");
				break;
			case Failure_FailureType_Failure_PinExpected:
				text = _("PIN expected");
				break;
			case Failure_FailureType_Failure_PinCancelled:
				text = _("PIN cancelled");
				break;
			case Failure_FailureType_Failure_PinInvalid:
				text = _("PIN invalid");
				break;
			case Failure_FailureType_Failure_InvalidSignature:
				text = _("Invalid signature");
				break;
			case Failure_FailureType_Failure_ProcessError:
				text = _("Process error");
				break;
			case Failure_FailureType_Failure_NotEnoughFunds:
				text = _("Not enough funds");
				break;
			case Failure_FailureType_Failure_NotInitialized:
				text = _("Device not initialized");
				break;
			case Failure_FailureType_Failure_PinMismatch:
				text = _("PIN mismatch");
				break;
			case Failure_FailureType_Failure_FirmwareError:
				text = _("Firmware error");
				break;
		}
	}
#if DEBUG_LINK
	resp->has_message = true;
	strlcpy(resp->message, source, sizeof(resp->message));
	if (text) {
		strlcat(resp->message, text, sizeof(resp->message));
	}
#else
	if (text) {
		resp->has_message = true;
		strlcpy(resp->message, text, sizeof(resp->message));
	}
#endif
	msg_write(MessageType_MessageType_Failure, resp);
}
Example #28
0
void fsm_msgEncryptMessage(EncryptMessage *msg)
{

    if (!storage_is_initialized()) 
    {
        fsm_sendFailure(FailureType_Failure_NotInitialized, "Device not initialized");
        return;
    }

    if(!msg->has_pubkey)
    {
        fsm_sendFailure(FailureType_Failure_SyntaxError, "No public key provided");
        return;
    }

    if(!msg->has_message)
    {
        fsm_sendFailure(FailureType_Failure_SyntaxError, "No message provided");
        return;
    }

    curve_point pubkey;

    if(msg->pubkey.size != 33 ||
            ecdsa_read_pubkey(&secp256k1, msg->pubkey.bytes, &pubkey) == 0)
    {
        fsm_sendFailure(FailureType_Failure_SyntaxError, "Invalid public key provided");
        return;
    }

    bool display_only = msg->has_display_only && msg->display_only;
    bool signing = msg->address_n_count > 0;
    RESP_INIT(EncryptedMessage);
    const CoinType *coin = 0;
    const HDNode *node = 0;
    uint8_t address_raw[21];

    if(signing)
    {
        coin = coinByName(msg->coin_name);

        if(!coin)
        {
            fsm_sendFailure(FailureType_Failure_Other, "Invalid coin name");
            return;
        }

        if(!pin_protect_cached())
        {
            go_home();
            return;
        }

        node = fsm_getDerivedNode(msg->address_n, msg->address_n_count);

        if(!node) { return; }

        uint8_t public_key[33];
        ecdsa_get_public_key33(&secp256k1, node->private_key, public_key);
        ecdsa_get_address_raw(public_key, coin->address_type, address_raw);
    }

    if(!confirm_encrypt_msg((char *)msg->message.bytes, signing))
    {
        fsm_sendFailure(FailureType_Failure_ActionCancelled,
                        "Encrypt message cancelled");
        go_home();
        return;
    }

    layout_simple_message("Encrypting Message...");

    if(cryptoMessageEncrypt(&pubkey, msg->message.bytes, msg->message.size,
                            display_only,
                            resp->nonce.bytes, &(resp->nonce.size), resp->message.bytes,
                            &(resp->message.size),
                            resp->hmac.bytes, &(resp->hmac.size), signing ? node->private_key : 0,
                            signing ? address_raw : 0) != 0)
    {
        fsm_sendFailure(FailureType_Failure_ActionCancelled,
                        "Error encrypting message");
        go_home();
        return;
    }

    resp->has_nonce = true;
    resp->has_message = true;
    resp->has_hmac = true;
    msg_write(MessageType_MessageType_EncryptedMessage, resp);
    go_home();
}