Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

device/trezor: integration tests #4977

Merged
merged 1 commit into from
Mar 14, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,10 @@ debug-test:
mkdir -p $(builddir)/debug
cd $(builddir)/debug && cmake -D BUILD_TESTS=ON -D CMAKE_BUILD_TYPE=Debug $(topdir) && $(MAKE) && $(MAKE) ARGS="-E libwallet_api_tests" test

debug-test-trezor:
mkdir -p $(builddir)/debug
cd $(builddir)/debug && cmake -D BUILD_TESTS=ON -D TREZOR_DEBUG=ON -D CMAKE_BUILD_TYPE=Debug $(topdir) && $(MAKE) && $(MAKE) ARGS="-E libwallet_api_tests" test

debug-all:
mkdir -p $(builddir)/debug
cd $(builddir)/debug && cmake -D BUILD_TESTS=ON -D BUILD_SHARED_LIBS=OFF -D CMAKE_BUILD_TYPE=Debug $(topdir) && $(MAKE)
Expand Down
17 changes: 16 additions & 1 deletion cmake/CheckTrezor.cmake
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
OPTION(USE_DEVICE_TREZOR "Trezor support compilation" ON)
OPTION(USE_DEVICE_TREZOR_LIBUSB "Trezor LibUSB compilation" ON)
OPTION(USE_DEVICE_TREZOR_UDP_RELEASE "Trezor UdpTransport in release mode" OFF)
OPTION(USE_DEVICE_TREZOR_DEBUG "Trezor Debugging enabled" OFF)
OPTION(TREZOR_DEBUG "Main trezor debugging switch" OFF)

# Helper function to fix cmake < 3.6.0 FindProtobuf variables
function(_trezor_protobuf_fix_vars)
Expand Down Expand Up @@ -53,6 +55,14 @@ if (USE_DEVICE_TREZOR)
set(Protobuf_FOUND 1) # override found if all rquired info was provided by variables
endif()

if(TREZOR_DEBUG)
set(USE_DEVICE_TREZOR_DEBUG 1)
endif()

# Compile debugging support (for tests)
if (USE_DEVICE_TREZOR_DEBUG)
add_definitions(-DWITH_TREZOR_DEBUGGING=1)
endif()
else()
message(STATUS "Trezor support disabled by USE_DEVICE_TREZOR")
endif()
Expand Down Expand Up @@ -106,7 +116,12 @@ endif()
if(Protobuf_FOUND AND USE_DEVICE_TREZOR AND TREZOR_PYTHON AND Protobuf_COMPILE_TEST_PASSED)
set(ENV{PROTOBUF_INCLUDE_DIRS} "${Protobuf_INCLUDE_DIR}")
set(ENV{PROTOBUF_PROTOC_EXECUTABLE} "${Protobuf_PROTOC_EXECUTABLE}")
execute_process(COMMAND ${TREZOR_PYTHON} tools/build_protob.py WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/../src/device_trezor/trezor RESULT_VARIABLE RET OUTPUT_VARIABLE OUT ERROR_VARIABLE ERR)
set(TREZOR_PROTOBUF_PARAMS "")
if (USE_DEVICE_TREZOR_DEBUG)
set(TREZOR_PROTOBUF_PARAMS "--debug")
endif()

execute_process(COMMAND ${TREZOR_PYTHON} tools/build_protob.py ${TREZOR_PROTOBUF_PARAMS} WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/../src/device_trezor/trezor RESULT_VARIABLE RET OUTPUT_VARIABLE OUT ERROR_VARIABLE ERR)
if(RET)
message(WARNING "Trezor protobuf messages could not be regenerated (err=${RET}, python ${PYTHON})."
"OUT: ${OUT}, ERR: ${ERR}."
Expand Down
6 changes: 6 additions & 0 deletions src/device_trezor/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,12 @@ set(trezor_private_headers)
if(DEVICE_TREZOR_READY)
message(STATUS "Trezor support enabled")

if(USE_DEVICE_TREZOR_DEBUG)
list(APPEND trezor_headers trezor/debug_link.hpp trezor/messages/messages-debug.pb.h)
list(APPEND trezor_sources trezor/debug_link.cpp trezor/messages/messages-debug.pb.cc)
message(STATUS "Trezor debugging enabled")
endif()

monero_private_headers(device_trezor
${device_private_headers})

Expand Down
15 changes: 9 additions & 6 deletions src/device_trezor/device_trezor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,14 @@ namespace trezor {
auto res = get_view_key();
CHECK_AND_ASSERT_MES(res->watch_key().size() == 32, false, "Trezor returned invalid view key");

// Trezor does not make use of spendkey of the device API.
// Ledger loads encrypted spendkey, Trezor loads null key (never leaves device).
// In the test (debugging mode) we need to leave this field intact as it is already set by
// the debugging code and need to remain same for the testing purposes.
#ifndef WITH_TREZOR_DEBUGGING
spendkey = crypto::null_skey; // not given
#endif

memcpy(viewkey.data, res->watch_key().data(), 32);

return true;
Expand Down Expand Up @@ -362,13 +369,9 @@ namespace trezor {
CHECK_AND_ASSERT_THROW_MES(m_features, "Device state not initialized"); // make sure the caller did not reset features
const bool nonce_required = init_msg->tsx_data().has_payment_id() && init_msg->tsx_data().payment_id().size() > 0;

if (nonce_required){
if (nonce_required && init_msg->tsx_data().payment_id().size() == 8){
// Versions 2.0.9 and lower do not support payment ID
CHECK_AND_ASSERT_THROW_MES(m_features->has_major_version() && m_features->has_minor_version() && m_features->has_patch_version(), "Invalid Trezor firmware version information");
const uint32_t vma = m_features->major_version();
const uint32_t vmi = m_features->minor_version();
const uint32_t vpa = m_features->patch_version();
if (vma < 2 || (vma == 2 && vmi == 0 && vpa <= 9)) {
if (get_version() <= pack_version(2, 0, 9)) {
throw exc::TrezorException("Trezor firmware 2.0.9 and lower does not support transactions with short payment IDs or integrated addresses. Please update.");
}
}
Expand Down
116 changes: 105 additions & 11 deletions src/device_trezor/device_trezor_base.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,9 @@ namespace trezor {
const uint32_t device_trezor_base::DEFAULT_BIP44_PATH[] = {0x8000002c, 0x80000080};

device_trezor_base::device_trezor_base(): m_callback(nullptr) {

#ifdef WITH_TREZOR_DEBUGGING
m_debug = false;
#endif
}

device_trezor_base::~device_trezor_base() {
Expand Down Expand Up @@ -130,6 +132,10 @@ namespace trezor {
}

m_transport->open();

#ifdef WITH_TREZOR_DEBUGGING
setup_debug();
#endif
return true;

} catch(std::exception const& e){
Expand All @@ -153,6 +159,13 @@ namespace trezor {
return false;
}
}

#ifdef WITH_TREZOR_DEBUGGING
if (m_debug_callback) {
m_debug_callback->on_disconnect();
m_debug_callback = nullptr;
}
#endif
return true;
}

Expand Down Expand Up @@ -355,6 +368,32 @@ namespace trezor {
device_state_reset_unsafe();
}

#ifdef WITH_TREZOR_DEBUGGING
#define TREZOR_CALLBACK(method, ...) do { \
if (m_debug_callback) m_debug_callback->method(__VA_ARGS__); \
if (m_callback) m_callback->method(__VA_ARGS__); \
}while(0)

void device_trezor_base::setup_debug(){
if (!m_debug){
return;
}

if (!m_debug_callback){
CHECK_AND_ASSERT_THROW_MES(m_transport, "Transport does not exist");
auto debug_transport = m_transport->find_debug();
if (debug_transport) {
m_debug_callback = std::make_shared<trezor_debug_callback>(debug_transport);
} else {
MDEBUG("Transport does not have debug link option");
}
}
}

#else
#define TREZOR_CALLBACK(method, ...) do { if (m_callback) m_callback->method(__VA_ARGS__); } while(0)
#endif

void device_trezor_base::on_button_request(GenericMessage & resp, const messages::common::ButtonRequest * msg)
{
CHECK_AND_ASSERT_THROW_MES(msg, "Empty message");
Expand All @@ -363,10 +402,7 @@ namespace trezor {
messages::common::ButtonAck ack;
write_raw(&ack);

if (m_callback){
m_callback->on_button_request();
}

TREZOR_CALLBACK(on_button_request);
resp = read_raw();
}

Expand All @@ -377,9 +413,7 @@ namespace trezor {

epee::wipeable_string pin;

if (m_callback){
m_callback->on_pin_request(pin);
}
TREZOR_CALLBACK(on_pin_request, pin);

// TODO: remove PIN from memory
messages::common::PinMatrixAck m;
Expand All @@ -393,9 +427,7 @@ namespace trezor {
MDEBUG("on_passhprase_request, on device: " << msg->on_device());
epee::wipeable_string passphrase;

if (m_callback){
m_callback->on_passphrase_request(msg->on_device(), passphrase);
}
TREZOR_CALLBACK(on_passphrase_request, msg->on_device(), passphrase);

messages::common::PassphraseAck m;
if (!msg->on_device()){
Expand All @@ -421,5 +453,67 @@ namespace trezor {
resp = call_raw(&m);
}

#ifdef WITH_TREZOR_DEBUGGING
void device_trezor_base::wipe_device()
{
auto msg = std::make_shared<messages::management::WipeDevice>();
auto ret = client_exchange<messages::common::Success>(msg);
(void)ret;
init_device();
}

void device_trezor_base::init_device()
{
auto msg = std::make_shared<messages::management::Initialize>();
m_features = client_exchange<messages::management::Features>(msg);
}

void device_trezor_base::load_device(const std::string & mnemonic, const std::string & pin,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wipeable_string ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function is applicable only with debugging Trezor firmware, basically with an emulator for integration tests. It cannot be used on production so I thought normal strings would do the job here.

bool passphrase_protection, const std::string & label, const std::string & language,
bool skip_checksum, bool expand)
{
if (m_features && m_features->initialized()){
throw std::runtime_error("Device is initialized already. Call device.wipe() and try again.");
}

auto msg = std::make_shared<messages::management::LoadDevice>();
msg->set_mnemonic(mnemonic);
msg->set_pin(pin);
msg->set_passphrase_protection(passphrase_protection);
msg->set_label(label);
msg->set_language(language);
msg->set_skip_checksum(skip_checksum);
auto ret = client_exchange<messages::common::Success>(msg);
(void)ret;

init_device();
}

trezor_debug_callback::trezor_debug_callback(std::shared_ptr<Transport> & debug_transport){
m_debug_link = std::make_shared<DebugLink>();
m_debug_link->init(debug_transport);
}

void trezor_debug_callback::on_button_request() {
if (m_debug_link) m_debug_link->press_yes();
}

void trezor_debug_callback::on_pin_request(epee::wipeable_string &pin) {

}

void trezor_debug_callback::on_passphrase_request(bool on_device, epee::wipeable_string &passphrase) {

}

void trezor_debug_callback::on_passphrase_state_request(const std::string &state) {

}

void trezor_debug_callback::on_disconnect(){
if (m_debug_link) m_debug_link->close();
}
#endif

#endif //WITH_DEVICE_TREZOR
}}
53 changes: 52 additions & 1 deletion src/device_trezor/device_trezor_base.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@
#include "cryptonote_config.h"
#include "trezor.hpp"

#ifdef WITH_TREZOR_DEBUGGING
#include "trezor/debug_link.hpp"
#endif

//automatic lock one more level on device ensuring the current thread is allowed to use it
#define AUTO_LOCK_CMD() \
/* lock both mutexes without deadlock*/ \
Expand All @@ -57,6 +61,23 @@ namespace trezor {
#ifdef WITH_DEVICE_TREZOR
class device_trezor_base;

#ifdef WITH_TREZOR_DEBUGGING
class trezor_debug_callback {
public:
trezor_debug_callback()=default;
explicit trezor_debug_callback(std::shared_ptr<Transport> & debug_transport);

void on_button_request();
void on_pin_request(epee::wipeable_string &pin);
void on_passphrase_request(bool on_device, epee::wipeable_string &passphrase);
void on_passphrase_state_request(const std::string &state);
void on_disconnect();
protected:
std::shared_ptr<DebugLink> m_debug_link;
};

#endif

/**
* TREZOR device template with basic functions
*/
Expand All @@ -77,6 +98,13 @@ namespace trezor {

cryptonote::network_type network_type;

#ifdef WITH_TREZOR_DEBUGGING
std::shared_ptr<trezor_debug_callback> m_debug_callback;
bool m_debug;

void setup_debug();
#endif

//
// Internal methods
//
Expand All @@ -103,7 +131,7 @@ namespace trezor {
* @throws UnexpectedMessageException if the response message type is different than expected.
* Exception contains message type and the message itself.
*/
template<class t_message>
template<class t_message=google::protobuf::Message>
std::shared_ptr<t_message>
client_exchange(const std::shared_ptr<const google::protobuf::Message> &req,
const boost::optional<messages::MessageType> & resp_type = boost::none,
Expand Down Expand Up @@ -229,6 +257,12 @@ namespace trezor {
return m_features;
}

uint64_t get_version() const {
CHECK_AND_ASSERT_THROW_MES(m_features, "Features not loaded");
CHECK_AND_ASSERT_THROW_MES(m_features->has_major_version() && m_features->has_minor_version() && m_features->has_patch_version(), "Invalid Trezor firmware version information");
return pack_version(m_features->major_version(), m_features->minor_version(), m_features->patch_version());
}
ph4r05 marked this conversation as resolved.
Show resolved Hide resolved

void set_derivation_path(const std::string &deriv_path) override;

/* ======================================================================= */
Expand Down Expand Up @@ -268,6 +302,23 @@ namespace trezor {
void on_pin_request(GenericMessage & resp, const messages::common::PinMatrixRequest * msg);
void on_passphrase_request(GenericMessage & resp, const messages::common::PassphraseRequest * msg);
void on_passphrase_state_request(GenericMessage & resp, const messages::common::PassphraseStateRequest * msg);

#ifdef WITH_TREZOR_DEBUGGING
void set_debug(bool debug){
m_debug = debug;
}

void set_debug_callback(std::shared_ptr<trezor_debug_callback> & debug_callback){
m_debug_callback = debug_callback;
}

void wipe_device();
void init_device();
void load_device(const std::string & mnemonic, const std::string & pin="", bool passphrase_protection=false,
const std::string & label="test", const std::string & language="english",
bool skip_checksum=false, bool expand=false);

#endif
};

#endif
Expand Down
Loading