Replace USB-CCID (smartcard) by USB-HID
Remove PCSC dependencies which is a bit hard (not user friendly) to install on linux and Mac Split Ledger logic and device IO
This commit is contained in:
parent
5c637c7910
commit
bb6e3bbc0f
|
@ -435,7 +435,7 @@ if(STATIC AND NOT IOS)
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
find_package(PCSC)
|
find_package(HIDAPI)
|
||||||
|
|
||||||
add_definition_if_library_exists(c memset_s "string.h" HAVE_MEMSET_S)
|
add_definition_if_library_exists(c memset_s "string.h" HAVE_MEMSET_S)
|
||||||
add_definition_if_library_exists(c explicit_bzero "strings.h" HAVE_EXPLICIT_BZERO)
|
add_definition_if_library_exists(c explicit_bzero "strings.h" HAVE_EXPLICIT_BZERO)
|
||||||
|
@ -476,14 +476,14 @@ endif()
|
||||||
include_directories(${LIBUNWIND_INCLUDE})
|
include_directories(${LIBUNWIND_INCLUDE})
|
||||||
link_directories(${LIBUNWIND_LIBRARY_DIRS})
|
link_directories(${LIBUNWIND_LIBRARY_DIRS})
|
||||||
|
|
||||||
# Final setup for libpcsc
|
# Final setup for hid
|
||||||
if (PCSC_FOUND)
|
if (HIDAPI_FOUND)
|
||||||
message(STATUS "Using PCSC include dir at ${PCSC_INCLUDE_DIR}")
|
message(STATUS "Using HIDAPI include dir at ${HIDAPI_INCLUDE_DIR}")
|
||||||
add_definitions(-DHAVE_PCSC)
|
add_definitions(-DHAVE_HIDAPI)
|
||||||
include_directories(${PCSC_INCLUDE_DIR})
|
include_directories(${HIDAPI_INCLUDE_DIR})
|
||||||
link_directories(${LIBPCSC_LIBRARY_DIRS})
|
link_directories(${LIBHIDAPI_LIBRARY_DIRS})
|
||||||
else (PCSC_FOUND)
|
else (HIDAPI_FOUND)
|
||||||
message(STATUS "Could not find PCSC")
|
message(STATUS "Could not find HIDAPI")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(MSVC)
|
if(MSVC)
|
||||||
|
@ -881,6 +881,18 @@ endif()
|
||||||
|
|
||||||
list(APPEND EXTRA_LIBRARIES ${CMAKE_DL_LIBS})
|
list(APPEND EXTRA_LIBRARIES ${CMAKE_DL_LIBS})
|
||||||
|
|
||||||
|
if (HIDAPI_FOUND)
|
||||||
|
if (APPLE)
|
||||||
|
find_library(COREFOUNDATION CoreFoundation)
|
||||||
|
find_library(IOKIT IOKit)
|
||||||
|
list(APPEND EXTRA_LIBRARIES ${IOKIT})
|
||||||
|
list(APPEND EXTRA_LIBRARIES ${COREFOUNDATION})
|
||||||
|
endif()
|
||||||
|
if (WIN32)
|
||||||
|
list(APPEND EXTRA_LIBRARIES setupapi)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
option(USE_READLINE "Build with GNU readline support." ON)
|
option(USE_READLINE "Build with GNU readline support." ON)
|
||||||
if(USE_READLINE)
|
if(USE_READLINE)
|
||||||
find_package(Readline)
|
find_package(Readline)
|
||||||
|
|
|
@ -0,0 +1,46 @@
|
||||||
|
# - try to find HIDAPI library
|
||||||
|
# from http://www.signal11.us/oss/hidapi/
|
||||||
|
#
|
||||||
|
# Cache Variables: (probably not for direct use in your scripts)
|
||||||
|
# HIDAPI_INCLUDE_DIR
|
||||||
|
# HIDAPI_LIBRARY
|
||||||
|
#
|
||||||
|
# Non-cache variables you might use in your CMakeLists.txt:
|
||||||
|
# HIDAPI_FOUND
|
||||||
|
# HIDAPI_INCLUDE_DIRS
|
||||||
|
# HIDAPI_LIBRARIES
|
||||||
|
#
|
||||||
|
# Requires these CMake modules:
|
||||||
|
# FindPackageHandleStandardArgs (known included with CMake >=2.6.2)
|
||||||
|
#
|
||||||
|
# Original Author:
|
||||||
|
# 2009-2010 Ryan Pavlik <rpavlik@iastate.edu> <abiryan@ryand.net>
|
||||||
|
# http://academic.cleardefinition.com
|
||||||
|
# Iowa State University HCI Graduate Program/VRAC
|
||||||
|
#
|
||||||
|
# Copyright Iowa State University 2009-2010.
|
||||||
|
# Distributed under the Boost Software License, Version 1.0.
|
||||||
|
# (See accompanying file LICENSE_1_0.txt or copy at
|
||||||
|
# http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
find_library(HIDAPI_LIBRARY
|
||||||
|
NAMES hidapi hidapi-libusb)
|
||||||
|
|
||||||
|
find_path(HIDAPI_INCLUDE_DIR
|
||||||
|
NAMES hidapi.h
|
||||||
|
PATH_SUFFIXES
|
||||||
|
hidapi)
|
||||||
|
|
||||||
|
include(FindPackageHandleStandardArgs)
|
||||||
|
find_package_handle_standard_args(HIDAPI
|
||||||
|
DEFAULT_MSG
|
||||||
|
HIDAPI_LIBRARY
|
||||||
|
HIDAPI_INCLUDE_DIR)
|
||||||
|
|
||||||
|
if(HIDAPI_FOUND)
|
||||||
|
set(HIDAPI_LIBRARIES "${HIDAPI_LIBRARY}")
|
||||||
|
|
||||||
|
set(HIDAPI_INCLUDE_DIRS "${HIDAPI_INCLUDE_DIR}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
mark_as_advanced(HIDAPI_INCLUDE_DIR HIDAPI_LIBRARY)
|
|
@ -1,54 +0,0 @@
|
||||||
# - Find PCSC
|
|
||||||
# Find the native PCSC includes and library
|
|
||||||
#
|
|
||||||
# PCSC_INCLUDE_DIR - where to find winscard.h, wintypes.h, etc.
|
|
||||||
# PCSC_LIBRARIES - List of libraries when using PCSC.
|
|
||||||
# PCSC_FOUND - True if PCSC found.
|
|
||||||
|
|
||||||
|
|
||||||
IF (PCSC_INCLUDE_DIR AND PCSC_LIBRARIES)
|
|
||||||
# Already in cache, be silent
|
|
||||||
SET(PCSC_FIND_QUIETLY TRUE)
|
|
||||||
ENDIF (PCSC_INCLUDE_DIR AND PCSC_LIBRARIES)
|
|
||||||
|
|
||||||
IF (NOT WIN32)
|
|
||||||
FIND_PACKAGE(PkgConfig)
|
|
||||||
PKG_CHECK_MODULES(PC_PCSC libpcsclite)
|
|
||||||
|
|
||||||
FIND_PATH(PCSC_INCLUDE_DIR winscard.h
|
|
||||||
HINTS
|
|
||||||
/usr/include/PCSC
|
|
||||||
${PC_PCSC_INCLUDEDIR}
|
|
||||||
${PC_PCSC_INCLUDE_DIRS}
|
|
||||||
PATH_SUFFIXES PCSC
|
|
||||||
)
|
|
||||||
|
|
||||||
FIND_LIBRARY(PCSC_LIBRARY NAMES pcsclite libpcsclite PCSC
|
|
||||||
HINTS
|
|
||||||
${PC_PCSC_LIBDIR}
|
|
||||||
${PC_PCSC_LIBRARY_DIRS}
|
|
||||||
)
|
|
||||||
|
|
||||||
ELSE (NOT WIN32)
|
|
||||||
IF(BUILD_64 STREQUAL "ON")
|
|
||||||
set(PCSC_INCLUDE_DIR /mingw64/x86_64-w64-mingw32/include)
|
|
||||||
set(PCSC_LIBRARY /mingw64/x86_64-w64-mingw32/lib/libwinscard.a)
|
|
||||||
ELSE(BUILD_64 STREQUAL "ON")
|
|
||||||
set(PCSC_INCLUDE_DIR /mingw32/i686-w64-mingw32/include)
|
|
||||||
set(PCSC_LIBRARY /mingw32/i686-w64-mingw32/lib/libwinscard.a)
|
|
||||||
ENDIF(BUILD_64 STREQUAL "ON")
|
|
||||||
ENDIF (NOT WIN32)
|
|
||||||
|
|
||||||
# handle the QUIETLY and REQUIRED arguments and set PCSC_FOUND to TRUE if
|
|
||||||
# all listed variables are TRUE
|
|
||||||
INCLUDE(FindPackageHandleStandardArgs)
|
|
||||||
FIND_PACKAGE_HANDLE_STANDARD_ARGS(PCSC DEFAULT_MSG PCSC_LIBRARY PCSC_INCLUDE_DIR)
|
|
||||||
|
|
||||||
IF(PCSC_FOUND)
|
|
||||||
SET( PCSC_LIBRARIES ${PCSC_LIBRARY} )
|
|
||||||
SET(PCSC_STATIC_LIBRARIES ${PCSC_STATIC_LIBRARY})
|
|
||||||
ELSE(PCSC_FOUND)
|
|
||||||
SET( PCSC_LIBRARIES )
|
|
||||||
ENDIF(PCSC_FOUND)
|
|
||||||
|
|
||||||
MARK_AS_ADVANCED( PCSC_LIBRARY PCSC_INCLUDE_DIR PCSC_STATIC_LIBRARY)
|
|
|
@ -32,18 +32,27 @@ set(device_sources
|
||||||
log.cpp
|
log.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
if(PCSC_FOUND)
|
if(HIDAPI_FOUND)
|
||||||
set(device_sources ${device_sources} device_ledger.cpp)
|
set(device_sources
|
||||||
|
${device_sources}
|
||||||
|
device_ledger.cpp
|
||||||
|
device_io_hid.cpp
|
||||||
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
set(device_headers
|
set(device_headers
|
||||||
device.hpp
|
device.hpp
|
||||||
|
device_io.hpp
|
||||||
device_default.hpp
|
device_default.hpp
|
||||||
log.hpp
|
log.hpp
|
||||||
)
|
)
|
||||||
|
|
||||||
if(PCSC_FOUND)
|
if(HIDAPI_FOUND)
|
||||||
set(device_headers ${device_headers} device_ledger.hpp)
|
set(device_headers
|
||||||
|
${device_headers}
|
||||||
|
device_ledger.hpp
|
||||||
|
device_io_hid.hpp
|
||||||
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
set(device_private_headers)
|
set(device_private_headers)
|
||||||
|
@ -65,7 +74,7 @@ monero_add_library(device
|
||||||
|
|
||||||
target_link_libraries(device
|
target_link_libraries(device
|
||||||
PUBLIC
|
PUBLIC
|
||||||
${PCSC_LIBRARIES}
|
${HIDAPI_LIBRARIES}
|
||||||
cncrypto
|
cncrypto
|
||||||
ringct_basic
|
ringct_basic
|
||||||
${OPENSSL_CRYPTO_LIBRARIES}
|
${OPENSSL_CRYPTO_LIBRARIES}
|
||||||
|
|
|
@ -29,7 +29,7 @@
|
||||||
|
|
||||||
#include "device.hpp"
|
#include "device.hpp"
|
||||||
#include "device_default.hpp"
|
#include "device_default.hpp"
|
||||||
#ifdef HAVE_PCSC
|
#ifdef WITH_DEVICE_LEDGER
|
||||||
#include "device_ledger.hpp"
|
#include "device_ledger.hpp"
|
||||||
#endif
|
#endif
|
||||||
#include "misc_log_ex.h"
|
#include "misc_log_ex.h"
|
||||||
|
@ -45,7 +45,7 @@ namespace hw {
|
||||||
|
|
||||||
device_registry::device_registry(){
|
device_registry::device_registry(){
|
||||||
hw::core::register_all(registry);
|
hw::core::register_all(registry);
|
||||||
#ifdef HAVE_PCSC
|
#ifdef WITH_DEVICE_LEDGER
|
||||||
hw::ledger::register_all(registry);
|
hw::ledger::register_all(registry);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,11 +48,12 @@
|
||||||
#include "crypto/chacha.h"
|
#include "crypto/chacha.h"
|
||||||
#include "ringct/rctTypes.h"
|
#include "ringct/rctTypes.h"
|
||||||
|
|
||||||
|
|
||||||
#ifndef USE_DEVICE_LEDGER
|
#ifndef USE_DEVICE_LEDGER
|
||||||
#define USE_DEVICE_LEDGER 1
|
#define USE_DEVICE_LEDGER 1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !defined(HAVE_PCSC)
|
#if !defined(HAVE_HIDAPI)
|
||||||
#undef USE_DEVICE_LEDGER
|
#undef USE_DEVICE_LEDGER
|
||||||
#define USE_DEVICE_LEDGER 0
|
#define USE_DEVICE_LEDGER 0
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -0,0 +1,56 @@
|
||||||
|
// Copyright (c) 2017-2018, The Monero Project
|
||||||
|
//
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without modification, are
|
||||||
|
// permitted provided that the following conditions are met:
|
||||||
|
//
|
||||||
|
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||||
|
// conditions and the following disclaimer.
|
||||||
|
//
|
||||||
|
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||||
|
// of conditions and the following disclaimer in the documentation and/or other
|
||||||
|
// materials provided with the distribution.
|
||||||
|
//
|
||||||
|
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||||
|
// used to endorse or promote products derived from this software without specific
|
||||||
|
// prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||||
|
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||||
|
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||||
|
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||||
|
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||||
|
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
|
||||||
|
namespace hw {
|
||||||
|
namespace io {
|
||||||
|
|
||||||
|
class device_io {
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
device_io() {};
|
||||||
|
~device_io() {};
|
||||||
|
|
||||||
|
virtual void init() = 0;
|
||||||
|
virtual void release() = 0;
|
||||||
|
|
||||||
|
virtual void connect(void *parms) = 0;
|
||||||
|
virtual void disconnect() = 0;
|
||||||
|
virtual bool connected() const = 0;
|
||||||
|
|
||||||
|
virtual int exchange(unsigned char *command, unsigned int cmd_len, unsigned char *response, unsigned int max_resp_len) = 0;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
|
@ -0,0 +1,288 @@
|
||||||
|
// used to endorse or promote products derived from this software without specific
|
||||||
|
// prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||||
|
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||||
|
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||||
|
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||||
|
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||||
|
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
//
|
||||||
|
#if defined(HAVE_HIDAPI)
|
||||||
|
|
||||||
|
#include "log.hpp"
|
||||||
|
#include "device_io_hid.hpp"
|
||||||
|
|
||||||
|
namespace hw {
|
||||||
|
namespace io {
|
||||||
|
|
||||||
|
#undef MONERO_DEFAULT_LOG_CATEGORY
|
||||||
|
#define MONERO_DEFAULT_LOG_CATEGORY "device.io"
|
||||||
|
|
||||||
|
#define ASSERT_X(exp,msg) CHECK_AND_ASSERT_THROW_MES(exp, msg);
|
||||||
|
|
||||||
|
#define MAX_BLOCK 64
|
||||||
|
|
||||||
|
static std::string safe_hid_error(hid_device *hwdev) {
|
||||||
|
if (hwdev) {
|
||||||
|
return std::string((char*)hid_error(hwdev));
|
||||||
|
}
|
||||||
|
return std::string("NULL device");
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string safe_hid_path(const hid_device_info *hwdev_info) {
|
||||||
|
if (hwdev_info && hwdev_info->path) {
|
||||||
|
return std::string(hwdev_info->path);
|
||||||
|
}
|
||||||
|
return std::string("NULL path");
|
||||||
|
}
|
||||||
|
|
||||||
|
device_io_hid::device_io_hid(unsigned short c, unsigned char t, unsigned int ps, unsigned int to) :
|
||||||
|
channel(c),
|
||||||
|
tag(t),
|
||||||
|
packet_size(ps),
|
||||||
|
timeout(to),
|
||||||
|
usb_vid(0),
|
||||||
|
usb_pid(0),
|
||||||
|
usb_device(NULL) {
|
||||||
|
}
|
||||||
|
|
||||||
|
device_io_hid::device_io_hid() : device_io_hid(DEFAULT_CHANNEL, DEFAULT_TAG, DEFAULT_PACKET_SIZE, DEFAULT_TIMEOUT) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void device_io_hid::io_hid_log(int read, unsigned char* buffer, int block_len) {
|
||||||
|
if (hid_verbose) {
|
||||||
|
char strbuffer[1024];
|
||||||
|
hw::buffer_to_str(strbuffer, sizeof(strbuffer), (char*)buffer, block_len);
|
||||||
|
MDEBUG( "HID " << (read?"<":">") <<" : "<<strbuffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void device_io_hid::init() {
|
||||||
|
int r;
|
||||||
|
r = hid_init();
|
||||||
|
ASSERT_X(r>=0, "Unable to init hidapi library. Error "+std::to_string(r)+": "+safe_hid_error(this->usb_device));
|
||||||
|
}
|
||||||
|
|
||||||
|
void device_io_hid::connect(void *params) {
|
||||||
|
hid_conn_params *p = (struct hid_conn_params*)params;
|
||||||
|
this->connect(p->vid, p->pid, p->interface_number, p->usage_page, p->interface_OR_page);
|
||||||
|
}
|
||||||
|
|
||||||
|
void device_io_hid::connect(unsigned int vid, unsigned int pid, unsigned int interface_number, unsigned int usage_page, bool interface_OR_page ) {
|
||||||
|
hid_device_info *hwdev_info, *hwdev_info_list;
|
||||||
|
hid_device *hwdev;
|
||||||
|
|
||||||
|
this->disconnect();
|
||||||
|
|
||||||
|
hwdev_info_list = hid_enumerate(vid, pid);
|
||||||
|
ASSERT_X(hwdev_info_list, "Unable to enumerate device "+std::to_string(vid)+":"+std::to_string(vid)+ ": "+ safe_hid_error(this->usb_device));
|
||||||
|
hwdev = NULL;
|
||||||
|
hwdev_info = hwdev_info_list;
|
||||||
|
while (hwdev_info) {
|
||||||
|
if ((interface_OR_page && ((usage_page == 0xffa0) || (interface_number == 0))) ||
|
||||||
|
((usage_page == 0xffa0) && (interface_number == 0)) ) {
|
||||||
|
MDEBUG("HID Device found: " << safe_hid_path(hwdev_info));
|
||||||
|
hwdev = hid_open_path(hwdev_info->path);
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
MDEBUG("HID Device discard: " << safe_hid_path(hwdev_info) << "("+std::to_string(hwdev_info->usage_page) << "," << std::to_string(hwdev_info->interface_number) << ")");
|
||||||
|
}
|
||||||
|
hwdev_info = hwdev_info->next;
|
||||||
|
}
|
||||||
|
hid_free_enumeration(hwdev_info_list);
|
||||||
|
ASSERT_X(hwdev, "Unable to open device "+std::to_string(pid)+":"+std::to_string(vid));
|
||||||
|
this->usb_vid = vid;
|
||||||
|
this->usb_pid = pid;
|
||||||
|
this->usb_device = hwdev;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool device_io_hid::connected() const {
|
||||||
|
return this->usb_device != NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int device_io_hid::exchange(unsigned char *command, unsigned int cmd_len, unsigned char *response, unsigned int max_resp_len) {
|
||||||
|
unsigned char buffer[400];
|
||||||
|
unsigned char padding_buffer[MAX_BLOCK+1];
|
||||||
|
unsigned int result;
|
||||||
|
int hid_ret;
|
||||||
|
unsigned int sw_offset;
|
||||||
|
unsigned int remaining;
|
||||||
|
unsigned int offset = 0;
|
||||||
|
|
||||||
|
ASSERT_X(this->usb_device,"No device opened");
|
||||||
|
|
||||||
|
//Split command in several HID packet
|
||||||
|
memset(buffer, 0, sizeof(buffer));
|
||||||
|
result = this->wrapCommand(command, cmd_len, buffer, sizeof(buffer));
|
||||||
|
remaining = result;
|
||||||
|
|
||||||
|
while (remaining > 0) {
|
||||||
|
int block_size = (remaining > MAX_BLOCK ? MAX_BLOCK : remaining);
|
||||||
|
memset(padding_buffer, 0, sizeof(padding_buffer));
|
||||||
|
memcpy(padding_buffer+1, buffer + offset, block_size);
|
||||||
|
io_hid_log(0, padding_buffer, block_size+1);
|
||||||
|
hid_ret = hid_write(this->usb_device, padding_buffer, block_size+1);
|
||||||
|
ASSERT_X(hid_ret>=0, "Unable to send hidapi command. Error "+std::to_string(result)+": "+ safe_hid_error(this->usb_device));
|
||||||
|
offset += block_size;
|
||||||
|
remaining -= block_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
//get first response
|
||||||
|
memset(buffer, 0, sizeof(buffer));
|
||||||
|
hid_ret = hid_read_timeout(this->usb_device, buffer, MAX_BLOCK, this->timeout);
|
||||||
|
ASSERT_X(hid_ret>=0, "Unable to read hidapi response. Error "+std::to_string(result)+": "+ safe_hid_error(this->usb_device));
|
||||||
|
result = (unsigned int)hid_ret;
|
||||||
|
io_hid_log(1, buffer, result);
|
||||||
|
offset = MAX_BLOCK;
|
||||||
|
//parse first response and get others if any
|
||||||
|
for (;;) {
|
||||||
|
result = this->unwrapReponse(buffer, offset, response, max_resp_len);
|
||||||
|
if (result != 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
hid_ret = hid_read_timeout(this->usb_device, buffer + offset, MAX_BLOCK, this->timeout);
|
||||||
|
ASSERT_X(hid_ret>=0, "Unable to receive hidapi response. Error "+std::to_string(result)+": "+ safe_hid_error(this->usb_device));
|
||||||
|
result = (unsigned int)hid_ret;
|
||||||
|
io_hid_log(1, buffer + offset, result);
|
||||||
|
offset += MAX_BLOCK;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void device_io_hid::disconnect(void) {
|
||||||
|
if (this->usb_device) {
|
||||||
|
hid_close(this->usb_device);
|
||||||
|
}
|
||||||
|
this->usb_vid = 0;
|
||||||
|
this->usb_pid = 0;
|
||||||
|
this->usb_device = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void device_io_hid::release() {
|
||||||
|
/* Do not exit, as the lib context is global*/
|
||||||
|
//hid_exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int device_io_hid::wrapCommand(const unsigned char *command, size_t command_len, unsigned char *out, size_t out_len) {
|
||||||
|
unsigned int sequence_idx = 0;
|
||||||
|
unsigned int offset = 0;
|
||||||
|
unsigned int offset_out = 0;
|
||||||
|
unsigned int block_size;
|
||||||
|
|
||||||
|
ASSERT_X(this->packet_size >= 3, "Invalid Packet size: "+std::to_string(this->packet_size)) ;
|
||||||
|
ASSERT_X(out_len >= 7, "out_len too short: "+std::to_string(out_len));
|
||||||
|
|
||||||
|
out_len -= 7;
|
||||||
|
out[offset_out++] = ((this->channel >> 8) & 0xff);
|
||||||
|
out[offset_out++] = (this->channel & 0xff);
|
||||||
|
out[offset_out++] = this->tag;
|
||||||
|
out[offset_out++] = ((sequence_idx >> 8) & 0xff);
|
||||||
|
out[offset_out++] = (sequence_idx & 0xff);
|
||||||
|
sequence_idx++;
|
||||||
|
out[offset_out++] = ((command_len >> 8) & 0xff);
|
||||||
|
out[offset_out++] = (command_len & 0xff);
|
||||||
|
block_size = (command_len > this->packet_size - 7 ? this->packet_size - 7 : command_len);
|
||||||
|
ASSERT_X(out_len >= block_size, "out_len too short: "+std::to_string(out_len));
|
||||||
|
out_len -= block_size;
|
||||||
|
memcpy(out + offset_out, command + offset, block_size);
|
||||||
|
offset_out += block_size;
|
||||||
|
offset += block_size;
|
||||||
|
while (offset != command_len) {
|
||||||
|
ASSERT_X(out_len >= 5, "out_len too short: "+std::to_string(out_len));
|
||||||
|
out_len -= 5;
|
||||||
|
out[offset_out++] = ((this->channel >> 8) & 0xff);
|
||||||
|
out[offset_out++] = (this->channel & 0xff);
|
||||||
|
out[offset_out++] = this->tag;
|
||||||
|
out[offset_out++] = ((sequence_idx >> 8) & 0xff);
|
||||||
|
out[offset_out++] = (sequence_idx & 0xff);
|
||||||
|
sequence_idx++;
|
||||||
|
block_size = ((command_len - offset) > this->packet_size - 5 ? this->packet_size - 5 : command_len - offset);
|
||||||
|
ASSERT_X(out_len >= block_size, "out_len too short: "+std::to_string(out_len));
|
||||||
|
out_len -= block_size;
|
||||||
|
memcpy(out + offset_out, command + offset, block_size);
|
||||||
|
offset_out += block_size;
|
||||||
|
offset += block_size;
|
||||||
|
}
|
||||||
|
while ((offset_out % this->packet_size) != 0) {
|
||||||
|
ASSERT_X(out_len >= 1, "out_len too short: "+std::to_string(out_len));
|
||||||
|
out_len--;
|
||||||
|
out[offset_out++] = 0;
|
||||||
|
}
|
||||||
|
return offset_out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* return 0 if more data are needed
|
||||||
|
* >0 if response is fully available
|
||||||
|
*/
|
||||||
|
unsigned int device_io_hid::unwrapReponse(const unsigned char *data, size_t data_len, unsigned char *out, size_t out_len) {
|
||||||
|
unsigned int sequence_idx = 0;
|
||||||
|
unsigned int offset = 0;
|
||||||
|
unsigned int offset_out = 0;
|
||||||
|
unsigned int response_len;
|
||||||
|
unsigned int block_size;
|
||||||
|
unsigned int val;
|
||||||
|
|
||||||
|
//end?
|
||||||
|
if ((data == NULL) || (data_len < 7 + 5)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//check hid header
|
||||||
|
val = (data[offset]<<8) + data[offset+1];
|
||||||
|
offset += 2;
|
||||||
|
ASSERT_X(val == this->channel, "Wrong Channel");
|
||||||
|
val = data[offset];
|
||||||
|
offset++;
|
||||||
|
ASSERT_X(val == this->tag, "Wrong TAG");
|
||||||
|
val = (data[offset]<<8) + data[offset+1];
|
||||||
|
offset += 2;
|
||||||
|
ASSERT_X(val == sequence_idx, "Wrong sequence_idx");
|
||||||
|
|
||||||
|
//fetch
|
||||||
|
response_len = (data[offset++] << 8);
|
||||||
|
response_len |= data[offset++];
|
||||||
|
ASSERT_X(out_len >= response_len, "Out Buffer too short");
|
||||||
|
if (data_len < (7 + response_len)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
block_size = (response_len > (this->packet_size - 7) ? this->packet_size - 7 : response_len);
|
||||||
|
memcpy(out + offset_out, data + offset, block_size);
|
||||||
|
offset += block_size;
|
||||||
|
offset_out += block_size;
|
||||||
|
while (offset_out != response_len) {
|
||||||
|
sequence_idx++;
|
||||||
|
if (offset == data_len) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
val = (data[offset]<<8) + data[offset+1];
|
||||||
|
offset += 2;
|
||||||
|
ASSERT_X(val == this->channel, "Wrong Channel");
|
||||||
|
val = data[offset];
|
||||||
|
offset++;
|
||||||
|
ASSERT_X(val == this->tag, "Wrong TAG");
|
||||||
|
val = (data[offset]<<8) + data[offset+1];
|
||||||
|
offset += 2;
|
||||||
|
ASSERT_X(val == sequence_idx, "Wrong sequence_idx");
|
||||||
|
|
||||||
|
block_size = ((response_len - offset_out) > this->packet_size - 5 ? this->packet_size - 5 : response_len - offset_out);
|
||||||
|
if (block_size > (data_len - offset)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
memcpy(out + offset_out, data + offset, block_size);
|
||||||
|
offset += block_size;
|
||||||
|
offset_out += block_size;
|
||||||
|
}
|
||||||
|
return offset_out;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif //#if defined(HAVE_HIDAPI)
|
|
@ -0,0 +1,112 @@
|
||||||
|
// Copyright (c) 2017-2018, The Monero Project
|
||||||
|
//
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without modification, are
|
||||||
|
// permitted provided that the following conditions are met:
|
||||||
|
//
|
||||||
|
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||||
|
// conditions and the following disclaimer.
|
||||||
|
//
|
||||||
|
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||||
|
// of conditions and the following disclaimer in the documentation and/or other
|
||||||
|
// materials provided with the distribution.
|
||||||
|
//
|
||||||
|
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||||
|
// used to endorse or promote products derived from this software without specific
|
||||||
|
// prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||||
|
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||||
|
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||||
|
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||||
|
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||||
|
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
//
|
||||||
|
|
||||||
|
#if defined(HAVE_HIDAPI)
|
||||||
|
|
||||||
|
#include <hidapi/hidapi.h>
|
||||||
|
#include "device_io.hpp"
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace hw {
|
||||||
|
namespace io {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** HID class base. Commands are formated as follow:
|
||||||
|
*
|
||||||
|
* |----------------------------------------------------------|
|
||||||
|
* | 2 bytes | 1 byte | 2 bytes | 2 bytes | len bytes |
|
||||||
|
* |-----------|----------|-----------|----------|------------|
|
||||||
|
* | channel | tag | sequence | len | payload |
|
||||||
|
* |----------------------------------------------------------|
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
struct hid_conn_params {
|
||||||
|
unsigned int vid;
|
||||||
|
unsigned int pid;
|
||||||
|
unsigned int interface_number;
|
||||||
|
unsigned int usage_page;
|
||||||
|
bool interface_OR_page ;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class device_io_hid: device_io {
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
|
||||||
|
unsigned short channel;
|
||||||
|
unsigned char tag;
|
||||||
|
unsigned int packet_size;
|
||||||
|
unsigned int timeout;
|
||||||
|
|
||||||
|
unsigned int usb_vid;
|
||||||
|
unsigned int usb_pid;
|
||||||
|
hid_device *usb_device;
|
||||||
|
|
||||||
|
void io_hid_log(int read, unsigned char* buf, int buf_len);
|
||||||
|
void io_hid_init();
|
||||||
|
void io_hid_exit() ;
|
||||||
|
void io_hid_open(int vid, int pid, int mode);
|
||||||
|
void io_hid_close (void);
|
||||||
|
|
||||||
|
unsigned int wrapCommand(const unsigned char *command, size_t command_len, unsigned char *out, size_t out_len);
|
||||||
|
unsigned int unwrapReponse(const unsigned char *data, size_t data_len, unsigned char *out, size_t out_len);
|
||||||
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
bool hid_verbose = false;
|
||||||
|
|
||||||
|
const unsigned int OR_SELECT = 1;
|
||||||
|
const unsigned int AND_SELECT = 2;
|
||||||
|
|
||||||
|
const unsigned char DEFAULT_CHANNEL = 0x0001;
|
||||||
|
const unsigned char DEFAULT_TAG = 0x01;
|
||||||
|
const unsigned int DEFAULT_PACKET_SIZE = 64;
|
||||||
|
const unsigned int DEFAULT_TIMEOUT = 120000;
|
||||||
|
|
||||||
|
device_io_hid(unsigned short channel, unsigned char tag, unsigned int packet_zize, unsigned int timeout);
|
||||||
|
device_io_hid();
|
||||||
|
~device_io_hid() {};
|
||||||
|
|
||||||
|
void init();
|
||||||
|
void connect(void *params);
|
||||||
|
void connect(unsigned int vid, unsigned int pid, unsigned int interface_number, unsigned int usage_page, bool interface_OR_page );
|
||||||
|
bool connected() const;
|
||||||
|
int exchange(unsigned char *command, unsigned int cmd_len, unsigned char *response, unsigned int max_resp_len);
|
||||||
|
void disconnect();
|
||||||
|
void release();
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //#if defined(HAVE_HIDAPI)
|
|
@ -185,41 +185,8 @@ namespace hw {
|
||||||
#define INS_GET_RESPONSE 0xc0
|
#define INS_GET_RESPONSE 0xc0
|
||||||
|
|
||||||
|
|
||||||
void device_ledger::logCMD() {
|
device_ledger::device_ledger(): hw_device(0x0101, 0x05, 64, 10000) {
|
||||||
if (apdu_verbose) {
|
|
||||||
char strbuffer[1024];
|
|
||||||
snprintf(strbuffer, sizeof(strbuffer), "%.02x %.02x %.02x %.02x %.02x ",
|
|
||||||
this->buffer_send[0],
|
|
||||||
this->buffer_send[1],
|
|
||||||
this->buffer_send[2],
|
|
||||||
this->buffer_send[3],
|
|
||||||
this->buffer_send[4]
|
|
||||||
);
|
|
||||||
const size_t len = strlen(strbuffer);
|
|
||||||
buffer_to_str(strbuffer+len, sizeof(strbuffer)-len, (char*)(this->buffer_send+5), this->length_send-5);
|
|
||||||
MDEBUG( "CMD :" << strbuffer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void device_ledger::logRESP() {
|
|
||||||
if (apdu_verbose) {
|
|
||||||
char strbuffer[1024];
|
|
||||||
snprintf(strbuffer, sizeof(strbuffer), "%.02x%.02x ",
|
|
||||||
this->buffer_recv[this->length_recv-2],
|
|
||||||
this->buffer_recv[this->length_recv-1]
|
|
||||||
);
|
|
||||||
const size_t len = strlen(strbuffer);
|
|
||||||
buffer_to_str(strbuffer+len, sizeof(strbuffer)-len, (char*)(this->buffer_recv), this->length_recv-2);
|
|
||||||
MDEBUG( "RESP :" << strbuffer);
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* -------------------------------------------------------------- */
|
|
||||||
device_ledger::device_ledger() {
|
|
||||||
this->id = device_id++;
|
this->id = device_id++;
|
||||||
this->hCard = 0;
|
|
||||||
this->hContext = 0;
|
|
||||||
this->reset_buffer();
|
this->reset_buffer();
|
||||||
this->mode = NONE;
|
this->mode = NONE;
|
||||||
this->has_view_key = false;
|
this->has_view_key = false;
|
||||||
|
@ -272,10 +239,39 @@ namespace hw {
|
||||||
MDEBUG( "Device "<<this->name << " UNLOCKed");
|
MDEBUG( "Device "<<this->name << " UNLOCKed");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* ======================================================================= */
|
/* ======================================================================= */
|
||||||
/* MISC */
|
/* IO */
|
||||||
/* ======================================================================= */
|
/* ======================================================================= */
|
||||||
int device_ledger::set_command_header(BYTE ins, BYTE p1, BYTE p2) {
|
|
||||||
|
void device_ledger::logCMD() {
|
||||||
|
if (apdu_verbose) {
|
||||||
|
char strbuffer[1024];
|
||||||
|
snprintf(strbuffer, sizeof(strbuffer), "%.02x %.02x %.02x %.02x %.02x ",
|
||||||
|
this->buffer_send[0],
|
||||||
|
this->buffer_send[1],
|
||||||
|
this->buffer_send[2],
|
||||||
|
this->buffer_send[3],
|
||||||
|
this->buffer_send[4]
|
||||||
|
);
|
||||||
|
const size_t len = strlen(strbuffer);
|
||||||
|
buffer_to_str(strbuffer+len, sizeof(strbuffer)-len, (char*)(this->buffer_send+5), this->length_send-5);
|
||||||
|
MDEBUG( "CMD : " << strbuffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void device_ledger::logRESP() {
|
||||||
|
if (apdu_verbose) {
|
||||||
|
char strbuffer[1024];
|
||||||
|
snprintf(strbuffer, sizeof(strbuffer), "%.04x ", this->sw);
|
||||||
|
const size_t len = strlen(strbuffer);
|
||||||
|
buffer_to_str(strbuffer+len, sizeof(strbuffer)-len, (char*)(this->buffer_recv), this->length_recv);
|
||||||
|
MDEBUG( "RESP : " << strbuffer);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int device_ledger::set_command_header(unsigned char ins, unsigned char p1, unsigned char p2) {
|
||||||
reset_buffer();
|
reset_buffer();
|
||||||
int offset = 0;
|
int offset = 0;
|
||||||
this->buffer_send[0] = 0x00;
|
this->buffer_send[0] = 0x00;
|
||||||
|
@ -286,7 +282,7 @@ namespace hw {
|
||||||
return 5;
|
return 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
int device_ledger::set_command_header_noopt(BYTE ins, BYTE p1, BYTE p2) {
|
int device_ledger::set_command_header_noopt(unsigned char ins, unsigned char p1, unsigned char p2) {
|
||||||
int offset = set_command_header(ins, p1, p2);
|
int offset = set_command_header(ins, p1, p2);
|
||||||
//options
|
//options
|
||||||
this->buffer_send[offset++] = 0;
|
this->buffer_send[offset++] = 0;
|
||||||
|
@ -294,7 +290,7 @@ namespace hw {
|
||||||
return offset;
|
return offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
void device_ledger::send_simple(BYTE ins, BYTE p1) {
|
void device_ledger::send_simple(unsigned char ins, unsigned char p1) {
|
||||||
this->length_send = set_command_header_noopt(ins, p1);
|
this->length_send = set_command_header_noopt(ins, p1);
|
||||||
this->exchange();
|
this->exchange();
|
||||||
}
|
}
|
||||||
|
@ -305,23 +301,17 @@ namespace hw {
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int device_ledger::exchange(unsigned int ok, unsigned int mask) {
|
unsigned int device_ledger::exchange(unsigned int ok, unsigned int mask) {
|
||||||
LONG rv;
|
|
||||||
unsigned int sw;
|
|
||||||
|
|
||||||
ASSERT_T0(this->length_send <= BUFFER_SEND_SIZE);
|
|
||||||
logCMD();
|
logCMD();
|
||||||
this->length_recv = BUFFER_RECV_SIZE;
|
|
||||||
rv = SCardTransmit(this->hCard,
|
|
||||||
SCARD_PCI_T0, this->buffer_send, this->length_send,
|
|
||||||
NULL, this->buffer_recv, &this->length_recv);
|
|
||||||
ASSERT_RV(rv);
|
|
||||||
ASSERT_T0(this->length_recv >= 2);
|
|
||||||
ASSERT_T0(this->length_recv <= BUFFER_RECV_SIZE);
|
|
||||||
logRESP();
|
|
||||||
|
|
||||||
sw = (this->buffer_recv[this->length_recv-2]<<8) | this->buffer_recv[this->length_recv-1];
|
this->length_recv = hw_device.exchange(this->buffer_send, this->length_send, this->buffer_recv, BUFFER_SEND_SIZE);
|
||||||
ASSERT_SW(sw,ok,msk);
|
ASSERT_X(this->length_recv>=2, "Communication error, less than tow bytes received");
|
||||||
return sw;
|
|
||||||
|
this->length_recv -= 2;
|
||||||
|
this->sw = (this->buffer_recv[length_recv]<<8) | this->buffer_recv[length_recv+1];
|
||||||
|
ASSERT_SW(this->sw,ok,msk);
|
||||||
|
|
||||||
|
logRESP();
|
||||||
|
return this->sw;
|
||||||
}
|
}
|
||||||
|
|
||||||
void device_ledger::reset_buffer() {
|
void device_ledger::reset_buffer() {
|
||||||
|
@ -341,101 +331,25 @@ namespace hw {
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string device_ledger::get_name() const {
|
const std::string device_ledger::get_name() const {
|
||||||
if (this->full_name.empty() || (this->hCard == 0)) {
|
if (this->full_name.empty() || !this->connected()) {
|
||||||
return std::string("<disconnected:").append(this->name).append(">");
|
return std::string("<disconnected:").append(this->name).append(">");
|
||||||
}
|
}
|
||||||
return this->full_name;
|
return this->name;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool device_ledger::init(void) {
|
bool device_ledger::init(void) {
|
||||||
#ifdef DEBUG_HWDEVICE
|
#ifdef DEBUG_HWDEVICE
|
||||||
this->controle_device = &hw::get_device("default");
|
this->controle_device = &hw::get_device("default");
|
||||||
#endif
|
#endif
|
||||||
LONG rv;
|
|
||||||
this->release();
|
this->release();
|
||||||
rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM,0,0, &this->hContext);
|
hw_device.init();
|
||||||
ASSERT_RV(rv);
|
MDEBUG( "Device "<<this->id <<" HIDUSB inited");
|
||||||
MDEBUG( "Device "<<this->id <<" SCardContext created: hContext="<<this->hContext);
|
|
||||||
this->hCard = 0;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool device_ledger::release() {
|
|
||||||
this->disconnect();
|
|
||||||
if (this->hContext) {
|
|
||||||
SCardReleaseContext(this->hContext);
|
|
||||||
MDEBUG( "Device "<<this->id <<" SCardContext released: hContext="<<this->hContext);
|
|
||||||
this->hContext = 0;
|
|
||||||
this->full_name.clear();
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool device_ledger::connect(void) {
|
bool device_ledger::connect(void) {
|
||||||
BYTE pbAtr[MAX_ATR_SIZE];
|
|
||||||
LPSTR mszReaders;
|
|
||||||
DWORD dwReaders;
|
|
||||||
LONG rv;
|
|
||||||
DWORD dwState, dwProtocol, dwAtrLen, dwReaderLen;
|
|
||||||
|
|
||||||
this->disconnect();
|
this->disconnect();
|
||||||
#ifdef SCARD_AUTOALLOCATE
|
hw_device.connect(0x2c97,0x0001, 0, 0xffa0, hw_device.OR_SELECT);
|
||||||
dwReaders = SCARD_AUTOALLOCATE;
|
|
||||||
rv = SCardListReaders(this->hContext, NULL, (LPSTR)&mszReaders, &dwReaders);
|
|
||||||
#else
|
|
||||||
dwReaders = 0;
|
|
||||||
rv = SCardListReaders(this->hContext, NULL, NULL, &dwReaders);
|
|
||||||
if (rv != SCARD_S_SUCCESS)
|
|
||||||
return false;
|
|
||||||
mszReaders = (LPSTR)calloc(dwReaders, sizeof(char));
|
|
||||||
rv = SCardListReaders(this->hContext, NULL, mszReaders, &dwReaders);
|
|
||||||
#endif
|
|
||||||
if (rv == SCARD_S_SUCCESS) {
|
|
||||||
char* p;
|
|
||||||
const char* prefix = this->name.c_str();
|
|
||||||
|
|
||||||
p = mszReaders;
|
|
||||||
MDEBUG( "Looking for " << std::string(prefix));
|
|
||||||
while (*p) {
|
|
||||||
MDEBUG( "Device Found: " << std::string(p));
|
|
||||||
if ((strncmp(prefix, p, strlen(prefix))==0)) {
|
|
||||||
MDEBUG( "Device Match: " << std::string(p));
|
|
||||||
if ((rv = SCardConnect(this->hContext,
|
|
||||||
p, SCARD_SHARE_EXCLUSIVE, SCARD_PROTOCOL_T0,
|
|
||||||
&this->hCard, &dwProtocol))!=SCARD_S_SUCCESS) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
MDEBUG( "Device "<<this->id <<" Connected: hCard="<<this->hCard);
|
|
||||||
dwAtrLen = sizeof(pbAtr);
|
|
||||||
if ((rv = SCardStatus(this->hCard, NULL, &dwReaderLen, &dwState, &dwProtocol, pbAtr, &dwAtrLen))!=SCARD_S_SUCCESS) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
MDEBUG( "Device "<<this->id <<" Status OK");
|
|
||||||
rv = SCARD_S_SUCCESS ;
|
|
||||||
this->full_name = std::string(p);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
p += strlen(p) +1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rv == SCARD_S_SUCCESS && mszReaders) {
|
|
||||||
#ifdef SCARD_AUTOALLOCATE
|
|
||||||
SCardFreeMemory(this->hContext, mszReaders);
|
|
||||||
#else
|
|
||||||
free(mszReaders);
|
|
||||||
#endif
|
|
||||||
mszReaders = NULL;
|
|
||||||
}
|
|
||||||
if (rv != SCARD_S_SUCCESS) {
|
|
||||||
if ( hCard) {
|
|
||||||
SCardDisconnect(this->hCard, SCARD_UNPOWER_CARD);
|
|
||||||
MDEBUG( "Device "<<this->id <<" disconnected: hCard="<<this->hCard);
|
|
||||||
this->hCard = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ASSERT_RV(rv);
|
|
||||||
|
|
||||||
this->reset();
|
this->reset();
|
||||||
#ifdef DEBUG_HWDEVICE
|
#ifdef DEBUG_HWDEVICE
|
||||||
cryptonote::account_public_address pubkey;
|
cryptonote::account_public_address pubkey;
|
||||||
|
@ -445,15 +359,21 @@ namespace hw {
|
||||||
crypto::secret_key skey;
|
crypto::secret_key skey;
|
||||||
this->get_secret_keys(vkey,skey);
|
this->get_secret_keys(vkey,skey);
|
||||||
|
|
||||||
return rv==SCARD_S_SUCCESS;
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool device_ledger::connected(void) const {
|
||||||
|
return hw_device.connected();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool device_ledger::disconnect() {
|
bool device_ledger::disconnect() {
|
||||||
if (this->hCard) {
|
hw_device.disconnect();
|
||||||
SCardDisconnect(this->hCard, SCARD_UNPOWER_CARD);
|
return true;
|
||||||
MDEBUG( "Device "<<this->id <<" disconnected: hCard="<<this->hCard);
|
}
|
||||||
this->hCard = 0;
|
|
||||||
}
|
bool device_ledger::release() {
|
||||||
|
this->disconnect();
|
||||||
|
hw_device.release();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -33,13 +33,7 @@
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include "device.hpp"
|
#include "device.hpp"
|
||||||
#ifdef WIN32
|
#include "device_io_hid.hpp"
|
||||||
#include <winscard.h>
|
|
||||||
#define MAX_ATR_SIZE 33
|
|
||||||
#else
|
|
||||||
#include <PCSC/winscard.h>
|
|
||||||
#include <PCSC/wintypes.h>
|
|
||||||
#endif
|
|
||||||
#include <boost/thread/mutex.hpp>
|
#include <boost/thread/mutex.hpp>
|
||||||
#include <boost/thread/recursive_mutex.hpp>
|
#include <boost/thread/recursive_mutex.hpp>
|
||||||
|
|
||||||
|
@ -89,22 +83,23 @@ namespace hw {
|
||||||
mutable boost::recursive_mutex device_locker;
|
mutable boost::recursive_mutex device_locker;
|
||||||
mutable boost::mutex command_locker;
|
mutable boost::mutex command_locker;
|
||||||
|
|
||||||
//PCSC management
|
//IO
|
||||||
std::string full_name;
|
hw::io::device_io_hid hw_device;
|
||||||
SCARDCONTEXT hContext;
|
std::string full_name;
|
||||||
SCARDHANDLE hCard;
|
unsigned int length_send;
|
||||||
DWORD length_send;
|
unsigned char buffer_send[BUFFER_SEND_SIZE];
|
||||||
BYTE buffer_send[BUFFER_SEND_SIZE];
|
unsigned int length_recv;
|
||||||
DWORD length_recv;
|
unsigned char buffer_recv[BUFFER_RECV_SIZE];
|
||||||
BYTE buffer_recv[BUFFER_RECV_SIZE];
|
unsigned int sw;
|
||||||
unsigned int id;
|
unsigned int id;
|
||||||
void logCMD(void);
|
void logCMD(void);
|
||||||
void logRESP(void);
|
void logRESP(void);
|
||||||
unsigned int exchange(unsigned int ok=0x9000, unsigned int mask=0xFFFF);
|
unsigned int exchange(unsigned int ok=0x9000, unsigned int mask=0xFFFF);
|
||||||
void reset_buffer(void);
|
void reset_buffer(void);
|
||||||
int set_command_header(BYTE ins, BYTE p1 = 0x00, BYTE p2 = 0x00);
|
int set_command_header(unsigned char ins, unsigned char p1 = 0x00, unsigned char p2 = 0x00);
|
||||||
int set_command_header_noopt(BYTE ins, BYTE p1 = 0x00, BYTE p2 = 0x00);
|
int set_command_header_noopt(unsigned char ins, unsigned char p1 = 0x00, unsigned char p2 = 0x00);
|
||||||
void send_simple(BYTE ins, BYTE p1 = 0x00);
|
void send_simple(unsigned char ins, unsigned char p1 = 0x00);
|
||||||
|
|
||||||
|
|
||||||
// hw running mode
|
// hw running mode
|
||||||
device_mode mode;
|
device_mode mode;
|
||||||
|
@ -127,7 +122,7 @@ namespace hw {
|
||||||
device_ledger(const device_ledger &device) = delete ;
|
device_ledger(const device_ledger &device) = delete ;
|
||||||
device_ledger& operator=(const device_ledger &device) = delete;
|
device_ledger& operator=(const device_ledger &device) = delete;
|
||||||
|
|
||||||
explicit operator bool() const override {return this->hContext != 0;}
|
explicit operator bool() const override {return this->connected(); }
|
||||||
|
|
||||||
bool reset(void);
|
bool reset(void);
|
||||||
|
|
||||||
|
@ -141,6 +136,7 @@ namespace hw {
|
||||||
bool release() override;
|
bool release() override;
|
||||||
bool connect(void) override;
|
bool connect(void) override;
|
||||||
bool disconnect() override;
|
bool disconnect() override;
|
||||||
|
bool connected(void) const;
|
||||||
|
|
||||||
bool set_mode(device_mode mode) override;
|
bool set_mode(device_mode mode) override;
|
||||||
|
|
||||||
|
|
|
@ -32,29 +32,34 @@
|
||||||
|
|
||||||
namespace hw {
|
namespace hw {
|
||||||
|
|
||||||
#ifdef WITH_DEVICE_LEDGER
|
#undef MONERO_DEFAULT_LOG_CATEGORY
|
||||||
|
#define MONERO_DEFAULT_LOG_CATEGORY "device"
|
||||||
|
|
||||||
|
void buffer_to_str(char *to_buff, size_t to_len, const char *buff, size_t len) {
|
||||||
|
CHECK_AND_ASSERT_THROW_MES(to_len > (len*2), "destination buffer too short. At least" << (len*2+1) << " bytes required");
|
||||||
|
for (size_t i=0; i<len; i++) {
|
||||||
|
sprintf(to_buff+2*i, "%.02x", (unsigned char)buff[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void log_hexbuffer(const std::string &msg, const char* buff, size_t len) {
|
||||||
|
char logstr[1025];
|
||||||
|
buffer_to_str(logstr, sizeof(logstr), buff, len);
|
||||||
|
MDEBUG(msg<< ": " << logstr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void log_message(const std::string &msg, const std::string &info ) {
|
||||||
|
MDEBUG(msg << ": " << info);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef WITH_DEVICE_LEDGER
|
||||||
namespace ledger {
|
namespace ledger {
|
||||||
|
|
||||||
#undef MONERO_DEFAULT_LOG_CATEGORY
|
#undef MONERO_DEFAULT_LOG_CATEGORY
|
||||||
#define MONERO_DEFAULT_LOG_CATEGORY "device.ledger"
|
#define MONERO_DEFAULT_LOG_CATEGORY "device.ledger"
|
||||||
|
|
||||||
void buffer_to_str(char *to_buff, size_t to_len, const char *buff, size_t len) {
|
|
||||||
CHECK_AND_ASSERT_THROW_MES(to_len > (len*2), "destination buffer too short. At least" << (len*2+1) << " bytes required");
|
|
||||||
for (size_t i=0; i<len; i++) {
|
|
||||||
sprintf(to_buff+2*i, "%.02x", (unsigned char)buff[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void log_hexbuffer(const std::string &msg, const char* buff, size_t len) {
|
|
||||||
char logstr[1025];
|
|
||||||
buffer_to_str(logstr, sizeof(logstr), buff, len);
|
|
||||||
MDEBUG(msg<< ": " << logstr);
|
|
||||||
}
|
|
||||||
|
|
||||||
void log_message(const std::string &msg, const std::string &info ) {
|
|
||||||
MDEBUG(msg << ": " << info);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef DEBUG_HWDEVICE
|
#ifdef DEBUG_HWDEVICE
|
||||||
extern crypto::secret_key dbg_viewkey;
|
extern crypto::secret_key dbg_viewkey;
|
||||||
extern crypto::secret_key dbg_spendkey;
|
extern crypto::secret_key dbg_spendkey;
|
||||||
|
|
|
@ -40,12 +40,13 @@
|
||||||
|
|
||||||
namespace hw {
|
namespace hw {
|
||||||
|
|
||||||
|
void buffer_to_str(char *to_buff, size_t to_len, const char *buff, size_t len) ;
|
||||||
|
void log_hexbuffer(const std::string &msg, const char* buff, size_t len);
|
||||||
|
void log_message(const std::string &msg, const std::string &info );
|
||||||
|
|
||||||
#ifdef WITH_DEVICE_LEDGER
|
#ifdef WITH_DEVICE_LEDGER
|
||||||
namespace ledger {
|
namespace ledger {
|
||||||
|
|
||||||
void buffer_to_str(char *to_buff, size_t to_len, const char *buff, size_t len) ;
|
|
||||||
void log_hexbuffer(const std::string &msg, const char* buff, size_t len);
|
|
||||||
void log_message(const std::string &msg, const std::string &info );
|
|
||||||
#ifdef DEBUG_HWDEVICE
|
#ifdef DEBUG_HWDEVICE
|
||||||
#define TRACK printf("file %s:%d\n",__FILE__, __LINE__)
|
#define TRACK printf("file %s:%d\n",__FILE__, __LINE__)
|
||||||
//#define TRACK MCDEBUG("ledger"," At file " << __FILE__ << ":" << __LINE__)
|
//#define TRACK MCDEBUG("ledger"," At file " << __FILE__ << ":" << __LINE__)
|
||||||
|
|
Loading…
Reference in New Issue