diff --git a/tests/docker/jammy/Dockerfile b/tests/docker/jammy/Dockerfile index b6d1092..677968e 100644 --- a/tests/docker/jammy/Dockerfile +++ b/tests/docker/jammy/Dockerfile @@ -22,6 +22,20 @@ RUN apt install -y libccid \ cmake \ vsmartcard-vpcd \ libgcrypt-dev \ + libssl-dev \ + check \ + gengetopt \ && rm -rf /var/lib/apt/lists/* RUN pip3 install pytest pycvc cryptography pyscard +RUN git clone https://github.com/Yubico/yubico-piv-tool +WORKDIR /yubico-piv-tool +RUN git checkout tags/yubico-piv-tool-2.5.1 +ADD tests/docker/jammy/yubico-piv-tool.patch /yubico-piv-tool/yubico-piv-tool.patch +RUN git apply yubico-piv-tool.patch +RUN mkdir build +WORKDIR /yubico-piv-tool/build +RUN cmake .. -DENABLE_HARDWARE_TESTS=1 +RUN make -j`nproc` +RUN make install WORKDIR / +RUN ldconfig diff --git a/tests/docker/jammy/yubico-piv-tool.patch b/tests/docker/jammy/yubico-piv-tool.patch new file mode 100644 index 0000000..028cdf0 --- /dev/null +++ b/tests/docker/jammy/yubico-piv-tool.patch @@ -0,0 +1,68 @@ +diff --git a/lib/tests/api.c b/lib/tests/api.c +index fb7c1a8..b569ec3 100644 +--- a/lib/tests/api.c ++++ b/lib/tests/api.c +@@ -515,7 +515,7 @@ START_TEST(test_pin_policy_always) { + unsigned char rand[128] = {0}; + + size_t sig_len = sizeof(signature); +- size_t padlen = 256; ++ size_t padlen = 512; + unsigned int enc_len; + unsigned int data_len; + +@@ -1009,8 +1009,8 @@ END_TEST + START_TEST(test_pin_cache) { + ykpiv_rc res; + ykpiv_state *local_state; +- unsigned char data[256] = {0}; +- unsigned char data_in[256] = {0}; ++ unsigned char data[512] = {0}; ++ unsigned char data_in[512] = {0}; + int len = sizeof(data); + size_t len2 = sizeof(data); + +@@ -1028,17 +1028,17 @@ START_TEST(test_pin_cache) { + ck_assert_int_eq(res, YKPIV_OK); + + // Verify decryption does not work without auth +- res = ykpiv_decipher_data(g_state, data_in, (size_t)len, data, &len2, YKPIV_ALGO_RSA2048, 0x9a); ++ res = ykpiv_decipher_data(g_state, data_in, (size_t)len, data, &len2, YKPIV_ALGO_RSA4096, 0x9a); + ck_assert_int_eq(res, YKPIV_AUTHENTICATION_ERROR); + + // Verify decryption does work when authed + res = ykpiv_verify_select(g_state, "123456", 6, NULL, true); + ck_assert_int_eq(res, YKPIV_OK); +- res = ykpiv_decipher_data(g_state, data_in, (size_t)len, data, &len2, YKPIV_ALGO_RSA2048, 0x9a); ++ res = ykpiv_decipher_data(g_state, data_in, (size_t)len, data, &len2, YKPIV_ALGO_RSA4096, 0x9a); + ck_assert_int_eq(res, YKPIV_OK); + + // Verify PIN policy allows continuing to decrypt without re-verifying +- res = ykpiv_decipher_data(g_state, data_in, (size_t)len, data, &len2, YKPIV_ALGO_RSA2048, 0x9a); ++ res = ykpiv_decipher_data(g_state, data_in, (size_t)len, data, &len2, YKPIV_ALGO_RSA4096, 0x9a); + ck_assert_int_eq(res, YKPIV_OK); + + // Create a new ykpiv state, connect, and close it. +@@ -1059,7 +1059,7 @@ START_TEST(test_pin_cache) { + // + // Note that you can verify that this fails by rebuilding with + // DISABLE_PIN_CACHE set to 1. +- res = ykpiv_decipher_data(g_state, data_in, (size_t)len, data, &len2, YKPIV_ALGO_RSA2048, 0x9a); ++ res = ykpiv_decipher_data(g_state, data_in, (size_t)len, data, &len2, YKPIV_ALGO_RSA4096, 0x9a); + ck_assert_int_eq(res, YKPIV_OK); + } + END_TEST +diff --git a/tools/confirm.sh b/tools/confirm.sh +index 81c10ac..4ab15c5 100755 +--- a/tools/confirm.sh ++++ b/tools/confirm.sh +@@ -20,7 +20,8 @@ echo "WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WA + echo "******* ******* ******* ******* ******* ******* ******* ******* ******* ******* ******* ******* ******* ******* *******" >&0 + echo >&0 + echo -n "Are you SURE you wish to proceed? If so, type 'CONFIRM': " >&0 +- ++echo "0" ++exit 0 + read CONFIRM + if [[ "x$CONFIRM" != "xCONFIRM" ]]; then + echo "1" diff --git a/tests/docker_env.sh b/tests/docker_env.sh index c11fcb0..27cca93 100644 --- a/tests/docker_env.sh +++ b/tests/docker_env.sh @@ -49,7 +49,7 @@ : ${MBEDTLS_DOCKER_GUEST:=jammy} -DOCKER_IMAGE_TAG="pico-hsm-test:${MBEDTLS_DOCKER_GUEST}" +DOCKER_IMAGE_TAG="pico-openpgp-test:${MBEDTLS_DOCKER_GUEST}" # Make sure docker is available if ! which docker > /dev/null; then @@ -79,7 +79,7 @@ ${DOCKER} image build \ --cache-from=${DOCKER_IMAGE_TAG} \ --network host \ --build-arg MAKEFLAGS_PARALLEL="-j ${NUM_PROC}" \ - tests/docker/${MBEDTLS_DOCKER_GUEST} + -f tests/docker/${MBEDTLS_DOCKER_GUEST}/Dockerfile . run_in_docker() { diff --git a/tests/scripts/attestation.sh b/tests/scripts/attestation.sh new file mode 100755 index 0000000..e797bbe --- /dev/null +++ b/tests/scripts/attestation.sh @@ -0,0 +1,33 @@ +#!/bin/bash + +source ./tests/scripts/func.sh + +echo -n " Fetch attestation certificate... " +piv read-cert -sf9 -o sf9.pem +test $? -eq 0 && echo -e ".\t${OK}" || exit $? + +algs=("RSA1024" "RSA2048" "ECCP256" "ECCP384") +slots=("9a" "9c" "9d" "9e" "82" "83" "84" "85" "86" "87" "88" "89" "8a" "8b" "8c" "8d" "8e" "8f" "90" "91" "92" "93" "94" "95") +for alg in ${algs[*]}; do + for slot in ${slots[*]}; do + echo " Test attestation with ${alg} in slot ${slot}" + echo -n " Keygen... " + gen_and_check $alg $slot && echo -e ".\t${OK}" || exit $? + + echo -n " Fetch attesting certificate... " + piv attest -s$slot -o attestation.pem + test $? -eq 0 && echo -e ".\t${OK}" || exit $? + + echo -n " OpenSSL verify attestation... " + e=$(openssl verify -CAfile sf9.pem attestation.pem 2>&1) + test $? -eq 0 && echo -n "." || exit $? + grep -q ": OK" <<< $e && echo -e ".\t${OK}" || exit $? + + echo -n " Key deletion... " + delete_key $alg $slot && echo -e ".\t${OK}" || exit $? + + done +done + +rm -rf cert.pem +rm -rf sf9.pem diff --git a/tests/scripts/cli-test.sh b/tests/scripts/cli-test.sh new file mode 100755 index 0000000..e03f36a --- /dev/null +++ b/tests/scripts/cli-test.sh @@ -0,0 +1,6 @@ +#!/bin/bash + +chmod a+x tests/scripts/*.sh + +echo "======== CLI Test suite ========" +./tests/scripts/yubico-piv-tool.sh diff --git a/tests/scripts/func.sh b/tests/scripts/func.sh new file mode 100755 index 0000000..ef17273 --- /dev/null +++ b/tests/scripts/func.sh @@ -0,0 +1,38 @@ +#!/bin/bash + +OK="\033[32mok\033[0m" +FAIL="\033[31mfail\033[0m" + +READER="u" + +piv() { + yubico-piv-tool -r${READER} -a$@ +} + +gen_and_check() { + e=$(piv generate -s$2 -A$1 -opublic.pem 2>&1) + test $? -eq 0 && echo -n "." || exit $? + grep -q "Successfully generated a new private key" <<< $e && echo -n "." || exit $? + e=$(piv status 2>&1) + e=${e//$'\t'/} + e=${e//$'\n'/} + test $? -eq 0 && echo -n "." || exit $? + grep -q "Slot $2:Algorithm:$1" <<< $e && echo -n "." || exit $? +} +delete_key() { + piv delete-key -s$2 > /dev/null 2>&1 + test $? -eq 0 && echo -n "." || exit $? + piv delete-cert -s$2 > /dev/null 2>&1 + test $? -eq 0 && echo -n "." || exit $? + e=$(piv status 2>&1) + test $? -eq 0 && echo -n "." || exit $? + q=$(grep -q "Slot $2: Algorithm: $1" <<< $e) + test $? -eq 1 && echo -n "." || exit $? + rm -rf public.pem +} +gen_and_delete() { + gen_and_check $1 $2 + test $? -eq 0 && echo -n "." || exit $? + delete_key $1 $2 + test $? -eq 0 && echo -n "." || exit $? +} diff --git a/tests/scripts/keygen.sh b/tests/scripts/keygen.sh new file mode 100755 index 0000000..4edfc93 --- /dev/null +++ b/tests/scripts/keygen.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +source ./tests/scripts/func.sh + +algs=("RSA1024" "RSA2048" "ECCP256" "ECCP384") +slots=("9a" "9c" "9d" "9e" "82" "83" "84" "85" "86" "87" "88" "89" "8a" "8b" "8c" "8d" "8e" "8f" "90" "91" "92" "93" "94" "95") +for alg in ${algs[*]}; do + for slot in ${slots[*]}; do + echo -n " Test ${alg} in slot ${slot}... " + gen_and_delete ${alg} $slot && echo -e ".\t${OK}" || exit $? + done +done diff --git a/tests/scripts/signatures.sh b/tests/scripts/signatures.sh new file mode 100755 index 0000000..3a93c02 --- /dev/null +++ b/tests/scripts/signatures.sh @@ -0,0 +1,46 @@ +#!/bin/bash + +source ./tests/scripts/func.sh + +algs=("RSA1024" "RSA2048" "ECCP256" "ECCP384") +slots=("9a" "9c" "9d" "9e" "82" "83" "84" "85" "86" "87" "88" "89" "8a" "8b" "8c" "8d" "8e" "8f" "90" "91" "92" "93" "94" "95") +for alg in ${algs[*]}; do + for slot in ${slots[*]}; do + echo " Test signature with ${alg} in slot ${slot}" + echo -n " Keygen... " + gen_and_check $alg $slot && echo -e ".\t${OK}" || exit $? + + echo -n " Test request certificate... " + e=$(piv verify -arequest -P123456 -s$slot -S'/CN=bar/OU=test/O=example.com/' -ipublic.pem -ocert.pem 2>&1) + test $? -eq 0 && echo -n "." || exit $? + grep -q "Successfully verified PIN" <<< $e && echo -n "." || exit $? + grep -q "Successfully generated a certificate request" <<< $e && echo -e ".\t${OK}" || exit $? + + echo -n " OpenSSL verify request... " + e=$(openssl req -verify -in cert.pem 2>&1) + test $? -eq 0 && echo -n "." || exit $? + grep -q " OK" <<< $e && echo -e ".\t${OK}" || exit $? + + echo -n " Test self-signed certificate... " + e=$(piv verify -aselfsign -P123456 -s$slot -S'/CN=bar/OU=test/O=example.com/' -ipublic.pem -ocert.pem 2>&1) + test $? -eq 0 && echo -n "." || exit $? + grep -q "Successfully verified PIN" <<< $e && echo -n "." || exit $? + grep -q "Successfully generated a new self signed certificate" <<< $e && echo -e ".\t${OK}" || exit $? + + echo -n " Test signature... " + e=$(piv verify-pin -atest-signature -s$slot -P123456 -icert.pem 2>&1) + test $? -eq 0 && echo -n "." || exit $? + grep -q "Successful" <<< $e && echo -e ".\t${OK}" || exit $? + + echo -n " OpenSSL verify cert... " + e=$(openssl verify -CAfile cert.pem cert.pem 2>&1) + test $? -eq 0 && echo -n "." || exit $? + grep -q ": OK" <<< $e && echo -e ".\t${OK}" || exit $? + + echo -n " Key deletion... " + delete_key $alg $slot && echo -e ".\t${OK}" || exit $? + + done +done + +rm -rf cert.pem diff --git a/tests/scripts/version.sh b/tests/scripts/version.sh new file mode 100755 index 0000000..5715a01 --- /dev/null +++ b/tests/scripts/version.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +source ./tests/scripts/func.sh + +# Get version +echo -n " Test version... " +e=$(piv version 2>&1) +test $? -eq 0 && echo -n "." || exit $? +grep -q "Application version" <<< $e && echo -n "." || exit $? +grep -q " found" <<< $e && echo -e ".\t${OK}" || exit $? diff --git a/tests/scripts/yubico-piv-test.sh b/tests/scripts/yubico-piv-test.sh new file mode 100755 index 0000000..1f8b197 --- /dev/null +++ b/tests/scripts/yubico-piv-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/yubico-piv-tool.sh b/tests/scripts/yubico-piv-tool.sh new file mode 100755 index 0000000..a4230a4 --- /dev/null +++ b/tests/scripts/yubico-piv-tool.sh @@ -0,0 +1,30 @@ +#!/bin/bash + +source ./tests/scripts/func.sh +echo "==== Test version ====" +./tests/scripts/version.sh +test $? -eq 0 || { + echo -e "\t${FAIL}" + exit 1 +} + +echo "==== Test asymmetric keygen ====" +./tests/scripts/keygen.sh +test $? -eq 0 || { + echo -e "\t${FAIL}" + exit 1 +} + +echo "==== Test self-signed certificates ====" +./tests/scripts/signatures.sh +test $? -eq 0 || { + echo -e "\t${FAIL}" + exit 1 +} + +echo "==== Test attestation ====" +./tests/scripts/attestation.sh +test $? -eq 0 || { + echo -e "\t${FAIL}" + exit 1 +} diff --git a/tests/start-up-and-test.sh b/tests/start-up-and-test.sh index f3fb9be..c17c958 100755 --- a/tests/start-up-and-test.sh +++ b/tests/start-up-and-test.sh @@ -1,7 +1,30 @@ -#!/bin/bash -eu +#!/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 & -sleep 2 -rm -rf memory.flash -./build_in_docker/pico_openpgp > /dev/null & +test $? -eq 0 && echo -e "${OK}" || { + echo -e "${FAIL}" + exit 1 +} +sleep 1 +rm -f memory.flash +echo -n "Start Pico OpenPGP..." +./build_in_docker/pico_openpgp > /dev/null 2>&1 & +test $? -eq 0 && echo -n "." || fail +sleep 1 +ATR="3b:da:18:ff:81:b1:fe:75:1f:03:00:31:f5:73:c0:01:60:00:90:00:1c" +e=$(opensc-tool -an 2>&1) +grep -q "${ATR}" <<< $e && echo -n "." || fail +test $? -eq 0 && echo -e "${OK}" || fail + pytest tests -W ignore::DeprecationWarning + +./tests/scripts/cli-test.sh