├── .eslintignore ├── .eslintrc ├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── c_src ├── CMakeLists.txt ├── hidapi │ ├── hid-linux-hidraw.c │ ├── hid-linux-libusb.c │ ├── hid-mac.c │ ├── hid-win.c │ └── hidapi.h ├── json-c │ ├── arraylist.c │ ├── arraylist.h │ ├── bits.h │ ├── config.h.in │ ├── debug.c │ ├── debug.h │ ├── json.h │ ├── json_c_version.c │ ├── json_c_version.h │ ├── json_config.h.in │ ├── json_inttypes.h │ ├── json_object.c │ ├── json_object.h │ ├── json_object_iterator.c │ ├── json_object_iterator.h │ ├── json_object_private.h │ ├── json_tokener.c │ ├── json_tokener.h │ ├── json_util.c │ ├── json_util.h │ ├── libjson.c │ ├── linkhash.c │ ├── linkhash.h │ ├── math_compat.h │ ├── printbuf.c │ ├── printbuf.h │ ├── random_seed.c │ └── random_seed.h ├── libu2f-host │ ├── authenticate.c │ ├── b64 │ │ ├── cdecode.h │ │ └── cencode.h │ ├── cdecode.c │ ├── cencode.c │ ├── devs.c │ ├── error.c │ ├── global.c │ ├── inc │ │ ├── u2f.h │ │ └── u2f_hid.h │ ├── internal.h │ ├── register.c │ ├── sha256.c │ ├── sha256.h │ ├── stdalign.h.in │ ├── u2f-host-types.h │ ├── u2f-host-version.h │ ├── u2f-host.h │ └── u2fmisc.c └── main.c ├── ext ├── appIdValidator.js ├── bootstrap.js ├── data │ ├── content-script.js │ ├── logs.html │ └── logs.js ├── icon.png ├── icon64.png ├── index.js ├── install.rdf ├── options.xul └── package.json └── scripts ├── make-xpi.sh └── prepare-release.sh /.eslintignore: -------------------------------------------------------------------------------- 1 | ext/bootstrap.js 2 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "eslint:recommended", 3 | "env": { 4 | "es6": true 5 | }, 6 | "globals": { 7 | "require": true 8 | }, 9 | "rules" : { 10 | "curly": 0, 11 | "eqeqeq": 0, 12 | "global-strict": 0, 13 | // The add-on SDK console logging is controlled by preferences. 14 | "no-console": 0, 15 | "semi": 2 16 | }, 17 | } 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ext/bin 2 | c_src/build* 3 | *.xpi 4 | update.rdf 5 | u2f-src*.zip 6 | .idea -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: c++ 2 | 3 | addons: 4 | apt: 5 | sources: 6 | - george-edison55-precise-backports 7 | packages: 8 | - cmake 9 | - cmake-data 10 | - libudev-dev 11 | 12 | compiler: 13 | - clang 14 | - gcc 15 | 16 | script: 17 | - mkdir build 18 | - cd build; cmake ../c_src 19 | - cd build; make 20 | 21 | notifications: 22 | email: false 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # U2F Support Firefox Extension [![Build Status](https://travis-ci.org/prefiks/u2f4moz.svg?branch=master)](https://travis-ci.org/prefiks/u2f4moz) 2 | 3 | This extension adds support for the U2F specification with Yubico devices to Firefox. 4 | 5 | It can be used by accessing window.u2f object from content pages. 6 | 7 | Install from https://addons.mozilla.org/firefox/addon/u2f-support-add-on/ 8 | 9 | ## Build instructions ## 10 | 11 | 1. `cd c_src` 12 | 2. `cmake` 13 | 3. `make && make install` 14 | 4. `cd ../ext` 15 | 5. `jpm run` 16 | 17 | On OS X and Linux the u2f binary may lose its executable bit upon packaging XPI this way. 18 | 19 | It's possible to make XPI file manually by executing `cd ext; zip -9r ../u2f.xpi *` or 20 | included bash script `scripts/make-xpi.sh`, this way permissions in final file will be correct. 21 | 22 | ## Enabling U2f on Yubico Neo and Neo-n ## 23 | 24 | Those two devices didn't have U2F enabled by default before November 2015. For the older models, it requires manual configuration changes 25 | described described in this [document](http://yubi.co/unlockU2F). If you've purchased one recently, you won't have to do anything. 26 | 27 | ## Permissions tweaks for Linux ## 28 | 29 | On Linux access to U2F devices may not be permitted to Firefox, installing extra 30 | [udev rules](https://github.com/Yubico/libu2f-host/blob/master/70-u2f.rules) may help 31 | in this situation. 32 | -------------------------------------------------------------------------------- /c_src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | CMAKE_MINIMUM_REQUIRED(VERSION 3.0) 2 | 3 | INCLUDE (CheckIncludeFiles) 4 | INCLUDE (CheckSymbolExists) 5 | INCLUDE (CheckFunctionExists) 6 | 7 | SET(COMPILE_FOR_32 0 CACHE PATH "Compile for 32 bit target") 8 | 9 | SET(CMAKE_CXX_VISIBILITY_PRESET hidden) 10 | SET(CMAKE_C_VISIBILITY_PRESET hidden) 11 | 12 | IF(CMAKE_VERSION VERSION_LESS "3.4.0") 13 | ELSE() 14 | #CMAKE_POLICY(SET CMP0063 NEW) 15 | CMAKE_POLICY(VERSION 3.4) 16 | ENDIF() 17 | 18 | IF(APPLE) 19 | SET(hidapi_SRC hidapi/hid-mac.c) 20 | LIST(APPEND extra_LIBS "-framework IOKit" "-framework CoreFoundation") 21 | SET(TARGET_LOCATION darwin_${CMAKE_SYSTEM_PROCESSOR}-gcc3) 22 | ELSEIF(WIN32) 23 | SET(hidapi_SRC hidapi/hid-win.c) 24 | LIST(APPEND extra_LIBS "setupapi") 25 | SET(TARGET_LOCATION winnt_x86-msvc) 26 | ELSEIF(UNIX) 27 | SET(extra_LIBS pthread) 28 | SET(extra_INCLUDES) 29 | IF(COMPILE_FOR_32) 30 | SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -m32") 31 | SET(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -m32") 32 | SET(SYSTEM_PROCESSOR "x86") 33 | ELSE(COMPILE_FOR_32) 34 | IF(${CMAKE_SYSTEM_NAME} STREQUAL "Linux") 35 | SET(SYSTEM_PROCESSOR "${CMAKE_SYSTEM_PROCESSOR}") 36 | ELSE() 37 | IF("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "amd64") 38 | SET(SYSTEM_PROCESSOR "x86_64") 39 | ELSE() 40 | SET(SYSTEM_PROCESSOR "x86") 41 | ENDIF() 42 | ENDIF() 43 | ENDIF(COMPILE_FOR_32) 44 | IF(${CMAKE_SYSTEM_NAME} STREQUAL "Linux") 45 | IF(USE_LIBUSB) 46 | FIND_PACKAGE(PkgConfig) 47 | PKG_CHECK_MODULES(libusb REQUIRED libusb-1.0) 48 | LIST(APPEND extra_LIBS ${libusb_LIBRARIES}) 49 | LIST(APPEND extra_INCLUDES ${libusb_INCLUDE_DIRS}) 50 | SET(hidapi_SRC hidapi/hid-linux-libusb.c) 51 | ELSE() 52 | FIND_PACKAGE(PkgConfig) 53 | PKG_CHECK_MODULES(libudev REQUIRED libudev) 54 | LIST(APPEND extra_LIBS ${libudev_LIBRARIES}) 55 | LIST(APPEND extra_INCLUDES ${libudev_INCLUDE_DIRS}) 56 | SET(hidapi_SRC hidapi/hid-linux-hidraw.c) 57 | ENDIF(USE_LIBUSB) 58 | SET(TARGET_LOCATION linux_${SYSTEM_PROCESSOR}-gcc3) 59 | ELSE() 60 | FIND_PACKAGE(PkgConfig) 61 | PKG_CHECK_MODULES(libusb REQUIRED libusb-1.0) 62 | LIST(APPEND extra_LIBS ${libusb_LIBRARIES}) 63 | LIST(APPEND extra_INCLUDES ${libusb_INCLUDE_DIRS}) 64 | SET(hidapi_SRC hidapi/hid-linux-libusb.c) 65 | SET(TARGET_LOCATION freebsd_${SYSTEM_PROCESSOR}-gcc3) 66 | ENDIF() 67 | ENDIF(APPLE) 68 | 69 | INCLUDE_DIRECTORIES(${extra_INCLUDES} json-c libu2f-host hidapi ${CMAKE_CURRENT_BINARY_DIR}) 70 | 71 | CHECK_INCLUDE_FILES(fcntl.h STDC_HEADERS) 72 | CHECK_INCLUDE_FILES(fcntl.h HAVE_FCNTL_H) 73 | CHECK_INCLUDE_FILES(limits.h HAVE_LIMITS_H) 74 | CHECK_INCLUDE_FILES(strings.h HAVE_STRINGS_H) 75 | CHECK_INCLUDE_FILES(syslog.h HAVE_SYSLOG_H) 76 | CHECK_INCLUDE_FILES(unistd.h HAVE_UNISTD_H) 77 | CHECK_INCLUDE_FILES(sys/cdefs.h HAVE_SYS_CDEFS_H) 78 | CHECK_INCLUDE_FILES(sys/param.h HAVE_SYS_PARAM_H) 79 | CHECK_INCLUDE_FILES(stdarg.h HAVE_STDARG_H) 80 | CHECK_INCLUDE_FILES(locale.h HAVE_LOCALE_H) 81 | CHECK_INCLUDE_FILES(endian.h HAVE_ENDIAN_H) 82 | CHECK_INCLUDE_FILES(inttypes.h JSON_C_HAVE_INTTYPES_H) 83 | CHECK_INCLUDE_FILES(stdalign.h HAVE_STDALIGN_H) 84 | 85 | CHECK_FUNCTION_EXISTS(vprintf HAVE_VPRINTF) 86 | CHECK_FUNCTION_EXISTS(_doprnt HAVE_DOPRNT) 87 | CHECK_FUNCTION_EXISTS(memcpm HAVE_MEMCMP) 88 | CHECK_FUNCTION_EXISTS(realloc HAVE_REALLOC) 89 | CHECK_FUNCTION_EXISTS(strcasecmp HAVE_STRCASECMP) 90 | CHECK_FUNCTION_EXISTS(strdup HAVE_STRDUP) 91 | CHECK_FUNCTION_EXISTS(strerror HAVE_STRERROR) 92 | CHECK_FUNCTION_EXISTS(snprintf HAVE_SNPRINTF) 93 | CHECK_FUNCTION_EXISTS(vsnprintf HAVE_VSNPRINTF) 94 | CHECK_SYMBOL_EXISTS(vasprintf stdio.h HAVE_VASPRINTF) 95 | CHECK_FUNCTION_EXISTS(open HAVE_OPEN) 96 | CHECK_FUNCTION_EXISTS(vsyslog HAVE_VSYSLOG) 97 | CHECK_FUNCTION_EXISTS(strncasecmp HAVE_STRNCASECMP) 98 | CHECK_FUNCTION_EXISTS(setlocale HAVE_SETLOCALE) 99 | 100 | CHECK_SYMBOL_EXISTS(INFINITY math.h HAVE_DECL_INFINITY) 101 | CHECK_SYMBOL_EXISTS(NAN math.h HAVE_DECL_NAN) 102 | CHECK_SYMBOL_EXISTS(isnan math.h HAVE_DECL_ISNAN) 103 | CHECK_SYMBOL_EXISTS(isinf math.h HAVE_DECL_ISINF) 104 | CHECK_SYMBOL_EXISTS(_isinf math.h HAVE_DECL__ISINF) 105 | CHECK_SYMBOL_EXISTS(_finite math.h HAVE_DECL__FINITE) 106 | 107 | CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/json-c/config.h.in ${CMAKE_CURRENT_BINARY_DIR}/config.h) 108 | CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/json-c/json_config.h.in ${CMAKE_CURRENT_BINARY_DIR}/json_config.h) 109 | IF(NOT HAVE_STDALIGN_H) 110 | CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/libu2f-host/stdalign.h.in ${CMAKE_CURRENT_BINARY_DIR}/stdalign.h) 111 | ENDIF(NOT HAVE_STDALIGN_H) 112 | 113 | ADD_LIBRARY(hidapi OBJECT ${hidapi_SRC}) 114 | 115 | ADD_LIBRARY(jsonc OBJECT json-c/arraylist.c 116 | json-c/debug.c 117 | json-c/json_c_version.c 118 | json-c/json_object.c 119 | json-c/json_object_iterator.c 120 | json-c/json_tokener.c 121 | json-c/json_util.c 122 | json-c/libjson.c 123 | json-c/linkhash.c 124 | json-c/printbuf.c 125 | json-c/random_seed.c) 126 | 127 | ADD_LIBRARY(u2fhost OBJECT 128 | libu2f-host/authenticate.c 129 | libu2f-host/cdecode.c 130 | libu2f-host/cencode.c 131 | libu2f-host/devs.c 132 | libu2f-host/error.c 133 | libu2f-host/global.c 134 | libu2f-host/register.c 135 | libu2f-host/u2fmisc.c 136 | libu2f-host/sha256.c) 137 | 138 | ADD_EXECUTABLE(u2f 139 | main.c 140 | $ 141 | $ 142 | $) 143 | 144 | 145 | TARGET_LINK_LIBRARIES(u2f ${extra_LIBS}) 146 | 147 | INSTALL(TARGETS u2f DESTINATION ${PROJECT_SOURCE_DIR}/../ext/bin/${TARGET_LOCATION}) 148 | -------------------------------------------------------------------------------- /c_src/hidapi/hidapi.h: -------------------------------------------------------------------------------- 1 | /******************************************************* 2 | HIDAPI - Multi-Platform library for 3 | communication with HID devices. 4 | 5 | Alan Ott 6 | Signal 11 Software 7 | 8 | 8/22/2009 9 | 10 | Copyright 2009, All Rights Reserved. 11 | 12 | At the discretion of the user of this library, 13 | this software may be licensed under the terms of the 14 | GNU General Public License v3, a BSD-Style license, or the 15 | original HIDAPI license as outlined in the LICENSE.txt, 16 | LICENSE-gpl3.txt, LICENSE-bsd.txt, and LICENSE-orig.txt 17 | files located at the root of the source distribution. 18 | These files may also be found in the public source 19 | code repository located at: 20 | http://github.com/signal11/hidapi . 21 | ********************************************************/ 22 | 23 | /** @file 24 | * @defgroup API hidapi API 25 | */ 26 | 27 | #ifndef HIDAPI_H__ 28 | #define HIDAPI_H__ 29 | 30 | #include 31 | 32 | #ifdef _WIN32 33 | #define HID_API_EXPORT __declspec(dllexport) 34 | #define HID_API_CALL 35 | #else 36 | #define HID_API_EXPORT /**< API export macro */ 37 | #define HID_API_CALL /**< API call macro */ 38 | #endif 39 | 40 | #define HID_API_EXPORT_CALL HID_API_EXPORT HID_API_CALL /**< API export and call macro*/ 41 | 42 | #ifdef __cplusplus 43 | extern "C" { 44 | #endif 45 | struct hid_device_; 46 | typedef struct hid_device_ hid_device; /**< opaque hidapi structure */ 47 | 48 | /** hidapi info structure */ 49 | struct hid_device_info { 50 | /** Platform-specific device path */ 51 | char *path; 52 | /** Device Vendor ID */ 53 | unsigned short vendor_id; 54 | /** Device Product ID */ 55 | unsigned short product_id; 56 | /** Serial Number */ 57 | wchar_t *serial_number; 58 | /** Device Release Number in binary-coded decimal, 59 | also known as Device Version Number */ 60 | unsigned short release_number; 61 | /** Manufacturer String */ 62 | wchar_t *manufacturer_string; 63 | /** Product string */ 64 | wchar_t *product_string; 65 | /** Usage Page for this Device/Interface 66 | (Windows/Mac only). */ 67 | unsigned short usage_page; 68 | /** Usage for this Device/Interface 69 | (Windows/Mac only).*/ 70 | unsigned short usage; 71 | /** The USB interface which this logical device 72 | represents. Valid on both Linux implementations 73 | in all cases, and valid on the Windows implementation 74 | only if the device contains more than one interface. */ 75 | int interface_number; 76 | 77 | /** Pointer to the next device */ 78 | struct hid_device_info *next; 79 | }; 80 | 81 | 82 | /** @brief Initialize the HIDAPI library. 83 | 84 | This function initializes the HIDAPI library. Calling it is not 85 | strictly necessary, as it will be called automatically by 86 | hid_enumerate() and any of the hid_open_*() functions if it is 87 | needed. This function should be called at the beginning of 88 | execution however, if there is a chance of HIDAPI handles 89 | being opened by different threads simultaneously. 90 | 91 | @ingroup API 92 | 93 | @returns 94 | This function returns 0 on success and -1 on error. 95 | */ 96 | int HID_API_EXPORT HID_API_CALL hid_init(void); 97 | 98 | /** @brief Finalize the HIDAPI library. 99 | 100 | This function frees all of the static data associated with 101 | HIDAPI. It should be called at the end of execution to avoid 102 | memory leaks. 103 | 104 | @ingroup API 105 | 106 | @returns 107 | This function returns 0 on success and -1 on error. 108 | */ 109 | int HID_API_EXPORT HID_API_CALL hid_exit(void); 110 | 111 | /** @brief Enumerate the HID Devices. 112 | 113 | This function returns a linked list of all the HID devices 114 | attached to the system which match vendor_id and product_id. 115 | If @p vendor_id is set to 0 then any vendor matches. 116 | If @p product_id is set to 0 then any product matches. 117 | If @p vendor_id and @p product_id are both set to 0, then 118 | all HID devices will be returned. 119 | 120 | @ingroup API 121 | @param vendor_id The Vendor ID (VID) of the types of device 122 | to open. 123 | @param product_id The Product ID (PID) of the types of 124 | device to open. 125 | 126 | @returns 127 | This function returns a pointer to a linked list of type 128 | struct #hid_device, containing information about the HID devices 129 | attached to the system, or NULL in the case of failure. Free 130 | this linked list by calling hid_free_enumeration(). 131 | */ 132 | struct hid_device_info HID_API_EXPORT * HID_API_CALL hid_enumerate(unsigned short vendor_id, unsigned short product_id); 133 | 134 | /** @brief Free an enumeration Linked List 135 | 136 | This function frees a linked list created by hid_enumerate(). 137 | 138 | @ingroup API 139 | @param devs Pointer to a list of struct_device returned from 140 | hid_enumerate(). 141 | */ 142 | void HID_API_EXPORT HID_API_CALL hid_free_enumeration(struct hid_device_info *devs); 143 | 144 | /** @brief Open a HID device using a Vendor ID (VID), Product ID 145 | (PID) and optionally a serial number. 146 | 147 | If @p serial_number is NULL, the first device with the 148 | specified VID and PID is opened. 149 | 150 | @ingroup API 151 | @param vendor_id The Vendor ID (VID) of the device to open. 152 | @param product_id The Product ID (PID) of the device to open. 153 | @param serial_number The Serial Number of the device to open 154 | (Optionally NULL). 155 | 156 | @returns 157 | This function returns a pointer to a #hid_device object on 158 | success or NULL on failure. 159 | */ 160 | HID_API_EXPORT hid_device * HID_API_CALL hid_open(unsigned short vendor_id, unsigned short product_id, const wchar_t *serial_number); 161 | 162 | /** @brief Open a HID device by its path name. 163 | 164 | The path name be determined by calling hid_enumerate(), or a 165 | platform-specific path name can be used (eg: /dev/hidraw0 on 166 | Linux). 167 | 168 | @ingroup API 169 | @param path The path name of the device to open 170 | 171 | @returns 172 | This function returns a pointer to a #hid_device object on 173 | success or NULL on failure. 174 | */ 175 | HID_API_EXPORT hid_device * HID_API_CALL hid_open_path(const char *path); 176 | 177 | /** @brief Write an Output report to a HID device. 178 | 179 | The first byte of @p data[] must contain the Report ID. For 180 | devices which only support a single report, this must be set 181 | to 0x0. The remaining bytes contain the report data. Since 182 | the Report ID is mandatory, calls to hid_write() will always 183 | contain one more byte than the report contains. For example, 184 | if a hid report is 16 bytes long, 17 bytes must be passed to 185 | hid_write(), the Report ID (or 0x0, for devices with a 186 | single report), followed by the report data (16 bytes). In 187 | this example, the length passed in would be 17. 188 | 189 | hid_write() will send the data on the first OUT endpoint, if 190 | one exists. If it does not, it will send the data through 191 | the Control Endpoint (Endpoint 0). 192 | 193 | @ingroup API 194 | @param device A device handle returned from hid_open(). 195 | @param data The data to send, including the report number as 196 | the first byte. 197 | @param length The length in bytes of the data to send. 198 | 199 | @returns 200 | This function returns the actual number of bytes written and 201 | -1 on error. 202 | */ 203 | int HID_API_EXPORT HID_API_CALL hid_write(hid_device *device, const unsigned char *data, size_t length); 204 | 205 | /** @brief Read an Input report from a HID device with timeout. 206 | 207 | Input reports are returned 208 | to the host through the INTERRUPT IN endpoint. The first byte will 209 | contain the Report number if the device uses numbered reports. 210 | 211 | @ingroup API 212 | @param device A device handle returned from hid_open(). 213 | @param data A buffer to put the read data into. 214 | @param length The number of bytes to read. For devices with 215 | multiple reports, make sure to read an extra byte for 216 | the report number. 217 | @param milliseconds timeout in milliseconds or -1 for blocking wait. 218 | 219 | @returns 220 | This function returns the actual number of bytes read and 221 | -1 on error. If no packet was available to be read within 222 | the timeout period, this function returns 0. 223 | */ 224 | int HID_API_EXPORT HID_API_CALL hid_read_timeout(hid_device *dev, unsigned char *data, size_t length, int milliseconds); 225 | 226 | /** @brief Read an Input report from a HID device. 227 | 228 | Input reports are returned 229 | to the host through the INTERRUPT IN endpoint. The first byte will 230 | contain the Report number if the device uses numbered reports. 231 | 232 | @ingroup API 233 | @param device A device handle returned from hid_open(). 234 | @param data A buffer to put the read data into. 235 | @param length The number of bytes to read. For devices with 236 | multiple reports, make sure to read an extra byte for 237 | the report number. 238 | 239 | @returns 240 | This function returns the actual number of bytes read and 241 | -1 on error. If no packet was available to be read and 242 | the handle is in non-blocking mode, this function returns 0. 243 | */ 244 | int HID_API_EXPORT HID_API_CALL hid_read(hid_device *device, unsigned char *data, size_t length); 245 | 246 | /** @brief Set the device handle to be non-blocking. 247 | 248 | In non-blocking mode calls to hid_read() will return 249 | immediately with a value of 0 if there is no data to be 250 | read. In blocking mode, hid_read() will wait (block) until 251 | there is data to read before returning. 252 | 253 | Nonblocking can be turned on and off at any time. 254 | 255 | @ingroup API 256 | @param device A device handle returned from hid_open(). 257 | @param nonblock enable or not the nonblocking reads 258 | - 1 to enable nonblocking 259 | - 0 to disable nonblocking. 260 | 261 | @returns 262 | This function returns 0 on success and -1 on error. 263 | */ 264 | int HID_API_EXPORT HID_API_CALL hid_set_nonblocking(hid_device *device, int nonblock); 265 | 266 | /** @brief Send a Feature report to the device. 267 | 268 | Feature reports are sent over the Control endpoint as a 269 | Set_Report transfer. The first byte of @p data[] must 270 | contain the Report ID. For devices which only support a 271 | single report, this must be set to 0x0. The remaining bytes 272 | contain the report data. Since the Report ID is mandatory, 273 | calls to hid_send_feature_report() will always contain one 274 | more byte than the report contains. For example, if a hid 275 | report is 16 bytes long, 17 bytes must be passed to 276 | hid_send_feature_report(): the Report ID (or 0x0, for 277 | devices which do not use numbered reports), followed by the 278 | report data (16 bytes). In this example, the length passed 279 | in would be 17. 280 | 281 | @ingroup API 282 | @param device A device handle returned from hid_open(). 283 | @param data The data to send, including the report number as 284 | the first byte. 285 | @param length The length in bytes of the data to send, including 286 | the report number. 287 | 288 | @returns 289 | This function returns the actual number of bytes written and 290 | -1 on error. 291 | */ 292 | int HID_API_EXPORT HID_API_CALL hid_send_feature_report(hid_device *device, const unsigned char *data, size_t length); 293 | 294 | /** @brief Get a feature report from a HID device. 295 | 296 | Set the first byte of @p data[] to the Report ID of the 297 | report to be read. Make sure to allow space for this 298 | extra byte in @p data[]. Upon return, the first byte will 299 | still contain the Report ID, and the report data will 300 | start in data[1]. 301 | 302 | @ingroup API 303 | @param device A device handle returned from hid_open(). 304 | @param data A buffer to put the read data into, including 305 | the Report ID. Set the first byte of @p data[] to the 306 | Report ID of the report to be read, or set it to zero 307 | if your device does not use numbered reports. 308 | @param length The number of bytes to read, including an 309 | extra byte for the report ID. The buffer can be longer 310 | than the actual report. 311 | 312 | @returns 313 | This function returns the number of bytes read plus 314 | one for the report ID (which is still in the first 315 | byte), or -1 on error. 316 | */ 317 | int HID_API_EXPORT HID_API_CALL hid_get_feature_report(hid_device *device, unsigned char *data, size_t length); 318 | 319 | /** @brief Close a HID device. 320 | 321 | @ingroup API 322 | @param device A device handle returned from hid_open(). 323 | */ 324 | void HID_API_EXPORT HID_API_CALL hid_close(hid_device *device); 325 | 326 | /** @brief Get The Manufacturer String from a HID device. 327 | 328 | @ingroup API 329 | @param device A device handle returned from hid_open(). 330 | @param string A wide string buffer to put the data into. 331 | @param maxlen The length of the buffer in multiples of wchar_t. 332 | 333 | @returns 334 | This function returns 0 on success and -1 on error. 335 | */ 336 | int HID_API_EXPORT_CALL hid_get_manufacturer_string(hid_device *device, wchar_t *string, size_t maxlen); 337 | 338 | /** @brief Get The Product String from a HID device. 339 | 340 | @ingroup API 341 | @param device A device handle returned from hid_open(). 342 | @param string A wide string buffer to put the data into. 343 | @param maxlen The length of the buffer in multiples of wchar_t. 344 | 345 | @returns 346 | This function returns 0 on success and -1 on error. 347 | */ 348 | int HID_API_EXPORT_CALL hid_get_product_string(hid_device *device, wchar_t *string, size_t maxlen); 349 | 350 | /** @brief Get The Serial Number String from a HID device. 351 | 352 | @ingroup API 353 | @param device A device handle returned from hid_open(). 354 | @param string A wide string buffer to put the data into. 355 | @param maxlen The length of the buffer in multiples of wchar_t. 356 | 357 | @returns 358 | This function returns 0 on success and -1 on error. 359 | */ 360 | int HID_API_EXPORT_CALL hid_get_serial_number_string(hid_device *device, wchar_t *string, size_t maxlen); 361 | 362 | /** @brief Get a string from a HID device, based on its string index. 363 | 364 | @ingroup API 365 | @param device A device handle returned from hid_open(). 366 | @param string_index The index of the string to get. 367 | @param string A wide string buffer to put the data into. 368 | @param maxlen The length of the buffer in multiples of wchar_t. 369 | 370 | @returns 371 | This function returns 0 on success and -1 on error. 372 | */ 373 | int HID_API_EXPORT_CALL hid_get_indexed_string(hid_device *device, int string_index, wchar_t *string, size_t maxlen); 374 | 375 | /** @brief Get a string describing the last error which occurred. 376 | 377 | @ingroup API 378 | @param device A device handle returned from hid_open(). 379 | 380 | @returns 381 | This function returns a string containing the last error 382 | which occurred or NULL if none has occurred. 383 | */ 384 | HID_API_EXPORT const wchar_t* HID_API_CALL hid_error(hid_device *device); 385 | 386 | #ifdef __cplusplus 387 | } 388 | #endif 389 | 390 | #endif 391 | 392 | -------------------------------------------------------------------------------- /c_src/json-c/arraylist.c: -------------------------------------------------------------------------------- 1 | /* 2 | * $Id: arraylist.c,v 1.4 2006/01/26 02:16:28 mclark Exp $ 3 | * 4 | * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. 5 | * Michael Clark 6 | * 7 | * This library is free software; you can redistribute it and/or modify 8 | * it under the terms of the MIT license. See COPYING for details. 9 | * 10 | */ 11 | 12 | #include "config.h" 13 | 14 | #ifdef STDC_HEADERS 15 | # include 16 | # include 17 | #endif /* STDC_HEADERS */ 18 | 19 | #if defined(HAVE_STRINGS_H) && !defined(_STRING_H) && !defined(__USE_BSD) 20 | # include 21 | #endif /* HAVE_STRINGS_H */ 22 | 23 | #include "arraylist.h" 24 | 25 | struct array_list* 26 | array_list_new(array_list_free_fn *free_fn) 27 | { 28 | struct array_list *arr; 29 | 30 | arr = (struct array_list*)calloc(1, sizeof(struct array_list)); 31 | if(!arr) return NULL; 32 | arr->size = ARRAY_LIST_DEFAULT_SIZE; 33 | arr->length = 0; 34 | arr->free_fn = free_fn; 35 | if(!(arr->array = (void**)calloc(sizeof(void*), arr->size))) { 36 | free(arr); 37 | return NULL; 38 | } 39 | return arr; 40 | } 41 | 42 | extern void 43 | array_list_free(struct array_list *arr) 44 | { 45 | int i; 46 | for(i = 0; i < arr->length; i++) 47 | if(arr->array[i]) arr->free_fn(arr->array[i]); 48 | free(arr->array); 49 | free(arr); 50 | } 51 | 52 | void* 53 | array_list_get_idx(struct array_list *arr, int i) 54 | { 55 | if(i >= arr->length) return NULL; 56 | return arr->array[i]; 57 | } 58 | 59 | static int array_list_expand_internal(struct array_list *arr, int max) 60 | { 61 | void *t; 62 | int new_size; 63 | 64 | if(max < arr->size) return 0; 65 | new_size = arr->size << 1; 66 | if (new_size < max) 67 | new_size = max; 68 | if(!(t = realloc(arr->array, new_size*sizeof(void*)))) return -1; 69 | arr->array = (void**)t; 70 | (void)memset(arr->array + arr->size, 0, (new_size-arr->size)*sizeof(void*)); 71 | arr->size = new_size; 72 | return 0; 73 | } 74 | 75 | int 76 | array_list_put_idx(struct array_list *arr, int idx, void *data) 77 | { 78 | if(array_list_expand_internal(arr, idx+1)) return -1; 79 | if(arr->array[idx]) arr->free_fn(arr->array[idx]); 80 | arr->array[idx] = data; 81 | if(arr->length <= idx) arr->length = idx + 1; 82 | return 0; 83 | } 84 | 85 | int 86 | array_list_add(struct array_list *arr, void *data) 87 | { 88 | return array_list_put_idx(arr, arr->length, data); 89 | } 90 | 91 | void 92 | array_list_sort(struct array_list *arr, int(*sort_fn)(const void *, const void *)) 93 | { 94 | qsort(arr->array, arr->length, sizeof(arr->array[0]), sort_fn); 95 | } 96 | 97 | void* array_list_bsearch(const void **key, struct array_list *arr, 98 | int (*sort_fn)(const void *, const void *)) 99 | { 100 | return bsearch(key, arr->array, arr->length, sizeof(arr->array[0]), 101 | sort_fn); 102 | } 103 | 104 | int 105 | array_list_length(struct array_list *arr) 106 | { 107 | return arr->length; 108 | } 109 | -------------------------------------------------------------------------------- /c_src/json-c/arraylist.h: -------------------------------------------------------------------------------- 1 | /* 2 | * $Id: arraylist.h,v 1.4 2006/01/26 02:16:28 mclark Exp $ 3 | * 4 | * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. 5 | * Michael Clark 6 | * 7 | * This library is free software; you can redistribute it and/or modify 8 | * it under the terms of the MIT license. See COPYING for details. 9 | * 10 | */ 11 | 12 | #ifndef _arraylist_h_ 13 | #define _arraylist_h_ 14 | 15 | #ifdef __cplusplus 16 | extern "C" { 17 | #endif 18 | 19 | #define ARRAY_LIST_DEFAULT_SIZE 32 20 | 21 | typedef void (array_list_free_fn) (void *data); 22 | 23 | struct array_list 24 | { 25 | void **array; 26 | int length; 27 | int size; 28 | array_list_free_fn *free_fn; 29 | }; 30 | 31 | extern struct array_list* 32 | array_list_new(array_list_free_fn *free_fn); 33 | 34 | extern void 35 | array_list_free(struct array_list *al); 36 | 37 | extern void* 38 | array_list_get_idx(struct array_list *al, int i); 39 | 40 | extern int 41 | array_list_put_idx(struct array_list *al, int i, void *data); 42 | 43 | extern int 44 | array_list_add(struct array_list *al, void *data); 45 | 46 | extern int 47 | array_list_length(struct array_list *al); 48 | 49 | extern void 50 | array_list_sort(struct array_list *arr, int(*compar)(const void *, const void *)); 51 | 52 | extern void* array_list_bsearch(const void **key, 53 | struct array_list *arr, 54 | int (*sort_fn)(const void *, const void *)); 55 | 56 | 57 | #ifdef __cplusplus 58 | } 59 | #endif 60 | 61 | #endif 62 | -------------------------------------------------------------------------------- /c_src/json-c/bits.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file 3 | * @deprecated Use json_util.h instead. 4 | * 5 | * $Id: bits.h,v 1.10 2006/01/30 23:07:57 mclark Exp $ 6 | * 7 | * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. 8 | * Michael Clark 9 | * 10 | * This library is free software; you can redistribute it and/or modify 11 | * it under the terms of the MIT license. See COPYING for details. 12 | * 13 | */ 14 | 15 | #ifndef _bits_h_ 16 | #define _bits_h_ 17 | 18 | /** 19 | * @deprecated 20 | */ 21 | #define hexdigit(x) (((x) <= '9') ? (x) - '0' : ((x) & 7) + 9) 22 | /** 23 | * @deprecated 24 | */ 25 | #define error_ptr(error) ((void*)error) 26 | /** 27 | * @deprecated 28 | */ 29 | #define error_description(error) (json_tokener_get_error(error)) 30 | /** 31 | * @deprecated 32 | */ 33 | #define is_error(ptr) (ptr == NULL) 34 | 35 | #endif 36 | -------------------------------------------------------------------------------- /c_src/json-c/config.h.in: -------------------------------------------------------------------------------- 1 | /* config.h.in. Generated from configure.ac by autoheader. */ 2 | 3 | /* Enable RDRANR Hardware RNG Hash Seed */ 4 | #cmakedefine ENABLE_RDRAND 1 5 | 6 | /* Define if .gnu.warning accepts long strings. */ 7 | #cmakedefine HAS_GNU_WARNING_LONG 1 8 | 9 | /* Define to 1 if you have the declaration of `INFINITY', and to 0 if you 10 | don't. */ 11 | #cmakedefine HAVE_DECL_INFINITY 1 12 | 13 | /* Define to 1 if you have the declaration of `isinf', and to 0 if you don't. 14 | */ 15 | #cmakedefine HAVE_DECL_ISINF 1 16 | 17 | /* Define to 1 if you have the declaration of `isnan', and to 0 if you don't. 18 | */ 19 | #cmakedefine HAVE_DECL_ISNAN 1 20 | 21 | /* Define to 1 if you have the declaration of `nan', and to 0 if you don't. */ 22 | #cmakedefine HAVE_DECL_NAN 1 23 | 24 | /* Define to 1 if you have the declaration of `_finite', and to 0 if you 25 | don't. */ 26 | #cmakedefine HAVE_DECL__FINITE 1 27 | 28 | /* Define to 1 if you have the declaration of `_isnan', and to 0 if you don't. 29 | */ 30 | #cmakedefine HAVE_DECL__ISNAN 1 31 | 32 | /* Define to 1 if you have the header file. */ 33 | #cmakedefine HAVE_DLFCN_H 1 34 | 35 | /* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */ 36 | #cmakedefine HAVE_DOPRNT 1 37 | 38 | /* Define to 1 if you have the header file. */ 39 | #cmakedefine HAVE_ENDIAN_H 1 40 | 41 | /* Define to 1 if you have the header file. */ 42 | #cmakedefine HAVE_FCNTL_H 1 43 | 44 | /* Define to 1 if you have the header file. */ 45 | #cmakedefine HAVE_INTTYPES_H 1 46 | 47 | /* Define to 1 if you have the header file. */ 48 | #cmakedefine HAVE_LIMITS_H 1 49 | 50 | /* Define to 1 if you have the header file. */ 51 | #cmakedefine HAVE_LOCALE_H 1 52 | 53 | /* Define to 1 if you have the header file. */ 54 | #cmakedefine HAVE_MEMORY_H 1 55 | 56 | /* Define to 1 if you have the `open' function. */ 57 | #cmakedefine HAVE_OPEN 1 58 | 59 | /* Define to 1 if your system has a GNU libc compatible `realloc' function, 60 | and to 0 otherwise. */ 61 | #cmakedefine HAVE_REALLOC 1 62 | 63 | /* Define to 1 if you have the `setlocale' function. */ 64 | #cmakedefine HAVE_SETLOCALE 1 65 | 66 | /* Define to 1 if you have the `snprintf' function. */ 67 | #cmakedefine HAVE_SNPRINTF 1 68 | 69 | /* Define to 1 if you have the header file. */ 70 | #cmakedefine HAVE_STDARG_H 1 71 | 72 | /* Define to 1 if you have the header file. */ 73 | #cmakedefine HAVE_STDINT_H 1 74 | 75 | /* Define to 1 if you have the header file. */ 76 | #cmakedefine HAVE_STDLIB_H 1 77 | 78 | /* Define to 1 if you have the `strcasecmp' function. */ 79 | #cmakedefine HAVE_STRCASECMP 1 80 | 81 | /* Define to 1 if you have the `strdup' function. */ 82 | #cmakedefine HAVE_STRDUP 1 83 | 84 | /* Define to 1 if you have the `strerror' function. */ 85 | #cmakedefine HAVE_STRERROR 1 86 | 87 | /* Define to 1 if you have the header file. */ 88 | #cmakedefine HAVE_STRINGS_H 1 89 | 90 | /* Define to 1 if you have the header file. */ 91 | #cmakedefine HAVE_STRING_H 1 92 | 93 | /* Define to 1 if you have the `strncasecmp' function. */ 94 | #cmakedefine HAVE_STRNCASECMP 1 95 | 96 | /* Define to 1 if you have the header file. */ 97 | #cmakedefine HAVE_SYSLOG_H 1 98 | 99 | /* Define to 1 if you have the header file. */ 100 | #cmakedefine HAVE_SYS_CDEFS_H 1 101 | 102 | /* Define to 1 if you have the header file. */ 103 | #cmakedefine HAVE_SYS_PARAM_H 1 104 | 105 | /* Define to 1 if you have the header file. */ 106 | #cmakedefine HAVE_SYS_STAT_H 1 107 | 108 | /* Define to 1 if you have the header file. */ 109 | #cmakedefine HAVE_SYS_TYPES_H 1 110 | 111 | /* Define to 1 if you have the header file. */ 112 | #cmakedefine HAVE_UNISTD_H 1 113 | 114 | /* Define to 1 if you have the `vasprintf' function. */ 115 | #cmakedefine HAVE_VASPRINTF 1 116 | 117 | /* Define to 1 if you have the `vprintf' function. */ 118 | #cmakedefine HAVE_VPRINTF 1 119 | 120 | /* Define to 1 if you have the `vsnprintf' function. */ 121 | #cmakedefine HAVE_VSNPRINTF 1 122 | 123 | /* Define to 1 if you have the `vsyslog' function. */ 124 | #cmakedefine HAVE_VSYSLOG 1 125 | 126 | /* Public define for json_inttypes.h */ 127 | #cmakedefine JSON_C_HAVE_INTTYPES_H 1 128 | 129 | /* Define to the sub-directory in which libtool stores uninstalled libraries. 130 | */ 131 | #cmakedefine LT_OBJDIR 132 | 133 | /* Name of package */ 134 | #cmakedefine PACKAGE 135 | 136 | /* Define to the address where bug reports for this package should be sent. */ 137 | #cmakedefine PACKAGE_BUGREPORT 138 | 139 | /* Define to the full name of this package. */ 140 | #cmakedefine PACKAGE_NAME 141 | 142 | /* Define to the full name and version of this package. */ 143 | #cmakedefine PACKAGE_STRING 144 | 145 | /* Define to the one symbol short name of this package. */ 146 | #cmakedefine PACKAGE_TARNAME 147 | 148 | /* Define to the home page for this package. */ 149 | #cmakedefine PACKAGE_URL 150 | 151 | /* Define to the version of this package. */ 152 | #cmakedefine PACKAGE_VERSION 153 | 154 | /* Define to 1 if you have the ANSI C header files. */ 155 | #cmakedefine STDC_HEADERS 156 | 157 | /* Version number of package */ 158 | #cmakedefine VERSION 159 | 160 | /* Define to empty if `const' does not conform to ANSI C. */ 161 | #cmakedefine const 162 | 163 | /* Define to rpl_realloc if the replacement function should be used. */ 164 | #cmakedefine realloc 165 | 166 | /* Define to `unsigned int' if does not define. */ 167 | #cmakedefine size_t 168 | 169 | #define HAVE_JSON_OBJECT_OBJECT_GET_EX 1 -------------------------------------------------------------------------------- /c_src/json-c/debug.c: -------------------------------------------------------------------------------- 1 | /* 2 | * $Id: debug.c,v 1.5 2006/01/26 02:16:28 mclark Exp $ 3 | * 4 | * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. 5 | * Michael Clark 6 | * 7 | * This library is free software; you can redistribute it and/or modify 8 | * it under the terms of the MIT license. See COPYING for details. 9 | * 10 | */ 11 | 12 | #include "config.h" 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #if HAVE_SYSLOG_H 20 | # include 21 | #endif /* HAVE_SYSLOG_H */ 22 | 23 | #if HAVE_UNISTD_H 24 | # include 25 | #endif /* HAVE_UNISTD_H */ 26 | 27 | #if HAVE_SYS_PARAM_H 28 | #include 29 | #endif /* HAVE_SYS_PARAM_H */ 30 | 31 | #include "debug.h" 32 | 33 | static int _syslog = 0; 34 | static int _debug = 0; 35 | 36 | void mc_set_debug(int debug) { _debug = debug; } 37 | int mc_get_debug(void) { return _debug; } 38 | 39 | extern void mc_set_syslog(int syslog) 40 | { 41 | _syslog = syslog; 42 | } 43 | 44 | void mc_debug(const char *msg, ...) 45 | { 46 | va_list ap; 47 | if(_debug) { 48 | va_start(ap, msg); 49 | #if HAVE_VSYSLOG 50 | if(_syslog) { 51 | vsyslog(LOG_DEBUG, msg, ap); 52 | } else 53 | #endif 54 | vprintf(msg, ap); 55 | va_end(ap); 56 | } 57 | } 58 | 59 | void mc_error(const char *msg, ...) 60 | { 61 | va_list ap; 62 | va_start(ap, msg); 63 | #if HAVE_VSYSLOG 64 | if(_syslog) { 65 | vsyslog(LOG_ERR, msg, ap); 66 | } else 67 | #endif 68 | vfprintf(stderr, msg, ap); 69 | va_end(ap); 70 | } 71 | 72 | void mc_info(const char *msg, ...) 73 | { 74 | va_list ap; 75 | va_start(ap, msg); 76 | #if HAVE_VSYSLOG 77 | if(_syslog) { 78 | vsyslog(LOG_INFO, msg, ap); 79 | } else 80 | #endif 81 | vfprintf(stderr, msg, ap); 82 | va_end(ap); 83 | } 84 | -------------------------------------------------------------------------------- /c_src/json-c/debug.h: -------------------------------------------------------------------------------- 1 | /* 2 | * $Id: debug.h,v 1.5 2006/01/30 23:07:57 mclark Exp $ 3 | * 4 | * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. 5 | * Michael Clark 6 | * Copyright (c) 2009 Hewlett-Packard Development Company, L.P. 7 | * 8 | * This library is free software; you can redistribute it and/or modify 9 | * it under the terms of the MIT license. See COPYING for details. 10 | * 11 | */ 12 | 13 | #ifndef _DEBUG_H_ 14 | #define _DEBUG_H_ 15 | 16 | #include 17 | 18 | #ifdef __cplusplus 19 | extern "C" { 20 | #endif 21 | 22 | extern void mc_set_debug(int debug); 23 | extern int mc_get_debug(void); 24 | 25 | extern void mc_set_syslog(int syslog); 26 | 27 | extern void mc_debug(const char *msg, ...); 28 | extern void mc_error(const char *msg, ...); 29 | extern void mc_info(const char *msg, ...); 30 | 31 | #ifndef __STRING 32 | #define __STRING(x) #x 33 | #endif 34 | 35 | #ifndef PARSER_BROKEN_FIXED 36 | 37 | #define JASSERT(cond) do {} while(0) 38 | 39 | #else 40 | 41 | #define JASSERT(cond) do { \ 42 | if (!(cond)) { \ 43 | mc_error("cjson assert failure %s:%d : cond \"" __STRING(cond) "failed\n", __FILE__, __LINE__); \ 44 | *(int *)0 = 1;\ 45 | abort(); \ 46 | }\ 47 | } while(0) 48 | 49 | #endif 50 | 51 | #define MC_ERROR(x, ...) mc_error(x, ##__VA_ARGS__) 52 | 53 | #ifdef MC_MAINTAINER_MODE 54 | #define MC_SET_DEBUG(x) mc_set_debug(x) 55 | #define MC_GET_DEBUG() mc_get_debug() 56 | #define MC_SET_SYSLOG(x) mc_set_syslog(x) 57 | #define MC_DEBUG(x, ...) mc_debug(x, ##__VA_ARGS__) 58 | #define MC_INFO(x, ...) mc_info(x, ##__VA_ARGS__) 59 | #else 60 | #define MC_SET_DEBUG(x) if (0) mc_set_debug(x) 61 | #define MC_GET_DEBUG() (0) 62 | #define MC_SET_SYSLOG(x) if (0) mc_set_syslog(x) 63 | #define MC_DEBUG(x, ...) if (0) mc_debug(x, ##__VA_ARGS__) 64 | #define MC_INFO(x, ...) if (0) mc_info(x, ##__VA_ARGS__) 65 | #endif 66 | 67 | #ifdef __cplusplus 68 | } 69 | #endif 70 | 71 | #endif 72 | -------------------------------------------------------------------------------- /c_src/json-c/json.h: -------------------------------------------------------------------------------- 1 | /* 2 | * $Id: json.h,v 1.6 2006/01/26 02:16:28 mclark Exp $ 3 | * 4 | * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. 5 | * Michael Clark 6 | * Copyright (c) 2009 Hewlett-Packard Development Company, L.P. 7 | * 8 | * This library is free software; you can redistribute it and/or modify 9 | * it under the terms of the MIT license. See COPYING for details. 10 | * 11 | */ 12 | 13 | #ifndef _json_h_ 14 | #define _json_h_ 15 | 16 | #ifdef __cplusplus 17 | extern "C" { 18 | #endif 19 | 20 | #include "debug.h" 21 | #include "linkhash.h" 22 | #include "arraylist.h" 23 | #include "json_util.h" 24 | #include "json_object.h" 25 | #include "json_tokener.h" 26 | #include "json_object_iterator.h" 27 | #include "json_c_version.h" 28 | 29 | #ifdef __cplusplus 30 | } 31 | #endif 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /c_src/json-c/json_c_version.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2012 Eric Haszlakiewicz 3 | * 4 | * This library is free software; you can redistribute it and/or modify 5 | * it under the terms of the MIT license. See COPYING for details. 6 | */ 7 | #include "config.h" 8 | 9 | #include "json_c_version.h" 10 | 11 | const char *json_c_version(void) 12 | { 13 | return JSON_C_VERSION; 14 | } 15 | 16 | int json_c_version_num(void) 17 | { 18 | return JSON_C_VERSION_NUM; 19 | } 20 | 21 | -------------------------------------------------------------------------------- /c_src/json-c/json_c_version.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2012 Eric Haszlakiewicz 3 | * 4 | * This library is free software; you can redistribute it and/or modify 5 | * it under the terms of the MIT license. See COPYING for details. 6 | */ 7 | 8 | #ifndef _json_c_version_h_ 9 | #define _json_c_version_h_ 10 | 11 | #define JSON_C_MAJOR_VERSION 0 12 | #define JSON_C_MINOR_VERSION 12 13 | #define JSON_C_MICRO_VERSION 99 14 | #define JSON_C_VERSION_NUM ((JSON_C_MAJOR_VERSION << 16) | \ 15 | (JSON_C_MINOR_VERSION << 8) | \ 16 | JSON_C_MICRO_VERSION) 17 | #define JSON_C_VERSION "0.12.99" 18 | 19 | const char *json_c_version(void); /* Returns JSON_C_VERSION */ 20 | int json_c_version_num(void); /* Returns JSON_C_VERSION_NUM */ 21 | 22 | #endif 23 | -------------------------------------------------------------------------------- /c_src/json-c/json_config.h.in: -------------------------------------------------------------------------------- 1 | 2 | /* Define to 1 if you have the header file. */ 3 | #cmakedefine JSON_C_HAVE_INTTYPES_H 1 4 | -------------------------------------------------------------------------------- /c_src/json-c/json_inttypes.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef _json_inttypes_h_ 3 | #define _json_inttypes_h_ 4 | 5 | #include "json_config.h" 6 | 7 | #ifdef JSON_C_HAVE_INTTYPES_H 8 | /* inttypes.h includes stdint.h */ 9 | #include 10 | 11 | #else 12 | #include 13 | 14 | #define PRId64 "I64d" 15 | #define SCNd64 "I64d" 16 | 17 | #endif 18 | 19 | #endif 20 | -------------------------------------------------------------------------------- /c_src/json-c/json_object_iterator.c: -------------------------------------------------------------------------------- 1 | /** 2 | ******************************************************************************* 3 | * @file json_object_iterator.c 4 | * 5 | * Copyright (c) 2009-2012 Hewlett-Packard Development Company, L.P. 6 | * 7 | * This library is free software; you can redistribute it and/or modify 8 | * it under the terms of the MIT license. See COPYING for details. 9 | * 10 | * @brief json-c forces clients to use its private data 11 | * structures for JSON Object iteration. This API 12 | * implementation corrects that by abstracting the 13 | * private json-c details. 14 | * 15 | ******************************************************************************* 16 | */ 17 | 18 | #include 19 | 20 | #include "json.h" 21 | #include "json_object_private.h" 22 | 23 | #include "json_object_iterator.h" 24 | 25 | /** 26 | * How It Works 27 | * 28 | * For each JSON Object, json-c maintains a linked list of zero 29 | * or more lh_entry (link-hash entry) structures inside the 30 | * Object's link-hash table (lh_table). 31 | * 32 | * Each lh_entry structure on the JSON Object's linked list 33 | * represents a single name/value pair. The "next" field of the 34 | * last lh_entry in the list is set to NULL, which terminates 35 | * the list. 36 | * 37 | * We represent a valid iterator that refers to an actual 38 | * name/value pair via a pointer to the pair's lh_entry 39 | * structure set as the iterator's opaque_ field. 40 | * 41 | * We follow json-c's current pair list representation by 42 | * representing a valid "end" iterator (one that refers past the 43 | * last pair) with a NULL value in the iterator's opaque_ field. 44 | * 45 | * A JSON Object without any pairs in it will have the "head" 46 | * field of its lh_table structure set to NULL. For such an 47 | * object, json_object_iter_begin will return an iterator with 48 | * the opaque_ field set to NULL, which is equivalent to the 49 | * "end" iterator. 50 | * 51 | * When iterating, we simply update the iterator's opaque_ field 52 | * to point to the next lh_entry structure in the linked list. 53 | * opaque_ will become NULL once we iterate past the last pair 54 | * in the list, which makes the iterator equivalent to the "end" 55 | * iterator. 56 | */ 57 | 58 | /// Our current representation of the "end" iterator; 59 | /// 60 | /// @note May not always be NULL 61 | static const void* kObjectEndIterValue = NULL; 62 | 63 | /** 64 | * **************************************************************************** 65 | */ 66 | struct json_object_iterator 67 | json_object_iter_begin(struct json_object* obj) 68 | { 69 | struct json_object_iterator iter; 70 | struct lh_table* pTable; 71 | 72 | /// @note json_object_get_object will return NULL if passed NULL 73 | /// or a non-json_type_object instance 74 | pTable = json_object_get_object(obj); 75 | JASSERT(NULL != pTable); 76 | 77 | /// @note For a pair-less Object, head is NULL, which matches our 78 | /// definition of the "end" iterator 79 | iter.opaque_ = pTable->head; 80 | return iter; 81 | } 82 | 83 | /** 84 | * **************************************************************************** 85 | */ 86 | struct json_object_iterator 87 | json_object_iter_end(const struct json_object* obj) 88 | { 89 | struct json_object_iterator iter; 90 | 91 | JASSERT(NULL != obj); 92 | JASSERT(json_object_is_type(obj, json_type_object)); 93 | 94 | iter.opaque_ = kObjectEndIterValue; 95 | 96 | return iter; 97 | } 98 | 99 | /** 100 | * **************************************************************************** 101 | */ 102 | void 103 | json_object_iter_next(struct json_object_iterator* iter) 104 | { 105 | JASSERT(NULL != iter); 106 | JASSERT(kObjectEndIterValue != iter->opaque_); 107 | 108 | iter->opaque_ = ((struct lh_entry *)iter->opaque_)->next; 109 | } 110 | 111 | 112 | /** 113 | * **************************************************************************** 114 | */ 115 | const char* 116 | json_object_iter_peek_name(const struct json_object_iterator* iter) 117 | { 118 | JASSERT(NULL != iter); 119 | JASSERT(kObjectEndIterValue != iter->opaque_); 120 | 121 | return (const char*)(((struct lh_entry *)iter->opaque_)->k); 122 | } 123 | 124 | 125 | /** 126 | * **************************************************************************** 127 | */ 128 | struct json_object* 129 | json_object_iter_peek_value(const struct json_object_iterator* iter) 130 | { 131 | JASSERT(NULL != iter); 132 | JASSERT(kObjectEndIterValue != iter->opaque_); 133 | 134 | return (struct json_object*)(((struct lh_entry *)iter->opaque_)->v); 135 | } 136 | 137 | 138 | /** 139 | * **************************************************************************** 140 | */ 141 | json_bool 142 | json_object_iter_equal(const struct json_object_iterator* iter1, 143 | const struct json_object_iterator* iter2) 144 | { 145 | JASSERT(NULL != iter1); 146 | JASSERT(NULL != iter2); 147 | 148 | return (iter1->opaque_ == iter2->opaque_); 149 | } 150 | 151 | 152 | /** 153 | * **************************************************************************** 154 | */ 155 | struct json_object_iterator 156 | json_object_iter_init_default(void) 157 | { 158 | struct json_object_iterator iter; 159 | 160 | /** 161 | * @note Make this a negative, invalid value, such that 162 | * accidental access to it would likely be trapped by the 163 | * hardware as an invalid address. 164 | */ 165 | iter.opaque_ = NULL; 166 | 167 | return iter; 168 | } 169 | -------------------------------------------------------------------------------- /c_src/json-c/json_object_iterator.h: -------------------------------------------------------------------------------- 1 | /** 2 | ******************************************************************************* 3 | * @file json_object_iterator.h 4 | * 5 | * Copyright (c) 2009-2012 Hewlett-Packard Development Company, L.P. 6 | * 7 | * This library is free software; you can redistribute it and/or modify 8 | * it under the terms of the MIT license. See COPYING for details. 9 | * 10 | * @brief json-c forces clients to use its private data 11 | * structures for JSON Object iteration. This API 12 | * corrects that by abstracting the private json-c 13 | * details. 14 | * 15 | * API attributes:
16 | * * Thread-safe: NO
17 | * * Reentrant: NO 18 | * 19 | ******************************************************************************* 20 | */ 21 | 22 | 23 | #ifndef JSON_OBJECT_ITERATOR_H 24 | #define JSON_OBJECT_ITERATOR_H 25 | 26 | #include 27 | 28 | #ifdef __cplusplus 29 | extern "C" { 30 | #endif 31 | 32 | /** 33 | * Forward declaration for the opaque iterator information. 34 | */ 35 | struct json_object_iter_info_; 36 | 37 | /** 38 | * The opaque iterator that references a name/value pair within 39 | * a JSON Object instance or the "end" iterator value. 40 | */ 41 | struct json_object_iterator { 42 | const void* opaque_; 43 | }; 44 | 45 | 46 | /** 47 | * forward declaration of json-c's JSON value instance structure 48 | */ 49 | struct json_object; 50 | 51 | 52 | /** 53 | * Initializes an iterator structure to a "default" value that 54 | * is convenient for initializing an iterator variable to a 55 | * default state (e.g., initialization list in a class' 56 | * constructor). 57 | * 58 | * @code 59 | * struct json_object_iterator iter = json_object_iter_init_default(); 60 | * MyClass() : iter_(json_object_iter_init_default()) 61 | * @endcode 62 | * 63 | * @note The initialized value doesn't reference any specific 64 | * pair, is considered an invalid iterator, and MUST NOT 65 | * be passed to any json-c API that expects a valid 66 | * iterator. 67 | * 68 | * @note User and internal code MUST NOT make any assumptions 69 | * about and dependencies on the value of the "default" 70 | * iterator value. 71 | * 72 | * @return json_object_iterator 73 | */ 74 | struct json_object_iterator 75 | json_object_iter_init_default(void); 76 | 77 | /** Retrieves an iterator to the first pair of the JSON Object. 78 | * 79 | * @warning Any modification of the underlying pair invalidates all 80 | * iterators to that pair. 81 | * 82 | * @param obj JSON Object instance (MUST be of type json_object) 83 | * 84 | * @return json_object_iterator If the JSON Object has at 85 | * least one pair, on return, the iterator refers 86 | * to the first pair. If the JSON Object doesn't 87 | * have any pairs, the returned iterator is 88 | * equivalent to the "end" iterator for the same 89 | * JSON Object instance. 90 | * 91 | * @code 92 | * struct json_object_iterator it; 93 | * struct json_object_iterator itEnd; 94 | * struct json_object* obj; 95 | * 96 | * obj = json_tokener_parse("{'first':'george', 'age':100}"); 97 | * it = json_object_iter_begin(obj); 98 | * itEnd = json_object_iter_end(obj); 99 | * 100 | * while (!json_object_iter_equal(&it, &itEnd)) { 101 | * printf("%s\n", 102 | * json_object_iter_peek_name(&it)); 103 | * json_object_iter_next(&it); 104 | * } 105 | * 106 | * @endcode 107 | */ 108 | struct json_object_iterator 109 | json_object_iter_begin(struct json_object* obj); 110 | 111 | /** Retrieves the iterator that represents the position beyond the 112 | * last pair of the given JSON Object instance. 113 | * 114 | * @warning Do NOT write code that assumes that the "end" 115 | * iterator value is NULL, even if it is so in a 116 | * particular instance of the implementation. 117 | * 118 | * @note The reason we do not (and MUST NOT) provide 119 | * "json_object_iter_is_end(json_object_iterator* iter)" 120 | * type of API is because it would limit the underlying 121 | * representation of name/value containment (or force us 122 | * to add additional, otherwise unnecessary, fields to 123 | * the iterator structure). The "end" iterator and the 124 | * equality test method, on the other hand, permit us to 125 | * cleanly abstract pretty much any reasonable underlying 126 | * representation without burdening the iterator 127 | * structure with unnecessary data. 128 | * 129 | * @note For performance reasons, memorize the "end" iterator prior 130 | * to any loop. 131 | * 132 | * @param obj JSON Object instance (MUST be of type json_object) 133 | * 134 | * @return json_object_iterator On return, the iterator refers 135 | * to the "end" of the Object instance's pairs 136 | * (i.e., NOT the last pair, but "beyond the last 137 | * pair" value) 138 | */ 139 | struct json_object_iterator 140 | json_object_iter_end(const struct json_object* obj); 141 | 142 | /** Returns an iterator to the next pair, if any 143 | * 144 | * @warning Any modification of the underlying pair 145 | * invalidates all iterators to that pair. 146 | * 147 | * @param iter [IN/OUT] Pointer to iterator that references a 148 | * name/value pair; MUST be a valid, non-end iterator. 149 | * WARNING: bad things will happen if invalid or "end" 150 | * iterator is passed. Upon return will contain the 151 | * reference to the next pair if there is one; if there 152 | * are no more pairs, will contain the "end" iterator 153 | * value, which may be compared against the return value 154 | * of json_object_iter_end() for the same JSON Object 155 | * instance. 156 | */ 157 | void 158 | json_object_iter_next(struct json_object_iterator* iter); 159 | 160 | 161 | /** Returns a const pointer to the name of the pair referenced 162 | * by the given iterator. 163 | * 164 | * @param iter pointer to iterator that references a name/value 165 | * pair; MUST be a valid, non-end iterator. 166 | * 167 | * @warning bad things will happen if an invalid or 168 | * "end" iterator is passed. 169 | * 170 | * @return const char* Pointer to the name of the referenced 171 | * name/value pair. The name memory belongs to the 172 | * name/value pair, will be freed when the pair is 173 | * deleted or modified, and MUST NOT be modified or 174 | * freed by the user. 175 | */ 176 | const char* 177 | json_object_iter_peek_name(const struct json_object_iterator* iter); 178 | 179 | 180 | /** Returns a pointer to the json-c instance representing the 181 | * value of the referenced name/value pair, without altering 182 | * the instance's reference count. 183 | * 184 | * @param iter pointer to iterator that references a name/value 185 | * pair; MUST be a valid, non-end iterator. 186 | * 187 | * @warning bad things will happen if invalid or 188 | * "end" iterator is passed. 189 | * 190 | * @return struct json_object* Pointer to the json-c value 191 | * instance of the referenced name/value pair; the 192 | * value's reference count is not changed by this 193 | * function: if you plan to hold on to this json-c node, 194 | * take a look at json_object_get() and 195 | * json_object_put(). IMPORTANT: json-c API represents 196 | * the JSON Null value as a NULL json_object instance 197 | * pointer. 198 | */ 199 | struct json_object* 200 | json_object_iter_peek_value(const struct json_object_iterator* iter); 201 | 202 | 203 | /** Tests two iterators for equality. Typically used to test 204 | * for end of iteration by comparing an iterator to the 205 | * corresponding "end" iterator (that was derived from the same 206 | * JSON Object instance). 207 | * 208 | * @note The reason we do not (and MUST NOT) provide 209 | * "json_object_iter_is_end(json_object_iterator* iter)" 210 | * type of API is because it would limit the underlying 211 | * representation of name/value containment (or force us 212 | * to add additional, otherwise unnecessary, fields to 213 | * the iterator structure). The equality test method, on 214 | * the other hand, permits us to cleanly abstract pretty 215 | * much any reasonable underlying representation. 216 | * 217 | * @param iter1 Pointer to first valid, non-NULL iterator 218 | * @param iter2 POinter to second valid, non-NULL iterator 219 | * 220 | * @warning if a NULL iterator pointer or an uninitialized 221 | * or invalid iterator, or iterators derived from 222 | * different JSON Object instances are passed, bad things 223 | * will happen! 224 | * 225 | * @return json_bool non-zero if iterators are equal (i.e., both 226 | * reference the same name/value pair or are both at 227 | * "end"); zero if they are not equal. 228 | */ 229 | json_bool 230 | json_object_iter_equal(const struct json_object_iterator* iter1, 231 | const struct json_object_iterator* iter2); 232 | 233 | 234 | #ifdef __cplusplus 235 | } 236 | #endif 237 | 238 | 239 | #endif /* JSON_OBJECT_ITERATOR_H */ 240 | -------------------------------------------------------------------------------- /c_src/json-c/json_object_private.h: -------------------------------------------------------------------------------- 1 | /* 2 | * $Id: json_object_private.h,v 1.4 2006/01/26 02:16:28 mclark Exp $ 3 | * 4 | * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. 5 | * Michael Clark 6 | * 7 | * This library is free software; you can redistribute it and/or modify 8 | * it under the terms of the MIT license. See COPYING for details. 9 | * 10 | */ 11 | 12 | #ifndef _json_object_private_h_ 13 | #define _json_object_private_h_ 14 | 15 | #ifdef __cplusplus 16 | extern "C" { 17 | #endif 18 | 19 | #define LEN_DIRECT_STRING_DATA 32 /**< how many bytes are directly stored in json_object for strings? */ 20 | 21 | typedef void (json_object_private_delete_fn)(struct json_object *o); 22 | 23 | struct json_object 24 | { 25 | enum json_type o_type; 26 | json_object_private_delete_fn *_delete; 27 | json_object_to_json_string_fn *_to_json_string; 28 | int _ref_count; 29 | struct printbuf *_pb; 30 | union data { 31 | json_bool c_boolean; 32 | double c_double; 33 | int64_t c_int64; 34 | struct lh_table *c_object; 35 | struct array_list *c_array; 36 | struct { 37 | union { 38 | /* optimize: if we have small strings, we can store them 39 | * directly. This saves considerable CPU cycles AND memory. 40 | */ 41 | char *ptr; 42 | char data[LEN_DIRECT_STRING_DATA]; 43 | } str; 44 | int len; 45 | } c_string; 46 | } o; 47 | json_object_delete_fn *_user_delete; 48 | void *_userdata; 49 | }; 50 | 51 | #ifdef __cplusplus 52 | } 53 | #endif 54 | 55 | #endif 56 | -------------------------------------------------------------------------------- /c_src/json-c/json_tokener.h: -------------------------------------------------------------------------------- 1 | /* 2 | * $Id: json_tokener.h,v 1.10 2006/07/25 03:24:50 mclark Exp $ 3 | * 4 | * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. 5 | * Michael Clark 6 | * 7 | * This library is free software; you can redistribute it and/or modify 8 | * it under the terms of the MIT license. See COPYING for details. 9 | * 10 | */ 11 | 12 | #ifndef _json_tokener_h_ 13 | #define _json_tokener_h_ 14 | 15 | #include 16 | #include "json_object.h" 17 | 18 | #ifdef __cplusplus 19 | extern "C" { 20 | #endif 21 | 22 | enum json_tokener_error { 23 | json_tokener_success, 24 | json_tokener_continue, 25 | json_tokener_error_depth, 26 | json_tokener_error_parse_eof, 27 | json_tokener_error_parse_unexpected, 28 | json_tokener_error_parse_null, 29 | json_tokener_error_parse_boolean, 30 | json_tokener_error_parse_number, 31 | json_tokener_error_parse_array, 32 | json_tokener_error_parse_object_key_name, 33 | json_tokener_error_parse_object_key_sep, 34 | json_tokener_error_parse_object_value_sep, 35 | json_tokener_error_parse_string, 36 | json_tokener_error_parse_comment, 37 | json_tokener_error_size 38 | }; 39 | 40 | enum json_tokener_state { 41 | json_tokener_state_eatws, 42 | json_tokener_state_start, 43 | json_tokener_state_finish, 44 | json_tokener_state_null, 45 | json_tokener_state_comment_start, 46 | json_tokener_state_comment, 47 | json_tokener_state_comment_eol, 48 | json_tokener_state_comment_end, 49 | json_tokener_state_string, 50 | json_tokener_state_string_escape, 51 | json_tokener_state_escape_unicode, 52 | json_tokener_state_boolean, 53 | json_tokener_state_number, 54 | json_tokener_state_array, 55 | json_tokener_state_array_add, 56 | json_tokener_state_array_sep, 57 | json_tokener_state_object_field_start, 58 | json_tokener_state_object_field, 59 | json_tokener_state_object_field_end, 60 | json_tokener_state_object_value, 61 | json_tokener_state_object_value_add, 62 | json_tokener_state_object_sep, 63 | json_tokener_state_array_after_sep, 64 | json_tokener_state_object_field_start_after_sep, 65 | json_tokener_state_inf 66 | }; 67 | 68 | struct json_tokener_srec 69 | { 70 | enum json_tokener_state state, saved_state; 71 | struct json_object *obj; 72 | struct json_object *current; 73 | char *obj_field_name; 74 | }; 75 | 76 | #define JSON_TOKENER_DEFAULT_DEPTH 32 77 | 78 | struct json_tokener 79 | { 80 | char *str; 81 | struct printbuf *pb; 82 | int max_depth, depth, is_double, st_pos, char_offset; 83 | enum json_tokener_error err; 84 | unsigned int ucs_char; 85 | char quote_char; 86 | struct json_tokener_srec *stack; 87 | int flags; 88 | }; 89 | 90 | /** 91 | * Be strict when parsing JSON input. Use caution with 92 | * this flag as what is considered valid may become more 93 | * restrictive from one release to the next, causing your 94 | * code to fail on previously working input. 95 | * 96 | * This flag is not set by default. 97 | * 98 | * @see json_tokener_set_flags() 99 | */ 100 | #define JSON_TOKENER_STRICT 0x01 101 | 102 | /** 103 | * Given an error previously returned by json_tokener_get_error(), 104 | * return a human readable description of the error. 105 | * 106 | * @return a generic error message is returned if an invalid error value is provided. 107 | */ 108 | const char *json_tokener_error_desc(enum json_tokener_error jerr); 109 | 110 | /** 111 | * Retrieve the error caused by the last call to json_tokener_parse_ex(), 112 | * or json_tokener_success if there is no error. 113 | * 114 | * When parsing a JSON string in pieces, if the tokener is in the middle 115 | * of parsing this will return json_tokener_continue. 116 | * 117 | * See also json_tokener_error_desc(). 118 | */ 119 | enum json_tokener_error json_tokener_get_error(struct json_tokener *tok); 120 | 121 | extern struct json_tokener* json_tokener_new(void); 122 | extern struct json_tokener* json_tokener_new_ex(int depth); 123 | extern void json_tokener_free(struct json_tokener *tok); 124 | extern void json_tokener_reset(struct json_tokener *tok); 125 | extern struct json_object* json_tokener_parse(const char *str); 126 | extern struct json_object* json_tokener_parse_verbose(const char *str, enum json_tokener_error *error); 127 | 128 | /** 129 | * Set flags that control how parsing will be done. 130 | */ 131 | extern void json_tokener_set_flags(struct json_tokener *tok, int flags); 132 | 133 | /** 134 | * Parse a string and return a non-NULL json_object if a valid JSON value 135 | * is found. The string does not need to be a JSON object or array; 136 | * it can also be a string, number or boolean value. 137 | * 138 | * A partial JSON string can be parsed. If the parsing is incomplete, 139 | * NULL will be returned and json_tokener_get_error() will be return 140 | * json_tokener_continue. 141 | * json_tokener_parse_ex() can then be called with additional bytes in str 142 | * to continue the parsing. 143 | * 144 | * If json_tokener_parse_ex() returns NULL and the error anything other than 145 | * json_tokener_continue, a fatal error has occurred and parsing must be 146 | * halted. Then tok object must not be re-used until json_tokener_reset() is 147 | * called. 148 | * 149 | * When a valid JSON value is parsed, a non-NULL json_object will be 150 | * returned. Also, json_tokener_get_error() will return json_tokener_success. 151 | * Be sure to check the type with json_object_is_type() or 152 | * json_object_get_type() before using the object. 153 | * 154 | * @b XXX this shouldn't use internal fields: 155 | * Trailing characters after the parsed value do not automatically cause an 156 | * error. It is up to the caller to decide whether to treat this as an 157 | * error or to handle the additional characters, perhaps by parsing another 158 | * json value starting from that point. 159 | * 160 | * Extra characters can be detected by comparing the tok->char_offset against 161 | * the length of the last len parameter passed in. 162 | * 163 | * The tokener does \b not maintain an internal buffer so the caller is 164 | * responsible for calling json_tokener_parse_ex with an appropriate str 165 | * parameter starting with the extra characters. 166 | * 167 | * This interface is presently not 64-bit clean due to the int len argument 168 | * so the function limits the maximum string size to INT32_MAX (2GB). 169 | * If the function is called with len == -1 then strlen is called to check 170 | * the string length is less than INT32_MAX (2GB) 171 | * 172 | * Example: 173 | * @code 174 | json_object *jobj = NULL; 175 | const char *mystring = NULL; 176 | int stringlen = 0; 177 | enum json_tokener_error jerr; 178 | do { 179 | mystring = ... // get JSON string, e.g. read from file, etc... 180 | stringlen = strlen(mystring); 181 | jobj = json_tokener_parse_ex(tok, mystring, stringlen); 182 | } while ((jerr = json_tokener_get_error(tok)) == json_tokener_continue); 183 | if (jerr != json_tokener_success) 184 | { 185 | fprintf(stderr, "Error: %s\n", json_tokener_error_desc(jerr)); 186 | // Handle errors, as appropriate for your application. 187 | } 188 | if (tok->char_offset < stringlen) // XXX shouldn't access internal fields 189 | { 190 | // Handle extra characters after parsed object as desired. 191 | // e.g. issue an error, parse another object from that point, etc... 192 | } 193 | // Success, use jobj here. 194 | 195 | @endcode 196 | * 197 | * @param tok a json_tokener previously allocated with json_tokener_new() 198 | * @param str an string with any valid JSON expression, or portion of. This does not need to be null terminated. 199 | * @param len the length of str 200 | */ 201 | extern struct json_object* json_tokener_parse_ex(struct json_tokener *tok, 202 | const char *str, int len); 203 | 204 | #ifdef __cplusplus 205 | } 206 | #endif 207 | 208 | #endif 209 | -------------------------------------------------------------------------------- /c_src/json-c/json_util.c: -------------------------------------------------------------------------------- 1 | /* 2 | * $Id: json_util.c,v 1.4 2006/01/30 23:07:57 mclark Exp $ 3 | * 4 | * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. 5 | * Michael Clark 6 | * 7 | * This library is free software; you can redistribute it and/or modify 8 | * it under the terms of the MIT license. See COPYING for details. 9 | * 10 | */ 11 | 12 | #include "config.h" 13 | #undef realloc 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | #ifdef HAVE_SYS_TYPES_H 24 | #include 25 | #endif /* HAVE_SYS_TYPES_H */ 26 | 27 | #ifdef HAVE_SYS_STAT_H 28 | #include 29 | #endif /* HAVE_SYS_STAT_H */ 30 | 31 | #ifdef HAVE_FCNTL_H 32 | #include 33 | #endif /* HAVE_FCNTL_H */ 34 | 35 | #ifdef HAVE_UNISTD_H 36 | # include 37 | #endif /* HAVE_UNISTD_H */ 38 | 39 | #ifdef WIN32 40 | # define WIN32_LEAN_AND_MEAN 41 | # include 42 | # include 43 | #endif /* defined(WIN32) */ 44 | 45 | #if !defined(HAVE_OPEN) && defined(WIN32) 46 | # define open _open 47 | #endif 48 | 49 | #if !defined(HAVE_SNPRINTF) && defined(_MSC_VER) 50 | /* MSC has the version as _snprintf */ 51 | # define snprintf _snprintf 52 | #elif !defined(HAVE_SNPRINTF) 53 | # error You do not have snprintf on your system. 54 | #endif /* HAVE_SNPRINTF */ 55 | 56 | #include "debug.h" 57 | #include "printbuf.h" 58 | #include "json_inttypes.h" 59 | #include "json_object.h" 60 | #include "json_tokener.h" 61 | #include "json_util.h" 62 | 63 | static int sscanf_is_broken = 0; 64 | static int sscanf_is_broken_testdone = 0; 65 | static void sscanf_is_broken_test(void); 66 | 67 | /* 68 | * Create a JSON object from already opened file descriptor. 69 | * 70 | * This function can be helpful, when you opened the file already, 71 | * e.g. when you have a temp file. 72 | * Note, that the fd must be readable at the actual position, i.e. 73 | * use lseek(fd, 0, SEEK_SET) before. 74 | */ 75 | struct json_object* json_object_from_fd(int fd) 76 | { 77 | struct printbuf *pb; 78 | struct json_object *obj; 79 | char buf[JSON_FILE_BUF_SIZE]; 80 | int ret; 81 | 82 | if(!(pb = printbuf_new())) { 83 | MC_ERROR("json_object_from_file: printbuf_new failed\n"); 84 | return NULL; 85 | } 86 | while((ret = read(fd, buf, JSON_FILE_BUF_SIZE)) > 0) { 87 | printbuf_memappend(pb, buf, ret); 88 | } 89 | if(ret < 0) { 90 | MC_ERROR("json_object_from_fd: error reading fd %d: %s\n", fd, strerror(errno)); 91 | printbuf_free(pb); 92 | return NULL; 93 | } 94 | obj = json_tokener_parse(pb->buf); 95 | printbuf_free(pb); 96 | return obj; 97 | } 98 | 99 | struct json_object* json_object_from_file(const char *filename) 100 | { 101 | struct json_object *obj; 102 | int fd; 103 | 104 | if((fd = open(filename, O_RDONLY)) < 0) { 105 | MC_ERROR("json_object_from_file: error opening file %s: %s\n", 106 | filename, strerror(errno)); 107 | return NULL; 108 | } 109 | obj = json_object_from_fd(fd); 110 | close(fd); 111 | return obj; 112 | } 113 | 114 | /* extended "format and write to file" function */ 115 | 116 | int json_object_to_file_ext(const char *filename, struct json_object *obj, int flags) 117 | { 118 | const char *json_str; 119 | int fd, ret; 120 | unsigned int wpos, wsize; 121 | 122 | if(!obj) { 123 | MC_ERROR("json_object_to_file: object is null\n"); 124 | return -1; 125 | } 126 | 127 | if((fd = open(filename, O_WRONLY | O_TRUNC | O_CREAT, 0644)) < 0) { 128 | MC_ERROR("json_object_to_file: error opening file %s: %s\n", 129 | filename, strerror(errno)); 130 | return -1; 131 | } 132 | 133 | if(!(json_str = json_object_to_json_string_ext(obj,flags))) { 134 | close(fd); 135 | return -1; 136 | } 137 | 138 | wsize = (unsigned int)(strlen(json_str) & UINT_MAX); /* CAW: probably unnecessary, but the most 64bit safe */ 139 | wpos = 0; 140 | while(wpos < wsize) { 141 | if((ret = write(fd, json_str + wpos, wsize-wpos)) < 0) { 142 | close(fd); 143 | MC_ERROR("json_object_to_file: error writing file %s: %s\n", 144 | filename, strerror(errno)); 145 | return -1; 146 | } 147 | 148 | /* because of the above check for ret < 0, we can safely cast and add */ 149 | wpos += (unsigned int)ret; 150 | } 151 | 152 | close(fd); 153 | return 0; 154 | } 155 | 156 | // backwards compatible "format and write to file" function 157 | 158 | int json_object_to_file(const char *filename, struct json_object *obj) 159 | { 160 | return json_object_to_file_ext(filename, obj, JSON_C_TO_STRING_PLAIN); 161 | } 162 | 163 | int json_parse_double(const char *buf, double *retval) 164 | { 165 | return (sscanf(buf, "%lf", retval)==1 ? 0 : 1); 166 | } 167 | 168 | /* 169 | * Not all implementations of sscanf actually work properly. 170 | * Check whether the one we're currently using does, and if 171 | * it's broken, enable the workaround code. 172 | */ 173 | static void sscanf_is_broken_test() 174 | { 175 | int64_t num64; 176 | int ret_errno, is_int64_min, ret_errno2, is_int64_max; 177 | 178 | (void)sscanf(" -01234567890123456789012345", "%" SCNd64, &num64); 179 | ret_errno = errno; 180 | is_int64_min = (num64 == INT64_MIN); 181 | 182 | (void)sscanf(" 01234567890123456789012345", "%" SCNd64, &num64); 183 | ret_errno2 = errno; 184 | is_int64_max = (num64 == INT64_MAX); 185 | 186 | if (ret_errno != ERANGE || !is_int64_min || 187 | ret_errno2 != ERANGE || !is_int64_max) 188 | { 189 | MC_DEBUG("sscanf_is_broken_test failed, enabling workaround code\n"); 190 | sscanf_is_broken = 1; 191 | } 192 | } 193 | 194 | int json_parse_int64(const char *buf, int64_t *retval) 195 | { 196 | int64_t num64; 197 | const char *buf_sig_digits; 198 | int orig_has_neg; 199 | int saved_errno; 200 | 201 | if (!sscanf_is_broken_testdone) 202 | { 203 | sscanf_is_broken_test(); 204 | sscanf_is_broken_testdone = 1; 205 | } 206 | 207 | // Skip leading spaces 208 | while (isspace((int)*buf) && *buf) 209 | buf++; 210 | 211 | errno = 0; // sscanf won't always set errno, so initialize 212 | if (sscanf(buf, "%" SCNd64, &num64) != 1) 213 | { 214 | MC_DEBUG("Failed to parse, sscanf != 1\n"); 215 | return 1; 216 | } 217 | 218 | saved_errno = errno; 219 | buf_sig_digits = buf; 220 | orig_has_neg = 0; 221 | if (*buf_sig_digits == '-') 222 | { 223 | buf_sig_digits++; 224 | orig_has_neg = 1; 225 | } 226 | 227 | // Not all sscanf implementations actually work 228 | if (sscanf_is_broken && saved_errno != ERANGE) 229 | { 230 | char buf_cmp[100]; 231 | char *buf_cmp_start = buf_cmp; 232 | int recheck_has_neg = 0; 233 | int buf_cmp_len; 234 | 235 | // Skip leading zeros, but keep at least one digit 236 | while (buf_sig_digits[0] == '0' && buf_sig_digits[1] != '\0') 237 | buf_sig_digits++; 238 | if (num64 == 0) // assume all sscanf impl's will parse -0 to 0 239 | orig_has_neg = 0; // "-0" is the same as just plain "0" 240 | 241 | snprintf(buf_cmp_start, sizeof(buf_cmp), "%" PRId64, num64); 242 | if (*buf_cmp_start == '-') 243 | { 244 | recheck_has_neg = 1; 245 | buf_cmp_start++; 246 | } 247 | // No need to skip leading spaces or zeros here. 248 | 249 | buf_cmp_len = strlen(buf_cmp_start); 250 | /** 251 | * If the sign is different, or 252 | * some of the digits are different, or 253 | * there is another digit present in the original string 254 | * then we have NOT successfully parsed the value. 255 | */ 256 | if (orig_has_neg != recheck_has_neg || 257 | strncmp(buf_sig_digits, buf_cmp_start, strlen(buf_cmp_start)) != 0 || 258 | ((int)strlen(buf_sig_digits) != buf_cmp_len && 259 | isdigit((int)buf_sig_digits[buf_cmp_len]) 260 | ) 261 | ) 262 | { 263 | saved_errno = ERANGE; 264 | } 265 | } 266 | 267 | // Not all sscanf impl's set the value properly when out of range. 268 | // Always do this, even for properly functioning implementations, 269 | // since it shouldn't slow things down much. 270 | if (saved_errno == ERANGE) 271 | { 272 | if (orig_has_neg) 273 | num64 = INT64_MIN; 274 | else 275 | num64 = INT64_MAX; 276 | } 277 | *retval = num64; 278 | return 0; 279 | } 280 | 281 | #ifndef HAVE_REALLOC 282 | void* rpl_realloc(void* p, size_t n) 283 | { 284 | if (n == 0) 285 | n = 1; 286 | if (p == 0) 287 | return malloc(n); 288 | return realloc(p, n); 289 | } 290 | #endif 291 | 292 | #define NELEM(a) (sizeof(a) / sizeof(a[0])) 293 | static const char* json_type_name[] = { 294 | /* If you change this, be sure to update the enum json_type definition too */ 295 | "null", 296 | "boolean", 297 | "double", 298 | "int", 299 | "object", 300 | "array", 301 | "string", 302 | }; 303 | 304 | const char *json_type_to_name(enum json_type o_type) 305 | { 306 | int o_type_int = (int)o_type; 307 | if (o_type_int < 0 || o_type_int >= (int)NELEM(json_type_name)) 308 | { 309 | MC_ERROR("json_type_to_name: type %d is out of range [0,%d]\n", o_type, NELEM(json_type_name)); 310 | return NULL; 311 | } 312 | return json_type_name[o_type]; 313 | } 314 | 315 | -------------------------------------------------------------------------------- /c_src/json-c/json_util.h: -------------------------------------------------------------------------------- 1 | /* 2 | * $Id: json_util.h,v 1.4 2006/01/30 23:07:57 mclark Exp $ 3 | * 4 | * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. 5 | * Michael Clark 6 | * 7 | * This library is free software; you can redistribute it and/or modify 8 | * it under the terms of the MIT license. See COPYING for details. 9 | * 10 | */ 11 | 12 | #ifndef _json_util_h_ 13 | #define _json_util_h_ 14 | 15 | #include "json_object.h" 16 | 17 | #ifndef json_min 18 | #define json_min(a,b) ((a) < (b) ? (a) : (b)) 19 | #endif 20 | 21 | #ifndef json_max 22 | #define json_max(a,b) ((a) > (b) ? (a) : (b)) 23 | #endif 24 | 25 | 26 | #ifdef __cplusplus 27 | extern "C" { 28 | #endif 29 | 30 | #define JSON_FILE_BUF_SIZE 4096 31 | 32 | /* utility functions */ 33 | extern struct json_object* json_object_from_file(const char *filename); 34 | extern struct json_object* json_object_from_fd(int fd); 35 | extern int json_object_to_file(const char *filename, struct json_object *obj); 36 | extern int json_object_to_file_ext(const char *filename, struct json_object *obj, int flags); 37 | extern int json_parse_int64(const char *buf, int64_t *retval); 38 | extern int json_parse_double(const char *buf, double *retval); 39 | 40 | 41 | /** 42 | * Return a string describing the type of the object. 43 | * e.g. "int", or "object", etc... 44 | */ 45 | extern const char *json_type_to_name(enum json_type o_type); 46 | 47 | #ifdef __cplusplus 48 | } 49 | #endif 50 | 51 | #endif 52 | -------------------------------------------------------------------------------- /c_src/json-c/libjson.c: -------------------------------------------------------------------------------- 1 | 2 | /* dummy source file for compatibility purposes */ 3 | 4 | #if defined(HAVE_CDEFS_H) 5 | #include 6 | #endif 7 | 8 | #ifndef __warn_references 9 | 10 | #if defined(__GNUC__) && defined (HAS_GNU_WARNING_LONG) 11 | 12 | #define __warn_references(sym,msg) \ 13 | __asm__(".section .gnu" #sym ",\n\t.ascii \"" msg "\"\n\t.text"); 14 | 15 | #else 16 | #define __warn_references(sym,msg) /* nothing */ 17 | #endif 18 | 19 | #endif 20 | 21 | #include "json_object.h" 22 | 23 | __warn_references(json_object_get, "Warning: please link against libjson-c instead of libjson"); 24 | 25 | /* __asm__(".section .gnu.warning." __STRING(sym) \ 26 | " ; .ascii \"" msg "\" ; .text") */ 27 | -------------------------------------------------------------------------------- /c_src/json-c/linkhash.h: -------------------------------------------------------------------------------- 1 | /* 2 | * $Id: linkhash.h,v 1.6 2006/01/30 23:07:57 mclark Exp $ 3 | * 4 | * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. 5 | * Michael Clark 6 | * Copyright (c) 2009 Hewlett-Packard Development Company, L.P. 7 | * 8 | * This library is free software; you can redistribute it and/or modify 9 | * it under the terms of the MIT license. See COPYING for details. 10 | * 11 | */ 12 | 13 | #ifndef _linkhash_h_ 14 | #define _linkhash_h_ 15 | 16 | #include "json_object.h" 17 | 18 | #ifdef __cplusplus 19 | extern "C" { 20 | #endif 21 | 22 | /** 23 | * golden prime used in hash functions 24 | */ 25 | #define LH_PRIME 0x9e370001UL 26 | 27 | /** 28 | * The fraction of filled hash buckets until an insert will cause the table 29 | * to be resized. 30 | * This can range from just above 0 up to 1.0. 31 | */ 32 | #define LH_LOAD_FACTOR 0.66 33 | 34 | /** 35 | * sentinel pointer value for empty slots 36 | */ 37 | #define LH_EMPTY (void*)-1 38 | 39 | /** 40 | * sentinel pointer value for freed slots 41 | */ 42 | #define LH_FREED (void*)-2 43 | 44 | /** 45 | * default string hash function 46 | */ 47 | #define JSON_C_STR_HASH_DFLT 0 48 | 49 | /** 50 | * perl-like string hash function 51 | */ 52 | #define JSON_C_STR_HASH_PERLLIKE 1 53 | 54 | /** 55 | * This function sets the hash function to be used for strings. 56 | * Must be one of the JSON_C_STR_HASH_* values. 57 | * @returns 0 - ok, -1 if parameter was invalid 58 | */ 59 | int json_global_set_string_hash(const int h); 60 | 61 | struct lh_entry; 62 | 63 | /** 64 | * callback function prototypes 65 | */ 66 | typedef void (lh_entry_free_fn) (struct lh_entry *e); 67 | /** 68 | * callback function prototypes 69 | */ 70 | typedef unsigned long (lh_hash_fn) (const void *k); 71 | /** 72 | * callback function prototypes 73 | */ 74 | typedef int (lh_equal_fn) (const void *k1, const void *k2); 75 | 76 | /** 77 | * An entry in the hash table 78 | */ 79 | struct lh_entry { 80 | /** 81 | * The key. 82 | */ 83 | void *k; 84 | int k_is_constant; 85 | /** 86 | * The value. 87 | */ 88 | const void *v; 89 | /** 90 | * The next entry 91 | */ 92 | struct lh_entry *next; 93 | /** 94 | * The previous entry. 95 | */ 96 | struct lh_entry *prev; 97 | }; 98 | 99 | 100 | /** 101 | * The hash table structure. 102 | */ 103 | struct lh_table { 104 | /** 105 | * Size of our hash. 106 | */ 107 | int size; 108 | /** 109 | * Numbers of entries. 110 | */ 111 | int count; 112 | 113 | /** 114 | * The first entry. 115 | */ 116 | struct lh_entry *head; 117 | 118 | /** 119 | * The last entry. 120 | */ 121 | struct lh_entry *tail; 122 | 123 | struct lh_entry *table; 124 | 125 | /** 126 | * A pointer onto the function responsible for freeing an entry. 127 | */ 128 | lh_entry_free_fn *free_fn; 129 | lh_hash_fn *hash_fn; 130 | lh_equal_fn *equal_fn; 131 | }; 132 | 133 | 134 | /** 135 | * Convenience list iterator. 136 | */ 137 | #define lh_foreach(table, entry) \ 138 | for(entry = table->head; entry; entry = entry->next) 139 | 140 | /** 141 | * lh_foreach_safe allows calling of deletion routine while iterating. 142 | */ 143 | #define lh_foreach_safe(table, entry, tmp) \ 144 | for(entry = table->head; entry && ((tmp = entry->next) || 1); entry = tmp) 145 | 146 | 147 | 148 | /** 149 | * Create a new linkhash table. 150 | * @param size initial table size. The table is automatically resized 151 | * although this incurs a performance penalty. 152 | * @param free_fn callback function used to free memory for entries 153 | * when lh_table_free or lh_table_delete is called. 154 | * If NULL is provided, then memory for keys and values 155 | * must be freed by the caller. 156 | * @param hash_fn function used to hash keys. 2 standard ones are defined: 157 | * lh_ptr_hash and lh_char_hash for hashing pointer values 158 | * and C strings respectively. 159 | * @param equal_fn comparison function to compare keys. 2 standard ones defined: 160 | * lh_ptr_hash and lh_char_hash for comparing pointer values 161 | * and C strings respectively. 162 | * @return a pointer onto the linkhash table. 163 | */ 164 | extern struct lh_table* lh_table_new(int size, 165 | lh_entry_free_fn *free_fn, 166 | lh_hash_fn *hash_fn, 167 | lh_equal_fn *equal_fn); 168 | 169 | /** 170 | * Convenience function to create a new linkhash 171 | * table with char keys. 172 | * @param size initial table size. 173 | * @param name table name. 174 | * @param free_fn callback function used to free memory for entries. 175 | * @return a pointer onto the linkhash table. 176 | */ 177 | extern struct lh_table* lh_kchar_table_new(int size, 178 | lh_entry_free_fn *free_fn); 179 | 180 | 181 | /** 182 | * Convenience function to create a new linkhash 183 | * table with ptr keys. 184 | * @param size initial table size. 185 | * @param name table name. 186 | * @param free_fn callback function used to free memory for entries. 187 | * @return a pointer onto the linkhash table. 188 | */ 189 | extern struct lh_table* lh_kptr_table_new(int size, 190 | lh_entry_free_fn *free_fn); 191 | 192 | 193 | /** 194 | * Free a linkhash table. 195 | * If a callback free function is provided then it is called for all 196 | * entries in the table. 197 | * @param t table to free. 198 | */ 199 | extern void lh_table_free(struct lh_table *t); 200 | 201 | 202 | /** 203 | * Insert a record into the table. 204 | * @param t the table to insert into. 205 | * @param k a pointer to the key to insert. 206 | * @param v a pointer to the value to insert. 207 | */ 208 | extern int lh_table_insert(struct lh_table *t, void *k, const void *v); 209 | 210 | 211 | /** 212 | * Insert a record into the table. This one accepts the key's hash in additon 213 | * to the key. This is an exension to support functions that need to calculate 214 | * the hash several times and allows them to do it just once and then pass 215 | * in the hash to all utility functions. Depending on use case, this can be a 216 | * very considerate performance improvement. 217 | * @param t the table to insert into. 218 | * @param k a pointer to the key to insert. 219 | * @param v a pointer to the value to insert. 220 | * @param h hash value of the key to insert 221 | * @param opts opts, a subset of JSON_OBJECT_ADD_* flags is supported 222 | */ 223 | extern int lh_table_insert_w_hash(struct lh_table *t, void *k, const void *v, const unsigned long h, const unsigned opts); 224 | 225 | 226 | /** 227 | * Lookup a record into the table. 228 | * @param t the table to lookup 229 | * @param k a pointer to the key to lookup 230 | * @return a pointer to the record structure of the value or NULL if it does not exist. 231 | */ 232 | extern struct lh_entry* lh_table_lookup_entry(struct lh_table *t, const void *k); 233 | 234 | /** 235 | * Lookup a record into the table. This one accepts the key's hash in additon 236 | * to the key. This is an exension to support functions that need to calculate 237 | * the hash several times and allows them to do it just once and then pass 238 | * in the hash to all utility functions. Depending on use case, this can be a 239 | * very considerate performance improvement. 240 | * @param t the table to lookup 241 | * @param k a pointer to the key to lookup 242 | * @param h hash value of the key to lookup 243 | * @return a pointer to the record structure of the value or NULL if it does not exist. 244 | */ 245 | extern struct lh_entry* lh_table_lookup_entry_w_hash(struct lh_table *t, const void *k, const unsigned long h); 246 | 247 | /** 248 | * Lookup a record into the table 249 | * @param t the table to lookup 250 | * @param k a pointer to the key to lookup 251 | * @return a pointer to the found value or NULL if it does not exist. 252 | * @deprecated Use lh_table_lookup_ex instead. 253 | */ 254 | THIS_FUNCTION_IS_DEPRECATED(extern const void* lh_table_lookup(struct lh_table *t, const void *k)); 255 | 256 | /** 257 | * Lookup a record in the table 258 | * @param t the table to lookup 259 | * @param k a pointer to the key to lookup 260 | * @param v a pointer to a where to store the found value (set to NULL if it doesn't exist). 261 | * @return whether or not the key was found 262 | */ 263 | extern json_bool lh_table_lookup_ex(struct lh_table *t, const void *k, void **v); 264 | 265 | /** 266 | * Delete a record from the table. 267 | * If a callback free function is provided then it is called for the 268 | * for the item being deleted. 269 | * @param t the table to delete from. 270 | * @param e a pointer to the entry to delete. 271 | * @return 0 if the item was deleted. 272 | * @return -1 if it was not found. 273 | */ 274 | extern int lh_table_delete_entry(struct lh_table *t, struct lh_entry *e); 275 | 276 | 277 | /** 278 | * Delete a record from the table. 279 | * If a callback free function is provided then it is called for the 280 | * for the item being deleted. 281 | * @param t the table to delete from. 282 | * @param k a pointer to the key to delete. 283 | * @return 0 if the item was deleted. 284 | * @return -1 if it was not found. 285 | */ 286 | extern int lh_table_delete(struct lh_table *t, const void *k); 287 | 288 | extern int lh_table_length(struct lh_table *t); 289 | 290 | void lh_abort(const char *msg, ...); 291 | void lh_table_resize(struct lh_table *t, int new_size); 292 | 293 | 294 | /** 295 | * Calculate the hash of a key for a given table. 296 | * This is an exension to support functions that need to calculate 297 | * the hash several times and allows them to do it just once and then pass 298 | * in the hash to all utility functions. Depending on use case, this can be a 299 | * very considerate performance improvement. 300 | * @param t the table (used to obtain hash function) 301 | * @param k a pointer to the key to lookup 302 | * @return the key's hash 303 | */ 304 | static inline unsigned long lh_get_hash(const struct lh_table *t, const void *k) 305 | { 306 | return t->hash_fn(k); 307 | } 308 | 309 | #ifdef __cplusplus 310 | } 311 | #endif 312 | 313 | #endif 314 | -------------------------------------------------------------------------------- /c_src/json-c/math_compat.h: -------------------------------------------------------------------------------- 1 | #ifndef __math_compat_h 2 | #define __math_compat_h 3 | 4 | /* Define isnan, isinf, infinity and nan on Windows/MSVC */ 5 | 6 | #ifndef HAVE_DECL_ISNAN 7 | # ifdef HAVE_DECL__ISNAN 8 | #include 9 | #define isnan(x) _isnan(x) 10 | # endif 11 | #endif 12 | 13 | #ifndef HAVE_DECL_ISINF 14 | # ifdef HAVE_DECL__FINITE 15 | #include 16 | #define isinf(x) (!_finite(x)) 17 | # endif 18 | #endif 19 | 20 | #ifndef HAVE_DECL_INFINITY 21 | #include 22 | #define INFINITY (DBL_MAX + DBL_MAX) 23 | #define HAVE_DECL_INFINITY 24 | #endif 25 | 26 | #ifndef HAVE_DECL_NAN 27 | #define NAN (INFINITY - INFINITY) 28 | #define HAVE_DECL_NAN 29 | #endif 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /c_src/json-c/printbuf.c: -------------------------------------------------------------------------------- 1 | /* 2 | * $Id: printbuf.c,v 1.5 2006/01/26 02:16:28 mclark Exp $ 3 | * 4 | * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. 5 | * Michael Clark 6 | * 7 | * This library is free software; you can redistribute it and/or modify 8 | * it under the terms of the MIT license. See COPYING for details. 9 | * 10 | * 11 | * Copyright (c) 2008-2009 Yahoo! Inc. All rights reserved. 12 | * The copyrights to the contents of this file are licensed under the MIT License 13 | * (http://www.opensource.org/licenses/mit-license.php) 14 | */ 15 | 16 | #include "config.h" 17 | 18 | #include 19 | #include 20 | #include 21 | 22 | #ifdef HAVE_STDARG_H 23 | # include 24 | #else /* !HAVE_STDARG_H */ 25 | # error Not enough var arg support! 26 | #endif /* HAVE_STDARG_H */ 27 | 28 | #include "debug.h" 29 | #include "printbuf.h" 30 | 31 | static int printbuf_extend(struct printbuf *p, int min_size); 32 | 33 | struct printbuf* printbuf_new(void) 34 | { 35 | struct printbuf *p; 36 | 37 | p = (struct printbuf*)calloc(1, sizeof(struct printbuf)); 38 | if(!p) return NULL; 39 | p->size = 32; 40 | p->bpos = 0; 41 | if(!(p->buf = (char*)malloc(p->size))) { 42 | free(p); 43 | return NULL; 44 | } 45 | return p; 46 | } 47 | 48 | 49 | /** 50 | * Extend the buffer p so it has a size of at least min_size. 51 | * 52 | * If the current size is large enough, nothing is changed. 53 | * 54 | * Note: this does not check the available space! The caller 55 | * is responsible for performing those calculations. 56 | */ 57 | static int printbuf_extend(struct printbuf *p, int min_size) 58 | { 59 | char *t; 60 | int new_size; 61 | 62 | if (p->size >= min_size) 63 | return 0; 64 | 65 | new_size = p->size * 2; 66 | if (new_size < min_size + 8) 67 | new_size = min_size + 8; 68 | #ifdef PRINTBUF_DEBUG 69 | MC_DEBUG("printbuf_memappend: realloc " 70 | "bpos=%d min_size=%d old_size=%d new_size=%d\n", 71 | p->bpos, min_size, p->size, new_size); 72 | #endif /* PRINTBUF_DEBUG */ 73 | if(!(t = (char*)realloc(p->buf, new_size))) 74 | return -1; 75 | p->size = new_size; 76 | p->buf = t; 77 | return 0; 78 | } 79 | 80 | int printbuf_memappend(struct printbuf *p, const char *buf, int size) 81 | { 82 | if (p->size <= p->bpos + size + 1) { 83 | if (printbuf_extend(p, p->bpos + size + 1) < 0) 84 | return -1; 85 | } 86 | memcpy(p->buf + p->bpos, buf, size); 87 | p->bpos += size; 88 | p->buf[p->bpos]= '\0'; 89 | return size; 90 | } 91 | 92 | int printbuf_memset(struct printbuf *pb, int offset, int charvalue, int len) 93 | { 94 | int size_needed; 95 | 96 | if (offset == -1) 97 | offset = pb->bpos; 98 | size_needed = offset + len; 99 | if (pb->size < size_needed) 100 | { 101 | if (printbuf_extend(pb, size_needed) < 0) 102 | return -1; 103 | } 104 | 105 | memset(pb->buf + offset, charvalue, len); 106 | if (pb->bpos < size_needed) 107 | pb->bpos = size_needed; 108 | 109 | return 0; 110 | } 111 | 112 | #if !defined(HAVE_VSNPRINTF) && defined(_MSC_VER) 113 | # define vsnprintf _vsnprintf 114 | #elif !defined(HAVE_VSNPRINTF) /* !HAVE_VSNPRINTF */ 115 | # error Need vsnprintf! 116 | #endif /* !HAVE_VSNPRINTF && defined(WIN32) */ 117 | 118 | #if !defined(HAVE_VASPRINTF) 119 | /* CAW: compliant version of vasprintf */ 120 | static int vasprintf(char **buf, const char *fmt, va_list ap) 121 | { 122 | #ifndef WIN32 123 | static char _T_emptybuffer = '\0'; 124 | #endif /* !defined(WIN32) */ 125 | int chars; 126 | char *b; 127 | 128 | if(!buf) { return -1; } 129 | 130 | #ifdef WIN32 131 | chars = _vscprintf(fmt, ap)+1; 132 | #else /* !defined(WIN32) */ 133 | /* CAW: RAWR! We have to hope to god here that vsnprintf doesn't overwrite 134 | our buffer like on some 64bit sun systems.... but hey, its time to move on */ 135 | chars = vsnprintf(&_T_emptybuffer, 0, fmt, ap)+1; 136 | if(chars < 0) { chars *= -1; } /* CAW: old glibc versions have this problem */ 137 | #endif /* defined(WIN32) */ 138 | 139 | b = (char*)malloc(sizeof(char)*chars); 140 | if(!b) { return -1; } 141 | 142 | if((chars = vsprintf(b, fmt, ap)) < 0) 143 | { 144 | free(b); 145 | } else { 146 | *buf = b; 147 | } 148 | 149 | return chars; 150 | } 151 | #endif /* !HAVE_VASPRINTF */ 152 | 153 | int sprintbuf(struct printbuf *p, const char *msg, ...) 154 | { 155 | va_list ap; 156 | char *t; 157 | int size; 158 | char buf[128]; 159 | 160 | /* user stack buffer first */ 161 | va_start(ap, msg); 162 | size = vsnprintf(buf, 128, msg, ap); 163 | va_end(ap); 164 | /* if string is greater than stack buffer, then use dynamic string 165 | with vasprintf. Note: some implementation of vsnprintf return -1 166 | if output is truncated whereas some return the number of bytes that 167 | would have been written - this code handles both cases. */ 168 | if(size == -1 || size > 127) { 169 | va_start(ap, msg); 170 | if((size = vasprintf(&t, msg, ap)) < 0) { va_end(ap); return -1; } 171 | va_end(ap); 172 | printbuf_memappend(p, t, size); 173 | free(t); 174 | return size; 175 | } else { 176 | printbuf_memappend(p, buf, size); 177 | return size; 178 | } 179 | } 180 | 181 | void printbuf_reset(struct printbuf *p) 182 | { 183 | p->buf[0] = '\0'; 184 | p->bpos = 0; 185 | } 186 | 187 | void printbuf_free(struct printbuf *p) 188 | { 189 | if(p) { 190 | free(p->buf); 191 | free(p); 192 | } 193 | } 194 | -------------------------------------------------------------------------------- /c_src/json-c/printbuf.h: -------------------------------------------------------------------------------- 1 | /* 2 | * $Id: printbuf.h,v 1.4 2006/01/26 02:16:28 mclark Exp $ 3 | * 4 | * Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. 5 | * Michael Clark 6 | * 7 | * This library is free software; you can redistribute it and/or modify 8 | * it under the terms of the MIT license. See COPYING for details. 9 | * 10 | * 11 | * Copyright (c) 2008-2009 Yahoo! Inc. All rights reserved. 12 | * The copyrights to the contents of this file are licensed under the MIT License 13 | * (http://www.opensource.org/licenses/mit-license.php) 14 | */ 15 | 16 | #ifndef _printbuf_h_ 17 | #define _printbuf_h_ 18 | 19 | #ifdef __cplusplus 20 | extern "C" { 21 | #endif 22 | 23 | struct printbuf { 24 | char *buf; 25 | int bpos; 26 | int size; 27 | }; 28 | 29 | extern struct printbuf* 30 | printbuf_new(void); 31 | 32 | /* As an optimization, printbuf_memappend_fast is defined as a macro 33 | * that handles copying data if the buffer is large enough; otherwise 34 | * it invokes printbuf_memappend_real() which performs the heavy 35 | * lifting of realloc()ing the buffer and copying data. 36 | * Your code should not use printbuf_memappend directly--use 37 | * printbuf_memappend_fast instead. 38 | */ 39 | extern int 40 | printbuf_memappend(struct printbuf *p, const char *buf, int size); 41 | 42 | #define printbuf_memappend_fast(p, bufptr, bufsize) \ 43 | do { \ 44 | if ((p->size - p->bpos) > bufsize) { \ 45 | memcpy(p->buf + p->bpos, (bufptr), bufsize); \ 46 | p->bpos += bufsize; \ 47 | p->buf[p->bpos]= '\0'; \ 48 | } else { printbuf_memappend(p, (bufptr), bufsize); } \ 49 | } while (0) 50 | 51 | #define printbuf_length(p) ((p)->bpos) 52 | 53 | /** 54 | * Set len bytes of the buffer to charvalue, starting at offset offset. 55 | * Similar to calling memset(x, charvalue, len); 56 | * 57 | * The memory allocated for the buffer is extended as necessary. 58 | * 59 | * If offset is -1, this starts at the end of the current data in the buffer. 60 | */ 61 | extern int 62 | printbuf_memset(struct printbuf *pb, int offset, int charvalue, int len); 63 | 64 | extern int 65 | sprintbuf(struct printbuf *p, const char *msg, ...); 66 | 67 | extern void 68 | printbuf_reset(struct printbuf *p); 69 | 70 | extern void 71 | printbuf_free(struct printbuf *p); 72 | 73 | #ifdef __cplusplus 74 | } 75 | #endif 76 | 77 | #endif 78 | -------------------------------------------------------------------------------- /c_src/json-c/random_seed.c: -------------------------------------------------------------------------------- 1 | /* 2 | * random_seed.c 3 | * 4 | * Copyright (c) 2013 Metaparadigm Pte. Ltd. 5 | * Michael Clark 6 | * 7 | * This library is free software; you can redistribute it and/or modify 8 | * it under the terms of the MIT license. See COPYING for details. 9 | * 10 | */ 11 | 12 | #include 13 | #include "config.h" 14 | #include "random_seed.h" 15 | 16 | #define DEBUG_SEED(s) 17 | 18 | 19 | #if defined ENABLE_RDRAND 20 | 21 | /* cpuid */ 22 | 23 | #if defined __GNUC__ && (defined __i386__ || defined __x86_64__) 24 | #define HAS_X86_CPUID 1 25 | 26 | static void do_cpuid(int regs[], int h) 27 | { 28 | __asm__ __volatile__( 29 | #if defined __x86_64__ 30 | "pushq %%rbx;\n" 31 | #else 32 | "pushl %%ebx;\n" 33 | #endif 34 | "cpuid;\n" 35 | #if defined __x86_64__ 36 | "popq %%rbx;\n" 37 | #else 38 | "popl %%ebx;\n" 39 | #endif 40 | : "=a"(regs[0]), [ebx] "=r"(regs[1]), "=c"(regs[2]), "=d"(regs[3]) 41 | : "a"(h)); 42 | } 43 | 44 | #elif defined _MSC_VER 45 | 46 | #define HAS_X86_CPUID 1 47 | #define do_cpuid __cpuid 48 | 49 | #endif 50 | 51 | /* has_rdrand */ 52 | 53 | #if HAS_X86_CPUID 54 | 55 | static int has_rdrand() 56 | { 57 | // CPUID.01H:ECX.RDRAND[bit 30] == 1 58 | int regs[4]; 59 | do_cpuid(regs, 1); 60 | return (regs[2] & (1 << 30)) != 0; 61 | } 62 | 63 | #endif 64 | 65 | /* get_rdrand_seed - GCC x86 and X64 */ 66 | 67 | #if defined __GNUC__ && (defined __i386__ || defined __x86_64__) 68 | 69 | #define HAVE_RDRAND 1 70 | 71 | static int get_rdrand_seed() 72 | { 73 | DEBUG_SEED("get_rdrand_seed"); 74 | int _eax; 75 | // rdrand eax 76 | __asm__ __volatile__("1: .byte 0x0F\n" 77 | " .byte 0xC7\n" 78 | " .byte 0xF0\n" 79 | " jnc 1b;\n" 80 | : "=a" (_eax)); 81 | return _eax; 82 | } 83 | 84 | #endif 85 | 86 | #if defined _MSC_VER 87 | 88 | #if _MSC_VER >= 1700 89 | #define HAVE_RDRAND 1 90 | 91 | /* get_rdrand_seed - Visual Studio 2012 and above */ 92 | 93 | static int get_rdrand_seed() 94 | { 95 | DEBUG_SEED("get_rdrand_seed"); 96 | int r; 97 | while (_rdrand32_step(&r) == 0); 98 | return r; 99 | } 100 | 101 | #elif defined _M_IX86 102 | #define HAVE_RDRAND 1 103 | 104 | /* get_rdrand_seed - Visual Studio 2010 and below - x86 only */ 105 | 106 | static int get_rdrand_seed() 107 | { 108 | DEBUG_SEED("get_rdrand_seed"); 109 | int _eax; 110 | retry: 111 | // rdrand eax 112 | __asm _emit 0x0F __asm _emit 0xC7 __asm _emit 0xF0 113 | __asm jnc retry 114 | __asm mov _eax, eax 115 | return _eax; 116 | } 117 | 118 | #endif 119 | #endif 120 | 121 | #endif /* defined ENABLE_RDRAND */ 122 | 123 | 124 | /* has_dev_urandom */ 125 | 126 | #if defined (__APPLE__) || defined(__unix__) || defined(__linux__) 127 | 128 | #include 129 | #include 130 | #include 131 | #include 132 | #include 133 | #include 134 | 135 | #define HAVE_DEV_RANDOM 1 136 | 137 | static const char *dev_random_file = "/dev/urandom"; 138 | 139 | static int has_dev_urandom() 140 | { 141 | struct stat buf; 142 | if (stat(dev_random_file, &buf)) { 143 | return 0; 144 | } 145 | return ((buf.st_mode & S_IFCHR) != 0); 146 | } 147 | 148 | 149 | /* get_dev_random_seed */ 150 | 151 | static int get_dev_random_seed() 152 | { 153 | DEBUG_SEED("get_dev_random_seed"); 154 | 155 | int fd = open(dev_random_file, O_RDONLY); 156 | if (fd < 0) { 157 | fprintf(stderr, "error opening %s: %s", dev_random_file, strerror(errno)); 158 | exit(1); 159 | } 160 | 161 | int r; 162 | ssize_t nread = read(fd, &r, sizeof(r)); 163 | if (nread != sizeof(r)) { 164 | fprintf(stderr, "error short read %s: %s", dev_random_file, strerror(errno)); 165 | exit(1); 166 | } 167 | 168 | close(fd); 169 | return r; 170 | } 171 | 172 | #endif 173 | 174 | 175 | /* get_cryptgenrandom_seed */ 176 | 177 | #ifdef WIN32 178 | 179 | #define HAVE_CRYPTGENRANDOM 1 180 | 181 | #include 182 | #include 183 | #ifndef __GNUC__ 184 | #pragma comment(lib, "advapi32.lib") 185 | #endif 186 | 187 | static int get_cryptgenrandom_seed() 188 | { 189 | DEBUG_SEED("get_cryptgenrandom_seed"); 190 | 191 | HCRYPTPROV hProvider = 0; 192 | int r; 193 | 194 | if (!CryptAcquireContextW(&hProvider, 0, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) { 195 | fprintf(stderr, "error CryptAcquireContextW"); 196 | exit(1); 197 | } 198 | 199 | if (!CryptGenRandom(hProvider, sizeof(r), (BYTE*)&r)) { 200 | fprintf(stderr, "error CryptGenRandom"); 201 | exit(1); 202 | } 203 | 204 | CryptReleaseContext(hProvider, 0); 205 | 206 | return r; 207 | } 208 | 209 | #endif 210 | 211 | 212 | /* get_time_seed */ 213 | 214 | #include 215 | 216 | static int get_time_seed() 217 | { 218 | DEBUG_SEED("get_time_seed"); 219 | 220 | return (int)time(NULL) * 433494437; 221 | } 222 | 223 | 224 | /* json_c_get_random_seed */ 225 | 226 | int json_c_get_random_seed() 227 | { 228 | #if HAVE_RDRAND 229 | if (has_rdrand()) return get_rdrand_seed(); 230 | #endif 231 | #if HAVE_DEV_RANDOM 232 | if (has_dev_urandom()) return get_dev_random_seed(); 233 | #endif 234 | #if HAVE_CRYPTGENRANDOM 235 | return get_cryptgenrandom_seed(); 236 | #endif 237 | return get_time_seed(); 238 | } 239 | -------------------------------------------------------------------------------- /c_src/json-c/random_seed.h: -------------------------------------------------------------------------------- 1 | /* 2 | * random_seed.h 3 | * 4 | * Copyright (c) 2013 Metaparadigm Pte. Ltd. 5 | * Michael Clark 6 | * 7 | * This library is free software; you can redistribute it and/or modify 8 | * it under the terms of the MIT license. See COPYING for details. 9 | * 10 | */ 11 | 12 | #ifndef seed_h 13 | #define seed_h 14 | 15 | #ifdef __cplusplus 16 | extern "C" { 17 | #endif 18 | 19 | extern int json_c_get_random_seed(); 20 | 21 | #ifdef __cplusplus 22 | } 23 | #endif 24 | 25 | #endif 26 | -------------------------------------------------------------------------------- /c_src/libu2f-host/authenticate.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2013-2015 Yubico AB 3 | 4 | This program is free software; you can redistribute it and/or modify it 5 | under the terms of the GNU Lesser General Public License as published by 6 | the Free Software Foundation; either version 2.1, or (at your option) any 7 | later version. 8 | 9 | This program is distributed in the hope that it will be useful, but 10 | WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 12 | General Public License for more details. 13 | 14 | You should have received a copy of the GNU Lesser General Public License 15 | along with this program; if not, see . 16 | */ 17 | 18 | #include 19 | #include "internal.h" 20 | 21 | #include 22 | #include 23 | #include "b64/cencode.h" 24 | #include "b64/cdecode.h" 25 | #include "sha256.h" 26 | 27 | static int 28 | prepare_response2 (const char *encstr, const char *bdstr, const char *input, 29 | char **response) 30 | { 31 | int rc = U2FH_JSON_ERROR; 32 | struct json_object *jo = NULL, *enc = NULL, *bd = NULL, *key = NULL; 33 | char keyb64[256]; 34 | size_t keylen = sizeof (keyb64); 35 | 36 | enc = json_object_new_string (encstr); 37 | if (enc == NULL) 38 | goto done; 39 | bd = json_object_new_string (bdstr); 40 | if (bd == NULL) 41 | goto done; 42 | 43 | rc = get_fixed_json_data (input, "keyHandle", keyb64, &keylen); 44 | if (rc != U2FH_OK) 45 | { 46 | goto done; 47 | } 48 | 49 | rc = U2FH_JSON_ERROR; 50 | key = json_object_new_string (keyb64); 51 | if (key == NULL) 52 | goto done; 53 | 54 | jo = json_object_new_object (); 55 | if (jo == NULL) 56 | goto done; 57 | 58 | json_object_object_add (jo, "signatureData", enc); 59 | json_object_object_add (jo, "clientData", bd); 60 | json_object_object_add (jo, "keyHandle", key); 61 | 62 | *response = strdup (json_object_to_json_string (jo)); 63 | if (*response == NULL) 64 | rc = U2FH_MEMORY_ERROR; 65 | else 66 | rc = U2FH_OK; 67 | 68 | done: 69 | json_object_put (jo); 70 | if (!jo) { 71 | json_object_put (enc); 72 | json_object_put (bd); 73 | json_object_put (key); 74 | } 75 | 76 | return rc; 77 | } 78 | 79 | static int 80 | prepare_response (const unsigned char *buf, int len, const char *bd, 81 | const char *input, char **response) 82 | { 83 | base64_encodestate b64ctx; 84 | char b64enc[2048]; 85 | char bdstr[2048]; 86 | int cnt; 87 | 88 | if (len > 2048) 89 | return U2FH_MEMORY_ERROR; 90 | if (strlen (bd) > 2048) 91 | return U2FH_MEMORY_ERROR; 92 | 93 | base64_init_encodestate (&b64ctx); 94 | cnt = base64_encode_block (buf, len, b64enc, &b64ctx); 95 | base64_encode_blockend (b64enc + cnt, &b64ctx); 96 | 97 | base64_init_encodestate (&b64ctx); 98 | cnt = base64_encode_block (bd, strlen (bd), bdstr, &b64ctx); 99 | base64_encode_blockend (bdstr + cnt, &b64ctx); 100 | 101 | return prepare_response2 (b64enc, bdstr, input, response); 102 | } 103 | 104 | #define CHALLBINLEN 32 105 | #define HOSIZE 32 106 | #define MAXKHLEN 128 107 | #define NOTSATISFIED "\x69\x85" 108 | 109 | /** 110 | * u2fh_authenticate: 111 | * @devs: a device handle, from u2fh_devs_init() and u2fh_devs_discover(). 112 | * @challenge: string with JSON data containing the challenge. 113 | * @origin: U2F origin URL. 114 | * @response: pointer to output string with JSON data. 115 | * @flags: set of ORed #u2fh_cmdflags values. 116 | * 117 | * Perform the U2F Authenticate operation. 118 | * 119 | * Returns: On success %U2FH_OK (integer 0) is returned, and on errors 120 | * an #u2fh_rc error code. 121 | */ 122 | u2fh_rc 123 | u2fh_authenticate (u2fh_devs * devs, 124 | const char *challenge, 125 | const char *origin, char **response, u2fh_cmdflags flags) 126 | { 127 | unsigned char data[CHALLBINLEN + HOSIZE + MAXKHLEN + 1]; 128 | unsigned char buf[MAXDATASIZE]; 129 | char bd[2048]; 130 | size_t bdlen = sizeof (bd); 131 | size_t len; 132 | int rc; 133 | char chalb64[256]; 134 | size_t challen = sizeof (chalb64); 135 | char khb64[256]; 136 | size_t kh64len = sizeof (khb64); 137 | base64_decodestate b64; 138 | size_t khlen; 139 | int skip_devices[devs->num_devices]; 140 | int skipped = 0; 141 | int iterations = 0; 142 | 143 | memset (skip_devices, 0, sizeof (skip_devices)); 144 | 145 | rc = get_fixed_json_data (challenge, "challenge", chalb64, &challen); 146 | if (rc != U2FH_OK) 147 | return rc; 148 | 149 | rc = prepare_browserdata (chalb64, origin, AUTHENTICATE_TYP, bd, &bdlen); 150 | if (rc != U2FH_OK) 151 | return rc; 152 | 153 | sha256_buffer (bd, bdlen, data); 154 | 155 | prepare_origin (challenge, data + CHALLBINLEN); 156 | 157 | /* confusion between key_handle and keyHandle */ 158 | rc = get_fixed_json_data (challenge, "keyHandle", khb64, &kh64len); 159 | if (rc != U2FH_OK) 160 | return rc; 161 | 162 | base64_init_decodestate (&b64); 163 | khlen = base64_decode_block (khb64, kh64len, 164 | data + HOSIZE + CHALLBINLEN + 1, &b64); 165 | data[HOSIZE + CHALLBINLEN] = khlen; 166 | 167 | /* FIXME: Support asynchronous usage, through a new u2fh_cmdflags 168 | flag. */ 169 | 170 | do 171 | { 172 | int i; 173 | if (iterations++ > 15) 174 | { 175 | return U2FH_TIMEOUT_ERROR; 176 | } 177 | for (i = 0; i < devs->num_devices; i++) 178 | { 179 | unsigned char tmp_buf[MAXDATASIZE]; 180 | if (skip_devices[i] != 0) 181 | { 182 | continue; 183 | } 184 | if (!devs->devs[i].is_alive) 185 | { 186 | skipped++; 187 | skip_devices[i] = 1; 188 | continue; 189 | } 190 | len = MAXDATASIZE; 191 | rc = send_apdu (devs, i, U2F_AUTHENTICATE, data, 192 | HOSIZE + CHALLBINLEN + khlen + 1, 193 | flags & U2FH_REQUEST_USER_PRESENCE ? 3 : 7, tmp_buf, 194 | &len); 195 | if (rc != U2FH_OK) 196 | { 197 | return rc; 198 | } 199 | else if (len != 2) 200 | { 201 | memcpy (buf, tmp_buf, len); 202 | break; 203 | } 204 | else if (memcmp (tmp_buf, NOTSATISFIED, 2) != 0) 205 | { 206 | skipped++; 207 | skip_devices[i] = 2; 208 | } 209 | memcpy (buf, tmp_buf, len); 210 | } 211 | if (len == 2 && memcmp (buf, NOTSATISFIED, 2) == 0) 212 | { 213 | if (flags & U2FH_REQUEST_NON_BLOCKING) 214 | { 215 | return U2FH_NOT_FINISHED_ERROR; 216 | } 217 | Sleep (1000); 218 | } 219 | } 220 | while ((flags & U2FH_REQUEST_USER_PRESENCE) 221 | && len == 2 && memcmp (buf, NOTSATISFIED, 2) == 0); 222 | 223 | if (len == 2 && memcmp (buf, NOTSATISFIED, 2) != 0) 224 | { 225 | return U2FH_AUTHENTICATOR_ERROR; 226 | } 227 | if (len != 2) 228 | { 229 | prepare_response (buf, len - 2, bd, challenge, response); 230 | return U2FH_OK; 231 | } 232 | 233 | return U2FH_TRANSPORT_ERROR; 234 | } 235 | -------------------------------------------------------------------------------- /c_src/libu2f-host/b64/cdecode.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2013-2015 Yubico AB 3 | 4 | This program is free software; you can redistribute it and/or modify it 5 | under the terms of the GNU Lesser General Public License as published by 6 | the Free Software Foundation; either version 2.1, or (at your option) any 7 | later version. 8 | 9 | This program is distributed in the hope that it will be useful, but 10 | WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 12 | General Public License for more details. 13 | 14 | You should have received a copy of the GNU Lesser General Public License 15 | along with this program; if not, see . 16 | */ 17 | 18 | /* 19 | cdecode.h - c header for a base64 decoding algorithm 20 | 21 | This is part of the libb64 project, and has been placed in the public domain. 22 | For details, see http://sourceforge.net/projects/libb64 23 | */ 24 | 25 | #ifndef BASE64_CDECODE_H 26 | #define BASE64_CDECODE_H 27 | 28 | typedef enum 29 | { 30 | step_a, step_b, step_c, step_d 31 | } base64_decodestep; 32 | 33 | typedef struct 34 | { 35 | base64_decodestep step; 36 | char plainchar; 37 | } base64_decodestate; 38 | 39 | void base64_init_decodestate (base64_decodestate * state_in); 40 | 41 | int base64_decode_value (char value_in); 42 | 43 | int base64_decode_block (const char *code_in, const int length_in, 44 | char *plaintext_out, base64_decodestate * state_in); 45 | 46 | #endif /* BASE64_CDECODE_H */ 47 | -------------------------------------------------------------------------------- /c_src/libu2f-host/b64/cencode.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2013-2015 Yubico AB 3 | 4 | This program is free software; you can redistribute it and/or modify it 5 | under the terms of the GNU Lesser General Public License as published by 6 | the Free Software Foundation; either version 2.1, or (at your option) any 7 | later version. 8 | 9 | This program is distributed in the hope that it will be useful, but 10 | WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 12 | General Public License for more details. 13 | 14 | You should have received a copy of the GNU Lesser General Public License 15 | along with this program; if not, see . 16 | */ 17 | 18 | /* 19 | cencode.h - c header for a base64 encoding algorithm 20 | 21 | This is part of the libb64 project, and has been placed in the public domain. 22 | For details, see http://sourceforge.net/projects/libb64 23 | */ 24 | 25 | #ifndef BASE64_CENCODE_H 26 | #define BASE64_CENCODE_H 27 | 28 | typedef enum 29 | { 30 | step_A, step_B, step_C 31 | } base64_encodestep; 32 | 33 | typedef struct 34 | { 35 | base64_encodestep step; 36 | char result; 37 | int stepcount; 38 | } base64_encodestate; 39 | 40 | void base64_init_encodestate (base64_encodestate * state_in); 41 | 42 | char base64_encode_value (char value_in); 43 | 44 | int base64_encode_block (const char *plaintext_in, int length_in, 45 | char *code_out, base64_encodestate * state_in); 46 | 47 | int base64_encode_blockend (char *code_out, base64_encodestate * state_in); 48 | 49 | #endif /* BASE64_CENCODE_H */ 50 | -------------------------------------------------------------------------------- /c_src/libu2f-host/cdecode.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2013-2015 Yubico AB 3 | 4 | This program is free software; you can redistribute it and/or modify it 5 | under the terms of the GNU Lesser General Public License as published by 6 | the Free Software Foundation; either version 2.1, or (at your option) any 7 | later version. 8 | 9 | This program is distributed in the hope that it will be useful, but 10 | WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 12 | General Public License for more details. 13 | 14 | You should have received a copy of the GNU Lesser General Public License 15 | along with this program; if not, see . 16 | */ 17 | 18 | #include 19 | 20 | /* 21 | cdecoder.c - c source to a base64 decoding algorithm implementation 22 | 23 | This is part of the libb64 project, and has been placed in the public domain. 24 | For details, see http://sourceforge.net/projects/libb64 25 | */ 26 | 27 | #include 28 | 29 | int 30 | base64_decode_value (char value_in) 31 | { 32 | static const char decoding[] = 33 | { 62, -1, -1, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -2, -1, 34 | -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 35 | 19, 20, 21, 22, 23, 24, 25, 36 | -1, -1, -1, -1, 63, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 37 | 38, 39, 40, 41, 42, 43, 44, 38 | 45, 46, 47, 48, 49, 50, 51 39 | }; 40 | static const char decoding_size = sizeof (decoding); 41 | value_in -= 45; 42 | if (value_in < 0 || value_in >= decoding_size) 43 | return -1; 44 | return decoding[(int) value_in]; 45 | } 46 | 47 | void 48 | base64_init_decodestate (base64_decodestate * state_in) 49 | { 50 | state_in->step = step_a; 51 | state_in->plainchar = 0; 52 | } 53 | 54 | int 55 | base64_decode_block (const char *code_in, const int length_in, 56 | char *plaintext_out, base64_decodestate * state_in) 57 | { 58 | const char *codechar = code_in; 59 | char *plainchar = plaintext_out; 60 | char fragment; 61 | 62 | *plainchar = state_in->plainchar; 63 | 64 | switch (state_in->step) 65 | { 66 | while (1) 67 | { 68 | case step_a: 69 | do 70 | { 71 | if (codechar == code_in + length_in) 72 | { 73 | state_in->step = step_a; 74 | state_in->plainchar = *plainchar; 75 | return plainchar - plaintext_out; 76 | } 77 | fragment = (char) base64_decode_value (*codechar++); 78 | } 79 | while (fragment < 0); 80 | *plainchar = (fragment & 0x03f) << 2; 81 | case step_b: 82 | do 83 | { 84 | if (codechar == code_in + length_in) 85 | { 86 | state_in->step = step_b; 87 | state_in->plainchar = *plainchar; 88 | return plainchar - plaintext_out; 89 | } 90 | fragment = (char) base64_decode_value (*codechar++); 91 | } 92 | while (fragment < 0); 93 | *plainchar++ |= (fragment & 0x030) >> 4; 94 | *plainchar = (fragment & 0x00f) << 4; 95 | case step_c: 96 | do 97 | { 98 | if (codechar == code_in + length_in) 99 | { 100 | state_in->step = step_c; 101 | state_in->plainchar = *plainchar; 102 | return plainchar - plaintext_out; 103 | } 104 | fragment = (char) base64_decode_value (*codechar++); 105 | } 106 | while (fragment < 0); 107 | *plainchar++ |= (fragment & 0x03c) >> 2; 108 | *plainchar = (fragment & 0x003) << 6; 109 | case step_d: 110 | do 111 | { 112 | if (codechar == code_in + length_in) 113 | { 114 | state_in->step = step_d; 115 | state_in->plainchar = *plainchar; 116 | return plainchar - plaintext_out; 117 | } 118 | fragment = (char) base64_decode_value (*codechar++); 119 | } 120 | while (fragment < 0); 121 | *plainchar++ |= (fragment & 0x03f); 122 | } 123 | } 124 | /* control should not reach here */ 125 | return plainchar - plaintext_out; 126 | } 127 | -------------------------------------------------------------------------------- /c_src/libu2f-host/cencode.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2013-2015 Yubico AB 3 | 4 | This program is free software; you can redistribute it and/or modify it 5 | under the terms of the GNU Lesser General Public License as published by 6 | the Free Software Foundation; either version 2.1, or (at your option) any 7 | later version. 8 | 9 | This program is distributed in the hope that it will be useful, but 10 | WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 12 | General Public License for more details. 13 | 14 | You should have received a copy of the GNU Lesser General Public License 15 | along with this program; if not, see . 16 | */ 17 | 18 | #include 19 | 20 | /* 21 | cencoder.c - c source to a base64 encoding algorithm implementation 22 | 23 | This is part of the libb64 project, and has been placed in the public domain. 24 | For details, see http://sourceforge.net/projects/libb64 25 | */ 26 | 27 | #include 28 | 29 | const int CHARS_PER_LINE = 72; 30 | 31 | void 32 | base64_init_encodestate (base64_encodestate * state_in) 33 | { 34 | state_in->step = step_A; 35 | state_in->result = 0; 36 | state_in->stepcount = 0; 37 | } 38 | 39 | char 40 | base64_encode_value (char value_in) 41 | { 42 | static const char *encoding = 43 | "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"; 44 | if (value_in > 63) 45 | return '='; 46 | return encoding[(int) value_in]; 47 | } 48 | 49 | int 50 | base64_encode_block (const char *plaintext_in, int length_in, char *code_out, 51 | base64_encodestate * state_in) 52 | { 53 | const char *plainchar = plaintext_in; 54 | const char *const plaintextend = plaintext_in + length_in; 55 | char *codechar = code_out; 56 | char result; 57 | char fragment; 58 | 59 | result = state_in->result; 60 | 61 | switch (state_in->step) 62 | { 63 | while (1) 64 | { 65 | case step_A: 66 | if (plainchar == plaintextend) 67 | { 68 | state_in->result = result; 69 | state_in->step = step_A; 70 | return codechar - code_out; 71 | } 72 | fragment = *plainchar++; 73 | result = (fragment & 0x0fc) >> 2; 74 | *codechar++ = base64_encode_value (result); 75 | result = (fragment & 0x003) << 4; 76 | case step_B: 77 | if (plainchar == plaintextend) 78 | { 79 | state_in->result = result; 80 | state_in->step = step_B; 81 | return codechar - code_out; 82 | } 83 | fragment = *plainchar++; 84 | result |= (fragment & 0x0f0) >> 4; 85 | *codechar++ = base64_encode_value (result); 86 | result = (fragment & 0x00f) << 2; 87 | case step_C: 88 | if (plainchar == plaintextend) 89 | { 90 | state_in->result = result; 91 | state_in->step = step_C; 92 | return codechar - code_out; 93 | } 94 | fragment = *plainchar++; 95 | result |= (fragment & 0x0c0) >> 6; 96 | *codechar++ = base64_encode_value (result); 97 | result = (fragment & 0x03f) >> 0; 98 | *codechar++ = base64_encode_value (result); 99 | 100 | ++(state_in->stepcount); 101 | if (state_in->stepcount == CHARS_PER_LINE / 4) 102 | { 103 | /* *codechar++ = '\n'; */ 104 | state_in->stepcount = 0; 105 | } 106 | } 107 | } 108 | /* control should not reach here */ 109 | return codechar - code_out; 110 | } 111 | 112 | int 113 | base64_encode_blockend (char *code_out, base64_encodestate * state_in) 114 | { 115 | char *codechar = code_out; 116 | 117 | switch (state_in->step) 118 | { 119 | case step_B: 120 | *codechar++ = base64_encode_value (state_in->result); 121 | *codechar++ = '='; 122 | *codechar++ = '='; 123 | break; 124 | case step_C: 125 | *codechar++ = base64_encode_value (state_in->result); 126 | *codechar++ = '='; 127 | break; 128 | case step_A: 129 | break; 130 | } 131 | *codechar++ = '\0'; 132 | 133 | return codechar - code_out; 134 | } 135 | -------------------------------------------------------------------------------- /c_src/libu2f-host/devs.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2013-2015 Yubico AB 3 | 4 | This program is free software; you can redistribute it and/or modify it 5 | under the terms of the GNU Lesser General Public License as published by 6 | the Free Software Foundation; either version 2.1, or (at your option) any 7 | later version. 8 | 9 | This program is distributed in the hope that it will be useful, but 10 | WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 12 | General Public License for more details. 13 | 14 | You should have received a copy of the GNU Lesser General Public License 15 | along with this program; if not, see . 16 | */ 17 | 18 | #include 19 | #include "internal.h" 20 | 21 | #include 22 | #include 23 | #ifdef __linux 24 | #include 25 | #include 26 | #include 27 | #include 28 | #endif 29 | 30 | #ifdef __linux 31 | static uint32_t 32 | get_bytes (uint8_t * rpt, size_t len, size_t num_bytes, size_t cur) 33 | { 34 | /* Return if there aren't enough bytes. */ 35 | if (cur + num_bytes >= len) 36 | return 0; 37 | 38 | if (num_bytes == 0) 39 | return 0; 40 | else if (num_bytes == 1) 41 | { 42 | return rpt[cur + 1]; 43 | } 44 | else if (num_bytes == 2) 45 | { 46 | return (rpt[cur + 2] * 256 + rpt[cur + 1]); 47 | } 48 | else 49 | return 0; 50 | } 51 | 52 | static int 53 | get_usage (uint8_t * report_descriptor, size_t size, 54 | unsigned short *usage_page, unsigned short *usage) 55 | { 56 | size_t i = 0; 57 | int size_code; 58 | int data_len, key_size; 59 | int usage_found = 0, usage_page_found = 0; 60 | 61 | while (i < size) 62 | { 63 | int key = report_descriptor[i]; 64 | int key_cmd = key & 0xfc; 65 | 66 | if ((key & 0xf0) == 0xf0) 67 | { 68 | fprintf (stderr, "invalid data received.\n"); 69 | return -1; 70 | } 71 | else 72 | { 73 | size_code = key & 0x3; 74 | switch (size_code) 75 | { 76 | case 0: 77 | case 1: 78 | case 2: 79 | data_len = size_code; 80 | break; 81 | case 3: 82 | data_len = 4; 83 | break; 84 | default: 85 | /* Can't ever happen since size_code is & 0x3 */ 86 | data_len = 0; 87 | break; 88 | }; 89 | key_size = 1; 90 | } 91 | 92 | if (key_cmd == 0x4) 93 | { 94 | *usage_page = get_bytes (report_descriptor, size, data_len, i); 95 | usage_page_found = 1; 96 | } 97 | if (key_cmd == 0x8) 98 | { 99 | *usage = get_bytes (report_descriptor, size, data_len, i); 100 | usage_found = 1; 101 | } 102 | 103 | if (usage_page_found && usage_found) 104 | return 0; /* success */ 105 | 106 | i += data_len + key_size; 107 | } 108 | 109 | return -1; /* failure */ 110 | } 111 | #endif 112 | 113 | static int 114 | get_usages (struct hid_device_info *dev, unsigned short *usage_page, 115 | unsigned short *usage) 116 | { 117 | #ifdef __linux 118 | int res, desc_size; 119 | int ret = U2FH_TRANSPORT_ERROR; 120 | struct hidraw_report_descriptor rpt_desc; 121 | int handle = open (dev->path, O_RDWR); 122 | if (handle > 0) 123 | { 124 | memset (&rpt_desc, 0, sizeof (rpt_desc)); 125 | res = ioctl (handle, HIDIOCGRDESCSIZE, &desc_size); 126 | if (res >= 0) 127 | { 128 | rpt_desc.size = desc_size; 129 | res = ioctl (handle, HIDIOCGRDESC, &rpt_desc); 130 | if (res >= 0) 131 | { 132 | res = 133 | get_usage (rpt_desc.value, rpt_desc.size, usage_page, usage); 134 | if (res >= 0) 135 | { 136 | ret = U2FH_OK; 137 | } 138 | } 139 | } 140 | close (handle); 141 | } 142 | return ret; 143 | #else 144 | *usage_page = dev->usage_page; 145 | *usage = dev->usage; 146 | return U2FH_OK; 147 | #endif 148 | } 149 | 150 | static void 151 | close_device (struct u2fdevice *dev) 152 | { 153 | hid_close (dev->devh); 154 | free (dev->device_path); 155 | free (dev->device_string); 156 | dev->is_alive = 0; 157 | } 158 | 159 | static void 160 | close_devices (u2fh_devs * devs) 161 | { 162 | int i; 163 | if (devs == NULL || devs->num_devices == 0) 164 | { 165 | return; 166 | } 167 | 168 | for (i = 0; i < devs->num_devices; i++) 169 | { 170 | struct u2fdevice *dev = &devs->devs[i]; 171 | if (dev->is_alive) 172 | { 173 | close_device (dev); 174 | } 175 | } 176 | devs->num_devices = 0; 177 | } 178 | 179 | static int 180 | init_device (u2fh_devs * devs, unsigned index) 181 | { 182 | unsigned char resp[1024]; 183 | /* FIXME: use something slightly more random as nonce */ 184 | unsigned char nonce[] = { 0x8, 0x7, 0x6, 0x5, 0x4, 0x3, 0x2, 0x1 }; 185 | size_t resplen = sizeof (resp); 186 | devs->devs[index].cid = CID_BROADCAST; 187 | 188 | if (u2fh_sendrecv 189 | (devs, index, U2FHID_INIT, nonce, sizeof (nonce), resp, 190 | &resplen) == U2FH_OK) 191 | { 192 | U2FHID_INIT_RESP initresp; 193 | memcpy (&initresp, resp, resplen); 194 | devs->devs[index].cid = initresp.cid; 195 | devs->devs[index].versionInterface = initresp.versionInterface; 196 | devs->devs[index].versionMajor = initresp.versionMajor; 197 | devs->devs[index].versionMinor = initresp.versionMinor; 198 | devs->devs[index].capFlags = initresp.capFlags; 199 | } 200 | else 201 | { 202 | return U2FH_TRANSPORT_ERROR; 203 | } 204 | return U2FH_OK; 205 | } 206 | 207 | static int 208 | ping_device (u2fh_devs * devs, unsigned index) 209 | { 210 | unsigned char data[1] = { 0 }; 211 | unsigned char resp[1024]; 212 | size_t resplen = sizeof (resp); 213 | return u2fh_sendrecv (devs, index, U2FHID_PING, data, sizeof (data), resp, 214 | &resplen); 215 | } 216 | 217 | 218 | /** 219 | * u2fh_devs_init: 220 | * @devs: pointer to #u2fh_devs type to initialize. 221 | * 222 | * Initialize device handle. 223 | * 224 | * Returns: On success %U2FH_OK (integer 0) is returned, on memory 225 | * allocation errors %U2FH_MEMORY_ERROR is returned, or another 226 | * #u2fh_rc error code is returned. 227 | */ 228 | u2fh_rc 229 | u2fh_devs_init (u2fh_devs ** devs) 230 | { 231 | u2fh_devs *d; 232 | int rc; 233 | 234 | d = malloc (sizeof (*d)); 235 | if (d == NULL) 236 | return U2FH_MEMORY_ERROR; 237 | 238 | memset (d, 0, sizeof (*d)); 239 | 240 | rc = hid_init (); 241 | if (rc != 0) 242 | { 243 | free (d); 244 | return U2FH_TRANSPORT_ERROR; 245 | } 246 | 247 | *devs = d; 248 | 249 | return U2FH_OK; 250 | } 251 | 252 | /** 253 | * u2fh_devs_discover: 254 | * @devs: device handle, from u2fh_devs_init(). 255 | * @max_index: will on return be set to the maximum index, may be NULL; if 256 | * there is 1 device this will be 0, if there are 2 devices this 257 | * will be 1, and so on. 258 | * 259 | * Discover and open new devices. This function can safely be called 260 | * several times and will free resources associated with unplugged 261 | * devices and open new. 262 | * 263 | * Returns: On success, %U2FH_OK (integer 0) is returned, when no U2F 264 | * device could be found %U2FH_NO_U2F_DEVICE is returned, or another 265 | * #u2fh_rc error code. 266 | */ 267 | u2fh_rc 268 | u2fh_devs_discover (u2fh_devs * devs, unsigned *max_index) 269 | { 270 | struct hid_device_info *di, *cur_dev; 271 | u2fh_rc res = U2FH_NO_U2F_DEVICE; 272 | unsigned index; 273 | 274 | di = hid_enumerate (0, 0); 275 | for (cur_dev = di; cur_dev; cur_dev = cur_dev->next) 276 | { 277 | int found = 0; 278 | unsigned short usage_page = 0, usage = 0; 279 | 280 | for (index = 0; index < devs->num_devices; index++) 281 | { 282 | struct u2fdevice *dev = &devs->devs[index]; 283 | if (!dev->is_alive) 284 | { 285 | continue; 286 | } 287 | if (strcmp (dev->device_path, cur_dev->path) == 0) 288 | { 289 | if (ping_device (devs, index) == U2FH_OK) 290 | { 291 | found = 1; 292 | res = U2FH_OK; 293 | break; 294 | } 295 | else 296 | { 297 | if (debug) 298 | { 299 | fprintf (stderr, "Device %s failed ping, dead.\n", 300 | dev->device_path); 301 | } 302 | close_device (dev); 303 | break; 304 | } 305 | } 306 | } 307 | if (found) 308 | { 309 | continue; 310 | } 311 | 312 | if (debug) 313 | fprintf (stderr, "Checking device %ls.\n", 314 | cur_dev->product_string); 315 | get_usages (cur_dev, &usage_page, &usage); 316 | if (debug) 317 | fprintf (stderr, "Usage: %x UsagePage: %x.\n", 318 | usage, usage_page); 319 | if (usage_page == FIDO_USAGE_PAGE && usage == FIDO_USAGE_U2FHID) 320 | { 321 | devs->devs = 322 | realloc (devs->devs, 323 | (devs->num_devices + 1) * sizeof (struct u2fdevice)); 324 | struct u2fdevice *dev = &devs->devs[devs->num_devices]; 325 | memset (dev, 0, sizeof (struct u2fdevice)); 326 | dev->devh = hid_open_path (cur_dev->path); 327 | if (dev->devh != NULL) 328 | { 329 | dev->device_path = strdup (cur_dev->path); 330 | if (dev->device_path == NULL) 331 | { 332 | close_device (dev); 333 | return U2FH_MEMORY_ERROR; 334 | } 335 | index = devs->num_devices++; 336 | dev->is_alive = 1; 337 | if (init_device (devs, index) == U2FH_OK) 338 | { 339 | if (cur_dev->product_string) 340 | { 341 | size_t len = 342 | wcstombs (NULL, cur_dev->product_string, 0); 343 | dev->device_string = malloc (len + 1); 344 | if (dev->device_string == NULL) 345 | { 346 | close_device (dev); 347 | return U2FH_MEMORY_ERROR; 348 | } 349 | memset (dev->device_string, 0, len + 1); 350 | wcstombs (dev->device_string, cur_dev->product_string, 351 | len); 352 | if (debug) 353 | { 354 | fprintf (stderr, "device %s discovered as '%s'\n", 355 | dev->device_path, dev->device_string); 356 | fprintf (stderr, 357 | " version (Interface, Major, " 358 | "Minor, Build): %d, %d, " 359 | "%d, %d capFlags: %d\n", 360 | dev->versionInterface, 361 | dev->versionMajor, 362 | dev->versionMinor, 363 | dev->versionBuild, dev->capFlags); 364 | } 365 | } 366 | res = U2FH_OK; 367 | } 368 | else 369 | { 370 | close_device (dev); 371 | devs->num_devices--; 372 | } 373 | } 374 | } 375 | } 376 | 377 | for (index = 0; index < devs->num_devices; index++) 378 | { 379 | struct u2fdevice *dev = &devs->devs[index]; 380 | int found = 0; 381 | 382 | if (!dev->is_alive) 383 | { 384 | continue; 385 | } 386 | for (cur_dev = di; cur_dev; cur_dev = cur_dev->next) 387 | { 388 | if (strcmp (cur_dev->path, dev->device_path) == 0) 389 | { 390 | found = 1; 391 | } 392 | } 393 | if (!found) 394 | { 395 | if (debug) 396 | { 397 | fprintf (stderr, "device %s looks dead.\n", dev->device_path); 398 | } 399 | close_device (dev); 400 | } 401 | } 402 | 403 | hid_free_enumeration (di); 404 | if (res == U2FH_OK && max_index) 405 | *max_index = devs->num_devices - 1; 406 | 407 | return res; 408 | } 409 | 410 | /** 411 | * u2fh_devs_done: 412 | * @devs: device handle, from u2fh_devs_init(). 413 | * 414 | * Release all resources associated with @devs. This function must be 415 | * called when you are finished with a device handle. 416 | */ 417 | void 418 | u2fh_devs_done (u2fh_devs * devs) 419 | { 420 | if (devs == NULL) 421 | return; 422 | 423 | close_devices (devs); 424 | free (devs->devs); 425 | hid_exit (); 426 | 427 | free (devs); 428 | } 429 | 430 | /** 431 | * u2fh_get_device_description: 432 | * @devs: device_handle, from u2fh_devs_init(). 433 | * @index: index of device 434 | * @out: buffer for storing device description 435 | * @len: maximum amount of data to store in @out. Will be updated. 436 | * 437 | * Get the device description of the device at @index. Stores the 438 | * string in @out. 439 | * 440 | * Returns: %U2FH_OK on success. 441 | */ 442 | u2fh_rc 443 | u2fh_get_device_description (u2fh_devs * devs, unsigned index, char *out, 444 | size_t * len) 445 | { 446 | struct u2fdevice *dev; 447 | size_t i; 448 | 449 | if (index >= devs->num_devices || !devs->devs[index].is_alive) 450 | { 451 | return U2FH_NO_U2F_DEVICE; 452 | } 453 | 454 | dev = &devs->devs[index]; 455 | i = strlen (dev->device_string); 456 | if (i < *len) 457 | { 458 | *len = i; 459 | } 460 | else 461 | { 462 | return U2FH_MEMORY_ERROR; 463 | } 464 | strcpy (out, dev->device_string); 465 | return U2FH_OK; 466 | } 467 | 468 | /** 469 | * u2fh_is_alive: 470 | * @devs: device_handle, from u2fh_devs_init(). 471 | * @index: index of device 472 | * 473 | * Get the liveliness of the device @index. 474 | * 475 | * Returns: 1 if the device is considered alive, 0 otherwise. 476 | */ 477 | int 478 | u2fh_is_alive (u2fh_devs * devs, unsigned index) 479 | { 480 | if (index >= devs->num_devices || !devs->devs[index].is_alive) 481 | return 0; 482 | return 1; 483 | } 484 | -------------------------------------------------------------------------------- /c_src/libu2f-host/error.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2013-2015 Yubico AB 3 | 4 | This program is free software; you can redistribute it and/or modify it 5 | under the terms of the GNU Lesser General Public License as published by 6 | the Free Software Foundation; either version 2.1, or (at your option) any 7 | later version. 8 | 9 | This program is distributed in the hope that it will be useful, but 10 | WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 12 | General Public License for more details. 13 | 14 | You should have received a copy of the GNU Lesser General Public License 15 | along with this program; if not, see . 16 | */ 17 | 18 | #include 19 | #include 20 | 21 | #define ERR(name, desc) { name, #name, desc } 22 | 23 | typedef struct 24 | { 25 | int rc; 26 | const char *name; 27 | const char *description; 28 | } err_t; 29 | 30 | static const err_t errors[] = { 31 | ERR (U2FH_OK, "successful return"), 32 | ERR (U2FH_MEMORY_ERROR, "out of memory or other memory error"), 33 | ERR (U2FH_TRANSPORT_ERROR, "error in transport layer"), 34 | ERR (U2FH_JSON_ERROR, "error in JSON handling"), 35 | ERR (U2FH_BASE64_ERROR, "base64 error"), 36 | ERR (U2FH_NO_U2F_DEVICE, "cannot find U2F device"), 37 | ERR (U2FH_AUTHENTICATOR_ERROR, "authenticator error"), 38 | ERR (U2FH_TIMEOUT_ERROR, "timeout error"), 39 | }; 40 | 41 | /** 42 | * u2fh_strerror: 43 | * @err: error code 44 | * 45 | * Convert return code to human readable string explanation of the 46 | * reason for the particular error code. 47 | * 48 | * This string can be used to output a diagnostic message to the user. 49 | * 50 | * This function is one of few in the library that can be used without 51 | * a successful call to u2fh_global_init(). 52 | * 53 | * Return value: Returns a pointer to a statically allocated string 54 | * containing an explanation of the error code @err. 55 | **/ 56 | const char * 57 | u2fh_strerror (int err) 58 | { 59 | static const char *unknown = "Unknown libu2f-host error"; 60 | const char *p; 61 | 62 | if (-err < 0 || -err >= (int) (sizeof (errors) / sizeof (errors[0]))) 63 | return unknown; 64 | 65 | p = errors[-err].description; 66 | if (!p) 67 | p = unknown; 68 | 69 | return p; 70 | } 71 | 72 | /** 73 | * u2fh_strerror_name: 74 | * @err: error code 75 | * 76 | * Convert return code to human readable string representing the error 77 | * code symbol itself. For example, u2fh_strerror_name(%U2FH_OK) 78 | * returns the string "U2FH_OK". 79 | * 80 | * This string can be used to output a diagnostic message to the user. 81 | * 82 | * This function is one of few in the library that can be used without 83 | * a successful call to u2fh_global_init(). 84 | * 85 | * Return value: Returns a pointer to a statically allocated string 86 | * containing a string version of the error code @err, or NULL if 87 | * the error code is not known. 88 | **/ 89 | const char * 90 | u2fh_strerror_name (int err) 91 | { 92 | if (-err < 0 || -err >= (int) (sizeof (errors) / sizeof (errors[0]))) 93 | return NULL; 94 | 95 | return errors[-err].name; 96 | } 97 | -------------------------------------------------------------------------------- /c_src/libu2f-host/global.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2013-2015 Yubico AB 3 | 4 | This program is free software; you can redistribute it and/or modify it 5 | under the terms of the GNU Lesser General Public License as published by 6 | the Free Software Foundation; either version 2.1, or (at your option) any 7 | later version. 8 | 9 | This program is distributed in the hope that it will be useful, but 10 | WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 12 | General Public License for more details. 13 | 14 | You should have received a copy of the GNU Lesser General Public License 15 | along with this program; if not, see . 16 | */ 17 | 18 | #include 19 | #include "internal.h" 20 | 21 | int debug; 22 | 23 | /** 24 | * u2fh_global_init: 25 | * @flags: initialization flags, ORed #u2fh_initflags. 26 | * 27 | * Initialize the library. This function is not guaranteed to be 28 | * thread safe and must be invoked on application startup. 29 | * 30 | * Returns: On success %U2FH_OK (integer 0) is returned, and on errors 31 | * an #u2fh_rc error code. 32 | */ 33 | u2fh_rc 34 | u2fh_global_init (u2fh_initflags flags) 35 | { 36 | if (flags & U2FH_DEBUG) 37 | debug = 1; 38 | 39 | return U2FH_OK; 40 | } 41 | 42 | /** 43 | * u2fh_global_done: 44 | * 45 | * Release all resources from the library. Call this function when no 46 | * further use of the library is needed. 47 | */ 48 | void 49 | u2fh_global_done (void) 50 | { 51 | debug = 0; 52 | } 53 | -------------------------------------------------------------------------------- /c_src/libu2f-host/inc/u2f.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2013-2015 Yubico AB 3 | 4 | This program is free software; you can redistribute it and/or modify it 5 | under the terms of the GNU Lesser General Public License as published by 6 | the Free Software Foundation; either version 2.1, or (at your option) any 7 | later version. 8 | 9 | This program is distributed in the hope that it will be useful, but 10 | WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 12 | General Public License for more details. 13 | 14 | You should have received a copy of the GNU Lesser General Public License 15 | along with this program; if not, see . 16 | */ 17 | 18 | // Common U2F raw message format header. 19 | // 2014-08-14 J Ehrensvard, Yubico, Inc. 20 | 21 | #ifndef __U2F_H_INCLUDED__ 22 | #define __U2F_H_INCLUDED__ 23 | 24 | #ifdef _MSC_VER // Windows 25 | typedef unsigned char uint8_t; 26 | typedef unsigned short uint16_t; 27 | typedef unsigned int uint32_t; 28 | typedef unsigned long int uint64_t; 29 | #else 30 | #include 31 | #endif 32 | 33 | #ifdef __cplusplus 34 | extern "C" 35 | { 36 | #endif 37 | 38 | // General constants 39 | 40 | #define U2F_EC_KEY_SIZE 32 // EC key size in bytes 41 | #define U2F_EC_POINT_SIZE ((U2F_EC_KEY_SIZE * 2) + 1) // Size of EC point 42 | #define U2F_MAX_KH_SIZE 128 // Max size of key handle 43 | #define U2F_MAX_ATT_CERT_SIZE 1024 // Max size of attestation certificate 44 | #define U2F_MAX_EC_SIG_SIZE 72 // Max size of DER coded EC signature 45 | #define U2F_CTR_SIZE 4 // Size of counter field 46 | #define U2F_APPID_SIZE 32 // Size of application id 47 | #define U2F_CHAL_SIZE 32 // Size of challenge 48 | 49 | #define ENC_SIZE(x) ((x + 7) & 0xfff8) 50 | 51 | // EC (uncompressed) point 52 | 53 | #define U2F_POINT_UNCOMPRESSED 0x04 // Uncompressed point format 54 | 55 | typedef struct 56 | { 57 | uint8_t pointFormat; // Point type 58 | uint8_t x[U2F_EC_KEY_SIZE]; // X-value 59 | uint8_t y[U2F_EC_KEY_SIZE]; // Y-value 60 | } U2F_EC_POINT; 61 | 62 | // U2F native commands 63 | 64 | #define U2F_REGISTER 0x01 // Registration command 65 | #define U2F_AUTHENTICATE 0x02 // Authenticate/sign command 66 | #define U2F_VERSION 0x03 // Read version string command 67 | 68 | #define U2F_VENDOR_FIRST 0x40 // First vendor defined command 69 | #define U2F_VENDOR_LAST 0x7f // Last vendor defined command 70 | 71 | // U2F_CMD_REGISTER command defines 72 | 73 | #define U2F_REGISTER_ID 0x05 // Version 2 registration identifier 74 | #define U2F_REGISTER_HASH_ID 0x00 // Version 2 hash identintifier 75 | 76 | typedef struct 77 | { 78 | uint8_t chal[U2F_CHAL_SIZE]; // Challenge 79 | uint8_t appId[U2F_APPID_SIZE]; // Application id 80 | } U2F_REGISTER_REQ; 81 | 82 | typedef struct 83 | { 84 | uint8_t registerId; // Registration identifier (U2F_REGISTER_ID_V2) 85 | U2F_EC_POINT pubKey; // Generated public key 86 | uint8_t keyHandleLen; // Length of key handle 87 | uint8_t keyHandleCertSig[U2F_MAX_KH_SIZE + // Key handle 88 | U2F_MAX_ATT_CERT_SIZE + // Attestation certificate 89 | U2F_MAX_EC_SIG_SIZE]; // Registration signature 90 | } U2F_REGISTER_RESP; 91 | 92 | // U2F_CMD_AUTHENTICATE command defines 93 | 94 | // Authentication control byte 95 | 96 | #define U2F_AUTH_ENFORCE 0x03 // Enforce user presence and sign 97 | #define U2F_AUTH_CHECK_ONLY 0x07 // Check only 98 | #define U2F_AUTH_FLAG_TUP 0x01 // Test of user presence set 99 | 100 | typedef struct 101 | { 102 | uint8_t chal[U2F_CHAL_SIZE]; // Challenge 103 | uint8_t appId[U2F_APPID_SIZE]; // Application id 104 | uint8_t keyHandleLen; // Length of key handle 105 | uint8_t keyHandle[U2F_MAX_KH_SIZE]; // Key handle 106 | } U2F_AUTHENTICATE_REQ; 107 | 108 | typedef struct 109 | { 110 | uint8_t flags; // U2F_AUTH_FLAG_ values 111 | uint8_t ctr[U2F_CTR_SIZE]; // Counter field (big-endian) 112 | uint8_t sig[U2F_MAX_EC_SIG_SIZE]; // Signature 113 | } U2F_AUTHENTICATE_RESP; 114 | 115 | // Common raw message format (ISO7816-4:2005 mapping) 116 | 117 | typedef struct 118 | { 119 | uint8_t cla; // Class - reserved 120 | uint8_t ins; // U2F instruction 121 | uint8_t p1; // U2F parameter 1 122 | uint8_t p2; // U2F parameter 2 123 | uint8_t lc1; // Length field, set to zero 124 | uint8_t lc2; // Length field, MSB 125 | uint8_t lc3; // Length field, LSB 126 | uint8_t data[1]; // Data field 127 | } U2F_MSG; 128 | 129 | // Command status responses 130 | 131 | #define U2F_SW_NO_ERROR 0x9000 // SW_NO_ERROR 132 | #define U2F_SW_WRONG_DATA 0x6984 // SW_WRONG_DATA 133 | #define U2F_SW_CONDITIONS_NOT_SATISFIED 0x6985 // SW_CONDITIONS_NOT_SATISFIED 134 | #define U2F_SW_INS_NOT_SUPPORTED 0x6d00 // SW_INS_NOT_SUPPORTED 135 | #define U2F_SW_CLA_NOT_SUPPORTED 0x6e00 // SW_CLA_NOT_SUPPORTED 136 | 137 | #ifdef __cplusplus 138 | } 139 | #endif 140 | 141 | #endif // __U2F_H_INCLUDED__ 142 | -------------------------------------------------------------------------------- /c_src/libu2f-host/inc/u2f_hid.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2013-2015 Yubico AB 3 | 4 | This program is free software; you can redistribute it and/or modify it 5 | under the terms of the GNU Lesser General Public License as published by 6 | the Free Software Foundation; either version 2.1, or (at your option) any 7 | later version. 8 | 9 | This program is distributed in the hope that it will be useful, but 10 | WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 12 | General Public License for more details. 13 | 14 | You should have received a copy of the GNU Lesser General Public License 15 | along with this program; if not, see . 16 | */ 17 | 18 | // Common U2F HID transport header. 19 | // 2014-08-21 J Ehrensvard, Yubico, Inc. 20 | 21 | #ifndef __U2FHID_H_INCLUDED__ 22 | #define __U2FHID_H_INCLUDED__ 23 | 24 | #ifdef _MSC_VER // Windows 25 | typedef unsigned char uint8_t; 26 | typedef unsigned short uint16_t; 27 | typedef unsigned int uint32_t; 28 | typedef unsigned long int uint64_t; 29 | #else 30 | #include 31 | #endif 32 | 33 | #ifdef __cplusplus 34 | extern "C" 35 | { 36 | #endif 37 | 38 | // Size of HID reports 39 | 40 | #define HID_RPT_SIZE 64 // Default size of raw HID report 41 | 42 | // Frame layout - command- and continuation frames 43 | 44 | #define CID_BROADCAST 0xffffffff // Broadcast channel id 45 | 46 | #define TYPE_MASK 0x80 // Frame type mask 47 | #define TYPE_INIT 0x80 // Initial frame identifier 48 | #define TYPE_CONT 0x00 // Continuation frame identifier 49 | 50 | typedef struct 51 | { 52 | uint32_t cid; // Channel identifier 53 | union 54 | { 55 | uint8_t type; // Frame type - b7 defines type 56 | struct 57 | { 58 | uint8_t cmd; // Command - b7 set 59 | uint8_t bcnth; // Message byte count - high part 60 | uint8_t bcntl; // Message byte count - low part 61 | uint8_t data[HID_RPT_SIZE - 7]; // Data payload 62 | } init; 63 | struct 64 | { 65 | uint8_t seq; // Sequence number - b7 cleared 66 | uint8_t data[HID_RPT_SIZE - 5]; // Data payload 67 | } cont; 68 | }; 69 | } U2FHID_FRAME; 70 | 71 | #define FRAME_TYPE(f) ((f).type & TYPE_MASK) 72 | #define FRAME_CMD(f) ((f).init.cmd & ~TYPE_MASK) 73 | #define MSG_LEN(f) (((f).init.bcnth << 8) + (f).init.bcntl) 74 | #define FRAME_SEQ(f) ((f).cont.seq & ~TYPE_MASK) 75 | 76 | // HID usage- and usage-page definitions 77 | 78 | #define FIDO_USAGE_PAGE 0xf1d0 // FIDO alliance HID usage page 79 | #define FIDO_USAGE_U2FHID 0x01 // U2FHID usage for top-level collection 80 | #define FIDO_USAGE_DATA_IN 0x20 // Raw IN data report 81 | #define FIDO_USAGE_DATA_OUT 0x21 // Raw OUT data report 82 | 83 | // General constants 84 | 85 | #define U2FHID_IF_VERSION 2 // Current interface implementation version 86 | #define U2FHID_FRAME_TIMEOUT 500 // Default frame timeout in ms 87 | #define U2FHID_TRANS_TIMEOUT 3000 // Default message timeout in ms 88 | 89 | // U2FHID native commands 90 | 91 | #define U2FHID_PING (TYPE_INIT | 0x01) // Echo data through local processor only 92 | #define U2FHID_MSG (TYPE_INIT | 0x03) // Send U2F message frame 93 | #define U2FHID_LOCK (TYPE_INIT | 0x04) // Send lock channel command 94 | #define U2FHID_INIT (TYPE_INIT | 0x06) // Channel initialization 95 | #define U2FHID_WINK (TYPE_INIT | 0x08) // Send device identification wink 96 | #define U2FHID_ERROR (TYPE_INIT | 0x3f) // Error response 97 | 98 | #define U2FHID_VENDOR_FIRST (TYPE_INIT | 0x40) // First vendor defined command 99 | #define U2FHID_VENDOR_LAST (TYPE_INIT | 0x7f) // Last vendor defined command 100 | 101 | // U2FHID_INIT command defines 102 | 103 | #define INIT_NONCE_SIZE 8 // Size of channel initialization challenge 104 | #define CAPFLAG_WINK 0x01 // Device supports WINK command 105 | #define CAPFLAG_LOCK 0x02 // Device supports LOCK command 106 | 107 | typedef struct 108 | { 109 | uint8_t nonce[INIT_NONCE_SIZE]; // Client application nonce 110 | } U2FHID_INIT_REQ; 111 | 112 | typedef struct 113 | { 114 | uint8_t nonce[INIT_NONCE_SIZE]; // Client application nonce 115 | uint32_t cid; // Channel identifier 116 | uint8_t versionInterface; // Interface version 117 | uint8_t versionMajor; // Major version number 118 | uint8_t versionMinor; // Minor version number 119 | uint8_t versionBuild; // Build version number 120 | uint8_t capFlags; // Capabilities flags 121 | } U2FHID_INIT_RESP; 122 | 123 | // Low-level error codes. Return as negatives. 124 | 125 | #define ERR_NONE 0x00 // No error 126 | #define ERR_INVALID_CMD 0x01 // Invalid command 127 | #define ERR_INVALID_PAR 0x02 // Invalid parameter 128 | #define ERR_INVALID_LEN 0x03 // Invalid message length 129 | #define ERR_INVALID_SEQ 0x04 // Invalid message sequencing 130 | #define ERR_MSG_TIMEOUT 0x05 // Message has timed out 131 | #define ERR_CHANNEL_BUSY 0x06 // Channel busy 132 | #define ERR_LOCK_REQUIRED 0x0a // Command requires channel lock 133 | #define ERR_INVALID_CID 0x0b // Command not allowed on this cid 134 | #define ERR_OTHER 0x7f // Other unspecified error 135 | 136 | #ifdef __cplusplus 137 | } 138 | #endif 139 | 140 | #endif // __U2FHID_H_INCLUDED__ 141 | -------------------------------------------------------------------------------- /c_src/libu2f-host/internal.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2013-2015 Yubico AB 3 | 4 | This program is free software; you can redistribute it and/or modify it 5 | under the terms of the GNU Lesser General Public License as published by 6 | the Free Software Foundation; either version 2.1, or (at your option) any 7 | later version. 8 | 9 | This program is distributed in the hope that it will be useful, but 10 | WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 12 | General Public License for more details. 13 | 14 | You should have received a copy of the GNU Lesser General Public License 15 | along with this program; if not, see . 16 | */ 17 | 18 | #ifndef INTERNAL_H 19 | #define INTERNAL_H 20 | 21 | #include 22 | #include "hidapi.h" 23 | #include 24 | 25 | #include "inc/u2f.h" 26 | #include "inc/u2f_hid.h" 27 | 28 | #ifdef _WIN32 29 | #include 30 | #else 31 | #include 32 | #define Sleep(x) (usleep((x) * 1000)) 33 | #endif 34 | 35 | struct u2fdevice 36 | { 37 | hid_device *devh; 38 | uint32_t cid; 39 | char *device_string; 40 | char *device_path; 41 | int is_alive; 42 | uint8_t versionInterface; // Interface version 43 | uint8_t versionMajor; // Major version number 44 | uint8_t versionMinor; // Minor version number 45 | uint8_t versionBuild; // Build version number 46 | uint8_t capFlags; // Capabilities flags 47 | }; 48 | 49 | struct u2fh_devs 50 | { 51 | int num_devices; 52 | struct u2fdevice *devs; 53 | }; 54 | 55 | extern int debug; 56 | 57 | #define MAXDATASIZE 1024 58 | 59 | #define MAXFIXEDLEN 1024 60 | 61 | #define REGISTER_TYP "navigator.id.finishEnrollment" 62 | #define AUTHENTICATE_TYP "navigator.id.getAssertion" 63 | 64 | int prepare_browserdata (const char *challenge, const char *origin, 65 | const char *typstr, char *out, size_t * outlen); 66 | int prepare_origin (const char *origin, unsigned char *p); 67 | u2fh_rc send_apdu (u2fh_devs * devs, int index, int cmd, 68 | const unsigned char *d, size_t dlen, int p1, 69 | unsigned char *out, size_t * outlen); 70 | int get_fixed_json_data (const char *jsonstr, const char *key, char *p, 71 | size_t * len); 72 | int hash_data (const char *in, size_t len, unsigned char *out); 73 | 74 | #endif 75 | -------------------------------------------------------------------------------- /c_src/libu2f-host/register.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2013-2015 Yubico AB 3 | 4 | This program is free software; you can redistribute it and/or modify it 5 | under the terms of the GNU Lesser General Public License as published by 6 | the Free Software Foundation; either version 2.1, or (at your option) any 7 | later version. 8 | 9 | This program is distributed in the hope that it will be useful, but 10 | WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 12 | General Public License for more details. 13 | 14 | You should have received a copy of the GNU Lesser General Public License 15 | along with this program; if not, see . 16 | */ 17 | 18 | #include 19 | #include "internal.h" 20 | 21 | #include 22 | #include 23 | #include "b64/cencode.h" 24 | #include "sha256.h" 25 | 26 | static int 27 | prepare_response2 (const char *respstr, const char *bdstr, char **response) 28 | { 29 | int rc = U2FH_JSON_ERROR; 30 | struct json_object *jo = NULL, *resp = NULL, *bd = NULL; 31 | 32 | bd = json_object_new_string (bdstr); 33 | if (bd == NULL) 34 | goto done; 35 | resp = json_object_new_string (respstr); 36 | if (resp == NULL) 37 | goto done; 38 | 39 | jo = json_object_new_object (); 40 | if (jo == NULL) 41 | goto done; 42 | 43 | json_object_object_add (jo, "registrationData", resp); 44 | json_object_object_add (jo, "clientData", bd); 45 | 46 | *response = strdup (json_object_to_json_string (jo)); 47 | if (*response == NULL) 48 | rc = U2FH_MEMORY_ERROR; 49 | else 50 | rc = U2FH_OK; 51 | 52 | done: 53 | json_object_put (jo); 54 | if (!jo) { 55 | json_object_put (resp); 56 | json_object_put (bd); 57 | } 58 | 59 | return rc; 60 | } 61 | 62 | static int 63 | prepare_response (const unsigned char *buf, int len, const char *bd, 64 | char **response) 65 | { 66 | base64_encodestate b64ctx; 67 | char b64resp[2048]; 68 | char bdstr[2048]; 69 | int cnt; 70 | 71 | if (len > 2048) 72 | return U2FH_MEMORY_ERROR; 73 | if (strlen (bd) > 2048) 74 | return U2FH_MEMORY_ERROR; 75 | 76 | base64_init_encodestate (&b64ctx); 77 | cnt = base64_encode_block (buf, len, b64resp, &b64ctx); 78 | base64_encode_blockend (b64resp + cnt, &b64ctx); 79 | 80 | base64_init_encodestate (&b64ctx); 81 | cnt = base64_encode_block (bd, strlen (bd), bdstr, &b64ctx); 82 | base64_encode_blockend (bdstr + cnt, &b64ctx); 83 | 84 | return prepare_response2 (b64resp, bdstr, response); 85 | } 86 | 87 | #define V2CHALLEN 32 88 | 89 | #define HOSIZE 32 90 | #define NOTSATISFIED "\x69\x85" 91 | 92 | /** 93 | * u2fh_register: 94 | * @devs: a device set handle, from u2fh_devs_init() and u2fh_devs_discover(). 95 | * @challenge: string with JSON data containing the challenge. 96 | * @origin: U2F origin URL. 97 | * @response: pointer to output string with JSON data. 98 | * @flags: set of ORed #u2fh_cmdflags values. 99 | * 100 | * Perform the U2F Register operation. 101 | * 102 | * Returns: On success %U2FH_OK (integer 0) is returned, and on errors 103 | * an #u2fh_rc error code. 104 | */ 105 | u2fh_rc 106 | u2fh_register (u2fh_devs * devs, 107 | const char *challenge, 108 | const char *origin, char **response, u2fh_cmdflags flags) 109 | { 110 | unsigned char data[V2CHALLEN + HOSIZE]; 111 | unsigned char buf[MAXDATASIZE]; 112 | char bd[2048]; 113 | size_t bdlen = sizeof (bd); 114 | size_t len; 115 | int rc = U2FH_JSON_ERROR; 116 | char chalb64[256]; 117 | size_t challen = sizeof (chalb64); 118 | int iterations = 0; 119 | 120 | rc = get_fixed_json_data (challenge, "challenge", chalb64, &challen); 121 | if (rc != U2FH_OK) 122 | { 123 | return rc; 124 | } 125 | 126 | rc = prepare_browserdata (chalb64, origin, REGISTER_TYP, bd, &bdlen); 127 | if (rc != U2FH_OK) 128 | return rc; 129 | 130 | sha256_buffer (bd, bdlen, data); 131 | 132 | prepare_origin (challenge, data + V2CHALLEN); 133 | 134 | /* FIXME: Support asynchronous usage, through a new u2fh_cmdflags 135 | flag. */ 136 | 137 | do 138 | { 139 | int i; 140 | if (iterations++ > 15) 141 | { 142 | return U2FH_TIMEOUT_ERROR; 143 | } 144 | for (i = 0; i < devs->num_devices; i++) 145 | { 146 | if (!devs->devs[i].is_alive) 147 | { 148 | continue; 149 | } 150 | len = MAXDATASIZE; 151 | rc = send_apdu (devs, i, U2F_REGISTER, data, sizeof (data), 152 | flags & U2FH_REQUEST_USER_PRESENCE ? 3 : 0, buf, 153 | &len); 154 | if (rc != U2FH_OK) 155 | { 156 | return rc; 157 | } 158 | else if (len != 2) 159 | { 160 | break; 161 | } 162 | } 163 | if (len != 2) 164 | { 165 | break; 166 | } 167 | if (flags & U2FH_REQUEST_NON_BLOCKING) 168 | { 169 | return U2FH_NOT_FINISHED_ERROR; 170 | } 171 | Sleep (1000); 172 | } 173 | while ((flags & U2FH_REQUEST_USER_PRESENCE) 174 | && len == 2 && memcmp (buf, NOTSATISFIED, 2) == 0); 175 | 176 | if (len != 2) 177 | { 178 | prepare_response (buf, len - 2, bd, response); 179 | return U2FH_OK; 180 | } 181 | return U2FH_TRANSPORT_ERROR; 182 | } 183 | -------------------------------------------------------------------------------- /c_src/libu2f-host/sha256.h: -------------------------------------------------------------------------------- 1 | /* Declarations of functions and data types used for SHA256 and SHA224 sum 2 | library functions. 3 | Copyright (C) 2005-2006, 2008-2015 Free Software Foundation, Inc. 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU Lesser General Public License as published by 7 | the Free Software Foundation, either version 2.1 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU Lesser General Public License for more details. 14 | 15 | You should have received a copy of the GNU Lesser General Public License 16 | along with this program. If not, see . */ 17 | 18 | #ifndef SHA256_H 19 | # define SHA256_H 1 20 | 21 | # include 22 | # include 23 | 24 | # if HAVE_OPENSSL_SHA256 25 | # include 26 | # endif 27 | 28 | # ifdef __cplusplus 29 | extern "C" { 30 | # endif 31 | 32 | enum { SHA224_DIGEST_SIZE = 224 / 8 }; 33 | enum { SHA256_DIGEST_SIZE = 256 / 8 }; 34 | 35 | # if HAVE_OPENSSL_SHA256 36 | # define GL_OPENSSL_NAME 224 37 | # include "gl_openssl.h" 38 | # define GL_OPENSSL_NAME 256 39 | # include "gl_openssl.h" 40 | # else 41 | /* Structure to save state of computation between the single steps. */ 42 | struct sha256_ctx 43 | { 44 | uint32_t state[8]; 45 | 46 | uint32_t total[2]; 47 | size_t buflen; 48 | uint32_t buffer[32]; 49 | }; 50 | 51 | /* Initialize structure containing state of computation. */ 52 | extern void sha256_init_ctx (struct sha256_ctx *ctx); 53 | extern void sha224_init_ctx (struct sha256_ctx *ctx); 54 | 55 | /* Starting with the result of former calls of this function (or the 56 | initialization function update the context for the next LEN bytes 57 | starting at BUFFER. 58 | It is necessary that LEN is a multiple of 64!!! */ 59 | extern void sha256_process_block (const void *buffer, size_t len, 60 | struct sha256_ctx *ctx); 61 | 62 | /* Starting with the result of former calls of this function (or the 63 | initialization function update the context for the next LEN bytes 64 | starting at BUFFER. 65 | It is NOT required that LEN is a multiple of 64. */ 66 | extern void sha256_process_bytes (const void *buffer, size_t len, 67 | struct sha256_ctx *ctx); 68 | 69 | /* Process the remaining bytes in the buffer and put result from CTX 70 | in first 32 (28) bytes following RESBUF. The result is always in little 71 | endian byte order, so that a byte-wise output yields to the wanted 72 | ASCII representation of the message digest. */ 73 | extern void *sha256_finish_ctx (struct sha256_ctx *ctx, void *resbuf); 74 | extern void *sha224_finish_ctx (struct sha256_ctx *ctx, void *resbuf); 75 | 76 | 77 | /* Put result from CTX in first 32 (28) bytes following RESBUF. The result is 78 | always in little endian byte order, so that a byte-wise output yields 79 | to the wanted ASCII representation of the message digest. */ 80 | extern void *sha256_read_ctx (const struct sha256_ctx *ctx, void *resbuf); 81 | extern void *sha224_read_ctx (const struct sha256_ctx *ctx, void *resbuf); 82 | 83 | 84 | /* Compute SHA256 (SHA224) message digest for LEN bytes beginning at BUFFER. The 85 | result is always in little endian byte order, so that a byte-wise 86 | output yields to the wanted ASCII representation of the message 87 | digest. */ 88 | extern void *sha256_buffer (const char *buffer, size_t len, void *resblock); 89 | extern void *sha224_buffer (const char *buffer, size_t len, void *resblock); 90 | 91 | # endif 92 | /* Compute SHA256 (SHA224) message digest for bytes read from STREAM. The 93 | resulting message digest number will be written into the 32 (28) bytes 94 | beginning at RESBLOCK. */ 95 | extern int sha256_stream (FILE *stream, void *resblock); 96 | extern int sha224_stream (FILE *stream, void *resblock); 97 | 98 | 99 | # ifdef __cplusplus 100 | } 101 | # endif 102 | 103 | #endif 104 | -------------------------------------------------------------------------------- /c_src/libu2f-host/stdalign.h.in: -------------------------------------------------------------------------------- 1 | /* A substitute for ISO C11 . 2 | 3 | Copyright 2011-2015 Free Software Foundation, Inc. 4 | 5 | This program is free software; you can redistribute it and/or modify 6 | it under the terms of the GNU Lesser General Public License as published by 7 | the Free Software Foundation; either version 2.1, or (at your option) 8 | any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU Lesser General Public License for more details. 14 | 15 | You should have received a copy of the GNU Lesser General Public License 16 | along with this program; if not, see . */ 17 | 18 | /* Written by Paul Eggert and Bruno Haible. */ 19 | 20 | #ifndef _GL_STDALIGN_H 21 | #define _GL_STDALIGN_H 22 | 23 | /* ISO C11 for platforms that lack it. 24 | 25 | References: 26 | ISO C11 (latest free draft 27 | ) 28 | sections 6.5.3.4, 6.7.5, 7.15. 29 | C++11 (latest free draft 30 | ) 31 | section 18.10. */ 32 | 33 | /* alignof (TYPE), also known as _Alignof (TYPE), yields the alignment 34 | requirement of a structure member (i.e., slot or field) that is of 35 | type TYPE, as an integer constant expression. 36 | 37 | This differs from GCC's __alignof__ operator, which can yield a 38 | better-performing alignment for an object of that type. For 39 | example, on x86 with GCC, __alignof__ (double) and __alignof__ 40 | (long long) are 8, whereas alignof (double) and alignof (long long) 41 | are 4 unless the option '-malign-double' is used. 42 | 43 | The result cannot be used as a value for an 'enum' constant, if you 44 | want to be portable to HP-UX 10.20 cc and AIX 3.2.5 xlc. 45 | 46 | Include for offsetof. */ 47 | #include 48 | 49 | /* FreeBSD 9.1 , included by and lots of other 50 | standard headers, defines conflicting implementations of _Alignas 51 | and _Alignof that are no better than ours; override them. */ 52 | #undef _Alignas 53 | #undef _Alignof 54 | 55 | #if !defined __STDC_VERSION__ || __STDC_VERSION__ < 201112 56 | # ifdef __cplusplus 57 | # if 201103 <= __cplusplus 58 | # define _Alignof(type) alignof (type) 59 | # else 60 | template struct __alignof_helper { char __a; __t __b; }; 61 | # define _Alignof(type) offsetof (__alignof_helper, __b) 62 | # endif 63 | # else 64 | # define _Alignof(type) offsetof (struct { char __a; type __b; }, __b) 65 | # endif 66 | #endif 67 | #define alignof _Alignof 68 | #define __alignof_is_defined 1 69 | 70 | /* alignas (A), also known as _Alignas (A), aligns a variable or type 71 | to the alignment A, where A is an integer constant expression. For 72 | example: 73 | 74 | int alignas (8) foo; 75 | struct s { int a; int alignas (8) bar; }; 76 | 77 | aligns the address of FOO and the offset of BAR to be multiples of 8. 78 | 79 | A should be a power of two that is at least the type's alignment 80 | and at most the implementation's alignment limit. This limit is 81 | 2**28 on typical GNUish hosts, and 2**13 on MSVC. To be portable 82 | to MSVC through at least version 10.0, A should be an integer 83 | constant, as MSVC does not support expressions such as 1 << 3. 84 | To be portable to Sun C 5.11, do not align auto variables to 85 | anything stricter than their default alignment. 86 | 87 | The following C11 requirements are not supported here: 88 | 89 | - If A is zero, alignas has no effect. 90 | - alignas can be used multiple times; the strictest one wins. 91 | - alignas (TYPE) is equivalent to alignas (alignof (TYPE)). 92 | 93 | */ 94 | 95 | #if !defined __STDC_VERSION__ || __STDC_VERSION__ < 201112 96 | # if defined __cplusplus && 201103 <= __cplusplus 97 | # define _Alignas(a) alignas (a) 98 | # elif ((defined __APPLE__ && defined __MACH__ \ 99 | ? 4 < __GNUC__ + (1 <= __GNUC_MINOR__) \ 100 | : __GNUC__) \ 101 | || __HP_cc || __HP_aCC || __IBMC__ || __IBMCPP__ \ 102 | || __ICC || 0x5110 <= __SUNPRO_C) 103 | # define _Alignas(a) __attribute__ ((__aligned__ (a))) 104 | # elif 1300 <= _MSC_VER 105 | # define _Alignas(a) __declspec (align (a)) 106 | # endif 107 | #endif 108 | #if defined _Alignas || (defined __STDC_VERSION && 201112 <= __STDC_VERSION__) 109 | # define alignas _Alignas 110 | # define __alignas_is_defined 1 111 | #endif 112 | 113 | #endif /* _GL_STDALIGN_H */ 114 | -------------------------------------------------------------------------------- /c_src/libu2f-host/u2f-host-types.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2013-2015 Yubico AB 3 | 4 | This program is free software; you can redistribute it and/or modify it 5 | under the terms of the GNU Lesser General Public License as published by 6 | the Free Software Foundation; either version 2.1, or (at your option) any 7 | later version. 8 | 9 | This program is distributed in the hope that it will be useful, but 10 | WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 12 | General Public License for more details. 13 | 14 | You should have received a copy of the GNU Lesser General Public License 15 | along with this program; if not, see . 16 | */ 17 | 18 | #ifndef U2F_HOST_TYPES_H 19 | #define U2F_HOST_TYPES_H 20 | 21 | /** 22 | * u2fh_rc: 23 | * @U2FH_OK: Success. 24 | * @U2FH_MEMORY_ERROR: Memory error. 25 | * @U2FH_TRANSPORT_ERROR: Transport (e.g., USB) error. 26 | * @U2FH_JSON_ERROR: Json error. 27 | * @U2FH_BASE64_ERROR: Base64 error. 28 | * @U2FH_NO_U2F_DEVICE: Missing U2F device. 29 | * @U2FH_AUTHENTICATOR_ERROR: Authenticator error. 30 | * @U2FH_TIMEOUT_ERROR: Timeout error. 31 | * 32 | * Error codes. 33 | */ 34 | typedef enum 35 | { 36 | U2FH_OK = 0, 37 | U2FH_MEMORY_ERROR = -1, 38 | U2FH_TRANSPORT_ERROR = -2, 39 | U2FH_JSON_ERROR = -3, 40 | U2FH_BASE64_ERROR = -4, 41 | U2FH_NO_U2F_DEVICE = -5, 42 | U2FH_AUTHENTICATOR_ERROR = -6, 43 | U2FH_TIMEOUT_ERROR = -7, 44 | U2FH_NOT_FINISHED_ERROR = -8, 45 | } u2fh_rc; 46 | 47 | /** 48 | * u2fh_initflags: 49 | * @U2FH_DEBUG: Print debug messages. 50 | * 51 | * Flags passed to u2fh_global_init(). 52 | */ 53 | typedef enum 54 | { 55 | U2FH_DEBUG = 1 56 | } u2fh_initflags; 57 | 58 | /** 59 | * u2fh_cmdflags: 60 | * @U2FH_REQUEST_USER_PRESENCE: Request user precense. 61 | * 62 | * Flags passed to u2fh_register() and u2fh_authenticate(). 63 | */ 64 | typedef enum 65 | { 66 | U2FH_REQUEST_USER_PRESENCE = 1, 67 | U2FH_REQUEST_NON_BLOCKING = 2 68 | } u2fh_cmdflags; 69 | 70 | typedef struct u2fh_devs u2fh_devs; 71 | 72 | #endif 73 | -------------------------------------------------------------------------------- /c_src/libu2f-host/u2f-host-version.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2013-2015 Yubico AB 3 | 4 | This program is free software; you can redistribute it and/or modify it 5 | under the terms of the GNU Lesser General Public License as published by 6 | the Free Software Foundation; either version 2.1, or (at your option) any 7 | later version. 8 | 9 | This program is distributed in the hope that it will be useful, but 10 | WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 12 | General Public License for more details. 13 | 14 | You should have received a copy of the GNU Lesser General Public License 15 | along with this program; if not, see . 16 | */ 17 | 18 | #ifndef U2F_HOST_VERSION_H 19 | #define U2F_HOST_VERSION_H 20 | 21 | #ifdef __cplusplus 22 | extern "C" 23 | { 24 | #endif 25 | 26 | /** 27 | * U2FH_VERSION_STRING 28 | * 29 | * Pre-processor symbol with a string that describe the header file 30 | * version number. Used together with u2fh_check_version() to verify 31 | * header file and run-time library consistency. 32 | */ 33 | #define U2FH_VERSION_STRING "1.0.1" 34 | 35 | /** 36 | * U2FH_VERSION_NUMBER 37 | * 38 | * Pre-processor symbol with a hexadecimal value describing the header 39 | * file version number. For example, when the header version is 1.2.3 40 | * this symbol will have the value 0x01020300. The last two digits 41 | * are only used between public releases, and will otherwise be 00. 42 | */ 43 | #define U2FH_VERSION_NUMBER 0x010001 44 | 45 | /** 46 | * U2FH_VERSION_MAJOR 47 | * 48 | * Pre-processor symbol with a decimal value that describe the major 49 | * level of the header file version number. For example, when the 50 | * header version is 1.2.3 this symbol will be 1. 51 | */ 52 | #define U2FH_VERSION_MAJOR 1 53 | 54 | /** 55 | * U2FH_VERSION_MINOR 56 | * 57 | * Pre-processor symbol with a decimal value that describe the minor 58 | * level of the header file version number. For example, when the 59 | * header version is 1.2.3 this symbol will be 2. 60 | */ 61 | #define U2FH_VERSION_MINOR 0 62 | 63 | /** 64 | * U2FH_VERSION_PATCH 65 | * 66 | * Pre-processor symbol with a decimal value that describe the patch 67 | * level of the header file version number. For example, when the 68 | * header version is 1.2.3 this symbol will be 3. 69 | */ 70 | #define U2FH_VERSION_PATCH 1 71 | 72 | const char *u2fh_check_version (const char *req_version); 73 | 74 | #ifdef __cplusplus 75 | } 76 | #endif 77 | #endif 78 | -------------------------------------------------------------------------------- /c_src/libu2f-host/u2f-host.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2013-2015 Yubico AB 3 | 4 | This program is free software; you can redistribute it and/or modify it 5 | under the terms of the GNU Lesser General Public License as published by 6 | the Free Software Foundation; either version 2.1, or (at your option) any 7 | later version. 8 | 9 | This program is distributed in the hope that it will be useful, but 10 | WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 12 | General Public License for more details. 13 | 14 | You should have received a copy of the GNU Lesser General Public License 15 | along with this program; if not, see . 16 | */ 17 | 18 | #ifndef U2F_HOST_H 19 | #define U2F_HOST_H 20 | 21 | #include 22 | #include 23 | 24 | #include 25 | #include 26 | 27 | #ifdef __cplusplus 28 | extern "C" 29 | { 30 | #endif 31 | 32 | /* Must be called successfully before using any other functions. */ 33 | extern u2fh_rc u2fh_global_init (u2fh_initflags flags); 34 | extern void u2fh_global_done (void); 35 | 36 | extern const char *u2fh_strerror (int err); 37 | extern const char *u2fh_strerror_name (int err); 38 | 39 | extern u2fh_rc u2fh_devs_init (u2fh_devs ** devs); 40 | extern u2fh_rc u2fh_devs_discover (u2fh_devs * devs, unsigned *max_index); 41 | extern void u2fh_devs_done (u2fh_devs * devs); 42 | 43 | extern u2fh_rc u2fh_register (u2fh_devs * devs, 44 | const char *challenge, 45 | const char *origin, 46 | char **response, u2fh_cmdflags flags); 47 | 48 | extern u2fh_rc u2fh_authenticate (u2fh_devs * devs, 49 | const char *challenge, 50 | const char *origin, 51 | char **response, u2fh_cmdflags flags); 52 | 53 | extern u2fh_rc u2fh_sendrecv (u2fh_devs * devs, 54 | unsigned index, 55 | uint8_t cmd, 56 | const unsigned char *send, 57 | uint16_t sendlen, 58 | unsigned char *recv, size_t * recvlen); 59 | 60 | extern u2fh_rc u2fh_get_device_description (u2fh_devs * devs, 61 | unsigned index, char *out, 62 | size_t * len); 63 | 64 | extern int u2fh_is_alive (u2fh_devs * devs, unsigned index); 65 | 66 | #ifdef __cplusplus 67 | } 68 | #endif 69 | #endif 70 | -------------------------------------------------------------------------------- /c_src/libu2f-host/u2fmisc.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2013-2015 Yubico AB 3 | 4 | This program is free software; you can redistribute it and/or modify it 5 | under the terms of the GNU Lesser General Public License as published by 6 | the Free Software Foundation; either version 2.1, or (at your option) any 7 | later version. 8 | 9 | This program is distributed in the hope that it will be useful, but 10 | WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 12 | General Public License for more details. 13 | 14 | You should have received a copy of the GNU Lesser General Public License 15 | along with this program; if not, see . 16 | */ 17 | 18 | #include 19 | #include "internal.h" 20 | 21 | #include 22 | 23 | #include "sha256.h" 24 | 25 | #define RESPHEAD_SIZE 7 26 | #define HID_TIMEOUT 2 27 | #define HID_MAX_TIMEOUT 4096 28 | 29 | #ifdef HAVE_JSON_OBJECT_OBJECT_GET_EX 30 | #define u2fh_json_object_object_get(obj, key, value) json_object_object_get_ex(obj, key, &value) 31 | #else 32 | typedef int json_bool; 33 | #define u2fh_json_object_object_get(obj, key, value) (value = json_object_object_get(obj, key)) == NULL ? (json_bool)FALSE : (json_bool)TRUE 34 | #endif 35 | 36 | static void 37 | dumpHex (unsigned char *data, int offs, int len) 38 | { 39 | int i; 40 | for (i = offs; i < len; i++) 41 | { 42 | fprintf (stderr, "%02x", data[i] & 0xFF); 43 | } 44 | fprintf (stderr, "\n"); 45 | } 46 | 47 | int 48 | prepare_browserdata (const char *challenge, const char *origin, 49 | const char *typstr, char *out, size_t * outlen) 50 | { 51 | int rc = U2FH_JSON_ERROR; 52 | struct json_object *jo = NULL; 53 | struct json_object *chal = NULL, *orig = NULL, *typ = NULL; 54 | const char *buf; 55 | size_t len; 56 | 57 | chal = json_object_new_string (challenge); 58 | if (chal == NULL) 59 | goto done; 60 | 61 | orig = json_object_new_string (origin); 62 | if (orig == NULL) 63 | goto done; 64 | 65 | typ = json_object_new_string (typstr); 66 | if (typ == NULL) 67 | goto done; 68 | 69 | jo = json_object_new_object (); 70 | if (jo == NULL) 71 | goto done; 72 | 73 | json_object_object_add (jo, "challenge", chal); 74 | json_object_object_add (jo, "origin", orig); 75 | json_object_object_add (jo, "typ", typ); 76 | 77 | if (debug) 78 | { 79 | fprintf (stderr, "client data: %s\n", json_object_to_json_string (jo)); 80 | } 81 | 82 | buf = json_object_to_json_string (jo); 83 | len = strlen (buf); 84 | if (len >= *outlen) 85 | { 86 | rc = U2FH_MEMORY_ERROR; 87 | goto done; 88 | } 89 | 90 | strcpy (out, buf); 91 | *outlen = len; 92 | rc = U2FH_OK; 93 | 94 | done: 95 | json_object_put (jo); 96 | if (!jo) { 97 | json_object_put (chal); 98 | json_object_put (orig); 99 | json_object_put (typ); 100 | } 101 | return rc; 102 | } 103 | 104 | int 105 | prepare_origin (const char *jsonstr, unsigned char *p) 106 | { 107 | const char *app_id; 108 | struct json_object *jo; 109 | struct json_object *k; 110 | 111 | jo = json_tokener_parse (jsonstr); 112 | if (jo == NULL) 113 | return U2FH_MEMORY_ERROR; 114 | 115 | if (debug) 116 | fprintf (stderr, "JSON: %s\n", json_object_to_json_string (jo)); 117 | 118 | if (u2fh_json_object_object_get (jo, "appId", k) == FALSE) 119 | return U2FH_JSON_ERROR; 120 | 121 | app_id = json_object_get_string (k); 122 | if (app_id == NULL) 123 | return U2FH_JSON_ERROR; 124 | 125 | if (debug) 126 | fprintf (stderr, "JSON app_id %s\n", app_id); 127 | 128 | sha256_buffer (app_id ? app_id : "", app_id ? strlen (app_id) : 0, p); 129 | 130 | json_object_put (jo); 131 | 132 | return U2FH_OK; 133 | } 134 | 135 | /** 136 | * u2fh_sendrecv: 137 | * @devs: device handle, from u2fh_devs_init(). 138 | * @index: index of device 139 | * @cmd: command to run 140 | * @send: buffer of data to send 141 | * @sendlen: length of data to send 142 | * @recv: buffer of data to receive 143 | * @recvlen: length of data to receive 144 | * 145 | * Send a command with data to the device at @index. 146 | * 147 | * Returns: %U2FH_OK on success, another #u2fh_rc error code 148 | * otherwise. 149 | */ 150 | u2fh_rc 151 | u2fh_sendrecv (u2fh_devs * devs, unsigned index, uint8_t cmd, 152 | const unsigned char *send, uint16_t sendlen, 153 | unsigned char *recv, size_t * recvlen) 154 | { 155 | int datasent = 0; 156 | int sequence = 0; 157 | struct u2fdevice *dev; 158 | 159 | if (index >= devs->num_devices || !devs->devs[index].is_alive) 160 | { 161 | return U2FH_NO_U2F_DEVICE; 162 | } 163 | 164 | dev = &devs->devs[index]; 165 | 166 | while (sendlen > datasent) 167 | { 168 | U2FHID_FRAME frame = { 0 }; 169 | { 170 | int len = sendlen - datasent; 171 | int maxlen; 172 | unsigned char *data; 173 | frame.cid = dev->cid; 174 | if (datasent == 0) 175 | { 176 | frame.init.cmd = cmd; 177 | frame.init.bcnth = (sendlen >> 8) & 0xff; 178 | frame.init.bcntl = sendlen & 0xff; 179 | data = frame.init.data; 180 | maxlen = sizeof (frame.init.data); 181 | } 182 | else 183 | { 184 | frame.cont.seq = sequence++; 185 | data = frame.cont.data; 186 | maxlen = sizeof (frame.cont.data); 187 | } 188 | if (len > maxlen) 189 | { 190 | len = maxlen; 191 | } 192 | memcpy (data, send + datasent, len); 193 | datasent += len; 194 | } 195 | 196 | { 197 | unsigned char data[sizeof (U2FHID_FRAME) + 1]; 198 | int len; 199 | /* FIXME: add report as first byte, is report 0 correct? */ 200 | data[0] = 0; 201 | memcpy (data + 1, &frame, sizeof (U2FHID_FRAME)); 202 | if (debug) 203 | { 204 | fprintf (stderr, "USB send: "); 205 | dumpHex (data, 0, sizeof (U2FHID_FRAME)); 206 | } 207 | 208 | len = hid_write (dev->devh, data, sizeof (U2FHID_FRAME) + 1); 209 | if (debug) 210 | fprintf (stderr, "USB write returned %d\n", len); 211 | if (len < 0) 212 | return U2FH_TRANSPORT_ERROR; 213 | if (sizeof (U2FHID_FRAME) + 1 != len) 214 | return U2FH_TRANSPORT_ERROR; 215 | } 216 | } 217 | 218 | { 219 | U2FHID_FRAME frame; 220 | unsigned char data[HID_RPT_SIZE]; 221 | int len = HID_RPT_SIZE; 222 | int maxlen = *recvlen; 223 | int recvddata = 0; 224 | short datalen; 225 | int timeout = HID_TIMEOUT; 226 | int rc = 0; 227 | 228 | while (rc == 0) 229 | { 230 | if (debug) 231 | { 232 | fprintf (stderr, "now trying with timeout %d\n", timeout); 233 | } 234 | rc = hid_read_timeout (dev->devh, data, len, timeout); 235 | timeout *= 2; 236 | if (timeout > HID_MAX_TIMEOUT) 237 | { 238 | rc = -2; 239 | break; 240 | } 241 | } 242 | sequence = 0; 243 | 244 | if (debug) 245 | { 246 | fprintf (stderr, "USB read rc read %d\n", len); 247 | if (rc > 0) 248 | { 249 | fprintf (stderr, "USB recv: "); 250 | dumpHex (data, 0, rc); 251 | } 252 | } 253 | if (rc < 0) 254 | { 255 | return U2FH_TRANSPORT_ERROR; 256 | } 257 | 258 | memcpy (&frame, data, HID_RPT_SIZE); 259 | if (frame.cid != dev->cid || frame.init.cmd != cmd) 260 | { 261 | return U2FH_TRANSPORT_ERROR; 262 | } 263 | datalen = frame.init.bcnth << 8 | frame.init.bcntl; 264 | if (datalen + datalen % HID_RPT_SIZE > maxlen) 265 | { 266 | return U2FH_TRANSPORT_ERROR; 267 | } 268 | memcpy (recv, frame.init.data, sizeof (frame.init.data)); 269 | recvddata = sizeof (frame.init.data); 270 | 271 | while (datalen > recvddata) 272 | { 273 | timeout = HID_TIMEOUT; 274 | rc = 0; 275 | while (rc == 0) 276 | { 277 | if (debug) 278 | { 279 | fprintf (stderr, "now trying with timeout %d\n", timeout); 280 | } 281 | rc = hid_read_timeout (dev->devh, data, len, timeout); 282 | timeout *= 2; 283 | if (timeout > HID_MAX_TIMEOUT) 284 | { 285 | rc = -2; 286 | break; 287 | } 288 | } 289 | if (debug) 290 | { 291 | fprintf (stderr, "USB read rc read %d\n", len); 292 | if (rc > 0) 293 | { 294 | fprintf (stderr, "USB recv: "); 295 | dumpHex (data, 0, rc); 296 | } 297 | } 298 | if (rc < 0) 299 | { 300 | return U2FH_TRANSPORT_ERROR; 301 | } 302 | 303 | memcpy (&frame, data, HID_RPT_SIZE); 304 | if (frame.cid != dev->cid || frame.cont.seq != sequence++) 305 | { 306 | fprintf (stderr, "bar: %d %d %d %d\n", frame.cid, dev->cid, 307 | frame.cont.seq, sequence); 308 | return U2FH_TRANSPORT_ERROR; 309 | } 310 | memcpy (recv + recvddata, frame.cont.data, sizeof (frame.cont.data)); 311 | recvddata += sizeof (frame.cont.data); 312 | } 313 | *recvlen = datalen; 314 | } 315 | return U2FH_OK; 316 | } 317 | 318 | u2fh_rc 319 | send_apdu (u2fh_devs * devs, int index, int cmd, const unsigned char *d, 320 | size_t dlen, int p1, unsigned char *out, size_t * outlen) 321 | { 322 | unsigned char data[2048]; 323 | int rc; 324 | 325 | if (dlen > MAXDATASIZE) 326 | return U2FH_MEMORY_ERROR; 327 | 328 | sprintf (data, "%c%c%c%c%c%c%c", 0, cmd, p1, 0, 0, (dlen >> 8) & 0xff, 329 | dlen & 0xff); 330 | memcpy (data + RESPHEAD_SIZE, d, dlen); 331 | memset (data + RESPHEAD_SIZE + dlen, 0, 2); 332 | 333 | rc = 334 | u2fh_sendrecv (devs, index, U2FHID_MSG, data, RESPHEAD_SIZE + dlen + 2, out, 335 | outlen); 336 | if (rc != U2FH_OK) 337 | { 338 | if (debug) 339 | fprintf (stderr, "USB rc %d\n", rc); 340 | return rc; 341 | } 342 | if (*outlen < 2) 343 | { 344 | if (debug) 345 | fprintf (stderr, "USB read too short\n"); 346 | return U2FH_TRANSPORT_ERROR; 347 | } 348 | 349 | if (*outlen > MAXDATASIZE) 350 | { 351 | if (debug) 352 | fprintf (stderr, "USB too large response?\n"); 353 | return U2FH_MEMORY_ERROR; 354 | } 355 | 356 | /* FIXME: Improve APDU error handling? */ 357 | 358 | if (debug) 359 | { 360 | fprintf (stderr, "USB data (len %zu): ", *outlen); 361 | dumpHex (out, 0, *outlen); 362 | } 363 | 364 | return U2FH_OK; 365 | } 366 | 367 | int 368 | get_fixed_json_data (const char *jsonstr, const char *key, char *p, 369 | size_t * len) 370 | { 371 | struct json_object *jo; 372 | struct json_object *k; 373 | const char *urlb64; 374 | 375 | jo = json_tokener_parse (jsonstr); 376 | if (jo == NULL) 377 | return U2FH_JSON_ERROR; 378 | 379 | if (debug) 380 | fprintf (stderr, "JSON: %s\n", json_object_to_json_string (jo)); 381 | 382 | if (u2fh_json_object_object_get (jo, key, k) == FALSE) 383 | return U2FH_JSON_ERROR; 384 | 385 | urlb64 = json_object_get_string (k); 386 | if (urlb64 == NULL) 387 | return U2FH_JSON_ERROR; 388 | 389 | if (debug) 390 | fprintf (stderr, "JSON %s URL-B64: %s\n", key, urlb64); 391 | 392 | if (strlen (urlb64) >= *len) 393 | { 394 | return U2FH_JSON_ERROR; 395 | } 396 | *len = strlen (urlb64); 397 | 398 | strcpy (p, urlb64); 399 | 400 | json_object_put (jo); 401 | 402 | return U2FH_OK; 403 | } 404 | -------------------------------------------------------------------------------- /c_src/main.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2013-2015 Yubico AB 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see . 16 | */ 17 | 18 | #include "u2f-host.h" 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | #ifdef _WIN32 25 | #include 26 | #else 27 | 28 | #include 29 | #include 30 | 31 | #endif 32 | 33 | #define TIMEOUT 60 34 | 35 | typedef struct { 36 | int op; 37 | char *domain; 38 | char **challenges; 39 | } OP; 40 | 41 | static OP eof_op = {'e'}; 42 | 43 | static int 44 | read_n_bytes(char *buf, size_t len) { 45 | while (len > 0) { 46 | long r = read(0, buf, len); 47 | if (!r) 48 | return 0; 49 | buf += r; 50 | len -= r; 51 | } 52 | return 1; 53 | } 54 | 55 | #define READ_LEN(buf, val) do {long read_len = strtol(buf, NULL, 16); if (read_len <= 0) return &eof_op; val = read_len;} while(0) 56 | 57 | static OP * 58 | read_action(int timeout) { 59 | #ifdef _WIN32 60 | HANDLE hIn = GetStdHandle(STD_INPUT_HANDLE); 61 | DWORD available; 62 | 63 | PeekNamedPipe(hIn, NULL, 0, NULL, &available, NULL); 64 | if (available == 0) 65 | return NULL; 66 | #else 67 | struct pollfd pfd[] = {{0, POLLIN, 0}}; 68 | poll(pfd, 1, timeout); 69 | if ((pfd[0].revents & (POLLIN | POLLERR | POLLHUP)) == 0) 70 | return NULL; 71 | #endif 72 | char op; 73 | 74 | if (read(0, &op, 1) == 0) 75 | return &eof_op; 76 | 77 | if (op == 'r' || op == 's') { 78 | char input_buf[9]; 79 | size_t challenges_lengths[16]; 80 | size_t challenges_num, challenges_buf_len = 0, domain_len; 81 | int i; 82 | 83 | if (!read_n_bytes(input_buf, 8)) 84 | return &eof_op; 85 | 86 | input_buf[8] = '\0'; 87 | READ_LEN(input_buf + 4, challenges_num); 88 | input_buf[4] = '\0'; 89 | READ_LEN(input_buf, domain_len); 90 | 91 | if (challenges_num >= sizeof(challenges_lengths) / sizeof(challenges_lengths[0])) 92 | return &eof_op; 93 | 94 | for (i = 0; i < challenges_num; i++) { 95 | if (!read_n_bytes(input_buf, 4)) 96 | return &eof_op; 97 | READ_LEN(input_buf, challenges_lengths[i]); 98 | challenges_buf_len += challenges_lengths[i]; 99 | } 100 | 101 | OP *buf = malloc(domain_len + (sizeof(char *) * (challenges_num + 1)) + 102 | challenges_buf_len + challenges_num + 1 + sizeof(OP)); 103 | if (!buf) 104 | return &eof_op; 105 | 106 | buf->op = op; 107 | buf->challenges = (char **) (buf + 1); 108 | buf->domain = (char *) (buf->challenges + challenges_num + 1); 109 | buf->domain[domain_len] = '\0'; 110 | 111 | if (!read_n_bytes(buf->domain, domain_len)) { 112 | free(buf); 113 | return &eof_op; 114 | } 115 | 116 | char *challenge = buf->domain + domain_len + 1; 117 | for (i = 0; i < challenges_num; i++) { 118 | buf->challenges[i] = challenge; 119 | if (!read_n_bytes(buf->challenges[i], challenges_lengths[i])) { 120 | free(buf); 121 | return &eof_op; 122 | } 123 | challenge[challenges_lengths[i]] = '\0'; 124 | challenge += challenges_lengths[i]; 125 | } 126 | buf->challenges[challenges_num] = NULL; 127 | return buf; 128 | } else 129 | return &eof_op; 130 | } 131 | 132 | static void 133 | report_error(u2fh_rc rc, char *label) { 134 | char buf[1024]; 135 | int code = rc == U2FH_AUTHENTICATOR_ERROR ? 4 : 136 | rc == U2FH_MEMORY_ERROR || rc == U2FH_TRANSPORT_ERROR ? 1 : 137 | rc == U2FH_TIMEOUT_ERROR ? 5 : 2; 138 | 139 | if (label) 140 | sprintf(buf, "{\"errorCode\": %d, \"errorMessage\":\"%s:%s\"}", 141 | code, label, u2fh_strerror(rc)); 142 | else 143 | sprintf(buf, "{\"errorCode\": %d}", code); 144 | 145 | printf("e%04lx%s", strlen(buf), buf); 146 | 147 | fflush(stdout); 148 | } 149 | 150 | #ifdef _WIN32 151 | static HANDLE timer_handle = NULL; 152 | 153 | static VOID CALLBACK 154 | WaitOrTimerCallback(PVOID param, BOOLEAN timerFired) { 155 | exit(14); 156 | } 157 | 158 | static void 159 | reset_quit_timer() { 160 | if (timer_handle) 161 | DeleteTimerQueueTimer(NULL, timer_handle, NULL); 162 | 163 | CreateTimerQueueTimer(&timer_handle, NULL, &WaitOrTimerCallback, 164 | NULL, TIMEOUT*1000, 0, 0); 165 | } 166 | #else 167 | 168 | static void 169 | reset_quit_timer() { 170 | signal(SIGALRM, exit); 171 | alarm(TIMEOUT); 172 | } 173 | 174 | #endif 175 | 176 | int 177 | main(int argc, char *argv[]) { 178 | int exit_code = EXIT_FAILURE; 179 | char *response = NULL; 180 | u2fh_devs *devs = NULL; 181 | u2fh_rc rc; 182 | OP *action = NULL; 183 | char device_state = 'u'; 184 | u2fh_rc device_disappeared_rc = U2FH_OK; 185 | char *device_disappeared_msg = NULL; 186 | 187 | reset_quit_timer(); 188 | 189 | rc = u2fh_global_init(0); 190 | if (rc != U2FH_OK) { 191 | report_error(rc, "global_init"); 192 | exit(1); 193 | } 194 | 195 | rc = u2fh_devs_init(&devs); 196 | if (rc != U2FH_OK) { 197 | report_error(rc, "devs_init"); 198 | goto done; 199 | } 200 | 201 | while (1) { 202 | int need_sleep = 1; 203 | rc = u2fh_devs_discover(devs, NULL); 204 | if (device_disappeared_rc != U2FH_OK && rc != U2FH_NO_U2F_DEVICE) { 205 | report_error(device_disappeared_rc, device_disappeared_msg); 206 | 207 | free(response); 208 | free(action); 209 | action = NULL; 210 | } 211 | if (rc != U2FH_OK && rc != U2FH_NO_U2F_DEVICE) { 212 | report_error(rc, "devs_discover"); 213 | goto done; 214 | } 215 | 216 | if (rc == U2FH_OK && device_state == 'm') { 217 | printf("j"); 218 | fflush(stdout); 219 | device_state = 'p'; 220 | need_sleep = 0; 221 | } 222 | 223 | if (rc == U2FH_NO_U2F_DEVICE && device_state != 'm') { 224 | printf("i"); 225 | fflush(stdout); 226 | device_state = 'm'; 227 | } 228 | 229 | device_disappeared_rc = U2FH_OK; 230 | 231 | if (!action) { 232 | action = read_action(1000); 233 | if (action) 234 | reset_quit_timer(); 235 | } else if (need_sleep) 236 | sleep(1); 237 | 238 | if (action && (rc == U2FH_OK || action->op == 'e')) { 239 | if (action->op == 'e') 240 | goto done; 241 | else if (action->op == 'r' || action->op == 's') { 242 | int requests_count = 0; 243 | do { 244 | int i = 0; 245 | do { 246 | if (action->op == 'r') { 247 | rc = u2fh_register(devs, action->challenges[i], action->domain, 248 | &response, 249 | U2FH_REQUEST_USER_PRESENCE | U2FH_REQUEST_NON_BLOCKING); 250 | } else { 251 | rc = u2fh_authenticate(devs, action->challenges[i], action->domain, 252 | &response, 253 | U2FH_REQUEST_USER_PRESENCE | U2FH_REQUEST_NON_BLOCKING); 254 | } 255 | i++; 256 | } while (action->challenges[i] && rc == U2FH_AUTHENTICATOR_ERROR); 257 | 258 | if (rc == U2FH_NOT_FINISHED_ERROR) { 259 | if (device_state != 'b') { 260 | printf("b"); 261 | fflush(stdout); 262 | device_state = 'b'; 263 | } 264 | sleep(1); 265 | } else 266 | break; 267 | } while (requests_count++ < 15); 268 | 269 | if (requests_count >= 15) { 270 | report_error(U2FH_TIMEOUT_ERROR, NULL); 271 | } else if (rc != U2FH_OK) { 272 | device_disappeared_rc = rc; 273 | device_disappeared_msg = action->op == 'r' ? "register" : "authenticate"; 274 | continue; 275 | } else { 276 | printf("r%04lx%s", strlen(response), response); 277 | fflush(stdout); 278 | } 279 | 280 | free(response); 281 | free(action); 282 | action = NULL; 283 | } else { 284 | report_error(U2FH_TRANSPORT_ERROR, NULL); 285 | goto done; 286 | } 287 | } 288 | } 289 | 290 | done: 291 | u2fh_devs_done(devs); 292 | u2fh_global_done(); 293 | 294 | exit(exit_code); 295 | } 296 | -------------------------------------------------------------------------------- /ext/appIdValidator.js: -------------------------------------------------------------------------------- 1 | /* global exports, console:true */ 2 | "use strict"; 3 | 4 | const { Request } = require("sdk/request"); 5 | const { resolve, reject, defer } = require('sdk/core/promise'); 6 | const { URL, getTLD } = require("sdk/url"); 7 | 8 | function allValid(promises) { 9 | const { resolve, promise } = defer(); 10 | 11 | if (promises.length == 0) { 12 | resolve([]); 13 | return promise; 14 | } 15 | 16 | var goodValues = []; 17 | var valuesLeft = {count: promises.length}; 18 | 19 | var finished = function() { 20 | if (--valuesLeft.count) 21 | return; 22 | resolve(goodValues.sort((a,b) => a[0] - b[0]).map(v=>v[1])); 23 | }; 24 | 25 | promises.forEach((p,i) => p.then(v => { 26 | goodValues.push([i, v]); 27 | finished(); 28 | }).catch(v => { 29 | console.info("Failed resolve", v); 30 | finished(); 31 | })); 32 | 33 | return promise; 34 | } 35 | 36 | function fetchTrustedFacetsList(url) { 37 | const { resolve, reject, promise } = defer(); 38 | let r = new Request({ 39 | url: url, 40 | anonymous: true, 41 | onComplete: res => { 42 | if (res.status < 200 || res.status > 399) 43 | return reject("Can't fetch trusted facets list"); 44 | 45 | let found = false; 46 | for (let n in res.headers) { 47 | if (n.toLowerCase() == "content-type") { 48 | if (res.headers[n] == "application/fido.trusted-apps+json") 49 | found = true; 50 | break; 51 | } 52 | } 53 | if (!found) 54 | return reject("Invalid content-type when fetching trusted facets list"); 55 | 56 | if (!res.json || !res.json.trustedFacets || !Array.isArray(res.json.trustedFacets)) 57 | return reject("Invalid content of trusted facets list"); 58 | 59 | let facets = res.json.trustedFacets.filter(v => v.version && 60 | v.version.major == 1 && v.version.minor == 0); 61 | if (facets.length != 1) 62 | return reject("No trusted facet with version 1.0"); 63 | 64 | resolve(facets[0].ids); 65 | } 66 | }); 67 | r.get(); 68 | return promise; 69 | } 70 | 71 | function url2str(url, includePath) { 72 | let port; 73 | if (!url.port || (url.scheme == "https" && url.port == 433) || 74 | (url.scheme == "http" && url.port == 80)) 75 | port = ""; 76 | else 77 | port = ":" + url.port; 78 | 79 | return url.scheme + "://" + url.host + port + (includePath ? url.path : ""); 80 | } 81 | 82 | function getTLDPlusOne(url) { 83 | if (typeof(url) == "string") { 84 | try { 85 | url = URL(url); 86 | } catch (ex) { 87 | return ""; 88 | } 89 | } 90 | 91 | let tld = getTLD(url); 92 | return url.host.slice(0, -tld.length - 1).replace(/.*\.([^.]+)$/, "$1") + "." + tld; 93 | } 94 | 95 | function hasValidAppId(facetId, challenge) { 96 | try { 97 | let ou = URL(facetId); 98 | 99 | if (!challenge.appId) { 100 | challenge.appId = url2str(ou, true); 101 | return resolve(challenge); 102 | } 103 | 104 | let u = URL(challenge.appId); 105 | 106 | if (u.scheme == "http") 107 | if (url2str(u, true) == url2str(ou, true)) 108 | return resolve(challenge); 109 | else 110 | return reject("Not matching appID"); 111 | 112 | if (url2str(u) == url2str(ou)) 113 | return resolve(challenge); 114 | 115 | if (getTLDPlusOne(u) != getTLDPlusOne(ou)) 116 | return reject("Not matching origin domain and appID"); 117 | 118 | { 119 | const { resolve, reject, promise } = defer(); 120 | 121 | fetchTrustedFacetsList(challenge.appId).then(ids => { 122 | let tld = getTLDPlusOne(u); 123 | ids = ids.filter(id => getTLDPlusOne(id) == tld); 124 | if (ids.indexOf(url2str(ou)) < 0) { 125 | reject("No entry for facet in trusted facet list"); 126 | return; 127 | } 128 | resolve(challenge); 129 | }); 130 | return promise; 131 | } 132 | } catch (ex) { 133 | reject("Invalid appId"); 134 | } 135 | } 136 | 137 | function allValidAppIds(facetId, challenges) { 138 | return allValid(challenges.map(c => hasValidAppId(facetId, c))); 139 | } 140 | 141 | exports.hasValidAppId = hasValidAppId; 142 | exports.allValidAppIds = allValidAppIds; 143 | -------------------------------------------------------------------------------- /ext/bootstrap.js: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | "use strict"; 5 | 6 | const { utils: Cu } = Components; 7 | const rootURI = __SCRIPT_URI_SPEC__.replace("bootstrap.js", ""); 8 | const COMMONJS_URI = "resource://gre/modules/commonjs"; 9 | const { require } = Cu.import(COMMONJS_URI + "/toolkit/require.js", {}); 10 | const { Bootstrap } = require(COMMONJS_URI + "/sdk/addon/bootstrap.js"); 11 | var { startup, shutdown, install, uninstall } = new Bootstrap(rootURI); 12 | -------------------------------------------------------------------------------- /ext/data/content-script.js: -------------------------------------------------------------------------------- 1 | /* eslint-env browser */ 2 | /* globals cloneInto, createObjectIn, exportFunction, unsafeWindow */ 3 | "use strict"; 4 | 5 | const DEFAULT_TIMEOUT_SECONDS = 30; 6 | 7 | var nextCallbackID = 0; 8 | var activeRequests = 0; 9 | var callbacks = []; 10 | 11 | var noopOnPage = exportFunction(() => {}, unsafeWindow); 12 | 13 | function deliverResponse(id, payload) { 14 | if (!callbacks[id]) 15 | return; 16 | 17 | var value = cloneInto(payload, document.defaultView); 18 | 19 | try { 20 | clearTimeout(callbacks[id].timer); 21 | callbacks[id].callback(value); 22 | delete callbacks[id]; 23 | } catch (ex) { 24 | console.info(ex + ""); 25 | } 26 | 27 | if (--activeRequests == 0) 28 | self.port.removeListener("U2FRequestResponse", processChromeResponse); 29 | } 30 | 31 | function processChromeResponse(id, response) { 32 | if (response.errorMessage) 33 | console.info("U2F error response:", response.errorMessage); 34 | 35 | delete response.errorMessage; 36 | 37 | deliverResponse(id, response); 38 | } 39 | 40 | function handleTimeout(id) { 41 | deliverResponse(id, {errorCode: 5}); 42 | } 43 | 44 | function sendToChrome(msg, callback, timeout) { 45 | var origin = document.location.origin; 46 | var callbackID = nextCallbackID++; 47 | 48 | timeout = 1000 * (timeout || DEFAULT_TIMEOUT_SECONDS); 49 | var timer = setTimeout(handleTimeout, timeout, callbackID); 50 | 51 | callbacks[callbackID] = {callback: callback, timer: timer}; 52 | if (activeRequests++ == 0) 53 | self.port.on("U2FRequestResponse", processChromeResponse); 54 | 55 | self.port.emit("U2FRequest", msg, callbackID, origin, timeout); 56 | } 57 | 58 | function cloneFunctions(obj, clone) { 59 | Object.getOwnPropertyNames(obj).forEach(i => { 60 | if (typeof obj[i] == "function") { 61 | // instead of freezing the clone use accessor property to allow further extension 62 | let value = exportFunction(obj[i], clone); 63 | let getter = exportFunction(() => { 64 | return value; 65 | }, clone); 66 | Object.defineProperty(clone, i, { 67 | get: getter, 68 | set: noopOnPage, // readonly: silently avoid strict mode TypeError on assignment 69 | enumerable: true 70 | }); 71 | } else if (typeof obj[i] == "object") { 72 | cloneFunctions(obj[i], clone[i]); 73 | } 74 | }); 75 | } 76 | 77 | var u2f = { 78 | register: function(requests, signRequests, callback, timeout) { 79 | if (typeof(timeout) == "function" && typeof(callback) != "function") { 80 | let appId, keys; 81 | [appId, requests, keys, callback, timeout] = Array.from(arguments); 82 | Array.forEach(requests, v => v.appId = appId); 83 | signRequests = Array.map(keys, v => ({ 84 | version: v.version, 85 | challenge: requests[0].challenge, 86 | keyHandle: v.keyHandle, 87 | appId: appId 88 | })); 89 | } 90 | 91 | sendToChrome({ 92 | type: "register", 93 | requests: requests, 94 | signRequests: signRequests 95 | }, callback, timeout); 96 | }, 97 | 98 | sign: function(signRequests, callback, timeout, extra) { 99 | if (typeof(extra) == "function" && typeof(callback) != "function") { 100 | let appId, challenge, keys; 101 | [appId, challenge, keys, callback, timeout] = Array.from(arguments); 102 | signRequests = Array.map(keys, v => ({ 103 | version: v.version, 104 | challenge: challenge, 105 | keyHandle: v.keyHandle, 106 | appId: appId 107 | })); 108 | } 109 | 110 | sendToChrome({ 111 | type: "sign", 112 | signRequests: signRequests 113 | }, callback, timeout); 114 | } 115 | }; 116 | 117 | var allowToOverride = document.location.origin.indexOf(".google.") >= 0; 118 | 119 | var u2fOnPage = createObjectIn(unsafeWindow, allowToOverride ? {defineAs: "u2f"} : {}); 120 | cloneFunctions(u2f, u2fOnPage); 121 | 122 | if (!allowToOverride) { 123 | Object.defineProperty(unsafeWindow, "u2f", { 124 | get: exportFunction(() => u2fOnPage, unsafeWindow), 125 | set: noopOnPage, 126 | configurable: true, 127 | enumerable: true 128 | }); 129 | } 130 | -------------------------------------------------------------------------------- /ext/data/logs.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | U2F4Moz Logs 7 | 27 | 28 | 29 | 30 |

Last logs entries

31 | 32 |
    33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /ext/data/logs.js: -------------------------------------------------------------------------------- 1 | /* global self, document */ 2 | var receivedLogs; 3 | 4 | function displayLogs() { 5 | if (!receivedLogs) 6 | return; 7 | 8 | var ul = document.getElementsByTagName("ul")[0]; 9 | var hd = document.getElementById("hide-data").checked; 10 | 11 | while (ul.firstChild) 12 | ul.removeChild(ul.firstChild); 13 | 14 | receivedLogs.forEach(v => { 15 | var el = document.createElement("li"); 16 | if (hd) 17 | v = v.replace(/("?challenge"?)\s*:\s*".*?"/g, "$1:\"...\""). 18 | replace(/("?keyHandle"?)\s*:\s*".*?"/g, "$1:\"...\""). 19 | replace(/("?signatureData"?)\s*:\s*".*?"/g, "$1:\"...\""). 20 | replace(/("?clientData"?)\s*:\s*".*?"/g, "$1:\"...\""); 21 | el.textContent = v; 22 | ul.appendChild(el); 23 | }); 24 | } 25 | 26 | self.port.on("logs", function(logs) { 27 | receivedLogs = logs; 28 | displayLogs(); 29 | }); 30 | 31 | document.getElementById("hide-data").addEventListener("input", displayLogs, false); 32 | -------------------------------------------------------------------------------- /ext/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prefiks/u2f4moz/893377f46b1f2b3bd9afb1ce132d32c70f733977/ext/icon.png -------------------------------------------------------------------------------- /ext/icon64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prefiks/u2f4moz/893377f46b1f2b3bd9afb1ce132d32c70f733977/ext/icon64.png -------------------------------------------------------------------------------- /ext/index.js: -------------------------------------------------------------------------------- 1 | /* global console, uneval, clearTimeout:true, self:true, setTimeout:true, require:true */ 2 | "use strict"; 3 | 4 | const self = require("sdk/self"); 5 | const pageMod = require("sdk/page-mod"); 6 | const childProcess = require("sdk/system/child_process"); 7 | const { emit } = require("sdk/event/core"); 8 | const system = require("sdk/system"); 9 | const { URL, toFilename } = require("sdk/url"); 10 | const { setTimeout, clearTimeout } = require("sdk/timers"); 11 | const { allValidAppIds } = require("./appIdValidator"); 12 | const { viewFor } = require("sdk/view/core"); 13 | const {get: _} = require("sdk/l10n"); 14 | const events = require("sdk/system/events"); 15 | const tabs = require("sdk/tabs"); 16 | 17 | 18 | var activeRequest; 19 | var timeStart = Date.now(); 20 | 21 | var logs = []; 22 | function log() { 23 | var msg = Array.map(arguments, v => typeof(v) == "string" ? v : uneval(v)).join(" "); 24 | logs.push((Date.now()-timeStart)+" "+msg); 25 | 26 | if (logs.length > 100) 27 | logs.shift(); 28 | 29 | console.info.apply(console, arguments); 30 | } 31 | 32 | function cleanNotification() { 33 | if (!activeRequest) 34 | return; 35 | if (activeRequest.notification) 36 | viewFor(activeRequest.worker.tab).ownerGlobal. 37 | PopupNotifications.remove(activeRequest.notification); 38 | activeRequest.notification = null; 39 | } 40 | 41 | function showNotification(msg) { 42 | let tab = viewFor(activeRequest.worker.tab); 43 | if (activeRequest.notification) 44 | cleanNotification(); 45 | 46 | activeRequest.notification = tab.ownerGlobal. 47 | PopupNotifications.show(tab.linkedBrowser, "u2f-device-info", msg, null, null, 48 | null, { 49 | popupIconURL: self.data.url("../icon.png"), 50 | removeOnDismissal: true 51 | }); 52 | } 53 | 54 | function killExe() { 55 | if (!activeRequest) 56 | return; 57 | cleanNotification(); 58 | clearTimeout(activeRequest.timer); 59 | activeRequest.killing = true; 60 | try { 61 | activeRequest.cmd.kill(); 62 | } catch (ex) { 63 | log("killExe exception", ex); 64 | } 65 | activeRequest = null; 66 | } 67 | 68 | function toHex(num) { 69 | return (0x10000 + num).toString(16).substr(1); 70 | } 71 | 72 | function challengesToStr(signRequest, origin, challenges) { 73 | if (challenges.length > 16) 74 | challenges = challenges.slice(0, 16); 75 | 76 | let strChallenges = challenges.map(JSON.stringify); 77 | return (signRequest ? "s" : "r") + toHex(origin.length) + 78 | toHex(challenges.length) + strChallenges.map(v => toHex(v.length)).join("") + 79 | origin + strChallenges.join(""); 80 | 81 | } 82 | 83 | function execBin(event, origin, challenges, checkSignChallenges, callbackid, worker, timeout) { 84 | let facetId = URL(origin); 85 | allValidAppIds(facetId, challenges).then(ch => { 86 | if (ch.length == 0) { 87 | worker.port.emit(event, callbackid, { 88 | errorCode: 2, 89 | errorMessage: "Invalid input" 90 | }); 91 | return; 92 | } 93 | if (checkSignChallenges && checkSignChallenges.length > 0) { 94 | allValidAppIds(facetId, checkSignChallenges).then(sch => { 95 | if (sch.length == 0) { 96 | worker.port.emit(event, callbackid, { 97 | errorCode: 2, 98 | errorMessage: "Invalid input" 99 | }); 100 | return; 101 | } 102 | _execBin(event, origin, ch, sch, callbackid, worker, timeout); 103 | }); 104 | } else 105 | _execBin(event, origin, ch, null, callbackid, worker, timeout); 106 | }); 107 | } 108 | 109 | function _execBin(event, origin, challenges, checkSignChallenges, callbackid, worker, timeout) { 110 | log("execBin event =", event, "origin =", origin, "challeges =",challenges, "checkSignChallenges =",checkSignChallenges); 111 | var [arch, ext] = system.platform == "winnt" ? ["x86", ".exe"] : [system.architecture, ""]; 112 | var exe = system.platform + "_" + arch + "-" + system.compiler + "/u2f" + ext; 113 | var path = toFilename(self.data.url("../bin/" + exe)); 114 | log("exec path", path); 115 | var cmd = childProcess.spawn(path, [], {}); 116 | log("exec cmd", cmd); 117 | var response = { 118 | value: "", 119 | responded: false 120 | }; 121 | 122 | var timer = setTimeout(function() { 123 | killExe(); 124 | }, timeout); 125 | 126 | cmd.stdout.on("data", function(data) { 127 | log("device data", data); 128 | response.value += data; 129 | if (response.value[0] == "i") { 130 | log("insert device"); 131 | showNotification(_("Please plug in your U2F device")); 132 | response.value = response.value.substr(1); 133 | } 134 | if (response.value[0] == "j") { 135 | cleanNotification(); 136 | log("device inserted"); 137 | response.value = response.value.substr(1); 138 | } 139 | if (response.value[0] == "b") { 140 | log("device waits for button press"); 141 | showNotification(_("Please press button on your U2F device")); 142 | response.value = response.value.substr(1); 143 | } 144 | var r = response.value.match(/^(.)(....)/); 145 | var len = r && parseInt(r[2], 16); 146 | if (r && response.value.length >= len + 5) { 147 | if (checkSignChallenges) { 148 | let json = JSON.parse(response.value.substr(5, len)); 149 | if (json.errorCode == 4) { 150 | checkSignChallenges = null; 151 | let stdin = challengesToStr(false, origin, challenges); 152 | log("emit data", stdin); 153 | emit(cmd.stdin, "data", stdin); 154 | } else if (json.errorCode) { 155 | worker.port.emit("U2FRequestResponse", callbackid, { 156 | errorCode: 1, 157 | errorMessage: "Unknown error" 158 | }); 159 | } else { 160 | worker.port.emit("U2FRequestResponse", callbackid, { 161 | errorCode: 4, 162 | errorMessage: "Device already registered" 163 | }); 164 | } 165 | response.value = response.value.substr(5 + len); 166 | 167 | log("emit end"); 168 | emit(cmd.stdin, "end"); 169 | } else { 170 | let json = JSON.parse(response.value.substr(5, len)); 171 | if (!json.version && json.registrationData) 172 | json.version = "U2F_V2"; 173 | worker.port.emit("U2FRequestResponse", callbackid, json); 174 | response.value = response.value.substr(5 + len); 175 | response.responded = true; 176 | } 177 | } 178 | }); 179 | cmd.on("error", function() { 180 | worker.port.emit("U2FRequestResponse", callbackid, { 181 | errorCode: 1, 182 | errorMessage: "Couldn't spawn binary" 183 | }); 184 | killExe(); 185 | }); 186 | cmd.on("exit", function(code, signal) { 187 | log("exit code =", code, "signal =",signal, "killed =",cmd.killed, "activeRequest =", !!activeRequest, 188 | "activeRequest.killing =", activeRequest && activeRequest.killing); 189 | cleanNotification(); 190 | clearTimeout(timer); 191 | 192 | if (cmd.killed || !activeRequest || activeRequest.killing) { 193 | activeRequest = null; 194 | return; 195 | } 196 | activeRequest = null; 197 | 198 | if (code == null || code < 0) 199 | worker.port.emit("U2FRequestResponse", callbackid, { 200 | errorCode: 1, 201 | errorMessage: "Couldn't spawn binary" 202 | }); 203 | else if (!response.responded) 204 | worker.port.emit("U2FRequestResponse", callbackid, { 205 | errorCode: 1, 206 | errorMessage: "No response from binary: " + response.value 207 | }); 208 | }); 209 | if (challenges.length > 16) 210 | challenges = challenges.slice(0, 16); 211 | 212 | let stdin = challengesToStr(checkSignChallenges || event == "sign", origin, 213 | checkSignChallenges ? checkSignChallenges : challenges); 214 | 215 | activeRequest = { 216 | worker: worker, 217 | cmd: cmd, 218 | timer: timer 219 | }; 220 | 221 | log("emit data", stdin); 222 | emit(cmd.stdin, "data", stdin); 223 | if (!checkSignChallenges) { 224 | log("emit end"); 225 | emit(cmd.stdin, "end"); 226 | } 227 | } 228 | 229 | pageMod.PageMod({ // eslint-disable-line new-cap 230 | include: "*", 231 | contentScriptWhen: "start", 232 | attachTo: ["top", "frame"], 233 | contentScriptFile: "./content-script.js", 234 | onAttach: function(worker) { 235 | worker.port.on("U2FRequest", function(msg, callbackid, domain, timeout) { 236 | let req, signCheckReq; 237 | 238 | if (msg.type == "register") 239 | [req, signCheckReq] = [msg.requests, msg.signRequests]; 240 | else 241 | [req, signCheckReq] = [msg.signRequests, null]; 242 | 243 | req = Array.isArray(req) ? req : [req]; 244 | execBin(msg.type, domain, req, signCheckReq, callbackid, worker, timeout); 245 | }); 246 | worker.on("detach", function() { 247 | if (activeRequest && activeRequest.worker == worker) { 248 | killExe(); 249 | } 250 | }); 251 | } 252 | }); 253 | 254 | function showLogs() { 255 | log("showLogsCalled"); 256 | tabs.open({ 257 | url: self.data.url("logs.html"), 258 | onReady: function(tab) { 259 | var worker = tab.attach({ 260 | contentScriptFile: self.data.url("./logs.js") 261 | }); 262 | worker.port.emit("logs", logs); 263 | } 264 | }); 265 | } 266 | 267 | function optionsDisplayed(event) { 268 | if (event.type != "addon-options-displayed" || 269 | event.data != "u2f4moz@prefiks.org") 270 | return; 271 | var doc = event.subject; 272 | var el = doc.getElementById("showLogsButton"); 273 | el.label = "Show Logs"; 274 | el.addEventListener("command", showLogs); 275 | } 276 | 277 | events.on("addon-options-displayed", optionsDisplayed); 278 | -------------------------------------------------------------------------------- /ext/install.rdf: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | u2f4moz@prefiks.org 5 | 2 6 | true 7 | true 8 | true 9 | 1.0.1 10 | U2F Support Add-on 11 | Extension adding support for U2F 12 | Paweł Chmielowski 13 | Baptiste Mille-Mathias 14 | Matt N 15 | WINNT_x86-msvc 16 | WINNT_x86_64-msvc 17 | Linux_x86-gcc3 18 | Linux_x86_64-gcc3 19 | Darwin_x86_64-gcc3 20 | FreeBSD_x86_64-gcc3 21 | 22 | 23 | 24 | {ec8030f7-c20a-464f-9b0e-13a3a9e97384} 25 | 38.0a1 26 | 51.0 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /ext/options.xul: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 |