├── .Dockerignore
├── .gitignore
├── .gitlab-ci.yml
├── .gitmodules
├── .idea
├── codeStyleSettings.xml
├── dictionaries
│ └── sz.xml
└── vcs.xml
├── .travis.yml
├── CHANGELOG.md
├── CMakeLists.txt
├── CMakeSettings.json
├── DeviceCommunicationExceptions.cpp
├── Dockerfile
├── Doxyfile.in
├── LICENSE
├── Makefile
├── NK_C_API.cc
├── NK_C_API.h
├── NitrokeyManager.cc
├── README.md
├── TODO
├── ci-script
├── build.sh
└── package.sh
├── command_id.cc
├── data
├── 41-nitrokey.rules
├── 41-nitrokey_old.rules
├── Pipfile
├── Pipfile.lock
├── README.md
└── generate_udev_docs.py
├── device.cc
├── libnitrokey.pc.in
├── libnitrokey.pro
├── libnitrokey
├── CommandFailedException.h
├── DeviceCommunicationExceptions.h
├── LibraryException.h
├── LongOperationInProgressException.h
├── NitrokeyManager.h
├── command.h
├── command_id.h
├── cxx_semantics.h
├── deprecated.h
├── device.h
├── device_proto.h
├── dissect.h
├── hidapi
│ └── hidapi.h
├── log.h
├── misc.h
├── stick10_commands.h
├── stick10_commands_0.8.h
├── stick20_commands.h
└── version.h
├── log.cc
├── meson.build
├── meson_options.txt
├── misc.cc
├── python3_bindings_example.py
├── python_bindings_example.py
├── unittest
├── Pipfile
├── Pipfile.lock
├── build
│ ├── libnitrokey.so
│ └── run.sh
├── catch_main.cpp
├── conftest.py
├── constants.py
├── helpers.py
├── libnk-tool.py
├── misc.py
├── pyproject.toml
├── requirements.txt
├── setup_python_dependencies.sh
├── test1.cc
├── test2.cc
├── test3.cc
├── test_C_API.cpp
├── test_HOTP.cc
├── test_command_ids_header.h
├── test_issues.cc
├── test_issues.py
├── test_library.py
├── test_memory.c
├── test_minimal.c
├── test_multiple.py
├── test_multiple_devices.cc
├── test_offline.cc
├── test_offline.py
├── test_pro.py
├── test_pro_bootloader.py
├── test_safe.cpp
├── test_storage.py
└── test_strdup.cpp
├── version.cc
└── version.cc.in
/.Dockerignore:
--------------------------------------------------------------------------------
1 | build*
2 |
3 |
4 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.sw*
2 | *.log
3 | *.o
4 | build
5 | unittest/build/
6 | unittest/.pytest_cache/
7 | *.pyc
8 | core
9 | .cache/
10 | .idea/
11 | CMakeFiles/
12 | /.vs
13 |
--------------------------------------------------------------------------------
/.gitlab-ci.yml:
--------------------------------------------------------------------------------
1 | include: 'https://raw.githubusercontent.com/Nitrokey/common-ci-jobs/master/common_jobs.yml'
2 |
3 | stages:
4 | - pull-github
5 | - fetch
6 | - build
7 | - deploy
8 |
9 | variables:
10 | #Repo for shared scripts (pull.sh release.sh, nightly_upload.sh):
11 | GIT_STRATEGY: clone #This seems to have no effect also set in webinterface
12 | GIT_DEPTH: 0 #This seems to have no effect also set in webinterface
13 | GIT_SUBMODULE_STRATEGY: recursive #This seems to have no effect also set in webinterfac
14 | SCRIPTS_REPO: git@git.dotplex.com:nitrokey/gitlab-ci.git
15 | REPO_USER: nitrokey
16 | REPO_NAME: libnitrokey
17 | MAIN_BRANCH: master
18 | COMMON_PULL: "true"
19 | COMMON_UPLOAD_NIGHTLY: "true"
20 | COMMON_GITHUB_RELEASE: "true"
21 | COMMON_UPLOAD_FILES: "false"
22 |
23 | fetch-and-package:
24 | image: registry.git.dotplex.com/nitrokey/libnitrokey/libnitrokey-bionic-gcc8:latest
25 | rules:
26 | - if: '$CI_PIPELINE_SOURCE == "push"'
27 | - if: '$CI_PIPELINE_SOURCE == "schedule"'
28 | - if: '$CI_PIPELINE_SOURCE == "web"'
29 |
30 | tags:
31 | - docker
32 | stage: fetch
33 | script:
34 | - ci-script/package.sh
35 | after_script:
36 | - wget $icon_server/checkmark/$CI_COMMIT_REF_NAME/$CI_COMMIT_SHA/$CI_JOB_NAME/$CI_JOB_STATUS/${CI_JOB_URL#*/*/*/}
37 | artifacts:
38 | paths:
39 | - artifacts
40 | - libnitrokey-source-metadata
41 | expire_in: 2 weeks
42 |
43 | .build:
44 | rules:
45 | - if: '$CI_PIPELINE_SOURCE == "push"'
46 | - if: '$CI_PIPELINE_SOURCE == "schedule"'
47 | - if: '$CI_PIPELINE_SOURCE == "web"'
48 | tags:
49 | - docker
50 | stage: build
51 | script:
52 | - ci-script/build.sh
53 | after_script:
54 | - wget $icon_server/checkmark/$CI_COMMIT_REF_NAME/$CI_COMMIT_SHA/$CI_JOB_NAME/$CI_JOB_STATUS/${CI_JOB_URL#*/*/*/}
55 |
56 | build-bionic-gcc8:
57 | extends: .build
58 | image: registry.git.dotplex.com/nitrokey/libnitrokey/libnitrokey-bionic-gcc8:latest
59 |
60 | build-bionic-gcc7:
61 | extends: .build
62 | image: registry.git.dotplex.com/nitrokey/libnitrokey/libnitrokey-bionic-gcc7:latest
63 |
64 | build-bionic-gcc6:
65 | extends: .build
66 | image: registry.git.dotplex.com/nitrokey/libnitrokey/libnitrokey-bionic-gcc6:latest
67 |
68 | build-bionic-gcc5:
69 | extends: .build
70 | image: registry.git.dotplex.com/nitrokey/libnitrokey/libnitrokey-bionic-gcc5:latest
71 |
72 | build-bionic-llvm7:
73 | extends: .build
74 | image: registry.git.dotplex.com/nitrokey/libnitrokey/libnitrokey-bionic-llvm7:latest
75 |
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "unittest/Catch"]
2 | path = unittest/Catch
3 | url = https://github.com/catchorg/Catch2.git
4 | [submodule "hidapi"]
5 | path = hidapi
6 | url = https://github.com/Nitrokey/hidapi.git
7 |
--------------------------------------------------------------------------------
/.idea/codeStyleSettings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/.idea/dictionaries/sz.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | loglevel
5 | nitrokey
6 | totp
7 |
8 |
9 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: generic
2 | os: osx
3 | env:
4 | global:
5 | - CF="-DCOMPILE_OFFLINE_TESTS=1 -DERROR_ON_WARNING=ON"
6 |
7 | jobs:
8 | include:
9 | - osx_image: xcode11.5
10 | - osx_image: xcode9.1
11 | - os: linux
12 | dist: trusty
13 | env: COMPILER_NAME=gcc CXX=g++-5 CC=gcc-5
14 | addons:
15 | apt:
16 | packages:
17 | - cmake
18 | - libhidapi-dev
19 | - g++-5
20 | sources: &sources
21 | - ubuntu-toolchain-r-test
22 | - os: linux
23 | dist: trusty
24 | env: COMPILER_NAME=gcc CXX=g++-7 CC=gcc-7
25 | addons:
26 | apt:
27 | packages:
28 | - cmake
29 | - libhidapi-dev
30 | - g++-7
31 | sources: *sources
32 | - os: linux
33 | dist: bionic
34 | env: COMPILER_NAME=gcc CXX=g++-10 CC=gcc-10
35 | addons:
36 | apt:
37 | packages:
38 | - cmake
39 | - libhidapi-dev
40 | - g++-10
41 | - python3
42 | - python3-pip
43 | - meson
44 | - ninja-build
45 | sources: *sources
46 | script:
47 | - make -j2
48 | - ctest -VV
49 | - mkdir install && make install DESTDIR=install
50 | - cd ../
51 | - python3 -m pip install -r unittest/requirements.txt --user
52 | - cd unittest && python3 -m pytest -sv test_offline.py
53 | - cd ../
54 | - mkdir -p build-meson && meson build-meson
55 | - cd build-meson && ninja
56 | - env DESTDIR=install ninja install
57 | - os: linux
58 | dist: trusty
59 | env: COMPILER_NAME=clang CXX=clang++-3.8 CC=clang-3.8
60 | addons:
61 | apt:
62 | packages:
63 | - cmake
64 | - libhidapi-dev
65 | - g++-5
66 | - clang-3.8
67 | sources: *sources
68 | - os: linux
69 | dist: bionic
70 | env: COMPILER_NAME=clang CXX=clang++-6.0 CC=clang-6.0
71 | addons:
72 | apt:
73 | packages:
74 | - cmake
75 | - libhidapi-dev
76 | - clang-6.0
77 | sources: *sources
78 | - os: linux
79 | dist: bionic
80 | env: COMPILER_NAME=clang CXX=clang++-9 CC=clang-9
81 | addons:
82 | apt:
83 | packages:
84 | - cmake
85 | - libhidapi-dev
86 | - clang-9
87 | sources: *sources
88 |
89 |
90 | install:
91 | - mkdir -p build
92 | - cd build
93 | # - export CXXFLAGS="${CXX_FLAGS} -Wall -Wextra -Werror" # TODO enable when fixed
94 | - ${CXX} --version || true
95 | - cmake --version
96 | - cmake .. ${CF}
97 |
98 | script:
99 | - make -j2
100 | - ctest -VV
101 | - mkdir install && make install DESTDIR=install
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Change Log
2 |
3 | ## [v3.2](https://github.com/Nitrokey/libnitrokey/tree/v3.2) (2018-01-16)
4 | [Full Changelog](https://github.com/Nitrokey/libnitrokey/compare/v3.1...v3.2)
5 |
6 | **Closed issues:**
7 |
8 | - Communication exceptions are not catched in C API [\#89](https://github.com/Nitrokey/libnitrokey/issues/89)
9 | - Devices are not detected under Windows [\#88](https://github.com/Nitrokey/libnitrokey/issues/88)
10 | - Python bindings example is not working [\#82](https://github.com/Nitrokey/libnitrokey/issues/82)
11 | - Missing NK\_C\_API.h in install includes [\#77](https://github.com/Nitrokey/libnitrokey/issues/77)
12 | - Handle time-taking commands [\#67](https://github.com/Nitrokey/libnitrokey/issues/67)
13 |
14 | ## [v3.1](https://github.com/Nitrokey/libnitrokey/tree/v3.1) (2017-10-11)
15 | [Full Changelog](https://github.com/Nitrokey/libnitrokey/compare/v3.0...v3.1)
16 |
17 | ## [v3.0](https://github.com/Nitrokey/libnitrokey/tree/v3.0) (2017-10-07)
18 | [Full Changelog](https://github.com/Nitrokey/libnitrokey/compare/v2.0...v3.0)
19 |
20 | **Implemented enhancements:**
21 |
22 | - Support for NK Pro 0.8 [\#51](https://github.com/Nitrokey/libnitrokey/issues/51)
23 |
24 | **Closed issues:**
25 |
26 | - tests are failing [\#71](https://github.com/Nitrokey/libnitrokey/issues/71)
27 | - cmake doesn't install any headers [\#70](https://github.com/Nitrokey/libnitrokey/issues/70)
28 | - SONAME versioning [\#69](https://github.com/Nitrokey/libnitrokey/issues/69)
29 | - Read slot returns invalid counter value for Storage [\#59](https://github.com/Nitrokey/libnitrokey/issues/59)
30 | - Return OTP codes as strings [\#57](https://github.com/Nitrokey/libnitrokey/issues/57)
31 | - Fix compilation warnings [\#56](https://github.com/Nitrokey/libnitrokey/issues/56)
32 | - Add Travis support [\#48](https://github.com/Nitrokey/libnitrokey/issues/48)
33 | - Correct get\_time [\#27](https://github.com/Nitrokey/libnitrokey/issues/27)
34 | - Move from Makefile to CMake [\#18](https://github.com/Nitrokey/libnitrokey/issues/18)
35 |
36 | ## [v2.0](https://github.com/Nitrokey/libnitrokey/tree/v2.0) (2016-12-12)
37 | [Full Changelog](https://github.com/Nitrokey/libnitrokey/compare/v1.0...v2.0)
38 |
39 | **Implemented enhancements:**
40 |
41 | - Support for Nitrokey Storage - Nitrokey Storage commands [\#14](https://github.com/Nitrokey/libnitrokey/issues/14)
42 | - Support for Nitrokey Storage - Nitrokey Pro commands [\#13](https://github.com/Nitrokey/libnitrokey/issues/13)
43 |
44 | **Fixed bugs:**
45 |
46 | - Fails to compile on ubuntu 16.04 [\#46](https://github.com/Nitrokey/libnitrokey/issues/46)
47 | - C++ tests do not compile [\#45](https://github.com/Nitrokey/libnitrokey/issues/45)
48 | - HOTP counter values limited to 8bit [\#44](https://github.com/Nitrokey/libnitrokey/issues/44)
49 | - Device is not released after library function disconnect call [\#43](https://github.com/Nitrokey/libnitrokey/issues/43)
50 |
51 | **Closed issues:**
52 |
53 | - Compilation error on G++6 \(flexible array member\) [\#49](https://github.com/Nitrokey/libnitrokey/issues/49)
54 | - No library function for getting device's serial number [\#33](https://github.com/Nitrokey/libnitrokey/issues/33)
55 | - Pass binary data \(OTP secrets\) coded as hex values [\#31](https://github.com/Nitrokey/libnitrokey/issues/31)
56 | - set\_time not always work [\#29](https://github.com/Nitrokey/libnitrokey/issues/29)
57 |
58 | **Merged pull requests:**
59 |
60 | - Support for Nitrokey Pro 0.8 [\#53](https://github.com/Nitrokey/libnitrokey/pull/53) ([szszszsz](https://github.com/szszszsz))
61 | - Support Nitrokey Storage [\#52](https://github.com/Nitrokey/libnitrokey/pull/52) ([szszszsz](https://github.com/szszszsz))
62 | - Fix compilation G++6 error [\#50](https://github.com/Nitrokey/libnitrokey/pull/50) ([szszszsz](https://github.com/szszszsz))
63 | - Fix compilation warning and error under G++ [\#47](https://github.com/Nitrokey/libnitrokey/pull/47) ([szszszsz](https://github.com/szszszsz))
64 | - Support Pro stick commands on Storage device [\#42](https://github.com/Nitrokey/libnitrokey/pull/42) ([szszszsz](https://github.com/szszszsz))
65 | - Readme update - dependencies, compilers, format [\#40](https://github.com/Nitrokey/libnitrokey/pull/40) ([szszszsz](https://github.com/szszszsz))
66 | - Issue 31 secret as hex [\#36](https://github.com/Nitrokey/libnitrokey/pull/36) ([szszszsz](https://github.com/szszszsz))
67 | - Function for getting device's serial number in hex. Fixes \#33 [\#34](https://github.com/Nitrokey/libnitrokey/pull/34) ([szszszsz](https://github.com/szszszsz))
68 |
69 | ## [v1.0](https://github.com/Nitrokey/libnitrokey/tree/v1.0) (2016-08-09)
70 | [Full Changelog](https://github.com/Nitrokey/libnitrokey/compare/v0.9...v1.0)
71 |
72 | **Closed issues:**
73 |
74 | - Automatically detect any connected stick [\#22](https://github.com/Nitrokey/libnitrokey/issues/22)
75 | - Security check [\#20](https://github.com/Nitrokey/libnitrokey/issues/20)
76 | - Show friendly message when no device is connected and do not abort [\#17](https://github.com/Nitrokey/libnitrokey/issues/17)
77 | - Fix PIN protected OTP for Pro [\#15](https://github.com/Nitrokey/libnitrokey/issues/15)
78 |
79 | ## [v0.9](https://github.com/Nitrokey/libnitrokey/tree/v0.9) (2016-08-05)
80 | [Full Changelog](https://github.com/Nitrokey/libnitrokey/compare/v0.8...v0.9)
81 |
82 | **Closed issues:**
83 |
84 | - Add README [\#6](https://github.com/Nitrokey/libnitrokey/issues/6)
85 | - Support configs for OTP slots [\#19](https://github.com/Nitrokey/libnitrokey/issues/19)
86 | - Cover remaining Nitrokey Pro commands in lib and tests [\#16](https://github.com/Nitrokey/libnitrokey/issues/16)
87 |
88 | **Merged pull requests:**
89 |
90 | - waffle.io Badge [\#21](https://github.com/Nitrokey/libnitrokey/pull/21) ([waffle-iron](https://github.com/waffle-iron))
91 |
92 | ## [v0.8](https://github.com/Nitrokey/libnitrokey/tree/v0.8) (2016-08-02)
93 | **Implemented enhancements:**
94 |
95 | - Change license to LGPLv3 [\#1](https://github.com/Nitrokey/libnitrokey/issues/1)
96 |
97 | **Closed issues:**
98 |
99 | - Python wrapper for OTP and PINs [\#12](https://github.com/Nitrokey/libnitrokey/issues/12)
100 | - Fails to built with default setting on ubuntu 14.04 [\#11](https://github.com/Nitrokey/libnitrokey/issues/11)
101 | - Check why packet buffers are not zeroed [\#8](https://github.com/Nitrokey/libnitrokey/issues/8)
102 |
103 | **Merged pull requests:**
104 |
105 | - Reset the HOTP counter [\#9](https://github.com/Nitrokey/libnitrokey/pull/9) ([cornelinux](https://github.com/cornelinux))
106 |
107 |
108 |
109 | \* *This Change Log was automatically generated by [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)*
--------------------------------------------------------------------------------
/CMakeSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | // See https://go.microsoft.com//fwlink//?linkid=834763 for more information about this file.
3 | "configurations": [
4 | {
5 | "name": "x86-Debug",
6 | "generator": "Visual Studio 15 2017",
7 | "configurationType" : "Debug",
8 | "buildRoot": "${env.LOCALAPPDATA}\\CMakeBuild\\${workspaceHash}\\build\\${name}",
9 | "cmakeCommandArgs": "",
10 | "buildCommandArgs": "-m -v:minimal"
11 | },
12 | {
13 | "name": "x86-Release",
14 | "generator": "Visual Studio 15 2017",
15 | "configurationType" : "Release",
16 | "buildRoot": "${env.LOCALAPPDATA}\\CMakeBuild\\${workspaceHash}\\build\\${name}",
17 | "cmakeCommandArgs": "",
18 | "buildCommandArgs": "-m -v:minimal"
19 | },
20 | {
21 | "name": "x64-Debug",
22 | "generator": "Visual Studio 15 2017 Win64",
23 | "configurationType" : "Debug",
24 | "buildRoot": "${env.LOCALAPPDATA}\\CMakeBuild\\${workspaceHash}\\build\\${name}",
25 | "cmakeCommandArgs": "",
26 | "buildCommandArgs": "-m -v:minimal"
27 | },
28 | {
29 | "name": "x64-Release",
30 | "generator": "Visual Studio 15 2017 Win64",
31 | "configurationType" : "Release",
32 | "buildRoot": "${env.LOCALAPPDATA}\\CMakeBuild\\${workspaceHash}\\build\\${name}",
33 | "cmakeCommandArgs": "",
34 | "buildCommandArgs": "-m -v:minimal"
35 | }
36 | ]
37 | }
--------------------------------------------------------------------------------
/DeviceCommunicationExceptions.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2015-2018 Nitrokey UG
3 | *
4 | * This file is part of libnitrokey.
5 | *
6 | * libnitrokey is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU Lesser General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * any later version.
10 | *
11 | * libnitrokey is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU Lesser General Public License
17 | * along with libnitrokey. If not, see .
18 | *
19 | * SPDX-License-Identifier: LGPL-3.0
20 | */
21 |
22 | #include "DeviceCommunicationExceptions.h"
23 |
24 | std::atomic_int DeviceCommunicationException::occurred {0};
25 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM ubuntu:22.04
2 | MAINTAINER Nitrokey
3 |
4 | ENV DEBIAN_FRONTEND=noninteractive
5 | RUN apt update && apt install -qy --no-install-recommends \
6 | libhidapi-dev libusb-1.0-0-dev cmake gcc g++ make doxygen pkg-config alien git graphviz \
7 | build-essential:native pkg-kde-tools udev gnupg curl devscripts \
8 | debian-keyring ubuntu-keyring \
9 | && rm -rf /var/lib/apt/lists/*
10 |
11 | RUN mkdir -p /app /root/.gnupg
12 |
13 | WORKDIR /app
14 |
--------------------------------------------------------------------------------
/Doxyfile.in:
--------------------------------------------------------------------------------
1 | # For better readability, the documentation and default settings are removed
2 | # from this file. For more information on the Doxygen configuration, generate
3 | # a new Doxyfile using `doxygen -g` or have a look at the Doxygen manual at
4 | # http://www.doxygen.nl/manual/config.html
5 | #
6 | # This file is processed by CMake. To generate the documentation, run `make
7 | # doc` in the build directory.
8 |
9 | PROJECT_NAME = "@CMAKE_PROJECT_NAME@"
10 | PROJECT_NUMBER = "@PROJECT_VERSION@"
11 | PROJECT_BRIEF =
12 | OUTPUT_DIRECTORY = doc
13 | STRIP_FROM_PATH = @CMAKE_CURRENT_SOURCE_DIR@
14 | JAVADOC_AUTOBRIEF = YES
15 | OPTIMIZE_OUTPUT_FOR_C = YES
16 | WARN_NO_PARAMDOC = YES
17 | INPUT = @CMAKE_CURRENT_SOURCE_DIR@/NK_C_API.h
18 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | GNU LESSER GENERAL PUBLIC LICENSE
2 | Version 3, 29 June 2007
3 |
4 | Copyright (C) 2007 Free Software Foundation, Inc.
5 | Everyone is permitted to copy and distribute verbatim copies
6 | of this license document, but changing it is not allowed.
7 |
8 |
9 | This version of the GNU Lesser General Public License incorporates
10 | the terms and conditions of version 3 of the GNU General Public
11 | License, supplemented by the additional permissions listed below.
12 |
13 | 0. Additional Definitions.
14 |
15 | As used herein, "this License" refers to version 3 of the GNU Lesser
16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU
17 | General Public License.
18 |
19 | "The Library" refers to a covered work governed by this License,
20 | other than an Application or a Combined Work as defined below.
21 |
22 | An "Application" is any work that makes use of an interface provided
23 | by the Library, but which is not otherwise based on the Library.
24 | Defining a subclass of a class defined by the Library is deemed a mode
25 | of using an interface provided by the Library.
26 |
27 | A "Combined Work" is a work produced by combining or linking an
28 | Application with the Library. The particular version of the Library
29 | with which the Combined Work was made is also called the "Linked
30 | Version".
31 |
32 | The "Minimal Corresponding Source" for a Combined Work means the
33 | Corresponding Source for the Combined Work, excluding any source code
34 | for portions of the Combined Work that, considered in isolation, are
35 | based on the Application, and not on the Linked Version.
36 |
37 | The "Corresponding Application Code" for a Combined Work means the
38 | object code and/or source code for the Application, including any data
39 | and utility programs needed for reproducing the Combined Work from the
40 | Application, but excluding the System Libraries of the Combined Work.
41 |
42 | 1. Exception to Section 3 of the GNU GPL.
43 |
44 | You may convey a covered work under sections 3 and 4 of this License
45 | without being bound by section 3 of the GNU GPL.
46 |
47 | 2. Conveying Modified Versions.
48 |
49 | If you modify a copy of the Library, and, in your modifications, a
50 | facility refers to a function or data to be supplied by an Application
51 | that uses the facility (other than as an argument passed when the
52 | facility is invoked), then you may convey a copy of the modified
53 | version:
54 |
55 | a) under this License, provided that you make a good faith effort to
56 | ensure that, in the event an Application does not supply the
57 | function or data, the facility still operates, and performs
58 | whatever part of its purpose remains meaningful, or
59 |
60 | b) under the GNU GPL, with none of the additional permissions of
61 | this License applicable to that copy.
62 |
63 | 3. Object Code Incorporating Material from Library Header Files.
64 |
65 | The object code form of an Application may incorporate material from
66 | a header file that is part of the Library. You may convey such object
67 | code under terms of your choice, provided that, if the incorporated
68 | material is not limited to numerical parameters, data structure
69 | layouts and accessors, or small macros, inline functions and templates
70 | (ten or fewer lines in length), you do both of the following:
71 |
72 | a) Give prominent notice with each copy of the object code that the
73 | Library is used in it and that the Library and its use are
74 | covered by this License.
75 |
76 | b) Accompany the object code with a copy of the GNU GPL and this license
77 | document.
78 |
79 | 4. Combined Works.
80 |
81 | You may convey a Combined Work under terms of your choice that,
82 | taken together, effectively do not restrict modification of the
83 | portions of the Library contained in the Combined Work and reverse
84 | engineering for debugging such modifications, if you also do each of
85 | the following:
86 |
87 | a) Give prominent notice with each copy of the Combined Work that
88 | the Library is used in it and that the Library and its use are
89 | covered by this License.
90 |
91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license
92 | document.
93 |
94 | c) For a Combined Work that displays copyright notices during
95 | execution, include the copyright notice for the Library among
96 | these notices, as well as a reference directing the user to the
97 | copies of the GNU GPL and this license document.
98 |
99 | d) Do one of the following:
100 |
101 | 0) Convey the Minimal Corresponding Source under the terms of this
102 | License, and the Corresponding Application Code in a form
103 | suitable for, and under terms that permit, the user to
104 | recombine or relink the Application with a modified version of
105 | the Linked Version to produce a modified Combined Work, in the
106 | manner specified by section 6 of the GNU GPL for conveying
107 | Corresponding Source.
108 |
109 | 1) Use a suitable shared library mechanism for linking with the
110 | Library. A suitable mechanism is one that (a) uses at run time
111 | a copy of the Library already present on the user's computer
112 | system, and (b) will operate properly with a modified version
113 | of the Library that is interface-compatible with the Linked
114 | Version.
115 |
116 | e) Provide Installation Information, but only if you would otherwise
117 | be required to provide such information under section 6 of the
118 | GNU GPL, and only to the extent that such information is
119 | necessary to install and execute a modified version of the
120 | Combined Work produced by recombining or relinking the
121 | Application with a modified version of the Linked Version. (If
122 | you use option 4d0, the Installation Information must accompany
123 | the Minimal Corresponding Source and Corresponding Application
124 | Code. If you use option 4d1, you must provide the Installation
125 | Information in the manner specified by section 6 of the GNU GPL
126 | for conveying Corresponding Source.)
127 |
128 | 5. Combined Libraries.
129 |
130 | You may place library facilities that are a work based on the
131 | Library side by side in a single library together with other library
132 | facilities that are not Applications and are not covered by this
133 | License, and convey such a combined library under terms of your
134 | choice, if you do both of the following:
135 |
136 | a) Accompany the combined library with a copy of the same work based
137 | on the Library, uncombined with any other library facilities,
138 | conveyed under the terms of this License.
139 |
140 | b) Give prominent notice with the combined library that part of it
141 | is a work based on the Library, and explaining where to find the
142 | accompanying uncombined form of the same work.
143 |
144 | 6. Revised Versions of the GNU Lesser General Public License.
145 |
146 | The Free Software Foundation may publish revised and/or new versions
147 | of the GNU Lesser General Public License from time to time. Such new
148 | versions will be similar in spirit to the present version, but may
149 | differ in detail to address new problems or concerns.
150 |
151 | Each version is given a distinguishing version number. If the
152 | Library as you received it specifies that a certain numbered version
153 | of the GNU Lesser General Public License "or any later version"
154 | applies to it, you have the option of following the terms and
155 | conditions either of that published version or of any later version
156 | published by the Free Software Foundation. If the Library as you
157 | received it does not specify a version number of the GNU Lesser
158 | General Public License, you may choose any version of the GNU Lesser
159 | General Public License ever published by the Free Software Foundation.
160 |
161 | If the Library as you received it specifies that a proxy can decide
162 | whether future versions of the GNU Lesser General Public License shall
163 | apply, that proxy's public statement of acceptance of any version is
164 | permanent authorization for you to choose that version for the
165 | Library.
166 |
167 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | NPROC=$(shell nproc)
2 | IMAGE_NAME=libnk-build
3 | BUILD_DIR=build
4 |
5 | .PHONY: docker-build-all
6 | docker-build-all:
7 | @echo "Running isolated build"
8 | $(MAKE) docker-build-image
9 | $(MAKE) docker-build
10 |
11 | .PHONY: docker-build-image
12 | docker-build-image:
13 | sudo docker build -t $(IMAGE_NAME) .
14 |
15 | .PHONY: docker-build
16 | docker-build:
17 | sudo docker run -it --rm -v $(PWD):/app $(IMAGE_NAME) bash -c "make ci-build"
18 |
19 | DOCKERCMD=bash -c "make ci-package"
20 | .PHONY: docker-package
21 | docker-package:
22 | sudo docker run -it --rm -v $(PWD):/app $(IMAGE_NAME) $(DOCKERCMD)
23 |
24 | .PHONY: docker-clean
25 | docker-clean:
26 | cd $(BUILD_DIR) && $(MAKE) clean
27 | sudo docker rmi $(IMAGE_NAME) --force
28 |
29 | .PHONY: ci-build
30 | ci-build:
31 | mkdir -p $(BUILD_DIR) && rm -rf $(BUILD_DIR)/*
32 | cd $(BUILD_DIR) && cmake .. && $(MAKE) -j$(NPROC) package
33 | cd $(BUILD_DIR) && ctest -VV
34 | cd $(BUILD_DIR) && mkdir -p install && $(MAKE) install DESTDIR=install
35 | @echo "== Results available in $(BUILD_DIR)"
36 | @date
37 |
38 | DGET_URL=https://people.debian.org/~patryk/tmp/libnitrokey/libnitrokey_3.7-1.dsc
39 | .PHONY: ci-package
40 | ci-package:
41 | mkdir -p $(BUILD_DIR) && rm -rf $(BUILD_DIR)/*
42 | cd $(BUILD_DIR) && dget $(DGET_URL)
43 | cd $(BUILD_DIR) && cd libnitrokey-* && dpkg-buildpackage
44 |
45 | .PHONY: ci-tests
46 | ci-tests:
47 | pip install pytest --user
48 | pip install -r unittest/requirements.txt --user
49 | cd unittest && python3 -m pytest -sv test_offline.py
50 |
51 | REPORT_NAME=libnitrokey-tests-report.html
52 | PYTEST_ARG=-vx --randomly-dont-reorganize --template=html1/index.html --report=$(REPORT_NAME)
53 |
54 | tests-setup:
55 | cd unittest && pipenv --python $(shell which python3) && pipenv install --dev
56 |
57 | .PHONY: tests-pro
58 | tests-pro:
59 | cd unittest && pipenv run pytest $(PYTEST_ARG) test_pro.py ; xdg-open $(REPORT_NAME)
60 |
61 | .PHONY: tests-storage
62 | tests-storage:
63 | cd unittest && pipenv run pytest $(PYTEST_ARG) test_pro.py
64 | cd unittest && pipenv run pytest $(PYTEST_ARG) test_storage.py ; xdg-open $(REPORT_NAME)
65 |
66 | .PHONY: clean clean-all
67 | clean:
68 | -rm $(REPORT_NAME)
69 |
70 | clean-all: clean docker-clean
--------------------------------------------------------------------------------
/TODO:
--------------------------------------------------------------------------------
1 | use strings instead of char* and vectors instead of others
2 |
--------------------------------------------------------------------------------
/ci-script/build.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -exuo pipefail
3 | export
4 |
5 | . ./libnitrokey-source-metadata/metadata
6 | tar xf artifacts/${LIBNITROKEY_BUILD_OUTNAME}.tar.gz
7 |
8 |
9 | pushd ${LIBNITROKEY_BUILD_OUTNAME}
10 | pip3 install --user -r unittest/requirements.txt
11 |
12 | ## This is quite sketchy but will work for now - we're using a tarball prepared by git archive, so we can't pull submodules.
13 | ## Instead, we download the Catch2 header manually. The version is hardcoded, which is bad.
14 | ## TODO: figure out a better way to handle that
15 | ## One possibility is to install Catch2 system-wide on builder images.
16 | mkdir -p unittest/Catch/single_include/catch2
17 | curl -L -o unittest/Catch/single_include/catch2/catch.hpp https://github.com/catchorg/Catch2/releases/download/v2.3.0/catch.hpp
18 |
19 | mkdir build
20 | mkdir install
21 |
22 | pushd build
23 | cmake .. -DERROR_ON_WARNING=OFF -DCOMPILE_TESTS=ON
24 | make -j2
25 | ctest -VV
26 | make install DESTDIR=../install
27 | popd
28 |
29 | pushd unittest
30 | python3 -m pytest -sv test_offline.py
31 | popd
32 |
--------------------------------------------------------------------------------
/ci-script/package.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -exuo pipefail
3 | export
4 | mkdir -p artifacts
5 | OUTDIR="$(realpath artifacts)"
6 |
7 | BASENAME="libnitrokey"
8 | #pushd libnitrokey
9 |
10 | VERSION="$(git describe --abbrev=0)"
11 | BUILD="${VERSION}.${CI_COMMIT_SHORT_SHA}"
12 | DATE="$(date -Iseconds)"
13 | case "${CI_PIPELINE_SOURCE}" in
14 | push)
15 | OUTNAME="${BASENAME}-${BUILD}"
16 | ;;
17 | schedule)
18 | OUTNAME="${BASENAME}-${DATE}"
19 | ;;
20 | web)
21 | OUTNAME="${BASENAME}-${VERSION}"
22 | ;;
23 | esac
24 |
25 | git archive --format tar --prefix ${OUTNAME}/ ${CI_COMMIT_SHA} | gzip > ${OUTDIR}/${OUTNAME}.tar.gz
26 | echo size:
27 | gzip -l ${OUTDIR}/${OUTNAME}.tar.gz
28 |
29 | echo "LIBNITROKEY_BUILD_VERSION=\"${VERSION}\"" >> ./metadata
30 | echo "LIBNITROKEY_BUILD_ID=\"${BUILD}\"" >> ./metadata
31 | echo "LIBNITROKEY_BUILD_DATE=\"${DATE}\"" >> ./metadata
32 | echo "LIBNITROKEY_BUILD_TYPE=\"${CI_PIPELINE_SOURCE}\"" >> ./metadata
33 | echo "LIBNITROKEY_BUILD_OUTNAME=\"${OUTNAME}\"" >> ./metadata
34 | cat ./metadata
35 | pwd
36 | ls
37 | mkdir -p libnitrokey-source-metadata
38 | mv metadata libnitrokey-source-metadata/
39 | cat libnitrokey-source-metadata/metadata
40 | pushd ${OUTDIR}
41 | sha256sum *.tar.gz > SHA256SUM
42 | popd
43 |
--------------------------------------------------------------------------------
/command_id.cc:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2015-2018 Nitrokey UG
3 | *
4 | * This file is part of libnitrokey.
5 | *
6 | * libnitrokey is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU Lesser General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * any later version.
10 | *
11 | * libnitrokey is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU Lesser General Public License
17 | * along with libnitrokey. If not, see .
18 | *
19 | * SPDX-License-Identifier: LGPL-3.0
20 | */
21 |
22 | #include
23 | #include "command_id.h"
24 |
25 | namespace nitrokey {
26 | namespace proto {
27 |
28 | const char *commandid_to_string(CommandID id) {
29 | #ifdef NO_LOG
30 | return "";
31 | #endif
32 | switch (id) {
33 | case CommandID::GET_STATUS:
34 | return "GET_STATUS";
35 | case CommandID::WRITE_TO_SLOT:
36 | return "WRITE_TO_SLOT";
37 | case CommandID::READ_SLOT_NAME:
38 | return "READ_SLOT_NAME";
39 | case CommandID::READ_SLOT:
40 | return "READ_SLOT";
41 | case CommandID::GET_CODE:
42 | return "GET_CODE";
43 | case CommandID::WRITE_CONFIG:
44 | return "WRITE_CONFIG";
45 | case CommandID::ERASE_SLOT:
46 | return "ERASE_SLOT";
47 | case CommandID::FIRST_AUTHENTICATE:
48 | return "FIRST_AUTHENTICATE";
49 | case CommandID::AUTHORIZE:
50 | return "AUTHORIZE";
51 | case CommandID::GET_PASSWORD_RETRY_COUNT:
52 | return "GET_PASSWORD_RETRY_COUNT";
53 | case CommandID::CLEAR_WARNING:
54 | return "CLEAR_WARNING";
55 | case CommandID::SET_TIME:
56 | return "SET_TIME";
57 | case CommandID::TEST_COUNTER:
58 | return "TEST_COUNTER";
59 | case CommandID::TEST_TIME:
60 | return "TEST_TIME";
61 | case CommandID::USER_AUTHENTICATE:
62 | return "USER_AUTHENTICATE";
63 | case CommandID::GET_USER_PASSWORD_RETRY_COUNT:
64 | return "GET_USER_PASSWORD_RETRY_COUNT";
65 | case CommandID::USER_AUTHORIZE:
66 | return "USER_AUTHORIZE";
67 | case CommandID::UNLOCK_USER_PASSWORD:
68 | return "UNLOCK_USER_PASSWORD";
69 | case CommandID::LOCK_DEVICE:
70 | return "LOCK_DEVICE";
71 | case CommandID::FACTORY_RESET:
72 | return "FACTORY_RESET";
73 | case CommandID::CHANGE_USER_PIN:
74 | return "CHANGE_USER_PIN";
75 | case CommandID::CHANGE_ADMIN_PIN:
76 | return "CHANGE_ADMIN_PIN";
77 | case CommandID::FIRMWARE_UPDATE:
78 | return "FIRMWARE_UPDATE";
79 | case CommandID::FIRMWARE_PASSWORD_CHANGE:
80 | return "FIRMWARE_PASSWORD_CHANGE";
81 |
82 | case CommandID::ENABLE_CRYPTED_PARI:
83 | return "ENABLE_CRYPTED_PARI";
84 | case CommandID::DISABLE_CRYPTED_PARI:
85 | return "DISABLE_CRYPTED_PARI";
86 | case CommandID::ENABLE_HIDDEN_CRYPTED_PARI:
87 | return "ENABLE_HIDDEN_CRYPTED_PARI";
88 | case CommandID::DISABLE_HIDDEN_CRYPTED_PARI:
89 | return "DISABLE_HIDDEN_CRYPTED_PARI";
90 | case CommandID::ENABLE_FIRMWARE_UPDATE:
91 | return "ENABLE_FIRMWARE_UPDATE";
92 | case CommandID::EXPORT_FIRMWARE_TO_FILE:
93 | return "EXPORT_FIRMWARE_TO_FILE";
94 | case CommandID::GENERATE_NEW_KEYS:
95 | return "GENERATE_NEW_KEYS";
96 | case CommandID::FILL_SD_CARD_WITH_RANDOM_CHARS:
97 | return "FILL_SD_CARD_WITH_RANDOM_CHARS";
98 |
99 | case CommandID::WRITE_STATUS_DATA:
100 | return "WRITE_STATUS_DATA";
101 | case CommandID::ENABLE_READONLY_UNCRYPTED_LUN:
102 | return "ENABLE_READONLY_UNCRYPTED_LUN";
103 | case CommandID::ENABLE_READWRITE_UNCRYPTED_LUN:
104 | return "ENABLE_READWRITE_UNCRYPTED_LUN";
105 |
106 | case CommandID::SEND_PASSWORD_MATRIX:
107 | return "SEND_PASSWORD_MATRIX";
108 | case CommandID::SEND_PASSWORD_MATRIX_PINDATA:
109 | return "SEND_PASSWORD_MATRIX_PINDATA";
110 | case CommandID::SEND_PASSWORD_MATRIX_SETUP:
111 | return "SEND_PASSWORD_MATRIX_SETUP";
112 |
113 | case CommandID::GET_DEVICE_STATUS:
114 | return "GET_DEVICE_STATUS";
115 | case CommandID::SEND_DEVICE_STATUS:
116 | return "SEND_DEVICE_STATUS";
117 |
118 | case CommandID::SEND_HIDDEN_VOLUME_PASSWORD:
119 | return "SEND_HIDDEN_VOLUME_PASSWORD";
120 | case CommandID::SEND_HIDDEN_VOLUME_SETUP:
121 | return "SEND_HIDDEN_VOLUME_SETUP";
122 | case CommandID::SEND_PASSWORD:
123 | return "SEND_PASSWORD";
124 | case CommandID::SEND_NEW_PASSWORD:
125 | return "SEND_NEW_PASSWORD";
126 | case CommandID::CLEAR_NEW_SD_CARD_FOUND:
127 | return "CLEAR_NEW_SD_CARD_FOUND";
128 |
129 | case CommandID::SEND_STARTUP:
130 | return "SEND_STARTUP";
131 | case CommandID::SEND_CLEAR_STICK_KEYS_NOT_INITIATED:
132 | return "SEND_CLEAR_STICK_KEYS_NOT_INITIATED";
133 | case CommandID::SEND_LOCK_STICK_HARDWARE:
134 | return "SEND_LOCK_STICK_HARDWARE";
135 |
136 | case CommandID::PRODUCTION_TEST:
137 | return "PRODUCTION_TEST";
138 | case CommandID::SEND_DEBUG_DATA:
139 | return "SEND_DEBUG_DATA";
140 |
141 | case CommandID::CHANGE_UPDATE_PIN:
142 | return "CHANGE_UPDATE_PIN";
143 |
144 | case CommandID::ENABLE_ADMIN_READONLY_UNCRYPTED_LUN:
145 | return "ENABLE_ADMIN_READONLY_UNCRYPTED_LUN";
146 | case CommandID::ENABLE_ADMIN_READWRITE_UNCRYPTED_LUN:
147 | return "ENABLE_ADMIN_READWRITE_UNCRYPTED_LUN";
148 | case CommandID::ENABLE_ADMIN_READONLY_ENCRYPTED_LUN:
149 | return "ENABLE_ADMIN_READONLY_ENCRYPTED_LUN";
150 | case CommandID::ENABLE_ADMIN_READWRITE_ENCRYPTED_LUN:
151 | return "ENABLE_ADMIN_READWRITE_ENCRYPTED_LUN";
152 | case CommandID::CHECK_SMARTCARD_USAGE:
153 | return "CHECK_SMARTCARD_USAGE";
154 |
155 | case CommandID::GET_PW_SAFE_SLOT_STATUS:
156 | return "GET_PW_SAFE_SLOT_STATUS";
157 | case CommandID::GET_PW_SAFE_SLOT_NAME:
158 | return "GET_PW_SAFE_SLOT_NAME";
159 | case CommandID::GET_PW_SAFE_SLOT_PASSWORD:
160 | return "GET_PW_SAFE_SLOT_PASSWORD";
161 | case CommandID::GET_PW_SAFE_SLOT_LOGINNAME:
162 | return "GET_PW_SAFE_SLOT_LOGINNAME";
163 | case CommandID::SET_PW_SAFE_SLOT_DATA_1:
164 | return "SET_PW_SAFE_SLOT_DATA_1";
165 | case CommandID::SET_PW_SAFE_SLOT_DATA_2:
166 | return "SET_PW_SAFE_SLOT_DATA_2";
167 | case CommandID::PW_SAFE_ERASE_SLOT:
168 | return "PW_SAFE_ERASE_SLOT";
169 | case CommandID::PW_SAFE_ENABLE:
170 | return "PW_SAFE_ENABLE";
171 | case CommandID::PW_SAFE_INIT_KEY:
172 | return "PW_SAFE_INIT_KEY";
173 | case CommandID::PW_SAFE_SEND_DATA:
174 | return "PW_SAFE_SEND_DATA";
175 | case CommandID::SD_CARD_HIGH_WATERMARK:
176 | return "SD_CARD_HIGH_WATERMARK";
177 | case CommandID::DETECT_SC_AES:
178 | return "DETECT_SC_AES";
179 | case CommandID::NEW_AES_KEY:
180 | return "NEW_AES_KEY";
181 | case CommandID::WRITE_TO_SLOT_2:
182 | return "WRITE_TO_SLOT_2";
183 | case CommandID::SEND_OTP_DATA:
184 | return "SEND_OTP_DATA";
185 | case CommandID::WINK:
186 | return "WINK";
187 | case CommandID::GET_RANDOM:
188 | return "GET_RANDOM";
189 | }
190 | return "UNKNOWN";
191 | }
192 | }
193 | }
194 |
--------------------------------------------------------------------------------
/data/41-nitrokey.rules:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright (c) 2015-2022 Nitrokey GmbH
3 | #
4 | # This file is part of libnitrokey.
5 | #
6 | # libnitrokey is free software: you can redistribute it and/or modify
7 | # it under the terms of the GNU Lesser General Public License as published by
8 | # the Free Software Foundation, either version 3 of the License, or
9 | # any later version.
10 | #
11 | # libnitrokey is distributed in the hope that it will be useful,
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | # GNU General Public License for more details.
15 | #
16 | # You should have received a copy of the GNU Lesser General Public License
17 | # along with libnitrokey. If not, see .
18 | #
19 | # SPDX-License-Identifier: LGPL-3.0
20 | #
21 |
22 | # Here rules in new style should be provided. Matching devices should be tagged with 'uaccess'.
23 | # File prefix number should be lower than 73, to be correctly processed by the Udev.
24 | # Recommended udev version: >= 188.
25 | #
26 | ACTION!="add|change", GOTO="u2f_end"
27 |
28 | # Nitrokey U2F
29 | KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="2581", ATTRS{idProduct}=="f1d0", TAG+="uaccess"
30 | # Nitrokey FIDO U2F
31 | KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="20a0", ATTRS{idProduct}=="4287", TAG+="uaccess"
32 | # Nitrokey FIDO2
33 | KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="20a0", ATTRS{idProduct}=="42b1", TAG+="uaccess"
34 | # Nitrokey 3A Mini/3A NFC/3C NFC
35 | KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="20a0", ATTRS{idProduct}=="42b2", TAG+="uaccess"
36 | # Nitrokey 3A NFC Bootloader/3C NFC Bootloader
37 | KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="20a0", ATTRS{idProduct}=="42dd", TAG+="uaccess"
38 | # Nitrokey 3A Mini Bootloader
39 | ATTRS{idVendor}=="20a0", ATTRS{idProduct}=="42e8", TAG+="uaccess"
40 |
41 | LABEL="u2f_end"
42 |
43 |
44 | SUBSYSTEM!="usb", GOTO="gnupg_rules_end"
45 | ACTION!="add", GOTO="gnupg_rules_end"
46 |
47 | # USB SmartCard Readers
48 | ## Crypto Stick 1.2
49 | ATTR{idVendor}=="20a0", ATTR{idProduct}=="4107", ENV{ID_SMARTCARD_READER}="1", ENV{ID_SMARTCARD_READER_DRIVER}="gnupg", TAG+="uaccess"
50 | ## Nitrokey Pro
51 | ATTR{idVendor}=="20a0", ATTR{idProduct}=="4108", ENV{ID_SMARTCARD_READER}="1", ENV{ID_SMARTCARD_READER_DRIVER}="gnupg", TAG+="uaccess"
52 | ## Nitrokey Pro Bootloader
53 | ATTRS{idVendor}=="20a0", ATTRS{idProduct}=="42b4", TAG+="uaccess"
54 | ## Nitrokey Storage
55 | ATTR{idVendor}=="20a0", ATTR{idProduct}=="4109", ENV{ID_SMARTCARD_READER}="1", ENV{ID_SMARTCARD_READER_DRIVER}="gnupg", TAG+="uaccess"
56 | ## Nitrokey Storage Bootloader
57 | ATTR{idVendor}=="03eb", ATTR{idProduct}=="2ff1", TAG+="uaccess"
58 | ## Nitrokey Start
59 | ATTR{idVendor}=="20a0", ATTR{idProduct}=="4211", ENV{ID_SMARTCARD_READER}="1", ENV{ID_SMARTCARD_READER_DRIVER}="gnupg", TAG+="uaccess"
60 | ## Nitrokey HSM
61 | ATTR{idVendor}=="20a0", ATTR{idProduct}=="4230", ENV{ID_SMARTCARD_READER}="1", ENV{ID_SMARTCARD_READER_DRIVER}="gnupg", TAG+="uaccess"
62 |
63 | LABEL="gnupg_rules_end"
64 |
65 |
66 | # Nitrokey Storage dev Entry
67 | KERNEL=="sd?1", ATTRS{idVendor}=="20a0", ATTRS{idProduct}=="4109", SYMLINK+="nitrospace"
68 |
--------------------------------------------------------------------------------
/data/41-nitrokey_old.rules:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright (c) 2015-2022 Nitrokey GmbH
3 | #
4 | # This file is part of libnitrokey.
5 | #
6 | # libnitrokey is free software: you can redistribute it and/or modify
7 | # it under the terms of the GNU Lesser General Public License as published by
8 | # the Free Software Foundation, either version 3 of the License, or
9 | # any later version.
10 | #
11 | # libnitrokey is distributed in the hope that it will be useful,
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | # GNU General Public License for more details.
15 | #
16 | # You should have received a copy of the GNU Lesser General Public License
17 | # along with libnitrokey. If not, see .
18 | #
19 | # SPDX-License-Identifier: LGPL-3.0
20 | #
21 |
22 | # Here rules in old style should be provided. Matching devices should be added to 'plugdev' group,
23 | # and with mode set to "0660".
24 | # File prefix number should be lower than 73, to be correctly processed by the Udev.
25 | # Recommended udev version: < 188.
26 | #
27 | ACTION!="add|change", GOTO="u2f_end"
28 |
29 | # Nitrokey U2F
30 | KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="2581", ATTRS{idProduct}=="f1d0", MODE="0660", GROUP+="plugdev"
31 | # Nitrokey FIDO U2F
32 | KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="20a0", ATTRS{idProduct}=="4287", MODE="0660", GROUP+="plugdev"
33 | # Nitrokey FIDO2
34 | KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="20a0", ATTRS{idProduct}=="42b1", MODE="0660", GROUP+="plugdev"
35 | # Nitrokey 3A Mini/3A NFC/3C NFC
36 | KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="20a0", ATTRS{idProduct}=="42b2", MODE="0660", GROUP+="plugdev"
37 | # Nitrokey 3A NFC Bootloader/3C NFC Bootloader
38 | KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="20a0", ATTRS{idProduct}=="42dd", MODE="0660", GROUP+="plugdev"
39 | # Nitrokey 3A Mini Bootloader
40 | KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="20a0", ATTRS{idProduct}=="42e8", MODE="0660", GROUP+="plugdev"
41 |
42 | LABEL="u2f_end"
43 |
44 |
45 | SUBSYSTEM!="usb", GOTO="gnupg_rules_end"
46 | ACTION!="add", GOTO="gnupg_rules_end"
47 |
48 | # USB SmartCard Readers
49 | ## Crypto Stick 1.2
50 | ATTR{idVendor}=="20a0", ATTR{idProduct}=="4107", ENV{ID_SMARTCARD_READER}="1", ENV{ID_SMARTCARD_READER_DRIVER}="gnupg", MODE="0660", GROUP+="plugdev"
51 | ## Nitrokey Pro
52 | ATTR{idVendor}=="20a0", ATTR{idProduct}=="4108", ENV{ID_SMARTCARD_READER}="1", ENV{ID_SMARTCARD_READER_DRIVER}="gnupg", MODE="0660", GROUP+="plugdev"
53 | ## Nitrokey Pro Bootloader
54 | ATTRS{idVendor}=="20a0", ATTRS{idProduct}=="42b4", MODE="0660", GROUP+="plugdev"
55 | ## Nitrokey Storage
56 | ATTR{idVendor}=="20a0", ATTR{idProduct}=="4109", ENV{ID_SMARTCARD_READER}="1", ENV{ID_SMARTCARD_READER_DRIVER}="gnupg", MODE="0660", GROUP+="plugdev"
57 | ## Nitrokey Storage Bootloader
58 | ATTRS{idVendor}=="03eb", ATTRS{idProduct}=="2ff1", MODE="0660", GROUP+="plugdev"
59 | ## Nitrokey Start
60 | ATTR{idVendor}=="20a0", ATTR{idProduct}=="4211", ENV{ID_SMARTCARD_READER}="1", ENV{ID_SMARTCARD_READER_DRIVER}="gnupg", MODE="0660", GROUP+="plugdev"
61 | ## Nitrokey HSM
62 | ATTR{idVendor}=="20a0", ATTR{idProduct}=="4230", ENV{ID_SMARTCARD_READER}="1", ENV{ID_SMARTCARD_READER_DRIVER}="gnupg", MODE="0660", GROUP+="plugdev"
63 |
64 | LABEL="gnupg_rules_end"
65 |
66 |
67 | # Nitrokey Storage dev Entry
68 | KERNEL=="sd?1", ATTRS{idVendor}=="20a0", ATTRS{idProduct}=="4109", SYMLINK+="nitrospace"
69 |
--------------------------------------------------------------------------------
/data/Pipfile:
--------------------------------------------------------------------------------
1 | [[source]]
2 | name = "pypi"
3 | url = "https://pypi.org/simple"
4 | verify_ssl = true
5 |
6 | [dev-packages]
7 |
8 | [packages]
9 | click = "*"
10 | regex = "*"
11 |
12 | [requires]
13 | python_version = "3.8"
14 |
15 |
16 |
--------------------------------------------------------------------------------
/data/Pipfile.lock:
--------------------------------------------------------------------------------
1 | {
2 | "_meta": {
3 | "hash": {
4 | "sha256": "dbef89dbb42c3ae6b022f78b5e003cca039534820aa0e047b11872492211927b"
5 | },
6 | "pipfile-spec": 6,
7 | "requires": {
8 | "python_version": "3.8"
9 | },
10 | "sources": [
11 | {
12 | "name": "pypi",
13 | "url": "https://pypi.org/simple",
14 | "verify_ssl": true
15 | }
16 | ]
17 | },
18 | "default": {
19 | "click": {
20 | "hashes": [
21 | "sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e",
22 | "sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48"
23 | ],
24 | "index": "pypi",
25 | "version": "==8.1.3"
26 | },
27 | "regex": {
28 | "hashes": [
29 | "sha256:02543d6d5c32d361b7cc468079ba4cddaaf4a6544f655901ba1ff9d8e3f18755",
30 | "sha256:036d1c1fbe69eba3ee253c107e71749cdbb4776db93d674bc0d5e28f30300734",
31 | "sha256:071bcb625e890f28b7c4573124a6512ea65107152b1d3ca101ce33a52dad4593",
32 | "sha256:0f8da3145f4b72f7ce6181c804eaa44cdcea313c8998cdade3d9e20a8717a9cb",
33 | "sha256:0fb6cb16518ac7eff29d1e0b0cce90275dfae0f17154165491058c31d58bdd1d",
34 | "sha256:0fd464e547dbabf4652ca5fe9d88d75ec30182981e737c07b3410235a44b9939",
35 | "sha256:12af15b6edb00e425f713160cfd361126e624ec0de86e74f7cad4b97b7f169b3",
36 | "sha256:165cc75cfa5aa0f12adb2ac6286330e7229a06dc0e6c004ec35da682b5b89579",
37 | "sha256:1a07e8366115069f26822c47732122ab61598830a69f5629a37ea8881487c107",
38 | "sha256:1c2de7f32fa87d04d40f54bce3843af430697aba51c3a114aa62837a0772f219",
39 | "sha256:253f858a0255cd91a0424a4b15c2eedb12f20274f85731b0d861c8137e843065",
40 | "sha256:275afc7352982ee947fc88f67a034b52c78395977b5fc7c9be15f7dc95b76f06",
41 | "sha256:2bde99f2cdfd6db1ec7e02d68cadd384ffe7413831373ea7cc68c5415a0cb577",
42 | "sha256:3241db067a7f69da57fba8bca543ac8a7ca415d91e77315690202749b9fdaba1",
43 | "sha256:37903d5ca11fa47577e8952d2e2c6de28553b11c70defee827afb941ab2c6729",
44 | "sha256:3dfbadb7b74d95f72f9f9dbf9778f7de92722ab520a109ceaf7927461fa85b10",
45 | "sha256:3e35c50b27f36176c792738cb9b858523053bc495044d2c2b44db24376b266f1",
46 | "sha256:3e9e983fc8e0d4d5ded7caa5aed39ca2cf6026d7e39801ef6f0af0b1b6cd9276",
47 | "sha256:3f6bd8178cce5bb56336722d5569d19c50bba5915a69a2050c497fb921e7cb0f",
48 | "sha256:43ee0df35925ae4b0cc6ee3f60b73369e559dd2ac40945044da9394dd9d3a51d",
49 | "sha256:45b761406777a681db0c24686178532134c937d24448d9e085279b69e9eb7da4",
50 | "sha256:46cbc5b23f85e94161b093dba1b49035697cf44c7db3c930adabfc0e6d861b95",
51 | "sha256:4f2e2cef324ca9355049ee1e712f68e2e92716eba24275e6767b9bfa15f1f478",
52 | "sha256:50b77622016f03989cd06ecf6b602c7a6b4ed2e3ce04133876b041d109c934ee",
53 | "sha256:582ea06079a03750b5f71e20a87cd99e646d796638b5894ff85987ebf5e04924",
54 | "sha256:58521abdab76583bd41ef47e5e2ddd93b32501aee4ee8cee71dee10a45ba46b1",
55 | "sha256:5b9c7b6895a01204296e9523b3e12b43e013835a9de035a783907c2c1bc447f0",
56 | "sha256:6165e737acb3bea3271372e8aa5ebe7226c8a8e8da1b94af2d6547c5a09d689d",
57 | "sha256:66fb765b2173d90389384708e3e1d3e4be1148bd8d4d50476b1469da5a2f0229",
58 | "sha256:68aed3fb0c61296bd6d234f558f78c51671f79ccb069cbcd428c2eea6fee7a5b",
59 | "sha256:6a0ef57cccd8089b4249eebad95065390e56c04d4a92c51316eab4131bca96a9",
60 | "sha256:709396c0c95b95045fac89b94f997410ff39b81a09863fe21002f390d48cc7d3",
61 | "sha256:73ed1b06abadbf6b61f6033a07c06f36ec0ddca117e41ef2ac37056705e46458",
62 | "sha256:7a608022f4593fc67518c6c599ae5abdb03bb8acd75993c82cd7a4c8100eff81",
63 | "sha256:7c4d9770e579eb11b582b2e2fd19fa204a15cb1589ae73cd4dcbb63b64f3e828",
64 | "sha256:7dbc96419ef0fb6ac56626014e6d3a345aeb8b17a3df8830235a88626ffc8d84",
65 | "sha256:7f271d0831d8ebc56e17b37f9fa1824b0379221d1238ae77c18a6e8c47f1fdce",
66 | "sha256:82b7fc67e49fdce671bdbec1127189fc979badf062ce6e79dc95ef5e07a8bf92",
67 | "sha256:85b7ee4d0c7a46296d884f6b489af8b960c4291d76aea4b22fd4fbe05e6ec08e",
68 | "sha256:8b747cef8e5dcdaf394192d43a0c02f5825aeb0ecd3d43e63ae500332ab830b0",
69 | "sha256:8bf867ba71856414a482e4b683500f946c300c4896e472e51d3db8dfa8dc8f32",
70 | "sha256:8e0da7ef160d4f3eb3d4d3e39a02c3c42f7dbcfce62c81f784cc99fc7059765f",
71 | "sha256:8e7d33f93cdd01868327d834d0f5bb029241cd293b47d51b96814dec27fc9b4b",
72 | "sha256:92183e9180c392371079262879c6532ccf55f808e6900df5d9f03c9ca8807255",
73 | "sha256:92ad03f928675ca05b79d3b1d3dfc149e2226d57ed9d57808f82105d511d0212",
74 | "sha256:97af238389cb029d63d5f2d931a7e8f5954ad96e812de5faaed373b68e74df86",
75 | "sha256:9913bcf730eb6e9b441fb176832eea9acbebab6035542c7c89d90c803f5cd3be",
76 | "sha256:9dae5affbb66178dad6c6fd5b02221ca9917e016c75ee3945e9a9563eb1fbb6f",
77 | "sha256:a850f5f369f1e3b6239da7fb43d1d029c1e178263df671819889c47caf7e4ff3",
78 | "sha256:aa6daa189db9104787ff1fd7a7623ce017077aa59eaac609d0d25ba95ed251a0",
79 | "sha256:aabc28f7599f781ddaeac168d0b566d0db82182cc3dcf62129f0a4fc2927b811",
80 | "sha256:af1e687ffab18a75409e5e5d6215b6ccd41a5a1a0ea6ce9665e01253f737a0d3",
81 | "sha256:b1d53835922cd0f9b74b2742453a444865a70abae38d12eb41c59271da66f38d",
82 | "sha256:b2df3ede85d778c949d9bd2a50237072cee3df0a423c91f5514f78f8035bde87",
83 | "sha256:b415b82e5be7389ec5ee7ee35431e4a549ea327caacf73b697c6b3538cb5c87f",
84 | "sha256:b7ba3c304a4a5d8112dbd30df8b3e4ef59b4b07807957d3c410d9713abaee9a8",
85 | "sha256:bcc6f7a3a95119c3568c572ca167ada75f8319890706283b9ba59b3489c9bcb3",
86 | "sha256:be392d9cd5309509175a9d7660dc17bf57084501108dbff0c5a8bfc3646048c3",
87 | "sha256:bea61de0c688198e3d9479344228c7accaa22a78b58ec408e41750ebafee6c08",
88 | "sha256:bedb3d01ad35ea1745bdb1d57f3ee0f996f988c98f5bbae9d068c3bb3065d210",
89 | "sha256:c36906a7855ec33a9083608e6cd595e4729dab18aeb9aad0dd0b039240266239",
90 | "sha256:c4fdf837666f7793a5c3cfa2f2f39f03eb6c7e92e831bc64486c2f547580c2b3",
91 | "sha256:cfad3a770839aa456ff9a9aa0e253d98b628d005a3ccb37da1ff9be7c84fee16",
92 | "sha256:d128e278e5e554c5c022c7bed410ca851e00bacebbb4460de546a73bc53f8de4",
93 | "sha256:dffd9114ade73137ab2b79a8faf864683dbd2dbbb6b23a305fbbd4cbaeeb2187",
94 | "sha256:e2acf5c66fbb62b5fe4c40978ddebafa50818f00bf79d60569d9762f6356336e",
95 | "sha256:e65580ae3137bce712f505ec7c2d700aef0014a3878c4767b74aff5895fc454f",
96 | "sha256:e944268445b5694f5d41292c9228f0ca46d5a32a67f195d5f8547c1f1d91f4bc",
97 | "sha256:ed26c3d2d62c6588e0dad175b8d8cc0942a638f32d07b80f92043e5d73b7db67",
98 | "sha256:ed625205f5f26984382b68e4cbcbc08e6603c9e84c14b38457170b0cc71c823b",
99 | "sha256:f2a5d9f612091812dee18375a45d046526452142e7b78c4e21ab192db15453d5",
100 | "sha256:f86aef546add4ff1202e1f31e9bb54f9268f17d996b2428877283146bf9bc013",
101 | "sha256:f89d26e50a4c7453cb8c415acd09e72fbade2610606a9c500a1e48c43210a42d",
102 | "sha256:fb7107faf0168de087f62a2f2ed00f9e9da12e0b801582b516ddac236b871cda"
103 | ],
104 | "index": "pypi",
105 | "version": "==2022.4.24"
106 | }
107 | },
108 | "develop": {}
109 | }
110 |
--------------------------------------------------------------------------------
/data/README.md:
--------------------------------------------------------------------------------
1 |
2 | The specified USB IDs in the Udev rules file are as follows:
3 |
4 | | Name | USB ID |
5 | |----------------------------------------------|:---------:|
6 | | Crypto Stick 1.2 | 20a0:4107 |
7 | | Nitrokey 3A Mini/3A NFC/3C NFC | 20a0:42b2 |
8 | | Nitrokey 3A NFC Bootloader/3C NFC Bootloader | 20a0:42dd |
9 | | Nitrokey 3A Mini Bootloader | 20a0:42e8 |
10 | | Nitrokey FIDO U2F | 20a0:4287 |
11 | | Nitrokey FIDO2 | 20a0:42b1 |
12 | | Nitrokey HSM | 20a0:4230 |
13 | | Nitrokey Pro | 20a0:4108 |
14 | | Nitrokey Pro Bootloader | 20a0:42b4 |
15 | | Nitrokey Start | 20a0:4211 |
16 | | Nitrokey Storage | 20a0:4109 |
17 | | Nitrokey Storage Bootloader | 03eb:2ff1 |
18 | | Nitrokey U2F | 2581:f1d0 |
19 |
20 | Generated from `41-nitrokey.rules`.
--------------------------------------------------------------------------------
/data/generate_udev_docs.py:
--------------------------------------------------------------------------------
1 | import click
2 | import regex as re
3 |
4 |
5 | @click.command()
6 | @click.argument('input', type=click.File('rt'))
7 | def main(input: click.File):
8 | print(f"| {'Name':40s} | {'USB ID':9s} |")
9 | print("|------------------------------------------|:---------:|")
10 | name = ''
11 | res = []
12 | for l in input:
13 | l = l.strip()
14 | if l.startswith("#"):
15 | name = l.strip("#").strip()
16 | continue
17 | pid = re.findall(r'ATTR[S]?\{idProduct\}=="(\w+)"', l, re.VERSION1)
18 | vid = re.findall(r'ATTR[S]?\{idVendor\}=="(\w+)"', l, re.VERSION1)
19 | if pid:
20 | res.append((name, vid[0], pid[0]))
21 |
22 | res = sorted(res)
23 | for r in res:
24 | if "dev Entry" in r[0]:
25 | continue
26 | print(f"| {r[0]:40s} | {r[1]}:{r[2]} |")
27 |
28 | print()
29 | print(f'Generated from {input.name}')
30 |
31 |
32 | if __name__ == '__main__':
33 | main()
34 |
--------------------------------------------------------------------------------
/libnitrokey.pc.in:
--------------------------------------------------------------------------------
1 | libdir=@CMAKE_INSTALL_FULL_LIBDIR@
2 | includedir=@CMAKE_INSTALL_FULL_INCLUDEDIR@
3 |
4 | Name: libnitrokey
5 | Description: Library for communicating with Nitrokey in a clean and easy manner
6 | Version: @libnitrokey_VERSION@
7 | Requires.private: @HIDAPI_LIBUSB_NAME@
8 |
9 | Libs: -L${libdir} -lnitrokey
10 | Cflags: -I${includedir}
11 |
--------------------------------------------------------------------------------
/libnitrokey.pro:
--------------------------------------------------------------------------------
1 | # Created by and for Qt Creator. This file was created for editing the project sources only.
2 | # You may attempt to use it for building too, by modifying this file here.
3 |
4 | CONFIG += c++14 shared debug
5 |
6 |
7 | TEMPLATE = lib
8 | TARGET = nitrokey
9 |
10 | VERSION = 3.7.0
11 | LIBNK_VERSION_MAJOR = 3
12 | LIBNK_VERSION_MINOR = 7
13 |
14 | QMAKE_TARGET_COMPANY = Nitrokey
15 | QMAKE_TARGET_PRODUCT = libnitrokey
16 | QMAKE_TARGET_DESCRIPTION = Communicate with Nitrokey stick devices in a clean and easy manner
17 | QMAKE_TARGET_COPYRIGHT = Copyright (c) 2015-2022 Nitrokey Gmbh
18 |
19 | HEADERS = \
20 | $$PWD/hidapi/hidapi/hidapi.h \
21 | $$PWD/libnitrokey/command.h \
22 | $$PWD/libnitrokey/command_id.h \
23 | $$PWD/libnitrokey/CommandFailedException.h \
24 | $$PWD/libnitrokey/cxx_semantics.h \
25 | $$PWD/libnitrokey/device.h \
26 | $$PWD/libnitrokey/device_proto.h \
27 | $$PWD/libnitrokey/DeviceCommunicationExceptions.h \
28 | $$PWD/libnitrokey/dissect.h \
29 | $$PWD/libnitrokey/LibraryException.h \
30 | $$PWD/libnitrokey/log.h \
31 | $$PWD/libnitrokey/version.h \
32 | $$PWD/libnitrokey/LongOperationInProgressException.h \
33 | $$PWD/libnitrokey/misc.h \
34 | $$PWD/libnitrokey/NitrokeyManager.h \
35 | $$PWD/libnitrokey/stick10_commands.h \
36 | $$PWD/libnitrokey/stick10_commands_0.8.h \
37 | $$PWD/libnitrokey/stick20_commands.h \
38 | $$PWD/NK_C_API.h
39 |
40 |
41 | SOURCES = \
42 | $$PWD/command_id.cc \
43 | $$PWD/device.cc \
44 | $$PWD/DeviceCommunicationExceptions.cpp \
45 | $$PWD/log.cc \
46 | $$PWD/version.cc \
47 | $$PWD/misc.cc \
48 | $$PWD/NitrokeyManager.cc \
49 | $$PWD/NK_C_API.cc
50 |
51 |
52 | tests {
53 | SOURCES += \
54 | $$PWD/unittest/catch_main.cpp \
55 | $$PWD/unittest/test.cc \
56 | $$PWD/unittest/test2.cc \
57 | $$PWD/unittest/test3.cc \
58 | $$PWD/unittest/test_C_API.cpp \
59 | $$PWD/unittest/test_HOTP.cc
60 | }
61 |
62 | unix:!macx{
63 | # SOURCES += $$PWD/hidapi/linux/hid.c
64 | LIBS += -lhidapi-libusb
65 | }
66 |
67 | macx{
68 | SOURCES += $$PWD/hidapi/mac/hid.c
69 | LIBS+= -framework IOKit -framework CoreFoundation
70 | }
71 |
72 | win32 {
73 | SOURCES += $$PWD/hidapi/windows/hid.c
74 | LIBS += -lsetupapi
75 | }
76 |
77 | INCLUDEPATH = \
78 | $$PWD/. \
79 | $$PWD/hidapi/hidapi \
80 | $$PWD/libnitrokey \
81 | $$PWD/libnitrokey/hidapi \
82 | $$PWD/unittest \
83 | $$PWD/unittest/Catch/single_include
84 |
85 | unix:!macx{
86 | # Install rules for QMake (CMake is preffered though)
87 | udevrules.path = $$system(pkg-config --variable=udevdir udev)
88 | isEmpty(udevrules.path){
89 | udevrules.path = "/lib/udev/"
90 | message("Could not detect path for udev rules - setting default: " $$udevrules.path)
91 | }
92 | udevrules.path = $$udevrules.path"/rules.d"
93 | udevrules.files = $$PWD/"data/41-nitrokey.rules"
94 | message ($$udevrules.files)
95 | INSTALLS +=udevrules
96 |
97 | headers.files = $$HEADERS
98 | headers.path = /usr/local/include/libnitrokey/
99 | INSTALLS += headers
100 |
101 | libbin.path = /usr/local/lib
102 | INSTALLS += libbin
103 | }
104 |
105 | DEFINES += LIBNK_GIT_VERSION=\"\\\"$$system(git describe --abbrev=4 --always)\\\"\" LIBNK_VERSION="\\\"$${VERSION}\\\""
106 | DEFINES += LIBNK_VERSION_MAJOR=$${LIBNK_VERSION_MAJOR} LIBNK_VERSION_MINOR=$${LIBNK_VERSION_MINOR}
107 | message($$DEFINES)
108 |
--------------------------------------------------------------------------------
/libnitrokey/CommandFailedException.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2015-2018 Nitrokey UG
3 | *
4 | * This file is part of libnitrokey.
5 | *
6 | * libnitrokey is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU Lesser General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * any later version.
10 | *
11 | * libnitrokey is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU Lesser General Public License
17 | * along with libnitrokey. If not, see .
18 | *
19 | * SPDX-License-Identifier: LGPL-3.0
20 | */
21 |
22 | #ifndef LIBNITROKEY_COMMANDFAILEDEXCEPTION_H
23 | #define LIBNITROKEY_COMMANDFAILEDEXCEPTION_H
24 |
25 | #include
26 | #include
27 | #include "log.h"
28 | #include "command_id.h"
29 |
30 | using cs = nitrokey::proto::stick10::command_status;
31 | using cs2 = nitrokey::proto::stick20::device_status;
32 |
33 | class CommandFailedException : public std::exception {
34 | public:
35 | const uint8_t last_command_id;
36 | const uint8_t last_command_status;
37 |
38 | CommandFailedException(uint8_t last_command_id_, uint8_t last_command_status_) :
39 | last_command_id(last_command_id_),
40 | last_command_status(last_command_status_) {
41 | LOG(std::string("CommandFailedException, status: ")+ std::to_string(last_command_status), nitrokey::log::Loglevel::DEBUG);
42 | }
43 |
44 | virtual const char *what() const noexcept override {
45 | return "Command execution has failed on device";
46 | }
47 |
48 |
49 | bool reason_timestamp_warning() const noexcept {
50 | return last_command_status == static_cast(cs::timestamp_warning);
51 | }
52 |
53 | bool reason_AES_not_initialized() const noexcept {
54 | return last_command_status == static_cast(cs::AES_dec_failed);
55 | }
56 |
57 | bool reason_not_authorized() const noexcept {
58 | return last_command_status == static_cast(cs::not_authorized);
59 | }
60 |
61 | bool reason_slot_not_programmed() const noexcept {
62 | return last_command_status == static_cast(cs::slot_not_programmed);
63 | }
64 |
65 | bool reason_wrong_password() const noexcept {
66 | return last_command_status == static_cast(cs::wrong_password);
67 | }
68 |
69 | bool reason_smartcard_busy() const noexcept {
70 | return last_command_status == static_cast(cs2::smartcard_error);
71 | }
72 |
73 | };
74 |
75 |
76 | #endif //LIBNITROKEY_COMMANDFAILEDEXCEPTION_H
77 |
--------------------------------------------------------------------------------
/libnitrokey/DeviceCommunicationExceptions.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2015-2018 Nitrokey UG
3 | *
4 | * This file is part of libnitrokey.
5 | *
6 | * libnitrokey is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU Lesser General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * any later version.
10 | *
11 | * libnitrokey is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU Lesser General Public License
17 | * along with libnitrokey. If not, see .
18 | *
19 | * SPDX-License-Identifier: LGPL-3.0
20 | */
21 |
22 |
23 | #ifndef LIBNITROKEY_DEVICECOMMUNICATIONEXCEPTIONS_H
24 | #define LIBNITROKEY_DEVICECOMMUNICATIONEXCEPTIONS_H
25 |
26 | #include
27 | #include
28 | #include
29 | #include
30 |
31 |
32 | class DeviceCommunicationException: public std::runtime_error
33 | {
34 | std::string message;
35 | static std::atomic_int occurred;
36 | public:
37 | explicit DeviceCommunicationException(const std::string& _msg): std::runtime_error(_msg), message(_msg){
38 | ++occurred;
39 | }
40 | uint8_t getType() const {return 1;}
41 | // virtual const char* what() const noexcept override {
42 | // return message.c_str();
43 | // }
44 | static bool has_occurred(){ return occurred > 0; }
45 | static void reset_occurred_flag(){ occurred = 0; }
46 | };
47 |
48 | class DeviceNotConnected: public DeviceCommunicationException {
49 | public:
50 | DeviceNotConnected(std::string msg) : DeviceCommunicationException(msg){}
51 | uint8_t getType() const {return 2;}
52 | };
53 |
54 | class DeviceSendingFailure: public DeviceCommunicationException {
55 | public:
56 | DeviceSendingFailure(std::string msg) : DeviceCommunicationException(msg){}
57 | uint8_t getType() const {return 3;}
58 | };
59 |
60 | class DeviceReceivingFailure: public DeviceCommunicationException {
61 | public:
62 | DeviceReceivingFailure(std::string msg) : DeviceCommunicationException(msg){}
63 | uint8_t getType() const {return 4;}
64 | };
65 |
66 | class InvalidCRCReceived: public DeviceReceivingFailure {
67 | public:
68 | InvalidCRCReceived(std::string msg) : DeviceReceivingFailure(msg){}
69 | uint8_t getType() const {return 5;}
70 | };
71 |
72 |
73 | #endif //LIBNITROKEY_DEVICECOMMUNICATIONEXCEPTIONS_H
74 |
--------------------------------------------------------------------------------
/libnitrokey/LibraryException.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2015-2018 Nitrokey UG
3 | *
4 | * This file is part of libnitrokey.
5 | *
6 | * libnitrokey is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU Lesser General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * any later version.
10 | *
11 | * libnitrokey is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU Lesser General Public License
17 | * along with libnitrokey. If not, see .
18 | *
19 | * SPDX-License-Identifier: LGPL-3.0
20 | */
21 |
22 | #ifndef LIBNITROKEY_LIBRARYEXCEPTION_H
23 | #define LIBNITROKEY_LIBRARYEXCEPTION_H
24 |
25 | #include
26 | #include
27 | #include
28 | #include
29 | #include "log.h"
30 |
31 | class LibraryException: std::exception {
32 | public:
33 | virtual uint8_t exception_id()= 0;
34 | };
35 |
36 | // Use static string object for keeping the c_str message for the caller.
37 | // Strings collection used as an alternative to memory leaks done via strdup().
38 | // TargetBufferSmallerThanSource Exception should never happen in a correctly written library client.
39 | static std::vector g_exception_messages;
40 | static std::mutex g_exception_message_mutex;
41 |
42 | class TargetBufferSmallerThanSource: public LibraryException {
43 | public:
44 | virtual uint8_t exception_id() override {
45 | return 203;
46 | }
47 |
48 | public:
49 | size_t source_size;
50 | size_t target_size;
51 |
52 | TargetBufferSmallerThanSource(
53 | size_t source_size_, size_t target_size_
54 | ) : source_size(source_size_), target_size(target_size_) {}
55 |
56 | virtual const char *what() const noexcept override {
57 | std::lock_guard lock(g_exception_message_mutex);
58 | std::string s = " ";
59 | auto ts = [](size_t x){ return std::to_string(x); };
60 | g_exception_messages.emplace_back(std::string("Target buffer size is smaller than source: [source size, buffer size]")
61 | + s + ts(source_size) + s + ts(target_size));
62 | return g_exception_messages.back().c_str();
63 | }
64 |
65 | };
66 |
67 | class InvalidHexString : public LibraryException {
68 | public:
69 | virtual uint8_t exception_id() override {
70 | return 202;
71 | }
72 |
73 | public:
74 | uint8_t invalid_char;
75 |
76 | InvalidHexString (uint8_t invalid_char_) : invalid_char(invalid_char_) {}
77 |
78 | virtual const char *what() const noexcept override {
79 | return "Invalid character in hex string";
80 | }
81 |
82 | };
83 |
84 | class InvalidSlotException : public LibraryException {
85 | public:
86 | virtual uint8_t exception_id() override {
87 | return 201;
88 | }
89 |
90 | public:
91 | uint8_t slot_selected;
92 |
93 | InvalidSlotException(uint8_t slot_selected_) : slot_selected(slot_selected_) {}
94 |
95 | virtual const char *what() const noexcept override {
96 | return "Wrong slot selected";
97 | }
98 |
99 | };
100 |
101 |
102 |
103 | class TooLongStringException : public LibraryException {
104 | public:
105 | virtual uint8_t exception_id() override {
106 | return 200;
107 | }
108 |
109 | std::size_t size_source;
110 | std::size_t size_destination;
111 | std::string message;
112 |
113 | TooLongStringException(size_t size_source_, size_t size_destination_, const std::string &message_ = "") : size_source(
114 | size_source_), size_destination(size_destination_), message(message_) {
115 | LOG(std::string("TooLongStringException, size diff: ")+ std::to_string(size_source-size_destination), nitrokey::log::Loglevel::DEBUG);
116 |
117 | }
118 |
119 | virtual const char *what() const noexcept override {
120 | //TODO add sizes and message data to final message
121 | return "Too long string has been supplied as an argument";
122 | }
123 |
124 | };
125 |
126 | #endif //LIBNITROKEY_LIBRARYEXCEPTION_H
127 |
--------------------------------------------------------------------------------
/libnitrokey/LongOperationInProgressException.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2015-2018 Nitrokey UG
3 | *
4 | * This file is part of libnitrokey.
5 | *
6 | * libnitrokey is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU Lesser General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * any later version.
10 | *
11 | * libnitrokey is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU Lesser General Public License
17 | * along with libnitrokey. If not, see .
18 | *
19 | * SPDX-License-Identifier: LGPL-3.0
20 | */
21 |
22 | #ifndef LIBNITROKEY_LONGOPERATIONINPROGRESSEXCEPTION_H
23 | #define LIBNITROKEY_LONGOPERATIONINPROGRESSEXCEPTION_H
24 |
25 | #include "CommandFailedException.h"
26 |
27 | class LongOperationInProgressException : public CommandFailedException {
28 |
29 | public:
30 | unsigned char progress_bar_value;
31 |
32 | LongOperationInProgressException(
33 | unsigned char command_id_, uint8_t last_command_status_, unsigned char progress_bar_value_)
34 | : CommandFailedException(command_id_, last_command_status_), progress_bar_value(progress_bar_value_){
35 | LOG(
36 | std::string("LongOperationInProgressException, progress bar status: ")+
37 | std::to_string(progress_bar_value), nitrokey::log::Loglevel::DEBUG);
38 | }
39 | virtual const char *what() const noexcept override {
40 | return "Device returned busy status with long operation in progress";
41 | }
42 | };
43 |
44 |
45 | #endif //LIBNITROKEY_LONGOPERATIONINPROGRESSEXCEPTION_H
46 |
--------------------------------------------------------------------------------
/libnitrokey/command.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2015-2018 Nitrokey UG
3 | *
4 | * This file is part of libnitrokey.
5 | *
6 | * libnitrokey is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU Lesser General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * any later version.
10 | *
11 | * libnitrokey is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU Lesser General Public License
17 | * along with libnitrokey. If not, see .
18 | *
19 | * SPDX-License-Identifier: LGPL-3.0
20 | */
21 |
22 | #ifndef COMMAND_H
23 | #define COMMAND_H
24 | #include
25 | #include "command_id.h"
26 | #include "cxx_semantics.h"
27 |
28 | #define print_to_ss(x) ( ss << " " << (#x) <<":\t" << (x) << std::endl );
29 | #define print_to_ss_int(x) ( ss << " " << (#x) <<":\t" << static_cast(x) << std::endl );
30 | #ifdef LOG_VOLATILE_DATA
31 | #define print_to_ss_volatile(x) print_to_ss(x);
32 | #else
33 | #define print_to_ss_volatile(x) ( ss << " " << (#x) <<":\t" << "***********" << std::endl );
34 | #endif
35 | #define hexdump_to_ss(x) (ss << #x":\n"\
36 | << ::nitrokey::misc::hexdump(reinterpret_cast(&x), sizeof x, false));
37 |
38 | namespace nitrokey {
39 | namespace proto {
40 |
41 | template
42 | class Command : semantics::non_constructible {
43 | public:
44 | constexpr static CommandID command_id() { return cmd_id; }
45 |
46 | template
47 | std::string dissect(const T &) {
48 | return std::string("Payload dissection is unavailable");
49 | }
50 | };
51 |
52 | namespace stick20{
53 | enum class PasswordKind : uint8_t {
54 | User = 'P',
55 | Admin = 'A',
56 | AdminPrefixed
57 | };
58 |
59 | template
60 | class PasswordCommand : public Command {
61 | constexpr static CommandID _command_id() { return cmd_id; }
62 | public:
63 | struct CommandPayload {
64 | uint8_t kind;
65 | uint8_t password[password_length];
66 |
67 | std::string dissect() const {
68 | std::stringstream ss;
69 | print_to_ss( kind );
70 | print_to_ss_volatile(password);
71 | return ss.str();
72 | }
73 | void set_kind_admin() {
74 | kind = 'A';
75 | }
76 | void set_kind_admin_prefixed() {
77 | kind = 'P';
78 | }
79 | void set_kind_user() {
80 | kind = 'P';
81 | }
82 |
83 | void set_defaults(){
84 | set_kind(Tpassword_kind);
85 | }
86 |
87 | void set_kind(PasswordKind password_kind){
88 | switch (password_kind){
89 | case PasswordKind::Admin:
90 | set_kind_admin();
91 | break;
92 | case PasswordKind::User:
93 | set_kind_user();
94 | break;
95 | case PasswordKind::AdminPrefixed:
96 | set_kind_admin_prefixed();
97 | break;
98 | }
99 | }
100 |
101 | } __packed;
102 |
103 | //typedef Transaction::command_id(), struct CommandPayload, struct EmptyPayload>
104 | // CommandTransaction;
105 | using CommandTransaction = Transaction;
106 | //using CommandTransaction = Transaction<_command_id(), CommandPayload, EmptyPayload>;
107 |
108 | };
109 | }
110 | }
111 | }
112 |
113 | #endif
114 |
--------------------------------------------------------------------------------
/libnitrokey/command_id.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2015-2018 Nitrokey UG
3 | *
4 | * This file is part of libnitrokey.
5 | *
6 | * libnitrokey is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU Lesser General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * any later version.
10 | *
11 | * libnitrokey is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU Lesser General Public License
17 | * along with libnitrokey. If not, see .
18 | *
19 | * SPDX-License-Identifier: LGPL-3.0
20 | */
21 |
22 | #ifndef COMMAND_ID_H
23 | #define COMMAND_ID_H
24 | #include
25 |
26 | namespace nitrokey {
27 | namespace proto {
28 | namespace stick20 {
29 | enum class device_status : uint8_t {
30 | idle = 0,
31 | ok,
32 | busy,
33 | wrong_password,
34 | busy_progressbar,
35 | password_matrix_ready,
36 | no_user_password_unlock, // FIXME: translate on receive to command status error (fix in firmware?)
37 | smartcard_error,
38 | security_bit_active
39 | };
40 | const int CMD_START_VALUE = 0x20;
41 | const int CMD_END_VALUE = 0x60;
42 | }
43 | namespace stick10 {
44 | enum class command_status : uint8_t {
45 | ok = 0,
46 | wrong_CRC,
47 | wrong_slot,
48 | slot_not_programmed,
49 | wrong_password = 4,
50 | not_authorized,
51 | timestamp_warning,
52 | no_name_error,
53 | not_supported,
54 | unknown_command,
55 | AES_dec_failed
56 | };
57 | enum class device_status : uint8_t {
58 | ok = 0,
59 | busy = 1,
60 | error,
61 | received_report,
62 | };
63 | }
64 |
65 |
66 | enum class CommandID : uint8_t {
67 | GET_STATUS = 0x00,
68 | WRITE_TO_SLOT = 0x01,
69 | READ_SLOT_NAME = 0x02,
70 | READ_SLOT = 0x03,
71 | GET_CODE = 0x04,
72 | WRITE_CONFIG = 0x05,
73 | ERASE_SLOT = 0x06,
74 | FIRST_AUTHENTICATE = 0x07,
75 | AUTHORIZE = 0x08,
76 | GET_PASSWORD_RETRY_COUNT = 0x09,
77 | CLEAR_WARNING = 0x0A,
78 | SET_TIME = 0x0B,
79 | TEST_COUNTER = 0x0C,
80 | TEST_TIME = 0x0D,
81 | USER_AUTHENTICATE = 0x0E,
82 | GET_USER_PASSWORD_RETRY_COUNT = 0x0F,
83 | USER_AUTHORIZE = 0x10,
84 | UNLOCK_USER_PASSWORD = 0x11,
85 | LOCK_DEVICE = 0x12,
86 | FACTORY_RESET = 0x13,
87 | CHANGE_USER_PIN = 0x14,
88 | CHANGE_ADMIN_PIN = 0x15,
89 | WRITE_TO_SLOT_2 = 0x16,
90 | SEND_OTP_DATA = 0x17,
91 | FIRMWARE_UPDATE = 0x19,
92 | FIRMWARE_PASSWORD_CHANGE = 0x1A,
93 | GET_RANDOM = 0x1B,
94 |
95 | ENABLE_CRYPTED_PARI = 0x20,
96 | DISABLE_CRYPTED_PARI = 0x20 + 1,
97 | ENABLE_HIDDEN_CRYPTED_PARI = 0x20 + 2,
98 | DISABLE_HIDDEN_CRYPTED_PARI = 0x20 + 3,
99 | ENABLE_FIRMWARE_UPDATE = 0x20 + 4, //enables update mode
100 | EXPORT_FIRMWARE_TO_FILE = 0x20 + 5,
101 | GENERATE_NEW_KEYS = 0x20 + 6,
102 | FILL_SD_CARD_WITH_RANDOM_CHARS = 0x20 + 7,
103 |
104 | WRITE_STATUS_DATA = 0x20 + 8, //@unused
105 | ENABLE_READONLY_UNCRYPTED_LUN = 0x20 + 9,
106 | ENABLE_READWRITE_UNCRYPTED_LUN = 0x20 + 10,
107 |
108 | SEND_PASSWORD_MATRIX = 0x20 + 11, //@unused
109 | SEND_PASSWORD_MATRIX_PINDATA = 0x20 + 12, //@unused
110 | SEND_PASSWORD_MATRIX_SETUP = 0x20 + 13, //@unused
111 |
112 | GET_DEVICE_STATUS = 0x20 + 14,
113 | SEND_DEVICE_STATUS = 0x20 + 15,
114 |
115 | SEND_HIDDEN_VOLUME_PASSWORD = 0x20 + 16, //@unused
116 | SEND_HIDDEN_VOLUME_SETUP = 0x20 + 17,
117 | SEND_PASSWORD = 0x20 + 18,
118 | SEND_NEW_PASSWORD = 0x20 + 19,
119 | CLEAR_NEW_SD_CARD_FOUND = 0x20 + 20,
120 |
121 | SEND_STARTUP = 0x20 + 21,
122 | SEND_CLEAR_STICK_KEYS_NOT_INITIATED = 0x20 + 22,
123 | SEND_LOCK_STICK_HARDWARE = 0x20 + 23, //locks firmware upgrade
124 |
125 | PRODUCTION_TEST = 0x20 + 24,
126 | SEND_DEBUG_DATA = 0x20 + 25, //@unused
127 |
128 | CHANGE_UPDATE_PIN = 0x20 + 26,
129 |
130 | //added in v0.48.5
131 | ENABLE_ADMIN_READONLY_UNCRYPTED_LUN = 0x20 + 28,
132 | ENABLE_ADMIN_READWRITE_UNCRYPTED_LUN = 0x20 + 29,
133 | ENABLE_ADMIN_READONLY_ENCRYPTED_LUN = 0x20 + 30,
134 | ENABLE_ADMIN_READWRITE_ENCRYPTED_LUN = 0x20 + 31,
135 | CHECK_SMARTCARD_USAGE = 0x20 + 32,
136 | //v0.52+
137 | WINK = 0x20 + 33,
138 |
139 | GET_PW_SAFE_SLOT_STATUS = 0x60,
140 | GET_PW_SAFE_SLOT_NAME = 0x61,
141 | GET_PW_SAFE_SLOT_PASSWORD = 0x62,
142 | GET_PW_SAFE_SLOT_LOGINNAME = 0x63,
143 | SET_PW_SAFE_SLOT_DATA_1 = 0x64,
144 | SET_PW_SAFE_SLOT_DATA_2 = 0x65,
145 | PW_SAFE_ERASE_SLOT = 0x66,
146 | PW_SAFE_ENABLE = 0x67,
147 | PW_SAFE_INIT_KEY = 0x68, //@unused
148 | PW_SAFE_SEND_DATA = 0x69, //@unused
149 | SD_CARD_HIGH_WATERMARK = 0x70,
150 | DETECT_SC_AES = 0x6a,
151 | NEW_AES_KEY = 0x6b,
152 | };
153 |
154 | const char *commandid_to_string(CommandID id);
155 | }
156 | }
157 | #endif
158 |
--------------------------------------------------------------------------------
/libnitrokey/cxx_semantics.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2015-2018 Nitrokey UG
3 | *
4 | * This file is part of libnitrokey.
5 | *
6 | * libnitrokey is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU Lesser General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * any later version.
10 | *
11 | * libnitrokey is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU Lesser General Public License
17 | * along with libnitrokey. If not, see .
18 | *
19 | * SPDX-License-Identifier: LGPL-3.0
20 | */
21 |
22 | #ifndef CXX_SEMANTICS_H
23 | #define CXX_SEMANTICS_H
24 |
25 | #ifndef _MSC_VER
26 | #define __packed __attribute__((__packed__))
27 | #else
28 | #define __packed
29 | #endif
30 |
31 | #ifdef _MSC_VER
32 | #define strdup _strdup
33 | #endif
34 |
35 | /*
36 | * There's no need to include Boost for a simple subset this project needs.
37 | */
38 | namespace semantics {
39 | class non_constructible {
40 | non_constructible() {}
41 | };
42 | }
43 |
44 | #endif
45 |
--------------------------------------------------------------------------------
/libnitrokey/deprecated.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018 Nitrokey UG
3 | *
4 | * This file is part of libnitrokey.
5 | *
6 | * libnitrokey is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU Lesser General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * any later version.
10 | *
11 | * libnitrokey is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU Lesser General Public License
17 | * along with libnitrokey. If not, see .
18 | *
19 | * SPDX-License-Identifier: LGPL-3.0
20 | */
21 |
22 |
23 | #ifndef LIBNITROKEY_DEPRECATED_H
24 | #define LIBNITROKEY_DEPRECATED_H
25 |
26 | #if defined(__GNUC__) || defined(__clang__)
27 | #define DEPRECATED __attribute__((deprecated))
28 | #elif defined(_MSC_VER)
29 | #define DEPRECATED __declspec(deprecated)
30 | #else
31 | #pragma message("WARNING: DEPRECATED macro is not defined for this compiler")
32 | #define DEPRECATED
33 | #endif
34 |
35 | #endif //LIBNITROKEY_DEPRECATED_H
36 |
--------------------------------------------------------------------------------
/libnitrokey/device.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2015-2018 Nitrokey UG
3 | *
4 | * This file is part of libnitrokey.
5 | *
6 | * libnitrokey is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU Lesser General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * any later version.
10 | *
11 | * libnitrokey is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU Lesser General Public License
17 | * along with libnitrokey. If not, see .
18 | *
19 | * SPDX-License-Identifier: LGPL-3.0
20 | */
21 |
22 | #ifndef DEVICE_H
23 | #define DEVICE_H
24 | #include
25 | #include "hidapi/hidapi.h"
26 | #include
27 | #include
28 | #include
29 | #include
30 | #include
31 | #include "misc.h"
32 |
33 | #define HID_REPORT_SIZE 65
34 |
35 | #include
36 |
37 | namespace nitrokey {
38 | namespace device {
39 | using namespace std::chrono_literals;
40 | using std::chrono::milliseconds;
41 |
42 | struct EnumClassHash
43 | {
44 | template
45 | std::size_t operator()(T t) const
46 | {
47 | return static_cast(t);
48 | }
49 | };
50 |
51 | enum class DeviceModel{
52 | PRO,
53 | STORAGE,
54 | LIBREM
55 | };
56 |
57 | std::ostream& operator<<(std::ostream& stream, DeviceModel model);
58 |
59 | /**
60 | * The USB vendor ID for Nitrokey devices.
61 | */
62 | extern const uint16_t NITROKEY_VID;
63 | /**
64 | * The USB product ID for the Nitrokey Pro.
65 | */
66 | extern const uint16_t NITROKEY_PRO_PID;
67 | /**
68 | * The USB product ID for the Nitrokey Storage.
69 | */
70 | extern const uint16_t NITROKEY_STORAGE_PID;
71 | /**
72 | * The USB vendor ID for Purism devices.
73 | */
74 | extern const uint16_t PURISM_VID;
75 | /**
76 | * The USB product ID for the Librem Key.
77 | */
78 | extern const uint16_t LIBREM_KEY_PID;
79 |
80 | /**
81 | * Convert the given USB product ID to a Nitrokey model. If there is no model
82 | * with that ID, return an absent value.
83 | */
84 | misc::Option product_id_to_model(uint16_t product_id);
85 | misc::Option product_id_to_model(uint16_t vendor_id, uint16_t product_id);
86 |
87 | /**
88 | * Information about a connected device.
89 | *
90 | * This struct contains the information about a connected device returned by
91 | * hidapi when enumerating the connected devices.
92 | */
93 | struct DeviceInfo {
94 | /**
95 | * The model of the connected device.
96 | */
97 | DeviceModel m_deviceModel;
98 | /**
99 | * The USB connection path for the device.
100 | */
101 | std::string m_path;
102 | /**
103 | * The serial number of the device.
104 | */
105 | std::string m_serialNumber;
106 | };
107 |
108 | #include
109 |
110 | class Device {
111 |
112 | public:
113 |
114 | struct ErrorCounters{
115 | using cnt = std::atomic_int;
116 | cnt wrong_CRC;
117 | cnt CRC_other_than_awaited;
118 | cnt busy;
119 | cnt total_retries;
120 | cnt sending_error;
121 | cnt receiving_error;
122 | cnt total_comm_runs;
123 | cnt successful_storage_commands;
124 | cnt command_successful_recv;
125 | cnt recv_executed;
126 | cnt sends_executed;
127 | cnt busy_progressbar;
128 | cnt command_result_not_equal_0_recv;
129 | cnt communication_successful;
130 | cnt low_level_reconnect;
131 | std::string get_as_string();
132 |
133 | } m_counters = {};
134 |
135 |
136 | Device(const uint16_t vid, const uint16_t pid, const DeviceModel model,
137 | const milliseconds send_receive_delay, const int retry_receiving_count,
138 | const milliseconds retry_timeout);
139 |
140 | virtual ~Device();
141 |
142 | // lack of device is not actually an error,
143 | // so it doesn't throw
144 | bool connect();
145 | bool disconnect();
146 |
147 | /*
148 | * Sends packet of HID_REPORT_SIZE.
149 | */
150 | virtual int send(const void *packet);
151 |
152 | /*
153 | * Gets packet of HID_REPORT_SIZE.
154 | * Can sleep. See below.
155 | */
156 | virtual int recv(void *packet);
157 |
158 | /***
159 | * Returns true if some device is visible by OS with given VID and PID
160 | * whether the device is connected through HID API or not.
161 | * @return true if visible by OS
162 | */
163 | bool could_be_enumerated();
164 | /**
165 | * Returns a vector with all connected Nitrokey devices.
166 | *
167 | * @return information about all connected devices
168 | */
169 | static std::vector enumerate();
170 |
171 | /**
172 | * Create a Device of the given model.
173 | */
174 | static std::shared_ptr create(DeviceModel model);
175 |
176 |
177 | void show_stats();
178 | // ErrorCounters get_stats(){ return m_counters; }
179 | int get_retry_receiving_count() const { return m_retry_receiving_count; }
180 | int get_retry_sending_count() const { return m_retry_sending_count; }
181 | std::chrono::milliseconds get_retry_timeout() const { return m_retry_timeout; }
182 | std::chrono::milliseconds get_send_receive_delay() const {return m_send_receive_delay;}
183 |
184 | int get_last_command_status() {int a = std::atomic_exchange(&last_command_status, static_cast(0)); return a;}
185 | void set_last_command_status(uint8_t _err) { last_command_status = _err;}
186 | bool last_command_sucessfull() const {return last_command_status == 0;}
187 | DeviceModel get_device_model() const {return m_model;}
188 | void set_receiving_delay(std::chrono::milliseconds delay);
189 | void set_retry_delay(std::chrono::milliseconds delay);
190 | static void set_default_device_speed(int delay);
191 | void setDefaultDelay();
192 | void set_path(const std::string path);
193 |
194 |
195 | private:
196 | std::atomic last_command_status;
197 | void _reconnect();
198 | bool _connect();
199 | bool _disconnect();
200 |
201 | protected:
202 | const uint16_t m_vid;
203 | const uint16_t m_pid;
204 | const DeviceModel m_model;
205 |
206 | /*
207 | * While the project uses Signal11 portable HIDAPI
208 | * library, there's no way of doing it asynchronously,
209 | * hence polling.
210 | */
211 | const int m_retry_sending_count;
212 | const int m_retry_receiving_count;
213 | std::chrono::milliseconds m_retry_timeout;
214 | std::chrono::milliseconds m_send_receive_delay;
215 | std::atomicmp_devhandle;
216 | std::string m_path;
217 |
218 | static std::atomic_int instances_count;
219 | static std::chrono::milliseconds default_delay ;
220 | };
221 |
222 | class Stick10 : public Device {
223 | public:
224 | Stick10();
225 |
226 | };
227 |
228 | class Stick20 : public Device {
229 | public:
230 | Stick20();
231 | };
232 |
233 | class LibremKey : public Device {
234 | public:
235 | LibremKey();
236 | };
237 |
238 | }
239 | }
240 | #endif
241 |
--------------------------------------------------------------------------------
/libnitrokey/dissect.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2015-2018 Nitrokey UG
3 | *
4 | * This file is part of libnitrokey.
5 | *
6 | * libnitrokey is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU Lesser General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * any later version.
10 | *
11 | * libnitrokey is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU Lesser General Public License
17 | * along with libnitrokey. If not, see .
18 | *
19 | * SPDX-License-Identifier: LGPL-3.0
20 | */
21 |
22 | /*
23 | * Protocol packet dissection
24 | */
25 | #ifndef DISSECT_H
26 | #define DISSECT_H
27 | #include
28 | #include
29 | #include
30 | #include "misc.h"
31 | #include "cxx_semantics.h"
32 | #include "command_id.h"
33 | #include "device_proto.h"
34 |
35 | namespace nitrokey {
36 | namespace proto {
37 |
38 | template
39 | class QueryDissector : semantics::non_constructible {
40 | public:
41 | static std::string dissect(const HIDPacket &pod) {
42 | std::stringstream out;
43 |
44 | #ifdef LOG_VOLATILE_DATA
45 | out << "Raw HID packet:" << std::endl;
46 | out << ::nitrokey::misc::hexdump(reinterpret_cast(&pod), sizeof pod);
47 | #endif
48 |
49 | out << "Contents:" << std::endl;
50 | out << "Command ID:\t" << commandid_to_string(static_cast(pod.command_id))
51 | << std::endl;
52 | out << "CRC:\t"
53 | << std::hex << std::setw(2) << std::setfill('0')
54 | << pod.crc << std::endl;
55 |
56 | out << "Payload:" << std::endl;
57 | out << pod.payload.dissect();
58 | return out.str();
59 | }
60 | };
61 |
62 |
63 |
64 |
65 | template
66 | class ResponseDissector : semantics::non_constructible {
67 | public:
68 | static std::string status_translate_device(int status){
69 | auto enum_status = static_cast(status);
70 | switch (enum_status){
71 | case stick10::device_status::ok: return "OK";
72 | case stick10::device_status::busy: return "BUSY";
73 | case stick10::device_status::error: return "ERROR";
74 | case stick10::device_status::received_report: return "RECEIVED_REPORT";
75 | }
76 | return std::string("UNKNOWN: ") + std::to_string(status);
77 | }
78 |
79 | static std::string to_upper(std::string str){
80 | for (auto & c: str) c = toupper(c);
81 | return str;
82 | }
83 | static std::string status_translate_command(int status){
84 | auto enum_status = static_cast(status);
85 | switch (enum_status) {
86 | #define p(X) case X: return to_upper(std::string(#X));
87 | p(stick10::command_status::ok)
88 | p(stick10::command_status::wrong_CRC)
89 | p(stick10::command_status::wrong_slot)
90 | p(stick10::command_status::slot_not_programmed)
91 | p(stick10::command_status::wrong_password)
92 | p(stick10::command_status::not_authorized)
93 | p(stick10::command_status::timestamp_warning)
94 | p(stick10::command_status::no_name_error)
95 | p(stick10::command_status::not_supported)
96 | p(stick10::command_status::unknown_command)
97 | p(stick10::command_status::AES_dec_failed)
98 | #undef p
99 | }
100 | return std::string("UNKNOWN: ") + std::to_string(status);
101 | }
102 |
103 | static std::string dissect(const HIDPacket &pod) {
104 | std::stringstream out;
105 |
106 | // FIXME use values from firmware (possibly generate separate
107 | // header automatically)
108 |
109 | #ifdef LOG_VOLATILE_DATA
110 | out << "Raw HID packet:" << std::endl;
111 | out << ::nitrokey::misc::hexdump(reinterpret_cast(&pod), sizeof pod);
112 | #endif
113 |
114 | out << "Device status:\t" << pod.device_status + 0 << " "
115 | << status_translate_device(pod.device_status) << std::endl;
116 | out << "Command ID:\t" << commandid_to_string(static_cast(pod.command_id)) << " hex: " << std::hex << static_cast(pod.command_id)
117 | << std::endl;
118 | out << "Last command CRC:\t"
119 | << std::hex << std::setw(2) << std::setfill('0')
120 | << pod.last_command_crc << std::endl;
121 | out << "Last command status:\t" << pod.last_command_status + 0 << " "
122 | << status_translate_command(pod.last_command_status) << std::endl;
123 | out << "CRC:\t"
124 | << std::hex << std::setw(2) << std::setfill('0')
125 | << pod.crc << std::endl;
126 | if(static_cast(pod.command_id) == pod.storage_status.command_id){
127 | out << "Storage stick status (where applicable):" << std::endl;
128 | #define d(x) out << " "#x": \t"<< std::hex << std::setw(2) \
129 | << std::setfill('0')<< static_cast(x) << std::endl;
130 | d(pod.storage_status.command_counter);
131 | d(pod.storage_status.command_id);
132 | d(pod.storage_status.device_status);
133 | d(pod.storage_status.progress_bar_value);
134 | #undef d
135 | }
136 |
137 | out << "Payload:" << std::endl;
138 | out << pod.payload.dissect();
139 | return out.str();
140 | }
141 | };
142 | }
143 | }
144 |
145 | #endif
146 |
--------------------------------------------------------------------------------
/libnitrokey/log.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2015-2018 Nitrokey UG
3 | *
4 | * This file is part of libnitrokey.
5 | *
6 | * libnitrokey is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU Lesser General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * any later version.
10 | *
11 | * libnitrokey is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU Lesser General Public License
17 | * along with libnitrokey. If not, see .
18 | *
19 | * SPDX-License-Identifier: LGPL-3.0
20 | */
21 |
22 | #ifndef LOG_H
23 | #define LOG_H
24 |
25 | #include
26 | #include
27 |
28 | namespace nitrokey {
29 | namespace log {
30 |
31 | //for MSVC
32 | #ifdef ERROR
33 | #undef ERROR
34 | #endif
35 |
36 |
37 | enum class Loglevel : int {
38 | ERROR,
39 | WARNING,
40 | INFO,
41 | DEBUG_L1,
42 | DEBUG,
43 | DEBUG_L2
44 | };
45 |
46 | class LogHandler {
47 | public:
48 | virtual void print(const std::string &, Loglevel lvl) = 0;
49 | virtual ~LogHandler() = default;
50 | protected:
51 | std::string loglevel_to_str(Loglevel);
52 | std::string format_message_to_string(const std::string &str, const Loglevel &lvl);
53 |
54 | };
55 |
56 | class StdlogHandler : public LogHandler {
57 | public:
58 | virtual void print(const std::string &, Loglevel lvl) override;
59 | };
60 |
61 | class FunctionalLogHandler : public LogHandler {
62 | using log_function_type = std::function;
63 | log_function_type log_function;
64 | public:
65 | FunctionalLogHandler(log_function_type _log_function);
66 | virtual void print(const std::string &, Loglevel lvl) override;
67 |
68 | };
69 |
70 | class RawFunctionalLogHandler : public LogHandler {
71 | using log_function_type = std::function;
72 | log_function_type log_function;
73 | public:
74 | RawFunctionalLogHandler(log_function_type _log_function);
75 | virtual void print(const std::string &, Loglevel lvl) override;
76 |
77 | };
78 |
79 | extern StdlogHandler stdlog_handler;
80 |
81 | class Log {
82 | public:
83 | Log() : mp_loghandler(&stdlog_handler), m_loglevel(Loglevel::WARNING) {}
84 |
85 | static Log &instance() {
86 | if (mp_instance == nullptr) mp_instance = new Log;
87 | return *mp_instance;
88 | }
89 |
90 | void operator()(const std::string &, Loglevel);
91 | void set_loglevel(Loglevel lvl) { m_loglevel = lvl; }
92 | void set_handler(LogHandler *handler) { mp_loghandler = handler; }
93 |
94 | private:
95 | LogHandler *mp_loghandler;
96 | Loglevel m_loglevel;
97 | static std::string prefix;
98 | public:
99 | static void setPrefix(std::string prefix = std::string());
100 |
101 | private:
102 |
103 | static Log *mp_instance;
104 | };
105 | }
106 | }
107 |
108 |
109 | #ifdef NO_LOG
110 | #define LOG(string, level) while(false){}
111 | #define LOGD(string) while(false){}
112 | #define LOGD1(string) while(false){}
113 | #else
114 | #define LOG(string, level) nitrokey::log::Log::instance()((string), (level))
115 | #define LOGD1(string) nitrokey::log::Log::instance()((string), (nitrokey::log::Loglevel::DEBUG_L1))
116 | #define LOGD(string) nitrokey::log::Log::instance()((string), (nitrokey::log::Loglevel::DEBUG_L2))
117 | #endif
118 |
119 | #endif
120 |
--------------------------------------------------------------------------------
/libnitrokey/misc.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2015-2018 Nitrokey UG
3 | *
4 | * This file is part of libnitrokey.
5 | *
6 | * libnitrokey is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU Lesser General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * any later version.
10 | *
11 | * libnitrokey is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU Lesser General Public License
17 | * along with libnitrokey. If not, see .
18 | *
19 | * SPDX-License-Identifier: LGPL-3.0
20 | */
21 |
22 |
23 | #ifndef MISC_H
24 | #define MISC_H
25 | #include
26 | #include
27 | #include
28 | #include
29 | #include "log.h"
30 | #include "LibraryException.h"
31 | #include
32 | #include
33 | #include
34 |
35 |
36 | namespace nitrokey {
37 | namespace misc {
38 |
39 | /**
40 | * Simple replacement for std::optional (C++17).
41 | */
42 | template
43 | class Option {
44 | public:
45 | Option() : m_hasValue(false), m_value() {}
46 | Option(T value) : m_hasValue(true), m_value(value) {}
47 |
48 | bool has_value() const {
49 | return m_hasValue;
50 | }
51 | T value() const {
52 | if (!m_hasValue) {
53 | throw std::logic_error("Called Option::value without value");
54 | }
55 | return m_value;
56 | }
57 |
58 | private:
59 | bool m_hasValue;
60 | T m_value;
61 | };
62 |
63 | template
64 | std::string toHex(T value){
65 | using namespace std;
66 | std::ostringstream oss;
67 | oss << std::hex << std::setw(sizeof(value)*2) << std::setfill('0') << value;
68 | return oss.str();
69 | }
70 |
71 | #define FIELD_WIDTH_MAX (100)
72 | /**
73 | * Copies string from pointer to fixed size C-style array. Src needs to be a valid C-string - eg. ended with '\0'.
74 | * Throws when source is bigger than destination.
75 | * @tparam T type of destination array
76 | * @param dest fixed size destination array
77 | * @param src pointer to source c-style valid string
78 | */
79 | template
80 | void strcpyT(T& dest, const char* src){
81 |
82 | if (src == nullptr)
83 | // throw EmptySourceStringException(slot_number);
84 | return;
85 | const size_t s_dest = sizeof dest;
86 | const size_t src_strlen = strnlen(src, FIELD_WIDTH_MAX);
87 | LOG(std::string("strcpyT sizes dest src ")
88 | + std::to_string(s_dest) + " "
89 | + std::to_string(src_strlen) + " "
90 | , nitrokey::log::Loglevel::DEBUG_L2);
91 | if (src_strlen > s_dest){
92 | throw TooLongStringException(src_strlen, s_dest, src);
93 | }
94 | strncpy(reinterpret_cast(&dest), src, s_dest);
95 | }
96 |
97 | #define bzero(b,len) (memset((b), '\0', (len)), (void) 0)
98 | template
99 | typename T::CommandPayload get_payload(){
100 | //Create, initialize and return by value command payload
101 | typename T::CommandPayload st;
102 | bzero(&st, sizeof(st));
103 | return st;
104 | }
105 |
106 | template
107 | void execute_password_command(Tdev &stick, const char *password) {
108 | auto p = get_payload();
109 | p.set_defaults();
110 | strcpyT(p.password, password);
111 | CMDTYPE::CommandTransaction::run(stick, p);
112 | }
113 |
114 | std::string hexdump(const uint8_t *p, size_t size, bool print_header=true, bool print_ascii=true,
115 | bool print_empty=true);
116 | uint32_t stm_crc32(const uint8_t *data, size_t size);
117 | std::vector hex_string_to_byte(const char* hexString);
118 | }
119 | }
120 |
121 | #endif
122 |
--------------------------------------------------------------------------------
/libnitrokey/version.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018 Nitrokey UG
3 | *
4 | * This file is part of libnitrokey.
5 | *
6 | * libnitrokey is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU Lesser General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * any later version.
10 | *
11 | * libnitrokey is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU Lesser General Public License
17 | * along with libnitrokey. If not, see .
18 | *
19 | * SPDX-License-Identifier: LGPL-3.0
20 | */
21 |
22 | #ifndef LIBNITROKEY_VERSION_H
23 | #define LIBNITROKEY_VERSION_H
24 |
25 | namespace nitrokey {
26 | unsigned int get_major_library_version();
27 |
28 | unsigned int get_minor_library_version();
29 |
30 | const char* get_library_version();
31 | }
32 |
33 | #endif
34 |
--------------------------------------------------------------------------------
/log.cc:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2015-2018 Nitrokey UG
3 | *
4 | * This file is part of libnitrokey.
5 | *
6 | * libnitrokey is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU Lesser General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * any later version.
10 | *
11 | * libnitrokey is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU Lesser General Public License
17 | * along with libnitrokey. If not, see .
18 | *
19 | * SPDX-License-Identifier: LGPL-3.0
20 | */
21 |
22 | #include "log.h"
23 | #include
24 | #include
25 | #include
26 |
27 | #include
28 |
29 | namespace nitrokey {
30 | namespace log {
31 |
32 | Log *Log::mp_instance = nullptr;
33 | StdlogHandler stdlog_handler;
34 |
35 | std::string Log::prefix = "";
36 |
37 |
38 | std::string LogHandler::loglevel_to_str(Loglevel lvl) {
39 | switch (lvl) {
40 | case Loglevel::DEBUG_L1:
41 | return std::string("DEBUG_L1");
42 | case Loglevel::DEBUG_L2:
43 | return std::string("DEBUG_L2");
44 | case Loglevel::DEBUG:
45 | return std::string("DEBUG");
46 | case Loglevel::INFO:
47 | return std::string("INFO");
48 | case Loglevel::WARNING:
49 | return std::string("WARNING");
50 | case Loglevel::ERROR:
51 | return std::string("ERROR");
52 | }
53 | return std::string("");
54 | }
55 |
56 | void Log::operator()(const std::string &logstr, Loglevel lvl) {
57 | if (mp_loghandler != nullptr){
58 | // FIXME crashes on exit because static object under mp_loghandler is not valid anymore, see NitrokeyManager::set_log_function
59 | if (static_cast(lvl) <= static_cast(m_loglevel)) mp_loghandler->print(prefix+logstr, lvl);
60 | }
61 | }
62 |
63 | void Log::setPrefix(const std::string prefix) {
64 | if (!prefix.empty()){
65 | Log::prefix = "["+prefix+"]";
66 | } else {
67 | Log::prefix = "";
68 | }
69 | }
70 |
71 | void StdlogHandler::print(const std::string &str, Loglevel lvl) {
72 | std::string s = format_message_to_string(str, lvl);
73 | std::clog << s;
74 | }
75 |
76 | void FunctionalLogHandler::print(const std::string &str, Loglevel lvl) {
77 | std::string s = format_message_to_string(str, lvl);
78 | log_function(s);
79 | }
80 |
81 | void RawFunctionalLogHandler::print(const std::string &str, Loglevel lvl) {
82 | log_function(str, lvl);
83 | }
84 |
85 | std::string LogHandler::format_message_to_string(const std::string &str, const Loglevel &lvl) {
86 | static bool last_short = false;
87 | if (str.length() == 1){
88 | last_short = true;
89 | return str;
90 | }
91 | time_t t = time(nullptr);
92 | tm tm = *localtime(&t);
93 |
94 | std::stringstream s;
95 | s
96 | << (last_short? "\n" : "")
97 | << "[" << std::put_time(&tm, "%c") << "]"
98 | << "[" << loglevel_to_str(lvl) << "]\t"
99 | << str << std::endl;
100 | last_short = false;
101 | return s.str();
102 | }
103 |
104 | FunctionalLogHandler::FunctionalLogHandler(log_function_type _log_function) {
105 | log_function = _log_function;
106 | }
107 |
108 | RawFunctionalLogHandler::RawFunctionalLogHandler(log_function_type _log_function) {
109 | log_function = _log_function;
110 | }
111 | }
112 | }
113 |
--------------------------------------------------------------------------------
/meson.build:
--------------------------------------------------------------------------------
1 | project(
2 | 'libnitrokey', 'cpp',
3 | version : '3.7.0',
4 | license : 'LGPL-3.0+',
5 | default_options : [
6 | 'cpp_std=c++14'
7 | ],
8 | meson_version : '>= 0.48.0',
9 | )
10 | cxx = meson.get_compiler('cpp')
11 | host_system = host_machine.system()
12 | pkg = import('pkgconfig')
13 |
14 | common_flags = [
15 | '-Wno-unused-function',
16 | '-Wcast-qual',
17 | ]
18 | test_cxxflags = common_flags + [
19 | '-Woverloaded-virtual',
20 | ]
21 | test_cflags = common_flags
22 | add_project_arguments(cxx.get_supported_arguments(test_cxxflags), language : 'cpp')
23 | if get_option('offline-tests')
24 | add_languages('c', required: get_option('offline-tests'))
25 | c = meson.get_compiler('c')
26 | add_project_arguments(c.get_supported_arguments(test_cflags), language : 'c')
27 | endif
28 |
29 | if target_machine.system() == 'freebsd'
30 | dep_hidapi = dependency('hidapi')
31 | else
32 | dep_hidapi = dependency('hidapi-libusb')
33 | endif
34 |
35 | inc_libnitrokey = include_directories('libnitrokey')
36 | libnitrokey_args = []
37 | if not get_option('log')
38 | libnitrokey_args += ['-DNO_LOG']
39 | endif
40 | if get_option('log-volatile-data')
41 | libnitrokey_args += ['-DLOG_VOLATILE_DATA']
42 | endif
43 |
44 | version_array = meson.project_version().split('.')
45 | version_major = version_array[0].to_int()
46 | version_minor = version_array[1].to_int()
47 | version_data = configuration_data()
48 | version_data.set('PROJECT_VERSION_MAJOR', version_major)
49 | version_data.set('PROJECT_VERSION_MINOR', version_minor)
50 | # We don't want to substitute it by noop
51 | version_data.set('PROJECT_VERSION_GIT', '@VCS_TAG@')
52 | version_cc_in = configure_file(
53 | input : 'version.cc.in',
54 | output : 'version.cc.in',
55 | configuration : version_data,
56 | )
57 | version_cc = vcs_tag(
58 | input : version_cc_in,
59 | output : 'version.cc',
60 | fallback : 'v@0@'.format(meson.project_version()),
61 | )
62 | libnitrokey = library(
63 | 'nitrokey',
64 | sources : [
65 | 'command_id.cc',
66 | 'device.cc',
67 | 'log.cc',
68 | version_cc,
69 | 'misc.cc',
70 | 'NitrokeyManager.cc',
71 | 'NK_C_API.cc',
72 | 'DeviceCommunicationExceptions.cpp',
73 | ],
74 | include_directories : [
75 | inc_libnitrokey,
76 | ],
77 | dependencies : [
78 | dep_hidapi,
79 | ],
80 | cpp_args : libnitrokey_args,
81 | version : meson.project_version(),
82 | install : true,
83 | )
84 | install_headers(
85 | 'libnitrokey/CommandFailedException.h',
86 | 'libnitrokey/command.h',
87 | 'libnitrokey/command_id.h',
88 | 'libnitrokey/cxx_semantics.h',
89 | 'libnitrokey/DeviceCommunicationExceptions.h',
90 | 'libnitrokey/device.h',
91 | 'libnitrokey/device_proto.h',
92 | 'libnitrokey/dissect.h',
93 | 'libnitrokey/LibraryException.h',
94 | 'libnitrokey/log.h',
95 | 'libnitrokey/LongOperationInProgressException.h',
96 | 'libnitrokey/misc.h',
97 | 'libnitrokey/version.h',
98 | 'libnitrokey/NitrokeyManager.h',
99 | 'libnitrokey/stick10_commands_0.8.h',
100 | 'libnitrokey/stick10_commands.h',
101 | 'libnitrokey/stick20_commands.h',
102 | subdir : meson.project_name(),
103 | )
104 |
105 | ext_libnitrokey = declare_dependency(
106 | link_with : libnitrokey,
107 | include_directories : inc_libnitrokey,
108 | )
109 |
110 | pkg.generate(
111 | name : meson.project_name(),
112 | filebase : 'libnitrokey-1',
113 | libraries : libnitrokey,
114 | version : meson.project_version(),
115 | requires_private : dep_hidapi.name(),
116 | description : 'Library for communicating with Nitrokey in a clean and easy manner',
117 | )
118 |
119 | if target_machine.system() == 'freebsd'
120 | dep_udev = dependency('libudev')
121 | else
122 | dep_udev = dependency('udev')
123 | endif
124 | install_data(
125 | 'data/41-nitrokey.rules',
126 | install_dir : '@0@/rules.d'.format(dep_udev.get_pkgconfig_variable('udevdir')),
127 | )
128 |
129 | if get_option('tests') or get_option('offline-tests')
130 | dep_catch = dependency('catch2', version : '>=2.3.0', required : false)
131 | if not dep_catch.found()
132 | dep_catch = declare_dependency(
133 | include_directories : include_directories('unittest/Catch/single_include')
134 | )
135 | endif
136 | _catch = static_library(
137 | 'catch',
138 | sources : [
139 | 'unittest/catch_main.cpp',
140 | ],
141 | dependencies : [
142 | dep_catch,
143 | ],
144 | )
145 | _dep_catch = declare_dependency(
146 | link_with : _catch,
147 | dependencies : dep_catch,
148 | )
149 | endif
150 |
151 | tests = []
152 | if get_option('offline-tests')
153 | tests += [
154 | ['test_offline', 'test_offline.cc'],
155 | ['test_minimal', 'test_minimal.c'],
156 | ]
157 | endif
158 | if get_option('tests')
159 | tests += [
160 | ['test_C_API', 'test_C_API.cpp'],
161 | ['test1', 'test1.cc'],
162 | ['test2', 'test2.cc'],
163 | ['test3', 'test3.cc'],
164 | ['test_HOTP', 'test_HOTP.cc'],
165 | ['test_memory', 'test_memory.c'],
166 | ['test_issues', 'test_issues.cc'],
167 | ['test_multiple_devices', 'test_multiple_devices.cc'],
168 | ['test_strdup', 'test_strdup.cpp'],
169 | ['test_safe', 'test_safe.cpp'],
170 | ]
171 | endif
172 | foreach tst : tests
173 | test(
174 | tst[0],
175 | executable(
176 | tst[0],
177 | sources : 'unittest/@0@'.format(tst[1]),
178 | dependencies : [
179 | ext_libnitrokey,
180 | _dep_catch,
181 | ],
182 | )
183 | )
184 | endforeach
185 |
--------------------------------------------------------------------------------
/meson_options.txt:
--------------------------------------------------------------------------------
1 | option('log', type : 'boolean', value : true, description : 'Logging functionality')
2 | option('log-volatile-data', type : 'boolean', value : false, description : 'Log volatile data (debug)')
3 | option('tests', type : 'boolean', value : false, description : 'Compile tests (needs connected PRO device)')
4 | option('offline-tests', type : 'boolean', value : false, description : 'Compile offline tests')
5 |
--------------------------------------------------------------------------------
/misc.cc:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2015-2018 Nitrokey UG
3 | *
4 | * This file is part of libnitrokey.
5 | *
6 | * libnitrokey is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU Lesser General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * any later version.
10 | *
11 | * libnitrokey is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU Lesser General Public License
17 | * along with libnitrokey. If not, see .
18 | *
19 | * SPDX-License-Identifier: LGPL-3.0
20 | */
21 |
22 | #include
23 | #include
24 | #include "misc.h"
25 | #include "inttypes.h"
26 | #include
27 | #include
28 | #include "LibraryException.h"
29 | #include
30 |
31 | namespace nitrokey {
32 | namespace misc {
33 |
34 |
35 |
36 | ::std::vector hex_string_to_byte(const char* hexString){
37 | const size_t big_string_size = 257; //arbitrary 'big' number
38 | const size_t s_size = strnlen(hexString, big_string_size);
39 | const size_t d_size = s_size/2;
40 | if (s_size%2!=0 || s_size>=big_string_size){
41 | throw InvalidHexString(0);
42 | }
43 | auto data = ::std::vector();
44 | data.reserve(d_size);
45 |
46 | char buf[3];
47 | buf[2] = '\0';
48 | for(size_t i=0; i
64 | ::std::string hexdump(const uint8_t *p, size_t size, bool print_header,
65 | bool print_ascii, bool print_empty) {
66 | ::std::stringstream out;
67 | char formatbuf[128];
68 | const uint8_t *pstart = p;
69 |
70 | for (const uint8_t *pend = p + size; p < pend;) {
71 | if (print_header){
72 | snprintf(formatbuf, 128, "%04x\t", static_cast (p - pstart));
73 | out << formatbuf;
74 | }
75 |
76 | const uint8_t* pp = p;
77 | for (const uint8_t *le = p + 16; p < le; p++) {
78 | if (p < pend){
79 | snprintf(formatbuf, 128, "%02x ", uint8_t(*p));
80 | out << formatbuf;
81 | } else {
82 | if(print_empty)
83 | out << "-- ";
84 | }
85 |
86 | }
87 | if(print_ascii){
88 | out << " ";
89 | for (const uint8_t *le = pp + 16; pp < le && pp < pend; pp++) {
90 | if (std::isgraph(*pp))
91 | out << uint8_t(*pp);
92 | else
93 | out << '.';
94 | }
95 | }
96 | out << ::std::endl;
97 | }
98 | return out.str();
99 | }
100 |
101 | static uint32_t _crc32(uint32_t crc, uint32_t data) {
102 | int i;
103 | crc = crc ^ data;
104 |
105 | for (i = 0; i < 32; i++) {
106 | if (crc & 0x80000000)
107 | crc = (crc << 1) ^ 0x04C11DB7; // polynomial used in STM32
108 | else
109 | crc = (crc << 1);
110 | }
111 |
112 | return crc;
113 | }
114 |
115 | uint32_t stm_crc32(const uint8_t *data, size_t size) {
116 | uint32_t crc = 0xffffffff;
117 | const uint32_t *pend = reinterpret_cast(data + size);
118 | for (const uint32_t *p = reinterpret_cast(data); p < pend; p++)
119 | crc = _crc32(crc, *p);
120 | return crc;
121 | }
122 | }
123 | }
124 |
--------------------------------------------------------------------------------
/python3_bindings_example.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | """
3 | Copyright (c) 2015-2018 Nitrokey UG
4 |
5 | This file is part of libnitrokey.
6 |
7 | libnitrokey is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU Lesser General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | any later version.
11 |
12 | libnitrokey is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU Lesser General Public License
18 | along with libnitrokey. If not, see .
19 |
20 | SPDX-License-Identifier: LGPL-3.0
21 | """
22 |
23 | import cffi
24 | from enum import Enum
25 |
26 | """
27 | This example will print 10 HOTP codes from just written HOTP#2 slot.
28 | For more examples of use please refer to unittest/test_*.py files.
29 | """
30 |
31 | ffi = cffi.FFI()
32 | get_string = ffi.string
33 |
34 | class DeviceErrorCode(Enum):
35 | STATUS_OK = 0
36 | NOT_PROGRAMMED = 3
37 | WRONG_PASSWORD = 4
38 | STATUS_NOT_AUTHORIZED = 5
39 | STATUS_AES_DEC_FAILED = 0xa
40 |
41 |
42 | def get_library():
43 | fp = 'NK_C_API.h' # path to C API header
44 |
45 | declarations = []
46 | with open(fp, 'r') as f:
47 | declarations = f.readlines()
48 |
49 | cnt = 0
50 | a = iter(declarations)
51 | for declaration in a:
52 | if declaration.strip().startswith('NK_C_API'):
53 | declaration = declaration.replace('NK_C_API', '').strip()
54 | while ';' not in declaration:
55 | declaration += (next(a)).strip()
56 | # print(declaration)
57 | ffi.cdef(declaration, override=True)
58 | cnt +=1
59 | print('Imported {} declarations'.format(cnt))
60 |
61 |
62 | C = None
63 | import os, sys
64 | path_build = os.path.join(".", "build")
65 | paths = [
66 | os.environ.get('LIBNK_PATH', None),
67 | os.path.join(path_build,"libnitrokey.so"),
68 | os.path.join(path_build,"libnitrokey.dylib"),
69 | os.path.join(path_build,"libnitrokey.dll"),
70 | os.path.join(path_build,"nitrokey.dll"),
71 | ]
72 | for p in paths:
73 | if not p: continue
74 | print("Trying " +p)
75 | p = os.path.abspath(p)
76 | if os.path.exists(p):
77 | print("Found: "+p)
78 | C = ffi.dlopen(p)
79 | break
80 | else:
81 | print("File does not exist: " + p)
82 | if not C:
83 | print("No library file found")
84 | print("Please set the path using LIBNK_PATH environment variable to existing library or compile it (see "
85 | "README.md for details)")
86 | sys.exit(1)
87 |
88 | return C
89 |
90 |
91 | def get_hotp_code(lib, i):
92 | return get_string(lib.NK_get_hotp_code(i))
93 |
94 | def to_hex(ss):
95 | return ''.join([ format(ord(s),'02x') for s in ss ])
96 |
97 | print('Warning!')
98 | print('This example will change your configuration on inserted stick and overwrite your HOTP#2 slot.')
99 | print('Please write "continue" to continue or any other string to quit')
100 | a = input()
101 |
102 | if not a == 'continue':
103 | exit()
104 |
105 | ADMIN = input('Please enter your admin PIN (empty string uses 12345678) ')
106 | ADMIN = ADMIN or '12345678' # use default if empty string
107 |
108 | show_log = input('Should log messages be shown (please write "yes" to enable; this will make harder reading script output) ') == 'yes'
109 | libnitrokey = get_library()
110 |
111 | if show_log:
112 | log_level = input('Please select verbosity level (0-5, 2 is library default, 3 will be selected on empty input) ')
113 | log_level = log_level or '3'
114 | log_level = int(log_level)
115 | libnitrokey.NK_set_debug_level(log_level)
116 | else:
117 | libnitrokey.NK_set_debug_level(2)
118 |
119 |
120 | ADMIN_TEMP = '123123123'
121 | RFC_SECRET = to_hex('12345678901234567890')
122 |
123 | # libnitrokey.NK_login('S') # connect only to Nitrokey Storage device
124 | # libnitrokey.NK_login('P') # connect only to Nitrokey Pro device
125 | device_connected = libnitrokey.NK_login_auto() # connect to any Nitrokey Stick
126 | if device_connected:
127 | print('Connected to Nitrokey device!')
128 | else:
129 | print('Could not connect to Nitrokey device!')
130 | exit()
131 |
132 | use_8_digits = True
133 | pin_correct = libnitrokey.NK_first_authenticate(ADMIN.encode('ascii'), ADMIN_TEMP.encode('ascii')) == DeviceErrorCode.STATUS_OK.value
134 | if pin_correct:
135 | print('Your PIN is correct!')
136 | else:
137 | print('Your PIN is not correct! Please try again. Please be careful to not lock your stick!')
138 | retry_count_left = libnitrokey.NK_get_admin_retry_count()
139 | print('Retry count left: %d' % retry_count_left )
140 | exit()
141 |
142 | # For function parameters documentation please check NK_C_API.h
143 | assert libnitrokey.NK_write_config(255, 255, 255, False, True, ADMIN_TEMP.encode('ascii')) == DeviceErrorCode.STATUS_OK.value
144 | libnitrokey.NK_first_authenticate(ADMIN.encode('ascii'), ADMIN_TEMP.encode('ascii'))
145 | libnitrokey.NK_write_hotp_slot(1, 'python_test'.encode('ascii'), RFC_SECRET.encode('ascii'), 0, use_8_digits, False, False, "".encode('ascii'),
146 | ADMIN_TEMP.encode('ascii'))
147 | # RFC test according to: https://tools.ietf.org/html/rfc4226#page-32
148 | test_data = [
149 | 1284755224, 1094287082, 137359152, 1726969429, 1640338314, 868254676, 1918287922, 82162583, 673399871,
150 | 645520489,
151 | ]
152 | print('Getting HOTP code from Nitrokey Stick (RFC test, 8 digits): ')
153 | for i in range(10):
154 | hotp_slot_1_code = get_hotp_code(libnitrokey, 1)
155 | correct_str = "correct!" if hotp_slot_1_code.decode('ascii') == str(test_data[i])[-8:] else "not correct"
156 | print('%d: %s, should be %s -> %s' % (i, hotp_slot_1_code.decode('ascii'), str(test_data[i])[-8:], correct_str))
157 | libnitrokey.NK_logout() # disconnect device
158 |
--------------------------------------------------------------------------------
/python_bindings_example.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python2
2 | """
3 | Copyright (c) 2015-2018 Nitrokey UG
4 |
5 | This file is part of libnitrokey.
6 |
7 | libnitrokey is free software: you can redistribute it and/or modify
8 | it under the terms of the GNU Lesser General Public License as published by
9 | the Free Software Foundation, either version 3 of the License, or
10 | any later version.
11 |
12 | libnitrokey is distributed in the hope that it will be useful,
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | GNU General Public License for more details.
16 |
17 | You should have received a copy of the GNU Lesser General Public License
18 | along with libnitrokey. If not, see .
19 |
20 | SPDX-License-Identifier: LGPL-3.0
21 | """
22 |
23 | import cffi
24 | from enum import Enum
25 |
26 | """
27 | This example will print 10 HOTP codes from just written HOTP#2 slot.
28 | For more examples of use please refer to unittest/test_*.py files.
29 | """
30 |
31 | ffi = cffi.FFI()
32 | get_string = ffi.string
33 |
34 | class DeviceErrorCode(Enum):
35 | STATUS_OK = 0
36 | NOT_PROGRAMMED = 3
37 | WRONG_PASSWORD = 4
38 | STATUS_NOT_AUTHORIZED = 5
39 | STATUS_AES_DEC_FAILED = 0xa
40 |
41 |
42 | def get_library():
43 | fp = 'NK_C_API.h' # path to C API header
44 |
45 | declarations = []
46 | with open(fp, 'r') as f:
47 | declarations = f.readlines()
48 |
49 | cnt = 0
50 | a = iter(declarations)
51 | for declaration in a:
52 | if declaration.strip().startswith('NK_C_API'):
53 | declaration = declaration.replace('NK_C_API', '').strip()
54 | while ';' not in declaration:
55 | declaration += (next(a)).strip()
56 | # print(declaration)
57 | ffi.cdef(declaration, override=True)
58 | cnt +=1
59 | print('Imported {} declarations'.format(cnt))
60 |
61 |
62 | C = None
63 | import os, sys
64 | path_build = os.path.join(".", "build")
65 | paths = [
66 | os.environ.get('LIBNK_PATH', None),
67 | os.path.join(path_build,"libnitrokey.so"),
68 | os.path.join(path_build,"libnitrokey.dylib"),
69 | os.path.join(path_build,"libnitrokey.dll"),
70 | os.path.join(path_build,"nitrokey.dll"),
71 | ]
72 | for p in paths:
73 | if not p: continue
74 | print("Trying " +p)
75 | p = os.path.abspath(p)
76 | if os.path.exists(p):
77 | print("Found: "+p)
78 | C = ffi.dlopen(p)
79 | break
80 | else:
81 | print("File does not exist: " + p)
82 | if not C:
83 | print("No library file found")
84 | print("Please set the path using LIBNK_PATH environment variable to existing library or compile it (see "
85 | "README.md for details)")
86 | sys.exit(1)
87 |
88 | return C
89 |
90 |
91 | def get_hotp_code(lib, i):
92 | return get_string(lib.NK_get_hotp_code(i))
93 |
94 | def to_hex(ss):
95 | return ''.join([ format(ord(s),'02x') for s in ss ])
96 |
97 | print('Warning!')
98 | print('This example will change your configuration on inserted stick and overwrite your HOTP#2 slot.')
99 | print('Please write "continue" to continue or any other string to quit')
100 | a = raw_input()
101 |
102 | if not a == 'continue':
103 | exit()
104 |
105 | ADMIN = raw_input('Please enter your admin PIN (empty string uses 12345678) ')
106 | ADMIN = ADMIN or '12345678' # use default if empty string
107 |
108 | show_log = raw_input('Should log messages be shown (please write "yes" to enable; this will make harder reading script output) ') == 'yes'
109 | libnitrokey = get_library()
110 |
111 | if show_log:
112 | log_level = raw_input('Please select verbosity level (0-5, 2 is library default, 3 will be selected on empty input) ')
113 | log_level = log_level or '3'
114 | log_level = int(log_level)
115 | libnitrokey.NK_set_debug_level(log_level)
116 | else:
117 | libnitrokey.NK_set_debug_level(2)
118 |
119 |
120 | ADMIN_TEMP = '123123123'
121 | RFC_SECRET = to_hex('12345678901234567890')
122 |
123 | # libnitrokey.NK_login('S') # connect only to Nitrokey Storage device
124 | # libnitrokey.NK_login('P') # connect only to Nitrokey Pro device
125 | device_connected = libnitrokey.NK_login_auto() # connect to any Nitrokey Stick
126 | if device_connected:
127 | print('Connected to Nitrokey device!')
128 | else:
129 | print('Could not connect to Nitrokey device!')
130 | exit()
131 | use_8_digits = True
132 | pin_correct = libnitrokey.NK_first_authenticate(ADMIN, ADMIN_TEMP) == DeviceErrorCode.STATUS_OK
133 | if pin_correct:
134 | print('Your PIN is correct!')
135 | else:
136 | print('Your PIN is not correct! Please try again. Please be careful to not lock your stick!')
137 | retry_count_left = libnitrokey.NK_get_admin_retry_count()
138 | print('Retry count left: %d' % retry_count_left )
139 | exit()
140 |
141 | # For function parameters documentation please check NK_C_API.h
142 | assert libnitrokey.NK_write_config(255, 255, 255, False, True, ADMIN_TEMP) == DeviceErrorCode.STATUS_OK
143 | libnitrokey.NK_first_authenticate(ADMIN, ADMIN_TEMP)
144 | libnitrokey.NK_write_hotp_slot(1, 'python_test', RFC_SECRET, 0, use_8_digits, False, False, "",
145 | ADMIN_TEMP)
146 | # RFC test according to: https://tools.ietf.org/html/rfc4226#page-32
147 | test_data = [
148 | 1284755224, 1094287082, 137359152, 1726969429, 1640338314, 868254676, 1918287922, 82162583, 673399871,
149 | 645520489,
150 | ]
151 | print('Getting HOTP code from Nitrokey Stick (RFC test, 8 digits): ')
152 | for i in range(10):
153 | hotp_slot_1_code = get_hotp_code(libnitrokey, 1)
154 | correct_str = "correct!" if hotp_slot_1_code == str(test_data[i])[-8:] else "not correct"
155 | print('%d: %s, should be %s -> %s' % (i, hotp_slot_1_code, str(test_data[i])[-8:], correct_str))
156 | libnitrokey.NK_logout() # disconnect device
157 |
--------------------------------------------------------------------------------
/unittest/Pipfile:
--------------------------------------------------------------------------------
1 | [[source]]
2 | name = "pypi"
3 | url = "https://pypi.org/simple"
4 | verify_ssl = true
5 |
6 | [dev-packages]
7 |
8 | [packages]
9 | cffi = "*"
10 | pytest-repeat = "*"
11 | pytest-randomly = "*"
12 | tqdm = "*"
13 | oath = "*"
14 | pyexpect = "*"
15 | pytest = "*"
16 | pytest-reporter-html1 = "*"
17 | pytest-reporter = "*"
18 | hypothesis = "*"
19 |
20 | [requires]
21 | python_version = "3.11"
22 |
--------------------------------------------------------------------------------
/unittest/build/libnitrokey.so:
--------------------------------------------------------------------------------
1 | ../../build/libnitrokey.so
--------------------------------------------------------------------------------
/unittest/build/run.sh:
--------------------------------------------------------------------------------
1 | LD_LIBRARY_PATH=. ./test_HOTP
2 |
--------------------------------------------------------------------------------
/unittest/catch_main.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2015-2018 Nitrokey UG
3 | *
4 | * This file is part of libnitrokey.
5 | *
6 | * libnitrokey is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU Lesser General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * any later version.
10 | *
11 | * libnitrokey is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU Lesser General Public License
17 | * along with libnitrokey. If not, see .
18 | *
19 | * SPDX-License-Identifier: LGPL-3.0
20 | */
21 |
22 | #define CATCH_CONFIG_MAIN // This tells Catch to provide a main()
23 | #include "catch2/catch.hpp"
--------------------------------------------------------------------------------
/unittest/conftest.py:
--------------------------------------------------------------------------------
1 | """
2 | Copyright (c) 2015-2019 Nitrokey UG
3 |
4 | This file is part of libnitrokey.
5 |
6 | libnitrokey is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU Lesser General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | any later version.
10 |
11 | libnitrokey is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU Lesser General Public License
17 | along with libnitrokey. If not, see .
18 |
19 | SPDX-License-Identifier: LGPL-3.0
20 | """
21 |
22 | import pytest
23 | import os, sys
24 |
25 | from misc import ffi, gs
26 |
27 | device_type = None
28 |
29 | from logging import getLogger, basicConfig, DEBUG
30 |
31 | basicConfig(format='* %(relativeCreated)6d %(filename)s:%(lineno)d %(message)s',level=DEBUG)
32 | log = getLogger('conftest')
33 | print = log.debug
34 |
35 | def get_device_type():
36 | return device_type
37 |
38 |
39 | def skip_if_device_version_lower_than(allowed_devices):
40 | global device_type
41 | model, version = device_type
42 | infinite_version_number = 999
43 | if allowed_devices.get(model, infinite_version_number) > version:
44 | pytest.skip('This device model is not applicable to run this test')
45 |
46 |
47 | class AtrrCallProx(object):
48 | def __init__(self, C, name):
49 | self.C = C
50 | self.name = name
51 |
52 | def __call__(self, *args, **kwargs):
53 | print('Calling {}{}'.format(self.name, args))
54 | res = self.C(*args, **kwargs)
55 | res_s = res
56 | try:
57 | res_s = '{} => '.format(res) + '{}'.format(gs(res))
58 | except Exception as e:
59 | pass
60 | print('Result of {}: {}'.format(self.name, res_s))
61 | return res
62 |
63 |
64 | class AttrProxy(object):
65 | def __init__(self, C, name):
66 | self.C = C
67 | self.name = name
68 |
69 | def __getattr__(self, attr):
70 | return AtrrCallProx(getattr(self.C, attr), attr)
71 |
72 |
73 | @pytest.fixture(scope="module")
74 | def C_offline(request=None):
75 | print("Getting library without initializing connection")
76 | return get_library(request, allow_offline=True)
77 |
78 |
79 | @pytest.fixture(scope="session")
80 | def C(request=None):
81 | import platform
82 | print(f"Python version: {platform.python_version()}")
83 | print(f"OS: {platform.system()} {platform.release()} {platform.version()}")
84 | print("Getting library with connection initialized")
85 | return get_library(request)
86 |
87 |
88 | def get_library(request, allow_offline=False):
89 | library_read_declarations()
90 | C = library_open_lib()
91 |
92 | C.NK_set_debug_level(int(os.environ.get('LIBNK_DEBUG', 2)))
93 |
94 | nk_login = C.NK_login_auto()
95 | if nk_login != 1:
96 | print('No devices detected!')
97 | if not allow_offline:
98 | assert nk_login != 0 # returns 0 if not connected or wrong model or 1 when connected
99 | global device_type
100 | firmware_version = C.NK_get_minor_firmware_version()
101 | model = C.NK_get_device_model()
102 | model = 'P' if model == 1 else 'S' if model == 2 else 'U'
103 | device_type = (model, firmware_version)
104 | print('Connected library: {}'.format(gs(C.NK_get_library_version())))
105 | print('Connected device: {} {}'.format(model, firmware_version))
106 |
107 | # assert C.NK_first_authenticate(DefaultPasswords.ADMIN, DefaultPasswords.ADMIN_TEMP) == DeviceErrorCode.STATUS_OK
108 | # assert C.NK_user_authenticate(DefaultPasswords.USER, DefaultPasswords.USER_TEMP) == DeviceErrorCode.STATUS_OK
109 |
110 | # C.NK_status()
111 |
112 | def fin():
113 | print('\nFinishing connection to device')
114 | C.NK_logout()
115 | print('Finished')
116 |
117 | if request:
118 | request.addfinalizer(fin)
119 | # C.NK_set_debug(True)
120 | C.NK_set_debug_level(int(os.environ.get('LIBNK_DEBUG', 3)))
121 |
122 | return AttrProxy(C, "libnitrokey C")
123 |
124 |
125 | def library_open_lib():
126 | C = None
127 | path_build = os.path.join("..", "build")
128 | paths = [
129 | os.environ.get('LIBNK_PATH', None),
130 | os.path.join(path_build, "libnitrokey.so"),
131 | os.path.join(path_build, "libnitrokey.dylib"),
132 | os.path.join(path_build, "libnitrokey.dll"),
133 | os.path.join(path_build, "nitrokey.dll"),
134 | ]
135 | for p in paths:
136 | if not p: continue
137 | print("Trying " + p)
138 | p = os.path.abspath(p)
139 | if os.path.exists(p):
140 | print("Found: " + p)
141 | C = ffi.dlopen(p)
142 | break
143 | else:
144 | print("File does not exist: " + p)
145 | if not C:
146 | print("No library file found")
147 | sys.exit(1)
148 | return C
149 |
150 |
151 | def library_read_declarations():
152 | fp = '../NK_C_API.h'
153 | declarations = []
154 | with open(fp, 'r') as f:
155 | declarations = f.readlines()
156 | cnt = 0
157 | a = iter(declarations)
158 | for declaration in a:
159 | if declaration.strip().startswith('NK_C_API') \
160 | or declaration.strip().startswith('struct'):
161 | declaration = declaration.replace('NK_C_API', '').strip()
162 | while ');' not in declaration and '};' not in declaration:
163 | declaration += (next(a)).strip() + '\n'
164 | ffi.cdef(declaration, override=True)
165 | cnt += 1
166 | print('Imported {} declarations'.format(cnt))
167 |
168 |
169 | def pytest_addoption(parser):
170 | parser.addoption(
171 | "--runslow", action="store_true", default=False, help="run slow tests"
172 | )
173 | parser.addoption("--run-skipped", action="store_true",
174 | help="run the tests skipped by default, e.g. adding side effects")
175 |
176 | def pytest_runtest_setup(item):
177 | if 'skip_by_default' in item.keywords and not item.config.getoption("--run-skipped"):
178 | pytest.skip("need --run-skipped option to run this test")
179 |
180 | def pytest_configure(config):
181 | config.addinivalue_line("markers", "slow: mark test as slow to run")
182 |
183 |
184 |
185 | def library_device_reconnect(C):
186 | C.NK_logout()
187 | C = library_open_lib()
188 | C.NK_logout()
189 | assert C.NK_login_auto() == 1, 'Device not found'
190 | return C
--------------------------------------------------------------------------------
/unittest/constants.py:
--------------------------------------------------------------------------------
1 | """
2 | Copyright (c) 2015-2018 Nitrokey UG
3 |
4 | This file is part of libnitrokey.
5 |
6 | libnitrokey is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU Lesser General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | any later version.
10 |
11 | libnitrokey is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU Lesser General Public License
17 | along with libnitrokey. If not, see .
18 |
19 | SPDX-License-Identifier: LGPL-3.0
20 | """
21 | from enum import Enum
22 | from sys import stderr
23 |
24 | from misc import to_hex, bb
25 | from conftest import print
26 |
27 | RFC_SECRET_HR = '12345678901234567890'
28 | RFC_SECRET = to_hex(RFC_SECRET_HR) # '31323334353637383930...'
29 | bbRFC_SECRET = bb(RFC_SECRET)
30 |
31 |
32 | # print( repr((RFC_SECRET, RFC_SECRET_, len(RFC_SECRET))) )
33 |
34 | class DefaultPasswords:
35 | ADMIN = b'12345678'
36 | USER = b'123456'
37 | ADMIN_TEMP = b'123123123'
38 | USER_TEMP = b'234234234'
39 | UPDATE = b'12345678'
40 | UPDATE_TEMP = b'123update123'
41 | UPDATE_LONG = b'1234567890'*2
42 | UPDATE_TOO_LONG = UPDATE_LONG + b'x'
43 | UPDATE_TOO_SHORT = UPDATE_LONG[:7]
44 |
45 |
46 | class DeviceErrorCode(Enum):
47 | STATUS_OK = 0
48 | BUSY = 1 # busy or busy progressbar in place of wrong_CRC status
49 | NOT_PROGRAMMED = 3
50 | WRONG_PASSWORD = 4
51 | STATUS_NOT_AUTHORIZED = 5
52 | STATUS_AES_DEC_FAILED = 10
53 | STATUS_WRONG_SLOT = 2
54 | STATUS_TIMESTAMP_WARNING = 6
55 | STATUS_NO_NAME_ERROR = 7
56 | STATUS_NOT_SUPPORTED = 8
57 | STATUS_UNKNOWN_COMMAND = 9
58 | STATUS_AES_CREATE_KEY_FAILED = 11
59 | STATUS_ERROR_CHANGING_USER_PASSWORD = 12
60 | STATUS_ERROR_CHANGING_ADMIN_PASSWORD = 13
61 | STATUS_ERROR_UNBLOCKING_PIN = 14
62 |
63 | STATUS_UNKNOWN_ERROR = 100
64 | STATUS_DISCONNECTED = 255
65 |
66 | def __eq__(self, other):
67 | other_name = 'Unknown'
68 | try:
69 | other_name = str(DeviceErrorCode(other).name)
70 | except:
71 | pass
72 | result = self.value == other
73 | print(f'Returned {other_name}, expected {self.name} => {result}')
74 | return result
75 |
76 | class LibraryErrors(Enum):
77 | TOO_LONG_STRING = 200
78 | INVALID_SLOT = 201
79 | INVALID_HEX_STRING = 202
80 | TARGET_BUFFER_SIZE_SMALLER_THAN_SOURCE = 203
81 |
82 | def __eq__(self, other):
83 | other_name = 'Unknown'
84 | try:
85 | other_name = str(LibraryErrors(other).name)
86 | except:
87 | pass
88 | result = self.value == other
89 | print(f'Returned {other_name}, expected {self.name} => {result}')
90 | return result
91 |
92 |
93 | HOTP_slot_count = 3
94 | TOTP_slot_count = 15
95 | PWS_SLOT_COUNT = 16
96 |
--------------------------------------------------------------------------------
/unittest/helpers.py:
--------------------------------------------------------------------------------
1 | from constants import DeviceErrorCode, PWS_SLOT_COUNT, DefaultPasswords
2 | from misc import gs, bb
3 |
4 |
5 | def helper_fill(str_to_fill, target_width):
6 | assert target_width >= len(str_to_fill)
7 | numbers = '1234567890' * 4
8 | str_to_fill += numbers[:target_width - len(str_to_fill)]
9 | assert len(str_to_fill) == target_width
10 | return bb(str_to_fill)
11 |
12 |
13 | def helper_PWS_get_pass(suffix):
14 | return helper_fill('pass' + suffix, 20)
15 |
16 |
17 | def helper_PWS_get_loginname(suffix):
18 | return helper_fill('login' + suffix, 32)
19 |
20 |
21 | def helper_PWS_get_slotname(suffix):
22 | return helper_fill('slotname' + suffix, 11)
23 |
24 |
25 | def helper_check_device_for_data(C):
26 | assert C.NK_lock_device() == DeviceErrorCode.STATUS_OK
27 | assert C.NK_enable_password_safe(DefaultPasswords.USER) == DeviceErrorCode.STATUS_OK
28 |
29 | for i in range(0, PWS_SLOT_COUNT):
30 | iss = str(i)
31 | assert gs(C.NK_get_password_safe_slot_name(i)) == helper_PWS_get_slotname(iss)
32 | assert gs(C.NK_get_password_safe_slot_login(i)) == helper_PWS_get_loginname(iss)
33 | assert gs(C.NK_get_password_safe_slot_password(i)) == helper_PWS_get_pass(iss)
34 | return True
35 |
36 |
37 | def helper_populate_device(C):
38 | # FIXME use object with random data, and check against it
39 | # FIXME generate OTP as well, and check codes against its secrets
40 | assert C.NK_lock_device() == DeviceErrorCode.STATUS_OK
41 | res = C.NK_enable_password_safe(DefaultPasswords.USER)
42 | if res != DeviceErrorCode.STATUS_OK:
43 | assert C.NK_build_aes_key(DefaultPasswords.ADMIN) == DeviceErrorCode.STATUS_OK
44 | assert C.NK_enable_password_safe(DefaultPasswords.USER) == DeviceErrorCode.STATUS_OK
45 |
46 | for i in range(0, PWS_SLOT_COUNT):
47 | iss = str(i)
48 | assert C.NK_write_password_safe_slot(i,
49 | helper_PWS_get_slotname(iss), helper_PWS_get_loginname(iss),
50 | helper_PWS_get_pass(iss)) == DeviceErrorCode.STATUS_OK
51 | return True
52 |
--------------------------------------------------------------------------------
/unittest/libnk-tool.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | """
4 | Copyright (c) 2015-2019 Nitrokey UG
5 |
6 | This file is part of libnitrokey.
7 |
8 | libnitrokey is free software: you can redistribute it and/or modify
9 | it under the terms of the GNU Lesser General Public License as published by
10 | the Free Software Foundation, either version 3 of the License, or
11 | any later version.
12 |
13 | libnitrokey is distributed in the hope that it will be useful,
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 | GNU General Public License for more details.
17 |
18 | You should have received a copy of the GNU Lesser General Public License
19 | along with libnitrokey. If not, see .
20 |
21 | SPDX-License-Identifier: LGPL-3.0
22 | """
23 |
24 | import click
25 |
26 | from conftest import get_library, get_device_type
27 | from constants import DefaultPasswords, DeviceErrorCode
28 |
29 |
30 | @click.group()
31 | def cli():
32 | pass
33 |
34 |
35 | @click.command()
36 | def update():
37 | libnk = get_library(None)
38 | device_type = get_device_type()
39 | print(device_type)
40 | assert device_type[0] == 'S'
41 | assert libnk.NK_enable_firmware_update(DefaultPasswords.UPDATE) == DeviceErrorCode.STATUS_OK
42 |
43 |
44 | cli.add_command(update)
45 |
46 | if __name__ == '__main__':
47 | cli()
48 |
--------------------------------------------------------------------------------
/unittest/misc.py:
--------------------------------------------------------------------------------
1 | """
2 | Copyright (c) 2015-2018 Nitrokey UG
3 |
4 | This file is part of libnitrokey.
5 |
6 | libnitrokey is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU Lesser General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | any later version.
10 |
11 | libnitrokey is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU Lesser General Public License
17 | along with libnitrokey. If not, see .
18 |
19 | SPDX-License-Identifier: LGPL-3.0
20 | """
21 |
22 | import cffi
23 |
24 | ffi = cffi.FFI()
25 | gs = ffi.string
26 |
27 |
28 | def to_hex(s):
29 | return "".join("{:02x}".format(ord(c)) for c in s)
30 |
31 |
32 | def wait(t):
33 | import time
34 | msg = 'Waiting for %d seconds' % t
35 | print(msg.center(40, '='))
36 | time.sleep(t)
37 |
38 |
39 | def cast_pointer_to_tuple(obj, typen, len):
40 | # usage:
41 | # config = cast_pointer_to_tuple(config_raw_data, 'uint8_t', 5)
42 | return tuple(ffi.cast("%s [%d]" % (typen, len), obj)[0:len])
43 |
44 |
45 | def get_devices_firmware_version(C):
46 | firmware = C.NK_get_minor_firmware_version()
47 | return firmware
48 |
49 |
50 | def is_pro_rtm_07(C):
51 | firmware = get_devices_firmware_version(C)
52 | return firmware == 7
53 |
54 |
55 | def is_pro_rtm_08(C):
56 | firmware = get_devices_firmware_version(C)
57 | return firmware in [8,9]
58 |
59 |
60 | def is_storage(C):
61 | """
62 | exact firmware storage is sent by other function
63 | """
64 | # TODO identify connected device directly
65 | firmware = get_devices_firmware_version(C)
66 | return firmware >= 45
67 |
68 |
69 | def is_long_OTP_secret_handled(C):
70 | return is_pro_rtm_08(C) or is_storage(C) and get_devices_firmware_version(C) >= 54
71 |
72 |
73 | def has_binary_counter(C):
74 | return (not is_storage(C)) or (is_storage(C) and get_devices_firmware_version(C) >= 54)
75 |
76 |
77 | def bb(x):
78 | return bytes(x, encoding='ascii')
--------------------------------------------------------------------------------
/unittest/pyproject.toml:
--------------------------------------------------------------------------------
1 | [tool.pytest.ini_options]
2 | markers = [
3 | "slow: marks tests as slow (deselect with '-m \"not slow\"')",
4 | "serial",
5 | "aes",
6 | "encrypted",
7 | "factory_reset",
8 | "firmware",
9 | "hidden",
10 | "info",
11 | "lock_device",
12 | "other",
13 | "otp",
14 | "pin",
15 | "PWS",
16 | "skip",
17 | "skip_by_default",
18 | "slowtest",
19 | "status",
20 | "unencrypted",
21 | "update",
22 | ]
--------------------------------------------------------------------------------
/unittest/requirements.txt:
--------------------------------------------------------------------------------
1 | cffi
2 | pytest
3 | pytest-repeat
4 | pytest-randomly
5 | tqdm
6 | oath
7 | hypothesis
8 |
--------------------------------------------------------------------------------
/unittest/setup_python_dependencies.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | pip install -r requirements.txt --user
4 |
--------------------------------------------------------------------------------
/unittest/test1.cc:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2015-2018 Nitrokey UG
3 | *
4 | * This file is part of libnitrokey.
5 | *
6 | * libnitrokey is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU Lesser General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * any later version.
10 | *
11 | * libnitrokey is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU Lesser General Public License
17 | * along with libnitrokey. If not, see .
18 | *
19 | * SPDX-License-Identifier: LGPL-3.0
20 | */
21 |
22 | #include "catch2/catch.hpp"
23 |
24 | #include
25 | #include
26 | #include "device_proto.h"
27 | #include "log.h"
28 | #include "stick10_commands.h"
29 |
30 | using namespace std;
31 | using namespace nitrokey::device;
32 | using namespace nitrokey::proto::stick10;
33 | using namespace nitrokey::log;
34 | using namespace nitrokey::misc;
35 |
36 | using Dev10 = std::shared_ptr;
37 |
38 | std::string getSlotName(Dev10 stick, int slotNo) {
39 | auto slot_req = get_payload();
40 | slot_req.slot_number = slotNo;
41 | auto slot = ReadSlot::CommandTransaction::run(stick, slot_req);
42 | std::string sName(reinterpret_cast(slot.data().slot_name));
43 | return sName;
44 | }
45 |
46 | TEST_CASE("Slot names are correct", "[slotNames]") {
47 | auto stick = make_shared();
48 | bool connected = stick->connect();
49 | REQUIRE(connected == true);
50 |
51 | Log::instance().set_loglevel(Loglevel::DEBUG);
52 |
53 | auto resp = GetStatus::CommandTransaction::run(stick);
54 |
55 | auto authreq = get_payload();
56 | strcpy((char *)(authreq.card_password), "12345678");
57 | FirstAuthenticate::CommandTransaction::run(stick, authreq);
58 |
59 | {
60 | auto authreq = get_payload();
61 | strcpy((char *)(authreq.user_password), "123456");
62 | EnablePasswordSafe::CommandTransaction::run(stick, authreq);
63 | }
64 |
65 | //assuming these values were set earlier, thus failing on normal use
66 | REQUIRE(getSlotName(stick, 0x20) == std::string("1"));
67 | REQUIRE(getSlotName(stick, 0x21) == std::string("slot2"));
68 |
69 | {
70 | auto resp = GetPasswordRetryCount::CommandTransaction::run(stick);
71 | REQUIRE(resp.data().password_retry_count == 3);
72 | }
73 | {
74 | auto resp = GetUserPasswordRetryCount::CommandTransaction::run(stick);
75 | REQUIRE(resp.data().password_retry_count == 3);
76 | }
77 |
78 | {
79 | auto slot = get_payload();
80 | slot.slot_number = 0;
81 | auto resp2 = GetPasswordSafeSlotName::CommandTransaction::run(stick, slot);
82 | std::string sName(reinterpret_cast(resp2.data().slot_name));
83 | REQUIRE(sName == std::string("web1"));
84 | }
85 |
86 | {
87 | auto slot = get_payload();
88 | slot.slot_number = 0;
89 | auto resp2 =
90 | GetPasswordSafeSlotPassword::CommandTransaction::run(stick, slot);
91 | std::string sName(reinterpret_cast(resp2.data().slot_password));
92 | REQUIRE(sName == std::string("pass1"));
93 | }
94 |
95 | {
96 | auto slot = get_payload();
97 | slot.slot_number = 0;
98 | auto resp2 = GetPasswordSafeSlotLogin::CommandTransaction::run(stick, slot);
99 | std::string sName(reinterpret_cast(resp2.data().slot_login));
100 | REQUIRE(sName == std::string("login1"));
101 | }
102 |
103 | stick->disconnect();
104 | }
105 |
--------------------------------------------------------------------------------
/unittest/test3.cc:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2015-2018 Nitrokey UG
3 | *
4 | * This file is part of libnitrokey.
5 | *
6 | * libnitrokey is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU Lesser General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * any later version.
10 | *
11 | * libnitrokey is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU Lesser General Public License
17 | * along with libnitrokey. If not, see .
18 | *
19 | * SPDX-License-Identifier: LGPL-3.0
20 | */
21 |
22 |
23 | static const char *const default_admin_pin = "12345678";
24 | static const char *const default_user_pin = "123456";
25 | const char * temporary_password = "123456789012345678901234";
26 | const char * RFC_SECRET = "12345678901234567890";
27 |
28 | #include "catch2/catch.hpp"
29 |
30 | #include
31 | #include
32 | #include
33 | #include "device_proto.h"
34 | #include "log.h"
35 | #include "stick10_commands_0.8.h"
36 | //#include "stick20_commands.h"
37 |
38 | using namespace std;
39 | using namespace nitrokey::device;
40 | using namespace nitrokey::proto;
41 | using namespace nitrokey::proto::stick10_08;
42 | using namespace nitrokey::log;
43 | using namespace nitrokey::misc;
44 |
45 | using Dev = Stick10;
46 | using Dev10 = std::shared_ptr;
47 |
48 | void connect_and_setup(Dev10 stick) {
49 | bool connected = stick->connect();
50 | REQUIRE(connected == true);
51 | Log::instance().set_loglevel(Loglevel::DEBUG);
52 | }
53 |
54 | void authorize(Dev10 stick) {
55 | auto authreq = get_payload();
56 | strcpy((char *) (authreq.card_password), default_admin_pin);
57 | strcpy((char *) (authreq.temporary_password), temporary_password);
58 | FirstAuthenticate::CommandTransaction::run(stick, authreq);
59 |
60 | auto user_auth = get_payload();
61 | strcpyT(user_auth.temporary_password, temporary_password);
62 | strcpyT(user_auth.card_password, default_user_pin);
63 | UserAuthenticate::CommandTransaction::run(stick, user_auth);
64 | }
65 |
66 | TEST_CASE("write slot", "[pronew]"){
67 | auto stick = make_shared();
68 |
69 | connect_and_setup(stick);
70 | authorize(stick);
71 |
72 | auto p2 = get_payload();
73 | strcpyT(p2.temporary_admin_password, temporary_password);
74 | p2.setTypeName();
75 | strcpyT(p2.data, "test name aaa");
76 | stick10_08::SendOTPData::CommandTransaction::run(stick, p2);
77 |
78 | p2 = get_payload();
79 | strcpyT(p2.temporary_admin_password, temporary_password);
80 | strcpyT(p2.data, RFC_SECRET);
81 | p2.setTypeSecret();
82 | stick10_08::SendOTPData::CommandTransaction::run(stick, p2);
83 |
84 | auto p = get_payload();
85 | strcpyT(p.temporary_admin_password, temporary_password);
86 | p.use_8_digits = true;
87 | p.slot_number = 0 + 0x10;
88 | p.slot_counter_or_interval = 0;
89 | stick10_08::WriteToOTPSlot::CommandTransaction::run(stick, p);
90 |
91 | auto pc = get_payload();
92 | pc.enable_user_password = 0;
93 | strcpyT(pc.temporary_admin_password, temporary_password);
94 | WriteGeneralConfig::CommandTransaction::run(stick, pc);
95 |
96 | auto p3 = get_payload();
97 | p3.slot_number = 0 + 0x10;
98 | GetHOTP::CommandTransaction::run(stick, p3);
99 |
100 | }
101 |
102 |
103 | TEST_CASE("erase slot", "[pronew]"){
104 | auto stick = make_shared();
105 | connect_and_setup(stick);
106 | authorize(stick);
107 |
108 | auto p = get_payload();
109 | p.enable_user_password = 0;
110 | strcpyT(p.temporary_admin_password, temporary_password);
111 | WriteGeneralConfig::CommandTransaction::run(stick, p);
112 |
113 | auto p3 = get_payload();
114 | p3.slot_number = 0 + 0x10;
115 | GetHOTP::CommandTransaction::run(stick, p3);
116 |
117 | auto erase_payload = get_payload();
118 | erase_payload.slot_number = 0 + 0x10;
119 | strcpyT(erase_payload.temporary_admin_password, temporary_password);
120 | EraseSlot::CommandTransaction::run(stick, erase_payload);
121 |
122 | auto p4 = get_payload();
123 | p4.slot_number = 0 + 0x10;
124 | REQUIRE_THROWS(
125 | GetHOTP::CommandTransaction::run(stick, p4)
126 | );
127 | }
128 |
129 | TEST_CASE("write general config", "[pronew]") {
130 | auto stick = make_shared();
131 | connect_and_setup(stick);
132 | authorize(stick);
133 |
134 | auto p = get_payload();
135 | p.enable_user_password = 1;
136 | REQUIRE_THROWS(
137 | WriteGeneralConfig::CommandTransaction::run(stick, p)
138 | );
139 | strcpyT(p.temporary_admin_password, temporary_password);
140 | WriteGeneralConfig::CommandTransaction::run(stick, p);
141 | }
142 |
143 | TEST_CASE("authorize user HOTP", "[pronew]") {
144 | auto stick = make_shared();
145 | connect_and_setup(stick);
146 | authorize(stick);
147 |
148 | {
149 | auto p = get_payload();
150 | p.enable_user_password = 1;
151 | strcpyT(p.temporary_admin_password, temporary_password);
152 | WriteGeneralConfig::CommandTransaction::run(stick, p);
153 | }
154 |
155 | auto p2 = get_payload();
156 | strcpyT(p2.temporary_admin_password, temporary_password);
157 | p2.setTypeName();
158 | strcpyT(p2.data, "test name aaa");
159 | stick10_08::SendOTPData::CommandTransaction::run(stick, p2);
160 |
161 | p2 = get_payload();
162 | strcpyT(p2.temporary_admin_password, temporary_password);
163 | strcpyT(p2.data, RFC_SECRET);
164 | p2.setTypeSecret();
165 | stick10_08::SendOTPData::CommandTransaction::run(stick, p2);
166 |
167 | auto p = get_payload();
168 | strcpyT(p.temporary_admin_password, temporary_password);
169 | p.use_8_digits = true;
170 | p.slot_number = 0 + 0x10;
171 | p.slot_counter_or_interval = 0;
172 | stick10_08::WriteToOTPSlot::CommandTransaction::run(stick, p);
173 |
174 |
175 | auto p3 = get_payload();
176 | p3.slot_number = 0 + 0x10;
177 | REQUIRE_THROWS(
178 | GetHOTP::CommandTransaction::run(stick, p3)
179 | );
180 | strcpyT(p3.temporary_user_password, temporary_password);
181 | auto code_response = GetHOTP::CommandTransaction::run(stick, p3);
182 | REQUIRE(code_response.data().code == 84755224);
183 |
184 | }
185 |
186 | TEST_CASE("check firmware version", "[pronew]") {
187 | auto stick = make_shared();
188 | connect_and_setup(stick);
189 |
190 | auto p = GetStatus::CommandTransaction::run(stick);
191 | REQUIRE(p.data().firmware_version == 8);
192 | }
193 |
194 | TEST_CASE("authorize user TOTP", "[pronew]") {
195 | auto stick = make_shared();
196 | connect_and_setup(stick);
197 | authorize(stick);
198 |
199 | {
200 | auto p = get_payload();
201 | p.enable_user_password = 1;
202 | strcpyT(p.temporary_admin_password, temporary_password);
203 | WriteGeneralConfig::CommandTransaction::run(stick, p);
204 | }
205 |
206 | auto p2 = get_payload();
207 | strcpyT(p2.temporary_admin_password, temporary_password);
208 | p2.setTypeName();
209 | strcpyT(p2.data, "test name TOTP");
210 | stick10_08::SendOTPData::CommandTransaction::run(stick, p2);
211 |
212 | p2 = get_payload();
213 | strcpyT(p2.temporary_admin_password, temporary_password);
214 | strcpyT(p2.data, RFC_SECRET);
215 | p2.setTypeSecret();
216 | stick10_08::SendOTPData::CommandTransaction::run(stick, p2);
217 |
218 | auto p = get_payload();
219 | strcpyT(p.temporary_admin_password, temporary_password);
220 | p.use_8_digits = true;
221 | p.slot_number = 0 + 0x20;
222 | p.slot_counter_or_interval = 30;
223 | stick10_08::WriteToOTPSlot::CommandTransaction::run(stick, p);
224 |
225 | auto p_get_totp = get_payload();
226 | p_get_totp.slot_number = 0 + 0x20;
227 |
228 | REQUIRE_THROWS(
229 | GetTOTP::CommandTransaction::run(stick, p_get_totp)
230 | );
231 | strcpyT(p_get_totp.temporary_user_password, temporary_password);
232 |
233 | auto p_set_time = get_payload();
234 | p_set_time.reset = 1;
235 | p_set_time.time = 59;
236 | SetTime::CommandTransaction::run(stick, p_set_time);
237 | auto code = GetTOTP::CommandTransaction::run(stick, p_get_totp);
238 | REQUIRE(code.data().code == 94287082);
239 |
240 | }
241 |
--------------------------------------------------------------------------------
/unittest/test_C_API.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2015-2018 Nitrokey UG
3 | *
4 | * This file is part of libnitrokey.
5 | *
6 | * libnitrokey is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU Lesser General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * any later version.
10 | *
11 | * libnitrokey is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU Lesser General Public License
17 | * along with libnitrokey. If not, see .
18 | *
19 | * SPDX-License-Identifier: LGPL-3.0
20 | */
21 |
22 | static const int TOO_LONG_STRING = 200;
23 |
24 | #include "catch2/catch.hpp"
25 |
26 | #include
27 | #include
28 | #include "log.h"
29 | #include "../NK_C_API.h"
30 |
31 | int login;
32 |
33 | TEST_CASE("C API connect", "[BASIC]") {
34 | login = NK_login_auto();
35 | REQUIRE(login != 0);
36 | NK_logout();
37 | login = NK_login_auto();
38 | REQUIRE(login != 0);
39 | NK_logout();
40 | login = NK_login_auto();
41 | REQUIRE(login != 0);
42 | }
43 |
44 | TEST_CASE("Check retry count", "[BASIC]") {
45 | REQUIRE(login != 0);
46 | NK_set_debug_level(3);
47 | REQUIRE(NK_get_admin_retry_count() == 3);
48 | REQUIRE(NK_get_user_retry_count() == 3);
49 | }
50 |
51 | TEST_CASE("Check long strings", "[STANDARD]") {
52 | REQUIRE(login != 0);
53 | const char* longPin = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
54 | const char* pin = "123123123";
55 | auto result = NK_change_user_PIN(longPin, pin);
56 | REQUIRE(result == TOO_LONG_STRING);
57 | result = NK_change_user_PIN(pin, longPin);
58 | REQUIRE(result == TOO_LONG_STRING);
59 | CAPTURE(result);
60 | }
61 |
62 | #include
63 |
64 | TEST_CASE("multiple devices with ID", "[BASIC]") {
65 | NK_logout();
66 | NK_set_debug_level(3);
67 | auto s = NK_list_devices_by_cpuID();
68 | REQUIRE(s!=nullptr);
69 | REQUIRE(strnlen(s, 4096) < 4096);
70 | REQUIRE(strnlen(s, 4096) > 2*4);
71 | std::cout << s << std::endl;
72 |
73 | char *string, *token;
74 | int t;
75 |
76 | string = strndup(s, 4096);
77 | free (static_cast(const_cast(s)));
78 |
79 | while ((token = strsep(&string, ";")) != nullptr){
80 | if (strnlen(token, 4096) < 3) continue;
81 | std::cout << token << " connecting: ";
82 | std::cout << (t=NK_connect_with_ID(token)) << std::endl;
83 | REQUIRE(t == 1);
84 | }
85 |
86 | free (string);
87 | }
88 |
89 | TEST_CASE("Get device model", "[BASIC]") {
90 | NK_logout();
91 | NK_device_model model = NK_get_device_model();
92 | REQUIRE(model == NK_device_model::NK_DISCONNECTED);
93 |
94 | auto success = NK_login_auto() == 1;
95 | REQUIRE(success);
96 | model = NK_get_device_model();
97 | REQUIRE(model != NK_device_model::NK_DISCONNECTED);
98 |
99 | REQUIRE((model == NK_PRO || model == NK_STORAGE));
100 | NK_logout();
101 | }
102 |
--------------------------------------------------------------------------------
/unittest/test_HOTP.cc:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2015-2018 Nitrokey UG
3 | *
4 | * This file is part of libnitrokey.
5 | *
6 | * libnitrokey is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU Lesser General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * any later version.
10 | *
11 | * libnitrokey is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU Lesser General Public License
17 | * along with libnitrokey. If not, see .
18 | *
19 | * SPDX-License-Identifier: LGPL-3.0
20 | */
21 |
22 |
23 | #include "catch2/catch.hpp"
24 | #include
25 | #include "device_proto.h"
26 | #include "log.h"
27 | #include "stick10_commands.h"
28 | #include
29 | #include "misc.h"
30 |
31 | using namespace std;
32 | using namespace nitrokey::device;
33 | using namespace nitrokey::proto::stick10;
34 | using namespace nitrokey::log;
35 | using namespace nitrokey::misc;
36 |
37 | void hexStringToByte(uint8_t data[], const char* hexString){
38 | REQUIRE(strlen(hexString)%2==0);
39 | char buf[3];
40 | buf[2] = '\0';
41 | for(size_t i=0; i(slot_secret) ) == 0 );
56 | }
57 |
58 | TEST_CASE("Test HOTP codes according to RFC", "[HOTP]") {
59 | std::shared_ptr stick = make_shared();
60 | bool connected = stick->connect();
61 |
62 | REQUIRE(connected == true);
63 |
64 | Log::instance().set_loglevel(Loglevel::DEBUG);
65 |
66 | auto resp = GetStatus::CommandTransaction::run(stick);
67 |
68 | const char * temporary_password = "123456789012345678901234";
69 | {
70 | auto authreq = get_payload();
71 | strcpy((char *)(authreq.card_password), "12345678");
72 | strcpy((char *)(authreq.temporary_password), temporary_password);
73 | FirstAuthenticate::CommandTransaction::run(stick, authreq);
74 | }
75 |
76 | //test according to https://tools.ietf.org/html/rfc4226#page-32
77 | {
78 | auto hwrite = get_payload();
79 | hwrite.slot_number = 0x10;
80 | strcpy(reinterpret_cast(hwrite.slot_name), "rfc4226_lib");
81 | //strcpy(reinterpret_cast(hwrite.slot_secret), "");
82 | const char* secretHex = "3132333435363738393031323334353637383930";
83 | hexStringToByte(hwrite.slot_secret, secretHex);
84 |
85 | //hwrite.slot_config; //TODO check various configs in separate test cases
86 | //strcpy(reinterpret_cast(hwrite.slot_token_id), "");
87 | //strcpy(reinterpret_cast(hwrite.slot_counter), "");
88 |
89 | //authorize writehotp first
90 | {
91 | auto auth = get_payload();
92 | strcpy((char *)(auth.temporary_password), temporary_password);
93 | auth.crc_to_authorize = WriteToHOTPSlot::CommandTransaction::getCRC(hwrite);
94 | Authorize::CommandTransaction::run(stick, auth);
95 | }
96 |
97 | //run hotp command
98 | WriteToHOTPSlot::CommandTransaction::run(stick, hwrite);
99 |
100 | uint32_t codes[] = {
101 | 755224, 287082, 359152, 969429, 338314,
102 | 254676, 287922, 162583, 399871, 520489
103 | };
104 |
105 | for( auto code: codes){
106 | auto gh = get_payload();
107 | gh.slot_number = 0x10;
108 | auto resp = GetHOTP::CommandTransaction::run(stick, gh);
109 | REQUIRE( resp.data().code == code);
110 | }
111 | //checking slot programmed before with nitro-app
112 | /*
113 | for( auto code: codes){
114 | GetHOTP::CommandTransaction::CommandPayload gh;
115 | gh.slot_number = 0x12;
116 | auto resp = GetHOTP::CommandTransaction::run(stick, gh);
117 | REQUIRE( resp.code == code);
118 | }
119 | */
120 | }
121 |
122 |
123 | stick->disconnect();
124 | }
125 |
--------------------------------------------------------------------------------
/unittest/test_command_ids_header.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2015-2018 Nitrokey UG
3 | *
4 | * This file is part of libnitrokey.
5 | *
6 | * libnitrokey is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU Lesser General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * any later version.
10 | *
11 | * libnitrokey is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU Lesser General Public License
17 | * along with libnitrokey. If not, see .
18 | *
19 | * SPDX-License-Identifier: LGPL-3.0
20 | */
21 |
22 | #ifndef LIBNITROKEY_TEST_COMMAND_IDS_HEADER_H_H
23 | #define LIBNITROKEY_TEST_COMMAND_IDS_HEADER_H_H
24 |
25 | #define STICK20_CMD_START_VALUE 0x20
26 | #define STICK20_CMD_ENABLE_CRYPTED_PARI (STICK20_CMD_START_VALUE + 0)
27 | #define STICK20_CMD_DISABLE_CRYPTED_PARI (STICK20_CMD_START_VALUE + 1)
28 | #define STICK20_CMD_ENABLE_HIDDEN_CRYPTED_PARI (STICK20_CMD_START_VALUE + 2)
29 | #define STICK20_CMD_DISABLE_HIDDEN_CRYPTED_PARI (STICK20_CMD_START_VALUE + 3)
30 | #define STICK20_CMD_ENABLE_FIRMWARE_UPDATE (STICK20_CMD_START_VALUE + 4)
31 | #define STICK20_CMD_EXPORT_FIRMWARE_TO_FILE (STICK20_CMD_START_VALUE + 5)
32 | #define STICK20_CMD_GENERATE_NEW_KEYS (STICK20_CMD_START_VALUE + 6)
33 | #define STICK20_CMD_FILL_SD_CARD_WITH_RANDOM_CHARS (STICK20_CMD_START_VALUE + 7)
34 |
35 | #define STICK20_CMD_WRITE_STATUS_DATA (STICK20_CMD_START_VALUE + 8)
36 | #define STICK20_CMD_ENABLE_READONLY_UNCRYPTED_LUN (STICK20_CMD_START_VALUE + 9)
37 | #define STICK20_CMD_ENABLE_READWRITE_UNCRYPTED_LUN (STICK20_CMD_START_VALUE + 10)
38 |
39 | #define STICK20_CMD_SEND_PASSWORD_MATRIX (STICK20_CMD_START_VALUE + 11)
40 | #define STICK20_CMD_SEND_PASSWORD_MATRIX_PINDATA (STICK20_CMD_START_VALUE + 12)
41 | #define STICK20_CMD_SEND_PASSWORD_MATRIX_SETUP (STICK20_CMD_START_VALUE + 13)
42 |
43 | #define STICK20_CMD_GET_DEVICE_STATUS (STICK20_CMD_START_VALUE + 14)
44 | #define STICK20_CMD_SEND_DEVICE_STATUS (STICK20_CMD_START_VALUE + 15)
45 |
46 | #define STICK20_CMD_SEND_HIDDEN_VOLUME_PASSWORD (STICK20_CMD_START_VALUE + 16)
47 | #define STICK20_CMD_SEND_HIDDEN_VOLUME_SETUP (STICK20_CMD_START_VALUE + 17)
48 | #define STICK20_CMD_SEND_PASSWORD (STICK20_CMD_START_VALUE + 18)
49 | #define STICK20_CMD_SEND_NEW_PASSWORD (STICK20_CMD_START_VALUE + 19)
50 | #define STICK20_CMD_CLEAR_NEW_SD_CARD_FOUND (STICK20_CMD_START_VALUE + 20)
51 |
52 | #define STICK20_CMD_SEND_STARTUP (STICK20_CMD_START_VALUE + 21)
53 | #define STICK20_CMD_SEND_CLEAR_STICK_KEYS_NOT_INITIATED (STICK20_CMD_START_VALUE + 22)
54 | #define STICK20_CMD_SEND_LOCK_STICK_HARDWARE (STICK20_CMD_START_VALUE + 23)
55 |
56 | #define STICK20_CMD_PRODUCTION_TEST (STICK20_CMD_START_VALUE + 24)
57 | #define STICK20_CMD_SEND_DEBUG_DATA (STICK20_CMD_START_VALUE + 25)
58 |
59 | #define STICK20_CMD_CHANGE_UPDATE_PIN (STICK20_CMD_START_VALUE + 26)
60 |
61 |
62 | #endif //LIBNITROKEY_TEST_COMMAND_IDS_HEADER_H_H
63 |
--------------------------------------------------------------------------------
/unittest/test_issues.cc:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2015-2018 Nitrokey UG
3 | *
4 | * This file is part of libnitrokey.
5 | *
6 | * libnitrokey is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU Lesser General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * any later version.
10 | *
11 | * libnitrokey is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU Lesser General Public License
17 | * along with libnitrokey. If not, see .
18 | *
19 | * SPDX-License-Identifier: LGPL-3.0
20 | */
21 |
22 |
23 | const char * const default_admin_pin = "12345678";
24 | const char * const default_user_pin = "123456";
25 | const char * const temporary_password = "123456789012345678901234";
26 | const char * const RFC_SECRET = "12345678901234567890";
27 | const char * const hidden_volume_pass = "123456789012345";
28 |
29 | #include "catch2/catch.hpp"
30 |
31 | #include
32 |
33 | using namespace std;
34 | using namespace nitrokey;
35 |
36 |
37 | bool test_36(){
38 | auto i = NitrokeyManager::instance();
39 | i->set_loglevel(3);
40 | REQUIRE(i->connect());
41 |
42 | for (int j = 0; j < 200; ++j) {
43 | i->get_status();
44 | i->get_status_storage_as_string();
45 | INFO( "Iteration: " << j);
46 | }
47 | return true;
48 | }
49 |
50 | bool test_31(){
51 | auto i = NitrokeyManager::instance();
52 | i->set_loglevel(3);
53 | REQUIRE(i->connect());
54 |
55 | // i->unlock_encrypted_volume(default_user_pin);
56 | // i->create_hidden_volume(0, 70, 80, hidden_volume_pass);
57 | // i->lock_device();
58 |
59 | try{
60 | i->get_password_safe_slot_status();
61 | }
62 | catch (...){
63 | //pass
64 | }
65 |
66 | i->get_status_storage();
67 | i->get_admin_retry_count();
68 | i->get_status_storage();
69 | i->get_user_retry_count();
70 | i->unlock_encrypted_volume(default_user_pin);
71 | i->get_status_storage();
72 | i->get_password_safe_slot_status();
73 | i->get_status_storage();
74 | i->get_user_retry_count();
75 | i->get_password_safe_slot_status();
76 | i->get_status();
77 | i->get_status_storage();
78 | i->get_admin_retry_count();
79 | i->get_status();
80 | i->get_user_retry_count();
81 | i->unlock_hidden_volume(hidden_volume_pass);
82 | i->get_status_storage();
83 | i->get_password_safe_slot_status();
84 |
85 |
86 | return true;
87 | }
88 |
89 | TEST_CASE("issue 31", "[issue]"){
90 | {
91 | auto i = NitrokeyManager::instance();
92 | i->set_loglevel(4);
93 | REQUIRE(i->connect());
94 |
95 | i->unlock_encrypted_volume(default_user_pin);
96 | i->create_hidden_volume(0, 70, 80, hidden_volume_pass);
97 | i->lock_device();
98 | }
99 |
100 | for(int i=0; i<20; i++){
101 | REQUIRE(test_31());
102 | }
103 | }
104 |
105 |
106 |
107 | TEST_CASE("issue 36", "[issue]"){
108 | REQUIRE(test_36());
109 | }
110 |
--------------------------------------------------------------------------------
/unittest/test_issues.py:
--------------------------------------------------------------------------------
1 | from enum import Enum
2 |
3 | import pytest
4 |
5 | from conftest import skip_if_device_version_lower_than
6 | from constants import DefaultPasswords, DeviceErrorCode
7 | from misc import gs, ffi
8 | from test_pro import check_HOTP_RFC_codes, test_random
9 |
10 |
11 | def test_destroy_encrypted_data_leaves_OTP_intact(C):
12 | """
13 | Make sure AES key regeneration will not remove OTP records.
14 | Test for Nitrokey Storage.
15 | Details: https://github.com/Nitrokey/libnitrokey/issues/199
16 | """
17 | skip_if_device_version_lower_than({'S': 55})
18 |
19 | assert C.NK_enable_password_safe(DefaultPasswords.USER) == DeviceErrorCode.STATUS_OK
20 | # write password safe slot
21 | assert C.NK_write_password_safe_slot(0, b'slotname1', b'login1', b'pass1') == DeviceErrorCode.STATUS_OK
22 | # read slot
23 | assert gs(C.NK_get_password_safe_slot_name(0)) == b'slotname1'
24 | assert C.NK_get_last_command_status() == DeviceErrorCode.STATUS_OK
25 | slot_login = C.NK_get_password_safe_slot_login(0)
26 | assert C.NK_get_last_command_status() == DeviceErrorCode.STATUS_OK
27 | assert gs(slot_login) == b'login1'
28 |
29 | # write OTP
30 | use_8_digits = False
31 | use_pin_protection = False
32 | assert C.NK_first_authenticate(DefaultPasswords.ADMIN, DefaultPasswords.ADMIN_TEMP) == DeviceErrorCode.STATUS_OK
33 | assert C.NK_write_config(255, 255, 255, use_pin_protection, not use_pin_protection,
34 | DefaultPasswords.ADMIN_TEMP) == DeviceErrorCode.STATUS_OK
35 | check_HOTP_RFC_codes(C, lambda x: gs(C.NK_get_hotp_code(x)), use_8_digits=use_8_digits)
36 |
37 | # confirm OTP
38 | assert C.NK_first_authenticate(DefaultPasswords.ADMIN, DefaultPasswords.ADMIN_TEMP) == DeviceErrorCode.STATUS_OK
39 | assert gs(C.NK_get_hotp_slot_name(1)) == b'python_test'
40 |
41 | # destroy password safe by regenerating aes key
42 | assert C.NK_lock_device() == DeviceErrorCode.STATUS_OK
43 |
44 | assert C.NK_first_authenticate(DefaultPasswords.ADMIN, DefaultPasswords.ADMIN_TEMP) == DeviceErrorCode.STATUS_OK
45 | assert C.NK_build_aes_key(DefaultPasswords.ADMIN) == DeviceErrorCode.STATUS_OK
46 | assert C.NK_lock_device() == DeviceErrorCode.STATUS_OK
47 | assert C.NK_enable_password_safe(DefaultPasswords.USER) == DeviceErrorCode.STATUS_OK
48 | assert gs(C.NK_get_password_safe_slot_name(0)) != b'slotname1'
49 | assert C.NK_get_last_command_status() == DeviceErrorCode.STATUS_OK
50 |
51 | # confirm OTP
52 | assert C.NK_first_authenticate(DefaultPasswords.ADMIN, DefaultPasswords.ADMIN_TEMP) == DeviceErrorCode.STATUS_OK
53 | assert gs(C.NK_get_hotp_slot_name(1)) == b'python_test'
54 |
55 |
56 | class Modes(Enum):
57 | EmptyBody = 0
58 | FactoryResetWithAES = 1
59 | FactoryReset = 2
60 | AESGeneration = 3
61 |
62 | @pytest.mark.firmware
63 | @pytest.mark.factory_reset
64 | @pytest.mark.parametrize("mode", map(Modes, reversed(range(4))))
65 | def test_pro_factory_reset_breaks_update_password(C, mode: Modes):
66 | from test_pro_bootloader import test_bootloader_password_change_pro, test_bootloader_password_change_pro_length
67 | from test_pro import test_factory_reset
68 | skip_if_device_version_lower_than({'P': 14})
69 |
70 | func = {
71 | Modes.EmptyBody: lambda: True,
72 | Modes.FactoryResetWithAES: lambda: test_factory_reset(C) or True,
73 | Modes.FactoryReset: lambda: C.NK_factory_reset(DefaultPasswords.ADMIN) == DeviceErrorCode.STATUS_OK,
74 | Modes.AESGeneration: lambda: C.NK_build_aes_key(DefaultPasswords.ADMIN) == DeviceErrorCode.STATUS_OK,
75 | }
76 |
77 | def boot_test(C):
78 | test_bootloader_password_change_pro(C)
79 | # test_bootloader_password_change_pro_length(C)
80 |
81 | def random(C):
82 | data = ffi.new('struct GetRandom_t *')
83 | req_count = 50
84 | res = C.NK_get_random(req_count, data)
85 | assert res == DeviceErrorCode.STATUS_OK
86 | assert C.NK_get_last_command_status() == DeviceErrorCode.STATUS_OK
87 | assert data.op_success == 1
88 | assert data.size_effective == req_count
89 |
90 | random(C)
91 | boot_test(C)
92 | random(C)
93 | func[mode]()
94 | random(C) # fails here
95 | boot_test(C)
96 | random(C)
97 |
--------------------------------------------------------------------------------
/unittest/test_library.py:
--------------------------------------------------------------------------------
1 | """
2 | Copyright (c) 2015-2018 Nitrokey UG
3 |
4 | This file is part of libnitrokey.
5 |
6 | libnitrokey is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU Lesser General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | any later version.
10 |
11 | libnitrokey is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU Lesser General Public License
17 | along with libnitrokey. If not, see .
18 |
19 | SPDX-License-Identifier: LGPL-3.0
20 | """
21 |
22 | import pytest
23 |
24 | from misc import ffi, gs, to_hex, is_pro_rtm_07, is_long_OTP_secret_handled
25 | from constants import DefaultPasswords, DeviceErrorCode, RFC_SECRET, LibraryErrors, bbRFC_SECRET
26 |
27 |
28 | def test_too_long_strings(C):
29 | new_password = b'123123123'
30 | long_string = b'a' * 100
31 | assert C.NK_change_user_PIN(long_string, new_password) == LibraryErrors.TOO_LONG_STRING
32 | assert C.NK_change_user_PIN(new_password, long_string) == LibraryErrors.TOO_LONG_STRING
33 | assert C.NK_change_admin_PIN(long_string, new_password) == LibraryErrors.TOO_LONG_STRING
34 | assert C.NK_change_admin_PIN(new_password, long_string) == LibraryErrors.TOO_LONG_STRING
35 | assert C.NK_first_authenticate(long_string, DefaultPasswords.ADMIN_TEMP) == LibraryErrors.TOO_LONG_STRING
36 | assert C.NK_erase_totp_slot(0, long_string) == LibraryErrors.TOO_LONG_STRING
37 | digits = False
38 | assert C.NK_write_hotp_slot(1, long_string, bbRFC_SECRET, 0, digits, False, False, b"",
39 | DefaultPasswords.ADMIN_TEMP) == LibraryErrors.TOO_LONG_STRING
40 | assert C.NK_write_hotp_slot(1, b'long_test', bbRFC_SECRET, 0, digits, False, False, b"",
41 | long_string) == LibraryErrors.TOO_LONG_STRING
42 | assert gs(C.NK_get_hotp_code_PIN(0, long_string)) == b""
43 | assert C.NK_get_last_command_status() == LibraryErrors.TOO_LONG_STRING
44 | assert C.NK_change_firmware_password_pro(long_string, long_string) == LibraryErrors.TOO_LONG_STRING
45 | assert C.NK_change_firmware_password_pro(DefaultPasswords.UPDATE, long_string) == LibraryErrors.TOO_LONG_STRING
46 |
47 |
48 | def test_invalid_slot(C):
49 | invalid_slot = 255
50 | assert C.NK_erase_totp_slot(invalid_slot, b'some password') == LibraryErrors.INVALID_SLOT
51 | assert C.NK_write_hotp_slot(invalid_slot, b'long_test', bbRFC_SECRET, 0, False, False, False, b"",
52 | b'aaa') == LibraryErrors.INVALID_SLOT
53 | assert gs(C.NK_get_hotp_code_PIN(invalid_slot, b'some password')) == b""
54 | assert C.NK_get_last_command_status() == LibraryErrors.INVALID_SLOT
55 | assert C.NK_erase_password_safe_slot(invalid_slot) == LibraryErrors.INVALID_SLOT
56 | assert C.NK_enable_password_safe(DefaultPasswords.USER) == DeviceErrorCode.STATUS_OK
57 | assert gs(C.NK_get_password_safe_slot_name(invalid_slot)) == b''
58 | assert C.NK_get_last_command_status() == LibraryErrors.INVALID_SLOT
59 | assert gs(C.NK_get_password_safe_slot_login(invalid_slot)) == b''
60 | assert C.NK_get_last_command_status() == LibraryErrors.INVALID_SLOT
61 |
62 |
63 | @pytest.mark.parametrize("invalid_hex_string",
64 | ['text', '00 ', '0xff', 'zzzzzzzzzzzz', 'fff', 'f' * 257, 'f' * 258])
65 | def test_invalid_secret_hex_string_for_OTP_write(C, invalid_hex_string):
66 | """
67 | Tests for invalid secret hex string during writing to OTP slot. Invalid strings are not hexadecimal number,
68 | empty or longer than 255 characters.
69 | """
70 | invalid_hex_string = invalid_hex_string.encode('ascii')
71 | assert C.NK_first_authenticate(DefaultPasswords.ADMIN, DefaultPasswords.ADMIN_TEMP) == DeviceErrorCode.STATUS_OK
72 | assert C.NK_write_hotp_slot(1, b'slot_name', invalid_hex_string, 0, True, False, False, b'',
73 | DefaultPasswords.ADMIN_TEMP) == LibraryErrors.INVALID_HEX_STRING
74 | assert C.NK_write_totp_slot(1, b'python_test', invalid_hex_string, 30, True, False, False, b"",
75 | DefaultPasswords.ADMIN_TEMP) == LibraryErrors.INVALID_HEX_STRING
76 |
77 | def test_warning_binary_bigger_than_secret_buffer(C):
78 | invalid_hex_string = to_hex('1234567890') * 3
79 | invalid_hex_string = invalid_hex_string.encode('ascii')
80 | if is_long_OTP_secret_handled(C):
81 | invalid_hex_string *= 2
82 | assert C.NK_write_hotp_slot(1, b'slot_name', invalid_hex_string, 0, True, False, False, b'',
83 | DefaultPasswords.ADMIN_TEMP) == LibraryErrors.TARGET_BUFFER_SIZE_SMALLER_THAN_SOURCE
84 |
85 |
86 | @pytest.mark.skip(reason='Experimental')
87 | def test_clear(C):
88 | d = 'asdasdasd'
89 | print(d)
90 | C.clear_password(d)
91 | print(d)
--------------------------------------------------------------------------------
/unittest/test_memory.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2020 Nitrokey UG
3 | *
4 | * This file is part of libnitrokey.
5 | *
6 | * libnitrokey is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU Lesser General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * any later version.
10 | *
11 | * libnitrokey is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU Lesser General Public License
17 | * along with libnitrokey. If not, see .
18 | *
19 | * SPDX-License-Identifier: LGPL-3.0
20 | */
21 |
22 | #include
23 | #include "../NK_C_API.h"
24 |
25 | // This test should be run with valgrind to make sure that there are no
26 | // memory leaks in the tested functions:
27 | // valgrind ./test_memory
28 | int main() {
29 | int result = NK_login_auto();
30 | if (result != 1)
31 | return 1;
32 |
33 | int retry_count = NK_get_admin_retry_count();
34 | if (retry_count != 3)
35 | return 1;
36 | retry_count = NK_get_user_retry_count();
37 | if (retry_count != 3)
38 | return 1;
39 |
40 | enum NK_device_model model = NK_get_device_model();
41 | if (model != NK_PRO && model != NK_STORAGE)
42 | return 1;
43 |
44 | uint8_t *config = NK_read_config();
45 | if (config == NULL)
46 | return 1;
47 | NK_free_config(config);
48 |
49 | result = NK_enable_password_safe("123456");
50 | if (result != 0)
51 | return 1;
52 |
53 | uint8_t *slot_status = NK_get_password_safe_slot_status();
54 | if (slot_status == NULL) {
55 | return 1;
56 | }
57 | NK_free_password_safe_slot_status(slot_status);
58 |
59 | NK_logout();
60 |
61 | return 0;
62 | }
63 |
64 |
--------------------------------------------------------------------------------
/unittest/test_minimal.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018 Nitrokey UG
3 | *
4 | * This file is part of libnitrokey.
5 | *
6 | * libnitrokey is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU Lesser General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * any later version.
10 | *
11 | * libnitrokey is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU Lesser General Public License
17 | * along with libnitrokey. If not, see .
18 | *
19 | * SPDX-License-Identifier: LGPL-3.0
20 | */
21 |
22 | #include "../NK_C_API.h"
23 |
24 | // This test is only intended to make sure that the C API header can be
25 | // compiled by a C compiler. (All other tests are written in C++.)
26 | int main() {
27 | return 0;
28 | }
29 |
--------------------------------------------------------------------------------
/unittest/test_multiple.py:
--------------------------------------------------------------------------------
1 | """
2 | Copyright (c) 2017-2018 Nitrokey UG
3 |
4 | This file is part of libnitrokey.
5 |
6 | libnitrokey is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU Lesser General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | any later version.
10 |
11 | libnitrokey is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU Lesser General Public License
17 | along with libnitrokey. If not, see .
18 |
19 | SPDX-License-Identifier: LGPL-3.0
20 | """
21 |
22 | import pprint
23 | from time import sleep
24 |
25 | import pytest
26 | from collections import defaultdict
27 |
28 | from tqdm import tqdm
29 |
30 | from conftest import skip_if_device_version_lower_than
31 | from constants import DefaultPasswords, DeviceErrorCode
32 | from misc import gs, wait, ffi, bb
33 |
34 | pprint = pprint.PrettyPrinter(indent=4).pprint
35 |
36 |
37 | @pytest.mark.other
38 | @pytest.mark.info
39 | def test_list_devices(C):
40 | infos = C.NK_list_devices()
41 | assert infos != ffi.NULL
42 | C.NK_free_device_info(infos)
43 |
44 |
45 | @pytest.mark.other
46 | @pytest.mark.info
47 | def test_connect_with_path(C):
48 | ids = gs(C.NK_list_devices_by_cpuID())
49 | # NK_list_devices_by_cpuID already opened the devices, so we have to close
50 | # them before trying to reconnect
51 | assert C.NK_logout() == 0
52 |
53 | devices_list = ids.split(b';')
54 | for value in devices_list:
55 | parts = value.split(b'_p_')
56 | assert len(parts) < 3
57 | if len(parts) == 2:
58 | path = parts[1]
59 | else:
60 | path = parts[0]
61 | assert C.NK_connect_with_path(path) == 1
62 |
63 |
64 | @pytest.mark.other
65 | @pytest.mark.info
66 | def test_get_status_storage_multiple(C):
67 | ids = gs(C.NK_list_devices_by_cpuID())
68 | print(ids)
69 | devices_list = ids.split(b';')
70 | #
71 | # for s in devices_list:
72 | # res = C.NK_connect_with_ID(s)
73 | # assert res == 1
74 | # # st = gs(C.NK_get_status_storage_as_string())
75 | # # print(len(st))
76 | # C.NK_lock_device()
77 | #
78 | for s in devices_list:
79 | res = C.NK_connect_with_ID(s)
80 | assert res == 1
81 | v = C.NK_fill_SD_card_with_random_data(b'12345678')
82 | # print(v)
83 |
84 | devices_count = len(devices_list)
85 | assert devices_count != 0
86 | b = 0
87 |
88 | last_b = 0
89 | with tqdm(total=devices_count*100) as pbar:
90 | while b/devices_count < 100:
91 | pbar.update(b - last_b)
92 |
93 | b = defaultdict (lambda: 0)
94 |
95 | ids = gs(C.NK_list_devices_by_cpuID())
96 | devices_list = ids.split(b';')
97 | devices_count = len(devices_list)
98 |
99 | for s in devices_list:
100 | res = C.NK_connect_with_ID(s)
101 | if res != 1: continue
102 | b[s] += C.NK_get_progress_bar_value()
103 | print(b)
104 | b = sum(b.values())
105 | print('{}: {}'.format(b, int(b/devices_count) * '='))
106 | sleep(5)
107 |
108 |
109 |
--------------------------------------------------------------------------------
/unittest/test_multiple_devices.cc:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2017-2018 Nitrokey UG
3 | *
4 | * This file is part of libnitrokey.
5 | *
6 | * libnitrokey is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU Lesser General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * any later version.
10 | *
11 | * libnitrokey is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU Lesser General Public License
17 | * along with libnitrokey. If not, see .
18 | *
19 | * SPDX-License-Identifier: LGPL-3.0
20 | */
21 |
22 | static const char *const default_admin_pin = "12345678";
23 | static const char *const default_user_pin = "123456";
24 | const char * temporary_password = "123456789012345678901234";
25 | const char * RFC_SECRET = "12345678901234567890";
26 |
27 | #include "catch2/catch.hpp"
28 |
29 | #include
30 | #include
31 | #include
32 | #include "../NK_C_API.h"
33 |
34 | using namespace nitrokey;
35 |
36 |
37 | TEST_CASE("List devices", "[BASIC]") {
38 | auto v = Device::enumerate();
39 | REQUIRE(v.size() > 0);
40 | for (auto i : v){
41 | auto d = Device::create(i.m_deviceModel);
42 | if (!d) {
43 | std::cout << "Could not create device with model " << i.m_deviceModel << "\n";
44 | continue;
45 | }
46 | std::cout << i.m_deviceModel << " " << i.m_path << " "
47 | << i.m_serialNumber << " |";
48 | d->set_path(i.m_path);
49 | d->connect();
50 | auto res = GetStatus::CommandTransaction::run(d);
51 | std::cout << " " << res.data().card_serial_u32 << " "
52 | << res.data().get_card_serial_hex()
53 | << std::endl;
54 | d->disconnect();
55 | }
56 | }
57 |
58 | TEST_CASE("List Storage devices", "[BASIC]") {
59 | shared_ptr d = make_shared();
60 | auto v = Device::enumerate();
61 | REQUIRE(v.size() > 0);
62 | for (auto i : v){
63 | if (i.m_deviceModel != DeviceModel::STORAGE)
64 | continue;
65 | auto a = i.m_path;
66 | std::cout << a;
67 | d->set_path(a);
68 | d->connect();
69 | auto res = GetStatus::CommandTransaction::run(d);
70 | auto res2 = GetDeviceStatus::CommandTransaction::run(d);
71 | std::cout << " " << res.data().card_serial_u32 << " "
72 | << res.data().get_card_serial_hex()
73 | << " " << std::to_string(res2.data().versionInfo.minor)
74 | << std::endl;
75 | d->disconnect();
76 | }
77 | }
78 |
79 | TEST_CASE("Regenerate AES keys", "[BASIC]") {
80 | shared_ptr d = make_shared();
81 | auto v = Device::enumerate();
82 | REQUIRE(v.size() > 0);
83 |
84 | std::vector> devices;
85 | for (auto i : v){
86 | if (i.m_deviceModel != DeviceModel::STORAGE)
87 | continue;
88 | auto a = i.m_path;
89 | std::cout << a << endl;
90 | d = make_shared();
91 | d->set_path(a);
92 | d->connect();
93 | devices.push_back(d);
94 | }
95 |
96 | for (auto d : devices){
97 | auto res2 = GetDeviceStatus::CommandTransaction::run(d);
98 | std::cout << std::to_string(res2.data().versionInfo.minor) << std::endl;
99 | // nitrokey::proto::stick20::CreateNewKeys::CommandPayload p;
100 | // p.set_defaults();
101 | // memcpy(p.password, "12345678", 8);
102 | // auto res3 = nitrokey::proto::stick20::CreateNewKeys::CommandTransaction::run(d, p);
103 | }
104 |
105 | for (auto d : devices){
106 | //TODO watch out for multiple hid_exit calls
107 | d->disconnect();
108 | }
109 | }
110 |
111 |
112 | TEST_CASE("Use C API", "[BASIC]") {
113 | auto ptr = NK_list_devices();
114 | auto first_ptr = ptr;
115 | REQUIRE(ptr != nullptr);
116 |
117 | while (ptr) {
118 | std::cout << "Connect with: " << ptr->model << " " << ptr->path << " "
119 | << ptr->serial_number << " | " << NK_connect_with_path(ptr->path) << " | ";
120 | auto status = NK_get_status_as_string();
121 | std::cout << status << std::endl;
122 | free(status);
123 | ptr = ptr->next;
124 | }
125 |
126 | NK_free_device_info(first_ptr);
127 | }
128 |
129 |
130 | TEST_CASE("Use API", "[BASIC]") {
131 | auto nm = NitrokeyManager::instance();
132 | nm->set_loglevel(2);
133 | auto v = nm->list_devices();
134 | REQUIRE(v.size() > 0);
135 |
136 | for (auto i : v) {
137 | std::cout << "Connect with: " << i.m_deviceModel << " " << i.m_path << " "
138 | << i.m_serialNumber << " | " << std::boolalpha << nm->connect_with_path(i.m_path) << " |";
139 | try {
140 | auto status = nm->get_status();
141 | std::cout << " " << status.card_serial_u32 << " "
142 | << status.get_card_serial_hex()
143 | << std::endl;
144 | } catch (const LongOperationInProgressException &e) {
145 | std::cout << "long operation in progress on " << i.m_path
146 | << " " << std::to_string(e.progress_bar_value) << std::endl;
147 | }
148 | }
149 | }
150 |
151 |
152 | TEST_CASE("Use Storage API", "[BASIC]") {
153 | auto nm = NitrokeyManager::instance();
154 | nm->set_loglevel(2);
155 | auto v = nm->list_devices();
156 | REQUIRE(v.size() > 0);
157 |
158 | for (int i=0; i<10; i++){
159 | for (auto i : v) {
160 | if (i.m_deviceModel != DeviceModel::STORAGE)
161 | continue;
162 | auto a = i.m_path;
163 | std::cout <<"Connect with: " << a <<
164 | " " << std::boolalpha << nm->connect_with_path(a) << " ";
165 | try{
166 | auto status_storage = nm->get_status_storage();
167 | std::cout << status_storage.ActiveSmartCardID_u32
168 | << " " << status_storage.ActiveSD_CardID_u32
169 | << std::endl;
170 |
171 | // nm->fill_SD_card_with_random_data("12345678");
172 | }
173 | catch (const LongOperationInProgressException &e){
174 | std::cout << "long operation in progress on " << a
175 | << " " << std::to_string(e.progress_bar_value) << std::endl;
176 | // this_thread::sleep_for(1000ms);
177 | }
178 | }
179 | std::cout <<"Iteration: " << i << std::endl;
180 | }
181 |
182 | }
183 |
184 |
185 | TEST_CASE("Use API ID", "[BASIC]") {
186 | auto nm = NitrokeyManager::instance();
187 | nm->set_loglevel(2);
188 |
189 | auto v = nm->list_devices_by_cpuID();
190 | REQUIRE(v.size() > 0);
191 |
192 | //no refresh - should not reconnect to new devices
193 | // Scenario:
194 | // 1. Run test
195 | // 2. Remove one of the devices and reinsert it after a while
196 | // 3. Device should not be reconnected and test should not crash
197 | // 4. Remove all devices - test should continue
198 |
199 | for (int j = 0; j < 100; j++) {
200 | for (auto i : v) {
201 | if (!nm->connect_with_ID(i)) continue;
202 | int retry_count = 99;
203 | try {
204 | retry_count = nm->get_admin_retry_count();
205 | std::cout << j << " " << i << " " << to_string(retry_count) << std::endl;
206 | }
207 | catch (...) {
208 | retry_count = 99;
209 | //pass
210 | }
211 | }
212 | }
213 | std::cout << "finished" << std::endl;
214 | }
215 |
216 | TEST_CASE("Use API ID refresh", "[BASIC]") {
217 | auto nm = NitrokeyManager::instance();
218 | nm->set_loglevel(2);
219 |
220 | //refresh in each iteration - should reconnect to new devices
221 | // Scenario:
222 | // 1. Run test
223 | // 2. Remove one of the devices and reinsert it after a while
224 | // 3. Device should be reconnected
225 |
226 | for(int j=0; j<100; j++) {
227 | auto v = nm->list_devices_by_cpuID();
228 | REQUIRE(v.size() > 0);
229 | for (auto i : v) {
230 | nm->connect_with_ID(i);
231 | int retry_count = 99;
232 | try {
233 | retry_count = nm->get_admin_retry_count();
234 | std::cout << j <<" " << i << " " << to_string(retry_count) << std::endl;
235 | }
236 | catch (...){
237 | retry_count = 99;
238 | //pass
239 | }
240 | }
241 | }
242 | std::cout << "finished" << std::endl;
243 | }
244 |
--------------------------------------------------------------------------------
/unittest/test_offline.cc:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2015-2018 Nitrokey UG
3 | *
4 | * This file is part of libnitrokey.
5 | *
6 | * libnitrokey is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU Lesser General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * any later version.
10 | *
11 | * libnitrokey is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU Lesser General Public License
17 | * along with libnitrokey. If not, see .
18 | *
19 | * SPDX-License-Identifier: LGPL-3.0
20 | */
21 |
22 | #include "catch2/catch.hpp"
23 | #include
24 | #include
25 | #include
26 | #include
27 | #include "../NK_C_API.h"
28 |
29 | using namespace nitrokey::proto;
30 | using namespace nitrokey::device;
31 |
32 | using namespace std;
33 | using namespace nitrokey;
34 |
35 | //This test suite assumes no Pro or Storage devices are connected
36 |
37 | TEST_CASE("Return false on no device connected", "[fast]") {
38 | INFO("This test case assumes no Pro or Storage devices are connected");
39 | auto stick = make_shared();
40 | bool connected = true;
41 | REQUIRE_NOTHROW(connected = stick->connect());
42 | REQUIRE_FALSE(connected);
43 |
44 | auto stick_pro = make_shared();
45 | REQUIRE_NOTHROW(connected = stick_pro->connect());
46 | REQUIRE_FALSE(connected);
47 |
48 |
49 | auto i = NitrokeyManager::instance();
50 | REQUIRE_NOTHROW(connected = i->connect());
51 | REQUIRE_FALSE(connected);
52 | REQUIRE_FALSE(i->is_connected());
53 | REQUIRE_FALSE(i->disconnect());
54 | REQUIRE_FALSE(i->could_current_device_be_enumerated());
55 |
56 |
57 | int C_connected = 1;
58 | REQUIRE_NOTHROW(C_connected = NK_login_auto());
59 | REQUIRE(0 == C_connected);
60 | }
61 |
62 | TEST_CASE("Test C++ side behaviour in offline", "[fast]") {
63 | auto i = NitrokeyManager::instance();
64 |
65 | string serial_number;
66 | REQUIRE_NOTHROW (serial_number = i->get_serial_number());
67 | REQUIRE(serial_number.empty());
68 |
69 | REQUIRE_THROWS_AS(
70 | i->get_serial_number_as_u32(), DeviceNotConnected
71 | );
72 |
73 | REQUIRE_THROWS_AS(
74 | i->get_status(), DeviceNotConnected
75 | );
76 |
77 | REQUIRE_THROWS_AS(
78 | i->get_HOTP_code(0xFF, ""), InvalidSlotException
79 | );
80 |
81 | REQUIRE_THROWS_AS(
82 | i->get_TOTP_code(0xFF, ""), InvalidSlotException
83 | );
84 |
85 | REQUIRE_THROWS_AS(
86 | i->erase_hotp_slot(0xFF, ""), InvalidSlotException
87 | );
88 |
89 | REQUIRE_THROWS_AS(
90 | i->erase_totp_slot(0xFF, ""), InvalidSlotException
91 | );
92 |
93 | REQUIRE_THROWS_AS(
94 | i->get_totp_slot_name(0xFF), InvalidSlotException
95 | );
96 |
97 | REQUIRE_THROWS_AS(
98 | i->get_hotp_slot_name(0xFF), InvalidSlotException
99 | );
100 |
101 | REQUIRE_THROWS_AS(
102 | i->first_authenticate("123123", "123123"), DeviceNotConnected
103 | );
104 |
105 | REQUIRE_THROWS_AS(
106 | i->get_connected_device_model(), DeviceNotConnected
107 | );
108 |
109 | REQUIRE_THROWS_AS(
110 | i->clear_new_sd_card_warning("123123"), DeviceNotConnected
111 | );
112 |
113 | }
114 |
115 |
116 | TEST_CASE("Test helper function - hex_string_to_byte", "[fast]") {
117 | using namespace nitrokey::misc;
118 | std::vector v;
119 | REQUIRE_NOTHROW(v = hex_string_to_byte("00112233445566"));
120 | const uint8_t test_data[] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66};
121 | REQUIRE(v.size() == sizeof(test_data));
122 | for (size_t i = 0; i < v.size(); ++i) {
123 | INFO("Position i: " << i);
124 | REQUIRE(v[i] == test_data[i]);
125 | }
126 | }
127 |
128 | #include "test_command_ids_header.h"
129 | TEST_CASE("Test device commands ids", "[fast]") {
130 | // Make sure CommandID values are in sync with firmware's header
131 |
132 | // REQUIRE(STICK20_CMD_START_VALUE == static_cast(CommandID::START_VALUE));
133 | REQUIRE(STICK20_CMD_ENABLE_CRYPTED_PARI == static_cast(CommandID::ENABLE_CRYPTED_PARI));
134 | REQUIRE(STICK20_CMD_DISABLE_CRYPTED_PARI == static_cast(CommandID::DISABLE_CRYPTED_PARI));
135 | REQUIRE(STICK20_CMD_ENABLE_HIDDEN_CRYPTED_PARI == static_cast(CommandID::ENABLE_HIDDEN_CRYPTED_PARI));
136 | REQUIRE(STICK20_CMD_DISABLE_HIDDEN_CRYPTED_PARI == static_cast(CommandID::DISABLE_HIDDEN_CRYPTED_PARI));
137 | REQUIRE(STICK20_CMD_ENABLE_FIRMWARE_UPDATE == static_cast(CommandID::ENABLE_FIRMWARE_UPDATE));
138 | REQUIRE(STICK20_CMD_EXPORT_FIRMWARE_TO_FILE == static_cast(CommandID::EXPORT_FIRMWARE_TO_FILE));
139 | REQUIRE(STICK20_CMD_GENERATE_NEW_KEYS == static_cast(CommandID::GENERATE_NEW_KEYS));
140 | REQUIRE(STICK20_CMD_FILL_SD_CARD_WITH_RANDOM_CHARS == static_cast(CommandID::FILL_SD_CARD_WITH_RANDOM_CHARS));
141 |
142 | REQUIRE(STICK20_CMD_WRITE_STATUS_DATA == static_cast(CommandID::WRITE_STATUS_DATA));
143 | REQUIRE(STICK20_CMD_ENABLE_READONLY_UNCRYPTED_LUN == static_cast(CommandID::ENABLE_READONLY_UNCRYPTED_LUN));
144 | REQUIRE(STICK20_CMD_ENABLE_READWRITE_UNCRYPTED_LUN == static_cast(CommandID::ENABLE_READWRITE_UNCRYPTED_LUN));
145 |
146 | REQUIRE(STICK20_CMD_SEND_PASSWORD_MATRIX == static_cast(CommandID::SEND_PASSWORD_MATRIX));
147 | REQUIRE(STICK20_CMD_SEND_PASSWORD_MATRIX_PINDATA == static_cast(CommandID::SEND_PASSWORD_MATRIX_PINDATA));
148 | REQUIRE(STICK20_CMD_SEND_PASSWORD_MATRIX_SETUP == static_cast(CommandID::SEND_PASSWORD_MATRIX_SETUP));
149 |
150 | REQUIRE(STICK20_CMD_GET_DEVICE_STATUS == static_cast(CommandID::GET_DEVICE_STATUS));
151 | REQUIRE(STICK20_CMD_SEND_DEVICE_STATUS == static_cast(CommandID::SEND_DEVICE_STATUS));
152 |
153 | REQUIRE(STICK20_CMD_SEND_HIDDEN_VOLUME_PASSWORD == static_cast(CommandID::SEND_HIDDEN_VOLUME_PASSWORD));
154 | REQUIRE(STICK20_CMD_SEND_HIDDEN_VOLUME_SETUP == static_cast(CommandID::SEND_HIDDEN_VOLUME_SETUP));
155 | REQUIRE(STICK20_CMD_SEND_PASSWORD == static_cast(CommandID::SEND_PASSWORD));
156 | REQUIRE(STICK20_CMD_SEND_NEW_PASSWORD == static_cast(CommandID::SEND_NEW_PASSWORD));
157 | REQUIRE(STICK20_CMD_CLEAR_NEW_SD_CARD_FOUND == static_cast(CommandID::CLEAR_NEW_SD_CARD_FOUND));
158 |
159 | REQUIRE(STICK20_CMD_SEND_STARTUP == static_cast(CommandID::SEND_STARTUP));
160 | REQUIRE(STICK20_CMD_SEND_CLEAR_STICK_KEYS_NOT_INITIATED == static_cast(CommandID::SEND_CLEAR_STICK_KEYS_NOT_INITIATED));
161 | REQUIRE(STICK20_CMD_SEND_LOCK_STICK_HARDWARE == static_cast(CommandID::SEND_LOCK_STICK_HARDWARE));
162 |
163 | REQUIRE(STICK20_CMD_PRODUCTION_TEST == static_cast(CommandID::PRODUCTION_TEST));
164 | REQUIRE(STICK20_CMD_SEND_DEBUG_DATA == static_cast(CommandID::SEND_DEBUG_DATA));
165 |
166 | REQUIRE(STICK20_CMD_CHANGE_UPDATE_PIN == static_cast(CommandID::CHANGE_UPDATE_PIN));
167 |
168 | }
169 |
170 | #include "version.h"
171 | TEST_CASE("Test version getter", "[fast]") {
172 | REQUIRE(nitrokey::get_major_library_version() >= 3u);
173 | REQUIRE(nitrokey::get_minor_library_version() >= 3u);
174 | const char *library_version = nitrokey::get_library_version();
175 | REQUIRE(library_version != nullptr);
176 | CAPTURE(library_version);
177 |
178 | // The library version has to match the pattern returned by git describe:
179 | // v. or v.--g, where is the number
180 | // of commits since the last tag, and is the hash of the current
181 | // commit. (This assumes that all tags have the name v..).
182 | // Optional field is allowed as well.
183 | INFO("This test will fail, if the full git commit version was not collected during library build.");
184 | std::string s = library_version;
185 | std::string version("(pre-)?v[0-9]+\\.[0-9]+(\\.[0-9]+)?");
186 | std::string git_suffix("(-[0-9]+)+-g[0-9a-z]+");
187 | std::regex pattern(version + "(" + git_suffix + ")?");
188 | REQUIRE(std::regex_match(s, pattern));
189 | }
190 |
191 | TEST_CASE("Connect should not return true after the second attempt", "[fast]") {
192 | int result = 0;
193 |
194 | result = NK_login("S");
195 | REQUIRE(result == 0);
196 |
197 | result = NK_login_auto();
198 | REQUIRE(result == 0);
199 |
200 | result = NK_logout();
201 | REQUIRE(result == 0);
202 |
203 | result = NK_logout();
204 | REQUIRE(result == 0);
205 |
206 | result = NK_login("P");
207 | REQUIRE(result == 0);
208 |
209 | result = NK_login_auto();
210 | REQUIRE(result == 0);
211 |
212 | result = NK_logout();
213 | REQUIRE(result == 0);
214 | }
215 |
--------------------------------------------------------------------------------
/unittest/test_offline.py:
--------------------------------------------------------------------------------
1 | """
2 | Copyright (c) 2019 Nitrokey UG
3 |
4 | This file is part of libnitrokey.
5 |
6 | libnitrokey is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU Lesser General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | any later version.
10 |
11 | libnitrokey is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU Lesser General Public License
17 | along with libnitrokey. If not, see .
18 |
19 | SPDX-License-Identifier: LGPL-3.0
20 | """
21 |
22 | from misc import gs
23 | import re
24 |
25 |
26 | def test_offline(C_offline):
27 | C_offline.NK_set_debug(False)
28 | C_offline.NK_set_debug_level(4)
29 | assert C_offline.NK_get_major_library_version() == 3
30 | assert C_offline.NK_get_minor_library_version() >= 3
31 | assert C_offline.NK_login_auto() == 0
32 |
33 | libnk_version = gs(C_offline.NK_get_library_version())
34 | assert libnk_version
35 | print(libnk_version)
36 |
37 | # v3.4.1-29-g1f3d
38 | search = re.search(b'v\d\.\d(\.\d)?', libnk_version)
39 | assert search is not None
--------------------------------------------------------------------------------
/unittest/test_pro_bootloader.py:
--------------------------------------------------------------------------------
1 | import pytest
2 |
3 | from conftest import skip_if_device_version_lower_than, library_device_reconnect
4 | from constants import DefaultPasswords, DeviceErrorCode, LibraryErrors
5 | from helpers import helper_populate_device, helper_check_device_for_data
6 |
7 |
8 | @pytest.mark.firmware
9 | def test_bootloader_password_change_pro_length(C):
10 | skip_if_device_version_lower_than({'P': 11})
11 |
12 | # Test whether the correct password is set
13 | assert C.NK_change_firmware_password_pro(DefaultPasswords.UPDATE, DefaultPasswords.UPDATE) == DeviceErrorCode.STATUS_OK
14 | # Change to the longest possible password
15 | assert C.NK_change_firmware_password_pro(DefaultPasswords.UPDATE, DefaultPasswords.UPDATE_LONG) == DeviceErrorCode.STATUS_OK
16 | assert C.NK_change_firmware_password_pro(DefaultPasswords.UPDATE_LONG, DefaultPasswords.UPDATE) == DeviceErrorCode.STATUS_OK
17 | # Use longer or shorter passwords than possible
18 | assert C.NK_change_firmware_password_pro(DefaultPasswords.UPDATE, DefaultPasswords.UPDATE_TOO_LONG) == LibraryErrors.TOO_LONG_STRING
19 | assert C.NK_change_firmware_password_pro(DefaultPasswords.UPDATE, DefaultPasswords.UPDATE_TOO_SHORT) == DeviceErrorCode.WRONG_PASSWORD
20 |
21 |
22 |
23 | @pytest.mark.firmware
24 | def test_bootloader_password_change_pro(C):
25 | skip_if_device_version_lower_than({'P': 11})
26 | assert C.NK_change_firmware_password_pro(b'zxcasd', b'zxcasd') == DeviceErrorCode.WRONG_PASSWORD
27 |
28 | # Revert effects of broken test run, if needed
29 | C.NK_change_firmware_password_pro(DefaultPasswords.UPDATE_TEMP, DefaultPasswords.UPDATE)
30 |
31 | # Change to the same password
32 | assert C.NK_change_firmware_password_pro(DefaultPasswords.UPDATE, DefaultPasswords.UPDATE) == DeviceErrorCode.STATUS_OK
33 | assert C.NK_change_firmware_password_pro(DefaultPasswords.UPDATE, DefaultPasswords.UPDATE) == DeviceErrorCode.STATUS_OK
34 | # Change password
35 | assert C.NK_change_firmware_password_pro(DefaultPasswords.UPDATE, DefaultPasswords.UPDATE_TEMP) == DeviceErrorCode.STATUS_OK
36 | assert C.NK_change_firmware_password_pro(DefaultPasswords.UPDATE_TEMP, DefaultPasswords.UPDATE) == DeviceErrorCode.STATUS_OK
37 |
38 |
39 | @pytest.mark.firmware
40 | def test_bootloader_run_pro_wrong_password(C):
41 | skip_if_device_version_lower_than({'P': 11})
42 | assert C.NK_enable_firmware_update_pro(DefaultPasswords.UPDATE_TEMP) == DeviceErrorCode.WRONG_PASSWORD
43 |
44 |
45 | @pytest.mark.skip_by_default
46 | @pytest.mark.firmware
47 | def test_bootloader_run_pro_real(C):
48 | skip_if_device_version_lower_than({'P': 11})
49 | # Not enabled due to lack of side-effect removal at this point
50 | assert C.NK_enable_firmware_update_pro(DefaultPasswords.UPDATE) == DeviceErrorCode.STATUS_DISCONNECTED
51 |
52 |
53 | @pytest.mark.firmware
54 | def test_bootloader_password_change_pro_too_long(C):
55 | skip_if_device_version_lower_than({'P': 11})
56 | long_string = b'a' * 100
57 | assert C.NK_change_firmware_password_pro(long_string, long_string) == LibraryErrors.TOO_LONG_STRING
58 | assert C.NK_change_firmware_password_pro(DefaultPasswords.UPDATE, long_string) == LibraryErrors.TOO_LONG_STRING
59 |
60 |
61 | @pytest.mark.skip_by_default
62 | @pytest.mark.firmware
63 | def test_bootloader_data_retention(C):
64 | skip_if_device_version_lower_than({'P': 11})
65 | # Not enabled due to lack of side-effect removal at this point
66 |
67 | assert helper_populate_device(C)
68 | assert C.NK_enable_firmware_update_pro(DefaultPasswords.UPDATE) == DeviceErrorCode.STATUS_DISCONNECTED
69 | input('Please press ENTER after uploading new firmware to the device')
70 | C = library_device_reconnect(C)
71 | assert helper_check_device_for_data(C)
72 |
73 |
74 | @pytest.mark.firmware
75 | def test_factory_reset_does_not_change_update_password(C):
76 | """
77 | Check if factory reset changes the update password, which should not happen
78 | """
79 | skip_if_device_version_lower_than({'P': 13})
80 | from test_pro import test_factory_reset
81 | # Revert effects of a broken test run, if needed
82 | C.NK_change_firmware_password_pro(DefaultPasswords.UPDATE_TEMP, DefaultPasswords.UPDATE)
83 |
84 | # actual test
85 | assert C.NK_change_firmware_password_pro(DefaultPasswords.UPDATE, DefaultPasswords.UPDATE_TEMP) == DeviceErrorCode.STATUS_OK
86 | test_factory_reset(C)
87 | assert C.NK_change_firmware_password_pro(DefaultPasswords.UPDATE, DefaultPasswords.UPDATE_TEMP) == DeviceErrorCode.WRONG_PASSWORD
88 | assert C.NK_change_firmware_password_pro(DefaultPasswords.UPDATE_TEMP, DefaultPasswords.UPDATE) == DeviceErrorCode.STATUS_OK
89 |
90 |
--------------------------------------------------------------------------------
/unittest/test_safe.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2019 Nitrokey UG
3 | *
4 | * This file is part of libnitrokey.
5 | *
6 | * libnitrokey is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU Lesser General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * any later version.
10 | *
11 | * libnitrokey is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU Lesser General Public License
17 | * along with libnitrokey. If not, see .
18 | *
19 | * SPDX-License-Identifier: LGPL-3.0
20 | */
21 |
22 | #include "catch2/catch.hpp"
23 |
24 | #include
25 | #include
26 | #include "log.h"
27 | #include "../NK_C_API.h"
28 |
29 | int login;
30 |
31 | TEST_CASE("C API connect", "[BASIC]") {
32 | INFO("This test set assumes either Pro or Storage device is connected.");
33 | INFO("Here should be implemented only tests not changing the device's state, "
34 | "and safe to user data.");
35 |
36 | login = NK_login_auto();
37 | REQUIRE(login != 0);
38 | NK_set_debug_level(3);
39 | }
40 |
41 | TEST_CASE("Check retry count", "[BASIC]") {
42 | INFO("This test assumes your PINs' attempt counters are set to 3");
43 | REQUIRE(login != 0);
44 | REQUIRE(NK_get_admin_retry_count() == 3);
45 | REQUIRE(NK_get_user_retry_count() == 3);
46 | }
47 |
48 | void validate_cstring(char *s){
49 | constexpr uint16_t max_length = 8*1024;
50 | REQUIRE(s != nullptr);
51 | REQUIRE(strnlen(s, max_length) > 0);
52 | REQUIRE(strnlen(s, max_length) < max_length);
53 | std::cout << s << std::endl;
54 | }
55 |
56 | TEST_CASE("Status command for Pro or Storage", "[BASIC]") {
57 | REQUIRE(login != 0);
58 | char* s = nullptr;
59 |
60 | auto const m = NK_get_device_model();
61 | REQUIRE(m != NK_DISCONNECTED);
62 | if (m == NK_PRO)
63 | s = NK_get_status_as_string();
64 | else if (m == NK_STORAGE){
65 | s = NK_get_status_storage_as_string();
66 | }
67 |
68 | validate_cstring(s);
69 | free(s);
70 | s = nullptr;
71 | }
72 |
73 | TEST_CASE("Device serial", "[BASIC]") {
74 | REQUIRE(login != 0);
75 | char* s = nullptr;
76 | s = NK_device_serial_number();
77 | validate_cstring(s);
78 | free(s);
79 | s = nullptr;
80 | }
81 |
82 | TEST_CASE("Firmware version", "[BASIC]") {
83 | REQUIRE(login != 0);
84 | // Currently all devices has major version '0'
85 | // No firmware ever had a minor equal to '0'
86 | REQUIRE(NK_get_major_firmware_version() == 0);
87 | REQUIRE(NK_get_minor_firmware_version() != 0);
88 | }
89 |
90 | TEST_CASE("Library version", "[BASIC]") {
91 | REQUIRE(NK_get_major_library_version() == 3);
92 | REQUIRE(NK_get_minor_library_version() >= 4);
93 | }
94 |
--------------------------------------------------------------------------------
/unittest/test_strdup.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2015-2018 Nitrokey UG
3 | *
4 | * This file is part of libnitrokey.
5 | *
6 | * libnitrokey is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU Lesser General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * any later version.
10 | *
11 | * libnitrokey is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU Lesser General Public License
17 | * along with libnitrokey. If not, see .
18 | *
19 | * SPDX-License-Identifier: LGPL-3.0
20 | */
21 |
22 | // issue: https://github.com/Nitrokey/libnitrokey/issues/110
23 | // tests according to the issue's author, Robin Krahl (robinkrahl)
24 | // suggested run command: valgrind --tool=memcheck --leak-check=full ./test_strdup
25 |
26 | #include
27 | #include
28 | #include "../NK_C_API.h"
29 | #include "catch2/catch.hpp"
30 |
31 |
32 | static const int SHORT_STRING_LENGTH = 10;
33 |
34 | TEST_CASE("Test strdup memory free error", "[BASIC]")
35 | {
36 | NK_set_debug(false);
37 | char *c = NK_get_status_as_string(); /* error --> string literal */
38 | REQUIRE(c != nullptr);
39 | REQUIRE(strnlen(c, SHORT_STRING_LENGTH) == 0);
40 | puts(c);
41 | free(c);
42 | }
43 |
44 | TEST_CASE("Test strdup memory leak", "[BASIC]")
45 | {
46 | NK_set_debug(false);
47 | bool connected = NK_login_auto() == 1;
48 | if (!connected) return;
49 |
50 | REQUIRE(connected);
51 | char *c = NK_get_status_as_string(); /* no error --> dynamically allocated */
52 | REQUIRE(c != nullptr);
53 | REQUIRE(strnlen(c, SHORT_STRING_LENGTH) > 0);
54 | puts(c);
55 | free(c);
56 | }
57 |
58 |
--------------------------------------------------------------------------------
/version.cc:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018 Nitrokey UG
3 | *
4 | * This file is part of libnitrokey.
5 | *
6 | * libnitrokey is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU Lesser General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * any later version.
10 | *
11 | * libnitrokey is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU Lesser General Public License
17 | * along with libnitrokey. If not, see .
18 | *
19 | * SPDX-License-Identifier: LGPL-3.0
20 | */
21 |
22 | #include "version.h"
23 |
24 | namespace nitrokey {
25 | unsigned int get_major_library_version() {
26 | #ifdef LIBNK_VERSION_MAJOR
27 | return LIBNK_VERSION_MAJOR;
28 | #endif
29 | return 3;
30 | }
31 |
32 | unsigned int get_minor_library_version() {
33 | #ifdef LIBNK_VERSION_MINOR
34 | return LIBNK_VERSION_MINOR;
35 | #endif
36 | return 0;
37 | }
38 |
39 | const char* get_library_version() {
40 | return "unknown";
41 | }
42 | }
43 |
44 |
--------------------------------------------------------------------------------
/version.cc.in:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2018 Nitrokey UG
3 | *
4 | * This file is part of libnitrokey.
5 | *
6 | * libnitrokey is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU Lesser General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * any later version.
10 | *
11 | * libnitrokey is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU Lesser General Public License
17 | * along with libnitrokey. If not, see .
18 | *
19 | * SPDX-License-Identifier: LGPL-3.0
20 | */
21 |
22 | #include "version.h"
23 |
24 | namespace nitrokey {
25 | unsigned int get_major_library_version() {
26 | return @PROJECT_VERSION_MAJOR@;
27 | }
28 |
29 | unsigned int get_minor_library_version() {
30 | return @PROJECT_VERSION_MINOR@;
31 | }
32 |
33 | const char* get_library_version() {
34 | return "@PROJECT_VERSION_GIT@";
35 | }
36 | }
37 |
38 |
--------------------------------------------------------------------------------