From 6e27dd8db591170039180030981c56685664112c Mon Sep 17 00:00:00 2001 From: Jonathan White Date: Sun, 5 Sep 2021 08:51:25 -0400 Subject: [PATCH] Initial ykcore import into code base --- CMakeLists.txt | 7 - COPYING | 6 + cmake/CLangFormat.cmake | 4 +- src/CMakeLists.txt | 4 +- src/keys/drivers/YubiKey.cpp | 19 +- src/qrcode/CMakeLists.txt | 1 + src/thirdparty/CMakeLists.txt | 19 + src/thirdparty/ykcore/CMakeLists.txt | 42 ++ src/thirdparty/ykcore/ykbzero.h | 62 ++ src/thirdparty/ykcore/ykcore.c | 782 ++++++++++++++++++++++ src/thirdparty/ykcore/ykcore.h | 191 ++++++ src/thirdparty/ykcore/ykcore_backend.h | 54 ++ src/thirdparty/ykcore/ykcore_lcl.h | 69 ++ src/thirdparty/ykcore/ykcore_libusb-1.0.c | 296 ++++++++ src/thirdparty/ykcore/ykcore_libusb.c | 216 ++++++ src/thirdparty/ykcore/ykcore_osx.c | 280 ++++++++ src/thirdparty/ykcore/ykcore_windows.c | 210 ++++++ src/thirdparty/ykcore/ykcrc.c | 54 ++ src/thirdparty/ykcore/ykdef.h | 310 +++++++++ src/thirdparty/ykcore/ykstatus.c | 90 +++ src/thirdparty/ykcore/ykstatus.h | 60 ++ src/thirdparty/ykcore/yktsd.h | 61 ++ src/thirdparty/ykcore/yubikey.h | 136 ++++ 23 files changed, 2948 insertions(+), 25 deletions(-) create mode 100644 src/thirdparty/CMakeLists.txt create mode 100644 src/thirdparty/ykcore/CMakeLists.txt create mode 100644 src/thirdparty/ykcore/ykbzero.h create mode 100644 src/thirdparty/ykcore/ykcore.c create mode 100644 src/thirdparty/ykcore/ykcore.h create mode 100644 src/thirdparty/ykcore/ykcore_backend.h create mode 100644 src/thirdparty/ykcore/ykcore_lcl.h create mode 100644 src/thirdparty/ykcore/ykcore_libusb-1.0.c create mode 100644 src/thirdparty/ykcore/ykcore_libusb.c create mode 100644 src/thirdparty/ykcore/ykcore_osx.c create mode 100644 src/thirdparty/ykcore/ykcore_windows.c create mode 100644 src/thirdparty/ykcore/ykcrc.c create mode 100644 src/thirdparty/ykcore/ykdef.h create mode 100644 src/thirdparty/ykcore/ykstatus.c create mode 100644 src/thirdparty/ykcore/ykstatus.h create mode 100644 src/thirdparty/ykcore/yktsd.h create mode 100644 src/thirdparty/ykcore/yubikey.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 5e82f452f..176b7682b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -458,13 +458,6 @@ include_directories(SYSTEM ${ZLIB_INCLUDE_DIR}) # QREncode required for TOTP find_package(QREncode REQUIRED) -# Optional -if(WITH_XC_YUBIKEY) - find_package(YubiKey REQUIRED) - - include_directories(SYSTEM ${YUBIKEY_INCLUDE_DIRS}) -endif() - if(UNIX) check_cxx_source_compiles("#include int main() { prctl(PR_SET_DUMPABLE, 0); return 0; }" diff --git a/COPYING b/COPYING index c086a6236..9806cb92c 100644 --- a/COPYING +++ b/COPYING @@ -238,3 +238,9 @@ Files: share/icons/application/scalable/actions/hibp.svg share/icons/database/C64_Apple.svg Copyright: GPL-2+ Comment: from the Simple Icons repo (https://github.com/simple-icons/simple-icons/) + +Files: src/thirdparty/ykcore/yk* + src/thirdparty/ykcore/yubikey.h +Copyright: 2006-2015, Yubico AB +License: BSD-2-Clause +Comment: from the yubikey-personalization repo (https://github.com/Yubico/yubikey-personalization) diff --git a/cmake/CLangFormat.cmake b/cmake/CLangFormat.cmake index c1e9572c2..8118d5423 100644 --- a/cmake/CLangFormat.cmake +++ b/cmake/CLangFormat.cmake @@ -15,6 +15,7 @@ set(EXCLUDED_DIRS # third-party directories + src/thirdparty/ src/zxcvbn/ # objective-c directories src/touchid/ @@ -29,9 +30,6 @@ set(EXCLUDED_FILES gui/KMessageWidget.cpp gui/MainWindowAdaptor.h gui/MainWindowAdaptor.cpp - crypto/ssh/bcrypt_pbkdf.cpp - crypto/ssh/blf.h - crypto/ssh/blowfish.c tests/modeltest.cpp tests/modeltest.h # objective-c files diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e0a0fd8c1..95c721edb 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -262,6 +262,8 @@ if(WITH_XC_FDOSECRETS) set(fdosecrets_LIB fdosecrets) endif() +add_subdirectory(thirdparty) + set(autotype_SOURCES core/Tools.cpp autotype/AutoType.cpp @@ -318,9 +320,9 @@ target_link_libraries(keepassx_core Qt5::Network Qt5::Widgets ${BOTAN2_LIBRARIES} - ${YUBIKEY_LIBRARIES} ${ZXCVBN_LIBRARIES} ${ZLIB_LIBRARIES} + ${thirdparty_LIBRARIES} ) if(WITH_XC_SSHAGENT) diff --git a/src/keys/drivers/YubiKey.cpp b/src/keys/drivers/YubiKey.cpp index c55a0267e..fb85f3f89 100644 --- a/src/keys/drivers/YubiKey.cpp +++ b/src/keys/drivers/YubiKey.cpp @@ -16,15 +16,14 @@ * along with this program. If not, see . */ -#include -#include -#include -#include +#include "YubiKey.h" #include "core/Tools.h" #include "crypto/Random.h" -#include "YubiKey.h" +#include "thirdparty/ykcore/ykcore.h" +#include "thirdparty/ykcore/ykdef.h" +#include "thirdparty/ykcore/ykstatus.h" #include @@ -38,16 +37,11 @@ namespace if (onlyKey) { *onlyKey = false; } -#if YKPERS_VERSION_NUMBER >= 0x011200 - // This function is only available in ykcore >= 1.18.0 - key = yk_open_key(ykIndex); -#else // Only allow for the first found key to be used if (ykIndex == 0) { key = yk_open_first_key(); } -#endif -#if YKPERS_VERSION_NUMBER >= 0x011400 + // New fuction available in yubikey-personalization version >= 1.20.0 that allows // selecting device VID/PID (yk_open_key_vid_pid) if (!key) { @@ -57,9 +51,6 @@ namespace *onlyKey = true; } } -#else - Q_UNUSED(okIndex); -#endif return key; } diff --git a/src/qrcode/CMakeLists.txt b/src/qrcode/CMakeLists.txt index 9ffcf5808..bce692d67 100644 --- a/src/qrcode/CMakeLists.txt +++ b/src/qrcode/CMakeLists.txt @@ -19,3 +19,4 @@ set(qrcode_SOURCES add_library(qrcode STATIC ${qrcode_SOURCES}) target_link_libraries(qrcode Qt5::Core Qt5::Widgets Qt5::Svg ${QRENCODE_LIBRARY}) +target_include_directories(qrcode PRIVATE ${QRENCODE_INCLUDE_DIR}) diff --git a/src/thirdparty/CMakeLists.txt b/src/thirdparty/CMakeLists.txt new file mode 100644 index 000000000..e88f3d05a --- /dev/null +++ b/src/thirdparty/CMakeLists.txt @@ -0,0 +1,19 @@ +# Copyright (C) 2021 KeePassXC Team +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 or (at your option) +# version 3 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +if(WITH_XC_YUBIKEY) + add_subdirectory(ykcore) + set(thirdparty_LIBRARIES ${thirdparty_LIBRARIES} ykcore PARENT_SCOPE) +endif() diff --git a/src/thirdparty/ykcore/CMakeLists.txt b/src/thirdparty/ykcore/CMakeLists.txt new file mode 100644 index 000000000..47191ea74 --- /dev/null +++ b/src/thirdparty/ykcore/CMakeLists.txt @@ -0,0 +1,42 @@ +# Copyright (C) 2021 KeePassXC Team +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 or (at your option) +# version 3 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +set(ykcore_SOURCES + ykcore.c + ykstatus.c + ykcrc.c +) + +add_library(ykcore STATIC ${ykcore_SOURCES}) + +if(WIN32) + target_sources(ykcore PRIVATE ykcore_windows.c) + target_link_libraries(ykcore PRIVATE uuid setupapi hid) +elseif(UNIX AND NOT APPLE) + target_sources(ykcore PRIVATE ykcore_libusb-1.0.c) + + find_library(LIBUSB_LIBRARY NAMES usb-1.0) + find_path(LIBUSB_INCLUDE_DIR NAMES libusb.h PATH_SUFFIXES "libusb-1.0" "libusb") + if(NOT LIBUSB_LIBRARY OR NOT LIBUSB_INCLUDE_DIR) + message(FATAL_ERROR "libusb-1.0 dev package required, but not found") + endif() + + target_link_libraries(ykcore PRIVATE ${LIBUSB_LIBRARY}) + target_include_directories(ykcore PRIVATE ${LIBUSB_INCLUDE_DIR}) + target_compile_definitions(ykcore PRIVATE _GNU_SOURCE) +elseif(APPLE) + target_sources(ykcore PRIVATE ykcore_osx.c) + target_link_libraries(ykcore PUBLIC "-framework IOKit") +endif() diff --git a/src/thirdparty/ykcore/ykbzero.h b/src/thirdparty/ykcore/ykbzero.h new file mode 100644 index 000000000..730407de2 --- /dev/null +++ b/src/thirdparty/ykcore/ykbzero.h @@ -0,0 +1,62 @@ +/* -*- mode:C; c-file-style: "bsd" -*- */ +/* + * Copyright (c) 2008-2019 Yubico AB + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * 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. + * + * 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 + * OWNER 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. + */ + +#ifndef __YKBZERO_H_INCLUDED__ +#define __YKBZERO_H_INCLUDED__ + +#ifdef _WIN32 +#include +#else +#include +#endif + +#if defined(_WIN32) +#define insecure_memzero(buf, len) SecureZeroMemory(buf, len) +#elif defined(HAVE_MEMSET_S) +#define insecure_memzero(buf, len) memset_s(buf, len, 0, len) +#elif defined(HAVE_EXPLICIT_BZERO) +#define insecure_memzero(buf, len) explicit_bzero(buf, len) +#elif defined(HAVE_EXPLICIT_MEMSET) +#define insecure_memzero(buf, len) explicit_memset(buf, 0, len) +#elif defined(HAVE_INLINE_ASM) +#define insecure_memzero(buf, len) do { \ + memset(buf, 0, len); \ + __asm__ __volatile__ ("" : : "r"(buf) : "memory"); \ + } while (0) +#else +#define insecure_memzero(buf, len) do { \ + volatile unsigned char *volatile __buf_ = \ + (volatile unsigned char *volatile)buf; \ + size_t __i_ = 0; \ + while (__i_ < len) __buf_[__i_++] = 0; \ + } while (0) +#endif + +#endif /* __YKBZERO_H_INCLUDED__ */ diff --git a/src/thirdparty/ykcore/ykcore.c b/src/thirdparty/ykcore/ykcore.c new file mode 100644 index 000000000..7d8dfb604 --- /dev/null +++ b/src/thirdparty/ykcore/ykcore.c @@ -0,0 +1,782 @@ +/* -*- mode:C; c-file-style: "bsd" -*- */ +/* + * Copyright (c) 2008-2015 Yubico AB + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * 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. + * + * 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 + * OWNER 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. + */ + +#include "ykcore_lcl.h" +#include "ykcore_backend.h" +#include "yktsd.h" +#include "ykbzero.h" + +/* To get modhex and crc16 */ +#include "yubikey.h" + +#include +#ifndef _WIN32 +#include +#define Sleep(milliseconds) \ + struct timespec ts; \ + ts.tv_sec = milliseconds / (unsigned int) 1e3; \ + ts.tv_nsec = (milliseconds % (unsigned int) 1e3) * 1e6; \ + nanosleep(&ts, NULL); +#endif + +#ifdef YK_DEBUG +#define _yk_hexdump(buffer, size) \ + do { \ + unsigned char *p = buffer; \ + int i; \ + fprintf(stderr, "%25s: ", __func__); \ + for(i = 0; i < size; i++) { \ + fprintf(stderr, "%02x ", *p++); \ + } \ + fprintf(stderr, "\n"); \ + } while(0) +#endif + +/* + * Yubikey low-level interface section 2.4 (Report arbitration polling) specifies + * a 600 ms timeout for a Yubikey to process something written to it. + * Where can that document be found? + * It has been discovered that for swap 600 is not enough, swapping can worst + * case take 920 ms, which we then add 25% to for safety margin, arriving at + * 1150 ms. + */ +#define WAIT_FOR_WRITE_FLAG 1150 + +int yk_init(void) +{ + return _ykusb_start(); +} + +int yk_release(void) +{ + return _ykusb_stop(); +} + +YK_KEY *yk_open_first_key(void) +{ + return yk_open_key(0); +} + +YK_KEY *yk_open_key_vid_pid(int vid, const int* pids, size_t pids_len, int index) +{ + YK_KEY *yk = _ykusb_open_device(vid, pids, pids_len, index); + int rc = yk_errno; + + if (yk) { + YK_STATUS st; + + if (!yk_get_status(yk, &st)) { + rc = yk_errno; + yk_close_key(yk); + yk = NULL; + } + } + yk_errno = rc; + return yk; +} + +static const int yubico_pids[] = {YUBIKEY_PID, NEO_OTP_PID, NEO_OTP_CCID_PID, + NEO_OTP_U2F_PID, NEO_OTP_U2F_CCID_PID, YK4_OTP_PID, + YK4_OTP_U2F_PID, YK4_OTP_CCID_PID, YK4_OTP_U2F_CCID_PID, + PLUS_U2F_OTP_PID}; + +YK_KEY *yk_open_key(int index) +{ + return yk_open_key_vid_pid(YUBICO_VID, yubico_pids, sizeof(yubico_pids) / sizeof(yubico_pids[0]), index); +} + +int yk_close_key(YK_KEY *yk) +{ + return _ykusb_close_device(yk); +} + +int yk_check_firmware_version(YK_KEY *k) +{ + YK_STATUS st; + + if (!yk_get_status(k, &st)) + return 0; + + return yk_check_firmware_version2(&st); +} + + +int yk_check_firmware_version2(YK_STATUS *st) +{ + (void)st; + return 1; +} + +int yk_get_status(YK_KEY *k, YK_STATUS *status) +{ + unsigned int status_count = 0; + + if (!yk_read_from_key(k, 0, status, sizeof(YK_STATUS), &status_count)) + return 0; + + if (status_count != sizeof(YK_STATUS)) { + yk_errno = YK_EWRONGSIZ; + return 0; + } + + status->touchLevel = yk_endian_swap_16(status->touchLevel); + + return 1; +} + +/* Read the factory programmed serial number from a YubiKey. + * The possibility to retreive the serial number might be disabled + * using configuration, so it should not be considered a fatal error + * to not be able to read the serial number using this function. + * + * Serial number reading might also be configured to require user + * interaction (YubiKey button press) on startup, in which case flags + * might have to have YK_FLAG_MAYBLOCK set - haven't tried that. + * + * The slot parameter is here for future purposes only. + */ +int yk_get_serial(YK_KEY *yk, uint8_t slot, unsigned int flags, unsigned int *serial) +{ + unsigned char buf[FEATURE_RPT_SIZE * 2]; + unsigned int response_len = 0; + unsigned int expect_bytes = 0; + + memset(buf, 0, sizeof(buf)); + + if (!yk_write_to_key(yk, SLOT_DEVICE_SERIAL, &buf, 0)) + return 0; + + expect_bytes = 4; + + if (! yk_read_response_from_key(yk, slot, flags, + &buf, sizeof(buf), + expect_bytes, + &response_len)) + return 0; + + /* Serial number is stored in big endian byte order, despite + * everything else in the YubiKey being little endian - for + * some good reason I don't remember. + */ + *serial = + (buf[0] << 24) + + (buf[1] << 16) + + (buf[2] << 8) + + (buf[3]); + + return 1; +} + +int yk_get_capabilities(YK_KEY *yk, uint8_t slot, unsigned int flags, + unsigned char *capabilities, unsigned int *len) +{ + unsigned int response_len = 0; + + if (!yk_write_to_key(yk, SLOT_YK4_CAPABILITIES, capabilities, 0)) + return 0; + + if (! yk_read_response_from_key(yk, slot, flags, + capabilities, *len, 0, /* we have no idea how much data we'll get */ + &response_len)) + return 0; + + /* the first data of the capabilities string is the length */ + response_len = capabilities[0]; + response_len++; + + /* validate the length we got back from the hardware */ + if (response_len > *len) { + yk_errno = YK_EWRONGSIZ; + return 0; + } + + *len = response_len; + return 1; +} + +static int _yk_write(YK_KEY *yk, uint8_t yk_cmd, unsigned char *buf, size_t len) +{ + YK_STATUS stat; + int seq; + + /* Get current sequence # from status block */ + + if (!yk_get_status(yk, &stat /*, 0*/)) + return 0; + + seq = stat.pgmSeq; + + /* Write to Yubikey */ + if (!yk_write_to_key(yk, yk_cmd, buf, len)) + return 0; + + /* When the Yubikey clears the SLOT_WRITE_FLAG, it has processed the last write. + * This wait can't be done in yk_write_to_key since some users of that function + * want to get the bytes in the status message, but when writing configuration + * we don't expect any data back. + */ + if(!yk_wait_for_key_status(yk, yk_cmd, 0, WAIT_FOR_WRITE_FLAG, false, SLOT_WRITE_FLAG, NULL)) + return 0; + + /* Verify update */ + + if (!yk_get_status(yk, &stat /*, 0*/)) + return 0; + + yk_errno = YK_EWRITEERR; + + /* when both configurations from a YubiKey is erased it will return + * pgmSeq 0, if one is still configured after an erase pgmSeq is + * counted up as usual. */ + if((stat.touchLevel & (CONFIG1_VALID | CONFIG2_VALID)) == 0 && stat.pgmSeq == 0) { + return 1; + } + return stat.pgmSeq != seq; +} + +int yk_write_device_info(YK_KEY *yk, unsigned char *buf, unsigned int len) +{ + return _yk_write(yk, SLOT_YK4_SET_DEVICE_INFO, buf, len); +} + + +int yk_write_command(YK_KEY *yk, YK_CONFIG *cfg, uint8_t command, + unsigned char *acc_code) +{ + int ret; + unsigned char buf[sizeof(YK_CONFIG) + ACC_CODE_SIZE]; + + /* Update checksum and insert config block in buffer if present */ + + memset(buf, 0, sizeof(buf)); + + if (cfg) { + cfg->crc = ~yubikey_crc16 ((unsigned char *) cfg, + sizeof(YK_CONFIG) - sizeof(cfg->crc)); + cfg->crc = yk_endian_swap_16(cfg->crc); + memcpy(buf, cfg, sizeof(YK_CONFIG)); + } + + /* Append current access code if present */ + + if (acc_code) + memcpy(buf + sizeof(YK_CONFIG), acc_code, ACC_CODE_SIZE); + + ret = _yk_write(yk, command, buf, sizeof(buf)); + insecure_memzero(buf, sizeof(buf)); + return ret; +} + +int yk_write_config(YK_KEY *yk, YK_CONFIG *cfg, int confnum, + unsigned char *acc_code) +{ + uint8_t command; + switch(confnum) { + case 1: + command = SLOT_CONFIG; + break; + case 2: + command = SLOT_CONFIG2; + break; + default: + yk_errno = YK_EINVALIDCMD; + return 0; + } + if(!yk_write_command(yk, cfg, command, acc_code)) { + return 0; + } + return 1; +} + +int yk_write_ndef(YK_KEY *yk, YK_NDEF *ndef) +{ + /* just wrap yk_write_ndef2() with confnum 1 */ + return yk_write_ndef2(yk, ndef, 1); +} + +int yk_write_ndef2(YK_KEY *yk, YK_NDEF *ndef, int confnum) +{ + unsigned char buf[sizeof(YK_NDEF)]; + uint8_t command; + + switch(confnum) { + case 1: + command = SLOT_NDEF; + break; + case 2: + command = SLOT_NDEF2; + break; + default: + yk_errno = YK_EINVALIDCMD; + return 0; + } + + /* Insert config block in buffer */ + + memset(buf, 0, sizeof(buf)); + memcpy(buf, ndef, sizeof(YK_NDEF)); + + return _yk_write(yk, command, buf, sizeof(YK_NDEF)); +} + +int yk_write_device_config(YK_KEY *yk, YK_DEVICE_CONFIG *device_config) +{ + unsigned char buf[sizeof(YK_DEVICE_CONFIG)]; + + memset(buf, 0, sizeof(buf)); + memcpy(buf, device_config, sizeof(YK_DEVICE_CONFIG)); + + return _yk_write(yk, SLOT_DEVICE_CONFIG, buf, sizeof(YK_DEVICE_CONFIG)); +} + +int yk_write_scan_map(YK_KEY *yk, unsigned char *scan_map) +{ + return _yk_write(yk, SLOT_SCAN_MAP, scan_map, strlen(SCAN_MAP)); +} + +/* + * This function is for doing HMAC-SHA1 or Yubico challenge-response with a key. + */ +int yk_challenge_response(YK_KEY *yk, uint8_t yk_cmd, int may_block, + unsigned int challenge_len, const unsigned char *challenge, + unsigned int response_len, unsigned char *response) +{ + unsigned int flags = 0; + unsigned int bytes_read = 0; + unsigned int expect_bytes = 0; + + switch(yk_cmd) { + case SLOT_CHAL_HMAC1: + case SLOT_CHAL_HMAC2: + expect_bytes = 20; + break; + case SLOT_CHAL_OTP1: + case SLOT_CHAL_OTP2: + expect_bytes = 16; + break; + default: + yk_errno = YK_EINVALIDCMD; + return 0; + } + + if (may_block) + flags |= YK_FLAG_MAYBLOCK; + + if (! yk_write_to_key(yk, yk_cmd, challenge, challenge_len)) { + return 0; + } + + if (! yk_read_response_from_key(yk, yk_cmd, flags, + response, response_len, + expect_bytes, + &bytes_read)) { + return 0; + } + + return 1; +} + +int * _yk_errno_location(void) +{ + static int tsd_init = 0; + static int nothread_errno = 0; + YK_DEFINE_TSD_METADATA(errno_key); + int rc = 0; + + if (tsd_init == 0) { + if ((rc = YK_TSD_INIT(errno_key, free)) == 0) { + tsd_init = 1; + } else { + tsd_init = -1; + } + } + + if(YK_TSD_GET(int *, errno_key) == NULL) { + void *p = calloc(1, sizeof(int)); + if (!p) { + tsd_init = -1; + } else { + (void)!YK_TSD_SET(errno_key, p); + } + } + if (tsd_init == 1) { + return YK_TSD_GET(int *, errno_key); + } + return ¬hread_errno; +} + +static const char *errtext[] = { + "", + "USB error", + "wrong size", + "write error", + "timeout", + "no yubikey present", + "unsupported firmware version", + "out of memory", + "no status structure given", + "not yet implemented", + "checksum mismatch", + "operation would block", + "invalid command for operation", + "expected only one YubiKey but several present", + "no data returned from device", +}; +const char *yk_strerror(int errnum) +{ + if (errnum < (int)(sizeof(errtext)/sizeof(errtext[0]))) + return errtext[errnum]; + return NULL; +} +const char *yk_usb_strerror(void) +{ + return _ykusb_strerror(); +} + +/* This function would've been better named 'yk_read_status_from_key'. Because + * it disregards the first byte in each feature report, it can't be used to read + * generic feature reports from the Yubikey, and this behaviour can't be changed + * without breaking compatibility with existing programs. + * + * See yk_read_response_from_key() for a generic purpose data reading function. + * + * The slot parameter is here for future purposes only. + */ +int yk_read_from_key(YK_KEY *yk, uint8_t slot, + void *buf, unsigned int bufsize, unsigned int *bufcount) +{ + (void)slot; + unsigned char data[FEATURE_RPT_SIZE]; + + if (bufsize > FEATURE_RPT_SIZE - 1) { + yk_errno = YK_EWRONGSIZ; + return 0; + } + + memset(data, 0, sizeof(data)); + + if (!_ykusb_read(yk, REPORT_TYPE_FEATURE, 0, (char *)data, FEATURE_RPT_SIZE)) + return 0; + + /* This makes it apparent that there's some mysterious value in + the first byte... I wonder what... /Richard Levitte */ + memcpy(buf, data + 1, bufsize); + *bufcount = bufsize; + + return 1; +} + +/* Wait for the Yubikey to either set or clear (controlled by the boolean logic_and) + * the bits in mask. + * + * The slot parameter is here for future purposes only. + */ +int yk_wait_for_key_status(YK_KEY *yk, uint8_t slot, unsigned int flags, + unsigned int max_time_ms, + bool logic_and, unsigned char mask, + unsigned char *last_data) +{ + unsigned char data[FEATURE_RPT_SIZE]; + + unsigned int sleepval = 1; + unsigned int slept_time = 0; + int blocking = 0; + + /* Non-zero slot breaks on Windows (libusb-1.0.8-win32), while working fine + * on Linux (and probably MacOS X). + * + * The YubiKey doesn't support per-slot status anyways at the moment (2.2), + * so we just set it to 0 (meaning slot 1). + */ + slot = 0; + + while (slept_time < max_time_ms) { + Sleep(sleepval); + slept_time += sleepval; + /* exponential backoff, up to 500 ms */ + sleepval *= 2; + if (sleepval > 500) + sleepval = 500; + + /* Read a status report from the key */ + memset(data, 0, sizeof(data)); + if (!_ykusb_read(yk, REPORT_TYPE_FEATURE, slot, (char *) &data, FEATURE_RPT_SIZE)) + return 0; +#ifdef YK_DEBUG + _yk_hexdump(data, FEATURE_RPT_SIZE); +#endif + + if (last_data != NULL) + memcpy(last_data, data, sizeof(data)); + + /* The status byte from the key is now in last byte of data */ + if (logic_and) { + /* Check if Yubikey has SET the bit(s) in mask */ + if ((data[FEATURE_RPT_SIZE - 1] & mask) == mask) { + return 1; + } + } else { + /* Check if Yubikey has CLEARED the bit(s) in mask */ + if (! (data[FEATURE_RPT_SIZE - 1] & mask)) { + return 1; + } + } + + /* Check if Yubikey says it will wait for user interaction */ + if ((data[FEATURE_RPT_SIZE - 1] & RESP_TIMEOUT_WAIT_FLAG) == RESP_TIMEOUT_WAIT_FLAG) { + if ((flags & YK_FLAG_MAYBLOCK) == YK_FLAG_MAYBLOCK) { + if (! blocking) { + /* Extend timeout first time we see RESP_TIMEOUT_WAIT_FLAG. */ + blocking = 1; + max_time_ms += 256 * 1000; + } + } else { + /* Reset read mode of Yubikey before aborting. */ + yk_force_key_update(yk); + yk_errno = YK_EWOULDBLOCK; + return 0; + } + } else { + if (blocking) { + /* YubiKey timed out waiting for user interaction */ + break; + } + } + } + + yk_errno = YK_ETIMEOUT; + return 0; +} + +/* Read one or more feature reports from a Yubikey and put them together. + * + * Bufsize must be able to hold at least 2 more bytes than you are expecting + * (the CRC), but since all read requests return 7 bytes of data bufsize needs + * to be up to 7 bytes more than you expect. + * + * If the key returns more data than bufsize, we fail and set yk_errno to + * YK_EWRONGSIZ. If that happens there will be partial data in buf. + * + * If we read a response from a Yubikey that is configured to block and wait for + * a button press (in challenge response), this function will abort unless + * flags contain YK_FLAG_MAYBLOCK, in which case it might take up to 15 seconds + * for this function to return. + * + * The slot parameter is here for future purposes only. + */ +int yk_read_response_from_key(YK_KEY *yk, uint8_t slot, unsigned int flags, + void *buf, unsigned int bufsize, unsigned int expect_bytes, + unsigned int *bytes_read) +{ + unsigned char data[FEATURE_RPT_SIZE]; + memset(data, 0, sizeof(data)); + + memset(buf, 0, bufsize); + *bytes_read = 0; + +#ifdef YK_DEBUG + fprintf(stderr, "YK_DEBUG: Read %i bytes from YubiKey :\n", expect_bytes); +#endif + /* Wait for the key to turn on RESP_PENDING_FLAG */ + if (! yk_wait_for_key_status(yk, slot, flags, 1000, true, RESP_PENDING_FLAG, (unsigned char *) &data)) + return 0; + + /* The first part of the response was read by yk_wait_for_key_status(). We need + * to copy it to buf. + */ + memcpy((char*)buf + *bytes_read, data, sizeof(data) - 1); + *bytes_read += sizeof(data) - 1; + + while (*bytes_read + FEATURE_RPT_SIZE <= bufsize) { + memset(data, 0, sizeof(data)); + + if (!_ykusb_read(yk, REPORT_TYPE_FEATURE, 0, (char *)data, FEATURE_RPT_SIZE)) + return 0; +#ifdef YK_DEBUG + _yk_hexdump(data, FEATURE_RPT_SIZE); +#endif + if (data[FEATURE_RPT_SIZE - 1] & RESP_PENDING_FLAG) { + /* The lower five bits of the status byte has the response sequence + * number. If that gets reset to zero we are done. + */ + if ((data[FEATURE_RPT_SIZE - 1] & 31) == 0) { + if (expect_bytes > 0) { + /* Size of response is known. Verify CRC. */ + expect_bytes += 2; + int crc = yubikey_crc16(buf, expect_bytes); + if (crc != YK_CRC_OK_RESIDUAL) { + yk_errno = YK_ECHECKSUM; + return 0; + } + + /* since we get data in chunks of 7 we need to round expect bytes out to the closest higher multiple of 7 */ + if(expect_bytes % 7 != 0) { + expect_bytes += 7 - (expect_bytes % 7); + } + + if (*bytes_read != expect_bytes) { + yk_errno = YK_EWRONGSIZ; + return 0; + } + } + + /* Reset read mode of Yubikey before returning. */ + yk_force_key_update(yk); + + return 1; + } + + memcpy((char*)buf + *bytes_read, data, sizeof(data) - 1); + *bytes_read += sizeof(data) - 1; + } else { + /* Reset read mode of Yubikey before returning. */ + yk_force_key_update(yk); + + return 0; + } + } + + /* We're out of buffer space, abort reading */ + yk_force_key_update(yk); + + yk_errno = YK_EWRONGSIZ; + return 0; +} + +/* + * Send something to the YubiKey. The command, as well as the slot, is + * given in the 'slot' parameter (e.g. SLOT_CHAL_HMAC2 to send a HMAC-SHA1 + * challenge to slot 2). + */ +int yk_write_to_key(YK_KEY *yk, uint8_t slot, const void *buf, int bufcount) +{ + YK_FRAME frame; + unsigned char repbuf[FEATURE_RPT_SIZE]; + int i, seq; + int ret = 0; + unsigned char *ptr, *end; + + if (bufcount > (int)sizeof(frame.payload)) { + yk_errno = YK_EWRONGSIZ; + return 0; + } + + /* Insert data and set slot # */ + + memset(&frame, 0, sizeof(frame)); + memcpy(frame.payload, buf, bufcount); + frame.slot = slot; + + /* Append slot checksum */ + + i = yubikey_crc16 (frame.payload, sizeof(frame.payload)); + frame.crc = yk_endian_swap_16(i); + + /* Chop up the data into parts that fits into the payload of a + feature report. Set the sequence number | 0x80 in the end + of the feature report. When the Yubikey has processed it, + it will clear this byte, signaling that the next part can be + sent */ + + ptr = (unsigned char *) &frame; + end = (unsigned char *) &frame + sizeof(frame); + +#ifdef YK_DEBUG + fprintf(stderr, "YK_DEBUG: Write %i bytes to YubiKey :\n", bufcount); +#endif + for (seq = 0; ptr < end; seq++) { + int all_zeros = 1; + /* Ignore parts that are all zeroes except first and last + to speed up the transfer */ + + for (i = 0; i < (FEATURE_RPT_SIZE - 1); i++) { + if ((repbuf[i] = *ptr++)) all_zeros = 0; + } + if (all_zeros && (seq > 0) && (ptr < end)) + continue; + + /* sequence number goes into lower bits of last byte */ + repbuf[i] = seq | SLOT_WRITE_FLAG; + + /* When the Yubikey clears the SLOT_WRITE_FLAG, the + * next part can be sent. + */ + if (! yk_wait_for_key_status(yk, slot, 0, WAIT_FOR_WRITE_FLAG, + false, SLOT_WRITE_FLAG, NULL)) + goto end; +#ifdef YK_DEBUG + _yk_hexdump(repbuf, FEATURE_RPT_SIZE); +#endif + if (!_ykusb_write(yk, REPORT_TYPE_FEATURE, 0, + (char *)repbuf, FEATURE_RPT_SIZE)) + goto end; + } + + ret = 1; +end: + insecure_memzero(&frame, sizeof(YK_FRAME)); + insecure_memzero(repbuf, sizeof(repbuf)); + return ret; +} + +int yk_force_key_update(YK_KEY *yk) +{ + unsigned char buf[FEATURE_RPT_SIZE]; + + memset(buf, 0, sizeof(buf)); + buf[FEATURE_RPT_SIZE - 1] = DUMMY_REPORT_WRITE; /* Invalid sequence = update only */ + if (!_ykusb_write(yk, REPORT_TYPE_FEATURE, 0, (char *)buf, FEATURE_RPT_SIZE)) + return 0; + + return 1; +} + +int yk_get_key_vid_pid(YK_KEY *yk, int *vid, int *pid) { + return _ykusb_get_vid_pid(yk, vid, pid); +} + +uint16_t yk_endian_swap_16(uint16_t x) +{ + static int testflag = -1; + + if (testflag == -1) { + uint16_t testword = 0x0102; + unsigned char *testchars = (unsigned char *)&testword; + if (*testchars == '\1') + testflag = 1; /* Big endian arch, swap needed */ + else + testflag = 0; /* Little endian arch, no swap needed */ + } + + if (testflag) + x = (x >> 8) | ((x & 0xff) << 8); + + return x; +} diff --git a/src/thirdparty/ykcore/ykcore.h b/src/thirdparty/ykcore/ykcore.h new file mode 100644 index 000000000..5dc0b0d30 --- /dev/null +++ b/src/thirdparty/ykcore/ykcore.h @@ -0,0 +1,191 @@ +/* -*- mode:C; c-file-style: "bsd" -*- */ +/* + * Copyright (c) 2008-2015 Yubico AB + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * 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. + * + * 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 + * OWNER 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. + */ + +#ifndef __YKCORE_H_INCLUDED__ +#define __YKCORE_H_INCLUDED__ + +#include +#include +#include + +# ifdef __cplusplus +extern "C" { +# endif + +/************************************************************************* + ** + ** N O T E : For all functions that return a value, 0 and NULL indicates + ** an error, other values indicate success. + ** + ************************************************************************/ + +/************************************************************************* + * + * Structures used. They are further defined in ykdef.h + * + ****/ + +typedef struct yk_key_st YK_KEY; /* Really a USB device handle. */ +typedef struct yk_status_st YK_STATUS; /* Status structure, + filled by yk_get_status(). */ + +typedef struct yk_ticket_st YK_TICKET; /* Ticket structure... */ +typedef struct yk_config_st YK_CONFIG; /* Configuration structure. + Other libraries provide access. */ +typedef struct yk_nav_st YK_NAV; /* Navigation structure. + Other libraries provide access. */ +typedef struct yk_frame_st YK_FRAME; /* Data frame for write operation */ +typedef struct ndef_st YK_NDEF; +typedef struct yk_device_config_st YK_DEVICE_CONFIG; + +/************************************************************************* + * + * Library initialisation functions. + * + ****/ +extern int yk_init(void); +extern int yk_release(void); + +/************************************************************************* + * + * Functions to get and release the key itself. + * + ****/ +/* opens first key available. For backwards compatability */ +extern YK_KEY *yk_open_first_key(void); +extern YK_KEY *yk_open_key(int); /* opens nth key available */ +extern YK_KEY *yk_open_key_vid_pid(int, const int*, size_t, int); +extern int yk_close_key(YK_KEY *k); /* closes a previously opened key */ + +/************************************************************************* + * + * Functions to get data from the key. + * + ****/ +/* fetches key status into the structure given by `status' */ +extern int yk_get_status(YK_KEY *k, YK_STATUS *status /*, int forceUpdate */); +/* checks that the firmware revision of the key is supported */ +extern int yk_check_firmware_version(YK_KEY *k); +extern int yk_check_firmware_version2(YK_STATUS *status); +/* Read the factory set serial number from a YubiKey 2.0 or higher. */ +extern int yk_get_serial(YK_KEY *yk, uint8_t slot, unsigned int flags, unsigned int *serial); +/* Wait for the key to either set or clear bits in it's status byte */ +extern int yk_wait_for_key_status(YK_KEY *yk, uint8_t slot, unsigned int flags, + unsigned int max_time_ms, + bool logic_and, unsigned char mask, + unsigned char *last_data); +/* Read the response to a command from the YubiKey */ +extern int yk_read_response_from_key(YK_KEY *yk, uint8_t slot, unsigned int flags, + void *buf, unsigned int bufsize, unsigned int expect_bytes, + unsigned int *bytes_read); + +/************************************************************************* + * + * Functions to write data to the key. + * + ****/ + +/* writes the given configuration to the key. If the configuration is NULL, + zap the key configuration. + acc_code has to be provided of the key has a protecting access code. */ +extern int yk_write_command(YK_KEY *k, YK_CONFIG *cfg, uint8_t command, + unsigned char *acc_code); +/* wrapper function of yk_write_command */ +extern int yk_write_config(YK_KEY *k, YK_CONFIG *cfg, int confnum, + unsigned char *acc_code); +/* writes the given ndef to the key as SLOT_NDEF */ +extern int yk_write_ndef(YK_KEY *yk, YK_NDEF *ndef); +/* writes the given ndef to the key. */ +extern int yk_write_ndef2(YK_KEY *yk, YK_NDEF *ndef, int confnum); +/* writes a device config block to the key. */ +extern int yk_write_device_config(YK_KEY *yk, YK_DEVICE_CONFIG *device_config); +/* writes a scanmap to the key. */ +extern int yk_write_scan_map(YK_KEY *yk, unsigned char *scan_map); +/* Write something to the YubiKey (a command that is). */ +extern int yk_write_to_key(YK_KEY *yk, uint8_t slot, const void *buf, int bufcount); +/* Do a challenge-response round with the key. */ +extern int yk_challenge_response(YK_KEY *yk, uint8_t yk_cmd, int may_block, + unsigned int challenge_len, const unsigned char *challenge, + unsigned int response_len, unsigned char *response); + +extern int yk_force_key_update(YK_KEY *yk); +/* Get the VID and PID of an opened device. */ +extern int yk_get_key_vid_pid(YK_KEY *yk, int *vid, int *pid); +/* Get the YK4 capabilities */ +int yk_get_capabilities(YK_KEY *yk, uint8_t slot, unsigned int flags, + unsigned char *capabilities, unsigned int *len); +/* Set the device info (TLV string) */ +int yk_write_device_info(YK_KEY *yk, unsigned char *buf, unsigned int len); + + +/************************************************************************* + * + * Error handling fuctions + * + ****/ +extern int * _yk_errno_location(void); +#define yk_errno (*_yk_errno_location()) +const char *yk_strerror(int errnum); +/* The following function is only useful if yk_errno == YK_EUSBERR and + no other USB-related operations have been performed since the time of + error. */ +const char *yk_usb_strerror(void); + + +/* Swaps the two bytes between little and big endian on big endian machines */ +extern uint16_t yk_endian_swap_16(uint16_t x); + +#define YK_EUSBERR 0x01 /* USB error reporting should be used */ +#define YK_EWRONGSIZ 0x02 +#define YK_EWRITEERR 0x03 +#define YK_ETIMEOUT 0x04 +#define YK_ENOKEY 0x05 +#define YK_EFIRMWARE 0x06 +#define YK_ENOMEM 0x07 +#define YK_ENOSTATUS 0x08 +#define YK_ENOTYETIMPL 0x09 +#define YK_ECHECKSUM 0x0a /* checksum validation failed */ +#define YK_EWOULDBLOCK 0x0b /* operation would block */ +#define YK_EINVALIDCMD 0x0c /* supplied command is invalid for this operation */ +#define YK_EMORETHANONE 0x0d /* expected to find only one key but found more */ +#define YK_ENODATA 0x0e /* no data was returned from a read */ + +/* Flags for response reading. Use high numbers to not exclude the possibility + * to combine these with for example SLOT commands from ykdef.h in the future. + */ +#define YK_FLAG_MAYBLOCK 0x01 << 16 + +#define YK_CRC_OK_RESIDUAL 0xf0b8 + +# ifdef __cplusplus +} +# endif + +#endif /* __YKCORE_H_INCLUDED__ */ diff --git a/src/thirdparty/ykcore/ykcore_backend.h b/src/thirdparty/ykcore/ykcore_backend.h new file mode 100644 index 000000000..d27184b16 --- /dev/null +++ b/src/thirdparty/ykcore/ykcore_backend.h @@ -0,0 +1,54 @@ +/* -*- mode:C; c-file-style: "bsd" -*- */ +/* + * Written by Richard Levitte + * Copyright (c) 2008-2014 Yubico AB + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * 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. + * + * 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 + * OWNER 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. + */ + +#ifndef __YKCORE_BACKEND_H_INCLUDED__ +#define __YKCORE_BACKEND_H_INCLUDED__ + +#define FEATURE_RPT_SIZE 8 + +#define REPORT_TYPE_FEATURE 0x03 + +int _ykusb_start(void); +int _ykusb_stop(void); + +void * _ykusb_open_device(int vendor_id, const int *product_ids, size_t pids_len, int index); +int _ykusb_close_device(void *); + +int _ykusb_read(void *dev, int report_type, int report_number, + char *buffer, int buffer_size); +int _ykusb_write(void *dev, int report_type, int report_number, + char *buffer, int buffer_size); + +int _ykusb_get_vid_pid(void *dev, int *vid, int *pid); + +const char *_ykusb_strerror(void); + +#endif /* __YKCORE_BACKEND_H_INCLUDED__ */ diff --git a/src/thirdparty/ykcore/ykcore_lcl.h b/src/thirdparty/ykcore/ykcore_lcl.h new file mode 100644 index 000000000..53619acb9 --- /dev/null +++ b/src/thirdparty/ykcore/ykcore_lcl.h @@ -0,0 +1,69 @@ +/* -*- mode:C; c-file-style: "bsd" -*- */ +/* + * Copyright (c) 2008-2012 Yubico AB + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * 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. + * + * 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 + * OWNER 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. + */ + +#ifndef __YKCORE_LCL_H_INCLUDED__ +#define __YKCORE_LCL_H_INCLUDED__ + +/* This is a hack to map official structure names (in ykcore.h) to + internal ones (in ykdef.h) */ +#define yk_key_st yubikey_st +#define yk_status_st status_st +#define yk_ticket_st ticket_st +#define yk_config_st config_st +#define yk_nav_st nav_st +#define yk_frame_st frame_st +#define yk_device_config_st device_config_st + +#include "ykcore.h" +#include "ykdef.h" + +/************************************************************************* + ** + ** = = = = = = = = = B I G F A T W A R N I N G = = = = = = = = = + ** + ** DO NOT USE THE FOLLOWING FUCTIONS DIRECTLY UNLESS YOU WRITE CORE ROUTINES! + ** + ** These functions are declared here only to make sure they get defined + ** correctly internally. + ** + ** YOU HAVE BEEN WARNED! + ** + ****/ + +/************************************************************************* + * + * Functions to send and receive data to/from the key. + * + ****/ +extern int yk_read_from_key(YK_KEY *k, uint8_t slot, + void *buf, unsigned int bufsize, + unsigned int *bufcount); + +#endif /* __YKCORE_LCL_H_INCLUDED__ */ diff --git a/src/thirdparty/ykcore/ykcore_libusb-1.0.c b/src/thirdparty/ykcore/ykcore_libusb-1.0.c new file mode 100644 index 000000000..b123d6c2f --- /dev/null +++ b/src/thirdparty/ykcore/ykcore_libusb-1.0.c @@ -0,0 +1,296 @@ +/* -*- mode:C; c-file-style: "bsd" -*- */ +/* + * Copyright (c) 2008-2014 Yubico AB + * Copyright (c) 2009 Tollef Fog Heen + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * 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. + * + * 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 + * OWNER 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. + */ + +#include +#include +#include + +#include "ykcore.h" +#include "ykdef.h" +#include "ykcore_backend.h" + +#define HID_GET_REPORT 0x01 +#define HID_SET_REPORT 0x09 + +static int ykl_errno; +static int libusb_inited = 0; +static libusb_context *usb_ctx = NULL; + +/************************************************************************* + ** function _ykusb_write ** + ** Set HID report ** + ** ** + ** int _ykusb_write(YUBIKEY *yk, int report_type, int report_number, ** + ** char *buffer, int size) ** + ** ** + ** Where: ** + ** "yk" is handle to open Yubikey ** + ** "report_type" is HID report type (in, out or feature) ** + ** "report_number" is report identifier ** + ** "buffer" is pointer to in buffer ** + ** "size" is size of the buffer ** + ** ** + ** Returns: Nonzero if successful, zero otherwise ** + ** ** + *************************************************************************/ + +int _ykusb_write(void *dev, int report_type, int report_number, + char *buffer, int size) +{ + ykl_errno = libusb_claim_interface((libusb_device_handle *)dev, 0); + + if (ykl_errno == 0) { + int rc2; + ykl_errno = libusb_control_transfer((libusb_device_handle *)dev, + LIBUSB_REQUEST_TYPE_CLASS | + LIBUSB_RECIPIENT_INTERFACE | + LIBUSB_ENDPOINT_OUT, + HID_SET_REPORT, + report_type << 8 | report_number, 0, + (unsigned char *)buffer, size, + 1000); + /* preserve a control message error over an interface + release one */ + rc2 = libusb_release_interface((libusb_device_handle *)dev, 0); + if (ykl_errno > 0 && rc2 < 0) + ykl_errno = rc2; + } + if (ykl_errno > 0) + return 1; + yk_errno = YK_EUSBERR; + return 0; +} + +/************************************************************************* +** function _ykusb_read ** +** Get HID report ** +** ** +** int _ykusb_read(YUBIKEY *dev, int report_type, int report_number, ** +** char *buffer, int size) ** +** ** +** Where: ** +** "dev" is handle to open Yubikey ** +** "report_type" is HID report type (in, out or feature) ** +** "report_number" is report identifier ** +** "buffer" is pointer to in buffer ** +** "size" is size of the buffer ** +** ** +** Returns: Number of bytes read. Zero if failure ** +** ** +*************************************************************************/ + +int _ykusb_read(void *dev, int report_type, int report_number, + char *buffer, int size) +{ + ykl_errno = libusb_claim_interface((libusb_device_handle *)dev, 0); + + if (ykl_errno == 0) { + int rc2; + ykl_errno = libusb_control_transfer((libusb_device_handle *)dev, + LIBUSB_REQUEST_TYPE_CLASS | + LIBUSB_RECIPIENT_INTERFACE | + LIBUSB_ENDPOINT_IN, + HID_GET_REPORT, + report_type << 8 | report_number, 0, + (unsigned char *)buffer, size, + 1000); + /* preserve a control message error over an interface + release one */ + rc2 = libusb_release_interface((libusb_device_handle *)dev, 0); + if (ykl_errno > 0 && rc2 < 0) + ykl_errno = rc2; + } + if (ykl_errno > 0) { + return ykl_errno; + } else if(ykl_errno == 0) { + yk_errno = YK_ENODATA; + } else { + yk_errno = YK_EUSBERR; + } + return 0; +} + +int _ykusb_start(void) +{ + ykl_errno = libusb_init(&usb_ctx); + if(ykl_errno) { + yk_errno = YK_EUSBERR; + return 0; + } + libusb_inited = 1; + return 1; +} + +extern int _ykusb_stop(void) +{ + if (libusb_inited == 1) { + libusb_exit(usb_ctx); + usb_ctx = NULL; + libusb_inited = 0; + return 1; + } + yk_errno = YK_EUSBERR; + return 0; +} + +void *_ykusb_open_device(int vendor_id, const int *product_ids, size_t pids_len, int index) +{ + libusb_device *dev = NULL; + libusb_device_handle *h = NULL; + struct libusb_device_descriptor desc; + libusb_device **list; + ssize_t cnt = libusb_get_device_list(usb_ctx, &list); + ssize_t i = 0; + int rc = YK_ENOKEY; + const int desired_cfg = 1; + int found = 0; + + for (i = 0; i < cnt; i++) { + ykl_errno = libusb_get_device_descriptor(list[i], &desc); + if (ykl_errno != 0) + goto done; + + if (desc.idVendor == vendor_id) { + size_t j; + for(j = 0; j < pids_len; j++) { + if (desc.idProduct == product_ids[j]) { + found++; + if (found-1 == index) { + dev = list[i]; + break; + } + } + } + } + } + + if (dev) { + int current_cfg; + rc = YK_EUSBERR; + ykl_errno = libusb_open(dev, &h); + if (ykl_errno != 0) + goto done; + ykl_errno = libusb_kernel_driver_active(h, 0); + if (ykl_errno == 1) { + ykl_errno = libusb_detach_kernel_driver(h, 0); + if (ykl_errno != 0) + goto done; + } else if (ykl_errno != 0) + goto done; + /* This is needed for yubikey-personalization to work inside virtualbox virtualization. */ + ykl_errno = libusb_get_configuration(h, ¤t_cfg); + if (ykl_errno != 0) + goto done; + if (desired_cfg != current_cfg) { + ykl_errno = libusb_set_configuration(h, desired_cfg); + if (ykl_errno != 0) + goto done; + } + } + done: + libusb_free_device_list(list, 1); + if (h == NULL) + yk_errno = rc; + return h; +} + +int _ykusb_close_device(void *yk) +{ + libusb_attach_kernel_driver(yk, 0); + libusb_close((libusb_device_handle *) yk); + return 1; +} + +int _ykusb_get_vid_pid(void *yk, int *vid, int *pid) +{ + struct libusb_device_descriptor desc; + libusb_device *dev = libusb_get_device(yk); + int rc = libusb_get_device_descriptor(dev, &desc); + + if (rc == 0) { + *vid = desc.idVendor; + *pid = desc.idProduct; + return 1; + } + yk_errno = YK_EUSBERR; + return 0; +} + +const char *_ykusb_strerror(void) +{ + static const char *buf; + switch (ykl_errno) { + case LIBUSB_SUCCESS: + buf = "Success (no error)"; + break; + case LIBUSB_ERROR_IO: + buf = "Input/output error"; + break; + case LIBUSB_ERROR_INVALID_PARAM: + buf = "Invalid parameter"; + break; + case LIBUSB_ERROR_ACCESS: + buf = "Access denied (insufficient permissions)"; + break; + case LIBUSB_ERROR_NO_DEVICE: + buf = "No such device (it may have been disconnected)"; + break; + case LIBUSB_ERROR_NOT_FOUND: + buf = "Entity not found"; + break; + case LIBUSB_ERROR_BUSY: + buf = "Resource busy"; + break; + case LIBUSB_ERROR_TIMEOUT: + buf = "Operation timed out"; + break; + case LIBUSB_ERROR_OVERFLOW: + buf = "Overflow"; + break; + case LIBUSB_ERROR_PIPE: + buf = "Pipe error"; + break; + case LIBUSB_ERROR_INTERRUPTED: + buf = "System call interrupted (perhaps due to signal)"; + break; + case LIBUSB_ERROR_NO_MEM: + buf = "Insufficient memory"; + break; + case LIBUSB_ERROR_NOT_SUPPORTED: + buf = "Operation not supported or unimplemented on this platform"; + break; + case LIBUSB_ERROR_OTHER: + default: + buf = "Other/unknown error"; + break; + } + return buf; +} diff --git a/src/thirdparty/ykcore/ykcore_libusb.c b/src/thirdparty/ykcore/ykcore_libusb.c new file mode 100644 index 000000000..cb6171cf9 --- /dev/null +++ b/src/thirdparty/ykcore/ykcore_libusb.c @@ -0,0 +1,216 @@ +/* -*- mode:C; c-file-style: "bsd" -*- */ +/* + * Copyright (c) 2008-2014 Yubico AB + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * 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. + * + * 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 + * OWNER 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. + */ + +#include +#include +#include + +#include "ykcore.h" +#include "ykdef.h" +#include "ykcore_backend.h" + +#define HID_GET_REPORT 0x01 +#define HID_SET_REPORT 0x09 + +/************************************************************************* + ** function _ykusb_write ** + ** Set HID report ** + ** ** + ** int _ykusb_write(YUBIKEY *yk, int report_type, int report_number, ** + ** char *buffer, int size) ** + ** ** + ** Where: ** + ** "yk" is handle to open Yubikey ** + ** "report_type" is HID report type (in, out or feature) ** + ** "report_number" is report identifier ** + ** "buffer" is pointer to in buffer ** + ** "size" is size of the buffer ** + ** ** + ** Returns: Nonzero if successful, zero otherwise ** + ** ** + *************************************************************************/ + +int _ykusb_write(void *dev, int report_type, int report_number, + char *buffer, int size) +{ + int rc = usb_claim_interface((usb_dev_handle *)dev, 0); + + if (rc >= 0) { + int rc2; + rc = usb_control_msg((usb_dev_handle *)dev, + USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_ENDPOINT_OUT, + HID_SET_REPORT, + report_type << 8 | report_number, 0, + buffer, size, + 1000); + /* preserve a control message error over an interface + release one */ + rc2 = usb_release_interface((usb_dev_handle *)dev, 0); + if (rc >= 0 && rc2 < 0) + rc = rc2; + } + if (rc >= 0) + return 1; + yk_errno = YK_EUSBERR; + return 0; +} + +/************************************************************************* +** function _ykusb_read ** +** Get HID report ** +** ** +** int _ykusb_read(YUBIKEY *dev, int report_type, int report_number, ** +** char *buffer, int size) ** +** ** +** Where: ** +** "dev" is handle to open Yubikey ** +** "report_type" is HID report type (in, out or feature) ** +** "report_number" is report identifier ** +** "buffer" is pointer to in buffer ** +** "size" is size of the buffer ** +** ** +** Returns: Number of bytes read. Zero if failure ** +** ** +*************************************************************************/ + +int _ykusb_read(void *dev, int report_type, int report_number, + char *buffer, int size) +{ + int rc = usb_claim_interface((usb_dev_handle *)dev, 0); + + if (rc >= 0) { + int rc2; + rc = usb_control_msg((usb_dev_handle *)dev, + USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_ENDPOINT_IN, + HID_GET_REPORT, + report_type << 8 | report_number, 0, + buffer, size, + 1000); + /* preserve a control message error over an interface + release one */ + rc2 = usb_release_interface((usb_dev_handle *)dev, 0); + if (rc >= 0 && rc2 < 0) + rc = rc2; + } + if (rc >= 0) + return rc; + if(rc == 0) + yk_errno = YK_ENODATA; + else + yk_errno = YK_EUSBERR; + return 0; +} + +int _ykusb_start(void) +{ + int rc; + usb_init(); + + rc = usb_find_busses(); + if (rc >= 0) + rc = usb_find_devices(); + + if (rc >= 0) + return 1; + yk_errno = YK_EUSBERR; + return 0; +} + +extern int _ykusb_stop(void) +{ + return 1; +} + +void *_ykusb_open_device(int vendor_id, const int *product_ids, size_t pids_len, int index) +{ + struct usb_bus *bus; + struct usb_device *yk_device = NULL; + struct usb_dev_handle *h = NULL; + int rc = YK_EUSBERR; + int found = 0; + + for (bus = usb_get_busses(); bus; bus = bus->next) { + struct usb_device *dev; + rc = YK_ENOKEY; + for (dev = bus->devices; dev; dev = dev->next) { + if (dev->descriptor.idVendor == vendor_id) { + size_t j; + for (j = 0; j < pids_len; j++) { + if (dev->descriptor.idProduct == product_ids[j]) { + found++; + if (found-1 == index) { + yk_device = dev; + break; + } + } + } + } + } + } + if(yk_device != NULL) { + rc = YK_EUSBERR; + h = usb_open(yk_device); +#ifdef LIBUSB_HAS_DETACH_KERNEL_DRIVER_NP + if (h != NULL) + usb_detach_kernel_driver_np(h, 0); +#endif + /* This is needed for yubikey-personalization to work inside virtualbox virtualization. */ + if (h != NULL) + usb_set_configuration(h, 1); + goto done; + } + done: + if (h == NULL) + yk_errno = rc; + return h; +} + +int _ykusb_close_device(void *yk) +{ + int rc = usb_close((usb_dev_handle *) yk); + + if (rc >= 0) + return 1; + yk_errno = YK_EUSBERR; + return 0; +} + +int _ykusb_get_vid_pid(void *yk, int *vid, int *pid) { + struct usb_dev_handle *h = yk; + struct usb_device *dev = usb_device(h); + *vid = dev->descriptor.idVendor; + *pid = dev->descriptor.idProduct; + return 1; +} + +const char *_ykusb_strerror(void) +{ + return usb_strerror(); +} diff --git a/src/thirdparty/ykcore/ykcore_osx.c b/src/thirdparty/ykcore/ykcore_osx.c new file mode 100644 index 000000000..8f9816a3a --- /dev/null +++ b/src/thirdparty/ykcore/ykcore_osx.c @@ -0,0 +1,280 @@ +/* -*- mode:C; c-file-style: "bsd" -*- */ +/* + * Copyright (c) 2008-2014 Yubico AB + * Copyright (c) 2009 Christer Kaivo-oja + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * 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. + * + * 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 + * OWNER 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. + */ + +#include "ykcore.h" +#include "ykdef.h" +#include "ykcore_backend.h" + +#include +#include +#include +#include + +#include "ykcore_backend.h" + +#define FEATURE_RPT_SIZE 8 +#define FIDO_HID_USAGE_PAGE 0xF1D0 +#define FIDO_U2F_DEVICE_USAGE 0x01 + +static IOHIDManagerRef ykosxManager = NULL; +static IOReturn _ykusb_IOReturn = 0; + +int _ykusb_start(void) +{ + ykosxManager = IOHIDManagerCreate( kCFAllocatorDefault, 0L ); + + return 1; +} + +int _ykusb_stop(void) +{ + if (ykosxManager != NULL) { + CFRelease(ykosxManager); + ykosxManager = NULL; + return 1; + } + + yk_errno = YK_EUSBERR; + return 0; +} + +static void _ykosx_CopyToCFArray(const void *value, void *context) +{ + CFArrayAppendValue( ( CFMutableArrayRef ) context, value ); +} + +static int _ykosx_getIntProperty( IOHIDDeviceRef dev, CFStringRef key ) +{ + int result = 0; + CFTypeRef tCFTypeRef = IOHIDDeviceGetProperty( dev, key ); + if ( tCFTypeRef ) { + if ( CFNumberGetTypeID( ) == CFGetTypeID( tCFTypeRef ) ) { + CFNumberGetValue( ( CFNumberRef ) tCFTypeRef, kCFNumberSInt32Type, &result ); + } + } + return result; +} + +static IOHIDDeviceRef _ykosx_getHIDDeviceMatching(CFArrayRef devices, + int primaryUsagePage, + int primaryUsage, + const int *productIDs, + size_t productIDsCount, + int index) +{ + IOHIDDeviceRef matchingDevice = NULL; + size_t cnt, i, j; + int found = 0; + + cnt = CFArrayGetCount( devices ); + + for(i = 0; i < cnt; ++i) { + IOHIDDeviceRef dev = (IOHIDDeviceRef)CFArrayGetValueAtIndex( devices, i ); + const int usagePage = _ykosx_getIntProperty( dev, CFSTR( kIOHIDPrimaryUsagePageKey )); + const int usage = _ykosx_getIntProperty( dev, CFSTR( kIOHIDPrimaryUsageKey )); + const int devProductId = _ykosx_getIntProperty( dev, CFSTR( kIOHIDProductIDKey )); + + if (usagePage != primaryUsagePage || usage != primaryUsage) { + continue; + } + + for(j = 0; j < productIDsCount; j++) { + if(productIDs[j] == devProductId) { + found++; + if(found - 1 == index) { + matchingDevice = dev; + break; + } + } + } + } + + return matchingDevice; +} + +void *_ykusb_open_device(int vendor_id, const int *product_ids, size_t pids_len, int index) +{ + IOHIDDeviceRef yk = NULL; + + int rc = YK_ENOKEY; + + IOHIDManagerSetDeviceMatchingMultiple( ykosxManager, NULL ); + + CFSetRef devSet = IOHIDManagerCopyDevices( ykosxManager ); + + if ( devSet ) { + CFMutableArrayRef array = CFArrayCreateMutable( kCFAllocatorDefault, 0, NULL ); + + CFSetApplyFunction( devSet, _ykosx_CopyToCFArray, array ); + + /* ensure that we are attempting to open the FIDO interface instead + of the keyboard interface. macOS requires explicit user + authorization before we are able to open HID devices such as + keyboards and mice, while it is not required for FIDO devices + that communicate over HID. */ + yk = _ykosx_getHIDDeviceMatching( + array, // devices + FIDO_HID_USAGE_PAGE, // primaryUsagePage + FIDO_U2F_DEVICE_USAGE, // primaryUsage + product_ids, // productIDs + pids_len, // productIDsCount + index // index + ); + + if(yk == NULL) { + /* fallback to the keyboard device if it is present. */ + yk = _ykosx_getHIDDeviceMatching( + array, // devices + kHIDPage_GenericDesktop, // primaryUsagePage + kHIDUsage_GD_Keyboard, // primaryUsage + product_ids, // productIDs + pids_len, // productIDsCount + index // index + ); + } + + /* this is a workaround for a memory leak in IOHIDManagerCopyDevices() in 10.8 */ + IOHIDManagerScheduleWithRunLoop( ykosxManager, CFRunLoopGetCurrent( ), kCFRunLoopDefaultMode ); + IOHIDManagerUnscheduleFromRunLoop( ykosxManager, CFRunLoopGetCurrent( ), kCFRunLoopDefaultMode ); + + CFRelease( array ); + CFRelease( devSet ); + } + + if (yk) { + CFRetain(yk); + _ykusb_IOReturn = IOHIDDeviceOpen( yk, 0L ); + + if ( _ykusb_IOReturn != kIOReturnSuccess ) { + CFRelease(yk); + rc = YK_EUSBERR; + goto error; + } + + return (void *)yk; + } + +error: + yk_errno = rc; + return 0; +} + +int _ykusb_close_device(void *dev) +{ + _ykusb_IOReturn = IOHIDDeviceClose( dev, 0L ); + CFRelease(dev); + + if ( _ykusb_IOReturn == kIOReturnSuccess ) + return 1; + + yk_errno = YK_EUSBERR; + return 0; +} + +int _ykusb_read(void *dev, int report_type, int report_number, + char *buffer, int size) +{ + CFIndex sizecf = (CFIndex)size; + + if (report_type != REPORT_TYPE_FEATURE) + { + yk_errno = YK_ENOTYETIMPL; + return 0; + } + + _ykusb_IOReturn = IOHIDDeviceGetReport( dev, kIOHIDReportTypeFeature, report_number, (uint8_t *)buffer, (CFIndex *) &sizecf ); + + if ( _ykusb_IOReturn != kIOReturnSuccess ) + { + yk_errno = YK_EUSBERR; + return 0; + } + + if(sizecf == 0) + yk_errno = YK_ENODATA; + + return (int)sizecf; +} + +int _ykusb_write(void *dev, int report_type, int report_number, + char *buffer, int size) +{ + if (report_type != REPORT_TYPE_FEATURE) + { + yk_errno = YK_ENOTYETIMPL; + return 0; + } + + _ykusb_IOReturn = IOHIDDeviceSetReport( dev, kIOHIDReportTypeFeature, report_number, (unsigned char *)buffer, size); + + if ( _ykusb_IOReturn != kIOReturnSuccess ) + { + yk_errno = YK_EUSBERR; + return 0; + } + + return 1; +} + +int _ykusb_get_vid_pid(void *yk, int *vid, int *pid) { + IOHIDDeviceRef dev = (IOHIDDeviceRef)yk; + *vid = _ykosx_getIntProperty( dev, CFSTR( kIOHIDVendorIDKey )); + *pid = _ykosx_getIntProperty( dev, CFSTR( kIOHIDProductIDKey )); + return 1; +} + +const char *_ykusb_strerror() +{ + switch (_ykusb_IOReturn) { + case kIOReturnSuccess: + return "kIOReturnSuccess"; + case kIOReturnNotOpen: + return "kIOReturnNotOpen"; + case kIOReturnNoDevice: + return "kIOReturnNoDevice"; + case kIOReturnExclusiveAccess: + return "kIOReturnExclusiveAccess"; + case kIOReturnError: + return "kIOReturnError"; + case kIOReturnBadArgument: + return "kIOReturnBadArgument"; + case kIOReturnAborted: + return "kIOReturnAborted"; + case kIOReturnNotResponding: + return "kIOReturnNotResponding"; + case kIOReturnOverrun: + return "kIOReturnOverrun"; + case kIOReturnCannotWire: + return "kIOReturnCannotWire"; + default: + return "unknown error"; + } +} diff --git a/src/thirdparty/ykcore/ykcore_windows.c b/src/thirdparty/ykcore/ykcore_windows.c new file mode 100644 index 000000000..9346b3972 --- /dev/null +++ b/src/thirdparty/ykcore/ykcore_windows.c @@ -0,0 +1,210 @@ +/* -*- mode:C; c-file-style: "bsd" -*- */ +/* + * Copyright (c) 2008-2014 Yubico AB + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * 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. + * + * 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 + * OWNER 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. + */ + +#include "ykcore.h" +#include "ykdef.h" +#include "ykcore_backend.h" + +#define INITGUID +#include +#include +#include +#include +#include + +int _ykusb_start(void) +{ + return 1; +} + +int _ykusb_stop(void) +{ + return 1; +} + +void * _ykusb_open_device(int vendor_id, const int *product_ids, size_t pids_len, int index) +{ + HDEVINFO hi; + SP_DEVICE_INTERFACE_DATA di; + PSP_DEVICE_INTERFACE_DETAIL_DATA pi; + int i; + DWORD len, rc; + HANDLE ret_handle = NULL; + int found = 0; + + yk_errno = YK_EUSBERR; + + hi = SetupDiGetClassDevs(&GUID_DEVINTERFACE_KEYBOARD, 0, 0, + DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); + if (hi == INVALID_HANDLE_VALUE) + return NULL; + + di.cbSize = sizeof (SP_DEVICE_INTERFACE_DATA); + + for (i = 0; i < 1000; i++) { + if (!SetupDiEnumDeviceInterfaces(hi, 0, &GUID_DEVINTERFACE_KEYBOARD, i, &di)) + break; + + if (SetupDiGetDeviceInterfaceDetail(hi, &di, 0, 0, &len, 0) || GetLastError() != ERROR_INSUFFICIENT_BUFFER) + break; + + pi = malloc (len); + if (!pi) { + yk_errno = YK_ENOMEM; + goto done; + } + pi->cbSize = sizeof (SP_DEVICE_INTERFACE_DETAIL_DATA); + + rc = SetupDiGetDeviceInterfaceDetail(hi, &di, pi, len, &len, 0); + if (rc) { + HANDLE m_handle; + + m_handle = CreateFile(pi->DevicePath, GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0); + if (m_handle != INVALID_HANDLE_VALUE) { + HIDD_ATTRIBUTES devInfo; + + if (HidD_GetAttributes(m_handle, &devInfo)) { + if (devInfo.VendorID == vendor_id) { + size_t j; + for (j = 0; j < pids_len; j++) { + if (devInfo.ProductID == product_ids[j]) { + found++; + if (found-1 == index) { + ret_handle = m_handle; + break; + } + } + } + } + } + } + if(ret_handle == NULL) { + CloseHandle (m_handle); + } else { + break; + } + } + + free (pi); + } + if(ret_handle != NULL) { + goto done; + } + + yk_errno = YK_ENOKEY; + +done: + SetupDiDestroyDeviceInfoList(hi); + return ret_handle; +} + +int _ykusb_close_device(void *yk) +{ + HANDLE h = yk; + + CloseHandle(h); + + return 1; +} + +#define EXPECT_SIZE 8 +#define FEATURE_BUF_SIZE 9 + +int _ykusb_read(void *dev, int report_type, int report_number, + char *buffer, int buffer_size) +{ + (void)report_type; + (void)report_number; + + HANDLE h = dev; + BYTE buf[FEATURE_BUF_SIZE]; + + if (buffer_size != EXPECT_SIZE) { + yk_errno = YK_EUSBERR; + return 0; + } + + memset(buf, 0, sizeof(buf)); + + if (!HidD_GetFeature(h, buf, sizeof (buf))) { + yk_errno = YK_EUSBERR; + return 0; + } + + memcpy (buffer, buf + 1, buffer_size); + + return buffer_size; +} + +int _ykusb_write(void *dev, int report_type, int report_number, + char *buffer, int buffer_size) +{ + (void)report_type; + (void)report_number; + + HANDLE h = dev; + BYTE buf[FEATURE_BUF_SIZE]; + + if (buffer_size != EXPECT_SIZE) { + yk_errno = YK_EUSBERR; + return 0; + } + + buf[0] = 0; + memcpy (buf + 1, buffer, buffer_size); + + if (!HidD_SetFeature(h, buf, sizeof (buf))) { + yk_errno = YK_EUSBERR; + return 0; + } + + return 1; +} + +int _ykusb_get_vid_pid(void *yk, int *vid, int *pid) { + HIDD_ATTRIBUTES devInfo; + int rc = HidD_GetAttributes(yk, &devInfo); + if (rc) { + *vid = devInfo.VendorID; + *pid = devInfo.ProductID; + return 1; + } + yk_errno = YK_EUSBERR; + return 0; +} + +const char *_ykusb_strerror(void) +{ + static char buf[1024]; + FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), 0, + buf, sizeof(buf), NULL); + return buf; +} diff --git a/src/thirdparty/ykcore/ykcrc.c b/src/thirdparty/ykcore/ykcrc.c new file mode 100644 index 000000000..8a3e70320 --- /dev/null +++ b/src/thirdparty/ykcore/ykcrc.c @@ -0,0 +1,54 @@ +/* ykcrc.c --- Implementation of YubiKey CRC-16 function. + * + * Written by Simon Josefsson . + * Copyright (c) 2006-2012 Yubico AB + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * 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. + * + * 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 + * OWNER 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. + * + */ + +#include "yubikey.h" + +uint16_t +yubikey_crc16 (const uint8_t * buf, size_t buf_size) +{ + uint16_t m_crc = 0xffff; + + while (buf_size--) + { + int i, j; + m_crc ^= (uint8_t) * buf++ & 0xFF; + for (i = 0; i < 8; i++) + { + j = m_crc & 1; + m_crc >>= 1; + if (j) + m_crc ^= 0x8408; + } + } + + return m_crc; +} diff --git a/src/thirdparty/ykcore/ykdef.h b/src/thirdparty/ykcore/ykdef.h new file mode 100644 index 000000000..0917342e3 --- /dev/null +++ b/src/thirdparty/ykcore/ykdef.h @@ -0,0 +1,310 @@ +/* -*- mode:C; c-file-style: "bsd" -*- */ +/***************************************************************************************** +** ** +** Y K D E F - Common Yubikey project header ** +** ** +** Date / Rev / Sign / Remark ** +** 06-06-03 / 0.9.0 / J E / Main ** +** 06-08-25 / 1.0.0 / J E / Rewritten for final spec ** +** 08-06-03 / 1.3.0 / J E / Added static OTP feature ** +** 09-06-02 / 2.0.0 / J E / Added version 2 flags ** +** 09-09-23 / 2.1.0 / J E / Added version 2.1 flags (OATH-HOTP) ** +** 10-05-01 / 2.2.0 / J E / Added support for 2.2 ext. + frame ** +** 11-04-15 / 2.3.0 / J E / Added support for 2.3 extensions ** +** 11-12-05 / 2.4.0 / J E / Added support for NFC and NDEF ** +** 12-10-28 / 3.0.0 / J E / NEO changes ** +** 13-03-05 / 3.1.0 / J E / Added EXTFLAG_LED_INV flag ** +** 13-03-06 / 3.1.0 / J E / Added NEO startup busy flag ** +** 14-06-13 / 3.3.0 / J E / Added U2F mode modifiers ** +** 14-11-20 / 4.0.0 / J E / Updated with Yubikey 4 PIDs ** +** 15-03-27 / 4.1.0 / K L / Added YK4 Capabilities ** +** 15-06-23 / 4.2.0 / K L / Added more YK4 Capabilities ** +** ** +*****************************************************************************************/ + +#ifndef __YKDEF_H_INCLUDED__ +#define __YKDEF_H_INCLUDED__ + +/* We need the structures defined here to be packed byte-wise */ +#if defined(_WIN32) || defined(__GNUC__) +#pragma pack(push, 1) +#endif + +/* Slot entries */ + +#define SLOT_CONFIG 1 /* First (default / V1) configuration */ +#define SLOT_NAV 2 /* V1 only */ +#define SLOT_CONFIG2 3 /* Second (V2) configuration */ +#define SLOT_UPDATE1 4 /* Update slot 1 */ +#define SLOT_UPDATE2 5 /* Update slot 2 */ +#define SLOT_SWAP 6 /* Swap slot 1 and 2 */ +#define SLOT_NDEF 8 /* Write NDEF record */ +#define SLOT_NDEF2 9 /* Write NDEF record for slot 2 */ + +#define SLOT_DEVICE_SERIAL 0x10 /* Device serial number */ +#define SLOT_DEVICE_CONFIG 0x11 /* Write device configuration record */ +#define SLOT_SCAN_MAP 0x12 /* Write scancode map */ +#define SLOT_YK4_CAPABILITIES 0x13 /* Read YK4 capabilities (device info) list */ +#define SLOT_YK4_SET_DEVICE_INFO 0x15 /* Write device info */ + +#define SLOT_CHAL_OTP1 0x20 /* Write 6 byte challenge to slot 1, get Yubico OTP response */ +#define SLOT_CHAL_OTP2 0x28 /* Write 6 byte challenge to slot 2, get Yubico OTP response */ + +#define SLOT_CHAL_HMAC1 0x30 /* Write 64 byte challenge to slot 1, get HMAC-SHA1 response */ +#define SLOT_CHAL_HMAC2 0x38 /* Write 64 byte challenge to slot 2, get HMAC-SHA1 response */ + +#define RESP_ITEM_MASK 0x07 /* Mask for slice item # in responses */ + +#define RESP_TIMEOUT_WAIT_MASK 0x1f /* Mask to get timeout value */ +#define RESP_TIMEOUT_WAIT_FLAG 0x20 /* Waiting for timeout operation - seconds left in lower 5 bits */ +#define RESP_PENDING_FLAG 0x40 /* Response pending flag */ +#define SLOT_WRITE_FLAG 0x80 /* Write flag - set by app - cleared by device */ + +#define DUMMY_REPORT_WRITE 0x8f /* Write a dummy report to force update or abort */ +#define NEO_STARTUP_BUSY 0x9f /* Status during startup (writes blocked) */ + +#define SHA1_MAX_BLOCK_SIZE 64 /* Max size of input SHA1 block */ +#define SHA1_DIGEST_SIZE 20 /* Size of SHA1 digest = 160 bits */ + +#define SERIAL_NUMBER_SIZE 4 /* Size of device serial number */ + +/* Frame structure */ + +#define SLOT_DATA_SIZE 64 + +struct frame_st { + unsigned char payload[SLOT_DATA_SIZE]; /* Frame payload */ + unsigned char slot; /* Slot # field */ + unsigned short crc; /* CRC field */ + unsigned char filler[3]; /* Filler */ +}; + +/* Ticket structure */ + +#define UID_SIZE 6 /* Size of secret ID field */ + +struct ticket_st { + unsigned char uid[UID_SIZE]; /* Unique (secret) ID */ + unsigned short useCtr; /* Use counter (incremented by 1 at first use after power up) + usage flag in msb */ + unsigned short tstpl; /* Timestamp incremented by approx 8Hz (low part) */ + unsigned char tstph; /* Timestamp (high part) */ + unsigned char sessionCtr; /* Number of times used within session. 0 for first use. After it wraps from 0xff to 1 */ + unsigned short rnd; /* Pseudo-random value */ + unsigned short crc; /* CRC16 value of all fields */ +}; + +/* Activation modifier of sessionUse field (bitfields not uses as they are not portable) */ + +#define TICKET_ACT_HIDRPT 0x8000 /* Ticket generated at activation by keyboard (scroll/num/caps) */ +#define TICKET_CTR_MASK 0x7fff /* Mask for useCtr value (except HID flag) */ + +/* Configuration structure */ + +#define FIXED_SIZE 16 /* Max size of fixed field */ +#define KEY_SIZE 16 /* Size of AES key */ +#define KEY_SIZE_OATH 20 /* Size of OATH-HOTP key (key field + first 4 of UID field) */ +#define ACC_CODE_SIZE 6 /* Size of access code to re-program device */ + +struct config_st { + unsigned char fixed[FIXED_SIZE];/* Fixed data in binary format */ + unsigned char uid[UID_SIZE]; /* Fixed UID part of ticket */ + unsigned char key[KEY_SIZE]; /* AES key */ + unsigned char accCode[ACC_CODE_SIZE]; /* Access code to re-program device */ + unsigned char fixedSize; /* Number of bytes in fixed field (0 if not used) */ + unsigned char extFlags; /* Extended flags - YubiKey 2.? and above */ + unsigned char tktFlags; /* Ticket configuration flags */ + unsigned char cfgFlags; /* General configuration flags */ + unsigned char rfu[2]; /* Reserved for future use */ + unsigned short crc; /* CRC16 value of all fields */ +}; + +/* Ticket flags **************************************************************/ + +/* Yubikey 1 and above */ +#define TKTFLAG_TAB_FIRST 0x01 /* Send TAB before first part */ +#define TKTFLAG_APPEND_TAB1 0x02 /* Send TAB after first part */ +#define TKTFLAG_APPEND_TAB2 0x04 /* Send TAB after second part */ +#define TKTFLAG_APPEND_DELAY1 0x08 /* Add 0.5s delay after first part */ +#define TKTFLAG_APPEND_DELAY2 0x10 /* Add 0.5s delay after second part */ +#define TKTFLAG_APPEND_CR 0x20 /* Append CR as final character */ + +/* Yubikey 2 and above */ +#define TKTFLAG_PROTECT_CFG2 0x80 /* Block update of config 2 unless config 2 is configured and has this bit set */ + +/* Configuration flags *******************************************************/ + +/* Yubikey 1 and above */ +#define CFGFLAG_SEND_REF 0x01 /* Send reference string (0..F) before data */ +#define CFGFLAG_PACING_10MS 0x04 /* Add 10ms intra-key pacing */ +#define CFGFLAG_PACING_20MS 0x08 /* Add 20ms intra-key pacing */ +#define CFGFLAG_STATIC_TICKET 0x20 /* Static ticket generation */ + +/* Yubikey 1 only */ +#define CFGFLAG_TICKET_FIRST 0x02 /* Send ticket first (default is fixed part) */ +#define CFGFLAG_ALLOW_HIDTRIG 0x10 /* Allow trigger through HID/keyboard */ + +/* Yubikey 2 and above */ +#define CFGFLAG_SHORT_TICKET 0x02 /* Send truncated ticket (half length) */ +#define CFGFLAG_STRONG_PW1 0x10 /* Strong password policy flag #1 (mixed case) */ +#define CFGFLAG_STRONG_PW2 0x40 /* Strong password policy flag #2 (subtitute 0..7 to digits) */ +#define CFGFLAG_MAN_UPDATE 0x80 /* Allow manual (local) update of static OTP */ + +/* Yubikey 2.1 and above */ +#define TKTFLAG_OATH_HOTP 0x40 /* OATH HOTP mode */ +#define CFGFLAG_OATH_HOTP8 0x02 /* Generate 8 digits HOTP rather than 6 digits */ +#define CFGFLAG_OATH_FIXED_MODHEX1 0x10 /* First byte in fixed part sent as modhex */ +#define CFGFLAG_OATH_FIXED_MODHEX2 0x40 /* First two bytes in fixed part sent as modhex */ +#define CFGFLAG_OATH_FIXED_MODHEX 0x50 /* Fixed part sent as modhex */ +#define CFGFLAG_OATH_FIXED_MASK 0x50 /* Mask to get out fixed flags */ + +/* Yubikey 2.2 and above */ + +#define TKTFLAG_CHAL_RESP 0x40 /* Challenge-response enabled (both must be set) */ +#define CFGFLAG_CHAL_YUBICO 0x20 /* Challenge-response enabled - Yubico OTP mode */ +#define CFGFLAG_CHAL_HMAC 0x22 /* Challenge-response enabled - HMAC-SHA1 */ +#define CFGFLAG_HMAC_LT64 0x04 /* Set when HMAC message is less than 64 bytes */ +#define CFGFLAG_CHAL_BTN_TRIG 0x08 /* Challenge-response operation requires button press */ + +#define EXTFLAG_SERIAL_BTN_VISIBLE 0x01 /* Serial number visible at startup (button press) */ +#define EXTFLAG_SERIAL_USB_VISIBLE 0x02 /* Serial number visible in USB iSerial field */ +#define EXTFLAG_SERIAL_API_VISIBLE 0x04 /* Serial number visible via API call */ + +/* V2.3 flags only */ + +#define EXTFLAG_USE_NUMERIC_KEYPAD 0x08 /* Use numeric keypad for digits */ +#define EXTFLAG_FAST_TRIG 0x10 /* Use fast trig if only cfg1 set */ +#define EXTFLAG_ALLOW_UPDATE 0x20 /* Allow update of existing configuration (selected flags + access code) */ +#define EXTFLAG_DORMANT 0x40 /* Dormant configuration (can be woken up and flag removed = requires update flag) */ + +/* V2.4/3.1 flags only */ + +#define EXTFLAG_LED_INV 0x80 /* LED idle state is off rather than on */ + +/* Flags valid for update */ + +#define TKTFLAG_UPDATE_MASK (TKTFLAG_TAB_FIRST | TKTFLAG_APPEND_TAB1 | TKTFLAG_APPEND_TAB2 | TKTFLAG_APPEND_DELAY1 | TKTFLAG_APPEND_DELAY2 | TKTFLAG_APPEND_CR) +#define CFGFLAG_UPDATE_MASK (CFGFLAG_PACING_10MS | CFGFLAG_PACING_20MS) +#define EXTFLAG_UPDATE_MASK (EXTFLAG_SERIAL_BTN_VISIBLE | EXTFLAG_SERIAL_USB_VISIBLE | EXTFLAG_SERIAL_API_VISIBLE | EXTFLAG_USE_NUMERIC_KEYPAD | EXTFLAG_FAST_TRIG | EXTFLAG_ALLOW_UPDATE | EXTFLAG_DORMANT | EXTFLAG_LED_INV) + +/* NDEF structure */ +#define NDEF_DATA_SIZE 54 + +/* backwards compatibility with version 1.7.0 */ +typedef struct ndef_st YKNDEF; + +struct ndef_st { + unsigned char len; /* Payload length */ + unsigned char type; /* NDEF type specifier */ + unsigned char data[NDEF_DATA_SIZE]; /* Payload size */ + unsigned char curAccCode[ACC_CODE_SIZE]; /* Access code */ +}; + + +/* Navigation */ + +/* NOTE: Navigation isn't available since Yubikey 1.3.5 and is strongly + discouraged. */ +#define MAX_URL 48 + +struct nav_st { + unsigned char scancode[MAX_URL];/* Scancode (lower 7 bits) */ + unsigned char scanmod[MAX_URL >> 2]; /* Modifier fields (packed 2 bits each) */ + unsigned char flags; /* NAVFLAG_xxx flags */ + unsigned char filler; /* Filler byte */ + unsigned short crc; /* CRC16 value of all fields */ +}; + +#define SCANMOD_SHIFT 0x80 /* Highest bit in scancode */ +#define SCANMOD_ALT_GR 0x01 /* Lowest bit in mod */ +#define SCANMOD_WIN 0x02 /* WIN key */ + +/* Navigation flags */ + +#define NAVFLAG_INSERT_TRIG 0x01 /* Automatic trigger when device is inserted */ +#define NAVFLAG_APPEND_TKT 0x02 /* Append ticket to URL */ +#define NAVFLAG_DUAL_KEY_USAGE 0x04 /* Dual usage of key: Short = ticket Long = Navigate */ + +/* Device configuration block (version 3.0) */ + +struct device_config_st { + unsigned char mode; /* Device mode */ + unsigned char crTimeout; /* Challenge-response timeout in seconds */ + unsigned short autoEjectTime; /* Auto eject time in x10 seconds */ +}; + +#define MODE_OTP 0x00 /* OTP only */ +#define MODE_CCID 0x01 /* CCID only, no eject */ +#define MODE_OTP_CCID 0x02 /* OTP + CCID composite */ +#define MODE_U2F 0x03 /* U2F mode */ +#define MODE_OTP_U2F 0x04 /* OTP + U2F composite */ +#define MODE_U2F_CCID 0x05 /* U2F + CCID composite */ +#define MODE_OTP_U2F_CCID 0x06 /* OTP + U2F + CCID composite */ +#define MODE_MASK 0x07 /* Mask for mode bits */ + +#define MODE_FLAG_EJECT 0x80 /* CCID device supports eject (mode 1 only) */ + +#define DEFAULT_CHAL_TIMEOUT 15 /* Default challenge timeout in seconds */ + +/* Scancode mapping (version 3.0) */ + +#define SCAN_MAP "cbdefghijklnrtuvCBDEFGHIJKLNRTUV0123456789!\t\r" +#define SHIFT_FLAG 0x80 /* Flag for shifted scan codes */ + +/* Status block */ + +struct status_st { + unsigned char versionMajor; /* Firmware version information */ + unsigned char versionMinor; + unsigned char versionBuild; + unsigned char pgmSeq; /* Programming sequence number. 0 if no valid configuration */ + unsigned short touchLevel; /* Level from touch detector */ +}; + +#define CONFIG1_VALID 0x01 /* Bit in touchLevel indicating that configuration 1 is valid (from firmware 2.1) */ +#define CONFIG2_VALID 0x02 /* Bit in touchLevel indicating that configuration 2 is valid (from firmware 2.1) */ +#define CONFIG1_TOUCH 0x04 /* Bit in touchLevel indicating that configuration 1 requires touch (from firmware 3.0) */ +#define CONFIG2_TOUCH 0x08 /* Bit in touchLevel indicating that configuration 2 requires touch (from firmware 3.0) */ +#define CONFIG_LED_INV 0x10 /* Bit in touchLevel indicating that LED behavior is inverted (EXTFLAG_LED_INV mirror) */ +#define CONFIG_STATUS_MASK 0x1f /* Mask for status bits */ + +/* Modified hex string mapping */ + +#define MODHEX_MAP "cbdefghijklnrtuv" + +/* USB vendor ID (VID) and product ID (PID) mapping */ + +#define YUBICO_VID 0x1050 /* Global vendor ID */ +#define YUBIKEY_PID 0x0010 /* Yubikey (version 1 and 2) */ +#define NEO_OTP_PID 0x0110 /* Yubikey NEO - OTP only */ +#define NEO_OTP_CCID_PID 0x0111 /* Yubikey NEO - OTP and CCID */ +#define NEO_CCID_PID 0x0112 /* Yubikey NEO - CCID only */ +#define NEO_U2F_PID 0x0113 /* Yubikey NEO - U2F only */ +#define NEO_OTP_U2F_PID 0x0114 /* Yubikey NEO - OTP and U2F */ +#define NEO_U2F_CCID_PID 0x0115 /* Yubikey NEO - U2F and CCID */ +#define NEO_OTP_U2F_CCID_PID 0x0116 /* Yubikey NEO - OTP, U2F and CCID */ + +#define YK4_OTP_PID 0x0401 /* Yubikey 4 - OTP only */ +#define YK4_U2F_PID 0x0402 /* Yubikey 4 - U2F only */ +#define YK4_OTP_U2F_PID 0x0403 /* Yubikey 4 - OTP and U2F */ +#define YK4_CCID_PID 0x0404 /* Yubikey 4 - CCID only */ +#define YK4_OTP_CCID_PID 0x0405 /* Yubikey 4 - OTP and CCID */ +#define YK4_U2F_CCID_PID 0x0406 /* Yubikey 4 - U2F and CCID */ +#define YK4_OTP_U2F_CCID_PID 0x0407 /* Yubikey 4 - OTP, U2F and CCID */ + +#define PLUS_U2F_OTP_PID 0x0410 /* Yubikey plus - OTP+U2F */ + +#define YK4_CAPA_TAG 0x01 /* TAG for capabilities */ +#define YK4_SERIAL_TAG 0x02 /* TAG for serial number */ + +#define YK4_CAPA1_OTP 0x01 /* Capability bit for OTP functonality */ +#define YK4_CAPA1_U2F 0x02 /* Capability bit for U2F functionality */ +#define YK4_CAPA1_CCID 0x04 /* Capability bit for CCID functionality */ +#define YK4_CAPA1_OPGP 0x08 /* Capability bit for OpenPGP functionality */ +#define YK4_CAPA1_PIV 0x10 /* Capability bit for PIV functionality */ +#define YK4_CAPA1_OATH 0x20 /* Capability bit for OATH functionality */ + +#if defined(_WIN32) || defined(__GNUC__) +#pragma pack(pop) +#endif + +#endif /* __YKDEF_H_INCLUDED__ */ diff --git a/src/thirdparty/ykcore/ykstatus.c b/src/thirdparty/ykcore/ykstatus.c new file mode 100644 index 000000000..4677fefb5 --- /dev/null +++ b/src/thirdparty/ykcore/ykstatus.c @@ -0,0 +1,90 @@ +/* -*- mode:C; c-file-style: "bsd" -*- */ +/* + * Written by Richard Levitte + * Copyright (c) 2008-2012 Yubico AB + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * 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. + * + * 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 + * OWNER 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. + */ + +#include "ykcore_lcl.h" +#include "ykdef.h" +#include "ykstatus.h" + +YK_STATUS *ykds_alloc(void) +{ + YK_STATUS *st = malloc(sizeof(YK_STATUS)); + if (!st) { + yk_errno = YK_ENOMEM; + } + return st; +} + +void ykds_free(YK_STATUS *st) +{ + free(st); +} + +YK_STATUS *ykds_static(void) +{ + static YK_STATUS st; + return &st; +} + +extern int ykds_version_major(const YK_STATUS *st) +{ + if (st) + return st->versionMajor; + yk_errno = YK_ENOSTATUS; + return 0; +} +extern int ykds_version_minor(const YK_STATUS *st) +{ + if (st) + return st->versionMinor; + yk_errno = YK_ENOSTATUS; + return 0; +} +extern int ykds_version_build(const YK_STATUS *st) +{ + if (st) + return st->versionBuild; + yk_errno = YK_ENOSTATUS; + return 0; +} +extern int ykds_pgm_seq(const YK_STATUS *st) +{ + if (st) + return st->pgmSeq; + yk_errno = YK_ENOSTATUS; + return 0; +} +extern int ykds_touch_level(const YK_STATUS *st) +{ + if (st) + return st->touchLevel; + yk_errno = YK_ENOSTATUS; + return 0; +} diff --git a/src/thirdparty/ykcore/ykstatus.h b/src/thirdparty/ykcore/ykstatus.h new file mode 100644 index 000000000..3b6d045e6 --- /dev/null +++ b/src/thirdparty/ykcore/ykstatus.h @@ -0,0 +1,60 @@ +/* -*- mode:C; c-file-style: "bsd" -*- */ +/* + * Written by Richard Levitte + * Copyright (c) 2008-2013 Yubico AB + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * 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. + * + * 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 + * OWNER 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. + */ + +#ifndef __YKSTATUS_H_INCLUDED__ +#define __YKSTATUS_H_INCLUDED__ + +#include "ykcore.h" + +# ifdef __cplusplus +extern "C" { +# endif + +/* Allocate and free status structures */ +extern YK_STATUS *ykds_alloc(void); +extern void ykds_free(YK_STATUS *st); + +/* Return static status structure, to be used for quick checks. + USE WITH CAUTION, as this is a SHARED OBJECT. */ +extern YK_STATUS *ykds_static(void); + +/* Accessor functions */ +extern int ykds_version_major(const YK_STATUS *st); +extern int ykds_version_minor(const YK_STATUS *st); +extern int ykds_version_build(const YK_STATUS *st); +extern int ykds_pgm_seq(const YK_STATUS *st); +extern int ykds_touch_level(const YK_STATUS *st); + +# ifdef __cplusplus +} +# endif + +#endif /* __YKSTATUS_H_INCLUDED__ */ diff --git a/src/thirdparty/ykcore/yktsd.h b/src/thirdparty/ykcore/yktsd.h new file mode 100644 index 000000000..9b5e5269e --- /dev/null +++ b/src/thirdparty/ykcore/yktsd.h @@ -0,0 +1,61 @@ +/* yktsd.h -*- mode:C; c-file-style: "gnu" -*- */ +/* Note: this file is copied from Levitte Programming's LPlib and reworked + for ykcore */ +/* + * Copyright (c) 2008-2012 Yubico AB + * Copyright (c) 2010 Simon Josefsson + * Copyright (c) 2003, 2004 Richard Levitte . + * 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. + * + * 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 + * OWNER 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. + */ + +#ifndef YKTSD_H +#define YKTSD_H + +/* Define thread-specific data primitives */ +#if defined _WIN32 +#include +#include +#define yk__TSD_TYPE DWORD +#define yk__TSD_ALLOC(key,nop) ((key = TlsAlloc()) == TLS_OUT_OF_INDEXES ? EAGAIN : 0) +#define yk__TSD_FREE(key) (!TlsFree(key)) +#define yk__TSD_SET(key,value) (!TlsSetValue(key,value)) +#define yk__TSD_GET(key) TlsGetValue(key) +#else +#include +#define yk__TSD_TYPE pthread_key_t +#define yk__TSD_ALLOC(key,destr) pthread_key_create(&key, destr) +#define yk__TSD_FREE(key) pthread_key_delete(key) +#define yk__TSD_SET(key,value) pthread_setspecific(key,(void *)value) +#define yk__TSD_GET(key) pthread_getspecific(key) +#endif + +/* Define the high-level macros that we use. */ +#define YK_TSD_METADATA(x) yk__tsd_##x +#define YK_DEFINE_TSD_METADATA(x) static yk__TSD_TYPE YK_TSD_METADATA(x) +#define YK_TSD_INIT(x,destr) yk__TSD_ALLOC(YK_TSD_METADATA(x),destr) +#define YK_TSD_DESTROY(x) yk__TSD_FREE(YK_TSD_METADATA(x)) +#define YK_TSD_SET(x,value) yk__TSD_SET(YK_TSD_METADATA(x),value) +#define YK_TSD_GET(type,x) (type)yk__TSD_GET(YK_TSD_METADATA(x)) + +#endif diff --git a/src/thirdparty/ykcore/yubikey.h b/src/thirdparty/ykcore/yubikey.h new file mode 100644 index 000000000..e877cc574 --- /dev/null +++ b/src/thirdparty/ykcore/yubikey.h @@ -0,0 +1,136 @@ +/* yubikey.h --- Prototypes for low-level YubiKey OTP functions. + * + * Written by Simon Josefsson . + * Copyright (c) 2006-2012 Yubico AB + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * 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. + * + * 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 + * OWNER 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. + * + */ + +#ifndef YUBIKEY_H +#define YUBIKEY_H + +#include +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + +#define YUBIKEY_BLOCK_SIZE 16 +#define YUBIKEY_KEY_SIZE 16 +#define YUBIKEY_UID_SIZE 6 +#define YUBIKEY_OTP_SIZE (2 * YUBIKEY_BLOCK_SIZE) + + typedef struct + { + /* Unique (secret) ID. */ + uint8_t uid[YUBIKEY_UID_SIZE]; + /* Session counter (incremented by 1 at each startup). High bit + indicates whether caps-lock triggered the token. */ + uint16_t ctr; + /* Timestamp incremented by approx 8Hz (low part). */ + uint16_t tstpl; + /* Timestamp (high part). */ + uint8_t tstph; + /* Number of times used within session + activation flags. */ + uint8_t use; + /* Pseudo-random value. */ + uint16_t rnd; + /* CRC16 value of all fields. */ + uint16_t crc; + } yubikey_token_st; + + typedef yubikey_token_st *yubikey_token_t; + +/* High-level functions. */ + + +/* Decrypt TOKEN using KEY and store output in OUT structure. Note + that there is no error checking whether the output data is valid or + not, use yubikey_check_* for that. */ + extern void yubikey_parse (const uint8_t token[YUBIKEY_BLOCK_SIZE], + const uint8_t key[YUBIKEY_KEY_SIZE], + yubikey_token_t out); + +/* Generate OTP */ + extern void yubikey_generate (yubikey_token_t token, + const uint8_t key[YUBIKEY_KEY_SIZE], + char out[YUBIKEY_OTP_SIZE + 1]); + +#define yubikey_counter(ctr) ((ctr) & 0x7FFF) +#define yubikey_capslock(ctr) ((ctr) & 0x8000) +#define yubikey_crc_ok_p(tok) \ + (yubikey_crc16 ((tok), YUBIKEY_BLOCK_SIZE) == YUBIKEY_CRC_OK_RESIDUE) + +/* + * Low-level functions; ModHex. + */ + +#define YUBIKEY_MODHEX_MAP "cbdefghijklnrtuv" + +/* ModHex encode input string SRC of length SRCSIZE and put the zero + terminated output string in DST. The size of the output string DST + must be at least 2*SRCSIZE+1. The output string is always + 2*SRCSIZE large plus the terminating zero. */ + extern void yubikey_modhex_encode (char *dst, + const char *src, size_t srcsize); + +/* ModHex decode input string SRC of length DSTSIZE/2 into output + string DST. The output string DST is always DSTSIZE/2 large plus + the terminating zero. */ + extern void yubikey_modhex_decode (char *dst, + const char *src, size_t dstsize); + +/* Hex encode/decode data, same interface as modhex functions. */ + extern void yubikey_hex_encode (char *dst, const char *src, size_t srcsize); + extern void yubikey_hex_decode (char *dst, const char *src, size_t dstsize); + +/* Return non-zero if zero-terminated input STR is a valid (mod)hex + string, and zero if any non-alphabetic characters are found. */ + extern int yubikey_modhex_p (const char *str); + extern int yubikey_hex_p (const char *str); + +/* + * Low-level functions; CRC. + */ + +#define YUBIKEY_CRC_OK_RESIDUE 0xf0b8 + extern uint16_t yubikey_crc16 (const uint8_t * buf, size_t buf_size); + +/* Low-level functions; AES. */ + +/* AES-decrypt/encrypt one 16-byte block STATE using the 128-bit KEY, + leaving the decrypted/encrypted output in the STATE buffer. */ + extern void yubikey_aes_decrypt (uint8_t * state, const uint8_t * key); + extern void yubikey_aes_encrypt (uint8_t * state, const uint8_t * key); + +#ifdef __cplusplus +} +#endif + +#endif