PKCS#11 testsuite (#1224)
* Initial version of pkcs11 testsuite * Refactor test cases to several files, clean up awful and unused stuff * Static mechanism list based on the actual token offer * Get rid of magic numbers * Documentation * License update based on the original project * Verbose readme * Cleanup unused code, long lines and method order * Typo; More verbose errors * Use fallback mechanisms * Refactor object allocation and certificate search * PKCS11SPY mentioned, more TODO * add SHA mechanisms * Do not try to Finalize already finalized cryptoki * Add more flags and mechanisms * Do not list table for no results * Logical order of the tests (regression last) * read ALWAYS_AUTHENTICATE from correct place * ALWAYS_AUTHENTICATE for decryption * Test EC key length signature based on the actual key length * Shorten CKM_ list output, add keygen types detection * Skip decrypting on non-supported mechanisms * Fail hard if the C_Login fails * Reorganize local FLAGS_ constants * Test RSA Digest mechanisms * Correct mechanisms naming, typos * Do not attempt to do signature using empty keys * CKM_ECDSA_SHA1 support * Correct type cast when getting attributes * Report failures from all mechanisms * Standardize return values, eliminate complete fails, documentation interface * Wait for slot event test * Add switch to allow interaction with a card (WaitForSlotEvent) * At least try to verify using C_Verify, if it fails, fall back to openssl * Get rid of function_pointers * Get rid of additional newline * Share always_authenticate() function between the test cases * Refactor Encrypt&decrypt test to functions * Do not overwrite bits if they are not provided by CKA, indentation * Cleanup and Break to more functions Sign&Verify test * CKM_RSA_X_509 sign and verify with openssl padding * More TODO's * Proper abstracted padding with RSA_X_509 mechanism * Add ongoing tasks from different TODO list * Update instructions. Another todo * Variables naming * Increase mechanism list size, use different static buffers for flags and mechanism names * nonstandard mechanism CKM_SHA224_RSA_PKCS supported by some softotkens * Get rid of loop initial declarations * Loop initial declaration, typos, strict warnings * Move the p11test to the new folder to avoid problems with dynamically linked opensc.so * Update path in README * Possibility to validate the testsuite agains software tokens * Add possibility to select slot ID on command-line (when there are more cards present) * Clean up readme to reflect current options and TODOs * Do not attempt to use keys without advertised sign&verify bits to avoid false positives * Get and present more object attributes in readonly test; refactor table * New test checking if the set of attributes (usage flags) is reasonable * Test multipart signatures. There is not reasonable mechanism supporting multipart encryption * Use PKCS#11 encryption if possible (with openssl fallback) * Identify few more mechanisms (PSS) in the lest * Resize table to fit new mechanisms * Remove initial loop declaration from multipart test * Use pkcs11-tool instead of p11tool form most of the operations (master have most of the features) * Preparation for machine readable results * Refactor log variables out of the main context, try to export generic data * Do not write to non-existing FD if not logging * Export missing data into the log file in JSON * Store database in json * Sanity check * Avoid uninitialized structure fields using in state structure * Dump always_authenticate attribute too * Manual selection of slots with possibility to use slots without tokens * Do not free before finalizing * Proper cleanup of message in all cases * Proper allocation and deallocation of messages * Sanitize missing cases (memory leaks) * Suppressions for testing under valgrind * Better handling message_lengt during sign&verify (avoid invalid access) * Suppress another PCSC error * Do not use default PIN. Fail if none specified * Sanitize initialization. Skip incomplete key pairs * Add missing newline in errors * Fix condition for certificate search * Avoid several calls for attributes of zero length * Handle if the private key is not present on the card * Improve memory handling, silent GCC warning of 'unused' variable * Fail early with missing private key, cleanup the messages * Use correct padding for encryption * Cache if the card supports Verify/Encrypt and avoid trying over and over again * Loosen the condition for the Usage flags * OpenSSL 1.1.0 compatibility * Add missing mechanisms * Do not require certificates on the card and pass valid data for RSA_PKCS mechanisms * Add missing PIN argument in runtest.sh * Add OpenSSL < 1.1 comatible bits * Add SHA2 ECDSA mechanisms handling * Use public key from PKCS#11 if the certificate is missing (or compare it with certificate) * Avoid long definitions in OpenSSL compat layer * In older OpenSSL, the header file is ecdsa.h * Add missing config.h to apply compat OpenSSL layer * ASN1_STRING_get0_data() is also new in 1.1.0 * Return back RSA_X_509 mechanism * Drop bogus CKM_* in the definitions * Drop CKM_SHA224_RSA_PKCS as it is already in pkcs11.h * Update documentation * Use NDEBUG as intended * typos, cleanup * Typos, cleanup, update copyright * Additional check for OpenCryptoki, generate more key types on soft tokens * Prepare for RSA-PSS and RSA-OAEP * Use usage&result flags for the tests, gracefully ignore PSS&OAEP * pkcs11.h: Add missing definitions for PSS * PSS and OAEP tests readonly: Typos, reformat * Working version, memory leak * Tweak message lengths for OAEP and PSS * Skip tests that are not aplicable for tokens * configure.ac: New switch --enable-tests Do not attempt to build tests if cmocka is not available or --enable-tests is provided. It makes also more lightweight release builds out of the box (or with --disable-tests). * travis: Install cmocka if not available * Do not build tests on Windows and make dist pass * Try to install cmocka from apt and from brew * Do not require sudo (cmocka from apt and brew works)
This commit is contained in:
parent
eb60481f89
commit
9858d05589
|
@ -128,5 +128,6 @@ src/tests/lottery
|
|||
src/tests/p15dump
|
||||
src/tests/pintest
|
||||
src/tests/prngtest
|
||||
src/tests/p11test/p11test
|
||||
|
||||
version.m4.ci
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
language: c
|
||||
|
||||
sudo: false
|
||||
|
||||
addons:
|
||||
apt_packages:
|
||||
- binutils-mingw-w64-i686
|
||||
|
@ -15,6 +13,7 @@ addons:
|
|||
- xsltproc
|
||||
- gengetopt
|
||||
- help2man
|
||||
- libcmocka-dev
|
||||
|
||||
env:
|
||||
global:
|
||||
|
@ -52,7 +51,7 @@ before_install:
|
|||
brew update;
|
||||
brew uninstall libtool;
|
||||
brew install libtool;
|
||||
brew install gengetopt help2man;
|
||||
brew install gengetopt help2man cmocka;
|
||||
fi
|
||||
|
||||
before_script:
|
||||
|
|
30
configure.ac
30
configure.ac
|
@ -255,6 +255,13 @@ AC_ARG_ENABLE(
|
|||
[enable_notify="detect"]
|
||||
)
|
||||
|
||||
AC_ARG_ENABLE(
|
||||
[tests],
|
||||
[AS_HELP_STRING([--enable-tests],[Build tests in src/tests/ directory @<:@detect@:>@])],
|
||||
,
|
||||
[enable_tests="detect"]
|
||||
)
|
||||
|
||||
AC_ARG_WITH(
|
||||
[xsl-stylesheetsdir],
|
||||
[AS_HELP_STRING([--with-xsl-stylesheetsdir=PATH],[docbook xsl-stylesheets for svn build @<:@detect@:>@])],
|
||||
|
@ -511,6 +518,26 @@ if test "${enable_notify}" = "yes"; then
|
|||
fi
|
||||
fi
|
||||
|
||||
PKG_CHECK_MODULES( [CMOCKA], [cmocka],
|
||||
[ have_cmocka="yes" ],
|
||||
[ have_cmocka="no" ])
|
||||
|
||||
if test "${enable_tests}" = "detect"; then
|
||||
if test "${have_cmocka}" = "yes"; then
|
||||
enable_tests="yes"
|
||||
else
|
||||
enable_tests="no"
|
||||
fi
|
||||
fi
|
||||
|
||||
if test "${enable_tests}" = "yes"; then
|
||||
if test "${have_cmocka}" = "yes"; then
|
||||
AC_DEFINE([ENABLE_TESTS], [1], [Build tests in tests/ subdirectory])
|
||||
else
|
||||
AC_MSG_ERROR([Tests required, but cmocka is not available])
|
||||
fi
|
||||
fi
|
||||
|
||||
AC_ARG_VAR([ZLIB_CFLAGS], [C compiler flags for zlib])
|
||||
AC_ARG_VAR([ZLIB_LIBS], [linker flags for zlib])
|
||||
if test -z "${ZLIB_LIBS}"; then
|
||||
|
@ -997,6 +1024,7 @@ AM_CONDITIONAL([ENABLE_MINIDRIVER_SETUP_CUSTOMACTION], [test "${enable_minidrive
|
|||
AM_CONDITIONAL([ENABLE_SM], [test "${enable_sm}" = "yes"])
|
||||
AM_CONDITIONAL([ENABLE_DNIE_UI], [test "${enable_dnie_ui}" = "yes"])
|
||||
AM_CONDITIONAL([ENABLE_NPATOOL], [test "${ENABLE_NPATOOL}" = "yes"])
|
||||
AM_CONDITIONAL([ENABLE_TESTS], [test "${ENABLE_TESTS}" = "yes"])
|
||||
AM_CONDITIONAL([GIT_CHECKOUT], [test "${GIT_CHECKOUT}" = "yes"])
|
||||
|
||||
if test "${enable_pedantic}" = "yes"; then
|
||||
|
@ -1025,6 +1053,7 @@ AC_CONFIG_FILES([
|
|||
src/scconf/Makefile
|
||||
src/tests/Makefile
|
||||
src/tests/regression/Makefile
|
||||
src/tests/p11test/Makefile
|
||||
src/tools/Makefile
|
||||
src/tools/versioninfo-tools.rc
|
||||
src/tools/versioninfo-opensc-notify.rc
|
||||
|
@ -1082,6 +1111,7 @@ SM support: ${enable_sm}
|
|||
SM default module: ${DEFAULT_SM_MODULE}
|
||||
DNIe UI support: ${enable_dnie_ui}
|
||||
Notification support: ${enable_notify}
|
||||
Build tests: ${enable_tests}
|
||||
Debug file: ${DEBUG_FILE}
|
||||
|
||||
PC/SC default provider: ${DEFAULT_PCSC_PROVIDER}
|
||||
|
|
|
@ -3,8 +3,12 @@ EXTRA_DIST = Makefile.mak
|
|||
|
||||
# Order IS important
|
||||
SUBDIRS = common scconf ui pkcs15init sm \
|
||||
libopensc pkcs11 tools tests minidriver
|
||||
libopensc pkcs11 tools minidriver
|
||||
|
||||
if ENABLE_SM
|
||||
SUBDIRS += smm
|
||||
endif
|
||||
|
||||
if ENABLE_TESTS
|
||||
SUBDIRS += tests
|
||||
endif
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
TOPDIR = ..
|
||||
|
||||
SUBDIRS = common scconf ui sm pkcs15init \
|
||||
libopensc pkcs11 tools tests
|
||||
libopensc pkcs11 tools
|
||||
|
||||
default: all
|
||||
|
||||
|
@ -15,6 +15,10 @@ SUBDIRS = $(SUBDIRS) minidriver
|
|||
SUBDIRS = $(SUBDIRS) smm
|
||||
!ENDIF
|
||||
|
||||
!IF "$(TESTS_DEF)" == "/DENABLE_TESTS"
|
||||
SUBDIRS = $(SUBDIRS) tests
|
||||
!ENDIF
|
||||
|
||||
all clean::
|
||||
@for %i in ( $(SUBDIRS) ) do \
|
||||
@cmd /c "cd %i && $(MAKE) /nologo /f Makefile.mak $@"
|
||||
|
|
|
@ -93,6 +93,7 @@ extern "C" {
|
|||
#define OPENSSL_malloc_init CRYPTO_malloc_init
|
||||
|
||||
#define EVP_PKEY_get0_RSA(x) (x->pkey.rsa)
|
||||
#define EVP_PKEY_get0_EC_KEY(x) (x->pkey.ec)
|
||||
#define EVP_PKEY_get0_DSA(x) (x->pkey.dsa)
|
||||
#define X509_get_extension_flags(x) (x->ex_flags)
|
||||
#define X509_get_key_usage(x) (x->ex_kusage)
|
||||
|
@ -103,6 +104,11 @@ extern "C" {
|
|||
#endif
|
||||
#endif
|
||||
|
||||
/* ASN1_STRING_data is deprecated in OpenSSL 1.1.0 */
|
||||
#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
|
||||
#define ASN1_STRING_get0_data(x) ASN1_STRING_data(x)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* OpenSSL-1.1.0-pre5 has hidden the RSA and DSA structures
|
||||
* One can no longer use statements like rsa->n = ...
|
||||
|
@ -140,6 +146,9 @@ extern "C" {
|
|||
#ifndef OPENSSL_NO_DSA
|
||||
#include <openssl/dsa.h>
|
||||
#endif
|
||||
#ifndef OPENSSL_NO_EC
|
||||
#include <openssl/ecdsa.h>
|
||||
#endif
|
||||
|
||||
#ifndef OPENSSL_NO_RSA
|
||||
static sc_ossl_inline int RSA_set0_key(RSA *r, BIGNUM *n, BIGNUM *e, BIGNUM *d)
|
||||
|
@ -239,6 +248,21 @@ static sc_ossl_inline void DSA_get0_key(const DSA *d, const BIGNUM **pub_key, co
|
|||
/* NOTE: DSA_set0_* functions not defined because they are not currently used in OpenSC */
|
||||
#endif /* OPENSSL_NO_DSA */
|
||||
|
||||
|
||||
#ifndef OPENSSL_NO_EC
|
||||
static sc_ossl_inline int ECDSA_SIG_set0(ECDSA_SIG *sig, BIGNUM *r, BIGNUM *s)
|
||||
{
|
||||
if (r == NULL || s == NULL)
|
||||
return 0;
|
||||
BN_clear_free(sig->r);
|
||||
BN_clear_free(sig->s);
|
||||
sig->r = r;
|
||||
sig->s = s;
|
||||
return 1;
|
||||
}
|
||||
#endif /* OPENSSL_NO_EC */
|
||||
|
||||
|
||||
#endif /* OPENSSL_VERSION_NUMBER < 0x10100000L */
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
|
|
@ -776,7 +776,7 @@ typedef struct CK_RSA_PKCS_OAEP_PARAMS {
|
|||
|
||||
typedef struct CK_RSA_PKCS_PSS_PARAMS {
|
||||
ck_mechanism_type_t hashAlg;
|
||||
unsigned long mgf;
|
||||
CK_RSA_PKCS_MGF_TYPE mgf;
|
||||
unsigned long sLen;
|
||||
} CK_RSA_PKCS_PSS_PARAMS;
|
||||
|
||||
|
@ -786,6 +786,8 @@ typedef struct CK_RSA_PKCS_PSS_PARAMS {
|
|||
#define CKG_MGF1_SHA384 (0x00000003UL)
|
||||
#define CKG_MGF1_SHA512 (0x00000004UL)
|
||||
|
||||
#define CKZ_DATA_SPECIFIED (0x00000001UL)
|
||||
|
||||
typedef unsigned long ck_rv_t;
|
||||
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ include $(top_srcdir)/win32/ltrc.inc
|
|||
MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
|
||||
EXTRA_DIST = Makefile.mak
|
||||
|
||||
SUBDIRS = regression
|
||||
SUBDIRS = regression p11test
|
||||
noinst_PROGRAMS = base64 lottery p15dump pintest prngtest
|
||||
|
||||
AM_CPPFLAGS = -I$(top_srcdir)/src
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
include $(top_srcdir)/win32/ltrc.inc
|
||||
|
||||
MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
|
||||
EXTRA_DIST = Makefile.mak
|
||||
|
||||
noinst_PROGRAMS = p11test
|
||||
noinst_HEADERS = p11test_loader.h p11test_case_common.h \
|
||||
p11test_case_readonly.h p11test_case_multipart.h \
|
||||
p11test_case_mechs.h p11test_case_ec_sign.h \
|
||||
p11test_case_usage.h p11test_case_wait.h \
|
||||
p11test_case_pss_oaep.h p11test_helpers.h
|
||||
|
||||
AM_CPPFLAGS = -I$(top_srcdir)/src
|
||||
|
||||
p11test_SOURCES = p11test.c p11test_loader.c \
|
||||
p11test_case_common.c \
|
||||
p11test_case_readonly.c \
|
||||
p11test_case_multipart.c \
|
||||
p11test_case_mechs.c \
|
||||
p11test_case_ec_sign.c \
|
||||
p11test_case_usage.c \
|
||||
p11test_case_wait.c \
|
||||
p11test_case_pss_oaep.c \
|
||||
p11test_helpers.c
|
||||
p11test_CFLAGS = -DNDEBUG
|
||||
p11test_LDADD = -lssl -lcrypto -lcmocka
|
||||
|
||||
if WIN32
|
||||
p11test_SOURCES += $(top_builddir)/win32/versioninfo.rc
|
||||
endif
|
|
@ -0,0 +1,26 @@
|
|||
TOPDIR = ..\..\..
|
||||
|
||||
TARGETS = p11test.exe
|
||||
|
||||
OBJECTS = p11test_loader.obj \
|
||||
p11test_case_common.obj \
|
||||
p11test_case_readonly.obj \
|
||||
p11test_case_multipart.obj \
|
||||
p11test_case_mechs.obj \
|
||||
p11test_case_ec_sign.obj \
|
||||
p11test_case_usage.obj \
|
||||
p11test_case_wait.obj \
|
||||
p11test_case_pss_oaep.obj \
|
||||
p11test_helpers.obj \
|
||||
$(TOPDIR)\win32\versioninfo.res
|
||||
|
||||
all: $(TARGETS)
|
||||
|
||||
!INCLUDE $(TOPDIR)\win32\Make.rules.mak
|
||||
|
||||
$(TARGETS): $(OBJECTS) $(LIBS)
|
||||
|
||||
.c.exe:
|
||||
cl $(COPTS) /c $<
|
||||
link $(LINKFLAGS) /pdb:$*.pdb /out:$@ $*.obj $(OBJECTS) $(LIBS)
|
||||
if EXIST $@.manifest mt -manifest $@.manifest -outputresource:$@;1
|
|
@ -0,0 +1,57 @@
|
|||
# Non-destructive PKCS#11 test suite (not only for readonly cards)
|
||||
|
||||
## What are the dependencies?
|
||||
|
||||
In addition to the dependencies needed by OpenSC, the test suite is
|
||||
using [`cmocka`](https://cmocka.org/) unit testing framework
|
||||
(`libcmocka-devel` package in Fedora/EPEL).
|
||||
|
||||
## How to use?
|
||||
|
||||
Build OpenSC from source:
|
||||
|
||||
git clone git@github.com:Jakuje/OpenSC.git
|
||||
cd OpenSC
|
||||
git checkout jjelen-testsuite # not in master yet
|
||||
./bootstrap
|
||||
./configure
|
||||
make -j4
|
||||
|
||||
Plug in the card/reader, change to test directory and run the test:
|
||||
|
||||
cd src/tests/p11test
|
||||
./p11test -p 123456
|
||||
|
||||
It will run all tests on the first card found in PKCS#11 API
|
||||
with pin `123456` and using just built OpenSC shared library from master.
|
||||
|
||||
### I have more slots with different cards.
|
||||
|
||||
Slot can be selected using `-s` switch on command-line.
|
||||
|
||||
./p11test -s 4
|
||||
|
||||
Slot numbers can be obtained using from `pkcs11-tool -L` (note that different
|
||||
libraries might have different numbers for the slots).
|
||||
|
||||
### I want to test different pkcs11 library
|
||||
|
||||
You can specify different library or build from different branch
|
||||
on command-line:
|
||||
|
||||
./p11test -m /usr/lib64/pkcs11/libcoolkeypk11.so
|
||||
|
||||
or to debug PKCS#11 calls using `/usr/lib64/pkcs11-spy.so`:
|
||||
|
||||
export PKCS11SPY="../pkcs11/.libs/opensc-pkcs11.so"
|
||||
./p11test -m ../pkcs11/.libs/pkcs11-spy.so
|
||||
|
||||
You can run the test suite also on the soft tokens. The testbench for
|
||||
`softhsm` and `opencryptoki` is available in the script `runtest.sh`.
|
||||
|
||||
TODO:
|
||||
|
||||
* Test `CKM_ECDSA_DERIVE` mechanism(s)
|
||||
* Read pin from environment variable?
|
||||
* Keygen write tests (optional)
|
||||
* Reflect cmocka dependency in the configure
|
|
@ -0,0 +1,6 @@
|
|||
organization = "OpenSC"
|
||||
expiration_days = 365
|
||||
email = "none@example.org"
|
||||
signing_key
|
||||
encryption_key
|
||||
|
|
@ -0,0 +1,132 @@
|
|||
/*
|
||||
* p11test.c: Test suite for PKCS#11 API
|
||||
*
|
||||
* Copyright (C) 2016 Martin Strhársky <strharsky.martin@gmail.com>
|
||||
* Copyright (C) 2016, 2017 Red Hat, Inc.
|
||||
*
|
||||
* Author: Jakub Jelen <jjelen@redhat.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <getopt.h>
|
||||
#include "p11test_helpers.h"
|
||||
|
||||
#include "p11test_case_readonly.h"
|
||||
#include "p11test_case_multipart.h"
|
||||
#include "p11test_case_ec_sign.h"
|
||||
#include "p11test_case_usage.h"
|
||||
#include "p11test_case_mechs.h"
|
||||
#include "p11test_case_wait.h"
|
||||
#include "p11test_case_pss_oaep.h"
|
||||
|
||||
#define DEFAULT_P11LIB "../../pkcs11/.libs/opensc-pkcs11.so"
|
||||
|
||||
void display_usage() {
|
||||
fprintf(stdout,
|
||||
" Usage:\n"
|
||||
" ./p11test [-m module_path] [-s slot_id] [-p pin]\n"
|
||||
" -m module_path Path to tested module (e.g. /usr/lib64/opensc-pkcs11.so)\n"
|
||||
" Default is "DEFAULT_P11LIB"\n"
|
||||
" -p pin Application PIN\n"
|
||||
" -s slot_id Slot ID with the card\n"
|
||||
" -i Wait for the card before running the test (interactive)\n"
|
||||
" -o File to write a log in JSON\n"
|
||||
" -h This help\n"
|
||||
"\n");
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
char command;
|
||||
const struct CMUnitTest readonly_tests_without_initialization[] = {
|
||||
/* Test card events on slot */
|
||||
cmocka_unit_test_setup_teardown(wait_test,
|
||||
token_initialize, token_cleanup),
|
||||
|
||||
/* Check all the mechanisms provided by the token */
|
||||
cmocka_unit_test_setup_teardown(supported_mechanisms_test,
|
||||
token_setup, token_cleanup),
|
||||
|
||||
/* Complex readonly test of all objects on the card */
|
||||
cmocka_unit_test_setup_teardown(readonly_tests,
|
||||
user_login_setup, after_test_cleanup),
|
||||
|
||||
/* Multipart signatures and encryption */
|
||||
cmocka_unit_test_setup_teardown(multipart_tests,
|
||||
user_login_setup, after_test_cleanup),
|
||||
|
||||
/* Regression test Sign&Verify with various data lengths */
|
||||
cmocka_unit_test_setup_teardown(ec_sign_size_test,
|
||||
user_login_setup, after_test_cleanup),
|
||||
|
||||
/* Verify that the Usage flags on the objects are sane */
|
||||
cmocka_unit_test_setup_teardown(usage_test,
|
||||
user_login_setup, after_test_cleanup),
|
||||
|
||||
/* Verify that RSA-PSS and RSA-OAEP functions if supported */
|
||||
cmocka_unit_test_setup_teardown(pss_oaep_test,
|
||||
user_login_setup, after_test_cleanup),
|
||||
};
|
||||
|
||||
token.library_path = NULL;
|
||||
token.pin = NULL;
|
||||
token.pin_length = 0;
|
||||
token.interactive = 0;
|
||||
token.slot_id = (unsigned long) -1;
|
||||
token.log.outfile = NULL;
|
||||
|
||||
while ((command = getopt(argc, argv, "?hm:s:p:io:")) != -1) {
|
||||
switch (command) {
|
||||
case 'o':
|
||||
token.log.outfile = strdup(optarg);
|
||||
break;
|
||||
case 'm':
|
||||
token.library_path = strdup(optarg);
|
||||
break;
|
||||
case 's':
|
||||
token.slot_id = atol(optarg);
|
||||
break;
|
||||
case 'p':
|
||||
token.pin = (CK_UTF8CHAR*) strdup(optarg);
|
||||
token.pin_length = strlen(optarg);
|
||||
break;
|
||||
case 'i':
|
||||
token.interactive = 1;
|
||||
break;
|
||||
case 'h':
|
||||
case '?':
|
||||
display_usage();
|
||||
return 0;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (token.library_path == NULL) {
|
||||
debug_print("Falling back to the default library " DEFAULT_P11LIB);
|
||||
token.library_path = strdup(DEFAULT_P11LIB);
|
||||
}
|
||||
|
||||
if (token.pin == NULL || token.pin_length == 0) {
|
||||
printf("No PIN specified. Please, specify it on command-line using -p switch\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
debug_print("Card info:\n\tPIN %s\n\tPIN LENGTH %lu\n\t",
|
||||
token.pin, token.pin_length);
|
||||
|
||||
return cmocka_run_group_tests(readonly_tests_without_initialization,
|
||||
group_setup, group_teardown);
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
{
|
||||
Suppress pcsc_detect_readers()
|
||||
Memcheck:Leak
|
||||
match-leak-kinds: definite
|
||||
fun:malloc
|
||||
obj:*
|
||||
obj:*
|
||||
fun:pcsc_detect_readers
|
||||
fun:sc_ctx_detect_readers
|
||||
fun:sc_context_create
|
||||
fun:C_Initialize
|
||||
}
|
||||
{
|
||||
Suppress MessageSend() errors
|
||||
Memcheck:Param
|
||||
socketcall.sendto(msg)
|
||||
fun:send
|
||||
fun:MessageSend
|
||||
fun:MessageSendWithHeader
|
||||
fun:SCardConnect
|
||||
fun:pcsc_detect_readers
|
||||
fun:sc_ctx_detect_readers
|
||||
fun:sc_context_create
|
||||
fun:C_Initialize
|
||||
fun:load_pkcs11_module
|
||||
fun:group_setup
|
||||
obj:/usr/lib64/libcmocka.so.0.3.1
|
||||
fun:_cmocka_run_group_tests
|
||||
}
|
||||
|
|
@ -0,0 +1,728 @@
|
|||
/*
|
||||
* p11test_case_common.c: Functions shared between test cases.
|
||||
*
|
||||
* Copyright (C) 2016, 2017 Red Hat, Inc.
|
||||
*
|
||||
* Author: Jakub Jelen <jjelen@redhat.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "p11test_case_common.h"
|
||||
|
||||
char name_buffer[11];
|
||||
char flag_buffer[11];
|
||||
|
||||
/**
|
||||
* If the object enforces re-authentication, do it now.
|
||||
*/
|
||||
void always_authenticate(test_cert_t *o, token_info_t *info)
|
||||
{
|
||||
CK_RV rv;
|
||||
if (!o->always_auth)
|
||||
return;
|
||||
|
||||
rv = info->function_pointer->C_Login(info->session_handle,
|
||||
CKU_CONTEXT_SPECIFIC, info->pin, info->pin_length);
|
||||
if (rv != CKR_OK) {
|
||||
fail_msg(" [ SKIP %s ] Re-authentication failed", o->id_str);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocate new place for next certificate to store in the list
|
||||
* and return pointer to this object
|
||||
*/
|
||||
test_cert_t *
|
||||
add_object(test_certs_t *objects, CK_ATTRIBUTE key_id, CK_ATTRIBUTE label)
|
||||
{
|
||||
test_cert_t *o = NULL;
|
||||
objects->count = objects->count+1;
|
||||
objects->data = realloc(objects->data, objects->count * sizeof(test_cert_t));
|
||||
if (objects->data == NULL)
|
||||
return NULL;
|
||||
|
||||
o = &(objects->data[objects->count - 1]);
|
||||
o->private_handle = CK_INVALID_HANDLE;
|
||||
o->public_handle = CK_INVALID_HANDLE;
|
||||
o->always_auth = 0;
|
||||
o->bits = 0;
|
||||
o->verify_public = 0;
|
||||
o->num_mechs = 0;
|
||||
o->type = -1;
|
||||
o->sign = 0;
|
||||
o->verify = 0;
|
||||
o->decrypt = 0;
|
||||
o->encrypt = 0;
|
||||
o->wrap = 0;
|
||||
o->unwrap = 0;
|
||||
o->derive_priv = 0;
|
||||
o->derive_pub = 0;
|
||||
o->key_type = -1;
|
||||
o->x509 = NULL; /* The "reuse" capability of d2i_X509() is strongly discouraged */
|
||||
o->key.rsa = NULL;
|
||||
o->key.ec = NULL;
|
||||
|
||||
/* Store the passed CKA_ID and CKA_LABEL */
|
||||
o->key_id = malloc(key_id.ulValueLen);
|
||||
memcpy(o->key_id, key_id.pValue, key_id.ulValueLen);
|
||||
o->key_id_size = key_id.ulValueLen;
|
||||
o->id_str = convert_byte_string(o->key_id, o->key_id_size);
|
||||
o->label = malloc(label.ulValueLen + 1);
|
||||
strncpy(o->label, label.pValue, label.ulValueLen);
|
||||
o->label[label.ulValueLen] = '\0';
|
||||
|
||||
return o;
|
||||
}
|
||||
|
||||
/*
|
||||
* Search for certificate in the list by ID and return pointer to it
|
||||
*/
|
||||
test_cert_t * search_certificate(test_certs_t *objects, CK_ATTRIBUTE *id)
|
||||
{
|
||||
unsigned int i = 0;
|
||||
|
||||
while (i < objects->count && (objects->data[i].key_id_size != id->ulValueLen ||
|
||||
memcmp(objects->data[i].key_id, id->pValue, id->ulValueLen) != 0))
|
||||
i++;
|
||||
|
||||
if (i == objects->count)
|
||||
return NULL;
|
||||
|
||||
return &(objects->data[i]);
|
||||
}
|
||||
|
||||
static void
|
||||
add_supported_mechs(test_cert_t *o)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
if (o->type == EVP_PK_RSA) {
|
||||
if (token.num_rsa_mechs > 0 ) {
|
||||
/* Get supported mechanisms by token */
|
||||
o->num_mechs = token.num_rsa_mechs;
|
||||
for (i = 0; i <= token.num_rsa_mechs; i++) {
|
||||
o->mechs[i].mech = token.rsa_mechs[i].mech;
|
||||
o->mechs[i].result_flags = 0;
|
||||
o->mechs[i].usage_flags =
|
||||
token.rsa_mechs[i].usage_flags;
|
||||
}
|
||||
} else {
|
||||
/* Use the default list */
|
||||
o->num_mechs = 1;
|
||||
o->mechs[0].mech = CKM_RSA_PKCS;
|
||||
o->mechs[0].result_flags = 0;
|
||||
o->mechs[0].usage_flags = CKF_SIGN | CKF_VERIFY
|
||||
| CKF_ENCRYPT | CKF_DECRYPT;
|
||||
}
|
||||
} else if (o->type == EVP_PK_EC) {
|
||||
if (token.num_ec_mechs > 0 ) {
|
||||
o->num_mechs = token.num_ec_mechs;
|
||||
for (i = 0; i <= token.num_ec_mechs; i++) {
|
||||
o->mechs[i].mech = token.ec_mechs[i].mech;
|
||||
o->mechs[i].result_flags = 0;
|
||||
o->mechs[i].usage_flags =
|
||||
token.ec_mechs[i].usage_flags;
|
||||
}
|
||||
} else {
|
||||
/* Use the default list */
|
||||
o->num_mechs = 1;
|
||||
o->mechs[0].mech = CKM_ECDSA;
|
||||
o->mechs[0].result_flags = 0;
|
||||
o->mechs[0].usage_flags = CKF_SIGN | CKF_VERIFY;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocate place in the structure for every certificate found
|
||||
* and store related information
|
||||
*/
|
||||
int callback_certificates(test_certs_t *objects,
|
||||
CK_ATTRIBUTE template[], unsigned int template_size, CK_OBJECT_HANDLE object_handle)
|
||||
{
|
||||
EVP_PKEY *evp = NULL;
|
||||
const u_char *cp;
|
||||
test_cert_t *o = NULL;
|
||||
|
||||
if ((o = add_object(objects, template[0], template[2])) == NULL)
|
||||
return -1;
|
||||
|
||||
/* Extract public key from the certificate */
|
||||
cp = template[1].pValue;
|
||||
if (d2i_X509(&(o->x509), &cp, template[1].ulValueLen) == NULL) {
|
||||
fail_msg("d2i_X509");
|
||||
} else if ((evp = X509_get_pubkey(o->x509)) == NULL) {
|
||||
fail_msg("X509_get_pubkey failed.");
|
||||
}
|
||||
|
||||
if (EVP_PKEY_base_id(evp) == EVP_PKEY_RSA) {
|
||||
/* Extract public RSA key */
|
||||
RSA *rsa = EVP_PKEY_get0_RSA(evp);
|
||||
if ((o->key.rsa = RSAPublicKey_dup(rsa)) == NULL)
|
||||
fail_msg("RSAPublicKey_dup failed");
|
||||
o->type = EVP_PK_RSA;
|
||||
o->bits = EVP_PKEY_bits(evp);
|
||||
|
||||
} else if (EVP_PKEY_base_id(evp) == EVP_PKEY_EC) {
|
||||
/* Extract public EC key */
|
||||
EC_KEY *ec = EVP_PKEY_get0_EC_KEY(evp);
|
||||
if ((o->key.ec = EC_KEY_dup(ec)) == NULL)
|
||||
fail_msg("EC_KEY_dup failed");
|
||||
o->type = EVP_PK_EC;
|
||||
o->bits = EVP_PKEY_bits(evp);
|
||||
|
||||
} else {
|
||||
fprintf(stderr, "[WARN %s ]evp->type = 0x%.4X (not RSA, EC)\n",
|
||||
o->id_str, EVP_PKEY_id(evp));
|
||||
}
|
||||
EVP_PKEY_free(evp);
|
||||
|
||||
debug_print(" [ OK %s ] Certificate with label %s loaded successfully",
|
||||
o->id_str, o->label);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pair found private keys on the card with existing certificates
|
||||
*/
|
||||
int callback_private_keys(test_certs_t *objects,
|
||||
CK_ATTRIBUTE template[], unsigned int template_size, CK_OBJECT_HANDLE object_handle)
|
||||
{
|
||||
test_cert_t *o = NULL;
|
||||
char *key_id;
|
||||
|
||||
/* Search for already stored certificate with same ID */
|
||||
if ((o = search_certificate(objects, &(template[3]))) == NULL) {
|
||||
key_id = convert_byte_string(template[3].pValue,
|
||||
template[3].ulValueLen);
|
||||
fprintf(stderr, "Can't find certificate for private key with ID %s\n", key_id);
|
||||
free(key_id);
|
||||
|
||||
fprintf(stderr, "Let's create a bogus structure without certificate data\n");
|
||||
if ((o = add_object(objects, template[3], template[7])) == NULL)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (o->private_handle != CK_INVALID_HANDLE) {
|
||||
key_id = convert_byte_string(template[3].pValue, template[3].ulValueLen);
|
||||
fprintf(stderr, "Object already filled? ID %s\n", key_id);
|
||||
free(key_id);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Store attributes, flags and handles */
|
||||
o->private_handle = object_handle;
|
||||
o->sign = (template[0].ulValueLen != (CK_ULONG) -1)
|
||||
? *((CK_BBOOL *) template[0].pValue) : CK_FALSE;
|
||||
o->decrypt = (template[1].ulValueLen != (CK_ULONG) -1)
|
||||
? *((CK_BBOOL *) template[1].pValue) : CK_FALSE;
|
||||
o->key_type = (template[2].ulValueLen != (CK_ULONG) -1)
|
||||
? *((CK_KEY_TYPE *) template[2].pValue) : (CK_KEY_TYPE) -1;
|
||||
o->always_auth = (template[4].ulValueLen != (CK_ULONG) -1)
|
||||
? *((CK_BBOOL *) template[4].pValue) : CK_FALSE;
|
||||
o->unwrap = (template[5].ulValueLen != (CK_ULONG) -1)
|
||||
? *((CK_BBOOL *) template[5].pValue) : CK_FALSE;
|
||||
o->derive_priv = (template[6].ulValueLen != (CK_ULONG) -1)
|
||||
? *((CK_BBOOL *) template[6].pValue) : CK_FALSE;
|
||||
|
||||
debug_print(" [ OK %s ] Private key loaded successfully S:%d D:%d T:%02lX",
|
||||
o->id_str, o->sign, o->decrypt, o->key_type);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pair found public keys on the card with existing certificates
|
||||
*/
|
||||
int callback_public_keys(test_certs_t *objects,
|
||||
CK_ATTRIBUTE template[], unsigned int template_size, CK_OBJECT_HANDLE object_handle)
|
||||
{
|
||||
test_cert_t *o = NULL;
|
||||
char *key_id;
|
||||
|
||||
/* Search for already stored certificate with same ID */
|
||||
if ((o = search_certificate(objects, &(template[3]))) == NULL) {
|
||||
key_id = convert_byte_string(template[3].pValue, template[3].ulValueLen);
|
||||
fprintf(stderr, "Can't find certificate for public key with ID %s\n", key_id);
|
||||
free(key_id);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (o->verify_public != 0) {
|
||||
key_id = convert_byte_string(template[3].pValue, template[3].ulValueLen);
|
||||
fprintf(stderr, "Object already filled? ID %s\n", key_id);
|
||||
free(key_id);
|
||||
return -1;
|
||||
}
|
||||
|
||||
o->public_handle = object_handle;
|
||||
o->verify = (template[0].ulValueLen != (CK_ULONG) -1)
|
||||
? *((CK_BBOOL *) template[0].pValue) : CK_FALSE;
|
||||
o->encrypt = (template[1].ulValueLen != (CK_ULONG) -1)
|
||||
? *((CK_BBOOL *) template[1].pValue) : CK_FALSE;
|
||||
/* store key type in case there is no corresponding private key */
|
||||
o->key_type = (template[2].ulValueLen != (CK_ULONG) -1)
|
||||
? *((CK_KEY_TYPE *) template[2].pValue) : (CK_KEY_TYPE) -1;
|
||||
o->wrap = (template[8].ulValueLen != (CK_ULONG) -1)
|
||||
? *((CK_BBOOL *) template[8].pValue) : CK_FALSE;
|
||||
o->derive_pub = (template[9].ulValueLen != (CK_ULONG) -1)
|
||||
? *((CK_BBOOL *) template[9].pValue) : CK_FALSE;
|
||||
|
||||
/* check if we get the same public key as from the certificate */
|
||||
if (o->key_type == CKK_RSA) {
|
||||
BIGNUM *n = NULL, *e = NULL;
|
||||
n = BN_bin2bn(template[4].pValue, template[4].ulValueLen, NULL);
|
||||
e = BN_bin2bn(template[5].pValue, template[5].ulValueLen, NULL);
|
||||
if (o->key.rsa != NULL) {
|
||||
const BIGNUM *cert_n = NULL, *cert_e = NULL;
|
||||
RSA_get0_key(o->key.rsa, &cert_n, &cert_e, NULL);
|
||||
if (BN_cmp(cert_n, n) != 0 ||
|
||||
BN_cmp(cert_e, e) != 0) {
|
||||
debug_print(" [WARN %s ] Got different public key then from the certificate",
|
||||
o->id_str);
|
||||
BN_free(n);
|
||||
BN_free(e);
|
||||
return -1;
|
||||
}
|
||||
BN_free(n);
|
||||
BN_free(e);
|
||||
o->verify_public = 1;
|
||||
} else { /* store the public key for future use */
|
||||
o->type = EVP_PK_RSA;
|
||||
o->key.rsa = RSA_new();
|
||||
RSA_set0_key(o->key.rsa, n, e, NULL);
|
||||
n = NULL;
|
||||
e = NULL;
|
||||
}
|
||||
} else if (o->key_type == CKK_EC) {
|
||||
ASN1_OBJECT *oid = NULL;
|
||||
ASN1_OCTET_STRING *s = NULL;
|
||||
const unsigned char *pub, *p;
|
||||
BIGNUM *bn = NULL;
|
||||
EC_POINT *ecpoint;
|
||||
EC_GROUP *ecgroup;
|
||||
int nid, pub_len;
|
||||
|
||||
/* Parse the nid out of the EC_PARAMS */
|
||||
p = template[6].pValue;
|
||||
oid = d2i_ASN1_OBJECT(NULL, &p, template[6].ulValueLen);
|
||||
nid = OBJ_obj2nid(oid);
|
||||
ASN1_OBJECT_free(oid);
|
||||
ecgroup = EC_GROUP_new_by_curve_name(nid);
|
||||
EC_GROUP_set_asn1_flag(ecgroup, OPENSSL_EC_NAMED_CURVE);
|
||||
|
||||
p = template[7].pValue;
|
||||
s = d2i_ASN1_OCTET_STRING(NULL, &p, template[7].ulValueLen);
|
||||
pub = ASN1_STRING_get0_data(s);
|
||||
pub_len = ASN1_STRING_length(s);
|
||||
bn = BN_bin2bn(pub, pub_len, NULL);
|
||||
ASN1_STRING_free(s);
|
||||
if (bn == NULL) {
|
||||
debug_print(" [WARN %s ] Can not convert EC_POINT from"
|
||||
"PKCS#11 to BIGNUM", o->id_str);
|
||||
EC_GROUP_free(ecgroup);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ecpoint = EC_POINT_bn2point(ecgroup, bn, NULL, NULL);
|
||||
BN_free(bn);
|
||||
if (ecpoint == NULL) {
|
||||
debug_print(" [WARN %s ] Can not convert EC_POINT from"
|
||||
"BIGNUM to OpenSSL format", o->id_str);
|
||||
EC_GROUP_free(ecgroup);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (o->key.ec != NULL) {
|
||||
const EC_GROUP *cert_group = EC_KEY_get0_group(o->key.ec);
|
||||
const EC_POINT *cert_point = EC_KEY_get0_public_key(o->key.ec);
|
||||
int cert_nid = EC_GROUP_get_curve_name(cert_group);
|
||||
|
||||
if (cert_nid != nid ||
|
||||
EC_GROUP_cmp(cert_group, ecgroup, NULL) != 0 ||
|
||||
EC_POINT_cmp(ecgroup, cert_point, ecpoint, NULL) != 0) {
|
||||
debug_print(" [WARN %s ] Got different public"
|
||||
"key then from the certificate",
|
||||
o->id_str);
|
||||
EC_GROUP_free(ecgroup);
|
||||
EC_POINT_free(ecpoint);
|
||||
return -1;
|
||||
}
|
||||
EC_GROUP_free(ecgroup);
|
||||
EC_POINT_free(ecpoint);
|
||||
o->verify_public = 1;
|
||||
} else { /* store the public key for future use */
|
||||
o->type = EVP_PK_EC;
|
||||
o->key.ec = EC_KEY_new_by_curve_name(nid);
|
||||
EC_KEY_set_public_key(o->key.ec, ecpoint);
|
||||
EC_KEY_set_group(o->key.ec, ecgroup);
|
||||
}
|
||||
} else {
|
||||
debug_print(" [WARN %s ] non-RSA, non-EC key. Key type: %02lX",
|
||||
o->id_str, o->key_type);
|
||||
return -1;
|
||||
}
|
||||
|
||||
add_supported_mechs(o);
|
||||
|
||||
debug_print(" [ OK %s ] Public key loaded successfully V:%d E:%d T:%02lX",
|
||||
o->id_str, o->verify, o->encrypt, o->key_type);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int search_objects(test_certs_t *objects, token_info_t *info,
|
||||
CK_ATTRIBUTE filter[], CK_LONG filter_size, CK_ATTRIBUTE template[], CK_LONG template_size,
|
||||
int (*callback)(test_certs_t *, CK_ATTRIBUTE[], unsigned int, CK_OBJECT_HANDLE))
|
||||
{
|
||||
CK_RV rv;
|
||||
CK_FUNCTION_LIST_PTR fp = info->function_pointer;
|
||||
CK_ULONG object_count;
|
||||
CK_OBJECT_HANDLE object_handle = CK_INVALID_HANDLE;
|
||||
CK_OBJECT_HANDLE_PTR object_handles = NULL;
|
||||
unsigned long i = 0, objects_length = 0;
|
||||
int j;
|
||||
|
||||
/* FindObjects first
|
||||
* https://wiki.oasis-open.org/pkcs11/CommonBugs
|
||||
*/
|
||||
rv = fp->C_FindObjectsInit(info->session_handle, filter, filter_size);
|
||||
if (rv != CKR_OK) {
|
||||
fprintf(stderr, "C_FindObjectsInit: rv = 0x%.8lX\n", rv);
|
||||
return -1;
|
||||
}
|
||||
|
||||
while(1) {
|
||||
rv = fp->C_FindObjects(info->session_handle, &object_handle, 1, &object_count);
|
||||
if (object_count == 0)
|
||||
break;
|
||||
if (rv != CKR_OK) {
|
||||
fprintf(stderr, "C_FindObjects: rv = 0x%.8lX\n", rv);
|
||||
return -1;
|
||||
}
|
||||
/* store handle */
|
||||
if (i >= objects_length) {
|
||||
objects_length += 4; // do not realloc after each row
|
||||
object_handles = realloc(object_handles, objects_length * sizeof(CK_OBJECT_HANDLE_PTR));
|
||||
if (object_handles == NULL)
|
||||
fail_msg("Realloc failed. Need to store object handles.\n");
|
||||
}
|
||||
object_handles[i++] = object_handle;
|
||||
}
|
||||
objects_length = i; //terminate list of handles
|
||||
|
||||
rv = fp->C_FindObjectsFinal(info->session_handle);
|
||||
if (rv != CKR_OK) {
|
||||
fprintf(stderr, "C_FindObjectsFinal: rv = 0x%.8lX\n", rv);
|
||||
fail_msg("Could not find certificate.\n");
|
||||
}
|
||||
|
||||
for (i = 0; i < objects_length; i++) {
|
||||
/* Find attributes one after another to handle errors
|
||||
* https://wiki.oasis-open.org/pkcs11/CommonBugs
|
||||
*/
|
||||
for (j = 0; j < template_size; j++) {
|
||||
template[j].pValue = NULL;
|
||||
template[j].ulValueLen = 0;
|
||||
|
||||
rv = fp->C_GetAttributeValue(info->session_handle, object_handles[i],
|
||||
&(template[j]), 1);
|
||||
if (rv == CKR_ATTRIBUTE_TYPE_INVALID)
|
||||
continue;
|
||||
else if (rv != CKR_OK)
|
||||
fail_msg("C_GetAttributeValue: rv = 0x%.8lX\n", rv);
|
||||
|
||||
/* Allocate memory to hold the data we want */
|
||||
if (template[j].ulValueLen == 0) {
|
||||
continue;
|
||||
} else {
|
||||
template[j].pValue = malloc(template[j].ulValueLen);
|
||||
if (template[j].pValue == NULL)
|
||||
fail_msg("malloc failed");
|
||||
}
|
||||
/* Call again to get actual attribute */
|
||||
rv = fp->C_GetAttributeValue(info->session_handle, object_handles[i],
|
||||
&(template[j]), 1);
|
||||
if (rv != CKR_OK)
|
||||
fail_msg("C_GetAttributeValue: rv = 0x%.8lX\n", rv);
|
||||
}
|
||||
|
||||
callback(objects, template, template_size, object_handles[i]);
|
||||
// XXX check results
|
||||
for (j = 0; j < template_size; j++)
|
||||
free(template[j].pValue);
|
||||
}
|
||||
free(object_handles);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void search_for_all_objects(test_certs_t *objects, token_info_t *info)
|
||||
{
|
||||
CK_OBJECT_CLASS keyClass = CKO_CERTIFICATE;
|
||||
CK_OBJECT_CLASS privateClass = CKO_PRIVATE_KEY;
|
||||
CK_OBJECT_CLASS publicClass = CKO_PUBLIC_KEY;
|
||||
CK_ATTRIBUTE filter[] = {
|
||||
{CKA_CLASS, &keyClass, sizeof(keyClass)},
|
||||
};
|
||||
CK_ULONG filter_size = 1;
|
||||
CK_ATTRIBUTE attrs[] = {
|
||||
{ CKA_ID, NULL_PTR, 0},
|
||||
{ CKA_VALUE, NULL_PTR, 0},
|
||||
{ CKA_LABEL, NULL_PTR, 0},
|
||||
{ CKA_CERTIFICATE_TYPE, NULL_PTR, 0},
|
||||
};
|
||||
CK_ULONG attrs_size = sizeof (attrs) / sizeof (CK_ATTRIBUTE);
|
||||
CK_ATTRIBUTE private_attrs[] = {
|
||||
{ CKA_SIGN, NULL, 0}, // CK_BBOOL
|
||||
{ CKA_DECRYPT, NULL, 0}, // CK_BBOOL
|
||||
{ CKA_KEY_TYPE, NULL, 0}, // CKK_
|
||||
{ CKA_ID, NULL, 0},
|
||||
{ CKA_ALWAYS_AUTHENTICATE, NULL, 0}, // CK_BBOOL
|
||||
{ CKA_UNWRAP, NULL, 0}, // CK_BBOOL
|
||||
{ CKA_DERIVE, NULL, 0}, // CK_BBOOL
|
||||
{ CKA_LABEL, NULL_PTR, 0},
|
||||
};
|
||||
CK_ULONG private_attrs_size = sizeof (private_attrs) / sizeof (CK_ATTRIBUTE);
|
||||
CK_ATTRIBUTE public_attrs[] = {
|
||||
{ CKA_VERIFY, NULL, 0}, // CK_BBOOL
|
||||
{ CKA_ENCRYPT, NULL, 0}, // CK_BBOOL
|
||||
{ CKA_KEY_TYPE, NULL, 0},
|
||||
{ CKA_ID, NULL, 0},
|
||||
{ CKA_MODULUS, NULL, 0},
|
||||
{ CKA_PUBLIC_EXPONENT, NULL, 0},
|
||||
{ CKA_EC_PARAMS, NULL, 0},
|
||||
{ CKA_EC_POINT, NULL, 0},
|
||||
{ CKA_WRAP, NULL, 0}, // CK_BBOOL
|
||||
{ CKA_DERIVE, NULL, 0}, // CK_BBOOL
|
||||
};
|
||||
CK_ULONG public_attrs_size = sizeof (public_attrs) / sizeof (CK_ATTRIBUTE);
|
||||
|
||||
debug_print("\nSearch for all certificates on the card");
|
||||
search_objects(objects, info, filter, filter_size,
|
||||
attrs, attrs_size, callback_certificates);
|
||||
|
||||
|
||||
/* do the same thing with private keys (collect handles based on the collected IDs) */
|
||||
debug_print("\nSearch for all private keys respective to the certificates");
|
||||
filter[0].pValue = &privateClass;
|
||||
// search for all and pair on the fly
|
||||
search_objects(objects, info, filter, filter_size,
|
||||
private_attrs, private_attrs_size, callback_private_keys);
|
||||
|
||||
debug_print("\nSearch for all public keys respective to the certificates");
|
||||
filter[0].pValue = &publicClass;
|
||||
search_objects(objects, info, filter, filter_size,
|
||||
public_attrs, public_attrs_size, callback_public_keys);
|
||||
}
|
||||
|
||||
void clean_all_objects(test_certs_t *objects) {
|
||||
unsigned int i;
|
||||
for (i = 0; i < objects->count; i++) {
|
||||
free(objects->data[i].key_id);
|
||||
free(objects->data[i].id_str);
|
||||
free(objects->data[i].label);
|
||||
X509_free(objects->data[i].x509);
|
||||
if (objects->data[i].key_type == CKK_RSA &&
|
||||
objects->data[i].key.rsa != NULL)
|
||||
RSA_free(objects->data[i].key.rsa);
|
||||
else if (objects->data[i].key.ec != NULL)
|
||||
EC_KEY_free(objects->data[i].key.ec);
|
||||
}
|
||||
free(objects->data);
|
||||
}
|
||||
|
||||
const char *get_mechanism_name(int mech_id)
|
||||
{
|
||||
switch (mech_id) {
|
||||
case CKM_RSA_PKCS:
|
||||
return "RSA_PKCS";
|
||||
case CKM_SHA1_RSA_PKCS:
|
||||
return "SHA1_RSA_PKCS";
|
||||
case CKM_SHA224_RSA_PKCS:
|
||||
return "SHA224_RSA_PKCS";
|
||||
case CKM_SHA256_RSA_PKCS:
|
||||
return "SHA256_RSA_PKCS";
|
||||
case CKM_SHA384_RSA_PKCS:
|
||||
return "SHA384_RSA_PKCS";
|
||||
case CKM_SHA512_RSA_PKCS:
|
||||
return "SHA512_RSA_PKCS";
|
||||
case CKM_RSA_X_509:
|
||||
return "RSA_X_509";
|
||||
case CKM_ECDSA:
|
||||
return "ECDSA";
|
||||
case CKM_ECDSA_SHA1:
|
||||
return "ECDSA_SHA1";
|
||||
case CKM_ECDSA_SHA256:
|
||||
return "ECDSA_SHA256";
|
||||
case CKM_ECDSA_SHA384:
|
||||
return "ECDSA_SHA384";
|
||||
case CKM_ECDSA_SHA512:
|
||||
return "ECDSA_SHA512";
|
||||
case CKM_ECDH1_DERIVE:
|
||||
return "ECDH1_DERIVE";
|
||||
case CKM_ECDH1_COFACTOR_DERIVE:
|
||||
return "ECDH1_COFACTOR_DERIVE";
|
||||
case CKM_EC_KEY_PAIR_GEN:
|
||||
return "EC_KEY_PAIR_GEN";
|
||||
case CKM_RSA_PKCS_KEY_PAIR_GEN:
|
||||
return "RSA_PKCS_KEY_PAIR_GEN";
|
||||
case CKM_MD5_RSA_PKCS:
|
||||
return "MD5_RSA_PKCS";
|
||||
case CKM_RIPEMD160_RSA_PKCS:
|
||||
return "RIPEMD160_RSA_PKCS";
|
||||
case CKM_RSA_PKCS_PSS:
|
||||
return "RSA_PKCS_PSS";
|
||||
case CKM_SHA1_RSA_PKCS_PSS:
|
||||
return "SHA1_RSA_PKCS_PSS";
|
||||
case CKM_SHA256_RSA_PKCS_PSS:
|
||||
return "SHA256_RSA_PKCS_PSS";
|
||||
case CKM_SHA384_RSA_PKCS_PSS:
|
||||
return "SHA384_RSA_PKCS_PSS";
|
||||
case CKM_SHA512_RSA_PKCS_PSS:
|
||||
return "SHA512_RSA_PKCS_PSS";
|
||||
case CKM_SHA_1_HMAC:
|
||||
return "SHA_1_HMAC";
|
||||
case CKM_SHA256_HMAC:
|
||||
return "SHA256_HMAC";
|
||||
case CKM_SHA384_HMAC:
|
||||
return "SHA384_HMAC";
|
||||
case CKM_SHA512_HMAC:
|
||||
return "SHA512_HMAC";
|
||||
case CKM_RSA_PKCS_OAEP:
|
||||
return "RSA_PKCS_OAEP";
|
||||
case CKM_SHA_1:
|
||||
return "SHA_1";
|
||||
case CKM_SHA224:
|
||||
return "SHA224";
|
||||
case CKM_SHA256:
|
||||
return "SHA256";
|
||||
case CKM_SHA384:
|
||||
return "SHA384";
|
||||
case CKM_SHA512:
|
||||
return "SHA512";
|
||||
default:
|
||||
sprintf(name_buffer, "0x%.8X", mech_id);
|
||||
return name_buffer;
|
||||
}
|
||||
}
|
||||
|
||||
const char *get_mgf_name(int mgf_id)
|
||||
{
|
||||
switch (mgf_id) {
|
||||
case CKG_MGF1_SHA1:
|
||||
return "MGF1_SHA_1";
|
||||
case CKG_MGF1_SHA224:
|
||||
return "MGF1_SHA224";
|
||||
case CKG_MGF1_SHA256:
|
||||
return "MGF1_SHA256";
|
||||
case CKG_MGF1_SHA384:
|
||||
return "MGF1_SHA384";
|
||||
case CKG_MGF1_SHA512:
|
||||
return "MGF1_SHA512";
|
||||
default:
|
||||
sprintf(name_buffer, "0x%.8X", mgf_id);
|
||||
return name_buffer;
|
||||
}
|
||||
}
|
||||
|
||||
const char *get_mechanism_flag_name(int mech_id)
|
||||
{
|
||||
switch (mech_id) {
|
||||
case CKF_HW:
|
||||
return "CKF_HW";
|
||||
case CKF_ENCRYPT:
|
||||
return "CKF_ENCRYPT";
|
||||
case CKF_DECRYPT:
|
||||
return "CKF_DECRYPT";
|
||||
case CKF_DIGEST:
|
||||
return "CKF_DIGEST";
|
||||
case CKF_SIGN:
|
||||
return "CKF_SIGN";
|
||||
case CKF_SIGN_RECOVER:
|
||||
return "CKF_SIGN_RECOVER";
|
||||
case CKF_VERIFY:
|
||||
return "CKF_VERIFY";
|
||||
case CKF_VERIFY_RECOVER:
|
||||
return "CKF_VERIFY_RECOVER";
|
||||
case CKF_GENERATE:
|
||||
return "CKF_GENERATE";
|
||||
case CKF_GENERATE_KEY_PAIR:
|
||||
return "CKF_GENERATE_KEY_PAIR";
|
||||
case CKF_WRAP:
|
||||
return "CKF_WRAP";
|
||||
case CKF_UNWRAP:
|
||||
return "CKF_UNWRAP";
|
||||
case CKF_DERIVE:
|
||||
return "CKF_DERIVE";
|
||||
case CKF_EC_F_P:
|
||||
return "CKF_EC_F_P";
|
||||
case CKF_EC_F_2M:
|
||||
return "CKF_EC_F_2M";
|
||||
case CKF_EC_NAMEDCURVE:
|
||||
return "CKF_EC_NAMEDCURVE";
|
||||
case CKF_EC_UNCOMPRESS:
|
||||
return "CKF_EC_UNCOMPRESS";
|
||||
case CKF_EC_COMPRESS:
|
||||
return "CKF_EC_COMPRESS";
|
||||
case CKF_EC_ECPARAMETERS:
|
||||
return "CKF_EC_ECPARAMETERS";
|
||||
default:
|
||||
sprintf(flag_buffer, "0x%.8X", mech_id);
|
||||
return flag_buffer;
|
||||
}
|
||||
}
|
||||
|
||||
char *convert_byte_string(unsigned char *id, unsigned long length)
|
||||
{
|
||||
unsigned int i;
|
||||
char *data = malloc(3 * length * sizeof(char) + 1);
|
||||
for (i = 0; i < length; i++)
|
||||
sprintf(&data[i*3], "%02X:", id[i]);
|
||||
data[length*3-1] = '\0';
|
||||
return data;
|
||||
}
|
||||
|
||||
void write_data_row(token_info_t *info, int cols, ...)
|
||||
{
|
||||
va_list ap;
|
||||
int i, intval, type;
|
||||
char *data;
|
||||
|
||||
cols = cols*2; /* shut GCC up */
|
||||
va_start(ap, cols);
|
||||
fprintf(info->log.fd, "\n\t[");
|
||||
for (i = 1; i <= cols; i+=2) {
|
||||
if (i > 1)
|
||||
fprintf(info->log.fd, ",");
|
||||
type = va_arg(ap, int);
|
||||
if (type == 'd') {
|
||||
intval = va_arg(ap, int);
|
||||
fprintf(info->log.fd, "\n\t\t\"%d\"", intval);
|
||||
} else if (type == 's') {
|
||||
data = va_arg(ap, char*);
|
||||
fprintf(info->log.fd, "\n\t\t\"%s\"", data);
|
||||
}
|
||||
}
|
||||
fprintf(info->log.fd, "\n\t]");
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
int is_pss_mechanism(CK_MECHANISM_TYPE mech)
|
||||
{
|
||||
return (mech == CKM_RSA_PKCS_PSS
|
||||
|| mech == CKM_SHA1_RSA_PKCS_PSS
|
||||
|| mech == CKM_SHA256_RSA_PKCS_PSS
|
||||
|| mech == CKM_SHA384_RSA_PKCS_PSS
|
||||
|| mech == CKM_SHA512_RSA_PKCS_PSS
|
||||
|| mech == CKM_SHA224_RSA_PKCS_PSS);
|
||||
}
|
|
@ -0,0 +1,127 @@
|
|||
/*
|
||||
* p11test_case_common.h: Functions shared between test cases.
|
||||
*
|
||||
* Copyright (C) 2016, 2017 Red Hat, Inc.
|
||||
*
|
||||
* Author: Jakub Jelen <jjelen@redhat.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef P11TEST_CASE_COMMON_H
|
||||
#define P11TEST_CASE_COMMON_H
|
||||
|
||||
#include <openssl/x509.h>
|
||||
#include <openssl/rsa.h>
|
||||
#include <openssl/err.h>
|
||||
#include "p11test_common.h"
|
||||
|
||||
typedef struct {
|
||||
unsigned char *key_id;
|
||||
CK_ULONG key_id_size;
|
||||
char *id_str;
|
||||
X509 *x509;
|
||||
int type;
|
||||
union {
|
||||
RSA *rsa;
|
||||
EC_KEY *ec;
|
||||
} key;
|
||||
CK_OBJECT_HANDLE private_handle;
|
||||
CK_OBJECT_HANDLE public_handle;
|
||||
CK_BBOOL sign;
|
||||
CK_BBOOL decrypt;
|
||||
CK_BBOOL verify;
|
||||
CK_BBOOL encrypt;
|
||||
CK_BBOOL wrap;
|
||||
CK_BBOOL unwrap;
|
||||
CK_BBOOL derive_priv;
|
||||
CK_BBOOL derive_pub;
|
||||
CK_KEY_TYPE key_type;
|
||||
CK_BBOOL always_auth;
|
||||
char *label;
|
||||
CK_ULONG bits;
|
||||
int verify_public;
|
||||
test_mech_t mechs[MAX_MECHS];
|
||||
int num_mechs;
|
||||
} test_cert_t;
|
||||
|
||||
typedef struct {
|
||||
unsigned int count;
|
||||
test_cert_t *data;
|
||||
} test_certs_t;
|
||||
|
||||
void always_authenticate(test_cert_t *o, token_info_t *info);
|
||||
|
||||
int search_objects(test_certs_t *objects, token_info_t *info,
|
||||
CK_ATTRIBUTE filter[], CK_LONG filter_size, CK_ATTRIBUTE template[], CK_LONG template_size,
|
||||
int (*callback)(test_certs_t *, CK_ATTRIBUTE[], unsigned int, CK_OBJECT_HANDLE));
|
||||
void search_for_all_objects(test_certs_t *objects, token_info_t *info);
|
||||
void clean_all_objects(test_certs_t *objects);
|
||||
|
||||
const char *get_mechanism_name(int mech_id);
|
||||
const char *get_mgf_name(int mech_id);
|
||||
const char *get_mechanism_flag_name(int flag_id);
|
||||
char *convert_byte_string(unsigned char *id, unsigned long length);
|
||||
|
||||
int is_pss_mechanism(CK_MECHANISM_TYPE mech);
|
||||
|
||||
// TODO sanitize inputs
|
||||
|
||||
#define P11TEST_START(info) if (info->log.fd) { \
|
||||
if (info->log.in_test) \
|
||||
fprintf(info->log.fd, "\n\t\"result\": \"unknown\"\n}"); \
|
||||
fprintf(info->log.fd, "%s\n{\n\t\"test_id\": \"%s\"", \
|
||||
info->log.first ? "" : ",", __func__); \
|
||||
info->log.in_test = 1; \
|
||||
info->log.first = 0; \
|
||||
info->log.in_data = 0; \
|
||||
} else {}
|
||||
|
||||
#define _P11TEST_FINALIZE(info, result) if (info->log.fd) {\
|
||||
if (info->log.in_data) {\
|
||||
fprintf(info->log.fd, "]"); \
|
||||
} \
|
||||
if (info->log.fd && info->log.in_test) { \
|
||||
fprintf(info->log.fd, ",\n\t\"result\": \"" result "\"\n}"); \
|
||||
info->log.in_test = 0; \
|
||||
} \
|
||||
} else {}
|
||||
|
||||
#define P11TEST_SKIP(info) do { _P11TEST_FINALIZE(info, "skip") skip(); } while(0);
|
||||
|
||||
#define P11TEST_PASS(info) do { _P11TEST_FINALIZE(info, "pass") } while(0);
|
||||
|
||||
#define P11TEST_FAIL(info, msg, ...) do { \
|
||||
if (info->log.fd && info->log.in_test) { \
|
||||
fprintf(info->log.fd, ",\n\t\"fail_reason\": \"" msg "\"", ##__VA_ARGS__); \
|
||||
} \
|
||||
_P11TEST_FINALIZE(info, "fail") \
|
||||
fail_msg(msg, ##__VA_ARGS__); \
|
||||
} while (0);
|
||||
|
||||
#define P11TEST_DATA_ROW(info, cols, ...) if (info->log.fd) { \
|
||||
if (info->log.in_test == 0) \
|
||||
fail_msg("Can't add data outside of the test");\
|
||||
if (info->log.in_data == 0) {\
|
||||
fprintf(info->log.fd, ",\n\t\"data\": [");\
|
||||
info->log.in_data = 1;\
|
||||
} else { \
|
||||
fprintf(info->log.fd, ",");\
|
||||
} \
|
||||
write_data_row(info, cols, ##__VA_ARGS__); \
|
||||
} else {}
|
||||
|
||||
void write_data_row(token_info_t *info, int cols, ...);
|
||||
|
||||
#endif /* P11TEST_CASE_COMMON_H */
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* p11test_case_ec_sign.c: Test different data lengths for EC signatures
|
||||
*
|
||||
* Copyright (C) 2016, 2017 Red Hat, Inc.
|
||||
*
|
||||
* Author: Jakub Jelen <jjelen@redhat.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "p11test_case_ec_sign.h"
|
||||
|
||||
void ec_sign_size_test(void **state) {
|
||||
unsigned int i;
|
||||
int min, max, j, l, errors = 0, rv;
|
||||
token_info_t *info = (token_info_t *) *state;
|
||||
|
||||
P11TEST_START(info);
|
||||
if (token.num_ec_mechs == 0 ) {
|
||||
fprintf(stderr, "Token does not support any ECC mechanisms. Skipping.\n");
|
||||
skip();
|
||||
}
|
||||
|
||||
test_certs_t objects;
|
||||
objects.count = 0;
|
||||
objects.data = NULL;
|
||||
|
||||
search_for_all_objects(&objects, info);
|
||||
|
||||
debug_print("\nCheck functionality of Sign&Verify on different data lengths");
|
||||
for (i = 0; i < objects.count; i++) {
|
||||
if (objects.data[i].key_type != CKK_EC)
|
||||
continue;
|
||||
// sanity: Test all mechanisms
|
||||
min = (objects.data[i].bits + 7) / 8 - 2;
|
||||
max = (objects.data[i].bits + 7) / 8 + 2;
|
||||
if (objects.data[i].sign && objects.data[i].verify) {
|
||||
for (j = 0; j < objects.data[i].num_mechs; j++) {
|
||||
for (l = min; l < max; l++) {
|
||||
rv = sign_verify_test(&(objects.data[i]), info,
|
||||
&(objects.data[i].mechs[j]), l, 0);
|
||||
if (rv == -1)
|
||||
errors++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
clean_all_objects(&objects);
|
||||
|
||||
if (errors > 0)
|
||||
P11TEST_FAIL(info, "Some signatures were not verified successfully. Please review the log");
|
||||
P11TEST_PASS(info);
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* p11test_case_ec_sign.h: Test different data lengths for EC signatures
|
||||
*
|
||||
* Copyright (C) 2016, 2017 Red Hat, Inc.
|
||||
*
|
||||
* Author: Jakub Jelen <jjelen@redhat.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "p11test_case_common.h"
|
||||
#include "p11test_case_readonly.h"
|
||||
|
||||
void ec_sign_size_test(void **state);
|
|
@ -0,0 +1,138 @@
|
|||
/*
|
||||
* p11test_case_mechs.c: Check mechanisms supported by token
|
||||
*
|
||||
* Copyright (C) 2016, 2017 Red Hat, Inc.
|
||||
*
|
||||
* Author: Jakub Jelen <jjelen@redhat.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "p11test_case_mechs.h"
|
||||
|
||||
void supported_mechanisms_test(void **state) {
|
||||
token_info_t *info = (token_info_t *) *state;
|
||||
CK_FUNCTION_LIST_PTR function_pointer = info->function_pointer;
|
||||
|
||||
CK_RV rv;
|
||||
CK_ULONG mechanism_count, i;
|
||||
CK_MECHANISM_TYPE_PTR mechanism_list;
|
||||
CK_MECHANISM_INFO_PTR mechanism_info;
|
||||
CK_FLAGS j;
|
||||
test_mech_t *mech = NULL;
|
||||
|
||||
P11TEST_START(info);
|
||||
rv = function_pointer->C_GetMechanismList(info->slot_id, NULL_PTR,
|
||||
&mechanism_count);
|
||||
if ((rv == CKR_OK) && (mechanism_count > 0)) {
|
||||
mechanism_list = (CK_MECHANISM_TYPE_PTR)
|
||||
malloc(mechanism_count * sizeof(CK_MECHANISM_TYPE));
|
||||
rv = function_pointer->C_GetMechanismList(info->slot_id,
|
||||
mechanism_list, &mechanism_count);
|
||||
if (rv != CKR_OK) {
|
||||
free(mechanism_list);
|
||||
function_pointer->C_Finalize(NULL_PTR);
|
||||
P11TEST_FAIL(info, "Could not get mechanism list!");
|
||||
}
|
||||
|
||||
mechanism_info = (CK_MECHANISM_INFO_PTR)
|
||||
malloc(mechanism_count * sizeof(CK_MECHANISM_INFO));
|
||||
if (mechanism_info == NULL)
|
||||
P11TEST_FAIL(info, "Couldn't malloc()");
|
||||
|
||||
for (i = 0; i < mechanism_count; i++) {
|
||||
CK_MECHANISM_TYPE mechanism_type = mechanism_list[i];
|
||||
rv = function_pointer->C_GetMechanismInfo(info->slot_id,
|
||||
mechanism_type, &mechanism_info[i]);
|
||||
if (rv != CKR_OK)
|
||||
continue;
|
||||
|
||||
/* store mechanisms list for later tests */
|
||||
|
||||
/* List all known RSA mechanisms */
|
||||
if (mechanism_list[i] == CKM_RSA_X_509
|
||||
|| mechanism_list[i] == CKM_RSA_PKCS
|
||||
|| mechanism_list[i] == CKM_MD5_RSA_PKCS
|
||||
|| mechanism_list[i] == CKM_RIPEMD160_RSA_PKCS
|
||||
|| mechanism_list[i] == CKM_SHA1_RSA_PKCS
|
||||
|| mechanism_list[i] == CKM_SHA224_RSA_PKCS
|
||||
|| mechanism_list[i] == CKM_SHA256_RSA_PKCS
|
||||
|| mechanism_list[i] == CKM_SHA384_RSA_PKCS
|
||||
|| mechanism_list[i] == CKM_SHA512_RSA_PKCS
|
||||
|| mechanism_list[i] == CKM_RSA_PKCS_PSS
|
||||
|| mechanism_list[i] == CKM_SHA1_RSA_PKCS_PSS
|
||||
|| mechanism_list[i] == CKM_SHA256_RSA_PKCS_PSS
|
||||
|| mechanism_list[i] == CKM_SHA384_RSA_PKCS_PSS
|
||||
|| mechanism_list[i] == CKM_SHA512_RSA_PKCS_PSS
|
||||
|| mechanism_list[i] == CKM_RSA_PKCS_OAEP) {
|
||||
if (token.num_rsa_mechs < MAX_MECHS) {
|
||||
mech = &token.rsa_mechs[token.num_rsa_mechs++];
|
||||
mech->mech = mechanism_list[i];
|
||||
mech->usage_flags = mechanism_info[i].flags;
|
||||
} else
|
||||
P11TEST_FAIL(info, "Too many RSA mechanisms (%d)", MAX_MECHS);
|
||||
}
|
||||
|
||||
/* We list all known EC mechanisms */
|
||||
if (mechanism_list[i] == CKM_ECDSA
|
||||
|| mechanism_list[i] == CKM_ECDSA_SHA1
|
||||
|| mechanism_list[i] == CKM_ECDSA_SHA256
|
||||
|| mechanism_list[i] == CKM_ECDSA_SHA384
|
||||
|| mechanism_list[i] == CKM_ECDSA_SHA512) {
|
||||
if (token.num_ec_mechs < MAX_MECHS) {
|
||||
mech = &token.ec_mechs[token.num_ec_mechs++];
|
||||
mech->mech = mechanism_list[i];
|
||||
mech->usage_flags = mechanism_info[i].flags;
|
||||
} else
|
||||
P11TEST_FAIL(info, "Too many EC mechanisms (%d)", MAX_MECHS);
|
||||
}
|
||||
if ((mechanism_info[i].flags & CKF_GENERATE_KEY_PAIR) != 0) {
|
||||
if (token.num_keygen_mechs < MAX_MECHS) {
|
||||
mech = &token.keygen_mechs[token.num_keygen_mechs++];
|
||||
mech->mech = mechanism_list[i];
|
||||
mech->usage_flags = mechanism_info[i].flags;
|
||||
} else
|
||||
P11TEST_FAIL(info, "Too many KEYGEN mechanisms (%d)", MAX_MECHS);
|
||||
}
|
||||
}
|
||||
|
||||
printf("[ MECHANISM ] [ KEY SIZE ] [ FLAGS ]\n");
|
||||
printf("[ CKM_* ] [ MIN][ MAX] [ ]\n");
|
||||
P11TEST_DATA_ROW(info, 4,
|
||||
's', "MECHANISM",
|
||||
's', "MIN KEY",
|
||||
's', "MAX KEY",
|
||||
's', "FLAGS");
|
||||
for (i = 0; i < mechanism_count; i++) {
|
||||
printf("[%-21s] [%4lu][%4lu] [%10s]",
|
||||
get_mechanism_name(mechanism_list[i]),
|
||||
mechanism_info[i].ulMinKeySize,
|
||||
mechanism_info[i].ulMaxKeySize,
|
||||
get_mechanism_flag_name(mechanism_info[i].flags));
|
||||
P11TEST_DATA_ROW(info, 4,
|
||||
's', get_mechanism_name(mechanism_list[i]),
|
||||
'd', mechanism_info[i].ulMinKeySize,
|
||||
'd', mechanism_info[i].ulMaxKeySize,
|
||||
's', get_mechanism_flag_name(mechanism_info[i].flags));
|
||||
for (j = 1; j <= CKF_EC_COMPRESS; j = j<<1)
|
||||
if ((mechanism_info[i].flags & j) != 0)
|
||||
printf(" %s", get_mechanism_flag_name(j));
|
||||
printf("\n");
|
||||
}
|
||||
free(mechanism_list);
|
||||
free(mechanism_info);
|
||||
}
|
||||
P11TEST_PASS(info);
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* p11test_case_mechs.h: Check mechanisms supported by token
|
||||
*
|
||||
* Copyright (C) 2016, 2017 Red Hat, Inc.
|
||||
*
|
||||
* Author: Jakub Jelen <jjelen@redhat.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "p11test_case_common.h"
|
||||
|
||||
void supported_mechanisms_test(void **state);
|
|
@ -0,0 +1,107 @@
|
|||
/*
|
||||
* p11test_case_multipart.c: Multipart Sign & Verify tests (RSA only)
|
||||
*
|
||||
* Copyright (C) 2016, 2017 Red Hat, Inc.
|
||||
*
|
||||
* Author: Jakub Jelen <jjelen@redhat.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "p11test_case_multipart.h"
|
||||
|
||||
void multipart_tests(void **state) {
|
||||
|
||||
token_info_t *info = (token_info_t *) *state;
|
||||
unsigned int i;
|
||||
int used, j;
|
||||
test_certs_t objects;
|
||||
|
||||
objects.count = 0;
|
||||
objects.data = NULL;
|
||||
|
||||
P11TEST_START(info);
|
||||
search_for_all_objects(&objects, info);
|
||||
|
||||
debug_print("\nCheck functionality of Multipart Sign&Verify and/or Encrypt&Decrypt");
|
||||
for (i = 0; i < objects.count; i++) {
|
||||
if (objects.data[i].type == EVP_PK_EC) {
|
||||
debug_print(" [ SKIP %s ] EC keys do not support multi-part operations",
|
||||
objects.data[i].id_str);
|
||||
continue;
|
||||
}
|
||||
used = 0;
|
||||
/* do the Sign&Verify and/or Encrypt&Decrypt */
|
||||
/* XXX some keys do not have appropriate flags, but we can use them
|
||||
* or vice versa */
|
||||
//if (objects.data[i].sign && objects.data[i].verify)
|
||||
for (j = 0; j < objects.data[i].num_mechs; j++)
|
||||
used |= sign_verify_test(&(objects.data[i]), info,
|
||||
&(objects.data[i].mechs[j]), 32, 1);
|
||||
|
||||
if (!used) {
|
||||
debug_print(" [ WARN %s ] Private key with unknown purpose T:%02lX",
|
||||
objects.data[i].id_str, objects.data[i].key_type);
|
||||
}
|
||||
}
|
||||
|
||||
if (objects.count == 0) {
|
||||
printf(" [WARN] No objects to display\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* print summary */
|
||||
printf("[KEY ID] [TYPE] [ SIZE ] [PUBLIC] [SIGN&VERIFY] [LABEL]\n");
|
||||
P11TEST_DATA_ROW(info, 3,
|
||||
's', "KEY ID",
|
||||
's', "MECHANISM",
|
||||
's', "MULTIPART SIGN&VERIFY WORKS");
|
||||
for (i = 0; i < objects.count; i++) {
|
||||
if (objects.data[i].type == EVP_PK_EC)
|
||||
continue;
|
||||
printf("[%-6s] [%s] [%6lu] [ %s ] [%s%s] [%s]\n",
|
||||
objects.data[i].id_str,
|
||||
objects.data[i].key_type == CKK_RSA ? "RSA " :
|
||||
objects.data[i].key_type == CKK_EC ? " EC " : " ?? ",
|
||||
objects.data[i].bits,
|
||||
objects.data[i].verify_public == 1 ? " ./ " : " ",
|
||||
objects.data[i].sign ? "[./] " : "[ ] ",
|
||||
objects.data[i].verify ? " [./] " : " [ ] ",
|
||||
objects.data[i].label);
|
||||
for (j = 0; j < objects.data[i].num_mechs; j++) {
|
||||
test_mech_t *mech = &objects.data[i].mechs[j];
|
||||
if ((mech->usage_flags & CKF_SIGN) == 0) {
|
||||
/* not applicable mechanisms are skipped */
|
||||
continue;
|
||||
}
|
||||
printf(" [ %-20s ] [ %s ]\n",
|
||||
get_mechanism_name(mech->mech),
|
||||
mech->result_flags & FLAGS_SIGN_ANY ? "[./]" : " ");
|
||||
if ((mech->result_flags & FLAGS_SIGN_ANY) == 0)
|
||||
continue; /* do not export unknown and non-working algorithms */
|
||||
P11TEST_DATA_ROW(info, 3,
|
||||
's', objects.data[i].id_str,
|
||||
's', get_mechanism_name(mech->mech),
|
||||
's', mech->result_flags & FLAGS_SIGN_ANY ? "YES" : "");
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
printf(" Public == Cert ------------^ ^ ^ ^\n");
|
||||
printf(" Sign Attribute --------------------' | |\n");
|
||||
printf(" Sign&Verify functionality ------------' |\n");
|
||||
printf(" Verify Attribute ------------------------'\n");
|
||||
|
||||
clean_all_objects(&objects);
|
||||
P11TEST_PASS(info);
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* p11test_case_multipart.h: Multipart Sign & Verify tests (RSA only)
|
||||
*
|
||||
* Copyright (C) 2016, 2017 Red Hat, Inc.
|
||||
*
|
||||
* Author: Jakub Jelen <jjelen@redhat.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "p11test_case_common.h"
|
||||
#include "p11test_case_readonly.h"
|
||||
|
||||
void multipart_tests(void **state);
|
||||
|
|
@ -0,0 +1,874 @@
|
|||
/*
|
||||
* p11test_case_pss_oaep.c: RSA-PSS and RSA-OAEP tests
|
||||
*
|
||||
* Copyright (C) 2017 Red Hat, Inc.
|
||||
*
|
||||
* Author: Jakub Jelen <jjelen@redhat.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "p11test_case_pss_oaep.h"
|
||||
#include "libopensc/internal.h"
|
||||
|
||||
#include <openssl/sha.h>
|
||||
#include <openssl/evp.h>
|
||||
|
||||
#define SHORT_MESSAGE_TO_SIGN "Simple message for signing & verifying. It needs to be little bit longer to fit also longer keys and allow the truncation.\n"
|
||||
#define BUFFER_SIZE 4096
|
||||
|
||||
const unsigned char *global_message = (unsigned char *) SHORT_MESSAGE_TO_SIGN;
|
||||
size_t global_message_length = sizeof(SHORT_MESSAGE_TO_SIGN);
|
||||
|
||||
const CK_MECHANISM_TYPE *
|
||||
get_oaep_mechanism_hashes(CK_MECHANISM_TYPE mech)
|
||||
{
|
||||
static CK_MECHANISM_TYPE h[6];
|
||||
|
||||
switch (mech) {
|
||||
case CKM_RSA_PKCS_OAEP:
|
||||
h[0] = CKM_SHA_1;
|
||||
h[1] = CKM_SHA224;
|
||||
h[2] = CKM_SHA256;
|
||||
h[3] = CKM_SHA384;
|
||||
h[4] = CKM_SHA512;
|
||||
h[5] = -1;
|
||||
break;
|
||||
|
||||
default:
|
||||
h[0] = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
return h;
|
||||
}
|
||||
const CK_MECHANISM_TYPE *
|
||||
get_pss_mechanism_hashes(CK_MECHANISM_TYPE mech)
|
||||
{
|
||||
static CK_MECHANISM_TYPE h[6];
|
||||
|
||||
switch (mech) {
|
||||
case CKM_RSA_PKCS_PSS:
|
||||
h[0] = CKM_SHA_1;
|
||||
h[1] = CKM_SHA224;
|
||||
h[2] = CKM_SHA256;
|
||||
h[3] = CKM_SHA384;
|
||||
h[4] = CKM_SHA512;
|
||||
h[5] = -1;
|
||||
break;
|
||||
|
||||
case CKM_SHA1_RSA_PKCS_PSS:
|
||||
h[0] = CKM_SHA_1;
|
||||
h[1] = -1;
|
||||
break;
|
||||
|
||||
case CKM_SHA224_RSA_PKCS_PSS:
|
||||
h[0] = CKM_SHA224;
|
||||
h[1] = -1;
|
||||
break;
|
||||
|
||||
case CKM_SHA256_RSA_PKCS_PSS:
|
||||
h[0] = CKM_SHA256;
|
||||
h[1] = -1;
|
||||
break;
|
||||
|
||||
case CKM_SHA384_RSA_PKCS_PSS:
|
||||
h[0] = CKM_SHA384;
|
||||
h[1] = -1;
|
||||
break;
|
||||
|
||||
case CKM_SHA512_RSA_PKCS_PSS:
|
||||
h[0] = CKM_SHA512;
|
||||
h[1] = -1;
|
||||
break;
|
||||
|
||||
default:
|
||||
h[0] = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
const CK_MECHANISM_TYPE *
|
||||
get_mechanism_hashes(CK_MECHANISM_TYPE mech)
|
||||
{
|
||||
if (mech == CKM_RSA_PKCS_OAEP)
|
||||
return get_oaep_mechanism_hashes(mech);
|
||||
else
|
||||
return get_pss_mechanism_hashes(mech);
|
||||
}
|
||||
|
||||
const CK_RSA_PKCS_MGF_TYPE *
|
||||
get_mgfs(void)
|
||||
{
|
||||
static CK_RSA_PKCS_MGF_TYPE h[6];
|
||||
h[0] = CKG_MGF1_SHA1;
|
||||
h[1] = CKG_MGF1_SHA224;
|
||||
h[2] = CKG_MGF1_SHA256;
|
||||
h[3] = CKG_MGF1_SHA384;
|
||||
h[4] = CKG_MGF1_SHA512;
|
||||
h[5] = -1;
|
||||
return h;
|
||||
}
|
||||
|
||||
const EVP_MD *mgf_cryptoki_to_ossl(CK_RSA_PKCS_MGF_TYPE mgf)
|
||||
{
|
||||
switch (mgf) {
|
||||
case CKG_MGF1_SHA224:
|
||||
return EVP_sha224();
|
||||
|
||||
case CKG_MGF1_SHA256:
|
||||
return EVP_sha256();
|
||||
|
||||
case CKG_MGF1_SHA384:
|
||||
return EVP_sha384();
|
||||
|
||||
case CKG_MGF1_SHA512:
|
||||
return EVP_sha512();
|
||||
|
||||
case CKG_MGF1_SHA1:
|
||||
default:
|
||||
return EVP_sha1();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
const EVP_MD *md_cryptoki_to_ossl(CK_MECHANISM_TYPE hash)
|
||||
{
|
||||
/* Digest mechanisms */
|
||||
switch (hash) {
|
||||
case CKM_SHA224:
|
||||
return EVP_sha224();
|
||||
|
||||
case CKM_SHA256:
|
||||
return EVP_sha256();
|
||||
|
||||
case CKM_SHA384:
|
||||
return EVP_sha384();
|
||||
|
||||
case CKM_SHA512:
|
||||
return EVP_sha512();
|
||||
|
||||
case CKM_SHA_1:
|
||||
default:
|
||||
return EVP_sha1();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
size_t get_hash_length(CK_MECHANISM_TYPE mech)
|
||||
{
|
||||
switch (mech) {
|
||||
case CKM_SHA224:
|
||||
return SHA224_DIGEST_LENGTH;
|
||||
case CKM_SHA256:
|
||||
return SHA256_DIGEST_LENGTH;
|
||||
case CKM_SHA384:
|
||||
return SHA384_DIGEST_LENGTH;
|
||||
case CKM_SHA512:
|
||||
return SHA512_DIGEST_LENGTH;
|
||||
default:
|
||||
case CKM_SHA_1:
|
||||
return SHA_DIGEST_LENGTH;
|
||||
}
|
||||
}
|
||||
|
||||
CK_BYTE *hash_message(const CK_BYTE *message, size_t message_length,
|
||||
CK_MECHANISM_TYPE hash)
|
||||
{
|
||||
switch (hash) {
|
||||
case CKM_SHA224:
|
||||
return SHA224(message, message_length, NULL);
|
||||
|
||||
case CKM_SHA256:
|
||||
return SHA256(message, message_length, NULL);
|
||||
|
||||
case CKM_SHA384:
|
||||
return SHA384(message, message_length, NULL);
|
||||
|
||||
case CKM_SHA512:
|
||||
return SHA512(message, message_length, NULL);
|
||||
|
||||
case CKM_SHA_1:
|
||||
default:
|
||||
return SHA1(message, message_length, NULL);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
int oaep_encrypt_message_openssl(test_cert_t *o, token_info_t *info, CK_BYTE *message,
|
||||
CK_ULONG message_length, test_mech_t *mech, unsigned char **enc_message)
|
||||
{
|
||||
size_t enc_length = 0;
|
||||
CK_RV rv = -1;
|
||||
EVP_PKEY_CTX *pctx = NULL;
|
||||
const EVP_MD *md = EVP_md_null();
|
||||
const EVP_MD *mgf1_md = EVP_md_null();
|
||||
EVP_PKEY *key = NULL;
|
||||
|
||||
md = md_cryptoki_to_ossl(mech->hash);
|
||||
mgf1_md = mgf_cryptoki_to_ossl(mech->mgf);
|
||||
|
||||
if ((key = EVP_PKEY_new()) == NULL
|
||||
|| RSA_up_ref(o->key.rsa) < 1
|
||||
|| EVP_PKEY_set1_RSA(key, o->key.rsa) != 1) {
|
||||
fprintf(stderr, " [ ERROR %s ] Failed to initialize EVP_PKEY. Error: %s\n",
|
||||
o->id_str, ERR_error_string(ERR_peek_last_error(), NULL));
|
||||
goto out;
|
||||
}
|
||||
|
||||
if ((pctx = EVP_PKEY_CTX_new(key, NULL)) == NULL
|
||||
|| EVP_PKEY_encrypt_init(pctx) != 1
|
||||
|| EVP_PKEY_CTX_set_rsa_padding(pctx, RSA_PKCS1_OAEP_PADDING) != 1
|
||||
|| EVP_PKEY_CTX_set_rsa_oaep_md(pctx, md) != 1
|
||||
|| EVP_PKEY_CTX_set_rsa_mgf1_md(pctx, mgf1_md) != 1) {
|
||||
fprintf(stderr, " [ ERROR %s ] Failed to initialize EVP_PKEY_CTX. Error: %s\n",
|
||||
o->id_str, ERR_error_string(ERR_peek_last_error(), NULL));
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (EVP_PKEY_encrypt(pctx, NULL, &enc_length, message, message_length) <= 0) {
|
||||
fprintf(stderr, " [ ERROR %s ] Failed get signature length. Error: %s\n",
|
||||
o->id_str, ERR_error_string(ERR_peek_last_error(), NULL));
|
||||
goto out;
|
||||
}
|
||||
|
||||
*enc_message = OPENSSL_malloc(enc_length);
|
||||
|
||||
rv = EVP_PKEY_encrypt(pctx, *enc_message, &enc_length, message, message_length);
|
||||
if (rv <= 0) {
|
||||
fprintf(stderr, " [ ERROR %s ] Signature is not valid. Error: %s\n",
|
||||
o->id_str, ERR_error_string(ERR_peek_last_error(), NULL));
|
||||
}
|
||||
out:
|
||||
EVP_PKEY_CTX_free(pctx);
|
||||
EVP_PKEY_free(key);
|
||||
return enc_length;
|
||||
}
|
||||
|
||||
void fill_oaep_params(CK_RSA_PKCS_OAEP_PARAMS *oaep_params,
|
||||
test_mech_t *mech)
|
||||
{
|
||||
oaep_params->hashAlg = mech->hash;
|
||||
oaep_params->mgf = mech->mgf;
|
||||
oaep_params->source = CKZ_DATA_SPECIFIED;
|
||||
oaep_params->pSourceData = NULL;
|
||||
oaep_params->ulSourceDataLen = 0;
|
||||
|
||||
}
|
||||
|
||||
int oaep_encrypt_message(test_cert_t *o, token_info_t *info, CK_BYTE *message,
|
||||
CK_ULONG message_length, test_mech_t *mech, unsigned char **enc_message)
|
||||
{
|
||||
CK_RV rv;
|
||||
CK_FUNCTION_LIST_PTR fp = info->function_pointer;
|
||||
CK_MECHANISM enc_mechanism = { mech->mech, NULL_PTR, 0 };
|
||||
CK_RSA_PKCS_OAEP_PARAMS oaep_params;
|
||||
CK_ULONG enc_message_length;
|
||||
static int encrypt_support = 1;
|
||||
|
||||
fill_oaep_params(&oaep_params, mech);
|
||||
enc_mechanism.pParameter = &oaep_params;
|
||||
enc_mechanism.ulParameterLen = sizeof(oaep_params);
|
||||
|
||||
if (!encrypt_support)
|
||||
goto openssl_encrypt;
|
||||
|
||||
rv = fp->C_EncryptInit(info->session_handle, &enc_mechanism,
|
||||
o->public_handle);
|
||||
if (rv != CKR_OK) {
|
||||
debug_print(" C_EncryptInit: rv = 0x%.8lX", rv);
|
||||
encrypt_support = 0; /* avoid trying over and over again */
|
||||
goto openssl_encrypt;
|
||||
}
|
||||
|
||||
/* get the expected length */
|
||||
rv = fp->C_Encrypt(info->session_handle, message, message_length,
|
||||
NULL, &enc_message_length);
|
||||
if (rv != CKR_OK) {
|
||||
debug_print(" C_Encrypt: rv = 0x%.8lX", rv);
|
||||
goto openssl_encrypt;
|
||||
}
|
||||
*enc_message = malloc(enc_message_length);
|
||||
if (*enc_message == NULL) {
|
||||
debug_print("malloc returned null");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Do the actual encryption with allocated buffer */
|
||||
rv = fp->C_Encrypt(info->session_handle, message, message_length,
|
||||
*enc_message, &enc_message_length);
|
||||
if (rv == CKR_OK) {
|
||||
mech->result_flags |= FLAGS_DECRYPT_OPENSSL;
|
||||
return enc_message_length;
|
||||
}
|
||||
debug_print(" C_Encrypt: rv = 0x%.8lX", rv);
|
||||
|
||||
openssl_encrypt:
|
||||
debug_print(" [ KEY %s ] Falling back to openssl encryption", o->id_str);
|
||||
return oaep_encrypt_message_openssl(o, info, message, message_length, mech,
|
||||
enc_message);
|
||||
}
|
||||
|
||||
int oaep_decrypt_message(test_cert_t *o, token_info_t *info, CK_BYTE *enc_message,
|
||||
CK_ULONG enc_message_length, test_mech_t *mech, unsigned char **dec_message)
|
||||
{
|
||||
CK_RV rv;
|
||||
CK_FUNCTION_LIST_PTR fp = info->function_pointer;
|
||||
CK_MECHANISM dec_mechanism = { mech->mech, NULL_PTR, 0 };
|
||||
CK_RSA_PKCS_OAEP_PARAMS oaep_params;
|
||||
CK_ULONG dec_message_length = BUFFER_SIZE;
|
||||
|
||||
fill_oaep_params(&oaep_params, mech);
|
||||
dec_mechanism.pParameter = &oaep_params;
|
||||
dec_mechanism.ulParameterLen = sizeof(oaep_params);
|
||||
|
||||
rv = fp->C_DecryptInit(info->session_handle, &dec_mechanism,
|
||||
o->private_handle);
|
||||
if (rv == CKR_KEY_TYPE_INCONSISTENT) {
|
||||
debug_print(" [SKIP %s ] Not allowed to decrypt with this key?", o->id_str);
|
||||
return 0;
|
||||
} else if (rv != CKR_OK) {
|
||||
debug_print(" C_DecryptInit: rv = 0x%.8lX\n", rv);
|
||||
return -1;
|
||||
}
|
||||
|
||||
*dec_message = malloc(dec_message_length);
|
||||
|
||||
always_authenticate(o, info);
|
||||
|
||||
rv = fp->C_Decrypt(info->session_handle, enc_message,
|
||||
enc_message_length, *dec_message, &dec_message_length);
|
||||
if (rv != CKR_OK) {
|
||||
free(*dec_message);
|
||||
debug_print(" C_Decrypt: rv = 0x%.8lX\n", rv);
|
||||
return -1;
|
||||
}
|
||||
return (int) dec_message_length;
|
||||
}
|
||||
|
||||
/* Perform encryption and decryption of a message using private key referenced
|
||||
* in the o object with mechanism defined by mech.
|
||||
*
|
||||
* NONE of the reasonable mechanisms support encryption/decryption
|
||||
*
|
||||
* Returns
|
||||
* * 1 for successful Encrypt&Decrypt sequence
|
||||
* * 0 for skipped test (unsupported mechanism, key, ...)
|
||||
* * -1 otherwise.
|
||||
* Serious errors terminate the execution.
|
||||
*/
|
||||
int oaep_encrypt_decrypt_test(test_cert_t *o, token_info_t *info, test_mech_t *mech)
|
||||
{
|
||||
CK_BYTE *message = (CK_BYTE *) SHORT_MESSAGE_TO_SIGN;
|
||||
CK_BYTE *dec_message = NULL;
|
||||
int dec_message_length = 0;
|
||||
int message_length = 16;
|
||||
unsigned char *enc_message;
|
||||
int enc_message_length, rv;
|
||||
|
||||
if (o->private_handle == CK_INVALID_HANDLE) {
|
||||
debug_print(" [SKIP %s ] Missing private key", o->id_str);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (o->type != EVP_PK_RSA) {
|
||||
debug_print(" [ KEY %s ] Skip non-RSA key for encryption", o->id_str);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (mech->mech != CKM_RSA_PKCS_OAEP) {
|
||||
mech->usage_flags &= ~CKF_DECRYPT;
|
||||
debug_print(" [SKIP %s ] non RSA-OAEP mechanism", o->id_str);
|
||||
return 0;
|
||||
}
|
||||
|
||||
message_length = MIN((int)global_message_length,
|
||||
(int)((o->bits+7)/8 - 2*get_hash_length(mech->hash) - 2));
|
||||
|
||||
/* will not work for 1024b RSA key and SHA512 hash: It has max size -2 */
|
||||
if (message_length < 0) {
|
||||
mech->usage_flags &= ~CKF_DECRYPT;
|
||||
debug_print(" [SKIP %s ] Too small modulus (%ld bits)"
|
||||
" or too large hash %s (%lu B) for OAEP", o->id_str,
|
||||
o->bits, get_mechanism_name(mech->hash),
|
||||
get_hash_length(mech->hash));
|
||||
return 0;
|
||||
}
|
||||
|
||||
debug_print(" [ KEY %s ] Encrypt message of length %d using CKM_%s, "
|
||||
"hash CKM_%s, mgf=CKG_%s", o->id_str, (unsigned) message_length,
|
||||
get_mechanism_name(mech->mech), get_mechanism_name(mech->hash),
|
||||
get_mgf_name(mech->mgf));
|
||||
enc_message_length = oaep_encrypt_message(o, info, message,
|
||||
(unsigned) message_length, mech, &enc_message);
|
||||
if (enc_message_length <= 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
debug_print(" [ KEY %s ] Decrypt message", o->id_str);
|
||||
dec_message_length = oaep_decrypt_message(o, info, enc_message,
|
||||
enc_message_length, mech, &dec_message);
|
||||
free(enc_message);
|
||||
if (dec_message_length <= 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (memcmp(dec_message, message, dec_message_length) == 0
|
||||
&& dec_message_length == message_length) {
|
||||
debug_print(" [ OK %s ] Text decrypted successfully.", o->id_str);
|
||||
mech->result_flags |= FLAGS_DECRYPT;
|
||||
rv = 1;
|
||||
} else {
|
||||
dec_message[dec_message_length] = '\0';
|
||||
debug_print(" [ ERROR %s ] Text decryption failed. Recovered text: %s",
|
||||
o->id_str, dec_message);
|
||||
rv = 0;
|
||||
}
|
||||
free(dec_message);
|
||||
return rv;
|
||||
}
|
||||
|
||||
static int get_max_salt_len(unsigned long bits, CK_MECHANISM_TYPE hash)
|
||||
{
|
||||
return (bits + 7)/8 - get_hash_length(hash) - 2;
|
||||
}
|
||||
|
||||
int fill_pss_params(CK_RSA_PKCS_PSS_PARAMS *pss_params,
|
||||
test_mech_t *mech, test_cert_t *o)
|
||||
{
|
||||
pss_params->hashAlg = mech->hash;
|
||||
pss_params->mgf = mech->mgf;
|
||||
switch (mech->salt){
|
||||
case -2:
|
||||
/* max possible ( modlen - hashlen -2 ) */
|
||||
pss_params->sLen = get_max_salt_len(o->bits,mech->hash);
|
||||
break;
|
||||
case -1:
|
||||
/* digest length */
|
||||
/* will not work with SHA512 and 1024b keys (max is 62b!) */
|
||||
if ((int) get_hash_length(mech->hash) > get_max_salt_len(o->bits, mech->hash)) {
|
||||
return -1;
|
||||
}
|
||||
pss_params->sLen = get_hash_length(mech->hash);
|
||||
break;
|
||||
case 0:
|
||||
default:
|
||||
pss_params->sLen = 0;
|
||||
break;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int pss_sign_message(test_cert_t *o, token_info_t *info, CK_BYTE *message,
|
||||
CK_ULONG message_length, test_mech_t *mech, unsigned char **sign)
|
||||
{
|
||||
CK_RV rv;
|
||||
CK_FUNCTION_LIST_PTR fp = info->function_pointer;
|
||||
CK_MECHANISM sign_mechanism = { mech->mech, NULL_PTR, 0 };
|
||||
CK_ULONG sign_length = 0;
|
||||
CK_RSA_PKCS_PSS_PARAMS pss_params;
|
||||
|
||||
if (fill_pss_params(&pss_params, mech, o) != 1) {
|
||||
debug_print(" [SKIP %s ] Impossible to use requested salt length", o->id_str);
|
||||
return 0;
|
||||
}
|
||||
sign_mechanism.pParameter = &pss_params;
|
||||
sign_mechanism.ulParameterLen = sizeof(pss_params);
|
||||
|
||||
rv = fp->C_SignInit(info->session_handle, &sign_mechanism,
|
||||
o->private_handle);
|
||||
if (rv == CKR_KEY_TYPE_INCONSISTENT) {
|
||||
debug_print(" [SKIP %s ] Not allowed to sign with this key?", o->id_str);
|
||||
return 0;
|
||||
} else if (rv == CKR_MECHANISM_INVALID) {
|
||||
debug_print(" [SKIP %s ] Bad mechanism. Not supported?", o->id_str);
|
||||
return 0;
|
||||
} else if (rv != CKR_OK) {
|
||||
debug_print(" C_SignInit: rv = 0x%.8lX\n", rv);
|
||||
return -1;
|
||||
}
|
||||
|
||||
always_authenticate(o, info);
|
||||
|
||||
/* Call C_Sign with NULL argument to find out the real size of signature */
|
||||
rv = fp->C_Sign(info->session_handle,
|
||||
message, message_length, *sign, &sign_length);
|
||||
if (rv != CKR_OK) {
|
||||
fprintf(stderr, " C_Sign: rv = 0x%.8lX\n", rv);
|
||||
return -1;
|
||||
}
|
||||
|
||||
*sign = malloc(sign_length);
|
||||
if (*sign == NULL) {
|
||||
fprintf(stderr, "%s: malloc failed", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Call C_Sign with allocated buffer to the actual signature */
|
||||
rv = fp->C_Sign(info->session_handle,
|
||||
message, message_length, *sign, &sign_length);
|
||||
|
||||
if (rv != CKR_OK) {
|
||||
free(*sign);
|
||||
fprintf(stderr, " C_Sign: rv = 0x%.8lX\n", rv);
|
||||
return -1;
|
||||
}
|
||||
return sign_length;
|
||||
}
|
||||
|
||||
int pss_verify_message_openssl(test_cert_t *o, token_info_t *info,
|
||||
CK_BYTE *message, CK_ULONG message_length, test_mech_t *mech,
|
||||
unsigned char *sign, CK_ULONG sign_length)
|
||||
{
|
||||
CK_RV rv = -1;
|
||||
EVP_PKEY_CTX *pctx = NULL;
|
||||
const CK_BYTE *my_message;
|
||||
CK_ULONG my_message_length;
|
||||
const EVP_MD *mgf_md = EVP_md_null();
|
||||
const EVP_MD *md = EVP_md_null();
|
||||
EVP_PKEY *key = NULL;
|
||||
|
||||
md = md_cryptoki_to_ossl(mech->hash);
|
||||
mgf_md = mgf_cryptoki_to_ossl(mech->mgf);
|
||||
|
||||
if (mech->mech != CKM_RSA_PKCS_PSS) {
|
||||
my_message = hash_message(message, message_length, mech->hash);
|
||||
my_message_length = get_hash_length(mech->hash);
|
||||
} else {
|
||||
my_message = message;
|
||||
my_message_length = message_length;
|
||||
}
|
||||
|
||||
if ((key = EVP_PKEY_new()) == NULL
|
||||
|| RSA_up_ref(o->key.rsa) < 1
|
||||
|| EVP_PKEY_set1_RSA(key, o->key.rsa) != 1) {
|
||||
fprintf(stderr, " [ ERROR %s ] Failed to initialize EVP_PKEY. Error: %s\n",
|
||||
o->id_str, ERR_error_string(ERR_peek_last_error(), NULL));
|
||||
goto out;
|
||||
}
|
||||
|
||||
if ((pctx = EVP_PKEY_CTX_new(key, NULL)) == NULL
|
||||
|| EVP_PKEY_verify_init(pctx) != 1
|
||||
|| EVP_PKEY_CTX_set_rsa_padding(pctx, RSA_PKCS1_PSS_PADDING) != 1
|
||||
|| EVP_PKEY_CTX_set_signature_md(pctx, md) != 1
|
||||
|| EVP_PKEY_CTX_set_rsa_pss_saltlen(pctx, mech->salt) != 1
|
||||
|| EVP_PKEY_CTX_set_rsa_mgf1_md(pctx, mgf_md) != 1) {
|
||||
fprintf(stderr, " [ ERROR %s ] Failed to initialize EVP_PKEY_CTX. Error: %s\n",
|
||||
o->id_str, ERR_error_string(ERR_peek_last_error(), NULL));
|
||||
goto out;
|
||||
}
|
||||
|
||||
rv = EVP_PKEY_verify(pctx, sign, sign_length, my_message, my_message_length);
|
||||
if (rv == 1) {
|
||||
debug_print(" [ OK %s ] Signature is valid.", o->id_str);
|
||||
mech->result_flags |= FLAGS_SIGN_OPENSSL;
|
||||
} else {
|
||||
fprintf(stderr, " [ ERROR %s ] Signature is not valid. Error: %s\n",
|
||||
o->id_str, ERR_error_string(ERR_peek_last_error(), NULL));
|
||||
goto out;
|
||||
}
|
||||
out:
|
||||
EVP_PKEY_CTX_free(pctx);
|
||||
EVP_PKEY_free(key);
|
||||
return rv;
|
||||
}
|
||||
|
||||
int pss_verify_message(test_cert_t *o, token_info_t *info, CK_BYTE *message,
|
||||
CK_ULONG message_length, test_mech_t *mech, unsigned char *sign,
|
||||
CK_ULONG sign_length)
|
||||
{
|
||||
CK_RV rv;
|
||||
CK_FUNCTION_LIST_PTR fp = info->function_pointer;
|
||||
CK_MECHANISM sign_mechanism = { mech->mech, NULL_PTR, 0 };
|
||||
CK_RSA_PKCS_PSS_PARAMS pss_params;
|
||||
static int verify_support = 1;
|
||||
|
||||
if (!verify_support)
|
||||
goto openssl_verify;
|
||||
|
||||
fill_pss_params(&pss_params, mech, o);
|
||||
sign_mechanism.pParameter = &pss_params;
|
||||
sign_mechanism.ulParameterLen = sizeof(pss_params);
|
||||
|
||||
/* try C_Verify() if it is supported */
|
||||
rv = fp->C_VerifyInit(info->session_handle, &sign_mechanism,
|
||||
o->public_handle);
|
||||
if (rv != CKR_OK) {
|
||||
debug_print(" C_VerifyInit: rv = 0x%.8lX", rv);
|
||||
verify_support = 0; /* avoid trying over and over again */
|
||||
goto openssl_verify;
|
||||
}
|
||||
|
||||
rv = fp->C_Verify(info->session_handle,
|
||||
message, message_length, sign, sign_length);
|
||||
|
||||
if (rv == CKR_OK) {
|
||||
mech->result_flags |= FLAGS_SIGN;
|
||||
debug_print(" [ OK %s ] Verification successful", o->id_str);
|
||||
return 1;
|
||||
}
|
||||
debug_print(" C_Verify: rv = 0x%.8lX", rv);
|
||||
verify_support = 0; /* avoid trying over and over again */
|
||||
|
||||
openssl_verify:
|
||||
debug_print(" [ KEY %s ] Falling back to openssl verification", o->id_str);
|
||||
return pss_verify_message_openssl(o, info, message, message_length, mech,
|
||||
sign, sign_length);
|
||||
}
|
||||
|
||||
/* Perform signature and verification of a message using private key referenced
|
||||
* in the o object with mechanism defined by mech.
|
||||
*
|
||||
* Returns
|
||||
* * 1 for successful Sign&Verify sequence
|
||||
* * 0 for skipped test (unsupported mechanism, key, ...)
|
||||
* * -1 otherwise.
|
||||
* Serious errors terminate the execution.
|
||||
*/
|
||||
int pss_sign_verify_test(test_cert_t *o, token_info_t *info, test_mech_t *mech)
|
||||
{
|
||||
CK_BYTE *message = NULL;
|
||||
size_t message_length = global_message_length;
|
||||
CK_BYTE *sign = NULL;
|
||||
CK_ULONG sign_length = 0;
|
||||
int rv = 0;
|
||||
|
||||
if (o->private_handle == CK_INVALID_HANDLE) {
|
||||
debug_print(" [SKIP %s ] Missing private key", o->id_str);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (o->type != EVP_PK_RSA) {
|
||||
debug_print(" [SKIP %s ] Skip non-RSA key", o->id_str);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!is_pss_mechanism(mech->mech)) {
|
||||
mech->usage_flags &= ~CKF_SIGN;
|
||||
debug_print(" [SKIP %s ] non RSA-PSS mechanism %s", o->id_str,
|
||||
get_mechanism_name(mech->mech));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (mech->mech == CKM_RSA_PKCS_PSS) {
|
||||
message = hash_message(global_message, global_message_length,
|
||||
mech->hash);
|
||||
message_length = get_hash_length(mech->hash);
|
||||
} else {
|
||||
message = (unsigned char *) SHORT_MESSAGE_TO_SIGN;
|
||||
}
|
||||
|
||||
debug_print(" [ KEY %s ] Signing message using CKM_%s, CKM_%s,"
|
||||
" CKG_%s, salt_len=%d", o->id_str,
|
||||
get_mechanism_name(mech->mech), get_mechanism_name(mech->hash),
|
||||
get_mgf_name(mech->mgf), mech->salt);
|
||||
rv = pss_sign_message(o, info, message, message_length, mech, &sign);
|
||||
if (rv <= 0) {
|
||||
return rv;
|
||||
}
|
||||
sign_length = (unsigned long) rv;
|
||||
|
||||
debug_print(" [ KEY %s ] Verify message signature", o->id_str);
|
||||
rv = pss_verify_message(o, info, message, message_length, mech,
|
||||
sign, sign_length);
|
||||
free(sign);
|
||||
return rv;
|
||||
}
|
||||
|
||||
/* ignore the prefilled mechanisms and list all combinations of mechanisms
|
||||
* found, all resonable hash functions, MGFs and salt lengths
|
||||
*/
|
||||
void fill_object_pss_mechanisms(token_info_t *info, test_cert_t *o)
|
||||
{
|
||||
const CK_MECHANISM_TYPE *h;
|
||||
const CK_RSA_PKCS_MGF_TYPE *mgf;
|
||||
int n = 0, s;
|
||||
unsigned int j;
|
||||
|
||||
for (j = 0; j < token.num_rsa_mechs; j++) {
|
||||
test_mech_t *source_mech = &token.rsa_mechs[j];
|
||||
|
||||
/* skip non-RSA-PSS mechs early */
|
||||
if (!is_pss_mechanism(source_mech->mech) &&
|
||||
source_mech->mech != CKM_RSA_PKCS_OAEP) {
|
||||
continue;
|
||||
}
|
||||
|
||||
h = get_mechanism_hashes(source_mech->mech);
|
||||
for (; *h != (CK_MECHANISM_TYPE) -1; h++) {
|
||||
mgf = get_mgfs();
|
||||
for (; *mgf != (CK_RSA_PKCS_MGF_TYPE) -1; mgf++) {
|
||||
/* OAEP does not have salt */
|
||||
if (source_mech->mech == CKM_RSA_PKCS_OAEP)
|
||||
s = 0;
|
||||
else
|
||||
s = -2;
|
||||
|
||||
for (; s <= 0; s++) {
|
||||
test_mech_t *mech = &o->mechs[n++];
|
||||
mech->mech = source_mech->mech;
|
||||
mech->hash = *h;
|
||||
mech->mgf = *mgf;
|
||||
mech->salt = s;
|
||||
mech->usage_flags =
|
||||
source_mech->usage_flags;
|
||||
mech->result_flags = 0;
|
||||
if (n >= MAX_MECHS)
|
||||
P11TEST_FAIL(info,
|
||||
"Too many mechanisms (%d)",
|
||||
MAX_MECHS);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
o->num_mechs = n;
|
||||
}
|
||||
|
||||
int have_pss_oaep_mechanisms()
|
||||
{
|
||||
unsigned have = 0, i;
|
||||
for (i = 0; i <= token.num_rsa_mechs; i++) {
|
||||
if (is_pss_mechanism(token.rsa_mechs[i].mech) ||
|
||||
token.rsa_mechs[i].mech == CKM_RSA_PKCS_OAEP) {
|
||||
have++;
|
||||
}
|
||||
}
|
||||
return have;
|
||||
}
|
||||
|
||||
void pss_oaep_test(void **state) {
|
||||
|
||||
token_info_t *info = (token_info_t *) *state;
|
||||
unsigned int i;
|
||||
int used, j;
|
||||
test_certs_t objects;
|
||||
|
||||
P11TEST_START(info);
|
||||
|
||||
if (have_pss_oaep_mechanisms() == 0) {
|
||||
fprintf(stderr, "Token does not support any RSA-PSS or OAEP mechanisms. Skipping.\n");
|
||||
skip();
|
||||
}
|
||||
|
||||
objects.count = 0;
|
||||
objects.data = NULL;
|
||||
search_for_all_objects(&objects, info);
|
||||
|
||||
debug_print("\nCheck functionality of Sign&Verify and/or Encrypt&Decrypt");
|
||||
for (i = 0; i < objects.count; i++) {
|
||||
test_cert_t *o = &objects.data[i];
|
||||
/* do the Sign&Verify and/or Encrypt&Decrypt */
|
||||
used = 0;
|
||||
if (o->private_handle == CK_INVALID_HANDLE) {
|
||||
debug_print(" [SKIP %s ] Missing private key",
|
||||
o->id_str);
|
||||
continue;
|
||||
}
|
||||
fill_object_pss_mechanisms(info, o);
|
||||
for (j = 0; j < o->num_mechs; j++)
|
||||
if (o->mechs[j].mech != CKM_RSA_PKCS_OAEP)
|
||||
used |= pss_sign_verify_test(o, info,
|
||||
&(o->mechs[j]));
|
||||
|
||||
for (j = 0; j < o->num_mechs; j++)
|
||||
if (o->mechs[j].mech == CKM_RSA_PKCS_OAEP)
|
||||
used |= oaep_encrypt_decrypt_test(o, info,
|
||||
&(o->mechs[j]));
|
||||
|
||||
if (!used) {
|
||||
debug_print(" [ WARN %s ] Private key with unknown purpose T:%02lX",
|
||||
o->id_str, o->key_type);
|
||||
}
|
||||
}
|
||||
|
||||
if (objects.count == 0) {
|
||||
printf(" [WARN] No objects to display\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* print summary */
|
||||
printf("[KEY ID] [LABEL]\n");
|
||||
printf("[ TYPE ] [ SIZE ] [PUBLIC] [SIGN&VERIFY] [ENC&DECRYPT]\n");
|
||||
printf("[ MECHANISM ] [ HASH ] [ MGF ] [SALT] [ WORKS ] [ WORKS ]\n");
|
||||
P11TEST_DATA_ROW(info, 7,
|
||||
's', "KEY ID",
|
||||
's', "MECHANISM",
|
||||
's', "HASH",
|
||||
's', "MGF",
|
||||
's', "SALT",
|
||||
's', "SIGN&VERIFY WORKS",
|
||||
's', "ENCRYPT&DECRYPT WORKS");
|
||||
for (i = 0; i < objects.count; i++) {
|
||||
test_cert_t *o = &objects.data[i];
|
||||
|
||||
/* Do not list non-RSA keys here */
|
||||
if (o->type != EVP_PK_RSA)
|
||||
continue;
|
||||
|
||||
printf("\n[%-6s] [%s]\n",
|
||||
o->id_str,
|
||||
o->label);
|
||||
printf("[ %s ] [%6lu] [ %s ] [%s%s] [%s%s]\n",
|
||||
o->key_type == CKK_RSA ? "RSA " :
|
||||
o->key_type == CKK_EC ? " EC " : " ?? ",
|
||||
o->bits,
|
||||
o->verify_public == 1 ? " ./ " : " ",
|
||||
o->sign ? "[./] " : "[ ] ",
|
||||
o->verify ? " [./] " : " [ ] ",
|
||||
o->encrypt ? "[./] " : "[ ] ",
|
||||
o->decrypt ? " [./] " : " [ ] ");
|
||||
if (!o->sign && !o->verify && !o->encrypt && !o->decrypt) {
|
||||
printf(" no usable attributes found ... ignored\n");
|
||||
continue;
|
||||
}
|
||||
for (j = 0; j < o->num_mechs; j++) {
|
||||
test_mech_t *mech = &o->mechs[j];
|
||||
printf(" [ %-20s ] [%-6s] [%-11s] [%4d] [ %s ] [ %s ]\n",
|
||||
get_mechanism_name(mech->mech),
|
||||
get_mechanism_name(mech->hash),
|
||||
get_mgf_name(mech->mgf),
|
||||
mech->salt,
|
||||
mech->result_flags & FLAGS_SIGN_ANY
|
||||
? "[./]" : " ",
|
||||
mech->result_flags & FLAGS_DECRYPT_ANY
|
||||
? "[./]" : " ");
|
||||
if ((mech->result_flags & FLAGS_SIGN_ANY) == 0 &&
|
||||
(mech->result_flags & FLAGS_DECRYPT_ANY) == 0)
|
||||
continue; /* skip empty rows for export */
|
||||
P11TEST_DATA_ROW(info, 7,
|
||||
's', o->id_str,
|
||||
's', get_mechanism_name(mech->mech),
|
||||
's', get_mechanism_name(mech->hash),
|
||||
's', get_mgf_name(mech->mgf),
|
||||
'd', mech->salt,
|
||||
's', mech->result_flags & FLAGS_SIGN_ANY
|
||||
? "YES" : "",
|
||||
's', mech->result_flags & FLAGS_DECRYPT_ANY
|
||||
? "YES" : "");
|
||||
}
|
||||
}
|
||||
printf(" Public == Cert ----------^ ^ ^ ^ ^ ^ ^\n");
|
||||
printf(" Sign Attribute -------------------------------------------' | | | | |\n");
|
||||
printf(" Sign&Verify functionality -----------------------------------' | | | |\n");
|
||||
printf(" Verify Attribute -----------------------------------------------' | | |\n");
|
||||
printf(" Encrypt Attribute ------------------------------------------------------' | |\n");
|
||||
printf(" Encrypt & Decrypt functionality -------------------------------------------' |\n");
|
||||
printf(" Decrypt Attribute ------------------------------------------------------------'\n");
|
||||
|
||||
clean_all_objects(&objects);
|
||||
P11TEST_PASS(info);
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* p11test_case_pss_oaep.h: RSA-PSS and RSA-OAEP tests
|
||||
*
|
||||
* Copyright (C) 2017 Red Hat, Inc.
|
||||
*
|
||||
* Author: Jakub Jelen <jjelen@redhat.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "p11test_case_common.h"
|
||||
|
||||
void pss_oaep_test(void **state);
|
|
@ -0,0 +1,699 @@
|
|||
/*
|
||||
* p11test_case_readonly.c: Sign & Verify tests
|
||||
*
|
||||
* Copyright (C) 2016, 2017 Red Hat, Inc.
|
||||
*
|
||||
* Author: Jakub Jelen <jjelen@redhat.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "p11test_case_readonly.h"
|
||||
|
||||
#include <openssl/sha.h>
|
||||
#include <openssl/md5.h>
|
||||
#include <openssl/ripemd.h>
|
||||
|
||||
#define SHORT_MESSAGE_TO_SIGN "Simple message for signing & verifying. It needs to be little bit longer to fit also longer keys and allow the truncation.\n"
|
||||
#define SHORT_MESSAGE_DIGEST "\x30\x21\x30\x09\x06\x05\x2b\x0e" \
|
||||
"\x03\x02\x1a\x05\x00\x04\x14\xd9" \
|
||||
"\xdd\xa3\x76\x44\x2f\x50\xe1\xec" \
|
||||
"\xd3\x8b\xcd\x6f\xc6\xce\x4e\xfd" \
|
||||
"\xd3\x1a\x3f"
|
||||
#define BUFFER_SIZE 4096
|
||||
|
||||
const unsigned char *const_message = (unsigned char *) SHORT_MESSAGE_TO_SIGN;
|
||||
|
||||
static unsigned char *
|
||||
rsa_x_509_pad_message(const unsigned char *message,
|
||||
unsigned long *message_length, test_cert_t *o, int encrypt)
|
||||
{
|
||||
int pad_message_length = (o->bits+7)/8;
|
||||
unsigned char *pad_message = malloc(pad_message_length);
|
||||
if (!encrypt)
|
||||
RSA_padding_add_PKCS1_type_1(pad_message, pad_message_length,
|
||||
message, *message_length);
|
||||
else
|
||||
RSA_padding_add_PKCS1_type_2(pad_message, pad_message_length,
|
||||
message, *message_length);
|
||||
*message_length = pad_message_length;
|
||||
return pad_message;
|
||||
}
|
||||
|
||||
int encrypt_message_openssl(test_cert_t *o, token_info_t *info, CK_BYTE *message,
|
||||
CK_ULONG message_length, test_mech_t *mech, unsigned char **enc_message)
|
||||
{
|
||||
int rv, padding;
|
||||
|
||||
*enc_message = malloc(RSA_size(o->key.rsa));
|
||||
if (*enc_message == NULL) {
|
||||
debug_print("malloc returned null");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Prepare padding for RSA_X_509 */
|
||||
padding = ((mech->mech == CKM_RSA_X_509) ? RSA_NO_PADDING : RSA_PKCS1_PADDING);
|
||||
rv = RSA_public_encrypt(message_length, message,
|
||||
*enc_message, o->key.rsa, padding);
|
||||
if (rv < 0) {
|
||||
free(*enc_message);
|
||||
debug_print("RSA_public_encrypt: rv = 0x%.8X\n", rv);
|
||||
return -1;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
int encrypt_message(test_cert_t *o, token_info_t *info, CK_BYTE *message,
|
||||
CK_ULONG message_length, test_mech_t *mech, unsigned char **enc_message)
|
||||
{
|
||||
CK_RV rv;
|
||||
CK_FUNCTION_LIST_PTR fp = info->function_pointer;
|
||||
CK_MECHANISM enc_mechanism = { mech->mech, NULL_PTR, 0 };
|
||||
CK_ULONG enc_message_length;
|
||||
static int encrypt_support = 1;
|
||||
|
||||
if (!encrypt_support)
|
||||
goto openssl_encrypt;
|
||||
|
||||
rv = fp->C_EncryptInit(info->session_handle, &enc_mechanism,
|
||||
o->public_handle);
|
||||
if (rv != CKR_OK) {
|
||||
debug_print(" C_EncryptInit: rv = 0x%.8lX", rv);
|
||||
encrypt_support = 0; /* avoid trying over and over again */
|
||||
goto openssl_encrypt;
|
||||
}
|
||||
|
||||
/* get the expected length */
|
||||
rv = fp->C_Encrypt(info->session_handle, message, message_length,
|
||||
NULL, &enc_message_length);
|
||||
if (rv != CKR_OK) {
|
||||
debug_print(" C_Encrypt: rv = 0x%.8lX", rv);
|
||||
goto openssl_encrypt;
|
||||
}
|
||||
*enc_message = malloc(enc_message_length);
|
||||
if (*enc_message == NULL) {
|
||||
debug_print("malloc returned null");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Do the actual encryption with allocated buffer */
|
||||
rv = fp->C_Encrypt(info->session_handle, message, message_length,
|
||||
*enc_message, &enc_message_length);
|
||||
if (rv == CKR_OK) {
|
||||
mech->result_flags |= FLAGS_SIGN;
|
||||
return enc_message_length;
|
||||
}
|
||||
debug_print(" C_Encrypt: rv = 0x%.8lX", rv);
|
||||
|
||||
openssl_encrypt:
|
||||
debug_print(" [ KEY %s ] Falling back to openssl encryption", o->id_str);
|
||||
return encrypt_message_openssl(o, info, message, message_length, mech,
|
||||
enc_message);
|
||||
}
|
||||
|
||||
int decrypt_message(test_cert_t *o, token_info_t *info, CK_BYTE *enc_message,
|
||||
CK_ULONG enc_message_length, test_mech_t *mech, unsigned char **dec_message)
|
||||
{
|
||||
CK_RV rv;
|
||||
CK_FUNCTION_LIST_PTR fp = info->function_pointer;
|
||||
CK_MECHANISM dec_mechanism = { mech->mech, NULL_PTR, 0 };
|
||||
CK_ULONG dec_message_length = BUFFER_SIZE;
|
||||
|
||||
rv = fp->C_DecryptInit(info->session_handle, &dec_mechanism,
|
||||
o->private_handle);
|
||||
if (rv == CKR_KEY_TYPE_INCONSISTENT) {
|
||||
debug_print(" [SKIP %s ] Not allowed to decrypt with this key?", o->id_str);
|
||||
return 0;
|
||||
} else if (rv != CKR_OK) {
|
||||
debug_print("C_DecryptInit: rv = 0x%.8lX\n", rv);
|
||||
return -1;
|
||||
}
|
||||
|
||||
*dec_message = malloc(dec_message_length);
|
||||
|
||||
always_authenticate(o, info);
|
||||
|
||||
rv = fp->C_Decrypt(info->session_handle, enc_message,
|
||||
enc_message_length, *dec_message, &dec_message_length);
|
||||
if (rv != CKR_OK) {
|
||||
free(*dec_message);
|
||||
debug_print(" C_Decrypt: rv = 0x%.8lX\n", rv);
|
||||
return -1;
|
||||
}
|
||||
return (int) dec_message_length;
|
||||
}
|
||||
|
||||
/* Perform encryption and decryption of a message using private key referenced
|
||||
* in the o object with mechanism defined by mech.
|
||||
*
|
||||
* NONE of the reasonable mechanisms support multipart encryption/decryption
|
||||
*
|
||||
* Returns
|
||||
* * 1 for successful Encrypt&Decrypt sequence
|
||||
* * 0 for skipped test (unsupported mechanism, key, ...)
|
||||
* * -1 otherwise.
|
||||
* Serious errors terminate the execution.
|
||||
*/
|
||||
int encrypt_decrypt_test(test_cert_t *o, token_info_t *info, test_mech_t *mech,
|
||||
CK_ULONG message_length, int multipart)
|
||||
{
|
||||
CK_BYTE *message = NULL;
|
||||
CK_BYTE *dec_message = NULL;
|
||||
int dec_message_length = 0;
|
||||
unsigned char *enc_message;
|
||||
int enc_message_length, rv;
|
||||
|
||||
if (o->private_handle == CK_INVALID_HANDLE) {
|
||||
debug_print(" [SKIP %s ] Missing private key", o->id_str);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (o->type != EVP_PK_RSA) {
|
||||
debug_print(" [ KEY %s ] Skip non-RSA key for encryption", o->id_str);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (mech->mech == CKM_RSA_PKCS_OAEP) {
|
||||
mech->usage_flags &= ~CKF_DECRYPT;
|
||||
debug_print(" [SKIP %s ] RSA-OAEP tested separately", o->id_str);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (mech->mech != CKM_RSA_X_509 && mech->mech != CKM_RSA_PKCS) {
|
||||
debug_print(" [ KEY %s ] Skip encryption for non-supported mechanism %s",
|
||||
o->id_str, get_mechanism_name(mech->mech));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (mech->mech == CKM_RSA_X_509)
|
||||
message = rsa_x_509_pad_message(const_message,
|
||||
&message_length, o, 1);
|
||||
else
|
||||
message = (CK_BYTE *) strdup(SHORT_MESSAGE_TO_SIGN);
|
||||
|
||||
debug_print(" [ KEY %s ] Encrypt message using CKM_%s",
|
||||
o->id_str, get_mechanism_name(mech->mech));
|
||||
enc_message_length = encrypt_message(o, info, message, message_length,
|
||||
mech, &enc_message);
|
||||
if (enc_message_length <= 0) {
|
||||
free(message);
|
||||
return -1;
|
||||
}
|
||||
|
||||
debug_print(" [ KEY %s ] Decrypt message", o->id_str);
|
||||
dec_message_length = decrypt_message(o, info, enc_message,
|
||||
enc_message_length, mech, &dec_message);
|
||||
free(enc_message);
|
||||
if (dec_message_length <= 0) {
|
||||
free(message);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (memcmp(dec_message, message, dec_message_length) == 0
|
||||
&& (unsigned int) dec_message_length == message_length) {
|
||||
debug_print(" [ OK %s ] Text decrypted successfully.", o->id_str);
|
||||
mech->result_flags |= FLAGS_DECRYPT;
|
||||
rv = 1;
|
||||
} else {
|
||||
dec_message[dec_message_length] = '\0';
|
||||
debug_print(" [ ERROR %s ] Text decryption failed. Recovered text: %s",
|
||||
o->id_str, dec_message);
|
||||
rv = 0;
|
||||
}
|
||||
free(dec_message);
|
||||
free(message);
|
||||
return rv;
|
||||
}
|
||||
|
||||
int sign_message(test_cert_t *o, token_info_t *info, CK_BYTE *message,
|
||||
CK_ULONG message_length, test_mech_t *mech, unsigned char **sign,
|
||||
int multipart)
|
||||
{
|
||||
CK_RV rv;
|
||||
CK_FUNCTION_LIST_PTR fp = info->function_pointer;
|
||||
CK_MECHANISM sign_mechanism = { mech->mech, NULL_PTR, 0 };
|
||||
CK_ULONG sign_length = 0;
|
||||
char *name;
|
||||
|
||||
rv = fp->C_SignInit(info->session_handle, &sign_mechanism,
|
||||
o->private_handle);
|
||||
if (rv == CKR_KEY_TYPE_INCONSISTENT) {
|
||||
debug_print(" [SKIP %s ] Not allowed to sign with this key?", o->id_str);
|
||||
return 0;
|
||||
} else if (rv == CKR_MECHANISM_INVALID) {
|
||||
debug_print(" [SKIP %s ] Bad mechanism. Not supported?", o->id_str);
|
||||
return 0;
|
||||
} else if (rv != CKR_OK) {
|
||||
debug_print(" C_SignInit: rv = 0x%.8lX\n", rv);
|
||||
return -1;
|
||||
}
|
||||
|
||||
always_authenticate(o, info);
|
||||
|
||||
if (multipart) {
|
||||
int part = message_length / 3;
|
||||
rv = fp->C_SignUpdate(info->session_handle, message, part);
|
||||
if (rv == CKR_MECHANISM_INVALID) {
|
||||
fprintf(stderr, " Multipart Signature not supported with CKM_%s\n",
|
||||
get_mechanism_name(mech->mech));
|
||||
return -1;
|
||||
} else if (rv != CKR_OK) {
|
||||
fprintf(stderr, " C_SignUpdate: rv = 0x%.8lX\n", rv);
|
||||
return -1;
|
||||
}
|
||||
rv = fp->C_SignUpdate(info->session_handle, message + part, message_length - part);
|
||||
if (rv != CKR_OK) {
|
||||
fprintf(stderr, " C_SignUpdate: rv = 0x%.8lX\n", rv);
|
||||
return -1;
|
||||
}
|
||||
/* Call C_SignFinal with NULL argument to find out the real size of signature */
|
||||
rv = fp->C_SignFinal(info->session_handle, *sign, &sign_length);
|
||||
if (rv != CKR_OK) {
|
||||
fprintf(stderr, " C_SignFinal: rv = 0x%.8lX\n", rv);
|
||||
return -1;
|
||||
}
|
||||
|
||||
*sign = malloc(sign_length);
|
||||
if (*sign == NULL) {
|
||||
fprintf(stderr, "%s: malloc failed", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Call C_SignFinal with allocated buffer to the actual signature */
|
||||
rv = fp->C_SignFinal(info->session_handle, *sign, &sign_length);
|
||||
name = "C_SignFinal";
|
||||
} else {
|
||||
/* Call C_Sign with NULL argument to find out the real size of signature */
|
||||
rv = fp->C_Sign(info->session_handle,
|
||||
message, message_length, *sign, &sign_length);
|
||||
if (rv != CKR_OK) {
|
||||
fprintf(stderr, " C_Sign: rv = 0x%.8lX\n", rv);
|
||||
return -1;
|
||||
}
|
||||
|
||||
*sign = malloc(sign_length);
|
||||
if (*sign == NULL) {
|
||||
fprintf(stderr, "%s: malloc failed", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Call C_Sign with allocated buffer to the actual signature */
|
||||
rv = fp->C_Sign(info->session_handle,
|
||||
message, message_length, *sign, &sign_length);
|
||||
name = "C_Sign";
|
||||
}
|
||||
if (rv != CKR_OK) {
|
||||
free(*sign);
|
||||
fprintf(stderr, " %s: rv = 0x%.8lX\n", name, rv);
|
||||
return -1;
|
||||
}
|
||||
return sign_length;
|
||||
}
|
||||
|
||||
int verify_message_openssl(test_cert_t *o, token_info_t *info, CK_BYTE *message,
|
||||
CK_ULONG message_length, test_mech_t *mech, unsigned char *sign,
|
||||
CK_ULONG sign_length)
|
||||
{
|
||||
CK_RV rv;
|
||||
CK_BYTE *cmp_message = NULL;
|
||||
int cmp_message_length;
|
||||
|
||||
if (o->type == EVP_PK_RSA) {
|
||||
int type;
|
||||
|
||||
/* raw RSA mechanism */
|
||||
if (mech->mech == CKM_RSA_PKCS || mech->mech == CKM_RSA_X_509) {
|
||||
CK_BYTE dec_message[BUFFER_SIZE];
|
||||
int padding = ((mech->mech == CKM_RSA_X_509)
|
||||
? RSA_NO_PADDING : RSA_PKCS1_PADDING);
|
||||
int dec_message_length = RSA_public_decrypt(sign_length, sign,
|
||||
dec_message, o->key.rsa, padding);
|
||||
if (dec_message_length < 0) {
|
||||
fprintf(stderr, "RSA_public_decrypt: rv = %d: %s\n", dec_message_length,
|
||||
ERR_error_string(ERR_peek_last_error(), NULL));
|
||||
return -1;
|
||||
}
|
||||
if (memcmp(dec_message, message, dec_message_length) == 0
|
||||
&& dec_message_length == (int) message_length) {
|
||||
debug_print(" [ OK %s ] Signature is valid.", o->id_str);
|
||||
mech->result_flags |= FLAGS_SIGN_OPENSSL;
|
||||
return 1;
|
||||
} else {
|
||||
fprintf(stderr, " [ ERROR %s ] Signature is not valid. Error: %s\n",
|
||||
o->id_str, ERR_error_string(ERR_peek_last_error(), NULL));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Digest mechanisms */
|
||||
switch (mech->mech) {
|
||||
case CKM_SHA1_RSA_PKCS:
|
||||
cmp_message = SHA1(message, message_length, NULL);
|
||||
cmp_message_length = SHA_DIGEST_LENGTH;
|
||||
type = NID_sha1;
|
||||
break;
|
||||
case CKM_SHA224_RSA_PKCS:
|
||||
cmp_message = SHA224(message, message_length, NULL);
|
||||
cmp_message_length = SHA224_DIGEST_LENGTH;
|
||||
type = NID_sha224;
|
||||
break;
|
||||
case CKM_SHA256_RSA_PKCS:
|
||||
cmp_message = SHA256(message, message_length, NULL);
|
||||
cmp_message_length = SHA256_DIGEST_LENGTH;
|
||||
type = NID_sha256;
|
||||
break;
|
||||
case CKM_SHA384_RSA_PKCS:
|
||||
cmp_message = SHA384(message, message_length, NULL);
|
||||
cmp_message_length = SHA384_DIGEST_LENGTH;
|
||||
type = NID_sha384;
|
||||
break;
|
||||
case CKM_SHA512_RSA_PKCS:
|
||||
cmp_message = SHA512(message, message_length, NULL);
|
||||
cmp_message_length = SHA512_DIGEST_LENGTH;
|
||||
type = NID_sha512;
|
||||
break;
|
||||
case CKM_MD5_RSA_PKCS:
|
||||
cmp_message = MD5(message, message_length, NULL);
|
||||
cmp_message_length = MD5_DIGEST_LENGTH;
|
||||
type = NID_md5;
|
||||
break;
|
||||
case CKM_RIPEMD160_RSA_PKCS:
|
||||
cmp_message = RIPEMD160(message, message_length, NULL);
|
||||
cmp_message_length = RIPEMD160_DIGEST_LENGTH;
|
||||
type = NID_ripemd160;
|
||||
break;
|
||||
default:
|
||||
debug_print(" [SKIP %s ] Skip verify of unknown mechanism", o->id_str);
|
||||
return 0;
|
||||
}
|
||||
rv = RSA_verify(type, cmp_message, cmp_message_length,
|
||||
sign, sign_length, o->key.rsa);
|
||||
if (rv == 1) {
|
||||
debug_print(" [ OK %s ] Signature is valid.", o->id_str);
|
||||
mech->result_flags |= FLAGS_SIGN_OPENSSL;
|
||||
} else {
|
||||
fprintf(stderr, " [ ERROR %s ] Signature is not valid. Error: %s\n",
|
||||
o->id_str, ERR_error_string(ERR_peek_last_error(), NULL));
|
||||
return -1;
|
||||
}
|
||||
} else if (o->type == EVP_PK_EC) {
|
||||
unsigned int nlen;
|
||||
ECDSA_SIG *sig = ECDSA_SIG_new();
|
||||
BIGNUM *r = NULL, *s = NULL;
|
||||
if (sig == NULL) {
|
||||
fprintf(stderr, "ECDSA_SIG_new: failed");
|
||||
return -1;
|
||||
}
|
||||
nlen = sign_length/2;
|
||||
r = BN_bin2bn(&sign[0], nlen, NULL);
|
||||
s = BN_bin2bn(&sign[nlen], nlen, NULL);
|
||||
ECDSA_SIG_set0(sig, r, s);
|
||||
switch (mech->mech) {
|
||||
case CKM_ECDSA_SHA512:
|
||||
cmp_message = SHA512(message, message_length, NULL);
|
||||
cmp_message_length = SHA512_DIGEST_LENGTH;
|
||||
break;
|
||||
case CKM_ECDSA_SHA384:
|
||||
cmp_message = SHA384(message, message_length, NULL);
|
||||
cmp_message_length = SHA384_DIGEST_LENGTH;
|
||||
break;
|
||||
case CKM_ECDSA_SHA256:
|
||||
cmp_message = SHA256(message, message_length, NULL);
|
||||
cmp_message_length = SHA256_DIGEST_LENGTH;
|
||||
break;
|
||||
case CKM_ECDSA_SHA1:
|
||||
cmp_message = SHA1(message, message_length, NULL);
|
||||
cmp_message_length = SHA_DIGEST_LENGTH;
|
||||
break;
|
||||
case CKM_ECDSA:
|
||||
cmp_message = message;
|
||||
cmp_message_length = message_length;
|
||||
break;
|
||||
default:
|
||||
debug_print(" [SKIP %s ] Skip verify of unknown mechanism", o->id_str);
|
||||
return 0;
|
||||
}
|
||||
rv = ECDSA_do_verify(cmp_message, cmp_message_length, sig, o->key.ec);
|
||||
if (rv == 1) {
|
||||
ECDSA_SIG_free(sig);
|
||||
debug_print(" [ OK %s ] EC Signature of length %lu is valid.",
|
||||
o->id_str, message_length);
|
||||
mech->result_flags |= FLAGS_SIGN_OPENSSL;
|
||||
return 1;
|
||||
} else {
|
||||
ECDSA_SIG_free(sig);
|
||||
fprintf(stderr, " [FAIL %s ] ECDSA_do_verify: rv = %lu: %s\n", o->id_str,
|
||||
rv, ERR_error_string(ERR_peek_last_error(), NULL));
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr, " [ KEY %s ] Unknown type. Not verifying", o->id_str);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int verify_message(test_cert_t *o, token_info_t *info, CK_BYTE *message,
|
||||
CK_ULONG message_length, test_mech_t *mech, unsigned char *sign,
|
||||
CK_ULONG sign_length, int multipart)
|
||||
{
|
||||
CK_RV rv;
|
||||
CK_FUNCTION_LIST_PTR fp = info->function_pointer;
|
||||
CK_MECHANISM sign_mechanism = { mech->mech, NULL_PTR, 0 };
|
||||
static int verify_support = 1;
|
||||
#ifndef NDEBUG
|
||||
char *name;
|
||||
#endif
|
||||
|
||||
if (!verify_support)
|
||||
goto openssl_verify;
|
||||
|
||||
/* try C_Verify() if it is supported */
|
||||
rv = fp->C_VerifyInit(info->session_handle, &sign_mechanism,
|
||||
o->public_handle);
|
||||
if (rv != CKR_OK) {
|
||||
debug_print(" C_VerifyInit: rv = 0x%.8lX", rv);
|
||||
verify_support = 0; /* avoid trying over and over again */
|
||||
goto openssl_verify;
|
||||
}
|
||||
if (multipart) {
|
||||
int part = message_length / 3;
|
||||
/* First part */
|
||||
rv = fp->C_VerifyUpdate(info->session_handle, message, part);
|
||||
if (rv != CKR_OK) {
|
||||
debug_print(" C_VerifyUpdate: rv = 0x%.8lX", rv);
|
||||
goto openssl_verify;
|
||||
}
|
||||
/* Second part */
|
||||
rv = fp->C_VerifyUpdate(info->session_handle, message + part,
|
||||
message_length - part);
|
||||
if (rv != CKR_OK) {
|
||||
debug_print(" C_VerifyUpdate: rv = 0x%.8lX", rv);
|
||||
goto openssl_verify;
|
||||
}
|
||||
/* Final */
|
||||
rv = fp->C_VerifyFinal(info->session_handle,
|
||||
sign, sign_length);
|
||||
#ifndef NDEBUG
|
||||
name = "C_VerifyFinal";
|
||||
#endif
|
||||
} else {
|
||||
rv = fp->C_Verify(info->session_handle,
|
||||
message, message_length, sign, sign_length);
|
||||
#ifndef NDEBUG
|
||||
name = "C_Verify";
|
||||
#endif
|
||||
}
|
||||
if (rv == CKR_OK) {
|
||||
mech->result_flags |= FLAGS_SIGN;
|
||||
debug_print(" [ OK %s ] Verification successful", o->id_str);
|
||||
return 1;
|
||||
}
|
||||
debug_print(" %s: rv = 0x%.8lX", name, rv);
|
||||
verify_support = 0; /* avoid trying over and over again */
|
||||
|
||||
openssl_verify:
|
||||
debug_print(" [ KEY %s ] Falling back to openssl verification", o->id_str);
|
||||
return verify_message_openssl(o, info, message, message_length, mech,
|
||||
sign, sign_length);
|
||||
}
|
||||
|
||||
/* Perform signature and verification of a message using private key referenced
|
||||
* in the o object with mechanism defined by mech. Message length can be
|
||||
* specified using argument message_length.
|
||||
*
|
||||
* Returns
|
||||
* * 1 for successful Sign&Verify sequence
|
||||
* * 0 for skipped test (unsupported mechanism, key, ...)
|
||||
* * -1 otherwise.
|
||||
* Serious errors terminate the execution.
|
||||
*/
|
||||
int sign_verify_test(test_cert_t *o, token_info_t *info, test_mech_t *mech,
|
||||
CK_ULONG message_length, int multipart)
|
||||
{
|
||||
CK_BYTE *message = NULL;
|
||||
CK_BYTE *sign = NULL;
|
||||
CK_ULONG sign_length = 0;
|
||||
int rv = 0;
|
||||
|
||||
if (message_length > strlen(SHORT_MESSAGE_TO_SIGN))
|
||||
fail_msg("Truncate is longer than the actual message");
|
||||
|
||||
if (o->private_handle == CK_INVALID_HANDLE) {
|
||||
debug_print(" [SKIP %s ] Missing private key", o->id_str);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (o->type != EVP_PK_EC && o->type != EVP_PK_RSA) {
|
||||
debug_print(" [SKIP %s ] Skip non-RSA and non-EC key", o->id_str);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (is_pss_mechanism(mech->mech)) {
|
||||
mech->usage_flags &= ~CKF_SIGN;
|
||||
debug_print(" [SKIP %s ] RSA-PSS tested separately", o->id_str);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (mech->mech == CKM_RSA_X_509) /* manually add padding */
|
||||
message = rsa_x_509_pad_message(const_message,
|
||||
&message_length, o, 0);
|
||||
else if (mech->mech == CKM_RSA_PKCS) {
|
||||
/* DigestInfo + SHA1(message) */
|
||||
message_length = 35;
|
||||
message = malloc(message_length * sizeof(unsigned char));
|
||||
memcpy(message, SHORT_MESSAGE_DIGEST, message_length);
|
||||
} else
|
||||
message = (CK_BYTE *) strdup(SHORT_MESSAGE_TO_SIGN);
|
||||
|
||||
debug_print(" [ KEY %s ] Signing message of length %lu using CKM_%s",
|
||||
o->id_str, message_length, get_mechanism_name(mech->mech));
|
||||
rv = sign_message(o, info, message, message_length, mech, &sign, multipart);
|
||||
if (rv <= 0) {
|
||||
free(message);
|
||||
return rv;
|
||||
}
|
||||
sign_length = (unsigned long) rv;
|
||||
|
||||
debug_print(" [ KEY %s ] Verify message signature", o->id_str);
|
||||
rv = verify_message(o, info, message, message_length, mech,
|
||||
sign, sign_length, multipart);
|
||||
free(sign);
|
||||
free(message);
|
||||
return rv;
|
||||
}
|
||||
|
||||
void readonly_tests(void **state) {
|
||||
|
||||
token_info_t *info = (token_info_t *) *state;
|
||||
unsigned int i;
|
||||
int used, j;
|
||||
test_certs_t objects;
|
||||
|
||||
objects.count = 0;
|
||||
objects.data = NULL;
|
||||
|
||||
search_for_all_objects(&objects, info);
|
||||
|
||||
P11TEST_START(info);
|
||||
debug_print("\nCheck functionality of Sign&Verify and/or Encrypt&Decrypt");
|
||||
for (i = 0; i < objects.count; i++) {
|
||||
test_cert_t *o = &objects.data[i];
|
||||
/* do the Sign&Verify and/or Encrypt&Decrypt */
|
||||
used = 0;
|
||||
if (o->private_handle == CK_INVALID_HANDLE) {
|
||||
debug_print(" [SKIP %s ] Missing private key",
|
||||
o->id_str);
|
||||
continue;
|
||||
}
|
||||
/* XXX some keys do not have appropriate flags, but we can use them
|
||||
* or vice versa */
|
||||
//if (o->sign && o->verify)
|
||||
for (j = 0; j < o->num_mechs; j++)
|
||||
used |= sign_verify_test(&(objects.data[i]), info,
|
||||
&(o->mechs[j]), 32, 0);
|
||||
|
||||
//if (o->encrypt && o->decrypt)
|
||||
for (j = 0; j < o->num_mechs; j++)
|
||||
used |= encrypt_decrypt_test(&(objects.data[i]), info,
|
||||
&(o->mechs[j]), 32, 0);
|
||||
|
||||
if (!used) {
|
||||
debug_print(" [ WARN %s ] Private key with unknown purpose T:%02lX",
|
||||
o->id_str, o->key_type);
|
||||
}
|
||||
}
|
||||
|
||||
if (objects.count == 0) {
|
||||
printf(" [WARN] No objects to display\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* print summary */
|
||||
printf("[KEY ID] [LABEL]\n");
|
||||
printf("[ TYPE ] [ SIZE ] [PUBLIC] [SIGN&VERIFY] [ENC&DECRYPT] [WRAP&UNWR] [ DERIVE ]\n");
|
||||
P11TEST_DATA_ROW(info, 4,
|
||||
's', "KEY ID",
|
||||
's', "MECHANISM",
|
||||
's', "SIGN&VERIFY WORKS",
|
||||
's', "ENCRYPT&DECRYPT WORKS");
|
||||
for (i = 0; i < objects.count; i++) {
|
||||
test_cert_t *o = &objects.data[i];
|
||||
printf("\n[%-6s] [%s]\n",
|
||||
o->id_str,
|
||||
o->label);
|
||||
printf("[ %s ] [%6lu] [ %s ] [%s%s] [%s%s] [%s %s] [%s%s]\n",
|
||||
o->key_type == CKK_RSA ? "RSA " :
|
||||
o->key_type == CKK_EC ? " EC " : " ?? ",
|
||||
o->bits,
|
||||
o->verify_public == 1 ? " ./ " : " ",
|
||||
o->sign ? "[./] " : "[ ] ",
|
||||
o->verify ? " [./] " : " [ ] ",
|
||||
o->encrypt ? "[./] " : "[ ] ",
|
||||
o->decrypt ? " [./] " : " [ ] ",
|
||||
o->wrap ? "[./]" : "[ ]",
|
||||
o->unwrap ? "[./]" : "[ ]",
|
||||
o->derive_pub ? "[./]" : "[ ]",
|
||||
o->derive_priv ? "[./]" : "[ ]");
|
||||
if (!o->sign && !o->verify && !o->encrypt && !o->decrypt) {
|
||||
printf(" no usable attributes found ... ignored\n");
|
||||
continue;
|
||||
}
|
||||
for (j = 0; j < o->num_mechs; j++) {
|
||||
test_mech_t *mech = &o->mechs[j];
|
||||
if ((mech->usage_flags & CKF_SIGN) == 0) {
|
||||
/* not applicable mechanisms are skipped */
|
||||
continue;
|
||||
}
|
||||
printf(" [ %-20s ] [ %s ] [ %s ] [ ] [ ]\n",
|
||||
get_mechanism_name(mech->mech),
|
||||
mech->result_flags & FLAGS_SIGN_ANY ? "[./]" : " ",
|
||||
mech->result_flags & FLAGS_DECRYPT_ANY ? "[./]" : " ");
|
||||
if ((mech->result_flags & FLAGS_SIGN_ANY) == 0 &&
|
||||
(mech->result_flags & FLAGS_DECRYPT_ANY) == 0)
|
||||
continue; /* skip empty rows for export */
|
||||
P11TEST_DATA_ROW(info, 4,
|
||||
's', o->id_str,
|
||||
's', get_mechanism_name(mech->mech),
|
||||
's', mech->result_flags & FLAGS_SIGN_ANY ? "YES" : "",
|
||||
's', mech->result_flags & FLAGS_DECRYPT_ANY ? "YES" : "");
|
||||
}
|
||||
}
|
||||
printf(" Public == Cert -----^ ^ ^ ^ ^ ^ ^ ^----^- Attributes\n");
|
||||
printf(" Sign Attribute -------------' | | | | '---- Decrypt Attribute\n");
|
||||
printf(" Sign&Verify functionality -----' | | '------- Enc&Dec functionality\n");
|
||||
printf(" Verify Attribute -----------------' '---------- Encrypt Attribute\n");
|
||||
|
||||
clean_all_objects(&objects);
|
||||
P11TEST_PASS(info);
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* p11test_case_readonly.h: Sign & Verify tests
|
||||
*
|
||||
* Copyright (C) 2016, 2017 Red Hat, Inc.
|
||||
*
|
||||
* Author: Jakub Jelen <jjelen@redhat.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "p11test_case_common.h"
|
||||
|
||||
void readonly_tests(void **state);
|
||||
int encrypt_decrypt_test(test_cert_t *o, token_info_t *info, test_mech_t *mech,
|
||||
CK_ULONG message_length, int multipart);
|
||||
int sign_verify_test(test_cert_t *o, token_info_t *info, test_mech_t *mech,
|
||||
CK_ULONG message_length, int multipart);
|
||||
|
|
@ -0,0 +1,137 @@
|
|||
/*
|
||||
* p11test_case_usage.c: Check if the usage flags are sane
|
||||
*
|
||||
* Copyright (C) 2016, 2017 Red Hat, Inc.
|
||||
*
|
||||
* Author: Jakub Jelen <jjelen@redhat.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "p11test_case_usage.h"
|
||||
|
||||
void usage_test(void **state) {
|
||||
unsigned int i;
|
||||
int errors = 0;
|
||||
token_info_t *info = (token_info_t *) *state;
|
||||
|
||||
test_certs_t objects;
|
||||
objects.count = 0;
|
||||
objects.data = NULL;
|
||||
|
||||
P11TEST_START(info);
|
||||
search_for_all_objects(&objects, info);
|
||||
|
||||
debug_print("Check if the usage flags are sane.\n");
|
||||
for (i = 0; i < objects.count; i++) {
|
||||
/* Ignore if there is missing private key */
|
||||
if (objects.data[i].private_handle == CK_INVALID_HANDLE)
|
||||
continue;
|
||||
|
||||
/* The usage flags are paired */
|
||||
if (objects.data[i].sign && !objects.data[i].verify) {
|
||||
errors++;
|
||||
fprintf(stderr, " [ ERROR %s ] If Sign is set, Verify should be set too.\n",
|
||||
objects.data[i].id_str);
|
||||
}
|
||||
if (objects.data[i].decrypt && !objects.data[i].encrypt) {
|
||||
errors++;
|
||||
fprintf(stderr, " [ ERROR %s ] If Decrypt is set, Encrypt should be set too.\n",
|
||||
objects.data[i].id_str);
|
||||
}
|
||||
if (objects.data[i].unwrap && !objects.data[i].wrap) {
|
||||
errors++;
|
||||
fprintf(stderr, " [ ERROR %s ] If Unwrap is set, Wrap should be set too.\n",
|
||||
objects.data[i].id_str);
|
||||
}
|
||||
if (objects.data[i].derive_pub != objects.data[i].derive_priv) {
|
||||
errors++;
|
||||
fprintf(stderr, " [ ERROR %s ] Derive should be set on both private and public part.\n",
|
||||
objects.data[i].id_str);
|
||||
}
|
||||
|
||||
/* We have at least one usage flag for every key group */
|
||||
if (! objects.data[i].sign && ! objects.data[i].verify &&
|
||||
! objects.data[i].encrypt && ! objects.data[i].decrypt &&
|
||||
! objects.data[i].wrap && ! objects.data[i].unwrap &&
|
||||
! objects.data[i].derive_pub && ! objects.data[i].derive_priv) {
|
||||
errors++;
|
||||
fprintf(stderr, " [ ERROR %s ] Key group should have at least one usage flag.\n",
|
||||
objects.data[i].id_str);
|
||||
}
|
||||
}
|
||||
|
||||
/* print summary */
|
||||
printf("[KEY ID] [LABEL]\n");
|
||||
printf("[ TYPE ] [ SIZE ] [PUBLIC] [SIGN&VERIFY] [ENC&DECRYPT] [WRAP&UNWR] [ DERIVE ] [ALWAYS_AUTH]\n");
|
||||
P11TEST_DATA_ROW(info, 14,
|
||||
's', "KEY ID",
|
||||
's', "LABEL",
|
||||
's', "TYPE",
|
||||
's', "BITS",
|
||||
's', "VERIFY PUBKEY",
|
||||
's', "SIGN",
|
||||
's', "VERIFY",
|
||||
's', "ENCRYPT",
|
||||
's', "DECRYPT",
|
||||
's', "WRAP",
|
||||
's', "UNWRAP",
|
||||
's', "DERIVE PUBLIC",
|
||||
's', "DERIVE PRIVATE",
|
||||
's', "ALWAYS AUTH");
|
||||
for (i = 0; i < objects.count; i++) {
|
||||
printf("\n[%-6s] [%s]\n",
|
||||
objects.data[i].id_str,
|
||||
objects.data[i].label);
|
||||
printf("[ %s ] [%6lu] [ %s ] [%s%s] [%s%s] [%s %s] [%s%s] [ %s ]\n",
|
||||
objects.data[i].key_type == CKK_RSA ? "RSA " :
|
||||
objects.data[i].key_type == CKK_EC ? " EC " : " ?? ",
|
||||
objects.data[i].bits,
|
||||
objects.data[i].verify_public == 1 ? " ./ " : " ",
|
||||
objects.data[i].sign ? "[./] " : "[ ] ",
|
||||
objects.data[i].verify ? " [./] " : " [ ] ",
|
||||
objects.data[i].encrypt ? "[./] " : "[ ] ",
|
||||
objects.data[i].decrypt ? " [./] " : " [ ] ",
|
||||
objects.data[i].wrap ? "[./]" : "[ ]",
|
||||
objects.data[i].unwrap ? "[./]" : "[ ]",
|
||||
objects.data[i].derive_pub ? "[./]" : "[ ]",
|
||||
objects.data[i].derive_priv ? "[./]" : "[ ]",
|
||||
objects.data[i].always_auth ? "[./]" : "[ ]");
|
||||
P11TEST_DATA_ROW(info, 14,
|
||||
's', objects.data[i].id_str,
|
||||
's', objects.data[i].label,
|
||||
's', objects.data[i].key_type == CKK_RSA ? "RSA" :
|
||||
objects.data[i].key_type == CKK_EC ? "EC" : "??",
|
||||
'd', objects.data[i].bits,
|
||||
's', objects.data[i].verify_public == 1 ? "YES" : "",
|
||||
's', objects.data[i].sign ? "YES" : "",
|
||||
's', objects.data[i].verify ? "YES" : "",
|
||||
's', objects.data[i].encrypt ? "YES" : "",
|
||||
's', objects.data[i].decrypt ? "YES" : "",
|
||||
's', objects.data[i].wrap ? "YES" : "",
|
||||
's', objects.data[i].unwrap ? "YES" : "",
|
||||
's', objects.data[i].derive_pub ? "YES" : "",
|
||||
's', objects.data[i].derive_priv ? "YES" : "",
|
||||
's', objects.data[i].always_auth ? "YES" : "");
|
||||
}
|
||||
printf(" Public == Cert -----^ ^-----^ ^-----^ ^----^ ^---^\n");
|
||||
printf(" Sign & Verify Attributes ------' | | |\n");
|
||||
printf(" Encrypt & Decrypt Attributes ----------------' | |\n");
|
||||
printf(" Wrap & Unwrap Attributes ---------------------------------' |\n");
|
||||
printf(" Public and Private key Derive Attributes -----------------------------'\n");
|
||||
|
||||
clean_all_objects(&objects);
|
||||
if (errors > 0)
|
||||
P11TEST_FAIL(info, "Not all the usage flags were successfully verified. See the verbose log.");
|
||||
P11TEST_PASS(info);
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* p11test_case_usage.h: Check if the usage flags are sane
|
||||
*
|
||||
* Copyright (C) 2016, 2017 Red Hat, Inc.
|
||||
*
|
||||
* Author: Jakub Jelen <jjelen@redhat.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "p11test_case_common.h"
|
||||
#include "p11test_case_readonly.h"
|
||||
|
||||
void usage_test(void **state);
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* p11test_case_wait.c: Test slot events (insert / remove)
|
||||
*
|
||||
* Copyright (C) 2016, 2017 Red Hat, Inc.
|
||||
*
|
||||
* Author: Jakub Jelen <jjelen@redhat.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "p11test_case_wait.h"
|
||||
|
||||
void wait_test(void **state) {
|
||||
|
||||
token_info_t *info = (token_info_t *) *state;
|
||||
CK_FUNCTION_LIST_PTR fp = info->function_pointer;
|
||||
CK_RV rv;
|
||||
CK_SLOT_ID slot_id;
|
||||
CK_SLOT_INFO slot_info;
|
||||
int token_present = 0;
|
||||
|
||||
P11TEST_START(info);
|
||||
if (!info->interactive) {
|
||||
fprintf(stderr, "To test wait, run in interactive mode (-i switch).\n");
|
||||
P11TEST_SKIP(info);
|
||||
}
|
||||
|
||||
do {
|
||||
printf(" [ Waiting for slot event ... ]\n");
|
||||
|
||||
rv = fp->C_WaitForSlotEvent(0, &slot_id, NULL_PTR);
|
||||
if (rv == CKR_FUNCTION_NOT_SUPPORTED) {
|
||||
fprintf(stderr, "Function does not support call with blocking wait. Skipping.\n");
|
||||
skip();
|
||||
} else if (rv != CKR_OK)
|
||||
P11TEST_FAIL(info, "C_WaitForSlotEvent: rv = 0x%.8lX\n", rv);
|
||||
|
||||
rv = fp->C_GetSlotInfo(slot_id, &slot_info);
|
||||
if (rv != CKR_OK)
|
||||
P11TEST_FAIL(info, "C_GetSlotInfo: rv = 0x%.8lX\n", rv);
|
||||
|
||||
token_present = ((slot_info.flags & CKF_TOKEN_PRESENT) != 0);
|
||||
|
||||
printf(" [ Slot %lu ] %s\n", slot_id, slot_info.slotDescription);
|
||||
printf(" Status: %s\n",
|
||||
token_present ? "Token present": "No token");
|
||||
} while (!token_present);
|
||||
P11TEST_PASS(info);
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* p11test_case_wait.h: Test slot events (insert / remove)
|
||||
*
|
||||
* Copyright (C) 2016, 2017 Red Hat, Inc.
|
||||
*
|
||||
* Author: Jakub Jelen <jjelen@redhat.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "p11test_case_common.h"
|
||||
|
||||
void wait_test(void **state);
|
||||
|
|
@ -0,0 +1,89 @@
|
|||
/*
|
||||
* p11test_common.h: Test suite shared declarations for PKCS#11 API
|
||||
*
|
||||
* Copyright (C) 2016 Martin Strhársky <strharsky.martin@gmail.com>
|
||||
* Copyright (C) 2016, 2017 Red Hat, Inc.
|
||||
*
|
||||
* Author: Jakub Jelen <jjelen@redhat.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef P11TEST_COMMON_H
|
||||
#define P11TEST_COMMON_H
|
||||
#include "config.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <setjmp.h>
|
||||
#include <cmocka.h>
|
||||
#include "pkcs11/pkcs11.h"
|
||||
#include "libopensc/sc-ossl-compat.h"
|
||||
|
||||
#define MAX_MECHS 200
|
||||
|
||||
#ifndef NDEBUG
|
||||
#define debug_print(fmt, ...) \
|
||||
{ fprintf(stderr, fmt "\n", ##__VA_ARGS__); } while (0)
|
||||
#else
|
||||
#define debug_print(fmt, ...)
|
||||
#endif
|
||||
|
||||
#define FLAGS_SIGN 0x01
|
||||
#define FLAGS_SIGN_OPENSSL 0x02
|
||||
#define FLAGS_SIGN_ANY ( FLAGS_SIGN | FLAGS_SIGN_OPENSSL )
|
||||
#define FLAGS_DECRYPT 0x04
|
||||
#define FLAGS_DECRYPT_OPENSSL 0x08
|
||||
#define FLAGS_DECRYPT_ANY ( FLAGS_DECRYPT | FLAGS_DECRYPT_OPENSSL )
|
||||
|
||||
typedef struct {
|
||||
char *outfile;
|
||||
FILE *fd;
|
||||
int in_test;
|
||||
int first;
|
||||
int in_data;
|
||||
int first_data;
|
||||
} log_context_t;
|
||||
|
||||
typedef struct {
|
||||
CK_MECHANISM_TYPE mech;
|
||||
CK_MECHANISM_TYPE hash;
|
||||
CK_RSA_PKCS_MGF_TYPE mgf;
|
||||
int salt;
|
||||
int usage_flags;
|
||||
int result_flags;
|
||||
} test_mech_t;
|
||||
|
||||
typedef struct {
|
||||
CK_FUNCTION_LIST_PTR function_pointer;
|
||||
CK_SLOT_ID slot_id;
|
||||
CK_SESSION_HANDLE session_handle;
|
||||
CK_UTF8CHAR* pin;
|
||||
size_t pin_length;
|
||||
char *library_path;
|
||||
unsigned int interactive;
|
||||
log_context_t log;
|
||||
|
||||
test_mech_t rsa_mechs[MAX_MECHS];
|
||||
size_t num_rsa_mechs;
|
||||
test_mech_t ec_mechs[MAX_MECHS];
|
||||
size_t num_ec_mechs;
|
||||
test_mech_t keygen_mechs[MAX_MECHS];
|
||||
size_t num_keygen_mechs;
|
||||
} token_info_t;
|
||||
|
||||
token_info_t token;
|
||||
|
||||
#endif /* P11TEST_COMMON_H */
|
||||
|
|
@ -0,0 +1,207 @@
|
|||
/*
|
||||
* p11test_helpers.c: Test suite for PKCS#11 API: Supporting functions
|
||||
*
|
||||
* Copyright (C) 2016 Martin Strhársky <strharsky.martin@gmail.com>
|
||||
* Copyright (C) 2016, 2017 Red Hat, Inc.
|
||||
*
|
||||
* Author: Jakub Jelen <jjelen@redhat.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "p11test_helpers.h"
|
||||
#include "p11test_loader.h"
|
||||
|
||||
int open_session(token_info_t *info) {
|
||||
CK_FUNCTION_LIST_PTR function_pointer = info->function_pointer;
|
||||
CK_RV rv;
|
||||
|
||||
rv = function_pointer->C_OpenSession(info->slot_id,
|
||||
CKF_SERIAL_SESSION | CKF_RW_SESSION, NULL_PTR, NULL_PTR,
|
||||
&info->session_handle);
|
||||
|
||||
if(rv != CKR_OK)
|
||||
return 1;
|
||||
|
||||
debug_print("Session was successfully created");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int initialize_cryptoki(token_info_t *info) {
|
||||
|
||||
CK_FUNCTION_LIST_PTR function_pointer = info->function_pointer;
|
||||
CK_RV rv;
|
||||
|
||||
rv = function_pointer->C_Initialize(NULL_PTR);
|
||||
if(rv != CKR_OK){
|
||||
fprintf(stderr,"Could not initialize CRYPTOKI!\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(get_slot_with_card(info)) {
|
||||
function_pointer->C_Finalize(NULL_PTR);
|
||||
fprintf(stderr,"There is no card present in reader.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int token_initialize(void **state) {
|
||||
token_info_t *info = (token_info_t *) *state;
|
||||
if(initialize_cryptoki(info)) {
|
||||
debug_print("CRYPTOKI couldn't be initialized");
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void logfile_init(token_info_t *info) {
|
||||
if (token.log.outfile == NULL)
|
||||
return;
|
||||
|
||||
if ((info->log.fd = fopen(token.log.outfile, "w")) == NULL)
|
||||
fail_msg("Couldn't open file for test results.");
|
||||
fprintf(info->log.fd, "{\n\"time\": 0,\n\"results\": [");
|
||||
info->log.in_test = 0;
|
||||
info->log.first = 1;
|
||||
}
|
||||
|
||||
void logfile_finalize(token_info_t *info) {
|
||||
if (info == NULL || info->log.fd == NULL)
|
||||
return;
|
||||
|
||||
/* Make sure the JSON object for test is closed */
|
||||
if (info->log.in_test) {
|
||||
fprintf(info->log.fd, ",\n\t\"result\": \"unknown\"\n},");
|
||||
info->log.in_test = 0;
|
||||
}
|
||||
|
||||
fprintf(info->log.fd, "]\n}\n");
|
||||
fclose(info->log.fd);
|
||||
}
|
||||
|
||||
int group_setup(void **state)
|
||||
{
|
||||
|
||||
token_info_t * info = calloc(sizeof(token_info_t), 1);
|
||||
|
||||
assert_non_null(info);
|
||||
|
||||
info->pin = token.pin;
|
||||
info->pin_length = token.pin_length;
|
||||
info->interactive = token.interactive;
|
||||
info->slot_id = token.slot_id;
|
||||
|
||||
if (load_pkcs11_module(info, token.library_path)) {
|
||||
free(info);
|
||||
fail_msg("Could not load module!\n");
|
||||
}
|
||||
|
||||
logfile_init(info);
|
||||
|
||||
*state = info;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int group_teardown(void **state) {
|
||||
|
||||
token_info_t *info = (token_info_t *) *state;
|
||||
debug_print("Clearing state after group tests!");
|
||||
// XXX do not finalize already Finalized
|
||||
//if(info && info->function_pointer)
|
||||
// info->function_pointer->C_Finalize(NULL_PTR);
|
||||
|
||||
free(token.library_path);
|
||||
free(token.pin);
|
||||
|
||||
logfile_finalize(info);
|
||||
free(info);
|
||||
|
||||
close_pkcs11_module();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int prepare_token(token_info_t *info) {
|
||||
if(initialize_cryptoki(info)) {
|
||||
debug_print("CRYPTOKI couldn't be initialized");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(open_session(info)) {
|
||||
debug_print("Could not open session to token!");
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int finalize_token(token_info_t *info) {
|
||||
CK_FUNCTION_LIST_PTR function_pointer = info->function_pointer;
|
||||
|
||||
info->session_handle = 0;
|
||||
debug_print("Closing all sessions");
|
||||
function_pointer->C_CloseAllSessions(info->slot_id);
|
||||
debug_print("Finalize CRYPTOKI");
|
||||
function_pointer->C_Finalize(NULL_PTR);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int user_login_setup(void **state) {
|
||||
token_info_t *info = (token_info_t *) *state;
|
||||
CK_FUNCTION_LIST_PTR function_pointer = info->function_pointer;
|
||||
CK_RV rv;
|
||||
|
||||
if (prepare_token(info))
|
||||
fail_msg("Could not prepare token.\n");
|
||||
|
||||
debug_print("Logging in to the token!");
|
||||
rv = function_pointer->C_Login(info->session_handle, CKU_USER,
|
||||
token.pin, token.pin_length);
|
||||
|
||||
if(rv != CKR_OK)
|
||||
fail_msg("Could not login to token with user PIN '%s'\n", token.pin);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int after_test_cleanup(void **state) {
|
||||
|
||||
token_info_t *info = (token_info_t *) *state;
|
||||
CK_FUNCTION_LIST_PTR function_pointer = info->function_pointer;
|
||||
|
||||
debug_print("Logging out from token");
|
||||
function_pointer->C_Logout(info->session_handle);
|
||||
|
||||
finalize_token(info);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int token_setup(void **state) {
|
||||
token_info_t *info = (token_info_t *) *state;
|
||||
|
||||
if(prepare_token(info))
|
||||
fail_msg("Could not prepare token.\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int token_cleanup(void **state) {
|
||||
token_info_t *info = (token_info_t *) *state;
|
||||
|
||||
finalize_token(info);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* p11test_helpers.h: Test suite for PKCS#11 API: Supporting functions
|
||||
*
|
||||
* Copyright (C) 2016 Martin Strhársky <strharsky.martin@gmail.com>
|
||||
* Copyright (C) 2016, 2017 Red Hat, Inc.
|
||||
*
|
||||
* Author: Jakub Jelen <jjelen@redhat.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef P11TEST_HELPERS_H
|
||||
#define P11TEST_HELPERS_H
|
||||
#include "p11test_common.h"
|
||||
|
||||
int group_setup(void **state);
|
||||
int group_teardown(void **state);
|
||||
|
||||
int user_login_setup(void **state);
|
||||
int after_test_cleanup(void **state);
|
||||
|
||||
int token_setup(void **state);
|
||||
int token_cleanup(void **state);
|
||||
|
||||
int token_initialize(void **state);
|
||||
#endif //P11TEST_HELPERS_H
|
|
@ -0,0 +1,147 @@
|
|||
/*
|
||||
* p11test_loader.c: Library loader for PKCS#11 test suite
|
||||
*
|
||||
* Copyright (C) 2016 Martin Strhársky <strharsky.martin@gmail.com>
|
||||
* Copyright (C) 2016, 2017 Red Hat, Inc.
|
||||
*
|
||||
* Author: Jakub Jelen <jjelen@redhat.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "p11test_loader.h"
|
||||
|
||||
static void *pkcs11_so;
|
||||
|
||||
int get_slot_with_card(token_info_t * info)
|
||||
{
|
||||
CK_SLOT_ID_PTR slot_list;
|
||||
CK_SLOT_ID slot_id;
|
||||
CK_ULONG slot_count = 0;
|
||||
CK_RV rv;
|
||||
int error = 0;
|
||||
unsigned int i;
|
||||
|
||||
CK_FUNCTION_LIST_PTR function_pointer = info->function_pointer;
|
||||
|
||||
/* Get slot list for memory allocation */
|
||||
rv = function_pointer->C_GetSlotList(0, NULL_PTR, &slot_count);
|
||||
|
||||
if ((rv == CKR_OK) && (slot_count > 0)) {
|
||||
slot_list = malloc(slot_count * sizeof (CK_SLOT_ID));
|
||||
|
||||
if (slot_list == NULL) {
|
||||
fprintf(stderr, "System error: unable to allocate memory\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Get the slot list for processing */
|
||||
rv = function_pointer->C_GetSlotList(0, slot_list, &slot_count);
|
||||
if (rv != CKR_OK) {
|
||||
fprintf(stderr, "GetSlotList failed: unable to get slot count.\n");
|
||||
error = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr, "GetSlotList failed: unable to get slot list.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Find a slot capable of specified mechanism */
|
||||
for (i = 0; i < slot_count; i++) {
|
||||
CK_SLOT_INFO slot_info;
|
||||
slot_id = slot_list[i];
|
||||
|
||||
rv = function_pointer->C_GetSlotInfo(slot_id, &slot_info);
|
||||
if (rv != CKR_OK)
|
||||
continue;
|
||||
|
||||
if (info->slot_id == slot_id) {
|
||||
if (info->slot_id == slot_list[i]) { /* explicitly specified slot */
|
||||
debug_print("Manually selected slot %lu (%s a token)\n", info->slot_id,
|
||||
((slot_info.flags & CKF_TOKEN_PRESENT) ? "with" : "without"));
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
if (slot_info.flags & CKF_TOKEN_PRESENT) {
|
||||
/* first found slot if not specified */
|
||||
if (info->slot_id == (unsigned long) -1) {
|
||||
info->slot_id = slot_id;
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
}
|
||||
error = 1;
|
||||
fprintf(stderr, "No slot with card inserted or the selected slot does not exist\n");
|
||||
|
||||
cleanup:
|
||||
if (slot_list) {
|
||||
free(slot_list);
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
int load_pkcs11_module(token_info_t * info, const char* path_to_pkcs11_library) {
|
||||
CK_RV rv;
|
||||
CK_RV (*C_GetFunctionList)(CK_FUNCTION_LIST_PTR_PTR) = 0;
|
||||
|
||||
if(strlen(path_to_pkcs11_library) == 0) {
|
||||
fprintf(stderr, "You have to specify path to PKCS#11 library.");
|
||||
return 1;
|
||||
}
|
||||
|
||||
pkcs11_so = dlopen(path_to_pkcs11_library, RTLD_NOW);
|
||||
|
||||
if (!pkcs11_so) {
|
||||
fprintf(stderr, "Error loading pkcs#11 so: %s\n", dlerror());
|
||||
return 1;
|
||||
}
|
||||
|
||||
C_GetFunctionList = (CK_RV (*)(CK_FUNCTION_LIST_PTR_PTR)) dlsym(pkcs11_so, "C_GetFunctionList");
|
||||
|
||||
if (!C_GetFunctionList) {
|
||||
fprintf(stderr, "Could not get function list: %s\n", dlerror());
|
||||
return 1;
|
||||
}
|
||||
|
||||
rv = C_GetFunctionList(&info->function_pointer);
|
||||
if (CKR_OK != rv) {
|
||||
fprintf(stderr, "C_GetFunctionList call failed: 0x%.8lX", rv);
|
||||
return 1;
|
||||
}
|
||||
|
||||
rv = info->function_pointer->C_Initialize(NULL_PTR);
|
||||
|
||||
if (rv != CKR_OK) {
|
||||
fprintf(stderr, "C_Initialize: Error = 0x%.8lX\n", rv);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (get_slot_with_card(info)) {
|
||||
fprintf(stderr, "There is no card present in reader.\n");
|
||||
info->function_pointer->C_Finalize(NULL_PTR);
|
||||
return 1;
|
||||
}
|
||||
|
||||
info->function_pointer->C_Finalize(NULL_PTR);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void close_pkcs11_module() {
|
||||
if(pkcs11_so)
|
||||
dlclose(pkcs11_so);
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* p11test_loader.h: Library loader for PKCS#11 test suite
|
||||
*
|
||||
* Copyright (C) 2016 Martin Strhársky <strharsky.martin@gmail.com>
|
||||
* Copyright (C) 2016, 2017 Red Hat, Inc.
|
||||
*
|
||||
* Author: Jakub Jelen <jjelen@redhat.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef P11TEST_LOADER_H
|
||||
#define P11TEST_LOADER_H
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include "p11test_helpers.h"
|
||||
|
||||
int load_pkcs11_module(token_info_t * info, const char* path_to_pkcs11_library);
|
||||
int get_slot_with_card(token_info_t * info);
|
||||
void close_pkcs11_module();
|
||||
|
||||
|
||||
#endif //P11TEST_LOADER_H
|
|
@ -0,0 +1,145 @@
|
|||
#!/bin/bash
|
||||
# runtest.sh: Run test on existing card with possible initialization
|
||||
#
|
||||
# Copyright (C) 2016, 2017 Red Hat, Inc.
|
||||
#
|
||||
# Author: Jakub Jelen <jjelen@redhat.com>
|
||||
#
|
||||
# This library is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU Lesser General Public
|
||||
# License as published by the Free Software Foundation; either
|
||||
# version 2.1 of the License, or (at your option) any later version.
|
||||
#
|
||||
# This library is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#set -x
|
||||
SOPIN="12345678"
|
||||
PIN="123456"
|
||||
export GNUTLS_PIN=$PIN
|
||||
GENERATE_KEYS=1
|
||||
PKCS11_TOOL="../../tools/pkcs11-tool";
|
||||
|
||||
function generate_cert() {
|
||||
TYPE="$1"
|
||||
ID="$2"
|
||||
LABEL="$3"
|
||||
|
||||
# Generate key pair
|
||||
$PKCS11_TOOL --keypairgen --key-type="$TYPE" --login --pin=$PIN \
|
||||
--module="$P11LIB" --label="$LABEL" --id=$ID
|
||||
|
||||
if [[ "$?" -ne "0" ]]; then
|
||||
echo "Couldn't generate $TYPE key pair"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# check type value for the PKCS#11 URI (RHEL7 is using old "object-type")
|
||||
TYPE_KEY="type"
|
||||
p11tool --list-all --provider="$P11LIB" --login | grep "object-type" && \
|
||||
TYPE_KEY="object-type"
|
||||
|
||||
# Generate certificate
|
||||
certtool --generate-self-signed --outfile="$TYPE.cert" --template=cert.cfg \
|
||||
--provider="$P11LIB" --load-privkey "pkcs11:object=$LABEL;$TYPE_KEY=private" \
|
||||
--load-pubkey "pkcs11:object=$LABEL;$TYPE_KEY=public"
|
||||
# convert to DER:
|
||||
openssl x509 -inform PEM -outform DER -in "$TYPE.cert" -out "$TYPE.cert.der"
|
||||
# Write certificate
|
||||
#p11tool --login --write --load-certificate="$TYPE.cert" --label="$LABEL" \
|
||||
# --provider="$P11LIB"
|
||||
$PKCS11_TOOL --write-object "$TYPE.cert.der" --type=cert --id=$ID \
|
||||
--label="$LABEL" --module="$P11LIB"
|
||||
|
||||
rm "$TYPE.cert" "$TYPE.cert.der"
|
||||
|
||||
p11tool --login --provider="$P11LIB" --list-all
|
||||
}
|
||||
|
||||
function card_setup() {
|
||||
ECC_KEYS=1
|
||||
case $1 in
|
||||
"softhsm")
|
||||
P11LIB="/usr/lib64/pkcs11/libsofthsm2.so"
|
||||
echo "directories.tokendir = .tokens/" > .softhsm2.conf
|
||||
mkdir ".tokens"
|
||||
export SOFTHSM2_CONF=".softhsm2.conf"
|
||||
# Init token
|
||||
softhsm2-util --init-token --slot 0 --label "SC test" --so-pin="$SOPIN" --pin="$PIN"
|
||||
;;
|
||||
"opencryptoki")
|
||||
# Supports only RSA mechanisms
|
||||
ECC_KEYS=0
|
||||
P11LIB="/usr/lib64/pkcs11/libopencryptoki.so"
|
||||
SO_PIN=87654321
|
||||
SLOT_ID=3 # swtok slot
|
||||
systemctl is-active pkcsslotd > /dev/null
|
||||
if [[ "$?" -ne "0" ]]; then
|
||||
echo "Opencryptoki needs pkcsslotd running"
|
||||
exit 1
|
||||
fi
|
||||
groups | grep pkcs11 > /dev/null
|
||||
if [[ "$?" -ne "0" ]]; then
|
||||
echo "Opencryptoki requires the user to be in pkcs11 group"
|
||||
exit 1
|
||||
fi
|
||||
echo "test_swtok" | /usr/sbin/pkcsconf -I -c $SLOT_ID -S $SO_PIN
|
||||
/usr/sbin/pkcsconf -u -c $SLOT_ID -S $SO_PIN -n $PIN
|
||||
;;
|
||||
"readonly")
|
||||
GENERATE_KEYS=0
|
||||
if [[ ! -z "$2" && -f "$2" ]]; then
|
||||
P11LIB="$2"
|
||||
else
|
||||
P11LIB="/usr/lib64/pkcs11/opensc-pkcs11.so"
|
||||
P11LIB="../pkcs11/.libs/opensc-pkcs11.so"
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
echo "Error: Missing argument."
|
||||
echo " Usage:"
|
||||
echo " runtest.sh [softhsm|opencryptoki|readonly [pkcs-library.so]]"
|
||||
exit 1;
|
||||
;;
|
||||
esac
|
||||
|
||||
if [[ $GENERATE_KEYS -eq 1 ]]; then
|
||||
# Generate 1024b RSA Key pair
|
||||
generate_cert "RSA:1024" "01" "RSA_auth"
|
||||
# Generate 2048b RSA Key pair
|
||||
generate_cert "RSA:2048" "02" "RSA2048"
|
||||
if [[ $ECC_KEYS -eq 1 ]]; then
|
||||
# Generate 256b ECC Key pair
|
||||
generate_cert "EC:secp256r1" "03" "ECC_auth"
|
||||
# Generate 521b ECC Key pair
|
||||
generate_cert "EC:secp521r1" "04" "ECC521"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
function card_cleanup() {
|
||||
case $1 in
|
||||
"softhsm")
|
||||
rm .softhsm2.conf
|
||||
rm -rf ".tokens"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
card_setup "$@"
|
||||
|
||||
make p11test || exit
|
||||
if [[ "$PKCS11SPY" -ne "" ]]; then
|
||||
export PKCS11SPY="$P11LIB"
|
||||
$VALGRIND ./p11test -m /usr/lib64/pkcs11/pkcs11-spy.so -p $PIN
|
||||
else
|
||||
#bash
|
||||
$VALGRIND ./p11test -m "$P11LIB" -o test.json -p $PIN
|
||||
fi
|
||||
|
||||
card_cleanup "$@"
|
|
@ -20,6 +20,9 @@ WIXVSVER = VS2015
|
|||
WIX_INCL_DIR = "/I$(WIX)\SDK\$(WIXVSVER)\inc"
|
||||
WIX_LIBS = "$(WIX)\SDK\$(WIXVSVER)\lib\$(PLATFORM)\dutil.lib" "$(WIX)\SDK\$(WIXVSVER)\lib\$(PLATFORM)\wcautil.lib"
|
||||
|
||||
# We do not build tests on windows
|
||||
#TESTS_DEF = /DENABLE_TESTS
|
||||
|
||||
#Include support for Secure Messaging
|
||||
SM_DEF = /DENABLE_SM
|
||||
|
||||
|
@ -137,10 +140,10 @@ ALL_INCLUDES = /I$(TOPDIR)\win32 /I$(TOPDIR)\src $(OPENPACE_INCL_DIR) $(OPENSSL_
|
|||
!IF "$(DEBUG_DEF)" == "/DDEBUG"
|
||||
LINKDEBUGFLAGS = /NODEFAULTLIB:LIBCMT /DEBUG
|
||||
CODE_OPTIMIZATION =
|
||||
COPTS = /GS /W3 /WX /D_CRT_SECURE_NO_DEPRECATE /D_CRT_NONSTDC_NO_WARNINGS /MTd /nologo /DHAVE_CONFIG_H $(ALL_INCLUDES) /DWINVER=0x0601 /D_WIN32_WINNT=0x0601 /DWIN32_LEAN_AND_MEAN $(OPENPACE_DEF) $(OPENSSL_DEF) $(ZLIB_DEF) $(MINIDRIVER_DEF) $(SM_DEF) /DOPENSC_FEATURES="\"$(OPENSC_FEATURES)\"" /DDEBUG /Zi /Od
|
||||
COPTS = /GS /W3 /WX /D_CRT_SECURE_NO_DEPRECATE /D_CRT_NONSTDC_NO_WARNINGS /MTd /nologo /DHAVE_CONFIG_H $(ALL_INCLUDES) /DWINVER=0x0601 /D_WIN32_WINNT=0x0601 /DWIN32_LEAN_AND_MEAN $(OPENPACE_DEF) $(OPENSSL_DEF) $(ZLIB_DEF) $(MINIDRIVER_DEF) $(SM_DEF) $(TESTS_DEF) /DOPENSC_FEATURES="\"$(OPENSC_FEATURES)\"" /DDEBUG /Zi /Od
|
||||
!ELSE
|
||||
LINKDEBUGFLAGS = /NODEFAULTLIB:LIBCMTD /DEBUG /OPT:REF /OPT:ICF
|
||||
COPTS = /GS /W3 /WX /D_CRT_SECURE_NO_DEPRECATE /D_CRT_NONSTDC_NO_WARNINGS /MT /nologo /DHAVE_CONFIG_H $(ALL_INCLUDES) /DWINVER=0x0601 /D_WIN32_WINNT=0x0601 /DWIN32_LEAN_AND_MEAN $(OPENPACE_DEF) $(OPENSSL_DEF) $(ZLIB_DEF) $(MINIDRIVER_DEF) $(SM_DEF) /DOPENSC_FEATURES="\"$(OPENSC_FEATURES)\"" /Zi
|
||||
COPTS = /GS /W3 /WX /D_CRT_SECURE_NO_DEPRECATE /D_CRT_NONSTDC_NO_WARNINGS /MT /nologo /DHAVE_CONFIG_H $(ALL_INCLUDES) /DWINVER=0x0601 /D_WIN32_WINNT=0x0601 /DWIN32_LEAN_AND_MEAN $(OPENPACE_DEF) $(OPENSSL_DEF) $(ZLIB_DEF) $(MINIDRIVER_DEF) $(SM_DEF) $(TESTS_DEF) /DOPENSC_FEATURES="\"$(OPENSC_FEATURES)\"" /Zi
|
||||
!ENDIF
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue