diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 0000000..b3c287f --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,4 @@ +# These are supported funding model platforms + +github: polhenarejos +custom: ["https://www.paypal.me/polhenarejos"] diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 30fa93a..f080f71 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -23,9 +23,7 @@ on: jobs: build: - runs-on: ubuntu-latest - steps: - name: Checkout repository and submodules uses: actions/checkout@v3 @@ -33,5 +31,36 @@ jobs: submodules: recursive - name: Build in container run: ./tests/build-in-docker.sh - - name: Start emulation and test - run: ./tests/run-test-in-docker.sh + - name: Export image + run: | + mkdir -p artifacts + docker save pico-hsm-test:bullseye -o artifacts/docker-image.tar + - name: Temporarily save image + uses: actions/upload-artifact@v3 + with: + name: docker-artifact + path: artifacts + retention-days: 1 + + test: + runs-on: ubuntu-latest + needs: build + strategy: + matrix: + suite: ["pkcs11", "pytest", "sc-hsm-pkcs11"] + steps: + - name: Checkout repository and submodules + uses: actions/checkout@v3 + with: + submodules: recursive + - name: Retrieve saved image + uses: actions/download-artifact@v3 + with: + name: docker-artifact + path: artifacts + - name: Load image + run: | + cd artifacts + docker load -q -i docker-image.tar + - name: Test ${{ matrix.suite }} + run: ./tests/run-test-in-docker.sh ${{ matrix.suite }} diff --git a/.gitmodules b/.gitmodules index 6e06e69..852c02c 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,3 @@ -[submodule "pico-hsm-sdk"] - path = pico-hsm-sdk - url = ../pico-hsm-sdk +[submodule "pico-keys-sdk"] + path = pico-keys-sdk + url = https://github.com/polhenarejos/pico-keys-sdk diff --git a/CMakeLists.txt b/CMakeLists.txt index a3f9046..8cc8556 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -32,6 +32,13 @@ else() pico_sdk_init() endif() +if (NOT DEFINED __FOR_CI) + set(__FOR_CI 0) +endif() +if (__FOR_CI) + add_definitions(-D__FOR_CI) +endif() + add_executable(pico_hsm) set(SOURCES ${SOURCES} @@ -70,7 +77,7 @@ set(SOURCES ${SOURCES} ) set(USB_ITF_CCID 1) -include(pico-hsm-sdk/pico_hsm_sdk_import.cmake) +include(pico-keys-sdk/pico_keys_sdk_import.cmake) set(INCLUDES ${INCLUDES} ${CMAKE_CURRENT_LIST_DIR}/src/hsm @@ -102,5 +109,5 @@ endif (APPLE) else() pico_add_extra_outputs(pico_hsm) -target_link_libraries(pico_hsm PRIVATE pico_hsm_sdk pico_stdlib pico_multicore hardware_flash hardware_sync hardware_adc pico_unique_id hardware_rtc tinyusb_device tinyusb_board) +target_link_libraries(pico_hsm PRIVATE pico_keys_sdk pico_stdlib pico_multicore hardware_flash hardware_sync hardware_adc pico_unique_id hardware_rtc tinyusb_device tinyusb_board) endif() diff --git a/build_pico_hsm.sh b/build_pico_hsm.sh index 4c716e9..aa6a112 100755 --- a/build_pico_hsm.sh +++ b/build_pico_hsm.sh @@ -1,7 +1,7 @@ #!/bin/bash VERSION_MAJOR="3" -VERSION_MINOR="2" +VERSION_MINOR="6" rm -rf release/* cd build_release @@ -17,6 +17,7 @@ for board in adafruit_feather_rp2040 \ eetree_gamekit_rp2040 \ garatronic_pybstick26_rp2040 \ melopero_shake_rp2040 \ + nullbits_bit_c_pro \ pico \ pico_w \ pimoroni_badger2040 \ @@ -31,6 +32,7 @@ for board in adafruit_feather_rp2040 \ pimoroni_servo2040 \ pimoroni_tiny2040 \ pimoroni_tiny2040_2mb \ + pololu_3pi_2040_robot \ seeed_xiao_rp2040 \ solderparty_rp2040_stamp \ solderparty_rp2040_stamp_carrier \ diff --git a/doc/usage.md b/doc/usage.md index 6dd2eb9..49cb297 100644 --- a/doc/usage.md +++ b/doc/usage.md @@ -30,7 +30,7 @@ PIN=648219 ## Initialization The first step is to initialize the HSM. To do so, use the `pico-hsm-tool.py` in `tools` folder: ``` -$ python3 pico-hsm-tool.py initialize --so-pin 3537363231383830 --pin 648219 +$ python3 tools/pico-hsm-tool.py --pin 648219 initialize --so-pin 57621880 ``` The PIN number is used to manage all private keys in the device. It supports three attemps. After the third PIN failure, it gets blocked. The PIN accepts from 6 to 16 characters. @@ -51,7 +51,7 @@ $ pkcs11-tool --login --pin 648219 --change-pin --new-pin 123456 To unblock the PIN: ``` -$ pkcs11-tool --login --login-type so --so-pin=3537363231383830 --init-pin --new-pin=648219 +$ pkcs11-tool --login --login-type so --so-pin 3537363231383830 --init-pin --new-pin 648219 ``` ## Keypair generation diff --git a/pico-keys-sdk b/pico-keys-sdk new file mode 160000 index 0000000..f0687c1 --- /dev/null +++ b/pico-keys-sdk @@ -0,0 +1 @@ +Subproject commit f0687c1ef392c2bcb293ea554f1dd8b784484922 diff --git a/src/hsm/cmd_cipher_sym.c b/src/hsm/cmd_cipher_sym.c index adddcb7..68a1f36 100644 --- a/src/hsm/cmd_cipher_sym.c +++ b/src/hsm/cmd_cipher_sym.c @@ -412,20 +412,21 @@ int cmd_cipher_sym() { res_APDU_size = keylen ? keylen : (apdu.ne > 0 && apdu.ne < 65536 ? apdu.ne : 32); } else if (memcmp(oid, OID_PKCS5_PBES2, oid_len) == 0) { + size_t olen = 0; mbedtls_asn1_buf params = - { .p = aad, .len = aad_len, .tag = (MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE) }; - int r = mbedtls_pkcs5_pbes2(¶ms, + {.p = aad, .len = aad_len, .tag = (MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)}; + int r = mbedtls_pkcs5_pbes2_ext(¶ms, algo == ALGO_EXT_CIPHER_ENCRYPT ? MBEDTLS_PKCS5_ENCRYPT : MBEDTLS_PKCS5_DECRYPT, kdata, key_size, enc, enc_len, - res_APDU); + res_APDU, 4096, &olen); mbedtls_platform_zeroize(kdata, sizeof(kdata)); if (r != 0) { return SW_WRONG_DATA(); } - res_APDU_size = enc_len; + res_APDU_size = olen; } else if (memcmp(oid, OID_KDF_X963, oid_len) == 0) { mbedtls_md_type_t md_type = MBEDTLS_MD_SHA1; diff --git a/src/hsm/cmd_derive_asym.c b/src/hsm/cmd_derive_asym.c index 25f1af8..555205f 100644 --- a/src/hsm/cmd_derive_asym.c +++ b/src/hsm/cmd_derive_asym.c @@ -88,7 +88,7 @@ int cmd_derive_asym() { mbedtls_ecp_keypair_free(&ctx); return SW_EXEC_ERROR(); } - r = store_keys(&ctx, HSM_KEY_EC, dest_id); + r = store_keys(&ctx, PICO_KEYS_KEY_EC, dest_id); if (r != CCID_OK) { mbedtls_ecp_keypair_free(&ctx); return SW_EXEC_ERROR(); diff --git a/src/hsm/cmd_initialize.c b/src/hsm/cmd_initialize.c index 06b1082..8dd45c1 100644 --- a/src/hsm/cmd_initialize.c +++ b/src/hsm/cmd_initialize.c @@ -187,13 +187,13 @@ int cmd_initialize() { mbedtls_ecdsa_free(&ecdsa); return SW_EXEC_ERROR(); } - ret = store_keys(&ecdsa, HSM_KEY_EC, key_id); + ret = store_keys(&ecdsa, PICO_KEYS_KEY_EC, key_id); if (ret != CCID_OK) { mbedtls_ecdsa_free(&ecdsa); return SW_EXEC_ERROR(); } size_t cvc_len = 0; - if ((cvc_len = asn1_cvc_aut(&ecdsa, HSM_KEY_EC, res_APDU, 4096, NULL, 0)) == 0) { + if ((cvc_len = asn1_cvc_aut(&ecdsa, PICO_KEYS_KEY_EC, res_APDU, 4096, NULL, 0)) == 0) { mbedtls_ecdsa_free(&ecdsa); return SW_EXEC_ERROR(); } @@ -205,7 +205,7 @@ int cmd_initialize() { return SW_EXEC_ERROR(); } - if ((cvc_len = asn1_cvc_cert(&ecdsa, HSM_KEY_EC, res_APDU, 4096, NULL, 0, true)) == 0) { + if ((cvc_len = asn1_cvc_cert(&ecdsa, PICO_KEYS_KEY_EC, res_APDU, 4096, NULL, 0, true)) == 0) { mbedtls_ecdsa_free(&ecdsa); return SW_EXEC_ERROR(); } diff --git a/src/hsm/cmd_key_domain.c b/src/hsm/cmd_key_domain.c index d548452..aeecb31 100644 --- a/src/hsm/cmd_key_domain.c +++ b/src/hsm/cmd_key_domain.c @@ -23,11 +23,14 @@ uint8_t get_key_domain(file_t *fkey) { size_t tag_len = 0; + if (!file_has_data(fkey)) { + return 0xff; + } const uint8_t *meta_tag = get_meta_tag(fkey, 0x92, &tag_len); if (meta_tag) { return *meta_tag; } - return 0xff; + return 0x0; } int cmd_key_domain() { @@ -65,10 +68,16 @@ int cmd_key_domain() { } import_dkek_share(p2, apdu.data); if (++current_dkeks >= dkeks) { - if (save_dkek_key(p2, NULL) != CCID_OK) { - /* On fail, it will return to previous dkek state. */ - import_dkek_share(p2, apdu.data); - return SW_FILE_NOT_FOUND(); + int r = save_dkek_key(p2, NULL); + if (r != CCID_OK) { + if (r == CCID_NO_LOGIN) { + pending_save_dkek = p2; + } + else { + /* On fail, it will return to previous dkek state. */ + import_dkek_share(p2, apdu.data); + return SW_FILE_NOT_FOUND(); + } } } uint8_t t[MAX_KEY_DOMAINS * 2]; @@ -94,8 +103,9 @@ int cmd_key_domain() { return SW_WRONG_LENGTH(); } if (p1 == 0x3) { //if key domain is not empty, command is denied - for (int i = 0; i < dynamic_files; i++) { - if (get_key_domain(&dynamic_file[i]) == p2) { + for (int i = 1; i < 256; i++) { + file_t *fkey = search_dynamic_file(KEY_PREFIX << 8 | i); + if (get_key_domain(fkey) == p2) { return SW_FILE_EXISTS(); } } diff --git a/src/hsm/cmd_key_gen.c b/src/hsm/cmd_key_gen.c index 78846be..9389cb7 100644 --- a/src/hsm/cmd_key_gen.c +++ b/src/hsm/cmd_key_gen.c @@ -44,16 +44,16 @@ int cmd_key_gen() { memcpy(aes_key, random_bytes_get(key_size), key_size); int aes_type = 0x0; if (key_size == 16) { - aes_type = HSM_KEY_AES_128; + aes_type = PICO_KEYS_KEY_AES_128; } else if (key_size == 24) { - aes_type = HSM_KEY_AES_192; + aes_type = PICO_KEYS_KEY_AES_192; } else if (key_size == 32) { - aes_type = HSM_KEY_AES_256; + aes_type = PICO_KEYS_KEY_AES_256; } else if (key_size == 64) { - aes_type = HSM_KEY_AES_512; + aes_type = PICO_KEYS_KEY_AES_512; } r = store_keys(aes_key, aes_type, key_id); if (r != CCID_OK) { diff --git a/src/hsm/cmd_key_unwrap.c b/src/hsm/cmd_key_unwrap.c index a67ec36..4f28c96 100644 --- a/src/hsm/cmd_key_unwrap.c +++ b/src/hsm/cmd_key_unwrap.c @@ -35,7 +35,7 @@ int cmd_key_unwrap() { if (key_type == 0x0) { return SW_DATA_INVALID(); } - if (key_type & HSM_KEY_RSA) { + if (key_type & PICO_KEYS_KEY_RSA) { mbedtls_rsa_context ctx; mbedtls_rsa_init(&ctx); do { @@ -45,8 +45,8 @@ int cmd_key_unwrap() { mbedtls_rsa_free(&ctx); return SW_EXEC_ERROR(); } - r = store_keys(&ctx, HSM_KEY_RSA, key_id); - if ((res_APDU_size = asn1_cvc_aut(&ctx, HSM_KEY_RSA, res_APDU, 4096, NULL, 0)) == 0) { + r = store_keys(&ctx, PICO_KEYS_KEY_RSA, key_id); + if ((res_APDU_size = asn1_cvc_aut(&ctx, PICO_KEYS_KEY_RSA, res_APDU, 4096, NULL, 0)) == 0) { mbedtls_rsa_free(&ctx); return SW_EXEC_ERROR(); } @@ -57,7 +57,7 @@ int cmd_key_unwrap() { } prkd_len = asn1_build_prkd_ecc(NULL, 0, NULL, 0, key_size * 8, prkd_buf, sizeof(prkd_buf)); } - else if (key_type & HSM_KEY_EC) { + else if (key_type & PICO_KEYS_KEY_EC) { mbedtls_ecp_keypair ctx; mbedtls_ecp_keypair_init(&ctx); do { @@ -67,7 +67,7 @@ int cmd_key_unwrap() { mbedtls_ecp_keypair_free(&ctx); return SW_EXEC_ERROR(); } - r = store_keys(&ctx, HSM_KEY_EC, key_id); + r = store_keys(&ctx, PICO_KEYS_KEY_EC, key_id); if ((res_APDU_size = asn1_cvc_aut(&ctx, HSM_KEY_EC, res_APDU, 4096, NULL, 0)) == 0) { mbedtls_ecp_keypair_free(&ctx); return SW_EXEC_ERROR(); @@ -79,7 +79,7 @@ int cmd_key_unwrap() { } prkd_len = asn1_build_prkd_ecc(NULL, 0, NULL, 0, key_size, prkd_buf, sizeof(prkd_buf)); } - else if (key_type & HSM_KEY_AES) { + else if (key_type & PICO_KEYS_KEY_AES) { uint8_t aes_key[64]; int key_size = 0, aes_type = 0; do { @@ -95,16 +95,16 @@ int cmd_key_unwrap() { return SW_EXEC_ERROR(); } if (key_size == 64) { - aes_type = HSM_KEY_AES_512; + aes_type = PICO_KEYS_KEY_AES_512; } else if (key_size == 32) { - aes_type = HSM_KEY_AES_256; + aes_type = PICO_KEYS_KEY_AES_256; } else if (key_size == 24) { - aes_type = HSM_KEY_AES_192; + aes_type = PICO_KEYS_KEY_AES_192; } else if (key_size == 16) { - aes_type = HSM_KEY_AES_128; + aes_type = PICO_KEYS_KEY_AES_128; } else { return SW_EXEC_ERROR(); diff --git a/src/hsm/cmd_key_wrap.c b/src/hsm/cmd_key_wrap.c index 581a718..e552730 100644 --- a/src/hsm/cmd_key_wrap.c +++ b/src/hsm/cmd_key_wrap.c @@ -67,7 +67,7 @@ int cmd_key_wrap() { } return SW_EXEC_ERROR(); } - r = dkek_encode_key(kdom, &ctx, HSM_KEY_RSA, res_APDU, &wrap_len, meta_tag, tag_len); + r = dkek_encode_key(kdom, &ctx, PICO_KEYS_KEY_RSA, res_APDU, &wrap_len, meta_tag, tag_len); mbedtls_rsa_free(&ctx); } else if (*dprkd == P15_KEYTYPE_ECC) { @@ -81,7 +81,7 @@ int cmd_key_wrap() { } return SW_EXEC_ERROR(); } - r = dkek_encode_key(kdom, &ctx, HSM_KEY_EC, res_APDU, &wrap_len, meta_tag, tag_len); + r = dkek_encode_key(kdom, &ctx, PICO_KEYS_KEY_EC, res_APDU, &wrap_len, meta_tag, tag_len); mbedtls_ecp_keypair_free(&ctx); } else if (*dprkd == P15_KEYTYPE_AES) { @@ -90,22 +90,22 @@ int cmd_key_wrap() { return SW_SECURE_MESSAGE_EXEC_ERROR(); } - int key_size = file_get_size(ef), aes_type = HSM_KEY_AES; + int key_size = file_get_size(ef), aes_type = PICO_KEYS_KEY_AES; memcpy(kdata, file_get_data(ef), key_size); if (mkek_decrypt(kdata, key_size) != 0) { return SW_EXEC_ERROR(); } if (key_size == 64) { - aes_type = HSM_KEY_AES_512; + aes_type = PICO_KEYS_KEY_AES_512; } else if (key_size == 32) { - aes_type = HSM_KEY_AES_256; + aes_type = PICO_KEYS_KEY_AES_256; } else if (key_size == 24) { - aes_type = HSM_KEY_AES_192; + aes_type = PICO_KEYS_KEY_AES_192; } else if (key_size == 16) { - aes_type = HSM_KEY_AES_128; + aes_type = PICO_KEYS_KEY_AES_128; } r = dkek_encode_key(kdom, kdata, aes_type, res_APDU, &wrap_len, meta_tag, tag_len); mbedtls_platform_zeroize(kdata, sizeof(kdata)); diff --git a/src/hsm/cmd_keypair_gen.c b/src/hsm/cmd_keypair_gen.c index 48e87ee..eb47a1c 100644 --- a/src/hsm/cmd_keypair_gen.c +++ b/src/hsm/cmd_keypair_gen.c @@ -69,10 +69,10 @@ int cmd_keypair_gen() { return SW_EXEC_ERROR(); } if ((res_APDU_size = - asn1_cvc_aut(&rsa, HSM_KEY_RSA, res_APDU, 4096, NULL, 0)) == 0) { + asn1_cvc_aut(&rsa, PICO_KEYS_KEY_RSA, res_APDU, 4096, NULL, 0)) == 0) { return SW_EXEC_ERROR(); } - ret = store_keys(&rsa, HSM_KEY_RSA, key_id); + ret = store_keys(&rsa, PICO_KEYS_KEY_RSA, key_id); if (ret != CCID_OK) { mbedtls_rsa_free(&rsa); return SW_EXEC_ERROR(); @@ -146,7 +146,7 @@ int cmd_keypair_gen() { } } if ((res_APDU_size = - asn1_cvc_aut(&ecdsa, HSM_KEY_EC, res_APDU, 4096, ext, ext_len)) == 0) { + asn1_cvc_aut(&ecdsa, PICO_KEYS_KEY_EC, res_APDU, 4096, ext, ext_len)) == 0) { if (ext) { free(ext); } @@ -156,7 +156,7 @@ int cmd_keypair_gen() { if (ext) { free(ext); } - ret = store_keys(&ecdsa, HSM_KEY_EC, key_id); + ret = store_keys(&ecdsa, PICO_KEYS_KEY_EC, key_id); mbedtls_ecdsa_free(&ecdsa); if (ret != CCID_OK) { return SW_EXEC_ERROR(); diff --git a/src/hsm/cmd_read_binary.c b/src/hsm/cmd_read_binary.c index eb66ff7..2fb7496 100644 --- a/src/hsm/cmd_read_binary.c +++ b/src/hsm/cmd_read_binary.c @@ -88,10 +88,10 @@ int cmd_read_binary() { return SW_WARNING_EOF(); } - uint16_t maxle = data_len - offset; - if (apdu.ne > maxle) { - apdu.ne = maxle; - } + //uint16_t maxle = data_len - offset; + //if (apdu.ne > maxle) { + // apdu.ne = maxle; + //} memcpy(res_APDU, file_get_data(ef) + offset, data_len - offset); res_APDU_size = data_len - offset; } diff --git a/src/hsm/cmd_reset_retry.c b/src/hsm/cmd_reset_retry.c index 0522fda..2388d75 100644 --- a/src/hsm/cmd_reset_retry.c +++ b/src/hsm/cmd_reset_retry.c @@ -36,16 +36,15 @@ int cmd_reset_retry() { if (P1(apdu) == 0x0 || P1(apdu) == 0x2) { int newpin_len = 0; if (P1(apdu) == 0x0) { - if (apdu.nc <= 8) { + uint8_t so_pin_len = file_read_uint8(file_get_data(file_sopin)); + if (apdu.nc <= so_pin_len + 1) { return SW_WRONG_LENGTH(); } - uint16_t r = check_pin(file_sopin, apdu.data, 8); + uint16_t r = check_pin(file_sopin, apdu.data, so_pin_len); if (r != 0x9000) { return r; } - newpin_len = apdu.nc - 8; - has_session_sopin = true; - hash_multi(apdu.data, 8, session_sopin); + newpin_len = apdu.nc - so_pin_len; } else if (P1(apdu) == 0x2) { if (!has_session_sopin) { @@ -83,15 +82,14 @@ int cmd_reset_retry() { return SW_COMMAND_NOT_ALLOWED(); } if (P1(apdu) == 0x1) { - if (apdu.nc != 8) { + uint8_t so_pin_len = file_read_uint8(file_get_data(file_sopin)); + if (apdu.nc != so_pin_len) { return SW_WRONG_LENGTH(); } - uint16_t r = check_pin(file_sopin, apdu.data, 8); + uint16_t r = check_pin(file_sopin, apdu.data, so_pin_len); if (r != 0x9000) { return r; } - has_session_sopin = true; - hash_multi(apdu.data, 8, session_sopin); } else if (P1(apdu) == 0x3) { if (!has_session_sopin) { diff --git a/src/hsm/cvc.c b/src/hsm/cvc.c index 80202e3..99f4912 100644 --- a/src/hsm/cvc.c +++ b/src/hsm/cvc.c @@ -166,10 +166,10 @@ size_t asn1_cvc_cert_body(void *rsa_ecdsa, size_t ext_len, bool full) { size_t pubkey_size = 0; - if (key_type & HSM_KEY_RSA) { + if (key_type & PICO_KEYS_KEY_RSA) { pubkey_size = asn1_cvc_public_key_rsa(rsa_ecdsa, NULL, 0); } - else if (key_type & HSM_KEY_EC) { + else if (key_type & PICO_KEYS_KEY_EC) { pubkey_size = asn1_cvc_public_key_ecdsa(rsa_ecdsa, NULL, 0); } size_t cpi_size = 4, ext_size = 0, role_size = 0, valid_size = 0; @@ -222,10 +222,10 @@ size_t asn1_cvc_cert_body(void *rsa_ecdsa, //car *p++ = 0x42; p += format_tlv_len(lencar, p); memcpy(p, car, lencar); p += lencar; //pubkey - if (key_type & HSM_KEY_RSA) { + if (key_type & PICO_KEYS_KEY_RSA) { p += asn1_cvc_public_key_rsa(rsa_ecdsa, p, pubkey_size); } - else if (key_type & HSM_KEY_EC) { + else if (key_type & PICO_KEYS_KEY_EC) { p += asn1_cvc_public_key_ecdsa(rsa_ecdsa, p, pubkey_size); } //chr @@ -266,10 +266,10 @@ size_t asn1_cvc_cert(void *rsa_ecdsa, size_t ext_len, bool full) { size_t key_size = 0; - if (key_type & HSM_KEY_RSA) { + if (key_type & PICO_KEYS_KEY_RSA) { key_size = mbedtls_mpi_size(&((mbedtls_rsa_context *) rsa_ecdsa)->N); } - else if (key_type & HSM_KEY_EC) { + else if (key_type & PICO_KEYS_KEY_EC) { key_size = 2 * (int)((mbedtls_ecp_curve_info_from_grp_id(((mbedtls_ecdsa_context *) rsa_ecdsa)->grp.id)->bit_size + 7) / 8); } size_t body_size = asn1_cvc_cert_body(rsa_ecdsa, key_type, NULL, 0, ext, ext_len, full), sig_size = asn1_len_tag(0x5f37, key_size); @@ -289,13 +289,13 @@ size_t asn1_cvc_cert(void *rsa_ecdsa, hash256(body, body_size, hsh); memcpy(p, "\x5F\x37", 2); p += 2; p += format_tlv_len(key_size, p); - if (key_type & HSM_KEY_RSA) { + if (key_type & PICO_KEYS_KEY_RSA) { if (mbedtls_rsa_rsassa_pkcs1_v15_sign(rsa_ecdsa, random_gen, NULL, MBEDTLS_MD_SHA256, 32, hsh, p) != 0) { memset(p, 0, key_size); } p += key_size; } - else if (key_type & HSM_KEY_EC) { + else if (key_type & PICO_KEYS_KEY_EC) { mbedtls_mpi r, s; int ret = 0; mbedtls_ecp_keypair *ecdsa = (mbedtls_ecp_keypair *) rsa_ecdsa; @@ -450,17 +450,17 @@ size_t asn1_build_prkd_generic(const uint8_t *label, size_t seq_len = 0; const uint8_t *seq = NULL; uint8_t first_tag = 0x0; - if (key_type & HSM_KEY_EC) { + if (key_type & PICO_KEYS_KEY_EC) { seq = (const uint8_t *)"\x07\x20\x80"; seq_len = 3; first_tag = 0xA0; } - else if (key_type & HSM_KEY_RSA) { + else if (key_type & PICO_KEYS_KEY_RSA) { seq = (const uint8_t *)"\x02\x74"; seq_len = 2; first_tag = 0x30; } - else if (key_type & HSM_KEY_AES) { + else if (key_type & PICO_KEYS_KEY_AES) { seq = (const uint8_t *)"\x07\xC0\x10"; seq_len = 3; first_tag = 0xA8; @@ -469,10 +469,10 @@ size_t asn1_build_prkd_generic(const uint8_t *label, size_t seq2_size = asn1_len_tag(0x30, asn1_len_tag(0x4, keyid_len) + asn1_len_tag(0x3, seq_len)); size_t seq3_size = 0, seq4_size = 0; - if (key_type & HSM_KEY_EC || key_type & HSM_KEY_RSA) { + if (key_type & PICO_KEYS_KEY_EC || key_type & PICO_KEYS_KEY_RSA) { seq4_size = asn1_len_tag(0xA1, asn1_len_tag(0x30, asn1_len_tag(0x30, asn1_len_tag(0x4, 0)) + asn1_len_tag(0x2, 2))); } - else if (key_type & HSM_KEY_AES) { + else if (key_type & PICO_KEYS_KEY_AES) { seq3_size = asn1_len_tag(0xA0, asn1_len_tag(0x30, asn1_len_tag(0x2, 2))); seq4_size = asn1_len_tag(0xA1, asn1_len_tag(0x30, asn1_len_tag(0x30, asn1_len_tag(0x4, 0)))); } @@ -504,7 +504,7 @@ size_t asn1_build_prkd_generic(const uint8_t *label, memcpy(p, seq, seq_len); p += seq_len; //Seq 3 - if (key_type & HSM_KEY_AES) { + if (key_type & PICO_KEYS_KEY_AES) { *p++ = 0xA0; p += format_tlv_len(asn1_len_tag(0x30, asn1_len_tag(0x2, 2)), p); *p++ = 0x30; @@ -518,7 +518,7 @@ size_t asn1_build_prkd_generic(const uint8_t *label, //Seq 4 *p++ = 0xA1; size_t inseq4_len = asn1_len_tag(0x30, asn1_len_tag(0x4, 0)); - if (key_type & HSM_KEY_EC || key_type & HSM_KEY_RSA) { + if (key_type & PICO_KEYS_KEY_EC || key_type & PICO_KEYS_KEY_RSA) { inseq4_len += asn1_len_tag(0x2, 2); } p += format_tlv_len(asn1_len_tag(0x30, inseq4_len), p); @@ -528,7 +528,7 @@ size_t asn1_build_prkd_generic(const uint8_t *label, p += format_tlv_len(asn1_len_tag(0x4, 0), p); *p++ = 0x4; p += format_tlv_len(0, p); - if (key_type & HSM_KEY_EC || key_type & HSM_KEY_RSA) { + if (key_type & PICO_KEYS_KEY_EC || key_type & PICO_KEYS_KEY_RSA) { *p++ = 0x2; p += format_tlv_len(2, p); *p++ = (keysize >> 8) & 0xff; @@ -549,7 +549,7 @@ size_t asn1_build_prkd_ecc(const uint8_t *label, keyid, keyid_len, keysize, - HSM_KEY_EC, + PICO_KEYS_KEY_EC, buf, buf_len); } @@ -566,7 +566,7 @@ size_t asn1_build_prkd_rsa(const uint8_t *label, keyid, keyid_len, keysize, - HSM_KEY_RSA, + PICO_KEYS_KEY_RSA, buf, buf_len); } @@ -583,7 +583,7 @@ size_t asn1_build_prkd_aes(const uint8_t *label, keyid, keyid_len, keysize, - HSM_KEY_AES, + PICO_KEYS_KEY_AES, buf, buf_len); } diff --git a/src/hsm/kek.c b/src/hsm/kek.c index 7506247..86a0f38 100644 --- a/src/hsm/kek.c +++ b/src/hsm/kek.c @@ -36,6 +36,7 @@ extern bool has_session_pin, has_session_sopin; extern uint8_t session_pin[32], session_sopin[32]; uint8_t mkek_mask[MKEK_KEY_SIZE]; bool has_mkek_mask = false; +uint8_t pending_save_dkek = 0xff; #define POLY 0xedb88320 @@ -286,7 +287,7 @@ int dkek_encode_key(uint8_t id, size_t *out_len, const uint8_t *allowed, size_t allowed_len) { - if (!(key_type & HSM_KEY_RSA) && !(key_type & HSM_KEY_EC) && !(key_type & HSM_KEY_AES)) { + if (!(key_type & PICO_KEYS_KEY_RSA) && !(key_type & PICO_KEYS_KEY_EC) && !(key_type & PICO_KEYS_KEY_AES)) { return CCID_WRONG_DATA; } @@ -316,17 +317,17 @@ int dkek_encode_key(uint8_t id, return r; } - if (key_type & HSM_KEY_AES) { - if (key_type & HSM_KEY_AES_128) { + if (key_type & PICO_KEYS_KEY_AES) { + if (key_type & PICO_KEYS_KEY_AES_128) { kb_len = 16; } - else if (key_type & HSM_KEY_AES_192) { + else if (key_type & PICO_KEYS_KEY_AES_192) { kb_len = 24; } - else if (key_type & HSM_KEY_AES_256) { + else if (key_type & PICO_KEYS_KEY_AES_256) { kb_len = 32; } - else if (key_type & HSM_KEY_AES_512) { + else if (key_type & PICO_KEYS_KEY_AES_512) { kb_len = 64; } @@ -344,7 +345,7 @@ int dkek_encode_key(uint8_t id, algo = (uint8_t *) "\x00\x08\x60\x86\x48\x01\x65\x03\x04\x01"; //2.16.840.1.101.3.4.1 (2+8) algo_len = 10; } - else if (key_type & HSM_KEY_RSA) { + else if (key_type & PICO_KEYS_KEY_RSA) { if (*out_len < 8 + 1 + 12 + 6 + (8 + 2 * 4 + 2 * 4096 / 8 + 3 + 13) + 16) { //13 bytes pading return CCID_WRONG_LENGTH; } @@ -365,7 +366,7 @@ int dkek_encode_key(uint8_t id, algo = (uint8_t *) "\x00\x0A\x04\x00\x7F\x00\x07\x02\x02\x02\x01\x02"; algo_len = 12; } - else if (key_type & HSM_KEY_EC) { + else if (key_type & PICO_KEYS_KEY_EC) { if (*out_len < 8 + 1 + 12 + 6 + (8 + 2 * 8 + 9 * 66 + 2 + 4) + 16) { //4 bytes pading return CCID_WRONG_LENGTH; } @@ -417,13 +418,13 @@ int dkek_encode_key(uint8_t id, memcpy(out + *out_len, kcv, 8); *out_len += 8; - if (key_type & HSM_KEY_AES) { + if (key_type & PICO_KEYS_KEY_AES) { out[*out_len] = 15; } - else if (key_type & HSM_KEY_RSA) { + else if (key_type & PICO_KEYS_KEY_RSA) { out[*out_len] = 5; } - else if (key_type & HSM_KEY_EC) { + else if (key_type & PICO_KEYS_KEY_EC) { out[*out_len] = 12; } *out_len += 1; @@ -457,7 +458,7 @@ int dkek_encode_key(uint8_t id, if (kb_len < kb_len_pad) { kb[kb_len] = 0x80; } - r = aes_encrypt(kenc, NULL, 256, HSM_AES_MODE_CBC, kb, kb_len_pad); + r = aes_encrypt(kenc, NULL, 256, PICO_KEYS_AES_MODE_CBC, kb, kb_len_pad); if (r != CCID_OK) { return r; } @@ -481,13 +482,13 @@ int dkek_encode_key(uint8_t id, int dkek_type_key(const uint8_t *in) { if (in[8] == 5 || in[8] == 6) { - return HSM_KEY_RSA; + return PICO_KEYS_KEY_RSA; } else if (in[8] == 12) { - return HSM_KEY_EC; + return PICO_KEYS_KEY_EC; } else if (in[8] == 15) { - return HSM_KEY_AES; + return PICO_KEYS_KEY_AES; } return 0x0; } @@ -584,7 +585,7 @@ int dkek_decode_key(uint8_t id, uint8_t kb[8 + 2 * 4 + 2 * 4096 / 8 + 3 + 13]; //worst case: RSA-4096 (plus, 13 bytes padding) memset(kb, 0, sizeof(kb)); memcpy(kb, in + ofs, in_len - 16 - ofs); - r = aes_decrypt(kenc, NULL, 256, HSM_AES_MODE_CBC, kb, in_len - 16 - ofs); + r = aes_decrypt(kenc, NULL, 256, PICO_KEYS_AES_MODE_CBC, kb, in_len - 16 - ofs); if (r != CCID_OK) { return r; } diff --git a/src/hsm/kek.h b/src/hsm/kek.h index e6b5ade..5c85c2f 100644 --- a/src/hsm/kek.h +++ b/src/hsm/kek.h @@ -74,4 +74,6 @@ extern mse_t mse; extern int mse_decrypt_ct(uint8_t *, size_t); +extern uint8_t pending_save_dkek; + #endif diff --git a/src/hsm/sc_hsm.c b/src/hsm/sc_hsm.c index 4485b19..52e3c93 100644 --- a/src/hsm/sc_hsm.c +++ b/src/hsm/sc_hsm.c @@ -24,7 +24,7 @@ #include "eac.h" #include "cvc.h" #include "asn1.h" -#include "hsm.h" +#include "pico_keys.h" #include "usb.h" #include "random.h" @@ -80,20 +80,16 @@ extern int cmd_bip_slip(); extern const uint8_t *ccid_atr; -app_t *sc_hsm_select_aid(app_t *a, const uint8_t *aid, uint8_t aid_len) { - if (!memcmp(aid, sc_hsm_aid + 1, MIN(aid_len, sc_hsm_aid[0]))) { - a->aid = sc_hsm_aid; - a->process_apdu = sc_hsm_process_apdu; - a->unload = sc_hsm_unload; - init_sc_hsm(); - return a; - } - return NULL; +int sc_hsm_select_aid(app_t *a) { + a->process_apdu = sc_hsm_process_apdu; + a->unload = sc_hsm_unload; + init_sc_hsm(); + return CCID_OK; } void __attribute__((constructor)) sc_hsm_ctor() { ccid_atr = atr_sc_hsm; - register_app(sc_hsm_select_aid); + register_app(sc_hsm_select_aid, sc_hsm_aid); } void scan_files() { @@ -289,7 +285,11 @@ bool wait_button_pressed() { } int parse_token_info(const file_t *f, int mode) { +#ifdef __FOR_CI + char *label = "SmartCard-HSM"; +#else char *label = "Pico-HSM"; +#endif char *manu = "Pol Henarejos"; if (mode == 1) { uint8_t *p = res_APDU; @@ -407,6 +407,10 @@ int check_pin(const file_t *pin, const uint8_t *data, size_t len) { hash_multi(data, len, session_sopin); has_session_sopin = true; } + if (pending_save_dkek != 0xff) { + save_dkek_key(pending_save_dkek, NULL); + pending_save_dkek = 0xff; + } return SW_OK(); } @@ -492,30 +496,30 @@ uint32_t decrement_key_counter(file_t *fkey) { int store_keys(void *key_ctx, int type, uint8_t key_id) { int r, key_size = 0; uint8_t kdata[4096 / 8]; // worst case - if (type & HSM_KEY_RSA) { + if (type & PICO_KEYS_KEY_RSA) { mbedtls_rsa_context *rsa = (mbedtls_rsa_context *) key_ctx; key_size = mbedtls_mpi_size(&rsa->P) + mbedtls_mpi_size(&rsa->Q); mbedtls_mpi_write_binary(&rsa->P, kdata, key_size / 2); mbedtls_mpi_write_binary(&rsa->Q, kdata + key_size / 2, key_size / 2); } - else if (type & HSM_KEY_EC) { + else if (type & PICO_KEYS_KEY_EC) { mbedtls_ecdsa_context *ecdsa = (mbedtls_ecdsa_context *) key_ctx; key_size = mbedtls_mpi_size(&ecdsa->d); kdata[0] = ecdsa->grp.id & 0xff; mbedtls_ecp_write_key(ecdsa, kdata + 1, key_size); key_size++; } - else if (type & HSM_KEY_AES) { - if (type == HSM_KEY_AES_128) { + else if (type & PICO_KEYS_KEY_AES) { + if (type == PICO_KEYS_KEY_AES_128) { key_size = 16; } - else if (type == HSM_KEY_AES_192) { + else if (type == PICO_KEYS_KEY_AES_192) { key_size = 24; } - else if (type == HSM_KEY_AES_256) { + else if (type == PICO_KEYS_KEY_AES_256) { key_size = 32; } - else if (type == HSM_KEY_AES_512) { + else if (type == PICO_KEYS_KEY_AES_512) { key_size = 64; } memcpy(kdata, key_ctx, key_size); diff --git a/src/hsm/sc_hsm.h b/src/hsm/sc_hsm.h index 5a9fcc6..53a1ec4 100644 --- a/src/hsm/sc_hsm.h +++ b/src/hsm/sc_hsm.h @@ -27,7 +27,7 @@ #endif #include "file.h" #include "apdu.h" -#include "hsm.h" +#include "pico_keys.h" extern const uint8_t sc_hsm_aid[]; diff --git a/src/hsm/version.h b/src/hsm/version.h index 8161144..43be6a3 100644 --- a/src/hsm/version.h +++ b/src/hsm/version.h @@ -18,7 +18,7 @@ #ifndef __VERSION_H_ #define __VERSION_H_ -#define HSM_VERSION 0x0304 +#define HSM_VERSION 0x0306 #define HSM_VERSION_MAJOR ((HSM_VERSION >> 8) & 0xff) #define HSM_VERSION_MINOR (HSM_VERSION & 0xff) diff --git a/tests/build-in-docker.sh b/tests/build-in-docker.sh index d0b636e..8a42b51 100755 --- a/tests/build-in-docker.sh +++ b/tests/build-in-docker.sh @@ -1,7 +1,14 @@ #!/bin/bash -eu source tests/docker_env.sh +build_image #run_in_docker rm -rf CMakeFiles run_in_docker mkdir -p build_in_docker -run_in_docker -w "$PWD/build_in_docker" cmake -DENABLE_EMULATION=1 .. +run_in_docker -w "$PWD/build_in_docker" cmake -DENABLE_EMULATION=1 -D__FOR_CI=1 .. run_in_docker -w "$PWD/build_in_docker" make -j ${NUM_PROC} +docker create --name temp_container pico-hsm-test:bullseye +docker cp $PWD/build_in_docker/pico_hsm temp_container:/pico_hsm +docker commit temp_container pico-hsm-test:bullseye +docker stop temp_container +docker rm temp_container +docker image prune -f diff --git a/tests/docker/bullseye/Dockerfile b/tests/docker/bullseye/Dockerfile index 6633cd8..032ba5c 100644 --- a/tests/docker/bullseye/Dockerfile +++ b/tests/docker/bullseye/Dockerfile @@ -4,6 +4,8 @@ ARG DEBIAN_FRONTEND=noninteractive RUN apt update && apt upgrade -y RUN apt install -y apt-utils +RUN apt autoremove -y +RUN rm -rf /var/cache/apt/archives/* RUN apt install -y libccid \ libpcsclite-dev \ git \ @@ -15,16 +17,33 @@ RUN apt install -y libccid \ gcc \ make \ build-essential \ - opensc \ python3 \ python3-pip \ swig \ + libssl-dev \ cmake \ + vsmartcard-vpcd \ && rm -rf /var/lib/apt/lists/* -RUN pip3 install pytest pycvc cryptography pyscard -RUN git clone https://github.com/polhenarejos/vsmartcard.git -WORKDIR /vsmartcard/virtualsmartcard -RUN autoreconf --verbose --install -RUN ./configure --sysconfdir=/etc -RUN make && make install +RUN pip3 install pytest pycvc cryptography pyscard base58 +WORKDIR / +RUN git clone https://github.com/OpenSC/OpenSC +WORKDIR /OpenSC +RUN git checkout tags/0.23.0 +RUN ./bootstrap +RUN ./configure --enable-openssl +RUN make -j `nproc` +RUN make install +RUN make clean +RUN ldconfig +WORKDIR / +RUN git clone https://github.com/polhenarejos/pypicohsm.git +RUN pip3 install -e pypicohsm +RUN git clone https://github.com/CardContact/sc-hsm-embedded +WORKDIR /sc-hsm-embedded +RUN autoreconf -fi +RUN ./configure +RUN make -j `nproc` +RUN make install +RUN cp ./src/tests/sc-hsm-pkcs11-test /usr/local/bin/sc-hsm-pkcs11-test +RUN make clean WORKDIR / diff --git a/tests/docker_env.sh b/tests/docker_env.sh old mode 100644 new mode 100755 index 41b1d75..c801fb8 --- a/tests/docker_env.sh +++ b/tests/docker_env.sh @@ -72,14 +72,16 @@ else NUM_PROC="$(nproc)" fi -# Build the Docker image -echo "Getting docker image up to date (this may take a few minutes)..." -${DOCKER} image build \ - -t ${DOCKER_IMAGE_TAG} \ - --cache-from=${DOCKER_IMAGE_TAG} \ - --network host \ - --build-arg MAKEFLAGS_PARALLEL="-j ${NUM_PROC}" \ - tests/docker/${MBEDTLS_DOCKER_GUEST} +build_image() { + # Build the Docker image + echo "Getting docker image up to date (this may take a few minutes)..." + ${DOCKER} image build \ + -t ${DOCKER_IMAGE_TAG} \ + --cache-from=${DOCKER_IMAGE_TAG} \ + --network host \ + --build-arg MAKEFLAGS_PARALLEL="-j ${NUM_PROC}" \ + tests/docker/${MBEDTLS_DOCKER_GUEST} +} run_in_docker() { diff --git a/tests/run-test-in-docker.sh b/tests/run-test-in-docker.sh index ca3486e..367ecf1 100755 --- a/tests/run-test-in-docker.sh +++ b/tests/run-test-in-docker.sh @@ -1,5 +1,11 @@ #!/bin/bash -eu source tests/docker_env.sh -run_in_docker ./tests/start-up-and-test.sh +if [[ $1 == "pkcs11" ]]; then + run_in_docker ./tests/start-up-and-test-pkcs11.sh +elif [[ $1 == "sc-hsm-pkcs11" ]]; then + run_in_docker ./tests/scripts/sc_hsm_test.sh +else + run_in_docker ./tests/start-up-and-test.sh +fi diff --git a/tests/scripts/aes.sh b/tests/scripts/aes.sh new file mode 100755 index 0000000..ae1a22b --- /dev/null +++ b/tests/scripts/aes.sh @@ -0,0 +1,38 @@ +#!/bin/bash + +source ./tests/scripts/func.sh +reset +test $? -eq 0 || exit $? + +TEST_DATA="This is a text." + +echo "${TEST_DATA}" > test + +sc_tool() { + pkcs11-tool --module /usr/local/lib/libsc-hsm-pkcs11.so -l --pin 648219 $@ +} + +aeses=("16" "24" "32") + +for aes in ${aeses[*]}; do + echo " Test AES (AES:${aes})" + echo -n " Keygen... " + sc_tool --keygen --key-type "AES:${aes}" --id 1 --label "AES:${aes}" > /dev/null 2>&1 + test $? -eq 0 && echo -n "." || exit $? + e=$(sc_tool --list-object --type secrkey 2>&1) + test $? -eq 0 && echo -n "." || exit $? + grep -q "AES length ${aes}" <<< $e && echo -n "." || exit $? + grep -q "AES:${aes}" <<< $e && echo -e ".\t${OK}" || exit $? + + echo -n " Encryption..." + sc_tool --encrypt --id 1 --input-file test --mechanism aes-cbc > crypted.aes 2>/dev/null + test $? -eq 0 && echo -e ".\t${OK}" || exit $? + + echo -n " Decryption..." + e=$(sc_tool --decrypt --id 1 --input-file crypted.aes --mechanism aes-cbc 2>/dev/null) + test $? -eq 0 && echo -n "." || exit $? + grep -q "${TEST_DATA}" <<< $e && echo -e ".\t${OK}" || exit $? + + sc_tool --delete --type secrkey --id 1 > /dev/null 2>&1 +done +rm -rf test crypted.aes diff --git a/tests/scripts/asym_cipher.sh b/tests/scripts/asym_cipher.sh new file mode 100755 index 0000000..c75bf20 --- /dev/null +++ b/tests/scripts/asym_cipher.sh @@ -0,0 +1,62 @@ +#!/bin/bash + +source ./tests/scripts/func.sh +reset +test $? -eq 0 || exit $? + +rsa_encrypt_decrypt() { + openssl pkeyutl -encrypt -pubin -inkey 1.pub $2 -in $1 -out data.crypt + test $? -eq 0 && echo -n "." || exit $? + TDATA=$(tr -d '\0' < <(pkcs11-tool --id 1 --pin 648219 --decrypt $3 -i data.crypt 2>/dev/null)) + test $? -eq 0 && echo -n "." || exit $? + if [[ ${TEST_STRING} != "$TDATA" ]]; then + exit 1 + fi + test $? -eq 0 && echo -n "." || exit $? +} + +TEST_STRING="This is a test string. Be safe, be secure." + +echo ${TEST_STRING} > data + +echo -n " Keygen RSA 2048..." +keygen_and_export rsa:2048 +test $? -eq 0 && echo -e ".\t${OK}" || exit $? + +echo -n " Test RSA-PKCS ciphering..." +rsa_encrypt_decrypt data "-pkeyopt rsa_padding_mode:pkcs1" "--mechanism RSA-PKCS" +test $? -eq 0 && echo -e ".\t${OK}" || exit $? + +echo -n " Test RSA-X-509 ciphering..." +cp data data_pad +tlen=${#TEST_STRING} +dd if=/dev/zero bs=1 count=$((256-$tlen-1)) >> data_pad 2> /dev/null +test $? -eq 0 && echo -n "." || exit $? +rsa_encrypt_decrypt data_pad "-pkeyopt rsa_padding_mode:none" "--mechanism RSA-X-509" +test $? -eq 0 && echo -e ".\t${OK}" || exit $? + +echo -n " Test RSA-PKCS-OAEP ciphering..." +rsa_encrypt_decrypt data "-pkeyopt rsa_padding_mode:oaep -pkeyopt rsa_oaep_md:sha256 -pkeyopt rsa_mgf1_md:sha256" "--mechanism RSA-PKCS-OAEP" +test $? -eq 0 && echo -e ".\t${OK}" || exit $? + +rm -rf data* 1.* +pkcs11-tool -l --pin 648219 --delete-object --type privkey --id 1 > /dev/null 2>&1 + +algs=("secp192r1" "secp256r1" "secp384r1" "secp521r1" "brainpoolP256r1" "brainpoolP384r1" "brainpoolP512r1" "secp192k1" "secp256k1") +for alg in ${algs[*]}; do + echo -n " Test EC derive with ${alg}..." + keygen_and_export ec:${alg} + test $? -eq 0 && echo -n "." || exit $? + openssl ecparam -genkey -name ${alg} > bob.pem 2>/dev/null + test $? -eq 0 && echo -n "." || exit $? + openssl ec -in bob.pem -pubout -outform DER > bob.der 2>/dev/null + test $? -eq 0 && echo -n "." || exit $? + pkcs11-tool --pin 648219 --id 1 --derive -i bob.der -o mine-bob.der > /dev/null 2>&1 + test $? -eq 0 && echo -n "." || exit $? + openssl pkeyutl -derive -out bob-mine.der -inkey bob.pem -peerkey 1.pub 2>/dev/null + test $? -eq 0 && echo -n "." || exit $? + cmp bob-mine.der mine-bob.der + test $? -eq 0 && echo -e ".\t${OK}" || exit $? + rm -rf data* 1.* + pkcs11-tool -l --pin 648219 --delete-object --type privkey --id 1 > /dev/null 2>&1 +done diff --git a/tests/scripts/backup.sh b/tests/scripts/backup.sh new file mode 100755 index 0000000..84a3d29 --- /dev/null +++ b/tests/scripts/backup.sh @@ -0,0 +1,60 @@ +#!/bin/bash + +source ./tests/scripts/func.sh +reset +test $? -eq 0 || exit $? + +sc_backup() { + for i in $(seq 1 $1); do + sc-hsm-tool --create-dkek-share dkek.${i}.pbe --password testpw > /dev/null 2>&1 + test $? -eq 0 && echo -n "." || exit $? + done + sc-hsm-tool --initialize --so-pin 3537363231383830 --pin 648219 --dkek-shares $1 > /dev/null 2>&1 + test $? -eq 0 && echo -n "." || exit $? + pkcs11-tool -l --pin 648219 -I > /dev/null 2>&1 + test $? -eq 0 && echo -n "." || exit $? + for i in $(seq 1 $1); do + e=$(sc-hsm-tool --import-dkek-share dkek.${i}.pbe --password testpw 2>&1) + test $? -eq 0 && echo -n "." || exit $? + grep -q "DKEK share imported" <<< $e && echo -n "." || exit $? + grep -q "DKEK shares[[:blank:]]*: $1" <<< $e && echo -n "." || exit $? + if [[ $i -lt $1 ]]; then + grep -q "DKEK import pending, $(( $1 - $i ))" <<< $e && echo -n "." || exit $? + fi + done + # Store DKEK, since it is not logged in + pkcs11-tool -l --pin 648219 -I > /dev/null 2>&1 + test $? -eq 0 && echo -n "." || exit $? +} +echo -n " Test single DKEK..." +sc_backup 1 +test $? -eq 0 && echo -e ".\t${OK}" || exit $? + +echo -n " Test multiple DKEK..." +sc_backup 3 +test $? -eq 0 && echo -e ".\t${OK}" || exit $? + +rm -rf dkek.*.pbe + +echo " Test backup and restore" +algs=("rsa:1024" "rsa:2048" "ec:secp192r1" "ec:secp256r1" "ec:secp384r1" "ec:secp521r1" "ec:brainpoolP256r1" "ec:brainpoolP384r1" "ec:brainpoolP512r1" "ec:secp192k1" "ec:secp256k1") +for alg in ${algs[*]}; do + echo -n " Keygen ${alg}..." + gen_and_check ${alg} + test $? -eq 0 && echo -e ".\t${OK}" || exit $? + echo -n " Wrap key..." + sc-hsm-tool --wrap-key wrap-key.bin --key-reference 1 --pin 648219 > /dev/null 2>&1 + test $? -eq 0 && echo -n "." || exit $? + e=$(pkcs15-tool -D 2>&1) + grep -q "Key ref[[:blank:]]*: 10" <<< $e && exit $? || echo -e ".\t${OK}" + echo -n " Unwrap key..." + sc-hsm-tool --unwrap-key wrap-key.bin --key-reference 10 --pin 648219 --force > /dev/null 2>&1 + test $? -eq 0 && echo -n "." || exit $? + e=$(pkcs15-tool -D 2>&1) + grep -q "Key ref[[:blank:]]*: 10" <<< $e && echo -e ".\t${OK}" || exit $? + echo -n " Cleaning..." + pkcs11-tool -l --pin 648219 --delete-object --type privkey --id 1 > /dev/null 2>&1 + test $? -eq 0 && echo -n "." || exit $? + pkcs11-tool -l --pin 648219 --delete-object --type privkey --id 1 > /dev/null 2>&1 + test $? -eq 0 && echo -e ".\t${OK}" || exit $? +done diff --git a/tests/scripts/func.sh b/tests/scripts/func.sh new file mode 100755 index 0000000..4a9b324 --- /dev/null +++ b/tests/scripts/func.sh @@ -0,0 +1,52 @@ +#!/bin/bash + +OK="\033[32mok\033[0m" +FAIL="\033[31mfail\033[0m" + +gen_and_check() { + e=$(pkcs11-tool -l --pin 648219 --keypairgen --key-type $1 --id 1 --label "TestLabel" 2>&1) + test $? -eq 0 && echo -n "." || exit $? + glabel="" + case $1 in + *"192"*) + glabel="EC_POINT 192 bits" + ;; + *"256"*) + glabel="EC_POINT 256 bits" + ;; + *"384"*) + glabel="EC_POINT 384 bits" + ;; + *"512"*) + glabel="EC_POINT 512 bits" + ;; + *"521"*) + glabel="EC_POINT 528 bits" + ;; + *"rsa"*) + IFS=: read -r v1 bits <<< "$1" + glabel="RSA ${bits} bits" + ;; + esac + grep -q "${glabel}" <<< $e && echo -n "." || exit $? +} +gen_and_delete() { + gen_and_check $1 + test $? -eq 0 && echo -n "." || exit $? + pkcs11-tool -l --pin 648219 --delete-object --type privkey --id 1 > /dev/null 2>&1 + test $? -eq 0 && echo -n "." || exit $? +} +reset() { + python3 tools/pico-hsm-tool.py --pin 648219 initialize --so-pin 57621880 --silent > /dev/null 2>&1 + test $? -eq 0 || exit $? +} + +keygen_and_export() { + gen_and_check $1 + test $? -eq 0 && echo -n "." || exit $? + pkcs11-tool --read-object --pin 648219 --id 1 --type pubkey > 1.der 2>/dev/null + test $? -eq 0 && echo -n "." || exit $? + IFS=: read -r mk bts <<< "$1" + openssl ${mk} -inform DER -outform PEM -in 1.der -pubin > 1.pub 2>/dev/null + test $? -eq 0 && echo -n "." || exit $? +} diff --git a/tests/scripts/initialize.sh b/tests/scripts/initialize.sh new file mode 100755 index 0000000..39426c8 --- /dev/null +++ b/tests/scripts/initialize.sh @@ -0,0 +1,49 @@ +#!/bin/bash + +source ./tests/scripts/func.sh +reset + +# Change SO-PIN +echo -n " Test SO-PIN change..." +pkcs11-tool --login --login-type so --so-pin 3537363231383830 --change-pin --new-pin 0123456789012345 > /dev/null 2>&1 +test $? -eq 0 && echo -n "." || exit $? + +pkcs11-tool --login --login-type so --so-pin 0123456789012345 --change-pin --new-pin 3537363231383830 > /dev/null 2>&1 +test $? -eq 0 && echo -e ".\t${OK}" || exit $? + +# Change PIN +echo -n " Test PIN change..." +pkcs11-tool --login --pin 648219 --change-pin --new-pin 123456 > /dev/null 2>&1 +test $? -eq 0 && echo -e ".\t${OK}" || exit $? + +# Reset PIN +echo -n " Test PIN reset..." +pkcs11-tool --login --login-type so --so-pin 3537363231383830 --init-pin --new-pin 648219 > /dev/null 2>&1 +test $? -eq 0 && echo -n "." || exit $? + +# Change PIN +pkcs11-tool --login --pin 648219 --change-pin --new-pin 123456 > /dev/null 2>&1 +test $? -eq 0 && echo -n "." || exit $? + +pkcs11-tool --login --pin 123456 --change-pin --new-pin 648219 > /dev/null 2>&1 +test $? -eq 0 && echo -e ".\t${OK}" || exit $? + +# Wrong PIN (1st and 2nd PIN_INCORRECT, 3rd PIN_LOCKED) +echo -n " Test wrong PIN attempts..." +e=$(pkcs11-tool --login --pin 123456 -I 2>&1) +test $? -eq 1 && echo -n "." || exit $? +grep -q CKR_PIN_INCORRECT <<< $e && echo -n "." || exit $? +e=$(pkcs11-tool --login --pin 123456 -I 2>&1) +test $? -eq 1 && echo -n "." || exit $? +grep -q CKR_PIN_INCORRECT <<< $e && echo -n "." || exit $? +e=$(pkcs11-tool --login --pin 123456 -I 2>&1) +test $? -eq 1 && echo -n "." || exit $? +grep -q CKR_PIN_LOCKED <<< $e && echo -e "\t${OK}" || exit $? + +# Reset PIN +echo -n " Test restore PIN..." +pkcs11-tool --login --login-type so --so-pin 3537363231383830 --init-pin --new-pin 648219 > /dev/null 2>&1 +test $? -eq 0 && echo -n "." || exit $? + +pkcs11-tool --login --pin 648219 -I > /dev/null 2>&1 +test $? -eq 0 && echo -e "\t${OK}" || exit $? diff --git a/tests/scripts/keygen.sh b/tests/scripts/keygen.sh new file mode 100755 index 0000000..0b59f71 --- /dev/null +++ b/tests/scripts/keygen.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +source ./tests/scripts/func.sh +reset +test $? -eq 0 || exit $? + +algs=("rsa:1024" "rsa:2048" "ec:secp192r1" "ec:secp256r1" "ec:secp384r1" "ec:secp521r1" "ec:brainpoolP256r1" "ec:brainpoolP384r1" "ec:brainpoolP512r1" "ec:secp192k1" "ec:secp256k1") +for alg in ${algs[*]}; do + IFS=: read -r a s <<< "${alg}" + au=$(awk '{print toupper($0)}' <<<${a}) + echo -n " Test ${au} ${s}..." + gen_and_delete ${alg} && echo -e ".\t${OK}" || exit $? +done diff --git a/tests/scripts/pkcs11.sh b/tests/scripts/pkcs11.sh new file mode 100755 index 0000000..c688fdc --- /dev/null +++ b/tests/scripts/pkcs11.sh @@ -0,0 +1,58 @@ +#!/bin/bash + +source ./tests/scripts/func.sh +echo "==== Test initialization ====" +./tests/scripts/initialize.sh +test $? -eq 0 || { + echo -e "\t${FAIL}" + exit 1 +} + +echo "==== Test keygen ====" +./tests/scripts/keygen.sh +test $? -eq 0 || { + echo -e "\t${FAIL}" + exit 1 +} + +echo "==== Test sign and verify ====" +./tests/scripts/sign_and_verify.sh +test $? -eq 0 || { + echo -e "\t${FAIL}" + exit 1 +} + +echo "==== Test asymmetric ciphering ====" +./tests/scripts/asym_cipher.sh +test $? -eq 0 || { + echo -e "\t${FAIL}" + exit 1 +} + +echo "==== Test binary storage ====" +./tests/scripts/store_binary.sh +test $? -eq 0 || { + echo -e "\t${FAIL}" + exit 1 +} + +echo "==== Test AES ====" +./tests/scripts/aes.sh +test $? -eq 0 || { + echo -e "\t${FAIL}" + exit 1 +} + +echo "==== Test PKCS11-tool ====" +./tests/scripts/pkcs11_test.sh +test $? -eq 0 || { + echo -e "\t${FAIL}" + exit 1 +} + +echo "==== Test backup and restore ====" +./tests/scripts/backup.sh +test $? -eq 0 || { + echo -e "\t${FAIL}" + exit 1 +} diff --git a/tests/scripts/pkcs11_test.sh b/tests/scripts/pkcs11_test.sh new file mode 100755 index 0000000..1f8b197 --- /dev/null +++ b/tests/scripts/pkcs11_test.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +source ./tests/scripts/func.sh +reset +test $? -eq 0 || exit $? + +echo -n " Test PKCS11 tool..." +gen_and_check rsa:2048 +test $? -eq 0 && echo -n "." || exit $? +e=$(pkcs11-tool --test -l --pin 648219 2>&1) +test $? -eq 0 && echo -n "." || exit $? +grep -q "No errors" <<< $e && echo -n "." || exit $? +pkcs11-tool -l --pin 648219 --delete-object --type privkey --id 1 > /dev/null 2>&1 +test $? -eq 0 && echo -e ".\t${OK}" || exit $? +#e=$(pkcs11-tool --test-ec -l --pin 648219 --id 1 --key-type ec:secp256r1 2>&1) +#test $? -eq 0 && echo -n "." || exit $? +#grep -q "==> OK" <<< $e && echo -e ".\t${OK}" || exit $? diff --git a/tests/scripts/sc_hsm_test.sh b/tests/scripts/sc_hsm_test.sh new file mode 100755 index 0000000..0885439 --- /dev/null +++ b/tests/scripts/sc_hsm_test.sh @@ -0,0 +1,24 @@ +#!/bin/bash + +source ./tests/startup.sh + +echo "==== Test SC HSM ====" +echo -n " Running sc-hsm-pkcs11-test..." +pkcs11-tool -l --pin 648219 --keypairgen --key-type ec:secp256r1 --id 1 --label "TestLabel" > /dev/null 2>&1 +test $? -eq 0 && echo -n "." || { + echo -e "\t${FAIL}" + exit 1 +} +e=$(/usr/local/bin/sc-hsm-pkcs11-test --module /usr/local/lib/libsc-hsm-pkcs11.so --pin 648219 --invasive 2>&1) +test $? -eq 0 && echo -n "." || { + echo -e "\t${FAIL}" + exit 1 +} +grep -q "338 tests performed" <<< $e && echo -n "." || { + echo -e "\t${FAIL}" + exit 1 +} +grep -q "0 tests failed" <<< $e && echo -e ".\t${OK}" || { + echo -e "\t${FAIL}" + exit 1 +} \ No newline at end of file diff --git a/tests/scripts/sign_and_verify.sh b/tests/scripts/sign_and_verify.sh new file mode 100755 index 0000000..02f856e --- /dev/null +++ b/tests/scripts/sign_and_verify.sh @@ -0,0 +1,126 @@ +#!/bin/bash + +source ./tests/scripts/func.sh +reset +test $? -eq 0 || exit $? + +TEST_DATA="This is a test string. Be safe, be secure." +echo ${TEST_DATA} > data + +create_dgst() { + openssl dgst -$1 -binary -out data.$1 data > /dev/null 2>&1 + test $? -eq 0 && echo -n "." || exit $? +} + +dgsts=("sha1" "sha224" "sha256" "sha384" "sha512") +for dgst in ${dgsts[*]}; do + echo -n " Create digest ${dgst}..." + create_dgst ${dgst} + test $? -eq 0 && echo -e ".\t${OK}" || exit $? +done + +# $1 sign mechanism +# $2 sign input file +# $3 sign parameters +# $4 vrfy input file +# $5 vrfy parameters +sign_and_verify() { + pkcs11-tool --id 1 --sign --pin 648219 --mechanism $1 -i $2 -o data.sig $3 > /dev/null 2>&1 + test $? -eq 0 && echo -n "." || exit $? + e=$(openssl pkeyutl -verify -pubin -inkey 1.pub -in $4 -sigfile data.sig $5 2>&1) + test $? -eq 0 && echo -n "." || exit $? + grep -q "Signature Verified Successfully" <<< $e && echo -n "." || exit $? +} + +sign_and_verify_rsa_pkcs() { + dgstl=$(awk '{print tolower($0)}' <<<$1) + dgstu=$(awk '{print toupper($0)}' <<<$1) + sign_and_verify "${dgstu}-RSA-PKCS" data "" data.${dgstl} "-pkeyopt digest:${dgstl}" + test $? -eq 0 && echo -n "." || exit $? +} + +sign_and_verify_rsa_pss() { + dgstl=$(awk '{print tolower($0)}' <<<$1) + dgstu=$(awk '{print toupper($0)}' <<<$1) + sign_and_verify "RSA-PKCS-PSS" data.${dgstl} "--mgf MGF1-${dgstu} --hash-algorithm ${dgstu}" data.${dgstl} "-pkeyopt rsa_padding_mode:pss -pkeyopt rsa_pss_saltlen:-1 -pkeyopt digest:${dgstl}" + test $? -eq 0 && echo -n "." || exit $? +} + +sign_and_verify_rsa_pss_dgst() { + dgstl=$(awk '{print tolower($0)}' <<<$1) + dgstu=$(awk '{print toupper($0)}' <<<$1) + sign_and_verify "${dgstu}-RSA-PKCS-PSS" data "" data.${dgstl} "-pkeyopt rsa_padding_mode:pss -pkeyopt rsa_pss_saltlen:-1 -pkeyopt digest:${dgstl}" + test $? -eq 0 && echo -n "." || exit $? +} + +keygen_sign_and_verify_ec() { + echo " Test ECDSA with $1" + echo -n " Keygen $1..." + keygen_and_export $1 + test $? -eq 0 && echo -e ".\t${OK}" || exit $? + for dgst in ${dgsts[*]}; do + dgstu=$(awk '{print toupper($0)}' <<<${dgst}) + echo -n " Test ECDSA with ${dgst} and $1..." + sign_and_verify ECDSA "data.${dgst}" "--signature-format openssl" data.${dgst} + test $? -eq 0 && echo -e ".\t${OK}" || exit $? + echo -n " Test ECDSA-${dgstu} with $1..." + sign_and_verify "ECDSA-${dgstu}" data "--signature-format openssl" data.${dgst} + test $? -eq 0 && echo -e ".\t${OK}" || exit $? + done + echo -n " Delete $1..." + pkcs11-tool -l --pin 648219 --delete-object --type privkey --id 1 > /dev/null 2>&1 + test $? -eq 0 && echo -e ".\t${OK}" || exit $? +} + +algs=("ec:secp192r1" "ec:secp256r1" "ec:secp384r1" "ec:secp521r1" "ec:brainpoolP256r1" "ec:brainpoolP384r1" "ec:brainpoolP512r1" "ec:secp192k1" "ec:secp256k1") +for alg in ${algs[*]}; do + keygen_sign_and_verify_ec ${alg} || exit $? +done + +echo " Test RSA PKCS" +echo -n " Keygen rsa:2048..." +keygen_and_export "rsa:2048" +test $? -eq 0 && echo -e ".\t${OK}" || exit $? + +echo -n " Test RSA-PKCS..." +pkcs11-tool --id 1 --sign --pin 648219 --mechanism RSA-PKCS -i data -o data.sig > /dev/null 2>&1 +test $? -eq 0 && echo -n "." || exit $? +e=$(openssl pkeyutl -verify -pubin -inkey 1.pub -in data -sigfile data.sig 2>&1) +test $? -eq 0 && echo -n "." || exit $? +grep -q "Signature Verified Successfully" <<< $e && echo -e ".\t${OK}" || exit $? + +for dgst in ${dgsts[*]}; do + dgstu=$(awk '{print toupper($0)}' <<<${dgst}) + echo -n " Test RSA-PKCS-${dgstu}..." + sign_and_verify_rsa_pkcs ${dgst} + test $? -eq 0 && echo -e ".\t${OK}" || exit $? +done + +echo -n " Test RSA-X-509..." +cp data data_pad +test $? -eq 0 && echo -n "." || exit $? +tlen=${#TEST_DATA} +dd if=/dev/zero bs=1 count=$((256-$tlen)) >> data_pad > /dev/null 2>&1 +test $? -eq 0 && echo -n "." || exit $? +pkcs11-tool --id 1 --sign --pin 648219 --mechanism RSA-X-509 -i data_pad -o data.sig > /dev/null 2>&1 +test $? -eq 0 && echo -n "." || exit $? +TDATA=$(tr -d '\0' < <(openssl rsautl -verify -inkey 1.pub -in data.sig -pubin -raw)) +if [[ ${TEST_DATA} != "$TDATA" ]]; then + exit 1 +fi +test $? -eq 0 && echo -e ".\t${OK}" || exit $? + +for dgst in ${dgsts[*]}; do + dgstu=$(awk '{print toupper($0)}' <<<${dgst}) + if [[ "${dgst}" != "sha1" ]]; then + echo -n " Test RSA-PKCS-PSS with ${dgst}..." + sign_and_verify_rsa_pss ${dgst} + test $? -eq 0 && echo -e ".\t${OK}" || exit $? + fi + echo -n " Test ${dgstu}-RSA-PKCS-PSS..." + sign_and_verify_rsa_pss_dgst ${dgst} + test $? -eq 0 && echo -e ".\t${OK}" || exit $? +done + +rm -rf data* 1.* +pkcs11-tool -l --pin 648219 --delete-object --type privkey --id 1 > /dev/null 2>&1 diff --git a/tests/scripts/store_binary.sh b/tests/scripts/store_binary.sh new file mode 100755 index 0000000..3b03cff --- /dev/null +++ b/tests/scripts/store_binary.sh @@ -0,0 +1,28 @@ +#!/bin/bash + +source ./tests/scripts/func.sh +reset +test $? -eq 0 || exit $? + +TEST_DATA="Pico HSM is awesome!" + +echo ${TEST_DATA} > test + +echo -n " Test public binary storage..." +pkcs11-tool --pin 648219 --write-object test --type data --id 1 --label 'test1' > /dev/null 2>&1 +test $? -eq 0 && echo -n "." || exit $? +e=$(pkcs11-tool --read-object --type data --label 'test1' 2>&1) +test $? -eq 0 && echo -n "." || exit $? +grep -q "${TEST_DATA}" <<< $e && echo -e ".\t${OK}" || exit $? +pkcs11-tool --pin 648219 --delete-object --type data --label 'test1' > /dev/null 2>&1 + +echo -n " Test private binary storage..." +pkcs11-tool --pin 648219 --write-object test --type data --id 1 --label 'test1' --private > /dev/null 2>&1 +test $? -eq 0 && echo -n "." || exit $? +e=$(pkcs11-tool --read-object --type data --label 'test1' --pin 648219 2>&1) +test $? -eq 0 && echo -n "." || exit $? +grep -q "${TEST_DATA}" <<< $e && echo -n "." || exit $? +e=$(pkcs11-tool --read-object --type data --label 'test1' 2>&1) +test $? -eq 1 && echo -n "." || exit $? +grep -q "error: object not found" <<< $e && echo -e ".\t${OK}" || exit $? +pkcs11-tool --pin 648219 --delete-object --type data --label 'test1' > /dev/null 2>&1 diff --git a/tests/start-up-and-test-pkcs11.sh b/tests/start-up-and-test-pkcs11.sh new file mode 100755 index 0000000..25363be --- /dev/null +++ b/tests/start-up-and-test-pkcs11.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +source ./tests/startup.sh + +chmod a+x tests/scripts/*.sh + +echo "======== PKCS11 Test suite ========" +./tests/scripts/pkcs11.sh diff --git a/tests/start-up-and-test.sh b/tests/start-up-and-test.sh index 9ba94b4..de0a302 100755 --- a/tests/start-up-and-test.sh +++ b/tests/start-up-and-test.sh @@ -1,11 +1,5 @@ -#!/bin/bash -eu +#!/bin/bash + +source ./tests/startup.sh -rm -rf pypicohsm -git clone https://github.com/polhenarejos/pypicohsm.git -pip3 install -e pypicohsm -/usr/sbin/pcscd & -sleep 2 -rm -f memory.flash -tar -xf tests/memory.tar.gz -./build_in_docker/pico_hsm > /dev/null & pytest tests -W ignore::DeprecationWarning diff --git a/tests/startup.sh b/tests/startup.sh new file mode 100644 index 0000000..91b1a0e --- /dev/null +++ b/tests/startup.sh @@ -0,0 +1,27 @@ +#!/bin/bash + +OK="\t\033[32mok\033[0m" +FAIL="\t\033[31mfail\033[0m" + +fail() { + echo -e "${FAIL}" + exit 1 +} + +echo -n "Start PCSC..." +/usr/sbin/pcscd & +test $? -eq 0 && echo -e "${OK}" || { + echo -e "${FAIL}" + exit 1 +} +sleep 2 +rm -f memory.flash +tar -xf tests/memory.tar.gz +echo -n "Start Pico HSM..." +/pico_hsm > /dev/null 2>&1 & +test $? -eq 0 && echo -n "." || fail +sleep 2 +ATR="3b:fe:18:00:00:81:31:fe:45:80:31:81:54:48:53:4d:31:73:80:21:40:81:07:fa" +e=$(opensc-tool -an 2>&1) +grep -q "${ATR}" <<< $e && echo -n "." || fail +test $? -eq 0 && echo -e "${OK}" || fail diff --git a/tools/pico-hsm-tool.py b/tools/pico-hsm-tool.py index 7e0353f..012c15f 100644 --- a/tools/pico-hsm-tool.py +++ b/tools/pico-hsm-tool.py @@ -39,7 +39,7 @@ except ModuleNotFoundError: sys.exit(-1) try: - from picohsm import PicoHSM, PinType, DOPrefixes, KeyType, EncryptionMode, utils + from picohsm import PicoHSM, PinType, DOPrefixes, KeyType, EncryptionMode, utils, APDUResponse, SWCodes except ModuleNotFoundError: print('ERROR: picohsm module not found! Install picohsm package.\nTry with `pip install pypicohsm`') sys.exit(-1) @@ -66,6 +66,7 @@ def parse_args(): parser_init = subparser.add_parser('initialize', help='Performs the first initialization of the Pico HSM.') parser.add_argument('--pin', help='PIN number') parser_init.add_argument('--so-pin', help='SO-PIN number') + parser_init.add_argument('--silent', help='Confirms initialization silently.', action='store_true') parser_attestate = subparser.add_parser('attestate', help='Generates an attestation report for a private key and verifies the private key was generated in the devices or outside.') parser_attestate.add_argument('-k', '--key', help='The private key index', metavar='KEY_ID') @@ -176,23 +177,30 @@ def pki(_, args): print('Error: no PKI is passed. Use --default to retrieve default PKI.') def initialize(picohsm, args): - print('********************************') - print('* PLEASE READ IT CAREFULLY *') - print('********************************') - print('') - print('This tool will erase and reset your device. It will delete all ' - 'private and secret keys.') - print('Are you sure?') - _ = input('[Press enter to confirm]') + if (not args.silent): + print('********************************') + print('* PLEASE READ IT CAREFULLY *') + print('********************************') + print('') + print('This tool will erase and reset your device. It will delete all ' + 'private and secret keys.') + print('Are you sure?') + _ = input('[Press enter to confirm]') if (args.pin): - picohsm.login(args.pin) - pin = args + try: + picohsm.login(args.pin) + except APDUResponse: + pass + pin = args.pin else: pin = '648219' if (args.so_pin): - picohsm.login(args.pin, who=PinType.SO_PIN) + try: + picohsm.login(args.so_pin, who=PinType.SO_PIN) + except APDUResponse: + pass so_pin = args.so_pin else: so_pin = '57621880' diff --git a/tools/secure_key/macos.py b/tools/secure_key/macos.py index ded5eda..a20e3d8 100644 --- a/tools/secure_key/macos.py +++ b/tools/secure_key/macos.py @@ -51,7 +51,9 @@ def get_secure_key(): try: backend = get_backend(False) key = backend.get_password(DOMAIN, USERNAME)[0] - except keyring.errors.KeyringError: + if (key is None): + raise TypeError + except (keyring.errors.KeyringError, TypeError): try: key = generate_secure_key(False)[0] # It should be True, but secure enclave causes python segfault except keyring.errors.PasswordSetError: diff --git a/tools/secure_key/windows.py b/tools/secure_key/windows.py index 3f26a79..79bec21 100644 --- a/tools/secure_key/windows.py +++ b/tools/secure_key/windows.py @@ -39,6 +39,8 @@ def get_secure_key(): key = None try: key = keyring.get_password(DOMAIN, USERNAME) - except keyring.errors.KeyringError: + if (key is None): + raise TypeError + except (keyring.errors.KeyringError, TypeError): key = generate_secure_key() return get_d(key.encode())