27#include <openssl/ec.h>
28#include <openssl/x509.h>
32#ifndef DEFAULT_CONNECTOR_URL
33#define DEFAULT_CONNECTOR_URL "http://127.0.0.1:12345"
40 0xce, 0x3d, 0x03, 0x01, 0x07};
47char *
CURVES[] = {
"secp224r1",
"secp384r1",
"secp521r1"};
51static void get_function_list(
char *
argv[]) {
52 void *handle = dlopen(
argv[1], RTLD_NOW | RTLD_GLOBAL);
53 assert(handle != NULL);
54 CK_C_GetFunctionList fn;
56 *(
void **) (&fn) = dlsym(handle,
"C_GetFunctionList");
59 CK_RV
rv = ((CK_C_GetFunctionList) fn)(&
p11);
63static void open_session() {
65 memset(&initArgs, 0,
sizeof(initArgs));
67 const char *connector_url;
68 connector_url = getenv(
"DEFAULT_CONNECTOR_URL");
69 if (connector_url == NULL) {
73 assert(strlen(connector_url) + strlen(
"connector=") < 256);
74 sprintf(
config,
"connector=%s", connector_url);
75 initArgs.pReserved = (
void *)
config;
83 const char *password =
"0001password";
87 printf(
"Session open and authenticated\n");
90static void close_session() {
98static void print_session_state() {
104 printf(
"session state: ");
107 printf(
"read-only public session\n");
110 printf(
"read-only user functions\n");
113 printf(
"read-write public session\n");
116 printf(
"read-write user functions\n");
119 printf(
"read-write so functions\n");
122 printf(
"unknown state\n");
127static void success(
const char *message) {
printf(
"%s. OK\n", message); }
129static void fail(
const char *message) {
printf(
"%s. FAIL!\n", message); }
131static bool destroy_object(CK_OBJECT_HANDLE key) {
133 printf(
"WARN. Failed to destroy object 0x%lx on HSM. FAIL\n", key);
139static void generate_keypair_yh(
CK_BYTE *curve,
149 char *
label =
"ecdhtest";
152 sizeof(pubkey_class)},
160 sizeof(privkey_class)},
165 privateKeyTemplate, 3, publicKeyPtr,
166 privateKeyPtr)) !=
CKR_OK) {
167 fail(
"Failed to generate EC key pair on YubiHSM");
170 success(
"Generated EC key pair on YubiHSM");
173static EVP_PKEY *generate_keypair_openssl(
const char *curve) {
174 EVP_PKEY *pkey = NULL;
175 EC_KEY *eckey = NULL;
176 OpenSSL_add_all_algorithms();
177 int eccgrp = OBJ_txt2nid(curve);
178 eckey = EC_KEY_new_by_curve_name(eccgrp);
179 if (!(EC_KEY_generate_key(eckey))) {
180 fail(
"Failed to generate EC keypair with openssl");
182 pkey = EVP_PKEY_new();
183 if (!EVP_PKEY_assign_EC_KEY(pkey, eckey)) {
184 fail(
"Failed to assign ECC key to EVP_PKEY structure");
190static CK_ULONG get_yhsize(CK_OBJECT_HANDLE
object) {
193 printf(
"Failed to get size of object 0x%lx from yubihsm-pkcs11. FAIL\n",
200static CK_ULONG get_yhvalue(CK_OBJECT_HANDLE
object,
unsigned char *
value,
202 if (object_size > 0) {
207 printf(
"Failed to retrieve object value from yubihsm-pkcs11. 0x%lx\n",
214static bool yh_derive(
unsigned char *peerkey_bytes,
int peerkey_len,
215 CK_OBJECT_HANDLE privkey,
char *
label,
219 params.pSharedData = NULL;
220 params.ulSharedDataLen = 0;
221 params.pPublicData = peerkey_bytes;
222 params.ulPublicDataLen = peerkey_len;
242static bool yh_derive_ecdh(CK_OBJECT_HANDLE priv_key, EVP_PKEY *peer_keypair,
245 EC_KEY *peerkey = EVP_PKEY_get1_EC_KEY(peer_keypair);
246 unsigned char *peerkey_bytes = NULL;
247 int peerkey_len = i2o_ECPublicKey(peerkey, &peerkey_bytes);
248 if (peerkey_len < 0) {
249 fail(
"Failed to extract public key from EC keypair generated with openssl");
253 EC_KEY_free(peerkey);
255 if (!yh_derive(peerkey_bytes, peerkey_len, priv_key,
label,
ecdh_key)) {
257 fail(
"Failed to derive ECDH key on yubihsm-pkcs11");
259 OPENSSL_free(peerkey_bytes);
263 OPENSSL_free(peerkey_bytes);
268static size_t openssl_derive(EVP_PKEY *private_key, EVP_PKEY *peer_key,
271 EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(private_key, NULL);
273 fail(
"Failed to create new openssl context");
279 if (EVP_PKEY_derive_init(ctx) != 1) {
280 fail(
"Failed to initialize openssl contex");
285 if (EVP_PKEY_derive_set_peer(ctx, peer_key) != 1) {
286 fail(
"Failed to set the peer public key in the openssl context");
291 if (EVP_PKEY_derive(ctx, NULL, &
len) != 1) {
292 fail(
"Failed to determine derived key expected size with openssl");
299 fail(
"Failed to allocate the buffer to hold the ECDH key derived with "
306 if ((EVP_PKEY_derive(ctx, *
ecdh_key, &
len)) != 1) {
307 fail(
"Failed to derive ECDH key with openssl");
313 EVP_PKEY_CTX_free(ctx);
314 EVP_PKEY_free(peer_key);
315 EVP_PKEY_free(private_key);
320static unsigned char *openssl_derive_ecdh(EVP_PKEY *private_key,
321 CK_OBJECT_HANDLE peer_key,
323 CK_LONG peerkey_len = get_yhsize(peer_key);
324 if (peerkey_len == 0) {
328 unsigned char peerkey_bytes[peerkey_len];
329 if (get_yhvalue(peer_key, peerkey_bytes, peerkey_len) == 0) {
330 fail(
"Failed to retrieve public key from yubihsm-pkcs11");
334 const unsigned char *
p = peerkey_bytes;
335 EVP_PKEY *pkey = d2i_PUBKEY(NULL, &
p, peerkey_len);
337 unsigned char *derivekey_openssl = NULL;
338 *ecdh_len = openssl_derive(private_key, pkey, &derivekey_openssl);
339 if (*ecdh_len == 0) {
340 fail(
"Failed to derive key with openssl");
342 return derivekey_openssl;
345static bool test_ecdh_value(
const char *curve, CK_OBJECT_HANDLE yh_privkey,
346 CK_OBJECT_HANDLE yh_pubkey,
350 EVP_PKEY *openssl_keypair = generate_keypair_openssl(curve);
351 if (openssl_keypair == NULL) {
356 yh_derive_ecdh(yh_privkey, openssl_keypair, ecdh1,
"ecdh1",
true);
359 size_t ecdh_openssl_len = 0;
360 unsigned char *ecdh_openssl =
361 openssl_derive_ecdh(openssl_keypair, yh_pubkey, &ecdh_openssl_len);
362 if (ecdh_openssl_len == 0) {
363 fail(
"Failed to derive key with openssl");
368 CK_ULONG ecdh1_len = get_yhsize(*ecdh1);
369 if (ecdh1_len != ecdh_openssl_len) {
371 "ECDH keys derived with yubihsm-pkcs11 and with openssl do not have the "
377 unsigned char ecdh1_bytes[
BUFSIZE];
378 if (get_yhvalue(*ecdh1, ecdh1_bytes, ecdh1_len) == 0) {
379 fail(
"Failed to retrieve derived key from yubihsm-pkcs11");
384 for (
unsigned int i = 0; i < ecdh_openssl_len; i++) {
385 if (ecdh1_bytes[i] != ecdh_openssl[i]) {
391 OPENSSL_free(ecdh_openssl);
395 "ECDH keys derived with yubihsm-pkcs11 and with openssl do not have the "
403static bool test_duplicate_ecdh(
const char *curve, CK_OBJECT_HANDLE yh_privkey,
406 EVP_PKEY *openssl_keypair = generate_keypair_openssl(curve);
407 if (openssl_keypair == NULL) {
411 if (!yh_derive_ecdh(yh_privkey, openssl_keypair, ecdh2,
"ecdh2",
true)) {
412 EVP_PKEY_free(openssl_keypair);
415 if (!yh_derive_ecdh(yh_privkey, openssl_keypair, ecdh3,
"ecdh3",
true)) {
416 EVP_PKEY_free(openssl_keypair);
420 EVP_PKEY_free(openssl_keypair);
422 size_t ecdh1_len = get_yhsize(*ecdh2);
423 size_t ecdh2_len = get_yhsize(*ecdh3);
424 if (ecdh1_len == 0 || ecdh2_len == 0) {
428 if (ecdh1_len != ecdh2_len) {
430 "2 ECDH keys derived from the same base keys do not have the same size");
435 if (get_yhvalue(*ecdh2, ecdh1_value, ecdh1_len) == 0) {
438 if (get_yhvalue(*ecdh3, ecdh2_value, ecdh2_len) == 0) {
443 for (
unsigned int i = 0; i < ecdh1_len; i++) {
444 if (ecdh1_value[i] != ecdh2_value[i]) {
451 "ECDH keys derived from the same base keys do not have the same value");
458static bool test_faulty_ecdh(
const char *curve1,
const char *curve2,
462 EVP_PKEY *openssl_keypair = generate_keypair_openssl(curve2);
463 if (openssl_keypair == NULL) {
467 CK_OBJECT_HANDLE faulty_ecdh;
468 if (yh_derive_ecdh(*yh_privkey, openssl_keypair, &faulty_ecdh,
"",
false)) {
469 fail(
"Was able to derive ECDH key from EC keys of different curves");
470 EVP_PKEY_free(openssl_keypair);
473 EVP_PKEY_free(openssl_keypair);
476 EVP_PKEY *key_openssl2 = generate_keypair_openssl(curve1);
477 if (yh_derive_ecdh(*
ecdh_key, key_openssl2, &faulty_ecdh,
"",
false)) {
478 fail(
"Was able to derive ECDH key using another ECDH key");
479 EVP_PKEY_free(key_openssl2);
482 EVP_PKEY_free(key_openssl2);
490 {
CKA_CLASS, &key_class,
sizeof(key_class)},
497 fail(
"Expected CKR_MECHANISM_INVALID when invalid mechanism is "
505static bool validate_ecdh_attributes(CK_OBJECT_HANDLE
key_id,
506 char *expected_label) {
508 CK_OBJECT_CLASS key_class;
530 char label[41] = {0};
534 {{
CKA_CLASS, &key_class,
sizeof(key_class)},
536 {
CKA_LOCAL, &is_local,
sizeof(is_local)},
537 {
CKA_TOKEN, &is_token,
sizeof(is_token)},
541 sizeof(is_never_extractable)},
546 {
CKA_SIGN, &is_sign,
sizeof(is_sign)},
549 sizeof(is_always_authenticated)},
551 {
CKA_WRAP, &is_wrap,
sizeof(is_wrap)},
553 sizeof(is_wrap_with_trusted)},
557 {
CKA_VALUE, &publicValue,
sizeof(publicValue)},
565 fail(
"Failed to retrieve ECDH key attributes from yubihsm-pkcs11");
570 fail(
"Derived ECDH key class is not CKO_SECRET_KEY");
575 fail(
"Derived ECDH key type is not CKK_GENERIC_SECRET");
580 fail(
"Derived ECDH key LOCAL attribute is not CK_FALSE");
585 fail(
"Derived ECDH key TOKEN attribute is not CK_FALSE");
589 if (is_destroyable !=
CK_TRUE) {
590 fail(
"Derived ECDH key DESTROYABLE attribute is not CK_TRUE");
594 if (is_extractable !=
CK_TRUE) {
595 fail(
"Derived ECDH key EXTRACTABLE attribute is not CK_TRUE");
599 if (is_never_extractable !=
CK_FALSE) {
600 fail(
"Derived ECDH key NEVER_EXTRACTABLE attribute is not CK_FALSE");
605 fail(
"Derived ECDH key SENSITIVE attribute is not CK_FALSE");
609 if (is_always_sensitive !=
CK_FALSE) {
610 fail(
"Derived ECDH key ALWAYS_SENSITIVE attribute is not CK_FALSE");
615 fail(
"Derived ECDH key MODIFIABLE attribute is not CK_FALSE");
620 fail(
"Derived ECDH key COPYABLE attribute is not CK_FALSE");
625 fail(
"Derived ECDH key SIGN attribute is not CK_FALSE");
630 fail(
"Derived ECDH key SIGN_RECOVER attribute is not CK_FALSE");
634 if (is_always_authenticated !=
CK_FALSE) {
635 fail(
"Derived ECDH key ALWAYS_AUTHENTICATED attribute is not CK_FALSE");
640 fail(
"Derived ECDH key UNWRAP attribute is not CK_FALSE");
645 fail(
"Derived ECDH key WRAP attribute is not CK_FALSE");
649 if (is_wrap_with_trusted !=
CK_FALSE) {
650 fail(
"Derived ECDH key WRAP_WITH_TRUSTED attribute is not CK_FALSE");
655 fail(
"Derived ECDH key VERIFY attribute is not CK_FALSE");
660 fail(
"Derived ECDH key ENCRYPT attribute is not CK_FALSE");
665 fail(
"Derived ECDH key DERIVE attribute is not CK_FALSE");
669 if (strcmp(
label, expected_label) != 0) {
670 fail(
"Derived ECDH key does not have the expected label");
682 fail(
"Failed to initialize search function");
685 int max_items_count = 256 + 255;
686 CK_OBJECT_HANDLE found_objects[max_items_count];
689 &total_objects_found)) ==
CKR_OK) {
690 if ((expected_ecdh_count > 0) && (total_objects_found == 0)) {
691 fail(
"Not enough objects were found");
695 for (
size_t i = 0; i < total_objects_found; i++) {
696 if (found_objects[i] == *ecdh1 || found_objects[i] == *ecdh2 ||
697 found_objects[i] == *ecdh3) {
701 if (found != expected_ecdh_count) {
702 fail(
"Target object were not found or were found when they should "
708 fail(
"Search operation failed");
713 fail(
"Failed to finalize search function");
726 {
CKA_CLASS, &secret_key_class,
sizeof(secret_key_class)}};
727 return find(
template, 1, ecdh1, ecdh2, ecdh3, 3);
736 {
CKA_CLASS, &public_key_class,
sizeof(public_key_class)}};
737 return find(
template, 1, ecdh1, ecdh2, ecdh3, 0);
743 int expected_count) {
748 sizeof(secret_key_class)},
750 return find(
template, 2, ecdh1, ecdh2, ecdh3, expected_count);
760 sizeof(secret_key_class)},
762 return find(
template, 2, ecdh1, ecdh2, ecdh3, 0);
772 char *
label =
"ecdhtest";
774 sizeof(secret_key_class)},
777 return find(
template, 3, ecdh1, ecdh2, ecdh3, 0);
787 sizeof(secret_key_class)},
789 return find(
template, 2, ecdh1, ecdh2, ecdh3, 0);
797 char *
label =
"ecdh2";
799 sizeof(secret_key_class)},
801 return find(
template, 2, ecdh1, ecdh2, ecdh3, 1);
811 sizeof(public_key_class)},
813 return find(
template, 2, ecdh1, ecdh2, ecdh3, 0);
820 return find(
template, 0, ecdh1, ecdh2, ecdh3, 3);
827 fail(
"Initializing decryption did not return the error code "
828 "CKR_KEY_TYPE_INCONSISTENT");
838 fail(
"Initializing signing did not return the error code "
839 "CKR_FUNCTION_NOT_SUPPORTED");
848 fprintf(stderr,
"usage: /path/to/yubihsm_pkcs11/module\n");
852 get_function_list(
argv);
854 print_session_state();
856 int exit_status = EXIT_SUCCESS;
858 CK_OBJECT_HANDLE yh_pubkey, yh_privkey;
862 printf(
"\n/////// Testing curve %s\n",
CURVES[i]);
864 generate_keypair_yh(
CURVE_PARAMS[i], &yh_pubkey, &yh_privkey);
865 CK_OBJECT_HANDLE ecdh1, ecdh2, ecdh3;
867 printf(
"Testing the value of ECDH key derived by yubihsm-pkcs11... ");
868 if (test_ecdh_value(
CURVES[i], yh_privkey, yh_pubkey, &ecdh1)) {
872 exit_status = EXIT_FAILURE;
877 "Testing that 2 ECDH keys derived from the same base keys are equal... ");
878 if (test_duplicate_ecdh(
CURVES[i], yh_privkey, &ecdh2, &ecdh3)) {
882 exit_status = EXIT_FAILURE;
886 printf(
"Testing deriving ECDH keys with faulty parameters... ");
887 if (test_faulty_ecdh(
CURVES[i],
"prime256v1", &yh_privkey, &ecdh1)) {
891 exit_status = EXIT_FAILURE;
895 printf(
"Validating ECDH attributes... ");
896 if (validate_ecdh_attributes(ecdh1,
"ecdh1")) {
900 exit_status = EXIT_FAILURE;
906 printf(
"Finding ECDH keys: secret keys... ");
907 if (find_secret_keys(&ecdh1, &ecdh2, &ecdh3)) {
911 exit_status = EXIT_FAILURE;
915 printf(
"Finding ECDH keys: public keys... ");
916 if (find_public_keys(&ecdh1, &ecdh2, &ecdh3)) {
920 exit_status = EXIT_FAILURE;
924 printf(
"Finding ECDH keys: secret, extractable keys... ");
925 if (find_secret_extractable_keys(&ecdh1, &ecdh2, &ecdh3, 3)) {
929 exit_status = EXIT_FAILURE;
933 printf(
"Finding ECDH keys: secret, un-extractable keys... ");
934 if (find_secret_unextractable_keys(&ecdh1, &ecdh2, &ecdh3)) {
938 exit_status = EXIT_FAILURE;
942 printf(
"Finding ECDH keys: secret, extractable keys with wrong label... ");
943 if (find_secret_extractable_keys_wrong_label(&ecdh1, &ecdh2, &ecdh3)) {
947 exit_status = EXIT_FAILURE;
951 printf(
"Finding ECDH keys: secret key with specific ID... ");
952 if (find_secret_key_with_id(&ecdh1, &ecdh2, &ecdh3, &yh_privkey)) {
956 exit_status = EXIT_FAILURE;
960 printf(
"Finding ECDH keys: secret key with right label... ");
961 if (find_secret_key_right_label(&ecdh1, &ecdh2, &ecdh3)) {
965 exit_status = EXIT_FAILURE;
969 printf(
"Finding ECDH keys: public key with right label... ");
970 if (find_public_key_right_label(&ecdh1, &ecdh2, &ecdh3)) {
974 exit_status = EXIT_FAILURE;
978 printf(
"Finding ECDH keys: use empty template... ");
979 if (find_empty_template(&ecdh1, &ecdh2, &ecdh3)) {
983 exit_status = EXIT_FAILURE;
989 printf(
"Destroying ECDH key 1... ");
990 destroy_object(ecdh1);
991 if (find_secret_extractable_keys(&ecdh1, &ecdh2, &ecdh3, 2)) {
995 exit_status = EXIT_FAILURE;
999 printf(
"Destroying ECDH key 2... ");
1000 destroy_object(ecdh3);
1001 if (find_secret_extractable_keys(&ecdh1, &ecdh2, &ecdh3, 1)) {
1005 exit_status = EXIT_FAILURE;
1009 printf(
"Testing decryption... ");
1010 if (test_decrypt(&ecdh2)) {
1014 exit_status = EXIT_FAILURE;
1018 printf(
"Testing signing... ");
1019 if (test_sign(&ecdh2)) {
1023 exit_status = EXIT_FAILURE;
1027 printf(
"Destroying ECDH key 3... ");
1028 destroy_object(ecdh2);
1029 if (find_secret_extractable_keys(&ecdh1, &ecdh2, &ecdh3, 0)) {
1033 exit_status = EXIT_FAILURE;
1037 destroy_object(yh_privkey);
1041 if (exit_status == EXIT_FAILURE) {
1042 destroy_object(yh_privkey);
1045 return (exit_status);
CK_SESSION_HANDLE session
#define DEFAULT_CONNECTOR_URL
RUNTIME_API Runtime::ObjectInstance * find(const std::string &name, const IR::ObjectType &type)
LOGGING_API void printf(Category category, const char *format,...)
#define CKA_NEVER_EXTRACTABLE
#define CKR_MECHANISM_INVALID
unsigned long int CK_ULONG
ck_object_handle_t * CK_OBJECT_HANDLE_PTR
#define CKF_SERIAL_SESSION
#define CKM_EC_KEY_PAIR_GEN
#define CKA_WRAP_WITH_TRUSTED
#define CKA_ALWAYS_AUTHENTICATE
#define CKK_GENERIC_SECRET
#define CKA_ALWAYS_SENSITIVE
#define CKR_FUNCTION_NOT_SUPPORTED
CK_UTF8CHAR * CK_UTF8CHAR_PTR
#define CKR_KEY_TYPE_INCONSISTENT
CK_C_OpenSession C_OpenSession
CK_C_GenerateKeyPair C_GenerateKeyPair
CK_C_FindObjectsFinal C_FindObjectsFinal
CK_C_DestroyObject C_DestroyObject
CK_C_FindObjectsInit C_FindObjectsInit
CK_C_FindObjects C_FindObjects
CK_C_DeriveKey C_DeriveKey
CK_C_Initialize C_Initialize
CK_C_GetAttributeValue C_GetAttributeValue
CK_C_DecryptInit C_DecryptInit
CK_C_GetObjectSize C_GetObjectSize
CK_C_GetSessionInfo C_GetSessionInfo
account_query_db::get_accounts_by_authorizers_params params
CK_SLOT_ID CK_SLOT_INFO_PTR pInfo
memset(pInfo->slotDescription, ' ', 64)
ecdh_session_key ecdh_key