diff --git a/.github/workflows/wolfssl-master-compatibility.yml b/.github/workflows/wolfssl-master-compatibility.yml new file mode 100644 index 00000000..039a7f53 --- /dev/null +++ b/.github/workflows/wolfssl-master-compatibility.yml @@ -0,0 +1,32 @@ +name: wolfPKCS11 interoperability tests against wolfSSL upstream + +on: + push: + branches: [ 'master', 'main', 'release/**' ] + pull_request: + branches: [ '*' ] + schedule: + - cron: "0 1 * * *" + +jobs: + build: + runs-on: ubuntu-latest + steps: +#pull wolfPKCS11 + - uses: actions/checkout@v4 + with: + submodules: true + +#setup wolfssl at master branch + - uses: actions/checkout@v4 + with: + repository: wolfssl/wolfssl + ref: master + path: wolfssl + +# build + run tests + - name: Build and run interoperability test + working-directory: ./ + run: make -C tests/wolfssl-interoperability + + diff --git a/tests/testdata.h b/tests/testdata.h index d3ded20a..da5b0875 100644 --- a/tests/testdata.h +++ b/tests/testdata.h @@ -422,6 +422,124 @@ static const int sizeof_dh_2048_exp = sizeof(dh_2048_exp); #endif #ifndef NO_AES +/* NIST SP 800-38D, Test Case 4 */ +static const unsigned char aes_gcm_key[16] = { + 0xFE, 0xFF, 0xE9, 0x92, 0x86, 0x65, 0x73, 0x1C, + 0x6D, 0x6A, 0x8F, 0x94, 0x67, 0x30, 0x83, 0x08 +}; +static const unsigned char aes_gcm_iv[12] = { + 0xCA, 0xFE, 0xBA, 0xBE, 0xFA, 0xCE, 0xDB, 0xAD, + 0xDE, 0xCA, 0xF8, 0x88 +}; +static const unsigned char aes_gcm_plain[32] = { + 0xD9, 0x31, 0x32, 0x25, 0xF8, 0x84, 0x06, 0xE5, + 0xA5, 0x59, 0x09, 0xC5, 0xAF, 0xF5, 0x26, 0x9A, + 0x86, 0xA7, 0xA9, 0x53, 0x15, 0x34, 0xF7, 0xDA, + 0x2E, 0x4C, 0x30, 0x3D, 0x8A, 0x31, 0x8A, 0x72 +}; +static const unsigned char aes_gcm_aad[] = { + 0xFE, 0xED, 0xFA, 0xCE, 0xDE, 0xAD, 0xBE, 0xEF, + 0xFE, 0xED, 0xFA, 0xCE, 0xDE, 0xAD, 0xBE, 0xEF, + 0xAB, 0xAD, 0xDA, 0xD2 +}; +static const unsigned char aes_gcm_cipher[32] = { + 0x42, 0x83, 0x1E, 0xC2, 0x21, 0x77, 0x74, 0x24, + 0x4B, 0x72, 0x21, 0xB7, 0x84, 0xD0, 0xD4, 0x9C, + 0xE3, 0xAA, 0x21, 0x2F, 0x2C, 0x02, 0xA4, 0xE0, + 0x35, 0xC1, 0x7E, 0x23, 0x29, 0xAC, 0xA1, 0x2E +}; +static const unsigned char aes_gcm_tag[16] = { + 0xE1, 0x3E, 0x14, 0x34, 0x28, 0x5A, 0x94, 0x26, + 0xAD, 0xDF, 0xBF, 0xC2, 0x70, 0xD2, 0x7F, 0x16 +}; + +static const unsigned char aes_cbc_key[16] = { + 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, + 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C +}; +static const unsigned char aes_cbc_iv[16] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F +}; +static const unsigned char aes_cbc_plain[16] = { + 0x6B, 0xC1, 0xBE, 0xE2, 0x2E, 0x40, 0x9F, 0x96, + 0xE9, 0x3D, 0x7E, 0x11, 0x73, 0x93, 0x17, 0x2A +}; +static const unsigned char aes_cbc_cipher[16] = { + 0x76, 0x49, 0xAB, 0xAC, 0x81, 0x19, 0xB2, 0x46, + 0xCE, 0xE9, 0x8E, 0x9B, 0x12, 0xE9, 0x19, 0x7D +}; + +static const unsigned char aes_cbc256_key[32] = { + 0x60, 0x3D, 0xEB, 0x10, 0x15, 0xCA, 0x71, 0xBE, + 0x2B, 0x73, 0xAE, 0xF0, 0x85, 0x7D, 0x77, 0x81, + 0x1F, 0x35, 0x2C, 0x07, 0x3B, 0x61, 0x08, 0xD7, + 0x2D, 0x98, 0x10, 0xA3, 0x09, 0x14, 0xDF, 0xF4 +}; +static const unsigned char aes_cbc256_iv[16] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F +}; +static const unsigned char aes_cbc256_cipher[16] = { + 0xF5, 0x8C, 0x4C, 0x04, 0xD6, 0xE5, 0xF1, 0xBA, + 0x77, 0x9E, 0xAB, 0xFB, 0x5F, 0x7B, 0xFB, 0xD6 +}; + +static const unsigned char aes_ctr_key[16] = { + 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, + 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C +}; +static const unsigned char aes_ctr_iv[16] = { + 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, + 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF +}; +static const unsigned char aes_ctr_plain[16] = { + 0x6B, 0xC1, 0xBE, 0xE2, 0x2E, 0x40, 0x9F, 0x96, + 0xE9, 0x3D, 0x7E, 0x11, 0x73, 0x93, 0x17, 0x2A +}; +static const unsigned char aes_ctr_cipher[16] = { + 0x87, 0x4D, 0x61, 0x91, 0xB6, 0x20, 0xE3, 0x26, + 0x1B, 0xEF, 0x68, 0x64, 0x99, 0x0D, 0xB6, 0xCE +}; + +static const unsigned char aes_ctr256_key[32] = { + 0x60, 0x3D, 0xEB, 0x10, 0x15, 0xCA, 0x71, 0xBE, + 0x2B, 0x73, 0xAE, 0xF0, 0x85, 0x7D, 0x77, 0x81, + 0x1F, 0x35, 0x2C, 0x07, 0x3B, 0x61, 0x08, 0xD7, + 0x2D, 0x98, 0x10, 0xA3, 0x09, 0x14, 0xDF, 0xF4 +}; +static const unsigned char aes_ctr256_iv[16] = { + 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, + 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF +}; +static const unsigned char aes_ctr256_cipher[16] = { + 0x60, 0x1E, 0xC3, 0x13, 0x77, 0x57, 0x89, 0xA5, + 0xB7, 0xA7, 0xF5, 0x04, 0xBB, 0xF3, 0xD2, 0x28 +}; + +static const unsigned char aes_xts_key[32] = { + 0x39, 0x25, 0x79, 0x05, 0xDF, 0xCC, 0x77, 0x76, + 0x6C, 0x87, 0x0A, 0x80, 0x6A, 0x60, 0xE3, 0xC0, + 0x93, 0xD1, 0x2A, 0xCF, 0xCB, 0x51, 0x42, 0xFA, + 0x09, 0x69, 0x89, 0x62, 0x5B, 0x60, 0xDB, 0x16 +}; +static const unsigned char aes_xts_tweak[16] = { + 0x5C, 0xF7, 0x9D, 0xB6, 0xC5, 0xCD, 0x99, 0x1A, + 0x1C, 0x78, 0x81, 0x42, 0x24, 0x95, 0x1E, 0x84 +}; +static const unsigned char aes_xts_plain[32] = { + 0xBD, 0xC5, 0x46, 0x8F, 0xBC, 0x8D, 0x50, 0xA1, + 0x0D, 0x1C, 0x85, 0x7F, 0x79, 0x1C, 0x5C, 0xBA, + 0xB3, 0x81, 0x0D, 0x0D, 0x73, 0xCF, 0x8F, 0x20, + 0x46, 0xB1, 0xD1, 0x9E, 0x7D, 0x5D, 0x8A, 0x56 +}; +static const unsigned char aes_xts_cipher[32] = { + 0xD6, 0xBE, 0x04, 0x6D, 0x41, 0xF2, 0x3B, 0x5E, + 0xD7, 0x0B, 0x6B, 0x3D, 0x5C, 0x8E, 0x66, 0x23, + 0x2B, 0xE6, 0xB8, 0x07, 0xD4, 0xDC, 0xC6, 0x0E, + 0xFF, 0x8D, 0xBC, 0x1D, 0x9F, 0x7F, 0xC8, 0x22 +}; + static unsigned char aes_128_key[] = { 0xf7, 0x88, 0x9e, 0x9a, 0x5f, 0xe2, 0xaa, 0xca, 0xba, 0x14, 0x8a, 0xd3, 0xd1, 0x2d, 0x39, 0xe0, @@ -472,6 +590,61 @@ static unsigned char aes_128_cts_exp[] = { #endif #endif +static const unsigned char hmac_key[20] = { + 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, + 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, + 0x0B, 0x0B, 0x0B, 0x0B +}; +static const unsigned char hmac_msg[] = { + 'H', 'i', ' ', 'T', 'h', 'e', 'r', 'e' +}; +static const unsigned char hmac_digest[32] = { + 0xB0, 0x34, 0x4C, 0x61, 0xD8, 0xDB, 0x38, 0x53, + 0x5C, 0xA8, 0xAF, 0xCE, 0xAF, 0x0B, 0xF1, 0x2B, + 0x88, 0x1D, 0xC2, 0x00, 0xC9, 0x83, 0x3D, 0xA7, + 0x26, 0xE9, 0x37, 0x6C, 0x2E, 0x32, 0xCF, 0xF7 +}; + +static const unsigned char sha_test_msg[] = { 'a', 'b', 'c' }; +static const unsigned char sha224_expected[] = { + 0x23, 0x09, 0x7D, 0x22, 0x34, 0x05, 0xD8, 0x22, + 0x86, 0x42, 0xA4, 0x77, 0xBD, 0xA2, 0x55, 0xB3, + 0x2A, 0xAD, 0xBC, 0xE4, 0xBD, 0xA0, 0xB3, 0xF7, + 0xE3, 0x6C, 0x9D, 0xA7 +}; +static const unsigned char sha256_expected[] = { + 0xBA, 0x78, 0x16, 0xBF, 0x8F, 0x01, 0xCF, 0xEA, + 0x41, 0x41, 0x40, 0xDE, 0x5D, 0xAE, 0x22, 0x23, + 0xB0, 0x03, 0x61, 0xA3, 0x96, 0x17, 0x7A, 0x9C, + 0xB4, 0x10, 0xFF, 0x61, 0xF2, 0x00, 0x15, 0xAD +}; +static const unsigned char sha384_expected[] = { + 0xCB, 0x00, 0x75, 0x3F, 0x45, 0xA3, 0x5E, 0x8B, + 0xB5, 0xA0, 0x3D, 0x69, 0x9A, 0xC6, 0x50, 0x07, + 0x27, 0x2C, 0x32, 0xAB, 0x0E, 0xDE, 0xD1, 0x63, + 0x1A, 0x8B, 0x60, 0x5A, 0x43, 0xFF, 0x5B, 0xED, + 0x80, 0x86, 0x07, 0x2B, 0xA1, 0xE7, 0xCC, 0x23, + 0x58, 0xBA, 0xEC, 0xA1, 0x34, 0xC8, 0x25, 0xA7 +}; +static const unsigned char sha512_expected[] = { + 0xDD, 0xAF, 0x35, 0xA1, 0x93, 0x61, 0x7A, 0xBA, + 0xCC, 0x41, 0x73, 0x49, 0xAE, 0x20, 0x41, 0x31, + 0x12, 0xE6, 0xFA, 0x4E, 0x89, 0xA9, 0x7E, 0xA2, + 0x0A, 0x9E, 0xEE, 0xE6, 0x4B, 0x55, 0xD3, 0x9A, + 0x21, 0x92, 0x99, 0x2A, 0x27, 0x4F, 0xC1, 0xA8, + 0x36, 0xBA, 0x3C, 0x23, 0xA3, 0xFE, 0xEB, 0xBD, + 0x45, 0x4D, 0x44, 0x23, 0x64, 0x3C, 0xE8, 0x0E, + 0x2A, 0x9A, 0xC9, 0x4F, 0xA5, 0x4C, 0xA4, 0x9F +}; +#ifdef WOLFSSL_SHA3 +static const unsigned char sha3_256_expected[] = { + 0x3A, 0x98, 0x5D, 0xA7, 0x4F, 0xE2, 0x25, 0xB2, + 0x04, 0x5C, 0x17, 0x2D, 0x6B, 0xD3, 0x90, 0xBD, + 0x85, 0x5F, 0x08, 0x6E, 0x3E, 0x9D, 0x52, 0x5B, + 0x46, 0xBF, 0xE2, 0x45, 0x11, 0x43, 0x15, 0x32 +}; +#endif /* WOLFSSL_SHA3 */ + #ifndef WOLFPKCS11_NO_ENV #include diff --git a/tests/wolfssl-interoperability/Makefile b/tests/wolfssl-interoperability/Makefile new file mode 100644 index 00000000..0abf3081 --- /dev/null +++ b/tests/wolfssl-interoperability/Makefile @@ -0,0 +1,105 @@ +CC ?= gcc +AR ?= ar +CFLAGS ?= -O2 -g +CFLAGS += -Wall -Wextra -Wno-unused-parameter -fPIC +LDFLAGS ?= +LDLIBS ?= +LDLIBS += -ldl -lpthread -lm +WOLFSSL_DIR ?= ../../wolfssl +WOLFPKCS11_DIR ?= ../.. + +BUILD_DIR := build + +COMMON_CPPFLAGS := -DWOLFSSL_USER_SETTINGS -I. -I.. \ + -I$(WOLFSSL_DIR) -I$(WOLFSSL_DIR)/wolfssl -I$(WOLFSSL_DIR)/wolfssl/wolfcrypt \ + -I$(WOLFPKCS11_DIR) -I$(WOLFPKCS11_DIR)/wolfpkcs11 -I$(WOLFPKCS11_DIR)/src +WOLFCRYPT_CPPFLAGS := $(COMMON_CPPFLAGS) -DWOLFSSL_LIB +ENGINE_CPPFLAGS := $(COMMON_CPPFLAGS) -DBUILDING_WOLFPKCS11 -DDEBUG_WOLFPKCS11 +TEST_CPPFLAGS := $(COMMON_CPPFLAGS) + +WOLFCRYPT_SRCS := \ + $(WOLFSSL_DIR)/wolfcrypt/src/aes.c \ + $(WOLFSSL_DIR)/wolfcrypt/src/asn.c \ + $(WOLFSSL_DIR)/wolfcrypt/src/coding.c \ + $(WOLFSSL_DIR)/wolfcrypt/src/cryptocb.c \ + $(WOLFSSL_DIR)/wolfcrypt/src/des3.c \ + $(WOLFSSL_DIR)/wolfcrypt/src/dsa.c \ + $(WOLFSSL_DIR)/wolfcrypt/src/dh.c \ + $(WOLFSSL_DIR)/wolfcrypt/src/ecc.c \ + $(WOLFSSL_DIR)/wolfcrypt/src/ecc_fp.c \ + $(WOLFSSL_DIR)/wolfcrypt/src/error.c \ + $(WOLFSSL_DIR)/wolfcrypt/src/hash.c \ + $(WOLFSSL_DIR)/wolfcrypt/src/md5.c \ + $(WOLFSSL_DIR)/wolfcrypt/src/hmac.c \ + $(WOLFSSL_DIR)/wolfcrypt/src/integer.c \ + $(WOLFSSL_DIR)/wolfcrypt/src/logging.c \ + $(WOLFSSL_DIR)/wolfcrypt/src/memory.c \ + $(WOLFSSL_DIR)/wolfcrypt/src/random.c \ + $(WOLFSSL_DIR)/wolfcrypt/src/kdf.c \ + $(WOLFSSL_DIR)/wolfcrypt/src/rsa.c \ + $(WOLFSSL_DIR)/wolfcrypt/src/sha.c \ + $(WOLFSSL_DIR)/wolfcrypt/src/sha256.c \ + $(WOLFSSL_DIR)/wolfcrypt/src/sha512.c \ + $(WOLFSSL_DIR)/wolfcrypt/src/sha3.c \ + $(WOLFSSL_DIR)/wolfcrypt/src/signature.c \ + $(WOLFSSL_DIR)/wolfcrypt/src/pwdbased.c \ + $(WOLFSSL_DIR)/wolfcrypt/src/sp_int.c \ + $(WOLFSSL_DIR)/wolfcrypt/src/sp_c32.c \ + $(WOLFSSL_DIR)/wolfcrypt/src/wc_encrypt.c \ + $(WOLFSSL_DIR)/wolfcrypt/src/wc_pkcs11.c \ + $(WOLFSSL_DIR)/wolfcrypt/src/wc_port.c \ + $(WOLFSSL_DIR)/wolfcrypt/src/wolfmath.c + +ENGINE_SRCS := \ + $(WOLFPKCS11_DIR)/src/internal.c \ + $(WOLFPKCS11_DIR)/src/wolfpkcs11.c \ + $(WOLFPKCS11_DIR)/src/slot.c \ + $(WOLFPKCS11_DIR)/src/crypto.c + +TEST_SRCS := pkcs11_interop.c + +WOLFCRYPT_OBJS := $(patsubst $(WOLFSSL_DIR)/%.c,$(BUILD_DIR)/wolfssl/%.o,$(WOLFCRYPT_SRCS)) +ENGINE_OBJS := $(patsubst $(WOLFPKCS11_DIR)/%.c,$(BUILD_DIR)/wolfpkcs11/%.o,$(ENGINE_SRCS)) +TEST_OBJS := $(patsubst %.c,$(BUILD_DIR)/interop-test/%.o,$(TEST_SRCS)) + +all: test + +interop: $(BUILD_DIR)/pkcs11_interop + +$(BUILD_DIR)/wolfssl/%.o: $(WOLFSSL_DIR)/%.c + @mkdir -p $(dir $@) + $(CC) $(CPPFLAGS) $(WOLFCRYPT_CPPFLAGS) $(CFLAGS) -c $< -o $@ + +$(BUILD_DIR)/wolfpkcs11/%.o: $(WOLFPKCS11_DIR)/%.c + @mkdir -p $(dir $@) + $(CC) $(CPPFLAGS) $(ENGINE_CPPFLAGS) $(CFLAGS) -c $< -o $@ + +$(BUILD_DIR)/interop-test/%.o: %.c + @mkdir -p $(dir $@) + $(CC) $(CPPFLAGS) $(TEST_CPPFLAGS) $(CFLAGS) -c $< -o $@ + +$(BUILD_DIR)/libwolfcrypt-interop.so: $(WOLFCRYPT_OBJS) + @mkdir -p $(dir $@) + $(CC) -shared -o $@ $(WOLFCRYPT_OBJS) $(LDFLAGS) $(LDLIBS) + +$(BUILD_DIR)/libwolfpkcs11-interop.so: $(ENGINE_OBJS) $(BUILD_DIR)/libwolfcrypt-interop.so + @mkdir -p $(dir $@) + $(CC) -shared -o $@ $(ENGINE_OBJS) -L$(BUILD_DIR) -lwolfcrypt-interop $(LDFLAGS) $(LDLIBS) + +$(BUILD_DIR)/pkcs11_interop: $(TEST_OBJS) $(BUILD_DIR)/libwolfpkcs11-interop.so $(BUILD_DIR)/libwolfcrypt-interop.so + $(CC) -o $@ $(TEST_OBJS) -L$(BUILD_DIR) -lwolfpkcs11-interop -lwolfcrypt-interop $(LDFLAGS) $(LDLIBS) + +.PHONY: test +test: $(BUILD_DIR)/pkcs11_interop + WOLFPKCS11_MODULE=$(BUILD_DIR)/libwolfpkcs11-interop.so LD_LIBRARY_PATH=$(BUILD_DIR) $(BUILD_DIR)/pkcs11_interop +debug: $(BUILD_DIR)/pkcs11_interop + WOLFPKCS11_MODULE=$(BUILD_DIR)/libwolfpkcs11-interop.so LD_LIBRARY_PATH=$(BUILD_DIR) gdb $(BUILD_DIR)/pkcs11_interop + +.PHONY: clean +clean: + rm -rf $(BUILD_DIR)/wolfssl $(BUILD_DIR)/wolfPKCS11 $(BUILD_DIR)/interop-test \ + $(BUILD_DIR)/libwolfcrypt-interop.so $(BUILD_DIR)/libwolfpkcs11-interop.so \ + $(BUILD_DIR)/pkcs11_interop + rm -rf token-store + @# Safely remove build directory, if local + rm -rf ./build diff --git a/tests/wolfssl-interoperability/pkcs11_interop.c b/tests/wolfssl-interoperability/pkcs11_interop.c new file mode 100644 index 00000000..b08dfbfb --- /dev/null +++ b/tests/wolfssl-interoperability/pkcs11_interop.c @@ -0,0 +1,1305 @@ +/* pkcs11_interop.c - Interoperability test with wolfSSL + * + * Copyright (C) 2006-2025 wolfSSL Inc. + * + * This file is part of wolfPKCS11. + * + * wolfPKCS11 is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * wolfPKCS11 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ +#include +#include +#include +#include +#include +#include + +#include "user_settings.h" +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef WOLFSSL_SHA3 +#include +#endif +#include +#include + +#include + +#include "tests/testdata.h" + +#ifndef HAVE_ECC +#define HAVE_ECC +#define INTEROP_DEFINED_ECC 1 +#endif +#include +#ifdef INTEROP_DEFINED_ECC +#undef HAVE_ECC +#undef INTEROP_DEFINED_ECC +#endif + +#define rsa_2048_priv_der client_key_der_2048 +#define rsa_2048_priv_der_len sizeof_client_key_der_2048 +#define rsa_2048_pub_der client_keypub_der_2048 +#define rsa_2048_pub_der_len sizeof_client_keypub_der_2048 + +#ifdef USE_CERT_BUFFERS_3072 +#define rsa_3072_priv_der client_key_der_3072 +#define rsa_3072_priv_der_len sizeof_client_key_der_3072 +#define rsa_3072_pub_der client_keypub_der_3072 +#define rsa_3072_pub_der_len sizeof_client_keypub_der_3072 +#endif + +#ifdef USE_CERT_BUFFERS_4096 +#define rsa_4096_priv_der client_key_der_4096 +#define rsa_4096_priv_der_len sizeof_client_key_der_4096 +#define rsa_4096_pub_der client_keypub_der_4096 +#define rsa_4096_pub_der_len sizeof_client_keypub_der_4096 +#endif + +#define ecc384_priv_der ca_ecc_key_der_384 +#define ecc384_priv_der_len sizeof_ca_ecc_key_der_384 + +#ifndef ARRAY_SIZE +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) +#endif + +#ifndef CKR_USER_ALREADY_LOGGED_IN +#define CKR_USER_ALREADY_LOGGED_IN 0x00000100UL +#endif + +void wolfPKCS11_Debugging_On(void); +void wolfPKCS11_Debugging_Off(void); + + +static void set_token_env(void) +{ + const char* token_path = "./token-store"; +#ifdef _WIN32 + _putenv("WOLFPKCS11_TOKEN_PATH=./token-store"); + _mkdir(token_path); +#else + setenv("WOLFPKCS11_TOKEN_PATH", token_path, 1); + mkdir(token_path, 0700); +#endif +} + +static const char* error_to_string(int err) +{ + const char* str = wc_GetErrorString(err); + return str != NULL ? str : "unknown"; +} + +static int destroy_objects_by_label(Pkcs11Token* token, CK_OBJECT_CLASS obj_class, + const char* label) +{ + CK_SESSION_HANDLE session; + int opened = 0; + CK_ATTRIBUTE template[2]; + CK_OBJECT_HANDLE object; + CK_ULONG count = 0; + CK_RV rv; + CK_RV login_rv = CKR_OK; + int ret = 0; + + if (token == NULL || label == NULL) + return BAD_FUNC_ARG; + + if (token->handle != CK_INVALID_HANDLE) + session = token->handle; + else { + rv = token->func->C_OpenSession(token->slotId, + CKF_SERIAL_SESSION | CKF_RW_SESSION, NULL, NULL, &session); + if (rv != CKR_OK) + return WC_HW_E; + opened = 1; + + if (token->userPinLogin && token->userPin != NULL && token->userPinSz > 0) { + login_rv = token->func->C_Login(session, CKU_USER, + token->userPin, token->userPinSz); + if (login_rv != CKR_OK && login_rv != CKR_USER_ALREADY_LOGGED_IN) { + token->func->C_CloseSession(session); + return WC_HW_E; + } + } + } + + template[0].type = CKA_CLASS; + template[0].pValue = &obj_class; + template[0].ulValueLen = (CK_ULONG)sizeof(obj_class); + template[1].type = CKA_LABEL; + template[1].pValue = (void*)label; + template[1].ulValueLen = (CK_ULONG)strlen(label); + + rv = token->func->C_FindObjectsInit(session, template, 2); + if (rv == CKR_OK) { + do { + rv = token->func->C_FindObjects(session, &object, 1, &count); + if (rv != CKR_OK) + break; + if (count > 0) + token->func->C_DestroyObject(session, object); + } while (rv == CKR_OK && count > 0); + token->func->C_FindObjectsFinal(session); + } + + if (opened) { + if (token->userPinLogin && login_rv == CKR_OK) + token->func->C_Logout(session); + token->func->C_CloseSession(session); + } + + return ret; +} + +static int init_token(const char* module_path, Pkcs11Dev* dev, + Pkcs11Token* token, CK_SLOT_ID* slot_id) +{ + CK_UTF8CHAR so_pin[] = "password123456"; + CK_UTF8CHAR user_pin_l[] = "interop-user"; + static const char token_label_text[] = "wolfPKCS11-Interop"; + CK_UTF8CHAR label[32]; + CK_RV rv; + CK_SLOT_ID_PTR slots = NULL; + CK_ULONG slot_cnt = 0; + CK_SESSION_HANDLE session = CK_INVALID_HANDLE; + int ret = 0; + + set_token_env(); + + ret = wc_Pkcs11_Initialize(dev, module_path, NULL); + if (ret != 0) { + fprintf(stderr, "wc_Pkcs11_Initialize failed: %d (%s)\n", ret, + error_to_string(ret)); + return ret; + } + + rv = dev->func->C_GetSlotList(CK_FALSE, NULL, &slot_cnt); + if (rv != CKR_OK || slot_cnt == 0) { + fprintf(stderr, "C_GetSlotList failed: 0x%lx\n", (unsigned long)rv); + ret = WC_HW_E; + goto exit; + } + + slots = (CK_SLOT_ID_PTR)calloc(slot_cnt, sizeof(CK_SLOT_ID)); + if (slots == NULL) { + ret = MEMORY_E; + goto exit; + } + rv = dev->func->C_GetSlotList(CK_FALSE, slots, &slot_cnt); + if (rv != CKR_OK || slot_cnt == 0) { + fprintf(stderr, "C_GetSlotList (2) failed: 0x%lx\n", (unsigned long)rv); + ret = WC_HW_E; + goto exit; + } + + *slot_id = slots[0]; + + memset(label, ' ', sizeof(label)); + memcpy(label, token_label_text, + strlen(token_label_text) < sizeof(label) ? strlen(token_label_text) + : sizeof(label)); + + rv = dev->func->C_InitToken(*slot_id, so_pin, + (CK_ULONG)strlen((const char*)so_pin), label); + if (rv != CKR_OK) { + fprintf(stderr, "C_InitToken failed: 0x%lx\n", (unsigned long)rv); + ret = WC_HW_E; + goto exit; + } + + rv = dev->func->C_OpenSession(*slot_id, + CKF_SERIAL_SESSION | CKF_RW_SESSION, NULL, NULL, &session); + if (rv != CKR_OK) { + fprintf(stderr, "C_OpenSession failed: 0x%lx\n", (unsigned long)rv); + ret = WC_HW_E; + goto exit; + } + + rv = dev->func->C_Login(session, CKU_SO, so_pin, + (CK_ULONG)strlen((const char*)so_pin)); + if (rv != CKR_OK) { + fprintf(stderr, "SO login failed: 0x%lx\n", (unsigned long)rv); + ret = WC_HW_E; + goto exit; + } + + rv = dev->func->C_InitPIN(session, user_pin_l, + (CK_ULONG)strlen((const char*)user_pin_l)); + if (rv != CKR_OK) { + fprintf(stderr, "C_InitPIN failed: 0x%lx\n", (unsigned long)rv); + ret = WC_HW_E; + goto exit; + } + + dev->func->C_Logout(session); + dev->func->C_CloseSession(session); + session = CK_INVALID_HANDLE; + + ret = wc_Pkcs11Token_Init(token, dev, (int)(*slot_id), + "wolfpkcs11", user_pin_l, + (int)strlen((const char*)user_pin_l)); + if (ret != 0) { + fprintf(stderr, "wc_Pkcs11Token_Init failed: %d (%s)\n", ret, + error_to_string(ret)); + goto exit; + } + + ret = wc_Pkcs11Token_Open(token, 1); + if (ret != 0) { + fprintf(stderr, "wc_Pkcs11Token_Open failed: %d (%s)\n", ret, + error_to_string(ret)); + goto exit; + } + +exit: + if (session != CK_INVALID_HANDLE) + dev->func->C_CloseSession(session); + free(slots); + if (ret != 0) { + wc_Pkcs11Token_Final(token); + wc_Pkcs11_Finalize(dev); + } + return ret; +} + +static int compare_bytes(const byte* a, const byte* b, size_t len) +{ + return memcmp(a, b, len) == 0 ? 0 : -1; +} + +static void dump_buffer(const char* label, const byte* buf, size_t len) +{ + size_t i; + fprintf(stderr, "%s: ", label); + for (i = 0; i < len; i++) + fprintf(stderr, "%02X", buf[i]); + fprintf(stderr, "\n"); +} + +static int test_aes_gcm(Pkcs11Token* token, int dev_id) +{ + int ret; + Aes aes; + byte cipher[ARRAY_SIZE(aes_gcm_plain)]; + byte plain[ARRAY_SIZE(aes_gcm_plain)]; + byte tag[ARRAY_SIZE(aes_gcm_tag)]; + + ret = wc_AesInit(&aes, NULL, dev_id); + if (ret != 0) + return ret; + + ret = wc_AesGcmSetKey(&aes, aes_gcm_key, (word32)sizeof(aes_gcm_key)); + if (ret != 0) + goto done; + + memcpy(aes.devKey, aes_gcm_key, sizeof(aes_gcm_key)); + aes.keylen = (int)sizeof(aes_gcm_key); + + { + static const char label[] = "aes-gcm-interop"; + aes.labelLen = (int)sizeof(label) - 1; + memcpy(aes.label, label, aes.labelLen); + destroy_objects_by_label(token, CKO_SECRET_KEY, label); + } + + ret = wc_Pkcs11StoreKey(token, PKCS11_KEY_TYPE_AES_GCM, 0, &aes); + if (ret != 0) + goto done; + + ret = wc_AesGcmEncrypt(&aes, cipher, aes_gcm_plain, + (word32)sizeof(aes_gcm_plain), + aes_gcm_iv, (word32)sizeof(aes_gcm_iv), + tag, (word32)sizeof(tag), + aes_gcm_aad, (word32)sizeof(aes_gcm_aad)); + if (ret != 0) + goto done; + + if (compare_bytes(cipher, aes_gcm_cipher, sizeof(cipher)) != 0 || + compare_bytes(tag, aes_gcm_tag, sizeof(tag)) != 0) { + dump_buffer("cipher", cipher, sizeof(cipher)); + dump_buffer("expect", aes_gcm_cipher, sizeof(aes_gcm_cipher)); + dump_buffer("tag", tag, sizeof(tag)); + dump_buffer("tag-exp", aes_gcm_tag, sizeof(aes_gcm_tag)); + ret = WC_HW_E; + goto done; + } + + ret = wc_AesGcmDecrypt(&aes, plain, cipher, (word32)sizeof(cipher), + aes_gcm_iv, (word32)sizeof(aes_gcm_iv), + tag, (word32)sizeof(tag), + aes_gcm_aad, (word32)sizeof(aes_gcm_aad)); + if (ret != 0) + goto done; + + if (compare_bytes(plain, aes_gcm_plain, sizeof(plain)) != 0) { + dump_buffer("plain", plain, sizeof(plain)); + dump_buffer("plain-exp", aes_gcm_plain, sizeof(aes_gcm_plain)); + ret = WC_HW_E; + } + +done: + wc_AesFree(&aes); + destroy_objects_by_label(token, CKO_SECRET_KEY, "aes-gcm-interop"); + return ret; +} + +static int test_hmac_sha256(Pkcs11Token* token, int dev_id) +{ + int ret; + Hmac hmac; + byte digest[ARRAY_SIZE(hmac_digest)]; + + ret = wc_HmacInit(&hmac, NULL, dev_id); + if (ret != 0) + return ret; + + ret = wc_HmacSetKey(&hmac, WC_SHA256, hmac_key, (word32)sizeof(hmac_key)); + if (ret != 0) + goto done; + + { + static const char label[] = "hmac-sha256-interop"; + hmac.labelLen = (int)sizeof(label) - 1; + memcpy(hmac.label, label, hmac.labelLen); + destroy_objects_by_label(token, CKO_SECRET_KEY, label); + } + + ret = wc_Pkcs11StoreKey(token, PKCS11_KEY_TYPE_HMAC, 0, &hmac); + if (ret != 0) + goto done; + + ret = wc_HmacUpdate(&hmac, hmac_msg, (word32)sizeof(hmac_msg)); + if (ret != 0) + goto done; + + ret = wc_HmacFinal(&hmac, digest); + if (ret != 0) + goto done; + + if (compare_bytes(digest, hmac_digest, sizeof(digest)) != 0) { + dump_buffer("hmac", digest, sizeof(digest)); + dump_buffer("hmac-exp", hmac_digest, sizeof(hmac_digest)); + ret = WC_HW_E; + } + +done: + wc_HmacFree(&hmac); + destroy_objects_by_label(token, CKO_SECRET_KEY, "hmac-sha256-interop"); + return ret; +} + +#ifdef WOLFSSL_SHA224 +static int test_sha224_digest(int dev_id) +{ + int ret; + wc_Sha224 sha; + byte digest[WC_SHA224_DIGEST_SIZE]; + + (void)dev_id; + + ret = wc_InitSha224_ex(&sha, NULL, INVALID_DEVID); + if (ret != 0) + return ret; + + ret = wc_Sha224Update(&sha, sha_test_msg, (word32)sizeof(sha_test_msg)); + if (ret == 0) + ret = wc_Sha224Final(&sha, digest); + wc_Sha224Free(&sha); + + if (ret == 0 && compare_bytes(digest, sha224_expected, + sizeof(sha224_expected)) != 0) + ret = WC_HW_E; + + return ret; +} +#endif /* WOLFSSL_SHA224 */ + +static int test_sha256_digest(int dev_id) +{ + int ret; + wc_Sha256 sha; + byte digest[WC_SHA256_DIGEST_SIZE]; + + (void)dev_id; + + ret = wc_InitSha256_ex(&sha, NULL, INVALID_DEVID); + if (ret != 0) + return ret; + + ret = wc_Sha256Update(&sha, sha_test_msg, (word32)sizeof(sha_test_msg)); + if (ret == 0) + ret = wc_Sha256Final(&sha, digest); + wc_Sha256Free(&sha); + + if (ret == 0 && compare_bytes(digest, sha256_expected, + sizeof(sha256_expected)) != 0) + ret = WC_HW_E; + + return ret; +} + +#ifdef WOLFSSL_SHA384 +static int test_sha384_digest(int dev_id) +{ + int ret; + wc_Sha384 sha; + byte digest[WC_SHA384_DIGEST_SIZE]; + + (void)dev_id; + + ret = wc_InitSha384_ex(&sha, NULL, INVALID_DEVID); + if (ret != 0) + return ret; + + ret = wc_Sha384Update(&sha, sha_test_msg, (word32)sizeof(sha_test_msg)); + if (ret == 0) + ret = wc_Sha384Final(&sha, digest); + wc_Sha384Free(&sha); + + if (ret == 0 && compare_bytes(digest, sha384_expected, + sizeof(sha384_expected)) != 0) + ret = WC_HW_E; + + return ret; +} +#endif /* WOLFSSL_SHA384 */ + +#ifdef WOLFSSL_SHA512 +static int test_sha512_digest(int dev_id) +{ + int ret; + wc_Sha512 sha; + byte digest[WC_SHA512_DIGEST_SIZE]; + + (void)dev_id; + + ret = wc_InitSha512_ex(&sha, NULL, INVALID_DEVID); + if (ret != 0) + return ret; + + ret = wc_Sha512Update(&sha, sha_test_msg, (word32)sizeof(sha_test_msg)); + if (ret == 0) + ret = wc_Sha512Final(&sha, digest); + wc_Sha512Free(&sha); + + if (ret == 0 && compare_bytes(digest, sha512_expected, + sizeof(sha512_expected)) != 0) + ret = WC_HW_E; + + return ret; +} +#endif /* WOLFSSL_SHA512 */ + +#ifdef WOLFSSL_SHA3 +static int test_sha3_256_digest(int dev_id) +{ + int ret; + wc_Sha3 sha; + byte digest[WC_SHA3_256_DIGEST_SIZE]; + + (void)dev_id; + + ret = wc_InitSha3_256(&sha, NULL, INVALID_DEVID); + if (ret != 0) + return ret; + + ret = wc_Sha3_256_Update(&sha, sha_test_msg, + (word32)sizeof(sha_test_msg)); + if (ret == 0) + ret = wc_Sha3_256_Final(&sha, digest); + wc_Sha3_256_Free(&sha); + + if (ret == 0 && compare_bytes(digest, sha3_256_expected, + sizeof(sha3_256_expected)) != 0) + ret = WC_HW_E; + + return ret; +} +#endif /* WOLFSSL_SHA3 */ + +static int rsa_decode_private_key_der(RsaKey* key, int devId, + const byte* priv_der, word32 priv_len) +{ + int ret; + word32 idx = 0; + + ret = wc_InitRsaKey_ex(key, NULL, devId); + if (ret != 0) + return ret; + + ret = wc_RsaPrivateKeyDecode(priv_der, &idx, key, priv_len); + if (ret != 0) + wc_FreeRsaKey(key); + + return ret; +} + +static int rsa_decode_public_key_der(RsaKey* key, int devId, + const byte* pub_der, word32 pub_len) +{ + int ret; + word32 idx = 0; + + ret = wc_InitRsaKey_ex(key, NULL, devId); + if (ret != 0) + return ret; + + ret = wc_RsaPublicKeyDecode(pub_der, &idx, key, pub_len); + if (ret != 0) + wc_FreeRsaKey(key); + + return ret; +} + +static int test_rsa_sign_verify_der(Pkcs11Token* token, int dev_id, + const byte* priv_der, word32 priv_len, const byte* pub_der, + word32 pub_len, const char* label) +{ + int ret; + RsaKey key; + RsaKey pubKey; + byte message[] = "wolfPKCS11 interoperability"; + byte digest[WC_SHA256_DIGEST_SIZE]; + byte signature[512]; + byte recovered[512]; + word32 sig_len; + word32 recovered_len; + WC_RNG rng; + + memset(&key, 0, sizeof(key)); + memset(&pubKey, 0, sizeof(pubKey)); + + ret = rsa_decode_private_key_der(&key, dev_id, priv_der, priv_len); + if (ret != 0) + return ret; + + if (label != NULL) { + size_t len = strlen(label); + if (len > sizeof(key.label)) + len = sizeof(key.label); + key.labelLen = (int)len; + memcpy(key.label, label, key.labelLen); + destroy_objects_by_label(token, CKO_PRIVATE_KEY, label); + } + key.idLen = 1; + key.id[0] = 0x01; + + if (ret == 0) + ret = wc_mp_to_bigint(&key.n, &key.n.raw); + if (ret == 0) + ret = wc_mp_to_bigint(&key.e, &key.e.raw); +#if defined(WOLFSSL_KEY_GEN) || defined(OPENSSL_EXTRA) || !defined(RSA_LOW_MEM) + if (ret == 0) + ret = wc_mp_to_bigint(&key.d, &key.d.raw); + if (ret == 0) + ret = wc_mp_to_bigint(&key.p, &key.p.raw); + if (ret == 0) + ret = wc_mp_to_bigint(&key.q, &key.q.raw); + if (ret == 0) + ret = wc_mp_to_bigint(&key.dP, &key.dP.raw); + if (ret == 0) + ret = wc_mp_to_bigint(&key.dQ, &key.dQ.raw); + if (ret == 0) + ret = wc_mp_to_bigint(&key.u, &key.u.raw); +#endif + if (ret != 0) + goto done_key; + + ret = wc_InitRng_ex(&rng, NULL, dev_id); + if (ret != 0) + goto done_key; + + ret = rsa_decode_public_key_der(&pubKey, dev_id, pub_der, pub_len); + if (ret != 0) + goto done_rng; + + ret = wc_Sha256Hash(message, (word32)sizeof(message) - 1, digest); + if (ret != 0) + goto done_rng; + + ret = wc_Pkcs11StoreKey(token, PKCS11_KEY_TYPE_RSA, 0, &key); + if (ret != 0) { + fprintf(stderr, "wc_Pkcs11StoreKey(RSA) failed: %d (%s)\n", ret, + error_to_string(ret)); + goto done_rng; + } + + sig_len = (word32)sizeof(signature); + ret = wc_RsaPSS_Sign_ex(digest, sizeof(digest), signature, sig_len, + WC_HASH_TYPE_SHA256, WC_MGF1SHA256, RSA_PSS_SALT_LEN_DEFAULT, &key, &rng); + if (ret < 0) { + fprintf(stderr, "wc_RsaPSS_Sign_ex failed: %d (%s)\n", ret, + error_to_string(ret)); + goto done_rng; + } + sig_len = (word32)ret; + + ret = wc_RsaPSS_Verify_ex(signature, sig_len, recovered, sizeof(recovered), + WC_HASH_TYPE_SHA256, WC_MGF1SHA256, RSA_PSS_SALT_LEN_DEFAULT, &pubKey); + if (ret < 0) { + fprintf(stderr, "wc_RsaPSS_Verify_ex failed: %d (%s)\n", ret, + error_to_string(ret)); + goto done_rng; + } + recovered_len = (word32)ret; + + ret = wc_RsaPSS_CheckPadding(digest, sizeof(digest), recovered, + recovered_len, WC_HASH_TYPE_SHA256); + if (ret != 0) { + fprintf(stderr, "PSS padding check failed: %d\n", ret); + goto done_rng; + } + + ret = 0; + +done_rng: + wc_FreeRng(&rng); + wc_FreeRsaKey(&pubKey); + +done_key: + wc_FreeRsaKey(&key); + if (label != NULL) + destroy_objects_by_label(token, CKO_PRIVATE_KEY, label); + return ret; +} + +static int test_rsa_sign_verify(Pkcs11Token* token, int dev_id) +{ + return test_rsa_sign_verify_der(token, dev_id, + rsa_2048_priv_der, (word32)rsa_2048_priv_der_len, + rsa_2048_pub_der, (word32)rsa_2048_pub_der_len, + "rsa-2048"); +} +static int test_rsa_sign_verify_3072(Pkcs11Token* token, int dev_id) +{ + return test_rsa_sign_verify_der(token, dev_id, + rsa_3072_priv_der, (word32)rsa_3072_priv_der_len, + rsa_3072_pub_der, (word32)rsa_3072_pub_der_len, + "rsa-3072"); +} + +static int test_rsa_sign_verify_4096(Pkcs11Token* token, int dev_id) +{ + return test_rsa_sign_verify_der(token, dev_id, + rsa_4096_priv_der, (word32)rsa_4096_priv_der_len, + rsa_4096_pub_der, (word32)rsa_4096_pub_der_len, + "rsa-4096"); +} + +static int run_aes_cbc_vector(Pkcs11Token* token, int dev_id, + const byte* key, word32 keyLen, const byte* iv, + const byte* plain, word32 dataLen, const byte* expected, + const char* label) +{ + int ret = 0; + Aes aes; + byte cipher[32]; + byte plainOut[32]; + + if (dataLen > (word32)sizeof(cipher)) + return BAD_FUNC_ARG; + + ret = wc_AesInit(&aes, NULL, dev_id); + if (ret != 0) + return ret; + + ret = wc_AesSetKey(&aes, key, keyLen, iv, AES_ENCRYPTION); + if (ret != 0) + goto done; + aes.keylen = (int)keyLen; + memcpy(aes.devKey, key, keyLen); + + if (label != NULL) { + size_t len = strlen(label); + if (len > sizeof(aes.label)) + len = sizeof(aes.label); + aes.labelLen = (int)len; + memcpy(aes.label, label, aes.labelLen); + destroy_objects_by_label(token, CKO_SECRET_KEY, label); + } + + ret = wc_Pkcs11StoreKey(token, PKCS11_KEY_TYPE_AES_CBC, 0, &aes); + if (ret != 0) + goto done; + + memset(cipher, 0xA5, dataLen); + ret = wc_AesCbcEncrypt(&aes, cipher, plain, dataLen); + if (ret != 0) + goto done; + if (compare_bytes(cipher, expected, dataLen) != 0) { + dump_buffer("cbc-enc", cipher, dataLen); + dump_buffer("cbc-exp", expected, dataLen); + ret = WC_HW_E; + goto done; + } + + ret = wc_AesSetKey(&aes, key, keyLen, iv, AES_DECRYPTION); + if (ret != 0) + goto done; + + memset(plainOut, 0x5A, dataLen); + ret = wc_AesCbcDecrypt(&aes, plainOut, cipher, dataLen); + if (ret != 0) + goto done; + if (compare_bytes(plainOut, plain, dataLen) != 0) { + dump_buffer("cbc-dec", plainOut, dataLen); + dump_buffer("cbc-exp", plain, dataLen); + ret = WC_HW_E; + } + +done: + wc_AesFree(&aes); + return ret; +} + +static int run_aes_ctr_vector(Pkcs11Token* token, int dev_id, + const byte* key, word32 keyLen, const byte* iv, + const byte* plain, word32 dataLen, const byte* expected, + const char* label) +{ + int ret = 0; + Aes aes; + byte cipher[32]; + byte plainOut[32]; + + if (dataLen > (word32)sizeof(cipher)) + return BAD_FUNC_ARG; + + ret = wc_AesInit(&aes, NULL, dev_id); + if (ret != 0) + return ret; + + ret = wc_AesSetKey(&aes, key, keyLen, iv, AES_ENCRYPTION); + if (ret != 0) + goto done; + aes.keylen = (int)keyLen; + memcpy(aes.devKey, key, keyLen); + + if (label != NULL) { + size_t len = strlen(label); + if (len > sizeof(aes.label)) + len = sizeof(aes.label); + aes.labelLen = (int)len; + memcpy(aes.label, label, aes.labelLen); + destroy_objects_by_label(token, CKO_SECRET_KEY, label); + } + + ret = wc_Pkcs11StoreKey(token, PKCS11_KEY_TYPE_AES_CBC, 0, &aes); + if (ret != 0) + goto done; + + memset(cipher, 0xA5, dataLen); + ret = wc_AesCtrEncrypt(&aes, cipher, plain, dataLen); + if (ret != 0) + goto done; + if (compare_bytes(cipher, expected, dataLen) != 0) { + dump_buffer("ctr-enc", cipher, dataLen); + dump_buffer("ctr-exp", expected, dataLen); + ret = WC_HW_E; + goto done; + } + + ret = wc_AesSetKey(&aes, key, keyLen, iv, AES_ENCRYPTION); + if (ret != 0) + goto done; + + memset(plainOut, 0x5A, dataLen); + ret = wc_AesCtrEncrypt(&aes, plainOut, cipher, dataLen); + if (ret != 0) + goto done; + if (compare_bytes(plainOut, plain, dataLen) != 0) { + dump_buffer("ctr-dec", plainOut, dataLen); + dump_buffer("ctr-exp", plain, dataLen); + ret = WC_HW_E; + } + +done: + wc_AesFree(&aes); + if (label != NULL) + destroy_objects_by_label(token, CKO_SECRET_KEY, label); + return ret; +} + +/* Test AES-CBC encryption/decryption */ +static int test_aes_cbc(Pkcs11Token* token, int dev_id) +{ + return run_aes_cbc_vector(token, dev_id, aes_cbc_key, + (word32)sizeof(aes_cbc_key), aes_cbc_iv, aes_cbc_plain, + (word32)sizeof(aes_cbc_plain), aes_cbc_cipher, + "aes-cbc-128"); +} + +static int test_aes_cbc_256(Pkcs11Token* token, int dev_id) +{ + return run_aes_cbc_vector(token, dev_id, aes_cbc256_key, + (word32)sizeof(aes_cbc256_key), aes_cbc256_iv, aes_cbc_plain, + (word32)sizeof(aes_cbc_plain), aes_cbc256_cipher, + "aes-cbc-256"); +} + +/* Test AES-CTR encryption/decryption */ +static int test_aes_ctr(Pkcs11Token* token, int dev_id) +{ + return run_aes_ctr_vector(token, dev_id, aes_ctr_key, + (word32)sizeof(aes_ctr_key), aes_ctr_iv, aes_ctr_plain, + (word32)sizeof(aes_ctr_plain), aes_ctr_cipher, + "aes-ctr-128"); +} + +static int test_aes_ctr_256(Pkcs11Token* token, int dev_id) +{ + return run_aes_ctr_vector(token, dev_id, aes_ctr256_key, + (word32)sizeof(aes_ctr256_key), aes_ctr256_iv, aes_ctr_plain, + (word32)sizeof(aes_ctr_plain), aes_ctr256_cipher, + "aes-ctr-256"); +} +static int test_ecc_sign_verify_der(Pkcs11Token* token, int devId, + const byte* priv_der, word32 priv_len, int curveId, + const char* name, int generate) +{ + int ret = 0; + ecc_key eccPriv; + ecc_key eccPub; + WC_RNG rng; + byte hash[32], sig[144]; + word32 hashSz = sizeof(hash); + word32 sigSz = sizeof(sig); + int verify = 0; + byte pubBuf[150]; + word32 pubSz = (word32)sizeof(pubBuf); + + (void)generate; + + memset(hash, 9, sizeof(hash)); + + ret = wc_InitRng(&rng); + if (ret != 0) + return ret; + + ret = wc_ecc_init_ex(&eccPriv, NULL, INVALID_DEVID); + if (ret != 0) + goto done_rng; + + if (priv_der != NULL && priv_len > 0) { + word32 idx = 0; + ret = wc_EccPrivateKeyDecode(priv_der, &idx, &eccPriv, priv_len); + } + else { + int keySz = wc_ecc_get_curve_size_from_id(curveId); + if (keySz <= 0) + ret = BAD_FUNC_ARG; + else + ret = wc_ecc_make_key_ex(&rng, keySz, &eccPriv, curveId); + } + if (ret != 0) + goto done_priv; + + if (curveId <= 0 && eccPriv.dp != NULL) + curveId = eccPriv.dp->id; + + ret = wc_ecc_init_ex(&eccPub, NULL, INVALID_DEVID); + if (ret != 0) + goto done_priv; + + ret = wc_ecc_export_x963(&eccPriv, pubBuf, &pubSz); + if (ret == 0) + ret = wc_ecc_import_x963_ex(pubBuf, pubSz, &eccPub, curveId); + if (ret != 0) + goto done_pub; + + ret = wc_ecc_sign_hash(hash, hashSz, sig, &sigSz, &rng, &eccPriv); + if (ret < 0) + goto done_pub; + + if (name != NULL) { + size_t len = strlen(name); + if (len > sizeof(eccPriv.label)) + len = sizeof(eccPriv.label); + eccPriv.labelLen = (int)len; + memcpy(eccPriv.label, name, eccPriv.labelLen); + if (token != NULL) + destroy_objects_by_label(token, CKO_PRIVATE_KEY, name); + } + + if (token != NULL) + (void)wc_Pkcs11StoreKey(token, PKCS11_KEY_TYPE_EC, 0, &eccPriv); + + ret = wc_ecc_verify_hash(sig, sigSz, hash, (int)hashSz, &verify, &eccPub); + if (ret < 0 || !verify) { + if (ret >= 0) + ret = BAD_FUNC_ARG; + goto done_pub; + } + + ret = 0; + +done_pub: + wc_ecc_free(&eccPub); +done_priv: + wc_ecc_free(&eccPriv); +done_rng: + wc_FreeRng(&rng); + if (token != NULL && name != NULL) + destroy_objects_by_label(token, CKO_PRIVATE_KEY, name); + return ret; +} + +static int test_ecc_p256(Pkcs11Token* token, int devId) +{ + return test_ecc_sign_verify_der(token, devId, ecc_clikey_der_256, + (word32)sizeof_ecc_clikey_der_256, ECC_SECP256R1, "secp256r1", 0); +} + +static int test_ecc_p384(Pkcs11Token* token, int devId) +{ + return test_ecc_sign_verify_der(token, devId, ecc384_priv_der, + (word32)ecc384_priv_der_len, ECC_SECP384R1, "secp384r1", 0); +} + +#ifdef HAVE_ECC521 +static int test_ecc_p521(Pkcs11Token* token, int devId) +{ + return test_ecc_sign_verify_der(token, devId, NULL, 0, + ECC_SECP521R1, "secp521r1", 1); +} +#endif + +/* Test AES-XTS encryption/decryption */ +int test_aes_xts(Pkcs11Token* token, int dev_id) +{ + int ret = 0; + XtsAes xts; + byte cipher[sizeof(aes_xts_plain)]; + byte plain[sizeof(aes_xts_plain)]; + byte tweak[sizeof(aes_xts_tweak)]; + + ret = wc_AesXtsInit(&xts, NULL, dev_id); + if (ret != 0) return ret; + + ret = wc_AesXtsSetKey(&xts, aes_xts_key, (word32)sizeof(aes_xts_key), + AES_ENCRYPTION, NULL, 0); + if (ret != 0) goto done; + + memcpy(tweak, aes_xts_tweak, sizeof(tweak)); + memset(cipher, 0xA5, sizeof(cipher)); + memset(plain, 0x5A, sizeof(plain)); + + { + static const char label[] = "aes-xts-interop"; + size_t len = sizeof(label) - 1; + if (len > sizeof(xts.aes.label)) + len = sizeof(xts.aes.label); + xts.aes.labelLen = (int)len; + memcpy(xts.aes.label, label, xts.aes.labelLen); + destroy_objects_by_label(token, CKO_SECRET_KEY, label); + } + + ret = wc_Pkcs11StoreKey(token, PKCS11_KEY_TYPE_AES_CBC, 0, &xts); + if (ret != 0) goto done; + + ret = wc_AesXtsEncrypt(&xts, cipher, aes_xts_plain, + (word32)sizeof(aes_xts_plain), tweak, + (word32)sizeof(tweak)); + if (ret != 0) goto done; + if (compare_bytes(cipher, aes_xts_cipher, sizeof(cipher)) != 0) { + dump_buffer("xts-enc", cipher, sizeof(cipher)); + dump_buffer("xts-exp", aes_xts_cipher, sizeof(aes_xts_cipher)); + ret = WC_HW_E; + goto done; + } + + memcpy(tweak, aes_xts_tweak, sizeof(tweak)); + memset(plain, 0x5A, sizeof(plain)); + + ret = wc_AesXtsSetKey(&xts, aes_xts_key, (word32)sizeof(aes_xts_key), + AES_DECRYPTION, NULL, 0); + if (ret != 0) goto done; + + ret = wc_AesXtsDecrypt(&xts, plain, cipher, (word32)sizeof(cipher), + tweak, (word32)sizeof(tweak)); + if (ret != 0) goto done; + + if (compare_bytes(plain, aes_xts_plain, sizeof(plain)) != 0) { + dump_buffer("xts-dec", plain, sizeof(plain)); + dump_buffer("xts-exp", aes_xts_plain, sizeof(aes_xts_plain)); + ret = WC_HW_E; + } + +done: + wc_AesXtsFree(&xts); + destroy_objects_by_label(token, CKO_SECRET_KEY, "aes-xts-interop"); + return ret; +} + + +int main(int argc, char** argv) +{ + const char* module_path = getenv("WOLFPKCS11_MODULE"); + CK_SLOT_ID slot_id = 0; + Pkcs11Dev dev; + Pkcs11Token token; + int dev_id = 23; + int ret; + int failures = 0; + + if (module_path == NULL) { + module_path = (argc > 1) ? argv[1] : "./build/libwolfpkcs11-interop.so"; + } + + { + static char resolved_path[PATH_MAX]; + if (realpath(module_path, resolved_path) != NULL) + module_path = resolved_path; + } + + memset(&dev, 0, sizeof(dev)); + memset(&token, 0, sizeof(token)); + + { + void* probe = dlopen(module_path, RTLD_NOW | RTLD_LOCAL); + if (probe == NULL) { + fprintf(stderr, "dlopen failed for %s: %s\n", module_path, dlerror()); + return EXIT_FAILURE; + } + void (*debug_on)(void) = (void (*)(void))dlsym(probe, + "wolfPKCS11_Debugging_On"); + if (debug_on != NULL) + debug_on(); + dlclose(probe); + } + + ret = init_token(module_path, &dev, &token, &slot_id); + if (ret != 0) + return EXIT_FAILURE; + + ret = wc_CryptoCb_RegisterDevice(dev_id, wc_Pkcs11_CryptoDevCb, &token); + if (ret != 0) { + fprintf(stderr, "wc_CryptoCb_RegisterDevice failed: %d\n", ret); + failures++; + goto cleanup; + } + + ret = test_aes_gcm(&token, dev_id); + if (ret != 0) { + fprintf(stderr, "AES-GCM test failed: %d (%s)\n", ret, error_to_string(ret)); + failures++; + } else { + printf("AES-GCM test_passed!\n"); + } + + ret = test_hmac_sha256(&token, dev_id); + if (ret != 0) { + fprintf(stderr, "HMAC-SHA256 test failed: %d (%s)\n", ret, + error_to_string(ret)); + failures++; + } else { + printf("HMAC-SHA256 test_passed!\n"); + } + +#ifdef WOLFSSL_SHA224 + ret = test_sha224_digest(dev_id); + if (ret != 0) { + fprintf(stderr, "SHA-224 test failed: %d (%s)\n", ret, + error_to_string(ret)); + failures++; + } else { + printf("SHA-224 test_passed!\n"); + } +#endif + + ret = test_sha256_digest(dev_id); + if (ret != 0) { + fprintf(stderr, "SHA-256 test failed: %d (%s)\n", ret, + error_to_string(ret)); + failures++; + } else { + printf("SHA-256 test_passed!\n"); + } + +#ifdef WOLFSSL_SHA384 + ret = test_sha384_digest(dev_id); + if (ret != 0) { + fprintf(stderr, "SHA-384 test failed: %d (%s)\n", ret, + error_to_string(ret)); + failures++; + } else { + printf("SHA-384 test_passed!\n"); + } +#endif + +#ifdef WOLFSSL_SHA512 + ret = test_sha512_digest(dev_id); + if (ret != 0) { + fprintf(stderr, "SHA-512 test failed: %d (%s)\n", ret, + error_to_string(ret)); + failures++; + } else { + printf("SHA-512 test_passed!\n"); + } +#endif + +#ifdef WOLFSSL_SHA3 + ret = test_sha3_256_digest(dev_id); + if (ret != 0) { + fprintf(stderr, "SHA3-256 test failed: %d (%s)\n", ret, + error_to_string(ret)); + failures++; + } else { + printf("SHA3-256 test_passed!\n"); + } +#endif + + ret = test_rsa_sign_verify(&token, dev_id); + if (ret != 0) { + fprintf(stderr, "RSA PKCS#1 test failed: %d (%s)\n", ret, + error_to_string(ret)); + failures++; + } else { + printf("RSA PKCS#1 test_passed!\n"); + } + + ret = test_rsa_sign_verify_3072(&token, dev_id); + if (ret != 0) { + fprintf(stderr, "RSA-3072 test failed: %d (%s)\n", ret, + error_to_string(ret)); + failures++; + } else { + printf("RSA-3072 test_passed!\n"); + } + + ret = test_rsa_sign_verify_4096(&token, dev_id); + if (ret != 0) { + fprintf(stderr, "RSA-4096 test failed: %d (%s)\n", ret, + error_to_string(ret)); + failures++; + } else { + printf("RSA-4096 test_passed!\n"); + } + + /* New AES mode tests */ + ret = test_aes_cbc(&token, dev_id); + if (ret != 0) { + fprintf(stderr, "AES-CBC test failed: %d (%s)\n", ret, + error_to_string(ret)); + failures++; + } else { + printf("AES-CBC test_passed!\n"); + } + + ret = test_aes_cbc_256(&token, dev_id); + if (ret != 0) { + fprintf(stderr, "AES-CBC (256-bit) test failed: %d (%s)\n", ret, + error_to_string(ret)); + failures++; + } else { + printf("AES-CBC (256-bit) test_passed!\n"); + } + + ret = test_aes_ctr(&token, dev_id); + if (ret != 0) { + fprintf(stderr, "AES-CTR test failed: %d (%s)\n", ret, + error_to_string(ret)); + failures++; + } else { + printf("AES-CTR test_passed!\n"); + } + + ret = test_aes_ctr_256(&token, dev_id); + if (ret != 0) { + fprintf(stderr, "AES-CTR (256-bit) test failed: %d (%s)\n", ret, + error_to_string(ret)); + failures++; + } else { + printf("AES-CTR (256-bit) test_passed!\n"); + } + + /* ---------- AES-XTS test ---------- */ + ret = test_aes_xts(&token, dev_id); + if (ret != 0) { + fprintf(stderr, "AES-XTS test failed: %d (%s)\n", ret, + error_to_string(ret)); + failures++; + } else { + printf("AES-XTS test_passed!\n"); + } + + ret = test_ecc_p256(&token, dev_id); + if (ret != 0) { + fprintf(stderr, "ECDSA test failed: %d (%s)\n", ret, + error_to_string(ret)); + failures++; + } else { + printf("ECDSA test_passed!\n"); + } + + ret = test_ecc_p384(&token, dev_id); + if (ret != 0) { + fprintf(stderr, "ECDSA P-384 test failed: %d (%s)\n", ret, + error_to_string(ret)); + failures++; + } else { + printf("ECDSA P-384 test_passed!\n"); + } + +#ifdef HAVE_ECC521 + ret = test_ecc_p521(&token, dev_id); + if (ret != 0) { + fprintf(stderr, "ECDSA P-521 test failed: %d (%s)\n", ret, + error_to_string(ret)); + failures++; + } else { + printf("ECDSA P-521 test_passed!\n"); + } +#endif + +cleanup: + wc_CryptoCb_UnRegisterDevice(dev_id); + wc_Pkcs11Token_Close(&token); + wc_Pkcs11Token_Final(&token); + wc_Pkcs11_Finalize(&dev); + + if (failures == 0) { + printf("All wolfPKCS11 interoperability tests passed.\n"); + return EXIT_SUCCESS; + } + + fprintf(stderr, "%d test(s) failed.\n", failures); + return EXIT_FAILURE; +} +#ifdef __cplusplus +extern "C" { +#endif +void wolfPKCS11_Debugging_On(void); +void wolfPKCS11_Debugging_Off(void); +#ifdef __cplusplus +} +#endif +#ifdef __cplusplus +extern "C" { +#endif +void wolfPKCS11_Debugging_On(void); +void wolfPKCS11_Debugging_Off(void); +#ifdef __cplusplus +} +#endif diff --git a/tests/wolfssl-interoperability/user_settings.h b/tests/wolfssl-interoperability/user_settings.h new file mode 100644 index 00000000..a267c5d5 --- /dev/null +++ b/tests/wolfssl-interoperability/user_settings.h @@ -0,0 +1,91 @@ +/* user_settings.h - user settings for wolfSSL + wolfPKCS11 interoperability + * tests. + * + * Copyright (C) 2006-2025 wolfSSL Inc. + * + * This file is part of wolfPKCS11. + * + * wolfPKCS11 is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * wolfPKCS11 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ +#ifndef INTEROP_USER_SETTINGS_H +#define INTEROP_USER_SETTINGS_H + +/* Enable PKCS#11 client support inside wolfCrypt */ +#define HAVE_PKCS11 +#define WOLF_CRYPTO_CB + +/* Core algorithm coverage needed for interoperability tests */ +#define HAVE_ECC +#define HAVE_ECC384 +#define HAVE_ECC521 +#define HAVE_ECC_SIGN +#define HAVE_ECC_VERIFY +#define HAVE_ECC_DHE +#define HAVE_ECDH +#define WOLFSSL_KEY_GEN + +#define HAVE_AESGCM +#define HAVE_AES_CBC +#define HAVE_AESCTR +#define WOLFSSL_AES_COUNTER +#define WOLFSSL_AES_XTS +#define WOLFSSL_AES_CFB + +/* Enable SHA-2 family exercised by the tests */ +#define WOLFSSL_SHA224 +#define WOLFSSL_SHA384 +#define WOLFSSL_SHA512 +#define WOLFSSL_SHA3 + +/* Use single-precision math backend (replaces legacy TFM fast math). */ +#define WOLFSSL_SP_MATH_ALL +#define SP_WORD_SIZE 32 +#define WOLFSSL_HAVE_SP_RSA +#define WOLFSSL_HAVE_SP_ECC +#define WOLFSSL_HAVE_SP_DH +#define WC_RSA_BLINDING +#define ECC_TIMING_RESISTANT +#define WOLFSSL_PUBLIC_MP +#define WC_RSA_DIRECT +#define WC_RSA_PSS +#define HAVE_WOLF_BIGINT +#define WOLF_PRIVATE_KEY_ID + + +#define HAVE_HKDF +#define HAVE_SCRYPT +#define WOLFCRYPT_ONLY +#define WOLFSSL_PKCS11_RW_TOKENS +#define WOLF_CRYPTO_CB_RSA_PAD + +/* Cert buffer from wolfssl for test keys */ + +#define SP_INT_BITS 4096 +#define WOLFSSL_SP_2048 +#define WOLFSSL_SP_3072 +#define WOLFSSL_SP_4096 +#define USE_CERT_BUFFERS_256 +#define USE_CERT_BUFFERS_384 +#define USE_CERT_BUFFERS_521 +#define USE_CERT_BUFFERS_2048 +#define USE_CERT_BUFFERS_4096 +#define USE_CERT_BUFFERS_3072 + +/* Remove unused features */ +#define NO_DSA +#define NO_RC4 +#define NO_MD4 + +#endif /* INTEROP_USER_SETTINGS_H */