Merge pull request #130 from Yubico/ykpiv_util
Refactor yubico-piv-tool/libykpiv with a ykpiv_util_* high-level API
This commit is contained in:
+24
-2
@@ -7,6 +7,7 @@ autom4te.cache/
|
|||||||
config.log
|
config.log
|
||||||
config.status
|
config.status
|
||||||
configure
|
configure
|
||||||
|
doxygen-doc/
|
||||||
libtool
|
libtool
|
||||||
m4/libtool.m4
|
m4/libtool.m4
|
||||||
m4/ltoptions.m4
|
m4/ltoptions.m4
|
||||||
@@ -15,6 +16,8 @@ m4/ltversion.m4
|
|||||||
m4/lt~obsolete.m4
|
m4/lt~obsolete.m4
|
||||||
*.c~
|
*.c~
|
||||||
*.h~
|
*.h~
|
||||||
|
*.plist
|
||||||
|
.libs
|
||||||
ChangeLog
|
ChangeLog
|
||||||
build-aux/ar-lib
|
build-aux/ar-lib
|
||||||
build-aux/compile
|
build-aux/compile
|
||||||
@@ -25,6 +28,9 @@ build-aux/install-sh
|
|||||||
build-aux/ltmain.sh
|
build-aux/ltmain.sh
|
||||||
build-aux/missing
|
build-aux/missing
|
||||||
build-aux/test-driver
|
build-aux/test-driver
|
||||||
|
GPATH
|
||||||
|
GRTAGS
|
||||||
|
GTAGS
|
||||||
tmp32/
|
tmp32/
|
||||||
tmp64/
|
tmp64/
|
||||||
yubico-piv-tool-*-win32.zip
|
yubico-piv-tool-*-win32.zip
|
||||||
@@ -35,6 +41,10 @@ yubico-piv-tool-*.tar.gz
|
|||||||
yubico-piv-tool-*.tar.gz.sig
|
yubico-piv-tool-*.tar.gz.sig
|
||||||
yubico-piv-tool-*-mac.zip
|
yubico-piv-tool-*-mac.zip
|
||||||
yubico-piv-tool-*-mac.zip.sig
|
yubico-piv-tool-*-mac.zip.sig
|
||||||
|
lib/tests/api
|
||||||
|
lib/tests/api.log
|
||||||
|
lib/tests/api.o
|
||||||
|
lib/tests/api.trs
|
||||||
lib/tests/basic
|
lib/tests/basic
|
||||||
lib/tests/basic.log
|
lib/tests/basic.log
|
||||||
lib/tests/basic.o
|
lib/tests/basic.o
|
||||||
@@ -46,7 +56,13 @@ lib/tests/parse_key.trs
|
|||||||
lib/tests/test-suite.log
|
lib/tests/test-suite.log
|
||||||
lib/error.lo
|
lib/error.lo
|
||||||
lib/error.o
|
lib/error.o
|
||||||
|
lib/internal.la
|
||||||
|
lib/internal.lo
|
||||||
|
lib/internal.o
|
||||||
lib/libykpiv.la
|
lib/libykpiv.la
|
||||||
|
lib/util.la
|
||||||
|
lib/util.lo
|
||||||
|
lib/util.o
|
||||||
lib/version.lo
|
lib/version.lo
|
||||||
lib/version.o
|
lib/version.o
|
||||||
lib/ykpiv-version.h
|
lib/ykpiv-version.h
|
||||||
@@ -67,17 +83,21 @@ tool/libpiv_cmd_la-cmdline.o
|
|||||||
tool/libpiv_util.la
|
tool/libpiv_util.la
|
||||||
tool/util.lo
|
tool/util.lo
|
||||||
tool/util.o
|
tool/util.o
|
||||||
|
tool/tests/cert_9a.pem
|
||||||
|
tool/tests/cert_9e.pem
|
||||||
tool/tests/basic.sh.log
|
tool/tests/basic.sh.log
|
||||||
tool/tests/basic.sh.trs
|
tool/tests/basic.sh.trs
|
||||||
tool/tests/test-suite.log
|
tool/tests/key_9a.pub
|
||||||
tool/tests/parse_name
|
tool/tests/parse_name
|
||||||
tool/tests/parse_name.log
|
tool/tests/parse_name.log
|
||||||
tool/tests/parse_name.o
|
tool/tests/parse_name.o
|
||||||
tool/tests/parse_name.trs
|
tool/tests/parse_name.trs
|
||||||
|
tool/tests/req_9e.pem
|
||||||
tool/tests/test_inout
|
tool/tests/test_inout
|
||||||
tool/tests/test_inout.log
|
tool/tests/test_inout.log
|
||||||
tool/tests/test_inout.o
|
tool/tests/test_inout.o
|
||||||
tool/tests/test_inout.trs
|
tool/tests/test_inout.trs
|
||||||
|
tool/tests/test-suite.log
|
||||||
coverage/
|
coverage/
|
||||||
lib/error.gcno
|
lib/error.gcno
|
||||||
lib/version.gcno
|
lib/version.gcno
|
||||||
@@ -91,9 +111,11 @@ ykcs11/*.lo
|
|||||||
ykcs11/ykcs11.pc
|
ykcs11/ykcs11.pc
|
||||||
ykcs11/libykcs11.la
|
ykcs11/libykcs11.la
|
||||||
ykcs11/ykcs11-version.h
|
ykcs11/ykcs11-version.h
|
||||||
|
ykcs11/tests/reset.sh.log
|
||||||
|
ykcs11/tests/reset.sh.trs
|
||||||
|
ykcs11/tests/test-suite.log
|
||||||
ykcs11/tests/ykcs11_tests
|
ykcs11/tests/ykcs11_tests
|
||||||
ykcs11/tests/ykcs11_tests.log
|
ykcs11/tests/ykcs11_tests.log
|
||||||
ykcs11/tests/ykcs11_tests.o
|
ykcs11/tests/ykcs11_tests.o
|
||||||
ykcs11/tests/ykcs11_tests.trs
|
ykcs11/tests/ykcs11_tests.trs
|
||||||
ykcs11/tests/test-suite.log
|
|
||||||
yubico-piv-tool.1.txt
|
yubico-piv-tool.1.txt
|
||||||
|
|||||||
+8
-1
@@ -33,7 +33,6 @@ EXTRA_DIST = windows.mk mac.mk tool/tests/basic.sh tools/fasc.pl
|
|||||||
|
|
||||||
EXTRA_DIST += doc/Attestation.adoc doc/YKCS11_release_notes.adoc doc/YubiKey_PIV_introduction.adoc
|
EXTRA_DIST += doc/Attestation.adoc doc/YKCS11_release_notes.adoc doc/YubiKey_PIV_introduction.adoc
|
||||||
|
|
||||||
|
|
||||||
if ENABLE_COV
|
if ENABLE_COV
|
||||||
cov-reset:
|
cov-reset:
|
||||||
rm -fr coverage
|
rm -fr coverage
|
||||||
@@ -63,6 +62,14 @@ endif
|
|||||||
|
|
||||||
# Maintainer rules.
|
# Maintainer rules.
|
||||||
|
|
||||||
|
if DX_COND_html
|
||||||
|
doxygen:
|
||||||
|
doxygen lib/Doxyfile
|
||||||
|
endif
|
||||||
|
|
||||||
|
hwcheck:
|
||||||
|
@$(srcdir)/tools/confirm.sh && YKPIV_ENV_HWTESTS_CONFIRMED="1" $(MAKE) check
|
||||||
|
|
||||||
check-doc-dist:
|
check-doc-dist:
|
||||||
perl -pe "s,^EXTRA_DIST \+= .*,EXTRA_DIST += `cd $(srcdir) && ls doc/*.adoc | xargs echo`," < $(srcdir)/Makefile.am > check-doc-dist.tmp
|
perl -pe "s,^EXTRA_DIST \+= .*,EXTRA_DIST += `cd $(srcdir) && ls doc/*.adoc | xargs echo`," < $(srcdir)/Makefile.am > check-doc-dist.tmp
|
||||||
diff -ur $(srcdir)/Makefile.am check-doc-dist.tmp || \
|
diff -ur $(srcdir)/Makefile.am check-doc-dist.tmp || \
|
||||||
|
|||||||
@@ -1,6 +1,20 @@
|
|||||||
yubico-piv-tool NEWS -- History of user-visible changes. -*- outline -*-
|
yubico-piv-tool NEWS -- History of user-visible changes. -*- outline -*-
|
||||||
|
|
||||||
* Version 1.4.5 (unreleased)
|
* Version 1.5.0 (unreleased)
|
||||||
|
|
||||||
|
** API additions: Higher-level "util" API added to libykpiv.
|
||||||
|
|
||||||
|
** Added ykpiv_attest(), ykpiv_get_pin_retries(), ykpiv_set_pin_retries()
|
||||||
|
|
||||||
|
** Added functions for using existing PCSC card handle.
|
||||||
|
|
||||||
|
** Support using custom memory allocator.
|
||||||
|
|
||||||
|
** Documentation updates. 'make doxygen' for HTML format.
|
||||||
|
|
||||||
|
** Expanded automated tests for hardware devices, moved to 'make hwcheck'.
|
||||||
|
|
||||||
|
** Moderate internal refactoring. Many small bugs fixed.
|
||||||
|
|
||||||
* Version 1.4.4 (released 2017-10-17)
|
* Version 1.4.4 (released 2017-10-17)
|
||||||
|
|
||||||
|
|||||||
@@ -67,8 +67,8 @@ situations, running ./configure should automatically find the proper
|
|||||||
backend to use.
|
backend to use.
|
||||||
|
|
||||||
=== Building from Git
|
=== Building from Git
|
||||||
Recent versions of autoconf, automake, pkg-config and libtool must
|
Recent versions of autoconf, automake, check, pkg-config, and libtool
|
||||||
be installed. Help2man is used to generate the manpages. Gengetopt
|
must be installed. Help2man is used to generate the manpages. Gengetopt
|
||||||
version 2.22.6 or later is needed for command line parameter handling.
|
version 2.22.6 or later is needed for command line parameter handling.
|
||||||
The
|
The
|
||||||
link:https://github.com/Yubico/yubico-piv-tool/tree/master/vagrant/development[Vagrant
|
link:https://github.com/Yubico/yubico-piv-tool/tree/master/vagrant/development[Vagrant
|
||||||
|
|||||||
+2
-1
@@ -32,7 +32,7 @@ if [ "x$TRAVIS_OS_NAME" != "xosx" ]; then
|
|||||||
sudo apt-get update -qq
|
sudo apt-get update -qq
|
||||||
sudo apt-get remove -qq -y $REMOVE
|
sudo apt-get remove -qq -y $REMOVE
|
||||||
sudo apt-get autoremove -qq
|
sudo apt-get autoremove -qq
|
||||||
sudo apt-get install -qq -y gengetopt help2man $EXTRA
|
sudo apt-get install -qq -y gengetopt help2man check $EXTRA
|
||||||
TAR=tar
|
TAR=tar
|
||||||
else
|
else
|
||||||
ARCH=osx
|
ARCH=osx
|
||||||
@@ -40,6 +40,7 @@ else
|
|||||||
brew uninstall libtool
|
brew uninstall libtool
|
||||||
brew install libtool
|
brew install libtool
|
||||||
brew install help2man
|
brew install help2man
|
||||||
|
brew install check
|
||||||
brew install pkg-config
|
brew install pkg-config
|
||||||
brew install gengetopt
|
brew install gengetopt
|
||||||
brew install gnu-tar
|
brew install gnu-tar
|
||||||
|
|||||||
+24
-4
@@ -25,7 +25,7 @@
|
|||||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
AC_INIT([yubico-piv-tool], [1.4.5])
|
AC_INIT([yubico-piv-tool], [1.5.0])
|
||||||
AC_CONFIG_AUX_DIR([build-aux])
|
AC_CONFIG_AUX_DIR([build-aux])
|
||||||
AC_CONFIG_MACRO_DIR([m4])
|
AC_CONFIG_MACRO_DIR([m4])
|
||||||
|
|
||||||
@@ -33,9 +33,9 @@ AC_CONFIG_MACRO_DIR([m4])
|
|||||||
# Interfaces changed/added/removed: CURRENT++ REVISION=0
|
# Interfaces changed/added/removed: CURRENT++ REVISION=0
|
||||||
# Interfaces added: AGE++
|
# Interfaces added: AGE++
|
||||||
# Interfaces removed: AGE=0
|
# Interfaces removed: AGE=0
|
||||||
AC_SUBST([LT_CURRENT], 4)
|
AC_SUBST([LT_CURRENT], 5)
|
||||||
AC_SUBST([LT_REVISION], 7)
|
AC_SUBST([LT_REVISION], 0)
|
||||||
AC_SUBST([LT_AGE], 3)
|
AC_SUBST([LT_AGE], 4)
|
||||||
|
|
||||||
AM_INIT_AUTOMAKE([-Wall -Werror foreign])
|
AM_INIT_AUTOMAKE([-Wall -Werror foreign])
|
||||||
AM_SILENT_RULES([yes])
|
AM_SILENT_RULES([yes])
|
||||||
@@ -50,10 +50,30 @@ AM_MISSING_PROG(GENGETOPT, gengetopt, $missing_dir)
|
|||||||
PKG_PROG_PKG_CONFIG
|
PKG_PROG_PKG_CONFIG
|
||||||
|
|
||||||
PKG_CHECK_MODULES(OPENSSL, libcrypto)
|
PKG_CHECK_MODULES(OPENSSL, libcrypto)
|
||||||
|
PKG_CHECK_MODULES([CHECK], [check >= 0.9.6])
|
||||||
|
|
||||||
|
DX_HTML_FEATURE(ON)
|
||||||
|
DX_INIT_DOXYGEN(libykpiv,lib/Doxyfile)
|
||||||
|
|
||||||
gl_LD_VERSION_SCRIPT
|
gl_LD_VERSION_SCRIPT
|
||||||
gl_VALGRIND_TESTS
|
gl_VALGRIND_TESTS
|
||||||
|
|
||||||
|
# Check for clang
|
||||||
|
AC_CACHE_CHECK([for clang],
|
||||||
|
_cv_clang,[
|
||||||
|
AC_TRY_COMPILE([], [
|
||||||
|
#ifdef __clang__
|
||||||
|
#else
|
||||||
|
#error "NOT CLANG"
|
||||||
|
#endif
|
||||||
|
return 0;
|
||||||
|
],
|
||||||
|
[_cv_clang=yes],
|
||||||
|
[_cv_clang=no],
|
||||||
|
[])
|
||||||
|
])
|
||||||
|
AM_CONDITIONAL([COMPILER_CLANG], [test "$_cv_clang" = yes])
|
||||||
|
|
||||||
AC_ARG_WITH([backend],
|
AC_ARG_WITH([backend],
|
||||||
[AS_HELP_STRING([--with-backend=ARG],
|
[AS_HELP_STRING([--with-backend=ARG],
|
||||||
[use specific backend/linkage; 'pcsc', 'macscard' or 'winscard'])],
|
[use specific backend/linkage; 'pcsc', 'macscard' or 'winscard'])],
|
||||||
|
|||||||
+2473
File diff suppressed because it is too large
Load Diff
+1
-1
@@ -32,7 +32,7 @@ AM_CPPFLAGS = $(OPENSSL_CFLAGS) $(PCSC_CFLAGS)
|
|||||||
|
|
||||||
lib_LTLIBRARIES = libykpiv.la
|
lib_LTLIBRARIES = libykpiv.la
|
||||||
|
|
||||||
libykpiv_la_SOURCES = ykpiv.c version.c ykpiv.pc.in ykpiv.map internal.h
|
libykpiv_la_SOURCES = ykpiv.c util.c internal.c internal.h version.c ykpiv.pc.in ykpiv.map
|
||||||
libykpiv_la_SOURCES += error.c
|
libykpiv_la_SOURCES += error.c
|
||||||
libykpiv_la_includedir = $(includedir)/ykpiv
|
libykpiv_la_includedir = $(includedir)/ykpiv
|
||||||
libykpiv_la_include_HEADERS = ykpiv.h ykpiv-version.h
|
libykpiv_la_include_HEADERS = ykpiv.h ykpiv-version.h
|
||||||
|
|||||||
+445
@@ -0,0 +1,445 @@
|
|||||||
|
|
||||||
|
#ifdef _WINDOWS
|
||||||
|
#include <windows.h>
|
||||||
|
#include <wincrypt.h>
|
||||||
|
#include <bcrypt.h>
|
||||||
|
#else
|
||||||
|
#include <openssl/des.h>
|
||||||
|
#include <openssl/evp.h>
|
||||||
|
#include <openssl/rand.h>
|
||||||
|
#include <string.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "internal.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Definitions
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef _WINDOWS
|
||||||
|
|
||||||
|
#define STATUS_SUCCESS ((NTSTATUS)0x00000000L)
|
||||||
|
|
||||||
|
struct des_key {
|
||||||
|
HCRYPTPROV hProv;
|
||||||
|
HCRYPTKEY hKey;
|
||||||
|
ALG_ID alg;
|
||||||
|
};
|
||||||
|
|
||||||
|
static const BYTE PRIVATEKEY_EXPOF1_BLOB[] =
|
||||||
|
{
|
||||||
|
0x07, 0x02, 0x00, 0x00, 0x00, 0xA4, 0x00, 0x00,
|
||||||
|
0x52, 0x53, 0x41, 0x32, 0x00, 0x02, 0x00, 0x00,
|
||||||
|
0x01, 0x00, 0x00, 0x00, 0xAB, 0xEF, 0xFA, 0xC6,
|
||||||
|
0x7D, 0xE8, 0xDE, 0xFB, 0x68, 0x38, 0x09, 0x92,
|
||||||
|
0xD9, 0x42, 0x7E, 0x6B, 0x89, 0x9E, 0x21, 0xD7,
|
||||||
|
0x52, 0x1C, 0x99, 0x3C, 0x17, 0x48, 0x4E, 0x3A,
|
||||||
|
0x44, 0x02, 0xF2, 0xFA, 0x74, 0x57, 0xDA, 0xE4,
|
||||||
|
0xD3, 0xC0, 0x35, 0x67, 0xFA, 0x6E, 0xDF, 0x78,
|
||||||
|
0x4C, 0x75, 0x35, 0x1C, 0xA0, 0x74, 0x49, 0xE3,
|
||||||
|
0x20, 0x13, 0x71, 0x35, 0x65, 0xDF, 0x12, 0x20,
|
||||||
|
0xF5, 0xF5, 0xF5, 0xC1, 0xED, 0x5C, 0x91, 0x36,
|
||||||
|
0x75, 0xB0, 0xA9, 0x9C, 0x04, 0xDB, 0x0C, 0x8C,
|
||||||
|
0xBF, 0x99, 0x75, 0x13, 0x7E, 0x87, 0x80, 0x4B,
|
||||||
|
0x71, 0x94, 0xB8, 0x00, 0xA0, 0x7D, 0xB7, 0x53,
|
||||||
|
0xDD, 0x20, 0x63, 0xEE, 0xF7, 0x83, 0x41, 0xFE,
|
||||||
|
0x16, 0xA7, 0x6E, 0xDF, 0x21, 0x7D, 0x76, 0xC0,
|
||||||
|
0x85, 0xD5, 0x65, 0x7F, 0x00, 0x23, 0x57, 0x45,
|
||||||
|
0x52, 0x02, 0x9D, 0xEA, 0x69, 0xAC, 0x1F, 0xFD,
|
||||||
|
0x3F, 0x8C, 0x4A, 0xD0,
|
||||||
|
|
||||||
|
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
|
||||||
|
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
|
||||||
|
0x64, 0xD5, 0xAA, 0xB1,
|
||||||
|
0xA6, 0x03, 0x18, 0x92, 0x03, 0xAA, 0x31, 0x2E,
|
||||||
|
0x48, 0x4B, 0x65, 0x20, 0x99, 0xCD, 0xC6, 0x0C,
|
||||||
|
0x15, 0x0C, 0xBF, 0x3E, 0xFF, 0x78, 0x95, 0x67,
|
||||||
|
0xB1, 0x74, 0x5B, 0x60,
|
||||||
|
|
||||||
|
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||||
|
};
|
||||||
|
|
||||||
|
const DWORD PRIVATEKEY_EXPOF1_BITLEN = 512;
|
||||||
|
const ALG_ID PRIVATEKEY_EXPOF1_ALG = CALG_RSA_KEYX;
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
struct des_key {
|
||||||
|
DES_key_schedule ks1;
|
||||||
|
DES_key_schedule ks2;
|
||||||
|
DES_key_schedule ks3;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Methods
|
||||||
|
*/
|
||||||
|
|
||||||
|
des_rc des_import_key(const int type, const unsigned char* keyraw, const size_t keyrawlen, des_key** key) {
|
||||||
|
des_rc rc = DES_OK;
|
||||||
|
size_t cb_expectedkey = DES_LEN_3DES;
|
||||||
|
|
||||||
|
#ifdef _WINDOWS
|
||||||
|
|
||||||
|
HCRYPTKEY hNullKey = 0;
|
||||||
|
ALG_ID alg = 0;
|
||||||
|
unsigned char* pbSessionBlob = NULL;
|
||||||
|
DWORD cbSessionBlob = 0;
|
||||||
|
DWORD cbRandom = 0;
|
||||||
|
unsigned char* pbTmp = NULL;
|
||||||
|
size_t n = 0;
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case DES_TYPE_3DES:
|
||||||
|
alg = CALG_3DES;
|
||||||
|
cb_expectedkey = DES_LEN_3DES;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
rc = DES_INVALID_PARAMETER;
|
||||||
|
goto ERROR_EXIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!keyraw) { rc = DES_INVALID_PARAMETER; goto ERROR_EXIT; }
|
||||||
|
if (keyrawlen != cb_expectedkey) { rc = DES_INVALID_PARAMETER; goto ERROR_EXIT; }
|
||||||
|
if (!key) { rc = DES_INVALID_PARAMETER; goto ERROR_EXIT; }
|
||||||
|
if (!(*key = (des_key*)malloc(sizeof(des_key)))) { rc = DES_MEMORY_ERROR; goto ERROR_EXIT; }
|
||||||
|
|
||||||
|
memset(*key, 0, sizeof(des_key));
|
||||||
|
|
||||||
|
(*key)->alg = alg;
|
||||||
|
|
||||||
|
if (!CryptAcquireContext(&((*key)->hProv), NULL, MS_ENHANCED_PROV, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) { rc = DES_GENERAL_ERROR; goto ERROR_EXIT; }
|
||||||
|
|
||||||
|
// Import the exponent-of-one private key.
|
||||||
|
if (!CryptImportKey((*key)->hProv, PRIVATEKEY_EXPOF1_BLOB, sizeof(PRIVATEKEY_EXPOF1_BLOB), 0, 0, &hNullKey)) { rc = DES_GENERAL_ERROR; goto ERROR_EXIT; }
|
||||||
|
|
||||||
|
// calculate Simple blob's length
|
||||||
|
cbSessionBlob = (PRIVATEKEY_EXPOF1_BITLEN / 8) + sizeof(ALG_ID) + sizeof(BLOBHEADER);
|
||||||
|
|
||||||
|
// allocate simple blob buffer
|
||||||
|
if (!(pbSessionBlob = malloc(cbSessionBlob))) { rc = DES_MEMORY_ERROR; goto ERROR_EXIT; }
|
||||||
|
memset(pbSessionBlob, 0, cbSessionBlob);
|
||||||
|
|
||||||
|
pbTmp = pbSessionBlob;
|
||||||
|
|
||||||
|
// SIMPLEBLOB Format is documented in SDK
|
||||||
|
// Copy header to buffer
|
||||||
|
((BLOBHEADER *)pbTmp)->bType = SIMPLEBLOB;
|
||||||
|
((BLOBHEADER *)pbTmp)->bVersion = 2;
|
||||||
|
((BLOBHEADER *)pbTmp)->reserved = 0;
|
||||||
|
((BLOBHEADER *)pbTmp)->aiKeyAlg = alg;
|
||||||
|
pbTmp += sizeof(BLOBHEADER);
|
||||||
|
|
||||||
|
// Copy private key algorithm to buffer
|
||||||
|
*((DWORD *)pbTmp) = PRIVATEKEY_EXPOF1_ALG;
|
||||||
|
pbTmp += sizeof(ALG_ID);
|
||||||
|
|
||||||
|
// Place the key material in reverse order
|
||||||
|
for (n = 0; n < keyrawlen; n++) {
|
||||||
|
pbTmp[n] = keyraw[keyrawlen - n - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3 is for the first reserved byte after the key material + the 2 reserved bytes at the end.
|
||||||
|
cbRandom = cbSessionBlob - (sizeof(ALG_ID) + sizeof(BLOBHEADER) + (DWORD)keyrawlen + 3);
|
||||||
|
pbTmp += (keyrawlen + 1);
|
||||||
|
|
||||||
|
// Generate random data for the rest of the buffer
|
||||||
|
// (except that last two bytes)
|
||||||
|
if (!CryptGenRandom((*key)->hProv, cbRandom, pbTmp)) { rc = DES_GENERAL_ERROR; goto ERROR_EXIT; }
|
||||||
|
|
||||||
|
for (n = 0; n < cbRandom; n++) {
|
||||||
|
if (pbTmp[n] == 0) pbTmp[n] = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
pbSessionBlob[cbSessionBlob - 2] = 2;
|
||||||
|
|
||||||
|
if (!CryptImportKey((*key)->hProv, pbSessionBlob, cbSessionBlob, hNullKey, CRYPT_EXPORTABLE, &((*key)->hKey))) { rc = DES_GENERAL_ERROR; goto ERROR_EXIT; }
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
const_DES_cblock key_tmp;
|
||||||
|
size_t cb_keysize = 8;
|
||||||
|
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case DES_TYPE_3DES:
|
||||||
|
cb_expectedkey = DES_LEN_3DES;
|
||||||
|
cb_keysize = 8;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
rc = DES_INVALID_PARAMETER;
|
||||||
|
goto ERROR_EXIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cb_keysize > sizeof(key_tmp)) { rc = DES_MEMORY_ERROR; goto ERROR_EXIT; }
|
||||||
|
if (!keyraw) { rc = DES_INVALID_PARAMETER; goto ERROR_EXIT; }
|
||||||
|
if (keyrawlen != cb_expectedkey) { rc = DES_INVALID_PARAMETER; goto ERROR_EXIT; }
|
||||||
|
if (!key) { rc = DES_INVALID_PARAMETER; goto ERROR_EXIT; }
|
||||||
|
if (!(*key = (des_key*)malloc(sizeof(des_key)))) { rc = DES_MEMORY_ERROR; goto ERROR_EXIT; }
|
||||||
|
|
||||||
|
memset(*key, 0, sizeof(des_key));
|
||||||
|
|
||||||
|
memcpy(key_tmp, keyraw, cb_keysize);
|
||||||
|
DES_set_key_unchecked(&key_tmp, &((*key)->ks1));
|
||||||
|
memcpy(key_tmp, keyraw + cb_keysize, cb_keysize);
|
||||||
|
DES_set_key_unchecked(&key_tmp, &((*key)->ks2));
|
||||||
|
memcpy(key_tmp, keyraw + (2 * cb_keysize), cb_keysize);
|
||||||
|
DES_set_key_unchecked(&key_tmp, &((*key)->ks3));
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
EXIT:
|
||||||
|
#ifdef _WINDOWS
|
||||||
|
if (pbSessionBlob) {
|
||||||
|
free(pbSessionBlob);
|
||||||
|
pbSessionBlob = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hNullKey) {
|
||||||
|
CryptDestroyKey(hNullKey);
|
||||||
|
hNullKey = 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
ERROR_EXIT:
|
||||||
|
if (key) {
|
||||||
|
des_destroy_key(*key);
|
||||||
|
*key = NULL;
|
||||||
|
}
|
||||||
|
goto EXIT;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
des_rc des_destroy_key(des_key* key) {
|
||||||
|
if (key) {
|
||||||
|
#ifdef _WINDOWS
|
||||||
|
if (key->hKey) {
|
||||||
|
CryptDestroyKey(key->hKey);
|
||||||
|
key->hKey = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (key->hProv) {
|
||||||
|
CryptReleaseContext(key->hProv, 0);
|
||||||
|
key->hProv = 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
free(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
return DES_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
des_rc des_encrypt(des_key* key, const unsigned char* in, const size_t inlen, unsigned char* out, size_t* outlen) {
|
||||||
|
des_rc rc = DES_OK;
|
||||||
|
|
||||||
|
#ifdef _WINDOWS
|
||||||
|
unsigned char buf[8] = { 0 };
|
||||||
|
size_t buflen = sizeof(buf);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (!key || !outlen || (*outlen < inlen) || !in || !out) { rc = DES_INVALID_PARAMETER; goto EXIT; }
|
||||||
|
|
||||||
|
#ifdef _WINDOWS
|
||||||
|
|
||||||
|
if (!key->hKey) { rc = DES_INVALID_PARAMETER; goto EXIT; }
|
||||||
|
|
||||||
|
memcpy(out, in, inlen);
|
||||||
|
*outlen = inlen;
|
||||||
|
|
||||||
|
if (!CryptEncrypt(key->hKey, 0, FALSE, 0, out, (DWORD*)&inlen, (DWORD)*outlen)) { fwprintf(stderr, L"GetLastError = %x\n", GetLastError()); rc = DES_GENERAL_ERROR; goto EXIT; }
|
||||||
|
// reset key usage by encrypting a fake padded block
|
||||||
|
CryptEncrypt(key->hKey, 0, TRUE, 0, buf, (DWORD*)&buflen, (DWORD)buflen);
|
||||||
|
|
||||||
|
//if (CALG_3DES == key->alg) {
|
||||||
|
// // truncate the final pad block
|
||||||
|
// *outlen = inlen - 8;
|
||||||
|
//}
|
||||||
|
//else {
|
||||||
|
// *outlen = inlen;
|
||||||
|
//}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
/* openssl returns void */
|
||||||
|
DES_ecb3_encrypt((const_DES_cblock *)in, (DES_cblock*)out, &(key->ks1), &(key->ks2), &(key->ks3), 1);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
EXIT:
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
des_rc des_decrypt(des_key* key, const unsigned char* in, const size_t inlen, unsigned char* out, size_t* outlen) {
|
||||||
|
des_rc rc = DES_OK;
|
||||||
|
|
||||||
|
#ifdef _WINDOWS
|
||||||
|
unsigned char buf[8] = { 0 };
|
||||||
|
size_t buflen = sizeof(buf);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (!key || !outlen || (*outlen < inlen) || !in || !out) { rc = DES_INVALID_PARAMETER; goto EXIT; }
|
||||||
|
|
||||||
|
#ifdef _WINDOWS
|
||||||
|
|
||||||
|
if (!key->hKey) { rc = DES_INVALID_PARAMETER; goto EXIT; }
|
||||||
|
|
||||||
|
memcpy(out, in, inlen);
|
||||||
|
*outlen = inlen;
|
||||||
|
|
||||||
|
if (!CryptDecrypt(key->hKey, 0, FALSE, 0, out, (DWORD*)outlen)) { fwprintf(stderr, L"GetLastError = %x\n", GetLastError()); rc = DES_GENERAL_ERROR; goto EXIT; }
|
||||||
|
// reset key usage by decrypting a fake padded block
|
||||||
|
CryptDecrypt(key->hKey, 0, TRUE, 0, buf, (DWORD*)&buflen);
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
/* openssl returns void */
|
||||||
|
DES_ecb3_encrypt((const_DES_cblock*)in, (DES_cblock*)out, &(key->ks1), &(key->ks2), &(key->ks3), 0);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
EXIT:
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool yk_des_is_weak_key(const unsigned char *key, const size_t cb_key) {
|
||||||
|
#ifdef _WINDOWS
|
||||||
|
/* defined weak keys, borrowed from openssl to be consistent across platforms */
|
||||||
|
static const unsigned char weak_keys[][DES_LEN_DES] = {
|
||||||
|
/* weak keys */
|
||||||
|
{0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01},
|
||||||
|
{0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE},
|
||||||
|
{0x1F,0x1F,0x1F,0x1F,0x0E,0x0E,0x0E,0x0E},
|
||||||
|
{0xE0,0xE0,0xE0,0xE0,0xF1,0xF1,0xF1,0xF1},
|
||||||
|
/* semi-weak keys */
|
||||||
|
{0x01,0xFE,0x01,0xFE,0x01,0xFE,0x01,0xFE},
|
||||||
|
{0xFE,0x01,0xFE,0x01,0xFE,0x01,0xFE,0x01},
|
||||||
|
{0x1F,0xE0,0x1F,0xE0,0x0E,0xF1,0x0E,0xF1},
|
||||||
|
{0xE0,0x1F,0xE0,0x1F,0xF1,0x0E,0xF1,0x0E},
|
||||||
|
{0x01,0xE0,0x01,0xE0,0x01,0xF1,0x01,0xF1},
|
||||||
|
{0xE0,0x01,0xE0,0x01,0xF1,0x01,0xF1,0x01},
|
||||||
|
{0x1F,0xFE,0x1F,0xFE,0x0E,0xFE,0x0E,0xFE},
|
||||||
|
{0xFE,0x1F,0xFE,0x1F,0xFE,0x0E,0xFE,0x0E},
|
||||||
|
{0x01,0x1F,0x01,0x1F,0x01,0x0E,0x01,0x0E},
|
||||||
|
{0x1F,0x01,0x1F,0x01,0x0E,0x01,0x0E,0x01},
|
||||||
|
{0xE0,0xFE,0xE0,0xFE,0xF1,0xFE,0xF1,0xFE},
|
||||||
|
{0xFE,0xE0,0xFE,0xE0,0xFE,0xF1,0xFE,0xF1} };
|
||||||
|
|
||||||
|
unsigned char tmp[DES_LEN_3DES] = { 0 };
|
||||||
|
int i = 0;
|
||||||
|
unsigned char c = 0x00;
|
||||||
|
|
||||||
|
if (sizeof(tmp) != cb_key) return true;
|
||||||
|
|
||||||
|
/* set odd parity of key */
|
||||||
|
|
||||||
|
for (i = 0; i < sizeof(tmp); i++) {
|
||||||
|
/* count number of set bits in byte, excluding the low-order bit - SWAR method */
|
||||||
|
c = key[i] & 0xFE;
|
||||||
|
|
||||||
|
c = (c & 0x55) + ((c >> 1) & 0x55);
|
||||||
|
c = (c & 0x33) + ((c >> 2) & 0x33);
|
||||||
|
c = (c & 0x0F) + ((c >> 4) & 0x0F);
|
||||||
|
|
||||||
|
/* if count is even, set low key bit to 1, otherwise 0 */
|
||||||
|
tmp[i] = (key[i] & 0xFE) | ((c & 0x01) ? 0x00 : 0x01);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* check odd parity key against table by DES key block*/
|
||||||
|
|
||||||
|
for (i = 0; i < sizeof(weak_keys) / sizeof(weak_keys[0]); i++) {
|
||||||
|
if ((0 == memcmp(weak_keys[i], tmp, DES_LEN_DES)) ||
|
||||||
|
(0 == memcmp(weak_keys[i], tmp + DES_LEN_DES, DES_LEN_DES)) ||
|
||||||
|
(0 == memcmp(weak_keys[i], tmp + 2*DES_LEN_DES, DES_LEN_DES))) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
#else
|
||||||
|
return DES_is_weak_key((const_DES_cblock *)key);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
prng_rc _ykpiv_prng_generate(unsigned char *buffer, const size_t cb_req) {
|
||||||
|
prng_rc rc = PRNG_OK;
|
||||||
|
|
||||||
|
#ifdef _WINDOWS
|
||||||
|
HCRYPTPROV hProv = 0;
|
||||||
|
|
||||||
|
if (CryptAcquireContext(&hProv, NULL, MS_ENHANCED_PROV, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) {
|
||||||
|
if (!CryptGenRandom(hProv, (DWORD)cb_req, buffer)) {
|
||||||
|
rc = PRNG_GENERAL_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
CryptReleaseContext(hProv, 0);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
rc = PRNG_GENERAL_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
if (-1 == RAND_pseudo_bytes(buffer, cb_req)) {
|
||||||
|
rc = PRNG_GENERAL_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
pkcs5_rc pkcs5_pbkdf2_sha1(const unsigned char* password, const size_t cb_password, const unsigned char* salt, const size_t cb_salt, unsigned long long iterations, unsigned char* key, const size_t cb_key) {
|
||||||
|
pkcs5_rc rc = PKCS5_OK;
|
||||||
|
|
||||||
|
#ifdef _WINDOWS
|
||||||
|
BCRYPT_ALG_HANDLE hAlg = 0;
|
||||||
|
|
||||||
|
/* mingw64 defines the BCryptDeriveKeyPBKDF2 function, but its dll link library doesn't include the export.
|
||||||
|
**
|
||||||
|
** In case this is needed, we'll need to dynamically load the function:
|
||||||
|
**
|
||||||
|
** typedef NTSTATUS WINAPI (*PFN_BCryptDeriveKeyPBKDF2) (BCRYPT_ALG_HANDLE hPrf, PUCHAR pbPassword, ULONG cbPassword, PUCHAR pbSalt, ULONG cbSalt, ULONGLONG cIterations, PUCHAR pbDerivedKey, ULONG cbDerivedKey, ULONG dwFlags);
|
||||||
|
** HMODULE hBCrypt = LoadLibrary("bcrypt.dll");
|
||||||
|
** PFN_BCryptDeriveKeyPBKDF2 pbkdf2 = GetProcAddress(hBCrypt, "BCryptDeriveKeyPBKDF2");
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (STATUS_SUCCESS == BCryptOpenAlgorithmProvider(&hAlg, BCRYPT_SHA1_ALGORITHM, NULL, BCRYPT_ALG_HANDLE_HMAC_FLAG)) {
|
||||||
|
if (STATUS_SUCCESS != BCryptDeriveKeyPBKDF2(hAlg, (PUCHAR)password, (ULONG)cb_password, (PUCHAR)salt, (ULONG)cb_salt, iterations, key, (ULONG)cb_key, 0)) {
|
||||||
|
rc = PKCS5_GENERAL_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
BCryptCloseAlgorithmProvider(hAlg, 0);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
rc = PKCS5_GENERAL_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
/* for some reason openssl always returns 1 for PBKDF2 */
|
||||||
|
PKCS5_PBKDF2_HMAC_SHA1((const char*)password, cb_password, salt, cb_salt, iterations, cb_key, key);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
+129
-3
@@ -31,6 +31,8 @@
|
|||||||
#ifndef YKPIV_INTERNAL_H
|
#ifndef YKPIV_INTERNAL_H
|
||||||
#define YKPIV_INTERNAL_H
|
#define YKPIV_INTERNAL_H
|
||||||
|
|
||||||
|
#include "ykpiv.h"
|
||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
#if BACKEND_PCSC
|
#if BACKEND_PCSC
|
||||||
@@ -42,14 +44,115 @@
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Typedef DWORD (defined by pcsc lib) to pcsc_word to make it clear that this
|
||||||
|
// is not the Windows meaning of DWORD, but the PCSC library's meaning. This
|
||||||
|
// differs: Windows defines a DWORD as 32-bits, but pcsclite defines it as
|
||||||
|
// 'unsigned long' on x86_64 Linux, which is often 64-bits.
|
||||||
|
typedef DWORD pcsc_word;
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define DES_TYPE_3DES 1
|
||||||
|
|
||||||
|
#define DES_LEN_DES 8
|
||||||
|
#define DES_LEN_3DES DES_LEN_DES*3
|
||||||
|
|
||||||
#define READER_LEN 32
|
#define READER_LEN 32
|
||||||
#define MAX_READERS 16
|
#define MAX_READERS 16
|
||||||
|
|
||||||
|
#define CB_MGM_KEY DES_LEN_3DES
|
||||||
|
|
||||||
|
// the object size is restricted to the firmware's message buffer size, which
|
||||||
|
// always contains 0x5C + 1 byte len + 3 byte id + 0x53 + 3 byte len = 9 bytes,
|
||||||
|
// so while the message buffer == CB_BUF_MAX, the maximum object we can store
|
||||||
|
// is CB_BUF_MAX - 9
|
||||||
|
#define CB_OBJ_MAX_NEO (CB_BUF_MAX_NEO - 9)
|
||||||
|
#define CB_OBJ_MAX_YK4 (CB_BUF_MAX_YK4 - 9)
|
||||||
|
#define CB_OBJ_MAX CB_OBJ_MAX_YK4
|
||||||
|
|
||||||
|
#define CB_BUF_MAX_NEO 2048
|
||||||
|
#define CB_BUF_MAX_YK4 3072
|
||||||
|
#define CB_BUF_MAX CB_BUF_MAX_YK4
|
||||||
|
|
||||||
|
#define CB_ATR_MAX 33
|
||||||
|
|
||||||
|
#define CHREF_ACT_CHANGE_PIN 0
|
||||||
|
#define CHREF_ACT_UNBLOCK_PIN 1
|
||||||
|
#define CHREF_ACT_CHANGE_PUK 2
|
||||||
|
|
||||||
|
#define TAG_CERT 0x70
|
||||||
|
#define TAG_CERT_COMPRESS 0x71
|
||||||
|
#define TAG_CERT_LRC 0xFE
|
||||||
|
#define TAG_ADMIN 0x80
|
||||||
|
#define TAG_ADMIN_FLAGS_1 0x81
|
||||||
|
#define TAG_ADMIN_SALT 0x82
|
||||||
|
#define TAG_ADMIN_TIMESTAMP 0x83
|
||||||
|
#define TAG_PROTECTED 0x88
|
||||||
|
#define TAG_PROTECTED_FLAGS_1 0x81
|
||||||
|
#define TAG_PROTECTED_MGM 0x89
|
||||||
|
#define TAG_MSCMAP 0x81
|
||||||
|
#define TAG_MSROOTS_END 0x82
|
||||||
|
#define TAG_MSROOTS_MID 0x83
|
||||||
|
|
||||||
|
#define TAG_RSA_MODULUS 0x81
|
||||||
|
#define TAG_RSA_EXP 0x82
|
||||||
|
#define TAG_ECC_POINT 0x86
|
||||||
|
|
||||||
|
#define CB_ECC_POINTP256 65
|
||||||
|
#define CB_ECC_POINTP384 97
|
||||||
|
|
||||||
|
#define YKPIV_OBJ_ADMIN_DATA 0x5fff00
|
||||||
|
#define YKPIV_OBJ_ATTESTATION 0x5fff01
|
||||||
|
#define YKPIV_OBJ_MSCMAP 0x5fff10
|
||||||
|
#define YKPIV_OBJ_MSROOTS1 0x5fff11
|
||||||
|
#define YKPIV_OBJ_MSROOTS2 0x5fff12
|
||||||
|
#define YKPIV_OBJ_MSROOTS3 0x5fff13
|
||||||
|
#define YKPIV_OBJ_MSROOTS4 0x5fff14
|
||||||
|
#define YKPIV_OBJ_MSROOTS5 0x5fff15
|
||||||
|
|
||||||
|
#define ADMIN_FLAGS_1_PUK_BLOCKED 0x01
|
||||||
|
#define ADMIN_FLAGS_1_PROTECTED_MGM 0x02
|
||||||
|
|
||||||
|
#define CB_ADMIN_SALT 16
|
||||||
|
#define CB_ADMIN_TIMESTAMP 4
|
||||||
|
|
||||||
|
#define ITER_MGM_PBKDF2 10000
|
||||||
|
|
||||||
|
#define PROTECTED_FLAGS_1_PUK_NOBLOCK 0x01
|
||||||
|
|
||||||
|
#define CB_OBJ_TAG_MIN 2 // 1 byte tag + 1 byte len
|
||||||
|
#define CB_OBJ_TAG_MAX (CB_OBJ_TAG_MIN + 2) // 1 byte tag + 3 bytes len
|
||||||
|
|
||||||
|
#define member_size(type, member) sizeof(((type*)0)->member)
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
DES_OK = 0,
|
||||||
|
DES_INVALID_PARAMETER = -1,
|
||||||
|
DES_BUFFER_TOO_SMALL = -2,
|
||||||
|
DES_MEMORY_ERROR = -3,
|
||||||
|
DES_GENERAL_ERROR = -4
|
||||||
|
} des_rc;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
PKCS5_OK = 0,
|
||||||
|
PKCS5_GENERAL_ERROR = -1
|
||||||
|
} pkcs5_rc;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
PRNG_OK = 0,
|
||||||
|
PRNG_GENERAL_ERROR = -1
|
||||||
|
} prng_rc;
|
||||||
|
|
||||||
struct ykpiv_state {
|
struct ykpiv_state {
|
||||||
SCARDCONTEXT context;
|
SCARDCONTEXT context;
|
||||||
SCARDHANDLE card;
|
SCARDHANDLE card;
|
||||||
int verbose;
|
int verbose;
|
||||||
char *pin;
|
char *pin;
|
||||||
|
ykpiv_allocator allocator;
|
||||||
|
bool isNEO;
|
||||||
};
|
};
|
||||||
|
|
||||||
union u_APDU {
|
union u_APDU {
|
||||||
@@ -65,9 +168,32 @@ union u_APDU {
|
|||||||
};
|
};
|
||||||
|
|
||||||
typedef union u_APDU APDU;
|
typedef union u_APDU APDU;
|
||||||
|
typedef struct des_key des_key;
|
||||||
|
|
||||||
unsigned const char aid[] = {
|
extern unsigned const char aid[];
|
||||||
0xa0, 0x00, 0x00, 0x03, 0x08
|
|
||||||
};
|
des_rc des_import_key(const int type, const unsigned char* keyraw, const size_t keyrawlen, des_key** key);
|
||||||
|
des_rc des_destroy_key(des_key* key);
|
||||||
|
des_rc des_encrypt(des_key* key, const unsigned char* in, const size_t inlen, unsigned char* out, size_t* outlen);
|
||||||
|
des_rc des_decrypt(des_key* key, const unsigned char* in, const size_t inlen, unsigned char* out, size_t* outlen);
|
||||||
|
pkcs5_rc pkcs5_pbkdf2_sha1(const unsigned char* password, const size_t cb_password, const unsigned char* salt, const size_t cb_salt, unsigned long long iterations, unsigned char* key, const size_t cb_key);
|
||||||
|
bool yk_des_is_weak_key(const unsigned char *key, const size_t cb_key);
|
||||||
|
|
||||||
|
prng_rc _ykpiv_prng_generate(unsigned char *buffer, const size_t cb_req);
|
||||||
|
ykpiv_rc _ykpiv_begin_transaction(ykpiv_state *state);
|
||||||
|
ykpiv_rc _ykpiv_end_transaction(ykpiv_state *state);
|
||||||
|
ykpiv_rc _ykpiv_ensure_application_selected(ykpiv_state *state);
|
||||||
|
int _ykpiv_set_length(unsigned char *buffer, size_t length);
|
||||||
|
int _ykpiv_get_length(const unsigned char *buffer, size_t *len);
|
||||||
|
|
||||||
|
void* _ykpiv_alloc(ykpiv_state *state, size_t size);
|
||||||
|
void* _ykpiv_realloc(ykpiv_state *state, void *address, size_t size);
|
||||||
|
void _ykpiv_free(ykpiv_state *state, void *data);
|
||||||
|
ykpiv_rc _ykpiv_save_object(ykpiv_state *state, int object_id, unsigned char *indata, size_t len);
|
||||||
|
ykpiv_rc _ykpiv_fetch_object(ykpiv_state *state, int object_id, unsigned char *data, unsigned long *len);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
+12
-5
@@ -25,13 +25,20 @@
|
|||||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
AM_CFLAGS = $(WARN_CFLAGS)
|
AM_CFLAGS = $(WARN_CFLAGS) @CHECK_CFLAGS@ $(OPENSSL_CFLAGS)
|
||||||
AM_CPPFLAGS = -I$(top_srcdir)/lib -I$(top_builddir)/lib
|
AM_CPPFLAGS = -I$(top_srcdir)/lib -I$(top_builddir)/lib $(OPENSSL_CFLAGS) $(PCSC_CFLAGS)
|
||||||
|
|
||||||
AM_LDFLAGS = -no-install
|
AM_LDFLAGS = @CHECK_LIBS@
|
||||||
LDADD = ../libykpiv.la
|
|
||||||
|
|
||||||
check_PROGRAMS = basic parse_key
|
if COMPILER_CLANG
|
||||||
|
AM_LDFLAGS += -no-fast-install
|
||||||
|
else
|
||||||
|
AM_LDFLAGS += -no-install
|
||||||
|
endif
|
||||||
|
|
||||||
|
LDADD = ../libykpiv.la $(OPENSSL_LIBS)
|
||||||
|
|
||||||
|
check_PROGRAMS = basic parse_key api
|
||||||
TESTS = $(check_PROGRAMS)
|
TESTS = $(check_PROGRAMS)
|
||||||
|
|
||||||
LOG_COMPILER = $(VALGRIND)
|
LOG_COMPILER = $(VALGRIND)
|
||||||
|
|||||||
+974
@@ -0,0 +1,974 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2014-2016 Yubico AB
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are
|
||||||
|
* met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* * Redistributions in binary form must reproduce the above
|
||||||
|
* copyright notice, this list of conditions and the following
|
||||||
|
* disclaimer in the documentation and/or other materials provided
|
||||||
|
* with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ykpiv.h"
|
||||||
|
#include "internal.h"
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <check.h>
|
||||||
|
|
||||||
|
#ifdef __MINGW32__
|
||||||
|
#define dprintf(fd, ...) fprintf(stdout, __VA_ARGS__)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int destruction_confirmed(void);
|
||||||
|
|
||||||
|
// only defined in libcheck 0.11+ (linux distros still shipping 0.10)
|
||||||
|
#ifndef ck_assert_ptr_nonnull
|
||||||
|
#define ck_assert_ptr_nonnull(a) ck_assert((a) != NULL)
|
||||||
|
#endif
|
||||||
|
#ifndef ck_assert_mem_eq
|
||||||
|
#define ck_assert_mem_eq(a,b,n) ck_assert(memcmp((a), (b), (n)) == 0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ykpiv_state *g_state;
|
||||||
|
const uint8_t g_cert[] = {
|
||||||
|
"0123456789ABCDEFGHIK0123456789ABCDEFGHIK0123456789ABCDEFGHIK0123456789ABCDEFGHIK"
|
||||||
|
"0123456789ABCDEFGHIK0123456789ABCDEFGHIK0123456789ABCDEFGHIK0123456789ABCDEFGHIK"
|
||||||
|
"0123456789ABCDEFGHIK0123456789ABCDEFGHIK0123456789ABCDEFGHIK0123456789ABCDEFGHIK"
|
||||||
|
"0123456789ABCDEFGHIK0123456789ABCDEFGHIK0123456789ABCDEFGHIK0123456789ABCDEFGHIK"
|
||||||
|
"0123456789ABCDEFGHIK0123456789ABCDEFGHIK0123456789ABCDEFGHIK0123456789ABCDEFGHIK"
|
||||||
|
};
|
||||||
|
|
||||||
|
void setup(void) {
|
||||||
|
ykpiv_rc res;
|
||||||
|
|
||||||
|
// Require user confirmation to continue, since this test suite will clear
|
||||||
|
// any data stored on connected keys.
|
||||||
|
if (!destruction_confirmed())
|
||||||
|
exit(77); // exit code 77 == skipped tests
|
||||||
|
|
||||||
|
res = ykpiv_init(&g_state, true);
|
||||||
|
ck_assert_int_eq(res, YKPIV_OK);
|
||||||
|
ck_assert_ptr_nonnull(g_state);
|
||||||
|
|
||||||
|
res = ykpiv_connect(g_state, NULL);
|
||||||
|
ck_assert_int_eq(res, YKPIV_OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
void teardown(void) {
|
||||||
|
ykpiv_rc res;
|
||||||
|
|
||||||
|
// This is the expected case, if the allocator test ran, since it de-inits.
|
||||||
|
if (NULL == g_state)
|
||||||
|
return;
|
||||||
|
|
||||||
|
res = ykpiv_disconnect(g_state);
|
||||||
|
ck_assert_int_eq(res, YKPIV_OK);
|
||||||
|
|
||||||
|
res = ykpiv_done(g_state);
|
||||||
|
ck_assert_int_eq(res, YKPIV_OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
START_TEST(test_devicemodel) {
|
||||||
|
ykpiv_rc res;
|
||||||
|
ykpiv_devmodel model;
|
||||||
|
char version[256];
|
||||||
|
char reader_buf[2048];
|
||||||
|
size_t num_readers = sizeof(reader_buf);
|
||||||
|
|
||||||
|
res = ykpiv_get_version(g_state, version, sizeof(version));
|
||||||
|
ck_assert_int_eq(res, YKPIV_OK);
|
||||||
|
fprintf(stderr, "Version: %s\n", version);
|
||||||
|
model = ykpiv_util_devicemodel(g_state);
|
||||||
|
fprintf(stdout, "Model: %u\n", model);
|
||||||
|
ck_assert(model == DEVTYPE_YK4 || model == DEVTYPE_NEOr3);
|
||||||
|
|
||||||
|
res = ykpiv_list_readers(g_state, reader_buf, &num_readers);
|
||||||
|
ck_assert_int_eq(res, YKPIV_OK);
|
||||||
|
ck_assert_int_gt(num_readers, 0);
|
||||||
|
if (model == DEVTYPE_YK4) {
|
||||||
|
ck_assert_ptr_nonnull(strstr(reader_buf, "Yubikey 4"));
|
||||||
|
ck_assert(version[0] == '4'); // Verify app version 4.x
|
||||||
|
ck_assert(version[1] == '.');
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ck_assert_ptr_nonnull(strstr(reader_buf, "Yubikey NEO"));
|
||||||
|
ck_assert(version[0] == '1'); // Verify app version 1.x
|
||||||
|
ck_assert(version[1] == '.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST(test_get_set_cardid) {
|
||||||
|
ykpiv_rc res;
|
||||||
|
ykpiv_cardid set_id;
|
||||||
|
ykpiv_cardid get_id;
|
||||||
|
|
||||||
|
memset(&set_id.data, 'i', sizeof(set_id.data));
|
||||||
|
memset(&get_id.data, 0, sizeof(get_id.data));
|
||||||
|
|
||||||
|
res = ykpiv_util_set_cardid(g_state, &set_id);
|
||||||
|
ck_assert_int_eq(res, YKPIV_OK);
|
||||||
|
|
||||||
|
res = ykpiv_util_get_cardid(g_state, &get_id);
|
||||||
|
ck_assert_int_eq(res, YKPIV_OK);
|
||||||
|
ck_assert_mem_eq(&set_id.data, &get_id.data, sizeof(set_id.data));
|
||||||
|
}
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST(test_list_readers) {
|
||||||
|
ykpiv_rc res;
|
||||||
|
char reader_buf[2048];
|
||||||
|
size_t num_readers = sizeof(reader_buf);
|
||||||
|
char *reader_ptr;
|
||||||
|
res = ykpiv_list_readers(g_state, reader_buf, &num_readers);
|
||||||
|
ck_assert_int_eq(res, YKPIV_OK);
|
||||||
|
ck_assert_int_gt(num_readers, 0);
|
||||||
|
for(reader_ptr = reader_buf; *reader_ptr != '\0'; reader_ptr += strlen(reader_ptr) + 1) {
|
||||||
|
fprintf(stdout, "Found device: %s\n", reader_ptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST(test_read_write_list_delete_cert) {
|
||||||
|
ykpiv_rc res;
|
||||||
|
uint8_t *read_cert = NULL;
|
||||||
|
size_t read_cert_len = 0;
|
||||||
|
|
||||||
|
{
|
||||||
|
res = ykpiv_util_write_cert(g_state, YKPIV_KEY_AUTHENTICATION, (uint8_t*)g_cert, sizeof(g_cert), YKPIV_CERTINFO_UNCOMPRESSED);
|
||||||
|
ck_assert_int_eq(res, YKPIV_OK);
|
||||||
|
|
||||||
|
res = ykpiv_util_read_cert(g_state, YKPIV_KEY_AUTHENTICATION, &read_cert, &read_cert_len);
|
||||||
|
ck_assert_int_eq(res, YKPIV_OK);
|
||||||
|
ck_assert_ptr_nonnull(read_cert);
|
||||||
|
ck_assert_int_eq(read_cert_len, sizeof(g_cert));
|
||||||
|
ck_assert_mem_eq(g_cert, read_cert, sizeof(g_cert));
|
||||||
|
|
||||||
|
res = ykpiv_util_free(g_state, read_cert);
|
||||||
|
ck_assert_int_eq(res, YKPIV_OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
ykpiv_key *keys = NULL;
|
||||||
|
size_t data_len;
|
||||||
|
uint8_t key_count;
|
||||||
|
res = ykpiv_util_list_keys(g_state, &key_count, &keys, &data_len);
|
||||||
|
ck_assert_int_eq(res, YKPIV_OK);
|
||||||
|
ck_assert_ptr_nonnull(keys);
|
||||||
|
ck_assert_int_gt(key_count, 0);
|
||||||
|
|
||||||
|
res = ykpiv_util_free(g_state, keys);
|
||||||
|
ck_assert_int_eq(res, YKPIV_OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
res = ykpiv_util_delete_cert(g_state, YKPIV_KEY_AUTHENTICATION);
|
||||||
|
ck_assert_int_eq(res, YKPIV_OK);
|
||||||
|
|
||||||
|
res = ykpiv_util_read_cert(g_state, YKPIV_KEY_AUTHENTICATION, &read_cert, &read_cert_len);
|
||||||
|
ck_assert_int_eq(res, YKPIV_GENERIC_ERROR);
|
||||||
|
|
||||||
|
res = ykpiv_util_free(g_state, read_cert);
|
||||||
|
ck_assert_int_eq(res, YKPIV_OK);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
#include <openssl/des.h>
|
||||||
|
#include <openssl/pem.h>
|
||||||
|
#include <openssl/pkcs12.h>
|
||||||
|
#include <openssl/rand.h>
|
||||||
|
|
||||||
|
// RSA2048 private key, generated with: `openssl genrsa 2048 -out private.pem`
|
||||||
|
static const char *private_key_pem =
|
||||||
|
"-----BEGIN RSA PRIVATE KEY-----\n"
|
||||||
|
"MIIEpAIBAAKCAQEAwVUwmVbc+ffOy2+RivxBpgleTVN6bUa0q7jNYB+AseFQYaYq\n"
|
||||||
|
"EGfa+VGdxSGo+8DV1KT9+fNEd5243gXn/tcjtMItKeB+oAQc64s9lIFlYuR8bpq1\n"
|
||||||
|
"ibr33iW2elnnv9mpecqohdCVwM2McWveoPyb7MwlwVuhqexOzJO29bqJcazLbtkf\n"
|
||||||
|
"ZETK0oBx53/ylA4Y6nE9Pa46jW2qhj+KShf1iBg+gAyt3eI+wI2Wmub1WxLLH8D2\n"
|
||||||
|
"w+kow8QhQOa8dHCkRRw771JxVO5+d+Y/Y+x9B1HgF4q0q9xUlhWLK2TR4ChBFzXe\n"
|
||||||
|
"47sAHsSqi/pl5JbwYrHPOE/VEBLukmjL8NFCSQIDAQABAoIBADmEyOK2DyRnb6Ti\n"
|
||||||
|
"2qBJEJb/boj+7wuX36S/ZIrWlIlXiXyj3RvoaiOG/rNpokbURknvlIhKsfIMgLW9\n"
|
||||||
|
"eBo/k6Xxp1IwMjwVPS1uzbFjFfDoHYUijiQd9iSnf7TDDsnrThqoCp9VQViNTt1n\n"
|
||||||
|
"xGKNBS7cRddTFbPiVEdVIzfUeZPR2oRrc4maBCRCrQgg8WNknawmc8zhkf2NiPj3\n"
|
||||||
|
"tWLQHMy1/MgW2W1LM9sgzllEtS5CZUnyGy2HbbhS2tbZ6j9kPzOp0pPxxTTzJmmV\n"
|
||||||
|
"fi1vkJcVW4+MdXjWmhALcPA4dO7Y2Ljiu6VxIxQORRO1DyiCjAs1AVMQxgPAAY41\n"
|
||||||
|
"YR4Q2EkCgYEA4zE0oytg97aVaBY9CKi7/PqR+NI/uEvfoQCnT+ddaJgp/qsspuXo\n"
|
||||||
|
"tJt94p13ANd8O7suqQTVNvbZq1rX10xQjJZ9nvlqQa6iHkN6Epq31XBK3Z+acjIV\n"
|
||||||
|
"A2rAgKBByjz9/CpKHqnOsrTWU1Y7x416IG4BZt42hHdrxRH98/wiDH8CgYEA2djj\n"
|
||||||
|
"AjwgK+MwDnshwT1NNgCSP/2ZHatBAykZ5BCs9BJ6MNYqqXVGYoqs5Z5kSkow+Db3\n"
|
||||||
|
"pipkEieo5w2Rd5zkolTThaVCvRkSe5wRiBpZhaeY+b0UFwavGCb6zU/MmJIMDPiI\n"
|
||||||
|
"2iRGeCXgQDvIS/icIqzbTtp6dZaoMgG7LdSR7TcCgYBtxGhaLas8A8tL7vKuLFgn\n"
|
||||||
|
"cij0vyBqOr5hW596y54l2t7vXGTGfm5gVIAN7WaB0ZsEgPuaTet2Eu44DDwcmZKR\n"
|
||||||
|
"WmR3Wqor8eQCGzfvpTEMvqRtT5+fbPMaI4m+m68ttyo/m28UQZbMYPLscM2RLJnE\n"
|
||||||
|
"8WFcAiD0/33iST8ZksggoQKBgQDE/7Yhsj+hkHxHzB+1QPtOp2uaBHnvc4uCESwB\n"
|
||||||
|
"qvbMbN0kxrejsJLqz98UcozdBYSNIiAHmvQN2uGJuCJhGXdEORNjGxRkLoUhVPwh\n"
|
||||||
|
"qTplfC8BQHQncnrqi21oNw6ctg3BuQsAwaccRZwqWiWCVhrT3J8iCr6NEaWeOySK\n"
|
||||||
|
"iF1CNwKBgQCRpkkZArlccwS0kMvkK+tQ1rG2xWm7c05G34gP/g6dHFRy0gPNMyvi\n"
|
||||||
|
"SkiLTJmQIEZSAEiq0FFgcVwM6o556ftvQZuwDp5rHUbwqnHCpMJKpD9aJpStvfPi\n"
|
||||||
|
"4p9JbYdaGqnq4eoNKemmGnbUof0dR9Zr0lGmcMTwwzBib+4E1d7soA==\n"
|
||||||
|
"-----END RSA PRIVATE KEY-----\n";
|
||||||
|
|
||||||
|
// Certificate signed with key above:
|
||||||
|
// `openssl req -x509 -key private.pem -out cert.pem -subj "/CN=bar/OU=test/O=example.com/" -new`
|
||||||
|
static const char *certificate_pem =
|
||||||
|
"-----BEGIN CERTIFICATE-----\n"
|
||||||
|
"MIIC5zCCAc+gAwIBAgIJAOq8A/cmpxF5MA0GCSqGSIb3DQEBCwUAMDMxDDAKBgNV\n"
|
||||||
|
"BAMMA2JhcjENMAsGA1UECwwEdGVzdDEUMBIGA1UECgwLZXhhbXBsZS5jb20wHhcN\n"
|
||||||
|
"MTcwODAzMTE1MDI2WhcNMTgwODAzMTE1MDI2WjAzMQwwCgYDVQQDDANiYXIxDTAL\n"
|
||||||
|
"BgNVBAsMBHRlc3QxFDASBgNVBAoMC2V4YW1wbGUuY29tMIIBIjANBgkqhkiG9w0B\n"
|
||||||
|
"AQEFAAOCAQ8AMIIBCgKCAQEAwVUwmVbc+ffOy2+RivxBpgleTVN6bUa0q7jNYB+A\n"
|
||||||
|
"seFQYaYqEGfa+VGdxSGo+8DV1KT9+fNEd5243gXn/tcjtMItKeB+oAQc64s9lIFl\n"
|
||||||
|
"YuR8bpq1ibr33iW2elnnv9mpecqohdCVwM2McWveoPyb7MwlwVuhqexOzJO29bqJ\n"
|
||||||
|
"cazLbtkfZETK0oBx53/ylA4Y6nE9Pa46jW2qhj+KShf1iBg+gAyt3eI+wI2Wmub1\n"
|
||||||
|
"WxLLH8D2w+kow8QhQOa8dHCkRRw771JxVO5+d+Y/Y+x9B1HgF4q0q9xUlhWLK2TR\n"
|
||||||
|
"4ChBFzXe47sAHsSqi/pl5JbwYrHPOE/VEBLukmjL8NFCSQIDAQABMA0GCSqGSIb3\n"
|
||||||
|
"DQEBCwUAA4IBAQCamrwdEhNmY2GCQWq6U90Q3XQT6w0HHW/JmtuGeF+BTpVr12gN\n"
|
||||||
|
"/UvEXTo9geWbGcCTjaMMURTa7mUjVUIttIWEVHZMKqBuvsUM1RcuOEX/vitaJJ8K\n"
|
||||||
|
"Sw4upjCNa3ZxUXmSA1FBixZgDzFqjEeSiaJjMU0yX5W2p1T4iNYtF3YqzMF5AWSI\n"
|
||||||
|
"qCO7gP5ezPyg5kDnrO3V7DBgnDiqawq7Pyn9DynKNULX/hc1yls/R+ebb2u8Z+h5\n"
|
||||||
|
"W4YXbzGZb8qdT27qIZaHD638tL6liLkI6UE4KCXH8X8e3fqdbmqvwrq403nOGmsP\n"
|
||||||
|
"cbJb2PEXibNEQG234riKxm7x7vNDLL79Jwtc\n"
|
||||||
|
"-----END CERTIFICATE-----\n";
|
||||||
|
|
||||||
|
static bool set_component(unsigned char *in_ptr, const BIGNUM *bn, int element_len) {
|
||||||
|
int real_len = BN_num_bytes(bn);
|
||||||
|
|
||||||
|
if(real_len > element_len) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
memset(in_ptr, 0, (size_t)(element_len - real_len));
|
||||||
|
in_ptr += element_len - real_len;
|
||||||
|
BN_bn2bin(bn, in_ptr);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool prepare_rsa_signature(const unsigned char *in, unsigned int in_len, unsigned char *out, unsigned int *out_len, int nid) {
|
||||||
|
X509_SIG digestInfo;
|
||||||
|
X509_ALGOR algor;
|
||||||
|
ASN1_TYPE parameter;
|
||||||
|
ASN1_OCTET_STRING digest;
|
||||||
|
unsigned char data[1024];
|
||||||
|
|
||||||
|
memcpy(data, in, in_len);
|
||||||
|
|
||||||
|
digestInfo.algor = &algor;
|
||||||
|
digestInfo.algor->algorithm = OBJ_nid2obj(nid);
|
||||||
|
digestInfo.algor->parameter = ¶meter;
|
||||||
|
digestInfo.algor->parameter->type = V_ASN1_NULL;
|
||||||
|
digestInfo.algor->parameter->value.ptr = NULL;
|
||||||
|
digestInfo.digest = &digest;
|
||||||
|
digestInfo.digest->data = data;
|
||||||
|
digestInfo.digest->length = (int)in_len;
|
||||||
|
*out_len = (unsigned int)i2d_X509_SIG(&digestInfo, &out);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void import_key(unsigned char slot, unsigned char pin_policy) {
|
||||||
|
ykpiv_rc res;
|
||||||
|
{
|
||||||
|
unsigned char pp = pin_policy;
|
||||||
|
unsigned char tp = YKPIV_TOUCHPOLICY_DEFAULT;
|
||||||
|
EVP_PKEY *private_key = NULL;
|
||||||
|
BIO *bio = NULL;
|
||||||
|
RSA *rsa_private_key = NULL;
|
||||||
|
unsigned char e[4];
|
||||||
|
unsigned char p[128];
|
||||||
|
unsigned char q[128];
|
||||||
|
unsigned char dmp1[128];
|
||||||
|
unsigned char dmq1[128];
|
||||||
|
unsigned char iqmp[128];
|
||||||
|
int element_len = 128;
|
||||||
|
|
||||||
|
bio = BIO_new_mem_buf(private_key_pem, strlen(private_key_pem));
|
||||||
|
private_key = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL);
|
||||||
|
ck_assert_ptr_nonnull(private_key);
|
||||||
|
BIO_free(bio);
|
||||||
|
rsa_private_key = EVP_PKEY_get1_RSA(private_key);
|
||||||
|
ck_assert_ptr_nonnull(rsa_private_key);
|
||||||
|
ck_assert(set_component(e, rsa_private_key->e, 3));
|
||||||
|
ck_assert(set_component(p, rsa_private_key->p, element_len));
|
||||||
|
ck_assert(set_component(q, rsa_private_key->q, element_len));
|
||||||
|
ck_assert(set_component(dmp1, rsa_private_key->dmp1, element_len));
|
||||||
|
ck_assert(set_component(dmq1, rsa_private_key->dmq1, element_len));
|
||||||
|
ck_assert(set_component(iqmp, rsa_private_key->iqmp, element_len));
|
||||||
|
|
||||||
|
// Try wrong algorithm, fail.
|
||||||
|
res = ykpiv_import_private_key(g_state,
|
||||||
|
slot,
|
||||||
|
YKPIV_ALGO_RSA1024,
|
||||||
|
p, element_len,
|
||||||
|
q, element_len,
|
||||||
|
dmp1, element_len,
|
||||||
|
dmq1, element_len,
|
||||||
|
iqmp, element_len,
|
||||||
|
NULL, 0,
|
||||||
|
pp, tp);
|
||||||
|
ck_assert_int_eq(res, YKPIV_ALGORITHM_ERROR);
|
||||||
|
|
||||||
|
// Try right algorithm
|
||||||
|
res = ykpiv_import_private_key(g_state,
|
||||||
|
slot,
|
||||||
|
YKPIV_ALGO_RSA2048,
|
||||||
|
p, element_len,
|
||||||
|
q, element_len,
|
||||||
|
dmp1, element_len,
|
||||||
|
dmq1, element_len,
|
||||||
|
iqmp, element_len,
|
||||||
|
NULL, 0,
|
||||||
|
pp, tp);
|
||||||
|
ck_assert_int_eq(res, YKPIV_OK);
|
||||||
|
EVP_PKEY_free(private_key);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use imported key to decrypt a thing. See that it works.
|
||||||
|
{
|
||||||
|
BIO *bio = NULL;
|
||||||
|
X509 *cert = NULL;
|
||||||
|
EVP_PKEY *pub_key = NULL;
|
||||||
|
unsigned char secret[32];
|
||||||
|
unsigned char secret2[32];
|
||||||
|
unsigned char data[256];
|
||||||
|
int len;
|
||||||
|
size_t len2 = sizeof(data);
|
||||||
|
RSA *rsa = NULL;
|
||||||
|
bio = BIO_new_mem_buf(certificate_pem, strlen(certificate_pem));
|
||||||
|
cert = PEM_read_bio_X509(bio, NULL, NULL, NULL);
|
||||||
|
ck_assert_ptr_nonnull(cert);
|
||||||
|
BIO_free(bio);
|
||||||
|
pub_key = X509_get_pubkey(cert);
|
||||||
|
ck_assert_ptr_nonnull(pub_key);
|
||||||
|
rsa = EVP_PKEY_get1_RSA(pub_key);
|
||||||
|
ck_assert_ptr_nonnull(rsa);
|
||||||
|
ck_assert_int_gt(RAND_pseudo_bytes(secret, sizeof(secret)), 0);
|
||||||
|
len = RSA_public_encrypt(sizeof(secret), secret, data, rsa, RSA_PKCS1_PADDING);
|
||||||
|
ck_assert_int_ge(len, 0);
|
||||||
|
res = ykpiv_verify(g_state, "123456", NULL);
|
||||||
|
ck_assert_int_eq(res, YKPIV_OK);
|
||||||
|
res = ykpiv_decipher_data(g_state, data, (size_t)len, data, &len2, YKPIV_ALGO_RSA2048, slot);
|
||||||
|
ck_assert_int_eq(res, YKPIV_OK);
|
||||||
|
len = RSA_padding_check_PKCS1_type_2(secret2, sizeof(secret2), data + 1, len2 - 1, RSA_size(rsa));
|
||||||
|
ck_assert_int_eq(len, sizeof(secret));
|
||||||
|
ck_assert_int_eq(memcmp(secret, secret2, sizeof(secret)), 0);
|
||||||
|
X509_free(cert);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
START_TEST(test_import_key) {
|
||||||
|
ykpiv_rc res;
|
||||||
|
|
||||||
|
import_key(0x9a, YKPIV_PINPOLICY_DEFAULT);
|
||||||
|
|
||||||
|
// Verify certificate
|
||||||
|
{
|
||||||
|
BIO *bio = NULL;
|
||||||
|
X509 *cert = NULL;
|
||||||
|
RSA *rsa = NULL;
|
||||||
|
EVP_PKEY *pub_key = NULL;
|
||||||
|
const EVP_MD *md = EVP_sha256();
|
||||||
|
EVP_MD_CTX *mdctx;
|
||||||
|
|
||||||
|
unsigned char signature[1024];
|
||||||
|
unsigned char encoded[1024];
|
||||||
|
unsigned char data[1024];
|
||||||
|
unsigned char signinput[1024];
|
||||||
|
unsigned char rand[128];
|
||||||
|
|
||||||
|
size_t sig_len = sizeof(signature);
|
||||||
|
size_t padlen = 256;
|
||||||
|
unsigned int enc_len;
|
||||||
|
unsigned int data_len;
|
||||||
|
|
||||||
|
bio = BIO_new_mem_buf(certificate_pem, strlen(certificate_pem));
|
||||||
|
cert = PEM_read_bio_X509(bio, NULL, NULL, NULL);
|
||||||
|
ck_assert_ptr_nonnull(cert);
|
||||||
|
BIO_free(bio);
|
||||||
|
pub_key = X509_get_pubkey(cert);
|
||||||
|
ck_assert_ptr_nonnull(pub_key);
|
||||||
|
rsa = EVP_PKEY_get1_RSA(pub_key);
|
||||||
|
ck_assert_ptr_nonnull(rsa);
|
||||||
|
|
||||||
|
ck_assert_int_gt(RAND_pseudo_bytes(rand, 128), 0);
|
||||||
|
mdctx = EVP_MD_CTX_create();
|
||||||
|
EVP_DigestInit_ex(mdctx, md, NULL);
|
||||||
|
EVP_DigestUpdate(mdctx, rand, 128);
|
||||||
|
EVP_DigestFinal_ex(mdctx, data, &data_len);
|
||||||
|
|
||||||
|
prepare_rsa_signature(data, data_len, encoded, &enc_len, EVP_MD_type(md));
|
||||||
|
ck_assert_int_ne(RSA_padding_add_PKCS1_type_1(signinput, padlen, encoded, enc_len), 0);
|
||||||
|
res = ykpiv_sign_data(g_state, signinput, padlen, signature, &sig_len, YKPIV_ALGO_RSA2048, 0x9a);
|
||||||
|
ck_assert_int_eq(res, YKPIV_OK);
|
||||||
|
|
||||||
|
ck_assert_int_eq(RSA_verify(EVP_MD_type(md), data, data_len, signature, sig_len, rsa), 1);
|
||||||
|
|
||||||
|
X509_free(cert);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify that imported key can not be attested
|
||||||
|
{
|
||||||
|
unsigned char attest[2048];
|
||||||
|
size_t attest_len = sizeof(attest);
|
||||||
|
ykpiv_devmodel model;
|
||||||
|
model = ykpiv_util_devicemodel(g_state);
|
||||||
|
res = ykpiv_attest(g_state, 0x9a, attest, &attest_len);
|
||||||
|
if (model == DEVTYPE_YK4) {
|
||||||
|
ck_assert_int_eq(res, YKPIV_GENERIC_ERROR);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ck_assert_int_eq(res, YKPIV_NOT_SUPPORTED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST(test_pin_policy_always) {
|
||||||
|
ykpiv_rc res;
|
||||||
|
|
||||||
|
{
|
||||||
|
ykpiv_devmodel model;
|
||||||
|
model = ykpiv_util_devicemodel(g_state);
|
||||||
|
// Only works with YK4. NEO should skip.
|
||||||
|
if (model != DEVTYPE_YK4) {
|
||||||
|
fprintf(stderr, "WARNING: Not supported with Yubikey NEO. Test skipped.\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
import_key(0x9e, YKPIV_PINPOLICY_ALWAYS);
|
||||||
|
|
||||||
|
// Verify certificate
|
||||||
|
{
|
||||||
|
BIO *bio = NULL;
|
||||||
|
X509 *cert = NULL;
|
||||||
|
RSA *rsa = NULL;
|
||||||
|
EVP_PKEY *pub_key = NULL;
|
||||||
|
const EVP_MD *md = EVP_sha256();
|
||||||
|
EVP_MD_CTX *mdctx;
|
||||||
|
|
||||||
|
unsigned char signature[1024];
|
||||||
|
unsigned char encoded[1024];
|
||||||
|
unsigned char data[1024];
|
||||||
|
unsigned char signinput[1024];
|
||||||
|
unsigned char rand[128];
|
||||||
|
|
||||||
|
size_t sig_len = sizeof(signature);
|
||||||
|
size_t padlen = 256;
|
||||||
|
unsigned int enc_len;
|
||||||
|
unsigned int data_len;
|
||||||
|
|
||||||
|
bio = BIO_new_mem_buf(certificate_pem, strlen(certificate_pem));
|
||||||
|
cert = PEM_read_bio_X509(bio, NULL, NULL, NULL);
|
||||||
|
ck_assert_ptr_nonnull(cert);
|
||||||
|
BIO_free(bio);
|
||||||
|
pub_key = X509_get_pubkey(cert);
|
||||||
|
ck_assert_ptr_nonnull(pub_key);
|
||||||
|
rsa = EVP_PKEY_get1_RSA(pub_key);
|
||||||
|
ck_assert_ptr_nonnull(rsa);
|
||||||
|
|
||||||
|
ck_assert_int_gt(RAND_pseudo_bytes(rand, 128), 0);
|
||||||
|
mdctx = EVP_MD_CTX_create();
|
||||||
|
EVP_DigestInit_ex(mdctx, md, NULL);
|
||||||
|
EVP_DigestUpdate(mdctx, rand, 128);
|
||||||
|
EVP_DigestFinal_ex(mdctx, data, &data_len);
|
||||||
|
|
||||||
|
prepare_rsa_signature(data, data_len, encoded, &enc_len, EVP_MD_type(md));
|
||||||
|
ck_assert_int_ne(RSA_padding_add_PKCS1_type_1(signinput, padlen, encoded, enc_len), 0);
|
||||||
|
|
||||||
|
// Sign without verify: fail
|
||||||
|
res = ykpiv_sign_data(g_state, signinput, padlen, signature, &sig_len, YKPIV_ALGO_RSA2048, 0x9e);
|
||||||
|
ck_assert_int_eq(res, YKPIV_AUTHENTICATION_ERROR);
|
||||||
|
|
||||||
|
// Sign with verify: pass
|
||||||
|
res = ykpiv_verify(g_state, "123456", NULL);
|
||||||
|
ck_assert_int_eq(res, YKPIV_OK);
|
||||||
|
res = ykpiv_sign_data(g_state, signinput, padlen, signature, &sig_len, YKPIV_ALGO_RSA2048, 0x9e);
|
||||||
|
ck_assert_int_eq(res, YKPIV_OK);
|
||||||
|
|
||||||
|
// Sign again without verify: fail
|
||||||
|
res = ykpiv_sign_data(g_state, signinput, padlen, signature, &sig_len, YKPIV_ALGO_RSA2048, 0x9e);
|
||||||
|
ck_assert_int_eq(res, YKPIV_AUTHENTICATION_ERROR);
|
||||||
|
|
||||||
|
// Sign again with verify: pass
|
||||||
|
res = ykpiv_verify(g_state, "123456", NULL);
|
||||||
|
ck_assert_int_eq(res, YKPIV_OK);
|
||||||
|
res = ykpiv_sign_data(g_state, signinput, padlen, signature, &sig_len, YKPIV_ALGO_RSA2048, 0x9e);
|
||||||
|
ck_assert_int_eq(res, YKPIV_OK);
|
||||||
|
|
||||||
|
ck_assert_int_eq(RSA_verify(EVP_MD_type(md), data, data_len, signature, sig_len, rsa), 1);
|
||||||
|
|
||||||
|
X509_free(cert);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST(test_generate_key) {
|
||||||
|
ykpiv_rc res;
|
||||||
|
uint8_t *mod, *exp;
|
||||||
|
size_t mod_len, exp_len;
|
||||||
|
res = ykpiv_util_write_cert(g_state, YKPIV_KEY_AUTHENTICATION, (uint8_t*)g_cert, sizeof(g_cert), YKPIV_CERTINFO_UNCOMPRESSED);
|
||||||
|
ck_assert_int_eq(res, YKPIV_OK);
|
||||||
|
res = ykpiv_util_generate_key(g_state,
|
||||||
|
YKPIV_KEY_AUTHENTICATION,
|
||||||
|
YKPIV_ALGO_RSA2048,
|
||||||
|
YKPIV_PINPOLICY_DEFAULT,
|
||||||
|
YKPIV_TOUCHPOLICY_DEFAULT,
|
||||||
|
&mod,
|
||||||
|
&mod_len,
|
||||||
|
&exp,
|
||||||
|
&exp_len,
|
||||||
|
NULL,
|
||||||
|
NULL);
|
||||||
|
ck_assert_int_eq(res, YKPIV_OK);
|
||||||
|
res = ykpiv_util_free(g_state, mod);
|
||||||
|
ck_assert_int_eq(res, YKPIV_OK);
|
||||||
|
res = ykpiv_util_free(g_state, exp);
|
||||||
|
ck_assert_int_eq(res, YKPIV_OK);
|
||||||
|
|
||||||
|
// Verify that imported key can be attested
|
||||||
|
{
|
||||||
|
ykpiv_devmodel model;
|
||||||
|
unsigned char attest[2048];
|
||||||
|
size_t attest_len = sizeof(attest);
|
||||||
|
model = ykpiv_util_devicemodel(g_state);
|
||||||
|
res = ykpiv_attest(g_state, YKPIV_KEY_AUTHENTICATION, attest, &attest_len);
|
||||||
|
// Only works with YK4. NEO should error.
|
||||||
|
if (model == DEVTYPE_YK4) {
|
||||||
|
ck_assert_int_eq(res, YKPIV_OK);
|
||||||
|
ck_assert_int_gt(attest_len, 0);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ck_assert_int_eq(res, YKPIV_NOT_SUPPORTED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST(test_authenticate) {
|
||||||
|
ykpiv_rc res;
|
||||||
|
const char *default_mgm_key = "010203040506070801020304050607080102030405060708";
|
||||||
|
const char *mgm_key = "112233445566778811223344556677881122334455667788";
|
||||||
|
const char *weak_mgm_key = "FEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFE";
|
||||||
|
unsigned char key[24];
|
||||||
|
size_t key_len = sizeof(key);
|
||||||
|
|
||||||
|
// Try new key, fail.
|
||||||
|
res = ykpiv_hex_decode(mgm_key, strlen(mgm_key), key, &key_len);
|
||||||
|
ck_assert_int_eq(res, YKPIV_OK);
|
||||||
|
res = ykpiv_authenticate(g_state, key);
|
||||||
|
ck_assert_int_eq(res, YKPIV_AUTHENTICATION_ERROR);
|
||||||
|
|
||||||
|
// Try default key, succeed
|
||||||
|
res = ykpiv_hex_decode(default_mgm_key, strlen(default_mgm_key), key, &key_len);
|
||||||
|
ck_assert_int_eq(res, YKPIV_OK);
|
||||||
|
res = ykpiv_authenticate(g_state, key);
|
||||||
|
ck_assert_int_eq(res, YKPIV_OK);
|
||||||
|
|
||||||
|
// Verify same key works twice
|
||||||
|
res = ykpiv_hex_decode(default_mgm_key, strlen(default_mgm_key), key, &key_len);
|
||||||
|
ck_assert_int_eq(res, YKPIV_OK);
|
||||||
|
res = ykpiv_authenticate(g_state, key);
|
||||||
|
ck_assert_int_eq(res, YKPIV_OK);
|
||||||
|
|
||||||
|
// Change to new key
|
||||||
|
res = ykpiv_hex_decode(mgm_key, strlen(mgm_key), key, &key_len);
|
||||||
|
ck_assert_int_eq(res, YKPIV_OK);
|
||||||
|
res = ykpiv_set_mgmkey(g_state, key);
|
||||||
|
ck_assert_int_eq(res, YKPIV_OK);
|
||||||
|
|
||||||
|
// Try new key, succeed.
|
||||||
|
res = ykpiv_hex_decode(mgm_key, strlen(mgm_key), key, &key_len);
|
||||||
|
ck_assert_int_eq(res, YKPIV_OK);
|
||||||
|
res = ykpiv_authenticate(g_state, key);
|
||||||
|
ck_assert_int_eq(res, YKPIV_OK);
|
||||||
|
|
||||||
|
// Change back to default key
|
||||||
|
res = ykpiv_hex_decode(default_mgm_key, strlen(default_mgm_key), key, &key_len);
|
||||||
|
ck_assert_int_eq(res, YKPIV_OK);
|
||||||
|
res = ykpiv_set_mgmkey(g_state, key);
|
||||||
|
ck_assert_int_eq(res, YKPIV_OK);
|
||||||
|
|
||||||
|
// Try default key, succeed
|
||||||
|
res = ykpiv_hex_decode(default_mgm_key, strlen(default_mgm_key), key, &key_len);
|
||||||
|
ck_assert_int_eq(res, YKPIV_OK);
|
||||||
|
res = ykpiv_authenticate(g_state, key);
|
||||||
|
ck_assert_int_eq(res, YKPIV_OK);
|
||||||
|
|
||||||
|
// Try to set a weak key, fail
|
||||||
|
res = ykpiv_hex_decode(weak_mgm_key, strlen(weak_mgm_key), key, &key_len);
|
||||||
|
ck_assert_int_eq(res, YKPIV_OK);
|
||||||
|
res = ykpiv_set_mgmkey(g_state, key);
|
||||||
|
ck_assert_int_eq(res, YKPIV_KEY_ERROR);
|
||||||
|
|
||||||
|
// Try default key, succeed
|
||||||
|
res = ykpiv_hex_decode(default_mgm_key, strlen(default_mgm_key), key, &key_len);
|
||||||
|
ck_assert_int_eq(res, YKPIV_OK);
|
||||||
|
res = ykpiv_authenticate(g_state, key);
|
||||||
|
ck_assert_int_eq(res, YKPIV_OK);
|
||||||
|
}
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST(test_change_pin) {
|
||||||
|
ykpiv_rc res;
|
||||||
|
|
||||||
|
res = ykpiv_verify(g_state, "123456", NULL);
|
||||||
|
ck_assert_int_eq(res, YKPIV_OK);
|
||||||
|
|
||||||
|
res = ykpiv_change_pin(g_state, "123456", 6, "ABCDEF", 6, NULL);
|
||||||
|
ck_assert_int_eq(res, YKPIV_OK);
|
||||||
|
|
||||||
|
res = ykpiv_verify(g_state, "123456", NULL);
|
||||||
|
ck_assert_int_eq(res, YKPIV_WRONG_PIN);
|
||||||
|
|
||||||
|
res = ykpiv_verify(g_state, "ABCDEF", NULL);
|
||||||
|
ck_assert_int_eq(res, YKPIV_OK);
|
||||||
|
|
||||||
|
res = ykpiv_change_pin(g_state, "ABCDEF", 6, "123456", 6, NULL);
|
||||||
|
ck_assert_int_eq(res, YKPIV_OK);
|
||||||
|
|
||||||
|
res = ykpiv_verify(g_state, "ABCDEF", NULL);
|
||||||
|
ck_assert_int_eq(res, YKPIV_WRONG_PIN);
|
||||||
|
|
||||||
|
res = ykpiv_verify(g_state, "123456", NULL);
|
||||||
|
ck_assert_int_eq(res, YKPIV_OK);
|
||||||
|
}
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST(test_change_puk) {
|
||||||
|
ykpiv_rc res;
|
||||||
|
|
||||||
|
res = ykpiv_unblock_pin(g_state, "12345678", 8, "123456", 6, NULL);
|
||||||
|
ck_assert_int_eq(res, YKPIV_OK);
|
||||||
|
|
||||||
|
res = ykpiv_change_puk(g_state, "12345678", 8, "ABCDEFGH", 8, NULL);
|
||||||
|
ck_assert_int_eq(res, YKPIV_OK);
|
||||||
|
|
||||||
|
res = ykpiv_unblock_pin(g_state, "12345678", 8, "123456", 6, NULL);
|
||||||
|
ck_assert_int_eq(res, YKPIV_WRONG_PIN);
|
||||||
|
|
||||||
|
res = ykpiv_unblock_pin(g_state, "ABCDEFGH", 8, "123456", 6, NULL);
|
||||||
|
ck_assert_int_eq(res, YKPIV_OK);
|
||||||
|
|
||||||
|
res = ykpiv_change_puk(g_state, "ABCDEFGH", 8, "12345678", 8, NULL);
|
||||||
|
ck_assert_int_eq(res, YKPIV_OK);
|
||||||
|
|
||||||
|
res = ykpiv_unblock_pin(g_state, "ABCDEFGH", 8, "123456", 6, NULL);
|
||||||
|
ck_assert_int_eq(res, YKPIV_WRONG_PIN);
|
||||||
|
|
||||||
|
res = ykpiv_unblock_pin(g_state, "12345678", 8, "123456", 6, NULL);
|
||||||
|
ck_assert_int_eq(res, YKPIV_OK);
|
||||||
|
}
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
static int block_and_reset() {
|
||||||
|
ykpiv_rc res;
|
||||||
|
int tries = 100;
|
||||||
|
int tries_until_blocked;
|
||||||
|
|
||||||
|
tries_until_blocked = 0;
|
||||||
|
while (tries) {
|
||||||
|
res = ykpiv_verify(g_state, "AAAAAA", &tries);
|
||||||
|
if (res == YKPIV_PIN_LOCKED)
|
||||||
|
break;
|
||||||
|
ck_assert_int_eq(res, YKPIV_WRONG_PIN);
|
||||||
|
tries_until_blocked++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify no PIN retries remaining
|
||||||
|
tries = 100;
|
||||||
|
res = ykpiv_get_pin_retries(g_state, &tries);
|
||||||
|
ck_assert_int_eq(res, YKPIV_OK);
|
||||||
|
ck_assert_int_eq(tries, 0);
|
||||||
|
|
||||||
|
tries = 100;
|
||||||
|
while (tries) {
|
||||||
|
res = ykpiv_change_puk(g_state, "AAAAAAAA", 8, "AAAAAAAA", 8, &tries);
|
||||||
|
if (res == YKPIV_PIN_LOCKED)
|
||||||
|
break;
|
||||||
|
ck_assert_int_eq(res, YKPIV_WRONG_PIN);
|
||||||
|
}
|
||||||
|
res = ykpiv_util_reset(g_state);
|
||||||
|
ck_assert_int_eq(res, YKPIV_OK);
|
||||||
|
return tries_until_blocked;
|
||||||
|
}
|
||||||
|
|
||||||
|
START_TEST(test_reset) {
|
||||||
|
ykpiv_rc res;
|
||||||
|
int tries = 100;
|
||||||
|
int tries_until_blocked;
|
||||||
|
|
||||||
|
// Block and reset, with default PIN retries
|
||||||
|
tries_until_blocked = block_and_reset();
|
||||||
|
ck_assert_int_eq(tries_until_blocked, 3);
|
||||||
|
|
||||||
|
// Authenticate and increase PIN retries
|
||||||
|
test_authenticate(0);
|
||||||
|
res = ykpiv_verify(g_state, "123456", NULL);
|
||||||
|
ck_assert_int_eq(res, YKPIV_OK);
|
||||||
|
res = ykpiv_set_pin_retries(g_state, 8, 3);
|
||||||
|
ck_assert_int_eq(res, YKPIV_OK);
|
||||||
|
|
||||||
|
// Block and reset again, verifying increased PIN retries
|
||||||
|
tries_until_blocked = block_and_reset();
|
||||||
|
ck_assert_int_eq(tries_until_blocked, 8);
|
||||||
|
// Note: defaults back to 3 retries after reset
|
||||||
|
|
||||||
|
// Verify default (3) PIN retries remaining
|
||||||
|
tries = 0;
|
||||||
|
res = ykpiv_get_pin_retries(g_state, &tries);
|
||||||
|
ck_assert_int_eq(res, YKPIV_OK);
|
||||||
|
ck_assert_int_eq(tries, 3);
|
||||||
|
|
||||||
|
// Verify still (3) PIN retries remaining
|
||||||
|
tries = 0;
|
||||||
|
res = ykpiv_get_pin_retries(g_state, &tries);
|
||||||
|
ck_assert_int_eq(res, YKPIV_OK);
|
||||||
|
ck_assert_int_eq(tries, 3);
|
||||||
|
|
||||||
|
// Try wrong PIN
|
||||||
|
res = ykpiv_verify(g_state, "AAAAAA", &tries);
|
||||||
|
ck_assert_int_eq(res, YKPIV_WRONG_PIN);
|
||||||
|
|
||||||
|
// Verify 2 PIN retries remaining
|
||||||
|
tries = 0;
|
||||||
|
res = ykpiv_get_pin_retries(g_state, &tries);
|
||||||
|
ck_assert_int_eq(res, YKPIV_OK);
|
||||||
|
ck_assert_int_eq(tries, 2);
|
||||||
|
|
||||||
|
// Verify correct PIN
|
||||||
|
tries = 100;
|
||||||
|
res = ykpiv_verify(g_state, "123456", &tries);
|
||||||
|
ck_assert_int_eq(res, YKPIV_OK);
|
||||||
|
|
||||||
|
// Verify back to 3 PIN retries remaining
|
||||||
|
tries = 0;
|
||||||
|
res = ykpiv_get_pin_retries(g_state, &tries);
|
||||||
|
ck_assert_int_eq(res, YKPIV_OK);
|
||||||
|
ck_assert_int_eq(tries, 3);
|
||||||
|
}
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
|
||||||
|
struct t_alloc_data{
|
||||||
|
uint32_t count;
|
||||||
|
} g_alloc_data;
|
||||||
|
|
||||||
|
static void* _test_alloc(void *data, size_t cb) {
|
||||||
|
ck_assert_ptr_eq(data, &g_alloc_data);
|
||||||
|
((struct t_alloc_data*)data)->count++;
|
||||||
|
return calloc(cb, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void * _test_realloc(void *data, void *p, size_t cb) {
|
||||||
|
ck_assert_ptr_eq(data, &g_alloc_data);
|
||||||
|
return realloc(p, cb);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _test_free(void *data, void *p) {
|
||||||
|
fflush(stderr);
|
||||||
|
ck_assert_ptr_eq(data, &g_alloc_data);
|
||||||
|
((struct t_alloc_data*)data)->count--;
|
||||||
|
free(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
ykpiv_allocator test_allocator_cbs = {
|
||||||
|
.pfn_alloc = _test_alloc,
|
||||||
|
.pfn_realloc = _test_realloc,
|
||||||
|
.pfn_free = _test_free,
|
||||||
|
.alloc_data = &g_alloc_data
|
||||||
|
};
|
||||||
|
|
||||||
|
uint8_t *alloc_auth_cert() {
|
||||||
|
ykpiv_rc res;
|
||||||
|
uint8_t *read_cert = NULL;
|
||||||
|
size_t read_cert_len = 0;
|
||||||
|
|
||||||
|
res = ykpiv_util_write_cert(g_state, YKPIV_KEY_AUTHENTICATION, (uint8_t*)g_cert, sizeof(g_cert), YKPIV_CERTINFO_UNCOMPRESSED);
|
||||||
|
ck_assert_int_eq(res, YKPIV_OK);
|
||||||
|
|
||||||
|
res = ykpiv_util_read_cert(g_state, YKPIV_KEY_AUTHENTICATION, &read_cert, &read_cert_len);
|
||||||
|
ck_assert_int_eq(res, YKPIV_OK);
|
||||||
|
ck_assert_ptr_nonnull(read_cert);
|
||||||
|
ck_assert_int_eq(read_cert_len, sizeof(g_cert));
|
||||||
|
ck_assert_mem_eq(g_cert, read_cert, sizeof(g_cert));
|
||||||
|
return read_cert;
|
||||||
|
}
|
||||||
|
|
||||||
|
START_TEST(test_allocator) {
|
||||||
|
ykpiv_rc res;
|
||||||
|
const ykpiv_allocator allocator;
|
||||||
|
uint8_t *cert1, *cert2;
|
||||||
|
|
||||||
|
res = ykpiv_done(g_state);
|
||||||
|
ck_assert_int_eq(res, YKPIV_OK);
|
||||||
|
g_state = NULL;
|
||||||
|
|
||||||
|
res = ykpiv_init_with_allocator(&g_state, false, &test_allocator_cbs);
|
||||||
|
ck_assert_int_eq(res, YKPIV_OK);
|
||||||
|
ck_assert_ptr_nonnull(g_state);
|
||||||
|
|
||||||
|
// Verify we can communicate with device and make some allocations
|
||||||
|
res = ykpiv_connect(g_state, NULL);
|
||||||
|
ck_assert_int_eq(res, YKPIV_OK);
|
||||||
|
test_authenticate(0);
|
||||||
|
cert1 = alloc_auth_cert();
|
||||||
|
cert2 = alloc_auth_cert();
|
||||||
|
|
||||||
|
// Verify allocations went through custom allocator, and still live
|
||||||
|
ck_assert_int_gt(g_alloc_data.count, 1);
|
||||||
|
|
||||||
|
// Free and shutdown everything
|
||||||
|
ykpiv_util_free(g_state, cert2);
|
||||||
|
ykpiv_util_free(g_state, cert1);
|
||||||
|
res = ykpiv_disconnect(g_state);
|
||||||
|
ck_assert_int_eq(res, YKPIV_OK);
|
||||||
|
res = ykpiv_done(g_state);
|
||||||
|
ck_assert_int_eq(res, YKPIV_OK);
|
||||||
|
|
||||||
|
// Verify equal number of frees as allocations
|
||||||
|
ck_assert_int_eq(g_alloc_data.count, 0);
|
||||||
|
|
||||||
|
// Clear g_state so teardown() is skipped
|
||||||
|
g_state = NULL;
|
||||||
|
}
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST(test_pin_cache) {
|
||||||
|
ykpiv_rc res;
|
||||||
|
ykpiv_state *local_state;
|
||||||
|
unsigned char data[256];
|
||||||
|
int len = sizeof(data);
|
||||||
|
size_t len2 = sizeof(data);
|
||||||
|
|
||||||
|
import_key(0x9a, YKPIV_PINPOLICY_DEFAULT);
|
||||||
|
|
||||||
|
// Disconnect and reconnect to device to guarantee it is not authed
|
||||||
|
res = ykpiv_disconnect(g_state);
|
||||||
|
ck_assert_int_eq(res, YKPIV_OK);
|
||||||
|
res = ykpiv_done(g_state);
|
||||||
|
ck_assert_int_eq(res, YKPIV_OK);
|
||||||
|
res = ykpiv_init(&g_state, true);
|
||||||
|
ck_assert_int_eq(res, YKPIV_OK);
|
||||||
|
ck_assert_ptr_nonnull(g_state);
|
||||||
|
res = ykpiv_connect(g_state, NULL);
|
||||||
|
ck_assert_int_eq(res, YKPIV_OK);
|
||||||
|
|
||||||
|
// Verify decryption does not work without auth
|
||||||
|
res = ykpiv_decipher_data(g_state, data, (size_t)len, data, &len2, YKPIV_ALGO_RSA2048, 0x9a);
|
||||||
|
ck_assert_int_eq(res, YKPIV_AUTHENTICATION_ERROR);
|
||||||
|
|
||||||
|
// Verify decryption does work when authed
|
||||||
|
res = ykpiv_verify_select(g_state, "123456", 6, NULL, true);
|
||||||
|
ck_assert_int_eq(res, YKPIV_OK);
|
||||||
|
res = ykpiv_decipher_data(g_state, data, (size_t)len, data, &len2, YKPIV_ALGO_RSA2048, 0x9a);
|
||||||
|
ck_assert_int_eq(res, YKPIV_OK);
|
||||||
|
|
||||||
|
// Verify PIN policy allows continuing to decrypt without re-verifying
|
||||||
|
res = ykpiv_decipher_data(g_state, data, (size_t)len, data, &len2, YKPIV_ALGO_RSA2048, 0x9a);
|
||||||
|
ck_assert_int_eq(res, YKPIV_OK);
|
||||||
|
|
||||||
|
// Create a new ykpiv state, connect, and close it.
|
||||||
|
// This forces a card reset from another context, so the original global
|
||||||
|
// context will require a reconnect for its next transaction.
|
||||||
|
res = ykpiv_init(&local_state, true);
|
||||||
|
ck_assert_int_eq(res, YKPIV_OK);
|
||||||
|
ck_assert_ptr_nonnull(local_state);
|
||||||
|
res = ykpiv_connect(local_state, NULL);
|
||||||
|
ck_assert_int_eq(res, YKPIV_OK);
|
||||||
|
res = ykpiv_disconnect(local_state);
|
||||||
|
ck_assert_int_eq(res, YKPIV_OK);
|
||||||
|
res = ykpiv_done(local_state);
|
||||||
|
ck_assert_int_eq(res, YKPIV_OK);
|
||||||
|
|
||||||
|
// Verify we are still authenticated on the global context. This will
|
||||||
|
// require an automatic reconnect and re-verify with the cached PIN.
|
||||||
|
//
|
||||||
|
// Note that you can verify that this fails by rebuilding with
|
||||||
|
// DISABLE_PIN_CACHE set to 1.
|
||||||
|
res = ykpiv_decipher_data(g_state, data, (size_t)len, data, &len2, YKPIV_ALGO_RSA2048, 0x9a);
|
||||||
|
ck_assert_int_eq(res, YKPIV_OK);
|
||||||
|
}
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
int destruction_confirmed(void) {
|
||||||
|
char *confirmed = getenv("YKPIV_ENV_HWTESTS_CONFIRMED");
|
||||||
|
if (confirmed && confirmed[0] == '1')
|
||||||
|
return 1;
|
||||||
|
// Use dprintf() to write directly to stdout, since automake eats the standard stdout/stderr pointers.
|
||||||
|
dprintf(0, "\n***\n*** Hardware tests skipped. Run \"make hwcheck\".\n***\n\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Suite *test_suite(void) {
|
||||||
|
Suite *s;
|
||||||
|
TCase *tc;
|
||||||
|
|
||||||
|
s = suite_create("libykpiv api");
|
||||||
|
tc = tcase_create("api");
|
||||||
|
#ifdef HW_TESTS
|
||||||
|
tcase_add_unchecked_fixture(tc, setup, teardown);
|
||||||
|
|
||||||
|
// Must be first: Reset device. Tests run serially, and depend on a clean slate.
|
||||||
|
tcase_add_test(tc, test_reset);
|
||||||
|
|
||||||
|
// Authenticate after reset.
|
||||||
|
tcase_add_test(tc, test_authenticate);
|
||||||
|
|
||||||
|
// Test API functionality
|
||||||
|
tcase_add_test(tc, test_change_pin);
|
||||||
|
tcase_add_test(tc, test_change_puk);
|
||||||
|
tcase_add_test(tc, test_devicemodel);
|
||||||
|
tcase_add_test(tc, test_get_set_cardid);
|
||||||
|
tcase_add_test(tc, test_list_readers);
|
||||||
|
tcase_add_test(tc, test_read_write_list_delete_cert);
|
||||||
|
tcase_add_test(tc, test_import_key);
|
||||||
|
tcase_add_test(tc, test_pin_policy_always);
|
||||||
|
tcase_add_test(tc, test_generate_key);
|
||||||
|
tcase_add_test(tc, test_pin_cache);
|
||||||
|
|
||||||
|
// Must be last: tear down and re-test with custom memory allocator
|
||||||
|
tcase_add_test(tc, test_allocator);
|
||||||
|
#endif
|
||||||
|
suite_add_tcase(s, tc);
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
int number_failed;
|
||||||
|
Suite *s;
|
||||||
|
SRunner *sr;
|
||||||
|
|
||||||
|
s = test_suite();
|
||||||
|
sr = srunner_create(s);
|
||||||
|
srunner_set_fork_status(sr, CK_NOFORK);
|
||||||
|
srunner_run_all(sr, CK_VERBOSE);
|
||||||
|
number_failed = srunner_ntests_failed(sr);
|
||||||
|
srunner_free(sr);
|
||||||
|
|
||||||
|
return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
|
||||||
|
}
|
||||||
+39
-16
@@ -35,41 +35,64 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
int main(void)
|
#include <check.h>
|
||||||
{
|
|
||||||
|
START_TEST(test_version_string) {
|
||||||
if (strcmp(YKPIV_VERSION_STRING, ykpiv_check_version(NULL)) != 0) {
|
if (strcmp(YKPIV_VERSION_STRING, ykpiv_check_version(NULL)) != 0) {
|
||||||
printf("version mismatch %s != %s\n", YKPIV_VERSION_STRING,
|
ck_abort_msg("version mismatch %s != %s\n", YKPIV_VERSION_STRING,
|
||||||
ykpiv_check_version(NULL));
|
ykpiv_check_version(NULL));
|
||||||
return EXIT_FAILURE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ykpiv_check_version(YKPIV_VERSION_STRING) == NULL) {
|
if (ykpiv_check_version(YKPIV_VERSION_STRING) == NULL) {
|
||||||
printf("version NULL?\n");
|
ck_abort_msg("version NULL?\n");
|
||||||
return EXIT_FAILURE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ykpiv_check_version("99.99.99") != NULL) {
|
if (ykpiv_check_version("99.99.99") != NULL) {
|
||||||
printf ("version not NULL?\n");
|
ck_abort_msg("version not NULL?\n");
|
||||||
return EXIT_FAILURE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
printf ("ykpiv version: header %s library %s\n",
|
fprintf(stderr, "ykpiv version: header %s library %s\n",
|
||||||
YKPIV_VERSION_STRING, ykpiv_check_version (NULL));
|
YKPIV_VERSION_STRING, ykpiv_check_version (NULL));
|
||||||
|
}
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST(test_strerror) {
|
||||||
|
const char *s;
|
||||||
|
|
||||||
if (ykpiv_strerror(YKPIV_OK) == NULL) {
|
if (ykpiv_strerror(YKPIV_OK) == NULL) {
|
||||||
printf ("ykpiv_strerror NULL\n");
|
ck_abort_msg("ykpiv_strerror NULL\n");
|
||||||
return EXIT_FAILURE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
|
||||||
const char *s;
|
|
||||||
s = ykpiv_strerror_name(YKPIV_OK);
|
s = ykpiv_strerror_name(YKPIV_OK);
|
||||||
if (s == NULL || strcmp(s, "YKPIV_OK") != 0) {
|
if (s == NULL || strcmp(s, "YKPIV_OK") != 0) {
|
||||||
printf("ykpiv_strerror_name %s\n", s);
|
ck_abort_msg("ykpiv_strerror_name %s\n", s);
|
||||||
return EXIT_FAILURE;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
Suite *basic_suite(void) {
|
||||||
|
Suite *s;
|
||||||
|
TCase *tc;
|
||||||
|
|
||||||
|
s = suite_create("libykpiv basic");
|
||||||
|
tc = tcase_create("basic");
|
||||||
|
tcase_add_test(tc, test_version_string);
|
||||||
|
tcase_add_test(tc, test_strerror);
|
||||||
|
suite_add_tcase(s, tc);
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
return EXIT_SUCCESS;
|
int main(void)
|
||||||
|
{
|
||||||
|
int number_failed;
|
||||||
|
Suite *s;
|
||||||
|
SRunner *sr;
|
||||||
|
|
||||||
|
s = basic_suite();
|
||||||
|
sr = srunner_create(s);
|
||||||
|
srunner_run_all(sr, CK_NORMAL);
|
||||||
|
number_failed = srunner_ntests_failed(sr);
|
||||||
|
srunner_free(sr);
|
||||||
|
return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|||||||
+35
-20
@@ -32,6 +32,8 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <check.h>
|
||||||
|
|
||||||
#include "ykpiv.h"
|
#include "ykpiv.h"
|
||||||
|
|
||||||
struct key {
|
struct key {
|
||||||
@@ -57,30 +59,43 @@ static int parse_key(const char *text, const unsigned char *expected, int valid)
|
|||||||
unsigned char key[24];
|
unsigned char key[24];
|
||||||
size_t len = sizeof(key);
|
size_t len = sizeof(key);
|
||||||
ykpiv_rc res = ykpiv_hex_decode(text, strlen(text), key, &len);
|
ykpiv_rc res = ykpiv_hex_decode(text, strlen(text), key, &len);
|
||||||
if(res != YKPIV_OK && valid == 1) {
|
if (valid) {
|
||||||
printf("key check failed for %s!\n", text);
|
ck_assert(res == YKPIV_OK);
|
||||||
return EXIT_FAILURE;
|
ck_assert(memcmp(expected, key, 24) == 0);
|
||||||
} else if(res != YKPIV_OK && valid == 0) {
|
} else {
|
||||||
|
ck_assert(res != YKPIV_OK);
|
||||||
|
}
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(memcmp(expected, key, 24) != 0) {
|
START_TEST(test_parse_key) {
|
||||||
printf("keys not matching for %s!\n", text);
|
int res = parse_key(keys[_i].text, keys[_i].formatted, keys[_i].valid);
|
||||||
return EXIT_FAILURE;
|
ck_assert(res == EXIT_SUCCESS);
|
||||||
|
}
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
Suite *parsekey_suite(void) {
|
||||||
|
Suite *s;
|
||||||
|
TCase *tc;
|
||||||
|
|
||||||
|
s = suite_create("libykpiv parsekey");
|
||||||
|
tc = tcase_create("parsekey");
|
||||||
|
tcase_add_loop_test(tc, test_parse_key, 0, sizeof(keys) / sizeof(struct key));
|
||||||
|
suite_add_tcase(s, tc);
|
||||||
|
|
||||||
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
return EXIT_SUCCESS;
|
int main(void)
|
||||||
}
|
{
|
||||||
|
int number_failed;
|
||||||
|
Suite *s;
|
||||||
|
SRunner *sr;
|
||||||
|
|
||||||
int main(void) {
|
s = parsekey_suite();
|
||||||
size_t i;
|
sr = srunner_create(s);
|
||||||
|
srunner_run_all(sr, CK_NORMAL);
|
||||||
for(i = 0; i < sizeof(keys) / sizeof(struct key); i++) {
|
number_failed = srunner_ntests_failed(sr);
|
||||||
int res = parse_key(keys[i].text, keys[i].formatted, keys[i].valid);
|
srunner_free(sr);
|
||||||
if(res != EXIT_SUCCESS) {
|
return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
|
||||||
return res;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return EXIT_SUCCESS;
|
|
||||||
}
|
}
|
||||||
|
|||||||
+1622
File diff suppressed because it is too large
Load Diff
+695
-172
File diff suppressed because it is too large
Load Diff
+461
-3
@@ -28,11 +28,20 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @mainpage
|
||||||
|
*
|
||||||
|
* See ykpiv.h
|
||||||
|
*
|
||||||
|
* @file ykpiv.h
|
||||||
|
* libykpiv API
|
||||||
|
*/
|
||||||
#ifndef YKPIV_H
|
#ifndef YKPIV_H
|
||||||
#define YKPIV_H
|
#define YKPIV_H
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
#include <ykpiv-version.h>
|
#include <ykpiv-version.h>
|
||||||
|
|
||||||
@@ -58,12 +67,27 @@ extern "C"
|
|||||||
YKPIV_INVALID_OBJECT = -11,
|
YKPIV_INVALID_OBJECT = -11,
|
||||||
YKPIV_ALGORITHM_ERROR = -12,
|
YKPIV_ALGORITHM_ERROR = -12,
|
||||||
YKPIV_PIN_LOCKED = -13,
|
YKPIV_PIN_LOCKED = -13,
|
||||||
|
|
||||||
|
YKPIV_ARGUMENT_ERROR = -14, //i.e. invalid input argument
|
||||||
|
YKPIV_RANGE_ERROR = -15, //i.e. value range error
|
||||||
|
YKPIV_NOT_SUPPORTED = -16
|
||||||
} ykpiv_rc;
|
} ykpiv_rc;
|
||||||
|
|
||||||
|
typedef void* (*ykpiv_pfn_alloc)(void* alloc_data, size_t size);
|
||||||
|
typedef void* (*ykpiv_pfn_realloc)(void* alloc_data, void* address, size_t size);
|
||||||
|
typedef void (*ykpiv_pfn_free)(void* alloc_data, void* address);
|
||||||
|
typedef struct ykpiv_allocator {
|
||||||
|
ykpiv_pfn_alloc pfn_alloc;
|
||||||
|
ykpiv_pfn_realloc pfn_realloc;
|
||||||
|
ykpiv_pfn_free pfn_free;
|
||||||
|
void * alloc_data;
|
||||||
|
} ykpiv_allocator;
|
||||||
|
|
||||||
const char *ykpiv_strerror(ykpiv_rc err);
|
const char *ykpiv_strerror(ykpiv_rc err);
|
||||||
const char *ykpiv_strerror_name(ykpiv_rc err);
|
const char *ykpiv_strerror_name(ykpiv_rc err);
|
||||||
|
|
||||||
ykpiv_rc ykpiv_init(ykpiv_state **state, int verbose);
|
ykpiv_rc ykpiv_init(ykpiv_state **state, int verbose);
|
||||||
|
ykpiv_rc ykpiv_init_with_allocator(ykpiv_state **state, int verbose, const ykpiv_allocator *allocator);
|
||||||
ykpiv_rc ykpiv_done(ykpiv_state *state);
|
ykpiv_rc ykpiv_done(ykpiv_state *state);
|
||||||
ykpiv_rc ykpiv_connect(ykpiv_state *state, const char *wanted);
|
ykpiv_rc ykpiv_connect(ykpiv_state *state, const char *wanted);
|
||||||
ykpiv_rc ykpiv_list_readers(ykpiv_state *state, char *readers, size_t *len);
|
ykpiv_rc ykpiv_list_readers(ykpiv_state *state, char *readers, size_t *len);
|
||||||
@@ -78,9 +102,6 @@ extern "C"
|
|||||||
ykpiv_rc ykpiv_sign_data(ykpiv_state *state, const unsigned char *sign_in,
|
ykpiv_rc ykpiv_sign_data(ykpiv_state *state, const unsigned char *sign_in,
|
||||||
size_t in_len, unsigned char *sign_out, size_t *out_len,
|
size_t in_len, unsigned char *sign_out, size_t *out_len,
|
||||||
unsigned char algorithm, unsigned char key);
|
unsigned char algorithm, unsigned char key);
|
||||||
ykpiv_rc ykpiv_sign_data2(ykpiv_state *state, const unsigned char *sign_in,
|
|
||||||
size_t in_len, unsigned char *sign_out, size_t *out_len,
|
|
||||||
unsigned char algorithm, unsigned char key, int padding); // Allow not to add padding
|
|
||||||
ykpiv_rc ykpiv_decipher_data(ykpiv_state *state, const unsigned char *enc_in,
|
ykpiv_rc ykpiv_decipher_data(ykpiv_state *state, const unsigned char *enc_in,
|
||||||
size_t in_len, unsigned char *enc_out, size_t *out_len,
|
size_t in_len, unsigned char *enc_out, size_t *out_len,
|
||||||
unsigned char algorithm, unsigned char key);
|
unsigned char algorithm, unsigned char key);
|
||||||
@@ -109,6 +130,423 @@ extern "C"
|
|||||||
const unsigned char *qinv, size_t qinv_len,
|
const unsigned char *qinv, size_t qinv_len,
|
||||||
const unsigned char *ec_data, unsigned char ec_data_len,
|
const unsigned char *ec_data, unsigned char ec_data_len,
|
||||||
const unsigned char pin_policy, const unsigned char touch_policy);
|
const unsigned char pin_policy, const unsigned char touch_policy);
|
||||||
|
ykpiv_rc ykpiv_attest(ykpiv_state *state, const unsigned char key, unsigned char *data, size_t *data_len);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the number of PIN attempts remaining before PIN is locked.
|
||||||
|
*
|
||||||
|
* **NOTE:** If PIN is already verified, calling ykpiv_get_pin_retries() will unverify the PIN.
|
||||||
|
*
|
||||||
|
* @param state State handle from ykpiv_init()
|
||||||
|
* @param tries [out] Number of attempts remaining
|
||||||
|
*
|
||||||
|
* @return Error code
|
||||||
|
*/
|
||||||
|
ykpiv_rc ykpiv_get_pin_retries(ykpiv_state *state, int *tries);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set number of attempts before locking for PIN and PUK codes.
|
||||||
|
*
|
||||||
|
* **NOTE:** If either \p pin_tries or \p puk_tries is 0, ykpiv_set_pin_retries() immediately returns YKPIV_OK.
|
||||||
|
*
|
||||||
|
* @param state State handle from ykpiv_init()
|
||||||
|
* @param pin_tries Number of attempts to permit for PIN code
|
||||||
|
* @param puk_tries Number of attempts to permit for PUK code
|
||||||
|
*
|
||||||
|
* @return Error code
|
||||||
|
*/
|
||||||
|
ykpiv_rc ykpiv_set_pin_retries(ykpiv_state *state, int pin_tries, int puk_tries);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Variant of ykpiv_connect() that accepts a card context obtained externally.
|
||||||
|
*
|
||||||
|
* Not for generic use. Use ykpiv_connect() instead.
|
||||||
|
*
|
||||||
|
* @param state State handle
|
||||||
|
* @param context Card context returned from SCardConnect() or equivalent.
|
||||||
|
* @param card Card ID returned from SCardConnect() or equivalent.
|
||||||
|
*
|
||||||
|
* @return Error code
|
||||||
|
*/
|
||||||
|
ykpiv_rc ykpiv_connect_with_external_card(ykpiv_state *state, uintptr_t context, uintptr_t card);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Variant of ykpiv_done() for external cards connected with ykpiv_connect_with_external_card()
|
||||||
|
*
|
||||||
|
* Card is not disconnected, unlike with normal calls to ykpiv_done().
|
||||||
|
*
|
||||||
|
* @param state State handle
|
||||||
|
*
|
||||||
|
* @return Error code
|
||||||
|
*/
|
||||||
|
ykpiv_rc ykpiv_done_with_external_card(ykpiv_state *state);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Variant of ykpiv_verify() that optionally selects the PIV applet first.
|
||||||
|
*
|
||||||
|
* @param state State handle
|
||||||
|
* @param pin PIN code to verify with
|
||||||
|
* @param pin_len Length of \p pin
|
||||||
|
* @param tries [out] Number of attempts remaining (if non-NULL)
|
||||||
|
* @param force_select Whether to select the PIV applet before verifying.
|
||||||
|
*
|
||||||
|
* @return Error code
|
||||||
|
*/
|
||||||
|
ykpiv_rc ykpiv_verify_select(ykpiv_state *state, const char *pin, const size_t pin_len, int *tries, bool force_select);
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
////
|
||||||
|
////
|
||||||
|
//// High-level Util API
|
||||||
|
////
|
||||||
|
////
|
||||||
|
//// Util api always allocates data on your behalf, if data = 0, *data != 0,
|
||||||
|
//// or data_len = 0 an invalid parameter will be returned; to free data, call
|
||||||
|
//// ykpiv_util_free().
|
||||||
|
////
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
typedef uint32_t ykpiv_devmodel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Card identifier
|
||||||
|
*/
|
||||||
|
#define YKPIV_CARDID_SIZE 16
|
||||||
|
typedef struct {
|
||||||
|
uint8_t data[YKPIV_CARDID_SIZE];
|
||||||
|
} ykpiv_cardid;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Card Capability
|
||||||
|
*/
|
||||||
|
#define YKPIV_CCCID_SIZE 14
|
||||||
|
typedef struct {
|
||||||
|
uint8_t data[YKPIV_CCCID_SIZE];
|
||||||
|
} ykpiv_cccid;
|
||||||
|
|
||||||
|
#pragma pack(push, 1)
|
||||||
|
|
||||||
|
typedef struct _ykpiv_key {
|
||||||
|
uint8_t slot;
|
||||||
|
uint16_t cert_len;
|
||||||
|
uint8_t cert[1];
|
||||||
|
} ykpiv_key;
|
||||||
|
|
||||||
|
typedef struct _ykpiv_container {
|
||||||
|
wchar_t name[40];
|
||||||
|
uint8_t slot;
|
||||||
|
uint8_t key_spec;
|
||||||
|
uint16_t key_size_bits;
|
||||||
|
uint8_t flags;
|
||||||
|
uint8_t pin_id;
|
||||||
|
uint8_t associated_echd_container;
|
||||||
|
uint8_t cert_fingerprint[20];
|
||||||
|
} ykpiv_container;
|
||||||
|
|
||||||
|
#pragma pack(pop)
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
YKPIV_CONFIG_MGM_MANUAL = 0,
|
||||||
|
YKPIV_CONFIG_MGM_DERIVED = 1,
|
||||||
|
YKPIV_CONFIG_MGM_PROTECTED = 2
|
||||||
|
} ykpiv_config_mgm_type;
|
||||||
|
|
||||||
|
#pragma pack(push, 1)
|
||||||
|
typedef struct _ykpiv_config {
|
||||||
|
uint8_t protected_data_available;
|
||||||
|
uint8_t puk_blocked;
|
||||||
|
uint8_t puk_noblock_on_upgrade;
|
||||||
|
uint32_t pin_last_changed;
|
||||||
|
ykpiv_config_mgm_type mgm_type;
|
||||||
|
} ykpiv_config;
|
||||||
|
|
||||||
|
typedef struct _ykpiv_mgm {
|
||||||
|
uint8_t data[24];
|
||||||
|
} ykpiv_mgm;
|
||||||
|
#pragma pack(pop)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Free allocated data
|
||||||
|
*
|
||||||
|
* Frees a buffer previously allocated by one of the other \p ykpiv_util functions.
|
||||||
|
*
|
||||||
|
* @param state State handle
|
||||||
|
* @param data Buffer previously allocated by a \p ykpiv_util function
|
||||||
|
*
|
||||||
|
* @return ypiv_rc error code
|
||||||
|
*/
|
||||||
|
ykpiv_rc ykpiv_util_free(ykpiv_state *state, void *data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a list of all saved certificates.
|
||||||
|
*
|
||||||
|
* \p data should be freed with \p ykpiv_util_free() after use.
|
||||||
|
*
|
||||||
|
* @param state State handle
|
||||||
|
* @param key_count [out] Number of certificates returned
|
||||||
|
* @param data [out] Set to a dynamically allocated list of certificates.
|
||||||
|
* @param data_len [out] Set to size of \p data in bytes
|
||||||
|
*
|
||||||
|
* @return Error code
|
||||||
|
*/
|
||||||
|
ykpiv_rc ykpiv_util_list_keys(ykpiv_state *state, uint8_t *key_count, ykpiv_key **data, size_t *data_len);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read a certificate stored in the given slot
|
||||||
|
*
|
||||||
|
* \p data should be freed with \p ykpiv_util_free() after use.
|
||||||
|
*
|
||||||
|
* @param state State handle
|
||||||
|
* @param slot Slot to read from
|
||||||
|
* @param data Pointer to buffer to store the read data
|
||||||
|
* @param data_len Pointer to size of input buffer, in bytes. Update to length of read data after call.
|
||||||
|
*
|
||||||
|
* @return Error code
|
||||||
|
*/
|
||||||
|
ykpiv_rc ykpiv_util_read_cert(ykpiv_state *state, uint8_t slot, uint8_t **data, size_t *data_len);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write a certificate to a given slot
|
||||||
|
*
|
||||||
|
* \p certinfo should be \p YKPIV_CERTINFO_UNCOMPRESSED for uncompressed certificates, which is the most
|
||||||
|
* common case, or \p YKPIV_CERTINFO_GZIP if the certificate in \p data is already compressed with gzip.
|
||||||
|
*
|
||||||
|
* @param state State handle
|
||||||
|
* @param slot Slot to write to
|
||||||
|
* @param data Buffer of data to write
|
||||||
|
* @param data_len Number of bytes to write
|
||||||
|
* @param certinfo Hint about type of certificate. Use the \p YKPIV_CERTINFO* defines.
|
||||||
|
*
|
||||||
|
* @return Error code
|
||||||
|
*/
|
||||||
|
ykpiv_rc ykpiv_util_write_cert(ykpiv_state *state, uint8_t slot, uint8_t *data, size_t data_len, uint8_t certinfo);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete the certificate stored in the given slot
|
||||||
|
*
|
||||||
|
* @param state State handle
|
||||||
|
* @param slot Slot to delete certificate from
|
||||||
|
*
|
||||||
|
* @return Error code
|
||||||
|
*/
|
||||||
|
ykpiv_rc ykpiv_util_delete_cert(ykpiv_state *state, uint8_t slot);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate key in given slot with specified parameters
|
||||||
|
*
|
||||||
|
* \p modulus, \p exp, and \p point should be freed with \p ykpiv_util_free() after use.
|
||||||
|
*
|
||||||
|
* If algorithm is RSA1024 or RSA2048, the modulus, modulus_len, exp, and exp_len output parameters must be supplied. They are filled with with public modulus (big-endian), its size, the public exponent (big-endian), and its size respectively.
|
||||||
|
*
|
||||||
|
* If algorithm is ECCP256 or ECCP384, the point and point_len output parameters must be supplied. They are filled with the public point (uncompressed octet-string encoded per SEC1 section 2.3.4)
|
||||||
|
*
|
||||||
|
* If algorithm is ECCP256, the curve is always ANSI X9.62 Prime 256v1
|
||||||
|
*
|
||||||
|
* If algorithm is ECCP384, the curve is always secp384r1
|
||||||
|
*
|
||||||
|
* @param state State handle
|
||||||
|
* @param slot Slot to generate key in
|
||||||
|
* @param algorithm Key algorithm, specified as one of the \p YKPIV_ALGO_* options
|
||||||
|
* @param pin_policy Per-slot PIN policy, specified as one of the \p YKPIV_PINPOLICY_* options
|
||||||
|
* @param touch_policy Per-slot touch policy, specified as one of the \p YKPIV_TOUCHPOLICY_* options.
|
||||||
|
* @param modulus [out] RSA public modulus (RSA-only)
|
||||||
|
* @param modulus_len [out] Size of \p modulus (RSA-only)
|
||||||
|
* @param exp [out] RSA public exponent (RSA-only)
|
||||||
|
* @param exp_len [out] Size of \p exp (RSA-only)
|
||||||
|
* @param point [out] Public curve point (ECC-only)
|
||||||
|
* @param point_len [out] Size of \p point (ECC-only)
|
||||||
|
*
|
||||||
|
* @return ykpiv_rc error code
|
||||||
|
*/
|
||||||
|
ykpiv_rc ykpiv_util_generate_key(ykpiv_state *state, uint8_t slot, uint8_t algorithm, uint8_t pin_policy, uint8_t touch_policy, uint8_t **modulus, size_t *modulus_len, uint8_t **exp, size_t *exp_len, uint8_t **point, size_t *point_len);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get current PIV applet administration configuration state
|
||||||
|
*
|
||||||
|
* @param state State handle
|
||||||
|
* @param config [out] ykpiv_config struct filled with current applet data
|
||||||
|
*
|
||||||
|
* @return ykpiv_rc error code
|
||||||
|
*/
|
||||||
|
ykpiv_rc ykpiv_util_get_config(ykpiv_state *state, ykpiv_config *config);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set last pin changed time to current time
|
||||||
|
*
|
||||||
|
* The applet must be authenticated to call this function
|
||||||
|
*
|
||||||
|
* @param state State handle
|
||||||
|
*
|
||||||
|
* @return ykpiv_rc error code
|
||||||
|
*/
|
||||||
|
ykpiv_rc ykpiv_util_set_pin_last_changed(ykpiv_state *state);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get Derived MGM key
|
||||||
|
*
|
||||||
|
* @param state State handle
|
||||||
|
* @param pin PIN used to derive mgm key
|
||||||
|
* @param pin_len Length of pin in bytes
|
||||||
|
* @param mgm [out] Protected MGM key
|
||||||
|
*
|
||||||
|
* @return ykpiv_rc error code
|
||||||
|
*/
|
||||||
|
ykpiv_rc ykpiv_util_get_derived_mgm(ykpiv_state *state, const uint8_t *pin, const size_t pin_len, ykpiv_mgm *mgm);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get Protected MGM key
|
||||||
|
*
|
||||||
|
* The user pin must be verified to call this function
|
||||||
|
*
|
||||||
|
* @param state State handle
|
||||||
|
* @param mgm [out] Protected MGM key
|
||||||
|
*
|
||||||
|
* @return ykpiv_rc error code
|
||||||
|
*/
|
||||||
|
ykpiv_rc ykpiv_util_get_protected_mgm(ykpiv_state *state, ykpiv_mgm *mgm);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set Protected MGM key
|
||||||
|
*
|
||||||
|
* The applet must be authenticated and the user pin verified to call this function
|
||||||
|
*
|
||||||
|
* If \p mgm is NULL or \p mgm.data is all zeroes, generate MGM, otherwise set specified key.
|
||||||
|
*
|
||||||
|
* @param state State handle
|
||||||
|
* @param mgm [in, out] Input: NULL or new MGM key. Output: Generated MGM key
|
||||||
|
*
|
||||||
|
* @return ykpiv_rc error code
|
||||||
|
*/
|
||||||
|
ykpiv_rc ykpiv_util_set_protected_mgm(ykpiv_state *state, ykpiv_mgm *mgm);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reset PIV applet
|
||||||
|
*
|
||||||
|
* The user PIN and PUK must be blocked to call this function.
|
||||||
|
*
|
||||||
|
* @param state State handle
|
||||||
|
*
|
||||||
|
* @return ykpiv_rc error code
|
||||||
|
*/
|
||||||
|
ykpiv_rc ykpiv_util_reset(ykpiv_state *state);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get card identifier
|
||||||
|
*
|
||||||
|
* Gets the card identifier from the Cardholder Unique Identifier (CHUID).
|
||||||
|
*
|
||||||
|
* ID can be set with \p ykpiv_util_set_cardid().
|
||||||
|
*
|
||||||
|
* @param state State handle
|
||||||
|
* @param cardid [out] Unique Card ID stored in the CHUID
|
||||||
|
*
|
||||||
|
* @return ykpiv_rc error code
|
||||||
|
*/
|
||||||
|
ykpiv_rc ykpiv_util_get_cardid(ykpiv_state *state, ykpiv_cardid *cardid);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set card identifier
|
||||||
|
*
|
||||||
|
* Set the card identifier in the Cardholder Unique Identifier (CHUID).
|
||||||
|
*
|
||||||
|
* The card must be authenticated to call this function.
|
||||||
|
*
|
||||||
|
* See also: \p ykpiv_util_set_cccid()
|
||||||
|
*
|
||||||
|
* @param state State handle
|
||||||
|
* @param cardid Unique Card ID to set. If NULL, randomly generate.
|
||||||
|
*
|
||||||
|
* @return ypiv_rc error code
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
ykpiv_rc ykpiv_util_set_cardid(ykpiv_state *state, const ykpiv_cardid *cardid);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get card capabilities identifier
|
||||||
|
*
|
||||||
|
* Gets the card identifier from the Card Capability Container (CCC).
|
||||||
|
*
|
||||||
|
* ID can be set with \p ykpiv_util_set_cccid().
|
||||||
|
*
|
||||||
|
* @param state State handle
|
||||||
|
* @param ccc [out] Unique Card ID stored in the CCC
|
||||||
|
*
|
||||||
|
* @return ykpiv_rc error code
|
||||||
|
*/
|
||||||
|
ykpiv_rc ykpiv_util_get_cccid(ykpiv_state *state, ykpiv_cccid *ccc);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set card capabilities identifier
|
||||||
|
*
|
||||||
|
* Sets the card identifier in the Card Capability Container (CCC).
|
||||||
|
*
|
||||||
|
* The card must be authenticated to call this function.
|
||||||
|
*
|
||||||
|
* See also: \p ykpiv_util_set_cardid()
|
||||||
|
*
|
||||||
|
* @param state state
|
||||||
|
* @param ccc Unique Card ID to set. If NULL, randomly generate.
|
||||||
|
*
|
||||||
|
* @return ypiv_rc error code
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
ykpiv_rc ykpiv_util_set_cccid(ykpiv_state *state, const ykpiv_cccid *ccc);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get device model
|
||||||
|
*
|
||||||
|
* The card must be connected to call this function.
|
||||||
|
*
|
||||||
|
* @param state State handle
|
||||||
|
*
|
||||||
|
* @return Device model
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
ykpiv_devmodel ykpiv_util_devicemodel(ykpiv_state *state);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Block PUK
|
||||||
|
*
|
||||||
|
* Utility function to block the PUK.
|
||||||
|
*
|
||||||
|
* To set the PUK blocked flag in the admin data, the applet must be authenticated.
|
||||||
|
*
|
||||||
|
* @param state State handle
|
||||||
|
*
|
||||||
|
* @return Error code
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
ykpiv_rc ykpiv_util_block_puk(ykpiv_state *state);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Object ID of given slot.
|
||||||
|
*
|
||||||
|
* @param slot Key slot
|
||||||
|
*/
|
||||||
|
uint32_t ykpiv_util_slot_object(uint8_t slot);
|
||||||
|
|
||||||
|
ykpiv_rc ykpiv_util_read_mscmap(ykpiv_state *state, ykpiv_container **containers, size_t *n_containers);
|
||||||
|
ykpiv_rc ykpiv_util_write_mscmap(ykpiv_state *state, ykpiv_container *containers, size_t n_containers);
|
||||||
|
ykpiv_rc ykpiv_util_read_msroots(ykpiv_state *state, uint8_t **data, size_t *data_len);
|
||||||
|
ykpiv_rc ykpiv_util_write_msroots(ykpiv_state *state, uint8_t *data, size_t data_len);
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
////
|
||||||
|
////
|
||||||
|
//// Defines
|
||||||
|
////
|
||||||
|
////
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#define YKPIV_ALGO_TAG 0x80
|
#define YKPIV_ALGO_TAG 0x80
|
||||||
#define YKPIV_ALGO_3DES 0x03
|
#define YKPIV_ALGO_3DES 0x03
|
||||||
@@ -181,6 +619,8 @@ extern "C"
|
|||||||
|
|
||||||
#define YKPIV_OBJ_ATTESTATION 0x5fff01
|
#define YKPIV_OBJ_ATTESTATION 0x5fff01
|
||||||
|
|
||||||
|
#define YKPIV_OBJ_MAX_SIZE 3072
|
||||||
|
|
||||||
#define YKPIV_INS_VERIFY 0x20
|
#define YKPIV_INS_VERIFY 0x20
|
||||||
#define YKPIV_INS_CHANGE_REFERENCE 0x24
|
#define YKPIV_INS_CHANGE_REFERENCE 0x24
|
||||||
#define YKPIV_INS_RESET_RETRY 0x2c
|
#define YKPIV_INS_RESET_RETRY 0x2c
|
||||||
@@ -188,6 +628,8 @@ extern "C"
|
|||||||
#define YKPIV_INS_AUTHENTICATE 0x87
|
#define YKPIV_INS_AUTHENTICATE 0x87
|
||||||
#define YKPIV_INS_GET_DATA 0xcb
|
#define YKPIV_INS_GET_DATA 0xcb
|
||||||
#define YKPIV_INS_PUT_DATA 0xdb
|
#define YKPIV_INS_PUT_DATA 0xdb
|
||||||
|
#define YKPIV_INS_SELECT_APPLICATION 0xa4
|
||||||
|
#define YKPIV_INS_GET_RESPONSE_APDU 0xc0
|
||||||
|
|
||||||
/* sw is status words, see NIST special publication 800-73-4, section 5.6 */
|
/* sw is status words, see NIST special publication 800-73-4, section 5.6 */
|
||||||
#define SW_SUCCESS 0x9000
|
#define SW_SUCCESS 0x9000
|
||||||
@@ -196,6 +638,7 @@ extern "C"
|
|||||||
#define SW_ERR_INCORRECT_PARAM 0x6a80
|
#define SW_ERR_INCORRECT_PARAM 0x6a80
|
||||||
/* this is a custom sw for yubikey */
|
/* this is a custom sw for yubikey */
|
||||||
#define SW_ERR_INCORRECT_SLOT 0x6b00
|
#define SW_ERR_INCORRECT_SLOT 0x6b00
|
||||||
|
#define SW_ERR_NOT_SUPPORTED 0x6d00
|
||||||
|
|
||||||
/* Yubico vendor specific instructions */
|
/* Yubico vendor specific instructions */
|
||||||
#define YKPIV_INS_SET_MGMKEY 0xff
|
#define YKPIV_INS_SET_MGMKEY 0xff
|
||||||
@@ -220,6 +663,21 @@ extern "C"
|
|||||||
#define YKPIV_IS_EC(a) ((a == YKPIV_ALGO_ECCP256 || a == YKPIV_ALGO_ECCP384))
|
#define YKPIV_IS_EC(a) ((a == YKPIV_ALGO_ECCP256 || a == YKPIV_ALGO_ECCP384))
|
||||||
#define YKPIV_IS_RSA(a) ((a == YKPIV_ALGO_RSA1024 || a == YKPIV_ALGO_RSA2048))
|
#define YKPIV_IS_RSA(a) ((a == YKPIV_ALGO_RSA1024 || a == YKPIV_ALGO_RSA2048))
|
||||||
|
|
||||||
|
#define YKPIV_RETRIES_DEFAULT 3
|
||||||
|
#define YKPIV_RETRIES_MAX 0xff
|
||||||
|
|
||||||
|
#define YKPIV_CERTINFO_UNCOMPRESSED 0
|
||||||
|
#define YKPIV_CERTINFO_GZIP 1
|
||||||
|
|
||||||
|
#define YKPIV_ATR_NEO_R3 "\x3b\xfc\x13\x00\x00\x81\x31\xfe\x15\x59\x75\x62\x69\x6b\x65\x79\x4e\x45\x4f\x72\x33\xe1"
|
||||||
|
#define YKPIV_ATR_YK4 "\x3b\xf8\x13\x00\x00\x81\x31\xfe\x15\x59\x75\x62\x69\x6b\x65\x79\x34\xd4"
|
||||||
|
|
||||||
|
#define DEVTYPE_UNKNOWN 0x00000000
|
||||||
|
#define DEVTYPE_NEO 0x4E450000 //"NE"
|
||||||
|
#define DEVTYPE_YK 0x594B0000 //"YK"
|
||||||
|
#define DEVTYPE_NEOr3 (DEVTYPE_NEO | 0x00007233) //"r3"
|
||||||
|
#define DEVTYPE_YK4 (DEVTYPE_YK | 0x00000034) // "4"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -75,3 +75,41 @@ global:
|
|||||||
ykpiv_change_puk;
|
ykpiv_change_puk;
|
||||||
ykpiv_unblock_pin;
|
ykpiv_unblock_pin;
|
||||||
} YKPIV_1.2.0;
|
} YKPIV_1.2.0;
|
||||||
|
|
||||||
|
YKPIV_1.5.0
|
||||||
|
{
|
||||||
|
global:
|
||||||
|
ykpiv_attest;
|
||||||
|
ykpiv_auth_getchallenge;
|
||||||
|
ykpiv_auth_verifyresponse;
|
||||||
|
ykpiv_connect_with_external_card;
|
||||||
|
ykpiv_done_with_external_card;
|
||||||
|
ykpiv_get_pin_retries;
|
||||||
|
ykpiv_init_with_allocator;
|
||||||
|
ykpiv_set_pin_retries;
|
||||||
|
ykpiv_util_block_puk;
|
||||||
|
ykpiv_util_delete_cert;
|
||||||
|
ykpiv_util_devicemodel;
|
||||||
|
ykpiv_util_free;
|
||||||
|
ykpiv_util_generate_key;
|
||||||
|
ykpiv_util_get_cardid;
|
||||||
|
ykpiv_util_get_cccid;
|
||||||
|
ykpiv_util_get_config;
|
||||||
|
ykpiv_util_get_derived_mgm;
|
||||||
|
ykpiv_util_get_protected_mgm;
|
||||||
|
ykpiv_util_list_keys;
|
||||||
|
ykpiv_util_list_keys;
|
||||||
|
ykpiv_util_read_cert;
|
||||||
|
ykpiv_util_read_mscmap;
|
||||||
|
ykpiv_util_read_msroots;
|
||||||
|
ykpiv_util_reset;
|
||||||
|
ykpiv_util_set_cardid;
|
||||||
|
ykpiv_util_set_cccid;
|
||||||
|
ykpiv_util_set_pin_last_changed;
|
||||||
|
ykpiv_util_set_protected_mgm;
|
||||||
|
ykpiv_util_slot_object;
|
||||||
|
ykpiv_util_write_cert;
|
||||||
|
ykpiv_util_write_mscmap;
|
||||||
|
ykpiv_util_write_msroots;
|
||||||
|
ykpiv_verify_select;
|
||||||
|
} YKPIV_1.3.0;
|
||||||
|
|||||||
@@ -0,0 +1,312 @@
|
|||||||
|
# This file is part of Autoconf. -*- Autoconf -*-
|
||||||
|
|
||||||
|
# Copyright (C) 2004 Oren Ben-Kiki
|
||||||
|
# This file is distributed under the same terms as the Autoconf macro files.
|
||||||
|
|
||||||
|
# Generate automatic documentation using Doxygen. Works in concert with the
|
||||||
|
# aminclude.m4 file and a compatible doxygen configuration file. Defines the
|
||||||
|
# following public macros:
|
||||||
|
#
|
||||||
|
# DX_???_FEATURE(ON|OFF) - control the default setting fo a Doxygen feature.
|
||||||
|
# Supported features are 'DOXYGEN' itself, 'DOT' for generating graphics,
|
||||||
|
# 'HTML' for plain HTML, 'CHM' for compressed HTML help (for MS users), 'CHI'
|
||||||
|
# for generating a seperate .chi file by the .chm file, and 'MAN', 'RTF',
|
||||||
|
# 'XML', 'PDF' and 'PS' for the appropriate output formats. The environment
|
||||||
|
# variable DOXYGEN_PAPER_SIZE may be specified to override the default 'a4wide'
|
||||||
|
# paper size.
|
||||||
|
#
|
||||||
|
# By default, HTML, PDF and PS documentation is generated as this seems to be
|
||||||
|
# the most popular and portable combination. MAN pages created by Doxygen are
|
||||||
|
# usually problematic, though by picking an appropriate subset and doing some
|
||||||
|
# massaging they might be better than nothing. CHM and RTF are specific for MS
|
||||||
|
# (note that you can't generate both HTML and CHM at the same time). The XML is
|
||||||
|
# rather useless unless you apply specialized post-processing to it.
|
||||||
|
#
|
||||||
|
# The macro mainly controls the default state of the feature. The use can
|
||||||
|
# override the default by specifying --enable or --disable. The macros ensure
|
||||||
|
# that contradictory flags are not given (e.g., --enable-doxygen-html and
|
||||||
|
# --enable-doxygen-chm, --enable-doxygen-anything with --disable-doxygen, etc.)
|
||||||
|
# Finally, each feature will be automatically disabled (with a warning) if the
|
||||||
|
# required programs are missing.
|
||||||
|
#
|
||||||
|
# Once all the feature defaults have been specified, call DX_INIT_DOXYGEN with
|
||||||
|
# the following parameters: a one-word name for the project for use as a
|
||||||
|
# filename base etc., an optional configuration file name (the default is
|
||||||
|
# 'Doxyfile', the same as Doxygen's default), and an optional output directory
|
||||||
|
# name (the default is 'doxygen-doc').
|
||||||
|
|
||||||
|
## ----------##
|
||||||
|
## Defaults. ##
|
||||||
|
## ----------##
|
||||||
|
|
||||||
|
DX_ENV=""
|
||||||
|
AC_DEFUN([DX_FEATURE_doc], ON)
|
||||||
|
AC_DEFUN([DX_FEATURE_dot], ON)
|
||||||
|
AC_DEFUN([DX_FEATURE_man], OFF)
|
||||||
|
AC_DEFUN([DX_FEATURE_html], ON)
|
||||||
|
AC_DEFUN([DX_FEATURE_chm], OFF)
|
||||||
|
AC_DEFUN([DX_FEATURE_chi], OFF)
|
||||||
|
AC_DEFUN([DX_FEATURE_rtf], OFF)
|
||||||
|
AC_DEFUN([DX_FEATURE_xml], OFF)
|
||||||
|
AC_DEFUN([DX_FEATURE_pdf], ON)
|
||||||
|
AC_DEFUN([DX_FEATURE_ps], ON)
|
||||||
|
|
||||||
|
## --------------- ##
|
||||||
|
## Private macros. ##
|
||||||
|
## --------------- ##
|
||||||
|
|
||||||
|
# DX_ENV_APPEND(VARIABLE, VALUE)
|
||||||
|
# ------------------------------
|
||||||
|
# Append VARIABLE="VALUE" to DX_ENV for invoking doxygen.
|
||||||
|
AC_DEFUN([DX_ENV_APPEND], [AC_SUBST([DX_ENV], ["$DX_ENV $1='$2'"])])
|
||||||
|
|
||||||
|
# DX_DIRNAME_EXPR
|
||||||
|
# ---------------
|
||||||
|
# Expand into a shell expression prints the directory part of a path.
|
||||||
|
AC_DEFUN([DX_DIRNAME_EXPR],
|
||||||
|
[[expr ".$1" : '\(\.\)[^/]*$' \| "x$1" : 'x\(.*\)/[^/]*$']])
|
||||||
|
|
||||||
|
# DX_IF_FEATURE(FEATURE, IF-ON, IF-OFF)
|
||||||
|
# -------------------------------------
|
||||||
|
# Expands according to the M4 (static) status of the feature.
|
||||||
|
AC_DEFUN([DX_IF_FEATURE], [ifelse(DX_FEATURE_$1, ON, [$2], [$3])])
|
||||||
|
|
||||||
|
# DX_REQUIRE_PROG(VARIABLE, PROGRAM)
|
||||||
|
# ----------------------------------
|
||||||
|
# Require the specified program to be found for the DX_CURRENT_FEATURE to work.
|
||||||
|
AC_DEFUN([DX_REQUIRE_PROG], [
|
||||||
|
AC_PATH_TOOL([$1], [$2])
|
||||||
|
if test "$DX_FLAG_[]DX_CURRENT_FEATURE$$1" = 1; then
|
||||||
|
AC_MSG_WARN([$2 not found - will not DX_CURRENT_DESCRIPTION])
|
||||||
|
AC_SUBST([DX_FLAG_]DX_CURRENT_FEATURE, 0)
|
||||||
|
fi
|
||||||
|
])
|
||||||
|
|
||||||
|
# DX_TEST_FEATURE(FEATURE)
|
||||||
|
# ------------------------
|
||||||
|
# Expand to a shell expression testing whether the feature is active.
|
||||||
|
AC_DEFUN([DX_TEST_FEATURE], [test "$DX_FLAG_$1" = 1])
|
||||||
|
|
||||||
|
# DX_CHECK_DEPEND(REQUIRED_FEATURE, REQUIRED_STATE)
|
||||||
|
# -------------------------------------------------
|
||||||
|
# Verify that a required features has the right state before trying to turn on
|
||||||
|
# the DX_CURRENT_FEATURE.
|
||||||
|
AC_DEFUN([DX_CHECK_DEPEND], [
|
||||||
|
test "$DX_FLAG_$1" = "$2" \
|
||||||
|
|| AC_MSG_ERROR([doxygen-DX_CURRENT_FEATURE ifelse([$2], 1,
|
||||||
|
requires, contradicts) doxygen-DX_CURRENT_FEATURE])
|
||||||
|
])
|
||||||
|
|
||||||
|
# DX_CLEAR_DEPEND(FEATURE, REQUIRED_FEATURE, REQUIRED_STATE)
|
||||||
|
# ----------------------------------------------------------
|
||||||
|
# Turn off the DX_CURRENT_FEATURE if the required feature is off.
|
||||||
|
AC_DEFUN([DX_CLEAR_DEPEND], [
|
||||||
|
test "$DX_FLAG_$1" = "$2" || AC_SUBST([DX_FLAG_]DX_CURRENT_FEATURE, 0)
|
||||||
|
])
|
||||||
|
|
||||||
|
# DX_FEATURE_ARG(FEATURE, DESCRIPTION,
|
||||||
|
# CHECK_DEPEND, CLEAR_DEPEND,
|
||||||
|
# REQUIRE, DO-IF-ON, DO-IF-OFF)
|
||||||
|
# --------------------------------------------
|
||||||
|
# Parse the command-line option controlling a feature. CHECK_DEPEND is called
|
||||||
|
# if the user explicitly turns the feature on (and invokes DX_CHECK_DEPEND),
|
||||||
|
# otherwise CLEAR_DEPEND is called to turn off the default state if a required
|
||||||
|
# feature is disabled (using DX_CLEAR_DEPEND). REQUIRE performs additional
|
||||||
|
# requirement tests (DX_REQUIRE_PROG). Finally, an automake flag is set and
|
||||||
|
# DO-IF-ON or DO-IF-OFF are called according to the final state of the feature.
|
||||||
|
AC_DEFUN([DX_ARG_ABLE], [
|
||||||
|
AC_DEFUN([DX_CURRENT_FEATURE], [$1])
|
||||||
|
AC_DEFUN([DX_CURRENT_DESCRIPTION], [$2])
|
||||||
|
AC_ARG_ENABLE(doxygen-$1,
|
||||||
|
[AS_HELP_STRING(DX_IF_FEATURE([$1], [--disable-doxygen-$1],
|
||||||
|
[--enable-doxygen-$1]),
|
||||||
|
DX_IF_FEATURE([$1], [don't $2], [$2]))],
|
||||||
|
[
|
||||||
|
case "$enableval" in
|
||||||
|
#(
|
||||||
|
y|Y|yes|Yes|YES)
|
||||||
|
AC_SUBST([DX_FLAG_$1], 1)
|
||||||
|
$3
|
||||||
|
;; #(
|
||||||
|
n|N|no|No|NO)
|
||||||
|
AC_SUBST([DX_FLAG_$1], 0)
|
||||||
|
;; #(
|
||||||
|
*)
|
||||||
|
AC_MSG_ERROR([invalid value '$enableval' given to doxygen-$1])
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
], [
|
||||||
|
AC_SUBST([DX_FLAG_$1], [DX_IF_FEATURE([$1], 1, 0)])
|
||||||
|
$4
|
||||||
|
])
|
||||||
|
if DX_TEST_FEATURE([$1]); then
|
||||||
|
$5
|
||||||
|
:
|
||||||
|
fi
|
||||||
|
if DX_TEST_FEATURE([$1]); then
|
||||||
|
AM_CONDITIONAL(DX_COND_$1, :)
|
||||||
|
$6
|
||||||
|
:
|
||||||
|
else
|
||||||
|
AM_CONDITIONAL(DX_COND_$1, false)
|
||||||
|
$7
|
||||||
|
:
|
||||||
|
fi
|
||||||
|
])
|
||||||
|
|
||||||
|
## -------------- ##
|
||||||
|
## Public macros. ##
|
||||||
|
## -------------- ##
|
||||||
|
|
||||||
|
# DX_XXX_FEATURE(DEFAULT_STATE)
|
||||||
|
# -----------------------------
|
||||||
|
AC_DEFUN([DX_DOXYGEN_FEATURE], [AC_DEFUN([DX_FEATURE_doc], [$1])])
|
||||||
|
AC_DEFUN([DX_MAN_FEATURE], [AC_DEFUN([DX_FEATURE_man], [$1])])
|
||||||
|
AC_DEFUN([DX_HTML_FEATURE], [AC_DEFUN([DX_FEATURE_html], [$1])])
|
||||||
|
AC_DEFUN([DX_CHM_FEATURE], [AC_DEFUN([DX_FEATURE_chm], [$1])])
|
||||||
|
AC_DEFUN([DX_CHI_FEATURE], [AC_DEFUN([DX_FEATURE_chi], [$1])])
|
||||||
|
AC_DEFUN([DX_RTF_FEATURE], [AC_DEFUN([DX_FEATURE_rtf], [$1])])
|
||||||
|
AC_DEFUN([DX_XML_FEATURE], [AC_DEFUN([DX_FEATURE_xml], [$1])])
|
||||||
|
AC_DEFUN([DX_XML_FEATURE], [AC_DEFUN([DX_FEATURE_xml], [$1])])
|
||||||
|
AC_DEFUN([DX_PDF_FEATURE], [AC_DEFUN([DX_FEATURE_pdf], [$1])])
|
||||||
|
AC_DEFUN([DX_PS_FEATURE], [AC_DEFUN([DX_FEATURE_ps], [$1])])
|
||||||
|
|
||||||
|
# DX_INIT_DOXYGEN(PROJECT, [CONFIG-FILE], [OUTPUT-DOC-DIR])
|
||||||
|
# ---------------------------------------------------------
|
||||||
|
# PROJECT also serves as the base name for the documentation files.
|
||||||
|
# The default CONFIG-FILE is "Doxyfile" and OUTPUT-DOC-DIR is "doxygen-doc".
|
||||||
|
AC_DEFUN([DX_INIT_DOXYGEN], [
|
||||||
|
|
||||||
|
# Files:
|
||||||
|
AC_SUBST([DX_PROJECT], [$1])
|
||||||
|
AC_SUBST([DX_CONFIG], [ifelse([$2], [], Doxyfile, [$2])])
|
||||||
|
AC_SUBST([DX_DOCDIR], [ifelse([$3], [], doxygen-doc, [$3])])
|
||||||
|
|
||||||
|
# Environment variables used inside doxygen.cfg:
|
||||||
|
DX_ENV_APPEND(SRCDIR, $srcdir)
|
||||||
|
DX_ENV_APPEND(PROJECT, $DX_PROJECT)
|
||||||
|
DX_ENV_APPEND(DOCDIR, $DX_DOCDIR)
|
||||||
|
DX_ENV_APPEND(VERSION, $PACKAGE_VERSION)
|
||||||
|
|
||||||
|
# Doxygen itself:
|
||||||
|
DX_ARG_ABLE(doc, [generate any doxygen documentation],
|
||||||
|
[],
|
||||||
|
[],
|
||||||
|
[DX_REQUIRE_PROG([DX_DOXYGEN], doxygen)
|
||||||
|
DX_REQUIRE_PROG([DX_PERL], perl)],
|
||||||
|
[DX_ENV_APPEND(PERL_PATH, $DX_PERL)])
|
||||||
|
|
||||||
|
# Dot for graphics:
|
||||||
|
DX_ARG_ABLE(dot, [generate graphics for doxygen documentation],
|
||||||
|
[DX_CHECK_DEPEND(doc, 1)],
|
||||||
|
[DX_CLEAR_DEPEND(doc, 1)],
|
||||||
|
[DX_REQUIRE_PROG([DX_DOT], dot)],
|
||||||
|
[DX_ENV_APPEND(HAVE_DOT, YES)
|
||||||
|
DX_ENV_APPEND(DOT_PATH, [`DX_DIRNAME_EXPR($DX_DOT)`])],
|
||||||
|
[DX_ENV_APPEND(HAVE_DOT, NO)])
|
||||||
|
|
||||||
|
# Man pages generation:
|
||||||
|
DX_ARG_ABLE(man, [generate doxygen manual pages],
|
||||||
|
[DX_CHECK_DEPEND(doc, 1)],
|
||||||
|
[DX_CLEAR_DEPEND(doc, 1)],
|
||||||
|
[],
|
||||||
|
[DX_ENV_APPEND(GENERATE_MAN, YES)],
|
||||||
|
[DX_ENV_APPEND(GENERATE_MAN, NO)])
|
||||||
|
|
||||||
|
# RTF file generation:
|
||||||
|
DX_ARG_ABLE(rtf, [generate doxygen RTF documentation],
|
||||||
|
[DX_CHECK_DEPEND(doc, 1)],
|
||||||
|
[DX_CLEAR_DEPEND(doc, 1)],
|
||||||
|
[],
|
||||||
|
[DX_ENV_APPEND(GENERATE_RTF, YES)],
|
||||||
|
[DX_ENV_APPEND(GENERATE_RTF, NO)])
|
||||||
|
|
||||||
|
# XML file generation:
|
||||||
|
DX_ARG_ABLE(xml, [generate doxygen XML documentation],
|
||||||
|
[DX_CHECK_DEPEND(doc, 1)],
|
||||||
|
[DX_CLEAR_DEPEND(doc, 1)],
|
||||||
|
[],
|
||||||
|
[DX_ENV_APPEND(GENERATE_XML, YES)],
|
||||||
|
[DX_ENV_APPEND(GENERATE_XML, NO)])
|
||||||
|
|
||||||
|
# (Compressed) HTML help generation:
|
||||||
|
DX_ARG_ABLE(chm, [generate doxygen compressed HTML help documentation],
|
||||||
|
[DX_CHECK_DEPEND(doc, 1)],
|
||||||
|
[DX_CLEAR_DEPEND(doc, 1)],
|
||||||
|
[DX_REQUIRE_PROG([DX_HHC], hhc)],
|
||||||
|
[DX_ENV_APPEND(HHC_PATH, $DX_HHC)
|
||||||
|
DX_ENV_APPEND(GENERATE_HTML, YES)
|
||||||
|
DX_ENV_APPEND(GENERATE_HTMLHELP, YES)],
|
||||||
|
[DX_ENV_APPEND(GENERATE_HTMLHELP, NO)])
|
||||||
|
|
||||||
|
# Seperate CHI file generation.
|
||||||
|
DX_ARG_ABLE(chi, [generate doxygen seperate compressed HTML help index file],
|
||||||
|
[DX_CHECK_DEPEND(chm, 1)],
|
||||||
|
[DX_CLEAR_DEPEND(chm, 1)],
|
||||||
|
[],
|
||||||
|
[DX_ENV_APPEND(GENERATE_CHI, YES)],
|
||||||
|
[DX_ENV_APPEND(GENERATE_CHI, NO)])
|
||||||
|
|
||||||
|
# Plain HTML pages generation:
|
||||||
|
DX_ARG_ABLE(html, [generate doxygen plain HTML documentation],
|
||||||
|
[DX_CHECK_DEPEND(doc, 1) DX_CHECK_DEPEND(chm, 0)],
|
||||||
|
[DX_CLEAR_DEPEND(doc, 1) DX_CLEAR_DEPEND(chm, 0)],
|
||||||
|
[],
|
||||||
|
[DX_ENV_APPEND(GENERATE_HTML, YES)],
|
||||||
|
[DX_TEST_FEATURE(chm) || DX_ENV_APPEND(GENERATE_HTML, NO)])
|
||||||
|
|
||||||
|
# PostScript file generation:
|
||||||
|
DX_ARG_ABLE(ps, [generate doxygen PostScript documentation],
|
||||||
|
[DX_CHECK_DEPEND(doc, 1)],
|
||||||
|
[DX_CLEAR_DEPEND(doc, 1)],
|
||||||
|
[DX_REQUIRE_PROG([DX_LATEX], latex)
|
||||||
|
DX_REQUIRE_PROG([DX_MAKEINDEX], makeindex)
|
||||||
|
DX_REQUIRE_PROG([DX_DVIPS], dvips)
|
||||||
|
DX_REQUIRE_PROG([DX_EGREP], egrep)])
|
||||||
|
|
||||||
|
# PDF file generation:
|
||||||
|
DX_ARG_ABLE(pdf, [generate doxygen PDF documentation],
|
||||||
|
[DX_CHECK_DEPEND(doc, 1)],
|
||||||
|
[DX_CLEAR_DEPEND(doc, 1)],
|
||||||
|
[DX_REQUIRE_PROG([DX_PDFLATEX], pdflatex)
|
||||||
|
DX_REQUIRE_PROG([DX_MAKEINDEX], makeindex)
|
||||||
|
DX_REQUIRE_PROG([DX_EGREP], egrep)])
|
||||||
|
|
||||||
|
# LaTeX generation for PS and/or PDF:
|
||||||
|
if DX_TEST_FEATURE(ps) || DX_TEST_FEATURE(pdf); then
|
||||||
|
AM_CONDITIONAL(DX_COND_latex, :)
|
||||||
|
DX_ENV_APPEND(GENERATE_LATEX, YES)
|
||||||
|
else
|
||||||
|
AM_CONDITIONAL(DX_COND_latex, false)
|
||||||
|
DX_ENV_APPEND(GENERATE_LATEX, NO)
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Paper size for PS and/or PDF:
|
||||||
|
AC_ARG_VAR(DOXYGEN_PAPER_SIZE,
|
||||||
|
[a4wide (default), a4, letter, legal or executive])
|
||||||
|
case "$DOXYGEN_PAPER_SIZE" in
|
||||||
|
#(
|
||||||
|
"")
|
||||||
|
AC_SUBST(DOXYGEN_PAPER_SIZE, "")
|
||||||
|
;; #(
|
||||||
|
a4wide|a4|letter|legal|executive)
|
||||||
|
DX_ENV_APPEND(PAPER_SIZE, $DOXYGEN_PAPER_SIZE)
|
||||||
|
;; #(
|
||||||
|
*)
|
||||||
|
AC_MSG_ERROR([unknown DOXYGEN_PAPER_SIZE='$DOXYGEN_PAPER_SIZE'])
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
#For debugging:
|
||||||
|
#echo DX_FLAG_doc=$DX_FLAG_doc
|
||||||
|
#echo DX_FLAG_dot=$DX_FLAG_dot
|
||||||
|
#echo DX_FLAG_man=$DX_FLAG_man
|
||||||
|
#echo DX_FLAG_html=$DX_FLAG_html
|
||||||
|
#echo DX_FLAG_chm=$DX_FLAG_chm
|
||||||
|
#echo DX_FLAG_chi=$DX_FLAG_chi
|
||||||
|
#echo DX_FLAG_rtf=$DX_FLAG_rtf
|
||||||
|
#echo DX_FLAG_xml=$DX_FLAG_xml
|
||||||
|
#echo DX_FLAG_pdf=$DX_FLAG_pdf
|
||||||
|
#echo DX_FLAG_ps=$DX_FLAG_ps
|
||||||
|
#echo DX_ENV=$DX_ENV
|
||||||
|
])
|
||||||
@@ -29,12 +29,18 @@ TESTS_ENVIRONMENT = export VERSION=$(PACKAGE_VERSION); export EXEEXT=$(EXEEXT);
|
|||||||
|
|
||||||
LOG_COMPILER = $(VALGRIND)
|
LOG_COMPILER = $(VALGRIND)
|
||||||
|
|
||||||
AM_CFLAGS = $(WARN_CFLAGS)
|
AM_CFLAGS = $(WARN_CFLAGS) @CHECK_CFLAGS@
|
||||||
AM_CPPFLAGS = -I$(top_srcdir)/lib -I$(top_builddir)/lib
|
AM_CPPFLAGS = -I$(top_srcdir)/lib -I$(top_builddir)/lib
|
||||||
AM_CPPFLAGS += -I$(top_srcdir)/tool -I$(top_builddir)/tool
|
AM_CPPFLAGS += -I$(top_srcdir)/tool -I$(top_builddir)/tool
|
||||||
AM_CPPFLAGS += $(OPENSSL_CFLAGS)
|
AM_CPPFLAGS += $(OPENSSL_CFLAGS)
|
||||||
|
|
||||||
AM_LDFLAGS = -no-install
|
AM_LDFLAGS = @CHECK_LIBS@
|
||||||
|
|
||||||
|
if COMPILER_CLANG
|
||||||
|
AM_LDFLAGS += -no-fast-install
|
||||||
|
else
|
||||||
|
AM_LDFLAGS += -no-install
|
||||||
|
endif
|
||||||
|
|
||||||
parse_name_LDADD = ../libpiv_util.la $(OPENSSL_LIBS)
|
parse_name_LDADD = ../libpiv_util.la $(OPENSSL_LIBS)
|
||||||
test_inout_LDADD = ../libpiv_util.la
|
test_inout_LDADD = ../libpiv_util.la
|
||||||
|
|||||||
+95
-1
@@ -1,4 +1,4 @@
|
|||||||
#!/bin/sh
|
#!/bin/bash
|
||||||
|
|
||||||
# Copyright (c) 2014-2016 Yubico AB
|
# Copyright (c) 2014-2016 Yubico AB
|
||||||
# All rights reserved.
|
# All rights reserved.
|
||||||
@@ -33,6 +33,7 @@
|
|||||||
set -e
|
set -e
|
||||||
|
|
||||||
BIN="../yubico-piv-tool${EXEEXT}"
|
BIN="../yubico-piv-tool${EXEEXT}"
|
||||||
|
ROOT_MAKEFILE="../../Makefile"
|
||||||
|
|
||||||
HELP_OUTPUT=$($BIN --help)
|
HELP_OUTPUT=$($BIN --help)
|
||||||
|
|
||||||
@@ -42,3 +43,96 @@ if [ "x$VERSION_OUTPUT" != "x$expected" ]; then
|
|||||||
echo "Version ($VERSION_OUTPUT) not matching expected output $expected."
|
echo "Version ($VERSION_OUTPUT) not matching expected output $expected."
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
################################################################################
|
||||||
|
# HARDWARE TESTS
|
||||||
|
################################################################################
|
||||||
|
################################################################################
|
||||||
|
#
|
||||||
|
# Tests below here require a Yubikey to be connected.
|
||||||
|
# These tests are destructive.
|
||||||
|
#
|
||||||
|
################################################################################
|
||||||
|
################################################################################
|
||||||
|
|
||||||
|
# Verify that --enable-hardware-tests was a build flag.
|
||||||
|
! $(set -e && cat "$ROOT_MAKEFILE" |grep "^DEFS =" | grep -- "-DHW_TESTS" >/dev/null)
|
||||||
|
HW_TESTS=$?
|
||||||
|
if [[ $HW_TESTS -eq 0 ]]; then
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Verify that user has confirmed destructive hw-tests
|
||||||
|
if [ "x$YKPIV_ENV_HWTESTS_CONFIRMED" != "x1" ]; then
|
||||||
|
printf "\n***\n*** Hardware tests skipped. Run \"make hwcheck\".\n***\n\n" >&0
|
||||||
|
exit 77 # exit code 77 == skipped tests
|
||||||
|
fi
|
||||||
|
|
||||||
|
#
|
||||||
|
# Run basic import/validation tests on included keys/certs. Test keys generated
|
||||||
|
# with the following commands:
|
||||||
|
#
|
||||||
|
# $ openssl genrsa -out private.pem 2048
|
||||||
|
# $ openssl rsa -in private.pem -outform PEM -pubout -out public.pem
|
||||||
|
# $ openssl req -x509 -key private.pem -out cert.pem -subj "/CN=YubicoTest/OU=YubicoTestUnit/O=yubico.com/" -new
|
||||||
|
#
|
||||||
|
|
||||||
|
# Reset
|
||||||
|
$BIN -averify-pin -P000000 || true
|
||||||
|
$BIN -averify-pin -P000000 || true
|
||||||
|
$BIN -averify-pin -P000000 || true
|
||||||
|
$BIN -averify-pin -P000000 || true
|
||||||
|
$BIN -averify-pin -P000000 || true
|
||||||
|
$BIN -achange-puk -P000000 -N00000000 || true
|
||||||
|
$BIN -achange-puk -P000000 -N00000000 || true
|
||||||
|
$BIN -achange-puk -P000000 -N00000000 || true
|
||||||
|
$BIN -achange-puk -P000000 -N00000000 || true
|
||||||
|
$BIN -achange-puk -P000000 -N00000000 || true
|
||||||
|
$BIN -areset
|
||||||
|
|
||||||
|
# Generate key on-board, issue certificate, and verify it
|
||||||
|
$BIN -agenerate -s9a -AECCP256 -o key_9a.pub
|
||||||
|
$BIN -averify -P123456 -s9a -S'/CN=YubicoTest/OU=YubicoGenerated/O=yubico.com/' -aselfsign -i key_9a.pub -o cert_9a.pem
|
||||||
|
$BIN -averify -P123456 -s9a -atest-signature -i cert_9a.pem
|
||||||
|
$BIN -aimport-certificate -P123456 -s9a -i cert_9a.pem
|
||||||
|
|
||||||
|
# Import key, generate self-signed certificate, and verify it
|
||||||
|
$BIN -aimport-key -P123456 -s9e -iprivate.pem
|
||||||
|
$BIN -arequest-certificate -s9e -S"/CN=bar/OU=test/O=example.com/" -i public.pem -o req_9e.pem
|
||||||
|
$BIN -averify -P123456 -s9e -S'/CN=bar/OU=test/O=example.com/' -aselfsign -i public.pem -o cert_9e.pem
|
||||||
|
$BIN -atest-decipher -s9e -i cert_9e.pem
|
||||||
|
$BIN -aimport-certificate -P123456 -s9e -i cert.pem
|
||||||
|
|
||||||
|
|
||||||
|
# Read status and validate fields
|
||||||
|
STATUS=$($BIN -astatus)
|
||||||
|
echo "$STATUS"
|
||||||
|
ALGO_9A=$(echo "$STATUS" |grep "Slot 9a" -A 6 |grep "Algorithm" |tr -d "[:blank:]")
|
||||||
|
if [[ "x$ALGO_9A" != "xAlgorithm:ECCP256" ]]; then
|
||||||
|
echo "$ALGO_9A"
|
||||||
|
echo "Generated algorithm incorrect." >/dev/stderr
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
ALGO_9E=$(echo "$STATUS" |grep "Slot 9e" -A 6 |grep "Algorithm" |tr -d "[:blank:]")
|
||||||
|
if [[ "x$ALGO_9E" != "xAlgorithm:RSA2048" ]]; then
|
||||||
|
echo "$ALGO_9E"
|
||||||
|
echo "Generated algorithm incorrect." >/dev/stderr
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
SUBJECT_9A=$(echo "$STATUS" |grep "Slot 9a" -A 6 |grep "Subject DN" |tr -d "[:blank:]")
|
||||||
|
if [[ "x$SUBJECT_9A" != "xSubjectDN:CN=YubicoTest,OU=YubicoGenerated,O=yubico.com" ]]; then
|
||||||
|
echo "$SUBJECT_9A"
|
||||||
|
echo "Certificate subject incorrect." >/dev/stderr
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
SUBJECT_9E=$(echo "$STATUS" |grep "Slot 9e" -A 6 |grep "Subject DN" |tr -d "[:blank:]")
|
||||||
|
if [[ "x$SUBJECT_9E" != "xSubjectDN:CN=YubicoTest,OU=YubicoTestUnit,O=yubico.com" ]]; then
|
||||||
|
echo "$SUBJECT_9E"
|
||||||
|
echo "Certificate subject incorrect." >/dev/stderr
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIDrzCCApegAwIBAgIJAM1blQIJfeuCMA0GCSqGSIb3DQEBBQUAMEMxEzARBgNV
|
||||||
|
BAMTCll1Ymljb1Rlc3QxFzAVBgNVBAsTDll1Ymljb1Rlc3RVbml0MRMwEQYDVQQK
|
||||||
|
Ewp5dWJpY28uY29tMB4XDTE3MDkyNzEzMzYxNFoXDTE3MTAyNzEzMzYxNFowQzET
|
||||||
|
MBEGA1UEAxMKWXViaWNvVGVzdDEXMBUGA1UECxMOWXViaWNvVGVzdFVuaXQxEzAR
|
||||||
|
BgNVBAoTCnl1Ymljby5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
|
||||||
|
AQDKRTcyy2rVuV6cex5GdRT3VWntbqVPC4p6BcATEAeSXDgORaWhQOnv7WF9a8Rc
|
||||||
|
bsWH0j807f+CvqirtFZHbSBsMYlxyko4Mer/gxb2uqy08B4fWeOxeTpNNQ63gfHZ
|
||||||
|
g4tqnDmFulAiZilVnuiimAdC0iLliXaowkFEcPFGPEmjV/lWTgalgFOe/utySbVs
|
||||||
|
vUp2EjeBDcOdUqc1oHH1GVoMRKMm7PTT9/8SVawVUneCqOFCNNxyW7PjRpTr5qPq
|
||||||
|
1ucMOmz2UIPwJVHIQEbL5IL3NtkozmbZ0G9cqnRrYSXGmlBrdcq5fH7qrMcifIMW
|
||||||
|
QXVinhzbIcrRpW0Vm653efxDAgMBAAGjgaUwgaIwHQYDVR0OBBYEFKEF2ASXCBPt
|
||||||
|
+4Wh0o36Ee6+HvRRMHMGA1UdIwRsMGqAFKEF2ASXCBPt+4Wh0o36Ee6+HvRRoUek
|
||||||
|
RTBDMRMwEQYDVQQDEwpZdWJpY29UZXN0MRcwFQYDVQQLEw5ZdWJpY29UZXN0VW5p
|
||||||
|
dDETMBEGA1UEChMKeXViaWNvLmNvbYIJAM1blQIJfeuCMAwGA1UdEwQFMAMBAf8w
|
||||||
|
DQYJKoZIhvcNAQEFBQADggEBADaeHhj7vjZ8OGIAOd86UAqJrqyQ6Lhu133pBRoV
|
||||||
|
4qQprZFRXxsxVyAqKDAWMF/GTidMRlVRAQNnR9kHYuG7zpy+NjlK2khAEflAa6Z5
|
||||||
|
nGMntv0+y7NLkKGAAk9qxqpNwj90VzFcvopDFA70FVnWtgkuJuFf5n+fHTUMOzTk
|
||||||
|
p6+BMRUjJqu7weK+QUI8b9zl7pSzWbcHqxyrJSNRW87xvEQhyJzFqbqQprYGheZk
|
||||||
|
py5wUX22HBhAuw7cvakeUMIX133UJI7Yxwy5DKoiqsESKGr/oXIU3+M0kqzDwQCA
|
||||||
|
HI1y9cIY/3Zi3Y7HgQnHX2Oos3k2SY0VpYtO47Ja/oIkolc=
|
||||||
|
-----END CERTIFICATE-----
|
||||||
+49
-17
@@ -28,6 +28,8 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <check.h>
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
@@ -39,18 +41,26 @@
|
|||||||
|
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
static void test_name(const char *name, const char *expected, bool fail) {
|
struct name {
|
||||||
|
const char *name;
|
||||||
|
const char *parsed_name;
|
||||||
|
bool valid;
|
||||||
|
} names[] = {
|
||||||
|
{"/CN=test foo/", "CN = test foo", true},
|
||||||
|
{"/CN=test/OU=bar/O=EXAMPLE/", "CN = test, OU = bar, O = EXAMPLE", true},
|
||||||
|
{"/CN=test/OU=bar/O=EXAMPLE/", "CN = test, OU = wrong, O = EXAMPLE", false},
|
||||||
|
{"/foo/", "", false},
|
||||||
|
{"/CN=test/foobar/", "", false},
|
||||||
|
{"/CN=test/foo=bar/", "", false},
|
||||||
|
};
|
||||||
|
|
||||||
|
static bool test_name(const char *name, const char *expected) {
|
||||||
char buf[1024];
|
char buf[1024];
|
||||||
BIO *bio;
|
BIO *bio;
|
||||||
const char none[] = {0};
|
const char none[] = {0};
|
||||||
X509_NAME *parsed = parse_name(name);
|
X509_NAME *parsed = parse_name(name);
|
||||||
if(parsed == NULL) {
|
if(parsed == NULL) {
|
||||||
if(fail) {
|
return false;
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
printf("Failed parsing of '%s'!\n", name);
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bio = BIO_new(BIO_s_mem());
|
bio = BIO_new(BIO_s_mem());
|
||||||
@@ -61,17 +71,39 @@ static void test_name(const char *name, const char *expected, bool fail) {
|
|||||||
BIO_free(bio);
|
BIO_free(bio);
|
||||||
X509_NAME_free(parsed);
|
X509_NAME_free(parsed);
|
||||||
if(strcmp(buf, expected) != 0) {
|
if(strcmp(buf, expected) != 0) {
|
||||||
printf("Names not matching: '%s' != '%s'\n", expected, buf);
|
fprintf(stderr, "Names not matching: '%s' != '%s'\n", expected, buf);
|
||||||
exit(EXIT_FAILURE);
|
return false;
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(void) {
|
START_TEST(test_parse_name) {
|
||||||
test_name("/CN=test foo/", "CN = test foo", false);
|
ck_assert(test_name(names[_i].name, names[_i].parsed_name) == names[_i].valid);
|
||||||
test_name("/CN=test/OU=bar/O=EXAMPLE/", "CN = test, OU = bar, O = EXAMPLE", false);
|
}
|
||||||
test_name("/foo/", "", true);
|
END_TEST
|
||||||
test_name("/CN=test/foobar/", "", true);
|
|
||||||
test_name("/CN=test/foo=bar/", "", true);
|
Suite *test_suite(void) {
|
||||||
|
Suite *s;
|
||||||
return EXIT_SUCCESS;
|
TCase *tc;
|
||||||
|
|
||||||
|
s = suite_create("yubico-piv-tool parse_name");
|
||||||
|
tc = tcase_create("parse_name");
|
||||||
|
tcase_add_loop_test(tc, test_parse_name, 0, sizeof(names) / sizeof(struct name));
|
||||||
|
suite_add_tcase(s, tc);
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
int number_failed;
|
||||||
|
Suite *s;
|
||||||
|
SRunner *sr;
|
||||||
|
|
||||||
|
s = test_suite();
|
||||||
|
sr = srunner_create(s);
|
||||||
|
srunner_run_all(sr, CK_NORMAL);
|
||||||
|
number_failed = srunner_ntests_failed(sr);
|
||||||
|
srunner_free(sr);
|
||||||
|
return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,27 @@
|
|||||||
|
-----BEGIN RSA PRIVATE KEY-----
|
||||||
|
MIIEpQIBAAKCAQEAykU3Mstq1blenHseRnUU91Vp7W6lTwuKegXAExAHklw4DkWl
|
||||||
|
oUDp7+1hfWvEXG7Fh9I/NO3/gr6oq7RWR20gbDGJccpKODHq/4MW9rqstPAeH1nj
|
||||||
|
sXk6TTUOt4Hx2YOLapw5hbpQImYpVZ7oopgHQtIi5Yl2qMJBRHDxRjxJo1f5Vk4G
|
||||||
|
pYBTnv7rckm1bL1KdhI3gQ3DnVKnNaBx9RlaDESjJuz00/f/ElWsFVJ3gqjhQjTc
|
||||||
|
cluz40aU6+aj6tbnDDps9lCD8CVRyEBGy+SC9zbZKM5m2dBvXKp0a2ElxppQa3XK
|
||||||
|
uXx+6qzHInyDFkF1Yp4c2yHK0aVtFZuud3n8QwIDAQABAoIBAE1Q9c+Bt/2oFMUl
|
||||||
|
vqXZ/UCpsorif2felnkcF5ZxyyMkAv1Zm/0ujf17NIe3mOBoKzNGp4h47PEyJdE0
|
||||||
|
ZsJ4sSsKKGqJk6M1WYl/t1hqdLfZDPqY5pMhLqryfASjNCobwT/oJYi7dgQgHu6u
|
||||||
|
hmgYSrY9Er/Ass3BKyeZMHDTfKZlvM8GZ/oF8bhkD1P/fi6xU1bhs1XCTQpkkING
|
||||||
|
eESbD5ZGMZU4HYusdmOmf2Y4LXqVZkag86Fw7XAg6b80FDR8Af6S9fzoPA7Aapmg
|
||||||
|
uvH19BHeSH/DiLTQ6d31GijSsx+rW/F5mrs5wldGO/htTJwRx0YoccUMPF2mMx+d
|
||||||
|
ShOlzckCgYEA9p9rT7kkj1ZglNB1gwo+IdbEZydlK3NvHmXMFa3IkmBg1nK1dpnM
|
||||||
|
0DK0Ycyb7LIuBN3sc2QV5+D3Yv8LspeTMBVajddts/dIJKQb51hRsC3PvQVUnaMD
|
||||||
|
3YYqDmZUlIv9bKfvAbOuNUOg4FXkaXFkkNNsLxv92bARKHPLo6eE7UcCgYEA0fYU
|
||||||
|
ImTKv9W8rpPcc7lf8Ffhw7mRrMTA/qFNSdJvjED9UXzH7Dp0abQ9nK8XxTWEl0oe
|
||||||
|
l0h+5H5YiV6Li8BXcWgnferbpi0Jwkdvh2Qc7LmJ/o278KLPKIqDItRd0gEgC9hR
|
||||||
|
H1M91Y1pNcv1Mj95hKx3L0ROXhwBAy4ohddjRyUCgYEAp8VFdEOHynbBVxsEhfNm
|
||||||
|
1xBKJb5YBZoOgohPsIO7SVCFL/1y0s7H1O5ZZZqSjA+eXLM30jvI5yhUQqUsKP8S
|
||||||
|
IwizxIBD4cSb8Ekvrk6Xq5lOk9DXgjFORNmrLIaSjUc6TDtlzSuVnCh4fYQQ0WZR
|
||||||
|
OnCJTPbm1rr+wR0c8CTauasCgYEAqie7eYQlrAITv4elCUQaNDWEiZJCNLnfjnw6
|
||||||
|
nrEkJY4lvXxaqV9WKLQhmnFr2i7dHZ672+6sp5CdP/aXMNLYCthV6P4EtE+bsQ8j
|
||||||
|
m53OsypKYzmKLiJDsJ9QV1G0FxVCW1cbpz9WxVKtCSQZuncmjBcZH/1DZZFcYK9v
|
||||||
|
t8gudOECgYEAh3hlXVeMv2/oEW21G7D0s3Cv2vOSvBogdwVRP8EGOkn43rh5GXZm
|
||||||
|
7NVJjJNwURwLcowb0F4B/RILxArtjW2srUo1nbq5UoCiFNJ/00JoRSzAz1ad7S2o
|
||||||
|
0nRuVLQ50WYG/HBTP2M4yQbpP/E+5PCNMGx2kgyuTUyeCl+LEE8bg5k=
|
||||||
|
-----END RSA PRIVATE KEY-----
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
-----BEGIN PUBLIC KEY-----
|
||||||
|
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAykU3Mstq1blenHseRnUU
|
||||||
|
91Vp7W6lTwuKegXAExAHklw4DkWloUDp7+1hfWvEXG7Fh9I/NO3/gr6oq7RWR20g
|
||||||
|
bDGJccpKODHq/4MW9rqstPAeH1njsXk6TTUOt4Hx2YOLapw5hbpQImYpVZ7oopgH
|
||||||
|
QtIi5Yl2qMJBRHDxRjxJo1f5Vk4GpYBTnv7rckm1bL1KdhI3gQ3DnVKnNaBx9Rla
|
||||||
|
DESjJuz00/f/ElWsFVJ3gqjhQjTccluz40aU6+aj6tbnDDps9lCD8CVRyEBGy+SC
|
||||||
|
9zbZKM5m2dBvXKp0a2ElxppQa3XKuXx+6qzHInyDFkF1Yp4c2yHK0aVtFZuud3n8
|
||||||
|
QwIDAQAB
|
||||||
|
-----END PUBLIC KEY-----
|
||||||
+43
-8
@@ -28,6 +28,8 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <check.h>
|
||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@@ -40,25 +42,58 @@
|
|||||||
#define pipe(fds) _pipe(fds,4096, 0)
|
#define pipe(fds) _pipe(fds,4096, 0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static void test_inout(enum enum_format format) {
|
enum enum_format formats[] = {
|
||||||
|
format_arg_base64,
|
||||||
|
format_arg_hex,
|
||||||
|
format_arg_binary,
|
||||||
|
};
|
||||||
|
|
||||||
|
static bool inout(enum enum_format format) {
|
||||||
const unsigned char buf[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08};
|
const unsigned char buf[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08};
|
||||||
unsigned char buf2[sizeof(buf)];
|
unsigned char buf2[sizeof(buf)];
|
||||||
int pipefd[2];
|
int pipefd[2];
|
||||||
FILE *tmp1, *tmp2;
|
FILE *tmp1, *tmp2;
|
||||||
|
|
||||||
assert(pipe(pipefd) == 0);
|
if (pipe(pipefd) != 0)
|
||||||
|
return false;
|
||||||
tmp1 = fdopen(pipefd[1], "w");
|
tmp1 = fdopen(pipefd[1], "w");
|
||||||
dump_data(buf, sizeof(buf), tmp1, false, format);
|
dump_data(buf, sizeof(buf), tmp1, false, format);
|
||||||
fclose(tmp1);
|
fclose(tmp1);
|
||||||
tmp2 = fdopen(pipefd[0], "r");
|
tmp2 = fdopen(pipefd[0], "r");
|
||||||
read_data(buf2, sizeof(buf2), tmp2, format);
|
read_data(buf2, sizeof(buf2), tmp2, format);
|
||||||
assert(memcmp(buf, buf2, sizeof(buf)) == 0);
|
if (memcmp(buf, buf2, sizeof(buf)) != 0)
|
||||||
|
return false;
|
||||||
fclose(tmp2);
|
fclose(tmp2);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(void) {
|
START_TEST(test_inout) {
|
||||||
test_inout(format_arg_base64);
|
ck_assert(inout(formats[_i]));
|
||||||
test_inout(format_arg_hex);
|
}
|
||||||
test_inout(format_arg_binary);
|
END_TEST
|
||||||
exit(0);
|
|
||||||
|
Suite *test_suite(void) {
|
||||||
|
Suite *s;
|
||||||
|
TCase *tc;
|
||||||
|
|
||||||
|
s = suite_create("yubico-piv-tool inout");
|
||||||
|
tc = tcase_create("inout");
|
||||||
|
tcase_add_loop_test(tc, test_inout, 0, sizeof(formats) / sizeof(*formats));
|
||||||
|
suite_add_tcase(s, tc);
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
int number_failed;
|
||||||
|
Suite *s;
|
||||||
|
SRunner *sr;
|
||||||
|
|
||||||
|
s = test_suite();
|
||||||
|
sr = srunner_create(s);
|
||||||
|
srunner_run_all(sr, CK_NORMAL);
|
||||||
|
number_failed = srunner_ntests_failed(sr);
|
||||||
|
srunner_free(sr);
|
||||||
|
return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|||||||
+34
-136
@@ -46,12 +46,31 @@
|
|||||||
#include "cmdline.h"
|
#include "cmdline.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
FILE *open_file(const char *file_name, int mode) {
|
FILE *open_file(const char *file_name, enum file_mode mode) {
|
||||||
FILE *file;
|
FILE *file;
|
||||||
|
const char *mod;
|
||||||
if(!strcmp(file_name, "-")) {
|
if(!strcmp(file_name, "-")) {
|
||||||
file = mode == INPUT ? stdin : stdout;
|
file = (mode == INPUT_TEXT || mode == INPUT_BIN) ? stdin : stdout;
|
||||||
} else {
|
} else {
|
||||||
file = fopen(file_name, mode == INPUT ? "r" : "w");
|
switch (mode) {
|
||||||
|
case INPUT_TEXT:
|
||||||
|
mod = "r";
|
||||||
|
break;
|
||||||
|
case INPUT_BIN:
|
||||||
|
mod = "rb";
|
||||||
|
break;
|
||||||
|
case OUTPUT_TEXT:
|
||||||
|
mod = "w";
|
||||||
|
break;
|
||||||
|
case OUTPUT_BIN:
|
||||||
|
mod = "wb";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
fprintf(stderr, "Invalid file mode.\n");
|
||||||
|
return NULL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
file = fopen(file_name, mod);
|
||||||
if(!file) {
|
if(!file) {
|
||||||
fprintf(stderr, "Failed opening '%s'!\n", file_name);
|
fprintf(stderr, "Failed opening '%s'!\n", file_name);
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -255,172 +274,49 @@ int set_length(unsigned char *buffer, int length) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int get_object_id(enum enum_slot slot) {
|
int get_slot_hex(enum enum_slot slot_enum) {
|
||||||
int object;
|
int slot = -1;
|
||||||
|
|
||||||
switch(slot) {
|
switch (slot_enum) {
|
||||||
case slot_arg_9a:
|
case slot_arg_9a:
|
||||||
object = YKPIV_OBJ_AUTHENTICATION;
|
slot = 0x9a;
|
||||||
break;
|
break;
|
||||||
case slot_arg_9c:
|
case slot_arg_9c:
|
||||||
object = YKPIV_OBJ_SIGNATURE;
|
|
||||||
break;
|
|
||||||
case slot_arg_9d:
|
case slot_arg_9d:
|
||||||
object = YKPIV_OBJ_KEY_MANAGEMENT;
|
|
||||||
break;
|
|
||||||
case slot_arg_9e:
|
case slot_arg_9e:
|
||||||
object = YKPIV_OBJ_CARD_AUTH;
|
slot = 0x9c + ((int)slot_enum - (int)slot_arg_9c);
|
||||||
break;
|
break;
|
||||||
case slot_arg_82:
|
case slot_arg_82:
|
||||||
object = YKPIV_OBJ_RETIRED1;
|
|
||||||
break;
|
|
||||||
case slot_arg_83:
|
case slot_arg_83:
|
||||||
object = YKPIV_OBJ_RETIRED2;
|
|
||||||
break;
|
|
||||||
case slot_arg_84:
|
case slot_arg_84:
|
||||||
object = YKPIV_OBJ_RETIRED3;
|
|
||||||
break;
|
|
||||||
case slot_arg_85:
|
case slot_arg_85:
|
||||||
object = YKPIV_OBJ_RETIRED4;
|
|
||||||
break;
|
|
||||||
case slot_arg_86:
|
case slot_arg_86:
|
||||||
object = YKPIV_OBJ_RETIRED5;
|
|
||||||
break;
|
|
||||||
case slot_arg_87:
|
case slot_arg_87:
|
||||||
object = YKPIV_OBJ_RETIRED6;
|
|
||||||
break;
|
|
||||||
case slot_arg_88:
|
case slot_arg_88:
|
||||||
object = YKPIV_OBJ_RETIRED7;
|
|
||||||
break;
|
|
||||||
case slot_arg_89:
|
case slot_arg_89:
|
||||||
object = YKPIV_OBJ_RETIRED8;
|
|
||||||
break;
|
|
||||||
case slot_arg_8a:
|
case slot_arg_8a:
|
||||||
object = YKPIV_OBJ_RETIRED9;
|
|
||||||
break;
|
|
||||||
case slot_arg_8b:
|
case slot_arg_8b:
|
||||||
object = YKPIV_OBJ_RETIRED10;
|
|
||||||
break;
|
|
||||||
case slot_arg_8c:
|
case slot_arg_8c:
|
||||||
object = YKPIV_OBJ_RETIRED11;
|
|
||||||
break;
|
|
||||||
case slot_arg_8d:
|
case slot_arg_8d:
|
||||||
object = YKPIV_OBJ_RETIRED12;
|
|
||||||
break;
|
|
||||||
case slot_arg_8e:
|
case slot_arg_8e:
|
||||||
object = YKPIV_OBJ_RETIRED13;
|
|
||||||
break;
|
|
||||||
case slot_arg_8f:
|
case slot_arg_8f:
|
||||||
object = YKPIV_OBJ_RETIRED14;
|
|
||||||
break;
|
|
||||||
case slot_arg_90:
|
case slot_arg_90:
|
||||||
object = YKPIV_OBJ_RETIRED15;
|
|
||||||
break;
|
|
||||||
case slot_arg_91:
|
case slot_arg_91:
|
||||||
object = YKPIV_OBJ_RETIRED16;
|
|
||||||
break;
|
|
||||||
case slot_arg_92:
|
case slot_arg_92:
|
||||||
object = YKPIV_OBJ_RETIRED17;
|
|
||||||
break;
|
|
||||||
case slot_arg_93:
|
case slot_arg_93:
|
||||||
object = YKPIV_OBJ_RETIRED18;
|
|
||||||
break;
|
|
||||||
case slot_arg_94:
|
case slot_arg_94:
|
||||||
object = YKPIV_OBJ_RETIRED19;
|
|
||||||
break;
|
|
||||||
case slot_arg_95:
|
case slot_arg_95:
|
||||||
object = YKPIV_OBJ_RETIRED20;
|
slot = 0x82 + ((int)slot_enum - (int)slot_arg_82);
|
||||||
break;
|
break;
|
||||||
case slot_arg_f9:
|
case slot_arg_f9:
|
||||||
object = YKPIV_OBJ_ATTESTATION;
|
slot = 0xf9;
|
||||||
break;
|
break;
|
||||||
case slot__NULL:
|
case slot__NULL:
|
||||||
default:
|
default:
|
||||||
object = 0;
|
slot = -1;
|
||||||
}
|
|
||||||
return object;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int key_to_object_id(int key) {
|
return slot;
|
||||||
int object;
|
|
||||||
|
|
||||||
switch(key) {
|
|
||||||
case YKPIV_KEY_AUTHENTICATION:
|
|
||||||
object = YKPIV_OBJ_AUTHENTICATION;
|
|
||||||
break;
|
|
||||||
case YKPIV_KEY_CARDMGM:
|
|
||||||
object = YKPIV_OBJ_SIGNATURE;
|
|
||||||
break;
|
|
||||||
case YKPIV_KEY_KEYMGM:
|
|
||||||
object = YKPIV_OBJ_KEY_MANAGEMENT;
|
|
||||||
break;
|
|
||||||
case YKPIV_KEY_CARDAUTH:
|
|
||||||
object = YKPIV_OBJ_CARD_AUTH;
|
|
||||||
break;
|
|
||||||
case YKPIV_KEY_RETIRED1:
|
|
||||||
object = YKPIV_OBJ_RETIRED1;
|
|
||||||
break;
|
|
||||||
case YKPIV_KEY_RETIRED2:
|
|
||||||
object = YKPIV_OBJ_RETIRED2;
|
|
||||||
break;
|
|
||||||
case YKPIV_KEY_RETIRED3:
|
|
||||||
object = YKPIV_OBJ_RETIRED3;
|
|
||||||
break;
|
|
||||||
case YKPIV_KEY_RETIRED4:
|
|
||||||
object = YKPIV_OBJ_RETIRED4;
|
|
||||||
break;
|
|
||||||
case YKPIV_KEY_RETIRED5:
|
|
||||||
object = YKPIV_OBJ_RETIRED5;
|
|
||||||
break;
|
|
||||||
case YKPIV_KEY_RETIRED6:
|
|
||||||
object = YKPIV_OBJ_RETIRED6;
|
|
||||||
break;
|
|
||||||
case YKPIV_KEY_RETIRED7:
|
|
||||||
object = YKPIV_OBJ_RETIRED7;
|
|
||||||
break;
|
|
||||||
case YKPIV_KEY_RETIRED8:
|
|
||||||
object = YKPIV_OBJ_RETIRED8;
|
|
||||||
break;
|
|
||||||
case YKPIV_KEY_RETIRED9:
|
|
||||||
object = YKPIV_OBJ_RETIRED9;
|
|
||||||
break;
|
|
||||||
case YKPIV_KEY_RETIRED10:
|
|
||||||
object = YKPIV_OBJ_RETIRED10;
|
|
||||||
break;
|
|
||||||
case YKPIV_KEY_RETIRED11:
|
|
||||||
object = YKPIV_OBJ_RETIRED11;
|
|
||||||
break;
|
|
||||||
case YKPIV_KEY_RETIRED12:
|
|
||||||
object = YKPIV_OBJ_RETIRED12;
|
|
||||||
break;
|
|
||||||
case YKPIV_KEY_RETIRED13:
|
|
||||||
object = YKPIV_OBJ_RETIRED13;
|
|
||||||
break;
|
|
||||||
case YKPIV_KEY_RETIRED14:
|
|
||||||
object = YKPIV_OBJ_RETIRED14;
|
|
||||||
break;
|
|
||||||
case YKPIV_KEY_RETIRED15:
|
|
||||||
object = YKPIV_OBJ_RETIRED15;
|
|
||||||
break;
|
|
||||||
case YKPIV_KEY_RETIRED16:
|
|
||||||
object = YKPIV_OBJ_RETIRED16;
|
|
||||||
break;
|
|
||||||
case YKPIV_KEY_RETIRED17:
|
|
||||||
object = YKPIV_OBJ_RETIRED17;
|
|
||||||
break;
|
|
||||||
case YKPIV_KEY_RETIRED18:
|
|
||||||
object = YKPIV_OBJ_RETIRED18;
|
|
||||||
break;
|
|
||||||
case YKPIV_KEY_RETIRED19:
|
|
||||||
object = YKPIV_OBJ_RETIRED19;
|
|
||||||
break;
|
|
||||||
case YKPIV_KEY_RETIRED20:
|
|
||||||
object = YKPIV_OBJ_RETIRED20;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
object = 0;
|
|
||||||
}
|
|
||||||
return object;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool set_component(unsigned char *in_ptr, const BIGNUM *bn, int element_len) {
|
bool set_component(unsigned char *in_ptr, const BIGNUM *bn, int element_len) {
|
||||||
@@ -647,7 +543,9 @@ int SSH_write_X509(FILE *fp, X509 *x) {
|
|||||||
|
|
||||||
rsa = EVP_PKEY_get1_RSA(pkey);
|
rsa = EVP_PKEY_get1_RSA(pkey);
|
||||||
|
|
||||||
set_component(n, rsa->n, RSA_size(rsa));
|
if (!set_component(n, rsa->n, RSA_size(rsa))) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t bytes = BN_num_bytes(rsa->n);
|
uint32_t bytes = BN_num_bytes(rsa->n);
|
||||||
char len_buf[5];
|
char len_buf[5];
|
||||||
|
|||||||
+8
-5
@@ -37,8 +37,12 @@
|
|||||||
|
|
||||||
#include "cmdline.h"
|
#include "cmdline.h"
|
||||||
|
|
||||||
#define INPUT 1
|
enum file_mode {
|
||||||
#define OUTPUT 2
|
INPUT_TEXT,
|
||||||
|
OUTPUT_TEXT,
|
||||||
|
INPUT_BIN,
|
||||||
|
OUTPUT_BIN,
|
||||||
|
};
|
||||||
|
|
||||||
size_t read_data(unsigned char*, size_t, FILE*, enum enum_format);
|
size_t read_data(unsigned char*, size_t, FILE*, enum enum_format);
|
||||||
void dump_data(unsigned const char*, unsigned int, FILE*, bool, enum enum_format);
|
void dump_data(unsigned const char*, unsigned int, FILE*, bool, enum enum_format);
|
||||||
@@ -46,9 +50,8 @@ int set_length(unsigned char*, int);
|
|||||||
int get_length(const unsigned char*, int*);
|
int get_length(const unsigned char*, int*);
|
||||||
X509_NAME *parse_name(const char*);
|
X509_NAME *parse_name(const char*);
|
||||||
unsigned char get_algorithm(EVP_PKEY*);
|
unsigned char get_algorithm(EVP_PKEY*);
|
||||||
FILE *open_file(const char*, int);
|
FILE *open_file(const char *file_name, enum file_mode mode);
|
||||||
int get_object_id(enum enum_slot slot);
|
int get_slot_hex(enum enum_slot slot_enum);
|
||||||
int key_to_object_id(int key);
|
|
||||||
bool set_component(unsigned char *in_ptr, const BIGNUM *bn, int element_len);
|
bool set_component(unsigned char *in_ptr, const BIGNUM *bn, int element_len);
|
||||||
bool prepare_rsa_signature(const unsigned char*, unsigned int, unsigned char*,
|
bool prepare_rsa_signature(const unsigned char*, unsigned int, unsigned char*,
|
||||||
unsigned int*, int);
|
unsigned int*, int);
|
||||||
|
|||||||
+148
-286
@@ -50,26 +50,8 @@
|
|||||||
#include "cmdline.h"
|
#include "cmdline.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
/* FASC-N containing S9999F9999F999999F0F1F0000000000300001E encoded in
|
#define MAX(a,b) (a) > (b) ? (a) : (b)
|
||||||
* 4-bit BCD with 1 bit parity. run through the tools/fasc.pl script to get
|
#define MIN(a,b) (a) < (b) ? (a) : (b)
|
||||||
* bytes. */
|
|
||||||
/* this CHUID has an expiry of 2030-01-01, maybe that should be variable.. */
|
|
||||||
unsigned const char chuid_tmpl[] = {
|
|
||||||
0x30, 0x19, 0xd4, 0xe7, 0x39, 0xda, 0x73, 0x9c, 0xed, 0x39, 0xce, 0x73, 0x9d,
|
|
||||||
0x83, 0x68, 0x58, 0x21, 0x08, 0x42, 0x10, 0x84, 0x21, 0x38, 0x42, 0x10, 0xc3,
|
|
||||||
0xf5, 0x34, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x35, 0x08, 0x32, 0x30, 0x33, 0x30, 0x30,
|
|
||||||
0x31, 0x30, 0x31, 0x3e, 0x00, 0xfe, 0x00,
|
|
||||||
};
|
|
||||||
#define CHUID_GUID_OFFS 29
|
|
||||||
|
|
||||||
unsigned const char ccc_tmpl[] = {
|
|
||||||
0xf0, 0x15, 0xa0, 0x00, 0x00, 0x01, 0x16, 0xff, 0x02, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf1, 0x01, 0x21,
|
|
||||||
0xf2, 0x01, 0x21, 0xf3, 0x00, 0xf4, 0x01, 0x00, 0xf5, 0x01, 0x10, 0xf6, 0x00,
|
|
||||||
0xf7, 0x00, 0xfa, 0x00, 0xfb, 0x00, 0xfc, 0x00, 0xfd, 0x00, 0xfe, 0x00
|
|
||||||
};
|
|
||||||
#define CCC_ID_OFFS 9
|
|
||||||
|
|
||||||
#define CHUID 0
|
#define CHUID 0
|
||||||
#define CCC 1
|
#define CCC 1
|
||||||
@@ -78,9 +60,35 @@ unsigned const char ccc_tmpl[] = {
|
|||||||
|
|
||||||
#define KEY_LEN 24
|
#define KEY_LEN 24
|
||||||
|
|
||||||
|
static enum file_mode key_file_mode(enum enum_key_format fmt, bool output) {
|
||||||
|
if (fmt == key_format_arg_PEM) {
|
||||||
|
if (output) {
|
||||||
|
return OUTPUT_TEXT;
|
||||||
|
}
|
||||||
|
return INPUT_TEXT;
|
||||||
|
}
|
||||||
|
if (output) {
|
||||||
|
return OUTPUT_BIN;
|
||||||
|
}
|
||||||
|
return INPUT_BIN;
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum file_mode data_file_mode(enum enum_format fmt, bool output) {
|
||||||
|
if (fmt == format_arg_binary) {
|
||||||
|
if (output) {
|
||||||
|
return OUTPUT_BIN;
|
||||||
|
}
|
||||||
|
return INPUT_BIN;
|
||||||
|
}
|
||||||
|
if (output) {
|
||||||
|
return OUTPUT_TEXT;
|
||||||
|
}
|
||||||
|
return INPUT_TEXT;
|
||||||
|
}
|
||||||
|
|
||||||
static void print_version(ykpiv_state *state, const char *output_file_name) {
|
static void print_version(ykpiv_state *state, const char *output_file_name) {
|
||||||
char version[7];
|
char version[7];
|
||||||
FILE *output_file = open_file(output_file_name, OUTPUT);
|
FILE *output_file = open_file(output_file_name, OUTPUT_TEXT);
|
||||||
if(!output_file) {
|
if(!output_file) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -115,167 +123,89 @@ static bool sign_data(ykpiv_state *state, const unsigned char *in, size_t len, u
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool generate_key(ykpiv_state *state, const char *slot,
|
static bool generate_key(ykpiv_state *state, enum enum_slot slot,
|
||||||
enum enum_algorithm algorithm, const char *output_file_name,
|
enum enum_algorithm algorithm, const char *output_file_name,
|
||||||
enum enum_key_format key_format, enum enum_pin_policy pin_policy,
|
enum enum_key_format key_format, enum enum_pin_policy pin_policy,
|
||||||
enum enum_touch_policy touch_policy) {
|
enum enum_touch_policy touch_policy) {
|
||||||
unsigned char in_data[11];
|
|
||||||
unsigned char *in_ptr = in_data;
|
|
||||||
unsigned char data[1024];
|
|
||||||
unsigned char templ[] = {0, YKPIV_INS_GENERATE_ASYMMETRIC, 0, 0};
|
|
||||||
unsigned long recv_len = sizeof(data);
|
|
||||||
int sw;
|
|
||||||
int key = 0;
|
int key = 0;
|
||||||
FILE *output_file = NULL;
|
|
||||||
bool ret = false;
|
bool ret = false;
|
||||||
|
ykpiv_rc res;
|
||||||
|
FILE *output_file = NULL;
|
||||||
EVP_PKEY *public_key = NULL;
|
EVP_PKEY *public_key = NULL;
|
||||||
RSA *rsa = NULL;
|
RSA *rsa = NULL;
|
||||||
BIGNUM *bignum_n = NULL;
|
|
||||||
BIGNUM *bignum_e = NULL;
|
|
||||||
EC_KEY *eckey = NULL;
|
EC_KEY *eckey = NULL;
|
||||||
EC_POINT *point = NULL;
|
EC_POINT *ecpoint = NULL;
|
||||||
char version[7];
|
uint8_t *mod = NULL;
|
||||||
|
uint8_t *exp = NULL;
|
||||||
|
uint8_t *point = NULL;
|
||||||
|
size_t mod_len = 0;
|
||||||
|
size_t exp_len = 0;
|
||||||
|
size_t point_len = 0;
|
||||||
|
|
||||||
if(algorithm == algorithm_arg_RSA1024 || algorithm == algorithm_arg_RSA2048) {
|
key = get_slot_hex(slot);
|
||||||
if(ykpiv_get_version(state, version, sizeof(version)) == YKPIV_OK) {
|
|
||||||
int major, minor, build;
|
|
||||||
int match = sscanf(version, "%d.%d.%d", &major, &minor, &build);
|
|
||||||
if(match == 3 && major == 4 && (minor < 3 || (minor == 3 && build < 5))) {
|
|
||||||
fprintf(stderr, "On-chip RSA key generation on this YubiKey has been blocked.\n");
|
|
||||||
fprintf(stderr, "Please see https://yubi.co/ysa201701/ for details.\n");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, "Failed to communicate.\n");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sscanf(slot, "%2x", &key);
|
output_file = open_file(output_file_name, key_file_mode(key_format, true));
|
||||||
templ[3] = key;
|
|
||||||
|
|
||||||
output_file = open_file(output_file_name, OUTPUT);
|
|
||||||
if(!output_file) {
|
if(!output_file) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
*in_ptr++ = 0xac;
|
res = ykpiv_util_generate_key(state,
|
||||||
*in_ptr++ = 3;
|
(uint8_t)(key & 0xFF),
|
||||||
*in_ptr++ = YKPIV_ALGO_TAG;
|
get_piv_algorithm(algorithm),
|
||||||
*in_ptr++ = 1;
|
get_pin_policy(pin_policy),
|
||||||
*in_ptr++ = get_piv_algorithm(algorithm);
|
get_touch_policy(touch_policy),
|
||||||
if(in_data[4] == 0) {
|
&mod,
|
||||||
fprintf(stderr, "Unexpected algorithm.\n");
|
&mod_len,
|
||||||
goto generate_out;
|
&exp,
|
||||||
}
|
&exp_len,
|
||||||
if(pin_policy != pin_policy__NULL) {
|
&point,
|
||||||
in_data[1] += 3;
|
&point_len);
|
||||||
*in_ptr++ = YKPIV_PINPOLICY_TAG;
|
if (res != YKPIV_OK) {
|
||||||
*in_ptr++ = 1;
|
fprintf(stderr, "Key generation failed.\n");
|
||||||
*in_ptr++ = get_pin_policy(pin_policy);
|
|
||||||
}
|
|
||||||
if(touch_policy != touch_policy__NULL) {
|
|
||||||
in_data[1] += 3;
|
|
||||||
*in_ptr++ = YKPIV_TOUCHPOLICY_TAG;
|
|
||||||
*in_ptr++ = 1;
|
|
||||||
*in_ptr++ = get_touch_policy(touch_policy);
|
|
||||||
}
|
|
||||||
if(ykpiv_transfer_data(state, templ, in_data, in_ptr - in_data, data,
|
|
||||||
&recv_len, &sw) != YKPIV_OK) {
|
|
||||||
fprintf(stderr, "Failed to communicate.\n");
|
|
||||||
goto generate_out;
|
|
||||||
} else if(sw != SW_SUCCESS) {
|
|
||||||
fprintf(stderr, "Failed to generate new key (");
|
|
||||||
if(sw == SW_ERR_INCORRECT_SLOT) {
|
|
||||||
fprintf(stderr, "slot not supported?)\n");
|
|
||||||
} else if(sw == SW_ERR_INCORRECT_PARAM) {
|
|
||||||
if(pin_policy != pin_policy__NULL) {
|
|
||||||
fprintf(stderr, "pin policy not supported?)\n");
|
|
||||||
} else if(touch_policy != touch_policy__NULL) {
|
|
||||||
fprintf(stderr, "touch policy not supported?)\n");
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, "algorithm not supported?)\n");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, "error %x)\n", sw);
|
|
||||||
}
|
|
||||||
goto generate_out;
|
goto generate_out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(key_format == key_format_arg_PEM) {
|
if(key_format == key_format_arg_PEM) {
|
||||||
public_key = EVP_PKEY_new();
|
public_key = EVP_PKEY_new();
|
||||||
if(algorithm == algorithm_arg_RSA1024 || algorithm == algorithm_arg_RSA2048) {
|
if(algorithm == algorithm_arg_RSA1024 || algorithm == algorithm_arg_RSA2048) {
|
||||||
unsigned char *data_ptr = data + 5;
|
|
||||||
int len = 0;
|
|
||||||
rsa = RSA_new();
|
rsa = RSA_new();
|
||||||
|
rsa->n = BN_bin2bn(mod, mod_len, NULL);
|
||||||
if(*data_ptr != 0x81) {
|
if (rsa->n == NULL) {
|
||||||
fprintf(stderr, "Failed to parse public key structure.\n");
|
|
||||||
goto generate_out;
|
|
||||||
}
|
|
||||||
data_ptr++;
|
|
||||||
data_ptr += get_length(data_ptr, &len);
|
|
||||||
bignum_n = BN_bin2bn(data_ptr, len, NULL);
|
|
||||||
if(bignum_n == NULL) {
|
|
||||||
fprintf(stderr, "Failed to parse public key modulus.\n");
|
fprintf(stderr, "Failed to parse public key modulus.\n");
|
||||||
goto generate_out;
|
goto generate_out;
|
||||||
}
|
}
|
||||||
data_ptr += len;
|
rsa->e = BN_bin2bn(exp, exp_len, NULL);
|
||||||
|
if(rsa->e == NULL) {
|
||||||
if(*data_ptr != 0x82) {
|
|
||||||
fprintf(stderr, "Failed to parse public key structure (2).\n");
|
|
||||||
goto generate_out;
|
|
||||||
}
|
|
||||||
data_ptr++;
|
|
||||||
data_ptr += get_length(data_ptr, &len);
|
|
||||||
bignum_e = BN_bin2bn(data_ptr, len, NULL);
|
|
||||||
if(bignum_e == NULL) {
|
|
||||||
fprintf(stderr, "Failed to parse public key exponent.\n");
|
fprintf(stderr, "Failed to parse public key exponent.\n");
|
||||||
goto generate_out;
|
goto generate_out;
|
||||||
}
|
}
|
||||||
|
|
||||||
rsa->n = bignum_n;
|
|
||||||
rsa->e = bignum_e;
|
|
||||||
EVP_PKEY_set1_RSA(public_key, rsa);
|
EVP_PKEY_set1_RSA(public_key, rsa);
|
||||||
} else if(algorithm == algorithm_arg_ECCP256 || algorithm == algorithm_arg_ECCP384) {
|
} else if(algorithm == algorithm_arg_ECCP256 || algorithm == algorithm_arg_ECCP384) {
|
||||||
EC_GROUP *group;
|
EC_GROUP *group;
|
||||||
unsigned char *data_ptr = data + 3;
|
|
||||||
int nid;
|
int nid;
|
||||||
size_t len;
|
|
||||||
|
|
||||||
if(algorithm == algorithm_arg_ECCP256) {
|
if(algorithm == algorithm_arg_ECCP256) {
|
||||||
nid = NID_X9_62_prime256v1;
|
nid = NID_X9_62_prime256v1;
|
||||||
len = 65;
|
|
||||||
} else {
|
} else {
|
||||||
nid = NID_secp384r1;
|
nid = NID_secp384r1;
|
||||||
len = 97;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
eckey = EC_KEY_new();
|
eckey = EC_KEY_new();
|
||||||
group = EC_GROUP_new_by_curve_name(nid);
|
group = EC_GROUP_new_by_curve_name(nid);
|
||||||
EC_GROUP_set_asn1_flag(group, nid);
|
EC_GROUP_set_asn1_flag(group, nid);
|
||||||
EC_KEY_set_group(eckey, group);
|
EC_KEY_set_group(eckey, group);
|
||||||
point = EC_POINT_new(group);
|
ecpoint = EC_POINT_new(group);
|
||||||
if(*data_ptr++ != 0x86) {
|
|
||||||
fprintf(stderr, "Failed to parse public key structure.\n");
|
if(!EC_POINT_oct2point(group, ecpoint, point, point_len, NULL)) {
|
||||||
goto generate_out;
|
|
||||||
}
|
|
||||||
if(*data_ptr++ != len) { /* the curve point should always be 65 bytes */
|
|
||||||
fprintf(stderr, "Unexpected length.\n");
|
|
||||||
goto generate_out;
|
|
||||||
}
|
|
||||||
if(!EC_POINT_oct2point(group, point, data_ptr, len, NULL)) {
|
|
||||||
fprintf(stderr, "Failed to load public point.\n");
|
fprintf(stderr, "Failed to load public point.\n");
|
||||||
goto generate_out;
|
goto generate_out;
|
||||||
}
|
}
|
||||||
if(!EC_KEY_set_public_key(eckey, point)) {
|
if(!EC_KEY_set_public_key(eckey, ecpoint)) {
|
||||||
fprintf(stderr, "Failed to set the public key.\n");
|
fprintf(stderr, "Failed to set the public key.\n");
|
||||||
goto generate_out;
|
goto generate_out;
|
||||||
}
|
}
|
||||||
EVP_PKEY_set1_EC_KEY(public_key, eckey);
|
EVP_PKEY_set1_EC_KEY(public_key, eckey);
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "Wrong algorithm.\n");
|
fprintf(stderr, "Wrong algorithm.\n");
|
||||||
goto generate_out;
|
|
||||||
}
|
}
|
||||||
PEM_write_PUBKEY(output_file, public_key);
|
PEM_write_PUBKEY(output_file, public_key);
|
||||||
ret = true;
|
ret = true;
|
||||||
@@ -288,8 +218,8 @@ generate_out:
|
|||||||
if (output_file != stdout) {
|
if (output_file != stdout) {
|
||||||
fclose(output_file);
|
fclose(output_file);
|
||||||
}
|
}
|
||||||
if(point) {
|
if (ecpoint) {
|
||||||
EC_POINT_free(point);
|
EC_POINT_free(ecpoint);
|
||||||
}
|
}
|
||||||
if (eckey) {
|
if (eckey) {
|
||||||
EC_KEY_free(eckey);
|
EC_KEY_free(eckey);
|
||||||
@@ -300,50 +230,38 @@ generate_out:
|
|||||||
if (public_key) {
|
if (public_key) {
|
||||||
EVP_PKEY_free(public_key);
|
EVP_PKEY_free(public_key);
|
||||||
}
|
}
|
||||||
|
if (point) {
|
||||||
|
ykpiv_util_free(state, point);
|
||||||
|
}
|
||||||
|
if (mod) {
|
||||||
|
ykpiv_util_free(state, mod);
|
||||||
|
}
|
||||||
|
if (exp) {
|
||||||
|
ykpiv_util_free(state, exp);
|
||||||
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool reset(ykpiv_state *state) {
|
static bool reset(ykpiv_state *state) {
|
||||||
unsigned char templ[] = {0, YKPIV_INS_RESET, 0, 0};
|
return ykpiv_util_reset(state) == YKPIV_OK;
|
||||||
unsigned char data[0xff];
|
|
||||||
unsigned long recv_len = sizeof(data);
|
|
||||||
int sw;
|
|
||||||
|
|
||||||
/* note: the reset function is only available when both pins are blocked. */
|
|
||||||
if(ykpiv_transfer_data(state, templ, NULL, 0, data, &recv_len, &sw) != YKPIV_OK) {
|
|
||||||
return false;
|
|
||||||
} else if(sw == SW_SUCCESS) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool set_pin_retries(ykpiv_state *state, int pin_retries, int puk_retries, int verbose) {
|
static bool set_pin_retries(ykpiv_state *state, int pin_retries, int puk_retries, int verbose) {
|
||||||
unsigned char templ[] = {0, YKPIV_INS_SET_PIN_RETRIES, pin_retries, puk_retries};
|
ykpiv_rc res;
|
||||||
unsigned char data[0xff];
|
|
||||||
unsigned long recv_len = sizeof(data);
|
|
||||||
int sw;
|
|
||||||
|
|
||||||
if(pin_retries > 0xff || puk_retries > 0xff || pin_retries < 1 || puk_retries < 1) {
|
|
||||||
fprintf(stderr, "pin and puk retries must be between 1 and 255.\n");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(verbose) {
|
if(verbose) {
|
||||||
fprintf(stderr, "Setting pin retries to %d and puk retries to %d.\n", pin_retries, puk_retries);
|
fprintf(stderr, "Setting pin retries to %d and puk retries to %d.\n", pin_retries, puk_retries);
|
||||||
}
|
}
|
||||||
|
res = ykpiv_set_pin_retries(state, pin_retries, puk_retries);
|
||||||
if(ykpiv_transfer_data(state, templ, NULL, 0, data, &recv_len, &sw) != YKPIV_OK) {
|
if (res == YKPIV_RANGE_ERROR) {
|
||||||
return false;
|
fprintf(stderr, "pin and puk retries must be between 1 and 255.\n");
|
||||||
} else if(sw == SW_SUCCESS) {
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
return false;
|
return res == YKPIV_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool import_key(ykpiv_state *state, enum enum_key_format key_format,
|
static bool import_key(ykpiv_state *state, enum enum_key_format key_format,
|
||||||
const char *input_file_name, const char *slot, char *password,
|
const char *input_file_name, enum enum_slot slot, char *password,
|
||||||
enum enum_pin_policy pin_policy, enum enum_touch_policy touch_policy) {
|
enum enum_pin_policy pin_policy, enum enum_touch_policy touch_policy) {
|
||||||
int key = 0;
|
int key = 0;
|
||||||
FILE *input_file = NULL;
|
FILE *input_file = NULL;
|
||||||
@@ -353,9 +271,9 @@ static bool import_key(ykpiv_state *state, enum enum_key_format key_format,
|
|||||||
bool ret = false;
|
bool ret = false;
|
||||||
ykpiv_rc rc = YKPIV_GENERIC_ERROR;
|
ykpiv_rc rc = YKPIV_GENERIC_ERROR;
|
||||||
|
|
||||||
sscanf(slot, "%2x", &key);
|
key = get_slot_hex(slot);
|
||||||
|
|
||||||
input_file = open_file(input_file_name, INPUT);
|
input_file = open_file(input_file_name, key_file_mode(key_format, false));
|
||||||
if(!input_file) {
|
if(!input_file) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -518,7 +436,7 @@ static bool import_cert(ykpiv_state *state, enum enum_key_format cert_format,
|
|||||||
int compress = 0;
|
int compress = 0;
|
||||||
int cert_len = -1;
|
int cert_len = -1;
|
||||||
|
|
||||||
input_file = open_file(input_file_name, INPUT);
|
input_file = open_file(input_file_name, key_file_mode(cert_format, false));
|
||||||
if(!input_file) {
|
if(!input_file) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -568,35 +486,18 @@ static bool import_cert(ykpiv_state *state, enum enum_key_format cert_format,
|
|||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
unsigned char certdata[3072];
|
unsigned char certdata[YKPIV_OBJ_MAX_SIZE];
|
||||||
unsigned char *certptr = certdata;
|
unsigned char *certptr = certdata;
|
||||||
int object = get_object_id(slot);
|
|
||||||
ykpiv_rc res;
|
ykpiv_rc res;
|
||||||
|
|
||||||
if(4 + cert_len + 5 > sizeof(certdata)) { /* 4 is prefix size, 5 is postfix size */
|
|
||||||
fprintf(stderr, "Certificate is too large to fit in buffer.\n");
|
|
||||||
goto import_cert_out;
|
|
||||||
}
|
|
||||||
|
|
||||||
*certptr++ = 0x70;
|
|
||||||
certptr += set_length(certptr, cert_len);
|
|
||||||
if (compress) {
|
if (compress) {
|
||||||
if (fread(certptr, 1, (size_t)cert_len, input_file) != (size_t)cert_len) {
|
if (fread(certdata, 1, (size_t)cert_len, input_file) != (size_t)cert_len) {
|
||||||
fprintf(stderr, "Failed to read compressed certificate\n");
|
fprintf(stderr, "Failed to read compressed certificate\n");
|
||||||
goto import_cert_out;
|
goto import_cert_out;
|
||||||
}
|
}
|
||||||
certptr += cert_len;
|
|
||||||
} else {
|
} else {
|
||||||
/* i2d_X509 increments certptr here.. */
|
|
||||||
i2d_X509(cert, &certptr);
|
i2d_X509(cert, &certptr);
|
||||||
}
|
}
|
||||||
*certptr++ = 0x71;
|
if ((res = ykpiv_util_write_cert(state, get_slot_hex(slot), certdata, cert_len, compress)) != YKPIV_OK) {
|
||||||
*certptr++ = 1;
|
|
||||||
*certptr++ = compress; /* certinfo (gzip etc) */
|
|
||||||
*certptr++ = 0xfe; /* LRC */
|
|
||||||
*certptr++ = 0;
|
|
||||||
|
|
||||||
if((res = ykpiv_save_object(state, object, certdata, (size_t)(certptr - certdata))) != YKPIV_OK) {
|
|
||||||
fprintf(stderr, "Failed commands with device: %s\n", ykpiv_strerror(res));
|
fprintf(stderr, "Failed commands with device: %s\n", ykpiv_strerror(res));
|
||||||
} else {
|
} else {
|
||||||
ret = true;
|
ret = true;
|
||||||
@@ -620,45 +521,32 @@ import_cert_out:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool set_dataobject(ykpiv_state *state, int verbose, int type) {
|
static bool set_cardid(ykpiv_state *state, int verbose, int type) {
|
||||||
unsigned char obj[1024];
|
|
||||||
ykpiv_rc res;
|
ykpiv_rc res;
|
||||||
size_t offs, rand_len, len;
|
unsigned char id[MAX(sizeof(ykpiv_cardid), sizeof(ykpiv_cccid))];
|
||||||
const unsigned char *tmpl;
|
|
||||||
int id;
|
|
||||||
|
|
||||||
if(type == CHUID) {
|
if(type == CHUID) {
|
||||||
offs = CHUID_GUID_OFFS;
|
res = ykpiv_util_set_cardid(state, NULL);
|
||||||
len = sizeof(chuid_tmpl);
|
|
||||||
rand_len = 0x10;
|
|
||||||
tmpl = chuid_tmpl;
|
|
||||||
id = YKPIV_OBJ_CHUID;
|
|
||||||
} else {
|
} else {
|
||||||
offs = CCC_ID_OFFS;
|
res = ykpiv_util_set_cccid(state, NULL);
|
||||||
rand_len = 0xe;
|
|
||||||
len = sizeof(ccc_tmpl);
|
|
||||||
tmpl = ccc_tmpl;
|
|
||||||
id = YKPIV_OBJ_CAPABILITY;
|
|
||||||
}
|
|
||||||
memcpy(obj, tmpl, len);
|
|
||||||
if(RAND_pseudo_bytes(obj + offs, rand_len) == -1) {
|
|
||||||
fprintf(stderr, "error: no randomness.\n");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if(verbose) {
|
|
||||||
fprintf(stderr, "Setting the %s to: ", type == CHUID ? "CHUID" : "CCC");
|
|
||||||
dump_data(obj, len, stderr, true, format_arg_hex);
|
|
||||||
}
|
|
||||||
if((res = ykpiv_save_object(state, id, obj, len)) != YKPIV_OK) {
|
|
||||||
fprintf(stderr, "Failed communicating with device: %s\n", ykpiv_strerror(res));
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
if(res == YKPIV_OK && verbose) {
|
||||||
|
if (type == CHUID) {
|
||||||
|
res = ykpiv_util_get_cardid(state, (ykpiv_cardid*)id);
|
||||||
|
} else {
|
||||||
|
res = ykpiv_util_get_cccid(state, (ykpiv_cccid*)id);
|
||||||
|
}
|
||||||
|
if (res == YKPIV_OK) {
|
||||||
|
fprintf(stderr, "Set the %s ID to: ", type == CHUID ? "CHUID" : "CCC");
|
||||||
|
dump_data(id, type == CHUID ? YKPIV_CARDID_SIZE : YKPIV_CCCID_SIZE, stderr, true, format_arg_hex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res == YKPIV_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool request_certificate(ykpiv_state *state, enum enum_key_format key_format,
|
static bool request_certificate(ykpiv_state *state, enum enum_key_format key_format,
|
||||||
const char *input_file_name, const char *slot, char *subject, enum enum_hash hash,
|
const char *input_file_name, enum enum_slot slot, char *subject, enum enum_hash hash,
|
||||||
const char *output_file_name) {
|
const char *output_file_name) {
|
||||||
X509_REQ *req = NULL;
|
X509_REQ *req = NULL;
|
||||||
X509_NAME *name = NULL;
|
X509_NAME *name = NULL;
|
||||||
@@ -682,10 +570,10 @@ static bool request_certificate(ykpiv_state *state, enum enum_key_format key_for
|
|||||||
null_parameter.type = V_ASN1_NULL;
|
null_parameter.type = V_ASN1_NULL;
|
||||||
null_parameter.value.ptr = NULL;
|
null_parameter.value.ptr = NULL;
|
||||||
|
|
||||||
sscanf(slot, "%2x", &key);
|
key = get_slot_hex(slot);
|
||||||
|
|
||||||
input_file = open_file(input_file_name, INPUT);
|
input_file = open_file(input_file_name, key_file_mode(key_format, false));
|
||||||
output_file = open_file(output_file_name, OUTPUT);
|
output_file = open_file(output_file_name, key_file_mode(key_format, true));
|
||||||
if(!input_file || !output_file) {
|
if(!input_file || !output_file) {
|
||||||
goto request_out;
|
goto request_out;
|
||||||
}
|
}
|
||||||
@@ -805,7 +693,7 @@ request_out:
|
|||||||
}
|
}
|
||||||
|
|
||||||
static bool selfsign_certificate(ykpiv_state *state, enum enum_key_format key_format,
|
static bool selfsign_certificate(ykpiv_state *state, enum enum_key_format key_format,
|
||||||
const char *input_file_name, const char *slot, char *subject, enum enum_hash hash,
|
const char *input_file_name, enum enum_slot slot, char *subject, enum enum_hash hash,
|
||||||
const int *serial, int validDays, const char *output_file_name) {
|
const int *serial, int validDays, const char *output_file_name) {
|
||||||
FILE *input_file = NULL;
|
FILE *input_file = NULL;
|
||||||
FILE *output_file = NULL;
|
FILE *output_file = NULL;
|
||||||
@@ -831,10 +719,10 @@ static bool selfsign_certificate(ykpiv_state *state, enum enum_key_format key_fo
|
|||||||
null_parameter.type = V_ASN1_NULL;
|
null_parameter.type = V_ASN1_NULL;
|
||||||
null_parameter.value.ptr = NULL;
|
null_parameter.value.ptr = NULL;
|
||||||
|
|
||||||
sscanf(slot, "%2x", &key);
|
key = get_slot_hex(slot);
|
||||||
|
|
||||||
input_file = open_file(input_file_name, INPUT);
|
input_file = open_file(input_file_name, key_file_mode(key_format, false));
|
||||||
output_file = open_file(output_file_name, OUTPUT);
|
output_file = open_file(output_file_name, key_file_mode(key_format, true));
|
||||||
if(!input_file || !output_file) {
|
if(!input_file || !output_file) {
|
||||||
goto selfsign_out;
|
goto selfsign_out;
|
||||||
}
|
}
|
||||||
@@ -1075,27 +963,17 @@ static bool change_pin(ykpiv_state *state, enum enum_action action, const char *
|
|||||||
}
|
}
|
||||||
|
|
||||||
static bool delete_certificate(ykpiv_state *state, enum enum_slot slot) {
|
static bool delete_certificate(ykpiv_state *state, enum enum_slot slot) {
|
||||||
int object = get_object_id(slot);
|
return ykpiv_util_delete_cert(state, get_slot_hex(slot)) == YKPIV_OK;
|
||||||
|
|
||||||
if(ykpiv_save_object(state, object, NULL, 0) != YKPIV_OK) {
|
|
||||||
fprintf(stderr, "Failed deleting object.\n");
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, "Certificate deleted.\n");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool read_certificate(ykpiv_state *state, enum enum_slot slot,
|
static bool read_certificate(ykpiv_state *state, enum enum_slot slot,
|
||||||
enum enum_key_format key_format, const char *output_file_name) {
|
enum enum_key_format key_format, const char *output_file_name) {
|
||||||
FILE *output_file;
|
FILE *output_file;
|
||||||
int object = get_object_id(slot);
|
uint8_t *data = NULL;
|
||||||
unsigned char data[3072];
|
const unsigned char *ptr = NULL;
|
||||||
const unsigned char *ptr = data;
|
|
||||||
unsigned long len = sizeof(data);
|
|
||||||
int cert_len;
|
|
||||||
bool ret = false;
|
|
||||||
X509 *x509 = NULL;
|
X509 *x509 = NULL;
|
||||||
|
bool ret = false;
|
||||||
|
size_t cert_len = 0;
|
||||||
|
|
||||||
if (key_format != key_format_arg_PEM &&
|
if (key_format != key_format_arg_PEM &&
|
||||||
key_format != key_format_arg_DER &&
|
key_format != key_format_arg_DER &&
|
||||||
@@ -1104,18 +982,17 @@ static bool read_certificate(ykpiv_state *state, enum enum_slot slot,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
output_file = open_file(output_file_name, OUTPUT);
|
output_file = open_file(output_file_name, key_file_mode(key_format, true));
|
||||||
if (!output_file) {
|
if (!output_file) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(ykpiv_fetch_object(state, object, data, &len) != YKPIV_OK) {
|
if (ykpiv_util_read_cert(state, get_slot_hex(slot), &data, &cert_len) != YKPIV_OK) {
|
||||||
fprintf(stderr, "Failed fetching certificate.\n");
|
fprintf(stderr, "Failed fetching certificate.\n");
|
||||||
goto read_cert_out;
|
goto read_cert_out;
|
||||||
}
|
}
|
||||||
|
ptr = data;
|
||||||
|
|
||||||
if(*ptr++ == 0x70) {
|
|
||||||
ptr += get_length(ptr, &cert_len);
|
|
||||||
if (key_format == key_format_arg_PEM ||
|
if (key_format == key_format_arg_PEM ||
|
||||||
key_format == key_format_arg_SSH) {
|
key_format == key_format_arg_SSH) {
|
||||||
x509 = X509_new();
|
x509 = X509_new();
|
||||||
@@ -1123,7 +1000,7 @@ static bool read_certificate(ykpiv_state *state, enum enum_slot slot,
|
|||||||
fprintf(stderr, "Failed allocating x509 structure.\n");
|
fprintf(stderr, "Failed allocating x509 structure.\n");
|
||||||
goto read_cert_out;
|
goto read_cert_out;
|
||||||
}
|
}
|
||||||
x509 = d2i_X509(NULL, &ptr, cert_len);
|
x509 = d2i_X509(NULL, (const unsigned char**)&ptr, cert_len);
|
||||||
if (!x509) {
|
if (!x509) {
|
||||||
fprintf(stderr, "Failed parsing x509 information.\n");
|
fprintf(stderr, "Failed parsing x509 information.\n");
|
||||||
goto read_cert_out;
|
goto read_cert_out;
|
||||||
@@ -1145,9 +1022,6 @@ static bool read_certificate(ykpiv_state *state, enum enum_slot slot,
|
|||||||
fwrite(ptr, (size_t)cert_len, 1, output_file);
|
fwrite(ptr, (size_t)cert_len, 1, output_file);
|
||||||
ret = true;
|
ret = true;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
fprintf(stderr, "Failed parsing data.\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
read_cert_out:
|
read_cert_out:
|
||||||
if (output_file != stdout) {
|
if (output_file != stdout) {
|
||||||
@@ -1156,11 +1030,14 @@ read_cert_out:
|
|||||||
if (x509) {
|
if (x509) {
|
||||||
X509_free(x509);
|
X509_free(x509);
|
||||||
}
|
}
|
||||||
|
if (data) {
|
||||||
|
ykpiv_util_free(state, data);
|
||||||
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool sign_file(ykpiv_state *state, const char *input, const char *output,
|
static bool sign_file(ykpiv_state *state, const char *input, const char *output,
|
||||||
const char *slot, enum enum_algorithm algorithm, enum enum_hash hash,
|
enum enum_slot slot, enum enum_algorithm algorithm, enum enum_hash hash,
|
||||||
int verbosity) {
|
int verbosity) {
|
||||||
FILE *input_file = NULL;
|
FILE *input_file = NULL;
|
||||||
FILE *output_file = NULL;
|
FILE *output_file = NULL;
|
||||||
@@ -1171,9 +1048,9 @@ static bool sign_file(ykpiv_state *state, const char *input, const char *output,
|
|||||||
int algo;
|
int algo;
|
||||||
const EVP_MD *md;
|
const EVP_MD *md;
|
||||||
|
|
||||||
sscanf(slot, "%2x", &key);
|
key = get_slot_hex(slot);
|
||||||
|
|
||||||
input_file = open_file(input, INPUT);
|
input_file = open_file(input, INPUT_BIN);
|
||||||
if(!input_file) {
|
if(!input_file) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -1182,7 +1059,7 @@ static bool sign_file(ykpiv_state *state, const char *input, const char *output,
|
|||||||
fprintf(stderr, "Please paste the input...\n");
|
fprintf(stderr, "Please paste the input...\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
output_file = open_file(output, OUTPUT);
|
output_file = open_file(output, OUTPUT_BIN);
|
||||||
if(!output_file) {
|
if(!output_file) {
|
||||||
if(input_file && input_file != stdin) {
|
if(input_file && input_file != stdin) {
|
||||||
fclose(input_file);
|
fclose(input_file);
|
||||||
@@ -1253,7 +1130,7 @@ out:
|
|||||||
|
|
||||||
static void print_cert_info(ykpiv_state *state, enum enum_slot slot, const EVP_MD *md,
|
static void print_cert_info(ykpiv_state *state, enum enum_slot slot, const EVP_MD *md,
|
||||||
FILE *output) {
|
FILE *output) {
|
||||||
int object = get_object_id(slot);
|
int object = ykpiv_util_slot_object(get_slot_hex(slot));
|
||||||
int slot_name;
|
int slot_name;
|
||||||
unsigned char data[3072];
|
unsigned char data[3072];
|
||||||
const unsigned char *ptr = data;
|
const unsigned char *ptr = data;
|
||||||
@@ -1267,12 +1144,7 @@ static void print_cert_info(ykpiv_state *state, enum enum_slot slot, const EVP_M
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (slot == slot_arg_9a)
|
slot_name = get_slot_hex(slot);
|
||||||
slot_name = 0x9a;
|
|
||||||
else if (slot >= slot_arg_9c && slot <= slot_arg_9e)
|
|
||||||
slot_name = 0x9b + slot;
|
|
||||||
else
|
|
||||||
slot_name = 0x82 + (slot - slot_arg_82);
|
|
||||||
|
|
||||||
fprintf(output, "Slot %x:\t", slot_name);
|
fprintf(output, "Slot %x:\t", slot_name);
|
||||||
|
|
||||||
@@ -1368,7 +1240,7 @@ static bool status(ykpiv_state *state, enum enum_hash hash,
|
|||||||
unsigned char buf[3072];
|
unsigned char buf[3072];
|
||||||
long unsigned len = sizeof(buf);
|
long unsigned len = sizeof(buf);
|
||||||
int i;
|
int i;
|
||||||
FILE *output_file = open_file(output_file_name, OUTPUT);
|
FILE *output_file = open_file(output_file_name, OUTPUT_TEXT);
|
||||||
if(!output_file) {
|
if(!output_file) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -1421,7 +1293,7 @@ static bool test_signature(ykpiv_state *state, enum enum_slot slot,
|
|||||||
unsigned int data_len;
|
unsigned int data_len;
|
||||||
X509 *x509 = NULL;
|
X509 *x509 = NULL;
|
||||||
EVP_PKEY *pubkey;
|
EVP_PKEY *pubkey;
|
||||||
FILE *input_file = open_file(input_file_name, INPUT);
|
FILE *input_file = open_file(input_file_name, key_file_mode(cert_format, false));
|
||||||
|
|
||||||
if(!input_file) {
|
if(!input_file) {
|
||||||
fprintf(stderr, "Failed opening input file %s.\n", input_file_name);
|
fprintf(stderr, "Failed opening input file %s.\n", input_file_name);
|
||||||
@@ -1486,7 +1358,7 @@ static bool test_signature(ykpiv_state *state, enum enum_slot slot,
|
|||||||
if(algorithm == 0) {
|
if(algorithm == 0) {
|
||||||
goto test_out;
|
goto test_out;
|
||||||
}
|
}
|
||||||
sscanf(cmdline_parser_slot_values[slot], "%2x", &key);
|
key = get_slot_hex(slot);
|
||||||
if(YKPIV_IS_RSA(algorithm)) {
|
if(YKPIV_IS_RSA(algorithm)) {
|
||||||
prepare_rsa_signature(data, data_len, encoded, &enc_len, EVP_MD_type(md));
|
prepare_rsa_signature(data, data_len, encoded, &enc_len, EVP_MD_type(md));
|
||||||
ptr = encoded;
|
ptr = encoded;
|
||||||
@@ -1554,7 +1426,7 @@ static bool test_decipher(ykpiv_state *state, enum enum_slot slot,
|
|||||||
X509 *x509 = NULL;
|
X509 *x509 = NULL;
|
||||||
EVP_PKEY *pubkey;
|
EVP_PKEY *pubkey;
|
||||||
EC_KEY *tmpkey = NULL;
|
EC_KEY *tmpkey = NULL;
|
||||||
FILE *input_file = open_file(input_file_name, INPUT);
|
FILE *input_file = open_file(input_file_name, key_file_mode(cert_format, false));
|
||||||
|
|
||||||
if(!input_file) {
|
if(!input_file) {
|
||||||
fprintf(stderr, "Failed opening input file %s.\n", input_file_name);
|
fprintf(stderr, "Failed opening input file %s.\n", input_file_name);
|
||||||
@@ -1591,7 +1463,7 @@ static bool test_decipher(ykpiv_state *state, enum enum_slot slot,
|
|||||||
if(algorithm == 0) {
|
if(algorithm == 0) {
|
||||||
goto decipher_out;
|
goto decipher_out;
|
||||||
}
|
}
|
||||||
sscanf(cmdline_parser_slot_values[slot], "%2x", &key);
|
key = get_slot_hex(slot);
|
||||||
if(YKPIV_IS_RSA(algorithm)) {
|
if(YKPIV_IS_RSA(algorithm)) {
|
||||||
unsigned char secret[32];
|
unsigned char secret[32];
|
||||||
unsigned char secret2[32];
|
unsigned char secret2[32];
|
||||||
@@ -1703,37 +1575,29 @@ static bool list_readers(ykpiv_state *state) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool attest(ykpiv_state *state, const char *slot,
|
static bool attest(ykpiv_state *state, enum enum_slot slot,
|
||||||
enum enum_key_format key_format, const char *output_file_name) {
|
enum enum_key_format key_format, const char *output_file_name) {
|
||||||
unsigned char data[2048];
|
unsigned char data[2048];
|
||||||
unsigned long len = sizeof(data);
|
unsigned long len = sizeof(data);
|
||||||
bool ret = false;
|
bool ret = false;
|
||||||
X509 *x509 = NULL;
|
X509 *x509 = NULL;
|
||||||
unsigned char templ[] = {0, YKPIV_INS_ATTEST, 0, 0};
|
|
||||||
int key;
|
int key;
|
||||||
int sw;
|
FILE *output_file = open_file(output_file_name, key_file_mode(key_format, true));
|
||||||
FILE *output_file = open_file(output_file_name, OUTPUT);
|
|
||||||
if(!output_file) {
|
if(!output_file) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
sscanf(slot, "%2x", &key);
|
|
||||||
templ[2] = key;
|
|
||||||
|
|
||||||
if(key_format != key_format_arg_PEM && key_format != key_format_arg_DER) {
|
if(key_format != key_format_arg_PEM && key_format != key_format_arg_DER) {
|
||||||
fprintf(stderr, "Only PEM and DER format are supported for attest..\n");
|
fprintf(stderr, "Only PEM and DER format are supported for attest..\n");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(ykpiv_transfer_data(state, templ, NULL, 0, data, &len, &sw) != YKPIV_OK) {
|
key = get_slot_hex(slot);
|
||||||
fprintf(stderr, "Failed to communicate.\n");
|
if (ykpiv_attest(state, key, data, &len) != YKPIV_OK) {
|
||||||
goto attest_out;
|
fprintf(stderr, "Failed to attest data.\n");
|
||||||
} else if(sw != SW_SUCCESS) {
|
|
||||||
fprintf(stderr, "Failed to attest key.\n");
|
|
||||||
goto attest_out;
|
goto attest_out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(data[0] == 0x30) {
|
|
||||||
if(key_format == key_format_arg_PEM) {
|
if(key_format == key_format_arg_PEM) {
|
||||||
const unsigned char *ptr = data;
|
const unsigned char *ptr = data;
|
||||||
int len2 = len;
|
int len2 = len;
|
||||||
@@ -1748,12 +1612,10 @@ static bool attest(ykpiv_state *state, const char *slot,
|
|||||||
goto attest_out;
|
goto attest_out;
|
||||||
}
|
}
|
||||||
PEM_write_X509(output_file, x509);
|
PEM_write_X509(output_file, x509);
|
||||||
ret = true;
|
|
||||||
} else {
|
} else {
|
||||||
fwrite(data, len, 1, output_file);
|
fwrite(data, len, 1, output_file);
|
||||||
}
|
}
|
||||||
ret = true;
|
ret = true;
|
||||||
}
|
|
||||||
|
|
||||||
attest_out:
|
attest_out:
|
||||||
if(output_file != stdout) {
|
if(output_file != stdout) {
|
||||||
@@ -1773,7 +1635,7 @@ static bool write_object(ykpiv_state *state, int id,
|
|||||||
size_t len = sizeof(data);
|
size_t len = sizeof(data);
|
||||||
ykpiv_rc res;
|
ykpiv_rc res;
|
||||||
|
|
||||||
input_file = open_file(input_file_name, INPUT);
|
input_file = open_file(input_file_name, data_file_mode(format, false));
|
||||||
if(!input_file) {
|
if(!input_file) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -1812,7 +1674,7 @@ static bool read_object(ykpiv_state *state, int id, const char *output_file_name
|
|||||||
unsigned long len = sizeof(data);
|
unsigned long len = sizeof(data);
|
||||||
bool ret = false;
|
bool ret = false;
|
||||||
|
|
||||||
output_file = open_file(output_file_name, OUTPUT);
|
output_file = open_file(output_file_name, data_file_mode(format, true));
|
||||||
if(!output_file) {
|
if(!output_file) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -1875,7 +1737,7 @@ int main(int argc, char *argv[]) {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case action_arg_pinMINUS_retries:
|
case action_arg_pinMINUS_retries:
|
||||||
if(!args_info.pin_retries_arg || !args_info.puk_retries_arg) {
|
if(!args_info.pin_retries_given || !args_info.puk_retries_given) {
|
||||||
fprintf(stderr, "The '%s' action needs both --pin-retries and --puk-retries arguments.\n",
|
fprintf(stderr, "The '%s' action needs both --pin-retries and --puk-retries arguments.\n",
|
||||||
cmdline_parser_action_values[action]);
|
cmdline_parser_action_values[action]);
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
@@ -2013,7 +1875,7 @@ int main(int argc, char *argv[]) {
|
|||||||
print_version(state, args_info.output_arg);
|
print_version(state, args_info.output_arg);
|
||||||
break;
|
break;
|
||||||
case action_arg_generate:
|
case action_arg_generate:
|
||||||
if(generate_key(state, args_info.slot_orig, args_info.algorithm_arg, args_info.output_arg, args_info.key_format_arg,
|
if(generate_key(state, args_info.slot_arg, args_info.algorithm_arg, args_info.output_arg, args_info.key_format_arg,
|
||||||
args_info.pin_policy_arg, args_info.touch_policy_arg) == false) {
|
args_info.pin_policy_arg, args_info.touch_policy_arg) == false) {
|
||||||
ret = EXIT_FAILURE;
|
ret = EXIT_FAILURE;
|
||||||
} else {
|
} else {
|
||||||
@@ -2068,7 +1930,7 @@ int main(int argc, char *argv[]) {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case action_arg_importMINUS_key:
|
case action_arg_importMINUS_key:
|
||||||
if(import_key(state, args_info.key_format_arg, args_info.input_arg, args_info.slot_orig, password,
|
if(import_key(state, args_info.key_format_arg, args_info.input_arg, args_info.slot_arg, password,
|
||||||
args_info.pin_policy_arg, args_info.touch_policy_arg) == false) {
|
args_info.pin_policy_arg, args_info.touch_policy_arg) == false) {
|
||||||
fprintf(stderr, "Unable to import private key\n");
|
fprintf(stderr, "Unable to import private key\n");
|
||||||
ret = EXIT_FAILURE;
|
ret = EXIT_FAILURE;
|
||||||
@@ -2085,7 +1947,7 @@ int main(int argc, char *argv[]) {
|
|||||||
break;
|
break;
|
||||||
case action_arg_setMINUS_ccc:
|
case action_arg_setMINUS_ccc:
|
||||||
case action_arg_setMINUS_chuid:
|
case action_arg_setMINUS_chuid:
|
||||||
if(set_dataobject(state, verbosity, action == action_arg_setMINUS_chuid ? CHUID : CCC) == false) {
|
if(set_cardid(state, verbosity, action == action_arg_setMINUS_chuid ? CHUID : CCC) == false) {
|
||||||
ret = EXIT_FAILURE;
|
ret = EXIT_FAILURE;
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "Successfully set new %s.\n", action == action_arg_setMINUS_chuid ? "CHUID" : "CCC");
|
fprintf(stderr, "Successfully set new %s.\n", action == action_arg_setMINUS_chuid ? "CHUID" : "CCC");
|
||||||
@@ -2093,7 +1955,7 @@ int main(int argc, char *argv[]) {
|
|||||||
break;
|
break;
|
||||||
case action_arg_requestMINUS_certificate:
|
case action_arg_requestMINUS_certificate:
|
||||||
if(request_certificate(state, args_info.key_format_arg, args_info.input_arg,
|
if(request_certificate(state, args_info.key_format_arg, args_info.input_arg,
|
||||||
args_info.slot_orig, args_info.subject_arg, args_info.hash_arg,
|
args_info.slot_arg, args_info.subject_arg, args_info.hash_arg,
|
||||||
args_info.output_arg) == false) {
|
args_info.output_arg) == false) {
|
||||||
ret = EXIT_FAILURE;
|
ret = EXIT_FAILURE;
|
||||||
} else {
|
} else {
|
||||||
@@ -2153,7 +2015,7 @@ int main(int argc, char *argv[]) {
|
|||||||
}
|
}
|
||||||
case action_arg_selfsignMINUS_certificate:
|
case action_arg_selfsignMINUS_certificate:
|
||||||
if(selfsign_certificate(state, args_info.key_format_arg, args_info.input_arg,
|
if(selfsign_certificate(state, args_info.key_format_arg, args_info.input_arg,
|
||||||
args_info.slot_orig, args_info.subject_arg, args_info.hash_arg,
|
args_info.slot_arg, args_info.subject_arg, args_info.hash_arg,
|
||||||
args_info.serial_given ? &args_info.serial_arg : NULL, args_info.valid_days_arg,
|
args_info.serial_given ? &args_info.serial_arg : NULL, args_info.valid_days_arg,
|
||||||
args_info.output_arg) == false) {
|
args_info.output_arg) == false) {
|
||||||
ret = EXIT_FAILURE;
|
ret = EXIT_FAILURE;
|
||||||
@@ -2207,7 +2069,7 @@ int main(int argc, char *argv[]) {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case action_arg_attest:
|
case action_arg_attest:
|
||||||
if(attest(state, args_info.slot_orig, args_info.key_format_arg,
|
if(attest(state, args_info.slot_arg, args_info.key_format_arg,
|
||||||
args_info.output_arg) == false) {
|
args_info.output_arg) == false) {
|
||||||
ret = EXIT_FAILURE;
|
ret = EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
@@ -2228,7 +2090,7 @@ int main(int argc, char *argv[]) {
|
|||||||
ret = EXIT_FAILURE;
|
ret = EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
else if(sign_file(state, args_info.input_arg, args_info.output_arg,
|
else if(sign_file(state, args_info.input_arg, args_info.output_arg,
|
||||||
args_info.slot_orig, args_info.algorithm_arg, args_info.hash_arg,
|
args_info.slot_arg, args_info.algorithm_arg, args_info.hash_arg,
|
||||||
verbosity)) {
|
verbosity)) {
|
||||||
fprintf(stderr, "Signature successful!\n");
|
fprintf(stderr, "Signature successful!\n");
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
Executable
+29
@@ -0,0 +1,29 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Output redirected to fd 0 so it can be run from 'make check' scripts.
|
||||||
|
|
||||||
|
echo >&0
|
||||||
|
echo "Hardware tests enabled!" >&0
|
||||||
|
echo >&0
|
||||||
|
echo "******* ******* ******* ******* ******* ******* ******* ******* ******* ******* ******* ******* ******* ******* *******" >&0
|
||||||
|
echo "WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING" >&0
|
||||||
|
echo "WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING" >&0
|
||||||
|
echo >&0
|
||||||
|
echo "******* ******* ******* ******* ******* ******* ******* ******* ******* ******* ******* ******* ******* ******* *******" >&0
|
||||||
|
echo >&0
|
||||||
|
echo " ALL DATA WILL BE ERASED ON CONNECTED YUBIKEYS " >&0
|
||||||
|
echo >&0
|
||||||
|
echo "******* ******* ******* ******* ******* ******* ******* ******* ******* ******* ******* ******* ******* ******* *******" >&0
|
||||||
|
echo >&0
|
||||||
|
echo "WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING" >&0
|
||||||
|
echo "WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING" >&0
|
||||||
|
echo "******* ******* ******* ******* ******* ******* ******* ******* ******* ******* ******* ******* ******* ******* *******" >&0
|
||||||
|
echo >&0
|
||||||
|
echo -n "Are you SURE you wish to proceed? If so, type 'CONFIRM': " >&0
|
||||||
|
|
||||||
|
read CONFIRM
|
||||||
|
if [[ "x$CONFIRM" != "xCONFIRM" ]]; then
|
||||||
|
echo "1"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "0"
|
||||||
+9
-1
@@ -27,6 +27,7 @@
|
|||||||
|
|
||||||
PACKAGE=yubico-piv-tool
|
PACKAGE=yubico-piv-tool
|
||||||
OPENSSLVERSION=1.0.2l
|
OPENSSLVERSION=1.0.2l
|
||||||
|
CHECKVERSION=0.12.0
|
||||||
|
|
||||||
all: usage 32bit 64bit
|
all: usage 32bit 64bit
|
||||||
|
|
||||||
@@ -55,11 +56,18 @@ doit:
|
|||||||
rm $(PWD)/tmp$(ARCH)/root/bin/c_rehash && \
|
rm $(PWD)/tmp$(ARCH)/root/bin/c_rehash && \
|
||||||
rm -rf $(PWD)/tmp$(ARCH)/root/lib/engines/ && \
|
rm -rf $(PWD)/tmp$(ARCH)/root/lib/engines/ && \
|
||||||
cd .. && \
|
cd .. && \
|
||||||
|
cp ../check-$(CHECKVERSION).tar.gz . || \
|
||||||
|
curl -L -O "https://github.com/libcheck/check/releases/download/$(CHECKVERSION)/check-$(CHECKVERSION).tar.gz" && \
|
||||||
|
tar xfa check-$(CHECKVERSION).tar.gz && \
|
||||||
|
cd check-$(CHECKVERSION) && \
|
||||||
|
CC=$(HOST)-gcc PKG_CONFIG_PATH=$(PWD)/tmp$(ARCH)/root/lib/pkgconfig ./configure --host=$(HOST) --build=x86_64-unknown-linux-gnu --prefix=$(PWD)/tmp$(ARCH)/root --disable-subunit --enable-static --disable-shared && \
|
||||||
|
make all install && \
|
||||||
|
cd .. && \
|
||||||
cp ../$(PACKAGE)-$(VERSION).tar.gz . && \
|
cp ../$(PACKAGE)-$(VERSION).tar.gz . && \
|
||||||
tar xfa $(PACKAGE)-$(VERSION).tar.gz && \
|
tar xfa $(PACKAGE)-$(VERSION).tar.gz && \
|
||||||
cd $(PACKAGE)-$(VERSION)/ && \
|
cd $(PACKAGE)-$(VERSION)/ && \
|
||||||
CC=$(HOST)-gcc PKG_CONFIG_PATH=$(PWD)/tmp$(ARCH)/root/lib/pkgconfig lt_cv_deplibs_check_method=pass_all ./configure --host=$(HOST) --build=x86_64-unknown-linux-gnu --prefix=$(PWD)/tmp$(ARCH)/root LDFLAGS=-L$(PWD)/tmp$(ARCH)/root/lib CPPFLAGS=-I$(PWD)/tmp$(ARCH)/root/include && \
|
CC=$(HOST)-gcc PKG_CONFIG_PATH=$(PWD)/tmp$(ARCH)/root/lib/pkgconfig lt_cv_deplibs_check_method=pass_all ./configure --host=$(HOST) --build=x86_64-unknown-linux-gnu --prefix=$(PWD)/tmp$(ARCH)/root LDFLAGS=-L$(PWD)/tmp$(ARCH)/root/lib CPPFLAGS=-I$(PWD)/tmp$(ARCH)/root/include && \
|
||||||
make install $(CHECK) && \
|
WINEPATH="/usr/$(HOST)/lib/" make install $(CHECK) && \
|
||||||
rm $(PWD)/tmp$(ARCH)/root/lib/*.la && \
|
rm $(PWD)/tmp$(ARCH)/root/lib/*.la && \
|
||||||
rm -rf $(PWD)/tmp$(ARCH)/root/lib/pkgconfig/ && \
|
rm -rf $(PWD)/tmp$(ARCH)/root/lib/pkgconfig/ && \
|
||||||
cp COPYING $(PWD)/tmp$(ARCH)/root/licenses/$(PACKAGE).txt && \
|
cp COPYING $(PWD)/tmp$(ARCH)/root/licenses/$(PACKAGE).txt && \
|
||||||
|
|||||||
@@ -173,7 +173,7 @@ CK_RV do_create_empty_cert(CK_BYTE_PTR in, CK_ULONG in_len, CK_BBOOL is_rsa,
|
|||||||
|
|
||||||
// Manually set a signature (same reason as before)
|
// Manually set a signature (same reason as before)
|
||||||
ASN1_BIT_STRING_set_bit(cert->signature, 8, 1);
|
ASN1_BIT_STRING_set_bit(cert->signature, 8, 1);
|
||||||
ASN1_BIT_STRING_set(cert->signature, "\x00", 1);
|
ASN1_BIT_STRING_set(cert->signature, (unsigned char*)"\x00", 1);
|
||||||
|
|
||||||
len = i2d_X509(cert, NULL);
|
len = i2d_X509(cert, NULL);
|
||||||
if (len < 0)
|
if (len < 0)
|
||||||
|
|||||||
@@ -29,17 +29,23 @@
|
|||||||
|
|
||||||
#LOG_COMPILER = $(VALGRIND)
|
#LOG_COMPILER = $(VALGRIND)
|
||||||
|
|
||||||
AM_CFLAGS = $(WARN_CFLAGS)
|
AM_CFLAGS = $(WARN_CFLAGS) @CHECK_CFLAGS@
|
||||||
AM_CPPFLAGS = -I$(top_srcdir)/lib -I$(top_builddir)/lib
|
AM_CPPFLAGS = -I$(top_srcdir)/lib -I$(top_builddir)/lib
|
||||||
AM_CPPFLAGS += -I$(top_srcdir)/ykcs11 -I$(top_builddir)/ykcs11
|
AM_CPPFLAGS += -I$(top_srcdir)/ykcs11 -I$(top_builddir)/ykcs11
|
||||||
AM_CPPFLAGS += $(OPENSSL_CFLAGS)
|
AM_CPPFLAGS += $(OPENSSL_CFLAGS)
|
||||||
|
|
||||||
AM_LDFLAGS = -no-install
|
AM_LDFLAGS = @CHECK_LIBS@
|
||||||
|
|
||||||
|
if COMPILER_CLANG
|
||||||
|
AM_LDFLAGS += -no-fast-install
|
||||||
|
else
|
||||||
|
AM_LDFLAGS += -no-install
|
||||||
|
endif
|
||||||
|
|
||||||
ykcs11_tests_LDADD = ../libykcs11.la $(OPENSSL_LIBS)
|
ykcs11_tests_LDADD = ../libykcs11.la $(OPENSSL_LIBS)
|
||||||
|
|
||||||
check_PROGRAMS = ykcs11_tests
|
check_PROGRAMS = ykcs11_tests
|
||||||
TESTS = $(check_PROGRAMS)
|
TESTS = reset.sh $(check_PROGRAMS)
|
||||||
|
|
||||||
if ENABLE_COV
|
if ENABLE_COV
|
||||||
AM_LDFLAGS += --coverage
|
AM_LDFLAGS += --coverage
|
||||||
|
|||||||
Executable
+20
@@ -0,0 +1,20 @@
|
|||||||
|
BIN="../../tool/yubico-piv-tool${EXEEXT}"
|
||||||
|
|
||||||
|
# Verify that user has confirmed destructive hw-tests
|
||||||
|
if [ "x$YKPIV_ENV_HWTESTS_CONFIRMED" != "x1" ]; then
|
||||||
|
printf "\n***\n*** Hardware tests skipped. Run \"make hwcheck\".\n***\n\n" >&0
|
||||||
|
exit 77 # exit code 77 == skipped tests
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Reset
|
||||||
|
$BIN -averify-pin -P000000 || true
|
||||||
|
$BIN -averify-pin -P000000 || true
|
||||||
|
$BIN -averify-pin -P000000 || true
|
||||||
|
$BIN -averify-pin -P000000 || true
|
||||||
|
$BIN -averify-pin -P000000 || true
|
||||||
|
$BIN -achange-puk -P000000 -N00000000 || true
|
||||||
|
$BIN -achange-puk -P000000 -N00000000 || true
|
||||||
|
$BIN -achange-puk -P000000 -N00000000 || true
|
||||||
|
$BIN -achange-puk -P000000 -N00000000 || true
|
||||||
|
$BIN -achange-puk -P000000 -N00000000 || true
|
||||||
|
$BIN -areset
|
||||||
@@ -39,6 +39,13 @@
|
|||||||
#include <openssl/x509.h>
|
#include <openssl/x509.h>
|
||||||
#include <openssl/rand.h>
|
#include <openssl/rand.h>
|
||||||
|
|
||||||
|
#pragma clang diagnostic push
|
||||||
|
#pragma clang diagnostic ignored "-Wpointer-sign"
|
||||||
|
|
||||||
|
#ifdef __MINGW32__
|
||||||
|
#define dprintf(fd, ...) fprintf(stdout, __VA_ARGS__)
|
||||||
|
#endif
|
||||||
|
|
||||||
void dump_hex(const unsigned char *buf, unsigned int len, FILE *output, int space) {
|
void dump_hex(const unsigned char *buf, unsigned int len, FILE *output, int space) {
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
for (i = 0; i < len; i++) {
|
for (i = 0; i < len; i++) {
|
||||||
@@ -104,10 +111,11 @@ static void test_initalize() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_token_info() {
|
static int test_token_info() {
|
||||||
|
|
||||||
const CK_CHAR_PTR TOKEN_LABEL = "YubiKey PIV";
|
const CK_CHAR_PTR TOKEN_LABEL = "YubiKey PIV";
|
||||||
const CK_CHAR_PTR TOKEN_MODEL = "YubiKey "; // Skip last 3 characters (version dependent)
|
const CK_CHAR_PTR TOKEN_MODEL = "YubiKey "; // Skip last 3 characters (version dependent)
|
||||||
|
const CK_CHAR_PTR TOKEN_MODEL_YK4 = "YubiKey YK4";
|
||||||
const CK_CHAR_PTR TOKEN_SERIAL = "1234";
|
const CK_CHAR_PTR TOKEN_SERIAL = "1234";
|
||||||
const CK_FLAGS TOKEN_FLAGS = CKF_RNG | CKF_LOGIN_REQUIRED | CKF_USER_PIN_INITIALIZED | CKF_TOKEN_INITIALIZED;
|
const CK_FLAGS TOKEN_FLAGS = CKF_RNG | CKF_LOGIN_REQUIRED | CKF_USER_PIN_INITIALIZED | CKF_TOKEN_INITIALIZED;
|
||||||
const CK_VERSION HW = {0, 0};
|
const CK_VERSION HW = {0, 0};
|
||||||
@@ -132,16 +140,22 @@ static void test_token_info() {
|
|||||||
asrt(info.ulFreePublicMemory, CK_UNAVAILABLE_INFORMATION, "FREE_PUB_MEM");
|
asrt(info.ulFreePublicMemory, CK_UNAVAILABLE_INFORMATION, "FREE_PUB_MEM");
|
||||||
asrt(info.ulTotalPrivateMemory, CK_UNAVAILABLE_INFORMATION, "TOTAL_PVT_MEM");
|
asrt(info.ulTotalPrivateMemory, CK_UNAVAILABLE_INFORMATION, "TOTAL_PVT_MEM");
|
||||||
asrt(info.ulFreePrivateMemory, CK_UNAVAILABLE_INFORMATION, "FREE_PVT_MEM");
|
asrt(info.ulFreePrivateMemory, CK_UNAVAILABLE_INFORMATION, "FREE_PVT_MEM");
|
||||||
|
|
||||||
|
if (strncmp(info.model, TOKEN_MODEL_YK4, strlen(TOKEN_MODEL_YK4)) != 0) {
|
||||||
|
dprintf(0, "\n\n** WARNING: Only YK4 supported. Skipping remaining tests.\n\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
asrt(info.hardwareVersion.major, HW.major, "HW_MAJ");
|
asrt(info.hardwareVersion.major, HW.major, "HW_MAJ");
|
||||||
asrt(info.hardwareVersion.minor, HW.minor, "HW_MIN");
|
asrt(info.hardwareVersion.minor, HW.minor, "HW_MIN");
|
||||||
|
|
||||||
if (info.firmwareVersion.major != 4 && info.firmwareVersion.major != 0)
|
if (info.firmwareVersion.major != 4 && info.firmwareVersion.major != 0)
|
||||||
asrt(info.firmwareVersion.major, 4, "FW_MAJ");
|
asrt(info.firmwareVersion.major, 4, "FW_MAJ");
|
||||||
|
|
||||||
asrt(strcmp(info.utcTime, TOKEN_TIME), 0, "TOKEN_TIME");
|
asrt(strncmp(info.utcTime, TOKEN_TIME, sizeof(info.utcTime)), 0, "TOKEN_TIME");
|
||||||
|
|
||||||
asrt(funcs->C_Finalize(NULL), CKR_OK, "FINALIZE");
|
asrt(funcs->C_Finalize(NULL), CKR_OK, "FINALIZE");
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_mechanism_list_and_info() {
|
static void test_mechanism_list_and_info() {
|
||||||
@@ -627,6 +641,15 @@ static void test_import_and_sign_all_10_RSA() {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
int destruction_confirmed(void) {
|
||||||
|
char *confirmed = getenv("YKPIV_ENV_HWTESTS_CONFIRMED");
|
||||||
|
if (confirmed && confirmed[0] == '1')
|
||||||
|
return 1;
|
||||||
|
// Use dprintf() to write directly to stdout, since automake eats the standard stdout/stderr pointers.
|
||||||
|
dprintf(0, "\n***\n*** Hardware tests skipped. Run \"make hwcheck\".\n***\n\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int main(void) {
|
int main(void) {
|
||||||
|
|
||||||
get_functions(&funcs);
|
get_functions(&funcs);
|
||||||
@@ -634,8 +657,15 @@ int main(void) {
|
|||||||
test_lib_info();
|
test_lib_info();
|
||||||
|
|
||||||
#ifdef HW_TESTS
|
#ifdef HW_TESTS
|
||||||
|
// Require user confirmation to continue, since this test suite will clear
|
||||||
|
// any data stored on connected keys.
|
||||||
|
if (!destruction_confirmed())
|
||||||
|
exit(77); // exit code 77 == skipped tests
|
||||||
|
|
||||||
test_initalize();
|
test_initalize();
|
||||||
test_token_info();
|
// Require YK4 to continue. Skip if different model found.
|
||||||
|
if (test_token_info() != 0)
|
||||||
|
exit(77);
|
||||||
test_mechanism_list_and_info();
|
test_mechanism_list_and_info();
|
||||||
test_session();
|
test_session();
|
||||||
test_login();
|
test_login();
|
||||||
@@ -648,3 +678,5 @@ int main(void) {
|
|||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#pragma clang diagnostic pop
|
||||||
|
|||||||
@@ -196,7 +196,7 @@ static CK_RV COMMON_token_generate_key(ykpiv_state *state, CK_BBOOL rsa,
|
|||||||
*certptr++ = 0;
|
*certptr++ = 0;
|
||||||
|
|
||||||
// Store the certificate into the token
|
// Store the certificate into the token
|
||||||
if (ykpiv_save_object(state, key_to_object_id(key), data, (size_t)(certptr - data)) != YKPIV_OK)
|
if (ykpiv_save_object(state, ykpiv_util_slot_object(key), data, (size_t)(certptr - data)) != YKPIV_OK)
|
||||||
return CKR_DEVICE_ERROR;
|
return CKR_DEVICE_ERROR;
|
||||||
|
|
||||||
return CKR_OK;
|
return CKR_OK;
|
||||||
|
|||||||
+1
-2
@@ -182,6 +182,7 @@ CK_RV create_token(ykpiv_state *state, CK_BYTE_PTR p, ykcs11_slot_t *slot) {
|
|||||||
|
|
||||||
t_info->ulFreePrivateMemory = CK_UNAVAILABLE_INFORMATION;
|
t_info->ulFreePrivateMemory = CK_UNAVAILABLE_INFORMATION;
|
||||||
|
|
||||||
|
memset(&t_info->hardwareVersion, 0, sizeof(t_info->hardwareVersion));
|
||||||
// Ignore hardware version, report firmware version
|
// Ignore hardware version, report firmware version
|
||||||
if (token.get_token_version(state, &t_info->firmwareVersion) != CKR_OK) {
|
if (token.get_token_version(state, &t_info->firmwareVersion) != CKR_OK) {
|
||||||
ykpiv_disconnect(state);
|
ykpiv_disconnect(state);
|
||||||
@@ -257,8 +258,6 @@ void strip_DER_encoding_from_ECSIG(CK_BYTE_PTR data, CK_ULONG_PTR len) {
|
|||||||
|
|
||||||
data_ptr++;
|
data_ptr++;
|
||||||
memcpy(buf_ptr, data_ptr, elem_len);
|
memcpy(buf_ptr, data_ptr, elem_len);
|
||||||
data_ptr += elem_len;
|
|
||||||
buf_ptr += elem_len;
|
|
||||||
|
|
||||||
*len = sig_halflen * 2;
|
*len = sig_halflen * 2;
|
||||||
memcpy(data, buf, *len);
|
memcpy(data, buf, *len);
|
||||||
|
|||||||
@@ -215,6 +215,11 @@ CK_DEFINE_FUNCTION(CK_RV, C_GetSlotList)(
|
|||||||
return CKR_OK;
|
return CKR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!pulCount) {
|
||||||
|
DOUT;
|
||||||
|
return CKR_ARGUMENTS_BAD;
|
||||||
|
}
|
||||||
|
|
||||||
if ((tokenPresent && *pulCount < n_slots_with_token) || (!tokenPresent && *pulCount < n_slots)) {
|
if ((tokenPresent && *pulCount < n_slots_with_token) || (!tokenPresent && *pulCount < n_slots)) {
|
||||||
DBG("Buffer too small: needed %lu, provided %lu", n_slots, *pulCount);
|
DBG("Buffer too small: needed %lu, provided %lu", n_slots, *pulCount);
|
||||||
return CKR_BUFFER_TOO_SMALL;
|
return CKR_BUFFER_TOO_SMALL;
|
||||||
@@ -1214,6 +1219,7 @@ CK_DEFINE_FUNCTION(CK_RV, C_DestroyObject)(
|
|||||||
|
|
||||||
rv = delete_cert(cert_id);
|
rv = delete_cert(cert_id);
|
||||||
if (rv != CKR_OK) {
|
if (rv != CKR_OK) {
|
||||||
|
free(obj_ptr);
|
||||||
DBG("Unable to delete certificate data");
|
DBG("Unable to delete certificate data");
|
||||||
return CKR_FUNCTION_FAILED;
|
return CKR_FUNCTION_FAILED;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,16 +32,16 @@
|
|||||||
#include "pkcs11.h"
|
#include "pkcs11.h"
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
static const CK_UTF8CHAR_PTR slot_manufacturer = "Yubico";
|
static const CK_UTF8CHAR_PTR slot_manufacturer = (const CK_UTF8CHAR_PTR)"Yubico";
|
||||||
static const CK_FLAGS slot_flags = CKF_TOKEN_PRESENT | CKF_HW_SLOT;
|
static const CK_FLAGS slot_flags = CKF_TOKEN_PRESENT | CKF_HW_SLOT;
|
||||||
static const CK_VERSION slot_version = {1, 0};
|
static const CK_VERSION slot_version = {1, 0};
|
||||||
|
|
||||||
CK_RV YUBICO_get_slot_manufacturer(CK_UTF8CHAR_PTR str, CK_ULONG len) {
|
CK_RV YUBICO_get_slot_manufacturer(CK_UTF8CHAR_PTR str, CK_ULONG len) {
|
||||||
|
|
||||||
if (strlen(slot_manufacturer) > len)
|
if (strlen((const char*)slot_manufacturer) > len)
|
||||||
return CKR_BUFFER_TOO_SMALL;
|
return CKR_BUFFER_TOO_SMALL;
|
||||||
|
|
||||||
memcpy(str, slot_manufacturer, strlen(slot_manufacturer));
|
memcpy(str, slot_manufacturer, strlen((const char*)slot_manufacturer));
|
||||||
return CKR_OK;
|
return CKR_OK;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -372,7 +372,7 @@ CK_RV YUBICO_token_change_pin(ykpiv_state *state, CK_USER_TYPE user_type, CK_UTF
|
|||||||
DBG("TODO implement other users pin change");
|
DBG("TODO implement other users pin change");
|
||||||
return CKR_FUNCTION_FAILED;
|
return CKR_FUNCTION_FAILED;
|
||||||
}
|
}
|
||||||
res = ykpiv_change_pin(state, pOldPin, ulOldLen, pNewPin, ulNewLen, &tries);
|
res = ykpiv_change_pin(state, (const char*)pOldPin, ulOldLen, (const char*)pNewPin, ulNewLen, &tries);
|
||||||
switch (res) {
|
switch (res) {
|
||||||
case YKPIV_OK:
|
case YKPIV_OK:
|
||||||
return CKR_OK;
|
return CKR_OK;
|
||||||
|
|||||||
Reference in New Issue
Block a user