| #!/bin/bash |
| # SPDX-License-Identifier: GPL-2.0-only |
| # Copyright (C) 2021 Foundries.io Ltd. |
| |
| # shellcheck disable=SC1091 |
| . ../../lib/sh-test-lib |
| OUTPUT="$(pwd)/output" |
| RESULT_FILE="${OUTPUT}/result.txt" |
| export RESULT_FILE |
| PTOOL="pkcs11-tool --module /usr/lib/libckteec.so.0.1.0" |
| USE_SE05X="True" |
| EXECUTE_LOOP="True" |
| TOKEN_LABEL=fio |
| SE05X_TOOL=ssscli |
| OTA=false |
| OTA_ACTION="sign" |
| OTA_DIRECTORY="/home" |
| |
| usage() { |
| echo "\ |
| Usage: $0 [-p <pkcs11-tool>] [-t <true|false>] [-s <true|false>] [-l <true|false>] |
| |
| -p <pkcs11-tool> |
| pkcs11-tool with all the options required. Default is: |
| pkcs11-tool --module /usr/lib/libckteec.so.0.1 |
| -t <true|false> |
| This flag switches on/off the use of SE05X TPM device. |
| It is turned on by default but users can choose to use |
| softhsm as alternative. Setting this flag to False will |
| prevent script from calling ssscli or fio-se05x-cli. |
| -l <true|false> |
| Run loop test. The test is meant to only be executed on |
| SE05x device. Running this test with sofhsm might take |
| a very long time and exhaust memory/storage on the device. |
| -s <true|false> |
| Skip install. True by default. |
| -o <true|false> |
| Test sign/OTA/verify scenario |
| -a <sign|verify> |
| Action to perform in the test for OTA scenario |
| -d <absolute dir path> |
| Directory to store files for OTA test. Should be kept intact |
| during OTA. |
| " |
| } |
| |
| while getopts "p:t:s:l:c:o:a:d:h" opts; do |
| case "$opts" in |
| p) PTOOL="${OPTARG}";; |
| t) USE_SE05X="${OPTARG}";; |
| s) SKIP_INSTALL="${OPTARG}";; |
| l) EXECUTE_LOOP="${OPTARG}";; |
| c) SE05X_TOOL="${OPTARG}";; |
| o) OTA="${OPTARG}";; |
| a) OTA_ACTION="${OPTARG}";; |
| d) OTA_DIRECTORY="${OPTARG}";; |
| h|*) usage ; exit 1 ;; |
| esac |
| done |
| |
| ! check_root && error_msg "You need to be root to run this script." |
| # Test run. |
| create_out_dir "${OUTPUT}" |
| install_deps "opensc openssl bc" "${SKIP_INSTALL}" |
| |
| SO_PIN=12345678 |
| PIN=87654321 |
| |
| se05x_cleanup() |
| { |
| if [ "${USE_SE05X}" = "True" ] || [ "${USE_SE05X}" = "true" ]; then |
| echo "Reset SE05x" |
| if [ "${SE05X_TOOL}" = "ssscli" ]; then |
| ssscli se05x reset |
| fi |
| if [ "${SE05X_TOOL}" = "fio-se05x-cli" ]; then |
| fio-se05x-cli --delete-objects all --se050 |
| fi |
| fi |
| } |
| |
| se05x_connect() |
| { |
| if [ "${USE_SE05X}" = "True" ] || [ "${USE_SE05X}" = "true" ]; then |
| echo "Connect SE05x" |
| if [ "${SE05X_TOOL}" = "ssscli" ]; then |
| ssscli connect se05x t1oi2c none |
| fi |
| # no need to connect when using fio-se05x-cli |
| fi |
| } |
| |
| housekeeping() |
| { |
| local ID="$1" |
| local FILE_LIST=( "$@" ) |
| # remove ID from the file list |
| unset "${FILE_LIST[0]}" |
| |
| echo "Cleanup" |
| # shellcheck disable=SC2086 |
| $PTOOL --list-objects --pin "${PIN}" |
| # shellcheck disable=SC2086 |
| $PTOOL -b --type privkey --id "${ID}" --pin "${PIN}" |
| # shellcheck disable=SC2086 |
| $PTOOL -b --type pubkey --id "${ID}" --pin "${PIN}" |
| # shellcheck disable=SC2086 |
| $PTOOL --list-objects --pin "${PIN}" |
| |
| for FILE in "${FILE_LIST[@]}"; |
| do |
| rm "${FILE}" |
| done |
| } |
| |
| test_cypher() |
| { |
| local ID=01 |
| local cypher="$1" |
| local mechanism="$2" |
| FILE=hello |
| se05x_connect |
| |
| echo "$cypher test" |
| echo "Create $cypher keypair" |
| # shellcheck disable=SC2086 |
| $PTOOL --keypairgen --key-type "${cypher}" --id "${ID}" --label ldts --token-label fio --pin "${PIN}" |
| check_return "$cypher-keypair" |
| |
| echo "Get the publick key to pubkey.spki" |
| # shellcheck disable=SC2086 |
| $PTOOL -l --pin "${PIN}" --id "${ID}" --read-object --type pubkey --output-file pubkey.spki |
| check_return "$cypher-pubkey-read" |
| |
| echo "hello world" > "${FILE}" |
| |
| echo "Create a digest sha256 : hello.hash" |
| openssl dgst -binary -sha256 "${FILE}" > "${FILE}.hash" |
| |
| # The block below is used to make sure that |
| # signing works for both ECC and RSA. In case of |
| # ECC signing is done using SHA256 digest of the data |
| # while in case of RSS signing is done using the data |
| # itself. |
| OPERATION="ec" |
| INFILE="${FILE}.hash" |
| if [ -z "${cypher##*RSA*}" ]; then |
| OPERATION="rsa" |
| INFILE="${FILE}" |
| fi |
| |
| echo "Transform pubkey.spki from DER to PEM" |
| openssl "${OPERATION}" -inform DER -outform PEM -in pubkey.spki -pubin > pubkey.pub |
| |
| echo "Sign hello.hash with the PEM key and generate hello.sig signature" |
| # shellcheck disable=SC2086 |
| $PTOOL --sign --pin "${PIN}" --id "${ID}" --input-file "${INFILE}" --output-file "${FILE}.sig" --mechanism "${mechanism}" -f openssl |
| |
| echo "Use the public key to verify the file signature" |
| openssl dgst -sha256 -verify pubkey.pub -signature "${FILE}.sig" "${FILE}" |
| check_return "$cypher-pubkey-verify" |
| |
| housekeeping "${ID}" "${FILE}" "${FILE}.sig" "${FILE}.hash" pubkey.spki pubkey.pub |
| se05x_cleanup |
| } |
| |
| test_ecc_derive() |
| { |
| se05x_connect |
| # Alice id = 01 |
| # shellcheck disable=SC2086 |
| $PTOOL --keypairgen --key-type EC:prime256v1 --id 01 --label alice --token-label fio --pin "${PIN}" |
| # shellcheck disable=SC2086 |
| $PTOOL --read-object --type pubkey --id 01 --token-label fio --pin "${PIN}" -o alice-pub.der |
| # Bob id = 02 |
| # shellcheck disable=SC2086 |
| $PTOOL --keypairgen --key-type EC:prime256v1 --id 02 --label bob --token-label fio --pin $PIN |
| # shellcheck disable=SC2086 |
| $PTOOL --read-object --type pubkey --id 02 --token-label fio --pin "${PIN}" -o bob-pub.der |
| echo "ECDH1-DERIVE" |
| # shellcheck disable=SC2086 |
| $PTOOL --derive -m ECDH1-DERIVE --id 01 --label alice --token-label fio --pin "${PIN}" --input-file bob-pub.der --output-file bob.secret |
| # shellcheck disable=SC2086 |
| $PTOOL --derive -m ECDH1-DERIVE --id 02 --label bob --token-label fio --pin "${PIN}" --input-file alice-pub.der --output-file alice.secret |
| echo "Diff secrets" |
| diff bob.secret alice.secret |
| check_return "ecc-pubkey-derive" |
| |
| housekeeping "${ID}" alice-pub.der alice.secret bob-pub.der bob.secret |
| # shellcheck disable=SC2086 |
| $PTOOL -b --type privkey --id 02 --pin "${PIN}" |
| # shellcheck disable=SC2086 |
| $PTOOL -b --type pubkey --id 02 --pin "${PIN}" |
| # shellcheck disable=SC2086 |
| $PTOOL --list-objects --pin "${PIN}" |
| se05x_cleanup |
| } |
| |
| test_sign() |
| { |
| local ID="$1" |
| local HASH="$2" |
| local MECHANISM="$3" |
| local DATA_FILE="$4" |
| if [ -n "${HASH}" ]; then |
| openssl dgst -binary -sha256 "${DATA_FILE}" > "${DATA_FILE}.hash" |
| # shellcheck disable=SC2086 |
| $PTOOL --pin "${PIN}" --salt-len=-1 --sign --id "${ID}" --token-label fio --hash-algorithm="${HASH}" --mechanism "${MECHANISM}" --input-file "${DATA_FILE}.hash" --output-file "${DATA_FILE}.sig" |
| else |
| # shellcheck disable=SC2086 |
| $PTOOL --pin "${PIN}" --sign --id "${ID}" --token-label fio --mechanism "${MECHANISM}" --input-file "${DATA_FILE}" --output-file "${DATA_FILE}.sig" |
| fi |
| } |
| |
| test_verify() |
| { |
| local ID="$1" |
| local HASH="$2" |
| local MECHANISM="$3" |
| local DATA_FILE="$4" |
| local LOG_FILE="$5" |
| if [ -n "${HASH}" ]; then |
| # shellcheck disable=SC2086 |
| $PTOOL --pin "${PIN}" --verify --salt-len=-1 --id "${ID}" --token-label fio --hash-algorithm="${HASH}" --mechanism "${MECHANISM}" --input-file "${DATA_FILE}.hash" --signature-file "${DATA_FILE}.sig" | tee "${LOG_FILE}" |
| else |
| # shellcheck disable=SC2086 |
| $PTOOL --pin "${PIN}" --verify --id "${ID}" --token-label fio --mechanism "${MECHANISM}" --input-file "${DATA_FILE}" --signature-file "${DATA_FILE}.sig" | tee "${LOG_FILE}" |
| fi |
| } |
| |
| generate_pubkey() |
| { |
| local ID="$1" |
| local FILE_NAME="$2" |
| local KEY_TYPE="$3" |
| local LABEL=rsa1 |
| local SSL_OP=rsa |
| case "${KEY_TYPE}" in |
| "*EC*") |
| LABEL=ec1; |
| SSL_OP=ec; |
| ;; |
| esac |
| # Generate keypair |
| echo "Generate ${KEY_TYPE} keypair" |
| # shellcheck disable=SC2086 |
| $PTOOL --pin "${PIN}" --keypairgen --key-type "${KEY_TYPE}" --id "${ID}" --label "${LABEL}" --token-label fio |
| |
| echo "Read object " |
| # shellcheck disable=SC2086 |
| $PTOOL --pin "${PIN}" --read-object --type pubkey --id "${ID}" --token-label fio --output-file "${FILE_NAME}.der" |
| openssl "${SSL_OP}" -inform DER -outform PEM -in "${FILE_NAME}.der" -pubin > "${FILE_NAME}.pub" |
| } |
| |
| generate_rsa_pubkey() |
| { |
| local ID="$1" |
| local FILE_NAME="$2" |
| generate_pubkey "${ID}" "${FILE_NAME}" rsa:2048 |
| } |
| |
| generate_ec_pubkey() |
| { |
| local ID="$1" |
| local FILE_NAME="$2" |
| generate_pubkey "${ID}" "${FILE_NAME}" EC:prime256v1 |
| } |
| |
| test_rsa_encrypt() |
| { |
| local ID="$1" |
| local PUB_KEY="$2" |
| local DATA_FILE="$3" |
| echo "RSA-PKCS Encrypt" |
| openssl rsautl -encrypt -inkey "${PUB_KEY}" -in "${DATA_FILE}" -pubin -out "${DATA_FILE}.crypt" |
| } |
| |
| test_rsa_decrypt() |
| { |
| local ID="$1" |
| local DATA_FILE="$2" |
| echo "RSA-PKCS Decrypt" |
| # shellcheck disable=SC2086 |
| $PTOOL --pin "${PIN}" --decrypt --id "${ID}" --token-label fio --mechanism RSA-PKCS --input-file "${DATA_FILE}.crypt" > "${DATA_FILE}.decrypted" |
| } |
| |
| test_sign_verify() |
| { |
| # test_sign_verify <mechanism> <hash> <rsa|ec> |
| # HASH can be emtpy |
| local ID=01 |
| local MECHANISM="$1" |
| local HASH="$2" |
| local KEY_TYPE="$3" |
| se05x_connect |
| |
| "generate_${KEY_TYPE}_pubkey" "${ID}" "${KEY_TYPE}-pubkey" |
| echo "Creating data to sign" |
| echo "data to sign (max 100 bytes)" > data |
| |
| echo "${MECHANISM} test sign/verify" |
| test_sign "${ID}" "${HASH}" "${MECHANISM}" data |
| test_verify "${ID}" "${HASH}" "${MECHANISM}" data "${MECHANISM}-sign-verify.log" |
| grep "Signature is valid" "${MECHANISM}-sign-verify.log" |
| check_return "${MECHANISM}-sign-verify" |
| |
| housekeeping "${ID}" data data.sig "${KEY_TYPE}-pubkey.der" "${KEY_TYPE}-pubkey.pub" "${MECHANISM}-sign-verify.log" |
| se05x_cleanup |
| } |
| |
| test_rsa_encrypt_decrypt() |
| { |
| local ID=03 |
| se05x_connect |
| |
| echo "Creating data to sign" |
| echo "data to sign (max 100 bytes)" > data |
| |
| generate_rsa_pubkey "${ID}" rsa-pubkey |
| |
| # Encrypt (RSA-PKCS) |
| test_rsa_encrypt "${ID}" rsa-pubkey.pub data |
| test_rsa_decrypt "${ID}" data |
| diff data data.decrypted |
| check_return "rsa-encrypt-decrypt" |
| |
| housekeeping "${ID}" data data.crypt data.decrypt rsa-pubkey.der rsa-pubkey.pub |
| se05x_cleanup |
| } |
| |
| test_import_key() { |
| se05x_connect |
| if [ "${USE_SE05X}" = "True" ] || [ "${USE_SE05X}" = "true" ]; then |
| if [ "${SE05X_TOOL}" = "ssscli" ]; then |
| OID=$(ssscli se05x readidlist | grep RSA_CRT | grep "Key Pair" | head -n 1 | awk '{print substr($2,3)}') |
| else |
| OID=$(fio-se05x-cli --list-objects --se050 2>&1 | grep RSA_KEY_PAIR_CRT | head -n 1 | awk '{print substr($2,3)}') |
| fi |
| ID=05 |
| # shellcheck disable=SC2086 |
| $PTOOL --keypairgen --key-type RSA:4096 --id "${ID}" --label "SE_${OID}" --token-label fio --pin "${PIN}" |
| NUM_KEYS=$($PTOOL --list-objects --pin "${PIN}" | grep -c "SE_${OID}") |
| if [ "${NUM_KEYS}" -eq "2" ]; then |
| report_pass "se05x-import-keys" |
| else |
| report_fail "se05x-import-keys" |
| fi |
| echo "Cleanup temporary certificates" |
| housekeeping "${ID}" |
| else |
| report_skip "se05x-import-keys" |
| fi |
| } |
| |
| test_rsa_loop() |
| { |
| se05x_connect |
| BREAK="False" |
| LABEL=0 |
| while [ "$BREAK" = "False" ] |
| do |
| # generate RSA:1024 certificate pairs until there is no |
| # more space to keep them. |
| # shellcheck disable=SC2086 |
| LABEL=$((LABEL+1)) |
| pipe0_status "$PTOOL --keypairgen --key-type RSA:1024 --label ${LABEL} --id 33 --token-label fio --pin ${PIN} 2>&1" "tee ${LABEL}.log" |
| test_status=$? |
| if [ "${test_status}" -ne 0 ]; then |
| # decrement the counter when key creation fails |
| LABEL=$((LABEL-1)) |
| if grep "CKR_DEVICE_MEMORY" "${LABEL}.log"; then |
| # If this test fails, remaining results may be tainted |
| # TA is unlikely to recover from OOM situation |
| echo "Out of memory" |
| report_fail "rsa-loop-key-create-memory" |
| else |
| report_pass "rsa-loop-key-create-memory" |
| fi |
| break |
| fi |
| done |
| NUM_CERTS=$($PTOOL --list-objects --token-label fio --pin "${PIN}" | grep ID | grep -c 33) |
| echo "Found ${NUM_CERTS} certificates with ID=33" |
| EXPECTED=$(echo "${LABEL}*2" | bc) |
| if [ "${NUM_CERTS}" = "${EXPECTED}" ]; then |
| report_pass "rsa-loop-key-create" |
| else |
| echo "Expected ${EXPECTED} keys, found ${NUM_CERTS}" |
| report_fail "rsa-loop-key-create" |
| fi |
| |
| if [ "${NUM_CERTS}" -ne "0" ]; then |
| # remove all certificates |
| LOOPS=$(echo "${NUM_CERTS}/2-1" | bc) |
| for a in $(seq 0 "${LOOPS}") |
| do |
| echo "Removing ${a} cert pair" |
| # shellcheck disable=SC2086 |
| $PTOOL -b --type privkey --id 33 --pin "${PIN}" |
| # shellcheck disable=SC2086 |
| $PTOOL -b --type pubkey --id 33 --pin "${PIN}" |
| done |
| fi |
| NUM_CERTS=$($PTOOL --list-objects --token-label fio --pin "${PIN}" | grep ID | grep -c 33) |
| if [ "${NUM_CERTS}" -ne "0" ]; then |
| report_fail "rsa-loop-remove-certs" |
| else |
| report_pass "rsa-loop-remove-certs" |
| fi |
| |
| se05x_cleanup |
| } |
| |
| if [ "${USE_SE05X}" = "True" ] || [ "${USE_SE05X}" = "true" ]; then |
| if [ "${SE05X_TOOL}" = "ssscli" ]; then |
| ssscli connect se05x t1oi2c none |
| check_return "ssscli-connect" |
| else |
| report_skip "ssscli-connect" |
| fi |
| fi |
| SKIP_INIT="False" |
| if [ "${OTA}" = "true" ] || [ "${OTA}" = "True" ]; then |
| if [ "${OTA_ACTION}" = "verify" ]; then |
| SKIP_INIT="True" |
| fi |
| fi |
| if [ "${SKIP_INIT}" = "true" ] || [ "${SKIP_INIT}" = "True" ]; then |
| info_msg "Skipping PKCS#11 initialization" |
| else |
| info_msg "PKCS#11 initialization" |
| # shellcheck disable=SC2086 |
| $PTOOL --init-token --label "${TOKEN_LABEL}" --so-pin "${SO_PIN}" |
| check_return "pkcs11-init-token" |
| # shellcheck disable=SC2086 |
| $PTOOL --init-pin --token-label "${TOKEN_LABEL}" --so-pin "${SO_PIN}" --pin "${PIN}" |
| check_return "pkcs11-init-pin" |
| # shellcheck disable=SC2086 |
| $PTOOL --list-mechanisms --token-label "${TOKEN_LABEL}" --pin "${PIN}" |
| check_return "pkcs11-list-mechanisms" |
| # shellcheck disable=SC2086 |
| $PTOOL --list-objects --token-label "${TOKEN_LABEL}" --pin "${PIN}" |
| check_return "pkcs11-list-objects" |
| fi |
| |
| if [ "${USE_SE05X}" = "True" ] || [ "${USE_SE05X}" = "true" ]; then |
| if [ "${SE05X_TOOL}" = "ssscli" ]; then |
| ssscli disconnect |
| check_return "ssscli-disconnect" |
| else |
| report_skip "ssscli-disconnect" |
| fi |
| fi |
| |
| if [ "${OTA}" = "true" ] || [ "${OTA}" = "True" ]; then |
| # test sign-OTA-verify scenario |
| cd "${OTA_DIRECTORY}" || error_fatal "Unable to find ${OTA_DIRECTORY} on the disk" |
| if [ "${OTA_ACTION}" = "sign" ]; then |
| echo "Sign RSA-PKCS-PSS SHA256" > rsa_sha256_pss |
| generate_rsa_pubkey "01" "RSA-01-pubkey" |
| test_sign "01" SHA256 RSA-PKCS-PSS rsa_sha256_pss |
| rm "RSA-01-pubkey.der" |
| rm "RSA-01-pubkey.pub" |
| |
| echo "Sign RSA-PKCS" > rsa |
| generate_rsa_pubkey "02" "RSA-01-pubkey" |
| test_sign "02" "" RSA-PKCS rsa |
| rm "RSA-02-pubkey.der" |
| rm "RSA-02-pubkey.pub" |
| |
| echo "Sign RSA-PKCS SHA256" > rsa_sha256 |
| generate_rsa_pubkey "03" "RSA-03-pubkey" |
| test_sign "03" "" SHA256-RSA-PKCS rsa_sha256 |
| rm "RSA-03-pubkey.der" |
| rm "RSA-03-pubkey.pub" |
| |
| echo "Sign ECDSA-SHA256 SHA256" > ecdsa_sha256 |
| generate_ec_pubkey "04" "ECDSA-04-pubkey" |
| test_sign "04" "" ECDSA-SHA256 ecdsa_sha256 |
| rm "ECDSA-04-pubkey.der" |
| rm "ECDSA-04-pubkey.pub" |
| |
| echo "Sign ECDSA-SHA256" > ecdsa |
| generate_ec_pubkey "05" "ECDSA-05-pubkey" |
| test_sign "05" "" ECDSA ecdsa |
| rm "ECDSA-05-pubkey.der" |
| rm "ECDSA-05-pubkey.pub" |
| else |
| test_verify "01" SHA256 RSA-PKCS-PSS rsa_sha256_pss rsa_sha256_pss.log |
| grep "Signature is valid" "rsa_sha256_pss.log" |
| check_return "RSA-PKCS-PSS-sign-ota-verify" |
| |
| test_verify "02" "" RSA-PKCS rsa rsa.log |
| grep "Signature is valid" "rsa.log" |
| check_return "RSA-PKCS-sign-ota-verify" |
| |
| test_verify "03" "" SHA256-RSA-PKCS rsa_sha256 rsa_sha256.log |
| grep "Signature is valid" "rsa_sha256.log" |
| check_return "SHA256-RSA-PKCS-sign-ota-verify" |
| |
| test_verify "04" "" ECDSA-SHA256 ecdsa_sha256 ecdsa_sha256.log |
| grep "Signature is valid" "ecdsa_sha256.log" |
| check_return "ECDSA-SHA256-sign-ota-verify" |
| |
| test_verify "05" "" ECDSA ecdsa ecdsa.log |
| grep "Signature is valid" "ecdsa.log" |
| check_return "ECDSA-sign-ota-verify" |
| fi |
| else |
| test_cypher "EC:prime256v1" "ECDSA" |
| test_cypher "RSA:2048" "SHA256-RSA-PKCS" |
| test_cypher "RSA:4096" "SHA256-RSA-PKCS" |
| test_ecc_derive |
| test_sign_verify RSA-PKCS-PSS SHA256 rsa |
| test_sign_verify RSA-PKCS "" rsa |
| test_sign_verify SHA256-RSA-PKCS "" rsa |
| test_sign_verify ECDSA-SHA256 "" ec |
| test_sign_verify ECDSA "" ec |
| test_rsa_encrypt_decrypt |
| test_import_key |
| if [ "${EXECUTE_LOOP}" = "True" ] || [ "${EXECUTE_LOOP}" = "true" ]; then |
| test_rsa_loop |
| else |
| report_skip "rsa-loop-remove-certs" |
| fi |
| fi |
| exit 0 |