diff --git a/.github/workflows/trustzone-emulator-tests.yml b/.github/workflows/trustzone-emulator-tests.yml index 3c1949f8..ddd11b1f 100644 --- a/.github/workflows/trustzone-emulator-tests.yml +++ b/.github/workflows/trustzone-emulator-tests.yml @@ -33,7 +33,7 @@ jobs: make clean distclean cp config/examples/stm32h5-tz.config .config - make wolfboot.bin PKCS11_TESTAPP=1 + make PKCS11_TESTAPP=1 first_log=/tmp/m33mu-pkcs11-first.log second_log=/tmp/m33mu-pkcs11-second.log @@ -42,18 +42,30 @@ jobs: rm -rf "$persist_dir" mkdir -p "$persist_dir" + dump_log() { + local log_file="$1" + if [ -f "$log_file" ]; then + echo "--- $log_file ---" + cat "$log_file" + fi + } + ( cd "$persist_dir" m33mu "$GITHUB_WORKSPACE/wolfboot.bin" \ "$GITHUB_WORKSPACE/test-app/image_v1_signed.bin:0x60000" \ - --persist --uart-stdout --timeout 120 --expect-bkpt 0x7f \ + --persist --uart-stdout --timeout 120 --expect-bkpt 0x7d \ >"$first_log" 2>&1 ) - grep -q "pkcs11: first boot path, creating persistent objects" "$first_log" - grep -q "pkcs11: created persistent PKCS11 objects" "$first_log" - grep -q "pkcs11: success" "$first_log" - grep -q "\\[EXPECT BKPT\\] Success" "$first_log" + grep -q "pkcs11: first boot path, creating persistent objects" "$first_log" && \ + grep -q "pkcs11: created persistent PKCS11 objects" "$first_log" && \ + grep -q "pkcs11: success" "$first_log" && \ + grep -q "\\[BKPT\\] imm=0x7d" "$first_log" && \ + grep -q "\\[EXPECT BKPT\\] Success" "$first_log" || { + dump_log "$first_log" + exit 1 + } ( cd "$persist_dir" @@ -63,10 +75,14 @@ jobs: >"$second_log" 2>&1 ) - grep -q "pkcs11: second boot path, restoring persistent objects" "$second_log" - grep -q "pkcs11: restored persistent PKCS11 objects" "$second_log" - grep -q "pkcs11: success" "$second_log" - grep -q "\\[EXPECT BKPT\\] Success" "$second_log" + grep -q "pkcs11: second boot path, restoring persistent objects" "$second_log" && \ + grep -q "pkcs11: restored persistent PKCS11 objects" "$second_log" && \ + grep -q "pkcs11: success" "$second_log" && \ + grep -q "\\[BKPT\\] imm=0x7f" "$second_log" && \ + grep -q "\\[EXPECT BKPT\\] Success" "$second_log" || { + dump_log "$second_log" + exit 1 + } - name: Clean and build stm32u5 (TZ + wolfcrypt) run: | diff --git a/test-app/app_stm32h5.c b/test-app/app_stm32h5.c index 55875d30..32a1d01b 100644 --- a/test-app/app_stm32h5.c +++ b/test-app/app_stm32h5.c @@ -1282,7 +1282,9 @@ void main(void) #ifdef WOLFBOOT_PKCS11_TESTAPP ret = test_pkcs11_start(); - if (ret == 0) + if (ret == PKCS11_TEST_FIRST_BOOT_OK) + asm volatile ("bkpt #0x7d"); + else if (ret == PKCS11_TEST_SECOND_BOOT_OK) asm volatile ("bkpt #0x7f"); else asm volatile ("bkpt #0x7e"); diff --git a/test-app/test_pkcs11.c b/test-app/test_pkcs11.c index 4791c881..d5142ebe 100644 --- a/test-app/test_pkcs11.c +++ b/test-app/test_pkcs11.c @@ -17,13 +17,16 @@ #include "test_pkcs11.h" +#include "wolfpkcs11/pkcs11.h" + #include #include +#include +#include +#include #include #include -#include "wolfpkcs11/pkcs11.h" - extern const char pkcs11_library_name[]; extern const CK_FUNCTION_LIST wolfpkcs11nsFunctionList; @@ -31,8 +34,10 @@ static const CK_BYTE test_token_label[32] = { 'E','c','c','K','e','y',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ', ' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ' }; +static const char test_token_name[] = "EccKey"; static const CK_BYTE test_so_pin[] = "0123456789ABCDEF"; -static const CK_BYTE test_user_pin[] = "ABCDEF0123456789"; +static const CK_BYTE test_user_pin[] = "0123456789ABCDEF"; +static const CK_BYTE test_so_pin_label[] = "SO-PIN"; static const CK_BYTE test_key_id[] = { 0x57, 0x42, 0x50, 0x31 }; static const CK_BYTE test_pub_label[] = "wolfBoot PKCS11 demo pub"; static const CK_BYTE test_priv_label[] = "wolfBoot PKCS11 demo priv"; @@ -73,6 +78,22 @@ static int test_pkcs11_ck_ok(const char *label, CK_RV rv) return 0; } +static void test_pkcs11_log_blob_checksum(const struct test_pkcs11_blob *blob, + const char *prefix) +{ + byte digest[WC_SHA256_DIGEST_SIZE]; + word32 blob_len = (word32)(blob->payload_len + blob->sig_len); + word32 i; + + if (wc_Sha256Hash(blob->data, blob_len, digest) != 0) + return; + + printf("pkcs11: %s blob_sha256=", prefix); + for (i = 0; i < (word32)sizeof(digest); i++) + printf("%02x", digest[i]); + printf("\r\n"); +} + static int test_pkcs11_find_one(CK_SESSION_HANDLE session, CK_ATTRIBUTE_PTR tmpl, CK_ULONG tmpl_count, CK_OBJECT_HANDLE *obj) { @@ -159,32 +180,46 @@ static int test_pkcs11_log_obj_attr(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE return 0; } -static int test_pkcs11_init_token_if_needed(void) +static int test_pkcs11_provision_token(void) { + int ret; CK_RV rv; - CK_TOKEN_INFO info; - CK_SESSION_HANDLE session; + CK_SESSION_HANDLE session = CK_INVALID_HANDLE; + Pkcs11Token token; + Pkcs11Dev dev; - rv = wolfpkcs11nsFunctionList.C_GetTokenInfo(TEST_PKCS11_SLOT_ID, &info); - if (rv == CKR_OK && (info.flags & CKF_TOKEN_INITIALIZED)) - return 0; + printf("pkcs11: provisioning token\r\n"); + + dev.heap = NULL; + dev.func = (CK_FUNCTION_LIST *)&wolfpkcs11nsFunctionList; + + ret = wc_Pkcs11Token_Init(&token, &dev, (int)TEST_PKCS11_SLOT_ID, + test_token_name, test_user_pin, (int)(sizeof(test_user_pin) - 1)); + if (ret != 0) { + printf("pkcs11: wc_Pkcs11Token_Init ret=%d\r\n", ret); + return -1; + } - printf("pkcs11: initializing token\r\n"); rv = wolfpkcs11nsFunctionList.C_InitToken(TEST_PKCS11_SLOT_ID, (CK_UTF8CHAR_PTR)test_so_pin, (CK_ULONG)(sizeof(test_so_pin) - 1), (CK_UTF8CHAR_PTR)test_token_label); - if (test_pkcs11_ck_ok("C_InitToken", rv) < 0) + if (test_pkcs11_ck_ok("C_InitToken", rv) < 0) { + wc_Pkcs11Token_Final(&token); return -1; + } rv = wolfpkcs11nsFunctionList.C_OpenSession(TEST_PKCS11_SLOT_ID, CKF_SERIAL_SESSION | CKF_RW_SESSION, NULL, NULL, &session); - if (test_pkcs11_ck_ok("C_OpenSession(SO)", rv) < 0) + if (test_pkcs11_ck_ok("C_OpenSession(SO)", rv) < 0) { + wc_Pkcs11Token_Final(&token); return -1; + } rv = wolfpkcs11nsFunctionList.C_Login(session, CKU_SO, (CK_UTF8CHAR_PTR)test_so_pin, (CK_ULONG)(sizeof(test_so_pin) - 1)); if (test_pkcs11_ck_ok("C_Login(SO)", rv) < 0) { (void)wolfpkcs11nsFunctionList.C_CloseSession(session); + wc_Pkcs11Token_Final(&token); return -1; } @@ -193,11 +228,13 @@ static int test_pkcs11_init_token_if_needed(void) if (test_pkcs11_ck_ok("C_InitPIN", rv) < 0) { (void)wolfpkcs11nsFunctionList.C_Logout(session); (void)wolfpkcs11nsFunctionList.C_CloseSession(session); + wc_Pkcs11Token_Final(&token); return -1; } (void)wolfpkcs11nsFunctionList.C_Logout(session); (void)wolfpkcs11nsFunctionList.C_CloseSession(session); + wc_Pkcs11Token_Final(&token); return 0; } @@ -310,7 +347,7 @@ static int test_pkcs11_sign_payload(CK_SESSION_HANDLE session, CK_ULONG payload_len = (CK_ULONG)(sizeof(test_payload) - 1); CK_ULONG sig_len = (CK_ULONG)(sizeof(blob->data) - payload_len); - mech.mechanism = CKM_ECDSA; + mech.mechanism = CKM_ECDSA_SHA256; mech.pParameter = NULL; mech.ulParameterLen = 0; @@ -333,6 +370,7 @@ static int test_pkcs11_sign_payload(CK_SESSION_HANDLE session, printf("pkcs11: signed payload len=%lu sig_len=%lu\r\n", (unsigned long)blob->payload_len, (unsigned long)blob->sig_len); + test_pkcs11_log_blob_checksum(blob, "created"); return 0; } @@ -376,6 +414,7 @@ static int test_pkcs11_load_blob(CK_SESSION_HANDLE session, printf("pkcs11: restored blob payload_len=%lu sig_len=%lu\r\n", (unsigned long)blob->payload_len, (unsigned long)blob->sig_len); + test_pkcs11_log_blob_checksum(blob, "restored"); return 0; } @@ -385,7 +424,7 @@ static int test_pkcs11_verify_blob(CK_SESSION_HANDLE session, CK_RV rv; CK_MECHANISM mech; - mech.mechanism = CKM_ECDSA; + mech.mechanism = CKM_ECDSA_SHA256; mech.pParameter = NULL; mech.ulParameterLen = 0; @@ -421,6 +460,7 @@ static int test_pkcs11_log_key_attrs(CK_SESSION_HANDLE session, int test_pkcs11_start(void) { + int wc_ret; CK_RV rv; CK_SESSION_HANDLE session = CK_INVALID_HANDLE; CK_OBJECT_HANDLE pub_obj = CK_INVALID_HANDLE; @@ -428,45 +468,68 @@ int test_pkcs11_start(void) CK_OBJECT_HANDLE data_obj = CK_INVALID_HANDLE; struct test_pkcs11_blob blob; int ret; + int key_state; + int data_state; + int result = PKCS11_TEST_FAIL; memset(&blob, 0, sizeof(blob)); printf("pkcs11: start\r\n"); printf("pkcs11: secure provider=%s\r\n", pkcs11_library_name); - rv = wolfpkcs11nsFunctionList.C_Initialize(NULL); - if (test_pkcs11_ck_ok("C_Initialize", rv) < 0) + wc_ret = wolfCrypt_Init(); + if (wc_ret != 0) { + printf("pkcs11: wolfCrypt_Init ret=%d\r\n", wc_ret); return -1; + } - if (test_pkcs11_init_token_if_needed() < 0) { - (void)wolfpkcs11nsFunctionList.C_Finalize(NULL); + rv = wolfpkcs11nsFunctionList.C_Initialize(NULL); + if (test_pkcs11_ck_ok("C_Initialize", rv) < 0) { + wolfCrypt_Cleanup(); return -1; } ret = test_pkcs11_open_user_session(&session); if (ret == -2) { - (void)wolfpkcs11nsFunctionList.C_Finalize(NULL); - return -1; + printf("pkcs11: first boot path, provisioning token\r\n"); + if (test_pkcs11_provision_token() < 0) { + (void)wolfpkcs11nsFunctionList.C_Finalize(NULL); + wolfCrypt_Cleanup(); + return -1; + } + ret = test_pkcs11_open_user_session(&session); } if (ret < 0) { (void)wolfpkcs11nsFunctionList.C_Finalize(NULL); + wolfCrypt_Cleanup(); return -1; } - ret = test_pkcs11_find_keypair(session, &pub_obj, &priv_obj); - if (ret < 0) { + key_state = test_pkcs11_find_keypair(session, &pub_obj, &priv_obj); + if (key_state < 0) { + ret = -1; + goto cleanup; + } + + data_state = test_pkcs11_find_data_obj(session, &data_obj); + if (data_state < 0) { (void)wolfpkcs11nsFunctionList.C_Logout(session); (void)wolfpkcs11nsFunctionList.C_CloseSession(session); (void)wolfpkcs11nsFunctionList.C_Finalize(NULL); + wolfCrypt_Cleanup(); return -1; } - if (ret == 1) { + if (key_state == 1 && data_state == 1) { printf("pkcs11: first boot path, creating persistent objects\r\n"); if (test_pkcs11_generate_keypair(session, &pub_obj, &priv_obj) < 0) ret = -1; - if (ret == 1 || ret == 0) + else + ret = 0; + if (ret == 0) ret = test_pkcs11_sign_payload(session, priv_obj, &blob); + if (ret == 0) + ret = test_pkcs11_verify_blob(session, pub_obj, &blob); if (ret == 0) ret = test_pkcs11_store_blob(session, &blob, &data_obj); if (ret == 0) @@ -477,12 +540,12 @@ int test_pkcs11_start(void) ret = test_pkcs11_log_obj_attr(session, data_obj, "data", CKA_OBJECT_ID); if (ret == 0) printf("pkcs11: created persistent PKCS11 objects\r\n"); - } - else { - printf("pkcs11: second boot path, restoring persistent objects\r\n"); - ret = test_pkcs11_find_data_obj(session, &data_obj); if (ret == 0) - ret = test_pkcs11_load_blob(session, data_obj, &blob); + result = PKCS11_TEST_FIRST_BOOT_OK; + } + else if (key_state == 0 && data_state == 0) { + printf("pkcs11: second boot path, restoring persistent objects\r\n"); + ret = test_pkcs11_load_blob(session, data_obj, &blob); if (ret == 0) ret = test_pkcs11_log_key_attrs(session, pub_obj, priv_obj); if (ret == 0) @@ -491,18 +554,27 @@ int test_pkcs11_start(void) ret = test_pkcs11_verify_blob(session, pub_obj, &blob); if (ret == 0) printf("pkcs11: restored persistent PKCS11 objects\r\n"); + if (ret == 0) + result = PKCS11_TEST_SECOND_BOOT_OK; + } + else { + printf("pkcs11: inconsistent persistent state key_state=%d data_state=%d\r\n", + key_state, data_state); + ret = -1; } +cleanup: (void)wolfpkcs11nsFunctionList.C_Logout(session); (void)wolfpkcs11nsFunctionList.C_CloseSession(session); (void)wolfpkcs11nsFunctionList.C_Finalize(NULL); + (void)wolfCrypt_Cleanup(); if (ret == 0) printf("pkcs11: success\r\n"); else printf("pkcs11: failure\r\n"); - return ret; + return (ret == 0) ? result : PKCS11_TEST_FAIL; } #else diff --git a/test-app/test_pkcs11.h b/test-app/test_pkcs11.h index cc76d49a..f0abd986 100644 --- a/test-app/test_pkcs11.h +++ b/test-app/test_pkcs11.h @@ -1,6 +1,12 @@ #ifndef WOLFBOOT_TEST_PKCS11_H #define WOLFBOOT_TEST_PKCS11_H +enum test_pkcs11_result { + PKCS11_TEST_FAIL = -1, + PKCS11_TEST_FIRST_BOOT_OK = 1, + PKCS11_TEST_SECOND_BOOT_OK = 2 +}; + int test_pkcs11_start(void); #endif /* WOLFBOOT_TEST_PKCS11_H */