0
0
mirror of https://github.com/keepassxreboot/keepassxc.git synced 2024-09-19 20:02:18 +02:00

Initial ykcore import into code base

This commit is contained in:
Jonathan White 2021-09-05 08:51:25 -04:00
parent 0450bf3487
commit 6e27dd8db5
23 changed files with 2948 additions and 25 deletions

View File

@ -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 <sys/prctl.h>
int main() { prctl(PR_SET_DUMPABLE, 0); return 0; }"

View File

@ -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)

View File

@ -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

View File

@ -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)

View File

@ -16,15 +16,14 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <ykcore.h>
#include <ykdef.h>
#include <ykpers-version.h>
#include <ykstatus.h>
#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 <QtConcurrent>
@ -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;
}

View File

@ -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})

19
src/thirdparty/CMakeLists.txt vendored Normal file
View File

@ -0,0 +1,19 @@
# Copyright (C) 2021 KeePassXC Team <team@keepassxc.org>
#
# 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 <http://www.gnu.org/licenses/>.
if(WITH_XC_YUBIKEY)
add_subdirectory(ykcore)
set(thirdparty_LIBRARIES ${thirdparty_LIBRARIES} ykcore PARENT_SCOPE)
endif()

42
src/thirdparty/ykcore/CMakeLists.txt vendored Normal file
View File

@ -0,0 +1,42 @@
# Copyright (C) 2021 KeePassXC Team <team@keepassxc.org>
#
# 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 <http://www.gnu.org/licenses/>.
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()

62
src/thirdparty/ykcore/ykbzero.h vendored Normal file
View File

@ -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 <windows.h>
#else
#include <string.h>
#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__ */

782
src/thirdparty/ykcore/ykcore.c vendored Normal file
View File

@ -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 <stdio.h>
#ifndef _WIN32
#include <time.h>
#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 &nothread_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;
}

191
src/thirdparty/ykcore/ykcore.h vendored Normal file
View File

@ -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 <stdlib.h>
#include <stdbool.h>
#include <stdint.h>
# 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__ */

54
src/thirdparty/ykcore/ykcore_backend.h vendored Normal file
View File

@ -0,0 +1,54 @@
/* -*- mode:C; c-file-style: "bsd" -*- */
/*
* Written by Richard Levitte <richar@levitte.org>
* 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__ */

69
src/thirdparty/ykcore/ykcore_lcl.h vendored Normal file
View File

@ -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__ */

View File

@ -0,0 +1,296 @@
/* -*- mode:C; c-file-style: "bsd" -*- */
/*
* Copyright (c) 2008-2014 Yubico AB
* Copyright (c) 2009 Tollef Fog Heen <tfheen@err.no>
* 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 <libusb.h>
#include <stdio.h>
#include <string.h>
#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, &current_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;
}

216
src/thirdparty/ykcore/ykcore_libusb.c vendored Normal file
View File

@ -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 <usb.h>
#include <stdio.h>
#include <string.h>
#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();
}

280
src/thirdparty/ykcore/ykcore_osx.c vendored Normal file
View File

@ -0,0 +1,280 @@
/* -*- mode:C; c-file-style: "bsd" -*- */
/*
* Copyright (c) 2008-2014 Yubico AB
* Copyright (c) 2009 Christer Kaivo-oja <christer.kaivooja@gmail.com>
* 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 <IOKit/hid/IOHIDLib.h>
#include <IOKit/hid/IOHIDKeys.h>
#include <IOKit/hid/IOHIDUsageTables.h>
#include <CoreFoundation/CoreFoundation.h>
#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";
}
}

210
src/thirdparty/ykcore/ykcore_windows.c vendored Normal file
View File

@ -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 <stdio.h>
#include <windows.h>
#include <setupapi.h>
#include <ntddkbd.h>
#include <hidsdi.h>
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;
}

54
src/thirdparty/ykcore/ykcrc.c vendored Normal file
View File

@ -0,0 +1,54 @@
/* ykcrc.c --- Implementation of YubiKey CRC-16 function.
*
* Written by Simon Josefsson <simon@josefsson.org>.
* 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;
}

310
src/thirdparty/ykcore/ykdef.h vendored Normal file
View File

@ -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__ */

90
src/thirdparty/ykcore/ykstatus.c vendored Normal file
View File

@ -0,0 +1,90 @@
/* -*- mode:C; c-file-style: "bsd" -*- */
/*
* Written by Richard Levitte <richard@levitte.org>
* 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;
}

60
src/thirdparty/ykcore/ykstatus.h vendored Normal file
View File

@ -0,0 +1,60 @@
/* -*- mode:C; c-file-style: "bsd" -*- */
/*
* Written by Richard Levitte <richard@levitte.org>
* 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__ */

61
src/thirdparty/ykcore/yktsd.h vendored Normal file
View File

@ -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 <simon@josefsson.org>
* Copyright (c) 2003, 2004 Richard Levitte <richard@levitte.org>.
* 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 <windows.h>
#include <errno.h>
#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 <pthread.h>
#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

136
src/thirdparty/ykcore/yubikey.h vendored Normal file
View File

@ -0,0 +1,136 @@
/* yubikey.h --- Prototypes for low-level YubiKey OTP functions.
*
* Written by Simon Josefsson <simon@josefsson.org>.
* 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 <stdint.h>
#include <string.h>
#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