yubihsm-shell-2.8.0/0000755000175100017510000000000015221003605013706 5ustar runnerrunneryubihsm-shell-2.8.0/resources/0000755000175100017510000000000015221003515015720 5ustar runnerrunneryubihsm-shell-2.8.0/resources/tests/0000755000175100017510000000000015221003515017062 5ustar runnerrunneryubihsm-shell-2.8.0/resources/tests/bash/0000755000175100017510000000000015221003515017777 5ustar runnerrunneryubihsm-shell-2.8.0/resources/tests/bash/reg.dat0000644000175100017510000000264015221003515021250 0ustar runnerrunnerZ355tsD9teEqE1c5Viy90V1J6S9/vFJVofKeCQ2ssvwwgfT7fHp54KPc4fpZKn3Y1ZRdNBkfxFVu7e1bMpL1vCxOsIwtKGnIShx42Te7iVo9oFBzjomisnRmauAx+drsFX2T0HPdQnexo+uZ8cXQ1LfOPfI80fHfnnZ97aC3YYtomxv4ieCqQNzn17pUhP/QBUHvr3huq63+1CQ7P5iHPq4/HzmQmA8zbeYPMgRxX3r7DMF8GphgsJRU/sFJC3IL2XhYVoR/j5WgzG4ugPz2001wefAO3JOe7nryNTrnl+BbD0CcvF5u7i9bfME5pZTnkqsz7o3Wu+kXAb+LGwVyQt1KRtEAAAAcc3NoLXJzYS1jZXJ0LXYwMUBvcGVuc3NoLmNvbQAAACCboUHYTJF015XKlH4MqI+aaPJePR7MbI2teXDYvVKUhAAAAAMBAAEAAAEBAK3EX7uFmuRyX/X3eGz+Mn7EyLn/76taYJzPP4WXd0KftRV2Y0TqAK8qvQUOReMaloQzRqRgxhbnuQP/l8Zz4eXKpE8jEFvlJng+HZbvYCGW3oMOjLBjN1c0zy1zM8tjxw9LAYSXD8vtvaa77owR1Jive5PB4kNQ9zF+UCyukOAeuqcDI43W8XVIjBmxaUOIKQxy5hF6anXdXlUFf/mtD2WM+tmT60hhW1JT9T8l+49et9XywWTJpYDLoz8c6JuBq92aDfR+MKdZM46MR96JKxP1AQpSXSjWktWt3WPnFcVhHHi8D6ZO1VQA2PDOTqOWZq9FY3EFqi1PQDo/2B5QOGkAAAAAAAAAAAAAAAEAAAAPdXNlckB5dWJpY28uY29tAAAACAAAAAR1c2VyAAAAAGd+eIoAAAAAZ38GVgAAAAAAAACCAAAAFXBlcm1pdC1YMTEtZm9yd2FyZGluZwAAAAAAAAAXcGVybWl0LWFnZW50LWZvcndhcmRpbmcAAAAAAAAAFnBlcm1pdC1wb3J0LWZvcndhcmRpbmcAAAAAAAAACnBlcm1pdC1wdHkAAAAAAAAADnBlcm1pdC11c2VyLXJjAAAAAAAAAAAAAAEXAAAAB3NzaC1yc2EAAAADAQABAAABAQCtRLg8mAY0p1CiXxrdTttMMXAI0BAdLMWe4xHbgll2zOSkVWl2z/+Bbb1MNxPOzGrahp6hI8kumeTmq976LY2+6An1grKrvmGHmBP8GmlCKl43hXMsYE+lWrFVoXuZvL6XYe0w09GEdswvVmoHbpARMRY+x03xq/uUNL91J0qYdscndQVpvv0vbRCEq31yBnMXznaj1vhs99SX9SENa6HBwzt6a1ezhPo7bvLbKi5sxAOYJlkgceK0X8Do/v9IUGV0gMRrouky/88SSiKN/8+PGqDUgVFs0Ntq9YcibWVdzGgUQ6G4nKlEIyYDJIn+9NXze6mV1PJ0yJNLYAyVUWBRyubihsm-shell-2.8.0/resources/tests/bash/test_hmackey.sh0000755000175100017510000000720415221003515023021 0ustar runnerrunner#!/bin/bash set -u if [ "$#" -ne 1 ]; then BIN="yubihsm-shell" else BIN=$1 # path to the yubico-piv-tool command line tool fi if [ -e yubihsm-shell_test_dir ]; then rm -rf yubihsm-shell_test_dir fi mkdir yubihsm-shell_test_dir; cd yubihsm-shell_test_dir echo test signing data > data.txt test () { set +e $1 > output.txt 2>&1 ret=$? if [ $ret -ne 0 ]; then echo $1 cat output.txt rm output.txt exit 1 else echo "$2 ... OK!" rm output.txt fi set -e } test_with_resp () { set +e $1 > resp.txt 2>&1 ret=$? if [ $ret -ne 0 ]; then echo $1 cat resp.txt rm resp.txt exit 1 else echo "$2 ... OK!" fi set -e } set -e echo "====================== HMAC keys ===================== " echo "------------- hmac-sha1" test_with_resp "$BIN -p password -a generate-hmac-key -i 0 -l hmackey -d 1,2,3 -c sign-hmac -A hmac-sha1" " Generate key" keyid=$(tail -1 resp.txt | awk '{print $4}') test "$BIN -p password -a get-object-info -i $keyid -t hmac-key" " Get object info" info=$($BIN -p password -a get-object-info -i $keyid -t hmac-key 2> /dev/null) test "echo $info | grep \"id: $keyid\"" " Object info contains correct ID" test "echo $info | grep \"type: hmac-key\"" " Object info contains correct type" test "echo $info | grep \"algorithm: hmac-sha1\"" " Object info contains correct algorithm" test "echo $info | grep 'label: \"hmackey\"'" " Object info contains correct label" test "echo $info | grep \"domains: 1:2:3\"" " Object info contains correct domains" test "echo $info | grep \"origin: generated\"" " Object info contains correct origin" test "echo $info | grep \"capabilities: sign-hmac\"" " Object info contains correct capabilities" #$BIN -p password -a sign-hmac -i $keyid --in data.txt test "$BIN -p password -a delete-object -i $keyid -t hmac-key" " Delete key" echo "------------- hmac-sha256" test_with_resp "$BIN -p password -a generate-hmac-key -i 0 -l hmackey -d 1,2,3 -c sign-hmac -A hmac-sha256" " Generate key" keyid=$(tail -1 resp.txt | awk '{print $4}') test "$BIN -p password -a get-object-info -i $keyid -t hmac-key" " Get object info" info=$($BIN -p password -a get-object-info -i $keyid -t hmac-key 2> /dev/null) test "echo $info | grep \"algorithm: hmac-sha256\"" " Object info contains correct algorithm" #$BIN -p password -a sign-hmac -i $keyid --in data.txt test "$BIN -p password -a delete-object -i $keyid -t hmac-key" " Delete key" echo "------------- hmac-sha384" test_with_resp "$BIN -p password -a generate-hmac-key -i 0 -l hmackey -d 1,2,3 -c sign-hmac -A hmac-sha384" " Generate key" keyid=$(tail -1 resp.txt | awk '{print $4}') test "$BIN -p password -a get-object-info -i $keyid -t hmac-key" " Get object info" info=$($BIN -p password -a get-object-info -i $keyid -t hmac-key 2> /dev/null) test "echo $info | grep \"algorithm: hmac-sha384\"" " Object info contains correct algorithm" #$BIN -p password -a sign-hmac -i $keyid --in data.txt test "$BIN -p password -a delete-object -i $keyid -t hmac-key" " Delete key" echo "------------- hmac-sha512" test_with_resp "$BIN -p password -a generate-hmac-key -i 0 -l hmackey -d 1,2,3 -c sign-hmac -A hmac-sha512" " Generate key" keyid=$(tail -1 resp.txt | awk '{print $4}') test "$BIN -p password -a get-object-info -i $keyid -t hmac-key" " Get object info" info=$($BIN -p password -a get-object-info -i $keyid -t hmac-key 2> /dev/null) test "echo $info | grep \"algorithm: hmac-sha512\"" " Object info contains correct algorithm" #$BIN -p password -a sign-hmac -i $keyid --in data.txt test "$BIN -p password -a delete-object -i $keyid -t hmac-key" " Delete key" cd .. rm -rf yubihsm-shell_test_dir set +e yubihsm-shell-2.8.0/resources/tests/bash/opensc_test.bats0000644000175100017510000005774615221003515023223 0ustar runnerrunnerload 'test_helper/bats-support/load' load 'test_helper/bats-assert/load' setup_file() { echo "--- Configuration via Environment Variables ---" >&3 echo "MODULE: Path to the PKCS#11 module, default /usr/local/lib/yubihsm_pkcs11.so (Linux) or /usr/local/lib/yubihsm_pkcs11.dylib (Mac)" >&3 echo "EDIT_PATH: (Windows/Msys only) Path to directory where pkcs11-tool.exe and libyubihsm is located if not in default locations. Use delimiter ":". Example: export EDIT_PATH='C:\Path\To\OpenSC\tools:C:\Path\To\YubiHSM Shell\bin" >&3 echo "CONFIG_FILE: Path to the yubihsm_pkcs11 configuration file, default is in current directory" >&3 echo "-----------------------------------------------" >&3 echo "" >&3 export EC_CURVES="secp224r1 secp256r1 secp384r1 secp521r1 secp256k1" export pkcs11="pkcs11-tool" export RSA_LENGTHS="2048 3072 4096" export YUBIHSM_PKCS11_CONF=${CONFIG_FILE:-"$(pwd)/yubihsm_pkcs11.conf"} local default_module_path="/usr/local/lib/yubihsm_pkcs11.dylib" #Default path for Mac os=$(uname -o) if ! { [[ "$os" == "Linux" ]] && grep -q 'Fedora' /etc/os-release 2>/dev/null; }; then EC_CURVES="$EC_CURVES brainpoolP256r1 brainpoolP384r1 brainpoolP512r1" fi if [[ "$os" == "Msys" ]]; then echo "This script expects that the pkcs11-tool from OpenSC is installed under "C:\Program Files\OpenSC Project\OpenSC\tools" and that libyubihsm.dll is installed under "C:\Program Files\Yubico\YubiHSM Shell\bin" " echo "If that is not the case, please point to the correct locations via the environment variable EDIT_PATH" pkcs11="pkcs11-tool.exe" default_module_path="C:\Program Files\Yubico\YubiHSM Shell\bin\pkcs11\yubihsm_pkcs11.dll" export MSYS2_ARG_CONV_EXCL=* if ! [ -z "$EDIT_PATH" ]; then export PATH="$PATH:"$EDIT_PATH"" else # Adds pkcs11-tool and yubihsm-shell to PATH export PATH="$PATH:C:\Program Files\OpenSC Project\OpenSC\tools:C:\Program Files\Yubico\YubiHSM Shell\bin" fi elif [[ "$os" == "GNU/LINUX" ]]; then default_module_path="/usr/local/lib/yubihsm_pkcs11.so" fi export MODULE=${MODULE:-$default_module_path} echo "--------------------------------" >&3 echo "Variables Check:" >&3 echo "Using module: "$MODULE"" >&3 echo "Using pkcs11: "$pkcs11"" >&3 echo "EC Curves to test: "$EC_CURVES"" >&3 echo "RSA Lengths to test: "$RSA_LENGTHS"" >&3 echo "--------------------------------" >&3 echo "These tests will reset your HSM" >&3 echo "Press Enter to continue or Ctrl-C + enter to abort" >&3 read -p "" if [ -e yubihsm-shell_test_dir ]; then rm -rf yubihsm-shell_test_dir fi mkdir yubihsm-shell_test_dir; cd yubihsm-shell_test_dir echo "test signing data" > data.txt } @test "EC Curve tests" { for curve in $EC_CURVES; do echo "Testing curve: "$curve"" >&3 #Generate key run "$pkcs11" --module "$MODULE" --login --pin 0001password --keypairgen --id 1 --key-type EC:"$curve" assert_success "Generate EC key with curve $curve" run "$pkcs11" --module "$MODULE" --login --pin 0001password --read-object --id 1 --type pubkey --output-file pubkey.der assert_success "Get public key of generated key" #Sign with generated key run "$pkcs11" --module "$MODULE" --sign --pin 0001password --id 1 -m ECDSA-SHA1 --signature-format openssl -i data.txt -o data.sig assert_success "Sign with generated key and ECDSA-SHA1" run openssl dgst -sha1 -verify pubkey.der -signature data.sig data.txt assert_success "Verify signature with openssl" run "$pkcs11" --module "$MODULE" --sign --pin 0001password --id 1 -m ECDSA-SHA256 --signature-format openssl -i data.txt -o data.sig assert_success "Sign with generated key and ECDSA-SHA256" run openssl dgst -sha256 -verify pubkey.der -signature data.sig data.txt assert_success "Verify signature with openssl" run "$pkcs11" --module "$MODULE" --sign --pin 0001password --id 1 -m ECDSA-SHA384 --signature-format openssl -i data.txt -o data.sig assert_success "Sign with generated key and ECDSA-SHA384" run openssl dgst -sha384 -verify pubkey.der -signature data.sig data.txt assert_success "Verify signature with openssl" run "$pkcs11" --module "$MODULE" --sign --pin 0001password --id 1 -m ECDSA-SHA512 --signature-format openssl -i data.txt -o data.sig assert_success "Sign with generated key and ECDSA-SHA512" run openssl dgst -sha512 -verify pubkey.der -signature data.sig data.txt assert_success "Verify signature with openssl" #Import key run openssl ecparam -name "$curve" -genkey -noout -out keypair.pem assert_success "Generate keypair with curve "$curve" using openssl" run "$pkcs11" --module "$MODULE" --login --pin 0001password --write-object keypair.pem --id 2 --type privkey --usage-sign assert_success "Import EC key with curve "$curve"" run "$pkcs11" --module "$MODULE" --login --pin 0001password --read-object --id 2 --type pubkey --output-file pubkey_imported.der assert_success "Get public key of imported key" #Sign with imported key run "$pkcs11" --module "$MODULE" --sign --pin 0001password --id 2 -m ECDSA-SHA1 --signature-format openssl -i data.txt -o data.sig assert_success "Sign with imported key and ECDSA-SHA1" run openssl dgst -sha1 -verify pubkey_imported.der -signature data.sig data.txt assert_success "Verify signature with openssl" run "$pkcs11" --module "$MODULE" --sign --pin 0001password --id 2 -m ECDSA-SHA256 --signature-format openssl -i data.txt -o data.sig assert_success "Sign with imported key and ECDSA-SHA256" run openssl dgst -sha256 -verify pubkey_imported.der -signature data.sig data.txt assert_success "Verify signature with openssl" run "$pkcs11" --module "$MODULE" --sign --pin 0001password --id 2 -m ECDSA-SHA384 --signature-format openssl -i data.txt -o data.sig assert_success "Sign with imported key and ECDSA-SHA384" run openssl dgst -sha384 -verify pubkey_imported.der -signature data.sig data.txt assert_success "Verify signature with openssl" run "$pkcs11" --module "$MODULE" --sign --pin 0001password --id 2 -m ECDSA-SHA512 --signature-format openssl -i data.txt -o data.sig assert_success "Sign with imported key and ECDSA-SHA512" run openssl dgst -sha512 -verify pubkey_imported.der -signature data.sig data.txt assert_success "Verify signature with openssl" #Derive ECDH run "$pkcs11" --module "$MODULE" --login --pin 0001password --derive --id 1 --input-file pubkey_imported.der --output-file ecdh_pkcs11.bin assert_success "Derive ECDH usin pkcs11-tool" run openssl pkeyutl -derive -inkey keypair.pem -peerkey pubkey.der -out ecdh_openssl.bin assert_success "Derive ECDH using openssl" run cmp ecdh_pkcs11.bin ecdh_openssl.bin assert_success "Compare the derived ECDH keys" run rm ecdh_pkcs11.bin ecdh_openssl.bin assert_success "Delete ECDH keys" # Requires writable session? yubihs-pkcs11 only allowed regular users #run "$pkcs11" --module ""$MODULE"" --login --pin 0001password --test-ec --id 200 --key-type EC:secp256r1 # assert_success "Test EC key with yubihs-pkcs11" #Delete keys run "$pkcs11" --module "$MODULE" --login --pin 0001password --delete-object --id 1 --type privkey assert_success "Delete generated key" run "$pkcs11" --module "$MODULE" --login --pin 0001password --delete-object --id 2 --type privkey assert_success "Delete imported key" done } @test "RSA Key tests" { run openssl dgst -sha1 -binary -out data.sha1 data.txt assert_success "Hash data with SHA1 and OpenSSL" run openssl dgst -sha256 -binary -out data.sha256 data.txt assert_success "Hash data with SHA256 and OpenSSL" run openssl dgst -sha384 -binary -out data.sha384 data.txt assert_success "Hash data with SHA384 and OpenSSL" run openssl dgst -sha512 -binary -out data.sha512 data.txt assert_success "Hash data with SHA512 and OpenSSL" for length in $RSA_LENGTHS; do echo "Testing RSA key with length: "$length"" >&3 #Generate key run "$pkcs11" --module "$MODULE" --login --pin 0001password --keypairgen --id 1 --key-type rsa:"$length" --usage-sign --usage-decrypt assert_success "Generate RSA key with length "$length"" run "$pkcs11" --module "$MODULE" --login --pin 0001password --read-object --id 1 --type pubkey --output-file pubkey.der assert_success "Get public key of generated key" #Sign with generated key and RSA-PKCS run "$pkcs11" --module "$MODULE" --sign --pin 0001password --id 1 -m SHA1-RSA-PKCS -i data.txt -o data.sig assert_success "Sign with generated key and SHA1-RSA-PKCS" run openssl dgst -sha1 -verify pubkey.der -signature data.sig data.txt assert_success "Verify signature with openssl" run "$pkcs11" --module "$MODULE" --sign --pin 0001password --id 1 -m SHA256-RSA-PKCS -i data.txt -o data.sig assert_success "Sign with generated key and SHA256-RSA-PKCS" run openssl dgst -sha256 -verify pubkey.der -signature data.sig data.txt assert_success "Verify signature with openssl" run "$pkcs11" --module "$MODULE" --sign --pin 0001password --id 1 -m SHA384-RSA-PKCS -i data.txt -o data.sig assert_success "Sign with generated key and SHA384-RSA-PKCS" run openssl dgst -sha384 -verify pubkey.der -signature data.sig data.txt assert_success "Verify signature with openssl" run "$pkcs11" --module "$MODULE" --sign --pin 0001password --id 1 -m SHA512-RSA-PKCS -i data.txt -o data.sig assert_success "Sign with generated key and SHA512-RSA-PKCS" run openssl dgst -sha512 -verify pubkey.der -signature data.sig data.txt assert_success "Verify signature with openssl" #Sign with generated key and RSA-PSS run "$pkcs11" --module "$MODULE" --sign --pin 0001password --id 1 -m SHA1-RSA-PKCS-PSS -i data.txt -o data.sig assert_success "Sign with generated key and SHA1-RSA-PKCS-PSS" run openssl pkeyutl -verify -in data.sha1 -sigfile data.sig -pkeyopt rsa_padding_mode:pss -pubin -inkey pubkey.der -pkeyopt rsa_pss_saltlen:-1 -pkeyopt digest:sha1 assert_success "Verify signature with openssl" run "$pkcs11" --module "$MODULE" --sign --pin 0001password --id 1 -m SHA256-RSA-PKCS-PSS -i data.txt -o data.sig assert_success "Sign with generated key and SHA256-RSA-PKCS-PSS" run openssl pkeyutl -verify -in data.sha256 -sigfile data.sig -pkeyopt rsa_padding_mode:pss -pubin -inkey pubkey.der -pkeyopt rsa_pss_saltlen:-1 -pkeyopt digest:sha256 assert_success "Verify signature with openssl" run "$pkcs11" --module "$MODULE" --sign --pin 0001password --id 1 -m SHA384-RSA-PKCS-PSS -i data.txt -o data.sig assert_success "Sign with generated key and SHA384-RSA-PKCS-PSS" run openssl pkeyutl -verify -in data.sha384 -sigfile data.sig -pkeyopt rsa_padding_mode:pss -pubin -inkey pubkey.der -pkeyopt rsa_pss_saltlen:-1 -pkeyopt digest:sha384 assert_success "Verify signature with openssl" run "$pkcs11" --module "$MODULE" --sign --pin 0001password --id 1 -m SHA512-RSA-PKCS-PSS -i data.txt -o data.sig assert_success "Sign with generated key and SHA512-RSA-PKCS-PSS" run openssl pkeyutl -verify -in data.sha512 -sigfile data.sig -pkeyopt rsa_padding_mode:pss -pubin -inkey pubkey.der -pkeyopt rsa_pss_saltlen:-1 -pkeyopt digest:sha512 assert_success "Verify signature with openssl" #Decrypt with generated key and PKCS1v15 run openssl rsautl -encrypt -inkey pubkey.der -pubin -in data.txt -out data.enc assert_success "Encrypt with openssl using PKCS1v15" run "$pkcs11" --module "$MODULE" --decrypt --pin 0001password --id 1 -m RSA-PKCS --input-file data.enc --output-file data.dec assert_success "Decrypt using generated key" run cmp data.dec data.txt assert_success "Compare decrypted data with plain text data" run rm data.enc data.dec assert_success "Delete test data" #Decrypt with generated key and OAEP run openssl pkeyutl -encrypt -pubin -inkey pubkey.der -pkeyopt rsa_padding_mode:oaep -pkeyopt rsa_oaep_md:sha1 -pkeyopt rsa_mgf1_md:sha1 -in data.txt -out data.enc assert_success "Encrypt with OpenSSL using OAEP and SHA1" run "$pkcs11" --module "$MODULE" --decrypt --pin 0001password --id 1 -m RSA-PKCS-OAEP --hash-algorithm=SHA-1 --input-file data.enc --output-file data.dec assert_success "Decrypt using generated key with SHA1" run cmp data.dec data.txt assert_success "Compare decrypted data for SHA1" run rm data.enc data.dec assert_success "Delete test data for SHA1" run openssl pkeyutl -encrypt -pubin -inkey pubkey.der -pkeyopt rsa_padding_mode:oaep -pkeyopt rsa_oaep_md:sha256 -pkeyopt rsa_mgf1_md:sha256 -in data.txt -out data.enc assert_success "Encrypt with OpenSSL using OAEP and SHA256" run "$pkcs11" --module "$MODULE" --decrypt --pin 0001password --id 1 -m RSA-PKCS-OAEP --hash-algorithm=SHA256 --input-file data.enc --output-file data.dec assert_success "Decrypt using generated key with SHA256" run cmp data.dec data.txt assert_success "Compare decrypted data for SHA256" run rm data.enc data.dec assert_success "Delete test data for SHA256" run openssl pkeyutl -encrypt -pubin -inkey pubkey.der -pkeyopt rsa_padding_mode:oaep -pkeyopt rsa_oaep_md:sha384 -pkeyopt rsa_mgf1_md:sha384 -in data.txt -out data.enc assert_success "Encrypt with OpenSSL using OAEP and SHA384" run "$pkcs11" --module "$MODULE" --decrypt --pin 0001password --id 1 -m RSA-PKCS-OAEP --hash-algorithm=SHA384 --input-file data.enc --output-file data.dec assert_success "Decrypt using generated key with SHA384" run cmp data.dec data.txt assert_success "Compare decrypted data for SHA384" run rm data.enc data.dec assert_success "Delete test data for SHA384" run openssl pkeyutl -encrypt -pubin -inkey pubkey.der -pkeyopt rsa_padding_mode:oaep -pkeyopt rsa_oaep_md:sha512 -pkeyopt rsa_mgf1_md:sha512 -in data.txt -out data.enc assert_success "Encrypt with OpenSSL using OAEP and SHA512" run "$pkcs11" --module "$MODULE" --decrypt --pin 0001password --id 1 -m RSA-PKCS-OAEP --hash-algorithm=SHA512 --input-file data.enc --output-file data.dec assert_success "Decrypt using generated key with SHA512" run cmp data.dec data.txt assert_success "Compare decrypted data for SHA512" run rm data.enc data.dec assert_success "Delete test data for SHA512" #Import key run openssl genrsa -out keypair.pem "$length" assert_success "Generate key with openssl" run "$pkcs11" --module "$MODULE" --login --pin 0001password --write-object keypair.pem --id 2 --type privkey --usage-sign --usage-decrypt assert_success "Import RSA"$length" key" run "$pkcs11" --module "$MODULE" --login --pin 0001password --read-object --id 2 --type pubkey --output-file pubkey_imported.der assert_success "Get public key of imported key" # Sign with imported key and PKCS run "$pkcs11" --module "$MODULE" --sign --pin 0001password --id 2 -m SHA1-RSA-PKCS -i data.txt -o data.sig assert_success "Sign with imported key and SHA1-RSA-PKCS" run openssl dgst -sha1 -verify pubkey_imported.der -signature data.sig data.txt assert_success "Verify signature with openssl" run "$pkcs11" --module "$MODULE" --sign --pin 0001password --id 2 -m SHA256-RSA-PKCS -i data.txt -o data.sig assert_success "Sign with imported key and SHA256-RSA-PKCS" run openssl dgst -sha256 -verify pubkey_imported.der -signature data.sig data.txt assert_success "Verify signature with openssl" run "$pkcs11" --module "$MODULE" --sign --pin 0001password --id 2 -m SHA384-RSA-PKCS -i data.txt -o data.sig assert_success "Sign with imported key and SHA384-RSA-PKCS" run openssl dgst -sha384 -verify pubkey_imported.der -signature data.sig data.txt assert_success "Verify sgnature with openssl" run "$pkcs11" --module "$MODULE" --sign --pin 0001password --id 2 -m SHA512-RSA-PKCS -i data.txt -o data.sig assert_success "Sign with imported key and SHA512-RSA-PKCS" run openssl dgst -sha512 -verify pubkey_imported.der -signature data.sig data.txt assert_success "Verify signature with openssl" # Sign with imported key and RSA-PSS run "$pkcs11" --module "$MODULE" --sign --pin 0001password --id 2 -m SHA1-RSA-PKCS-PSS -i data.txt -o data.sig assert_success "Sign with imported key and SHA1-RSA-PKCS-PSS" run openssl pkeyutl -verify -in data.sha1 -sigfile data.sig -pkeyopt rsa_padding_mode:pss -pubin -inkey pubkey_imported.der -pkeyopt rsa_pss_saltlen:-1 -pkeyopt digest:sha1 assert_success "Verify signature with openssl" run "$pkcs11" --module "$MODULE" --sign --pin 0001password --id 2 -m SHA256-RSA-PKCS-PSS -i data.txt -o data.sig assert_success "Sign with imported key and SHA256-RSA-PKCS-PSS" run openssl pkeyutl -verify -in data.sha256 -sigfile data.sig -pkeyopt rsa_padding_mode:pss -pubin -inkey pubkey_imported.der -pkeyopt rsa_pss_saltlen:-1 -pkeyopt digest:sha256 assert_success "Verify signature with openssl" run "$pkcs11" --module "$MODULE" --sign --pin 0001password --id 2 -m SHA384-RSA-PKCS-PSS -i data.txt -o data.sig assert_success "Sign with imported key and SHA384-RSA-PKCS-PSS" run openssl pkeyutl -verify -in data.sha384 -sigfile data.sig -pkeyopt rsa_padding_mode:pss -pubin -inkey pubkey_imported.der -pkeyopt rsa_pss_saltlen:-1 -pkeyopt digest:sha384 assert_success "Verify signature with openssl" run "$pkcs11" --module "$MODULE" --sign --pin 0001password --id 2 -m SHA512-RSA-PKCS-PSS -i data.txt -o data.sig assert_success "Sign with imported key and SHA512-RSA-PKCS-PSS" run openssl pkeyutl -verify -in data.sha512 -sigfile data.sig -pkeyopt rsa_padding_mode:pss -pubin -inkey pubkey_imported.der -pkeyopt rsa_pss_saltlen:-1 -pkeyopt digest:sha512 assert_success "Verify signature with openssl" # Decrypt with imported key and PKCS1v15 run openssl rsautl -encrypt -inkey pubkey_imported.der -pubin -in data.txt -out data.enc assert_success "Encryp with openssl using PKCS1v15" run "$pkcs11" --module "$MODULE" --decrypt --pin 0001password --id 2 -m RSA-PKCS --input-file data.enc --output-file data.dec assert_success "Decrypt using imported key" run cmp data.dec data.txt assert_success "Compare decrypted data with plain text data" run rm data.enc data.dec assert_success "Delete test data" # Decrypt with imported key and OAEP run openssl pkeyutl -encrypt -pubin -inkey pubkey_imported.der -pkeyopt rsa_padding_mode:oaep -pkeyopt rsa_oaep_md:sha1 -pkeyopt rsa_mgf1_md:sha1 -in data.txt -out data.enc assert_success "Encrypt with openssl using OAEP and SHA1" run openssl pkeyutl -encrypt -pubin -inkey pubkey_imported.der -pkeyopt rsa_padding_mode:oaep -pkeyopt rsa_oaep_md:sha1 -pkeyopt rsa_mgf1_md:sha1 -in data.txt -out data.enc assert_success "Encrypt with OpenSSL using OAEP and SHA1" run "$pkcs11" --module "$MODULE" --decrypt --pin 0001password --id 2 -m RSA-PKCS-OAEP --hash-algorithm=SHA-1 --input-file data.enc --output-file data.dec assert_success "Decrypt using imported key with SHA1" run cmp data.dec data.txt assert_success "Compare decrypted data for SHA1" run rm data.enc data.dec assert_success "Delete test data for SHA1" run openssl pkeyutl -encrypt -pubin -inkey pubkey_imported.der -pkeyopt rsa_padding_mode:oaep -pkeyopt rsa_oaep_md:sha256 -pkeyopt rsa_mgf1_md:sha256 -in data.txt -out data.enc assert_success "Encrypt with OpenSSL using OAEP and SHA256" run "$pkcs11" --module "$MODULE" --decrypt --pin 0001password --id 2 -m RSA-PKCS-OAEP --hash-algorithm=SHA256 --input-file data.enc --output-file data.dec assert_success "Decrypt using imported key with SHA256" run cmp data.dec data.txt assert_success "Compare decrypted data for SHA256" run rm data.enc data.dec assert_success "Delete test data for SHA256" run openssl pkeyutl -encrypt -pubin -inkey pubkey_imported.der -pkeyopt rsa_padding_mode:oaep -pkeyopt rsa_oaep_md:sha384 -pkeyopt rsa_mgf1_md:sha384 -in data.txt -out data.enc assert_success "Encrypt with OpenSSL using OAEP and SHA384" run "$pkcs11" --module "$MODULE" --decrypt --pin 0001password --id 2 -m RSA-PKCS-OAEP --hash-algorithm=SHA384 --input-file data.enc --output-file data.dec assert_success "Decrypt using imported key with SHA384" run cmp data.dec data.txt assert_success "Compare decrypted data for SHA384" run rm data.enc data.dec assert_success "Delete test data for SHA384" run openssl pkeyutl -encrypt -pubin -inkey pubkey_imported.der -pkeyopt rsa_padding_mode:oaep -pkeyopt rsa_oaep_md:sha512 -pkeyopt rsa_mgf1_md:sha512 -in data.txt -out data.enc assert_success "Encrypt with OpenSSL using OAEP and SHA512" run "$pkcs11" --module "$MODULE" --decrypt --pin 0001password --id 2 -m RSA-PKCS-OAEP --hash-algorithm=SHA512 --input-file data.enc --output-file data.dec assert_success "Decrypt using imported key with SHA512" run cmp data.dec data.txt assert_success "Compare decrypted data for SHA512" run rm data.enc data.dec assert_success "Delete test data for SHA512" #Delete keys run "$pkcs11" --module "$MODULE" --login --pin 0001password --delete-object --id 1 --type privkey assert_success "Delete generated key" run "$pkcs11" --module "$MODULE" --login --pin 0001password --delete-object --id 2 --type privkey assert_success "Delete generated key" done run rm data.sha1 data.sha256 data.sha384 data.sha512 data.sig data.txt assert_success "Delete test data" run rm keypair.pem pubkey.der pubkey_imported.der assert_success "Delete key files" } @test "Compress x509 Certificate" { run openssl req -x509 -newkey rsa:4096 -out too_large_cert.der -outform DER -sha256 -days 3650 -nodes -subj '/C=01/ST=01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567/L=01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567/O=0123456789012345678901234567890123456789012345678901234567890123/OU=0123456789012345678901234567890123456789012345678901234567890123' > /dev/null 2>&1 assert_success "Generating a large certificate" run "$pkcs11" --module "$MODULE" --login --pin 0001password --write-object too_large_cert.der --id 6464 --type cert assert_success "Import large x509 certificate" run "$pkcs11" --module "$MODULE" --login --pin 0001password --read-object --id 6464 --type cert --output-file too_large_cert_out.der assert_success "Get imported certificate" run cmp too_large_cert.der too_large_cert_out.der assert_success "Compare read certificate with the one imported" run "$pkcs11" --module "$MODULE" --login --pin 0001password --delete-object --id 6464 --type cert assert_success "Delete certificate" run rm too_large_cert.der too_large_cert_out.der privkey.pem assert_success "Delete files" } yubihsm-shell-2.8.0/resources/tests/bash/test_wrapkey.sh0000755000175100017510000005677215221003515023100 0ustar runnerrunner#!/bin/bash set -u if [ "$#" -ne 1 ]; then BIN="yubihsm-shell" else BIN=$1 # path to the yubico-piv-tool command line tool fi if [ -e yubihsm-shell_test_dir ]; then rm -rf yubihsm-shell_test_dir fi mkdir yubihsm-shell_test_dir; cd yubihsm-shell_test_dir echo test signing data > data.txt test () { set +e $1 > output.txt 2>&1 ret=$? if [ $ret -ne 0 ]; then echo $1 cat output.txt rm output.txt exit 1 else echo "$2 ... OK!" rm output.txt fi set -e } cmp_str_content () { set +e if [[ $1 == *"$2"* ]]; then echo " $3 in object info ... OK!" else echo "Wrong $3" echo $1 exit 1 fi set -e } test_with_resp () { set +e $1 > resp.txt 2>&1 ret=$? if [ $ret -ne 0 ]; then echo $1 cat resp.txt rm resp.txt exit 1 else echo "$2 ... OK!" fi set -e } set -e test "$BIN -p password -a reset" " Reset device" sleep 3 eckey=100 aeskey=200 test "$BIN -p password -a generate-asymmetric-key -i $eckey -l eckey -d 1 -c exportable-under-wrap,sign-ecdsa -A ecp224" " Generate EC Key to wrap" info=$($BIN -p password -a get-object-info -i $eckey -t asymmetric-key 2> /dev/null) cmp_str_content "$info" "sequence: 0" "Sequence" cmp_str_content "$info" "origin: generated" "Origin" echo "**********************************" echo " aes128-ccm-wrap" echo "**********************************" echo "=== Generate key" test_with_resp "$BIN -p password -a generate-wrap-key -i 0 -l wrapkey -d 1 -c export-wrapped,import-wrapped --delegated sign-ecdsa,exportable-under-wrap -A aes128-ccm-wrap" " Generate wrap key" keyid=$(tail -1 resp.txt | awk '{print $4}') info=$($BIN -p password -a get-object-info -i $keyid -t wrap-key 2> /dev/null) cmp_str_content "$info" "algorithm: aes128-ccm-wrap" "Algorithm" cmp_str_content "$info" "length: 24" "Length" echo "=== Import key" test_with_resp "$BIN -p password -a get-pseudo-random --count 16" " Get random 16 bytes" wrapkey=$(tail -1 resp.txt | awk '{print $0}') test_with_resp "$BIN -p password -a put-wrap-key -i 0 -l imported_wrapkey -d 1 -c export-wrapped,import-wrapped --delegated sign-ecdsa,exportable-under-wrap --in=$wrapkey" " Import wrap key" import_keyid=$(tail -1 resp.txt | awk '{print $4}') info=$($BIN -p password -a get-object-info -i $import_keyid -t wrap-key 2> /dev/null) cmp_str_content "$info" "algorithm: aes128-ccm-wrap" "Algorithm" cmp_str_content "$info" "length: 24" "Length" cmp_str_content "$info" "origin: imported" "Origin" echo "=== Wrap and unwrap objects with generated wrap key" test "$BIN -p password -a get-wrapped --wrap-id $keyid -i 100 -t asymmetric-key --out key.gen_wrapped" " Wrap EC key" test "$BIN -p password -a delete-object -i $eckey -t asymmetric-key" " Delete EC key" test "$BIN -p password -a put-wrapped --wrap-id $keyid --in key.gen_wrapped" " Wrap EC key" info=$($BIN -p password -a get-object-info -i $eckey -t asymmetric-key 2> /dev/null) cmp_str_content "$info" "sequence: 1" "Sequence" cmp_str_content "$info" "origin: generated:imported_wrapped" "Origin" cmp_str_content "$info" "capabilities: exportable-under-wrap:sign-ecdsa" "Capabilities" test "$BIN -p password -a sign-ecdsa -i $eckey -A ecdsa-sha1 --in data.txt" " Perform signature with imported wrapped key" echo "=== Wrap and unwrap objects with imported wrap key" test "$BIN -p password -a get-wrapped --wrap-id $import_keyid -i 100 -t asymmetric-key --out key.imp_wrapped" " Wrap EC key" test "$BIN -p password -a delete-object -i $eckey -t asymmetric-key" " Delete EC key" test "$BIN -p password -a put-wrapped --wrap-id $import_keyid --in key.imp_wrapped" " Wrap EC key" info=$($BIN -p password -a get-object-info -i $eckey -t asymmetric-key 2> /dev/null) cmp_str_content "$info" "sequence: 2" "Sequence" cmp_str_content "$info" "origin: generated:imported_wrapped" "Origin" cmp_str_content "$info" "capabilities: exportable-under-wrap:sign-ecdsa" "Capabilities" test "$BIN -p password -a sign-ecdsa -i $eckey -A ecdsa-sha1 --in data.txt" " Perform signature with imported wrapped key" echo "=== Clean up" test "$BIN -p password -a delete-object -i $keyid -t wrap-key" " Delete generated wrap key" test "$BIN -p password -a delete-object -i $import_keyid -t wrap-key" " Delete imported wrap key" rm key.gen_wrapped rm key.imp_wrapped echo "**********************************" echo " aes192-ccm-wrap" echo "**********************************" echo "=== Generate key" test_with_resp "$BIN -p password -a generate-wrap-key -i 0 -l wrapkey -d 1 -c export-wrapped,import-wrapped --delegated sign-ecdsa,exportable-under-wrap -A aes192-ccm-wrap" " Generate wrap key" keyid=$(tail -1 resp.txt | awk '{print $4}') info=$($BIN -p password -a get-object-info -i $keyid -t wrap-key 2> /dev/null) cmp_str_content "$info" "algorithm: aes192-ccm-wrap" "Algorithm" cmp_str_content "$info" "length: 32" "Length" echo "=== Import key" test_with_resp "$BIN -p password -a get-pseudo-random --count 24" " Get random 16 bytes" wrapkey=$(tail -1 resp.txt | awk '{print $0}') test_with_resp "$BIN -p password -a put-wrap-key -i 0 -l imported_wrapkey -d 1 -c export-wrapped,import-wrapped --delegated sign-ecdsa,exportable-under-wrap --in=$wrapkey" " Import wrap key" import_keyid=$(tail -1 resp.txt | awk '{print $4}') info=$($BIN -p password -a get-object-info -i $import_keyid -t wrap-key 2> /dev/null) cmp_str_content "$info" "algorithm: aes192-ccm-wrap" "Algorithm" cmp_str_content "$info" "length: 32" "Length" cmp_str_content "$info" "origin: imported" "Origin" echo "=== Wrap and unwrap objects with generated wrap key" test "$BIN -p password -a get-wrapped --wrap-id $keyid -i 100 -t asymmetric-key --out key.gen_wrapped" " Wrap EC key" test "$BIN -p password -a delete-object -i $eckey -t asymmetric-key" " Delete EC key" test "$BIN -p password -a put-wrapped --wrap-id $keyid --in key.gen_wrapped" " Wrap EC key" info=$($BIN -p password -a get-object-info -i $eckey -t asymmetric-key 2> /dev/null) cmp_str_content "$info" "sequence: 3" "Sequence" cmp_str_content "$info" "origin: generated:imported_wrapped" "Origin" cmp_str_content "$info" "capabilities: exportable-under-wrap:sign-ecdsa" "Capabilities" test "$BIN -p password -a sign-ecdsa -i $eckey -A ecdsa-sha1 --in data.txt" " Perform signature with imported wrapped key" echo "=== Wrap and unwrap objects with imported wrap key" test "$BIN -p password -a get-wrapped --wrap-id $import_keyid -i 100 -t asymmetric-key --out key.imp_wrapped" " Wrap EC key" test "$BIN -p password -a delete-object -i $eckey -t asymmetric-key" " Delete EC key" test "$BIN -p password -a put-wrapped --wrap-id $import_keyid --in key.imp_wrapped" " Wrap EC key" info=$($BIN -p password -a get-object-info -i $eckey -t asymmetric-key 2> /dev/null) cmp_str_content "$info" "sequence: 4" "Sequence" cmp_str_content "$info" "origin: generated:imported_wrapped" "Origin" cmp_str_content "$info" "capabilities: exportable-under-wrap:sign-ecdsa" "Capabilities" test "$BIN -p password -a sign-ecdsa -i $eckey -A ecdsa-sha1 --in data.txt" " Perform signature with imported wrapped key" echo "=== Clean up" test "$BIN -p password -a delete-object -i $keyid -t wrap-key" " Delete generated wrap key" test "$BIN -p password -a delete-object -i $import_keyid -t wrap-key" " Delete imported wrap key" rm key.gen_wrapped rm key.imp_wrapped echo "**********************************" echo " aes256-ccm-wrap" echo "**********************************" echo "=== Generate key" test_with_resp "$BIN -p password -a generate-wrap-key -i 0 -l wrapkey -d 1 -c export-wrapped,import-wrapped --delegated sign-ecdsa,exportable-under-wrap -A aes256-ccm-wrap" " Generate wrap key" keyid=$(tail -1 resp.txt | awk '{print $4}') info=$($BIN -p password -a get-object-info -i $keyid -t wrap-key 2> /dev/null) cmp_str_content "$info" "algorithm: aes256-ccm-wrap" "Algorithm" cmp_str_content "$info" "length: 40" "Length" echo "=== Import key" test_with_resp "$BIN -p password -a get-pseudo-random --count 32" " Get random 16 bytes" wrapkey=$(tail -1 resp.txt | awk '{print $0}') test_with_resp "$BIN -p password -a put-wrap-key -i 0 -l imported_wrapkey -d 1 -c export-wrapped,import-wrapped --delegated sign-ecdsa,exportable-under-wrap --in=$wrapkey" " Import wrap key" import_keyid=$(tail -1 resp.txt | awk '{print $4}') info=$($BIN -p password -a get-object-info -i $import_keyid -t wrap-key 2> /dev/null) cmp_str_content "$info" "algorithm: aes256-ccm-wrap" "Algorithm" cmp_str_content "$info" "length: 40" "Length" cmp_str_content "$info" "origin: imported" "Origin" echo "=== Wrap and unwrap objects with generated wrap key" test "$BIN -p password -a get-wrapped --wrap-id $keyid -i 100 -t asymmetric-key --out key.gen_wrapped" " Wrap EC key" test "$BIN -p password -a delete-object -i $eckey -t asymmetric-key" " Delete EC key" test "$BIN -p password -a put-wrapped --wrap-id $keyid --in key.gen_wrapped" " Wrap EC key" info=$($BIN -p password -a get-object-info -i $eckey -t asymmetric-key 2> /dev/null) cmp_str_content "$info" "sequence: 5" "Sequence" cmp_str_content "$info" "origin: generated:imported_wrapped" "Origin" cmp_str_content "$info" "capabilities: exportable-under-wrap:sign-ecdsa" "Capabilities" test "$BIN -p password -a sign-ecdsa -i $eckey -A ecdsa-sha1 --in data.txt" " Perform signature with imported wrapped key" echo "=== Wrap and unwrap objects with imported wrap key" test "$BIN -p password -a get-wrapped --wrap-id $import_keyid -i 100 -t asymmetric-key --out key.imp_wrapped" " Wrap EC key" test "$BIN -p password -a delete-object -i $eckey -t asymmetric-key" " Delete EC key" test "$BIN -p password -a put-wrapped --wrap-id $import_keyid --in key.imp_wrapped" " Wrap EC key" info=$($BIN -p password -a get-object-info -i $eckey -t asymmetric-key 2> /dev/null) cmp_str_content "$info" "sequence: 6" "Sequence" cmp_str_content "$info" "origin: generated:imported_wrapped" "Origin" cmp_str_content "$info" "capabilities: exportable-under-wrap:sign-ecdsa" "Capabilities" test "$BIN -p password -a sign-ecdsa -i $eckey -A ecdsa-sha1 --in data.txt" " Perform signature with imported wrapped key" echo "=== Clean up" test "$BIN -p password -a delete-object -i $keyid -t wrap-key" " Delete generated wrap key" test "$BIN -p password -a delete-object -i $import_keyid -t wrap-key" " Delete imported wrap key" rm key.gen_wrapped rm key.imp_wrapped device_info=$($BIN -p password -a get-device-info 2> /dev/null) if [[ "$device_info" != *"aes-kwp"* ]]; then test "$BIN -p password -a delete-object -i $eckey -t asymmetric-key" " Delete EC key" exit 0 fi aes_enabled=false if [[ "$device_info" == *"aes-cbc"* ]]; then aes_enabled=true test "$BIN -p password -a generate-symmetric-key -i $aeskey -l aeskey -d 1 -c exportable-under-wrap,encrypt-cbc,decrypt-cbc -A aes128" " Generate AES Key to wrap" test_with_resp "$BIN -p password -a get-pseudo-random --count 16" " Get random 16 bytes for IV" iv=$(tail -1 resp.txt | awk '{print $0}') test_with_resp "$BIN -p password -a get-pseudo-random --count 32" " Get random 32 bytes to test encryption" data=$(tail -1 resp.txt | awk '{print $0}') fi RSA_KEYSIZE=("2048" "3072" "4096") seq_ec=6 seq_aes=0 for k in ${RSA_KEYSIZE[@]}; do echo "**********************************" echo " RSA$k" echo "**********************************" echo "=== Generate RSA wrap keys" test_with_resp "$BIN -p password -a generate-wrap-key -i 0 -l wrapkey -c import-wrapped --delegated exportable-under-wrap,sign-ecdsa,encrypt-cbc,decrypt-cbc -A rsa$k" " Generate RSA wrap key" keyid=$(tail -1 resp.txt | awk '{print $4}') info=$($BIN -p password -a get-object-info -i $keyid -t wrap-key 2> /dev/null) cmp_str_content "$info" "algorithm: rsa$k" "Algorithm" cmp_str_content "$info" "origin: generated" "Origin" test "$BIN -p password -a get-public-key -i $keyid -t wrap-key --out public_wrapkey.pem" " Export rsa public wrap key" test "$BIN -p password -a put-public-wrapkey -i $keyid -c export-wrapped --delegated exportable-under-wrap,sign-ecdsa,encrypt-cbc,decrypt-cbc --in public_wrapkey.pem" " Import RSA public wrap key" rm public_wrapkey.pem echo "=== Wrap and unwrap EC object with generated RSA wrap key" test "$BIN -p password -a get-rsa-wrapped --wrap-id $keyid -i $eckey -t asymmetric-key --out rsawrapped.object" " Export wrapped EC object" test "$BIN -p password -a delete-object -i $eckey -t asymmetric-key" " Delete EC key" test "$BIN -p password -a put-rsa-wrapped --wrap-id $keyid --in rsawrapped.object" " Import wrapped EC object" info=$($BIN -p password -a get-object-info -i $eckey -t asymmetric-key 2> /dev/null) seq_ec=$((seq_ec+1)) cmp_str_content "$info" "sequence: $seq_ec" "Sequence" cmp_str_content "$info" "capabilities: exportable-under-wrap:sign-ecdsa" "Capabilities" test "$BIN -p password -a sign-ecdsa -i $eckey -A ecdsa-sha1 --in data.txt" " Perform signature with imported wrapped EC key" rm rsawrapped.object echo "=== Wrap and unwrap EC key material with generated RSA wrap key" test "$BIN -p password -a get-rsa-wrapped-key --wrap-id $keyid -i $eckey -t asymmetric-key --oaep rsa-oaep-sha1 --mgf1 mgf1-sha384 --out rsawrapped.key" " Export wrapped EC key material" test "$BIN -p password -a delete-object -i $eckey -t asymmetric-key" " Delete EC key" test "$BIN -p password -a put-rsa-wrapped-key --wrap-id $keyid -i $eckey -t asymmetric-key -A ecp224 -c exportable-under-wrap,sign-ecdsa --oaep rsa-oaep-sha1 --mgf1 mgf1-sha384 --in rsawrapped.key" " Import wrapped EC key material" info=$($BIN -p password -a get-object-info -i $eckey -t asymmetric-key 2> /dev/null) seq_ec=$((seq_ec+1)) cmp_str_content "$info" "sequence: $seq_ec" "Sequence" cmp_str_content "$info" "origin: imported:imported_wrapped" "Origin" cmp_str_content "$info" "capabilities: exportable-under-wrap:sign-ecdsa" "Capabilities" test "$BIN -p password -a sign-ecdsa -i $eckey -A ecdsa-sha1 --in data.txt" " Perform signature with imported wrapped EC key" rm rsawrapped.key if [[ "$aes_enabled" = true ]]; then echo "=== Wrap and unwrap AES object with generated RSA wrap key" test "$BIN -p password -a get-rsa-wrapped --wrap-id $keyid -i $aeskey -t symmetric-key --out rsawrapped.object" " Export wrapped AES object" test "$BIN -p password -a delete-object -i $aeskey -t symmetric-key" " Delete AES key" test "$BIN -p password -a put-rsa-wrapped --wrap-id $keyid --in rsawrapped.object" " Import wrapped AES object" info=$($BIN -p password -a get-object-info -i $aeskey -t symmetric-key 2> /dev/null) seq_aes=$((seq_aes+1)) cmp_str_content "$info" "sequence: $seq_aes" "Sequence" cmp_str_content "$info" "capabilities: decrypt-cbc:encrypt-cbc:exportable-under-wrap" "Capabilities" test "$BIN -p password -a encrypt-aescbc -i $aeskey --iv $iv --in $data --out data.enc" " Perform encryption with imported wrapped AES key" test_with_resp "$BIN -p password -a decrypt-aescbc -i $aeskey --iv $iv --in data.enc" " Perform decryption with imported wrapped AES key" data_dec=$(tail -1 resp.txt | awk '{print $0}') if [[ "$data" == "$data_dec" ]]; then echo " Compare decrypted data to plain text ... OK!" else $BIN -p password -a decrypt-aescbc -i $aeskey --iv $iv --in data.enc --out data.dec exit fi rm rsawrapped.object rm data.enc echo "=== Wrap and unwrap AES key material with generated RSA wrap key" test "$BIN -p password -a get-rsa-wrapped-key --wrap-id $keyid -i $aeskey -t symmetric-key --oaep rsa-oaep-sha384 --mgf1 mgf1-sha1 --out rsawrapped.key" " Export wrapped AES key material" test "$BIN -p password -a delete-object -i $aeskey -t symmetric-key" " Delete AES key" test "$BIN -p password -a put-rsa-wrapped-key --wrap-id $keyid -i $aeskey -t symmetric-key -A aes128 -c exportable-under-wrap,decrypt-cbc,encrypt-cbc --oaep rsa-oaep-sha384 --mgf1 mgf1-sha1 --in rsawrapped.key" " Import wrapped AES key material" info=$($BIN -p password -a get-object-info -i $aeskey -t symmetric-key 2> /dev/null) seq_aes=$((seq_aes+1)) cmp_str_content "$info" "sequence: $seq_aes" "Sequence" cmp_str_content "$info" "origin: imported:imported_wrapped" "Origin" cmp_str_content "$info" "capabilities: decrypt-cbc:encrypt-cbc:exportable-under-wrap" "Capabilities" test "$BIN -p password -a sign-ecdsa -i $eckey -A ecdsa-sha1 --in data.txt" " Perform signature with imported wrapped EC key" test "$BIN -p password -a encrypt-aescbc -i $aeskey --iv $iv --in $data --out data.enc" " Perform encryption with imported wrapped AES key" test_with_resp "$BIN -p password -a decrypt-aescbc -i $aeskey --iv $iv --in data.enc" " Perform decryption with imported wrapped AES key" data_dec=$(tail -1 resp.txt | awk '{print $0}') if [[ "$data" == "$data_dec" ]]; then echo " Compare decrypted data to plain text ... OK!" else $BIN -p password -a decrypt-aescbc -i $aeskey --iv $iv --in data.enc --out data.dec exit fi rm rsawrapped.key rm data.enc fi echo "=== Import RSA wrap keys" test "openssl genrsa -out keypair.pem $k" " Generate RSA key with OpenSSL" test "openssl rsa -in keypair.pem -pubout -out key.pub" " Extract public key from OpenSSL generated keypair" test_with_resp "$BIN -p password -a put-rsa-wrapkey -i 0 -d 1 -c import-wrapped --delegated exportable-under-wrap,sign-ecdsa,encrypt-cbc,decrypt-cbc --in keypair.pem" " Import RSA wrap key" import_keyid=$(tail -1 resp.txt | awk '{print $4}') info=$($BIN -p password -a get-object-info -i $import_keyid -t wrap-key 2> /dev/null) cmp_str_content "$info" "algorithm: rsa$k" "Algorithm" cmp_str_content "$info" "origin: imported" "Origin" test "$BIN -p password -a put-public-wrapkey -i $import_keyid -c export-wrapped --delegated exportable-under-wrap,sign-ecdsa,encrypt-cbc,decrypt-cbc --in key.pub" " Import RSA public wrap key" rm keypair.pem rm key.pub echo "=== Wrap and unwrap EC object with imported RSA wrap key" test "$BIN -p password -a get-rsa-wrapped --wrap-id $import_keyid -i $eckey -t asymmetric-key --out rsawrapped.object" " Export wrapped EC object" test "$BIN -p password -a delete-object -i $eckey -t asymmetric-key" " Delete EC key" test "$BIN -p password -a put-rsa-wrapped --wrap-id $import_keyid --in rsawrapped.object" " Import wrapped EC object" info=$($BIN -p password -a get-object-info -i $eckey -t asymmetric-key 2> /dev/null) seq_ec=$((seq_ec+1)) cmp_str_content "$info" "sequence: $seq_ec" "Sequence" cmp_str_content "$info" "origin: imported:imported_wrapped" "Origin" cmp_str_content "$info" "capabilities: exportable-under-wrap:sign-ecdsa" "Capabilities" test "$BIN -p password -a sign-ecdsa -i $eckey -A ecdsa-sha1 --in data.txt" " Perform signature with imported wrapped EC key" rm rsawrapped.object echo "=== Wrap and unwrap EC key material with imported RSA wrap key" test "$BIN -p password -a get-rsa-wrapped-key --wrap-id $import_keyid -i $eckey -t asymmetric-key --oaep rsa-oaep-sha512 --mgf1 mgf1-sha512 --out rsawrapped.key" " Export wrapped EC key material" test "$BIN -p password -a delete-object -i $eckey -t asymmetric-key" " Delete EC key" test "$BIN -p password -a put-rsa-wrapped-key --wrap-id $import_keyid -i $eckey -t asymmetric-key -A ecp224 -c exportable-under-wrap,sign-ecdsa --oaep rsa-oaep-sha512 --mgf1 mgf1-sha512 --in rsawrapped.key" " Import wrapped EC key material" info=$($BIN -p password -a get-object-info -i $eckey -t asymmetric-key 2> /dev/null) seq_ec=$((seq_ec+1)) cmp_str_content "$info" "sequence: $seq_ec" "Sequence" cmp_str_content "$info" "origin: imported:imported_wrapped" "Origin" cmp_str_content "$info" "capabilities: exportable-under-wrap:sign-ecdsa" "Capabilities" test "$BIN -p password -a sign-ecdsa -i $eckey -A ecdsa-sha1 --in data.txt" " Perform signature with imported wrapped EC key" rm rsawrapped.key if [[ "$aes_enabled" = true ]]; then echo "=== Wrap and unwrap AES object with imported RSA wrap key" test "$BIN -p password -a get-rsa-wrapped --wrap-id $import_keyid -i $aeskey -t symmetric-key --out rsawrapped.object" " Export wrapped AES object" test "$BIN -p password -a delete-object -i $aeskey -t symmetric-key" " Delete AES key" test "$BIN -p password -a put-rsa-wrapped --wrap-id $import_keyid --in rsawrapped.object" " Import wrapped AES object" info=$($BIN -p password -a get-object-info -i $aeskey -t symmetric-key 2> /dev/null) seq_aes=$((seq_aes+1)) cmp_str_content "$info" "sequence: $seq_aes" "Sequence" cmp_str_content "$info" "origin: imported:imported_wrapped" "Origin" cmp_str_content "$info" "capabilities: decrypt-cbc:encrypt-cbc:exportable-under-wrap" "Capabilities" test "$BIN -p password -a encrypt-aescbc -i $aeskey --iv $iv --in $data --out data.enc" " Perform encryption with imported wrapped AES key" test_with_resp "$BIN -p password -a decrypt-aescbc -i $aeskey --iv $iv --in data.enc" " Perform decryption with imported wrapped AES key" data_dec=$(tail -1 resp.txt | awk '{print $0}') if [[ "$data" == "$data_dec" ]]; then echo " Compare decrypted data to plain text ... OK!" else $BIN -p password -a decrypt-aescbc -i $aeskey --iv $iv --in data.enc --out data.dec exit fi rm rsawrapped.object rm data.enc echo "=== Wrap and unwrap AES key material with imported RSA wrap key" test "$BIN -p password -a get-rsa-wrapped-key --wrap-id $import_keyid -i $aeskey -t symmetric-key --oaep rsa-oaep-sha1 --mgf1 mgf1-sha384 --out rsawrapped.key" " Export wrapped AES key material" test "$BIN -p password -a delete-object -i $aeskey -t symmetric-key" " Delete AES key" test "$BIN -p password -a put-rsa-wrapped-key --wrap-id $import_keyid -i $aeskey -t symmetric-key -A aes128 -c exportable-under-wrap,decrypt-cbc,encrypt-cbc --oaep rsa-oaep-sha1 --mgf1 mgf1-sha384 --in rsawrapped.key" " Import wrapped AES key material" info=$($BIN -p password -a get-object-info -i $aeskey -t symmetric-key 2> /dev/null) seq_aes=$((seq_aes+1)) cmp_str_content "$info" "sequence: $seq_aes" "Sequence" cmp_str_content "$info" "origin: imported:imported_wrapped" "Origin" cmp_str_content "$info" "capabilities: decrypt-cbc:encrypt-cbc:exportable-under-wrap" "Capabilities" test "$BIN -p password -a sign-ecdsa -i $eckey -A ecdsa-sha1 --in data.txt" " Perform signature with imported wrapped EC key" test "$BIN -p password -a encrypt-aescbc -i $aeskey --iv $iv --in $data --out data.enc" " Perform encryption with imported wrapped AES key" test_with_resp "$BIN -p password -a decrypt-aescbc -i $aeskey --iv $iv --in data.enc" " Perform decryption with imported wrapped AES key" data_dec=$(tail -1 resp.txt | awk '{print $0}') if [[ "$data" == "$data_dec" ]]; then echo " Compare decrypted data to plain text ... OK!" else $BIN -p password -a decrypt-aescbc -i $aeskey --iv $iv --in data.enc --out data.dec exit fi rm rsawrapped.key rm data.enc fi echo "=== Clean up" test "$BIN -p password -a delete-object -i $keyid -t wrap-key" " Delete generated RSA wrap key" test "$BIN -p password -a delete-object -i $keyid -t public-wrap-key" " Delete generated RSA public wrap key" test "$BIN -p password -a delete-object -i $import_keyid -t wrap-key" " Delete imported RSA wrap key" test "$BIN -p password -a delete-object -i $import_keyid -t public-wrap-key" " Delete imported RSA public wrap key" done #test "$BIN -p password -a delete-object -i $eckey -t asymmetric-key" " Delete EC key" #if [[ "$aes_enabled" = true ]]; then # test "$BIN -p password -a delete-object -i $aeskey -t symmetric-key" " Delete AES key" #fi test "$BIN -p password -a reset" " Reset device" cd .. rm -rf yubihsm-shell_test_dir set +e yubihsm-shell-2.8.0/resources/tests/bash/test_otpaeadkey.sh0000755000175100017510000000646615221003515023537 0ustar runnerrunner#!/bin/bash set -u if [ "$#" -ne 1 ]; then BIN="yubihsm-shell" else BIN=$1 # path to the yubico-piv-tool command line tool fi if [ -e yubihsm-shell_test_dir ]; then rm -rf yubihsm-shell_test_dir fi mkdir yubihsm-shell_test_dir; cd yubihsm-shell_test_dir echo test signing data > data.txt test () { set +e $1 > output.txt 2>&1 ret=$? if [ $ret -ne 0 ]; then echo $1 cat output.txt rm output.txt exit 1 else echo "$2 ... OK!" rm output.txt fi set -e } test_with_resp () { set +e $1 > resp.txt 2>&1 ret=$? if [ $ret -ne 0 ]; then echo $1 cat resp.txt rm resp.txt exit 1 else echo "$2 ... OK!" fi set -e } set -e echo "====================== AEAD keys ===================== " echo "------------- AEAD Key 128" test_with_resp "$BIN -p password -a generate-otp-aead-key -i 0 -l aeadkey -d 1,2,3 -c randomize-otp-aead -A aes128-yubico-otp --nonce 0x01020304" " Generate key" keyid=$(tail -1 resp.txt | awk '{print $5}') test "$BIN -p password -a get-object-info -i $keyid -t otp-aead-key" " Get object info" info=$($BIN -p password -a get-object-info -i $keyid -t otp-aead-key 2> /dev/null) test "echo $info | grep \"id: $keyid\"" " Object info contains correct ID" test "echo $info | grep \"type: otp-aead-key\"" " Object info contains correct type" test "echo $info | grep \"algorithm: aes128-yubico-otp\"" " Object info contains correct algorithm" test "echo $info | grep 'label: \"aeadkey\"'" " Object info contains correct label" test "echo $info | grep \"domains: 1:2:3\"" " Object info contains correct domains" test "echo $info | grep \"origin: generated\"" " Object info contains correct origin" test "echo $info | grep \"capabilities: randomize-otp-aead\"" " Object info contains correct capabilities" test "$BIN -p password -a randomize-otp-aead -i $keyid" " Randomize OTP AEAD" test "$BIN -p password -a delete-object -i $keyid -t otp-aead-key" " Delete key" echo "------------- AEAD Key 128" test_with_resp "$BIN -p password -a generate-otp-aead-key -i 0 -l aeadkey -d 1,2,3 -c randomize-otp-aead -A aes192-yubico-otp --nonce 0x01020304" " Generate key" keyid=$(tail -1 resp.txt | awk '{print $5}') test "$BIN -p password -a get-object-info -i $keyid -t otp-aead-key" " Get object info" info=$($BIN -p password -a get-object-info -i $keyid -t otp-aead-key 2> /dev/null) test "echo $info | grep \"algorithm: aes192-yubico-otp\"" " Object info contains correct algorithm" test "$BIN -p password -a randomize-otp-aead -i $keyid" " Randomize OTP AEAD" test "$BIN -p password -a delete-object -i $keyid -t otp-aead-key" " Delete key" echo "------------- AEAD Key 256" test_with_resp "$BIN -p password -a generate-otp-aead-key -i 0 -l aeadkey -d 1,2,3 -c randomize-otp-aead -A aes256-yubico-otp --nonce 0x01020304" " Generate key" keyid=$(tail -1 resp.txt | awk '{print $5}') test "$BIN -p password -a get-object-info -i $keyid -t otp-aead-key" " Get object info" info=$($BIN -p password -a get-object-info -i $keyid -t otp-aead-key 2> /dev/null) test "echo $info | grep \"algorithm: aes256-yubico-otp\"" " Object info contains correct algorithm" test "$BIN -p password -a randomize-otp-aead -i $keyid" " Randomize OTP AEAD" test "$BIN -p password -a delete-object -i $keyid -t otp-aead-key" " Delete key" cd .. rm -rf yubihsm-shell_test_dir set +e yubihsm-shell-2.8.0/resources/tests/bash/test_edkey.sh0000755000175100017510000000553615221003515022507 0ustar runnerrunner#!/bin/bash set -u if [ "$#" -ne 1 ]; then BIN="yubihsm-shell" else BIN=$1 # path to the yubico-piv-tool command line tool fi if [ -e yubihsm-shell_test_dir ]; then rm -rf yubihsm-shell_test_dir fi mkdir yubihsm-shell_test_dir; cd yubihsm-shell_test_dir echo test signing data > data.txt test () { set +e $1 > output.txt 2>&1 ret=$? if [ $ret -ne 0 ]; then echo $1 cat output.txt rm output.txt exit 1 else echo "$2 ... OK!" rm output.txt fi set -e } set -e echo "====================== ED keys ===================== " # Generate echo "Generate key:" test "$BIN -p password -a generate-asymmetric-key -i 100 -l \"edKey\" -d 1,2,3 -c sign-eddsa -A ed25519" " Generate key" test "$BIN -p password -a get-object-info -i 100 -t asymmetric-key" " get-object-info" info=$($BIN -p password -a get-object-info -i 100 -t asymmetric-key 2>&1) test "echo $info | grep \"id: 0x0064\"" " Object info contains correct ID" test "echo $info | grep \"type: asymmetric-key\"" " Object info contains correct type" test "echo $info | grep \"algorithm: ed25519\"" " Object info contains correct algorithm" test "echo $info | grep 'label: \"edKey\"'" " Object info contains correct label" test "echo $info | grep \"domains: 1:2:3\"" " Object info contains correct domains" test "echo $info | grep \"origin: generated\"" " Object info contains correct origin" test "echo $info | grep \"capabilities: sign-eddsa\"" " Object info contains correct capabilities" # Import #ssh-keygen -t ed25519 -C "test@yubihsm.se" -f edkey -N foo123 #$BIN --verbose=5 -p password -a put-asymmetric-key -i 200 -l "edKey_imported" -d "5" -c "sign-eddsa" --in=edkey # Get public key echo "Get public key:" test "$BIN -p password -a get-public-key -i 100" " Get public key to stdout" $BIN -p password -a get-public-key -i 100 > edkey1.pub 2>/dev/null test "$BIN -p password -a get-public-key -i 100 --out edkey2.pub" " Get public key to file" test "cmp edkey1.pub edkey2.pub" " Match public key in stdout and file" # Signing echo "Signing:" test "$BIN -p password -a sign-eddsa -i 100 -A ed25519 --in data.txt" " Sign to stdout" $BIN -p password -a sign-eddsa -i 100 -A ed25519 --in data.txt > data.ed1.sig 2>/dev/null test "$BIN -p password -a sign-eddsa -i 100 -A ed25519 --in data.txt --out data.ed2.sig" " Sign to file" if [[ $(cat data.ed1.sig) != $(cat data.ed2.sig) ]]; then echo "Signature in stdout and file are different" exit 2 fi echo " Matching signature in stdout and file ... OK" # Generating CSR echo "Generating CSR:" test "$BIN -p password -a generate-csr -i 100 -S /CN=test/ --out csr.pem" " Generate CSR with yubihsm-shell" test "openssl req -in csr.pem -verify" " Verify CSR with openssl" # Delete echo "Clean up:" test "$BIN -p password -a delete-object -i 100 -t asymmetric-key" " Delete key" cd .. rm -rf yubihsm-shell_test_dir set +e yubihsm-shell-2.8.0/resources/tests/bash/test_x509template.pem0000644000175100017510000000172515221003515024007 0ustar runnerrunner-----BEGIN CERTIFICATE----- MIICpzCCAY+gAwIBAgIRALnaMgizd13cmPh34E4HNz0wDQYJKoZIhvcNAQELBQAw KjEoMCYGA1UEAwwfWXViaUhTTTIgQXR0ZXN0YXRpb24gKDEzMjAwNTAxKTAgFw0x NzAxMDEwMDAwMDBaGA8yMDcxMTAwNTAwMDAwMFowKDEmMCQGA1UEAwwdWXViaUhT TSBBdHRlc3RhdGlvbiBpZDoweDU2MGQwTjAQBgcqhkjOPQIBBgUrgQQAIQM6AATn 8QLCgsBZlpkoqdMOTbWS/tOiXfI1aOMrUQC+w6rWw8WwEbJ7LjqoPwdWg0DKrXeA 7sAEMUKX4aOBnTCBmjATBgorBgEEAYLECgQBBAUEAwIBAzAUBgorBgEEAYLECgQC BAYCBADJbHUwEgYKKwYBBAGCxAoEAwQEAwIAATATBgorBgEEAYLECgQEBAUDAwAQ kDAZBgorBgEEAYLECgQFBAsDCQAAAAAEAAAIgDASBgorBgEEAYLECgQGBAQCAlYN MBUGCisGAQQBgsQKBAkEBwwFZWNLZXkwDQYJKoZIhvcNAQELBQADggEBAEV/0jl7 ulAmLLiYGV8ELoavjtJ3wmMLyJpSURC8WPO8MucAopIsh0URXKpjLjHQHqscdAbP DyT+/l1VfFS7Fvsz/OXeMP1dYzpoYzw4iyHFkvf5G8k0hxY+BEqBa89MXKGrcDo0 iu0lSusaEJF2zq3PH3hnPIXm9SJDfWcZ7iueA0xGu6miUz3rHklnbPUqaM/omGyV MgAtLOolX7rnW7E3MEkAOII1kbwv8C/NlseKXyECRvAn2reAMH11c/t2BvGMbD81 OGTPZ2OvfNJcPnzy1olxE0Ajew5CrOB2XrOaqhVrNPA4aqpCT3ukMv60m6TXsHnU RdEhPSf0SomH7MQ= -----END CERTIFICATE----- yubihsm-shell-2.8.0/resources/tests/bash/test_rsakey.sh0000755000175100017510000003534715221003515022707 0ustar runnerrunner#!/bin/bash set -u if [ "$#" -ne 1 ]; then BIN="yubihsm-shell" else BIN=$1 # path to the yubihsm-shell command line tool fi if [ -e yubihsm-shell_test_dir ]; then rm -rf yubihsm-shell_test_dir fi mkdir yubihsm-shell_test_dir; cd yubihsm-shell_test_dir echo test signing and decryption data > data.txt test () { set +e $1 > output.txt 2>&1 ret=$? if [ $ret -ne 0 ]; then echo $1 cat output.txt rm output.txt exit 1 else echo " $2 ... OK!" rm output.txt fi set -e } test_with_resp () { set +e $1 > resp.txt 2>&1 ret=$? if [ $ret -ne 0 ]; then echo $1 cat resp.txt rm resp.txt exit 1 else echo " $2 ... OK!" fi set -e } set -e echo "====================== RSA keys ===================== " RSA_KEYSIZE=("2048" "3072" "4096") for k in ${RSA_KEYSIZE[@]}; do echo "**********************************" echo " RSA$k" echo "**********************************" echo "=== Generate key" test_with_resp "$BIN -p password -a generate-asymmetric-key -i 0 -l rsaKey -d 1 -c sign-pkcs,sign-pss,decrypt-pkcs,decrypt-oaep,sign-attestation-certificate -A rsa$k" "Generate key" keyid=$(tail -1 resp.txt | awk '{print $4}') test "$BIN -p password -a get-object-info -i $keyid -t asymmetric-key" "Get object info" info=$($BIN -p password -a get-object-info -i $keyid -t asymmetric-key 2> /dev/null) test "echo $info | grep \"id: $keyid\"" "Object info contains correct ID" test "echo $info | grep \"type: asymmetric-key\"" "Object info contains correct type" test "echo $info | grep \"algorithm: rsa$k\"" "Object info contains correct algorithm" test "echo $info | grep 'label: \"rsaKey\"'" "Object info contains correct label" test "echo $info | grep \"domains: 1\"" "Object info contains correct domains" test "echo $info | grep \"origin: generated\"" "Object info contains correct origin" test "echo $info | grep \"capabilities: decrypt-oaep:decrypt-pkcs:sign-attestation-certificate:sign-pkcs:sign-pss\"" "Object info contains correct capabilities" test "$BIN -p password -a get-public-key -i $keyid --outformat=PEM --out pubkey_rsa$k.pem" "Get public key" echo "=== Import key:" test "openssl genrsa -out rsa$k-keypair.pem $k" "Generate key with OpenSSL" test_with_resp "$BIN -p password -a put-asymmetric-key -i 0 -l rsaKeyImport -d 2 -c sign-pkcs,sign-pss,decrypt-pkcs,decrypt-oaep,sign-attestation-certificate --in=rsa$k-keypair.pem" "Import key" import_keyid=$(tail -1 resp.txt | awk '{print $4}') test "$BIN -p password -a get-object-info -i $import_keyid -t asymmetric-key" "Get object info" info=$($BIN -p password -a get-object-info -i $import_keyid -t asymmetric-key 2> /dev/null) test "echo $info | grep \"id: $import_keyid\"" "Object info contains correct ID" test "echo $info | grep \"type: asymmetric-key\"" "Object info contains correct type" test "echo $info | grep \"algorithm: rsa$k\"" "Object info contains correct algorithm" test "echo $info | grep 'label: \"rsaKeyImport\"'" "Object info contains correct label" test "echo $info | grep \"domains: 2\"" "Object info contains correct domains" test "echo $info | grep \"origin: imported\"" "Object info contains correct origin" test "echo $info | grep \"capabilities: decrypt-oaep:decrypt-pkcs:sign-attestation-certificate:sign-pkcs:sign-pss\"" "Object info contains correct capabilities" test "$BIN -p password -a get-public-key -i $import_keyid --outformat=PEM --out pubkey_rsa$k.imported.pem" "Get public key" echo "=== Signing with generated key:" test "$BIN -p password -a sign-pkcs1v15 -i $keyid -A rsa-pkcs1-sha1 --in data.txt --outformat binary --out data.$k-pkcs1sha1gen.sig" "Sign with rsa-pkcs1-sha1" test "openssl dgst -sha1 -verify pubkey_rsa$k.pem -signature data.$k-pkcs1sha1gen.sig data.txt" "Verify signature with OpenSSL" test "$BIN -p password -a sign-pkcs1v15 -i $keyid -A rsa-pkcs1-sha256 --in data.txt --outformat binary --out data.$k-pkcs1sha256gen.sig" "Sign with rsa-pkcs1-sha256" test "openssl dgst -sha256 -verify pubkey_rsa$k.pem -signature data.$k-pkcs1sha256gen.sig data.txt" "Verify signature with OpenSSL" test "$BIN -p password -a sign-pkcs1v15 -i $keyid -A rsa-pkcs1-sha384 --in data.txt --outformat binary --out data.$k-pkcs1sha384gen.sig" "Sign with rsa-pkcs1-sha384" test "openssl dgst -sha384 -verify pubkey_rsa$k.pem -signature data.$k-pkcs1sha384gen.sig data.txt" "Verify signature with OpenSSL" test "$BIN -p password -a sign-pkcs1v15 -i $keyid -A rsa-pkcs1-sha512 --in data.txt --outformat binary --out data.$k-pkcs1sha512gen.sig" "Sign with rsa-pkcs1-sha512" test "openssl dgst -sha512 -verify pubkey_rsa$k.pem -signature data.$k-pkcs1sha512gen.sig data.txt" "Verify signature with OpenSSL" test "$BIN -p password -a sign-pss -i $keyid -A rsa-pss-sha1 --in data.txt --outformat binary --out data.$k-psssha1gen.sig" "Sign with rsa-pss-sha1" test "openssl dgst -sha1 -binary -out data.sha1 data.txt" "Hash data with OpenSSL" test "openssl pkeyutl -verify -in data.sha1 -sigfile data.$k-psssha1gen.sig -pkeyopt rsa_padding_mode:pss -pubin -inkey pubkey_rsa$k.pem -pkeyopt rsa_pss_saltlen:-1 -pkeyopt digest:sha1" "Verify signature with OpenSSL" test "$BIN -p password -a sign-pss -i $keyid -A rsa-pss-sha256 --in data.txt --outformat binary --out data.$k-psssha256gen.sig" "Sign with rsa-pss-sha256" test "openssl dgst -sha256 -binary -out data.sha256 data.txt" "Hash data with OpenSSL" test "openssl pkeyutl -verify -in data.sha256 -sigfile data.$k-psssha256gen.sig -pkeyopt rsa_padding_mode:pss -pubin -inkey pubkey_rsa$k.pem -pkeyopt rsa_pss_saltlen:-1 -pkeyopt digest:sha256" "Verify signature with OpenSSL" test "$BIN -p password -a sign-pss -i $keyid -A rsa-pss-sha384 --in data.txt --outformat binary --out data.$k-psssha384gen.sig" "Sign with rsa-pss-sha384" test "openssl dgst -sha384 -binary -out data.sha384 data.txt" "Hash data with OpenSSL" test "openssl pkeyutl -verify -in data.sha384 -sigfile data.$k-psssha384gen.sig -pkeyopt rsa_padding_mode:pss -pubin -inkey pubkey_rsa$k.pem -pkeyopt rsa_pss_saltlen:-1 -pkeyopt digest:sha384" "Verify signature with OpenSSL" test "$BIN -p password -a sign-pss -i $keyid -A rsa-pss-sha512 --in data.txt --outformat binary --out data.$k-psssha512gen.sig" "Sign with rsa-pss-sha512" test "openssl dgst -sha512 -binary -out data.sha512 data.txt" "Hash data with OpenSSL" test "openssl pkeyutl -verify -in data.sha512 -sigfile data.$k-psssha512gen.sig -pkeyopt rsa_padding_mode:pss -pubin -inkey pubkey_rsa$k.pem -pkeyopt rsa_pss_saltlen:-1 -pkeyopt digest:sha512" "Verify signature with OpenSSL" echo "=== Signing with imported key:" test "$BIN -p password -a sign-pkcs1v15 -i $import_keyid -A rsa-pkcs1-sha1 --in data.txt --outformat binary --out data.$k-pkcs1sha1import.sig" "Sign with rsa-pkcs1-sha1" test "openssl dgst -sha1 -verify pubkey_rsa$k.imported.pem -signature data.$k-pkcs1sha1import.sig data.txt" "Verify signature with OpenSSL" test "$BIN -p password -a sign-pkcs1v15 -i $import_keyid -A rsa-pkcs1-sha256 --in data.txt --outformat binary --out data.$k-pkcs1sha256import.sig" "Sign with rsa-pkcs1-sha256" test "openssl dgst -sha256 -verify pubkey_rsa$k.imported.pem -signature data.$k-pkcs1sha256import.sig data.txt" "Verify signature with OpenSSL" test "$BIN -p password -a sign-pkcs1v15 -i $import_keyid -A rsa-pkcs1-sha384 --in data.txt --outformat binary --out data.$k-pkcs1sha384import.sig" "Sign with rsa-pkcs1-sha384" test "openssl dgst -sha384 -verify pubkey_rsa$k.imported.pem -signature data.$k-pkcs1sha384import.sig data.txt" "Verify signature with OpenSSL" test "$BIN -p password -a sign-pkcs1v15 -i $import_keyid -A rsa-pkcs1-sha512 --in data.txt --outformat binary --out data.$k-pkcs1sha512import.sig" "Sign with rsa-pkcs1-sha512" test "openssl dgst -sha512 -verify pubkey_rsa$k.imported.pem -signature data.$k-pkcs1sha512import.sig data.txt" "Verify signature with OpenSSL" test "$BIN -p password -a sign-pss -i $import_keyid -A rsa-pss-sha1 --in data.txt --outformat binary --out data.$k-psssha1import.sig" "Sign with rsa-pss-sha1" test "openssl dgst -sha1 -binary -out data.sha1 data.txt" "Hash data with OpenSSL" test "openssl pkeyutl -verify -in data.sha1 -sigfile data.$k-psssha1import.sig -pkeyopt rsa_padding_mode:pss -pubin -inkey pubkey_rsa$k.imported.pem -pkeyopt rsa_pss_saltlen:-1 -pkeyopt digest:sha1" "Verify signature with OpenSSL" test "$BIN -p password -a sign-pss -i $import_keyid -A rsa-pss-sha256 --in data.txt --outformat binary --out data.$k-psssha256import.sig" "Sign with rsa-pss-sha256" test "openssl dgst -sha256 -binary -out data.sha256 data.txt" "Hash data with OpenSSL" test "openssl pkeyutl -verify -in data.sha256 -sigfile data.$k-psssha256import.sig -pkeyopt rsa_padding_mode:pss -pubin -inkey pubkey_rsa$k.imported.pem -pkeyopt rsa_pss_saltlen:-1 -pkeyopt digest:sha256" "Verify signature with OpenSSL" test "$BIN -p password -a sign-pss -i $import_keyid -A rsa-pss-sha384 --in data.txt --outformat binary --out data.$k-psssha384import.sig" "Sign with rsa-pss-sha384" test "openssl dgst -sha384 -binary -out data.sha384 data.txt" "Hash data with OpenSSL" test "openssl pkeyutl -verify -in data.sha384 -sigfile data.$k-psssha384import.sig -pkeyopt rsa_padding_mode:pss -pubin -inkey pubkey_rsa$k.imported.pem -pkeyopt rsa_pss_saltlen:-1 -pkeyopt digest:sha384" "Verify signature with OpenSSL" test "$BIN -p password -a sign-pss -i $import_keyid -A rsa-pss-sha512 --in data.txt --outformat binary --out data.$k-psssha512import.sig" "Sign with rsa-pss-sha512" test "openssl dgst -sha512 -binary -out data.sha512 data.txt" "Hash data with OpenSSL" test "openssl pkeyutl -verify -in data.sha512 -sigfile data.$k-psssha512import.sig -pkeyopt rsa_padding_mode:pss -pubin -inkey pubkey_rsa$k.imported.pem -pkeyopt rsa_pss_saltlen:-1 -pkeyopt digest:sha512" "Verify signature with OpenSSL" echo "=== Make self signed certificate:" set +e $BIN -p password -a sign-attestation-certificate -i $keyid --attestation-id 0 2>&1 > /dev/null # Some YubiHSMs does not have default attestation certificate def_attestation=$? set -e if [ $def_attestation -eq 0 ]; then test "$BIN -p password -a sign-attestation-certificate -i $keyid --attestation-id 0 --out cert.pem" "Sign attestation cert with default key" test "openssl x509 -in cert.pem -out cert.der -outform DER" "Convert cert format" test "$BIN -p password -a put-opaque -i $keyid -l template_cert -A opaque-x509-certificate --in cert.der" "Import attestation cert as template cert (same ID as generated key)" test "$BIN -p password -a put-opaque -i $import_keyid -l template_cert -A opaque-x509-certificate --in cert.der" "Import attestation cert as template cert (same ID as imported key)" test "rm cert.der" "Cleaning up" else test "$BIN -p password -a put-opaque -i $keyid -l template_cert_gen -A opaque-x509-certificate --informat=PEM --in ../test_x509template.pem" "Import attestation cert as template cert (same ID as generated key)" test "$BIN -p password -a put-opaque -i $import_keyid -l template_cert_imp -A opaque-x509-certificate --informat=PEM --in ../test_x509template.pem" "Import attestation cert as template cert (same ID as imported key)" fi test "$BIN -p password -a sign-attestation-certificate -i $keyid --attestation-id=$keyid --out selfsigned_cert.pem" "Sign attestation with same key (aka. get selfsigned cert)" test "$BIN -p password -a delete-object -i $keyid -t opaque" "Delete template cert" test "$BIN -p password -a put-opaque -i $keyid -l java_cert -A opaque-x509-certificate --informat=PEM --in selfsigned_cert.pem" "Import selfsigned cert with same key ID" test "rm selfsigned_cert.pem" "Cleaning up" #-- Sign attestation certificate test "$BIN -p password -a sign-attestation-certificate -i $keyid --attestation-id=$import_keyid --out selfsigned_cert.pem" "Sign attestation cert with imported key" test "rm selfsigned_cert.pem" "Cleaning up" test "$BIN -p password -a delete-object -i $import_keyid -t opaque" "Delete certificate template" test "$BIN -p password -a delete-object -i $keyid -t opaque" "Delete certificate" echo "=== Decrypt with generated key and PKCS1v15:" test "openssl rsautl -encrypt -inkey pubkey_rsa$k.pem -pubin -in data.txt -out data.enc" "Encryp with OpenSSL" test "$BIN -p password -a decrypt-pkcs1v15 -i $keyid --in data.enc --out data.dec" "Decrypt with yubihsm-shell" test "cmp data.txt data.dec" "Compare decrypted data with plain text data" test "rm data.dec" "Clean up" echo "=== Decrypt with imported key and PKCS1v15:" test "openssl rsautl -encrypt -inkey pubkey_rsa$k.imported.pem -pubin -in data.txt -out data.enc" "Encryp with OpenSSL" test "$BIN -p password -a decrypt-pkcs1v15 -i $import_keyid --in data.enc --out data.dec" "Decrypt with yubihsm-shell" test "cmp data.txt data.dec" "Compare decrypted data with plain text data" test "rm data.dec" "Clean up" echo "=== Make PKCS10 Certificate Signing Request:" test "openssl req -new -key rsa$k-keypair.pem -subj /CN=test -out csr-ossl.pem" "Generate CSR with OpenSSL" test "$BIN -p password -a generate-csr -i $import_keyid -S /CN=test/ --out csr.pem" "Generate CSR with yubihsm-shell" test "openssl req -in csr.pem -verify" "Verify CSR with openssl" test "cmp csr-ossl.pem csr.pem" "Compare CSRs generated with openssl and yubihsm-shell" test "rm csr.pem csr-ossl.pem" "Clean up" echo "=== Clean up:" test "$BIN -p password -a delete-object -i $keyid -t asymmetric-key" "Delete generated key" test "$BIN -p password -a delete-object -i $import_keyid -t asymmetric-key" "Delete imported key" done echo "****************************************************" echo " Compress X509 Certificate" echo "****************************************************" openssl req -x509 -newkey rsa:4096 -out too_large_cert.pem -sha256 -days 3650 -nodes -subj '/C=01/ST=01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567/L=01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567/O=0123456789012345678901234567890123456789012345678901234567890123/OU=0123456789012345678901234567890123456789012345678901234567890123/CN=0123456789012345678901234567890123456789012345678901234567890123/CN=0123456789012345678901234567890123456789012345678901234567890123' > /dev/null 2>&1 test "$BIN -p password -a put-opaque -i 100 -l too_large_cert -A opaque-x509-certificate --with-compression --in too_large_cert.pem --informat PEM" "Import compressed X509 certificate" test "$BIN -p password -a get-opaque -i 100 --outformat=PEM --out too_large_cert_out.pem" "Read the large certificate from device" test "cmp too_large_cert.pem too_large_cert_out.pem" "Compare read certificate with the one imported" test "$BIN -p password -a delete-object -i 100 -t opaque" "Delete certificate" cd .. rm -rf yubihsm-shell_test_dir set +e set +xyubihsm-shell-2.8.0/resources/tests/bash/test_eckey.sh0000755000175100017510000002303215221003515022475 0ustar runnerrunner#!/bin/bash set -u if [ "$#" -ne 1 ]; then BIN="yubihsm-shell" else BIN=$1 # path to the yubico-piv-tool command line tool fi if [ -e yubihsm-shell_test_dir ]; then rm -rf yubihsm-shell_test_dir fi mkdir yubihsm-shell_test_dir; cd yubihsm-shell_test_dir echo test signing data > data.txt test () { set +e $1 > output.txt 2>&1 ret=$? if [ $ret -ne 0 ]; then echo $1 cat output.txt rm output.txt exit 1 else echo "$2 ... OK!" rm output.txt fi set -e } test_with_resp () { set +e $1 > resp.txt 2>&1 ret=$? if [ $ret -ne 0 ]; then echo $1 cat resp.txt rm resp.txt exit 1 else echo "$2 ... OK!" fi set -e } set -e EC_ALGOS=("ecp224" "ecp256" "ecp384" "ecp521" "eck256") EC_CURVES=("secp224r1" "secp256r1" "secp384r1" "secp521r1" "secp256k1") set +e cat /etc/os-release | grep 'Fedora' is_fedora=$? set -e echo "====================== EC keys ===================== " if [ $is_fedora -ne 0 ]; then EC_ALGOS=(${EC_ALGOS[@]} "ecbp256" "ecbp384" "ecbp512") EC_CURVES=(${EC_CURVES[@]} "brainpoolP256r1" "brainpoolP384r1" "brainpoolP512r1") fi genkey=100 import_key=200 for i in "${!EC_ALGOS[@]}"; do algo=${EC_ALGOS[i]} curve=${EC_CURVES[i]} echo "**********************************" echo " $algo" echo "**********************************" echo "=== Generate key" test_with_resp "$BIN -p password -a generate-asymmetric-key -i $genkey -l \"ecKey\" -d 5,8,13 -c sign-ecdsa,derive-ecdh,sign-attestation-certificate -A $algo" " Generate key" test "$BIN -p password -a get-object-info -i $genkey -t asymmetric-key" " get-object-info" info=$($BIN -p password -a get-object-info -i $genkey -t asymmetric-key 2> /dev/null) test "echo $info | grep \"id: $genkey\"" " Object info contains correct ID" test "echo $info | grep \"type: asymmetric-key\"" " Object info contains correct type" test "echo $info | grep \"algorithm: $algo\"" " Object info contains correct algorithm" test "echo $info | grep 'label: \"ecKey\"'" " Object info contains correct label" test "echo $info | grep \"domains: 5:8:13\"" " Object info contains correct domains" test "echo $info | grep \"origin: generated\"" " Object info contains correct origin" test "echo $info | grep \"capabilities: derive-ecdh:sign-attestation-certificate:sign-ecdsa\"" " Object info contains correct capabilities" test "$BIN -p password -a get-public-key -i $genkey --outformat=PEM --out $algo-gen.pubkey" " Get public key" echo "=== Import Key" test "openssl ecparam -genkey -name $curve -noout -out $curve-keypair.pem" " Generate key with OpenSSL" test_with_resp "$BIN -p password -a put-asymmetric-key -i $import_key -l "ecKeyImport" -d "2,6,7" -c "sign-ecdsa,sign-attestation-certificate" --in=$curve-keypair.pem" " Import key" test "$BIN -p password -a get-object-info -i $import_key -t asymmetric-key" " get-object-info" info=$($BIN -p password -a get-object-info -i $import_key -t asymmetric-key 2> /dev/null) test "echo $info | grep \"id: $import_key\"" " Object info contains correct ID" test "echo $info | grep \"type: asymmetric-key\"" " Object info contains correct type" test "echo $info | grep \"algorithm: $algo\"" " Object info contains correct algorithm" test "echo $info | grep 'label: \"ecKeyImport\"'" " Object info contains correct label" test "echo $info | grep \"domains: 2:6:7\"" " Object info contains correct domains" test "echo $info | grep \"origin: imported\"" " Object info contains correct origin" test "echo $info | grep \"capabilities: sign-attestation-certificate:sign-ecdsa\"" " Object info contains correct capabilities" test "$BIN -p password -a get-public-key -i $import_key --outformat=PEM --out $algo-import.pubkey" " Get public key" echo "=== Signing" test "$BIN -p password -a sign-ecdsa -i $genkey -A ecdsa-sha1 --in data.txt --outformat=PEM --out data.$algo-sha1gen.sig" " Sign with generated key and ecdsa-sha1" test "openssl dgst -sha1 -verify $algo-gen.pubkey -signature data.$algo-sha1gen.sig data.txt" " Verify signature with OpenSSL" test "$BIN -p password -a sign-ecdsa -i $genkey -A ecdsa-sha256 --in data.txt --outformat=PEM --out data.$algo-sha256gen.sig" " Sign with generated key and ecdsa-sha256" test "openssl dgst -sha256 -verify $algo-gen.pubkey -signature data.$algo-sha256gen.sig data.txt" " Verify signature with OpenSSL" test "$BIN -p password -a sign-ecdsa -i $genkey -A ecdsa-sha384 --in data.txt --outformat=PEM --out data.$algo-sha384gen.sig" " Sign with generated key and ecdsa-sha384" test "openssl dgst -sha384 -verify $algo-gen.pubkey -signature data.$algo-sha384gen.sig data.txt" " Verify signature with OpenSSL" test "$BIN -p password -a sign-ecdsa -i $genkey -A ecdsa-sha512 --in data.txt --outformat=PEM --out data.$algo-sha512gen.sig" " Sign with generated key and ecdsa-sha512" test "openssl dgst -sha512 -verify $algo-gen.pubkey -signature data.$algo-sha512gen.sig data.txt" " Verify signature with OpenSSL" test "$BIN -p password -a sign-ecdsa -i $import_key -A ecdsa-sha1 --in data.txt --outformat=PEM --out data.$algo-sha1import.sig" " Sign with imported key and ecdsa-sha1" test "openssl dgst -sha1 -verify $algo-import.pubkey -signature data.$algo-sha1import.sig data.txt" " Verify signature with OpenSSL" test "$BIN -p password -a sign-ecdsa -i $import_key -A ecdsa-sha256 --in data.txt --outformat=PEM --out data.$algo-sha256import.sig" " Sign with imported key and ecdsa-sha256" test "openssl dgst -sha256 -verify $algo-import.pubkey -signature data.$algo-sha256import.sig data.txt" " Verify signature with OpenSSL" test "$BIN -p password -a sign-ecdsa -i $import_key -A ecdsa-sha384 --in data.txt --outformat=PEM --out data.$algo-sha384import.sig" " Sign with imported key and ecdsa-sha384" test "openssl dgst -sha384 -verify $algo-import.pubkey -signature data.$algo-sha384import.sig data.txt" " Verify signature with OpenSSL" test "$BIN -p password -a sign-ecdsa -i $import_key -A ecdsa-sha512 --in data.txt --outformat=PEM --out data.$algo-sha512import.sig" " Sign with imported key and ecdsa-sha512" test "openssl dgst -sha512 -verify $algo-import.pubkey -signature data.$algo-sha512import.sig data.txt" " Verify signature with OpenSSL" echo "=== Get attestation certificate and a selfsigned certificate" set +e $BIN -p password -a sign-attestation-certificate -i $genkey --attestation-id 0 2>&1 > /dev/null # Some YubiHSMs does not have default attestation certificate def_attestation=$? set -e if [ $def_attestation -eq 0 ]; then test "$BIN -p password -a sign-attestation-certificate -i $genkey --attestation-id 0 --out cert.pem" " Sign attestation cert with default key" test "openssl x509 -in cert.pem -out cert.der -outform DER" " Convert cert format" test "$BIN -p password -a put-opaque -i $genkey -l template_cert -A opaque-x509-certificate --in cert.der" " Import attestation cert as template cert (same ID as generated key)" test "$BIN -p password -a put-opaque -i $import_key -l template_cert -A opaque-x509-certificate --in cert.der" " Import attestation cert as template cert (same ID as imported key)" test "rm cert.der" " Cleaning up" else test "$BIN -p password -a put-opaque -i $genkey -l template_cert_gen -A opaque-x509-certificate --informat=PEM --in ../test_x509template.pem" " Import attestation cert as template cert (same ID as generated key)" test "$BIN -p password -a put-opaque -i $import_key -l template_cert_imp -A opaque-x509-certificate --informat=PEM --in ../test_x509template.pem" " Import attestation cert as template cert (same ID as imported key)" fi test "$BIN -p password -a sign-attestation-certificate -i $genkey --attestation-id=$genkey --out selfsigned_cert.pem" " Sign attestation with same key (aka. get selfsigned cert)" test "$BIN -p password -a delete-object -i $genkey -t opaque" " Delete template cert" test "$BIN -p password -a put-opaque -i $genkey -l java_cert -A opaque-x509-certificate --informat=PEM --in selfsigned_cert.pem" " Import selfsigned cert with same key ID" test "rm selfsigned_cert.pem" " Cleaning up" #-- Sign attestation certificate test "$BIN -p password -a sign-attestation-certificate -i $genkey --attestation-id=$import_key --out selfsigned_cert.pem" " Sign attestation cert with imported key" test "$BIN -p password -a delete-object -i $genkey -t opaque" " Delete template cert" test "$BIN -p password -a delete-object -i $import_key -t opaque" " Delete template cert" test "rm selfsigned_cert.pem" " Cleaning up" echo "=== Derive ECDH:" test "openssl ec -in $curve-keypair.pem -pubout -out $curve-pubkey.pem" " Get imported key public key with OpenSSL" test "$BIN -p password -a derive-ecdh -i $genkey --in $curve-pubkey.pem --outformat binary --out $algo-ecdh-shell.key" " Derive ECDH using yubihsm-shell" test "openssl pkeyutl -derive -inkey $curve-keypair.pem -peerkey $algo-gen.pubkey -out $algo-ecdh-openssl.key" " Derive ECDH using OpenSSL" test "cmp $algo-ecdh-openssl.key $algo-ecdh-shell.key" " Compare ECDH value from yubihsm-shell and OpenSSL" echo "=== Make PKCS10 Certificate Signing Request:" test "$BIN -p password -a generate-csr -i $genkey -S /CN=test/ --out csr.pem" " Generate CSR with yubihsm-shell" test "openssl req -in csr.pem -verify" " Verify CSR with openssl" test "rm csr.pem" " Clean up" echo "=== Clean up:" test "$BIN -p password -a delete-object -i $genkey -t asymmetric-key" " Delete generated key" test "$BIN -p password -a delete-object -i $import_key -t asymmetric-key" " Delete imported key" doneyubihsm-shell-2.8.0/resources/tests/bash/cmdline_test.sh0000755000175100017510000002154715221003515023021 0ustar runnerrunner#!/bin/bash if [ "$#" -eq 1 ]; then BIN=$1 # path to the yubihsm-shell command line tool - using default connector elif [ "$#" -gt 1 ]; then BIN="$1 -C $2" # path to the yubihsm-shell command line tool - using specified connector else BIN="yubihsm-shell" fi if [ -e yubihsm-shell_test_dir ]; then rm -rf yubihsm-shell_test_dir fi test () { set +e $1 > output.txt 2>&1 ret=$? if [ $ret -ne 0 ]; then echo $1 cat output.txt rm output.txt exit 1 else echo "$2 ... OK!" rm output.txt fi set -e } test_with_resp () { set +e $1 > resp.txt 2>&1 ret=$? if [ $ret -ne 0 ]; then echo $1 cat resp.txt rm resp.txt exit 1 else echo "$2 ... OK!" fi set -e } set -e test "$BIN --version" "yubihsm-shell --version" test "$BIN --help" "yubihsm-shell --help" test "$BIN -a get-device-info | grep \"Serial number:\"" "yubihsm-shell -a get-device-info" echo "********************************************************** " echo " Reset YubiHSM" echo "********************************************************** " test "$BIN -p password -a reset" sleep 3 echo "********************************************************** " echo " Blink" echo "********************************************************** " test "$BIN -p password -a blink" "-a blink" test "$BIN -p password -a blink --duration=5" "-a blink --duration=5" test "$BIN -p password -a blink-device" "blink-device" test "$BIN -p password -a blink-device --duration=5" "-a blink-device --duration=5" echo "********************************************************** " echo " Get Pseudo-random" echo "********************************************************** " test "$BIN -p password -a get-pseudo-random | wc -c | grep 513" "get-pseudo-random" # includes a new line test "$BIN -p password -a get-pseudo-random --out=random.txt" get-pseudo-random --out=random.txt length=$(cat random.txt | wc -c) if [ $length -ne 512 ]; then echo "Expected 512 but was $length characters. Without specifying byte count, 256 bytes (=512 characters) pseudo random number should have been produced." exit 1; fi rm random.txt test "$BIN -p password -a get-pseudo-random --count=10 | wc -c | grep 21" "get-pseudo-random --count=10" # includes a new line test "$BIN -p password -a get-pseudo-random --count=10 --out=random.txt" "get-pseudo-random --count=10 --out=random.txt" length=$(cat random.txt | wc -c) if [ $length -ne 20 ]; then echo "Expected 20 but was $length characters." exit 1; fi rm random.txt echo "********************************************************** " echo " Asymmetric Keys" echo "********************************************************** " ./test_edkey.sh "$BIN" if [ -z ${DOCKER_IMAGE} ] || [ ${DOCKER_IMAGE} != "centos:7" ]; then # This DOCKER_IMAGE environment variable is set in the build_and_test.yml github workflow. ./test_eckey.sh "$BIN" fi ./test_rsakey.sh "$BIN" echo "********************************************************** " echo " HMAC Keys" echo "********************************************************** " ./test_hmackey.sh "$BIN" echo "********************************************************** " echo " AEAD Keys" echo "********************************************************** " ./test_otpaeadkey.sh "$BIN" echo "********************************************************** " echo " Template" echo "********************************************************** " test "$BIN -p password -a get-pseudo-random --count=512 --out=template.txt" " Generate 512 pseudo random bytes" test_with_resp "$BIN -p password -a put-template -i 0 -l template -d 1 -A template-ssh --in template.txt" " Import template" id=$(tail -1 resp.txt | awk '{print $4}') test "$BIN -p password -a get-object-info -i $id -t template" " Get object info" info=$($BIN -p password -a get-object-info -i $id -t template 2> /dev/null) test "echo $info | grep \"id: $id\"" " Object info contains correct ID" test "echo $info | grep \"type: template\"" " Object info contains correct type" test "echo $info | grep \"algorithm: template-ssh\"" " Object info contains correct algorithm" test "echo $info | grep 'label: \"template\"'" " Object info contains correct label" test "echo $info | grep \"domains: 1\"" " Object info contains correct domains" test "echo $info | grep \"origin: imported\"" " Object info contains correct origin" test "$BIN -p password -a get-template -i $id" " Get template" test "$BIN -p password -a delete-object -i $id -t template" " Delete template" rm resp.txt rm template.txt echo "********************************************************** " echo " Wrap Keys" echo "********************************************************** " ./test_wrapkey.sh "$BIN" echo "********************************************************** " echo " List Objects" echo "********************************************************** " test "$BIN -p password -a generate-asymmetric-key -i 100 -l ecKey -d 5,8,13 -c sign-ecdsa,derive-ecdh,sign-attestation-certificate -A ecp224" " Generate EC key for testing" test "$BIN -p password -a list-objects -A any -t any -i 100 | grep \"Found 1 object(s)\"" " List objects by ID" test "$BIN -p password -a list-objects -A any -t asymmetric-key | grep \"Found 1 object(s)\"" " List objects by type" test "$BIN -p password -a list-objects -A any -t any -d 5,8,13 | grep \"Found 2 object(s)\"" " List objects by domain" test "$BIN -p password -a list-objects -A any -t any -c sign-ecdsa,derive-ecdh,sign-attestation-certificate | grep \"Found 2 object(s)\"" " List objects by capabilities" test "$BIN -p password -a list-objects -A ecp224 -t any | grep \"Found 1 object(s)\"" " List objects by algorithm" test "$BIN -p password -a list-objects -A any -t any -l ecKey | grep \"Found 1 object(s)\"" " List objects by label" test "$BIN -p password -a delete-object -i 100 -t asymmetric-key" " Delete key" echo "********************************************************** " echo " Label Size" echo "********************************************************** " # Label 0 chars test "$BIN -p password -a generate-asymmetric-key -i 300 -d 5,8,13 -c sign-ecdsa -A ecp224" " Create key with no label" test "$BIN -p password -a get-object-info -i 300 -t asymmetric-key | grep 'label: \"\"'" " Object info contains empty label" #$BIN -p password -a list-objects -A any -t any -l "" | grep "Found 1 object(s)" # Label 39 chars test "$BIN -p password -a generate-asymmetric-key -i 200 -l abcdefghijklmnopqrstuvwxyz0123456789abc -d 5,8,13 -c sign-ecdsa -A ecp224" " Create object with 39 characters label" test "$BIN -p password -a get-object-info -i 200 -t asymmetric-key | grep 'label: \"abcdefghijklmnopqrstuvwxyz0123456789abc\"'" " Object info contains correct lable with 39 characters" test "$BIN -p password -a list-objects -A any -t any -l abcdefghijklmnopqrstuvwxyz0123456789abc | grep \"Found 1 object(s)\"" " list-objects found object with 39 characters" # Label 40 chars test "$BIN -p password -a generate-asymmetric-key -i 100 -l abcdefghijklmnopqrstuvwxyz0123456789abcd -d 5,8,13 -c sign-ecdsa -A ecp224" " Create object with 40 characters label" test "$BIN -p password -a get-object-info -i 100 -t asymmetric-key | grep 'label: \"abcdefghijklmnopqrstuvwxyz0123456789abcd\"'" " Object info contains correct lable with 40 characters" test "$BIN -p password -a list-objects -A any -t any -l abcdefghijklmnopqrstuvwxyz0123456789abcd | grep \"Found 1 object(s)\"" " list-objects found object with 40 characters" # Label 41 chars (set +e; $BIN -p password -a generate-asymmetric-key -i 400 -l "abcdefghijklmnopqrstuvwxyz0123456789abcde" -d "5,8,13" -c "sign-ecdsa" -A "ecp224"; true) 2>&1 >/dev/null | grep "Failed to generate asymmetric key: Invalid argument to a function" # Label doesn't exist test "$BIN -p password -a list-objects -A any -t any -l doesnotexist | grep \"Found 0 object(s)\"" " List objects by label that does not exist" test "$BIN -p password -a delete-object -i 100 -t asymmetric-key" " Clean up" test "$BIN -p password -a delete-object -i 200 -t asymmetric-key" " Clean up" test "$BIN -p password -a delete-object -i 300 -t asymmetric-key" " Clean up" echo "********************************************************** " echo " Authentication Keys" echo "********************************************************** " test_with_resp "$BIN -p password -a put-authentication-key -i 0 -l authkey -d 1,2,3 -c all --delegated all --new-password foo123" " Create new authentication key" keyid=$(tail -1 resp.txt | awk '{print $4}') test "$BIN --authkey $keyid -p foo123 -a get-object-info -i 1 -t authentication-key" " Login using new authetication key" test "$BIN -p password -a delete-object -i $keyid -t authentication-key" " Delete new authentication key" cd .. rm -rf yubihsm-shell_test_dir set +e yubihsm-shell-2.8.0/resources/tests/bash/cmdline_test.bats0000644000175100017510000017326515221003515023342 0ustar runnerrunnerload 'test_helper/bats-support/load' load 'test_helper/bats-assert/load' setup_file() { echo "--- Configuration via Environment Variables ---" >&3 echo "YUBIHSM_PATH: path to the yubihsm-shell command line tool - using default connector" >&3 echo "SPECIFIED_CONNECTOR: path to the yubihsm-shell command line tool - using specified connector" >&3 echo "TESTS: which tests to run. Possible values are: 'short', 'medium' or 'all'" >&3 echo "It is also possible to individually enable tests by setting the environment variables specified in the README file to 'true'" >&3 echo "-----------------------------------------------" >&3 case "$TESTS" in "all") ED_KEY_TESTS="true" EC_KEY_TESTS="true" RSA_KEY_TESTS="true" HMAC_KEY_TESTS="true" OTP_AEAD_TESTS="true" TEMPLATE_TESTS="true" WRAP_KEY_TESTS="true" LIST_TESTS="true" LABEL_TESTS="true" AUTHENTICATION_TESTS="true" ;; "medium") ED_KEY_TESTS="true" EC_KEY_TESTS="true" HMAC_KEY_TESTS="true" OTP_AEad_TESTS="true" TEMPLATE_TESTS="true" LIST_TESTS="true" LABEL_TESTS="true" AUTHENTICATION_TESTS="true" ;; "short") HMAC_KEY_TESTS="true" OTP_AEAD_TESTS="true" TEMPLATE_TESTS="true" LIST_TESTS="true" LABEL_TESTS="true" AUTHENTICATION_TESTS="true" ;; *) echo "---------------------------------------------------" >&3 echo "Warning: Unrecognized TEST level: '$TESTS'" >&3 echo "Ignore if you are setting individual test variables" >&3 echo "---------------------------------------------------" >&3 ;; esac export ED_KEY_TESTS=${ED_KEY_TESTS:-"false"} export EC_KEY_TESTS=${EC_KEY_TESTS:-"false"} export RSA_KEY_TESTS=${RSA_KEY_TESTS:-"false"} export HMAC_KEY_TESTS=${HMAC_KEY_TESTS:-"false"} export OTP_AEAD_TESTS=${OTP_AEAD_TESTS:-"false"} export TEMPLATE_TESTS=${TEMPLATE_TESTS:-"false"} export WRAP_KEY_TESTS=${WRAP_KEY_TESTS:-"false"} export LIST_TESTS=${LIST_TESTS:-"false"} export LABEL_TESTS=${LABEL_TESTS:-"false"} export AUTHENTICATION_TESTS=${AUTHENTICATION_TESTS:-"false"} local default_bin_path="yubihsm-shell" local os=$(uname -o) export c_var="" if [[ "$os" == "Msys" ]]; then default_bin_path="C:\Program Files\Yubico\YubiHSM Shell\bin\yubihsm-shell.exe" export MSYS2_ARG_CONV_EXCL=* # To prevent path conversion by MSYS2 elif [[ "$os" == "GNU/Linux" || "$os" == "Darwin" ]]; then default_bin_path="/usr/local/bin/yubihsm-shell" fi if [ -n "$SPECIFIED_CONNECTOR" ]; then echo "Specified connector exists" >&3 c_var="-C" fi export BIN=${YUBIHSM_PATH:-$default_bin_path} export SPECIFIED_CONNECTOR=${SPECIFIED_CONNECTOR:-""} echo "Variables Check:" >&3 echo "YubiHSM-shell: $BIN" >&3 echo "Connector: "$c_var" "$SPECIFIED_CONNECTOR"" >&3 echo "Tests to run: $TESTS" >&3 echo "These tests will reset your HSM" >&3 echo "Press Enter to continue or Ctrl-C + enter to abort" >&3 read -p "" if [ -e yubihsm-shell_test_dir ]; then rm -rf yubihsm-shell_test_dir fi mkdir yubihsm-shell_test_dir; cd yubihsm-shell_test_dir echo test signing data > data.txt } @test "Test basic functions and get Pseudo-Random" { command_args=("$BIN" "$c_var" "$SPECIFIED_CONNECTOR") run "${command_args[@]}" -p password -a reset assert_success "HSM was reset" sleep 3 run "${command_args[@]}" --version assert_success "Version works" run "${command_args[@]}" --help assert_success "Help works" run "${command_args[@]}" -a get-device-info assert_success "Get device info" assert_output --partial "Serial number:" run "${command_args[@]}" -p password -a blink assert_success "Blink works" run "${command_args[@]}" -p password -a blink --duration=5 assert_success "Blink with duration works" run "${command_args[@]}" -p password -a get-pseudo-random assert_success output_data=$(echo "$output" | tail -n 1) local byte_count byte_count=$(echo -n "$output_data" | wc -c | xargs) assert_equal "$byte_count" 512 run "${command_args[@]}" -p password -a get-pseudo-random --out=random.txt assert_success "Get Pseudo-Random to file" length=$(cat random.txt | wc -c) if [ "$length" -ne 512 ]; then echo "Expected 512 but was "$length" characters. Without specifying byte count, 256 bytes (=512 characters) pseudo random number should have been produced." >&3 exit 1 fi rm random.txt run "${command_args[@]}" -p password -a get-pseudo-random --count=10 assert_success "Get pseudo-random with --count=10" output_data=$(echo "$output" | tail -n 1) local byte_count byte_count=$(echo -n "$output_data" | wc -c | xargs) assert_equal "$byte_count" 20 run "${command_args[@]}" -p password -a get-pseudo-random --count=10 --out=random.txt assert_success "Get pseudo-random with --count=10" length=$(cat random.txt | wc -c) if [ "$length" -ne 20 ]; then echo "Expected 20 but was "$length" characters." >&3 exit 1 fi rm random.txt } @test "ED Key tests" { [[ "$ED_KEY_TESTS" == "true" ]] || skip "skipping right now" command_args=("$BIN" "$c_var" "$SPECIFIED_CONNECTOR") run "${command_args[@]}" -p password -a reset assert_success "HSM was reset" sleep 3 #Generate run "${command_args[@]}" -p password -a generate-asymmetric-key -i 100 -l \"edKey\" -d 1,2,3 -c sign-eddsa -A ed25519 assert_success "Generate key" run "${command_args[@]}" -p password -a get-object-info -i 100 -t asymmetric-key assert_success "get-object-info" assert_output --partial "id: 0x0064" assert_output --partial "type: asymmetric-key" assert_output --partial "algorithm: ed25519" assert_output --partial 'label: ""edKey""' assert_output --partial "domains: 1:2:3" assert_output --partial "origin: generated" assert_output --partial "capabilities: sign-eddsa" #Get public key run "${command_args[@]}" -p password -a get-public-key -i 100 assert_success "Get public key" "${command_args[@]}" -p password -a get-public-key -i 100 > edkey1.pub 2>/dev/null run "${command_args[@]}" -p password -a get-public-key -i 100 --out edkey2.pub assert_success "Get public key to file" local content1 local content2 content1=$(tr -d '\r' < edkey1.pub) content2=$(tr -d '\r' < edkey2.pub) assert_equal "$content1" "$content2" #Signing run "${command_args[@]}" -p password -a sign-eddsa -i 100 -A ed25519 --in data.txt assert_success "Sign to stdout" "${command_args[@]}" -p password -a sign-eddsa -i 100 -A ed25519 --in data.txt > data.ed1.sig 2>/dev/null run "${command_args[@]}" -p password -a sign-eddsa -i 100 -A ed25519 --in data.txt --out data.ed2.sig assert_success "Sign to file" content1=$(tr -d '[:space:]' < data.ed1.sig) content2=$(tr -d '[:space:]' < data.ed2.sig) assert_equal "$content1" "$content2" #Generating CSR run "${command_args[@]}" -p password -a generate-csr -i 100 -S /CN=test/ --out csr.pem assert_success "Generate CSR with yubihsm-shell" run openssl req -in csr.pem -verify assert_success "Verify CSR with openssl" #Delete run "${command_args[@]}" -p password -a delete-object -i 100 -t asymmetric-key assert_success "Delete key" run rm csr.pem assert_success "Remove CSR" } @test "EC Key tests" { [[ "$EC_KEY_TESTS" == "true" ]] || skip "skipping right now" command_args=("$BIN" "$c_var" "$SPECIFIED_CONNECTOR") genkey=100 import_key=200 run "${command_args[@]}" -p password -a reset assert_success "HSM was reset" sleep 3 EC_ALGOS=("ecp224" "ecp256" "ecp384" "ecp521" "eck256") EC_CURVES=("secp224r1" "secp256r1" "secp384r1" "secp521r1" "secp256k1") if ! grep -q 'Fedora' /etc/os-release 2>/dev/null; then EC_ALGOS+=("ecbp256" "ecbp384" "ecbp512") EC_CURVES+=("brainpoolP256r1" "brainpoolP384r1" "brainpoolP512r1") fi for i in "${!EC_ALGOS[@]}"; do algo=${EC_ALGOS[i]} curve=${EC_CURVES[i]} echo "Testing $algo with curve $curve" >&3 #Generate Key run "${command_args[@]}" -p password -a generate-asymmetric-key -i "$genkey" -l \"ecKey\" -d 5,8,13 -c sign-ecdsa,derive-ecdh,sign-attestation-certificate -A "$algo" assert_success "Generate key" run "${command_args[@]}" -p password -a get-object-info -i "$genkey" -t asymmetric-key assert_success "get-object-info" assert_output --partial "id: 0x0064" assert_output --partial "type: asymmetric-key" assert_output --partial "algorithm: "$algo"" assert_output --partial 'label: ""ecKey""' assert_output --partial "domains: 5:8:13" assert_output --partial "origin: generated" assert_output --partial "capabilities: derive-ecdh:sign-attestation-certificate:sign-ecdsa" run "${command_args[@]}" -p password -a get-public-key -i "$genkey" --outformat=PEM --out "$algo"-gen.pubkey assert_success "Get public key" #Import Key run openssl ecparam -genkey -name "$curve" -noout -out "$curve"-keypair.pem assert_success "Generate key with openssl" run "${command_args[@]}" -p password -a put-asymmetric-key -i "$import_key" -l "ecKeyImport" -d "2,6,7" -c "sign-ecdsa,sign-attestation-certificate" --in="$curve"-keypair.pem assert_success "Import $algo key" run "${command_args[@]}" -p password -a get-object-info -i "$import_key" -t asymmetric-key assert_success "get-object-info" assert_output --partial "id: 0x00c8" assert_output --partial "type: asymmetric-key" assert_output --partial "algorithm: "$algo"" assert_output --partial 'label: "ecKeyImport"' assert_output --partial "domains: 2:6:7" assert_output --partial "origin: imported" assert_output --partial "capabilities: sign-attestation-certificate:sign-ecdsa" run "${command_args[@]}" -p password -a get-public-key -i "$import_key" --outformat=PEM --out "$algo"-import.pubkey assert_success "Get public key" #Signing run "${command_args[@]}" -p password -a sign-ecdsa -i "$genkey" -A ecdsa-sha1 --in data.txt --outformat=PEM --out data."$algo"-sha1gen.sig assert_success "Sign with generated key and ecdsa-sha1" run openssl dgst -sha1 -verify "$algo"-gen.pubkey -signature data."$algo"-sha1gen.sig data.txt assert_success "Verify signature with openssl" run "${command_args[@]}" -p password -a sign-ecdsa -i "$genkey" -A ecdsa-sha256 --in data.txt --outformat=PEM --out data."$algo"-sha256gen.sig assert_success "Sign with generated key and ecdsa-sha256" run openssl dgst -sha256 -verify "$algo"-gen.pubkey -signature data."$algo"-sha256gen.sig data.txt assert_success "Verify signature with openssl" run "${command_args[@]}" -p password -a sign-ecdsa -i "$genkey" -A ecdsa-sha384 --in data.txt --outformat=PEM --out data."$algo"-sha384gen.sig assert_success "Sign with generated key and ecdsa-sha384" run openssl dgst -sha384 -verify "$algo"-gen.pubkey -signature data."$algo"-sha384gen.sig data.txt assert_success "Verify signature with openssl" run "${command_args[@]}" -p password -a sign-ecdsa -i "$genkey" -A ecdsa-sha512 --in data.txt --outformat=PEM --out data."$algo"-sha512gen.sig assert_success "Sign with generated key and ecdsa-sha512" run openssl dgst -sha512 -verify "$algo"-gen.pubkey -signature data."$algo"-sha512gen.sig data.txt assert_success "Verify signature with openssl" run "${command_args[@]}" -p password -a sign-ecdsa -i "$import_key" -A ecdsa-sha1 --in data.txt --outformat=PEM --out data."$algo"-sha1import.sig assert_success "Sign with imported key and ecdsa-sha1" run openssl dgst -sha1 -verify "$algo"-import.pubkey -signature data."$algo"-sha1import.sig data.txt assert_success "Verify signature with openssl" run "${command_args[@]}" -p password -a sign-ecdsa -i "$import_key" -A ecdsa-sha256 --in data.txt --outformat=PEM --out data."$algo"-sha256import.sig assert_success "Sign with imported key and ecdsa-sha256" run openssl dgst -sha256 -verify "$algo"-import.pubkey -signature data."$algo"-sha256import.sig data.txt assert_success "Verify signature with openssl" run "${command_args[@]}" -p password -a sign-ecdsa -i "$import_key" -A ecdsa-sha384 --in data.txt --outformat=PEM --out data."$algo"-sha384import.sig assert_success "Sign with imported key and ecdsa-sha384" run openssl dgst -sha384 -verify "$algo"-import.pubkey -signature data."$algo"-sha384import.sig data.txt assert_success "Verify signature with openssl" run "${command_args[@]}" -p password -a sign-ecdsa -i "$import_key" -A ecdsa-sha512 --in data.txt --outformat=PEM --out data."$algo"-sha512import.sig assert_success "Sign with imported key and ecdsa-sha512" run openssl dgst -sha512 -verify "$algo"-import.pubkey -signature data."$algo"-sha512import.sig data.txt assert_success "Verify signature with openssl" #Get attestation certificate and selfsigned certificate if "${command_args[@]}" -p password -a sign-attestation-certificate -i "$genkey" --attestation-id 0 2>&1 > /dev/null;then # Some YubiHSMs does not have default attestation certificate run "${command_args[@]}" -p password -a sign-attestation-certificate -i "$genkey" --attestation-id 0 --out cert.pem assert_success "Sign attestation cert with default key" run openssl x509 -in cert.pem -out cert.der -outform DER assert_success "Convert cert format" run "${command_args[@]}" -p password -a put-opaque -i "$genkey" -l template_cert -A opaque-x509-certificate --in cert.der assert_success "Import attestation cert as template cert (same ID as generated key)" run "${command_args[@]}" -p password -a put-opaque -i "$import_key" -l template_cert -A opaque-x509-certificate --in cert.der assert_success "Import attestation cert as template cert (same ID as imported key)" run rm cert.der assert_success "Remove der cert" else run "${command_args[@]}" -p password -a put-opaque -i "$genkey" -l template_cert_gen -A opaque-x509-certificate --informat=PEM --in ../test_x509template.pem assert_success "Import attestation cert as template cert (same ID as generated key)" run "${command_args[@]}" -p password -a put-opaque -i "$import_key" -l template_cert_imp -A opaque-x509-certificate --informat=PEM --in ../test_x509template.pem assert_success "Import attestation cert as template cert (same ID as imported key)" fi run "${command_args[@]}" -p password -a sign-attestation-certificate -i "$genkey" --attestation-id="$genkey" --out selfsigned_cert.pem assert_success "Get selfsigned certificate" run "${command_args[@]}" -p password -a delete-object -i "$genkey" -t opaque assert_success "Delete template certificate" run "${command_args[@]}" -p password -a put-opaque -i "$genkey" -l java_cert -A opaque-x509-certificate --informat=PEM --in selfsigned_cert.pem assert_success "Import selfsigned with same key ID" run rm selfsigned_cert.pem assert_success "Remove selfsigned cert" #Sign attestation certificate run "${command_args[@]}" -p password -a sign-attestation-certificate -i "$genkey" --attestation-id="$import_key" --out selfsigned_cert.pem assert_success "Sign attestation cert with imported key" run "${command_args[@]}" -p password -a delete-object -i "$genkey" -t opaque assert_success "Delete template certificate" run "${command_args[@]}" -p password -a delete-object -i "$import_key" -t opaque assert_success "Delete template certificate" run rm selfsigned_cert.pem assert_success "Remove selfsigned cert" #Derive ECDH run openssl ec -in "$curve"-keypair.pem -pubout -out "$curve"-pubkey.pem assert_success "Get imported key public key with OpenSSL" run "${command_args[@]}" -p password -a derive-ecdh -i "$genkey" --in "$curve"-pubkey.pem --outformat binary --out "$algo"-ecdh-shell.key assert_success "Derive ECDH key with yubihsm-shell" run openssl pkeyutl -derive -inkey "$curve"-keypair.pem -peerkey "$algo"-gen.pubkey -out "$algo"-ecdh-openssl.key assert_success "Derive ECDH key with OpenSSL" run cmp "$algo"-ecdh-shell.key "$algo"-ecdh-openssl.key assert_success "Compare derived keys" #make PKCS10 certificate signing request run "${command_args[@]}" -p password -a generate-csr -i "$genkey" -S /CN=test/ --out csr.pem assert_success "Generate CSR with yubihsm-shell" run openssl req -in csr.pem -verify assert_success "Verify CSR with openssl" run rm csr.pem assert_success "Remove CSR" #Clean up run "${command_args[@]}" -p password -a delete-object -i "$genkey" -t asymmetric-key assert_success "Delete generated key" run "${command_args[@]}" -p password -a delete-object -i "$import_key" -t asymmetric-key assert_success "Delete imported key" done } @test "RSA Key tests" { [[ "$RSA_KEY_TESTS" == "true" ]] || skip "skipping right now" command_args=("$BIN" "$c_var" "$SPECIFIED_CONNECTOR") RSA_KEYSIZE=("2048" "3072" "4096") run "${command_args[@]}" -p password -a reset assert_success "HSM was reset" sleep 3 for k in ${RSA_KEYSIZE[@]}; do echo "Testing RSA "$k" key" >&3 if [ "$k" -ne "2048" ]; then echo "This may take a while..." >&3 fi #Generate Key run "${command_args[@]}" -p password -a generate-asymmetric-key -i 0 -l rsaKey -d 1 -c sign-pkcs,sign-pss,decrypt-pkcs,decrypt-oaep,sign-attestation-certificate -A rsa"$k" assert_success "Generate RSA "$k" key" keyid=$(echo "$output" | tail -n 1 | awk '{print $4}') run "${command_args[@]}" -p password -a get-object-info -i "$keyid" -t asymmetric-key assert_success "get-object-info" assert_output --partial "id: "$keyid"" assert_output --partial "type: asymmetric-key" assert_output --partial "algorithm: rsa"$k"" assert_output --partial "label: \"rsaKey\"" assert_output --partial "domains: 1" assert_output --partial "origin: generated" assert_output --partial "decrypt-oaep:decrypt-pkcs:sign-attestation-certificate:sign-pkcs:sign-pss" run "${command_args[@]}" -p password -a get-public-key -i "$keyid" --outformat=PEM --out pubkey_rsa"$k".pem assert_success "Get public key" #Import key run openssl genrsa -out rsa"$k"-keypair.pem "$k" assert_success "Generate key with OpenSSL" run "${command_args[@]}" "${command_args[@]}" -p password -a put-asymmetric-key -i 0 -l rsaKeyImport -d 2 -c sign-pkcs,sign-pss,decrypt-pkcs,decrypt-oaep,sign-attestation-certificate --in=rsa"$k"-keypair.pem assert_success "Import key" import_keyid=$(echo "$output" | tail -n 1 | awk '{print $4}') run "${command_args[@]}" -p password -a get-object-info -i "$import_keyid" -t asymmetric-key assert_success "get-object-info" assert_output --partial "id: "$import_keyid"" assert_output --partial "type: asymmetric-key" assert_output --partial "algorithm: rsa"$k"" assert_output --partial "label: \"rsaKeyImport\"" assert_output --partial "domains: 2" assert_output --partial "origin: imported" assert_output --partial "decrypt-oaep:decrypt-pkcs:sign-attestation-certificate:sign-pkcs:sign-pss" run "${command_args[@]}" -p password -a get-public-key -i "$import_keyid" --outformat=PEM --out pubkey_rsa"$k".imported.pem assert_success "Get public key" #Signing with generated key run "${command_args[@]}" -p password -a sign-pkcs1v15 -i "$keyid" -A rsa-pkcs1-sha1 --in data.txt --outformat binary --out data."$k"-pkcs1sha1gen.sig assert_success "Sign with rsa-pkcs1-sha1" run openssl dgst -sha1 -verify pubkey_rsa"$k".pem -signature data."$k"-pkcs1sha1gen.sig data.txt assert_success "Verify signature with openssl" run "${command_args[@]}" -p password -a sign-pkcs1v15 -i "$keyid" -A rsa-pkcs1-sha256 --in data.txt --outformat binary --out data."$k"-pkcs1sha256gen.sig assert_success "Sign with rsa-pkcs1-sha256" run openssl dgst -sha256 -verify pubkey_rsa"$k".pem -signature data."$k"-pkcs1sha256gen.sig data.txt assert_success "Verify signature with openssl" run "${command_args[@]}" -p password -a sign-pkcs1v15 -i "$keyid" -A rsa-pkcs1-sha384 --in data.txt --outformat binary --out data."$k"-pkcs1sha384gen.sig assert_success "Sign with rsa-pkcs1-sha384" run openssl dgst -sha384 -verify pubkey_rsa"$k".pem -signature data."$k"-pkcs1sha384gen.sig data.txt assert_success "Verify signature with openssl" run "${command_args[@]}" -p password -a sign-pkcs1v15 -i "$keyid" -A rsa-pkcs1-sha512 --in data.txt --outformat binary --out data."$k"-pkcs1sha512gen.sig assert_success "Sign with rsa-pkcs1-sha512" run openssl dgst -sha512 -verify pubkey_rsa"$k".pem -signature data."$k"-pkcs1sha512gen.sig data.txt assert_success "Verify signature with openssl" run "${command_args[@]}" -p password -a sign-pss -i "$keyid" -A rsa-pss-sha1 --in data.txt --outformat binary --out data."$k"-psssha1gen.sig assert_success "Sign with rsa-pss-sha1" run openssl dgst -sha1 -binary -out data.sha1 data.txt assert_success "Hash data with openssl" run openssl pkeyutl -verify -in data.sha1 -sigfile data."$k"-psssha1gen.sig -pkeyopt rsa_padding_mode:pss -pubin -inkey pubkey_rsa"$k".pem -pkeyopt rsa_pss_saltlen:-1 -pkeyopt digest:sha1 assert_success "Verify signature with openssl" run "${command_args[@]}" -p password -a sign-pss -i "$keyid" -A rsa-pss-sha256 --in data.txt --outformat binary --out data."$k"-psssha256gen.sig assert_success "Sign with rsa-pss-sha256" run openssl dgst -sha256 -binary -out data.sha256 data.txt assert_success "Hash data with openssl" run openssl pkeyutl -verify -in data.sha256 -sigfile data."$k"-psssha256gen.sig -pkeyopt rsa_padding_mode:pss -pubin -inkey pubkey_rsa"$k".pem -pkeyopt rsa_pss_saltlen:-1 -pkeyopt digest:sha256 assert_success "Verify signature with openssl" run "${command_args[@]}" -p password -a sign-pss -i "$keyid" -A rsa-pss-sha384 --in data.txt --outformat binary --out data."$k"-psssha384gen.sig assert_success "Sign with rsa-pss-sha384" run openssl dgst -sha384 -binary -out data.sha384 data.txt assert_success "Hash data with openssl" run openssl pkeyutl -verify -in data.sha384 -sigfile data."$k"-psssha384gen.sig -pkeyopt rsa_padding_mode:pss -pubin -inkey pubkey_rsa"$k".pem -pkeyopt rsa_pss_saltlen:-1 -pkeyopt digest:sha384 assert_success "Verify signature with openssl" run "${command_args[@]}" -p password -a sign-pss -i "$keyid" -A rsa-pss-sha512 --in data.txt --outformat binary --out data."$k"-psssha512gen.sig assert_success "Sign with rsa-pss-sha512" run openssl dgst -sha512 -binary -out data.sha512 data.txt assert_success "Hash data with openssl" run openssl pkeyutl -verify -in data.sha512 -sigfile data."$k"-psssha512gen.sig -pkeyopt rsa_padding_mode:pss -pubin -inkey pubkey_rsa"$k".pem -pkeyopt rsa_pss_saltlen:-1 -pkeyopt digest:sha512 assert_success "Verify signature with openssl" #Signing with imported key run "${command_args[@]}" -p password -a sign-pkcs1v15 -i "$import_keyid" -A rsa-pkcs1-sha1 --in data.txt --outformat binary --out data."$k"-pkcs1sha1import.sig assert_success "Sign with rsa-pkcs1-sha1" run openssl dgst -sha1 -verify pubkey_rsa"$k".imported.pem -signature data."$k"-pkcs1sha1import.sig data.txt assert_success "Verify signature with openssl" run "${command_args[@]}" -p password -a sign-pkcs1v15 -i "$import_keyid" -A rsa-pkcs1-sha256 --in data.txt --outformat binary --out data."$k"-pkcs1sha256import.sig assert_success "Sign with rsa-pkcs1-sha256" run openssl dgst -sha256 -verify pubkey_rsa"$k".imported.pem -signature data."$k"-pkcs1sha256import.sig data.txt assert_success "Verify signature with openssl" run "${command_args[@]}" -p password -a sign-pkcs1v15 -i "$import_keyid" -A rsa-pkcs1-sha384 --in data.txt --outformat binary --out data."$k"-pkcs1sha384import.sig assert_success "Sign with rsa-pkcs1-sha384" run openssl dgst -sha384 -verify pubkey_rsa"$k".imported.pem -signature data."$k"-pkcs1sha384import.sig data.txt assert_success "Verify signature with openssl" run "${command_args[@]}" -p password -a sign-pkcs1v15 -i "$import_keyid" -A rsa-pkcs1-sha512 --in data.txt --outformat binary --out data."$k"-pkcs1sha512import.sig assert_success "Sign with rsa-pkcs1-sha512" run openssl dgst -sha512 -verify pubkey_rsa"$k".imported.pem -signature data."$k"-pkcs1sha512import.sig data.txt assert_success "Verify signature with openssl" run "${command_args[@]}" -p password -a sign-pss -i "$import_keyid" -A rsa-pss-sha1 --in data.txt --outformat binary --out data."$k"-psssha1import.sig assert_success "Sign with rsa-pss-sha1" run openssl dgst -sha1 -binary -out data.sha1 data.txt assert_success "Hash data with openssl" run openssl pkeyutl -verify -in data.sha1 -sigfile data."$k"-psssha1import.sig -pkeyopt rsa_padding_mode:pss -pubin -inkey pubkey_rsa"$k".imported.pem -pkeyopt rsa_pss_saltlen:-1 -pkeyopt digest:sha1 assert_success "Verify signature with openssl" run "${command_args[@]}" -p password -a sign-pss -i "$import_keyid" -A rsa-pss-sha256 --in data.txt --outformat binary --out data."$k"-psssha256import.sig assert_success "Sign with rsa-pss-sha256" run openssl dgst -sha256 -binary -out data.sha256 data.txt assert_success "Hash data with openssl" run openssl pkeyutl -verify -in data.sha256 -sigfile data."$k"-psssha256import.sig -pkeyopt rsa_padding_mode:pss -pubin -inkey pubkey_rsa"$k".imported.pem -pkeyopt rsa_pss_saltlen:-1 -pkeyopt digest:sha256 assert_success "Verify signature with openssl" run "${command_args[@]}" -p password -a sign-pss -i "$import_keyid" -A rsa-pss-sha384 --in data.txt --outformat binary --out data."$k"-psssha384import.sig assert_success "Sign with rsa-pss-sha384" run openssl dgst -sha384 -binary -out data.sha384 data.txt assert_success "Hash data with openssl" run openssl pkeyutl -verify -in data.sha384 -sigfile data."$k"-psssha384import.sig -pkeyopt rsa_padding_mode:pss -pubin -inkey pubkey_rsa"$k".imported.pem -pkeyopt rsa_pss_saltlen:-1 -pkeyopt digest:sha384 assert_success "Verify signature with openssl" run "${command_args[@]}" -p password -a sign-pss -i "$import_keyid" -A rsa-pss-sha512 --in data.txt --outformat binary --out data."$k"-psssha512import.sig assert_success "Sign with rsa-pss-sha512" run openssl dgst -sha512 -binary -out data.sha512 data.txt assert_success "Hash data with openssl" run openssl pkeyutl -verify -in data.sha512 -sigfile data."$k"-psssha512import.sig -pkeyopt rsa_padding_mode:pss -pubin -inkey pubkey_rsa"$k".imported.pem -pkeyopt rsa_pss_saltlen:-1 -pkeyopt digest:sha512 assert_success "Verify signature with openssl" #Make self signed certificate if "${command_args[@]}" -p password -a sign-attestation-certificate -i "$keyid" --attestation-id 0 2>&1 > /dev/null;then #Some YubiHSMs does not have default attestation certificate run "${command_args[@]}" -p password -a sign-attestation-certificate -i "$keyid" --attestation-id 0 --out cert.pem assert_success "Sign attestation cert with default key" run openssl x509 -in cert.pem -out cert.der -outform DER assert_success "Convert cert format" run "${command_args[@]}" -p password -a put-opaque -i "$keyid" -l template_cert -A opaque-x509-certificate --in cert.der assert_success "Import attestation cert as template cert (same ID as generated key)" run "${command_args[@]}" -p password -a put-opaque -i "$import_keyid" -l template_cert -A opaque-x509-certificate --in cert.der assert_success "Import attestation cert as template cert (same ID as imported key)" run rm cert.der assert_success "Remove der cert" else run "${command_args[@]}" -p password -a put-opaque -i "$keyid" -l template_cert_gen -A opaque-x509-certificate --informat=PEM --in ../test_x509template.pem assert_success "Import attestation cert as template cert (same ID as generated key)" run "${command_args[@]}" -p password -a put-opaque -i "$import_keyid" -l template_cert_imp -A opaque-x509-certificate --informat=PEM --in ../test_x509template.pem assert_success "Import attestation cert as template cert (same ID as imported key)" fi run "${command_args[@]}" -p password -a sign-attestation-certificate -i "$keyid" --attestation-id="$keyid" --out selfsigned_cert.pem assert_success "Sign attestation with same key (aka. get selfsigned cert)" run "${command_args[@]}" -p password -a delete-object -i "$keyid" -t opaque assert_success "Delete template certificate" run "${command_args[@]}" -p password -a put-opaque -i "$keyid" -l java_cert -A opaque-x509-certificate --informat=PEM --in selfsigned_cert.pem assert_success "Import selfsigned with same key ID" run rm selfsigned_cert.pem assert_success "Remove selfsigned cert" #Sign attestation certificate run "${command_args[@]}" -p password -a sign-attestation-certificate -i "$keyid" --attestation-id="$import_keyid" --out selfsigned_cert.pem assert_success "Sign attestation cert with imported key" run rm selfsigned_cert.pem assert_success "Remove selfsigned cert" run "${command_args[@]}" -p password -a delete-object -i "$import_keyid" -t opaque assert_success "Delete template certificate" run "${command_args[@]}" -p password -a delete-object -i "$keyid" -t opaque assert_success "Delete template certificate" #Decryption with generated key and PKCS1v15 run openssl rsautl -encrypt -inkey pubkey_rsa"$k".pem -pubin -in data.txt -out data.enc assert_success "Encrypt data with openssl" run "${command_args[@]}" -p password -a decrypt-pkcs1v15 -i "$keyid" --in data.enc --out data.dec assert_success "Decrypt data with yubihsm-shell" run cmp data.txt data.dec assert_success "Compare decrypted data with plain text data" run rm data.dec assert_success "Remove decrypted data" #Decryption with imported key and PKCS1v15 run openssl rsautl -encrypt -inkey pubkey_rsa"$k".imported.pem -pubin -in data.txt -out data.enc assert_success "Encrypt data with openssl" run "${command_args[@]}" -p password -a decrypt-pkcs1v15 -i "$import_keyid" --in data.enc --out data.dec assert_success "Decrypt data with yubihsm-shell" run cmp data.txt data.dec assert_success "Compare decrypted data with plain text data" run rm data.dec assert_success "Remove decrypted data" #Make PKCS10 Certificate Signing Request run openssl req -new -key rsa$k-keypair.pem -subj /CN=test -out csr-ossl.pem assert_success "Generate CSR with OpenSSL" run "${command_args[@]}" -p password -a generate-csr -i "$import_keyid" -S /CN=test/ --out csr.pem assert_success "Generate CSR with yubihsm-shell" run openssl req -in csr.pem -verify assert_success "Verify CSR with openssl" run cmp csr-ossl.pem csr.pem assert_success "Compare CSR with OpenSSL generated CSR" run rm csr.pem csr-ossl.pem assert_success "Remove CSR" #Clean up run "${command_args[@]}" -p password -a delete-object -i "$keyid" -t asymmetric-key assert_success "Delete generated key" run "${command_args[@]}" -p password -a delete-object -i "$import_keyid" -t asymmetric-key assert_success "Delete imported key" done run openssl req -x509 -newkey rsa:4096 -out too_large_cert.pem -sha256 -days 3650 -nodes -subj '/C=01/ST=01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567/L=01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567/O=0123456789012345678901234567890123456789012345678901234567890123/OU=0123456789012345678901234567890123456789012345678901234567890123/CN=0123456789012345678901234567890123456789012345678901234567890123/CN=0123456789012345678901234567890123456789012345678901234567890123' > /dev/null 2>&1 assert_success "Generate too large certificate with OpenSSL" run "${command_args[@]}" -p password -a put-opaque -i 100 -l too_large_cert -A opaque-x509-certificate --in too_large_cert.pem --informat PEM if [ "$status" -eq 0 ]; then assert_success "Import large certificate raw" echo "Imported x509 certificate raw" >&3 elif [[ "$output" == *"Failed to store opaque object: Not enough space to store data"* ]]; then run "${command_args[@]}" -p password -a put-opaque -i 100 -l too_large_cert -A opaque-x509-certificate --with-compression --in too_large_cert.pem --informat PEM assert_success "Import compressed x509 certificate" echo "Imported compressed x509 Certificate" >&3 else fail "Import of x509 certificate failed" fi run "${command_args[@]}" -p password -a get-opaque -i 100 --outformat=PEM --out too_large_cert_out.pem assert_success "Get too large certificate" run cmp too_large_cert.pem too_large_cert_out.pem assert_success "Compare imported and read certificate" run "${command_args[@]}" -p password -a delete-object -i 100 -t opaque assert_success "Delete too large certificate" } @test "HMAC Key tests" { [[ "$HMAC_KEY_TESTS" == "true" ]] || skip "skipping right now" command_args=("$BIN" "$c_var" "$SPECIFIED_CONNECTOR") algorithms=("hmac-sha1" "hmac-sha256" "hmac-sha384" "hmac-sha512") run "${command_args[@]}" -p password -a reset assert_success "HSM was reset" sleep 3 for algo in ${algorithms[@]}; do echo "$algo" >&3 run "${command_args[@]}" -p password -a generate-hmac-key -i 0 -l hmackey -d 1,2,3 -c sign-hmac -A "$algo" assert_success "Generate "$algo" key" keyid=$(echo "$output" | tail -n 1 | awk '{print $4}') run "${command_args[@]}" -p password -a get-object-info -i "$keyid" -t hmac-key assert_success "get-object-info" assert_output --partial "id: "$keyid"" assert_output --partial "type: hmac-key" assert_output --partial "algorithm: "$algo"" assert_output --partial "label: \"hmackey\"" assert_output --partial "domains: 1:2:3" assert_output --partial "origin: generated" assert_output --partial "sign-hmac" done } @test "OTP AEAD Key tests" { [[ "$OTP_AEAD_TESTS" == "true" ]] || skip "skipping right now" command_args=("$BIN" "$c_var" "$SPECIFIED_CONNECTOR") algorithms=("aes128" "aes192" "aes256") run "${command_args[@]}" -p password -a reset assert_success "HSM was reset" sleep 3 for algo in ${algorithms[@]}; do echo "$algo" >&3 run "${command_args[@]}" -p password -a generate-otp-aead-key -i 0 -l aeadkey -d 1,2,3 -c randomize-otp-aead -A "$algo"-yubico-otp --nonce 0x01020304 assert_success "Generate Key" keyid=$(echo "$output" | tail -n 1 | awk '{print $5}') run "${command_args[@]}" -p password -a get-object-info -i "$keyid" -t otp-aead-key assert_success "Get object info" assert_output --partial "id: "$keyid"" assert_output --partial "type: otp-aead-key" assert_output --partial "algorithm: "$algo"-yubico-otp" assert_output --partial "label: \"aeadkey\"" assert_output --partial "domains: 1:2:3" assert_output --partial "origin: generated" assert_output --partial "capabilities: randomize-otp-aead" run "${command_args[@]}" -p password -a randomize-otp-aead -i "$keyid" assert_success "Randomize OTP AEAD" run "${command_args[@]}" -p password -a delete-object -i "$keyid" -t otp-aead-key assert_success "Delete key" done } @test "Template tests" { [[ "$TEMPLATE_TESTS" == "true" ]] || skip "skipping right now" command_args=("$BIN" "$c_var" "$SPECIFIED_CONNECTOR") run "${command_args[@]}" -p password -a reset assert_success "HSM was reset" sleep 3 run "${command_args[@]}" -p password -a put-template -i 20 -l "SSH_Template" -d 1 -A template-ssh --in ../template.dat assert_success "Import template" id=$(echo "$output" | grep "Stored Template object" | awk '{print $4}') run "${command_args[@]}" -p password -a get-object-info -i "$id" -t template assert_success "Get object info" assert_output --partial "id: "$id"" assert_output --partial "type: template" assert_output --partial "algorithm: template-ssh" assert_output --partial "label: \"SSH_Template\"" assert_output --partial "domains: 1" assert_output --partial "origin: imported" #This command doesn't work right now. #run "${command_args[@]}" --authkey=0x0001 -p password -a sign-ssh-certificate -i 10 --template-id 20 -A rsa-pkcs1-sha256 --in ../req.dat --out ./id_rsa-cert.pub #assert_success "sign request" run "${command_args[@]}" -p password -a get-template -i "$id" assert_success "Get template" run "${command_args[@]}" -p password -a delete-object -i "$id" -t template assert_success "Delete template" } @test "Wrap Keys tests" { [[ "$WRAP_KEY_TESTS" == "true" ]] || skip "skipping right now" command_args=("$BIN" "$c_var" "$SPECIFIED_CONNECTOR") algorithms=("aes128-ccm-wrap" "aes192-ccm-wrap" "aes256-ccm-wrap") eckey=100 aeskey=200 sequence=0 RSA_KEYSIZE=("2048" "3072" "4096") seq_ec=6 seq_aes=0 aes_enabled=false run "${command_args[@]}" -p password -a reset assert_success "HSM was reset" sleep 3 run "${command_args[@]}" -p password -a generate-asymmetric-key -i "$eckey" -l eckey -d 1 -c exportable-under-wrap,sign-ecdsa -A ecp224 assert_success "Generate EC Key to wrap" run "${command_args[@]}" -p password -a get-object-info -i "$eckey" -t asymmetric-key assert_success "Get object info" assert_output --partial "sequence: "$sequence"" sequence=$((sequence+1)) assert_output --partial "origin: generated" for algo in ${algorithms[@]}; do echo "$algo" >&3 length=24 import_count=16 if [ "$algo" == "aes192-ccm-wrap" ]; then length=32 import_count=24 elif [ "$algo" == "aes256-ccm-wrap" ]; then length=40 import_count=32 fi #Generate key run "${command_args[@]}" -p password -a generate-wrap-key -i 0 -l wrapkey -d 1 -c export-wrapped,import-wrapped --delegated sign-ecdsa,exportable-under-wrap -A "$algo" assert_success "Generate wrap key" keyid=$(echo "$output" | awk '/Generated Wrap key/ {print $4}') run "${command_args[@]}" -p password -a get-object-info -i "$keyid" -t wrap-key assert_success "Get object info" assert_output --partial "algorithm: "$algo"" assert_output --partial "length: "$length"" #Import key run "${command_args[@]}" -p password -a get-pseudo-random --count "$import_count" assert_success "Get random 16 bytes" wrapkey=$(echo "$output" | tail -n 1) run "${command_args[@]}" -p password -a put-wrap-key -i 0 -l imported_wrapkey -d 1 -c export-wrapped,import-wrapped --delegated sign-ecdsa,exportable-under-wrap --in="$wrapkey" assert_success "Import wrap key" import_keyid=$(echo "$output" | awk '/Stored Wrap key/ {print $4}') run "${command_args[@]}" -p password -a get-object-info -i "$import_keyid" -t wrap-key assert_success "Get object info" assert_output --partial "algorithm: "$algo"" assert_output --partial "length: "$length"" assert_output --partial "origin: imported" #Wrap and unwrap with generated wrap key run "${command_args[@]}" -p password -a get-wrapped --wrap-id "$keyid" -i 100 -t asymmetric-key --out key.gen_wrapped assert_success "Wrap EC key" run "${command_args[@]}" -p password -a delete-object -i "$eckey" -t asymmetric-key assert_success "Delete EC key" run "${command_args[@]}" -p password -a put-wrapped --wrap-id "$keyid" --in key.gen_wrapped assert_success "Wrap EC key" run "${command_args[@]}" -p password -a get-object-info -i "$eckey" -t asymmetric-key assert_success "Get object info" assert_output --partial "sequence: "$sequence"" sequence=$((sequence+1)) assert_output --partial "origin: generated:imported_wrapped" assert_output --partial "capabilities: exportable-under-wrap:sign-ecdsa" run "${command_args[@]}" -p password -a sign-ecdsa -i "$eckey" -A ecdsa-sha1 --in data.txt assert_success "Perform signature with imported wrapped key" #Wrap and unwrap objects with imported wrap key run "${command_args[@]}" -p password -a get-wrapped --wrap-id "$import_keyid" -i 100 -t asymmetric-key --out key.imp_wrapped assert_success "Wrap EC key" run "${command_args[@]}" -p password -a delete-object -i "$eckey" -t asymmetric-key assert_success "Delete EC key" run "${command_args[@]}" -p password -a put-wrapped --wrap-id "$import_keyid" --in key.imp_wrapped assert_success "Wrap EC key" run "${command_args[@]}" -p password -a get-object-info -i "$eckey" -t asymmetric-key assert_success "Get object info" assert_output --partial "sequence: "$sequence"" sequence=$((sequence+1)) assert_output --partial "origin: generated:imported_wrapped" assert_output --partial "capabilities: exportable-under-wrap:sign-ecdsa" run "${command_args[@]}" -p password -a sign-ecdsa -i "$eckey" -A ecdsa-sha1 --in data.txt assert_success "Perform signature with imported wrapped key" #Clean up run "${command_args[@]}" -p password -a delete-object -i "$keyid" -t wrap-key assert_success "Delete generated wrap key" run "${command_args[@]}" -p password -a delete-object -i "$import_keyid" -t wrap-key assert_success "Delete imported wrap key" run rm key.gen_wrapped key.imp_wrapped assert_success "Deleted generated and imported wrap keys" done run "${command_args[@]}" -p password -a get-device-info assert_success "Get device info" if [[ "$output" != *"aes-kwp"* ]]; then run "${command_args[@]}" -p password -a delete-object -i "$eckey" -t asymmetric-key assert_success "Delete object" skip "Device does not support aes-kwp, skipping these tests." fi run "${command_args[@]}" -p password -a get-device-info assert_success "Get device info" if [[ "$output" == *"aes-cbc"* ]]; then aes_enabled=true run "${command_args[@]}" -p password -a generate-symmetric-key -i "$aeskey" -l aeskey -d 1 -c exportable-under-wrap,encrypt-cbc,decrypt-cbc -A aes128 assert_success "Generate AES key to wrap" run "${command_args[@]}" -p password -a get-pseudo-random --count 16 assert_success "Get random 16 bytes" iv=$(echo "$output" | tail -n 1) run "${command_args[@]}" -p password -a get-pseudo-random --count 32 assert_success "Get random 32 bytes for encryption" data=$(echo "$output" | tail -n 1) fi for k in ${RSA_KEYSIZE[@]}; do echo "RSA"$k"" >&3 if [[ "$k" != "2048" ]]; then echo "This may take a while..." >&3 fi #Generate RSA wrap keys run "${command_args[@]}" -p password -a generate-wrap-key -i 0 -l wrapkey -c import-wrapped --delegated exportable-under-wrap,sign-ecdsa,encrypt-cbc,decrypt-cbc -A rsa"$k" assert_success "Generate RSA wrap key" keyid=$(echo "$output" | awk '/Generated Wrap key/ {print $4}') run "${command_args[@]}" -p password -a get-object-info -i "$keyid" -t wrap-key assert_success "Get object into" assert_output --partial "algorithm: rsa"$k"" assert_output --partial "origin: generated" run "${command_args[@]}" -p password -a get-public-key -i "$keyid" -t wrap-key --out public_wrapkey.pem assert_success "Export rsa public wrap key" run "${command_args[@]}" -p password -a put-public-wrapkey -i "$keyid" -c export-wrapped --delegated exportable-under-wrap,sign-ecdsa,encrypt-cbc,decrypt-cbc --in public_wrapkey.pem assert_success "Import RSA public wrap key" run rm public_wrapkey.pem assert_success "Delete wrapkey" #Wrap and unwrap EC object with generated wrap key run "${command_args[@]}" -p password -a get-rsa-wrapped --wrap-id "$keyid" -i "$eckey" -t asymmetric-key --out rsawrapped.object assert_success "Export wrapped EC object" run "${command_args[@]}" -p password -a delete-object -i "$eckey" -t asymmetric-key assert_success "Delete EC key" run "${command_args[@]}" -p password -a put-rsa-wrapped --wrap-id "$keyid" --in rsawrapped.object assert_success "Import wrapped EC object" run "${command_args[@]}" -p password -a get-object-info -i "$eckey" -t asymmetric-key assert_success "Get object info" seq_ec=$((seq_ec+1)) assert_output --partial "sequence: "$seq_ec"" assert_output --partial "capabilities: exportable-under-wrap:sign-ecdsa" run "${command_args[@]}" -p password -a sign-ecdsa -i "$eckey" -A ecdsa-sha1 --in data.txt assert_success "Perform signature with imported wrapped EC key" run rm rsawrapped.object assert_success "Removed RSA wrapped object" #Wrap and unwrap EC key material with generated RSA wrap key run "${command_args[@]}" -p password -a get-rsa-wrapped-key --wrap-id "$keyid" -i "$eckey" -t asymmetric-key --oaep rsa-oaep-sha1 --mgf1 mgf1-sha384 --out rsawrapped.key assert_success "Export wrapped EC key material" run "${command_args[@]}" -p password -a delete-object -i "$eckey" -t asymmetric-key assert_success "Delete EC key" run "${command_args[@]}" -p password -a put-rsa-wrapped-key --wrap-id "$keyid" -i "$eckey" -t asymmetric-key -A ecp224 -c exportable-under-wrap,sign-ecdsa --oaep rsa-oaep-sha1 --mgf1 mgf1-sha384 --in rsawrapped.key assert_success "Import wrapped EC key material" run "${command_args[@]}" -p password -a get-object-info -i "$eckey" -t asymmetric-key assert_success "Get object info" seq_ec=$((seq_ec+1)) assert_output --partial "sequence: "$seq_ec"" assert_output --partial "origin: imported:imported_wrapped" assert_output --partial "capabilities: exportable-under-wrap:sign-ecdsa" run "${command_args[@]}" -p password -a sign-ecdsa -i "$eckey" -A ecdsa-sha1 --in data.txt assert_success "Perform signature with imported wrapped EC key" run rm rsawrapped.key assert_success "Removed RSA wrapped key" if [[ "$aes_enabled" = true ]]; then #Wrap and unwrap AES object with generated RSA wrap key run "${command_args[@]}" -p password -a get-rsa-wrapped --wrap-id "$keyid" -i "$aeskey" -t symmetric-key --out rsawrapped.object assert_success "Export wrapped AES object" run "${command_args[@]}" -p password -a delete-object -i "$aeskey" -t symmetric-key assert_success "Delete AES key" run "${command_args[@]}" -p password -a put-rsa-wrapped --wrap-id "$keyid" --in rsawrapped.object assert_success "Import wrapped AES object" run "${command_args[@]}" -p password -a get-object-info -i "$aeskey" -t symmetric-key assert_success "Get object info" seq_aes=$((seq_aes+1)) assert_output --partial "sequence: "$seq_aes"" assert_output --partial "capabilities: decrypt-cbc:encrypt-cbc:exportable-under-wrap" run "${command_args[@]}" -p password -a encrypt-aescbc -i "$aeskey" --iv "$iv" --in "$data" --out data.enc assert_success "Perform encryption with imported wrapped AES key" run "${command_args[@]}" -p password -a decrypt-aescbc -i "$aeskey" --iv "$iv" --in data.enc decrypted_data=$(echo "$output" | tail -n 1) assert_equal "$decrypted_data" "$data" assert_success "Perform decryption with imported wrapped AES key" run rm rsawrapped.object data.enc assert_success "Removed RSA wrapped object and encrypted data" #Wrap and unwrap AES key material with generated RSA wrap key run "${command_args[@]}" -p password -a get-rsa-wrapped-key --wrap-id "$keyid" -i "$aeskey" -t symmetric-key --oaep rsa-oaep-sha384 --mgf1 mgf1-sha1 --out rsawrapped.key assert_success "Export wrapped AES key material" run "${command_args[@]}" -p password -a delete-object -i "$aeskey" -t symmetric-key assert_success "Delete AES key" run "${command_args[@]}" -p password -a put-rsa-wrapped-key --wrap-id "$keyid" -i "$aeskey" -t symmetric-key -A aes128 -c exportable-under-wrap,decrypt-cbc,encrypt-cbc --oaep rsa-oaep-sha384 --mgf1 mgf1-sha1 --in rsawrapped.key assert_success "Import wrapped AES key material" run "${command_args[@]}" -p password -a get-object-info -i "$aeskey" -t symmetric-key assert_success "Get object info" seq_aes=$((seq_aes+1)) assert_output --partial "sequence: "$seq_aes"" assert_output --partial "origin: imported:imported_wrapped" assert_output --partial "capabilities: decrypt-cbc:encrypt-cbc:exportable-under-wrap" run "${command_args[@]}" -p password -a sign-ecdsa -i "$eckey" -A ecdsa-sha1 --in data.txt assert_success "Perform signature with imported wrapped EC key" run "${command_args[@]}" -p password -a encrypt-aescbc -i "$aeskey" --iv "$iv" --in "$data" --out data.enc assert_success "Perform encryption with imported wrapped AES key" run "${command_args[@]}" -p password -a decrypt-aescbc -i "$aeskey" --iv "$iv" --in data.enc assert_success "Perform decryption with imported wrapped AES key" run "${command_args[@]}" -p password -a decrypt-aescbc -i "$aeskey" --iv "$iv" --in data.enc assert_success "Decryption succeeded" last_line_of_output=$(echo "$output" | tail -n 1) assert_equal "$last_line_of_output" "$data" run rm rsawrapped.key data.enc assert_success "Removed RSA wrapped key and encrypted data" fi #Import RSA wrap keys run openssl genrsa -out keypair.pem "$k" assert_success "Generate RSA key with openssl" run openssl rsa -in keypair.pem -pubout -out key.pub assert_success "Extract public key from openssl generated keypair" run "${command_args[@]}" -p password -a put-rsa-wrapkey -i 0 -d 1 -c import-wrapped --delegated exportable-under-wrap,sign-ecdsa,encrypt-cbc,decrypt-cbc --in keypair.pem assert_success "Import RSA wrap key" import_keyid=$(echo "$output" | awk '/Stored Wrap key/ {print $4}') run "${command_args[@]}" -p password -a get-object-info -i "$import_keyid" -t wrap-key assert_success "Get object info" assert_output --partial "algorithm: rsa"$k"" assert_output --partial "origin: imported" run "${command_args[@]}" -p password -a put-public-wrapkey -i "$import_keyid" -c export-wrapped --delegated exportable-under-wrap,sign-ecdsa,encrypt-cbc,decrypt-cbc --in key.pub assert_success "Import RSA public wrap key" run rm keypair.pem key.pub assert_success "Remove keypairs" #Wrap and unwrap EC object with imported RSA wrap key run "${command_args[@]}" -p password -a get-rsa-wrapped --wrap-id "$import_keyid" -i "$eckey" -t asymmetric-key --out rsawrapped.object assert_success "Export wrapped EC object" run "${command_args[@]}" -p password -a delete-object -i "$eckey" -t asymmetric-key assert_success "Delete EC key" run "${command_args[@]}" -p password -a put-rsa-wrapped --wrap-id "$import_keyid" --in rsawrapped.object assert_success "Import wrapped EC objects" run "${command_args[@]}" -p password -a get-object-info -i "$eckey" -t asymmetric-key assert_success "Get object info" seq_ec=$((seq_ec+1)) assert_output --partial "sequence: "$seq_ec"" assert_output --partial "origin: imported:imported_wrapped" assert_output --partial "capabilities: exportable-under-wrap:sign-ecdsa" run "${command_args[@]}" -p password -a sign-ecdsa -i "$eckey" -A ecdsa-sha1 --in data.txt assert_success "Perform signature with imported wrapped EC key" run rm rsawrapped.object assert_success "Delete RSA wrapped object" #Wrap and unwrap EC key material with imported RSA wrap key run "${command_args[@]}" -p password -a get-rsa-wrapped-key --wrap-id "$import_keyid" -i "$eckey" -t asymmetric-key --oaep rsa-oaep-sha512 --mgf1 mgf1-sha512 --out rsawrapped.key assert_success "Export wrapped EC key material" run "${command_args[@]}" -p password -a delete-object -i "$eckey" -t asymmetric-key assert_success "Delete EC key" run "${command_args[@]}" -p password -a put-rsa-wrapped-key --wrap-id "$import_keyid" -i "$eckey" -t asymmetric-key -A ecp224 -c exportable-under-wrap,sign-ecdsa --oaep rsa-oaep-sha512 --mgf1 mgf1-sha512 --in rsawrapped.key assert_success "Import wrapped EC key material" run "${command_args[@]}" -p password -a get-object-info -i "$eckey" -t asymmetric-key assert_success "Get object info" seq_ec=$((seq_ec+1)) assert_output --partial "sequence: "$seq_ec"" assert_output --partial "origin: imported:imported_wrapped" assert_output --partial "capabilities: exportable-under-wrap:sign-ecdsa" run "${command_args[@]}" -p password -a sign-ecdsa -i "$eckey" -A ecdsa-sha1 --in data.txt assert_success "Perform signature with imported wrapped EC key" run rm rsawrapped.key assert_success "Removed RSA wrapped key" if [[ "$aes_enabled" = true ]]; then #Wrap and unwrap AES object with imported RSA wrap key run "${command_args[@]}" -p password -a get-rsa-wrapped --wrap-id "$import_keyid" -i "$aeskey" -t symmetric-key --out rsawrapped.object assert_success "Export wrapped AES object" run "${command_args[@]}" -p password -a delete-object -i "$aeskey" -t symmetric-key assert_success "Deleta AES key" run "${command_args[@]}" -p password -a put-rsa-wrapped --wrap-id "$import_keyid" --in rsawrapped.object assert_success "Import wrapped AES object" run "${command_args[@]}" -p password -a get-object-info -i "$aeskey" -t symmetric-key assert_success "Get object info" seq_aes=$((seq_aes+1)) assert_output --partial "sequence: "$seq_aes"" assert_output --partial "origin: imported:imported_wrapped" assert_output --partial "capabilities: decrypt-cbc:encrypt-cbc:exportable-under-wrap" run "${command_args[@]}" -p password -a encrypt-aescbc -i "$aeskey" --iv "$iv" --in "$data" --out data.enc assert_success "Perform encryption with imported wrapped AES key" run "${command_args[@]}" -p password -a decrypt-aescbc -i "$aeskey" --iv "$iv" --in data.enc assert_success "Perform decryption with imported wrapped AES key" run "${command_args[@]}" -p password -a decrypt-aescbc -i "$aeskey" --iv "$iv" --in data.enc assert_success "Decryption succeeded" last_line_of_output=$(echo "$output" | tail -n 1) assert_equal "$last_line_of_output" "$data" run rm rsawrapped.object data.enc assert_success "Removed RSA wrapped object and encrypted data" #Wrap and unwrap AES key material with imported RSA wrap key run "${command_args[@]}" -p password -a get-rsa-wrapped-key --wrap-id "$import_keyid" -i "$aeskey" -t symmetric-key --oaep rsa-oaep-sha1 --mgf1 mgf1-sha384 --out rsawrapped.key assert_success "Export wrapped AES key material" run "${command_args[@]}" -p password -a delete-object -i "$aeskey" -t symmetric-key assert_success "Delete AES key" run "${command_args[@]}" -p password -a put-rsa-wrapped-key --wrap-id "$import_keyid" -i "$aeskey" -t symmetric-key -A aes128 -c exportable-under-wrap,decrypt-cbc,encrypt-cbc --oaep rsa-oaep-sha1 --mgf1 mgf1-sha384 --in rsawrapped.key assert_success "Import wrapped AES key materiak" run "${command_args[@]}" -p password -a get-object-info -i "$aeskey" -t symmetric-key assert_success "Get object info" seq_aes=$((seq_aes+1)) assert_output --partial "sequence: "$seq_aes"" assert_output --partial "origin: imported:imported_wrapped" assert_output --partial "capabilities: decrypt-cbc:encrypt-cbc:exportable-under-wrap" run "${command_args[@]}" -p password -a sign-ecdsa -i "$eckey" -A ecdsa-sha1 --in data.txt assert_success "Perform encryption with imported wrapped EC key" run "${command_args[@]}" -p password -a encrypt-aescbc -i "$aeskey" --iv "$iv" --in "$data" --out data.enc assert_success "Perform encryption with imported wrapped AES key" run "${command_args[@]}" -p password -a decrypt-aescbc -i "$aeskey" --iv "$iv" --in data.enc assert_success "Perform decryption with imported wrapped AES key" run "${command_args[@]}" -p password -a decrypt-aescbc -i "$aeskey" --iv "$iv" --in data.enc assert_success "Decryption succeeded" last_line_of_output=$(echo "$output" | tail -n 1) assert_equal "$last_line_of_output" "$data" run rm rsawrapped.key data.enc assert_success "Removed RSA wrapped key and encrypted data" fi #Clean up run "${command_args[@]}" -p password -a delete-object -i "$keyid" -t wrap-key assert_success "Delete generated RSA wrap key" run "${command_args[@]}" -p password -a delete-object -i "$keyid" -t public-wrap-key assert_success "Delete generated RSA public wrap key" run "${command_args[@]}" -p password -a delete-object -i "$import_keyid" -t wrap-key assert_success "Delete imported RSA wrap key" run "${command_args[@]}" -p password -a delete-object -i "$import_keyid" -t public-wrap-key assert_success "Delete imported RSA public wrap key" done } @test "List Objects" { [[ "$LIST_TESTS" == "true" ]] || skip "skipping right now" command_args=("$BIN" "$c_var" "$SPECIFIED_CONNECTOR") run "${command_args[@]}" -p password -a reset assert_success "HSM was reset" sleep 3 run "${command_args[@]}" -p password -a generate-asymmetric-key -i 100 -l ecKey -d 5,8,13 -c sign-ecdsa,derive-ecdh,sign-attestation-certificate -A ecp224 assert_success "Generate EC key for testing" run "${command_args[@]}" -p password -a list-objects -A any -t any -i 100 assert_success "List objects by ID" assert_output --partial "Found 1 object(s)" run "${command_args[@]}" -p password -a list-objects -A any -t asymmetric-key assert_success "List objects by type" assert_output --partial "Found 1 object(s)" run "${command_args[@]}" -p password -a list-objects -A any -t any -d 5,8,13 assert_success "List objects by domain" assert_output --partial "Found 2 object(s)" run "${command_args[@]}" -p password -a list-objects -A any -t any -c sign-ecdsa,derive-ecdh,sign-attestation-certificate assert_success "List objects by capabilities" assert_output --partial "Found 2 object(s)" run "${command_args[@]}" -p password -a list-objects -A ecp224 -t any assert_success "List objects by algorithm" assert_output --partial "Found 1 object(s)" run "${command_args[@]}" -p password -a list-objects -A any -t any -l ecKey assert_success "List objects by label" assert_output --partial "Found 1 object(s)" run "${command_args[@]}" -p password -a delete-object -i 100 -t asymmetric-key assert_success "Delete key" } @test "Label Size" { [[ "$LABEL_TESTS" == "true" ]] || skip "skipping right now" command_args=("$BIN" "$c_var" "$SPECIFIED_CONNECTOR") run "${command_args[@]}" -p password -a reset assert_success "HSM was reset" sleep 3 run "${command_args[@]}" -p password -a generate-asymmetric-key -i 300 -d 5,8,13 -c sign-ecdsa -A ecp224 assert_success "Create key with no label" run "${command_args[@]}" -p password -a get-object-info -i 300 -t asymmetric-key assert_success "Get info for key with no label" assert_output --partial "label: \"\"" # --- Test with 39-character label --- run "${command_args[@]}" -p password -a generate-asymmetric-key -i 200 -l abcdefghijklmnopqrstuvwxyz0123456789abc -d 5,8,13 -c sign-ecdsa -A ecp224 assert_success "Create object with 39-character label" run "${command_args[@]}" -p password -a get-object-info -i 200 -t asymmetric-key assert_success "Get info for 39-character label" assert_output --partial "label: \"abcdefghijklmnopqrstuvwxyz0123456789abc\"" run "${command_args[@]}" -p password -a list-objects -A any -t any -l abcdefghijklmnopqrstuvwxyz0123456789abc assert_success "List objects with 39-character label" assert_output --partial "Found 1 object(s)" # --- Test with 40-character label --- run "${command_args[@]}" -p password -a generate-asymmetric-key -i 100 -l abcdefghijklmnopqrstuvwxyz0123456789abcd -d 5,8,13 -c sign-ecdsa -A ecp224 assert_success "Create object with 40-character label" run "${command_args[@]}" -p password -a list-objects -A any -t any -l abcdefghijklmnopqrstuvwxyz0123456789abcd assert_success "List objects with 40-character label" assert_output --partial "Found 1 object(s)" # --- Test that 41-character label FAILS --- run "${command_args[@]}" -p password -a generate-asymmetric-key -i 400 -l "abcdefghijklmnopqrstuvwxyz0123456789abcde" -d "5,8,13" -c "sign-ecdsa" -A "ecp224" assert_failure assert_output --partial "Invalid argument to a function" # --- Test listing a non-existent label --- run "${command_args[@]}" -p password -a list-objects -A any -t any -l doesnotexist assert_success "List objects by non-existent label" assert_output --partial "Found 0 object(s)" # --- Clean up created objects --- run "${command_args[@]}" -p password -a delete-object -i 100 -t asymmetric-key assert_success "Clean up key 100" run "${command_args[@]}" -p password -a delete-object -i 200 -t asymmetric-key assert_success "Clean up key 200" run "${command_args[@]}" -p password -a delete-object -i 300 -t asymmetric-key assert_success "Clean up key 300" } @test "Authentication" { [[ "$AUTHENTICATION_TESTS" == "true" ]] || skip "skipping right now" command_args=("$BIN" "$c_var" "$SPECIFIED_CONNECTOR") run "${command_args[@]}" -p password -a reset assert_success "HSM was reset" sleep 3 run "${command_args[@]}" -p password -a put-authentication-key -i 0 -l authkey -d 1,2,3 -c all --delegated all --new-password foo123 assert_success "Create new authentication key" keyid=$(echo "$output" | tail -1 | awk '{print $4}') run "${command_args[@]}" --authkey "$keyid" -p foo123 -a get-object-info -i 1 -t authentication-key assert_success "Authenticate with new authentication key" run "${command_args[@]}" -p password -a delete-object -i "$keyid" -t authentication-key assert_success "Delete authentication key" }yubihsm-shell-2.8.0/resources/tests/bash/opensc_test.sh0000755000175100017510000004620515221003515022673 0ustar runnerrunner#!/bin/bash if [ "$#" -ne 1 ]; then echo "Usage: ./opensc_test.sh " echo "" echo "This script expects that YUBIHSM_PKCS11_CONF environment variable is defined" exit fi MODULE=$1 #$env:YUBIHSM_PKCS11_CONF=$YHPKCS11CFG test () { set +e $1 > output.txt 2>&1 ret=$? if [ $ret -ne 0 ]; then echo $1 cat output.txt rm output.txt exit 1 else echo "$2 ... OK!" rm output.txt fi set -e } set -e echo "this is test data" > data.txt ### Note about pkcs11-tool and object id: ### When generating/importing private keys, an ID has to be specified otherwise, practically a random key will be used ### when, for example, signing. This is because pkcs11-tool, unless a specific ID is set in the command line, it will use ### the first private key it finds to perform the operation. Setting/using a key's label/alias will not have an effect ### because it will not look for a key by label/alias. However, specifying an object to delete by its label/alias seems ### to work just fine. EC_CURVES=("secp224r1" "secp256r1" "secp384r1" "secp521r1" "secp256k1") set +e cat /etc/os-release | grep 'Fedora' is_fedora=$? set -e if [ $is_fedora -ne 0 ]; then EC_CURVES=(${EC_CURVES[@]} "brainpoolP256r1" "brainpoolP384r1" "brainpoolP512r1") fi for curve in "${EC_CURVES[@]}"; do echo "**********************************" echo " $curve" echo "**********************************" # # Generate key test "pkcs11-tool --module $MODULE --login --pin 0001password --keypairgen --id 1 --key-type EC:$curve" " Generate EC key with curve $curve" test "pkcs11-tool --module $MODULE --login --pin 0001password --read-object --id 1 --type pubkey --output-file pubkey.der" " Get public key of generated key" # Sign with generated key test "pkcs11-tool --module $MODULE --sign --pin 0001password --id 1 -m ECDSA-SHA1 --signature-format openssl -i data.txt -o data.sig" " Sign with generated key and ECDSA-SHA1" test "openssl dgst -sha1 -verify pubkey.der -signature data.sig data.txt" " Verify signature with OpenSSL" test "pkcs11-tool --module $MODULE --sign --pin 0001password --id 1 -m ECDSA-SHA256 --signature-format openssl -i data.txt -o data.sig" " Sign with generated key and ECDSA-SHA256" test "openssl dgst -sha256 -verify pubkey.der -signature data.sig data.txt" " Verify signature with OpenSSL" test "pkcs11-tool --module $MODULE --sign --pin 0001password --id 1 -m ECDSA-SHA384 --signature-format openssl -i data.txt -o data.sig" " Sign with generated key and ECDSA-SHA384" test "openssl dgst -sha384 -verify pubkey.der -signature data.sig data.txt" " Verify signature with OpenSSL" test "pkcs11-tool --module $MODULE --sign --pin 0001password --id 1 -m ECDSA-SHA512 --signature-format openssl -i data.txt -o data.sig" " Sign with generated key and ECDSA-SHA512" test "openssl dgst -sha512 -verify pubkey.der -signature data.sig data.txt" " Verify signature with OpenSSL" # Import key test "openssl ecparam -genkey -name $curve -noout -out keypair.pem" " Generate keypair with curve $curve using OpenSSL" test "pkcs11-tool --module $MODULE --login --pin 0001password --write-object keypair.pem --id 2 --type privkey --usage-sign" " Import EC key with curve $curve" test "pkcs11-tool --module $MODULE --login --pin 0001password --read-object --id 2 --type pubkey --output-file pubkey_imported.der" " Get public key of imported key" # Sign with imported key test "pkcs11-tool --module $MODULE --sign --pin 0001password --id 2 -m ECDSA-SHA1 --signature-format openssl -i data.txt -o data.sig" " Sign with imported key and ECDSA-SHA1" test "openssl dgst -sha1 -verify pubkey_imported.der -signature data.sig data.txt" " Verify signature with OpenSSL" test "pkcs11-tool --module $MODULE --sign --pin 0001password --id 2 -m ECDSA-SHA256 --signature-format openssl -i data.txt -o data.sig" " Sign with imported key and ECDSA-SHA256" test "openssl dgst -sha256 -verify pubkey_imported.der -signature data.sig data.txt" " Verify signature with OpenSSL" test "pkcs11-tool --module $MODULE --sign --pin 0001password --id 2 -m ECDSA-SHA384 --signature-format openssl -i data.txt -o data.sig" " Sign with imported key and ECDSA-SHA384" test "openssl dgst -sha384 -verify pubkey_imported.der -signature data.sig data.txt" " Verify signature with OpenSSL" test "pkcs11-tool --module $MODULE --sign --pin 0001password --id 2 -m ECDSA-SHA512 --signature-format openssl -i data.txt -o data.sig" " Sign with imported key and ECDSA-SHA512" test "openssl dgst -sha512 -verify pubkey_imported.der -signature data.sig data.txt" " Verify signature with OpenSSL" # Derive ECDH test "pkcs11-tool --module $MODULE --login --pin 0001password --derive --id 1 --input-file pubkey_imported.der --output-file ecdh_pkcs11.bin" " Derive ECDH using pkcs11-tool" test "openssl pkeyutl -derive -inkey keypair.pem -peerkey pubkey.der -out ecdh_openssl.bin" " Derive ECDH using OpenSSL" test "cmp ecdh_pkcs11.bin ecdh_openssl.bin" " Compare the derived ECDH keys" test "rm ecdh_pkcs11.bin ecdh_openssl.bin" " Delete ecdh keys" # Requires writable session? yubihsm-pkcs11 only allowed regular users #pkcs11-tool --module $MODULE --login --pin 0001password --test-ec --id 200 --key-type EC:secp256r1 # Delete keys test "pkcs11-tool --module $MODULE --login --pin 0001password --delete-object --id 1 --type privkey" " Delete generated key" test "pkcs11-tool --module $MODULE --login --pin 0001password --delete-object --id 2 --type privkey" " Delete imported key" done RSA_LENGTHS=("2048" "3072" "4096") test "openssl dgst -sha1 -binary -out data.sha1 data.txt" " Hash data with SHA1 and OpenSSL" test "openssl dgst -sha256 -binary -out data.sha256 data.txt" " Hash data with SHA256 and OpenSSL" test "openssl dgst -sha384 -binary -out data.sha384 data.txt" " Hash data with SHA384 and OpenSSL" test "openssl dgst -sha512 -binary -out data.sha512 data.txt" " Hash data with SHA512 and OpenSSL" for len in "${RSA_LENGTHS[@]}"; do echo "**********************************" echo " RSA$len" echo "**********************************" # Generate key test "pkcs11-tool --module $MODULE --login --pin 0001password --keypairgen --id 1 --key-type rsa:$len --usage-sign --usage-decrypt" " Generate RSA$len key" test "pkcs11-tool --module $MODULE --login --pin 0001password --read-object --id 1 --type pubkey --output-file pubkey.der" " Get public key of generated key" # Sign with generated key and RSA-PKCS test "pkcs11-tool --module $MODULE --sign --pin 0001password --id 1 -m SHA1-RSA-PKCS -i data.txt -o data.sig" " Sign with generated key and SHA1-RSA-PKCS" test "openssl dgst -sha1 -verify pubkey.der -signature data.sig data.txt" " Verify signature with OpenSSL" test "pkcs11-tool --module $MODULE --sign --pin 0001password --id 1 -m SHA256-RSA-PKCS -i data.txt -o data.sig" " Sign with generated key and SHA256-RSA-PKCS" test "openssl dgst -sha256 -verify pubkey.der -signature data.sig data.txt" " Verify signature with OpenSSL" test "pkcs11-tool --module $MODULE --sign --pin 0001password --id 1 -m SHA384-RSA-PKCS -i data.txt -o data.sig" " Sign with generated key and SHA384-RSA-PKCS" test "openssl dgst -sha384 -verify pubkey.der -signature data.sig data.txt" " Verify signature with OpenSSL" test "pkcs11-tool --module $MODULE --sign --pin 0001password --id 1 -m SHA512-RSA-PKCS -i data.txt -o data.sig" " Sign with generated key and SHA512-RSA-PKCS" test "openssl dgst -sha512 -verify pubkey.der -signature data.sig data.txt" " Verify signature with OpenSSL" # Sign with generated key and RSA-PSS test "pkcs11-tool --module $MODULE --sign --pin 0001password --id 1 -m SHA1-RSA-PKCS-PSS -i data.txt -o data.sig" " Sign with generated key and SHA1-RSA-PKCS-PSS" test "openssl pkeyutl -verify -in data.sha1 -sigfile data.sig -pkeyopt rsa_padding_mode:pss -pubin -inkey pubkey.der -pkeyopt rsa_pss_saltlen:-1 -pkeyopt digest:sha1" " Verify signature with OpenSSL" test "pkcs11-tool --module $MODULE --sign --pin 0001password --id 1 -m SHA256-RSA-PKCS-PSS -i data.txt -o data.sig" " Sign with generated key and SHA256-RSA-PKCS-PSS" test "openssl pkeyutl -verify -in data.sha256 -sigfile data.sig -pkeyopt rsa_padding_mode:pss -pubin -inkey pubkey.der -pkeyopt rsa_pss_saltlen:-1 -pkeyopt digest:sha256" " Verify signature with OpenSSL" test "pkcs11-tool --module $MODULE --sign --pin 0001password --id 1 -m SHA384-RSA-PKCS-PSS -i data.txt -o data.sig" " Sign with generated key and SHA384-RSA-PKCS-PSS" test "openssl pkeyutl -verify -in data.sha384 -sigfile data.sig -pkeyopt rsa_padding_mode:pss -pubin -inkey pubkey.der -pkeyopt rsa_pss_saltlen:-1 -pkeyopt digest:sha384" " Verify signature with OpenSSL" test "pkcs11-tool --module $MODULE --sign --pin 0001password --id 1 -m SHA512-RSA-PKCS-PSS -i data.txt -o data.sig" " Sign with generated key and SHA512-RSA-PKCS-PSS" test "openssl pkeyutl -verify -in data.sha512 -sigfile data.sig -pkeyopt rsa_padding_mode:pss -pubin -inkey pubkey.der -pkeyopt rsa_pss_saltlen:-1 -pkeyopt digest:sha512" " Verify signature with OpenSSL" # Decrypt with generated key and PKCS1v15 test "openssl rsautl -encrypt -inkey pubkey.der -pubin -in data.txt -out data.enc" " Encryp with OpenSSL using PKCS1v15" test "pkcs11-tool --module $MODULE --decrypt --pin 0001password --id 1 -m RSA-PKCS --input-file data.enc --output-file data.dec" " Decrypt using generated key" test "cmp data.dec data.txt" " Compare decrypted data with plain text data" test "rm data.enc data.dec" " Delete test data" # Decrypt with generated key and OAEP test "openssl pkeyutl -encrypt -pubin -inkey pubkey.der -pkeyopt rsa_padding_mode:oaep -pkeyopt rsa_oaep_md:sha1 -pkeyopt rsa_mgf1_md:sha1 -in data.txt -out data.enc" " Encrypt with OpenSSL using OAEP and SHA1" test "pkcs11-tool --module $MODULE --decrypt --pin 0001password --id 1 -m RSA-PKCS-OAEP --hash-algorithm=SHA-1 --input-file data.enc --output-file data.dec" " Decrypt using generated key" test "cmp data.dec data.txt" " Compare decrypted data with plain text data" test "rm data.enc data.dec" " Delete test data" test "openssl pkeyutl -encrypt -pubin -inkey pubkey.der -pkeyopt rsa_padding_mode:oaep -pkeyopt rsa_oaep_md:sha256 -pkeyopt rsa_mgf1_md:sha256 -in data.txt -out data.enc" " Encrypt with OpenSSL using OAEP and SHA256" test "pkcs11-tool --module $MODULE --decrypt --pin 0001password --id 1 -m RSA-PKCS-OAEP --hash-algorithm=SHA256 --input-file data.enc --output-file data.dec" " Decrypt using generated key" test "cmp data.dec data.txt" " Compare decrypted data with plain text data" test "rm data.enc data.dec" " Delete test data" test "openssl pkeyutl -encrypt -pubin -inkey pubkey.der -pkeyopt rsa_padding_mode:oaep -pkeyopt rsa_oaep_md:sha384 -pkeyopt rsa_mgf1_md:sha384 -in data.txt -out data.enc" " Encrypt with OpenSSL using OAEP and SHA384" test "pkcs11-tool --module $MODULE --decrypt --pin 0001password --id 1 -m RSA-PKCS-OAEP --hash-algorithm=SHA384 --input-file data.enc --output-file data.dec" " Decrypt using generated key" test "cmp data.dec data.txt" " Compare decrypted data with plain text data" test "rm data.enc data.dec" " Delete test data" test "openssl pkeyutl -encrypt -pubin -inkey pubkey.der -pkeyopt rsa_padding_mode:oaep -pkeyopt rsa_oaep_md:sha512 -pkeyopt rsa_mgf1_md:sha512 -in data.txt -out data.enc" " Encrypt with OpenSSL using OAEP and SHA512" test "pkcs11-tool --module $MODULE --decrypt --pin 0001password --id 1 -m RSA-PKCS-OAEP --hash-algorithm=SHA512 --input-file data.enc --output-file data.dec" " Decrypt using generated key" test "cmp data.dec data.txt" " Compare decrypted data with plain text data" test "rm data.enc data.dec" " Delete test data" # Import key test "openssl genrsa -out keypair.pem $len" " Generate key with OpenSSL" test "pkcs11-tool --module $MODULE --login --pin 0001password --write-object keypair.pem --id 2 --type privkey --usage-sign --usage-decrypt" " Import RSA$len key" test "pkcs11-tool --module $MODULE --login --pin 0001password --read-object --id 2 --type pubkey --output-file pubkey_imported.der" " Get public key of imported key" # Sign with imported key and PKCS test "pkcs11-tool --module $MODULE --sign --pin 0001password --id 2 -m SHA1-RSA-PKCS -i data.txt -o data.sig" " Sign with imported key and SHA1-RSA-PKCS" test "openssl dgst -sha1 -verify pubkey_imported.der -signature data.sig data.txt" " Verify signature with OpenSSL" test "pkcs11-tool --module $MODULE --sign --pin 0001password --id 2 -m SHA256-RSA-PKCS -i data.txt -o data.sig" " Sign with imported key and SHA256-RSA-PKCS" test "openssl dgst -sha256 -verify pubkey_imported.der -signature data.sig data.txt" " Verify signature with OpenSSL" test "pkcs11-tool --module $MODULE --sign --pin 0001password --id 2 -m SHA384-RSA-PKCS -i data.txt -o data.sig" " Sign with imported key and SHA384-RSA-PKCS" test "openssl dgst -sha384 -verify pubkey_imported.der -signature data.sig data.txt" " Verify signature with OpenSSL" test "pkcs11-tool --module $MODULE --sign --pin 0001password --id 2 -m SHA512-RSA-PKCS -i data.txt -o data.sig" " Sign with imported key and SHA512-RSA-PKCS" test "openssl dgst -sha512 -verify pubkey_imported.der -signature data.sig data.txt" " Verify signature with OpenSSL" # Sign with imported key and RSA-PSS test "pkcs11-tool --module $MODULE --sign --pin 0001password --id 2 -m SHA1-RSA-PKCS-PSS -i data.txt -o data.sig" " Sign with imported key and SHA1-RSA-PKCS-PSS" test "openssl pkeyutl -verify -in data.sha1 -sigfile data.sig -pkeyopt rsa_padding_mode:pss -pubin -inkey pubkey_imported.der -pkeyopt rsa_pss_saltlen:-1 -pkeyopt digest:sha1" " Verify signature with OpenSSL" test "pkcs11-tool --module $MODULE --sign --pin 0001password --id 2 -m SHA256-RSA-PKCS-PSS -i data.txt -o data.sig" " Sign with imported key and SHA256-RSA-PKCS-PSS" test "openssl pkeyutl -verify -in data.sha256 -sigfile data.sig -pkeyopt rsa_padding_mode:pss -pubin -inkey pubkey_imported.der -pkeyopt rsa_pss_saltlen:-1 -pkeyopt digest:sha256" " Verify signature with OpenSSL" test "pkcs11-tool --module $MODULE --sign --pin 0001password --id 2 -m SHA384-RSA-PKCS-PSS -i data.txt -o data.sig" " Sign with imported key and SHA384-RSA-PKCS-PSS" test "openssl pkeyutl -verify -in data.sha384 -sigfile data.sig -pkeyopt rsa_padding_mode:pss -pubin -inkey pubkey_imported.der -pkeyopt rsa_pss_saltlen:-1 -pkeyopt digest:sha384" " Verify signature with OpenSSL" test "pkcs11-tool --module $MODULE --sign --pin 0001password --id 2 -m SHA512-RSA-PKCS-PSS -i data.txt -o data.sig" " Sign with imported key and SHA512-RSA-PKCS-PSS" test "openssl pkeyutl -verify -in data.sha512 -sigfile data.sig -pkeyopt rsa_padding_mode:pss -pubin -inkey pubkey_imported.der -pkeyopt rsa_pss_saltlen:-1 -pkeyopt digest:sha512" " Verify signature with OpenSSL" # Decrypt with imported key and PKCS1v15 test "openssl rsautl -encrypt -inkey pubkey_imported.der -pubin -in data.txt -out data.enc" " Encryp with OpenSSL using PKCS1v15" test "pkcs11-tool --module $MODULE --decrypt --pin 0001password --id 2 -m RSA-PKCS --input-file data.enc --output-file data.dec" " Decrypt using imported key" test "cmp data.dec data.txt" " Compare decrypted data with plain text data" test "rm data.enc data.dec" " Delete test data" # Decrypt with imported key and OAEP test "openssl pkeyutl -encrypt -pubin -inkey pubkey_imported.der -pkeyopt rsa_padding_mode:oaep -pkeyopt rsa_oaep_md:sha1 -pkeyopt rsa_mgf1_md:sha1 -in data.txt -out data.enc" " Encrypt with OpenSSL using OAEP and SHA1" test "pkcs11-tool --module $MODULE --decrypt --pin 0001password --id 2 -m RSA-PKCS-OAEP --hash-algorithm=SHA-1 --input-file data.enc --output-file data.dec" " Decrypt using imported key" test "cmp data.dec data.txt" " Compare decrypted data with plain text data" test "rm data.enc data.dec" " Delete test data" test "openssl pkeyutl -encrypt -pubin -inkey pubkey_imported.der -pkeyopt rsa_padding_mode:oaep -pkeyopt rsa_oaep_md:sha256 -pkeyopt rsa_mgf1_md:sha256 -in data.txt -out data.enc" " Encrypt with OpenSSL using OAEP and SHA256" test "pkcs11-tool --module $MODULE --decrypt --pin 0001password --id 2 -m RSA-PKCS-OAEP --hash-algorithm=SHA256 --input-file data.enc --output-file data.dec" " Decrypt using imported key" test "cmp data.dec data.txt" " Compare decrypted data with plain text data" test "rm data.enc data.dec" " Delete test data" test "openssl pkeyutl -encrypt -pubin -inkey pubkey_imported.der -pkeyopt rsa_padding_mode:oaep -pkeyopt rsa_oaep_md:sha384 -pkeyopt rsa_mgf1_md:sha384 -in data.txt -out data.enc" " Encrypt with OpenSSL using OAEP and SHA384" test "pkcs11-tool --module $MODULE --decrypt --pin 0001password --id 2 -m RSA-PKCS-OAEP --hash-algorithm=SHA384 --input-file data.enc --output-file data.dec" " Decrypt using imported key" test "cmp data.dec data.txt" " Compare decrypted data with plain text data" test "rm data.enc data.dec" " Delete test data" test "openssl pkeyutl -encrypt -pubin -inkey pubkey_imported.der -pkeyopt rsa_padding_mode:oaep -pkeyopt rsa_oaep_md:sha512 -pkeyopt rsa_mgf1_md:sha512 -in data.txt -out data.enc" " Encrypt with OpenSSL using OAEP and SHA512" test "pkcs11-tool --module $MODULE --decrypt --pin 0001password --id 2 -m RSA-PKCS-OAEP --hash-algorithm=SHA512 --input-file data.enc --output-file data.dec" " Decrypt using imported key" test "cmp data.dec data.txt" " Compare decrypted data with plain text data" test "rm data.enc data.dec" " Delete test data" # Perform pkcs11-tool RSA tests pkcs11-tool --module $MODULE --login --pin 0001password --test # Delete keys test "pkcs11-tool --module $MODULE --login --pin 0001password --delete-object --id 1 --type privkey" " Delete generated key" test "pkcs11-tool --module $MODULE --login --pin 0001password --delete-object --id 2 --type privkey" " Delete generated key" done rm data.sha1 data.sha256 data.sha384 data.sha512 data.sig data.txt rm keypair.pem pubkey.der pubkey_imported.der echo "****************************************************" echo " Compress X509 Certificate" echo "****************************************************" openssl req -x509 -newkey rsa:4096 -out too_large_cert.der -outform DER -sha256 -days 3650 -nodes -subj '/C=01/ST=01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567/L=01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567/O=0123456789012345678901234567890123456789012345678901234567890123/OU=0123456789012345678901234567890123456789012345678901234567890123' > /dev/null 2>&1 test "pkcs11-tool --module $MODULE --login --pin 0001password --write-object too_large_cert.der --id 6464 --type cert" " Import large X509 certificate" test "pkcs11-tool --module $MODULE --login --pin 0001password --read-object --id 6464 --type cert --output-file too_large_cert_out.der" " Get imported certificate" test "cmp too_large_cert.der too_large_cert_out.der" " Compare read certificate with the one imported" test "pkcs11-tool --module $MODULE --login --pin 0001password --delete-object --id 6464 --type cert" " Delete certificate" set +eyubihsm-shell-2.8.0/resources/tests/bash/template.dat0000644000175100017510000000060415221003515022304 0ustar runnerrunnerAQABCQIBAM3enEjbk5aw6JEezWDROOKvcLCmKB7kDPMn6IuLEUi7KsOjvetQJgD5kfRVwxYxCCAKlReTUvJFwg7gI5h3bF/xQF+FNZ2yojQ1rpvAAHvK8BROu6G6mlY4ZhzhzHDp6+8lUNDz5ljw2PTeGPj1T46MX3dY4r8OSljdsIn/IeVQoobriOF6cVXL5GGoLHzbqtr3jegM2WmrKUJjhKSEJL0WoAWRTYp+WeObMTlihZOM6KYYukQYE900K+YO3nnkEUHiQRDgYGTPNnUOXiGk5wcxk9xqHIHPUyzjdgwiP6/rWMCJ5fMc/EmyEBRFc1+sw1oZiT6cpJeqLHC0ocNKWB8DAAIACgQABAAAASwFAAQAAIygBgAFcm9vdAA=yubihsm-shell-2.8.0/resources/tests/ps1/0000755000175100017510000000000015221003515017565 5ustar runnerrunneryubihsm-shell-2.8.0/resources/tests/ps1/test_eckey.ps10000644000175100017510000010004615221003515022352 0ustar runnerrunner$ARCH=$args[0] if($ARCH -eq "x86") { if ((Get-Command "yubihsm-shell.exe" -ErrorAction SilentlyContinue) -eq $null) { $env:Path += ";C:/Program Files (x86)/Yubico/YubiHSM Shell/bin;C:/Users/dev/vcpkg/vcpkg-master/packages/openssl-windows_x86-windows/bin" } } elseif ($ARCH -eq "x64") { if ((Get-Command "yubihsm-shell.exe" -ErrorAction SilentlyContinue) -eq $null) { $env:Path += ";C:/Program Files/Yubico/YubiHSM Shell/bin;C:/Users/dev/vcpkg/vcpkg-master/packages/openssl-windows_x64-windows/bin" } } else { echo "Usage: ./cmdline_test.ps1 " echo "" echo "This is a test script that uses the yubihsm-shell command line tool to reset the conncted YubiHSM and then different commands." echo "" echo " x86 expects that yubihsm-shell.exe is installed in 'C:/Program Files (x86)/Yubico/Yubico PIV Tool/bin'" echo " x64 expects that yubhsm-shell.exe is installed in 'C:/Program Files/Yubico/Yubico PIV Tool/bin'" exit } $env:Path += ";C:\Users\dev\vcpkg\vcpkg-master\packages\openssl-windows_x64-windows\tools\openssl" echo "Running commands on $ARCH architecture" $TEST_DIR = "yubihsm-shell_test_dir" Remove-Item -Path "$TEST_DIR" -Recurse -ErrorAction SilentlyContinue New-Item $TEST_DIR -type Directory -Force cd $TEST_DIR echo "test signing data" > data.txt Set-PSDebug -Trace 1 $ErrorActionPreference = "Stop" function CheckExitStatus { param ( $ECode ) if(!$ECode) { echo "Fail!" exit } } $keyid=100 $import_keyid=200 echo "---------------------- EC keys --------------------- " # ECP224 echo "**********************************" echo " ECP224" echo "**********************************" #-- Generate yubihsm-shell.exe -p password -a generate-asymmetric-key -i $keyid -l "ecKey" -d "5,8,13" -c "sign-ecdsa,derive-ecdh,sign-attestation-certificate" -A "ecp224"; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a get-object-info -i $keyid -t asymmetric-key > info.txt; CheckExitStatus -ECode $? Select-String -Path "info.txt" -Pattern "id: 0x0064"; CheckExitStatus -ECode $? Select-String -Path "info.txt" -Pattern "type: asymmetric-key"; CheckExitStatus -ECode $? Select-String -Path "info.txt" -Pattern "algorithm: ec224df"; CheckExitStatus -ECode $? Select-String -Path "info.txt" -Pattern 'label: "ecKey"'; CheckExitStatus -ECode $? Select-String -Path "info.txt" -Pattern "domains: 5:8:13"; CheckExitStatus -ECode $? Select-String -Path "info.txt" -Pattern "origin: generated"; CheckExitStatus -ECode $? Select-String -Path "info.txt" -Pattern "capabilities: derive-ecdh:sign-attestation-certificate:sign-ecdsa"; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a get-public-key -i $keyid --outformat=PEM; CheckExitStatus -ECode $? #-- Import openssl.exe ecparam -genkey -name secp224r1 -noout -out secp224r1-keypair.pem; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a put-asymmetric-key -i $import_keyid -l "ecKeyImport" -d "2,6,7" -c "sign-ecdsa,sign-attestation-certificate" --in=secp224r1-keypair.pem; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a get-object-info -i $import_keyid -t asymmetric-key; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a get-public-key -i $import_keyid --outformat=PEM; CheckExitStatus -ECode $? # -- Sign yubihsm-shell.exe -p password -a sign-ecdsa -i $keyid -A ecdsa-sha1 --in data.txt > data.ecp224sha1.sig; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-ecdsa -i $keyid -A ecdsa-sha256 --in data.txt > data.ecp224sha256.sig; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-ecdsa -i $keyid -A ecdsa-sha384 --in data.txt > data.ecp224sha384.sig; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-ecdsa -i $keyid -A ecdsa-sha512 --in data.txt > data.ecp224sha512.sig; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-ecdsa -i $import_keyid -A ecdsa-sha1 --in data.txt > data.ecp224sha1.sig; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-ecdsa -i $import_keyid -A ecdsa-sha256 --in data.txt > data.ecp224sha256.sig; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-ecdsa -i $import_keyid -A ecdsa-sha384 --in data.txt > data.ecp224sha384.sig; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-ecdsa -i $import_keyid -A ecdsa-sha512 --in data.txt > data.ecp224sha512.sig; CheckExitStatus -ECode $? #-- Get attestation certificate and a selfsigned certificate yubihsm-shell.exe -p password -a sign-attestation-certificate -i $keyid --attestation-id 0 --out cert.pem; CheckExitStatus -ECode $? openssl.exe x509 -in cert.pem -out cert.der -outform DER; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a put-opaque -i $keyid -l template_cert -A opaque-x509-certificate --in cert.der; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-attestation-certificate -i $keyid --attestation-id=$keyid --out selfsigned_cert.pem; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a delete-object -i $keyid -t opaque; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a put-opaque -i $keyid -l java_cert -A opaque-x509-certificate --in selfsigned_cert.pem; CheckExitStatus -ECode $? rm selfsigned_cert.pem #-- Sign attestation certificate yubihsm-shell.exe -p password -a put-opaque -i $import_keyid -l template_cert -A opaque-x509-certificate --in cert.der; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-attestation-certificate -i $keyid --attestation-id=$import_keyid --out selfsigned_cert.der; CheckExitStatus -ECode $? #-- Derive ECDH openssl.exe ec -in secp224r1-keypair.pem -pubout -out secp224r1-pubkey.pem; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a derive-ecdh -i $keyid --in secp224r1-pubkey.pem; CheckExitStatus -ECode $? #-- Delete yubihsm-shell.exe -p password -a delete-object -i $keyid -t asymmetric-key; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a delete-object -i $keyid -t opaque; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a delete-object -i $import_keyid -t asymmetric-key; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a delete-object -i $import_keyid -t opaque; CheckExitStatus -ECode $? echo "**********************************" echo " ECP256" echo "**********************************" # ECP256 #-- Generate yubihsm-shell.exe -p password -a generate-asymmetric-key -i $keyid -l "ecKey" -d "5,8,13" -c "sign-ecdsa,derive-ecdh,sign-attestation-certificate" -A "ecp256"; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a get-public-key -i $keyid --outformat=PEM; CheckExitStatus -ECode $? #-- Import openssl.exe ecparam -genkey -name secp256r1 -noout -out secp256r1-keypair.pem; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a put-asymmetric-key -i $import_keyid -l "ecKeyImport" -d "1,2,3,4,5" -c "sign-ecdsa,sign-attestation-certificate" --in=secp256r1-keypair.pem; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a get-public-key -i $import_keyid --outformat=PEM; CheckExitStatus -ECode $? #-- Sign yubihsm-shell.exe -p password -a sign-ecdsa -i $keyid -A ecdsa-sha1 --in data.txt > data.ecp256sha1.sig; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-ecdsa -i $keyid -A ecdsa-sha256 --in data.txt > data.ecp256sha256.sig; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-ecdsa -i $keyid -A ecdsa-sha384 --in data.txt > data.ecp256sha384.sig; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-ecdsa -i $keyid -A ecdsa-sha512 --in data.txt > data.ecp256sha512.sig; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-ecdsa -i $import_keyid -A ecdsa-sha1 --in data.txt > data.ecp256sha1.sig; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-ecdsa -i $import_keyid -A ecdsa-sha256 --in data.txt > data.ecp256sha256.sig; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-ecdsa -i $import_keyid -A ecdsa-sha384 --in data.txt > data.ecp256sha384.sig; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-ecdsa -i $import_keyid -A ecdsa-sha512 --in data.txt > data.ecp256sha512.sig; CheckExitStatus -ECode $? #-- Get attestation certificate and a selfsigned certificate yubihsm-shell.exe -p password -a sign-attestation-certificate -i $keyid --attestation-id 0 --out cert.pem; CheckExitStatus -ECode $? openssl.exe x509 -in cert.pem -out cert.der -outform DER; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a put-opaque -i $keyid -l template_cert -A opaque-x509-certificate --in cert.der; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-attestation-certificate -i $keyid --attestation-id=$keyid --out selfsigned_cert.pem; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a delete-object -i $keyid -t opaque; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a put-opaque -i $keyid -l java_cert -A opaque-x509-certificate --in selfsigned_cert.pem; CheckExitStatus -ECode $? rm selfsigned_cert.pem #-- Sign attestation certificate yubihsm-shell.exe -p password -a put-opaque -i $import_keyid -l template_cert -A opaque-x509-certificate --in cert.der; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-attestation-certificate -i $keyid --attestation-id=$import_keyid --out selfsigned_cert.der; CheckExitStatus -ECode $? #-- Derive ECDH openssl.exe ec -in secp256r1-keypair.pem -pubout -out secp256r1-pubkey.pem; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a derive-ecdh -i $keyid --in secp256r1-pubkey.pem; CheckExitStatus -ECode $? #-- Delete yubihsm-shell.exe -p password -a delete-object -i $keyid -t asymmetric-key; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a delete-object -i $keyid -t opaque; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a delete-object -i $import_keyid -t asymmetric-key; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a delete-object -i $import_keyid -t opaque; CheckExitStatus -ECode $? echo "**********************************" echo " ECP384" echo "**********************************" # ECP384 #-- Generate yubihsm-shell.exe -p password -a generate-asymmetric-key -i $keyid -l "ecKey" -d "5,8,13" -c "sign-ecdsa,derive-ecdh,sign-attestation-certificate" -A "ecp384"; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a get-public-key -i $keyid --outformat=PEM; CheckExitStatus -ECode $? #-- Import openssl.exe ecparam -genkey -name secp384r1 -noout -out secp384r1-keypair.pem; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a put-asymmetric-key -i $import_keyid -l "ecKeyImport" -d "1,2,3,4,5" -c "sign-ecdsa,sign-attestation-certificate" --in=secp384r1-keypair.pem; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a get-public-key -i $import_keyid --outformat=PEM; CheckExitStatus -ECode $? #-- Sign yubihsm-shell.exe -p password -a sign-ecdsa -i $keyid -A ecdsa-sha1 --in data.txt > data.ecp384sha1.sig; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-ecdsa -i $keyid -A ecdsa-sha256 --in data.txt > data.ecp384sha256.sig; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-ecdsa -i $keyid -A ecdsa-sha384 --in data.txt > data.ecp384sha384.sig; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-ecdsa -i $keyid -A ecdsa-sha512 --in data.txt > data.ecp384sha512.sig; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-ecdsa -i $import_keyid -A ecdsa-sha1 --in data.txt > data.ecp384sha1.sig; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-ecdsa -i $import_keyid -A ecdsa-sha256 --in data.txt > data.ecp384sha256.sig; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-ecdsa -i $import_keyid -A ecdsa-sha384 --in data.txt > data.ecp384sha384.sig; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-ecdsa -i $import_keyid -A ecdsa-sha512 --in data.txt > data.ecp384sha512.sig; CheckExitStatus -ECode $? #-- Get attestation certificate and a selfsigned certificate yubihsm-shell.exe -p password -a sign-attestation-certificate -i $keyid --attestation-id 0 --out cert.pem; CheckExitStatus -ECode $? openssl.exe x509 -in cert.pem -out cert.der -outform DER; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a put-opaque -i $keyid -l template_cert -A opaque-x509-certificate --in cert.der; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-attestation-certificate -i $keyid --attestation-id=$keyid --out selfsigned_cert.pem; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a delete-object -i $keyid -t opaque; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a put-opaque -i $keyid -l java_cert -A opaque-x509-certificate --in selfsigned_cert.pem; CheckExitStatus -ECode $? rm selfsigned_cert.pem #-- Sign attestation certificate yubihsm-shell.exe -p password -a put-opaque -i $import_keyid -l template_cert -A opaque-x509-certificate --in cert.der; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-attestation-certificate -i $keyid --attestation-id=$import_keyid --out selfsigned_cert.der; CheckExitStatus -ECode $? #-- Derive ECDH openssl.exe ec -in secp384r1-keypair.pem -pubout -out secp384r1-pubkey.pem; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a derive-ecdh -i $keyid --in secp384r1-pubkey.pem; CheckExitStatus -ECode $? #-- Delete yubihsm-shell.exe -p password -a delete-object -i $keyid -t asymmetric-key; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a delete-object -i $keyid -t opaque; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a delete-object -i $import_keyid -t asymmetric-key; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a delete-object -i $import_keyid -t opaque; CheckExitStatus -ECode $? echo "**********************************" echo " ECP512" echo "**********************************" # ECP512 #-- Generate yubihsm-shell.exe -p password -a generate-asymmetric-key -i $keyid -l "ecKey" -d "5,8,13" -c "sign-ecdsa,derive-ecdh,sign-attestation-certificate" -A "ecp521"; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a get-public-key -i $keyid --outformat=PEM; CheckExitStatus -ECode $? #-- Import openssl ecparam -genkey -name secp521r1 -noout -out secp521r1-keypair.pem; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a put-asymmetric-key -i $import_keyid -l "ecKeyImport" -d "1,2,3,4,5" -c "sign-ecdsa,sign-attestation-certificate" --in=secp521r1-keypair.pem; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a get-public-key -i $import_keyid --outformat=PEM; CheckExitStatus -ECode $? #-- Sign yubihsm-shell.exe -p password -a sign-ecdsa -i $keyid -A ecdsa-sha1 --in data.txt > data.ecp521sha1.sig; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-ecdsa -i $keyid -A ecdsa-sha256 --in data.txt > data.ecp521sha256.sig; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-ecdsa -i $keyid -A ecdsa-sha384 --in data.txt > data.ecp521sha384.sig; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-ecdsa -i $keyid -A ecdsa-sha512 --in data.txt > data.ecp521sha512.sig; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-ecdsa -i $import_keyid -A ecdsa-sha1 --in data.txt > data.ecp521sha1.sig; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-ecdsa -i $import_keyid -A ecdsa-sha256 --in data.txt > data.ecp521sha256.sig; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-ecdsa -i $import_keyid -A ecdsa-sha384 --in data.txt > data.ecp521sha384.sig; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-ecdsa -i $import_keyid -A ecdsa-sha512 --in data.txt > data.ecp521sha512.sig; CheckExitStatus -ECode $? #-- Get attestation certificate and a selfsigned certificate yubihsm-shell.exe -p password -a sign-attestation-certificate -i $keyid --attestation-id 0 --out cert.pem; CheckExitStatus -ECode $? openssl.exe x509 -in cert.pem -out cert.der -outform DER; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a put-opaque -i $keyid -l template_cert -A opaque-x509-certificate --in cert.der; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-attestation-certificate -i $keyid --attestation-id=$keyid --out selfsigned_cert.pem; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a delete-object -i $keyid -t opaque; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a put-opaque -i $keyid -l java_cert -A opaque-x509-certificate --in selfsigned_cert.pem; CheckExitStatus -ECode $? rm selfsigned_cert.pem #-- Sign attestation certificate yubihsm-shell.exe -p password -a put-opaque -i $import_keyid -l template_cert -A opaque-x509-certificate --in cert.der; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-attestation-certificate -i $keyid --attestation-id=$import_keyid --out selfsigned_cert.der; CheckExitStatus -ECode $? #-- Derive ECDH openssl.exe ec -in secp521r1-keypair.pem -pubout -out secp521r1-pubkey.pem; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a derive-ecdh -i $keyid --in secp521r1-pubkey.pem; CheckExitStatus -ECode $? #-- Delete yubihsm-shell.exe -p password -a delete-object -i $keyid -t asymmetric-key; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a delete-object -i $keyid -t opaque; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a delete-object -i $import_keyid -t asymmetric-key; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a delete-object -i $import_keyid -t opaque; CheckExitStatus -ECode $? echo "**********************************" echo " ECK256" echo "**********************************" # ECK256 #-- Generate yubihsm-shell.exe -p password -a generate-asymmetric-key -i $keyid -l "ecKey" -d "5,8,13" -c "sign-ecdsa,derive-ecdh,sign-attestation-certificate" -A "eck256"; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a get-public-key -i $keyid --outformat=PEM; CheckExitStatus -ECode $? #-- Import openssl.exe ecparam -genkey -name secp256k1 -noout -out secp256k1-keypair.pem; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a put-asymmetric-key -i $import_keyid -l "ecKeyImport" -d "1,2,3,4,5" -c "sign-ecdsa,sign-attestation-certificate" --in=secp256k1-keypair.pem; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a get-public-key -i $import_keyid --outformat=PEM; CheckExitStatus -ECode $? #-- Sign yubihsm-shell.exe -p password -a sign-ecdsa -i $keyid -A ecdsa-sha1 --in data.txt > data.eck256sha1.sig; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-ecdsa -i $keyid -A ecdsa-sha256 --in data.txt > data.eck256sha256.sig; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-ecdsa -i $keyid -A ecdsa-sha384 --in data.txt > data.eck256sha384.sig; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-ecdsa -i $keyid -A ecdsa-sha512 --in data.txt > data.eck256sha512.sig; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-ecdsa -i $import_keyid -A ecdsa-sha1 --in data.txt > data.eck256sha1.sig; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-ecdsa -i $import_keyid -A ecdsa-sha256 --in data.txt > data.eck256sha256.sig; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-ecdsa -i $import_keyid -A ecdsa-sha384 --in data.txt > data.eck256sha384.sig; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-ecdsa -i $import_keyid -A ecdsa-sha512 --in data.txt > data.eck256sha512.sig; CheckExitStatus -ECode $? #-- Get attestation certificate and a selfsigned certificate yubihsm-shell.exe -p password -a sign-attestation-certificate -i $keyid --attestation-id 0 --out cert.pem; CheckExitStatus -ECode $? openssl.exe x509 -in cert.pem -out cert.der -outform DER yubihsm-shell.exe -p password -a put-opaque -i $keyid -l template_cert -A opaque-x509-certificate --in cert.der; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-attestation-certificate -i $keyid --attestation-id=$keyid --out selfsigned_cert.pem; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a delete-object -i $keyid -t opaque; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a put-opaque -i $keyid -l java_cert -A opaque-x509-certificate --in selfsigned_cert.pem; CheckExitStatus -ECode $? rm selfsigned_cert.pem #-- Sign attestation certificate yubihsm-shell.exe -p password -a put-opaque -i $import_keyid -l template_cert -A opaque-x509-certificate --in cert.der; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-attestation-certificate -i $keyid --attestation-id=$import_keyid --out selfsigned_cert.der; CheckExitStatus -ECode $? #-- Derive ECDH openssl.exe ec -in secp256k1-keypair.pem -pubout -out secp256k1-pubkey.pem; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a derive-ecdh -i $keyid --in secp256k1-pubkey.pem; CheckExitStatus -ECode $? #-- Delete yubihsm-shell.exe -p password -a delete-object -i $keyid -t asymmetric-key; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a delete-object -i $keyid -t opaque; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a delete-object -i $import_keyid -t asymmetric-key; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a delete-object -i $import_keyid -t opaque; CheckExitStatus -ECode $? echo "**********************************" echo " Brainpool256" echo "**********************************" # Brainpool256 #-- Generate yubihsm-shell.exe -p password -a generate-asymmetric-key -i $keyid -l "ecKey" -d "5,8,13" -c "sign-ecdsa,derive-ecdh,sign-attestation-certificate" -A "ecbp256"; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a get-public-key -i $keyid --outformat=PEM; CheckExitStatus -ECode $? #-- Import openssl.exe ecparam -genkey -name brainpoolP256r1 -noout -out brainpool256r1-keypair.pem; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a put-asymmetric-key -i $import_keyid -l "ecKeyImport" -d "1,2,3,4,5" -c "sign-ecdsa,sign-attestation-certificate" --in=brainpool256r1-keypair.pem; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a get-public-key -i $import_keyid --outformat=PEM; CheckExitStatus -ECode $? #-- Sign yubihsm-shell.exe -p password -a sign-ecdsa -i $keyid -A ecdsa-sha1 --in data.txt > data.ecbp256sha1.sig; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-ecdsa -i $keyid -A ecdsa-sha256 --in data.txt > data.ecbp256sha256.sig; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-ecdsa -i $keyid -A ecdsa-sha384 --in data.txt > data.ecbp256sha384.sig; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-ecdsa -i $keyid -A ecdsa-sha512 --in data.txt > data.ecbp256sha512.sig; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-ecdsa -i $import_keyid -A ecdsa-sha1 --in data.txt > data.ecbp256sha1.sig; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-ecdsa -i $import_keyid -A ecdsa-sha256 --in data.txt > data.ecbp256sha256.sig; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-ecdsa -i $import_keyid -A ecdsa-sha384 --in data.txt > data.ecbp256sha384.sig; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-ecdsa -i $import_keyid -A ecdsa-sha512 --in data.txt > data.ecbp256sha512.sig; CheckExitStatus -ECode $? #-- Get attestation certificate and a selfsigned certificate yubihsm-shell.exe -p password -a sign-attestation-certificate -i $keyid --attestation-id 0 --out cert.pem; CheckExitStatus -ECode $? openssl.exe x509 -in cert.pem -out cert.der -outform DER; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a put-opaque -i $keyid -l template_cert -A opaque-x509-certificate --in cert.der; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-attestation-certificate -i $keyid --attestation-id=$keyid --out selfsigned_cert.pem; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a delete-object -i $keyid -t opaque; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a put-opaque -i $keyid -l java_cert -A opaque-x509-certificate --in selfsigned_cert.pem; CheckExitStatus -ECode $? rm selfsigned_cert.pem #-- Sign attestation certificate yubihsm-shell.exe -p password -a put-opaque -i $import_keyid -l template_cert -A opaque-x509-certificate --in cert.der; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-attestation-certificate -i $keyid --attestation-id=$import_keyid --out selfsigned_cert.der; CheckExitStatus -ECode $? #-- Derive ECDH openssl.exe ec -in brainpool256r1-keypair.pem -pubout -out brainpool256r1-pubkey.pem; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a derive-ecdh -i $keyid --in brainpool256r1-pubkey.pem; CheckExitStatus -ECode $? #-- Delete yubihsm-shell.exe -p password -a delete-object -i $keyid -t asymmetric-key; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a delete-object -i $keyid -t opaque; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a delete-object -i $import_keyid -t asymmetric-key; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a delete-object -i $import_keyid -t opaque; CheckExitStatus -ECode $? echo "**********************************" echo " Brainpool384" echo "**********************************" # Brainpool384 #-- Generate yubihsm-shell.exe -p password -a generate-asymmetric-key -i $keyid -l "ecKey" -d "5,8,13" -c "sign-ecdsa,derive-ecdh,sign-attestation-certificate" -A "ecbp384"; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a get-public-key -i $keyid --outformat=PEM; CheckExitStatus -ECode $? #-- Import openssl.exe ecparam -genkey -name brainpoolP384r1 -noout -out brainpool384r1-keypair.pem; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a put-asymmetric-key -i $import_keyid -l "ecKeyImport" -d "1,2,3,4,5" -c "sign-ecdsa,sign-attestation-certificate" --in=brainpool384r1-keypair.pem; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a get-public-key -i $import_keyid --outformat=PEM; CheckExitStatus -ECode $? #-- Sign yubihsm-shell.exe -p password -a sign-ecdsa -i $keyid -A ecdsa-sha1 --in data.txt > data.ecbp384sha1.sig; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-ecdsa -i $keyid -A ecdsa-sha256 --in data.txt > data.ecbp384sha256.sig; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-ecdsa -i $keyid -A ecdsa-sha384 --in data.txt > data.ecbp384sha384.sig; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-ecdsa -i $keyid -A ecdsa-sha512 --in data.txt > data.ecbp384sha512.sig; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-ecdsa -i $import_keyid -A ecdsa-sha1 --in data.txt > data.ecbp384sha1.sig; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-ecdsa -i $import_keyid -A ecdsa-sha256 --in data.txt > data.ecbp384sha256.sig; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-ecdsa -i $import_keyid -A ecdsa-sha384 --in data.txt > data.ecbp384sha384.sig; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-ecdsa -i $import_keyid -A ecdsa-sha512 --in data.txt > data.ecbp384sha512.sig; CheckExitStatus -ECode $? #-- Get attestation certificate and a selfsigned certificate yubihsm-shell.exe -p password -a sign-attestation-certificate -i $keyid --attestation-id 0 --out cert.pem; CheckExitStatus -ECode $? openssl.exe x509 -in cert.pem -out cert.der -outform DER; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a put-opaque -i $keyid -l template_cert -A opaque-x509-certificate --in cert.der; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-attestation-certificate -i $keyid --attestation-id=$keyid --out selfsigned_cert.pem; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a delete-object -i $keyid -t opaque; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a put-opaque -i $keyid -l java_cert -A opaque-x509-certificate --in selfsigned_cert.pem; CheckExitStatus -ECode $? rm selfsigned_cert.pem #-- Sign attestation certificate yubihsm-shell.exe -p password -a put-opaque -i $import_keyid -l template_cert -A opaque-x509-certificate --in cert.der; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-attestation-certificate -i $keyid --attestation-id=$import_keyid --out selfsigned_cert.der; CheckExitStatus -ECode $? #-- Derive ECDH openssl.exe ec -in brainpool384r1-keypair.pem -pubout -out brainpool384r1-pubkey.pem; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a derive-ecdh -i $keyid --in brainpool384r1-pubkey.pem; CheckExitStatus -ECode $? #-- Delete yubihsm-shell.exe -p password -a delete-object -i $keyid -t asymmetric-key; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a delete-object -i $keyid -t opaque; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a delete-object -i $import_keyid -t asymmetric-key; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a delete-object -i $import_keyid -t opaque; CheckExitStatus -ECode $? echo "**********************************" echo " Brainpool512" echo "**********************************" # Brainpool512 #-- Generate yubihsm-shell.exe -p password -a generate-asymmetric-key -i $keyid -l "ecKey" -d "5,8,13" -c "sign-ecdsa,derive-ecdh,sign-attestation-certificate" -A "ecbp512"; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a get-public-key -i $keyid --outformat=PEM; CheckExitStatus -ECode $? #-- Import openssl.exe ecparam -genkey -name brainpoolP512r1 -noout -out brainpool512r1-keypair.pem; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a put-asymmetric-key -i $import_keyid -l "ecKeyImport" -d "1,2,3,4,5" -c "sign-ecdsa,sign-attestation-certificate" --in=brainpool512r1-keypair.pem; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a get-public-key -i $import_keyid --outformat=PEM; CheckExitStatus -ECode $? #-- Sign yubihsm-shell.exe -p password -a sign-ecdsa -i $keyid -A ecdsa-sha1 --in data.txt > data.ecbp512sha1.sig; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-ecdsa -i $keyid -A ecdsa-sha256 --in data.txt > data.ecbp512sha256.sig; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-ecdsa -i $keyid -A ecdsa-sha384 --in data.txt > data.ecbp512sha384.sig; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-ecdsa -i $keyid -A ecdsa-sha512 --in data.txt > data.ecbp512sha512.sig; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-ecdsa -i $import_keyid -A ecdsa-sha1 --in data.txt > data.ecbp512sha1.sig; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-ecdsa -i $import_keyid -A ecdsa-sha256 --in data.txt > data.ecbp512sha256.sig; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-ecdsa -i $import_keyid -A ecdsa-sha384 --in data.txt > data.ecbp512sha384.sig; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-ecdsa -i $import_keyid -A ecdsa-sha512 --in data.txt > data.ecbp512sha512.sig; CheckExitStatus -ECode $? #-- Get attestation certificate and a selfsigned certificate yubihsm-shell.exe -p password -a sign-attestation-certificate -i $keyid --attestation-id 0 --out cert.pem; CheckExitStatus -ECode $? openssl.exe x509 -in cert.pem -out cert.der -outform DER; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a put-opaque -i $keyid -l template_cert -A opaque-x509-certificate --in cert.der; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-attestation-certificate -i $keyid --attestation-id=$keyid --out selfsigned_cert.pem; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a delete-object -i $keyid -t opaque; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a put-opaque -i $keyid -l java_cert -A opaque-x509-certificate --in selfsigned_cert.pem; CheckExitStatus -ECode $? rm selfsigned_cert.pem #-- Sign attestation certificate yubihsm-shell.exe -p password -a put-opaque -i $import_keyid -l template_cert -A opaque-x509-certificate --in cert.der; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-attestation-certificate -i $keyid --attestation-id=$import_keyid --out selfsigned_cert.der; CheckExitStatus -ECode $? #-- Derive ECDH openssl.exe ec -in brainpool512r1-keypair.pem -pubout -out brainpool512r1-pubkey.pem; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a derive-ecdh -i $keyid --in brainpool512r1-pubkey.pem; CheckExitStatus -ECode $? #-- Delete yubihsm-shell.exe -p password -a delete-object -i $keyid -t asymmetric-key; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a delete-object -i $keyid -t opaque; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a delete-object -i $import_keyid -t asymmetric-key; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a delete-object -i $import_keyid -t opaque; CheckExitStatus -ECode $? cd .. Remove-Item -Path "$TEST_DIR" -Recurse -ErrorAction SilentlyContinue Set-PSDebug -Trace 0yubihsm-shell-2.8.0/resources/tests/ps1/opensc_test.ps10000644000175100017510000000427715221003515022552 0ustar runnerrunner# This script runs on Powershell. If running tests on the current Powershell terminal is not permitted, run the # following command to allow it only on the current terminal: # >> Set-ExecutionPolicy -ExecutionPolicy Bypass -Scope Process if($args.length -eq 0) { echo "Usage: ./opensc_tests.ps1 " echo "" echo "This script expects that libyubihsm.dll and the libcrypto.dll are on PATH and YUBIHSM_PKCS11_CONF environment variable is defined" exit } if ((Get-Command "pkcs11-tool.exe" -ErrorAction SilentlyContinue) -eq $null) { $env:Path +=";C:\Program Files\OpenSC Project\OpenSC\tools" } $MODULE=$args[0] #$YHPKCS11CFG=$args[2] #$env:YUBIHSM_PKCS11_CONF=$YHPKCS11CFG Set-PSDebug -Trace 1 echo "******************* Generation Tests ********************* " pkcs11-tool.exe --module $MODULE --login --pin 0001password --keypairgen --id 100 --key-type EC:secp384r1 pkcs11-tool.exe --module $MODULE --login --pin 0001password --keypairgen --id 2 --key-type EC:prime256v1 pkcs11-tool.exe --module $MODULE --login --pin 0001password --keypairgen --id 4 --key-type rsa:2048 pkcs11-tool.exe --module $MODULE --login --pin 0001password --keypairgen --id 5 --key-type rsa:3072 #Set-PSDebug -Trace 0 #exit echo "******************* Signing Tests ********************* " echo "this is test data" > Z:/data.txt pkcs11-tool.exe --module $MODULE --sign --pin 0001password --id 100 -m ECDSA-SHA1 --signature-format openssl -i Z:/data.txt -o Z:/data.sig pkcs11-tool.exe --module $MODULE --sign --pin 0001password --id 2 -m ECDSA-SHA1 --signature-format openssl -i Z:/data.txt -o Z:/data.sig pkcs11-tool.exe --module $MODULE --sign --pin 0001password --id 4 -m SHA512-RSA-PKCS -i Z:/data.txt -o Z:/data.sig pkcs11-tool.exe --module $MODULE --sign --pin 0001password --id 5 -m SHA512-RSA-PKCS -i Z:/data.txt -o Z:/data.sig rm Z:/data.txt rm Z:/data.sig echo "******************* Testing RSA Tests ********************* " pkcs11-tool.exe --module $MODULE --login --pin 0001password --test #echo "******************* Testing EC Tests ********************* " #pkcs11-tool.exe --module $MODULE --login --login-type so --so-pin 0001password --test-ec --id 200 --key-type EC:secp256r1 Set-PSDebug -Trace 0yubihsm-shell-2.8.0/resources/tests/ps1/test_otpaeadkey.ps10000644000175100017510000001242415221003515023402 0ustar runnerrunner$ARCH=$args[0] if($ARCH -eq "x86") { if ((Get-Command "yubihsm-shell.exe" -ErrorAction SilentlyContinue) -eq $null) { $env:Path += ";C:/Program Files (x86)/Yubico/YubiHSM Shell/bin" } } elseif ($ARCH -eq "x64") { if ((Get-Command "yubihsm-shell.exe" -ErrorAction SilentlyContinue) -eq $null) { $env:Path += ";C:/Program Files/Yubico/YubiHSM Shell/bin" } } else { echo "Usage: ./cmdline_test.ps1 " echo "" echo "This is a test script that uses the yubihsm-shell command line tool to reset the conncted YubiHSM and then different commands." echo "" echo " x86 expects that yubihsm-shell.exe is installed in 'C:/Program Files (x86)/Yubico/Yubico PIV Tool/bin'" echo " x64 expects that yubhsm-shell.exe is installed in 'C:/Program Files/Yubico/Yubico PIV Tool/bin'" exit } echo "Running commands on $ARCH architecture" $TEST_DIR = "yubihsm-shell_test_dir" Remove-Item -Path "$TEST_DIR" -Recurse -ErrorAction SilentlyContinue New-Item $TEST_DIR -type Directory -Force cd $TEST_DIR echo "test signing data" > data.txt Set-PSDebug -Trace 1 $ErrorActionPreference = "Stop" function CheckExitStatus { param ( $ECode ) if(!$ECode) { echo "Fail!" exit } } $keyid=100 echo "---------------------- HAMC keys --------------------- " echo "**********************************" echo " AEAD Key 128" echo "**********************************" echo "=== Generate on YubiHSM" yubihsm-shell.exe -p password -a generate-otp-aead-key -i $keyid -l "aeadkey" -d "1,2,3" -c "randomize-otp-aead" -A "aes128-yubico-otp" --nonce 0x01020304; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a get-object-info -i $keyid -t otp-aead-key > info.txt; CheckExitStatus -ECode $? Select-String -Path "info.txt" -Pattern "id: 0x0064"; CheckExitStatus -ECode $? Select-String -Path "info.txt" -Pattern "type: otp-aead-key"; CheckExitStatus -ECode $? Select-String -Path "info.txt" -Pattern "algorithm: aes128-yubico-otp"; CheckExitStatus -ECode $? Select-String -Path "info.txt" -Pattern 'label: "aeadkey"'; CheckExitStatus -ECode $? Select-String -Path "info.txt" -Pattern "domains: 1:2:3"; CheckExitStatus -ECode $? Select-String -Path "info.txt" -Pattern "origin: generated"; CheckExitStatus -ECode $? Select-String -Path "info.txt" -Pattern "capabilities: randomize-otp-aead"; CheckExitStatus -ECode $? echo "=== Randomize OTP AEAD" yubihsm-shell.exe -p password -a randomize-otp-aead -i $keyid; CheckExitStatus -ECode $? echo "=== Delete keys" yubihsm-shell.exe -p password -a delete-object -i $keyid -t otp-aead-key; CheckExitStatus -ECode $? echo "**********************************" echo " AEAD Key 192" echo "**********************************" echo "=== Generate on YubiHSM" yubihsm-shell.exe -p password -a generate-otp-aead-key -i $keyid -l "aeadkey" -d "1,2,3" -c "randomize-otp-aead" -A "aes192-yubico-otp" --nonce 0x01020304; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a get-object-info -i $keyid -t otp-aead-key > info.txt; CheckExitStatus -ECode $? Select-String -Path "info.txt" -Pattern "id: 0x0064"; CheckExitStatus -ECode $? Select-String -Path "info.txt" -Pattern "type: otp-aead-key"; CheckExitStatus -ECode $? Select-String -Path "info.txt" -Pattern "algorithm: aes192-yubico-otp"; CheckExitStatus -ECode $? Select-String -Path "info.txt" -Pattern 'label: "aeadkey"'; CheckExitStatus -ECode $? Select-String -Path "info.txt" -Pattern "domains: 1:2:3"; CheckExitStatus -ECode $? Select-String -Path "info.txt" -Pattern "origin: generated"; CheckExitStatus -ECode $? Select-String -Path "info.txt" -Pattern "capabilities: randomize-otp-aead"; CheckExitStatus -ECode $? echo "=== Randomize OTP AEAD" yubihsm-shell.exe -p password -a randomize-otp-aead -i $keyid; CheckExitStatus -ECode $? echo "=== Delete keys" yubihsm-shell.exe -p password -a delete-object -i $keyid -t otp-aead-key; CheckExitStatus -ECode $? echo "**********************************" echo " AEAD Key 256" echo "**********************************" echo "=== Generate on YubiHSM" yubihsm-shell.exe -p password -a generate-otp-aead-key -i $keyid -l "aeadkey" -d "1,2,3" -c "randomize-otp-aead" -A "aes256-yubico-otp" --nonce 0x01020304; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a get-object-info -i $keyid -t otp-aead-key > info.txt; CheckExitStatus -ECode $? Select-String -Path "info.txt" -Pattern "id: 0x0064"; CheckExitStatus -ECode $? Select-String -Path "info.txt" -Pattern "type: otp-aead-key"; CheckExitStatus -ECode $? Select-String -Path "info.txt" -Pattern "algorithm: aes256-yubico-otp"; CheckExitStatus -ECode $? Select-String -Path "info.txt" -Pattern 'label: "aeadkey"'; CheckExitStatus -ECode $? Select-String -Path "info.txt" -Pattern "domains: 1:2:3"; CheckExitStatus -ECode $? Select-String -Path "info.txt" -Pattern "origin: generated"; CheckExitStatus -ECode $? Select-String -Path "info.txt" -Pattern "capabilities: randomize-otp-aead"; CheckExitStatus -ECode $? echo "=== Randomize OTP AEAD" yubihsm-shell.exe -p password -a randomize-otp-aead -i $keyid; CheckExitStatus -ECode $? echo "=== Delete keys" yubihsm-shell.exe -p password -a delete-object -i $keyid -t otp-aead-key; CheckExitStatus -ECode $? cd .. Remove-Item -Path "$TEST_DIR" -Recurse -ErrorAction SilentlyContinue Set-PSDebug -Trace 0yubihsm-shell-2.8.0/resources/tests/ps1/test_edkey.ps10000644000175100017510000000435015221003515022354 0ustar runnerrunner$ARCH=$args[0] if($ARCH -eq "x86") { if ((Get-Command "yubihsm-shell.exe" -ErrorAction SilentlyContinue) -eq $null) { $env:Path += ";C:/Program Files (x86)/Yubico/YubiHSM Shell/bin" } } elseif ($ARCH -eq "x64") { if ((Get-Command "yubihsm-shell.exe" -ErrorAction SilentlyContinue) -eq $null) { $env:Path += ";C:/Program Files/Yubico/YubiHSM Shell/bin" } } else { echo "Usage: ./cmdline_test.ps1 " echo "" echo "This is a test script that uses the yubihsm-shell command line tool to reset the conncted YubiHSM and then different commands." echo "" echo " x86 expects that yubihsm-shell.exe is installed in 'C:/Program Files (x86)/Yubico/Yubico PIV Tool/bin'" echo " x64 expects that yubhsm-shell.exe is installed in 'C:/Program Files/Yubico/Yubico PIV Tool/bin'" exit } echo "Running commands on $ARCH architecture" $TEST_DIR = "yubihsm-shell_test_dir" Remove-Item -Path "$TEST_DIR" -Recurse -ErrorAction SilentlyContinue New-Item $TEST_DIR -type Directory -Force cd $TEST_DIR echo "test signing data" > data.txt Set-PSDebug -Trace 1 $ErrorActionPreference = "Stop" function CheckExitStatus { param ( $ECode ) if(!$ECode) { echo "Fail!" exit } } echo "---------------------- ED keys --------------------- " # Generate yubihsm-shell.exe -p password -a generate-asymmetric-key -i 100 -l "edKey" -d "1,2,3" -c "sign-eddsa" -A "ed25519"; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a get-object-info -i 100 -t asymmetric-key; CheckExitStatus -ECode $? # Get public key yubihsm-shell.exe -p password -a get-public-key -i 100 > edkey1.pub; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a get-public-key -i 100 --out edkey2.pub; CheckExitStatus -ECode $? # Signing yubihsm-shell.exe -p password -a sign-eddsa -i 100 -A ed25519 --in data.txt > data.ed1.sig; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-eddsa -i 100 -A ed25519 --in data.txt --out data.ed2.sig; CheckExitStatus -ECode $? # Delete yubihsm-shell.exe -p password -a delete-object -i 100 -t asymmetric-key; CheckExitStatus -ECode $? cd .. Remove-Item -Path "$TEST_DIR" -Recurse -ErrorAction SilentlyContinue Set-PSDebug -Trace 0yubihsm-shell-2.8.0/resources/tests/ps1/test_rsakey.ps10000644000175100017510000005311415221003515022553 0ustar runnerrunner$ARCH=$args[0] if($ARCH -eq "x86") { if ((Get-Command "yubihsm-shell.exe" -ErrorAction SilentlyContinue) -eq $null) { $env:Path += ";C:/Program Files (x86)/Yubico/YubiHSM Shell/bin" } } elseif ($ARCH -eq "x64") { if ((Get-Command "yubihsm-shell.exe" -ErrorAction SilentlyContinue) -eq $null) { $env:Path += ";C:/Program Files/Yubico/YubiHSM Shell/bin" } } else { echo "Usage: ./cmdline_test.ps1 " echo "" echo "This is a test script that uses the yubihsm-shell command line tool to reset the conncted YubiHSM and then different commands." echo "" echo " x86 expects that yubihsm-shell.exe is installed in 'C:/Program Files (x86)/Yubico/Yubico PIV Tool/bin'" echo " x64 expects that yubhsm-shell.exe is installed in 'C:/Program Files/Yubico/Yubico PIV Tool/bin'" exit } echo "Running commands on $ARCH architecture" $TEST_DIR = "yubihsm-shell_test_dir" Remove-Item -Path "$TEST_DIR" -Recurse -ErrorAction SilentlyContinue New-Item $TEST_DIR -type Directory -Force cd $TEST_DIR echo "test signing data" > data.txt Set-PSDebug -Trace 1 $ErrorActionPreference = "Stop" function CheckExitStatus { param ( $ECode ) if(!$ECode) { echo "Fail!" exit } } $keyid=100 $import_keyid=200 echo "---------------------- RSA keys --------------------- " echo "**********************************" echo " RSA2048" echo "**********************************" echo "=== Generate on YubiHSM" yubihsm-shell.exe -p password -a generate-asymmetric-key -i $keyid -l "rsaKey" -d "1" -c "sign-pkcs,sign-pss,decrypt-pkcs,decrypt-oaep,sign-attestation-certificate" -A "rsa2048"; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a get-object-info -i $keyid -t asymmetric-key > info.txt; CheckExitStatus -ECode $? Select-String -Path "info.txt" -Pattern "id: 0x0064"; CheckExitStatus -ECode $? Select-String -Path "info.txt" -Pattern "type: asymmetric-key"; CheckExitStatus -ECode $? Select-String -Path "info.txt" -Pattern "algorithm: rsa2048"; CheckExitStatus -ECode $? Select-String -Path "info.txt" -Pattern 'label: "rsaKey"'; CheckExitStatus -ECode $? Select-String -Path "info.txt" -Pattern "domains: 1"; CheckExitStatus -ECode $? Select-String -Path "info.txt" -Pattern "origin: generated"; CheckExitStatus -ECode $? Select-String -Path "info.txt" -Pattern "capabilities: decrypt-oaep:decrypt-pkcs:sign-attestation-certificate:sign-pkcs:sign-pss"; CheckExitStatus -ECode $? rm info.txt echo "=== Get public key of generated key" yubihsm-shell.exe -p password -a get-public-key -i $keyid --outformat=PEM --out pubkey.pem; CheckExitStatus -ECode $? echo "=== Import into YubiHSM" openssl.exe genrsa -out rsa2048-keypair.pem 2048; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a put-asymmetric-key -i $import_keyid -l "rsaKeyImport" -d "2" -c "sign-pkcs,sign-pss,decrypt-pkcs,decrypt-oaep,sign-attestation-certificate" --in=rsa2048-keypair.pem; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a get-object-info -i $import_keyid -t asymmetric-key > info.txt; CheckExitStatus -ECode $? Select-String -Path "info.txt" -Pattern "id: 0x00c8"; CheckExitStatus -ECode $? Select-String -Path "info.txt" -Pattern "type: asymmetric-key"; CheckExitStatus -ECode $? Select-String -Path "info.txt" -Pattern "algorithm: rsa2048"; CheckExitStatus -ECode $? Select-String -Path "info.txt" -Pattern 'label: "rsaKeyImport"'; CheckExitStatus -ECode $? Select-String -Path "info.txt" -Pattern "domains: 2"; CheckExitStatus -ECode $? Select-String -Path "info.txt" -Pattern "origin: imported"; CheckExitStatus -ECode $? Select-String -Path "info.txt" -Pattern "capabilities: decrypt-oaep:decrypt-pkcs:sign-attestation-certificate:sign-pkcs:sign-pss"; CheckExitStatus -ECode $? echo "=== Get public key of imported key" yubihsm-shell.exe -p password -a get-public-key -i $import_keyid --outformat=PEM --out pubkey_imported.pem; CheckExitStatus -ECode $? echo "=== Signing with generated key and" echo "===== rsa-pkcs1-sha1" yubihsm-shell.exe -p password -a sign-pkcs1v15 -i $keyid -A rsa-pkcs1-sha1 --in data.txt --out data.2048pkcs1sha1.sig; CheckExitStatus -ECode $? echo "===== rsa-pkcs1-sha256" yubihsm-shell.exe -p password -a sign-pkcs1v15 -i $keyid -A rsa-pkcs1-sha256 --in data.txt --out data.2048pkcs1sha256.sig; CheckExitStatus -ECode $? echo "===== rsa-pkcs1-sha384" yubihsm-shell.exe -p password -a sign-pkcs1v15 -i $keyid -A rsa-pkcs1-sha384 --in data.txt --out data.2048pkcs1sha384.sig; CheckExitStatus -ECode $? echo "===== rsa-pkcs1-sha512" yubihsm-shell.exe -p password -a sign-pkcs1v15 -i $keyid -A rsa-pkcs1-sha512 --in data.txt --out data.2048pkcs1sha512.sig; CheckExitStatus -ECode $? echo "===== rsa-pss-sha1" yubihsm-shell.exe -p password -a sign-pss -i $keyid -A rsa-pss-sha1 --in data.txt --out data.2048psssha1.sig; CheckExitStatus -ECode $? echo "===== rsa-pss-sha256" yubihsm-shell.exe -p password -a sign-pss -i $keyid -A rsa-pss-sha256 --in data.txt --out data.2048psssha256.sig; CheckExitStatus -ECode $? echo "===== rsa-pss-sha384" yubihsm-shell.exe -p password -a sign-pss -i $keyid -A rsa-pss-sha384 --in data.txt --out data.2048psssha384.sig; CheckExitStatus -ECode $? echo "===== rsa-pss-sha512" yubihsm-shell.exe -p password -a sign-pss -i $keyid -A rsa-pss-sha512 --in data.txt --out data.2048psssha512.sig; CheckExitStatus -ECode $? echo "=== Signing with imported key and" echo "===== rsa-pkcs1-sha1" yubihsm-shell.exe -p password -a sign-pkcs1v15 -i $import_keyid -A rsa-pkcs1-sha1 --in data.txt --out data.2048pkcs1sha1.sig; CheckExitStatus -ECode $? echo "===== rsa-pkcs1-sha256" yubihsm-shell.exe -p password -a sign-pkcs1v15 -i $import_keyid -A rsa-pkcs1-sha256 --in data.txt --out data.2048pkcs1sha256.sig; CheckExitStatus -ECode $? echo "===== rsa-pkcs1-sha384" yubihsm-shell.exe -p password -a sign-pkcs1v15 -i $import_keyid -A rsa-pkcs1-sha384 --in data.txt --out data.2048pkcs1sha384.sig; CheckExitStatus -ECode $? echo "===== rsa-pkcs1-sha512" yubihsm-shell.exe -p password -a sign-pkcs1v15 -i $import_keyid -A rsa-pkcs1-sha512 --in data.txt --out data.2048pkcs1sha512.sig; CheckExitStatus -ECode $? echo "===== rsa-pss-sha1" yubihsm-shell.exe -p password -a sign-pss -i $import_keyid -A rsa-pss-sha1 --in data.txt --out data.2048psssha1.sig; CheckExitStatus -ECode $? echo "===== rsa-pss-sha256" yubihsm-shell.exe -p password -a sign-pss -i $import_keyid -A rsa-pss-sha256 --in data.txt --out data.2048psssha256.sig; CheckExitStatus -ECode $? echo "===== rsa-pss-sha384" yubihsm-shell.exe -p password -a sign-pss -i $import_keyid -A rsa-pss-sha384 --in data.txt --out data.2048psssha384.sig; CheckExitStatus -ECode $? echo "===== rsa-pss-sha512" yubihsm-shell.exe -p password -a sign-pss -i $import_keyid -A rsa-pss-sha512 --in data.txt --out data.2048psssha512.sig; CheckExitStatus -ECode $? echo "=== Make self signed certificate" yubihsm-shell.exe -p password -a sign-attestation-certificate -i $keyid --attestation-id 0 --out cert.pem; CheckExitStatus -ECode $? openssl.exe x509 -in cert.pem -out cert.der -outform DER; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a put-opaque -i $keyid -l template_cert -A opaque-x509-certificate --in cert.der; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-attestation-certificate -i $keyid --attestation-id=$keyid --out selfsigned_cert.pem; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a delete-object -i $keyid -t opaque; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a put-opaque -i $keyid -l java_cert -A opaque-x509-certificate --in selfsigned_cert.pem; CheckExitStatus -ECode $? echo "=== Sign attestation certificate" yubihsm-shell.exe -p password -a put-opaque -i $import_keyid -l template_cert -A opaque-x509-certificate --in cert.der; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-attestation-certificate -i $keyid --attestation-id=$import_keyid --out selfsigned_cert.der; CheckExitStatus -ECode $? echo "=== Decrypt with generated key and PKCS1v15" openssl.exe rsautl -encrypt -inkey pubkey.pem -pubin -in data.txt -out data.enc; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a decrypt-pkcs1v15 -i $keyid --in data.enc --out data.dec; CheckExitStatus -ECode $? if (@(Compare-Object $(Get-Content "data.txt") $(Get-Content "data.dec") -sync 0).length -ne 0) { echo "Decrypt failed" exit 2 } rm data.dec echo "=== Decrypt with imported key and PKCS1v15" openssl.exe rsautl -encrypt -inkey pubkey_imported.pem -pubin -in data.txt -out data.enc; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a decrypt-pkcs1v15 -i $import_keyid --in data.enc --out data.dec; CheckExitStatus -ECode $? if (@(Compare-Object $(Get-Content "data.txt") $(Get-Content "data.dec") -sync 0).length -ne 0) { echo "Decrypt failed" exit 2 } rm data.dec echo "=== Delete keys" yubihsm-shell.exe -p password -a delete-object -i $keyid -t asymmetric-key; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a delete-object -i $import_keyid -t asymmetric-key; CheckExitStatus -ECode $? echo "**********************************" echo " RSA3072" echo "**********************************" echo "=== Generate on YubiHSM" yubihsm-shell.exe -p password -a generate-asymmetric-key -i $keyid -l "rsaKey" -d "1" -c "sign-pkcs,sign-pss,decrypt-pkcs,decrypt-oaep,sign-attestation-certificate" -A "rsa3072"; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a get-object-info -i $keyid -t asymmetric-key; CheckExitStatus -ECode $? echo "=== Get public key of generated key" yubihsm-shell.exe -p password -a get-public-key -i $keyid --outformat=PEM --out pubkey.pem; CheckExitStatus -ECode $? echo "=== Import into YubiHSM" openssl.exe genrsa -out rsa3072-keypair.pem 3072; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a put-asymmetric-key -i $import_keyid -l "rsaKeyImport" -d "2" -c "sign-pkcs,sign-pss,decrypt-pkcs,decrypt-oaep,sign-attestation-certificate" --in=rsa3072-keypair.pem; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a get-object-info -i $import_keyid -t asymmetric-key; CheckExitStatus -ECode $? echo "=== Get public key of imported key" yubihsm-shell.exe -p password -a get-public-key -i $import_keyid --outformat=PEM --out pubkey_imported.pem; CheckExitStatus -ECode $? echo "=== Signing with generated key and" echo "===== rsa-pkcs1-sha1" yubihsm-shell.exe -p password -a sign-pkcs1v15 -i $keyid -A rsa-pkcs1-sha1 --in data.txt --out data.3072pkcs1sha1.sig; CheckExitStatus -ECode $? echo "===== rsa-pkcs1-sha256" yubihsm-shell.exe -p password -a sign-pkcs1v15 -i $keyid -A rsa-pkcs1-sha256 --in data.txt --out data.3072pkcs1sha256.sig; CheckExitStatus -ECode $? echo "===== rsa-pkcs1-sha384" yubihsm-shell.exe -p password -a sign-pkcs1v15 -i $keyid -A rsa-pkcs1-sha384 --in data.txt --out data.3072pkcs1sha384.sig; CheckExitStatus -ECode $? echo "===== rsa-pkcs1-sha512" yubihsm-shell.exe -p password -a sign-pkcs1v15 -i $keyid -A rsa-pkcs1-sha512 --in data.txt --out data.3072pkcs1sha512.sig; CheckExitStatus -ECode $? echo "===== rsa-pss-sha1" yubihsm-shell.exe -p password -a sign-pss -i $keyid -A rsa-pss-sha1 --in data.txt --out data.3072psssha1.sig; CheckExitStatus -ECode $? echo "===== rsa-pss-sha256" yubihsm-shell.exe -p password -a sign-pss -i $keyid -A rsa-pss-sha256 --in data.txt --out data.3072psssha256.sig; CheckExitStatus -ECode $? echo "===== rsa-pss-sha384" yubihsm-shell.exe -p password -a sign-pss -i $keyid -A rsa-pss-sha384 --in data.txt --out data.3072psssha384.sig; CheckExitStatus -ECode $? echo "===== rsa-pss-sha512" yubihsm-shell.exe -p password -a sign-pss -i $keyid -A rsa-pss-sha512 --in data.txt --out data.3072psssha512.sig; CheckExitStatus -ECode $? echo "=== Signing with imported key and" echo "===== rsa-pkcs1-sha1" yubihsm-shell.exe -p password -a sign-pkcs1v15 -i $import_keyid -A rsa-pkcs1-sha1 --in data.txt --out data.3072pkcs1sha1.sig; CheckExitStatus -ECode $? echo "===== rsa-pkcs1-sha256" yubihsm-shell.exe -p password -a sign-pkcs1v15 -i $import_keyid -A rsa-pkcs1-sha256 --in data.txt --out data.3072pkcs1sha256.sig; CheckExitStatus -ECode $? echo "===== rsa-pkcs1-sha384" yubihsm-shell.exe -p password -a sign-pkcs1v15 -i $import_keyid -A rsa-pkcs1-sha384 --in data.txt --out data.3072pkcs1sha384.sig; CheckExitStatus -ECode $? echo "===== rsa-pkcs1-sha512" yubihsm-shell.exe -p password -a sign-pkcs1v15 -i $import_keyid -A rsa-pkcs1-sha512 --in data.txt --out data.3072pkcs1sha512.sig; CheckExitStatus -ECode $? echo "===== rsa-pss-sha1" yubihsm-shell.exe -p password -a sign-pss -i $import_keyid -A rsa-pss-sha1 --in data.txt --out data.3072psssha1.sig; CheckExitStatus -ECode $? echo "===== rsa-pss-sha256" yubihsm-shell.exe -p password -a sign-pss -i $import_keyid -A rsa-pss-sha256 --in data.txt --out data.3072psssha256.sig; CheckExitStatus -ECode $? echo "===== rsa-pss-sha384" yubihsm-shell.exe -p password -a sign-pss -i $import_keyid -A rsa-pss-sha384 --in data.txt --out data.3072psssha384.sig; CheckExitStatus -ECode $? echo "===== rsa-pss-sha512" yubihsm-shell.exe -p password -a sign-pss -i $import_keyid -A rsa-pss-sha512 --in data.txt --out data.3072psssha512.sig; CheckExitStatus -ECode $? echo "=== Make self signed certificate" yubihsm-shell.exe -p password -a delete-object -i $keyid -t opaque; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-attestation-certificate -i $keyid --attestation-id 0 --out cert.pem; CheckExitStatus -ECode $? openssl.exe x509 -in cert.pem -out cert.der -outform DER; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a put-opaque -i $keyid -l template_cert -A opaque-x509-certificate --in cert.der; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-attestation-certificate -i $keyid --attestation-id=$keyid --out selfsigned_cert.pem; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a delete-object -i $keyid -t opaque; CheckExitStatus -ECode $? #yubihsm-shell.exe -p password -a put-opaque -i $keyid -l java_cert -A opaque-x509-certificate --in selfsigned_cert.pem; CheckExitStatus -ECode $? echo "=== Sign attestation certificate" yubihsm-shell.exe -p password -a delete-object -i $import_keyid -t opaque; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a put-opaque -i $import_keyid -l template_cert -A opaque-x509-certificate --in cert.der; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-attestation-certificate -i $keyid --attestation-id=$import_keyid --out selfsigned_cert.der; CheckExitStatus -ECode $? <# echo "=== Decrypt with generated key and PKCS1v15" openssl rsautl -encrypt -inkey pubkey.pem -pubin -in data.txt -out data.enc yubihsm-shell.exe -p password -a decrypt-pkcs1v15 -i $keyid --in data.enc --out data.dec if (@(Compare-Object $(Get-Content "data.txt") $(Get-Content "data.dec") -sync 0).length -ne 0) { echo "Decrypt failed" exit 2 } rm data.dec echo "=== Decrypt with imported key and PKCS1v15" openssl.exe rsautl -encrypt -inkey pubkey_imported.pem -pubin -in data.txt -out data.enc yubihsm-shell.exe -p password -a decrypt-pkcs1v15 -i $import_keyid --in data.enc --out data.dec <# if (@(Compare-Object $(Get-Content "data.txt") $(Get-Content "data.dec") -sync 0).length -ne 0) { echo "Decrypt failed" exit 2 } rm data.dec #> echo "=== Delete keys" yubihsm-shell.exe -p password -a delete-object -i $keyid -t asymmetric-key; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a delete-object -i $import_keyid -t asymmetric-key; CheckExitStatus -ECode $? # RSA 4096 echo "**********************************" echo " RSA4096" echo "**********************************" echo "=== Generate on YubiHSM" yubihsm-shell.exe -p password -a generate-asymmetric-key -i $keyid -l "rsaKey" -d "1" -c "sign-pkcs,sign-pss,decrypt-pkcs,decrypt-oaep,sign-attestation-certificate" -A "rsa4096"; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a get-object-info -i $keyid -t asymmetric-key; CheckExitStatus -ECode $? echo "=== Get public key of generated key" yubihsm-shell.exe -p password -a get-public-key -i $keyid --outformat=PEM --out pubkey.pem; CheckExitStatus -ECode $? echo "=== Import into YubiHSM" openssl.exe genrsa -out rsa4096-keypair.pem 4096; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a put-asymmetric-key -i $import_keyid -l "rsaKeyImport" -d "2" -c "sign-pkcs,sign-pss,decrypt-pkcs,decrypt-oaep,sign-attestation-certificate" --in=rsa4096-keypair.pem; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a get-object-info -i $import_keyid -t asymmetric-key; CheckExitStatus -ECode $? echo "=== Get public key of imported key" yubihsm-shell.exe -p password -a get-public-key -i $import_keyid --outformat=PEM --out pubkey_imported.pem; CheckExitStatus -ECode $? echo "=== Signing with generated key and" echo "===== rsa-pkcs1-sha1" yubihsm-shell.exe -p password -a sign-pkcs1v15 -i $keyid -A rsa-pkcs1-sha1 --in data.txt --out data.4096pkcs1sha1.sig; CheckExitStatus -ECode $? echo "===== rsa-pkcs1-sha256" yubihsm-shell.exe -p password -a sign-pkcs1v15 -i $keyid -A rsa-pkcs1-sha256 --in data.txt --out data.4096pkcs1sha256.sig; CheckExitStatus -ECode $? echo "===== rsa-pkcs1-sha384" yubihsm-shell.exe -p password -a sign-pkcs1v15 -i $keyid -A rsa-pkcs1-sha384 --in data.txt --out data.4096pkcs1sha384.sig; CheckExitStatus -ECode $? echo "===== rsa-pkcs1-sha512" yubihsm-shell.exe -p password -a sign-pkcs1v15 -i $keyid -A rsa-pkcs1-sha512 --in data.txt --out data.4096pkcs1sha512.sig; CheckExitStatus -ECode $? echo "===== rsa-pss-sha1" yubihsm-shell.exe -p password -a sign-pss -i $keyid -A rsa-pss-sha1 --in data.txt --out data.4096psssha1.sig; CheckExitStatus -ECode $? echo "===== rsa-pss-sha256" yubihsm-shell.exe -p password -a sign-pss -i $keyid -A rsa-pss-sha256 --in data.txt --out data.4096psssha256.sig; CheckExitStatus -ECode $? echo "===== rsa-pss-sha384" yubihsm-shell.exe -p password -a sign-pss -i $keyid -A rsa-pss-sha384 --in data.txt --out data.4096psssha384.sig; CheckExitStatus -ECode $? echo "===== rsa-pss-sha512" yubihsm-shell.exe -p password -a sign-pss -i $keyid -A rsa-pss-sha512 --in data.txt --out data.4096psssha512.sig; CheckExitStatus -ECode $? echo "=== Signing with imported key and" echo "===== rsa-pkcs1-sha1" yubihsm-shell.exe -p password -a sign-pkcs1v15 -i $import_keyid -A rsa-pkcs1-sha1 --in data.txt --out data.4096pkcs1sha1.sig; CheckExitStatus -ECode $? echo "===== rsa-pkcs1-sha256" yubihsm-shell.exe -p password -a sign-pkcs1v15 -i $import_keyid -A rsa-pkcs1-sha256 --in data.txt --out data.4096pkcs1sha256.sig; CheckExitStatus -ECode $? echo "===== rsa-pkcs1-sha384" yubihsm-shell.exe -p password -a sign-pkcs1v15 -i $import_keyid -A rsa-pkcs1-sha384 --in data.txt --out data.4096pkcs1sha384.sig; CheckExitStatus -ECode $? echo "===== rsa-pkcs1-sha512" yubihsm-shell.exe -p password -a sign-pkcs1v15 -i $import_keyid -A rsa-pkcs1-sha512 --in data.txt --out data.4096pkcs1sha512.sig; CheckExitStatus -ECode $? echo "===== rsa-pss-sha1" yubihsm-shell.exe -p password -a sign-pss -i $import_keyid -A rsa-pss-sha1 --in data.txt --out data.4096psssha1.sig; CheckExitStatus -ECode $? echo "===== rsa-pss-sha256" yubihsm-shell.exe -p password -a sign-pss -i $import_keyid -A rsa-pss-sha256 --in data.txt --out data.4096psssha256.sig; CheckExitStatus -ECode $? echo "===== rsa-pss-sha384" yubihsm-shell.exe -p password -a sign-pss -i $import_keyid -A rsa-pss-sha384 --in data.txt --out data.4096psssha384.sig; CheckExitStatus -ECode $? echo "===== rsa-pss-sha512" yubihsm-shell.exe -p password -a sign-pss -i $import_keyid -A rsa-pss-sha512 --in data.txt --out data.4096psssha512.sig; CheckExitStatus -ECode $? echo "=== Make self signed certificate" #yubihsm-shell.exe -p password -a delete-object -i $keyid -t opaque; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-attestation-certificate -i $keyid --attestation-id 0 --out cert.pem; CheckExitStatus -ECode $? openssl.exe x509 -in cert.pem -out cert.der -outform DER; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a put-opaque -i $keyid -l template_cert -A opaque-x509-certificate --in cert.der; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-attestation-certificate -i $keyid --attestation-id=$keyid --out selfsigned_cert.pem; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a delete-object -i $keyid -t opaque; CheckExitStatus -ECode $? #yubihsm-shell.exe -p password -a put-opaque -i $keyid -l java_cert -A opaque-x509-certificate --in selfsigned_cert.pem; CheckExitStatus -ECode $? echo "=== Sign attestation certificate" yubihsm-shell.exe -p password -a delete-object -i $import_keyid -t opaque; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a put-opaque -i $import_keyid -l template_cert -A opaque-x509-certificate --in cert.der; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a sign-attestation-certificate -i $keyid --attestation-id=$import_keyid --out selfsigned_cert.der; CheckExitStatus -ECode $? <# echo "=== Decrypt with generated key and PKCS1v15" openssl.exe rsautl -encrypt -inkey pubkey.pem -pubin -in data.txt -out data.enc yubihsm-shell.exe -p password -a decrypt-pkcs1v15 -i $keyid --in data.enc --out data.dec if (@(Compare-Object $(Get-Content "data.txt") $(Get-Content "data.dec") -sync 0).length -ne 0) { echo "Decrypt failed" exit 2 } rm data.dec echo "=== Decrypt with imported key and PKCS1v15" openssl.exe rsautl -encrypt -inkey pubkey_imported.pem -pubin -in data.txt -out data.enc yubihsm-shell.exe -p password -a decrypt-pkcs1v15 -i $import_keyid --in data.enc --out data.dec if (@(Compare-Object $(Get-Content "data.txt") $(Get-Content "data.dec") -sync 0).length -ne 0) { echo "Decrypt failed" exit 2 } rm data.dec #> echo "=== Delete keys" yubihsm-shell.exe -p password -a delete-object -i $keyid -t asymmetric-key; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a delete-object -i $import_keyid -t asymmetric-key; CheckExitStatus -ECode $? cd .. Remove-Item -Path "$TEST_DIR" -Recurse -ErrorAction SilentlyContinue Set-PSDebug -Trace 0yubihsm-shell-2.8.0/resources/tests/ps1/test_hmackey.ps10000644000175100017510000001050615221003515022674 0ustar runnerrunner$ARCH=$args[0] if($ARCH -eq "x86") { if ((Get-Command "yubihsm-shell.exe" -ErrorAction SilentlyContinue) -eq $null) { $env:Path += ";C:/Program Files (x86)/Yubico/YubiHSM Shell/bin" } } elseif ($ARCH -eq "x64") { if ((Get-Command "yubihsm-shell.exe" -ErrorAction SilentlyContinue) -eq $null) { $env:Path += ";C:/Program Files/Yubico/YubiHSM Shell/bin" } } else { echo "Usage: ./cmdline_test.ps1 " echo "" echo "This is a test script that uses the yubihsm-shell command line tool to reset the conncted YubiHSM and then different commands." echo "" echo " x86 expects that yubihsm-shell.exe is installed in 'C:/Program Files (x86)/Yubico/Yubico PIV Tool/bin'" echo " x64 expects that yubhsm-shell.exe is installed in 'C:/Program Files/Yubico/Yubico PIV Tool/bin'" exit } echo "Running commands on $ARCH architecture" $TEST_DIR = "yubihsm-shell_test_dir" Remove-Item -Path "$TEST_DIR" -Recurse -ErrorAction SilentlyContinue New-Item $TEST_DIR -type Directory -Force cd $TEST_DIR echo "test signing data" > data.txt Set-PSDebug -Trace 1 $ErrorActionPreference = "Stop" function CheckExitStatus { param ( $ECode ) if(!$ECode) { echo "Fail!" exit } } $keyid=100 echo "---------------------- HAMC keys --------------------- " echo "**********************************" echo " hmac-sha1" echo "**********************************" echo "=== Generate on YubiHSM" yubihsm-shell.exe -p password -a generate-hmac-key -i $keyid -l "hmackey" -d "1,2,3" -c "sign-hmac" -A "hmac-sha1"; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a get-object-info -i $keyid -t hmac-key > info.txt; CheckExitStatus -ECode $? Select-String -Path "info.txt" -Pattern "id: 0x0064"; CheckExitStatus -ECode $? Select-String -Path "info.txt" -Pattern "type: hmac-key"; CheckExitStatus -ECode $? Select-String -Path "info.txt" -Pattern "algorithm: hmac-sha1"; CheckExitStatus -ECode $? Select-String -Path "info.txt" -Pattern 'label: "hmackey"'; CheckExitStatus -ECode $? Select-String -Path "info.txt" -Pattern "domains: 1:2:3"; CheckExitStatus -ECode $? Select-String -Path "info.txt" -Pattern "origin: generated"; CheckExitStatus -ECode $? Select-String -Path "info.txt" -Pattern "capabilities: sign-hmac"; CheckExitStatus -ECode $? echo "=== Delete keys" yubihsm-shell.exe -p password -a delete-object -i $keyid -t hmac-key; CheckExitStatus -ECode $? echo "**********************************" echo " hmac-sha256" echo "**********************************" echo "=== Generate on YubiHSM" yubihsm-shell.exe -p password -a generate-hmac-key -i $keyid -l "hmackey" -d "1,2,3" -c "sign-hmac" -A "hmac-sha256"; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a get-object-info -i $keyid -t hmac-key > info.txt; CheckExitStatus -ECode $? Select-String -Path "info.txt" -Pattern "algorithm: hmac-sha256"; CheckExitStatus -ECode $? echo "=== Delete keys" yubihsm-shell.exe -p password -a delete-object -i $keyid -t hmac-key; CheckExitStatus -ECode $? echo "**********************************" echo " hmac-sha384" echo "**********************************" echo "=== Generate on YubiHSM" yubihsm-shell.exe -p password -a generate-hmac-key -i $keyid -l "hmackey" -d "1,2,3" -c "sign-hmac" -A "hmac-sha384"; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a get-object-info -i $keyid -t hmac-key > info.txt; CheckExitStatus -ECode $? Select-String -Path "info.txt" -Pattern "algorithm: hmac-sha384"; CheckExitStatus -ECode $? echo "=== Delete keys" yubihsm-shell.exe -p password -a delete-object -i $keyid -t hmac-key; CheckExitStatus -ECode $? echo "**********************************" echo " hmac-sha512" echo "**********************************" echo "=== Generate on YubiHSM" yubihsm-shell.exe -p password -a generate-hmac-key -i $keyid -l "hmackey" -d "1,2,3" -c "sign-hmac" -A "hmac-sha512"; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a get-object-info -i $keyid -t hmac-key > info.txt; CheckExitStatus -ECode $? Select-String -Path "info.txt" -Pattern "algorithm: hmac-sha512"; CheckExitStatus -ECode $? echo "=== Delete keys" yubihsm-shell.exe -p password -a delete-object -i $keyid -t hmac-key; CheckExitStatus -ECode $? cd .. Remove-Item -Path "$TEST_DIR" -Recurse -ErrorAction SilentlyContinue Set-PSDebug -Trace 0yubihsm-shell-2.8.0/resources/tests/ps1/cmdline_test.ps10000644000175100017510000001021315221003515022661 0ustar runnerrunner$ARCH=$args[0] if($ARCH -eq "x86") { if ((Get-Command "yubihsm-shell.exe" -ErrorAction SilentlyContinue) -eq $null) { $env:Path += ";C:/Program Files (x86)/Yubico/YubiHSM Shell/bin" } } elseif ($ARCH -eq "x64") { if ((Get-Command "yubihsm-shell.exe" -ErrorAction SilentlyContinue) -eq $null) { $env:Path += ";C:/Program Files/Yubico/YubiHSM Shell/bin" } } else { echo "Usage: ./cmdline_test.ps1 " echo "" echo "This is a test script that uses the yubihsm-shell command line tool to reset the conncted YubiHSM and then different com mands." echo "" echo " x86 expects that yubihsm-shell.exe is installed in 'C:/Program Files (x86)/Yubico/Yubico PIV Tool/bin'" echo " x64 expects that yubhsm-shell.exe is installed in 'C:/Program Files/Yubico/Yubico PIV Tool/bin'" exit } echo "Running commands on $ARCH architecture" $TEST_DIR = "yubihsm-shell_test_dir" Remove-Item -Path "$TEST_DIR" -Recurse -ErrorAction SilentlyContinue New-Item $TEST_DIR -type Directory -Force Set-PSDebug -Trace 1 $ErrorActionPreference = "Stop" function CheckExitStatus { param ( $ECode ) if(!$ECode) { echo "Fail!" exit } } yubihsm-shell.exe --version; CheckExitStatus -ECode $? yubihsm-shell.exe --help; CheckExitStatus -ECode $? yubihsm-shell.exe -a get-device-info; CheckExitStatus -ECode $? echo "********************** Reset YubiHSM ********************* " yubihsm-shell.exe -p password -a reset; CheckExitStatus -ECode $? Start-Sleep -s 10 echo "********************** Blink ********************* " yubihsm-shell.exe -p password -a blink; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a blink --duration=5; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a blink-device; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a blink-device --duration=5; CheckExitStatus -ECode $? echo "********************** Get Pseudo-random ********************* " yubihsm-shell.exe -p password -a get-pseudo-random; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a get-pseudo-random --count=10; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a get-pseudo-random --count=10 --out=random.txt; CheckExitStatus -ECode $? rm random.txt echo "********************** Asym keys ********************* " & "$PSScriptRoot\test_edkey.ps1" "$ARCH" & "$PSScriptRoot\test_eckey.ps1" "$ARCH" & "$PSScriptRoot\test_rsakey.ps1" "$ARCH" echo "********************** HMAC keys ********************* " & "$PSScriptRoot\test_hmackey.ps1" "$ARCH" echo "********************** AEAD keys ********************* " & "$PSScriptRoot\test_otpaeadkey.ps1" "$ARCH" Set-PSDebug -Trace 1 #echo "********************** Template ********************* " #echo "=== Import template" #$id=100 #yubihsm-shell.exe -p password -a get-pseudo-random --count=512 --out=template.txt; CheckExitStatus -ECode $? #yubihsm-shell.exe -p password -a put-template -i $id -l template -d 1 -A template-ssh --in template.txt; CheckExitStatus -ECode $? #yubihsm-shell.exe -p password -a get-object-info -i $id -t template; CheckExitStatus -ECode $? #echo "=== Get template" #yubihsm-shell.exe -p password -a get-template -i $id; CheckExitStatus -ECode $? #echo "=== Delete template" #yubihsm-shell.exe -p password -a delete-object -i $id -t template; CheckExitStatus -ECode $? #rm template.txt #echo "********************** Wrap keys ********************* " echo "********************** Authentication keys ********************* " echo "=== Create new authentication key" $id=200 yubihsm-shell.exe -p password -a put-authentication-key -i $id -l authkey -d 1,2,3 -c all --new-password foo123; CheckExitStatus -ECode $? yubihsm-shell.exe -p password -a get-object-info -i $id -t authentication-key; CheckExitStatus -ECode $? echo "=== Login using new authetication key" yubihsm-shell.exe --authkey $id -p foo123 -a get-object-info -i 1 -t authentication-key; CheckExitStatus -ECode $? echo "=== Delete new authentication key" yubihsm-shell.exe -p password -a delete-object -i $id -t authentication-key; CheckExitStatus -ECode $? Remove-Item -Path "$TEST_DIR" -Recurse -ErrorAction SilentlyContinue Set-PSDebug -Trace 0yubihsm-shell-2.8.0/yhwrap/0000755000175100017510000000000015221003605015220 5ustar runnerrunneryubihsm-shell-2.8.0/yhwrap/cmdline.c0000644000175100017510000005351315221003605017006 0ustar runnerrunner/* File autogenerated by gengetopt version 2.23 generated with the following command: gengetopt -i /home/runner/work/yubihsm-shell/yubihsm-shell/yhwrap/cmdline.ggo --output-dir /home/runner/work/yubihsm-shell/yubihsm-shell/yhwrap cmdline The developers of gengetopt consider the fixed text that goes in all gengetopt output files to be in the public domain: we make no copyright claims on it. */ /* If we use autoconf. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #ifndef FIX_UNUSED #define FIX_UNUSED(X) (void) (X) /* avoid warnings for unused params */ #endif #include #include "cmdline.h" const char *gengetopt_args_info_purpose = ""; const char *gengetopt_args_info_usage = "Usage: " CMDLINE_PARSER_PACKAGE " [OPTION]..."; const char *gengetopt_args_info_versiontext = ""; const char *gengetopt_args_info_description = ""; const char *gengetopt_args_info_help[] = { " -h, --help Print help and exit", " -V, --version Print version and exit", " -a, --algorithm=STRING Object algorithm", " -c, --capabilities=STRING Object capabilities", " -e, --delegated=STRING Object delegates capabilities", " -d, --domains=STRING Object domains", " -i, --id=SHORT Object ID (default=`0')", " --in=STRING Input data (filename)", " --out=STRING Output data (filename)", " -l, --label=STRING Object label", " -k, --wrapkey=STRING Key to wrap data with (filename)", 0 }; typedef enum {ARG_NO , ARG_STRING , ARG_SHORT } cmdline_parser_arg_type; static void clear_given (struct gengetopt_args_info *args_info); static void clear_args (struct gengetopt_args_info *args_info); static int cmdline_parser_internal (int argc, char **argv, struct gengetopt_args_info *args_info, struct cmdline_parser_params *params, const char *additional_error); static int cmdline_parser_required2 (struct gengetopt_args_info *args_info, const char *prog_name, const char *additional_error); static char * gengetopt_strdup (const char *s); static void clear_given (struct gengetopt_args_info *args_info) { args_info->help_given = 0 ; args_info->version_given = 0 ; args_info->algorithm_given = 0 ; args_info->capabilities_given = 0 ; args_info->delegated_given = 0 ; args_info->domains_given = 0 ; args_info->id_given = 0 ; args_info->in_given = 0 ; args_info->out_given = 0 ; args_info->label_given = 0 ; args_info->wrapkey_given = 0 ; } static void clear_args (struct gengetopt_args_info *args_info) { FIX_UNUSED (args_info); args_info->algorithm_arg = NULL; args_info->algorithm_orig = NULL; args_info->capabilities_arg = NULL; args_info->capabilities_orig = NULL; args_info->delegated_arg = NULL; args_info->delegated_orig = NULL; args_info->domains_arg = NULL; args_info->domains_orig = NULL; args_info->id_arg = 0; args_info->id_orig = NULL; args_info->in_arg = NULL; args_info->in_orig = NULL; args_info->out_arg = NULL; args_info->out_orig = NULL; args_info->label_arg = NULL; args_info->label_orig = NULL; args_info->wrapkey_arg = NULL; args_info->wrapkey_orig = NULL; } static void init_args_info(struct gengetopt_args_info *args_info) { args_info->help_help = gengetopt_args_info_help[0] ; args_info->version_help = gengetopt_args_info_help[1] ; args_info->algorithm_help = gengetopt_args_info_help[2] ; args_info->capabilities_help = gengetopt_args_info_help[3] ; args_info->delegated_help = gengetopt_args_info_help[4] ; args_info->domains_help = gengetopt_args_info_help[5] ; args_info->id_help = gengetopt_args_info_help[6] ; args_info->in_help = gengetopt_args_info_help[7] ; args_info->out_help = gengetopt_args_info_help[8] ; args_info->label_help = gengetopt_args_info_help[9] ; args_info->wrapkey_help = gengetopt_args_info_help[10] ; } void cmdline_parser_print_version (void) { printf ("%s %s\n", (strlen(CMDLINE_PARSER_PACKAGE_NAME) ? CMDLINE_PARSER_PACKAGE_NAME : CMDLINE_PARSER_PACKAGE), CMDLINE_PARSER_VERSION); if (strlen(gengetopt_args_info_versiontext) > 0) printf("\n%s\n", gengetopt_args_info_versiontext); } static void print_help_common(void) { size_t len_purpose = strlen(gengetopt_args_info_purpose); size_t len_usage = strlen(gengetopt_args_info_usage); if (len_usage > 0) { printf("%s\n", gengetopt_args_info_usage); } if (len_purpose > 0) { printf("%s\n", gengetopt_args_info_purpose); } if (len_usage || len_purpose) { printf("\n"); } if (strlen(gengetopt_args_info_description) > 0) { printf("%s\n\n", gengetopt_args_info_description); } } void cmdline_parser_print_help (void) { int i = 0; print_help_common(); while (gengetopt_args_info_help[i]) printf("%s\n", gengetopt_args_info_help[i++]); } void cmdline_parser_init (struct gengetopt_args_info *args_info) { clear_given (args_info); clear_args (args_info); init_args_info (args_info); } void cmdline_parser_params_init(struct cmdline_parser_params *params) { if (params) { params->override = 0; params->initialize = 1; params->check_required = 1; params->check_ambiguity = 0; params->print_errors = 1; } } struct cmdline_parser_params * cmdline_parser_params_create(void) { struct cmdline_parser_params *params = (struct cmdline_parser_params *)malloc(sizeof(struct cmdline_parser_params)); cmdline_parser_params_init(params); return params; } static void free_string_field (char **s) { if (*s) { free (*s); *s = 0; } } static void cmdline_parser_release (struct gengetopt_args_info *args_info) { free_string_field (&(args_info->algorithm_arg)); free_string_field (&(args_info->algorithm_orig)); free_string_field (&(args_info->capabilities_arg)); free_string_field (&(args_info->capabilities_orig)); free_string_field (&(args_info->delegated_arg)); free_string_field (&(args_info->delegated_orig)); free_string_field (&(args_info->domains_arg)); free_string_field (&(args_info->domains_orig)); free_string_field (&(args_info->id_orig)); free_string_field (&(args_info->in_arg)); free_string_field (&(args_info->in_orig)); free_string_field (&(args_info->out_arg)); free_string_field (&(args_info->out_orig)); free_string_field (&(args_info->label_arg)); free_string_field (&(args_info->label_orig)); free_string_field (&(args_info->wrapkey_arg)); free_string_field (&(args_info->wrapkey_orig)); clear_given (args_info); } static void write_into_file(FILE *outfile, const char *opt, const char *arg, const char *values[]) { FIX_UNUSED (values); if (arg) { fprintf(outfile, "%s=\"%s\"\n", opt, arg); } else { fprintf(outfile, "%s\n", opt); } } int cmdline_parser_dump(FILE *outfile, struct gengetopt_args_info *args_info) { int i = 0; if (!outfile) { fprintf (stderr, "%s: cannot dump options to stream\n", CMDLINE_PARSER_PACKAGE); return EXIT_FAILURE; } if (args_info->help_given) write_into_file(outfile, "help", 0, 0 ); if (args_info->version_given) write_into_file(outfile, "version", 0, 0 ); if (args_info->algorithm_given) write_into_file(outfile, "algorithm", args_info->algorithm_orig, 0); if (args_info->capabilities_given) write_into_file(outfile, "capabilities", args_info->capabilities_orig, 0); if (args_info->delegated_given) write_into_file(outfile, "delegated", args_info->delegated_orig, 0); if (args_info->domains_given) write_into_file(outfile, "domains", args_info->domains_orig, 0); if (args_info->id_given) write_into_file(outfile, "id", args_info->id_orig, 0); if (args_info->in_given) write_into_file(outfile, "in", args_info->in_orig, 0); if (args_info->out_given) write_into_file(outfile, "out", args_info->out_orig, 0); if (args_info->label_given) write_into_file(outfile, "label", args_info->label_orig, 0); if (args_info->wrapkey_given) write_into_file(outfile, "wrapkey", args_info->wrapkey_orig, 0); i = EXIT_SUCCESS; return i; } int cmdline_parser_file_save(const char *filename, struct gengetopt_args_info *args_info) { FILE *outfile; int i = 0; outfile = fopen(filename, "w"); if (!outfile) { fprintf (stderr, "%s: cannot open file for writing: %s\n", CMDLINE_PARSER_PACKAGE, filename); return EXIT_FAILURE; } i = cmdline_parser_dump(outfile, args_info); fclose (outfile); return i; } void cmdline_parser_free (struct gengetopt_args_info *args_info) { cmdline_parser_release (args_info); } /** @brief replacement of strdup, which is not standard */ char * gengetopt_strdup (const char *s) { char *result = 0; if (!s) return result; result = (char*)malloc(strlen(s) + 1); if (result == (char*)0) return (char*)0; strcpy(result, s); return result; } int cmdline_parser (int argc, char **argv, struct gengetopt_args_info *args_info) { return cmdline_parser2 (argc, argv, args_info, 0, 1, 1); } int cmdline_parser_ext (int argc, char **argv, struct gengetopt_args_info *args_info, struct cmdline_parser_params *params) { int result; result = cmdline_parser_internal (argc, argv, args_info, params, 0); if (result == EXIT_FAILURE) { cmdline_parser_free (args_info); exit (EXIT_FAILURE); } return result; } int cmdline_parser2 (int argc, char **argv, struct gengetopt_args_info *args_info, int override, int initialize, int check_required) { int result; struct cmdline_parser_params params; params.override = override; params.initialize = initialize; params.check_required = check_required; params.check_ambiguity = 0; params.print_errors = 1; result = cmdline_parser_internal (argc, argv, args_info, ¶ms, 0); if (result == EXIT_FAILURE) { cmdline_parser_free (args_info); exit (EXIT_FAILURE); } return result; } int cmdline_parser_required (struct gengetopt_args_info *args_info, const char *prog_name) { int result = EXIT_SUCCESS; if (cmdline_parser_required2(args_info, prog_name, 0) > 0) result = EXIT_FAILURE; if (result == EXIT_FAILURE) { cmdline_parser_free (args_info); exit (EXIT_FAILURE); } return result; } int cmdline_parser_required2 (struct gengetopt_args_info *args_info, const char *prog_name, const char *additional_error) { int error_occurred = 0; FIX_UNUSED (additional_error); /* checks for required options */ if (! args_info->algorithm_given) { fprintf (stderr, "%s: '--algorithm' ('-a') option required%s\n", prog_name, (additional_error ? additional_error : "")); error_occurred = 1; } if (! args_info->capabilities_given) { fprintf (stderr, "%s: '--capabilities' ('-c') option required%s\n", prog_name, (additional_error ? additional_error : "")); error_occurred = 1; } if (! args_info->domains_given) { fprintf (stderr, "%s: '--domains' ('-d') option required%s\n", prog_name, (additional_error ? additional_error : "")); error_occurred = 1; } if (! args_info->in_given) { fprintf (stderr, "%s: '--in' option required%s\n", prog_name, (additional_error ? additional_error : "")); error_occurred = 1; } if (! args_info->out_given) { fprintf (stderr, "%s: '--out' option required%s\n", prog_name, (additional_error ? additional_error : "")); error_occurred = 1; } if (! args_info->label_given) { fprintf (stderr, "%s: '--label' ('-l') option required%s\n", prog_name, (additional_error ? additional_error : "")); error_occurred = 1; } if (! args_info->wrapkey_given) { fprintf (stderr, "%s: '--wrapkey' ('-k') option required%s\n", prog_name, (additional_error ? additional_error : "")); error_occurred = 1; } /* checks for dependences among options */ return error_occurred; } static char *package_name = 0; /** * @brief updates an option * @param field the generic pointer to the field to update * @param orig_field the pointer to the orig field * @param field_given the pointer to the number of occurrence of this option * @param prev_given the pointer to the number of occurrence already seen * @param value the argument for this option (if null no arg was specified) * @param possible_values the possible values for this option (if specified) * @param default_value the default value (in case the option only accepts fixed values) * @param arg_type the type of this option * @param check_ambiguity @see cmdline_parser_params.check_ambiguity * @param override @see cmdline_parser_params.override * @param no_free whether to free a possible previous value * @param multiple_option whether this is a multiple option * @param long_opt the corresponding long option * @param short_opt the corresponding short option (or '-' if none) * @param additional_error possible further error specification */ static int update_arg(void *field, char **orig_field, unsigned int *field_given, unsigned int *prev_given, char *value, const char *possible_values[], const char *default_value, cmdline_parser_arg_type arg_type, int check_ambiguity, int override, int no_free, int multiple_option, const char *long_opt, char short_opt, const char *additional_error) { char *stop_char = 0; const char *val = value; int found; char **string_field; FIX_UNUSED (field); stop_char = 0; found = 0; if (!multiple_option && prev_given && (*prev_given || (check_ambiguity && *field_given))) { if (short_opt != '-') fprintf (stderr, "%s: `--%s' (`-%c') option given more than once%s\n", package_name, long_opt, short_opt, (additional_error ? additional_error : "")); else fprintf (stderr, "%s: `--%s' option given more than once%s\n", package_name, long_opt, (additional_error ? additional_error : "")); return 1; /* failure */ } FIX_UNUSED (default_value); if (field_given && *field_given && ! override) return 0; if (prev_given) (*prev_given)++; if (field_given) (*field_given)++; if (possible_values) val = possible_values[found]; switch(arg_type) { case ARG_SHORT: if (val) *((short *)field) = (short)strtol (val, &stop_char, 0); break; case ARG_STRING: if (val) { string_field = (char **)field; if (!no_free && *string_field) free (*string_field); /* free previous string */ *string_field = gengetopt_strdup (val); } break; default: break; }; /* check numeric conversion */ switch(arg_type) { case ARG_SHORT: if (val && !(stop_char && *stop_char == '\0')) { fprintf(stderr, "%s: invalid numeric value: %s\n", package_name, val); return 1; /* failure */ } break; default: ; }; /* store the original value */ switch(arg_type) { case ARG_NO: break; default: if (value && orig_field) { if (no_free) { *orig_field = value; } else { if (*orig_field) free (*orig_field); /* free previous string */ *orig_field = gengetopt_strdup (value); } } }; return 0; /* OK */ } int cmdline_parser_internal ( int argc, char **argv, struct gengetopt_args_info *args_info, struct cmdline_parser_params *params, const char *additional_error) { int c; /* Character of the parsed option. */ int error_occurred = 0; struct gengetopt_args_info local_args_info; int override; int initialize; int check_required; int check_ambiguity; package_name = argv[0]; /* TODO: Why is this here? It is not used anywhere. */ override = params->override; FIX_UNUSED(override); initialize = params->initialize; check_required = params->check_required; /* TODO: Why is this here? It is not used anywhere. */ check_ambiguity = params->check_ambiguity; FIX_UNUSED(check_ambiguity); if (initialize) cmdline_parser_init (args_info); cmdline_parser_init (&local_args_info); optarg = 0; optind = 0; opterr = params->print_errors; optopt = '?'; while (1) { int option_index = 0; static struct option long_options[] = { { "help", 0, NULL, 'h' }, { "version", 0, NULL, 'V' }, { "algorithm", 1, NULL, 'a' }, { "capabilities", 1, NULL, 'c' }, { "delegated", 1, NULL, 'e' }, { "domains", 1, NULL, 'd' }, { "id", 1, NULL, 'i' }, { "in", 1, NULL, 0 }, { "out", 1, NULL, 0 }, { "label", 1, NULL, 'l' }, { "wrapkey", 1, NULL, 'k' }, { 0, 0, 0, 0 } }; c = getopt_long (argc, argv, "hVa:c:e:d:i:l:k:", long_options, &option_index); if (c == -1) break; /* Exit from `while (1)' loop. */ switch (c) { case 'h': /* Print help and exit. */ cmdline_parser_print_help (); cmdline_parser_free (&local_args_info); exit (EXIT_SUCCESS); case 'V': /* Print version and exit. */ cmdline_parser_print_version (); cmdline_parser_free (&local_args_info); exit (EXIT_SUCCESS); case 'a': /* Object algorithm. */ if (update_arg( (void *)&(args_info->algorithm_arg), &(args_info->algorithm_orig), &(args_info->algorithm_given), &(local_args_info.algorithm_given), optarg, 0, 0, ARG_STRING, check_ambiguity, override, 0, 0, "algorithm", 'a', additional_error)) goto failure; break; case 'c': /* Object capabilities. */ if (update_arg( (void *)&(args_info->capabilities_arg), &(args_info->capabilities_orig), &(args_info->capabilities_given), &(local_args_info.capabilities_given), optarg, 0, 0, ARG_STRING, check_ambiguity, override, 0, 0, "capabilities", 'c', additional_error)) goto failure; break; case 'e': /* Object delegates capabilities. */ if (update_arg( (void *)&(args_info->delegated_arg), &(args_info->delegated_orig), &(args_info->delegated_given), &(local_args_info.delegated_given), optarg, 0, 0, ARG_STRING, check_ambiguity, override, 0, 0, "delegated", 'e', additional_error)) goto failure; break; case 'd': /* Object domains. */ if (update_arg( (void *)&(args_info->domains_arg), &(args_info->domains_orig), &(args_info->domains_given), &(local_args_info.domains_given), optarg, 0, 0, ARG_STRING, check_ambiguity, override, 0, 0, "domains", 'd', additional_error)) goto failure; break; case 'i': /* Object ID. */ if (update_arg( (void *)&(args_info->id_arg), &(args_info->id_orig), &(args_info->id_given), &(local_args_info.id_given), optarg, 0, "0", ARG_SHORT, check_ambiguity, override, 0, 0, "id", 'i', additional_error)) goto failure; break; case 'l': /* Object label. */ if (update_arg( (void *)&(args_info->label_arg), &(args_info->label_orig), &(args_info->label_given), &(local_args_info.label_given), optarg, 0, 0, ARG_STRING, check_ambiguity, override, 0, 0, "label", 'l', additional_error)) goto failure; break; case 'k': /* Key to wrap data with (filename). */ if (update_arg( (void *)&(args_info->wrapkey_arg), &(args_info->wrapkey_orig), &(args_info->wrapkey_given), &(local_args_info.wrapkey_given), optarg, 0, 0, ARG_STRING, check_ambiguity, override, 0, 0, "wrapkey", 'k', additional_error)) goto failure; break; case 0: /* Long option with no short option */ /* Input data (filename). */ if (strcmp (long_options[option_index].name, "in") == 0) { if (update_arg( (void *)&(args_info->in_arg), &(args_info->in_orig), &(args_info->in_given), &(local_args_info.in_given), optarg, 0, 0, ARG_STRING, check_ambiguity, override, 0, 0, "in", '-', additional_error)) goto failure; } /* Output data (filename). */ else if (strcmp (long_options[option_index].name, "out") == 0) { if (update_arg( (void *)&(args_info->out_arg), &(args_info->out_orig), &(args_info->out_given), &(local_args_info.out_given), optarg, 0, 0, ARG_STRING, check_ambiguity, override, 0, 0, "out", '-', additional_error)) goto failure; } break; case '?': /* Invalid option. */ /* `getopt_long' already printed an error message. */ goto failure; default: /* bug: option not considered. */ fprintf (stderr, "%s: option unknown: %c%s\n", CMDLINE_PARSER_PACKAGE, c, (additional_error ? additional_error : "")); abort (); } /* switch */ } /* while */ if (check_required) { error_occurred += cmdline_parser_required2 (args_info, argv[0], additional_error); } cmdline_parser_release (&local_args_info); if ( error_occurred ) return (EXIT_FAILURE); return 0; failure: cmdline_parser_release (&local_args_info); return (EXIT_FAILURE); } /* vim: set ft=c noet ts=8 sts=8 sw=8 tw=80 nojs spell : */ yubihsm-shell-2.8.0/yhwrap/README.adoc0000644000175100017510000000472415221003515017014 0ustar runnerrunner== YubiHSM Wrap YubiHSM Wrap is a command-line tool to create "offline wraps" for a YubiHSM 2 device. One of the functionalities supported by the YubiHSM is to import objects under wrap. The typical use is to generate an object on one device, export it under wrap using a Wrap Key and import it to a different device which has the same Wrap Key. At times it is also useful to be able to create those wrapped objects from a computer, so that they can be encrypted at rest and also easily sent to devices for use. === Example This example shows how to generate a private key using OpenSSL, wrap it to a pre-shared Wrap Key and import it on a device. The first thing we need is a Wrap Key that we will use to wrap the object. For this example we are going to use `00112233445566778899aabbccddeeff` We first save it to a file called `wrap.key` by running [source, bash] ---- $ echo -en '\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xaa\xbb\xcc\xdd\xee\xff' >wrap.key ---- The Wrap Key has to also exist on the YubiHSM. We can import it in the device and give it Object ID `20` by running [source, bash] ---- $ yubihsm-shell -p password -a put-wrap-key -i 20 -c all --delegated all --informat bin --in wrap.key ---- At this point we can use OpenSSL to generate the RSA key that we would like to wrap and import [source, bash] ---- $ openssl genrsa -out private.pem ---- We can now use `yubihsm-wrap` to produce the wrapped version of the private key. Specifically, we will be asking for the key to have, once imported, Object ID `30`, label `RSA_Key` and belong to Domains `1`, `2` and `5`. [source, bash] ---- $ yubihsm-wrap -a rsa2048 -c sign-pkcs -d 1,2,5 --id 30 --label RSA_Key --in private.pem --wrapkey wrap.key --out private.yhw ---- The output file `private.yhw` is the wrapped version of the key and it is ready to be imported in the device using the Wrap Key that we stored before. The command to do that is [source, bash] ---- $ yubihsm-shell -p password -a put-wrapped --wrap-id 20 --in private.yhw ---- We should now be able to retrieve information about the Asymmetric Key with Object ID `30` by running [source, bash] ---- $ yubihsm-shell -p password -a get-object-info -i 30 -t asymmetric-key Using default connector URL: http://localhost:12345 Session keepalive set up to run every 15 seconds Created session 0 id: 0x001e, type: asymmetric-key, algorithm: rsa2048, label: "RSA_Key", length: 896, domains: 1:2:5, sequence: 0, origin: imported:imported_wrapped, capabilities: sign-pkcs ---- yubihsm-shell-2.8.0/yhwrap/main.c0000644000175100017510000003006115221003515016310 0ustar runnerrunner/* * Copyright 2015-2018 Yubico AB * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #include #include "../common/platform-config.h" #ifdef __WIN32 #include #else #include #endif #include #include #include "cmdline.h" #include "parsing.h" #include "pkcs5.h" #include "util.h" #include uint8_t _yh_verbosity = YH_VERB_ALL; FILE *_yh_output; #define INPUT_BUFSIZE 4096 #define WRAPKEY_BUFSIZE 32 #define OBJECT_HEADER_SIZE 59 static bool wrap_data(uint8_t *key, size_t key_len, uint8_t *in, size_t in_len, uint8_t *out, size_t *out_len) { EVP_CIPHER_CTX *ctx = NULL; const EVP_CIPHER *cipher_type; uint8_t nonce[13]; int nonce_len = 13; int tag_len = 16; int len; ctx = EVP_CIPHER_CTX_new(); if (ctx == NULL) { return false; } switch (key_len) { case 16: cipher_type = EVP_aes_128_ccm(); break; case 24: cipher_type = EVP_aes_192_ccm(); break; case 32: cipher_type = EVP_aes_256_ccm(); break; default: return false; } if (RAND_bytes(nonce, nonce_len) != 1) { return false; } memcpy(out, nonce, nonce_len); // Select cipher if (EVP_EncryptInit_ex(ctx, cipher_type, NULL, NULL, NULL) != 1) { return false; } // Set nonce length if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_SET_IVLEN, nonce_len, NULL) != 1) { return false; } // Set tag length if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_SET_TAG, tag_len, NULL) != 1) { return false; } // Initialize key and IV if (EVP_EncryptInit_ex(ctx, NULL, NULL, key, nonce) != 1) { return false; } // Provide the total plaintext length if (EVP_EncryptUpdate(ctx, NULL, &len, NULL, in_len) != 1) { return false; } // Provide the message to be encrypted, and obtain the encrypted output if (EVP_EncryptUpdate(ctx, out + nonce_len, &len, in, in_len) != 1) { return false; } *out_len = len; // Finalize the encryption if (EVP_EncryptFinal_ex(ctx, out + nonce_len + *out_len, &len) != 1) { return false; } *out_len += len; // Get the tag if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_GET_TAG, tag_len, out + nonce_len + *out_len) != 1) { return false; } *out_len += tag_len; *out_len += nonce_len; // Clean up EVP_CIPHER_CTX_free(ctx); return true; } static void format_header(yh_algorithm wrapkey_algorithm, yh_capabilities capabilities, uint16_t id, uint16_t data_len, uint16_t domains, yh_object_type type, yh_algorithm algorithm, uint8_t *label, uint8_t *header) { *header = (uint8_t) wrapkey_algorithm; header++; memcpy(header, capabilities.capabilities, YH_CAPABILITIES_LEN); header += YH_CAPABILITIES_LEN; *((uint16_t *) header) = htons(id); header += sizeof(uint16_t); *((uint16_t *) header) = htons(data_len); header += sizeof(uint16_t); *((uint16_t *) header) = htons(domains); header += sizeof(uint16_t); *header = (uint8_t) type; header++; *header = (uint8_t) algorithm; header++; *header = 0x00; // Sequence header++; *header = 0x02; // Origin header++; memcpy(header, label, YH_OBJ_LABEL_LEN); header += YH_OBJ_LABEL_LEN; } static FILE *open_file(const char *name, bool input) { if (input) { if (strcmp(name, "-") == 0) { return stdin; } else { return fopen(name, "rb"); } } else { if (strcmp(name, "-") == 0) { return stdout; } else { return fopen(name, "wb"); } } } static void dump_hex(const unsigned char *buf, unsigned int len) { unsigned int i; for (i = 0; i < len; i++) { if (i && !(i % 32)) fprintf(stderr, "\n"); else if (i && !(i % 8)) fprintf(stderr, " "); fprintf(stderr, "%02x", buf[i]); } fprintf(stderr, "\n"); } int main(int argc, char *argv[]) { struct gengetopt_args_info args_info; int rc = EXIT_FAILURE; yh_rc yhrc; FILE *input_file = NULL; FILE *output_file = NULL; FILE *wrapkey_file = NULL; #pragma pack(push, 1) union { struct { uint8_t header[OBJECT_HEADER_SIZE]; uint8_t body[INPUT_BUFSIZE]; }; uint8_t buf[1]; } wrap_object = {{{0}, {0}}}; #pragma pack(pop) size_t wrap_object_len = sizeof(wrap_object.body); if (cmdline_parser(argc, argv, &args_info) != 0) { goto main_exit; } yh_algorithm algorithm; yhrc = yh_string_to_algo(args_info.algorithm_arg, &algorithm); if (yhrc != YHR_SUCCESS) { fprintf(stderr, "Unable to parse algorithm: %s\n", yh_strerror(yhrc)); goto main_exit; } yh_capabilities capabilities = {{0}}; yhrc = yh_string_to_capabilities(args_info.capabilities_arg, &capabilities); if (yhrc != YHR_SUCCESS) { fprintf(stderr, "Unable to parse capabilities: %s\n", yh_strerror(yhrc)); goto main_exit; } uint16_t domains; yhrc = yh_string_to_domains(args_info.domains_arg, &domains); if (yhrc != YHR_SUCCESS) { fprintf(stderr, "Unable to parse domains: %s\n", yh_strerror(yhrc)); goto main_exit; } uint16_t id = args_info.id_arg; uint8_t label[YH_OBJ_LABEL_LEN] = {0}; size_t label_len = strlen(args_info.label_arg); if (label_len > YH_OBJ_LABEL_LEN) { fprintf(stderr, "Unable to parse label: label too long, maximum length is %d\n", YH_OBJ_LABEL_LEN); goto main_exit; } memcpy(label, args_info.label_arg, label_len); yh_object_type type; if (algo2type(algorithm, &type) == false) { fprintf(stderr, "Invalid algorithm\n"); goto main_exit; } yh_capabilities delegated = {{0}}; bool has_delegated = ((type == YH_AUTHENTICATION_KEY || type == YH_WRAP_KEY) ? true : false); if (has_delegated == true) { if (!args_info.delegated_given) { fprintf(stderr, "Missing delegated capabilities argument\n"); goto main_exit; } yhrc = yh_string_to_capabilities(args_info.delegated_arg, &delegated); if (yhrc != YHR_SUCCESS) { fprintf(stderr, "Unable to parse delegated capabilities: %s\n", yh_strerror(yhrc)); goto main_exit; } } input_file = open_file(args_info.in_arg, true); if (input_file == NULL) { perror("Unable to open input file"); goto main_exit; } switch (type) { case YH_AUTHENTICATION_KEY: { char password[256] = {0}; size_t password_len = sizeof(password); if (input_file == stdin) { const char *prompt = "Derivation Password: "; if (EVP_read_pw_string(password, password_len - 1, prompt, 1)) { fprintf(stderr, "Unable to read password prompt\n"); goto main_exit; } password_len = strlen(password); } else { if (read_file(input_file, (uint8_t *) password, &password_len) == false) { fprintf(stderr, "Unable to read input file\n"); goto main_exit; } if (password[password_len - 1] == '\n') { password_len--; } if (password[password_len - 1] == '\r') { password_len--; } password[password_len] = '\0'; } uint8_t key[YH_KEY_LEN * 2]; bool ret = pkcs5_pbkdf2_hmac((const uint8_t *) password, password_len, (const uint8_t *) YH_DEFAULT_SALT, strlen(YH_DEFAULT_SALT), YH_DEFAULT_ITERS, _SHA256, key, sizeof(key)); if (ret == false) { fprintf(stderr, "Unable to derive keys\n"); goto main_exit; } memcpy(wrap_object.body, delegated.capabilities, YH_CAPABILITIES_LEN); wrap_object_len -= YH_CAPABILITIES_LEN; memcpy(wrap_object.body + YH_CAPABILITIES_LEN, key, YH_KEY_LEN); memcpy(wrap_object.body + YH_CAPABILITIES_LEN + YH_KEY_LEN, key + YH_KEY_LEN, YH_KEY_LEN); wrap_object_len = YH_CAPABILITIES_LEN + YH_KEY_LEN * 2; } break; case YH_WRAP_KEY: { memcpy(wrap_object.body, delegated.capabilities, YH_CAPABILITIES_LEN); wrap_object_len -= YH_CAPABILITIES_LEN; if (read_file(input_file, wrap_object.body + YH_CAPABILITIES_LEN, &wrap_object_len) == false) { fprintf(stderr, "Unable to read input file\n"); goto main_exit; } wrap_object_len += YH_CAPABILITIES_LEN; } break; case YH_ASYMMETRIC_KEY: { yh_algorithm parsed_algorithm; if (read_file(input_file, wrap_object.body, &wrap_object_len) == false) { fprintf(stderr, "Unable to read input file\n"); goto main_exit; } if (read_private_key(wrap_object.body, wrap_object_len, &parsed_algorithm, wrap_object.body, &wrap_object_len, true) != true) { fprintf(stderr, "Unable to read asymmetric private key\n"); goto main_exit; } if (parsed_algorithm != algorithm) { fprintf(stderr, "Mismatched algorithm\n"); goto main_exit; } } break; case YH_HMAC_KEY: { if (read_file(input_file, wrap_object.body, &wrap_object_len) == false) { fprintf(stderr, "Unable to read input file\n"); goto main_exit; } if (split_hmac_key(algorithm, wrap_object.body, wrap_object_len, wrap_object.body, &wrap_object_len) != true) { fprintf(stderr, "Unable to format hmac key\n"); goto main_exit; } } break; default: if (read_file(input_file, wrap_object.body, &wrap_object_len) == false) { fprintf(stderr, "Unable to read input file\n"); goto main_exit; } } wrapkey_file = open_file(args_info.wrapkey_arg, true); if (wrapkey_file == NULL) { perror("Unable to open wrapkey file"); goto main_exit; } uint8_t wrapkey_buf[WRAPKEY_BUFSIZE]; size_t wrapkey_buf_len = sizeof(wrapkey_buf); if (read_file(wrapkey_file, wrapkey_buf, &wrapkey_buf_len) == false) { fprintf(stderr, "Unable to read wrapkey file\n"); } yh_algorithm wrapkey_algorithm; switch (wrapkey_buf_len) { case 16: wrapkey_algorithm = YH_ALGO_AES128_CCM_WRAP; break; case 24: wrapkey_algorithm = YH_ALGO_AES192_CCM_WRAP; break; case 32: wrapkey_algorithm = YH_ALGO_AES256_CCM_WRAP; break; default: fprintf(stderr, "Unable to parse wrapkey: invalid length\n"); goto main_exit; } output_file = open_file(args_info.out_arg, false); if (output_file == NULL) { perror("Unable to open output file"); goto main_exit; } format_header(wrapkey_algorithm, capabilities, id, wrap_object_len, domains, type, algorithm, label, wrap_object.header); uint8_t wrapped[2048] = {0}; size_t wrapped_len = sizeof(wrapped); if (wrap_data(wrapkey_buf, wrapkey_buf_len, wrap_object.buf, OBJECT_HEADER_SIZE + wrap_object_len, wrapped, &wrapped_len) == false) { fprintf(stderr, "Unable to wrap data\n"); goto main_exit; } if (getenv("DEBUG") != NULL) { dump_hex(wrap_object.buf, OBJECT_HEADER_SIZE + wrap_object_len); } if (write_file(wrapped, wrapped_len, output_file, _base64) == false || write_file((uint8_t *) "\n", 1, output_file, _binary) == false) { fprintf(stderr, "Unable to write output file\n"); goto main_exit; } rc = EXIT_SUCCESS; main_exit: cmdline_parser_free(&args_info); if (input_file != NULL) { fclose(input_file); input_file = NULL; } if (output_file != NULL) { fclose(output_file); output_file = NULL; } if (wrapkey_file != NULL) { fclose(wrapkey_file); wrapkey_file = NULL; } return rc; } yubihsm-shell-2.8.0/yhwrap/cmdline.h0000644000175100017510000002143015221003605017004 0ustar runnerrunner/** @file cmdline.h * @brief The header file for the command line option parser * generated by GNU Gengetopt version 2.23 * http://www.gnu.org/software/gengetopt. * DO NOT modify this file, since it can be overwritten * @author GNU Gengetopt */ #ifndef CMDLINE_H #define CMDLINE_H /* If we use autoconf. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include /* for FILE */ #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ #ifndef CMDLINE_PARSER_PACKAGE /** @brief the program name (used for printing errors) */ #define CMDLINE_PARSER_PACKAGE PACKAGE #endif #ifndef CMDLINE_PARSER_PACKAGE_NAME /** @brief the complete program name (used for help and version) */ #ifdef PACKAGE_NAME #define CMDLINE_PARSER_PACKAGE_NAME PACKAGE_NAME #else #define CMDLINE_PARSER_PACKAGE_NAME PACKAGE #endif #endif #ifndef CMDLINE_PARSER_VERSION /** @brief the program version */ #define CMDLINE_PARSER_VERSION VERSION #endif /** @brief Where the command line options are stored */ struct gengetopt_args_info { const char *help_help; /**< @brief Print help and exit help description. */ const char *version_help; /**< @brief Print version and exit help description. */ char * algorithm_arg; /**< @brief Object algorithm. */ char * algorithm_orig; /**< @brief Object algorithm original value given at command line. */ const char *algorithm_help; /**< @brief Object algorithm help description. */ char * capabilities_arg; /**< @brief Object capabilities. */ char * capabilities_orig; /**< @brief Object capabilities original value given at command line. */ const char *capabilities_help; /**< @brief Object capabilities help description. */ char * delegated_arg; /**< @brief Object delegates capabilities. */ char * delegated_orig; /**< @brief Object delegates capabilities original value given at command line. */ const char *delegated_help; /**< @brief Object delegates capabilities help description. */ char * domains_arg; /**< @brief Object domains. */ char * domains_orig; /**< @brief Object domains original value given at command line. */ const char *domains_help; /**< @brief Object domains help description. */ short id_arg; /**< @brief Object ID (default='0'). */ char * id_orig; /**< @brief Object ID original value given at command line. */ const char *id_help; /**< @brief Object ID help description. */ char * in_arg; /**< @brief Input data (filename). */ char * in_orig; /**< @brief Input data (filename) original value given at command line. */ const char *in_help; /**< @brief Input data (filename) help description. */ char * out_arg; /**< @brief Output data (filename). */ char * out_orig; /**< @brief Output data (filename) original value given at command line. */ const char *out_help; /**< @brief Output data (filename) help description. */ char * label_arg; /**< @brief Object label. */ char * label_orig; /**< @brief Object label original value given at command line. */ const char *label_help; /**< @brief Object label help description. */ char * wrapkey_arg; /**< @brief Key to wrap data with (filename). */ char * wrapkey_orig; /**< @brief Key to wrap data with (filename) original value given at command line. */ const char *wrapkey_help; /**< @brief Key to wrap data with (filename) help description. */ unsigned int help_given ; /**< @brief Whether help was given. */ unsigned int version_given ; /**< @brief Whether version was given. */ unsigned int algorithm_given ; /**< @brief Whether algorithm was given. */ unsigned int capabilities_given ; /**< @brief Whether capabilities was given. */ unsigned int delegated_given ; /**< @brief Whether delegated was given. */ unsigned int domains_given ; /**< @brief Whether domains was given. */ unsigned int id_given ; /**< @brief Whether id was given. */ unsigned int in_given ; /**< @brief Whether in was given. */ unsigned int out_given ; /**< @brief Whether out was given. */ unsigned int label_given ; /**< @brief Whether label was given. */ unsigned int wrapkey_given ; /**< @brief Whether wrapkey was given. */ } ; /** @brief The additional parameters to pass to parser functions */ struct cmdline_parser_params { int override; /**< @brief whether to override possibly already present options (default 0) */ int initialize; /**< @brief whether to initialize the option structure gengetopt_args_info (default 1) */ int check_required; /**< @brief whether to check that all required options were provided (default 1) */ int check_ambiguity; /**< @brief whether to check for options already specified in the option structure gengetopt_args_info (default 0) */ int print_errors; /**< @brief whether getopt_long should print an error message for a bad option (default 1) */ } ; /** @brief the purpose string of the program */ extern const char *gengetopt_args_info_purpose; /** @brief the usage string of the program */ extern const char *gengetopt_args_info_usage; /** @brief the description string of the program */ extern const char *gengetopt_args_info_description; /** @brief all the lines making the help output */ extern const char *gengetopt_args_info_help[]; /** * The command line parser * @param argc the number of command line options * @param argv the command line options * @param args_info the structure where option information will be stored * @return 0 if everything went fine, NON 0 if an error took place */ int cmdline_parser (int argc, char **argv, struct gengetopt_args_info *args_info); /** * The command line parser (version with additional parameters - deprecated) * @param argc the number of command line options * @param argv the command line options * @param args_info the structure where option information will be stored * @param override whether to override possibly already present options * @param initialize whether to initialize the option structure my_args_info * @param check_required whether to check that all required options were provided * @return 0 if everything went fine, NON 0 if an error took place * @deprecated use cmdline_parser_ext() instead */ int cmdline_parser2 (int argc, char **argv, struct gengetopt_args_info *args_info, int override, int initialize, int check_required); /** * The command line parser (version with additional parameters) * @param argc the number of command line options * @param argv the command line options * @param args_info the structure where option information will be stored * @param params additional parameters for the parser * @return 0 if everything went fine, NON 0 if an error took place */ int cmdline_parser_ext (int argc, char **argv, struct gengetopt_args_info *args_info, struct cmdline_parser_params *params); /** * Save the contents of the option struct into an already open FILE stream. * @param outfile the stream where to dump options * @param args_info the option struct to dump * @return 0 if everything went fine, NON 0 if an error took place */ int cmdline_parser_dump(FILE *outfile, struct gengetopt_args_info *args_info); /** * Save the contents of the option struct into a (text) file. * This file can be read by the config file parser (if generated by gengetopt) * @param filename the file where to save * @param args_info the option struct to save * @return 0 if everything went fine, NON 0 if an error took place */ int cmdline_parser_file_save(const char *filename, struct gengetopt_args_info *args_info); /** * Print the help */ void cmdline_parser_print_help(void); /** * Print the version */ void cmdline_parser_print_version(void); /** * Initializes all the fields a cmdline_parser_params structure * to their default values * @param params the structure to initialize */ void cmdline_parser_params_init(struct cmdline_parser_params *params); /** * Allocates dynamically a cmdline_parser_params structure and initializes * all its fields to their default values * @return the created and initialized cmdline_parser_params structure */ struct cmdline_parser_params *cmdline_parser_params_create(void); /** * Initializes the passed gengetopt_args_info structure's fields * (also set default values for options that have a default) * @param args_info the structure to initialize */ void cmdline_parser_init (struct gengetopt_args_info *args_info); /** * Deallocates the string fields of the gengetopt_args_info structure * (but does not deallocate the structure itself) * @param args_info the structure to deallocate */ void cmdline_parser_free (struct gengetopt_args_info *args_info); /** * Checks that all the required options were specified * @param args_info the structure to check * @param prog_name the name of the program that will be used to print * possible errors * @return */ int cmdline_parser_required (struct gengetopt_args_info *args_info, const char *prog_name); #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* CMDLINE_H */ yubihsm-shell-2.8.0/yhwrap/cmdline.ggo0000644000175100017510000000201415221003515017326 0ustar runnerrunner# # Copyright 2015-2018 Yubico AB # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # option "algorithm" a "Object algorithm" string option "capabilities" c "Object capabilities" string option "delegated" e "Object delegates capabilities" string optional option "domains" d "Object domains" string option "id" i "Object ID" short optional default="0" option "in" - "Input data (filename)" string option "out" - "Output data (filename)" string option "label" l "Object label" string option "wrapkey" k "Key to wrap data with (filename)" string yubihsm-shell-2.8.0/yhwrap/version.rc.in0000644000175100017510000000214515221003515017642 0ustar runnerrunner #include #define VER_FILEVERSION @yubihsm_shell_VERSION_MAJOR@,@yubihsm_shell_VERSION_MINOR@,@yubihsm_shell_VERSION_PATCH@,0 #define VER_FILEVERSION_STR "@yubihsm_shell_VERSION_MAJOR@.@yubihsm_shell_VERSION_MINOR@.@yubihsm_shell_VERSION_PATCH@.0" VS_VERSION_INFO VERSIONINFO FILEVERSION VER_FILEVERSION PRODUCTVERSION VER_FILEVERSION FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L #else FILEFLAGS 0x0L #endif FILEOS 0x40004L FILETYPE 0x2L FILESUBTYPE 0x0L BEGIN BLOCK "StringFileInfo" BEGIN BLOCK "040904b0" BEGIN VALUE "CompanyName", "Yubico AB" VALUE "FileDescription", "YubiHSM Wrap" VALUE "FileVersion", VER_FILEVERSION_STR VALUE "InternalName", "yubihsm-wrap.exe" VALUE "LegalCopyright", "\xa9 Yubico AB" VALUE "OriginalFilename", "yubihsm-wrap.exe" VALUE "ProductName", "YubiHSM" VALUE "ProductVersion", VER_FILEVERSION_STR END END BLOCK "VarFileInfo" BEGIN VALUE "Translation", 0x409, 1200 END END yubihsm-shell-2.8.0/yhwrap/CMakeLists.txt0000644000175100017510000000520715221003515017764 0ustar runnerrunner# # Copyright 2015-2018 Yubico AB # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # include(${CMAKE_SOURCE_DIR}/cmake/openssl.cmake) find_libcrypto() set ( SOURCE ../common/hash.c ../common/parsing.c ../common/pkcs5.c ../common/util.c ../common/openssl-compat.c main.c ) if(WIN32) set(SOURCE ${SOURCE} cmdline.c) include(${CMAKE_SOURCE_DIR}/cmake/getopt.cmake) find_getopt() else(WIN32) include(gengetopt) add_gengetopt_files (cmdline) set(SOURCE ${SOURCE} ${GGO_C}) message("${GGO_C}") endif(WIN32) include_directories ( ${LIBCRYPTO_INCLUDEDIR} ${CMAKE_CURRENT_SOURCE_DIR}/../lib ${CMAKE_CURRENT_SOURCE_DIR}/../common ) if(${WIN32}) list(APPEND SOURCE ${CMAKE_CURRENT_BINARY_DIR}/version.rc) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/version.rc.in ${CMAKE_CURRENT_BINARY_DIR}/version.rc @ONLY) endif(${WIN32}) # NOTE(adma): required by gengetopt add_definitions (-DPACKAGE="yubihsm-wrap") add_definitions (-DVERSION="${yubihsm_shell_VERSION_MAJOR}.${yubihsm_shell_VERSION_MINOR}.${yubihsm_shell_VERSION_PATCH}") list(APPEND LCOV_REMOVE_PATTERNS "'${PROJECT_SOURCE_DIR}/yhwrap/cmdline.c'") if ("${CMAKE_C_COMPILER_ID}" STREQUAL "GNU") set_property(SOURCE ${GGO_C} APPEND_STRING PROPERTY COMPILE_FLAGS " -Wno-unused-but-set-variable ") endif() add_executable (yubihsm-wrap ${SOURCE}) target_link_libraries ( yubihsm-wrap ${LIBCRYPTO_LDFLAGS} ${GETOPT_LIBS} yubihsm ) # Set install RPATH (Darwin default from root CMakeLists.txt is correct for bin/ targets) if(NOT ${CMAKE_SYSTEM_NAME} MATCHES "Darwin") set_target_properties(yubihsm-wrap PROPERTIES INSTALL_RPATH "${YUBIHSM_INSTALL_LIB_DIR}") endif() add_coverage(yubihsm-wrap) install( TARGETS yubihsm-wrap ARCHIVE DESTINATION "${YUBIHSM_INSTALL_LIB_DIR}" LIBRARY DESTINATION "${YUBIHSM_INSTALL_LIB_DIR}" RUNTIME DESTINATION "${YUBIHSM_INSTALL_BIN_DIR}") if (NOT WITHOUT_MANPAGES) include (help2man) add_help2man_manpage (yubihsm-wrap.1 yubihsm-wrap) add_custom_target (yubihsm-wrap-man ALL DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/yubihsm-wrap.1 ) install(FILES "${CMAKE_CURRENT_BINARY_DIR}/yubihsm-wrap.1" DESTINATION "${YUBIHSM_INSTALL_MAN_DIR}/man1") endif () yubihsm-shell-2.8.0/debian/0000755000175100017510000000000015221003515015130 5ustar runnerrunneryubihsm-shell-2.8.0/debian/yubihsm-shell.install0000644000175100017510000000007115221003515021303 0ustar runnerrunnerusr/bin/yubihsm-shell usr/share/man/man1/yubihsm-shell.1 yubihsm-shell-2.8.0/debian/source/0000755000175100017510000000000015221003515016430 5ustar runnerrunneryubihsm-shell-2.8.0/debian/source/format0000644000175100017510000000001515221003515017637 0ustar runnerrunner3.0 (native) yubihsm-shell-2.8.0/debian/changelog0000644000175100017510000001325715221003515017012 0ustar runnerrunneryubihsm-shell (2.8.0) unstable; urgency=medium * pkcs11: Add support for authenticating a YubiHSM session using a YubiKey * ykhsmauth: Fix a buffer size bug when using longer credential labels * build: Code hardening -- Aveen Ismail Tue, 30 Jun 2026 19:03:37 +0100 yubihsm-shell (2.7.3) unstable; urgency=medium * lib: Fix a bug in defining the capabilities related to managing Public Wrap Key objects -- Aveen Ismail Thu, 13 Apr 2026 14:03:06 +0100 yubihsm-shell (2.7.2) unstable; urgency=medium * lib: Ensure that command audit for command 0x05 cannot be turned on * pkcs11: Improve handling of public key component of RSA Wrap Key * pkcs11: Fix a bug where generating an RSA key pair can potentially result in the wrong type of object being created * build: Upgrade minimum CMake version requirement -- Aveen Ismail Thu, 12 Mar 2026 05:11:13 +0100 yubihsm-shell (2.7.1) unstable; urgency=medium * shell: Add support for decrypt-oaep command in non-interactive mode * test: Improve testing processes -- Aveen Ismail Sat, 17 Jan 2026 10:58:49 +0100 yubihsm-shell (2.7.0) unstable; urgency=medium * lib: shell: pkcs11: Add support for compressing X509Certificate before import * shell: Add subcommand to generate certificate signing request (CSR) * test: Increase test coverage -- Aveen Ismail Tue, 10 Jun 2025 10:56:54 +0100 yubihsm-shell (2.6.0) unstable; urgency=medium * lib: shell: pkcs11: Add support for asymmetric wrap * pkcs11: Add support for PKCS11 3.0 * cmd: Fix opening a session using credentials stored on a YubiKey * build: Always compile with YubiHSM Auth enabled -- Aveen Ismail Thu, 8 Aug 2024 16:08:45 +0100 yubihsm-shell (2.5.0) unstable; urgency=medium * pkcs11: Add support for applying KDF after ECDH derivation * pkcs11: shell: Fix minor bugs * test: Increase test coverage -- Aveen Ismail Mon, 25 Mar 2024 23:27:50 +0100 yubihsm-shell (2.4.2) unstable; urgency=medium * pkcs11: Add Symmetric key capabilities to searchable criteria * pkcs11: Add support for CKA_KEY_TYPE when searching for objects * pkcs11: Add support for CKA_MODIFIABLE and CKA_COPYABLE attributes for AES and Wrap keys * test: Increase test coverage -- Aveen Ismail Mon, 30 Oct 2023 14:55:20 +0100 yubihsm-shell (2.4.1) unstable; urgency=medium * pkcs11: Allow only a user with access to all the object's domains to edit its attributes * pkcs11: Allow for the creation of an asymmetric key even if CKA_ID or CKA_LABEL attribute values for the private and public key are different. * pkcs11: Improve backup capabilities of objects whose attributes have been changed * test: Improve test coverage -- Aveen Ismail Wed, 29 Mar 2023 15:14:26 +0100 yubihsm-shell (2.4.0) unstable; urgency=medium * lib: shell: pkcs11: Add support for symmetric encryption, AES-ECB and AES-CBC (Requires firmware version 2.3 and later) * shell: Enable asymmetric authentication by default (Requires firmware version 2.3 and later) * shell: Allow hex format when creating symmetric authentication key * shell: Improve usage of the list command * shell: Allow yubihsm-auth reader to be specified * shell: Enable backend TLS support in the command line * pkcs11: Add support for modifying CKA_ID and CKA_LABEL attribute values * pkcs11: Improve handling of attributes * pkcs11: Improve debug output * pkcs11: Improve error handling * pkcs11: Change in firmware/harware version representation. The version as reported by C_GetSlotInfo and C_GetTokenInfo will now show minor*10+patch, instead of minor*100+patch * build: Dependecy updates -- Aveen Ismail Sun, 15 Jan 2023 15:46:56 +0100 yubihsm-shell (2.3.2) unstable; urgency=medium * 2.3.2 release -- Aveen Ismail Tue, 14 Jun 2022 10:55:28 +0100 yubihsm-shell (2.3.1) unstable; urgency=medium * 2.3.1 release -- Aveen Ismail Wed, 2 Feb 2022 10:28:21 +0100 yubihsm-shell (2.3.0) unstable; urgency=medium * 2.3.0 release -- Aveen Ismail Wed, 24 Nov 2021 19:28:09 +0100 yubihsm-shell (2.1.0) unstable; urgency=medium * 2.1.0 release -- Aveen Ismail Mon, 1 Mar 2021 16:28:03 +0100 yubihsm-shell (2.0.3) unstable; urgency=medium * 2.0.3 release -- Aveen Ismail Tue, 13 Oct 2020 13:37:10 +0100 yubihsm-shell (2.0.2) unstable; urgency=medium * 2.0.2 release -- Aveen Ismail Wed, 20 Nov 2019 12:18:56 +0000 yubihsm-shell (2.0.1) unstable; urgency=medium * 2.0.1 release. -- Aveen Ismail Thu, 28 Mar 2019 08:10:37 +0000 yubihsm-shell (2.0.0) unstable; urgency=medium * 2.0.0 release. -- Klas Lindfors Mon, 05 Nov 2018 12:02:23 +0100 yubihsm-shell (1.0.4) unstable; urgency=medium * 1.0.4 release. -- Klas Lindfors Tue, 29 May 2018 12:39:05 +0200 yubihsm-shell (1.0.3) unstable; urgency=medium * 1.0.3 release. -- Klas Lindfors Wed, 25 Apr 2018 08:12:54 +0200 yubihsm-shell (1.0.2) unstable; urgency=medium * 1.0.2 release. -- Klas Lindfors Wed, 04 Apr 2018 13:55:59 +0200 yubihsm-shell (1.0.1) unstable; urgency=medium * 1.0.1 release. -- Klas Lindfors Fri, 19 Jan 2018 14:12:32 +0100 yubihsm-shell (1.0.0) unstable; urgency=low * Initial release. -- Alessio Di Mauro Thu, 07 Dec 2017 15:16:43 +0200 yubihsm-shell-2.8.0/debian/yubihsm-pkcs11.install0000755000175100017510000000011715221003515021302 0ustar runnerrunner#! /usr/bin/dh-exec usr/lib/pkcs11/*.so /usr/lib/${DEB_HOST_MULTIARCH}/pkcs11 yubihsm-shell-2.8.0/debian/watch0000644000175100017510000000017115221003515016160 0ustar runnerrunnerversion=3 opts=pgpsigurlmangle=s/$/.sig/ \ https://developers.yubico.com/YubiHSM2/Releases/ yubihsm2-sdk-(.*)\.tar\.gz yubihsm-shell-2.8.0/debian/rules0000755000175100017510000000066115221003515016213 0ustar runnerrunner#!/usr/bin/make -f DH_VERBOSE = 1 DEB_BUILD_OPTIONS=noddebs %: dh $@ --parallel override_dh_install: chrpath -d $(CURDIR)/debian/tmp/usr/bin/* chrpath -d $(CURDIR)/debian/tmp/usr/lib/*.so* chrpath -d $(CURDIR)/debian/tmp/usr/lib/pkcs11/*.so* dh_install --fail-missing override_dh_auto_configure: dh_auto_configure -- -DWITHOUT_YKYH=1 -DRELEASE_BUILD=1 override_dh_auto_test: true #override_dh_installdocs: # find debian yubihsm-shell-2.8.0/debian/libyubihsm-dev.install0000755000175100017510000000020515221003515021443 0ustar runnerrunner#! /usr/bin/dh-exec usr/lib/lib*.so /usr/lib/${DEB_HOST_MULTIARCH} usr/share/pkgconfig/ /usr/lib/${DEB_HOST_MULTIARCH} usr/include/ yubihsm-shell-2.8.0/debian/compat0000644000175100017510000000000215221003515016326 0ustar runnerrunner9 yubihsm-shell-2.8.0/debian/libykhsmauth-dev.install0000644000175100017510000000017315221003515022001 0ustar runnerrunner#! /usr/bin/dh-exec usr/lib/libykhsmauth*.so /usr/lib/ usr/share/pkgconfig/ykhsmauth.pc /usr/lib/ usr/include/ykhsmauth.h yubihsm-shell-2.8.0/debian/README.source0000644000175100017510000000077515221003515017320 0ustar runnerrunnerWe describe here one way to work with the package sources. Initialize cowbuilder: $ git-pbuilder create Optionally update cowbuilder: $ git-pbuilder update Clone the project from repository: $ git clone Build the package: $ gbp buildpackage --git-pbuilder --git-pbuilder-options=--twice If all goes well, you should have newly built packages in ../. Update the package to a new upstream release (don't forget debian/changelog): $ gbp import-orig /path/to/new-release.tar.gz yubihsm-shell-2.8.0/debian/gbp.conf0000644000175100017510000000005715221003515016551 0ustar runnerrunner[DEFAULT] pristine-tar = True sign-tags = True yubihsm-shell-2.8.0/debian/yubihsm-wrap.install0000644000175100017510000000006715221003515021152 0ustar runnerrunnerusr/bin/yubihsm-wrap usr/share/man/man1/yubihsm-wrap.1 yubihsm-shell-2.8.0/debian/copyright0000644000175100017510000000274315221003515017071 0ustar runnerrunnerFormat: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ Upstream-Name: yubihsm-shell Source: https://developers.yubico.com/YubiHSM2 Files: * Copyright: Copyright (c) 2017 Yubico AB License: BSD-2-clause Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: . * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. . * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. . THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. yubihsm-shell-2.8.0/debian/libyubihsm-http1.install0000755000175100017510000000012115221003515021722 0ustar runnerrunner#! /usr/bin/dh-exec usr/lib/libyubihsm_http.so.* /usr/lib/${DEB_HOST_MULTIARCH} yubihsm-shell-2.8.0/debian/libyubihsm-usb1.install0000755000175100017510000000012015221003515021533 0ustar runnerrunner#! /usr/bin/dh-exec usr/lib/libyubihsm_usb.so.* /usr/lib/${DEB_HOST_MULTIARCH} yubihsm-shell-2.8.0/debian/libyubihsm1.install0000755000175100017510000000011415221003515020747 0ustar runnerrunner#! /usr/bin/dh-exec usr/lib/libyubihsm.so.* /usr/lib/${DEB_HOST_MULTIARCH} yubihsm-shell-2.8.0/debian/libykhsmauth1.install0000755000175100017510000000007115221003515021306 0ustar runnerrunner#! /usr/bin/dh-exec usr/lib/libykhsmauth.so.* /usr/lib/ yubihsm-shell-2.8.0/debian/control0000644000175100017510000001622515221003515016541 0ustar runnerrunnerSource: yubihsm-shell Maintainer: Yubico Maintainers Uploaders: Klas Lindfors , Alessio Di Mauro Section: utils Priority: optional Build-Depends: debhelper (>= 9), chrpath, cmake, pkg-config, libedit-dev, libssl-dev, libcurl4-openssl-dev, libpcsclite-dev, libusb-1.0-0-dev, gengetopt, help2man, dh-exec, Standards-Version: 3.9.8 Homepage: https://developers.yubico.com/YubiHSM2 Vcs-Git: git://github.com/Yubico/RELEASEME.git Vcs-Browser: https://github.com/Yubico/RELEASEME Package: libyubihsm1 Architecture: any Section: libs Pre-Depends: ${misc:Pre-Depends} Depends: ${shlibs:Depends}, ${misc:Depends}, libyubihsm-http1 (= ${binary:Version}) | libyubihsm-usb1 (= ${binary:Version}) Description: Library for communication with the YubiHSM 2. The YubiHSM 2 is a Hardware Security Module that is within reach of all organizations. It provides advanced cryptography, including hashing, asymmetric and symmetric key cryptography, to protect the cryptographic keys that secure critical applications, identities, and sensitive data in an enterprise for certificate authorities, databases, code signing and more. . This package contains the run-time shared library. You normally don't need to install it manually. Package: libyubihsm-usb1 Architecture: any Section: libs Pre-Depends: ${misc:Pre-Depends} Depends: ${shlibs:Depends}, ${misc:Depends} Recommends: libyubihsm1 Description: Library for communication with the YubiHSM 2. The YubiHSM 2 is a Hardware Security Module that is within reach of all organizations. It provides advanced cryptography, including hashing, asymmetric and symmetric key cryptography, to protect the cryptographic keys that secure critical applications, identities, and sensitive data in an enterprise for certificate authorities, databases, code signing and more. . This package contains backend functions for direct usb access for the libyubihsm1 package. Package: libyubihsm-http1 Architecture: any Section: libs Pre-Depends: ${misc:Pre-Depends} Depends: ${shlibs:Depends}, ${misc:Depends} Recommends: libyubihsm1 Suggests: yubihsm-connector Description: Library for communication with the YubiHSM 2. The YubiHSM 2 is a Hardware Security Module that is within reach of all organizations. It provides advanced cryptography, including hashing, asymmetric and symmetric key cryptography, to protect the cryptographic keys that secure critical applications, identities, and sensitive data in an enterprise for certificate authorities, databases, code signing and more. . This package contains backend functions for http access to the yubihsm connector for the libyubihsm1 package. Package: libyubihsm-dev Architecture: any Section: libdevel Depends: ${shlibs:Depends}, ${misc:Depends}, libyubihsm1 (= ${binary:Version}) Description: Library for communication with the YubiHSM 2 The YubiHSM 2 is a Hardware Security Module that is within reach of all organizations. It provides advanced cryptography, including hashing, asymmetric and symmetric key cryptography, to protect the cryptographic keys that secure critical applications, identities, and sensitive data in an enterprise for certificate authorities, databases, code signing and more. . This package contains the development files for the library. Package: libykhsmauth1 Architecture: any Section: libs Pre-Depends: ${misc:Pre-Depends} Depends: ${shlibs:Depends}, ${misc:Depends} Description: Library for communication with the YubiKey to setup an authentication key that can be used to access the YubiHSM 2. The YubiHSM 2 is a Hardware Security Module that is within reach of all organizations. It provides advanced cryptography, including hashing, asymmetric and symmetric key cryptography, to protect the cryptographic keys that secure critical applications, identities, and sensitive data in an enterprise for certificate authorities, databases, code signing and more. . This package contains the libykhsmauth run-time shared library Package: libykhsmauth-dev Architecture: any Section: libdevel Depends: ${shlibs:Depends}, ${misc:Depends}, libykhsmauth1 (= ${binary:Version}) Description: Library for communication with the YubiKey to setup an authentication key that can be used to access the YubiHSM 2. The YubiHSM 2 is a Hardware Security Module that is within reach of all organizations. It provides advanced cryptography, including hashing, asymmetric and symmetric key cryptography, to protect the cryptographic keys that secure critical applications, identities, and sensitive data in an enterprise for certificate authorities, databases, code signing and more. . This package contains the development files for the libykhsmauth library. Package: yubihsm-pkcs11 Architecture: any Section: libs Depends: ${shlibs:Depends}, ${misc:Depends}, libyubihsm1 (= ${binary:Version}) Description: PKCS#11 module for communication with the YubiHSM 2. The YubiHSM 2 is a Hardware Security Module that is within reach of all organizations. It provides advanced cryptography, including hashing, asymmetric and symmetric key cryptography, to protect the cryptographic keys that secure critical applications, identities, and sensitive data in an enterprise for certificate authorities, databases, code signing and more. . This package contains the PKCS#11 module. Package: yubihsm-shell Architecture: any Depends: ${shlibs:Depends}, ${misc:Depends} Description: Command line and interactive tool for the YubiHSM 2. The YubiHSM 2 is a Hardware Security Module that is within reach of all organizations. It provides advanced cryptography, including hashing, asymmetric and symmetric key cryptography, to protect the cryptographic keys that secure critical applications, identities, and sensitive data in an enterprise for certificate authorities, databases, code signing and more. . This package contains the command-line tool. Package: yubihsm-wrap Architecture: any Depends: ${shlibs:Depends}, ${misc:Depends} Description: Command line tool for producing offline wrapped objects for the YubiHSM 2. The YubiHSM 2 is a Hardware Security Module that is within reach of all organizations. It provides advanced cryptography, including hashing, asymmetric and symmetric key cryptography, to protect the cryptographic keys that secure critical applications, identities, and sensitive data in an enterprise for certificate authorities, databases, code signing and more. . This package contains the yubihsm-wrap command-line tool. Package: yubihsm-auth Architecture: any Depends: ${shlibs:Depends}, ${misc:Depends} Description: Command line tool for storing the authentication keys of a YubiHSM in a YubiKey The YubiHSM 2 is a Hardware Security Module that is within reach of all organizations. It provides advanced cryptography, including hashing, asymmetric and symmetric key cryptography, to protect the cryptographic keys that secure critical applications, identities, and sensitive data in an enterprise for certificate authorities, databases, code signing and more. . This package contains the yubihsm-auth command-line tool. yubihsm-shell-2.8.0/debian/yubihsm-auth.install0000644000175100017510000000006715221003515021142 0ustar runnerrunnerusr/bin/yubihsm-auth usr/share/man/man1/yubihsm-auth.1 yubihsm-shell-2.8.0/cmake/0000755000175100017510000000000015221003515014766 5ustar runnerrunneryubihsm-shell-2.8.0/cmake/gengetopt.cmake0000644000175100017510000000153515221003515017770 0ustar runnerrunnermacro (find_gengetopt) if (NOT GENGETOPT_EXECUTABLE) find_program (GENGETOPT_EXECUTABLE gengetopt) if (NOT GENGETOPT_EXECUTABLE) message (FATAL_ERROR "gengetopt not found. Aborting...") endif () endif () endmacro () macro (add_gengetopt_files _basename) find_gengetopt () set (_ggo_extra_input ${ARGV}) set (_ggo_c ${CMAKE_CURRENT_SOURCE_DIR}/${_basename}.c) set (_ggo_h ${CMAKE_CURRENT_SOURCE_DIR}/${_basename}.h) set (_ggo_g ${CMAKE_CURRENT_SOURCE_DIR}/${_basename}.ggo) add_custom_command ( OUTPUT ${_ggo_c} ${_ggo_h} COMMAND gengetopt ${_ggo_extra_input} -i ${_ggo_g} --output-dir ${CMAKE_CURRENT_SOURCE_DIR} DEPENDS ${_ggo_g} # BYPRODUCTS COMMENT "Generating getopt parser code (cmdline.{h,c}) ..." VERBATIM ) set (GGO_C ${_ggo_c}) set (GGO_H ${_ggo_h}) endmacro (add_gengetopt_files) yubihsm-shell-2.8.0/cmake/getopt.cmake0000644000175100017510000000101315221003515017265 0ustar runnerrunnermacro (find_getopt) if (MSVC) if(NOT GETOPT_LIB_DIR AND NOT GETOPT_INCLUDE_DIR) message (FATAL_ERROR "Missing 'GETOPT_LIB_DIR' and 'GETOPT_INCLUDE_DIR' options to CMake command. Aborting...") else(NOT GETOPT_LIB_DIR AND NOT GETOPT_INCLUDE_DIR) find_library(GETOPT getopt PATHS ${GETOPT_LIB_DIR}) set(GETOPT_LIBS ${GETOPT}) include_directories(${GETOPT_INCLUDE_DIR}) endif(NOT GETOPT_LIB_DIR AND NOT GETOPT_INCLUDE_DIR) endif (MSVC) endmacro ()yubihsm-shell-2.8.0/cmake/FindGcov.cmake0000644000175100017510000001173615221003515017477 0ustar runnerrunner# This file is part of CMake-codecov. # # Copyright (c) # 2015-2017 RWTH Aachen University, Federal Republic of Germany # # See the LICENSE file in the package base directory for details # # Written by Alexander Haase, alexander.haase@rwth-aachen.de # # include required Modules include(FindPackageHandleStandardArgs) # Search for gcov binary. set(CMAKE_REQUIRED_QUIET_SAVE ${CMAKE_REQUIRED_QUIET}) set(CMAKE_REQUIRED_QUIET ${codecov_FIND_QUIETLY}) get_property(ENABLED_LANGUAGES GLOBAL PROPERTY ENABLED_LANGUAGES) foreach (LANG ${ENABLED_LANGUAGES}) # Gcov evaluation is dependend on the used compiler. Check gcov support for # each compiler that is used. If gcov binary was already found for this # compiler, do not try to find it again. if (NOT GCOV_${CMAKE_${LANG}_COMPILER_ID}_BIN) get_filename_component(COMPILER_PATH "${CMAKE_${LANG}_COMPILER}" PATH) if ("${CMAKE_${LANG}_COMPILER_ID}" STREQUAL "GNU") # Some distributions like OSX (homebrew) ship gcov with the compiler # version appended as gcov-x. To find this binary we'll build the # suggested binary name with the compiler version. string(REGEX MATCH "^[0-9]+" GCC_VERSION "${CMAKE_${LANG}_COMPILER_VERSION}") find_program(GCOV_BIN NAMES gcov-${GCC_VERSION} gcov HINTS ${COMPILER_PATH}) elseif ("${CMAKE_${LANG}_COMPILER_ID}" STREQUAL "Clang") # Some distributions like Debian ship llvm-cov with the compiler # version appended as llvm-cov-x.y. To find this binary we'll build # the suggested binary name with the compiler version. string(REGEX MATCH "^[0-9]+.[0-9]+" LLVM_VERSION "${CMAKE_${LANG}_COMPILER_VERSION}") # llvm-cov prior version 3.5 seems to be not working with coverage # evaluation tools, but these versions are compatible with the gcc # gcov tool. if(LLVM_VERSION VERSION_GREATER 3.4) find_program(LLVM_COV_BIN NAMES "llvm-cov-${LLVM_VERSION}" "llvm-cov" HINTS ${COMPILER_PATH}) mark_as_advanced(LLVM_COV_BIN) if (LLVM_COV_BIN) find_program(LLVM_COV_WRAPPER "llvm-cov-wrapper" PATHS ${CMAKE_MODULE_PATH}) if (LLVM_COV_WRAPPER) set(GCOV_BIN "${LLVM_COV_WRAPPER}" CACHE FILEPATH "") # set additional parameters set(GCOV_${CMAKE_${LANG}_COMPILER_ID}_ENV "LLVM_COV_BIN=${LLVM_COV_BIN}" CACHE STRING "Environment variables for llvm-cov-wrapper.") mark_as_advanced(GCOV_${CMAKE_${LANG}_COMPILER_ID}_ENV) endif () endif () endif () if (NOT GCOV_BIN) # Fall back to gcov binary if llvm-cov was not found or is # incompatible. This is the default on OSX, but may crash on # recent Linux versions. find_program(GCOV_BIN gcov HINTS ${COMPILER_PATH}) endif () endif () if (GCOV_BIN) set(GCOV_${CMAKE_${LANG}_COMPILER_ID}_BIN "${GCOV_BIN}" CACHE STRING "${LANG} gcov binary.") if (NOT CMAKE_REQUIRED_QUIET) message("-- Found gcov evaluation for " "${CMAKE_${LANG}_COMPILER_ID}: ${GCOV_BIN}") endif() unset(GCOV_BIN CACHE) endif () endif () endforeach () # Add a new global target for all gcov targets. This target could be used to # generate the gcov files for the whole project instead of calling -gcov # for each target. if (NOT TARGET gcov) add_custom_target(gcov) endif (NOT TARGET gcov) # This function will add gcov evaluation for target . Only sources of # this target will be evaluated and no dependencies will be added. It will call # Gcov on any source file of once and store the gcov file in the same # directory. function (add_gcov_target TNAME) set(TDIR ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/${TNAME}.dir) # We don't have to check, if the target has support for coverage, thus this # will be checked by add_coverage_target in Findcoverage.cmake. Instead we # have to determine which gcov binary to use. get_target_property(TSOURCES ${TNAME} SOURCES) set(SOURCES "") set(TCOMPILER "") foreach (FILE ${TSOURCES}) codecov_path_of_source(${FILE} FILE) if (NOT "${FILE}" STREQUAL "") codecov_lang_of_source(${FILE} LANG) if (NOT "${LANG}" STREQUAL "") list(APPEND SOURCES "${FILE}") set(TCOMPILER ${CMAKE_${LANG}_COMPILER_ID}) endif () endif () endforeach () # If no gcov binary was found, coverage data can't be evaluated. if (NOT GCOV_${TCOMPILER}_BIN) message(WARNING "No coverage evaluation binary found for ${TCOMPILER}.") return() endif () set(GCOV_BIN "${GCOV_${TCOMPILER}_BIN}") set(GCOV_ENV "${GCOV_${TCOMPILER}_ENV}") set(BUFFER "") foreach(FILE ${SOURCES}) get_filename_component(FILE_PATH "${TDIR}/${FILE}" PATH) # call gcov add_custom_command(OUTPUT ${TDIR}/${FILE}.gcov COMMAND ${GCOV_ENV} ${GCOV_BIN} ${TDIR}/${FILE}.gcno > /dev/null DEPENDS ${TNAME} ${TDIR}/${FILE}.gcno WORKING_DIRECTORY ${FILE_PATH} ) list(APPEND BUFFER ${TDIR}/${FILE}.gcov) endforeach() # add target for gcov evaluation of add_custom_target(${TNAME}-gcov DEPENDS ${BUFFER}) # add evaluation target to the global gcov target. add_dependencies(gcov ${TNAME}-gcov) endfunction (add_gcov_target) yubihsm-shell-2.8.0/cmake/help2man.cmake0000644000175100017510000000066115221003515017501 0ustar runnerrunnerfind_program (HELP2MAN_LOCATION help2man) IF (NOT HELP2MAN_LOCATION) message (FATAL_ERROR "Cannot find help2man. Please install it.") ENDIF () MACRO (add_help2man_manpage file command) add_custom_command (OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${file} COMMAND ${HELP2MAN_LOCATION} ARGS -s1 -N -o ${CMAKE_CURRENT_BINARY_DIR}/${file} ./${command} DEPENDS ${command} COMMENT "Building manpage for ${command}") ENDMACRO () yubihsm-shell-2.8.0/cmake/mingw32.cmake0000644000175100017510000000117315221003515017260 0ustar runnerrunner# the name of the target operating system SET(CMAKE_SYSTEM_NAME Windows) # which compilers to use for C and C++ SET(CMAKE_C_COMPILER i686-w64-mingw32-gcc) SET(CMAKE_CXX_COMPILER i686-w64-mingw32-g++) SET(CMAKE_RC_COMPILER i686-w64-mingw32-windres) # here is the target environment located SET(CMAKE_FIND_ROOT_PATH /usr/i686-w64-mingw32 ) # adjust the default behaviour of the FIND_XXX() commands: # search headers and libraries in the target environment, search # programs in the host environment set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) yubihsm-shell-2.8.0/cmake/zlib.cmake0000644000175100017510000000125115221003515016727 0ustar runnerrunnermacro(find_zlib) if(MSVC) if (ZLIB_LIB_DIR AND ZLIB_INCLUDE_DIR) # Legacy manual path override find_library(ZLIB NAMES zlib zlib1 z PATHS ${ZLIB_LIB_DIR}) set(ZLIB_LIBS ${ZLIB}) include_directories(${ZLIB_INCLUDE_DIR}) else(ZLIB_LIB_DIR AND ZLIB_INCLUDE_DIR) # Use vcpkg toolchain or system find_package find_package(ZLIB REQUIRED) set(ZLIB_LIBS ZLIB::ZLIB) endif(ZLIB_LIB_DIR AND ZLIB_INCLUDE_DIR) else (MSVC) find_package(ZLIB REQUIRED) set(ZLIB_LIBS ${ZLIB_LIBRARIES}) include_directories(${ZLIB_INCLUDE_DIRS}) endif (MSVC) endmacro()yubihsm-shell-2.8.0/cmake/Fuzzing.cmake0000644000175100017510000000220415221003515017422 0ustar runnerrunneroption(FUZZING "Compile binaries with fuzzing instrumentation" OFF) option(LIBFUZZER_ASAN "Enable ASAN instrumentation with libfuzzer" OFF) option(FUZZING_MSAN "Compile binaries with MemorySanitizer instrumentation" OFF) if (FUZZING) message(STATUS "Building with fuzzing instrumentation.") string (APPEND CMAKE_C_FLAGS " -DFUZZING") string (APPEND CMAKE_C_FLAGS " -fno-omit-frame-pointer -O1 -g") string (APPEND CMAKE_CXX_FLAGS " -std=c++17") string (APPEND CMAKE_CXX_FLAGS " -DFUZZING") string (APPEND CMAKE_CXX_FLAGS " -fno-omit-frame-pointer -O1 -g") string (APPEND CMAKE_EXE_LINKER_FLAGS " -g") if (FUZZING_MSAN) string (APPEND CMAKE_C_FLAGS " -fsanitize=memory") string (APPEND CMAKE_CXX_FLAGS " -fsanitize=memory") string (APPEND CMAKE_EXE_LINKER_FLAGS " -fsanitize=memory") else (FUZZING_MSAN) string (APPEND CMAKE_C_FLAGS " -fsanitize=address -fsanitize=undefined") string (APPEND CMAKE_CXX_FLAGS " -fsanitize=address -fsanitize=undefined") string (APPEND CMAKE_EXE_LINKER_FLAGS " -fsanitize=address -fsanitize=undefined") endif (FUZZING_MSAN) endif () yubihsm-shell-2.8.0/cmake/FindLcov.cmake0000644000175100017510000003005015221003515017472 0ustar runnerrunner# This file is part of CMake-codecov. # # Copyright (c) # 2015-2017 RWTH Aachen University, Federal Republic of Germany # # See the LICENSE file in the package base directory for details # # Written by Alexander Haase, alexander.haase@rwth-aachen.de # # configuration set(LCOV_DATA_PATH "${CMAKE_BINARY_DIR}/lcov/data") set(LCOV_DATA_PATH_INIT "${LCOV_DATA_PATH}/init") set(LCOV_DATA_PATH_CAPTURE "${LCOV_DATA_PATH}/capture") set(LCOV_HTML_PATH "${CMAKE_BINARY_DIR}/lcov/html") # Search for Gcov which is used by Lcov. find_package(Gcov) # This function will add lcov evaluation for target . Only sources of # this target will be evaluated and no dependencies will be added. It will call # geninfo on any source file of once and store the info file in the same # directory. # # Note: This function is only a wrapper to define this function always, even if # coverage is not supported by the compiler or disabled. This function must # be defined here, because the module will be exited, if there is no coverage # support by the compiler or it is disabled by the user. function (add_lcov_target TNAME) if (LCOV_FOUND) # capture initial coverage data lcov_capture_initial_tgt(${TNAME}) # capture coverage data after execution lcov_capture_tgt(${TNAME}) endif () endfunction (add_lcov_target) # include required Modules include(FindPackageHandleStandardArgs) # Search for required lcov binaries. find_program(LCOV_BIN lcov) find_program(GENINFO_BIN geninfo) find_program(GENHTML_BIN genhtml) find_package_handle_standard_args(lcov REQUIRED_VARS LCOV_BIN GENINFO_BIN GENHTML_BIN ) # enable genhtml C++ demangeling, if c++filt is found. set(GENHTML_CPPFILT_FLAG "") find_program(CPPFILT_BIN c++filt) if (NOT CPPFILT_BIN STREQUAL "") set(GENHTML_CPPFILT_FLAG "--demangle-cpp") endif (NOT CPPFILT_BIN STREQUAL "") # enable no-external flag for lcov, if available. if (GENINFO_BIN AND NOT DEFINED GENINFO_EXTERN_FLAG) set(FLAG "") execute_process(COMMAND ${GENINFO_BIN} --help OUTPUT_VARIABLE GENINFO_HELP) string(REGEX MATCH "external" GENINFO_RES "${GENINFO_HELP}") if (GENINFO_RES) set(FLAG "--no-external") endif () set(GENINFO_EXTERN_FLAG "${FLAG}" CACHE STRING "Geninfo flag to exclude system sources.") endif () # If Lcov was not found, exit module now. if (NOT LCOV_FOUND) return() endif (NOT LCOV_FOUND) # Create directories to be used. file(MAKE_DIRECTORY ${LCOV_DATA_PATH_INIT}) file(MAKE_DIRECTORY ${LCOV_DATA_PATH_CAPTURE}) set(LCOV_REMOVE_PATTERNS "") # This function will merge lcov files to a single target file. Additional lcov # flags may be set with setting LCOV_EXTRA_FLAGS before calling this function. function (lcov_merge_files OUTFILE ...) # Remove ${OUTFILE} from ${ARGV} and generate lcov parameters with files. list(REMOVE_AT ARGV 0) # Generate merged file. string(REPLACE "${CMAKE_BINARY_DIR}/" "" FILE_REL "${OUTFILE}") add_custom_command(OUTPUT "${OUTFILE}.raw" COMMAND cat ${ARGV} > ${OUTFILE}.raw DEPENDS ${ARGV} COMMENT "Generating ${FILE_REL}" ) add_custom_command(OUTPUT "${OUTFILE}" COMMAND ${LCOV_BIN} --quiet -a ${OUTFILE}.raw --output-file ${OUTFILE} --base-directory ${PROJECT_SOURCE_DIR} ${LCOV_EXTRA_FLAGS} COMMAND ${LCOV_BIN} --quiet -r ${OUTFILE} ${LCOV_REMOVE_PATTERNS} --output-file ${OUTFILE} ${LCOV_EXTRA_FLAGS} DEPENDS ${OUTFILE}.raw COMMENT "Post-processing ${FILE_REL}" ) endfunction () # Add a new global target to generate initial coverage reports for all targets. # This target will be used to generate the global initial info file, which is # used to gather even empty report data. if (NOT TARGET lcov-capture-init) add_custom_target(lcov-capture-init) set(LCOV_CAPTURE_INIT_FILES "" CACHE INTERNAL "") endif (NOT TARGET lcov-capture-init) # This function will add initial capture of coverage data for target , # which is needed to get also data for objects, which were not loaded at # execution time. It will call geninfo for every source file of once and # store the info file in the same directory. function (lcov_capture_initial_tgt TNAME) # We don't have to check, if the target has support for coverage, thus this # will be checked by add_coverage_target in Findcoverage.cmake. Instead we # have to determine which gcov binary to use. get_target_property(TSOURCES ${TNAME} SOURCES) set(SOURCES "") set(TCOMPILER "") foreach (FILE ${TSOURCES}) codecov_path_of_source(${FILE} FILE) if (NOT "${FILE}" STREQUAL "") codecov_lang_of_source(${FILE} LANG) if (NOT "${LANG}" STREQUAL "") list(APPEND SOURCES "${FILE}") set(TCOMPILER ${CMAKE_${LANG}_COMPILER_ID}) endif () endif () endforeach () # If no gcov binary was found, coverage data can't be evaluated. if (NOT GCOV_${TCOMPILER}_BIN) message(WARNING "No coverage evaluation binary found for ${TCOMPILER}.") return() endif () set(GCOV_BIN "${GCOV_${TCOMPILER}_BIN}") set(GCOV_ENV "${GCOV_${TCOMPILER}_ENV}") set(TDIR ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/${TNAME}.dir) set(GENINFO_FILES "") foreach(FILE ${SOURCES}) # generate empty coverage files set(OUTFILE "${TDIR}/${FILE}.info.init") list(APPEND GENINFO_FILES ${OUTFILE}) add_custom_command(OUTPUT ${OUTFILE} COMMAND ${GCOV_ENV} ${GENINFO_BIN} --quiet --base-directory ${PROJECT_SOURCE_DIR} --initial --gcov-tool ${GCOV_BIN} --output-filename ${OUTFILE} ${GENINFO_EXTERN_FLAG} ${TDIR}/${FILE}.gcno DEPENDS ${TNAME} COMMENT "Capturing initial coverage data for ${FILE}" ) endforeach() # Concatenate all files generated by geninfo to a single file per target. set(OUTFILE "${LCOV_DATA_PATH_INIT}/${TNAME}.info") set(LCOV_EXTRA_FLAGS "--initial") lcov_merge_files("${OUTFILE}" ${GENINFO_FILES}) add_custom_target(${TNAME}-capture-init ALL DEPENDS ${OUTFILE}) # add geninfo file generation to global lcov-geninfo target add_dependencies(lcov-capture-init ${TNAME}-capture-init) set(LCOV_CAPTURE_INIT_FILES "${LCOV_CAPTURE_INIT_FILES}" "${OUTFILE}" CACHE INTERNAL "" ) endfunction (lcov_capture_initial_tgt) # This function will generate the global info file for all targets. It has to be # called after all other CMake functions in the root CMakeLists.txt file, to get # a full list of all targets that generate coverage data. function (lcov_capture_initial) # Skip this function (and do not create the following targets), if there are # no input files. if ("${LCOV_CAPTURE_INIT_FILES}" STREQUAL "") return() endif () # Add a new target to merge the files of all targets. set(OUTFILE "${LCOV_DATA_PATH_INIT}/all_targets.info") lcov_merge_files("${OUTFILE}" ${LCOV_CAPTURE_INIT_FILES}) add_custom_target(lcov-geninfo-init ALL DEPENDS ${OUTFILE} lcov-capture-init ) endfunction (lcov_capture_initial) # Add a new global target to generate coverage reports for all targets. This # target will be used to generate the global info file. if (NOT TARGET lcov-capture) add_custom_target(lcov-capture) set(LCOV_CAPTURE_FILES "" CACHE INTERNAL "") endif (NOT TARGET lcov-capture) # This function will add capture of coverage data for target , which is # needed to get also data for objects, which were not loaded at execution time. # It will call geninfo for every source file of once and store the info # file in the same directory. function (lcov_capture_tgt TNAME) # We don't have to check, if the target has support for coverage, thus this # will be checked by add_coverage_target in Findcoverage.cmake. Instead we # have to determine which gcov binary to use. get_target_property(TSOURCES ${TNAME} SOURCES) set(SOURCES "") set(TCOMPILER "") foreach (FILE ${TSOURCES}) codecov_path_of_source(${FILE} FILE) if (NOT "${FILE}" STREQUAL "") codecov_lang_of_source(${FILE} LANG) if (NOT "${LANG}" STREQUAL "") list(APPEND SOURCES "${FILE}") set(TCOMPILER ${CMAKE_${LANG}_COMPILER_ID}) endif () endif () endforeach () # If no gcov binary was found, coverage data can't be evaluated. if (NOT GCOV_${TCOMPILER}_BIN) message(WARNING "No coverage evaluation binary found for ${TCOMPILER}.") return() endif () set(GCOV_BIN "${GCOV_${TCOMPILER}_BIN}") set(GCOV_ENV "${GCOV_${TCOMPILER}_ENV}") set(TDIR ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/${TNAME}.dir) set(GENINFO_FILES "") foreach(FILE ${SOURCES}) # Generate coverage files. If no .gcda file was generated during # execution, the empty coverage file will be used instead. set(OUTFILE "${TDIR}/${FILE}.info") list(APPEND GENINFO_FILES ${OUTFILE}) add_custom_command(OUTPUT ${OUTFILE} COMMAND test -f "${TDIR}/${FILE}.gcda" && ${GCOV_ENV} ${GENINFO_BIN} --quiet --base-directory ${PROJECT_SOURCE_DIR} --gcov-tool ${GCOV_BIN} --output-filename ${OUTFILE} ${GENINFO_EXTERN_FLAG} ${TDIR}/${FILE}.gcda || cp ${OUTFILE}.init ${OUTFILE} DEPENDS ${TNAME} ${TNAME}-capture-init COMMENT "Capturing coverage data for ${FILE}" ) endforeach() # Concatenate all files generated by geninfo to a single file per target. set(OUTFILE "${LCOV_DATA_PATH_CAPTURE}/${TNAME}.info") lcov_merge_files("${OUTFILE}" ${GENINFO_FILES}) add_custom_target(${TNAME}-geninfo DEPENDS ${OUTFILE}) # add geninfo file generation to global lcov-capture target add_dependencies(lcov-capture ${TNAME}-geninfo) set(LCOV_CAPTURE_FILES "${LCOV_CAPTURE_FILES}" "${OUTFILE}" CACHE INTERNAL "" ) # Add target for generating html output for this target only. file(MAKE_DIRECTORY ${LCOV_HTML_PATH}/${TNAME}) add_custom_target(${TNAME}-genhtml COMMAND ${GENHTML_BIN} --quiet --sort --prefix ${PROJECT_SOURCE_DIR} --baseline-file ${LCOV_DATA_PATH_INIT}/${TNAME}.info --output-directory ${LCOV_HTML_PATH}/${TNAME} --title "${CMAKE_PROJECT_NAME} - target ${TNAME}" ${GENHTML_CPPFILT_FLAG} ${OUTFILE} DEPENDS ${TNAME}-geninfo ${TNAME}-capture-init ) endfunction (lcov_capture_tgt) # This function will generate the global info file for all targets. It has to be # called after all other CMake functions in the root CMakeLists.txt file, to get # a full list of all targets that generate coverage data. function (lcov_capture) # Skip this function (and do not create the following targets), if there are # no input files. if ("${LCOV_CAPTURE_FILES}" STREQUAL "") return() endif () # Add a new target to merge the files of all targets. set(OUTFILE "${LCOV_DATA_PATH_CAPTURE}/all_targets.info") lcov_merge_files("${OUTFILE}" ${LCOV_CAPTURE_FILES}) add_custom_target(lcov-geninfo DEPENDS ${OUTFILE} lcov-capture) # Add a new global target for all lcov targets. This target could be used to # generate the lcov html output for the whole project instead of calling # -geninfo and -genhtml for each target. It will also be # used to generate a html site for all project data together instead of one # for each target. if (NOT TARGET lcov) file(MAKE_DIRECTORY ${LCOV_HTML_PATH}/all_targets) add_custom_target(lcov COMMAND ${GENHTML_BIN} --quiet --sort --baseline-file ${LCOV_DATA_PATH_INIT}/all_targets.info --output-directory ${LCOV_HTML_PATH}/all_targets --title "${CMAKE_PROJECT_NAME}" --prefix "${PROJECT_SOURCE_DIR}" ${GENHTML_CPPFILT_FLAG} ${OUTFILE} DEPENDS lcov-geninfo-init lcov-geninfo ) endif () endfunction (lcov_capture) # Add a new global target to generate the lcov html report for the whole project # instead of calling -genhtml for each target (to create an own report # for each target). Instead of the lcov target it does not require geninfo for # all targets, so you have to call -geninfo to generate the info files # the targets you'd like to have in your report or lcov-geninfo for generating # info files for all targets before calling lcov-genhtml. file(MAKE_DIRECTORY ${LCOV_HTML_PATH}/selected_targets) if (NOT TARGET lcov-genhtml) add_custom_target(lcov-genhtml COMMAND ${GENHTML_BIN} --quiet --output-directory ${LCOV_HTML_PATH}/selected_targets --title \"${CMAKE_PROJECT_NAME} - targets `find ${LCOV_DATA_PATH_CAPTURE} -name \"*.info\" ! -name \"all_targets.info\" -exec basename {} .info \\\;`\" --prefix ${PROJECT_SOURCE_DIR} --sort ${GENHTML_CPPFILT_FLAG} `find ${LCOV_DATA_PATH_CAPTURE} -name \"*.info\" ! -name \"all_targets.info\"` ) endif (NOT TARGET lcov-genhtml) yubihsm-shell-2.8.0/cmake/cppcheck.cmake0000644000175100017510000000265515221003515017560 0ustar runnerrunnermacro (add_cppcheck_target _cc_target _cc_directories _cc_ignore) set(_cc_directories_var ${_cc_directories}) string (REPLACE " " " ${CMAKE_CURRENT_SOURCE_DIR}/" _cc_abs_directories ${_cc_directories_var}) set (_cc_abs_directories "${CMAKE_CURRENT_SOURCE_DIR}/${_cc_abs_directories}") separate_arguments (xxx UNIX_COMMAND "${_cc_abs_directories}") if (_cc_ignore STREQUAL "") string (REPLACE " " "${CMAKE_CURRENT_SOURCE_DIR}/" _cc_abs_ignore ${_cc_ignore}) set (_cc_abs_ignore ";${CMAKE_CURRENT_SOURCE_DIR}/${_cc_abs_ignore}") endif () set (_cc_extra_input "${ARGV3}") message ("Replaced ?${_cc_abs_directories}?") message ("Replaxxx ?${xxx}?") list (LENGTH _cc_abs_directories bla) message ("ignored ${_cc_abs_ignore} length is ${bla}") file(GLOB_RECURSE ALL_SOURCE_FILES *.c *.h) #message (${ALL_SOURCE_FILES}) # # set (_ignore_arg "--ignore ${_ignore}") #else () # set (_ignore_arg "set ${_ignore}") #endif () #list (APPEND _cpp_remove_list "") #list (APPEND _cpp_remove_list ) #set (_ggo_extra_input ${ARGV1}) add_custom_target ( ${_cc_target} COMMAND cppcheck --enable=all --template="[{severity}][{id}] {message} {callstack} \(On {file}:{line}\)" --suppress="unusedStructMember" -i="${_cc_abs_ignore}" --verbose --quiet ${_cc_extra_input} #"${_cc_abs_directories}" ${CMAKE_SOURCE_DIR} #"${xxx}" #VERBATIM ) endmacro(add_cppcheck_target) yubihsm-shell-2.8.0/cmake/Findcodecov.cmake0000644000175100017510000002034315221003515020215 0ustar runnerrunner# This file is part of CMake-codecov. # # Copyright (c) # 2015-2017 RWTH Aachen University, Federal Republic of Germany # # See the LICENSE file in the package base directory for details # # Written by Alexander Haase, alexander.haase@rwth-aachen.de # # Add an option to choose, if coverage should be enabled or not. If enabled # marked targets will be build with coverage support and appropriate targets # will be added. If disabled coverage will be ignored for *ALL* targets. option(ENABLE_COVERAGE "Enable coverage build." OFF) set(COVERAGE_FLAG_CANDIDATES # gcc and clang "-O0 -g -fprofile-arcs -ftest-coverage" # gcc and clang fallback "-O0 -g --coverage" ) # Add coverage support for target ${TNAME} and register target for coverage # evaluation. If coverage is disabled or not supported, this function will # simply do nothing. # # Note: This function is only a wrapper to define this function always, even if # coverage is not supported by the compiler or disabled. This function must # be defined here, because the module will be exited, if there is no coverage # support by the compiler or it is disabled by the user. function (add_coverage TNAME) # only add coverage for target, if coverage is support and enabled. if (ENABLE_COVERAGE) foreach (TNAME ${ARGV}) add_coverage_target(${TNAME}) endforeach () endif () endfunction (add_coverage) # Add global target to gather coverage information after all targets have been # added. Other evaluation functions could be added here, after checks for the # specific module have been passed. # # Note: This function is only a wrapper to define this function always, even if # coverage is not supported by the compiler or disabled. This function must # be defined here, because the module will be exited, if there is no coverage # support by the compiler or it is disabled by the user. function (coverage_evaluate) # add lcov evaluation if (LCOV_FOUND) lcov_capture_initial() lcov_capture() endif (LCOV_FOUND) endfunction () # Exit this module, if coverage is disabled. add_coverage is defined before this # return, so this module can be exited now safely without breaking any build- # scripts. if (NOT ENABLE_COVERAGE) return() endif () # Find the reuired flags foreach language. set(CMAKE_REQUIRED_QUIET_SAVE ${CMAKE_REQUIRED_QUIET}) set(CMAKE_REQUIRED_QUIET ${codecov_FIND_QUIETLY}) get_property(ENABLED_LANGUAGES GLOBAL PROPERTY ENABLED_LANGUAGES) foreach (LANG ${ENABLED_LANGUAGES}) # Coverage flags are not dependend on language, but the used compiler. So # instead of searching flags foreach language, search flags foreach compiler # used. set(COMPILER ${CMAKE_${LANG}_COMPILER_ID}) if (NOT COVERAGE_${COMPILER}_FLAGS) foreach (FLAG ${COVERAGE_FLAG_CANDIDATES}) if(NOT CMAKE_REQUIRED_QUIET) message(STATUS "Try ${COMPILER} code coverage flag = [${FLAG}]") endif() set(CMAKE_REQUIRED_FLAGS "${FLAG}") unset(COVERAGE_FLAG_DETECTED CACHE) if (${LANG} STREQUAL "C") include(CheckCCompilerFlag) check_c_compiler_flag("${FLAG}" COVERAGE_FLAG_DETECTED) elseif (${LANG} STREQUAL "CXX") include(CheckCXXCompilerFlag) check_cxx_compiler_flag("${FLAG}" COVERAGE_FLAG_DETECTED) elseif (${LANG} STREQUAL "Fortran") # CheckFortranCompilerFlag was introduced in CMake 3.x. To be # compatible with older Cmake versions, we will check if this # module is present before we use it. Otherwise we will define # Fortran coverage support as not available. include(CheckFortranCompilerFlag OPTIONAL RESULT_VARIABLE INCLUDED) if (INCLUDED) check_fortran_compiler_flag("${FLAG}" COVERAGE_FLAG_DETECTED) elseif (NOT CMAKE_REQUIRED_QUIET) message("-- Performing Test COVERAGE_FLAG_DETECTED") message("-- Performing Test COVERAGE_FLAG_DETECTED - Failed" " (Check not supported)") endif () endif() if (COVERAGE_FLAG_DETECTED) set(COVERAGE_${COMPILER}_FLAGS "${FLAG}" CACHE STRING "${COMPILER} flags for code coverage.") mark_as_advanced(COVERAGE_${COMPILER}_FLAGS) break() else () message(WARNING "Code coverage is not available for ${COMPILER}" " compiler. Targets using this compiler will be " "compiled without it.") endif () endforeach () endif () endforeach () set(CMAKE_REQUIRED_QUIET ${CMAKE_REQUIRED_QUIET_SAVE}) # Helper function to get the language of a source file. function (codecov_lang_of_source FILE RETURN_VAR) get_filename_component(FILE_EXT "${FILE}" EXT) string(TOLOWER "${FILE_EXT}" FILE_EXT) string(SUBSTRING "${FILE_EXT}" 1 -1 FILE_EXT) get_property(ENABLED_LANGUAGES GLOBAL PROPERTY ENABLED_LANGUAGES) foreach (LANG ${ENABLED_LANGUAGES}) list(FIND CMAKE_${LANG}_SOURCE_FILE_EXTENSIONS "${FILE_EXT}" TEMP) if (NOT ${TEMP} EQUAL -1) set(${RETURN_VAR} "${LANG}" PARENT_SCOPE) return() endif () endforeach() set(${RETURN_VAR} "" PARENT_SCOPE) endfunction () # Helper function to get the relative path of the source file destination path. # This path is needed by FindGcov and FindLcov cmake files to locate the # captured data. function (codecov_path_of_source FILE RETURN_VAR) string(REGEX MATCH "TARGET_OBJECTS:([^ >]+)" _source ${FILE}) # If expression was found, SOURCEFILE is a generator-expression for an # object library. Currently we found no way to call this function automatic # for the referenced target, so it must be called in the directoryso of the # object library definition. if (NOT "${_source}" STREQUAL "") set(${RETURN_VAR} "" PARENT_SCOPE) return() endif () string(REPLACE "${CMAKE_CURRENT_BINARY_DIR}/" "" FILE "${FILE}") if(IS_ABSOLUTE ${FILE}) file(RELATIVE_PATH FILE ${CMAKE_CURRENT_SOURCE_DIR} ${FILE}) endif() # get the right path for file string(REPLACE ".." "__" PATH "${FILE}") set(${RETURN_VAR} "${PATH}" PARENT_SCOPE) endfunction() # Add coverage support for target ${TNAME} and register target for coverage # evaluation. function(add_coverage_target TNAME) # Check if all sources for target use the same compiler. If a target uses # e.g. C and Fortran mixed and uses different compilers (e.g. clang and # gfortran) this can trigger huge problems, because different compilers may # use different implementations for code coverage. get_target_property(TSOURCES ${TNAME} SOURCES) set(TARGET_COMPILER "") set(ADDITIONAL_FILES "") foreach (FILE ${TSOURCES}) # If expression was found, FILE is a generator-expression for an object # library. Object libraries will be ignored. string(REGEX MATCH "TARGET_OBJECTS:([^ >]+)" _file ${FILE}) if ("${_file}" STREQUAL "") codecov_lang_of_source(${FILE} LANG) if (LANG) list(APPEND TARGET_COMPILER ${CMAKE_${LANG}_COMPILER_ID}) list(APPEND ADDITIONAL_FILES "${FILE}.gcno") list(APPEND ADDITIONAL_FILES "${FILE}.gcda") endif () endif () endforeach () list(REMOVE_DUPLICATES TARGET_COMPILER) list(LENGTH TARGET_COMPILER NUM_COMPILERS) if (NUM_COMPILERS GREATER 1) message(WARNING "Can't use code coverage for target ${TNAME}, because " "it will be compiled by incompatible compilers. Target will be " "compiled without code coverage.") return() elseif (NUM_COMPILERS EQUAL 0) message(WARNING "Can't use code coverage for target ${TNAME}, because " "it uses an unknown compiler. Target will be compiled without " "code coverage.") return() elseif (NOT DEFINED "COVERAGE_${TARGET_COMPILER}_FLAGS") # A warning has been printed before, so just return if flags for this # compiler aren't available. return() endif() # enable coverage for target set_property(TARGET ${TNAME} APPEND_STRING PROPERTY COMPILE_FLAGS " ${COVERAGE_${TARGET_COMPILER}_FLAGS}") set_property(TARGET ${TNAME} APPEND_STRING PROPERTY LINK_FLAGS " ${COVERAGE_${TARGET_COMPILER}_FLAGS}") # Add gcov files generated by compiler to clean target. set(CLEAN_FILES "") foreach (FILE ${ADDITIONAL_FILES}) codecov_path_of_source(${FILE} FILE) list(APPEND CLEAN_FILES "CMakeFiles/${TNAME}.dir/${FILE}") endforeach() set_directory_properties(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES "${CLEAN_FILES}") add_gcov_target(${TNAME}) add_lcov_target(${TNAME}) endfunction(add_coverage_target) # Include modules for parsing the collected data and output it in a readable # format (like gcov and lcov). find_package(Gcov) find_package(Lcov) yubihsm-shell-2.8.0/cmake/SecurityFlags.cmake0000644000175100017510000000447015221003515020561 0ustar runnerrunnerinclude(CheckCCompilerFlag) if (CMAKE_C_COMPILER_ID STREQUAL "Clang" OR CMAKE_C_COMPILER_ID STREQUAL "AppleClang" OR CMAKE_C_COMPILER_ID STREQUAL "GNU") add_compile_options (-Wformat -Wformat-nonliteral -Wformat-security) add_compile_options (-Wshadow) #add_compile_options (-Wcast-qual) add_compile_options (-Wmissing-prototypes) add_compile_options (-Wbad-function-cast) add_compile_options (-pedantic -pedantic-errors) add_compile_options (-fpie -fpic) if (NOT FUZZING) add_compile_options (-Wall -Wextra -Werror) add_compile_options(-O2) add_definitions (-D_FORTIFY_SOURCE=2) endif () check_c_compiler_flag("-fstack-protector-all" HAVE_STACK_PROTECTOR_ALL) if (HAVE_STACK_PROTECTOR_ALL) message(STATUS "-fstack-protector-all support detected") add_compile_options(-fstack-protector-all) set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -fstack-protector-all") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fstack-protector-all") else () check_c_compiler_flag("-fstack-protector" HAVE_STACK_PROTECTOR) if(HAVE_STACK_PROTECTOR) message(STATUS "-fstack-protector support detected") add_compile_options(-fstack-protector) set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -fstack-protector") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fstack-protector") else () message(WARNING "No stack protection supported.") endif () endif () check_c_compiler_flag("-Wno-implicit-fallthrough" HAVE_NO_IMPLICIT_FALLTHROUGH) if (HAVE_NO_IMPLICIT_FALLTHROUGH) add_compile_options (-Wno-implicit-fallthrough) endif () if (NOT APPLE) set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -pie") set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,-z,noexecstack -Wl,-z,relro,-z,now") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-z,noexecstack -Wl,-z,relro,-z,now") endif() elseif (CMAKE_C_COMPILER_ID STREQUAL "MSVC") add_compile_options (/GS) add_compile_options (/Gs) add_link_options (/NXCOMPAT) add_link_options (/guard:cf) else () message(WARNING "Security related flags cannot be set for unknown C compiler.") endif () yubihsm-shell-2.8.0/cmake/openssl.cmake0000644000175100017510000000065315221003515017457 0ustar runnerrunnermacro (find_libcrypto) if(NOT LIBCRYPTO_LDFLAGS) if(WIN32) find_package(OpenSSL REQUIRED) set(LIBCRYPTO_LDFLAGS "OpenSSL::Crypto") set(LIBCRYPTO_VERSION ${OPENSSL_VERSION}) set(LIBCRYPTO_INCLUDEDIR ${OPENSSL_INCLUDE_DIR}) else(WIN32) pkg_search_module (LIBCRYPTO REQUIRED libcrypto) endif(WIN32) endif(NOT LIBCRYPTO_LDFLAGS) endmacro()yubihsm-shell-2.8.0/cmake/mingw64.cmake0000644000175100017510000000120315221003515017257 0ustar runnerrunner# the name of the target operating system SET(CMAKE_SYSTEM_NAME Windows) # which compilers to use for C and C++ SET(CMAKE_C_COMPILER x86_64-w64-mingw32-gcc) SET(CMAKE_CXX_COMPILER x86_64-w64-mingw32-g++) SET(CMAKE_RC_COMPILER x86_64-w64-mingw32-windres) # here is the target environment located SET(CMAKE_FIND_ROOT_PATH /usr/x86_64-w64-mingw32 ) # adjust the default behaviour of the FIND_XXX() commands: # search headers and libraries in the target environment, search # programs in the host environment set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) yubihsm-shell-2.8.0/.gitmodules0000644000175100017510000000051315221003515016062 0ustar runnerrunner[submodule "resources/tests/bash/test_helper/bats-support"] path = resources/tests/bash/test_helper/bats-support url = https://github.com/bats-core/bats-support.git [submodule "resources/tests/bash/test_helper/bats-assert"] path = resources/tests/bash/test_helper/bats-assert url = https://github.com/bats-core/bats-assert.git yubihsm-shell-2.8.0/src/0000755000175100017510000000000015221003575014503 5ustar runnerrunneryubihsm-shell-2.8.0/src/commands.c0000644000175100017510000036151515221003515016455 0ustar runnerrunner/* * Copyright 2015-2018 Yubico AB * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include "commands.h" #include "yubihsm-shell.h" #include "../common/insecure_memzero.h" #include "../common/parsing.h" #include "time_win.h" #include "hash.h" #include "util.h" #include "cmd_util.h" #include "openssl-compat.h" #ifdef __WIN32 #include #include #else #include #include #include #include #endif #include #include #include #include #include #include static format_t fmt_to_fmt(cmd_format fmt) { switch (fmt) { case fmt_base64: return _base64; case fmt_binary: return _binary; case fmt_hex: return _hex; case fmt_PEM: return _PEM; default: return 0; } } static bool is_compressed(yh_session *session, uint16_t id, yh_algorithm algorithm) { if (algorithm == YH_ALGO_OPAQUE_X509_CERTIFICATE) { uint8_t out[16384] = {0}; size_t out_len = sizeof(out); size_t stored_len = 0; yh_rc yrc = yh_util_get_opaque_ex(session, id, out, &out_len, &stored_len, true); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to get opaque data. Object compression status might " "not be accurate: %s\n", yh_strerror(yrc)); return false; } #ifdef ENABLE_CERT_COMPRESS if (out_len != stored_len) { return true; } #else if (out_len > 2 && out[0] == 0x1f && out[1] == 0x8b) { return true; } #endif } return false; } // NOTE(adma): Extract log entries // argc = 1 // arg 0: e:session int yh_com_audit(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(ctx); UNUSED(in_fmt); UNUSED(fmt); uint16_t unlogged_boot = 0; uint16_t unlogged_auth = 0; yh_log_entry logs[YH_MAX_LOG_ENTRIES] = {0}; size_t n_items = sizeof(logs) / sizeof(logs[0]); switch (fmt) { case fmt_binary: case fmt_PEM: case fmt_base64: case fmt_password: fprintf(stderr, "The selected output format is not supported for this operation. " "Supported format are \"ASCII\", \"hex\" and \"default\"\n"); return -1; default: break; } yh_rc yrc = yh_util_get_log_entries(argv[0].e, &unlogged_boot, &unlogged_auth, logs, &n_items); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to get logs: %s\n", yh_strerror(yrc)); return -1; } char digest_buf[(2 * YH_LOG_DIGEST_SIZE) + 1] = {0}; switch (fmt) { case fmt_hex: fprintf(ctx->out, "%04x%04x", unlogged_boot, unlogged_auth); for (size_t i = 0; i < n_items; i++) { format_digest(logs[i].digest, digest_buf, YH_LOG_DIGEST_SIZE); fprintf(ctx->out, "%04x%02x%04x%04x%04x%04x%02x%08lx%s", logs[i].number, logs[i].command, logs[i].length, logs[i].session_key, logs[i].target_key, logs[i].second_key, logs[i].result, (unsigned long) logs[i].systick, digest_buf); } fprintf(ctx->out, "\n"); break; case fmt_ASCII: default: fprintf(ctx->out, "%d unlogged boots found\n", unlogged_boot); fprintf(ctx->out, "%d unlogged authentications found\n", unlogged_auth); if (n_items == 0) { fprintf(ctx->out, "No logs to extract\n"); return 0; } else if (n_items == 1) { fprintf(ctx->out, "Found 1 item\n"); } else { fprintf(ctx->out, "Found %zu items\n", n_items); } for (size_t i = 0; i < n_items; i++) { format_digest(logs[i].digest, digest_buf, YH_LOG_DIGEST_SIZE); fprintf(ctx->out, "item: %5u -- cmd: 0x%02x -- length: %4u -- session key: " "0x%04x -- target key: 0x%04x -- second key: 0x%04x -- " "result: 0x%02x -- tick: %lu -- hash: %s\n", logs[i].number, logs[i].command, logs[i].length, logs[i].session_key, logs[i].target_key, logs[i].second_key, logs[i].result, (unsigned long) logs[i].systick, digest_buf); } break; } return 0; } // NOTE: Set the log index // argc = 2 // arg 0: e:session // arg 1: w:index int yh_com_set_log_index(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(ctx); UNUSED(in_fmt); UNUSED(fmt); yh_rc yrc = yh_util_set_log_index(argv[0].e, argv[1].w); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to set log index: %s\n", yh_strerror(yrc)); return -1; } return 0; } // NOTE: Blink the device // argc = 2 // arg 0: e:session // arg 1: b:seconds int yh_com_blink(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(in_fmt); UNUSED(fmt); UNUSED(ctx); yh_rc yrc = yh_util_blink_device(argv[0].e, argv[1].b); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to blink the device: %s\n", yh_strerror(yrc)); return -1; } return 0; } // NOTE(adma): Close a session with a connector // argc = 1 // arg 0: e:session int yh_com_close_session(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(in_fmt); UNUSED(fmt); uint8_t session_id = 0; yh_rc yrc = yh_get_session_id(argv[0].e, &session_id); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to get session id: %s\n", yh_strerror(yrc)); return -1; } yrc = yh_util_close_session(argv[0].e); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to close session: %s\n", yh_strerror(yrc)); return -1; } yrc = yh_destroy_session(&argv[0].e); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to destroy session: %s\n", yh_strerror(yrc)); return -1; } ctx->sessions[session_id] = NULL; return 0; } // NOTE(adma): Connect to a connector // argc = 0 int yh_com_connect(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(argv); UNUSED(in_fmt); UNUSED(fmt); ctx->connector = NULL; for (int i = 0; ctx->connector_list[i]; i++) { if (ctx->connector) { yh_disconnect(ctx->connector); ctx->connector = NULL; } yh_rc yrc = yh_init_connector(ctx->connector_list[i], &ctx->connector); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed initializing connector %s: %s\n", ctx->connector_list[i], yh_strerror(yrc)); break; } if (ctx->cacert) { if (yh_set_connector_option(ctx->connector, YH_CONNECTOR_HTTPS_CA, ctx->cacert) != YHR_SUCCESS) { fprintf(stderr, "Failed setting HTTPS CA\n"); break; } } if (ctx->cert) { if (yh_set_connector_option(ctx->connector, YH_CONNECTOR_HTTPS_CERT, ctx->cert) != YHR_SUCCESS) { fprintf(stderr, "Failed setting HTTPS cert\n"); break; } } if (ctx->key) { if (yh_set_connector_option(ctx->connector, YH_CONNECTOR_HTTPS_KEY, ctx->key) != YHR_SUCCESS) { fprintf(stderr, "Failed setting HTTPS key\n"); break; } } if (ctx->proxy) { if (yh_set_connector_option(ctx->connector, YH_CONNECTOR_PROXY_SERVER, ctx->proxy) != YHR_SUCCESS) { fprintf(stderr, "Failed setting proxy server\n"); break; } } if (ctx->noproxy) { if (yh_set_connector_option(ctx->connector, YH_CONNECTOR_NOPROXY, ctx->noproxy) != YHR_SUCCESS) { fprintf(stderr, "Failed setting noproxy\n"); break; } } yrc = yh_connect(ctx->connector, 0); if (yrc == YHR_SUCCESS) { yh_com_keepalive_on(NULL, NULL, fmt_nofmt, fmt_nofmt); return 0; } fprintf(stderr, "Failed connecting '%s': %s\n", ctx->connector_list[i], yh_strerror(yrc)); } if (ctx->connector) { yh_disconnect(ctx->connector); ctx->connector = NULL; } return -1; } // NOTE(adma): Enable all debug messages // argc = 0 int yh_com_debug_all(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(ctx); UNUSED(argv); UNUSED(in_fmt); UNUSED(fmt); yh_set_verbosity(ctx->connector, YH_VERB_ALL); fprintf(stderr, "Debug messages enabled\n"); return 0; } // NOTE(adma): Toggle debug messages // argc = 0 int yh_com_debug_error(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(ctx); UNUSED(argv); UNUSED(in_fmt); UNUSED(fmt); uint8_t yh_verbosity = 0; yh_get_verbosity(&yh_verbosity); yh_verbosity ^= YH_VERB_ERR; if (yh_verbosity & YH_VERB_ERR) fprintf(stderr, "Error messages on\n"); else fprintf(stderr, "Error messages off\n"); yh_set_verbosity(ctx->connector, yh_verbosity); return 0; } // NOTE(adma): Toggle debug messages // argc = 0 int yh_com_debug_info(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(ctx); UNUSED(argv); UNUSED(in_fmt); UNUSED(fmt); uint8_t yh_verbosity = 0; yh_get_verbosity(&yh_verbosity); yh_verbosity ^= YH_VERB_INFO; if (yh_verbosity & YH_VERB_INFO) fprintf(stderr, "Info messages on\n"); else fprintf(stderr, "Info messages off\n"); yh_set_verbosity(ctx->connector, yh_verbosity); return 0; } // NOTE(adma): Toggle debug messages // argc = 0 int yh_com_debug_intermediate(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(ctx); UNUSED(argv); UNUSED(in_fmt); UNUSED(fmt); uint8_t yh_verbosity = 0; yh_get_verbosity(&yh_verbosity); yh_verbosity ^= YH_VERB_INTERMEDIATE; if (yh_verbosity & YH_VERB_INTERMEDIATE) fprintf(stderr, "Intermediate messages on\n"); else fprintf(stderr, "Intermediate messages off\n"); yh_set_verbosity(ctx->connector, yh_verbosity); return 0; } // NOTE(adma): Toggle debug messages // argc = 0 int yh_com_debug_none(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(ctx); UNUSED(argv); UNUSED(in_fmt); UNUSED(fmt); yh_set_verbosity(ctx->connector, YH_VERB_QUIET); fprintf(stderr, "Debug messages disabled\n"); return 0; } // NOTE(adma): Toggle debug messages // argc = 0 int yh_com_debug_raw(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(ctx); UNUSED(argv); UNUSED(in_fmt); UNUSED(fmt); uint8_t yh_verbosity = 0; yh_get_verbosity(&yh_verbosity); yh_verbosity ^= YH_VERB_RAW; if (yh_verbosity & YH_VERB_RAW) fprintf(stderr, "Raw messages on\n"); else fprintf(stderr, "Raw messages off\n"); yh_set_verbosity(ctx->connector, yh_verbosity); return 0; } // NOTE(adma): Toggle debug messages // argc = 0 int yh_com_debug_crypto(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(ctx); UNUSED(argv); UNUSED(in_fmt); UNUSED(fmt); uint8_t yh_verbosity = 0; yh_get_verbosity(&yh_verbosity); yh_verbosity ^= YH_VERB_CRYPTO; if (yh_verbosity & YH_VERB_CRYPTO) fprintf(stderr, "Crypto messages on\n"); else fprintf(stderr, "Crypto messages off\n"); yh_set_verbosity(ctx->connector, yh_verbosity); return 0; } // NOTE(adma): Decrypt data // argc = 3 // arg 0: e:session // arg 1: w:key_id // arg 2: i:data int yh_com_decrypt_pkcs1v1_5(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(in_fmt); UNUSED(ctx); uint8_t response[YH_MSG_BUF_SIZE] = {0}; size_t response_len = sizeof(response); yh_rc yrc = yh_util_decrypt_pkcs1v1_5(argv[0].e, argv[1].w, argv[2].x, argv[2].len, response, &response_len); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to decrypt data: %s\n", yh_strerror(yrc)); return -1; } write_file(response, response_len, ctx->out, fmt_to_fmt(fmt)); return 0; } // NOTE: Do a ECDH key exchange // argc = 3 // arg 0: e:session // arg 1: w:key_id // arg 2: i:pubkey int yh_com_derive_ecdh(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(in_fmt); UNUSED(ctx); yh_algorithm algo = 0; uint8_t data[YH_MSG_BUF_SIZE] = {0}; size_t data_len = sizeof(data); if (!read_public_key(argv[2].x, argv[2].len, &algo, data, &data_len)) { fprintf(stderr, "Failed to load public key\n"); return -1; } uint8_t response[YH_MSG_BUF_SIZE] = {0}; size_t response_len = sizeof(response); yh_rc yrc = yh_util_derive_ecdh(argv[0].e, argv[1].w, data, data_len, response, &response_len); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to do key exchange: %s\n", yh_strerror(yrc)); return -1; } write_file(response, response_len, ctx->out, fmt_to_fmt(fmt)); return 0; } // NOTE: Decrypt data // argc = 3 // arg 0: e:session // arg 1: w:key_id // arg 2: i:data int yh_com_decrypt_aesccm(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(in_fmt); UNUSED(ctx); uint8_t response[YH_MSG_BUF_SIZE] = {0}; size_t response_len = sizeof(response); yh_rc yrc = yh_util_unwrap_data(argv[0].e, argv[1].w, argv[2].x, argv[2].len, response, &response_len); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to decrypt data: %s\n", yh_strerror(yrc)); return -1; } write_file(response, response_len, ctx->out, fmt_to_fmt(fmt)); return 0; } // NOTE: Encrypt data // argc = 3 // arg 0: e:session // arg 1: w:key_id // arg 2: i:data int yh_com_encrypt_aesccm(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(in_fmt); UNUSED(ctx); uint8_t response[YH_MSG_BUF_SIZE] = {0}; size_t response_len = sizeof(response); yh_rc yrc = yh_util_wrap_data(argv[0].e, argv[1].w, argv[2].x, argv[2].len, response, &response_len); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to encrypt data: %s\n", yh_strerror(yrc)); return -1; } write_file(response, response_len, ctx->out, fmt_to_fmt(fmt)); return 0; } // NOTE: Decrypt data // argc = 3 // arg 0: e:session // arg 1: w:key_id // arg 2: i:data int yh_com_decrypt_aes_ecb(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(in_fmt); UNUSED(ctx); yh_rc yrc = yh_util_decrypt_aes_ecb(argv[0].e, argv[1].w, argv[2].x, argv[2].len, argv[2].x, &argv[2].len); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to decrypt data: %s\n", yh_strerror(yrc)); return -1; } write_file(argv[2].x, argv[2].len, ctx->out, fmt_to_fmt(fmt)); return 0; } // NOTE: Encrypt data // argc = 3 // arg 0: e:session // arg 1: w:key_id // arg 2: s:iv // arg 3: i:data int yh_com_encrypt_aes_cbc(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(in_fmt); UNUSED(ctx); uint8_t iv[16] = {0}; size_t iv_len = sizeof(iv); if (hex_decode(argv[2].s, iv, &iv_len) == false) { fprintf(stderr, "Failed to decode IV\n"); return -1; } yh_rc yrc = yh_util_encrypt_aes_cbc(argv[0].e, argv[1].w, iv, argv[3].x, argv[3].len, argv[3].x, &argv[3].len); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to encrypt data: %s\n", yh_strerror(yrc)); return -1; } write_file(argv[3].x, argv[3].len, ctx->out, fmt_to_fmt(fmt)); return 0; } // NOTE: Decrypt data // argc = 3 // arg 0: e:session // arg 1: w:key_id // arg 2: s:iv // arg 3: i:data int yh_com_decrypt_aes_cbc(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(in_fmt); UNUSED(ctx); uint8_t iv[16] = {0}; size_t iv_len = sizeof(iv); if (hex_decode(argv[2].s, iv, &iv_len) == false) { fprintf(stderr, "Failed to decode IV\n"); return -1; } yh_rc yrc = yh_util_decrypt_aes_cbc(argv[0].e, argv[1].w, iv, argv[3].x, argv[3].len, argv[3].x, &argv[3].len); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to decrypt data: %s\n", yh_strerror(yrc)); return -1; } write_file(argv[3].x, argv[3].len, ctx->out, fmt_to_fmt(fmt)); return 0; } // NOTE: Encrypt data // argc = 3 // arg 0: e:session // arg 1: w:key_id // arg 2: i:data int yh_com_encrypt_aes_ecb(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(in_fmt); UNUSED(ctx); yh_rc yrc = yh_util_encrypt_aes_ecb(argv[0].e, argv[1].w, argv[2].x, argv[2].len, argv[2].x, &argv[2].len); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to encrypt data: %s\n", yh_strerror(yrc)); return -1; } write_file(argv[2].x, argv[2].len, ctx->out, fmt_to_fmt(fmt)); return 0; } // NOTE(adma): Disconnect from a connector // argc = 0 int yh_com_disconnect(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(argv); UNUSED(in_fmt); UNUSED(fmt); yh_rc yrc = YHR_SUCCESS; for (size_t i = 0; i < sizeof(ctx->sessions) / sizeof(ctx->sessions[0]); i++) { if (ctx->sessions[i]) { yrc = yh_util_close_session(ctx->sessions[i]); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to close session: %s\n", yh_strerror(yrc)); } yrc = yh_destroy_session(&ctx->sessions[i]); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to destroy session: %s\n", yh_strerror(yrc)); } ctx->sessions[i] = NULL; } } if (ctx->connector) { yrc = yh_disconnect(ctx->connector); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Unable to disconnect: %s\n", yh_strerror(yrc)); return -1; } ctx->connector = NULL; } return 0; } // NOTE(adma): Send authenticated echo // argc = 3 // arg 0: e:session // arg 1: b:byte // arg 2: w:count int yh_com_echo(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(ctx); UNUSED(in_fmt); UNUSED(fmt); uint8_t data[YH_MSG_BUF_SIZE] = {0}; size_t data_len = 0; uint8_t response[YH_MSG_BUF_SIZE] = {0}; size_t response_len = 0; yh_cmd response_cmd = 0; uint8_t byte = argv[1].b; uint16_t count = argv[2].w; if (count > YH_MSG_BUF_SIZE) { fprintf(stderr, "Count must be in [0, %d]\n", YH_MSG_BUF_SIZE); return -1; } memset(data, byte, count); data_len = count; response_len = sizeof(response); yh_rc yrc = yh_send_secure_msg(argv[0].e, YHC_ECHO, data, data_len, &response_cmd, response, &response_len); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to send ECHO command: %s\n", yh_strerror(yrc)); return -1; } fprintf(ctx->out, "Response (%zu bytes):\n", response_len); for (size_t i = 0; i < response_len; i++) { if (i && !(i % 64)) fprintf(ctx->out, "\n"); else if (i && !(i % 8)) fprintf(ctx->out, " "); fprintf(ctx->out, "%02x", response[i]); } fprintf(ctx->out, "\n"); return 0; } // Generate a Symmetric Key // argc = 6 // arg 0: e:session // arg 1: w:key_id // arg 2: s:label // arg 3: w:domains // arg 4: c:capabilities // arg 5: a:algorithm int yh_com_generate_symmetric(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(ctx); UNUSED(in_fmt); UNUSED(fmt); yh_rc yrc; if (yh_is_aes(argv[5].a)) { yrc = yh_util_generate_aes_key(argv[0].e, &argv[1].w, argv[2].s, argv[3].w, &argv[4].c, argv[5].a); } else { fprintf(stderr, "Invalid algorithm %d\n", argv[5].a); return -1; } if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to generate symmetric key: %s\n", yh_strerror(yrc)); return -1; } fprintf(stderr, "Generated symmetric key 0x%04x\n", argv[1].w); return 0; } // NOTE(adma): Generate an Asymmetric Key // argc = 6 // arg 0: e:session // arg 1: w:key_id // arg 2: s:label // arg 3: w:domains // arg 4: c:capabilities // arg 5: a:algorithm int yh_com_generate_asymmetric(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(ctx); UNUSED(in_fmt); UNUSED(fmt); yh_rc yrc = YHR_SUCCESS; if (yh_is_rsa(argv[5].a)) { yrc = yh_util_generate_rsa_key(argv[0].e, &argv[1].w, argv[2].s, argv[3].w, &argv[4].c, argv[5].a); } else if (yh_is_ec(argv[5].a)) { yrc = yh_util_generate_ec_key(argv[0].e, &argv[1].w, argv[2].s, argv[3].w, &argv[4].c, argv[5].a); } else if (yh_is_ed(argv[5].a)) { yrc = yh_util_generate_ed_key(argv[0].e, &argv[1].w, argv[2].s, argv[3].w, &argv[4].c, argv[5].a); } else { fprintf(stderr, "Invalid algorithm %d\n", argv[5].a); return -1; } if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to generate asymmetric key: %s\n", yh_strerror(yrc)); return -1; } fprintf(stderr, "Generated Asymmetric key 0x%04x\n", argv[1].w); return 0; } // NOTE: Generate HMAC key // argc = 6 // arg 0: e:session // arg 1: w:key_id // arg 2: s:label // arg 3: w:domains // arg 4: c:capabilities // arg 5: a:algorithm int yh_com_generate_hmac(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(ctx); UNUSED(in_fmt); UNUSED(fmt); if (!yh_is_hmac(argv[5].a)) { fprintf(stderr, "Invalid algorithm: %d\n", argv[5].a); return -1; } yh_rc yrc = yh_util_generate_hmac_key(argv[0].e, &argv[1].w, argv[2].s, argv[3].w, &argv[4].c, argv[5].a); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to generate HMAC key: %s\n", yh_strerror(yrc)); return -1; } fprintf(stderr, "Generated HMAC key 0x%04x\n", argv[1].w); return 0; } // NOTE: Generate wrap key // argc = 6 // arg 0: e:session // arg 1: w:key_id // arg 2: s:label // arg 3: w:domains // arg 4: c:capabilities // arg 5: c:delegated_capabilities // arg 6: a:algorithm int yh_com_generate_wrap(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(ctx); UNUSED(in_fmt); UNUSED(fmt); yh_rc yrc = yh_util_generate_wrap_key(argv[0].e, &argv[1].w, argv[2].s, argv[3].w, &argv[4].c, argv[6].a, &argv[5].c); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to generate wrapping key: %s\n", yh_strerror(yrc)); return -1; } fprintf(stderr, "Generated Wrap key 0x%04x\n", argv[1].w); return 0; } // NOTE(adma): Get an opaque object // argc = 2 // arg 0: e:session, // arg 1: w:object_id // arg 2: F:file int yh_com_get_opaque(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(ctx); UNUSED(in_fmt); yh_object_descriptor desc = {0}; uint8_t response[16384] = {0}; size_t response_len = sizeof(response); size_t stored_len = 0; int ret = -1; yh_util_get_object_info(argv[0].e, argv[1].w, YH_OPAQUE, &desc); yh_rc yrc = yh_util_get_opaque_ex(argv[0].e, argv[1].w, response, &response_len, &stored_len, desc.algorithm == YH_ALGO_OPAQUE_X509_CERTIFICATE); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to get opaque object: %s\n", yh_strerror(yrc)); return -1; } if (stored_len != response_len) { fprintf(stderr, "Successfully read compressed data\n"); } if (fmt == fmt_PEM) { const unsigned char *ptr = response; X509 *x509 = d2i_X509(NULL, &ptr, response_len); if (!x509) { fprintf(stderr, "Failed parsing x509 information\n"); } else { if (PEM_write_X509(ctx->out, x509) == 1) { ret = 0; } else { fprintf(stderr, "Failed writing x509 information\n"); } } X509_free(x509); } else { if (write_file(response, response_len, ctx->out, fmt_to_fmt(fmt))) { ret = 0; } } return ret; } // NOTE(adma): Get a global option value // argc = 2 // arg 0: o:session // arg 1: s:option int yh_com_get_option(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(ctx); UNUSED(in_fmt); UNUSED(fmt); uint8_t response[YH_MSG_BUF_SIZE] = {0}; size_t response_len = sizeof(response); yh_rc yrc = yh_util_get_option(argv[0].e, argv[1].o, response, &response_len); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to get option: %s\n", yh_strerror(yrc)); return -1; } fprintf(ctx->out, "Option value is: "); for (size_t i = 0; i < response_len; i++) { fprintf(ctx->out, "%02x", response[i]); } fprintf(ctx->out, "\n"); return 0; } // NOTE(adma): Get pseudo-random bytes // argc = 2 // arg 0: e:session // arg 1: w:count int yh_com_get_random(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(in_fmt); uint8_t response[YH_MSG_BUF_SIZE] = {0}; size_t response_len = sizeof(response); yh_rc yrc = yh_util_get_pseudo_random(argv[0].e, argv[1].w, response, &response_len); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to get pseudo random bytes: %s\n", yh_strerror(yrc)); return -1; } if (response_len != argv[1].w) { fprintf(stderr, "Wrong response length\n"); return -1; } write_file(response, response_len, ctx->out, fmt_to_fmt(fmt)); return 0; } // NOTE(adma): Obtain storage information // argc = 1 // arg 0: e:session int yh_com_get_storage(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(ctx); UNUSED(in_fmt); UNUSED(fmt); uint16_t total_records = 0, free_records = 0, free_pages = 0, total_pages = 0, page_size = 0; yh_rc yrc = yh_util_get_storage_info(argv[0].e, &total_records, &free_records, &total_pages, &free_pages, &page_size); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to get storage stats: %s\n", yh_strerror(yrc)); return -1; } fprintf(stderr, "free records: %d/%d, free pages: %d/%d page size: %d bytes\n", free_records, total_records, free_pages, total_pages, page_size); return 0; } // NOTE: Get public key // argc = 3 // arg 0: e:session // arg 1: w:key_id // arg 2: t:key_type // arg 3: f:filename int yh_com_get_pubkey(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(in_fmt); uint8_t response[YH_MSG_BUF_SIZE] = {0}; size_t response_len = sizeof(response); yh_algorithm algo = 0; EVP_PKEY *public_key = NULL; yh_rc yrc = yh_util_get_public_key_ex(argv[0].e, argv[2].t, argv[1].w, response, &response_len, &algo); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to get public key: %s\n", yh_strerror(yrc)); return -1; } if (yh_is_rsa(algo) || (yh_is_ec(algo))) { if (!get_pubkey_evp(response, response_len, algo, &public_key)) { fprintf(stderr, "Failed to encode public key\n"); return -1; } } else { // NOTE(adma): ED25519, there is (was) no support for this in // OpenSSL, so we manually export them EVP_PKEY_free(public_key); if (write_ed25519_key(response, response_len, ctx->out, fmt_to_fmt(fmt)) == false) { fprintf(stderr, "Unable to format ed25519 key\n"); return -1; } return 0; } if (fmt == fmt_PEM) { if (PEM_write_PUBKEY(ctx->out, public_key) != 1) { fprintf(stderr, "Failed to write public key in PEM format\n"); EVP_PKEY_free(public_key); return -1; } } else if (fmt == fmt_binary) { i2d_PUBKEY_fp(ctx->out, public_key); } else if (fmt == fmt_base64) { bool error = false; BIO *b64 = BIO_new(BIO_f_base64()); if (b64 == NULL) { fprintf(stderr, "Unable to allocate buffer\n"); error = true; goto getpk_base64_cleanup; } BIO *bio = BIO_new_fp(ctx->out, BIO_NOCLOSE); if (bio == NULL) { fprintf(stderr, "Unable to allocate BIO\n"); error = true; goto getpk_base64_cleanup; } bio = BIO_push(b64, bio); i2d_PUBKEY_bio(bio, public_key); if (BIO_flush(bio) != 1) { fprintf(stderr, "Unable to flush BIO\n"); error = true; goto getpk_base64_cleanup; } getpk_base64_cleanup: BIO_free_all(b64); if (error) { EVP_PKEY_free(public_key); return -1; } } // FIXME: other formats or error. EVP_PKEY_free(public_key); return 0; } // NOTE: Get device public key // argc = 0 int yh_com_get_device_pubkey(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(argv); UNUSED(in_fmt); if (ctx->connector == NULL) { fprintf(stderr, "Not connected\n"); return -1; } uint8_t response[YH_MSG_BUF_SIZE] = {0}; size_t response_len = sizeof(response); yh_algorithm algo = 0; yh_rc yrc = yh_util_get_device_pubkey(ctx->connector, response, &response_len, &algo); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to get device pubkey: %s\n", yh_strerror(yrc)); return -1; } if (fmt == fmt_hex) { for (size_t i = 0; i < response_len; i++) { fprintf(ctx->out, "%02x", response[i]); } fprintf(ctx->out, "\n"); return 0; } int nid = algo2nid(algo); EC_GROUP *group = EC_GROUP_new_by_curve_name(nid); if (group == NULL) { fprintf(stderr, "Invalid device public key algorithm\n"); return -1; } EC_GROUP_set_asn1_flag(group, OPENSSL_EC_NAMED_CURVE); EC_KEY *eckey = EC_KEY_new(); EC_KEY_set_group(eckey, group); EC_POINT *point = EC_POINT_new(group); EC_POINT_oct2point(group, point, response, response_len, NULL); EC_KEY_set_public_key(eckey, point); EVP_PKEY *public_key = EVP_PKEY_new(); EVP_PKEY_set1_EC_KEY(public_key, eckey); EC_POINT_free(point); EC_KEY_free(eckey); EC_GROUP_free(group); if (fmt == fmt_PEM) { PEM_write_PUBKEY(ctx->out, public_key); } else if (fmt == fmt_binary) { i2d_PUBKEY_fp(ctx->out, public_key); } else if (fmt == fmt_base64) { bool error = false; BIO *b64 = BIO_new(BIO_f_base64()); if (b64 == NULL) { fprintf(stderr, "Unable to allocate buffer\n"); error = true; goto getdpk_base64_cleanup; } BIO *bio = BIO_new_fp(ctx->out, BIO_NOCLOSE); if (bio == NULL) { fprintf(stderr, "Unable to allocate BIO\n"); BIO_free_all(b64); error = true; goto getdpk_base64_cleanup; } bio = BIO_push(b64, bio); i2d_PUBKEY_bio(bio, public_key); if (BIO_flush(bio) != 1) { fprintf(stderr, "Unable to flush BIO\n"); BIO_free_all(b64); error = true; goto getdpk_base64_cleanup; } BIO_free_all(bio); getdpk_base64_cleanup: if (error) { EVP_PKEY_free(public_key); return -1; } } // FIXME: other formats or error. EVP_PKEY_free(public_key); return 0; } // NOTE: Get object information // argc = 3 // arg 0: e:session // arg 1: w:id // arg 2: t:type int yh_com_get_object_info(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { yh_object_descriptor object = {0}; UNUSED(ctx); UNUSED(in_fmt); UNUSED(fmt); yh_rc yrc = yh_util_get_object_info(argv[0].e, argv[1].w, argv[2].b, &object); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to get object info: %s\n", yh_strerror(yrc)); return -1; } char domains[256] = {0}; const char *cap[sizeof(yh_capability) / sizeof(yh_capability[0])] = {0}; size_t n_cap = sizeof(yh_capability) / sizeof(yh_capability[0]); const char *type = 0; const char *algorithm = ""; const char *compressed_str = ""; const char *extra_algo = ""; char *label = object.label; size_t label_len = strlen(label); yh_type_to_string(object.type, &type); if (object.algorithm) { yh_algo_to_string(object.algorithm, &algorithm); if (is_compressed(argv[0].e, object.id, object.algorithm)) { compressed_str = "_compressed"; } extra_algo = ", algorithm: "; } yh_domains_to_string(object.domains, domains, 255); for (size_t i = 0; i < label_len; i++) { if (isprint(label[i]) == 0) { label[i] = '.'; } } fprintf(ctx->out, "id: 0x%04x, type: %s%s%s%s, label: \"%s\", length: %d, " "domains: %s, sequence: %hhu, origin: ", object.id, type, extra_algo, algorithm, compressed_str, label, object.len, domains, object.sequence); if (object.origin & YH_ORIGIN_GENERATED) { fprintf(ctx->out, "generated"); } if (object.origin & YH_ORIGIN_IMPORTED) { fprintf(ctx->out, "imported"); } if (object.origin & YH_ORIGIN_IMPORTED_WRAPPED) { fprintf(ctx->out, ":imported_wrapped"); } fprintf(ctx->out, ", capabilities: "); if (yh_capabilities_to_strings(&object.capabilities, cap, &n_cap) != YHR_SUCCESS) { for (size_t i = 0; i < YH_CAPABILITIES_LEN; i++) { fprintf(ctx->out, "0x%02x%s", object.capabilities.capabilities[i], i < YH_CAPABILITIES_LEN - 1 ? " " : ""); } } else { for (size_t i = 0; i < n_cap; i++) { fprintf(ctx->out, "%s%s", cap[i], i < n_cap - 1 ? ":" : ""); } } if (object.type == YH_WRAP_KEY || object.type == YH_PUBLIC_WRAP_KEY || object.type == YH_AUTHENTICATION_KEY) { fprintf(ctx->out, ", delegated_capabilities: "); n_cap = sizeof(yh_capability) / sizeof(yh_capability[0]); if (yh_capabilities_to_strings(&object.delegated_capabilities, cap, &n_cap) != YHR_SUCCESS) { for (size_t i = 0; i < YH_CAPABILITIES_LEN; i++) { fprintf(ctx->out, "0x%02x%s", object.delegated_capabilities.capabilities[i], i < YH_CAPABILITIES_LEN - 1 ? " " : ""); } } else { for (size_t i = 0; i < n_cap; i++) { fprintf(ctx->out, "%s%s", cap[i], i < n_cap - 1 ? ":" : ""); } } } fprintf(ctx->out, "\n"); return 0; } // NOTE: Get an object under wrap // argc = 5 // arg 0: e:session // arg 1: w:keyid // arg 2: t:type // arg 3: w:id // arg 4: b:include_seed // arg 5: f:file int yh_com_get_wrapped(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { uint8_t response[YH_MSG_BUF_SIZE] = {0}; size_t response_len = sizeof(response); UNUSED(in_fmt); uint8_t format = argv[4].b ? 1 : 0; yh_rc yrc = yh_util_export_wrapped_ex(argv[0].e, argv[1].w, argv[2].b, argv[3].w, format, response, &response_len); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to get wrapped object: %s\n", yh_strerror(yrc)); return -1; } if (write_file(response, response_len, ctx->out, fmt_to_fmt(fmt))) { return 0; } return -1; } // NOTE: Get an RSA wrapped key or object // argc = 7 // arg 0: e:session // arg 1: w:keyid // arg 2: t:type // arg 3: w:id // arg 4: a:aes // arg 5: a:oaep // arg 6: a:mgf1 // arg 7: f:file static int do_rsa_wrap(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt, bool key_wrap) { UNUSED(in_fmt); int hash = 0; yh_algorithm aes = argv[4].a; yh_algorithm oaep = argv[5].a; yh_algorithm mgf1 = argv[6].a; yh_rc yrc; if (aes == 0) { aes = YH_ALGO_AES256; } switch (oaep) { case YH_ALGO_RSA_OAEP_SHA1: hash = _SHA1; break; case YH_ALGO_RSA_OAEP_SHA256: hash = _SHA256; break; case YH_ALGO_RSA_OAEP_SHA384: hash = _SHA384; break; case YH_ALGO_RSA_OAEP_SHA512: hash = _SHA512; break; default: fprintf(stderr, "Unrecognized OAEP algorithm\n"); return -1; } uint8_t label[64] = {0}; size_t label_len = sizeof(label); if (hash_bytes(NULL, 0, hash, label, &label_len) == false) { fprintf(stderr, "Unable to hash data\n"); return -1; } uint8_t response[YH_MSG_BUF_SIZE] = {0}; size_t response_len = sizeof(response); if (key_wrap) { yrc = yh_util_get_rsa_wrapped_key(argv[0].e, argv[1].w, argv[2].b, argv[3].w, aes, oaep, mgf1, label, label_len, response, &response_len); } else { yrc = yh_util_export_rsa_wrapped(argv[0].e, argv[1].w, argv[2].b, argv[3].w, aes, oaep, mgf1, label, label_len, response, &response_len); } if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to encrypt data with OAEP: %s\n", yh_strerror(yrc)); return yrc; } if (!write_file(response, response_len, ctx->out, fmt_to_fmt(fmt))) { fprintf(stderr, "Failed to write wrapped object to file"); return YHR_GENERIC_ERROR; } return YHR_SUCCESS; } int yh_com_get_rsa_wrapped(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { return do_rsa_wrap(ctx, argv, in_fmt, fmt, false); } int yh_com_get_rsa_wrapped_key(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { return do_rsa_wrap(ctx, argv, in_fmt, fmt, true); } // NOTE(adma): Get a template object // argc = 2 // arg 0: e:session, // arg 1: w:object_id int yh_com_get_template(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { uint8_t response[YH_MSG_BUF_SIZE]; size_t response_len = sizeof(response); UNUSED(in_fmt); yh_rc yrc = yh_util_get_template(argv[0].e, argv[1].w, response, &response_len); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to get template object: %s\n", yh_strerror(yrc)); return -1; } write_file(response, response_len, ctx->out, fmt_to_fmt(fmt)); return 0; } // NOTE(adma): No operation command // argc = 0 int yh_com_noop(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(ctx); UNUSED(argv); UNUSED(in_fmt); UNUSED(fmt); return 0; } // NOTE(adma): List capabilities // argc = 0 int yh_com_list_capabilities(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(ctx); UNUSED(argv); UNUSED(in_fmt); UNUSED(fmt); for (size_t i = 0; i < sizeof(yh_capability) / sizeof(yh_capability[0]); i++) { fprintf(ctx->out, "%-30s (%016llx)\n", yh_capability[i].name, 1ULL << yh_capability[i].bit); } return 0; } // NOTE: List algorithms // argc = 0 int yh_com_list_algorithms(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(ctx); UNUSED(argv); UNUSED(in_fmt); UNUSED(fmt); for (size_t i = 0; i < sizeof(yh_algorithms) / sizeof(yh_algorithms[0]); i++) { fprintf(ctx->out, "%s\n", yh_algorithms[i].name); } return 0; } // NOTE: List types // argc = 0 int yh_com_list_types(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(ctx); UNUSED(argv); UNUSED(in_fmt); UNUSED(fmt); for (uint16_t i = 0; i < sizeof(yh_types) / sizeof(yh_types[0]); i++) { fprintf(ctx->out, "%s\n", yh_types[i].name); } return 0; } // NOTE(adma): List sessions // argc = 0 int yh_com_list_sessions(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(argv); UNUSED(in_fmt); UNUSED(fmt); if (ctx->connector == NULL) { fprintf(stderr, "Not connected\n"); return -1; } for (size_t i = 0; i < sizeof(ctx->sessions) / sizeof(ctx->sessions[0]); i++) { if (ctx->sessions[i] != NULL) { fprintf(stderr, "Session %zu\n", i); } } return 0; } static int compare_objects(const void *p1, const void *p2) { const yh_object_descriptor *a = p1; const yh_object_descriptor *b = p2; return a->id - b->id; } // NOTE: List object according to a filter // argc = 7 // arg 0: e:session // arg 1: w:id // arg 2: t:type // arg 3: w:domains // arg 4: u:capabilities // arg 5: a:algorithm // arg 6: b:with-compression // arg 7: s:label int yh_com_list_objects(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { yh_object_descriptor objects[YH_MAX_ITEMS_COUNT] = {0}; size_t num_objects = YH_MAX_ITEMS_COUNT; const char *label_arg = 0; UNUSED(ctx); UNUSED(in_fmt); UNUSED(fmt); if (argv[7].len == 0) { label_arg = NULL; } else { label_arg = argv[7].s; } yh_rc yrc = yh_util_list_objects(argv[0].e, argv[1].w, argv[2].b, argv[3].w, &argv[4].c, argv[5].a, label_arg, objects, &num_objects); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to list objects: %s\n", yh_strerror(yrc)); return -1; } qsort(objects, num_objects, sizeof(yh_object_descriptor), compare_objects); fprintf(ctx->out, "Found %zu object(s)\n", num_objects); for (size_t i = 0; i < num_objects; i++) { yrc = yh_util_get_object_info(argv[0].e, objects[i].id, objects[i].type, &objects[i]); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to get object info: %s\n", yh_strerror(yrc)); return -1; } const char *type = ""; yh_type_to_string(objects[i].type, &type); const char *algo = ""; yh_algo_to_string(objects[i].algorithm, &algo); const char *compressed = ""; if (argv[6].b && is_compressed(argv[0].e, objects[i].id, objects[i].algorithm)) { compressed = "_compressed"; } fprintf(ctx->out, "id: 0x%04x, type: %s, algo: %s%s, sequence: %hhu, label: %s\n", objects[i].id, type, algo, compressed, objects[i].sequence, objects[i].label); } return 0; } // NOTE(adma): Open a session with a connector using an Authentication Key // argc = 2 // arg 0: w:authkey // arg 1: i:password int yh_com_open_session(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(in_fmt); UNUSED(fmt); if (ctx->connector == NULL) { fprintf(stderr, "Not connected\n"); return -1; } yh_session *ses = NULL; yh_rc yrc = YHR_SUCCESS; if (in_fmt == fmt_password) { yrc = yh_create_session_derived(ctx->connector, argv[0].w, argv[1].x, argv[1].len, false, &ses); } else { yrc = yh_create_session(ctx->connector, argv[0].w, argv[1].x, argv[1].len / 2, argv[1].x + argv[1].len / 2, argv[1].len / 2, false, &ses); } insecure_memzero(argv[1].x, argv[1].len); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to create session: %s\n", yh_strerror(yrc)); return -1; } uint8_t session_id = 0; yrc = yh_get_session_id(ses, &session_id); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to get session id: %s\n", yh_strerror(yrc)); return -1; } if (ctx->sessions[session_id] != NULL) { yrc = yh_destroy_session(&ctx->sessions[session_id]); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to destroy old session with same id (%d): %s\n", session_id, yh_strerror(yrc)); return -1; } } ctx->sessions[session_id] = ses; fprintf(stderr, "Created session %d\n", session_id); return 0; } // NOTE: Open a session with a connector using an Asymmetric // Authentication Key argc = 2 arg 0: w:authkey arg 1: i:password int yh_com_open_session_asym(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(fmt); if (ctx->connector == NULL) { fprintf(stderr, "Not connected\n"); return -1; } uint16_t authkey = argv[0].w; uint8_t privkey[YH_EC_P256_PRIVKEY_LEN] = {0}; yh_rc yrc = YHR_SUCCESS; if (in_fmt == fmt_password) { uint8_t pubkey[YH_EC_P256_PUBKEY_LEN] = {0}; yrc = yh_util_derive_ec_p256_key(argv[1].x, argv[1].len, privkey, sizeof(privkey), pubkey, sizeof(pubkey)); insecure_memzero(argv[1].x, argv[1].len); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to derive asymmetric authentication key: %s\n", yh_strerror(yrc)); return -1; } } else if (in_fmt == fmt_PEM) { yh_algorithm algo; size_t len = sizeof(privkey); if (!read_private_key(argv[1].x, argv[1].len, &algo, privkey, &len, false)) { fprintf(stderr, "Failed to PEM decode asymmetric authentication key\n"); return -1; } if (len != sizeof(privkey)) { fprintf(stderr, "Invalid asymmetric authentication key\n"); return -1; } } else if (argv[1].len <= sizeof(privkey)) { memset(privkey, 0, sizeof(privkey) - argv[1].len); memcpy(privkey + sizeof(privkey) - argv[1].len, argv[1].x, argv[1].len); insecure_memzero(argv[1].x, argv[1].len); } else { insecure_memzero(argv[1].x, argv[1].len); fprintf(stderr, "Invalid asymmetric authkey: %s\n", yh_strerror(YHR_INVALID_PARAMETERS)); return -1; } uint8_t device_pubkey[YH_EC_P256_PUBKEY_LEN] = {0}; size_t device_pubkey_len = sizeof(device_pubkey); yrc = yh_util_get_device_pubkey(ctx->connector, device_pubkey, &device_pubkey_len, NULL); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to retrieve device pubkey: %s\n", yh_strerror(yrc)); return -1; } if (device_pubkey_len != YH_EC_P256_PUBKEY_LEN) { fprintf(stderr, "Invalid device pubkey\n"); return -1; } int matched = 0; for (uint8_t **pubkey = ctx->device_pubkey_list; *pubkey; pubkey++) { if (!memcmp(*pubkey, device_pubkey, device_pubkey_len)) { matched++; break; } } if (ctx->device_pubkey_list[0] == NULL) { fprintf(stderr, "CAUTION: Device public key (PK.SD) not validated\n"); for (size_t i = 0; i < device_pubkey_len; i++) fprintf(stderr, "%02x", device_pubkey[i]); fprintf(stderr, "\n"); } else if (matched == 0) { fprintf(stderr, "Failed to validate device pubkey\n"); return -1; } yh_session *ses = NULL; yrc = yh_create_session_asym(ctx->connector, authkey, privkey, sizeof(privkey), device_pubkey, device_pubkey_len, &ses); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to create session: %s\n", yh_strerror(yrc)); return -1; } uint8_t session_id = 0; yrc = yh_get_session_id(ses, &session_id); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to get session id: %s\n", yh_strerror(yrc)); return -1; } if (ctx->sessions[session_id] != NULL) { yrc = yh_destroy_session(&ctx->sessions[session_id]); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to destroy old session with same id (%d): %s\n", session_id, yh_strerror(yrc)); return -1; } } ctx->sessions[session_id] = ses; fprintf(stderr, "Created session %d\n", session_id); return 0; } // NOTE: Open a session using a key stored on YubiKey // argc = 3 // arg 0: w:authkey // arg 1: s:name // arg 2: i:password // arg 3: s:reader int yh_com_open_yksession(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(in_fmt); UNUSED(fmt); uint8_t key_s_enc[YH_KEY_LEN] = {0}; uint8_t key_s_mac[YH_KEY_LEN] = {0}; uint8_t key_s_rmac[YH_KEY_LEN] = {0}; uint8_t retries = 0; int ret = -1; if (ctx->connector == NULL) { fprintf(stderr, "Not connected\n"); goto cleanup; } ykhsmauth_rc ykhsmauthrc = ykhsmauth_connect(ctx->state, argv[3].s); if (ykhsmauthrc != YKHSMAUTHR_SUCCESS) { fprintf(stderr, "Failed to connect to the YubiKey: %s\n", ykhsmauth_strerror(ykhsmauthrc)); goto cleanup; } uint8_t host_challenge[YH_EC_P256_PUBKEY_LEN] = {0}; size_t host_challenge_len = sizeof(host_challenge); uint8_t major = 0, minor = 0, patch = 0; ykhsmauthrc = ykhsmauth_get_version_ex(ctx->state, &major, &minor, &patch); if (ykhsmauthrc != YKHSMAUTHR_SUCCESS) { fprintf(stderr, "Failed to get YubiKey firmware version: %s\n", ykhsmauth_strerror(ykhsmauthrc)); ykhsmauth_disconnect(ctx->state); goto cleanup; } if (major > 5 || (major == 5 && minor > 7) || (major == 5 && minor == 7 && patch >= 1) || (major == 0 && minor == 0 && patch == 1)) { ykhsmauthrc = ykhsmauth_get_challenge_ex(ctx->state, argv[1].s, argv[2].x, argv[2].len, host_challenge, &host_challenge_len); } else { ykhsmauthrc = ykhsmauth_get_challenge(ctx->state, argv[1].s, host_challenge, &host_challenge_len); } if (ykhsmauthrc != YKHSMAUTHR_SUCCESS) { fprintf(stderr, "Failed to get host challenge from the YubiKey: %s\n", ykhsmauth_strerror(ykhsmauthrc)); ykhsmauth_disconnect(ctx->state); goto cleanup; } uint8_t card_pubkey[YH_EC_P256_PUBKEY_LEN] = {0}; size_t card_pubkey_len = 0; yh_rc yrc = YHR_SUCCESS; if (host_challenge_len == YH_EC_P256_PUBKEY_LEN) { card_pubkey_len = sizeof(card_pubkey); yrc = yh_util_get_device_pubkey(ctx->connector, card_pubkey, &card_pubkey_len, NULL); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to retrieve device pubkey: %s\n", yh_strerror(yrc)); ykhsmauth_disconnect(ctx->state); goto cleanup; } if (card_pubkey_len != YH_EC_P256_PUBKEY_LEN) { fprintf(stderr, "Invalid device pubkey\n"); ykhsmauth_disconnect(ctx->state); goto cleanup; } int matched = 0; for (uint8_t **pubkey = ctx->device_pubkey_list; *pubkey; pubkey++) { if (!memcmp(*pubkey, card_pubkey, card_pubkey_len)) { matched++; break; } } if (ctx->device_pubkey_list[0] == NULL) { fprintf(stderr, "CAUTION: Device public key (PK.SD) not validated\n"); for (size_t i = 0; i < card_pubkey_len; i++) fprintf(stderr, "%02x", card_pubkey[i]); fprintf(stderr, "\n"); } else if (matched == 0) { fprintf(stderr, "Failed to validate device pubkey\n"); ykhsmauth_disconnect(ctx->state); goto cleanup; } } uint8_t card_cryptogram[YH_KEY_LEN] = {0}; size_t card_cryptogram_len = sizeof(card_cryptogram); uint8_t *yh_context = 0; yh_session *ses = NULL; yrc = yh_begin_create_session(ctx->connector, argv[0].w, &yh_context, host_challenge, &host_challenge_len, card_cryptogram, &card_cryptogram_len, &ses); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to create session: %s\n", yh_strerror(yrc)); ykhsmauth_disconnect(ctx->state); goto cleanup; } ykhsmauthrc = ykhsmauth_calculate_ex(ctx->state, argv[1].s, yh_context, 2 * host_challenge_len, card_pubkey, card_pubkey_len, card_cryptogram, card_cryptogram_len, argv[2].x, argv[2].len, key_s_enc, sizeof(key_s_enc), key_s_mac, sizeof(key_s_mac), key_s_rmac, sizeof(key_s_rmac), &retries); ykhsmauth_disconnect(ctx->state); if (ykhsmauthrc != YKHSMAUTHR_SUCCESS) { fprintf(stderr, "Failed to get session keys from the YubiKey: %s", ykhsmauth_strerror(ykhsmauthrc)); if (ykhsmauthrc == YKHSMAUTHR_WRONG_PW) { fprintf(stderr, ", %d attempts remaining", retries); } fprintf(stderr, "\n"); yh_destroy_session(&ses); goto cleanup; } yrc = yh_finish_create_session(ses, key_s_enc, sizeof(key_s_enc), key_s_mac, sizeof(key_s_mac), key_s_rmac, sizeof(key_s_rmac), card_cryptogram, card_cryptogram_len); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to create session: %s\n", yh_strerror(yrc)); yh_destroy_session(&ses); goto cleanup; } uint8_t session_id = 0; yrc = yh_get_session_id(ses, &session_id); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to fetch ID session: %s\n", yh_strerror(yrc)); yh_destroy_session(&ses); goto cleanup; } if (ctx->sessions[session_id] != NULL) { yrc = yh_destroy_session(&ctx->sessions[session_id]); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to destroy old session with same id (%d): %s\n", session_id, yh_strerror(yrc)); yh_destroy_session(&ses); goto cleanup; } } ctx->sessions[session_id] = ses; fprintf(stderr, "Created session %d\n", session_id); ret = 0; cleanup: insecure_memzero(argv[2].x, argv[2].len); insecure_memzero(key_s_enc, sizeof(key_s_enc)); insecure_memzero(key_s_mac, sizeof(key_s_mac)); insecure_memzero(key_s_rmac, sizeof(key_s_rmac)); return ret; } // NOTE(adma): Send unauthenticated echo // argc = 2 // arg 0: b:byte // arg 1: w:count int yh_com_pecho(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(in_fmt); UNUSED(fmt); uint8_t data[YH_MSG_BUF_SIZE] = {0}; uint16_t data_len = 0; uint8_t response[YH_MSG_BUF_SIZE] = {0}; size_t response_len = 0; yh_cmd response_cmd = 0; if (ctx->connector == NULL) { fprintf(stderr, "Not connected\n"); return -1; } uint8_t byte = argv[0].b; uint16_t count = argv[1].w; if (count > YH_MSG_BUF_SIZE) { fprintf(stderr, "Count must be in [0, %d]\n", YH_MSG_BUF_SIZE); return -1; } memset(data, byte, count); data_len = count; response_len = sizeof(response); yh_rc yrc = yh_send_plain_msg(ctx->connector, YHC_ECHO, data, data_len, &response_cmd, response, &response_len); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to send ECHO command: %s\n", yh_strerror(yrc)); return -1; } fprintf(ctx->out, "Response (%zu bytes):\n", response_len); for (size_t i = 0; i < response_len; i++) { if (i && !(i % 64)) fprintf(ctx->out, "\n"); else if (i && !(i % 8)) fprintf(ctx->out, " "); fprintf(ctx->out, "%02x", response[i]); } fprintf(ctx->out, "\n"); return 0; } // Store a symmetric key // argc = 6 // arg 0: e:session // arg 1: w:key_id // arg 2: s:label // arg 3: w:domains // arg 4: c:capabilities // arg 5: a:algorithm // arg 6: i:key int yh_com_put_symmetric(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(ctx); UNUSED(in_fmt); UNUSED(fmt); yh_rc yrc; if (yh_is_aes(argv[5].a)) { if ((argv[5].a == YH_ALGO_AES128 && argv[6].len != 16) || (argv[5].a == YH_ALGO_AES192 && argv[6].len != 24) || (argv[5].a == YH_ALGO_AES256 && argv[6].len != 32)) { fprintf(stderr, "Key length (%zu) not matching, should be 16, 24 or 32\n", argv[6].len); return -1; } yrc = yh_util_import_aes_key(argv[0].e, &argv[1].w, argv[2].s, argv[3].w, &argv[4].c, argv[5].a, argv[6].x); } else { fprintf(stderr, "Invalid algorithm\n"); return -1; } if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to store symmetric key: %s\n", yh_strerror(yrc)); return -1; } fprintf(stderr, "Stored symmetric key 0x%04x\n", argv[1].w); return 0; } // NOTE(adma): Store an asymmetric key // argc = 6 // arg 0: e:session // arg 1: w:key_id // arg 2: s:label // arg 3: w:domains // arg 4: c:capabilities // arg 5: x:key int yh_com_put_asymmetric(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(ctx); UNUSED(in_fmt); UNUSED(fmt); uint8_t key[512] = {0}; size_t key_material_len = sizeof(key); yh_algorithm algorithm = 0; bool ret = read_private_key(argv[5].x, argv[5].len, &algorithm, key, &key_material_len, false); if (ret == false) { fprintf(stderr, "Unable to read asymmetric key\n"); return -1; } yh_rc yrc = YHR_SUCCESS; switch (algorithm) { case YH_ALGO_RSA_2048: case YH_ALGO_RSA_3072: case YH_ALGO_RSA_4096: yrc = yh_util_import_rsa_key(argv[0].e, &argv[1].w, argv[2].s, argv[3].w, &argv[4].c, algorithm, key, key + key_material_len / 2); break; case YH_ALGO_EC_P224: case YH_ALGO_EC_P256: case YH_ALGO_EC_P384: case YH_ALGO_EC_P521: case YH_ALGO_EC_K256: case YH_ALGO_EC_BP256: case YH_ALGO_EC_BP384: case YH_ALGO_EC_BP512: yrc = yh_util_import_ec_key(argv[0].e, &argv[1].w, argv[2].s, argv[3].w, &argv[4].c, algorithm, key); break; case YH_ALGO_EC_ED25519: yrc = yh_util_import_ed_key(argv[0].e, &argv[1].w, argv[2].s, argv[3].w, &argv[4].c, algorithm, key); break; default: fprintf(stderr, "Unsupported algorithm\n"); return -1; } if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to store asymmetric key: %s\n", yh_strerror(yrc)); return -1; } fprintf(stderr, "Stored Asymmetric key 0x%04x\n", argv[1].w); return 0; } // NOTE(adma): Store an authentication key // argc = 7 // arg 0: e:session // arg 1: w:key_id // arg 2: s:label // arg 3: w:domains // arg 4: c:capabilities // arg 5: c:delegated_capabilities // arg 6: x:password int yh_com_put_authentication(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(ctx); UNUSED(in_fmt); UNUSED(fmt); yh_rc yrc = yh_util_import_authentication_key_derived(argv[0].e, &argv[1].w, argv[2].s, argv[3].w, &argv[4].c, &argv[5].c, argv[6].x, argv[6].len); insecure_memzero(argv[6].x, argv[6].len); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to store authkey: %s\n", yh_strerror(yrc)); return -1; } fprintf(stderr, "Stored Authentication key 0x%04x\n", argv[1].w); return 0; } // NOTE: Store an asymmetric authentication key // argc = 7 // arg 0: e:session // arg 1: w:key_id // arg 2: s:label // arg 3: w:domains // arg 4: c:capabilities // arg 5: c:delegated_capabilities // arg 6: x:password int yh_com_put_authentication_asym(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(ctx); UNUSED(fmt); yh_rc yrc = YHR_SUCCESS; uint8_t pubkey[YH_EC_P256_PUBKEY_LEN] = {0}; if (in_fmt == fmt_password) { uint8_t privkey[YH_EC_P256_PRIVKEY_LEN] = {0}; yrc = yh_util_derive_ec_p256_key(argv[6].x, argv[6].len, privkey, sizeof(privkey), pubkey, sizeof(pubkey)); insecure_memzero(argv[6].x, argv[6].len); insecure_memzero(privkey, sizeof(privkey)); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to derive asymmetric authentication key: %s\n", yh_strerror(yrc)); return -1; } fprintf(stderr, "Derived public key (PK.OCE)\n"); for (size_t i = 0; i < sizeof(pubkey); i++) fprintf(stderr, "%02x", pubkey[i]); fprintf(stderr, "\n"); } else if (in_fmt == fmt_PEM) { yh_algorithm algo = 0; size_t pubkey_len = sizeof(pubkey); if (!read_public_key(argv[6].x, argv[6].len, &algo, pubkey, &pubkey_len)) { fprintf(stderr, "Failed to load public key\n"); return -1; } if (pubkey_len != sizeof(pubkey)) { fprintf(stderr, "Invalid public key\n"); return -1; } } else if (argv[6].len <= sizeof(pubkey)) { memset(pubkey, 0, sizeof(pubkey) - argv[6].len); memcpy(pubkey + sizeof(pubkey) - argv[6].len, argv[6].x, argv[6].len); } else { fprintf(stderr, "Invalid asymmetric authkey: %s\n", yh_strerror(YHR_INVALID_PARAMETERS)); return -1; } yrc = yh_util_import_authentication_key(argv[0].e, &argv[1].w, argv[2].s, argv[3].w, &argv[4].c, &argv[5].c, pubkey + 1, sizeof(pubkey) - 1, NULL, 0); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to store asymmetric authkey: %s\n", yh_strerror(yrc)); return -1; } fprintf(stderr, "Stored Asymmetric Authentication key 0x%04x\n", argv[1].w); return 0; } // NOTE(adma): Store an opaque object // argc = 6 // arg 0: e:session // arg 1: w:object_id // arg 2: s:label // arg 3: w:domains // arg 4: c:capabilities // arg 5: a:algorithm // arg 6: b:with-compression // arg 7: i:datafile int yh_com_put_opaque(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(ctx); UNUSED(fmt); unsigned char buf[YH_MSG_BUF_SIZE], *data = argv[7].x; size_t len = argv[7].len; if (in_fmt == fmt_PEM) { // Decode X.509 Certificate regardless of algorithm in case fmt_PEM is // explicitly set BIO *bio = BIO_new_mem_buf(data, len); if (!bio) { fprintf(stderr, "Couldn't wrap PEM-encoded certificate data\n"); return 0; } X509 *cert = PEM_read_bio_X509(bio, NULL, NULL, NULL); if (!cert) { fprintf(stderr, "Couldn't parse PEM-encoded certificate\n"); BIO_free(bio); return 0; } BIO_free(bio); len = i2d_X509(cert, 0); if (len > sizeof(buf)) { fprintf(stderr, "Decoded certificate is too large: %zu\n", len); X509_free(cert); return 0; } data = buf; i2d_X509(cert, &data); data = buf; X509_free(cert); } else if (argv[5].a == YH_ALGO_OPAQUE_X509_CERTIFICATE) { // Enforce valid X.509 certificate const unsigned char *p = data; X509 *cert = d2i_X509(NULL, &p, len); if (!cert) { fprintf(stderr, "Couldn't parse DER-encoded certificate\n"); return 0; } X509_free(cert); } #ifdef ENABLE_CERT_COMPRESS if (argv[6].a && argv[5].a != YH_ALGO_OPAQUE_X509_CERTIFICATE) { fprintf(stderr, "Compression is only supported for X.509 certificates\n"); return -1; } #endif size_t import_len = 0; yh_rc yrc = yh_util_import_opaque_ex(argv[0].e, &argv[1].w, argv[2].s, argv[3].w, &argv[4].c, argv[5].a, data, len, argv[6].a ? COMPRESS : NO_COMPRESS, &import_len); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to store opaque object: %s\n", yh_strerror(yrc)); #ifdef ENABLE_CERT_COMPRESS if (yrc == YHR_BUFFER_TOO_SMALL && !argv[6].a && argv[5].a == YH_ALGO_OPAQUE_X509_CERTIFICATE) { fprintf(stderr, "Try compressing the certificate by using the " "'with-compression' flag. Beware that " "compressed certificates cannot be used for attestation\n"); } #endif return -1; } fprintf(stderr, "Stored %zu bytes to Opaque object 0x%04x\n", import_len, argv[1].w); return 0; } // NOTE(adma): Set a global option value // argc = 3 // arg 0: e:session // arg 1: o:option // arg 2: x:value int yh_com_put_option(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(ctx); UNUSED(in_fmt); UNUSED(fmt); yh_rc yrc = yh_util_set_option(argv[0].e, argv[1].o, argv[2].len, argv[2].x); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to store option: %s\n", yh_strerror(yrc)); return -1; } return 0; } // NOTE: Put a HMAC key // argc = 7 // arg 0: e:session // arg 1: w:key_id // arg 2: s:label // arg 3: w:domains // arg 4: c:capabilities // arg 5: a:algorithm // arg 6: x:key int yh_com_put_hmac(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(ctx); UNUSED(in_fmt); UNUSED(fmt); if (argv[6].len > 128) { fprintf(stderr, "Too long key supplied, max 128 bytes allowed\n"); return -1; } yh_rc yrc = yh_util_import_hmac_key(argv[0].e, &argv[1].w, argv[2].s, argv[3].w, &argv[4].c, argv[5].a, argv[6].x, argv[6].len); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to store HMAC key: %s\n", yh_strerror(yrc)); return -1; } fprintf(stderr, "Stored HMAC key 0x%04x\n", argv[1].w); return 0; } // NOTE: Store a wrapping key // argc = 6 // arg 0: e:session // arg 1: w:key_id // arg 2: s:label // arg 3: w:domains // arg 4: c:capabilities // arg 5: c:delegated_capabilities // arg 6: x:key int yh_com_put_wrapkey(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(ctx); UNUSED(in_fmt); UNUSED(fmt); yh_algorithm algo = 0; if (argv[6].len == 16) { algo = YH_ALGO_AES128_CCM_WRAP; } else if (argv[6].len == 24) { algo = YH_ALGO_AES192_CCM_WRAP; } else if (argv[6].len == 32) { algo = YH_ALGO_AES256_CCM_WRAP; } else { fprintf(stderr, "Key length not matching, should be 16, 24 or 32\n"); return -1; } yh_rc yrc = yh_util_import_wrap_key(argv[0].e, &argv[1].w, argv[2].s, argv[3].w, &argv[4].c, algo, &argv[5].c, argv[6].x, argv[6].len); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to store wrapkey: %s\n", yh_strerror(yrc)); return -1; } fprintf(stderr, "Stored Wrap key 0x%04x\n", argv[1].w); return 0; } // NOTE: Store an RSA wrapping key // argc = 6 // arg 0: e:session // arg 1: w:key_id // arg 2: s:label // arg 3: w:domains // arg 4: c:capabilities // arg 5: c:delegated_capabilities // arg 6: x:key int yh_com_put_rsa_wrapkey(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(ctx); UNUSED(in_fmt); UNUSED(fmt); uint8_t key[512] = {0}; size_t key_material_len = sizeof(key); yh_algorithm algo = 0; bool ret = read_private_key(argv[6].x, argv[6].len, &algo, key, &key_material_len, false); if (ret == false) { fprintf(stderr, "Unable to read wrap key\n"); return -1; } yh_rc yrc = yh_util_import_wrap_key(argv[0].e, &argv[1].w, argv[2].s, argv[3].w, &argv[4].c, algo, &argv[5].c, key, key_material_len); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to store wrapkey: %s\n", yh_strerror(yrc)); return -1; } fprintf(stderr, "Stored Wrap key 0x%04x\n", argv[1].w); return 0; } static bool read_rsa_pubkey(const uint8_t *buf, size_t len, uint8_t *bytes, size_t *bytes_len) { BIO *bio; if ((bio = BIO_new(BIO_s_mem())) == NULL) return false; if(BIO_write(bio, buf, len) <= 0) { fprintf(stderr, "%s: Failed to read RSA public key\n", __func__); BIO_free_all(bio); return false; } RSA *rsa = NULL; EVP_PKEY *pubkey = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL); BIO_free_all(bio); if (pubkey == NULL || EVP_PKEY_base_id(pubkey) != EVP_PKEY_RSA || (rsa = EVP_PKEY_get1_RSA(pubkey)) == NULL) { fprintf(stderr, "Failed to parse RSA public key\n"); EVP_PKEY_free(pubkey); return false; } bool ret = false; const BIGNUM *n = NULL; RSA_get0_key(rsa, &n, NULL, NULL); if (n == NULL) { goto fail; } size_t nn = BN_num_bytes(n); if (*bytes_len < nn) { fprintf(stderr, "%s: insufficient dst buffer space\n", __func__); goto fail; } *bytes_len = (size_t) BN_bn2bin(n, bytes); ret = true; fail: RSA_free(rsa); EVP_PKEY_free(pubkey); return ret; } // NOTE: Store a public wrap key // argc = 6 // arg 0: e:session // arg 1: w:key_id // arg 2: s:label // arg 3: w:domains // arg 4: c:capabilities // arg 5: c:delegated_capabilities // arg 6: i:pubkey int yh_com_put_public_wrapkey(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(ctx); UNUSED(in_fmt); UNUSED(fmt); uint8_t pubkey[512]; size_t pubkey_len = sizeof(pubkey); yh_algorithm algo = 0; if (!read_rsa_pubkey(argv[6].x, argv[6].len, pubkey, &pubkey_len)) { fprintf(stderr, "Failed to read public key\n"); return -1; } switch (pubkey_len) { case 256: algo = YH_ALGO_RSA_2048; break; case 384: algo = YH_ALGO_RSA_3072; break; case 512: algo = YH_ALGO_RSA_4096; break; default: fprintf(stderr, "Invalid public key length (%zu)\n", pubkey_len); return -1; } yh_rc yrc = yh_util_import_public_wrap_key(argv[0].e, &argv[1].w, argv[2].s, argv[3].w, &argv[4].c, algo, &argv[5].c, pubkey, pubkey_len); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to store public wrap key: %s\n", yh_strerror(yrc)); return -1; } fprintf(stderr, "Stored public wrap key 0x%04x\n", argv[1].w); return 0; } // NOTE: Store a wrapped object // argc = 3 // arg 0: e:session // arg 1: w:key_id // arg 2: i:data int yh_com_put_wrapped(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(ctx); UNUSED(in_fmt); UNUSED(fmt); yh_object_type object_type = 0; uint16_t object_id = 0; yh_rc yrc = yh_util_import_wrapped(argv[0].e, argv[1].w, argv[2].x, argv[2].len, &object_type, &object_id); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to store wrapped object: %s\n", yh_strerror(yrc)); return -1; } const char *type = ""; yh_type_to_string(object_type, &type); fprintf(stderr, "Object imported as 0x%04x of type %s\n", object_id, type); return 0; } // NOTE: Store an asymetrically wrapped object // argc = 3 // arg 0: e:session // arg 1: w:key_id // arg 2: a:oaep // arg 3: a:mgf1 // arg 4: i:data int yh_com_put_rsa_wrapped(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(ctx); UNUSED(in_fmt); UNUSED(fmt); yh_object_type object_type = 0; uint16_t object_id = 0; yh_algorithm mgf1 = argv[3].a; yh_algorithm oaep = argv[2].a; int hash = 0; switch (oaep) { case YH_ALGO_RSA_OAEP_SHA1: hash = _SHA1; break; case YH_ALGO_RSA_OAEP_SHA256: hash = _SHA256; break; case YH_ALGO_RSA_OAEP_SHA384: hash = _SHA384; break; case YH_ALGO_RSA_OAEP_SHA512: hash = _SHA512; break; default: fprintf(stderr, "Unrecognized OAEP algorithm\n"); return -1; } uint8_t label[64] = {0}; size_t label_len = sizeof(label); if (hash_bytes(NULL, 0, hash, label, &label_len) == false) { fprintf(stderr, "Unable to hash data.\n"); return -1; } yh_rc yrc = yh_util_import_rsa_wrapped(argv[0].e, argv[1].w, oaep, mgf1, label, label_len, argv[4].x, argv[4].len, &object_type, &object_id); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to store wrapped object: %s\n", yh_strerror(yrc)); return -1; } const char *type = ""; yh_type_to_string(object_type, &type); fprintf(stderr, "Object imported as 0x%04x of type %s\n", object_id, type); return 0; } // NOTE: Store an asymetrically wrapped key object // argc = 3 // arg 0: e:session // arg 1: w:wrapkey_id // arg 2: t:type // arg 3: w:key_id // arg 4: a:key_algorithm // arg 5: s:label // arg 6: w:domains // arg 7: c:capabilities // arg 8: a:oaep // arg 9: a:mgf1 // arg 10: i:data int yh_com_put_rsa_wrapped_key(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(ctx); UNUSED(in_fmt); UNUSED(fmt); yh_object_type object_type = argv[2].t; uint16_t object_id = argv[3].w; yh_algorithm mgf1 = argv[9].a; yh_algorithm oaep = argv[8].a; int hash = 0; switch (oaep) { case YH_ALGO_RSA_OAEP_SHA1: hash = _SHA1; break; case YH_ALGO_RSA_OAEP_SHA256: hash = _SHA256; break; case YH_ALGO_RSA_OAEP_SHA384: hash = _SHA384; break; case YH_ALGO_RSA_OAEP_SHA512: hash = _SHA512; break; default: fprintf(stderr, "Unrecognized OAEP algorithm\n"); return -1; } uint8_t label[64] = {0}; size_t label_len = sizeof(label); if (hash_bytes(NULL, 0, hash, label, &label_len) == false) { fprintf(stderr, "Unable to hash data\n"); return -1; } yh_rc yrc = yh_util_put_rsa_wrapped_key(argv[0].e, argv[1].w, object_type, &object_id, argv[4].a, argv[5].s, argv[6].w, &argv[7].c, oaep, mgf1, label, label_len, argv[10].x, argv[10].len); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to store wrapped object: %s\n", yh_strerror(yrc)); return -1; } const char *type = ""; yh_type_to_string(object_type, &type); fprintf(stderr, "Object imported as 0x%04x of type %s\n", object_id, type); return 0; } // NOTE(adma): Store a template object // argc = 7 // arg 0: e:session // arg 1: w:object_id // arg 2: s:label // arg 3: w:domains // arg 4: c:capabilities // arg 5: a:algorithm // arg 6: i:datafile int yh_com_put_template(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(ctx); UNUSED(in_fmt); UNUSED(fmt); yh_rc yrc = yh_util_import_template(argv[0].e, &argv[1].w, argv[2].s, argv[3].w, &argv[4].c, argv[5].a, argv[6].x, argv[6].len); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to store template object: %s\n", yh_strerror(yrc)); return -1; } fprintf(stderr, "Stored Template object 0x%04x\n", argv[1].w); return 0; } // NOTE(adma): Sign data using ECDSA // argc = 4 // arg 0: e:session // arg 1: w:key_id // arg 2: a:algorithm // arg 3: i:datafile int yh_com_sign_ecdsa(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(in_fmt); uint8_t data[YH_MSG_BUF_SIZE] = {0}; size_t data_len = sizeof(data); uint8_t response[YH_MSG_BUF_SIZE] = {0}; size_t response_len = sizeof(response); int hash = 0; switch (argv[2].a) { case YH_ALGO_EC_ECDSA_SHA1: hash = _SHA1; break; case YH_ALGO_EC_ECDSA_SHA256: hash = _SHA256; break; case YH_ALGO_EC_ECDSA_SHA384: hash = _SHA384; break; case YH_ALGO_EC_ECDSA_SHA512: hash = _SHA512; break; default: fprintf(stderr, "Invalid hash algorithm\n"); return -1; } if (hash_bytes(argv[3].x, argv[3].len, hash, data, &data_len) == false) { fprintf(stderr, "Unable to hash file\n"); return -1; } yh_rc yrc = yh_util_sign_ecdsa(argv[0].e, argv[1].w, data, data_len, response, &response_len); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to sign data with ecdsa: %s\n", yh_strerror(yrc)); return -1; } write_file(response, response_len, ctx->out, fmt_to_fmt(fmt)); return 0; } // NOTE(adma): Sign data using EDDSA // argc = 4 // arg 0: e:session // arg 1: w:key_id // arg 2: a:algorithm // arg 3: i:datafile int yh_com_sign_eddsa(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(in_fmt); uint8_t response[YH_MSG_BUF_SIZE] = {0}; size_t response_len = sizeof(response); if (argv[2].a != YH_ALGO_EC_ED25519) { fprintf(stderr, "Invalid algorithm\n"); return -1; } yh_rc yrc = yh_util_sign_eddsa(argv[0].e, argv[1].w, argv[3].x, argv[3].len, response, &response_len); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to sign data with eddsa: %s\n", yh_strerror(yrc)); return -1; } write_file(response, response_len, ctx->out, fmt_to_fmt(fmt)); return 0; } // NOTE(adma): Sign data using RSASSA-PKCS#1v1.5 // argc = 4 // arg 0: e:session // arg 1: w:key_id // arg 2: a:algorithm // arg 3: f:datafile int yh_com_sign_pkcs1v1_5(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(in_fmt); uint8_t data[YH_MSG_BUF_SIZE] = {0}; size_t data_len = sizeof(data); uint8_t response[YH_MSG_BUF_SIZE] = {0}; size_t response_len = sizeof(response); int hash = 0; switch (argv[2].a) { case YH_ALGO_RSA_PKCS1_SHA1: hash = _SHA1; break; case YH_ALGO_RSA_PKCS1_SHA256: hash = _SHA256; break; case YH_ALGO_RSA_PKCS1_SHA384: hash = _SHA384; break; case YH_ALGO_RSA_PKCS1_SHA512: hash = _SHA512; break; default: fprintf(stderr, "Invalid hash algorithm\n"); return -1; } if (hash_bytes(argv[3].x, argv[3].len, hash, data, &data_len) == false) { fprintf(stderr, "Unable to hash file\n"); return -1; } yh_rc yrc = yh_util_sign_pkcs1v1_5(argv[0].e, argv[1].w, true, data, data_len, response, &response_len); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to sign data with PKCS#1v1.5: %s\n", yh_strerror(yrc)); return -1; } write_file(response, response_len, ctx->out, fmt_to_fmt(fmt)); return 0; } // NOTE(adma): Sign data using RSASSA-PSS // argc = 4 // arg 0: e:session // arg 1: w:key_id // arg 2: a:algorithm // arg 3: f:datafile int yh_com_sign_pss(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(in_fmt); uint8_t data[YH_MSG_BUF_SIZE] = {0}; size_t data_len = sizeof(data); uint8_t response[YH_MSG_BUF_SIZE] = {0}; size_t response_len = sizeof(response); int hash = 0; yh_algorithm mgf = 0; switch (argv[2].a) { case YH_ALGO_RSA_PSS_SHA1: hash = _SHA1; mgf = YH_ALGO_MGF1_SHA1; break; case YH_ALGO_RSA_PSS_SHA256: hash = _SHA256; mgf = YH_ALGO_MGF1_SHA256; break; case YH_ALGO_RSA_PSS_SHA384: hash = _SHA384; mgf = YH_ALGO_MGF1_SHA384; break; case YH_ALGO_RSA_PSS_SHA512: hash = _SHA512; mgf = YH_ALGO_MGF1_SHA512; break; default: fprintf(stderr, "Invalid hash algorithm\n"); return -1; } if (hash_bytes(argv[3].x, argv[3].len, hash, data, &data_len) == false) { fprintf(stderr, "Unable to hash file\n"); return -1; } // NOTE(adma): Salt length always matches the length of the hash yh_rc yrc = yh_util_sign_pss(argv[0].e, argv[1].w, data, data_len, response, &response_len, data_len, mgf); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to sign data with PSS: %s\n", yh_strerror(yrc)); return -1; } write_file(response, response_len, ctx->out, fmt_to_fmt(fmt)); return 0; } // NOTE(adma): Extract the version number, serial number and supported // algorithms // argc = 0 int yh_com_get_device_info(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(argv); UNUSED(in_fmt); UNUSED(fmt); if (ctx->connector == NULL) { fprintf(stderr, "Not connected\n"); return -1; } yh_device_info device_info = {0}; yh_rc yrc = yh_util_get_device_info_ex(ctx->connector, &device_info); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to get device info: %s\n", yh_strerror(yrc)); return -1; } fprintf(ctx->out, "Version number:\t\t%hhu.%hhu.%hhu\n", device_info.major, device_info.minor, device_info.patch); fprintf(ctx->out, "Serial number:\t\t%u\n", device_info.serial); fprintf(ctx->out, "Log used:\t\t%d/%d\n", device_info.log_used, device_info.log_total); fprintf(ctx->out, "Supported algorithms:\t"); for (size_t i = 0; i < device_info.n_algorithms; i++) { const char *algo_str; yh_algo_to_string(device_info.algorithms[i], &algo_str); fprintf(ctx->out, "%s, ", algo_str); if ((i + 1) % 3 == 0 && i != 0) { fprintf(ctx->out, "\n\t\t\t"); } } fprintf(ctx->out, "\n"); char part_number[256] = {0}; size_t part_number_len = sizeof(part_number); yrc = yh_util_get_partnumber(ctx->connector, part_number, &part_number_len); if (yrc == YHR_SUCCESS && part_number_len > 0) { fprintf(ctx->out, "Part number:\t\t%s\n", part_number); } return 0; } // NOTE: HMAC data // argc = 3 // arg 0: e:session // arg 1: w:key_id // arg 2: x:data int yh_com_hmac(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(ctx); UNUSED(in_fmt); uint8_t response[YH_MSG_BUF_SIZE] = {0}; size_t response_len = sizeof(response); yh_rc yrc = yh_util_sign_hmac(argv[0].e, argv[1].w, argv[2].x, argv[2].len, response, &response_len); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to HMAC data: %s\n", yh_strerror(yrc)); return -1; } write_file(response, response_len, ctx->out, fmt_to_fmt(fmt)); return 0; } // NOTE: Reset device // argc = 1 // arg 0: e:session int yh_com_reset(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(ctx); UNUSED(in_fmt); UNUSED(fmt); yh_rc yrc = yh_util_reset_device(argv[0].e); if (yrc != YHR_CONNECTOR_ERROR && yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to reset device: %s\n", yh_strerror(yrc)); return -1; } fprintf(ctx->out, "Device successfully reset\n"); return 0; } // NOTE: Delete an object // argc = 3 // arg 0: e:session // arg 1: w:id // arg 2: t:type int yh_com_delete(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(ctx); UNUSED(in_fmt); UNUSED(fmt); yh_rc yrc = yh_util_delete_object(argv[0].e, argv[1].w, argv[2].t); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to delete object: %s\n", yh_strerror(yrc)); return -1; } // TODO(adma): the order of the arguments should be changed to id and type return 0; } // NOTE(adma): Sign an SSH public key // argc = 4 // arg 0: e:session // arg 1: w:key_id // arg 2: w:template_id // arg 3: a:algorithm // arg 4: i:datafile int yh_com_sign_ssh_certificate(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(in_fmt); UNUSED(fmt); // TODO: respect output format uint8_t data[YH_MSG_BUF_SIZE + 1024] = {0}; size_t response_len = sizeof(data); if (argv[4].len > YH_MSG_BUF_SIZE) { fprintf(stderr, "Failed to sign ssh certificate: %s. Data too long\n", yh_strerror(YHR_BUFFER_TOO_SMALL)); return -1; } const size_t certdata_offset = 4 + 256; // 4 bytes timestamp + 256 byte signature if(argv[4].len < certdata_offset) { fprintf(stderr, "Failed to sign ssh certificate: %s. Data too short.\n", yh_strerror(YHR_WRONG_LENGTH)); return -1; } memcpy(data, argv[4].x, argv[4].len); response_len -= argv[4].len; yh_rc yrc = yh_util_sign_ssh_certificate(argv[0].e, argv[1].w, argv[2].w, argv[3].a, data, argv[4].len, data + argv[4].len, &response_len); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to get certificate signature: %s\n", yh_strerror(yrc)); return -1; } BIO *b64 = BIO_new(BIO_f_base64()); if (b64 == NULL) { fprintf(stderr, "Failed to sign SSH certificate.\n"); return -1; } BIO *bio = BIO_new(BIO_s_mem()); if (bio == NULL) { fprintf(stderr, "Failed to sign SSH certificate.\n"); BIO_free_all(b64); return -1; } bio = BIO_push(b64, bio); int ret = 0; int cert_len = argv[4].len - certdata_offset + response_len; BUF_MEM *bufferPtr = 0; BIO_set_flags(bio, BIO_FLAGS_BASE64_NO_NL); if (BIO_write(bio, data + certdata_offset, cert_len) != cert_len) { fprintf(stderr, "Failed to write SSH certificate.\n"); ret = -1; goto clean_bio; } if (BIO_flush(bio) != 1) { fprintf(stderr, "Failed to sign SSH certificate.\n"); ret = -1; goto clean_bio; } BIO_get_mem_ptr(bio, &bufferPtr); const char *ssh_cert_str = "ssh-rsa-cert-v01@openssh.com "; // TODO(adma): ECDSA if (fwrite(ssh_cert_str, 1, strlen(ssh_cert_str), ctx->out) != strlen(ssh_cert_str) || ferror(ctx->out)) { fprintf(stderr, "Unable to write data to file\n"); ret = -1; goto clean_bio; } if (fwrite(bufferPtr->data, 1, bufferPtr->length, ctx->out) != bufferPtr->length || ferror(ctx->out)) { fprintf(stderr, "Unable to write data to file\n"); ret = -1; goto clean_bio; } if (fwrite("\n", 1, 1, ctx->out) != 1 || ferror(ctx->out)) { fprintf(stderr, "Unable to write data to file\n"); ret = -1; } clean_bio: BIO_free_all(bio); return ret; } static void time_elapsed(struct timeval *after, struct timeval *before, struct timeval *result) { result->tv_sec = after->tv_sec - before->tv_sec; result->tv_usec = after->tv_usec - before->tv_usec; if (result->tv_usec < 0) { result->tv_sec--; result->tv_usec += 1000000; } } static void time_add(struct timeval *a, struct timeval *b, struct timeval *result) { result->tv_sec = a->tv_sec + b->tv_sec; result->tv_usec = a->tv_usec + b->tv_usec; if (result->tv_usec >= 1000000) { result->tv_sec++; result->tv_usec -= 1000000; } } static void time_average(struct timeval *in, size_t num, struct timeval *result) { time_t remains = in->tv_sec % num; result->tv_sec = in->tv_sec / num; result->tv_usec = in->tv_usec / num; if (remains) { remains *= 1000000; result->tv_usec += remains / num; } } static double time_tps(struct timeval *in, size_t num) { double time = in->tv_sec + (double) in->tv_usec / 1000000; return num / time; } static bool time_less(struct timeval *a, struct timeval *b) { if (a->tv_sec < b->tv_sec) { return true; } else if (a->tv_sec == b->tv_sec && a->tv_usec < b->tv_usec) { return true; } else { return false; } } static int compare_algorithm(const void *a, const void *b) { return (*(const yh_algorithm *) a - *(const yh_algorithm *) b); } static yh_algorithm *algorithm_search(yh_algorithm key, const yh_algorithm *arr, size_t count) { return bsearch(&key, arr, count, sizeof(key), compare_algorithm); } // NOTE: Run a set of benchmarks // argc = 3 // arg 0: e:session // arg 1: d:count // arg 2: w:key_id // arg 3: a:algorithm int yh_com_benchmark(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(ctx); UNUSED(in_fmt); UNUSED(fmt); struct { yh_algorithm algo; yh_algorithm algo2; uint16_t bytes; const char *special; } benchmarks[] = { {YH_ALGO_RSA_2048, YH_ALGO_RSA_PKCS1_SHA256, 32, ""}, {YH_ALGO_RSA_3072, YH_ALGO_RSA_PKCS1_SHA384, 48, ""}, {YH_ALGO_RSA_4096, YH_ALGO_RSA_PKCS1_SHA512, 64, ""}, {YH_ALGO_RSA_2048, YH_ALGO_RSA_PSS_SHA256, 32, ""}, {YH_ALGO_RSA_3072, YH_ALGO_RSA_PSS_SHA384, 48, ""}, {YH_ALGO_RSA_4096, YH_ALGO_RSA_PSS_SHA512, 64, ""}, {YH_ALGO_EC_P224, YH_ALGO_EC_ECDSA_SHA1, 20, ""}, {YH_ALGO_EC_P256, YH_ALGO_EC_ECDSA_SHA256, 32, ""}, {YH_ALGO_EC_P384, YH_ALGO_EC_ECDSA_SHA384, 48, ""}, {YH_ALGO_EC_P521, YH_ALGO_EC_ECDSA_SHA512, 66, ""}, {YH_ALGO_EC_K256, YH_ALGO_EC_ECDSA_SHA256, 32, ""}, {YH_ALGO_EC_BP256, YH_ALGO_EC_ECDSA_SHA256, 32, ""}, {YH_ALGO_EC_BP384, YH_ALGO_EC_ECDSA_SHA384, 48, ""}, {YH_ALGO_EC_BP512, YH_ALGO_EC_ECDSA_SHA512, 64, ""}, {YH_ALGO_EC_P224, YH_ALGO_EC_ECDH, 56, ""}, {YH_ALGO_EC_P256, YH_ALGO_EC_ECDH, 64, ""}, {YH_ALGO_EC_P384, YH_ALGO_EC_ECDH, 96, ""}, {YH_ALGO_EC_P521, YH_ALGO_EC_ECDH, 132, ""}, {YH_ALGO_EC_K256, YH_ALGO_EC_ECDH, 64, ""}, {YH_ALGO_EC_BP256, YH_ALGO_EC_ECDH, 64, ""}, {YH_ALGO_EC_BP384, YH_ALGO_EC_ECDH, 96, ""}, {YH_ALGO_EC_BP512, YH_ALGO_EC_ECDH, 128, ""}, {YH_ALGO_EC_ED25519, 0, 32, "32 bytes data"}, {YH_ALGO_EC_ED25519, 0, 64, "64 bytes data"}, {YH_ALGO_EC_ED25519, 0, 128, "128 bytes data"}, {YH_ALGO_EC_ED25519, 0, 256, "256 bytes data"}, {YH_ALGO_EC_ED25519, 0, 512, "512 bytes data"}, {YH_ALGO_EC_ED25519, 0, 1024, "1024 bytes data"}, {YH_ALGO_HMAC_SHA1, 0, 64, ""}, {YH_ALGO_HMAC_SHA256, 0, 64, ""}, {YH_ALGO_HMAC_SHA384, 0, 128, ""}, {YH_ALGO_HMAC_SHA512, 0, 128, ""}, {YH_ALGO_AES128_CCM_WRAP, 0, 0, ""}, {YH_ALGO_AES192_CCM_WRAP, 0, 0, ""}, {YH_ALGO_AES256_CCM_WRAP, 0, 0, ""}, {YH_ALGO_AES128_CCM_WRAP, 0, 128, "1024 bytes data"}, {YH_ALGO_AES192_CCM_WRAP, 0, 128, "1024 bytes data"}, {YH_ALGO_AES256_CCM_WRAP, 0, 128, "1024 bytes data"}, {YH_ALGO_AES128_YUBICO_OTP, 0, 0, ""}, {YH_ALGO_AES192_YUBICO_OTP, 0, 0, ""}, {YH_ALGO_AES256_YUBICO_OTP, 0, 0, ""}, {YH_ALGO_AES128, YH_ALGO_AES_ECB, 128, ""}, {YH_ALGO_AES192, YH_ALGO_AES_ECB, 128, ""}, {YH_ALGO_AES256, YH_ALGO_AES_ECB, 128, ""}, {YH_ALGO_AES128, YH_ALGO_AES_CBC, 128, ""}, {YH_ALGO_AES192, YH_ALGO_AES_CBC, 128, ""}, {YH_ALGO_AES256, YH_ALGO_AES_CBC, 128, ""}, {0, 0, 8, "Random 8 bytes"}, {0, 0, 16, "Random 16 bytes"}, {0, 0, 32, "Random 32 bytes"}, {0, 0, 64, "Random 64 bytes"}, {0, 0, 128, "Random 128 bytes"}, {0, 0, 256, "Random 256 bytes"}, {0, 0, 512, "Random 512 bytes"}, {0, 0, 1024, "Random 1024 bytes"}, {YH_ALGO_AES128_YUBICO_AUTHENTICATION, 0, 0, ""}, {YH_ALGO_EC_P256_YUBICO_AUTHENTICATION, 0, 0, ""}, }; // this is some data for the OTP benchmark const uint8_t otp_key[] = "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"; const uint8_t otp_id[] = "\x01\x02\x03\x04\x05\x06"; const uint8_t otp[] = "\x2f\x5d\x71\xa4\x91\x5d\xec\x30\x4a\xa1\x3c\xcf\x97\xbb\x0d\xbb"; const uint8_t password[] = "benchmark"; if (argv[1].d == 0) { fprintf(stderr, "Benchmark with 0 rounds seems pointless\n"); return -1; } yh_algorithm algorithms[YH_MAX_ALGORITHM_COUNT]; size_t n_algorithms = sizeof(algorithms) / sizeof(algorithms[0]); if (yh_util_get_device_info(ctx->connector, NULL, NULL, NULL, NULL, NULL, NULL, algorithms, &n_algorithms) != YHR_SUCCESS) { fprintf(stderr, "Could not fetch supported algorithms\n"); return -1; } for (size_t i = 0; i < sizeof(benchmarks) / sizeof(benchmarks[0]); i++) { struct timeval total = {0, 0}; struct timeval avg = {0, 0}; struct timeval max = {0, 0}; struct timeval min = {0, 0}; yh_capabilities capabilities = {{0}}; yh_rc yrc = YHR_SUCCESS; uint8_t algo_data[1024] = {0}; size_t algo_len = sizeof(algo_data); const char *str1 = NULL, *str2 = "", *str3 = ""; uint16_t id = argv[2].w; char label[YH_OBJ_LABEL_LEN + 1] = {0}; uint8_t sk_oce[YH_EC_P256_PRIVKEY_LEN], pk_oce[YH_EC_P256_PUBKEY_LEN], pk_sd[YH_EC_P256_PUBKEY_LEN]; size_t pk_sd_len = sizeof(pk_sd); yh_object_type type = 0; #ifndef _WIN32 size_t chars = 0; #endif if (argv[3].a != 0) { if (argv[3].a != benchmarks[i].algo && argv[3].a != benchmarks[i].algo2) { continue; } } if (benchmarks[i].algo) { yh_algo_to_string(benchmarks[i].algo, &str1); } if (benchmarks[i].algo2) { str2 = " "; yh_algo_to_string(benchmarks[i].algo2, &str3); } if (str1) { snprintf(label, YH_OBJ_LABEL_LEN, "Benchmark: %s%s%s", str1, str2, str3); } if ((benchmarks[i].algo && !algorithm_search(benchmarks[i].algo, algorithms, n_algorithms)) || (benchmarks[i].algo2 && !algorithm_search(benchmarks[i].algo2, algorithms, n_algorithms))) { fprintf(stderr, "%s%s%s skipped (disabled or unsupported)\n", str1, str2, str3); continue; } if (str1) { #ifndef _WIN32 chars = #endif fprintf(stderr, "Doing benchmark setup for %s%s%s...", str1, str2, str3); } if (yh_is_rsa(benchmarks[i].algo)) { if (benchmarks[i].algo2 == YH_ALGO_RSA_PKCS1_SHA256 || benchmarks[i].algo2 == YH_ALGO_RSA_PKCS1_SHA384 || benchmarks[i].algo2 == YH_ALGO_RSA_PKCS1_SHA512) { yh_string_to_capabilities("sign-pkcs", &capabilities); } else if (benchmarks[i].algo2 == YH_ALGO_RSA_PSS_SHA256 || benchmarks[i].algo2 == YH_ALGO_RSA_PSS_SHA384 || benchmarks[i].algo2 == YH_ALGO_RSA_PSS_SHA512) { yh_string_to_capabilities("sign-pss", &capabilities); } else { fprintf(stderr, "Unknown benchmark algorithms\n"); return -1; } type = YH_ASYMMETRIC_KEY; yrc = yh_util_generate_rsa_key(argv[0].e, &id, label, 0xffff, &capabilities, benchmarks[i].algo); } else if (yh_is_ec(benchmarks[i].algo)) { if (benchmarks[i].algo2 == YH_ALGO_EC_ECDSA_SHA1 || benchmarks[i].algo2 == YH_ALGO_EC_ECDSA_SHA256 || benchmarks[i].algo2 == YH_ALGO_EC_ECDSA_SHA384 || benchmarks[i].algo2 == YH_ALGO_EC_ECDSA_SHA512) { yh_string_to_capabilities("sign-ecdsa", &capabilities); } else if (benchmarks[i].algo2 == YH_ALGO_EC_ECDH) { yh_string_to_capabilities("derive-ecdh", &capabilities); yrc = yh_util_generate_ec_key(argv[0].e, &id, label, 0xffff, &capabilities, benchmarks[i].algo); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed ECDH setup\n"); return -1; } algo_len--; yrc = yh_util_get_public_key_ex(argv[0].e, YH_ASYMMETRIC_KEY, id, algo_data + 1, &algo_len, NULL); if (yrc != YHR_SUCCESS || algo_len != benchmarks[i].bytes) { fprintf(stderr, "Failed to get ECDH pubkey (%zu)\n", algo_len); return -1; } algo_data[0] = 0x04; // this is a hack to make it look correct.. algo_len++; yrc = yh_util_delete_object(argv[0].e, id, YH_ASYMMETRIC_KEY); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed deleting temporary ec key\n"); return -1; } } else { fprintf(stderr, "Unknown benchmark algorithms\n"); return -1; } type = YH_ASYMMETRIC_KEY; yrc = yh_util_generate_ec_key(argv[0].e, &id, label, 0xffff, &capabilities, benchmarks[i].algo); } else if (benchmarks[i].algo == YH_ALGO_EC_ED25519) { yh_string_to_capabilities("sign-eddsa", &capabilities); type = YH_ASYMMETRIC_KEY; yrc = yh_util_generate_ed_key(argv[0].e, &id, label, 0xffff, &capabilities, benchmarks[i].algo); str2 = " "; str3 = benchmarks[i].special; } else if (yh_is_hmac(benchmarks[i].algo)) { type = YH_HMAC_KEY; yh_string_to_capabilities("sign-hmac", &capabilities); yrc = yh_util_generate_hmac_key(argv[0].e, &id, label, 0xffff, &capabilities, benchmarks[i].algo); } else if (benchmarks[i].algo == YH_ALGO_AES128_CCM_WRAP || benchmarks[i].algo == YH_ALGO_AES192_CCM_WRAP || benchmarks[i].algo == YH_ALGO_AES256_CCM_WRAP) { type = YH_WRAP_KEY; yh_string_to_capabilities( "export-wrapped,exportable-under-wrap,wrap-data", &capabilities); yrc = yh_util_generate_wrap_key(argv[0].e, &id, label, 0xffff, &capabilities, benchmarks[i].algo, &capabilities); if (benchmarks[i].bytes > 0) { str2 = " "; str3 = benchmarks[i].special; } } else if (benchmarks[i].algo == YH_ALGO_AES128_YUBICO_OTP || benchmarks[i].algo == YH_ALGO_AES192_YUBICO_OTP || benchmarks[i].algo == YH_ALGO_AES256_YUBICO_OTP) { type = YH_OTP_AEAD_KEY; yh_string_to_capabilities("decrypt-otp,create-otp-aead", &capabilities); yrc = yh_util_generate_otp_aead_key(argv[0].e, &id, label, 0xffff, &capabilities, benchmarks[i].algo, 0x12345678); if (yrc == YHR_SUCCESS) { yrc = yh_util_create_otp_aead(argv[0].e, id, otp_key, otp_id, algo_data, &algo_len); } } else if (yh_is_aes(benchmarks[i].algo)) { type = YH_SYMMETRIC_KEY; yh_string_to_capabilities( "decrypt-ecb,encrypt-ecb,decrypt-cbc,encrypt-cbc", &capabilities); yrc = yh_util_generate_aes_key(argv[0].e, &id, label, 0xffff, &capabilities, benchmarks[i].algo); } else if (strncmp(benchmarks[i].special, "Random ", 7) == 0) { str1 = benchmarks[i].special; } else if (benchmarks[i].algo == YH_ALGO_AES128_YUBICO_AUTHENTICATION) { type = YH_AUTHENTICATION_KEY; yh_string_to_capabilities("", &capabilities); yrc = yh_util_import_authentication_key_derived(argv[0].e, &id, label, 0xffff, &capabilities, &capabilities, password, sizeof(password) - 1); } else if (benchmarks[i].algo == YH_ALGO_EC_P256_YUBICO_AUTHENTICATION) { type = YH_AUTHENTICATION_KEY; yh_string_to_capabilities("", &capabilities); yrc = yh_util_generate_ec_p256_key(sk_oce, sizeof(sk_oce), pk_oce, sizeof(pk_oce)); if (yrc == YHR_SUCCESS) { yrc = yh_util_import_authentication_key(argv[0].e, &id, label, 0xffff, &capabilities, &capabilities, pk_oce + 1, sizeof(pk_oce) - 1, NULL, 0); if (yrc == YHR_SUCCESS) { pk_sd_len = sizeof(pk_sd); yrc = yh_util_get_device_pubkey(ctx->connector, pk_sd, &pk_sd_len, NULL); } } } else { fprintf(stderr, "Unknown benchmark algorithms\n"); return -1; } if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed benchmark setup for %s%s%s\n", str1, str2, str3); return -1; } memset(&min, 0x7f, sizeof(min)); for (uint32_t j = 0; j < argv[1].d; j++) { uint8_t data[1024]; uint8_t out[1024]; size_t out_len = sizeof(out); struct timeval before, after, result; memset(data, j, sizeof(data)); gettimeofday(&before, NULL); if (yh_is_rsa(benchmarks[i].algo) && (benchmarks[i].algo2 == YH_ALGO_RSA_PKCS1_SHA256 || benchmarks[i].algo2 == YH_ALGO_RSA_PKCS1_SHA384 || benchmarks[i].algo2 == YH_ALGO_RSA_PKCS1_SHA512)) { yrc = yh_util_sign_pkcs1v1_5(argv[0].e, id, true, data, benchmarks[i].bytes, out, &out_len); } else if (yh_is_rsa(benchmarks[i].algo) && (benchmarks[i].algo2 == YH_ALGO_RSA_PSS_SHA256 || benchmarks[i].algo2 == YH_ALGO_RSA_PSS_SHA384 || benchmarks[i].algo2 == YH_ALGO_RSA_PSS_SHA512)) { yrc = yh_util_sign_pss(argv[0].e, id, data, benchmarks[i].bytes, out, &out_len, benchmarks[i].bytes, YH_ALGO_MGF1_SHA1); } else if (yh_is_ec(benchmarks[i].algo) && (benchmarks[i].algo2 == YH_ALGO_EC_ECDSA_SHA1 || benchmarks[i].algo2 == YH_ALGO_EC_ECDSA_SHA256 || benchmarks[i].algo2 == YH_ALGO_EC_ECDSA_SHA384 || benchmarks[i].algo2 == YH_ALGO_EC_ECDSA_SHA512)) { yrc = yh_util_sign_ecdsa(argv[0].e, id, data, benchmarks[i].bytes, out, &out_len); } else if (yh_is_ec(benchmarks[i].algo) && benchmarks[i].algo2 == YH_ALGO_EC_ECDH) { yrc = yh_util_derive_ecdh(argv[0].e, id, algo_data, algo_len, out, &out_len); } else if (benchmarks[i].algo == YH_ALGO_EC_ED25519) { yrc = yh_util_sign_eddsa(argv[0].e, id, data, benchmarks[i].bytes, out, &out_len); } else if (yh_is_hmac(benchmarks[i].algo)) { yrc = yh_util_sign_hmac(argv[0].e, id, data, benchmarks[i].bytes, out, &out_len); } else if (benchmarks[i].bytes > 0 && (benchmarks[i].algo == YH_ALGO_AES128_CCM_WRAP || benchmarks[i].algo == YH_ALGO_AES192_CCM_WRAP || benchmarks[i].algo == YH_ALGO_AES256_CCM_WRAP)) { yrc = yh_util_wrap_data(argv[0].e, id, data, benchmarks[i].bytes, out, &out_len); } else if (benchmarks[i].algo == YH_ALGO_AES128_CCM_WRAP || benchmarks[i].algo == YH_ALGO_AES192_CCM_WRAP || benchmarks[i].algo == YH_ALGO_AES256_CCM_WRAP) { yrc = yh_util_export_wrapped(argv[0].e, id, YH_WRAP_KEY, id, out, &out_len); } else if (benchmarks[i].algo == YH_ALGO_AES128_YUBICO_OTP || benchmarks[i].algo == YH_ALGO_AES192_YUBICO_OTP || benchmarks[i].algo == YH_ALGO_AES256_YUBICO_OTP) { yrc = yh_util_decrypt_otp(argv[0].e, id, algo_data, algo_len, otp, NULL, NULL, NULL, NULL); } else if (yh_is_aes(benchmarks[i].algo)) { if (benchmarks[i].algo2 == YH_ALGO_AES_ECB) { yrc = yh_util_encrypt_aes_ecb(argv[0].e, id, data, benchmarks[i].bytes, out, &out_len); } else if (benchmarks[i].algo2 == YH_ALGO_AES_CBC) { yrc = yh_util_encrypt_aes_cbc(argv[0].e, id, data, data, benchmarks[i].bytes, out, &out_len); } else { fprintf(stderr, "Unknown benchmark algorithms\n"); return -1; } } else if (strncmp(benchmarks[i].special, "Random ", 7) == 0) { yrc = yh_util_get_pseudo_random(argv[0].e, benchmarks[i].bytes, out, &out_len); } else if (benchmarks[i].algo == YH_ALGO_AES128_YUBICO_AUTHENTICATION) { yh_session *ses = NULL; yrc = yh_create_session_derived(ctx->connector, id, password, sizeof(password) - 1, false, &ses); if (yrc == YHR_SUCCESS) { yrc = yh_util_close_session(ses); } } else if (benchmarks[i].algo == YH_ALGO_EC_P256_YUBICO_AUTHENTICATION) { yh_session *ses = NULL; yrc = yh_create_session_asym(ctx->connector, id, sk_oce, sizeof(sk_oce), pk_sd, pk_sd_len, &ses); if (yrc == YHR_SUCCESS) { yrc = yh_util_close_session(ses); } } else { fprintf(stderr, "Unknown benchmark algorithm\n"); return -1; } gettimeofday(&after, NULL); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed running benchmark %u for %s%s%s\n", j, str1, str2, str3); return -1; } time_elapsed(&after, &before, &result); if (time_less(&result, &min)) { min = result; } if (time_less(&max, &result)) { max = result; } time_add(&result, &total, &total); time_average(&total, j + 1, &avg); #ifndef _WIN32 struct winsize w; ioctl(fileno(stderr), TIOCGWINSZ, &w); if (chars > w.ws_col) { // move the cursor up and to column 1 fprintf(stderr, "\33[%zuF", chars / w.ws_col); } else { // if we're still on same line, just move to column 1 fprintf(stderr, "\33[1G"); } // clear display from cursor fprintf(stderr, "\33[J"); chars = fprintf(stderr, "%s%s%s (%u/%d times) total: %lld.%06ld avg: %lld.%06ld " "min: %lld.%06ld max: %lld.%06ld tps: %.06f", str1, str2, str3, j + 1, argv[1].w, (long long) total.tv_sec, (long) total.tv_usec, (long long) avg.tv_sec, (long) avg.tv_usec, (long long) min.tv_sec, (long) min.tv_usec, (long long) max.tv_sec, (long) max.tv_usec, time_tps(&total, j + 1)); fflush(stderr); #endif } #ifdef _WIN32 fprintf(stderr, "%s%s%s (%d times) total: %lld.%06ld avg: %lld.%06ld " "min: %lld.%06ld max: %lld.%06ld tps: %.06f", str1, str2, str3, argv[1].w, (long long) total.tv_sec, (long) total.tv_usec, (long long) avg.tv_sec, (long) avg.tv_usec, (long long) min.tv_sec, (long) min.tv_usec, (long long) max.tv_sec, (long) max.tv_usec, time_tps(&total, argv[1].w)); #endif fprintf(stderr, "\n"); if (type != 0) { yh_util_delete_object(argv[0].e, id, type); } } return 0; } // NOTE: create aead from OTP parameters // argc = 5 // arg 0: e:session // arg 1: w:key_id // arg 2: x:key // arg 3: x:private_id // arg 4: f:aead int yh_com_otp_aead_create(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(in_fmt); uint8_t response[YH_MSG_BUF_SIZE] = {0}; size_t response_len = sizeof(response); if (argv[2].len != 16) { fprintf(stderr, "Wrong length key supplied, has to be 16 bytes\n"); return -1; } if (argv[3].len != 6) { fprintf(stderr, "Wrong length id supplied, has to be 6 bytes\n"); return -1; } yh_rc yrc = yh_util_create_otp_aead(argv[0].e, argv[1].w, argv[2].x, argv[3].x, response, &response_len); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to create OTP AEAD: %s\n", yh_strerror(yrc)); return -1; } if (write_file(response, response_len, ctx->out, fmt_to_fmt(fmt))) { return 0; } return -1; } // NOTE: create aead from OTP parameters // argc = 3 // arg 0: e:session // arg 1: w:key_id // arg 2: f:aead int yh_com_otp_aead_random(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(in_fmt); uint8_t response[YH_MSG_BUF_SIZE] = {0}; size_t response_len = sizeof(response); yh_rc yrc = yh_util_randomize_otp_aead(argv[0].e, argv[1].w, response, &response_len); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to create OTP AEAD: %s\n", yh_strerror(yrc)); return -1; } if (write_file(response, response_len, ctx->out, fmt_to_fmt(fmt))) { return 0; } return -1; } // NOTE: decrypt OTP with AEAD // argc = 4 // arg 0: e:session // arg 1: w:key_id // arg 2: s:otp // arg 3: i:aead int yh_com_otp_decrypt(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(ctx); UNUSED(in_fmt); UNUSED(fmt); if (argv[2].len != 32) { fprintf(stderr, "Wrong length OTP supplied, has to be 16 bytes in hex\n"); return -1; } uint8_t otp[16] = {0}; size_t otp_len = sizeof(otp); if (hex_decode(argv[2].s, otp, &otp_len) == false) { fprintf(stderr, "Failed to decode OTP\n"); return -1; } uint16_t useCtr = 0; uint8_t sessionCtr = 0; uint8_t tstph = 0; uint16_t tstpl = 0; yh_rc yrc = yh_util_decrypt_otp(argv[0].e, argv[1].w, argv[3].x, argv[3].len, otp, &useCtr, &sessionCtr, &tstph, &tstpl); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to decrypt OTP: %s\n", yh_strerror(yrc)); return -1; } fprintf(stderr, "OTP decoded, useCtr:%d, sessionCtr:%d, tstph:%d, tstpl:%d\n", useCtr, sessionCtr, tstph, tstpl); return 0; } // NOTE: rewrap OTP AEAD to a different key // argc = 5 // arg 0: e:session // arg 1: w:id_from // arg 2: w:id_to // arg 3: i:aead_in // arg 4: F:aead_out int yh_com_otp_rewrap(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { uint8_t response[YH_MSG_BUF_SIZE] = {0}; size_t response_len = sizeof(response); UNUSED(ctx); UNUSED(in_fmt); yh_rc yrc = yh_util_rewrap_otp_aead(argv[0].e, argv[1].w, argv[2].w, argv[3].x, argv[3].len, response, &response_len); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to rewrap OTP AEAD: %s\n", yh_strerror(yrc)); return -1; } if (write_file(response, response_len, ctx->out, fmt_to_fmt(fmt))) { return 0; } return -1; } // NOTE: decrypt OTP with AEAD // argc = 3 // arg 0: e:session // arg 1: w:key_id // arg 2: 2:attest_id int yh_com_sign_attestation_certificate(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(in_fmt); uint8_t data[YH_MSG_BUF_SIZE] = {0}; size_t data_len = sizeof(data); int ret = -1; yh_rc yrc = yh_util_sign_attestation_certificate(argv[0].e, argv[1].w, argv[2].w, data, &data_len); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to attest asymmetric key: %s\n", yh_strerror(yrc)); yh_object_descriptor desc = {0}; yrc = yh_util_get_object_info(argv[0].e, argv[1].w, YH_OPAQUE, &desc); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to get object info: %s\n", yh_strerror(yrc)); return -1; } if (desc.algorithm != YH_ALGO_OPAQUE_X509_CERTIFICATE) { fprintf(stderr, "Certificate template is not stored as a certificate\n"); } else if (is_compressed(argv[0].e, argv[1].w, YH_ALGO_OPAQUE_X509_CERTIFICATE)) { fprintf(stderr, "Stored X509 certificated used as template is a compressed " "certificate. Compressed X509 certificates cannot be used as " "template for attestation. Try to re-import it without " "compression\n"); } return -1; } const unsigned char *ptr = data; X509 *x509 = d2i_X509(NULL, &ptr, data_len); if (!x509) { fprintf(stderr, "Failed parsing x509 information\n"); } else { if (fmt == fmt_base64 || fmt == fmt_PEM) { if (PEM_write_X509(ctx->out, x509) == 1) { ret = 0; } else { fprintf(stderr, "Failed writing x509 information\n"); } } else if (fmt == fmt_binary) { if (i2d_X509_fp(ctx->out, x509) == 1) { ret = 0; } else { fprintf(stderr, "Failed writing x509 information\n"); } } } X509_free(x509); return ret; } // NOTE: put OTP AEAD key // argc = 7 // arg 0: e:session // arg 1: w:key_id // arg 2: s:label // arg 3: w:domains // arg 4: c:capabilities // arg 5: d:nonce_id // arg 6: x:key int yh_com_put_otp_aead_key(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(ctx); UNUSED(in_fmt); UNUSED(fmt); if (argv[6].len != 16 && argv[6].len != 24 && argv[6].len != 32) { fprintf(stderr, "Key length (%zu) not matching, should be 16, 24 or 32\n", argv[6].len); return -1; } yh_rc yrc = yh_util_import_otp_aead_key(argv[0].e, &argv[1].w, argv[2].s, argv[3].w, &argv[4].c, argv[5].d, argv[6].x, argv[6].len); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to store OTP AEAD key: %s\n", yh_strerror(yrc)); return -1; } fprintf(stderr, "Stored OTP AEAD key 0x%04x\n", argv[1].w); return 0; } // NOTE: generate OTP AEAD key // argc = 7 // arg 0: e:session // arg 1: w:key_id // arg 2: s:label // arg 3: w:domains // arg 4: c:capabilities // arg 5: a:algorithm // arg 6: d:nonce_id int yh_com_generate_otp_aead_key(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(ctx); UNUSED(in_fmt); UNUSED(fmt); yh_rc yrc = yh_util_generate_otp_aead_key(argv[0].e, &argv[1].w, argv[2].s, argv[3].w, &argv[4].c, argv[5].a, argv[6].d); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to generate OTP AEAD key: %s\n", yh_strerror(yrc)); return -1; } fprintf(stderr, "Generated OTP AEAD key 0x%04x\n", argv[1].w); return 0; } // NOTE(adma): Decrypt data using RSAES-OAEP // argc = 5 // arg 0: e:session // arg 1: w:key_id // arg 2: a:algorithm // arg 3: f:datafile // arg 4: s:label int yh_com_decrypt_oaep(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(in_fmt); int hash = 0; yh_algorithm mgf = 0; switch (argv[2].a) { case YH_ALGO_RSA_OAEP_SHA1: hash = _SHA1; mgf = YH_ALGO_MGF1_SHA1; break; case YH_ALGO_RSA_OAEP_SHA256: hash = _SHA256; mgf = YH_ALGO_MGF1_SHA256; break; case YH_ALGO_RSA_OAEP_SHA384: hash = _SHA384; mgf = YH_ALGO_MGF1_SHA384; break; case YH_ALGO_RSA_OAEP_SHA512: hash = _SHA512; mgf = YH_ALGO_MGF1_SHA512; break; default: fprintf(stderr, "Invalid hash algorithm\n"); return -1; } uint8_t label[64] = {0}; size_t label_len = sizeof(label); if (hash_bytes((const uint8_t *) argv[4].s, argv[4].len, hash, label, &label_len) == false) { fprintf(stderr, "Unable to hash data\n"); return -1; } uint8_t response[YH_MSG_BUF_SIZE] = {0}; size_t response_len = sizeof(response); yh_rc yrc = yh_util_decrypt_oaep(argv[0].e, argv[1].w, argv[3].x, argv[3].len, response, &response_len, label, label_len, mgf); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to decrypt data with OAEP: %s\n", yh_strerror(yrc)); return -1; } write_file(response, response_len, ctx->out, fmt_to_fmt(fmt)); return 0; } // NOTE: Set ca cert for https validation // argc = 1 // arg 0: s:filename int yh_com_set_cacert(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(in_fmt); UNUSED(fmt); if (ctx->cacert) { free(ctx->cacert); } ctx->cacert = strdup(argv[0].s); return 0; } // NOTE: Set https client cert // argc = 1 // arg 0: s:filename int yh_com_set_cert(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(in_fmt); UNUSED(fmt); if (ctx->cert) { free(ctx->cert); } ctx->cert = strdup(argv[0].s); return 0; } // NOTE: Set https client key // argc = 1 // arg 0: s:filename int yh_com_set_key(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(in_fmt); UNUSED(fmt); if (ctx->key) { free(ctx->key); } ctx->key = strdup(argv[0].s); return 0; } // NOTE: Set proxy server to use for connector // argc = 1 // arg 0: s:proxy int yh_com_set_proxy(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(in_fmt); UNUSED(fmt); if (ctx->proxy) { free(ctx->proxy); } ctx->proxy = strdup(argv[0].s); return 0; } // NOTE: Set noproxy list to use for connector // argc = 1 // arg 0: s:proxy int yh_com_set_noproxy(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(in_fmt); UNUSED(fmt); if (ctx->noproxy) { free(ctx->noproxy); } ctx->noproxy = strdup(argv[0].s); return 0; } // NOTE: Change authentication key // argc = 3 // arg 0: e:session // arg 1: w:key_id // arg 2: i:password int yh_com_change_authentication_key(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(in_fmt); UNUSED(fmt); UNUSED(ctx); yh_rc yrc = yh_util_change_authentication_key_derived(argv[0].e, &argv[1].w, argv[2].x, argv[2].len); insecure_memzero(argv[2].x, argv[2].len); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to change authentication key: %s\n", yh_strerror(yrc)); return -1; } fprintf(stderr, "Changed Authentication key 0x%04x\n", argv[1].w); return 0; } // NOTE: Change asymmetric authentication key // argc = 3 // arg 0: e:session // arg 1: w:key_id // arg 2: i:password int yh_com_change_authentication_key_asym(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(fmt); UNUSED(ctx); uint8_t pubkey[YH_EC_P256_PUBKEY_LEN] = {0}; yh_rc yrc = YHR_SUCCESS; if (in_fmt == fmt_password) { uint8_t privkey[YH_EC_P256_PRIVKEY_LEN]; yrc = yh_util_derive_ec_p256_key(argv[2].x, argv[2].len, privkey, sizeof(privkey), pubkey, sizeof(pubkey)); insecure_memzero(argv[2].x, argv[2].len); insecure_memzero(privkey, sizeof(privkey)); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to derive asymmetric authentication key: %s\n", yh_strerror(yrc)); return -1; } fprintf(stderr, "Derived public key (PK.OCE)\n"); for (size_t i = 0; i < sizeof(pubkey); i++) fprintf(stderr, "%02x", pubkey[i]); fprintf(stderr, "\n"); } else if (in_fmt == fmt_PEM) { yh_algorithm algo = 0; size_t pubkey_len = sizeof(pubkey); if (!read_public_key(argv[2].x, argv[2].len, &algo, pubkey, &pubkey_len)) { fprintf(stderr, "Failed to load public key\n"); return -1; } if (pubkey_len != sizeof(pubkey)) { fprintf(stderr, "Invalid public key\n"); return -1; } } else if (argv[2].len <= sizeof(pubkey)) { memset(pubkey, 0, sizeof(pubkey) - argv[2].len); memcpy(pubkey + sizeof(pubkey) - argv[2].len, argv[2].x, argv[2].len); } else { fprintf(stderr, "Invalid asymmetric authkey: %s\n", yh_strerror(YHR_INVALID_PARAMETERS)); return -1; } yrc = yh_util_change_authentication_key(argv[0].e, &argv[1].w, pubkey + 1, sizeof(pubkey) - 1, NULL, 0); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to change asymmetric authentication key: %s\n", yh_strerror(yrc)); return -1; } fprintf(stderr, "Changed Asymmetric Authentication key 0x%04x\n", argv[1].w); return 0; } // NOTE: Generate a Certificate Signing Request // argc = 3 // arg 0: e:session // arg 1: w:key_id // arg 2: s:subject // arg 3: f:out_filename int yh_com_generate_csr(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { #if !(OPENSSL_VERSION_NUMBER >= 0x10100000L) fprintf(stderr, "Generating CSR is only supported with OpenSSL 3.0 or higher\n"); return -1; #endif UNUSED(in_fmt); X509_REQ *req = NULL; X509_NAME *name = NULL; EVP_PKEY *public_key = NULL; const EVP_MD *md = NULL; yh_algorithm algorithm; uint8_t response[YH_MSG_BUF_SIZE] = {0}; size_t response_len = sizeof(response); yh_rc yrc = yh_util_get_public_key(argv[0].e, argv[1].w, response, &response_len, &algorithm); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to get public key: %s\n", yh_strerror(yrc)); return -1; } if (!get_pubkey_evp(response, response_len, algorithm, &public_key)) { fprintf(stderr, "Failed to encode public key\n"); return -1; } req = X509_REQ_new(); if (!req) { fprintf(stderr, "Failed to allocate request structure.\n"); goto request_out; } if (algorithm != YH_ALGO_EC_ED25519) { md = EVP_sha256(); if (md == NULL) { goto request_out; } } if (!X509_REQ_set_pubkey(req, public_key)) { fprintf(stderr, "Failed setting the request public key.\n"); goto request_out; } if (X509_REQ_set_version(req, 0) != 1) { fprintf(stderr, "Failed setting the certificate request version.\n"); } name = parse_subject_name(argv[2].s); if (!name) { fprintf(stderr, "Failed encoding subject as name.\n"); goto request_out; } if (!X509_REQ_set_subject_name(req, name)) { fprintf(stderr, "Failed setting the request subject.\n"); goto request_out; } if (algorithm == YH_ALGO_EC_ED25519) { // Generate a dummy ED25519 to sign with OpenSSL EVP_PKEY *ed_key = NULL; EVP_PKEY_CTX *ed_ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_ED25519, NULL); EVP_PKEY_keygen_init(ed_ctx); EVP_PKEY_keygen(ed_ctx, &ed_key); EVP_PKEY_CTX_free(ed_ctx); // Sign the request object using the dummy key if (X509_REQ_sign(req, ed_key, md) == 0) { fprintf(stderr, "Failed signing certificate.\n"); ERR_print_errors_fp(stderr); EVP_PKEY_free(ed_key); goto request_out; } EVP_PKEY_free(ed_key); // Extract the request data without the signature unsigned char *tbs_data = NULL; int tbs_len = i2d_re_X509_REQ_tbs(req, &tbs_data); // Sign the request data using the YubiKey unsigned char yh_sig[64] = {0}; size_t yh_siglen = sizeof(yh_sig); yrc = yh_util_sign_eddsa(argv[0].e, argv[1].w, tbs_data, tbs_len, yh_sig, &yh_siglen); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed signing tbs request portion: %s\n", yh_strerror(yrc)); goto request_out; } // Replace the dummy signature with the signature from the yubikey ASN1_BIT_STRING *psig; const X509_ALGOR *palg; X509_REQ_get0_signature(req, (const ASN1_BIT_STRING **) &psig, &palg); ASN1_BIT_STRING_set(psig, yh_sig, yh_siglen); } else { /* With opaque structures we can not touch whatever we want, but we need * to embed the sign_data function in the RSA/EC key structures */ EVP_PKEY *sk = wrap_public_key(argv[0].e, algorithm, public_key, argv[1].w); if (X509_REQ_sign(req, sk, md) == 0) { fprintf(stderr, "Failed signing request.\n"); ERR_print_errors_fp(stderr); EVP_PKEY_free(sk); goto request_out; } EVP_PKEY_free(sk); } if (fmt == fmt_PEM) { if (PEM_write_X509_REQ(ctx->out, req) != 1) { fprintf(stderr, "Failed writing certificate request\n"); ERR_print_errors_fp(stderr); } } else { fprintf(stderr, "Only PEM support available for certificate requests.\n"); } request_out: EVP_PKEY_free(public_key); if (req != NULL) { X509_REQ_free(req); } if (name != NULL) { X509_NAME_free(name); } return 0; } yubihsm-shell-2.8.0/src/commands.h0000644000175100017510000002773415221003515016464 0ustar runnerrunner/* * Copyright 2015-2018 Yubico AB * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef COMMANDS_H #define COMMANDS_H #include #include "yubihsm.h" #include "yubihsm-shell.h" typedef struct { union { uint8_t b; uint16_t w; uint32_t d; const char *s; yh_session *e; yh_capabilities c; yh_algorithm a; yh_object_type t; yh_option o; }; uint8_t *x; size_t len; } Argument; typedef int CommandFunction(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_audit(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_set_log_index(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_close_session(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_connect(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_debug_all(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_debug_error(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_debug_info(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_debug_intermediate(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_debug_none(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_debug_raw(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_debug_crypto(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_decrypt_pkcs1v1_5(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_decrypt_oaep(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_derive_ecdh(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_decrypt_aesccm(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_encrypt_aesccm(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_decrypt_aes_ecb(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_encrypt_aes_ecb(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_decrypt_aes_cbc(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_encrypt_aes_cbc(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_disconnect(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_echo(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_echo(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_generate_symmetric(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_generate_asymmetric(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_generate_csr(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_generate_hmac(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_generate_wrap(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_generate_otp_aead_key(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_get_opaque(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_get_option(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_get_random(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_get_storage(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_get_pubkey(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_get_device_pubkey(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_get_object_info(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_get_wrapped(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_get_rsa_wrapped(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_get_rsa_wrapped_key(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_get_device_info(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_get_template(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_list_capabilities(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_list_algorithms(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_list_types(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_list_connectors(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_list_sessions(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_list_objects(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_open_session(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_open_session_asym(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_open_yksession(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_pecho(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_put_symmetric(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_put_asymmetric(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_put_authentication(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_put_authentication_asym(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_put_opaque(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_put_option(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_put_hmac(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_put_wrapkey(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_put_rsa_wrapkey(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_put_public_wrapkey(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_put_wrapped(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_put_rsa_wrapped(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_put_rsa_wrapped_key(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_put_template(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_put_otp_aead_key(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_sign_ecdsa(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_sign_eddsa(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_sign_pkcs1v1_5(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_sign_pss(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_hmac(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_reset(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_delete(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_sign_ssh_certificate(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_benchmark(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_otp_aead_create(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_otp_aead_random(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_otp_decrypt(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_otp_rewrap(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_sign_attestation_certificate(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_keepalive_on(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_keepalive_off(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_noop(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_blink(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_set_cacert(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_set_cert(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_set_key(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_set_proxy(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_set_noproxy(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_change_authentication_key(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_change_authentication_key_asym(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); #endif yubihsm-shell-2.8.0/src/yubihsm-shell.h0000644000175100017510000000317715221003515017443 0ustar runnerrunner/* * Copyright 2015-2018 Yubico AB * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef YUBIHSM_SHELL_H #define YUBIHSM_SHELL_H #include #include #include #include #define UNUSED(x) (void) (x) typedef enum { fmt_nofmt, fmt_base64, fmt_binary, fmt_hex, fmt_PEM, fmt_password, fmt_ASCII } cmd_format; static const struct { const char *name; cmd_format format; } formats[] = { {"default", fmt_nofmt}, {"base64", fmt_base64}, {"binary", fmt_binary}, {"hex", fmt_hex}, {"PEM", fmt_PEM}, {"password", fmt_password}, {"ASCII", fmt_ASCII}, }; typedef struct { uint8_t **device_pubkey_list; char **connector_list; yh_connector *connector; yh_session *sessions[256]; ykhsmauth_state *state; FILE *out; char *cacert; char *cert; char *key; char *proxy; char *noproxy; } yubihsm_context; int actions_run(struct gengetopt_args_info *args_info); int do_put_key(uint8_t *enc_key, uint8_t *mac_key, uint16_t key_id, uint16_t domains, uint32_t capabilities, yh_session *ses); #ifdef _MSC_VER #pragma strict_gs_check(on) #endif #endif yubihsm-shell-2.8.0/src/cmdline.c0000644000175100017510000023001615221003575016264 0ustar runnerrunner/* File autogenerated by gengetopt version 2.23 generated with the following command: gengetopt --conf-parser -i /home/runner/work/yubihsm-shell/yubihsm-shell/src/cmdline.ggo --output-dir /home/runner/work/yubihsm-shell/yubihsm-shell/src cmdline The developers of gengetopt consider the fixed text that goes in all gengetopt output files to be in the public domain: we make no copyright claims on it. */ /* If we use autoconf. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #ifndef FIX_UNUSED #define FIX_UNUSED(X) (void) (X) /* avoid warnings for unused params */ #endif #include #include "cmdline.h" const char *gengetopt_args_info_purpose = ""; const char *gengetopt_args_info_usage = "Usage: " CMDLINE_PARSER_PACKAGE " [OPTION]..."; const char *gengetopt_args_info_versiontext = ""; const char *gengetopt_args_info_description = ""; const char *gengetopt_args_info_help[] = { " -h, --help Print help and exit", " -V, --version Print version and exit", " -a, --action=ENUM Action to perform (possible\n values=\"benchmark\", \"blink-device\",\n \"create-otp-aead\", \"decrypt-aesccm\",\n \"decrypt-aescbc\", \"decrypt-aesecb\",\n \"decrypt-oaep\", \"decrypt-otp\",\n \"decrypt-pkcs1v15\", \"delete-object\",\n \"derive-ecdh\", \"encrypt-aesccm\",\n \"encrypt-aescbc\", \"encrypt-aesecb\",\n \"generate-asymmetric-key\",\n \"generate-csr\", \"generate-hmac-key\",\n \"generate-otp-aead-key\",\n \"generate-wrap-key\",\n \"generate-symmetric-key\",\n \"get-device-info\", \"get-logs\",\n \"get-object-info\", \"get-opaque\",\n \"get-option\", \"get-pseudo-random\",\n \"get-public-key\", \"get-storage-info\",\n \"get-template\", \"get-wrapped\",\n \"get-rsa-wrapped\", \"get-rsa-wrapped-key\",\n \"get-device-pubkey\", \"list-objects\",\n \"put-asymmetric-key\",\n \"put-authentication-key\", \"put-hmac-key\",\n \"put-opaque\", \"put-option\",\n \"put-otp-aead-key\", \"put-symmetric-key\",\n \"put-template\", \"put-wrap-key\",\n \"put-rsa-wrapkey\", \"put-public-wrapkey\",\n \"put-wrapped\", \"put-rsa-wrapped\",\n \"put-rsa-wrapped-key\",\n \"randomize-otp-aead\", \"reset\",\n \"set-log-index\",\n \"sign-attestation-certificate\",\n \"sign-ecdsa\", \"sign-eddsa\",\n \"sign-hmac\", \"sign-pkcs1v15\",\n \"sign-pss\", \"sign-ssh-certificate\")", " -p, --password=STRING Authentication password", " --authkey=SHORT Authentication key (default=`1')", " -i, --object-id=SHORT Object ID (default=`0')", " -l, --label=STRING Object label (default=`')", " -d, --domains=STRING Object domains\n (default=`1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16')", " -c, --capabilities=STRING Capabilities for an object (default=`0')", " -t, --object-type=STRING Object type (default=`any')", " -y, --ykhsmauth-label=STRING Credential label on YubiKey (implicitly enables\n ykhsmauth)", " -r, --ykhsmauth-reader=STRING Only use a matching YubiKey reader name\n (default=`')", " --delegated=STRING Delegated capabilities (default=`0')", " --new-password=STRING New authentication password", " -A, --algorithm=STRING Operation algorithm (default=`any')", " --oaep=STRING OAEP algorithm. Used primarily with asymmetric\n wrap (default=`rsa-oaep-sha256')", " --mgf1=STRING MGF1 algorithm. Used primarily with asymmetric\n wrap (default=`mgf1-sha256')", " --nonce=INT OTP nonce", " --iv=STRING An initialization vector as a hexadecimal\n string", " --count=INT Number of bytes to request (default=`256')", " --duration=INT Blink duration in seconds (default=`10')", " --wrap-id=SHORT Wrap key ID", " --include-seed Include seed when exporting an ED25519 key\n under wrap (default=off)", " --template-id=SHORT Template ID", " --attestation-id=SHORT Attestation ID", " --log-index=INT Log index", " --opt-name=STRING Device option name", " --opt-value=STRING Device option value", " --with-compression Compress a X509Certificate before importing it\n into the device or detect compressed\n certificates when listing objects\n (default=off)", " -S, --subject=STRING The subject to use for certificate request. The\n subject must be written as:\n /CN=host.example.com/OU=test/O=example.com/", " --in=STRING Input data (filename) (default=`-')", " --out=STRING Output data (filename) (default=`-')", " --informat=ENUM Input format (possible values=\"default\",\n \"base64\", \"binary\", \"PEM\",\n \"password\", \"hex\", \"ASCII\"\n default=`default')", " --outformat=ENUM Input and output format (possible\n values=\"default\", \"base64\", \"binary\",\n \"PEM\", \"hex\", \"ASCII\"\n default=`default')", " -f, --config-file=STRING Configuration file to read (default=`')", " -C, --connector=STRING List of connectors to use", " --cacert=STRING HTTPS cacert for connector", " --cert=STRING HTTPS client certificate to authenticate with", " --key=STRING HTTPS client certificate key", " --proxy=STRING Proxy server to use for connector", " --noproxy=STRING Comma separated list of hosts ignore proxy for", " -v, --verbose=INT Print more information (default=`0')", " -P, --pre-connect Connect immediately in interactive mode\n (default=off)", " --device-pubkey=STRING List of device public keys allowed for\n asymmetric authentication", 0 }; typedef enum {ARG_NO , ARG_FLAG , ARG_STRING , ARG_INT , ARG_SHORT , ARG_ENUM } cmdline_parser_arg_type; static void clear_given (struct gengetopt_args_info *args_info); static void clear_args (struct gengetopt_args_info *args_info); static int cmdline_parser_internal (int argc, char **argv, struct gengetopt_args_info *args_info, struct cmdline_parser_params *params, const char *additional_error); static int cmdline_parser_required2 (struct gengetopt_args_info *args_info, const char *prog_name, const char *additional_error); struct line_list { char * string_arg; struct line_list * next; }; static struct line_list *cmd_line_list = 0; static struct line_list *cmd_line_list_tmp = 0; static void free_cmd_list(void) { /* free the list of a previous call */ if (cmd_line_list) { while (cmd_line_list) { cmd_line_list_tmp = cmd_line_list; cmd_line_list = cmd_line_list->next; free (cmd_line_list_tmp->string_arg); free (cmd_line_list_tmp); } } } const char *cmdline_parser_action_values[] = {"benchmark", "blink-device", "create-otp-aead", "decrypt-aesccm", "decrypt-aescbc", "decrypt-aesecb", "decrypt-oaep", "decrypt-otp", "decrypt-pkcs1v15", "delete-object", "derive-ecdh", "encrypt-aesccm", "encrypt-aescbc", "encrypt-aesecb", "generate-asymmetric-key", "generate-csr", "generate-hmac-key", "generate-otp-aead-key", "generate-wrap-key", "generate-symmetric-key", "get-device-info", "get-logs", "get-object-info", "get-opaque", "get-option", "get-pseudo-random", "get-public-key", "get-storage-info", "get-template", "get-wrapped", "get-rsa-wrapped", "get-rsa-wrapped-key", "get-device-pubkey", "list-objects", "put-asymmetric-key", "put-authentication-key", "put-hmac-key", "put-opaque", "put-option", "put-otp-aead-key", "put-symmetric-key", "put-template", "put-wrap-key", "put-rsa-wrapkey", "put-public-wrapkey", "put-wrapped", "put-rsa-wrapped", "put-rsa-wrapped-key", "randomize-otp-aead", "reset", "set-log-index", "sign-attestation-certificate", "sign-ecdsa", "sign-eddsa", "sign-hmac", "sign-pkcs1v15", "sign-pss", "sign-ssh-certificate", 0}; /*< Possible values for action. */ const char *cmdline_parser_informat_values[] = {"default", "base64", "binary", "PEM", "password", "hex", "ASCII", 0}; /*< Possible values for informat. */ const char *cmdline_parser_outformat_values[] = {"default", "base64", "binary", "PEM", "hex", "ASCII", 0}; /*< Possible values for outformat. */ static char * gengetopt_strdup (const char *s); static void clear_given (struct gengetopt_args_info *args_info) { args_info->help_given = 0 ; args_info->version_given = 0 ; args_info->action_given = 0 ; args_info->password_given = 0 ; args_info->authkey_given = 0 ; args_info->object_id_given = 0 ; args_info->label_given = 0 ; args_info->domains_given = 0 ; args_info->capabilities_given = 0 ; args_info->object_type_given = 0 ; args_info->ykhsmauth_label_given = 0 ; args_info->ykhsmauth_reader_given = 0 ; args_info->delegated_given = 0 ; args_info->new_password_given = 0 ; args_info->algorithm_given = 0 ; args_info->oaep_given = 0 ; args_info->mgf1_given = 0 ; args_info->nonce_given = 0 ; args_info->iv_given = 0 ; args_info->count_given = 0 ; args_info->duration_given = 0 ; args_info->wrap_id_given = 0 ; args_info->include_seed_given = 0 ; args_info->template_id_given = 0 ; args_info->attestation_id_given = 0 ; args_info->log_index_given = 0 ; args_info->opt_name_given = 0 ; args_info->opt_value_given = 0 ; args_info->with_compression_given = 0 ; args_info->subject_given = 0 ; args_info->in_given = 0 ; args_info->out_given = 0 ; args_info->informat_given = 0 ; args_info->outformat_given = 0 ; args_info->config_file_given = 0 ; args_info->connector_given = 0 ; args_info->cacert_given = 0 ; args_info->cert_given = 0 ; args_info->key_given = 0 ; args_info->proxy_given = 0 ; args_info->noproxy_given = 0 ; args_info->verbose_given = 0 ; args_info->pre_connect_given = 0 ; args_info->device_pubkey_given = 0 ; } static void clear_args (struct gengetopt_args_info *args_info) { FIX_UNUSED (args_info); args_info->action_arg = NULL; args_info->action_orig = NULL; args_info->password_arg = NULL; args_info->password_orig = NULL; args_info->authkey_arg = 1; args_info->authkey_orig = NULL; args_info->object_id_arg = 0; args_info->object_id_orig = NULL; args_info->label_arg = gengetopt_strdup (""); args_info->label_orig = NULL; args_info->domains_arg = gengetopt_strdup ("1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16"); args_info->domains_orig = NULL; args_info->capabilities_arg = gengetopt_strdup ("0"); args_info->capabilities_orig = NULL; args_info->object_type_arg = gengetopt_strdup ("any"); args_info->object_type_orig = NULL; args_info->ykhsmauth_label_arg = NULL; args_info->ykhsmauth_label_orig = NULL; args_info->ykhsmauth_reader_arg = gengetopt_strdup (""); args_info->ykhsmauth_reader_orig = NULL; args_info->delegated_arg = gengetopt_strdup ("0"); args_info->delegated_orig = NULL; args_info->new_password_arg = NULL; args_info->new_password_orig = NULL; args_info->algorithm_arg = gengetopt_strdup ("any"); args_info->algorithm_orig = NULL; args_info->oaep_arg = gengetopt_strdup ("rsa-oaep-sha256"); args_info->oaep_orig = NULL; args_info->mgf1_arg = gengetopt_strdup ("mgf1-sha256"); args_info->mgf1_orig = NULL; args_info->nonce_orig = NULL; args_info->iv_arg = NULL; args_info->iv_orig = NULL; args_info->count_arg = 256; args_info->count_orig = NULL; args_info->duration_arg = 10; args_info->duration_orig = NULL; args_info->wrap_id_orig = NULL; args_info->include_seed_flag = 0; args_info->template_id_orig = NULL; args_info->attestation_id_orig = NULL; args_info->log_index_orig = NULL; args_info->opt_name_arg = NULL; args_info->opt_name_orig = NULL; args_info->opt_value_arg = NULL; args_info->opt_value_orig = NULL; args_info->with_compression_flag = 0; args_info->subject_arg = NULL; args_info->subject_orig = NULL; args_info->in_arg = gengetopt_strdup ("-"); args_info->in_orig = NULL; args_info->out_arg = gengetopt_strdup ("-"); args_info->out_orig = NULL; args_info->informat_arg = informat_arg_default; args_info->informat_orig = NULL; args_info->outformat_arg = outformat_arg_default; args_info->outformat_orig = NULL; args_info->config_file_arg = gengetopt_strdup (""); args_info->config_file_orig = NULL; args_info->connector_arg = NULL; args_info->connector_orig = NULL; args_info->cacert_arg = NULL; args_info->cacert_orig = NULL; args_info->cert_arg = NULL; args_info->cert_orig = NULL; args_info->key_arg = NULL; args_info->key_orig = NULL; args_info->proxy_arg = NULL; args_info->proxy_orig = NULL; args_info->noproxy_arg = NULL; args_info->noproxy_orig = NULL; args_info->verbose_arg = 0; args_info->verbose_orig = NULL; args_info->pre_connect_flag = 0; args_info->device_pubkey_arg = NULL; args_info->device_pubkey_orig = NULL; } static void init_args_info(struct gengetopt_args_info *args_info) { args_info->help_help = gengetopt_args_info_help[0] ; args_info->version_help = gengetopt_args_info_help[1] ; args_info->action_help = gengetopt_args_info_help[2] ; args_info->action_min = 0; args_info->action_max = 0; args_info->password_help = gengetopt_args_info_help[3] ; args_info->authkey_help = gengetopt_args_info_help[4] ; args_info->object_id_help = gengetopt_args_info_help[5] ; args_info->label_help = gengetopt_args_info_help[6] ; args_info->domains_help = gengetopt_args_info_help[7] ; args_info->capabilities_help = gengetopt_args_info_help[8] ; args_info->object_type_help = gengetopt_args_info_help[9] ; args_info->ykhsmauth_label_help = gengetopt_args_info_help[10] ; args_info->ykhsmauth_reader_help = gengetopt_args_info_help[11] ; args_info->delegated_help = gengetopt_args_info_help[12] ; args_info->new_password_help = gengetopt_args_info_help[13] ; args_info->algorithm_help = gengetopt_args_info_help[14] ; args_info->oaep_help = gengetopt_args_info_help[15] ; args_info->mgf1_help = gengetopt_args_info_help[16] ; args_info->nonce_help = gengetopt_args_info_help[17] ; args_info->iv_help = gengetopt_args_info_help[18] ; args_info->count_help = gengetopt_args_info_help[19] ; args_info->duration_help = gengetopt_args_info_help[20] ; args_info->wrap_id_help = gengetopt_args_info_help[21] ; args_info->include_seed_help = gengetopt_args_info_help[22] ; args_info->template_id_help = gengetopt_args_info_help[23] ; args_info->attestation_id_help = gengetopt_args_info_help[24] ; args_info->log_index_help = gengetopt_args_info_help[25] ; args_info->opt_name_help = gengetopt_args_info_help[26] ; args_info->opt_value_help = gengetopt_args_info_help[27] ; args_info->with_compression_help = gengetopt_args_info_help[28] ; args_info->subject_help = gengetopt_args_info_help[29] ; args_info->in_help = gengetopt_args_info_help[30] ; args_info->out_help = gengetopt_args_info_help[31] ; args_info->informat_help = gengetopt_args_info_help[32] ; args_info->outformat_help = gengetopt_args_info_help[33] ; args_info->config_file_help = gengetopt_args_info_help[34] ; args_info->connector_help = gengetopt_args_info_help[35] ; args_info->connector_min = 0; args_info->connector_max = 0; args_info->cacert_help = gengetopt_args_info_help[36] ; args_info->cert_help = gengetopt_args_info_help[37] ; args_info->key_help = gengetopt_args_info_help[38] ; args_info->proxy_help = gengetopt_args_info_help[39] ; args_info->noproxy_help = gengetopt_args_info_help[40] ; args_info->verbose_help = gengetopt_args_info_help[41] ; args_info->pre_connect_help = gengetopt_args_info_help[42] ; args_info->device_pubkey_help = gengetopt_args_info_help[43] ; args_info->device_pubkey_min = 0; args_info->device_pubkey_max = 0; } void cmdline_parser_print_version (void) { printf ("%s %s\n", (strlen(CMDLINE_PARSER_PACKAGE_NAME) ? CMDLINE_PARSER_PACKAGE_NAME : CMDLINE_PARSER_PACKAGE), CMDLINE_PARSER_VERSION); if (strlen(gengetopt_args_info_versiontext) > 0) printf("\n%s\n", gengetopt_args_info_versiontext); } static void print_help_common(void) { size_t len_purpose = strlen(gengetopt_args_info_purpose); size_t len_usage = strlen(gengetopt_args_info_usage); if (len_usage > 0) { printf("%s\n", gengetopt_args_info_usage); } if (len_purpose > 0) { printf("%s\n", gengetopt_args_info_purpose); } if (len_usage || len_purpose) { printf("\n"); } if (strlen(gengetopt_args_info_description) > 0) { printf("%s\n\n", gengetopt_args_info_description); } } void cmdline_parser_print_help (void) { int i = 0; print_help_common(); while (gengetopt_args_info_help[i]) printf("%s\n", gengetopt_args_info_help[i++]); } void cmdline_parser_init (struct gengetopt_args_info *args_info) { clear_given (args_info); clear_args (args_info); init_args_info (args_info); } void cmdline_parser_params_init(struct cmdline_parser_params *params) { if (params) { params->override = 0; params->initialize = 1; params->check_required = 1; params->check_ambiguity = 0; params->print_errors = 1; } } struct cmdline_parser_params * cmdline_parser_params_create(void) { struct cmdline_parser_params *params = (struct cmdline_parser_params *)malloc(sizeof(struct cmdline_parser_params)); cmdline_parser_params_init(params); return params; } static void free_string_field (char **s) { if (*s) { free (*s); *s = 0; } } /** @brief generic value variable */ union generic_value { int int_arg; short short_arg; char *string_arg; const char *default_string_arg; }; /** @brief holds temporary values for multiple options */ struct generic_list { union generic_value arg; char *orig; struct generic_list *next; }; /** * @brief add a node at the head of the list */ static void add_node(struct generic_list **list) { struct generic_list *new_node = (struct generic_list *) malloc (sizeof (struct generic_list)); new_node->next = *list; *list = new_node; new_node->arg.string_arg = 0; new_node->orig = 0; } /** * The passed arg parameter is NOT set to 0 from this function */ static void free_multiple_field(unsigned int len, void *arg, char ***orig) { unsigned int i; if (arg) { for (i = 0; i < len; ++i) { free_string_field(&((*orig)[i])); } free (arg); free (*orig); *orig = 0; } } static void free_multiple_string_field(unsigned int len, char ***arg, char ***orig) { unsigned int i; if (*arg) { for (i = 0; i < len; ++i) { free_string_field(&((*arg)[i])); free_string_field(&((*orig)[i])); } free_string_field(&((*arg)[0])); /* free default string */ free (*arg); *arg = 0; free (*orig); *orig = 0; } } static void cmdline_parser_release (struct gengetopt_args_info *args_info) { free_multiple_field (args_info->action_given, (void *)(args_info->action_arg), &(args_info->action_orig)); args_info->action_arg = 0; free_string_field (&(args_info->password_arg)); free_string_field (&(args_info->password_orig)); free_string_field (&(args_info->authkey_orig)); free_string_field (&(args_info->object_id_orig)); free_string_field (&(args_info->label_arg)); free_string_field (&(args_info->label_orig)); free_string_field (&(args_info->domains_arg)); free_string_field (&(args_info->domains_orig)); free_string_field (&(args_info->capabilities_arg)); free_string_field (&(args_info->capabilities_orig)); free_string_field (&(args_info->object_type_arg)); free_string_field (&(args_info->object_type_orig)); free_string_field (&(args_info->ykhsmauth_label_arg)); free_string_field (&(args_info->ykhsmauth_label_orig)); free_string_field (&(args_info->ykhsmauth_reader_arg)); free_string_field (&(args_info->ykhsmauth_reader_orig)); free_string_field (&(args_info->delegated_arg)); free_string_field (&(args_info->delegated_orig)); free_string_field (&(args_info->new_password_arg)); free_string_field (&(args_info->new_password_orig)); free_string_field (&(args_info->algorithm_arg)); free_string_field (&(args_info->algorithm_orig)); free_string_field (&(args_info->oaep_arg)); free_string_field (&(args_info->oaep_orig)); free_string_field (&(args_info->mgf1_arg)); free_string_field (&(args_info->mgf1_orig)); free_string_field (&(args_info->nonce_orig)); free_string_field (&(args_info->iv_arg)); free_string_field (&(args_info->iv_orig)); free_string_field (&(args_info->count_orig)); free_string_field (&(args_info->duration_orig)); free_string_field (&(args_info->wrap_id_orig)); free_string_field (&(args_info->template_id_orig)); free_string_field (&(args_info->attestation_id_orig)); free_string_field (&(args_info->log_index_orig)); free_string_field (&(args_info->opt_name_arg)); free_string_field (&(args_info->opt_name_orig)); free_string_field (&(args_info->opt_value_arg)); free_string_field (&(args_info->opt_value_orig)); free_string_field (&(args_info->subject_arg)); free_string_field (&(args_info->subject_orig)); free_string_field (&(args_info->in_arg)); free_string_field (&(args_info->in_orig)); free_string_field (&(args_info->out_arg)); free_string_field (&(args_info->out_orig)); free_string_field (&(args_info->informat_orig)); free_string_field (&(args_info->outformat_orig)); free_string_field (&(args_info->config_file_arg)); free_string_field (&(args_info->config_file_orig)); free_multiple_string_field (args_info->connector_given, &(args_info->connector_arg), &(args_info->connector_orig)); free_string_field (&(args_info->cacert_arg)); free_string_field (&(args_info->cacert_orig)); free_string_field (&(args_info->cert_arg)); free_string_field (&(args_info->cert_orig)); free_string_field (&(args_info->key_arg)); free_string_field (&(args_info->key_orig)); free_string_field (&(args_info->proxy_arg)); free_string_field (&(args_info->proxy_orig)); free_string_field (&(args_info->noproxy_arg)); free_string_field (&(args_info->noproxy_orig)); free_string_field (&(args_info->verbose_orig)); free_multiple_string_field (args_info->device_pubkey_given, &(args_info->device_pubkey_arg), &(args_info->device_pubkey_orig)); clear_given (args_info); } /** * @param val the value to check * @param values the possible values * @return the index of the matched value: * -1 if no value matched, * -2 if more than one value has matched */ static int check_possible_values(const char *val, const char *values[]) { int i, found, last; size_t len; if (!val) /* otherwise strlen() crashes below */ return -1; /* -1 means no argument for the option */ found = last = 0; for (i = 0, len = strlen(val); values[i]; ++i) { if (strncmp(val, values[i], len) == 0) { ++found; last = i; if (strlen(values[i]) == len) return i; /* exact macth no need to check more */ } } if (found == 1) /* one match: OK */ return last; return (found ? -2 : -1); /* return many values or none matched */ } static void write_into_file(FILE *outfile, const char *opt, const char *arg, const char *values[]) { int found = -1; if (arg) { if (values) { found = check_possible_values(arg, values); } if (found >= 0) fprintf(outfile, "%s=\"%s\" # %s\n", opt, arg, values[found]); else fprintf(outfile, "%s=\"%s\"\n", opt, arg); } else { fprintf(outfile, "%s\n", opt); } } static void write_multiple_into_file(FILE *outfile, int len, const char *opt, char **arg, const char *values[]) { int i; for (i = 0; i < len; ++i) write_into_file(outfile, opt, (arg ? arg[i] : 0), values); } int cmdline_parser_dump(FILE *outfile, struct gengetopt_args_info *args_info) { int i = 0; if (!outfile) { fprintf (stderr, "%s: cannot dump options to stream\n", CMDLINE_PARSER_PACKAGE); return EXIT_FAILURE; } if (args_info->help_given) write_into_file(outfile, "help", 0, 0 ); if (args_info->version_given) write_into_file(outfile, "version", 0, 0 ); write_multiple_into_file(outfile, args_info->action_given, "action", args_info->action_orig, cmdline_parser_action_values); if (args_info->password_given) write_into_file(outfile, "password", args_info->password_orig, 0); if (args_info->authkey_given) write_into_file(outfile, "authkey", args_info->authkey_orig, 0); if (args_info->object_id_given) write_into_file(outfile, "object-id", args_info->object_id_orig, 0); if (args_info->label_given) write_into_file(outfile, "label", args_info->label_orig, 0); if (args_info->domains_given) write_into_file(outfile, "domains", args_info->domains_orig, 0); if (args_info->capabilities_given) write_into_file(outfile, "capabilities", args_info->capabilities_orig, 0); if (args_info->object_type_given) write_into_file(outfile, "object-type", args_info->object_type_orig, 0); if (args_info->ykhsmauth_label_given) write_into_file(outfile, "ykhsmauth-label", args_info->ykhsmauth_label_orig, 0); if (args_info->ykhsmauth_reader_given) write_into_file(outfile, "ykhsmauth-reader", args_info->ykhsmauth_reader_orig, 0); if (args_info->delegated_given) write_into_file(outfile, "delegated", args_info->delegated_orig, 0); if (args_info->new_password_given) write_into_file(outfile, "new-password", args_info->new_password_orig, 0); if (args_info->algorithm_given) write_into_file(outfile, "algorithm", args_info->algorithm_orig, 0); if (args_info->oaep_given) write_into_file(outfile, "oaep", args_info->oaep_orig, 0); if (args_info->mgf1_given) write_into_file(outfile, "mgf1", args_info->mgf1_orig, 0); if (args_info->nonce_given) write_into_file(outfile, "nonce", args_info->nonce_orig, 0); if (args_info->iv_given) write_into_file(outfile, "iv", args_info->iv_orig, 0); if (args_info->count_given) write_into_file(outfile, "count", args_info->count_orig, 0); if (args_info->duration_given) write_into_file(outfile, "duration", args_info->duration_orig, 0); if (args_info->wrap_id_given) write_into_file(outfile, "wrap-id", args_info->wrap_id_orig, 0); if (args_info->include_seed_given) write_into_file(outfile, "include-seed", 0, 0 ); if (args_info->template_id_given) write_into_file(outfile, "template-id", args_info->template_id_orig, 0); if (args_info->attestation_id_given) write_into_file(outfile, "attestation-id", args_info->attestation_id_orig, 0); if (args_info->log_index_given) write_into_file(outfile, "log-index", args_info->log_index_orig, 0); if (args_info->opt_name_given) write_into_file(outfile, "opt-name", args_info->opt_name_orig, 0); if (args_info->opt_value_given) write_into_file(outfile, "opt-value", args_info->opt_value_orig, 0); if (args_info->with_compression_given) write_into_file(outfile, "with-compression", 0, 0 ); if (args_info->subject_given) write_into_file(outfile, "subject", args_info->subject_orig, 0); if (args_info->in_given) write_into_file(outfile, "in", args_info->in_orig, 0); if (args_info->out_given) write_into_file(outfile, "out", args_info->out_orig, 0); if (args_info->informat_given) write_into_file(outfile, "informat", args_info->informat_orig, cmdline_parser_informat_values); if (args_info->outformat_given) write_into_file(outfile, "outformat", args_info->outformat_orig, cmdline_parser_outformat_values); if (args_info->config_file_given) write_into_file(outfile, "config-file", args_info->config_file_orig, 0); write_multiple_into_file(outfile, args_info->connector_given, "connector", args_info->connector_orig, 0); if (args_info->cacert_given) write_into_file(outfile, "cacert", args_info->cacert_orig, 0); if (args_info->cert_given) write_into_file(outfile, "cert", args_info->cert_orig, 0); if (args_info->key_given) write_into_file(outfile, "key", args_info->key_orig, 0); if (args_info->proxy_given) write_into_file(outfile, "proxy", args_info->proxy_orig, 0); if (args_info->noproxy_given) write_into_file(outfile, "noproxy", args_info->noproxy_orig, 0); if (args_info->verbose_given) write_into_file(outfile, "verbose", args_info->verbose_orig, 0); if (args_info->pre_connect_given) write_into_file(outfile, "pre-connect", 0, 0 ); write_multiple_into_file(outfile, args_info->device_pubkey_given, "device-pubkey", args_info->device_pubkey_orig, 0); i = EXIT_SUCCESS; return i; } int cmdline_parser_file_save(const char *filename, struct gengetopt_args_info *args_info) { FILE *outfile; int i = 0; outfile = fopen(filename, "w"); if (!outfile) { fprintf (stderr, "%s: cannot open file for writing: %s\n", CMDLINE_PARSER_PACKAGE, filename); return EXIT_FAILURE; } i = cmdline_parser_dump(outfile, args_info); fclose (outfile); return i; } void cmdline_parser_free (struct gengetopt_args_info *args_info) { cmdline_parser_release (args_info); } /** @brief replacement of strdup, which is not standard */ char * gengetopt_strdup (const char *s) { char *result = 0; if (!s) return result; result = (char*)malloc(strlen(s) + 1); if (result == (char*)0) return (char*)0; strcpy(result, s); return result; } static char * get_multiple_arg_token(const char *arg) { const char *tok; char *ret; size_t len, num_of_escape, i, j; if (!arg) return 0; tok = strchr (arg, ','); num_of_escape = 0; /* make sure it is not escaped */ while (tok) { if (*(tok-1) == '\\') { /* find the next one */ tok = strchr (tok+1, ','); ++num_of_escape; } else break; } if (tok) len = (size_t)(tok - arg + 1); else len = strlen (arg) + 1; len -= num_of_escape; ret = (char *) malloc (len); i = 0; j = 0; while (arg[i] && (j < len-1)) { if (arg[i] == '\\' && arg[ i + 1 ] && arg[ i + 1 ] == ',') ++i; ret[j++] = arg[i++]; } ret[len-1] = '\0'; return ret; } static const char * get_multiple_arg_token_next(const char *arg) { const char *tok; if (!arg) return 0; tok = strchr (arg, ','); /* make sure it is not escaped */ while (tok) { if (*(tok-1) == '\\') { /* find the next one */ tok = strchr (tok+1, ','); } else break; } if (! tok || strlen(tok) == 1) return 0; return tok+1; } static int check_multiple_option_occurrences(const char *prog_name, unsigned int option_given, unsigned int min, unsigned int max, const char *option_desc); int check_multiple_option_occurrences(const char *prog_name, unsigned int option_given, unsigned int min, unsigned int max, const char *option_desc) { int error_occurred = 0; if (option_given && (min > 0 || max > 0)) { if (min > 0 && max > 0) { if (min == max) { /* specific occurrences */ if (option_given != (unsigned int) min) { fprintf (stderr, "%s: %s option occurrences must be %d\n", prog_name, option_desc, min); error_occurred = 1; } } else if (option_given < (unsigned int) min || option_given > (unsigned int) max) { /* range occurrences */ fprintf (stderr, "%s: %s option occurrences must be between %d and %d\n", prog_name, option_desc, min, max); error_occurred = 1; } } else if (min > 0) { /* at least check */ if (option_given < min) { fprintf (stderr, "%s: %s option occurrences must be at least %d\n", prog_name, option_desc, min); error_occurred = 1; } } else if (max > 0) { /* at most check */ if (option_given > max) { fprintf (stderr, "%s: %s option occurrences must be at most %d\n", prog_name, option_desc, max); error_occurred = 1; } } } return error_occurred; } int cmdline_parser (int argc, char **argv, struct gengetopt_args_info *args_info) { return cmdline_parser2 (argc, argv, args_info, 0, 1, 1); } int cmdline_parser_ext (int argc, char **argv, struct gengetopt_args_info *args_info, struct cmdline_parser_params *params) { int result; result = cmdline_parser_internal (argc, argv, args_info, params, 0); if (result == EXIT_FAILURE) { cmdline_parser_free (args_info); exit (EXIT_FAILURE); } return result; } int cmdline_parser2 (int argc, char **argv, struct gengetopt_args_info *args_info, int override, int initialize, int check_required) { int result; struct cmdline_parser_params params; params.override = override; params.initialize = initialize; params.check_required = check_required; params.check_ambiguity = 0; params.print_errors = 1; result = cmdline_parser_internal (argc, argv, args_info, ¶ms, 0); if (result == EXIT_FAILURE) { cmdline_parser_free (args_info); exit (EXIT_FAILURE); } return result; } int cmdline_parser_required (struct gengetopt_args_info *args_info, const char *prog_name) { int result = EXIT_SUCCESS; if (cmdline_parser_required2(args_info, prog_name, 0) > 0) result = EXIT_FAILURE; if (result == EXIT_FAILURE) { cmdline_parser_free (args_info); exit (EXIT_FAILURE); } return result; } int cmdline_parser_required2 (struct gengetopt_args_info *args_info, const char *prog_name, const char *additional_error) { int error_occurred = 0; FIX_UNUSED (additional_error); /* checks for required options */ if (check_multiple_option_occurrences(prog_name, args_info->action_given, args_info->action_min, args_info->action_max, "'--action' ('-a')")) error_occurred = 1; if (check_multiple_option_occurrences(prog_name, args_info->connector_given, args_info->connector_min, args_info->connector_max, "'--connector' ('-C')")) error_occurred = 1; if (check_multiple_option_occurrences(prog_name, args_info->device_pubkey_given, args_info->device_pubkey_min, args_info->device_pubkey_max, "'--device-pubkey'")) error_occurred = 1; /* checks for dependences among options */ return error_occurred; } static char *package_name = 0; /** * @brief updates an option * @param field the generic pointer to the field to update * @param orig_field the pointer to the orig field * @param field_given the pointer to the number of occurrence of this option * @param prev_given the pointer to the number of occurrence already seen * @param value the argument for this option (if null no arg was specified) * @param possible_values the possible values for this option (if specified) * @param default_value the default value (in case the option only accepts fixed values) * @param arg_type the type of this option * @param check_ambiguity @see cmdline_parser_params.check_ambiguity * @param override @see cmdline_parser_params.override * @param no_free whether to free a possible previous value * @param multiple_option whether this is a multiple option * @param long_opt the corresponding long option * @param short_opt the corresponding short option (or '-' if none) * @param additional_error possible further error specification */ static int update_arg(void *field, char **orig_field, unsigned int *field_given, unsigned int *prev_given, char *value, const char *possible_values[], const char *default_value, cmdline_parser_arg_type arg_type, int check_ambiguity, int override, int no_free, int multiple_option, const char *long_opt, char short_opt, const char *additional_error) { char *stop_char = 0; const char *val = value; int found; char **string_field; FIX_UNUSED (field); stop_char = 0; found = 0; if (!multiple_option && prev_given && (*prev_given || (check_ambiguity && *field_given))) { if (short_opt != '-') fprintf (stderr, "%s: `--%s' (`-%c') option given more than once%s\n", package_name, long_opt, short_opt, (additional_error ? additional_error : "")); else fprintf (stderr, "%s: `--%s' option given more than once%s\n", package_name, long_opt, (additional_error ? additional_error : "")); return 1; /* failure */ } if (possible_values && (found = check_possible_values((value ? value : default_value), possible_values)) < 0) { if (short_opt != '-') fprintf (stderr, "%s: %s argument, \"%s\", for option `--%s' (`-%c')%s\n", package_name, (found == -2) ? "ambiguous" : "invalid", value, long_opt, short_opt, (additional_error ? additional_error : "")); else fprintf (stderr, "%s: %s argument, \"%s\", for option `--%s'%s\n", package_name, (found == -2) ? "ambiguous" : "invalid", value, long_opt, (additional_error ? additional_error : "")); return 1; /* failure */ } if (field_given && *field_given && ! override) return 0; if (prev_given) (*prev_given)++; if (field_given) (*field_given)++; if (possible_values) val = possible_values[found]; switch(arg_type) { case ARG_FLAG: *((int *)field) = !*((int *)field); break; case ARG_INT: if (val) *((int *)field) = strtol (val, &stop_char, 0); break; case ARG_SHORT: if (val) *((short *)field) = (short)strtol (val, &stop_char, 0); break; case ARG_ENUM: if (val) *((int *)field) = found; break; case ARG_STRING: if (val) { string_field = (char **)field; if (!no_free && *string_field) free (*string_field); /* free previous string */ *string_field = gengetopt_strdup (val); } break; default: break; }; /* check numeric conversion */ switch(arg_type) { case ARG_INT: case ARG_SHORT: if (val && !(stop_char && *stop_char == '\0')) { fprintf(stderr, "%s: invalid numeric value: %s\n", package_name, val); return 1; /* failure */ } break; default: ; }; /* store the original value */ switch(arg_type) { case ARG_NO: case ARG_FLAG: break; default: if (value && orig_field) { if (no_free) { *orig_field = value; } else { if (*orig_field) free (*orig_field); /* free previous string */ *orig_field = gengetopt_strdup (value); } } }; return 0; /* OK */ } /** * @brief store information about a multiple option in a temporary list * @param list where to (temporarily) store multiple options */ static int update_multiple_arg_temp(struct generic_list **list, unsigned int *prev_given, const char *val, const char *possible_values[], const char *default_value, cmdline_parser_arg_type arg_type, const char *long_opt, char short_opt, const char *additional_error) { /* store single arguments */ char *multi_token; const char *multi_next; if (arg_type == ARG_NO) { (*prev_given)++; return 0; /* OK */ } multi_token = get_multiple_arg_token(val); multi_next = get_multiple_arg_token_next (val); while (1) { add_node (list); if (update_arg((void *)&((*list)->arg), &((*list)->orig), 0, prev_given, multi_token, possible_values, default_value, arg_type, 0, 1, 1, 1, long_opt, short_opt, additional_error)) { if (multi_token) free(multi_token); return 1; /* failure */ } if (multi_next) { multi_token = get_multiple_arg_token(multi_next); multi_next = get_multiple_arg_token_next (multi_next); } else break; } return 0; /* OK */ } /** * @brief free the passed list (including possible string argument) */ static void free_list(struct generic_list *list, short string_arg) { if (list) { struct generic_list *tmp; while (list) { tmp = list; if (string_arg && list->arg.string_arg) free (list->arg.string_arg); if (list->orig) free (list->orig); list = list->next; free (tmp); } } } /** * @brief updates a multiple option starting from the passed list */ static void update_multiple_arg(void *field, char ***orig_field, unsigned int field_given, unsigned int prev_given, union generic_value *default_value, cmdline_parser_arg_type arg_type, struct generic_list *list) { int i; struct generic_list *tmp; if (prev_given && list) { *orig_field = (char **) realloc (*orig_field, (field_given + prev_given) * sizeof (char *)); switch(arg_type) { case ARG_INT: case ARG_ENUM: *((int **)field) = (int *)realloc (*((int **)field), (field_given + prev_given) * sizeof (int)); break; case ARG_SHORT: *((short **)field) = (short *)realloc (*((short **)field), (field_given + prev_given) * sizeof (short)); break; case ARG_STRING: *((char ***)field) = (char **)realloc (*((char ***)field), (field_given + prev_given) * sizeof (char *)); break; default: break; }; for (i = (prev_given - 1); i >= 0; --i) { tmp = list; switch(arg_type) { case ARG_INT: (*((int **)field))[i + field_given] = tmp->arg.int_arg; break; case ARG_SHORT: (*((short **)field))[i + field_given] = tmp->arg.short_arg; break; case ARG_ENUM: (*((int **)field))[i + field_given] = tmp->arg.int_arg; break; case ARG_STRING: (*((char ***)field))[i + field_given] = tmp->arg.string_arg; break; default: break; } (*orig_field) [i + field_given] = list->orig; list = list->next; free (tmp); } } else { /* set the default value */ if (default_value && ! field_given) { switch(arg_type) { case ARG_INT: case ARG_ENUM: if (! *((int **)field)) { *((int **)field) = (int *)malloc (sizeof (int)); (*((int **)field))[0] = default_value->int_arg; } break; case ARG_SHORT: if (! *((short **)field)) { *((short **)field) = (short *)malloc (sizeof (short)); (*((short **)field))[0] = default_value->short_arg; } break; case ARG_STRING: if (! *((char ***)field)) { *((char ***)field) = (char **)malloc (sizeof (char *)); (*((char ***)field))[0] = gengetopt_strdup(default_value->string_arg); } break; default: break; } if (!(*orig_field)) { *orig_field = (char **) malloc (sizeof (char *)); (*orig_field)[0] = 0; } } } } int cmdline_parser_internal ( int argc, char **argv, struct gengetopt_args_info *args_info, struct cmdline_parser_params *params, const char *additional_error) { int c; /* Character of the parsed option. */ struct generic_list * action_list = NULL; struct generic_list * connector_list = NULL; struct generic_list * device_pubkey_list = NULL; int error_occurred = 0; struct gengetopt_args_info local_args_info; int override; int initialize; int check_required; int check_ambiguity; package_name = argv[0]; /* TODO: Why is this here? It is not used anywhere. */ override = params->override; FIX_UNUSED(override); initialize = params->initialize; check_required = params->check_required; /* TODO: Why is this here? It is not used anywhere. */ check_ambiguity = params->check_ambiguity; FIX_UNUSED(check_ambiguity); if (initialize) cmdline_parser_init (args_info); cmdline_parser_init (&local_args_info); optarg = 0; optind = 0; opterr = params->print_errors; optopt = '?'; while (1) { int option_index = 0; static struct option long_options[] = { { "help", 0, NULL, 'h' }, { "version", 0, NULL, 'V' }, { "action", 1, NULL, 'a' }, { "password", 1, NULL, 'p' }, { "authkey", 1, NULL, 0 }, { "object-id", 1, NULL, 'i' }, { "label", 1, NULL, 'l' }, { "domains", 1, NULL, 'd' }, { "capabilities", 1, NULL, 'c' }, { "object-type", 1, NULL, 't' }, { "ykhsmauth-label", 1, NULL, 'y' }, { "ykhsmauth-reader", 1, NULL, 'r' }, { "delegated", 1, NULL, 0 }, { "new-password", 1, NULL, 0 }, { "algorithm", 1, NULL, 'A' }, { "oaep", 1, NULL, 0 }, { "mgf1", 1, NULL, 0 }, { "nonce", 1, NULL, 0 }, { "iv", 1, NULL, 0 }, { "count", 1, NULL, 0 }, { "duration", 1, NULL, 0 }, { "wrap-id", 1, NULL, 0 }, { "include-seed", 0, NULL, 0 }, { "template-id", 1, NULL, 0 }, { "attestation-id", 1, NULL, 0 }, { "log-index", 1, NULL, 0 }, { "opt-name", 1, NULL, 0 }, { "opt-value", 1, NULL, 0 }, { "with-compression", 0, NULL, 0 }, { "subject", 1, NULL, 'S' }, { "in", 1, NULL, 0 }, { "out", 1, NULL, 0 }, { "informat", 1, NULL, 0 }, { "outformat", 1, NULL, 0 }, { "config-file", 1, NULL, 'f' }, { "connector", 1, NULL, 'C' }, { "cacert", 1, NULL, 0 }, { "cert", 1, NULL, 0 }, { "key", 1, NULL, 0 }, { "proxy", 1, NULL, 0 }, { "noproxy", 1, NULL, 0 }, { "verbose", 1, NULL, 'v' }, { "pre-connect", 0, NULL, 'P' }, { "device-pubkey", 1, NULL, 0 }, { 0, 0, 0, 0 } }; c = getopt_long (argc, argv, "hVa:p:i:l:d:c:t:y:r:A:S:f:C:v:P", long_options, &option_index); if (c == -1) break; /* Exit from `while (1)' loop. */ switch (c) { case 'h': /* Print help and exit. */ cmdline_parser_print_help (); cmdline_parser_free (&local_args_info); exit (EXIT_SUCCESS); case 'V': /* Print version and exit. */ cmdline_parser_print_version (); cmdline_parser_free (&local_args_info); exit (EXIT_SUCCESS); case 'a': /* Action to perform. */ if (update_multiple_arg_temp(&action_list, &(local_args_info.action_given), optarg, cmdline_parser_action_values, 0, ARG_ENUM, "action", 'a', additional_error)) goto failure; break; case 'p': /* Authentication password. */ if (update_arg( (void *)&(args_info->password_arg), &(args_info->password_orig), &(args_info->password_given), &(local_args_info.password_given), optarg, 0, 0, ARG_STRING, check_ambiguity, override, 0, 0, "password", 'p', additional_error)) goto failure; break; case 'i': /* Object ID. */ if (update_arg( (void *)&(args_info->object_id_arg), &(args_info->object_id_orig), &(args_info->object_id_given), &(local_args_info.object_id_given), optarg, 0, "0", ARG_SHORT, check_ambiguity, override, 0, 0, "object-id", 'i', additional_error)) goto failure; break; case 'l': /* Object label. */ if (update_arg( (void *)&(args_info->label_arg), &(args_info->label_orig), &(args_info->label_given), &(local_args_info.label_given), optarg, 0, "", ARG_STRING, check_ambiguity, override, 0, 0, "label", 'l', additional_error)) goto failure; break; case 'd': /* Object domains. */ if (update_arg( (void *)&(args_info->domains_arg), &(args_info->domains_orig), &(args_info->domains_given), &(local_args_info.domains_given), optarg, 0, "1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16", ARG_STRING, check_ambiguity, override, 0, 0, "domains", 'd', additional_error)) goto failure; break; case 'c': /* Capabilities for an object. */ if (update_arg( (void *)&(args_info->capabilities_arg), &(args_info->capabilities_orig), &(args_info->capabilities_given), &(local_args_info.capabilities_given), optarg, 0, "0", ARG_STRING, check_ambiguity, override, 0, 0, "capabilities", 'c', additional_error)) goto failure; break; case 't': /* Object type. */ if (update_arg( (void *)&(args_info->object_type_arg), &(args_info->object_type_orig), &(args_info->object_type_given), &(local_args_info.object_type_given), optarg, 0, "any", ARG_STRING, check_ambiguity, override, 0, 0, "object-type", 't', additional_error)) goto failure; break; case 'y': /* Credential label on YubiKey (implicitly enables ykhsmauth). */ if (update_arg( (void *)&(args_info->ykhsmauth_label_arg), &(args_info->ykhsmauth_label_orig), &(args_info->ykhsmauth_label_given), &(local_args_info.ykhsmauth_label_given), optarg, 0, 0, ARG_STRING, check_ambiguity, override, 0, 0, "ykhsmauth-label", 'y', additional_error)) goto failure; break; case 'r': /* Only use a matching YubiKey reader name. */ if (update_arg( (void *)&(args_info->ykhsmauth_reader_arg), &(args_info->ykhsmauth_reader_orig), &(args_info->ykhsmauth_reader_given), &(local_args_info.ykhsmauth_reader_given), optarg, 0, "", ARG_STRING, check_ambiguity, override, 0, 0, "ykhsmauth-reader", 'r', additional_error)) goto failure; break; case 'A': /* Operation algorithm. */ if (update_arg( (void *)&(args_info->algorithm_arg), &(args_info->algorithm_orig), &(args_info->algorithm_given), &(local_args_info.algorithm_given), optarg, 0, "any", ARG_STRING, check_ambiguity, override, 0, 0, "algorithm", 'A', additional_error)) goto failure; break; case 'S': /* The subject to use for certificate request. The subject must be written as: /CN=host.example.com/OU=test/O=example.com/. */ if (update_arg( (void *)&(args_info->subject_arg), &(args_info->subject_orig), &(args_info->subject_given), &(local_args_info.subject_given), optarg, 0, 0, ARG_STRING, check_ambiguity, override, 0, 0, "subject", 'S', additional_error)) goto failure; break; case 'f': /* Configuration file to read. */ if (update_arg( (void *)&(args_info->config_file_arg), &(args_info->config_file_orig), &(args_info->config_file_given), &(local_args_info.config_file_given), optarg, 0, "", ARG_STRING, check_ambiguity, override, 0, 0, "config-file", 'f', additional_error)) goto failure; break; case 'C': /* List of connectors to use. */ if (update_multiple_arg_temp(&connector_list, &(local_args_info.connector_given), optarg, 0, 0, ARG_STRING, "connector", 'C', additional_error)) goto failure; break; case 'v': /* Print more information. */ if (update_arg( (void *)&(args_info->verbose_arg), &(args_info->verbose_orig), &(args_info->verbose_given), &(local_args_info.verbose_given), optarg, 0, "0", ARG_INT, check_ambiguity, override, 0, 0, "verbose", 'v', additional_error)) goto failure; break; case 'P': /* Connect immediately in interactive mode. */ if (update_arg((void *)&(args_info->pre_connect_flag), 0, &(args_info->pre_connect_given), &(local_args_info.pre_connect_given), optarg, 0, 0, ARG_FLAG, check_ambiguity, override, 1, 0, "pre-connect", 'P', additional_error)) goto failure; break; case 0: /* Long option with no short option */ /* Authentication key. */ if (strcmp (long_options[option_index].name, "authkey") == 0) { if (update_arg( (void *)&(args_info->authkey_arg), &(args_info->authkey_orig), &(args_info->authkey_given), &(local_args_info.authkey_given), optarg, 0, "1", ARG_SHORT, check_ambiguity, override, 0, 0, "authkey", '-', additional_error)) goto failure; } /* Delegated capabilities. */ else if (strcmp (long_options[option_index].name, "delegated") == 0) { if (update_arg( (void *)&(args_info->delegated_arg), &(args_info->delegated_orig), &(args_info->delegated_given), &(local_args_info.delegated_given), optarg, 0, "0", ARG_STRING, check_ambiguity, override, 0, 0, "delegated", '-', additional_error)) goto failure; } /* New authentication password. */ else if (strcmp (long_options[option_index].name, "new-password") == 0) { if (update_arg( (void *)&(args_info->new_password_arg), &(args_info->new_password_orig), &(args_info->new_password_given), &(local_args_info.new_password_given), optarg, 0, 0, ARG_STRING, check_ambiguity, override, 0, 0, "new-password", '-', additional_error)) goto failure; } /* OAEP algorithm. Used primarily with asymmetric wrap. */ else if (strcmp (long_options[option_index].name, "oaep") == 0) { if (update_arg( (void *)&(args_info->oaep_arg), &(args_info->oaep_orig), &(args_info->oaep_given), &(local_args_info.oaep_given), optarg, 0, "rsa-oaep-sha256", ARG_STRING, check_ambiguity, override, 0, 0, "oaep", '-', additional_error)) goto failure; } /* MGF1 algorithm. Used primarily with asymmetric wrap. */ else if (strcmp (long_options[option_index].name, "mgf1") == 0) { if (update_arg( (void *)&(args_info->mgf1_arg), &(args_info->mgf1_orig), &(args_info->mgf1_given), &(local_args_info.mgf1_given), optarg, 0, "mgf1-sha256", ARG_STRING, check_ambiguity, override, 0, 0, "mgf1", '-', additional_error)) goto failure; } /* OTP nonce. */ else if (strcmp (long_options[option_index].name, "nonce") == 0) { if (update_arg( (void *)&(args_info->nonce_arg), &(args_info->nonce_orig), &(args_info->nonce_given), &(local_args_info.nonce_given), optarg, 0, 0, ARG_INT, check_ambiguity, override, 0, 0, "nonce", '-', additional_error)) goto failure; } /* An initialization vector as a hexadecimal string. */ else if (strcmp (long_options[option_index].name, "iv") == 0) { if (update_arg( (void *)&(args_info->iv_arg), &(args_info->iv_orig), &(args_info->iv_given), &(local_args_info.iv_given), optarg, 0, 0, ARG_STRING, check_ambiguity, override, 0, 0, "iv", '-', additional_error)) goto failure; } /* Number of bytes to request. */ else if (strcmp (long_options[option_index].name, "count") == 0) { if (update_arg( (void *)&(args_info->count_arg), &(args_info->count_orig), &(args_info->count_given), &(local_args_info.count_given), optarg, 0, "256", ARG_INT, check_ambiguity, override, 0, 0, "count", '-', additional_error)) goto failure; } /* Blink duration in seconds. */ else if (strcmp (long_options[option_index].name, "duration") == 0) { if (update_arg( (void *)&(args_info->duration_arg), &(args_info->duration_orig), &(args_info->duration_given), &(local_args_info.duration_given), optarg, 0, "10", ARG_INT, check_ambiguity, override, 0, 0, "duration", '-', additional_error)) goto failure; } /* Wrap key ID. */ else if (strcmp (long_options[option_index].name, "wrap-id") == 0) { if (update_arg( (void *)&(args_info->wrap_id_arg), &(args_info->wrap_id_orig), &(args_info->wrap_id_given), &(local_args_info.wrap_id_given), optarg, 0, 0, ARG_SHORT, check_ambiguity, override, 0, 0, "wrap-id", '-', additional_error)) goto failure; } /* Include seed when exporting an ED25519 key under wrap. */ else if (strcmp (long_options[option_index].name, "include-seed") == 0) { if (update_arg((void *)&(args_info->include_seed_flag), 0, &(args_info->include_seed_given), &(local_args_info.include_seed_given), optarg, 0, 0, ARG_FLAG, check_ambiguity, override, 1, 0, "include-seed", '-', additional_error)) goto failure; } /* Template ID. */ else if (strcmp (long_options[option_index].name, "template-id") == 0) { if (update_arg( (void *)&(args_info->template_id_arg), &(args_info->template_id_orig), &(args_info->template_id_given), &(local_args_info.template_id_given), optarg, 0, 0, ARG_SHORT, check_ambiguity, override, 0, 0, "template-id", '-', additional_error)) goto failure; } /* Attestation ID. */ else if (strcmp (long_options[option_index].name, "attestation-id") == 0) { if (update_arg( (void *)&(args_info->attestation_id_arg), &(args_info->attestation_id_orig), &(args_info->attestation_id_given), &(local_args_info.attestation_id_given), optarg, 0, 0, ARG_SHORT, check_ambiguity, override, 0, 0, "attestation-id", '-', additional_error)) goto failure; } /* Log index. */ else if (strcmp (long_options[option_index].name, "log-index") == 0) { if (update_arg( (void *)&(args_info->log_index_arg), &(args_info->log_index_orig), &(args_info->log_index_given), &(local_args_info.log_index_given), optarg, 0, 0, ARG_INT, check_ambiguity, override, 0, 0, "log-index", '-', additional_error)) goto failure; } /* Device option name. */ else if (strcmp (long_options[option_index].name, "opt-name") == 0) { if (update_arg( (void *)&(args_info->opt_name_arg), &(args_info->opt_name_orig), &(args_info->opt_name_given), &(local_args_info.opt_name_given), optarg, 0, 0, ARG_STRING, check_ambiguity, override, 0, 0, "opt-name", '-', additional_error)) goto failure; } /* Device option value. */ else if (strcmp (long_options[option_index].name, "opt-value") == 0) { if (update_arg( (void *)&(args_info->opt_value_arg), &(args_info->opt_value_orig), &(args_info->opt_value_given), &(local_args_info.opt_value_given), optarg, 0, 0, ARG_STRING, check_ambiguity, override, 0, 0, "opt-value", '-', additional_error)) goto failure; } /* Compress a X509Certificate before importing it into the device or detect compressed certificates when listing objects. */ else if (strcmp (long_options[option_index].name, "with-compression") == 0) { if (update_arg((void *)&(args_info->with_compression_flag), 0, &(args_info->with_compression_given), &(local_args_info.with_compression_given), optarg, 0, 0, ARG_FLAG, check_ambiguity, override, 1, 0, "with-compression", '-', additional_error)) goto failure; } /* Input data (filename). */ else if (strcmp (long_options[option_index].name, "in") == 0) { if (update_arg( (void *)&(args_info->in_arg), &(args_info->in_orig), &(args_info->in_given), &(local_args_info.in_given), optarg, 0, "-", ARG_STRING, check_ambiguity, override, 0, 0, "in", '-', additional_error)) goto failure; } /* Output data (filename). */ else if (strcmp (long_options[option_index].name, "out") == 0) { if (update_arg( (void *)&(args_info->out_arg), &(args_info->out_orig), &(args_info->out_given), &(local_args_info.out_given), optarg, 0, "-", ARG_STRING, check_ambiguity, override, 0, 0, "out", '-', additional_error)) goto failure; } /* Input format. */ else if (strcmp (long_options[option_index].name, "informat") == 0) { if (update_arg( (void *)&(args_info->informat_arg), &(args_info->informat_orig), &(args_info->informat_given), &(local_args_info.informat_given), optarg, cmdline_parser_informat_values, "default", ARG_ENUM, check_ambiguity, override, 0, 0, "informat", '-', additional_error)) goto failure; } /* Input and output format. */ else if (strcmp (long_options[option_index].name, "outformat") == 0) { if (update_arg( (void *)&(args_info->outformat_arg), &(args_info->outformat_orig), &(args_info->outformat_given), &(local_args_info.outformat_given), optarg, cmdline_parser_outformat_values, "default", ARG_ENUM, check_ambiguity, override, 0, 0, "outformat", '-', additional_error)) goto failure; } /* HTTPS cacert for connector. */ else if (strcmp (long_options[option_index].name, "cacert") == 0) { if (update_arg( (void *)&(args_info->cacert_arg), &(args_info->cacert_orig), &(args_info->cacert_given), &(local_args_info.cacert_given), optarg, 0, 0, ARG_STRING, check_ambiguity, override, 0, 0, "cacert", '-', additional_error)) goto failure; } /* HTTPS client certificate to authenticate with. */ else if (strcmp (long_options[option_index].name, "cert") == 0) { if (update_arg( (void *)&(args_info->cert_arg), &(args_info->cert_orig), &(args_info->cert_given), &(local_args_info.cert_given), optarg, 0, 0, ARG_STRING, check_ambiguity, override, 0, 0, "cert", '-', additional_error)) goto failure; } /* HTTPS client certificate key. */ else if (strcmp (long_options[option_index].name, "key") == 0) { if (update_arg( (void *)&(args_info->key_arg), &(args_info->key_orig), &(args_info->key_given), &(local_args_info.key_given), optarg, 0, 0, ARG_STRING, check_ambiguity, override, 0, 0, "key", '-', additional_error)) goto failure; } /* Proxy server to use for connector. */ else if (strcmp (long_options[option_index].name, "proxy") == 0) { if (update_arg( (void *)&(args_info->proxy_arg), &(args_info->proxy_orig), &(args_info->proxy_given), &(local_args_info.proxy_given), optarg, 0, 0, ARG_STRING, check_ambiguity, override, 0, 0, "proxy", '-', additional_error)) goto failure; } /* Comma separated list of hosts ignore proxy for. */ else if (strcmp (long_options[option_index].name, "noproxy") == 0) { if (update_arg( (void *)&(args_info->noproxy_arg), &(args_info->noproxy_orig), &(args_info->noproxy_given), &(local_args_info.noproxy_given), optarg, 0, 0, ARG_STRING, check_ambiguity, override, 0, 0, "noproxy", '-', additional_error)) goto failure; } /* List of device public keys allowed for asymmetric authentication. */ else if (strcmp (long_options[option_index].name, "device-pubkey") == 0) { if (update_multiple_arg_temp(&device_pubkey_list, &(local_args_info.device_pubkey_given), optarg, 0, 0, ARG_STRING, "device-pubkey", '-', additional_error)) goto failure; } break; case '?': /* Invalid option. */ /* `getopt_long' already printed an error message. */ goto failure; default: /* bug: option not considered. */ fprintf (stderr, "%s: option unknown: %c%s\n", CMDLINE_PARSER_PACKAGE, c, (additional_error ? additional_error : "")); abort (); } /* switch */ } /* while */ update_multiple_arg((void *)&(args_info->action_arg), &(args_info->action_orig), args_info->action_given, local_args_info.action_given, 0, ARG_ENUM, action_list); update_multiple_arg((void *)&(args_info->connector_arg), &(args_info->connector_orig), args_info->connector_given, local_args_info.connector_given, 0, ARG_STRING, connector_list); update_multiple_arg((void *)&(args_info->device_pubkey_arg), &(args_info->device_pubkey_orig), args_info->device_pubkey_given, local_args_info.device_pubkey_given, 0, ARG_STRING, device_pubkey_list); args_info->action_given += local_args_info.action_given; local_args_info.action_given = 0; args_info->connector_given += local_args_info.connector_given; local_args_info.connector_given = 0; args_info->device_pubkey_given += local_args_info.device_pubkey_given; local_args_info.device_pubkey_given = 0; if (check_required) { error_occurred += cmdline_parser_required2 (args_info, argv[0], additional_error); } cmdline_parser_release (&local_args_info); if ( error_occurred ) return (EXIT_FAILURE); return 0; failure: free_list (action_list, 0 ); free_list (connector_list, 1 ); free_list (device_pubkey_list, 1 ); cmdline_parser_release (&local_args_info); return (EXIT_FAILURE); } #ifndef CONFIG_FILE_LINE_SIZE #define CONFIG_FILE_LINE_SIZE 2048 #endif #define ADDITIONAL_ERROR " in configuration file " #define CONFIG_FILE_LINE_BUFFER_SIZE (CONFIG_FILE_LINE_SIZE+3) /* 3 is for "--" and "=" */ static int _cmdline_parser_configfile (const char *filename, int *my_argc) { FILE* file; char my_argv[CONFIG_FILE_LINE_BUFFER_SIZE+1]; char linebuf[CONFIG_FILE_LINE_SIZE]; int line_num = 0; int result = 0, equal; char *fopt, *farg; char *str_index; size_t len, next_token; char delimiter; if ((file = fopen(filename, "r")) == 0) { fprintf (stderr, "%s: Error opening configuration file '%s'\n", CMDLINE_PARSER_PACKAGE, filename); return EXIT_FAILURE; } while ((fgets(linebuf, CONFIG_FILE_LINE_SIZE, file)) != 0) { ++line_num; my_argv[0] = '\0'; len = strlen(linebuf); if (len > (CONFIG_FILE_LINE_BUFFER_SIZE-1)) { fprintf (stderr, "%s:%s:%d: Line too long in configuration file\n", CMDLINE_PARSER_PACKAGE, filename, line_num); result = EXIT_FAILURE; break; } /* find first non-whitespace character in the line */ next_token = strspn (linebuf, " \t\r\n"); str_index = linebuf + next_token; if ( str_index[0] == '\0' || str_index[0] == '#') continue; /* empty line or comment line is skipped */ fopt = str_index; /* truncate fopt at the end of the first non-valid character */ next_token = strcspn (fopt, " \t\r\n="); if (fopt[next_token] == '\0') /* the line is over */ { farg = 0; equal = 0; goto noarg; } /* remember if equal sign is present */ equal = (fopt[next_token] == '='); fopt[next_token++] = '\0'; /* advance pointers to the next token after the end of fopt */ next_token += strspn (fopt + next_token, " \t\r\n"); /* check for the presence of equal sign, and if so, skip it */ if ( !equal ) if ((equal = (fopt[next_token] == '='))) { next_token++; next_token += strspn (fopt + next_token, " \t\r\n"); } str_index += next_token; /* find argument */ farg = str_index; if ( farg[0] == '\"' || farg[0] == '\'' ) { /* quoted argument */ str_index = strchr (++farg, str_index[0] ); /* skip opening quote */ if (! str_index) { fprintf (stderr, "%s:%s:%d: unterminated string in configuration file\n", CMDLINE_PARSER_PACKAGE, filename, line_num); result = EXIT_FAILURE; break; } } else { /* read up the remaining part up to a delimiter */ next_token = strcspn (farg, " \t\r\n#\'\""); str_index += next_token; } /* truncate farg at the delimiter and store it for further check */ delimiter = *str_index, *str_index++ = '\0'; /* everything but comment is illegal at the end of line */ if (delimiter != '\0' && delimiter != '#') { str_index += strspn(str_index, " \t\r\n"); if (*str_index != '\0' && *str_index != '#') { fprintf (stderr, "%s:%s:%d: malformed string in configuration file\n", CMDLINE_PARSER_PACKAGE, filename, line_num); result = EXIT_FAILURE; break; } } noarg: if (!strcmp(fopt,"include")) { if (farg && *farg) { result = _cmdline_parser_configfile(farg, my_argc); } else { fprintf(stderr, "%s:%s:%d: include requires a filename argument.\n", CMDLINE_PARSER_PACKAGE, filename, line_num); } continue; } len = strlen(fopt); strcat (my_argv, len > 1 ? "--" : "-"); strcat (my_argv, fopt); if (len > 1 && ((farg && *farg) || equal)) strcat (my_argv, "="); if (farg && *farg) strcat (my_argv, farg); ++(*my_argc); cmd_line_list_tmp = (struct line_list *) malloc (sizeof (struct line_list)); cmd_line_list_tmp->next = cmd_line_list; cmd_line_list = cmd_line_list_tmp; cmd_line_list->string_arg = gengetopt_strdup(my_argv); } /* while */ if (file) fclose(file); return result; } int cmdline_parser_configfile ( const char *filename, struct gengetopt_args_info *args_info, int override, int initialize, int check_required) { struct cmdline_parser_params params; params.override = override; params.initialize = initialize; params.check_required = check_required; params.check_ambiguity = 0; params.print_errors = 1; return cmdline_parser_config_file (filename, args_info, ¶ms); } int cmdline_parser_config_file (const char *filename, struct gengetopt_args_info *args_info, struct cmdline_parser_params *params) { int i, result; int my_argc = 1; char **my_argv_arg; char *additional_error; /* store the program name */ cmd_line_list_tmp = (struct line_list *) malloc (sizeof (struct line_list)); cmd_line_list_tmp->next = cmd_line_list; cmd_line_list = cmd_line_list_tmp; cmd_line_list->string_arg = gengetopt_strdup (CMDLINE_PARSER_PACKAGE); result = _cmdline_parser_configfile(filename, &my_argc); if (result != EXIT_FAILURE) { my_argv_arg = (char **) malloc((my_argc+1) * sizeof(char *)); cmd_line_list_tmp = cmd_line_list; for (i = my_argc - 1; i >= 0; --i) { my_argv_arg[i] = cmd_line_list_tmp->string_arg; cmd_line_list_tmp = cmd_line_list_tmp->next; } my_argv_arg[my_argc] = 0; additional_error = (char *)malloc(strlen(filename) + strlen(ADDITIONAL_ERROR) + 1); strcpy (additional_error, ADDITIONAL_ERROR); strcat (additional_error, filename); result = cmdline_parser_internal (my_argc, my_argv_arg, args_info, params, additional_error); free (additional_error); free (my_argv_arg); } free_cmd_list(); if (result == EXIT_FAILURE) { cmdline_parser_free (args_info); exit (EXIT_FAILURE); } return result; } /* vim: set ft=c noet ts=8 sts=8 sw=8 tw=80 nojs spell : */ yubihsm-shell-2.8.0/src/README.adoc0000644000175100017510000000642415221003515016270 0ustar runnerrunner== YubiHSM Shell YubiHSM Shell is a tool to directly interface with a YubiHSM 2 device. For the most part it is a thin wrapper around `libyubihsm` exposing most of its functions directly to the user. YubiHSM Shell can be invoked in interactive mode and from the command line. Special (national) characters are supported on MacOS and Linux platforms. On Windows, they are supported in interactive mode and the same support can be activated through the OpenSSL environment variable `OPENSSL_WIN32_UTF8` for interactive password entry in non-interactive mode (i.e if password is not given on the command line). Such characters will be encoded according to current locale settings on MacOS/Linux (typically utf-8), and always as utf-8 on Windows. === Interactive Mode To invoke YubiHSM Shell in interactive mode simply run `yubihsm-shell` with no parameters. This mode supports tab-completion (not on Windows) and "classic" terminal shortcuts (`C-p`, `C-n`, `C-a`, `C-e`, etc.) In this mode, the default Connector URL is `http://127.0.01:12345`. If a different URL is needed, it can be specified with the `--connector` option. For example, to select direct USB run [source, bash] ---- yubihsm-shell --connector yhusb:// ---- Help can be obtained by running [source, bash] ---- yubihsm> help ---- to get a list of available commands and their syntax, or by running [source, bash] ---- yubihsm> help COMMAND ---- to get help on a specific command. Debug messages can be turned on by running [source, bash] ---- yubihsm> debug all ---- other levels of verbosity are available as well. Each command has its own default input and output format. Possible choices are `PEM`, `base64`, `binary`, `hex`, `password` and `default`. Those can be changed by running [source, bash] ---- yubihsm> set informat base64 ---- or [source, bash] ---- yubihsm> set outformat hex ---- Input and Output formats are a generic modifier and some values may not make sense in some cases. The default setting can be restored by using the `default` format. === Command-line Mode It is possible to run yubihsm-shell as a non-interactive command-line utility. To do so add the `--action` option with the desired command to execute. For example, to generate an RSA 2048 key with Label `Signature_Key`, Object ID `10` and Capabilities `sign-pss`, run [source, bash] ---- $ yubihsm-shell -p password -a generate-asymmetric -A rsa2048 -i 10 -c sign-pss -l Signature_Key ---- to sign a file called `message.dat` using the previously generated key, PSS with SHA256 as padding scheme and save the result to a file called `signature.dat` run [source, bash] ---- $ yubihsm-shell -p password -a sign-pss -i 10 -A rsa-pss-sha256 --in message.dat --out signature.dat --outformat binary ---- it is then possible to extract the public key by using [source, bash] ---- yubihsm-shell -p password -a get-public-key -i 10 --out key.pem --outformat PEM ---- and verify the signature with OpenSSL by running [source, bash] ---- $ openssl dgst -sha256 -binary message.dat > digest.dat $ openssl pkeyutl -verify -in digest.dat -sigfile signature.dat -pkeyopt rsa_padding_mode:pss -pubin -inkey key.pem -pkeyopt rsa_pss_saltlen:-1 -pkeyopt digest:sha256 ---- A detailed list of possible actions and parameters is available in the manpage or by running `yubihsm-shell --help`. yubihsm-shell-2.8.0/src/main.c0000644000175100017510000035071615221003515015601 0ustar runnerrunner/* * Copyright 2015-2018 Yubico AB * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #include #include #include #include #include #include "util.h" #include "parsing.h" #include "commands.h" #include "insecure_memzero.h" #include //#include #define PROMPT "yubihsm> " #define ARGS_BUFFER_SIZE 4096 #define COMPLETION_CANDIDATES 256 #define MAX_COMMAND_NAME 32 #define MAX_ARGUMENTS 32 #include "yubihsm-shell.h" #define SPACES " \f\n\r\t\v" #ifdef __WIN32 #include #include #include // TODO: cheat on windows, cheat better? #define S_ISLNK S_ISREG #else #include #include #include #include #include #include History *g_hist; #endif #ifdef _MSVC #define S_ISREG(m) (((m) &S_IFMT) == S_IFREG) #define strcasecmp _stricmp #define strncasecmp _strnicmp #endif #define UNUSED(x) (void) (x) #define LIB_SUCCEED_OR_DIE(x, s) \ if ((x) != YHR_SUCCESS) { \ fprintf(stderr, s "%s\n", yh_strerror(x)); \ rc = EXIT_FAILURE; \ break; \ } #define COM_SUCCEED_OR_DIE(x, s) \ if ((x) != 0) { \ fprintf(stderr, s "\n"); \ rc = EXIT_FAILURE; \ break; \ } static bool calling_device = false; static yubihsm_context g_ctx = {0}; int yh_com_help(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_history(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_quit(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_set_informat(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); int yh_com_set_outformat(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt); typedef struct Command Command; // NOTE(adma): supported values for the argument list are as follow // u: unsigned integer (either decimal or hex if starts with 0x) // w: unsigned short // b: unsigned byte // f: out filename // F: in filename // s: string // e: session struct Command { char *name; /* Command name to match against */ CommandFunction *func; /* Documentation for the function */ char *args; /* Argument string */ cmd_format in_fmt; /* Default input format for command */ cmd_format out_fmt; /* Default output format for command */ char *doc; /* Function to call to do the job */ Command *subcommands; /* List of subcommands */ Command *next; /* Pointer to next command */ }; typedef Command *CommandList; // NOTE(adma): push command to list and return the new head static Command *register_command(CommandList list, Command command) { Command *c = calloc(1, sizeof(Command)); if (c == NULL) { fprintf(stderr, "Failed to allocate memory\n"); exit(EXIT_FAILURE); } assert(strlen(command.name) <= MAX_COMMAND_NAME); memcpy(c, &command, sizeof(Command)); c->next = list; return c; } static void register_subcommand(Command *parent, Command command) { Command *c = malloc(sizeof(Command)); if (c == NULL) { fprintf(stderr, "Failed to allocate memory\n"); exit(EXIT_FAILURE); } memcpy(c, &command, sizeof(Command)); c->next = parent->subcommands; parent->subcommands = c; } static CommandList msort_list(CommandList list) { Command *left; Command *right; Command *e; int in_size; int left_size; int right_size; // NOTE(adma): do nothing on an empty list if (!list) { return NULL; } in_size = 1; while (1) { Command *tail = NULL; left = list; list = NULL; int n_merges = 0; while (left != NULL) { n_merges++; right = left; left_size = 0; for (int i = 0; i < in_size; i++) { left_size++; right = right->next; if (right == NULL) { break; } } right_size = in_size; while (left_size > 0 || (right_size > 0 && right)) { if (left_size == 0) { e = right; right = right->next; right_size--; } else if (right_size == 0 || !right) { e = left; left = left->next; left_size--; } else if (strcmp(left->name, right->name) <= 0) { e = left; left = left->next; left_size--; } else { e = right; right = right->next; right_size--; } if (tail) { tail->next = e; } else { list = e; } tail = e; } left = right; } if (tail != NULL) { tail->next = NULL; } if (n_merges <= 1) { return list; } in_size *= 2; } } static void create_command_list(CommandList *c) { // NOTE(adma): initialize *c = NULL; *c = register_command(*c, (Command){"audit", yh_com_noop, NULL, fmt_nofmt, fmt_nofmt, "Deal with audit log", NULL, NULL}); register_subcommand(*c, (Command){"get", yh_com_audit, "e:session,F:file=-", fmt_ASCII, fmt_nofmt, "Extract log entries", NULL, NULL}); register_subcommand(*c, (Command){"set", yh_com_set_log_index, "e:session,w:index", fmt_nofmt, fmt_nofmt, "Set the log index", NULL, NULL}); *c = register_command(*c, (Command){"connect", yh_com_connect, NULL, fmt_nofmt, fmt_nofmt, "Connect to a connector", NULL, NULL}); *c = register_command(*c, (Command){"debug", yh_com_noop, NULL, fmt_nofmt, fmt_nofmt, "Change debug settings", NULL, NULL}); register_subcommand(*c, (Command){"all", yh_com_debug_all, NULL, fmt_nofmt, fmt_nofmt, "Enable all debug messages", NULL, NULL}); register_subcommand(*c, (Command){"crypto", yh_com_debug_crypto, NULL, fmt_nofmt, fmt_nofmt, "Toggle crypto debug messages", NULL, NULL}); register_subcommand(*c, (Command){"error", yh_com_debug_error, NULL, fmt_nofmt, fmt_nofmt, "Toggle error debug messages", NULL, NULL}); register_subcommand(*c, (Command){"info", yh_com_debug_info, NULL, fmt_nofmt, fmt_nofmt, "Toggle info debug messages", NULL, NULL}); register_subcommand(*c, (Command){"intermediate", yh_com_debug_intermediate, NULL, fmt_nofmt, fmt_nofmt, "Toggle intermediate debug messages", NULL, NULL}); register_subcommand(*c, (Command){"none", yh_com_debug_none, NULL, fmt_nofmt, fmt_nofmt, "Disable all debug messages", NULL, NULL}); register_subcommand(*c, (Command){"raw", yh_com_debug_raw, NULL, fmt_nofmt, fmt_nofmt, "Toggle raw debug messages", NULL, NULL}); *c = register_command(*c, (Command){"decrypt", yh_com_noop, NULL, fmt_nofmt, fmt_nofmt, "Decrypt data", NULL, NULL}); register_subcommand(*c, (Command){"pkcs1v1_5", yh_com_decrypt_pkcs1v1_5, "e:session,w:key_id,i:data=-", fmt_binary, fmt_base64, "Decrypt data using RSAES-PKCS#1v1.5", NULL, NULL}); register_subcommand( *c, (Command){"oaep", yh_com_decrypt_oaep, "e:session,w:key_id,a:algorithm,i:data=-,s:label=", fmt_binary, fmt_base64, "Decrypt data using RSAES-OAEP", NULL, NULL}); register_subcommand(*c, (Command){"aesccm", yh_com_decrypt_aesccm, "e:session,w:key_id,i:data=-", fmt_base64, fmt_binary, "Decrypt data using Yubico-AES-CCM", NULL, NULL}); register_subcommand( *c, (Command){"aescbc", yh_com_decrypt_aes_cbc, "e:session,w:key_id,s:iv,i:data=-", fmt_base64, fmt_binary, "Decrypt data using an AES symmetric key in CBC mode", NULL, NULL}); register_subcommand( *c, (Command){"aesecb", yh_com_decrypt_aes_ecb, "e:session,w:key_id,i:data=-", fmt_base64, fmt_binary, "Decrypt data using an AES symmetric key in ECB mode", NULL, NULL}); *c = register_command(*c, (Command){"derive", yh_com_noop, NULL, fmt_nofmt, fmt_nofmt, "Derive data", NULL, NULL}); register_subcommand(*c, (Command){"ecdh", yh_com_derive_ecdh, "e:session,w:key_id,i:pubkey=-", fmt_PEM, fmt_hex, "Perform a ECDH key exchange", NULL, NULL}); *c = register_command(*c, (Command){"encrypt", yh_com_noop, NULL, fmt_nofmt, fmt_nofmt, "Encrypt data", NULL, NULL}); register_subcommand(*c, (Command){"aesccm", yh_com_encrypt_aesccm, "e:session,w:key_id,i:data=-", fmt_binary, fmt_base64, "Encrypt data using Yubico-AES-CCM", NULL, NULL}); register_subcommand( *c, (Command){"aescbc", yh_com_encrypt_aes_cbc, "e:session,w:key_id,s:iv,i:data=-", fmt_binary, fmt_base64, "Encrypt data using an AES symmetric key in CBC mode", NULL, NULL}); register_subcommand( *c, (Command){"aesecb", yh_com_encrypt_aes_ecb, "e:session,w:key_id,i:data=-", fmt_binary, fmt_base64, "Encrypt data using an AES symmetric key in ECB mode", NULL, NULL}); *c = register_command(*c, (Command){"disconnect", yh_com_disconnect, NULL, fmt_nofmt, fmt_nofmt, "Disconnect from a connector", NULL, NULL}); *c = register_command(*c, (Command){"echo", yh_com_echo, "e:session,b:byte,w:count", fmt_nofmt, fmt_nofmt, "Send an ECHO command over a given session", NULL, NULL}); *c = register_command(*c, (Command){"generate", yh_com_noop, NULL, fmt_nofmt, fmt_nofmt, "Generate key", NULL, NULL}); register_subcommand(*c, (Command){"asymmetric", yh_com_generate_asymmetric, "e:session,w:key_id,s:label,d:domains,c:" "capabilities,a:algorithm", fmt_nofmt, fmt_nofmt, "Generate an asymmetric key", NULL, NULL}); register_subcommand(*c, (Command){"csr", yh_com_generate_csr, "e:session,w:key_id,s:subject,F:file=-", fmt_nofmt, fmt_PEM, "Generate a certificate signing request", NULL, NULL}); register_subcommand(*c, (Command){"hmackey", yh_com_generate_hmac, "e:session,w:key_id,s:label,d:domains,c:" "capabilities,a:algorithm", fmt_nofmt, fmt_nofmt, "Generate HMAC key", NULL, NULL}); register_subcommand( *c, (Command){"wrapkey", yh_com_generate_wrap, "e:session,w:key_id,s:label,d:domains,c:" "capabilities,c:delegated_capabilities,a:algorithm", fmt_nofmt, fmt_nofmt, "Generate wrap key", NULL, NULL}); register_subcommand(*c, (Command){"otpaeadkey", yh_com_generate_otp_aead_key, "e:session,w:key_id,s:label,d:domains,c:" "capabilities,a:algorithm,u:nonce_id", fmt_nofmt, fmt_nofmt, "Generate OTP AEAD key", NULL, NULL}); register_subcommand(*c, (Command){"symmetric", yh_com_generate_symmetric, "e:session,w:key_id,s:label,d:domains,c:" "capabilities,a:algorithm", fmt_nofmt, fmt_nofmt, "Generate a symmetric key", NULL, NULL}); *c = register_command(*c, (Command){"get", yh_com_noop, NULL, fmt_nofmt, fmt_nofmt, "Retrieve data", NULL, NULL}); register_subcommand(*c, (Command){"opaque", yh_com_get_opaque, "e:session,w:object_id,F:file=-", fmt_nofmt, fmt_binary, "Get an opaque object", NULL, NULL}); register_subcommand(*c, (Command){"option", yh_com_get_option, "e:session,o:option", fmt_nofmt, fmt_nofmt, // FIXME: output "Get a global option value", NULL, NULL}); register_subcommand(*c, (Command){"random", yh_com_get_random, "e:session,w:count,F:out=-", fmt_nofmt, fmt_hex, "Get pseudo-random bytes", NULL, NULL}); register_subcommand(*c, (Command){"storage", yh_com_get_storage, "e:session", fmt_nofmt, fmt_nofmt, "Get storages stats", NULL, NULL}); register_subcommand(*c, (Command){"pubkey", yh_com_get_pubkey, "e:session,w:key_id,t:key_type=asymmetric-key,F:file=-", fmt_nofmt, fmt_PEM, "Get a public key", NULL, NULL}); register_subcommand(*c, (Command){"objectinfo", yh_com_get_object_info, "e:session,w:id,t:type", fmt_nofmt, fmt_nofmt, "Get information about an object", NULL, NULL}); register_subcommand(*c, (Command){"wrapped", yh_com_get_wrapped, "e:session,w:wrapkey_id,t:type,w:id,b:include_seed=0,F:file=-", fmt_nofmt, fmt_base64, "Get an object under wrap", NULL, NULL}); register_subcommand(*c, (Command){"rsa_wrapped", yh_com_get_rsa_wrapped, "e:session,w:wrapkey_id,t:type,w:id,a:aes=aes256,a:hash=rsa-oaep-sha256,a:mgf1=mgf1-sha256,F:file=-", fmt_nofmt, fmt_binary, "Get an object under RSA wrap", NULL, NULL}); register_subcommand(*c, (Command){"rsa_wrapped_key", yh_com_get_rsa_wrapped_key, "e:session,w:wrapkey_id,t:type,w:id,a:aes=aes256,a:hash=rsa-oaep-sha256,a:mgf1=mgf1-sha256,F:file=-", fmt_nofmt, fmt_binary, "Get a (a)symmetric key under RSA wrap", NULL, NULL}); register_subcommand(*c, (Command){"deviceinfo", yh_com_get_device_info, NULL, fmt_nofmt, fmt_nofmt, "Extract the version number, serial number " "and supported algorithms", NULL, NULL}); register_subcommand(*c, (Command){"template", yh_com_get_template, "e:session,w:object_id,F:out=-", fmt_nofmt, fmt_base64, "Get a template object", NULL, NULL}); register_subcommand(*c, (Command){"devicepubkey", yh_com_get_device_pubkey, NULL, fmt_nofmt, fmt_PEM, "Get the device public key for asymmetric " "authentication", NULL, NULL}); *c = register_command(*c, (Command){"help", yh_com_help, "s:command=", fmt_nofmt, fmt_nofmt, "Display help text", NULL, NULL}); *c = register_command(*c, (Command){"history", yh_com_history, NULL, fmt_nofmt, fmt_nofmt, "Display the command history", NULL, NULL}); *c = register_command(*c, (Command){"list", yh_com_noop, NULL, fmt_nofmt, fmt_nofmt, "List information", NULL, NULL}); register_subcommand(*c, (Command){"capabilities", yh_com_list_capabilities, NULL, fmt_nofmt, fmt_nofmt, "Prints a list of possible capabilities", NULL, NULL}); register_subcommand(*c, (Command){"algorithms", yh_com_list_algorithms, NULL, fmt_nofmt, fmt_nofmt, "Prints a list of possible algorithms", NULL, NULL}); register_subcommand(*c, (Command){"types", yh_com_list_types, NULL, fmt_nofmt, fmt_nofmt, "Prints a list of possible types", NULL, NULL}); register_subcommand(*c, (Command){"sessions", yh_com_list_sessions, NULL, fmt_nofmt, fmt_nofmt, "List the open session", NULL, NULL}); register_subcommand(*c, (Command){"objects", yh_com_list_objects, "e:session,w:id=0,t:type=any,d:domains=0,c:" "capabilities=0,a:algorithm=any,b:with-compression=0,s:label=", fmt_nofmt, fmt_nofmt, "List objects according to filter", NULL, NULL}); *c = register_command(*c, (Command){"plain", yh_com_noop, NULL, fmt_nofmt, fmt_nofmt, "Send unencrypted and unauthenticated commands", NULL, NULL}); register_subcommand(*c, (Command){"echo", yh_com_pecho, "b:byte,w:count", fmt_nofmt, fmt_nofmt, "Send a plain echo command", NULL, NULL}); *c = register_command(*c, (Command){"put", yh_com_noop, NULL, fmt_nofmt, fmt_nofmt, "Store data", NULL, NULL}); register_subcommand(*c, (Command){"asymmetric", yh_com_put_asymmetric, "e:session,w:key_id,s:label,d:domains,c:" "capabilities,i:key=-", fmt_PEM, fmt_nofmt, "Store an asymmetric key", NULL, NULL}); register_subcommand(*c, (Command){"authkey", yh_com_put_authentication, "e:session,w:key_id,s:label,d:domains,c:" "capabilities,c:delegated_capabilities,i:" "password=-", fmt_password, fmt_nofmt, "Store an authentication key", NULL, NULL}); register_subcommand(*c, (Command){"authkey_asym", yh_com_put_authentication_asym, "e:session,w:key_id,s:label,d:domains,c:" "capabilities,c:delegated_capabilities,i:" "pubkey=-", fmt_PEM, fmt_nofmt, "Store an asymmetric authentication key", NULL, NULL}); register_subcommand(*c, (Command){"opaque", yh_com_put_opaque, "e:session,w:object_id,s:label,d:domains,c:" "capabilities,a:algorithm,b:with-compression=0,i:data=-", fmt_binary, fmt_nofmt, "Store an opaque object", NULL, NULL}); register_subcommand(*c, (Command){"option", yh_com_put_option, "e:session,o:option,i:data", fmt_hex, fmt_nofmt, "Set a global option value", NULL, NULL}); register_subcommand(*c, (Command){"hmackey", yh_com_put_hmac, "e:session,w:key_id,s:label,d:domains,c:" "capabilities,a:algorithm,i:key", fmt_hex, fmt_nofmt, "Store a HMAC key", NULL, NULL}); register_subcommand(*c, (Command){"wrapkey", yh_com_put_wrapkey, "e:session,w:key_id,s:label,d:domains,c:" "capabilities,c:delegated_capabilities,i:key", fmt_hex, fmt_nofmt, "Store a wrapping key", NULL, NULL}); register_subcommand(*c, (Command){"rsa_wrapkey", yh_com_put_rsa_wrapkey, "e:session,w:key_id,s:label,d:domains,c:" "capabilities,c:delegated_capabilities,i:key=-", fmt_PEM, fmt_nofmt, "Store an RSA wrapping key", NULL, NULL}); register_subcommand(*c, (Command){"pub_wrapkey", yh_com_put_public_wrapkey, "e:session,w:key_id,s:label,d:domains,c:" "capabilities,c:delegated_capabilities,i:key=-", fmt_PEM, fmt_nofmt, "Store an RSA wrapping key", NULL, NULL}); register_subcommand(*c, (Command){"wrapped", yh_com_put_wrapped, "e:session,w:wrapkey_id,i:data=-", fmt_base64, fmt_nofmt, "Store a wrapped object", NULL, NULL}); register_subcommand(*c, (Command){"rsa_wrapped", yh_com_put_rsa_wrapped, "e:session,w:wrapkey_id,a:hash=rsa-oaep-sha256,a:mgf1=mgf1-sha256,i:data=-", fmt_binary, fmt_nofmt, "Store a wrapped object", NULL, NULL}); register_subcommand(*c, (Command){"rsa_wrapped_key", yh_com_put_rsa_wrapped_key, "e:session,w:wrapkey_id,t:type,w:key_id,a:algorithm,s:label,d:domains,c:capabilities,a:hash=rsa-oaep-sha256,a:mgf1=mgf1-sha256,i:data=-", fmt_binary, fmt_nofmt, "Store a wrapped object", NULL, NULL}); register_subcommand(*c, (Command){"template", yh_com_put_template, "e:session,w:object_id,s:label,d:domains,c:" "capabilities,a:algorithm,i:data=-", fmt_base64, fmt_nofmt, "Store a template object", NULL, NULL}); register_subcommand(*c, (Command){"otpaeadkey", yh_com_put_otp_aead_key, "e:session,w:key_id,s:label,d:domains,c:" "capabilities,u:nonce_id,i:key", fmt_hex, fmt_nofmt, "Store a OTP AEAD key", NULL, NULL}); register_subcommand(*c, (Command){"symmetric", yh_com_put_symmetric, "e:session,w:key_id,s:label,d:domains,c:" "capabilities,a:algorithm,i:key", fmt_hex, fmt_nofmt, "Store a symmetric key", NULL, NULL}); *c = register_command(*c, (Command){"quit", yh_com_quit, NULL, fmt_nofmt, fmt_nofmt, "Quit yubihsm-shell", NULL, NULL}); *c = register_command(*c, (Command){"exit", yh_com_quit, NULL, fmt_nofmt, fmt_nofmt, "Quit yubihsm-shell", NULL, NULL}); *c = register_command(*c, (Command){"session", yh_com_noop, NULL, fmt_nofmt, fmt_nofmt, "Manage sessions", NULL, NULL}); register_subcommand(*c, (Command){"close", yh_com_close_session, "e:session", fmt_nofmt, fmt_nofmt, "Close a session with a connector", NULL, NULL}); register_subcommand(*c, (Command){"open", yh_com_open_session, "w:authkey,i:password=-", fmt_password, fmt_nofmt, "Open a session with a device using a " "specific Authentication Key", NULL, NULL}); register_subcommand(*c, (Command){"open_asym", yh_com_open_session_asym, "w:authkey,i:privkey=-", fmt_PEM, fmt_nofmt, "Open a session with a device using a " "specific Asymmetric Authentication Key", NULL, NULL}); register_subcommand(*c, (Command){"ykopen", yh_com_open_yksession, "w:authkey,s:label,i:password=-,s:reader=", fmt_password, fmt_nofmt, "Open a session with a device using an " "Authentication in a YubiKey", NULL, NULL}); *c = register_command(*c, (Command){"sign", yh_com_noop, NULL, fmt_nofmt, fmt_nofmt, "Sign data", NULL, NULL}); register_subcommand( *c, (Command){"ecdsa", yh_com_sign_ecdsa, "e:session,w:key_id,a:algorithm,i:data=-,F:out=-", fmt_binary, fmt_base64, "Sign data using ECDSA", NULL, NULL}); register_subcommand( *c, (Command){"eddsa", yh_com_sign_eddsa, "e:session,w:key_id,a:algorithm,i:data=-,F:out=-", fmt_binary, fmt_base64, "Sign data using EDDSA", NULL, NULL}); register_subcommand( *c, (Command){"pkcs1v1_5", yh_com_sign_pkcs1v1_5, "e:session,w:key_id,a:algorithm,i:data=-,F:out=-", fmt_binary, fmt_base64, "Sign data using RSASSA-PKCS#1v1.5", NULL, NULL}); register_subcommand( *c, (Command){"pss", yh_com_sign_pss, "e:session,w:key_id,a:algorithm,i:data=-,F:out=-", fmt_binary, fmt_base64, "Sign data using RSASSA-PSS", NULL, NULL}); *c = register_command(*c, (Command){"hmac", yh_com_hmac, "e:session,w:key_id,i:data=-,F:out=-", fmt_hex, fmt_hex, "Hmac data", NULL, NULL}); *c = register_command(*c, (Command){"reset", yh_com_reset, "e:session", fmt_nofmt, fmt_nofmt, "Reset device", NULL, NULL}); *c = register_command(*c, (Command){"delete", yh_com_delete, "e:session,w:id,t:type", fmt_nofmt, fmt_nofmt, "Delete data", NULL, NULL}); *c = register_command(*c, (Command){"certify", yh_com_sign_ssh_certificate, "e:session,w:key_id,w:template_id,a:" "algorithm,i:infile=-,F:outfile=-", fmt_binary, fmt_binary, // TODO: correct default formats? "Sign SSH certificates", NULL, NULL}); *c = register_command(*c, (Command){"benchmark", yh_com_benchmark, "e:session,u:count,w:key_id=0,a:algorithm=any", fmt_nofmt, fmt_nofmt, "Run a set of benchmarks", NULL, NULL}); *c = register_command(*c, (Command){"otp", yh_com_noop, NULL, fmt_nofmt, fmt_nofmt, "OTP commands", NULL, NULL}); register_subcommand(*c, (Command){"aead_create", yh_com_otp_aead_create, "e:session,w:key_id,i:key,i:private_id,F:aead", fmt_hex, fmt_binary, "Create an OTP AEAD", NULL, NULL}); register_subcommand(*c, (Command){"aead_random", yh_com_otp_aead_random, "e:session,w:key_id,F:aead", fmt_nofmt, fmt_binary, "Create a random OTP AEAD", NULL, NULL}); register_subcommand(*c, (Command){"decrypt", yh_com_otp_decrypt, "e:session,w:key_id,s:otp,i:aead", fmt_binary, fmt_nofmt, "Decrypt an OTP with AEAD", NULL, NULL}); register_subcommand( *c, (Command){"rewrap", yh_com_otp_rewrap, "e:session,w:id_from,w:id_to,i:aead_in,F:aead_out", fmt_binary, fmt_binary, "Rewrap an OTP aead to a different key", NULL, NULL}); *c = register_command(*c, (Command){"attest", yh_com_noop, NULL, fmt_nofmt, fmt_nofmt, "Attest device objects", NULL, NULL}); register_subcommand(*c, (Command){"asymmetric", yh_com_sign_attestation_certificate, "e:session,w:key_id,w:attest_id=0,F:file=-", fmt_nofmt, fmt_PEM, "Sign attestation certificate", NULL, NULL}); *c = register_command(*c, (Command){"keepalive", yh_com_noop, NULL, fmt_nofmt, fmt_nofmt, "Change keepalive settings", NULL, NULL}); register_subcommand(*c, (Command){"on", yh_com_keepalive_on, NULL, fmt_nofmt, fmt_nofmt, "Enable keepalive", NULL, NULL}); register_subcommand(*c, (Command){"off", yh_com_keepalive_off, NULL, fmt_nofmt, fmt_nofmt, "Disable keepalive", NULL, NULL}); *c = register_command(*c, (Command){"set", yh_com_noop, NULL, fmt_nofmt, fmt_nofmt, "Set preferences", NULL, NULL}); register_subcommand(*c, (Command){"informat", yh_com_set_informat, "I:format", fmt_nofmt, fmt_nofmt, "Set input format", NULL, NULL}); register_subcommand(*c, (Command){"outformat", yh_com_set_outformat, "I:format", fmt_nofmt, fmt_nofmt, "Set output format", NULL, NULL}); register_subcommand(*c, (Command){"cacert", yh_com_set_cacert, "s:file", fmt_nofmt, fmt_nofmt, "Set CA cert to use for https to connector", NULL, NULL}); register_subcommand(*c, (Command){"cert", yh_com_set_cert, "s:file", fmt_nofmt, fmt_nofmt, "Set client cert to use for https to connector", NULL, NULL}); register_subcommand(*c, (Command){"key", yh_com_set_key, "s:file", fmt_nofmt, fmt_nofmt, "Set client key to use for https to connector", NULL, NULL}); register_subcommand(*c, (Command){"proxy", yh_com_set_proxy, "s:proxy", fmt_nofmt, fmt_nofmt, "Set proxyserver to use for connector", NULL, NULL}); register_subcommand(*c, (Command){"noproxy", yh_com_set_noproxy, "s:noproxy", fmt_nofmt, fmt_nofmt, "Set noproxy list to use for connector", NULL, NULL}); *c = register_command(*c, (Command){"blink", yh_com_blink, "e:session,b:seconds=10", fmt_nofmt, fmt_nofmt, "Blink the device", NULL, NULL}); *c = register_command(*c, (Command){"change", yh_com_noop, NULL, fmt_nofmt, fmt_nofmt, "Change objects", NULL, NULL}); register_subcommand(*c, (Command){"authkey", yh_com_change_authentication_key, "e:session,w:key_id,i:password=-", fmt_password, fmt_nofmt, "Change an authentication key", NULL, NULL}); register_subcommand(*c, (Command){"authkey_asym", yh_com_change_authentication_key_asym, "e:session,w:key_id,i:pubkey=-", fmt_PEM, fmt_nofmt, "Change an asymmetric authentication key", NULL, NULL}); *c = msort_list(*c); for (Command *t = *c; t != NULL; t = t->next) { if (t->subcommands != NULL) { t->subcommands = msort_list(t->subcommands); } } } // NOTE(adma): the prototype for el functions is fixed, no way to pass // in parameters, we must use globals CommandList g_commands; static bool g_running = true; static cmd_format g_in_fmt, g_out_fmt; // NOTE(adma): Print the command history // argc = 0 int yh_com_history(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(in_fmt); UNUSED(fmt); UNUSED(ctx); UNUSED(argv); #ifndef __WIN32 HistEvent ev; int rv; for (rv = history(g_hist, &ev, H_LAST); rv != -1; rv = history(g_hist, &ev, H_PREV)) { fprintf(ctx->out, "%4d %s", ev.num, ev.str); } #endif return 0; } static const char *fmt_to_string(cmd_format fmt) { for (size_t i = 0; i < sizeof(formats) / sizeof(formats[0]); i++) { if (formats[i].format == fmt) { return formats[i].name; } } return "No format"; } // NOTE(adma): Print information about a command // argc = 1 // arg 0: s:command int yh_com_help(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(in_fmt); UNUSED(fmt); UNUSED(ctx); bool match = false; // TODO(adma): once we have optional commands we can have a real help for (Command *command = g_commands; command; command = command->next) { if (strncmp(argv[0].s, command->name, strlen(argv[0].s)) == 0) { match = true; printf("%-25s%s\n", command->name, command->doc); if (strlen(argv[0].s)) { if (command->args) { printf("%-5s%s", "", command->args); if (command->in_fmt != fmt_nofmt) { printf(" (default input format: %s)", fmt_to_string(command->in_fmt)); } printf("\n"); } for (Command *subcommand = command->subcommands; subcommand; subcommand = subcommand->next) { printf("%-5s%-25s%s", "", subcommand->name, subcommand->doc); if (subcommand->args) { if (subcommand->in_fmt != fmt_nofmt) { printf(" (default input format: %s)", fmt_to_string(subcommand->in_fmt)); } printf("\n%-30s%s\n", "", subcommand->args); } else { printf("\n"); } } } } } if (match == false) { printf("Help for command %s not found\n", argv[0].s); } return 0; } // NOTE(adma): Quit // argc = 0 int yh_com_quit(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(in_fmt); UNUSED(fmt); UNUSED(ctx); UNUSED(argv); g_running = false; return 0; } static bool probe_session(yubihsm_context *ctx, size_t index) { if (ctx->sessions[index]) { uint8_t data = 0xff; uint8_t response[YH_MSG_BUF_SIZE]; size_t response_len = sizeof(response); yh_cmd response_cmd; yh_rc yrc; // silently ignore transmit errors..? if ((yrc = yh_send_secure_msg(ctx->sessions[index], YHC_ECHO, &data, 1, &response_cmd, response, &response_len)) != YHR_SUCCESS) { yh_destroy_session(&ctx->sessions[index]); fprintf(stderr, "Failed to probe session %zu: %s\n", index, yh_strerror(yrc)); return false; } return true; } else { return false; } } #ifdef __WIN32 static void WINAPI timer_handler(void *lpParam, unsigned char TimerOrWaitFired) { UNUSED(TimerOrWaitFired); #else static void timer_handler(int signo __attribute__((unused))) { #endif if (calling_device == true || g_ctx.connector == NULL) { return; } for (size_t i = 0; i < sizeof(g_ctx.sessions) / sizeof(g_ctx.sessions[0]); i++) { probe_session(&g_ctx, i); } } static int set_keepalive(uint16_t seconds) { #ifdef __WIN32 HANDLE timer; static HANDLE timerQueue = NULL; if (timerQueue != NULL) { DeleteTimerQueue(timerQueue); } timerQueue = CreateTimerQueue(); if (timerQueue == NULL) { fprintf(stderr, "Failed to setup timer\n"); return 1; } CreateTimerQueueTimer(&timer, timerQueue, timer_handler, NULL, seconds * 1000, seconds * 1000, 0); if (timer == NULL) { fprintf(stderr, "Failed to start time\n"); return 1; } #else struct itimerval itimer; itimer.it_interval.tv_sec = seconds; itimer.it_interval.tv_usec = 0; itimer.it_value.tv_sec = seconds; itimer.it_value.tv_usec = 0; if (setitimer(ITIMER_REAL, &itimer, NULL) != 0) { fprintf(stderr, "Failed to setup timer\n"); return 1; } #endif fprintf(stderr, "Session keepalive set up to run every %d seconds\n", seconds); return 0; } // NOTE: Enable keepalive // argc = 0 int yh_com_keepalive_on(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(ctx); UNUSED(argv); UNUSED(in_fmt); UNUSED(fmt); return set_keepalive(15); } // NOTE: Disable keepalive // argc = 0 int yh_com_keepalive_off(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(ctx); UNUSED(argv); UNUSED(in_fmt); UNUSED(fmt); return set_keepalive(0); } int yh_com_set_informat(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(ctx); UNUSED(in_fmt); UNUSED(fmt); for (size_t i = 0; i < sizeof(formats) / sizeof(formats[0]); i++) { if (strcasecmp(argv[0].s, formats[i].name) == 0) { g_in_fmt = formats[i].format; return 0; } } fprintf(stderr, "Failed to parse input format\n"); return -1; } int yh_com_set_outformat(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt) { UNUSED(ctx); UNUSED(in_fmt); UNUSED(fmt); for (size_t i = 0; i < sizeof(formats) / sizeof(formats[0]); i++) { if (strcasecmp(argv[0].s, formats[i].name) == 0) { if (formats[i].format == fmt_password) { break; } g_out_fmt = formats[i].format; return 0; } } fprintf(stderr, "Failed to parse output format\n"); return -1; } static void find_lcp(const char *items[], int n_items, const char **lcp, int *lcp_len) { int min = 0; int max = 0; if (items == NULL || n_items == 0) { *lcp = NULL; *lcp_len = 0; } for (int i = 1; i < n_items; i++) { if (strcmp(items[i], items[min]) < 0) { min = i; } else if (strcmp(items[i], items[max]) > 0) { max = i; } } *lcp = items[min]; for (size_t i = 0; i < strlen(items[min]) && i < strlen(items[max]); i++) { if (items[min][i] != items[max][i]) { *lcp_len = i; return; } } *lcp_len = strlen(items[min]); } static int tokenize(char *line, char **toks, int max_toks, int *cursorc, int *cursoro, const char *space) { int i; int tok = 0; int length = strlen(line); int start_of_word = 0; enum states { WHITESPACE, WORD, QUOTE } state = WHITESPACE; toks[0] = line; // set up as fall-through for (i = 0; i <= length; i++) { char c = line[i]; if (cursorc && i == *cursorc && tok > 0) { if (state == WHITESPACE) { *cursoro = 0; *cursorc = tok; } else { *cursoro = i - start_of_word; *cursorc = tok - 1; } } if (c == '\0') { break; } if (tok >= max_toks) { return -1; } switch (state) { case WHITESPACE: { bool found = false; for (size_t j = 0; j < strlen(space); j++) { if (c == space[j]) { found = true; break; } } if (found) { break; } if (c == '"') { state = QUOTE; start_of_word = i + 1; } else if (c == '#') { return tok; } else { state = WORD; start_of_word = i; } toks[tok++] = line + start_of_word; } break; case QUOTE: if (c == '"') { line[i] = '\0'; state = WHITESPACE; } break; case WORD: for (size_t j = 0; j < strlen(space); j++) { if (c == space[j]) { line[i] = '\0'; state = WHITESPACE; } } break; } } return tok; } #ifndef __WIN32 static int compare_strings(const void *a, const void *b) { return strcmp(*(char *const *) a, *(char *const *) b); } static unsigned char complete_arg(EditLine *el, const char *arg, char *line, int cursoro) { const char *candidates[COMPLETION_CANDIDATES]; int n_candidates = 0; struct winsize w; const LineInfo *li = el_line(el); ioctl(fileno(stdout), TIOCGWINSZ, &w); int lines = (li->cursor - li->buffer + strlen(PROMPT)) / w.ws_col; switch (arg[0]) { case 'u': printf("\nnumber"); break; case 'w': printf("\nword"); break; case 'b': printf("\nbyte"); break; case 'i': printf("\ninput data"); break; case 'F': printf("\noutput filename"); break; case 's': printf("\nstring"); break; case 'k': printf("\nkey"); break; case 'e': printf("\nsession"); break; case 'd': printf("\ndomains"); break; case 'c': { char *toks[COMPLETION_CANDIDATES]; int cursorc = cursoro; int num_toks = tokenize(line, toks, COMPLETION_CANDIDATES, &cursorc, &cursoro, ":,;|"); if (cursorc == num_toks) { toks[cursorc] = ""; } for (size_t i = 0; i < sizeof(yh_capability) / sizeof(yh_capability[0]); i++) { if (strncasecmp(toks[cursorc], yh_capability[i].name, strlen(toks[cursorc])) == 0) { candidates[n_candidates++] = yh_capability[i].name; assert(n_candidates < COMPLETION_CANDIDATES); } } } break; case 'a': for (size_t i = 0; i < sizeof(yh_algorithms) / sizeof(yh_algorithms[0]); i++) { if (strncasecmp(line, yh_algorithms[i].name, strlen(line)) == 0) { candidates[n_candidates++] = yh_algorithms[i].name; assert(n_candidates < COMPLETION_CANDIDATES); } } break; case 't': for (size_t i = 0; i < sizeof(yh_types) / sizeof(yh_types[0]); i++) { if (strncasecmp(line, yh_types[i].name, strlen(line)) == 0) { candidates[n_candidates++] = yh_types[i].name; assert(n_candidates < COMPLETION_CANDIDATES); } } break; case 'o': for (size_t i = 0; i < sizeof(yh_options) / sizeof(yh_options[0]); i++) { if (strncasecmp(line, yh_options[i].name, strlen(line)) == 0) { candidates[n_candidates++] = yh_options[i].name; assert(n_candidates < COMPLETION_CANDIDATES); } } break; case 'I': for (size_t i = 0; i < sizeof(formats) / sizeof(formats[0]); i++) { if (strncasecmp(line, formats[i].name, strlen(line)) == 0) { candidates[n_candidates++] = formats[i].name; assert(n_candidates < COMPLETION_CANDIDATES); } } break; case '\0': // NOTE(adma): completing an empty string, we reached the end, do // nothing return CC_ERROR; default: printf("\nunknown type"); break; } switch (n_candidates) { case 0: { int i = 1; while (arg[i] != '\0' && arg[i] != ',') { i++; } printf("%*.*s\n", i, i - 1, arg + 1); } break; case 1: el_insertstr(el, candidates[0] + cursoro); return CC_REDISPLAY; default: { const char *lcp; int lcp_len; qsort(candidates, n_candidates, sizeof(char *), compare_strings); find_lcp(candidates, n_candidates, &lcp, &lcp_len); if (cursoro == lcp_len) { // NOTE(adma): we already have lcp_len characters typed on // the prompt, display all the possible matches printf("\n"); for (int i = 0; i < n_candidates; i++) { printf("%s\n", candidates[i]); } } else { // NOTE(adma): we found an lcp, autocomplete with that char prefix[MAX_COMMAND_NAME]; strcpy(prefix, lcp + cursoro); prefix[lcp_len - cursoro] = '\0'; el_insertstr(el, prefix); return CC_REDISPLAY; } } } for (int i = 0; i < lines; i++) { printf("\n"); } return CC_REDISPLAY; } static unsigned char complete_command(EditLine *el, Command *to_complete, const char *line, int cursoro) { const char *candidates[COMPLETION_CANDIDATES]; int n_candidates = 0; // NOTE(adma): try to autocomplete the current command/subcomand for (Command *command = to_complete; command; command = command->next) { if (strncmp(line, command->name, strlen(line)) == 0) { // printf("%s\n", command->name); candidates[n_candidates++] = command->name; assert(n_candidates < COMPLETION_CANDIDATES); } else if (n_candidates != 0) { // NOTE(adma): the list is sorted no point in continuing, // bail out break; } } // printf("Found %d candidates\n", n_candidates); switch (n_candidates) { case 0: // NOTE(adma): no matches, do nothing return CC_ERROR; case 1: // NOTE(adma): only one match, autocomplete! el_insertstr(el, candidates[0] + cursoro); el_insertstr(el, " "); return CC_REDISPLAY; default: { // NOTE(adma): several matches, find longest common prefix const char *lcp; int lcp_len; find_lcp(candidates, n_candidates, &lcp, &lcp_len); if (cursoro == lcp_len) { // NOTE(adma): we already have lcp_len characters typed on // the prompt, display all the possible matches printf("\n"); for (int i = 0; i < n_candidates; i++) { printf("%s\n", candidates[i]); } } else { // NOTE(adma): we found an lcp, autocomplete with that char prefix[MAX_COMMAND_NAME]; strcpy(prefix, lcp + cursoro); prefix[lcp_len - cursoro] = '\0'; el_insertstr(el, prefix); } } return CC_REDISPLAY; } } static unsigned char yubihsm_complete(EditLine *el, int ch) { UNUSED(ch); const LineInfo *li; int argc, cursorc = 0, cursoro = 0; char *argv[64]; char data[ARGS_BUFFER_SIZE + 1] = {0}; li = el_line(el); cursorc = li->cursor - li->buffer; if (li->lastchar - li->buffer > 1024) { return CC_REDISPLAY; } memcpy(data, li->buffer, li->lastchar - li->buffer); argc = tokenize(data, argv, 64, &cursorc, &cursoro, SPACES); // printf("\nargc %d, cursorc: %d, cursoro: %d\n", argc, cursorc, cursoro); if (argc == 0) { // NOTE(adma): no prompt, don't even bother with finding a match, // just show all commands, one per line printf("\n"); for (Command *command = g_commands; command; command = command->next) { printf("%s\n", command->name); } return CC_REDISPLAY; } else { int i = 0; Command *command = g_commands; Command *to_complete = NULL; char *args = ""; bool completing_args = false; while (i < cursorc) { // NOTE(adma): match the first n-1 items if (completing_args == false) { // NOTE(adma): match subcommands if (strncmp(argv[i], command->name, strlen(argv[i])) == 0) { // printf("\nmatched %s\n", command->name); to_complete = command; // to_complete_position = i; if (command->subcommands != NULL) { // NOTE(adma): if we were matching subcommands, keep // matching subcommands if any command = command->subcommands; } else { // NOTE(adma): start matching arguments otherwise completing_args = true; if (command->args != NULL) { args = command->args; } else { // NOTE(adma): there are no args for this command break; } } i++; // NOTE(adma): next word } else { command = command->next; if (command == NULL) { // NOTE(adma): command not found break; } } } else { // NOTE(adma): match arguments while (*args != '\0' && *args != ',') { args++; } if (*args == ',') { args++; i++; // NOTE(adma): next word } else { break; } } } if (to_complete && cursorc != 0) { // NOTE(adma): 0 has a bit of a special meaning since the cursor // is after the last letter of the first word and we still want // to autocomplete commands and not subcommands nor args in that // case to_complete = to_complete->subcommands; } if (argc == cursorc) { if (to_complete && completing_args == false) { // NOTE(adma): cursor is after a command but there is no more // text to match, show all subcommands printf("\n"); for (Command *iter = to_complete; iter; iter = iter->next) { printf("%s\n", iter->name); } return CC_REDISPLAY; } else { // NOTE(adma): or show the current argument return complete_arg(el, args, "", 0); } } else { if (completing_args == false) { if (to_complete == NULL) { to_complete = g_commands; } return complete_command(el, to_complete, argv[i], cursoro); } else { return complete_arg(el, args, argv[i], cursoro); } } } return CC_ERROR; } static char *prompt(EditLine *el) { UNUSED(el); return PROMPT; } #else char *converting_fgets(char *s, int size, FILE *stream) { int translation = _setmode(_fileno(stream), _O_U16TEXT); if (translation == -1) { return NULL; } wchar_t *wide_str = calloc(size, sizeof(wchar_t)); if (wide_str == NULL) { _setmode(_fileno(stream), translation); return NULL; } fgetws(wide_str, sizeof(wchar_t) * size, stream); int len = WideCharToMultiByte(CP_UTF8, 0, wide_str, -1, s, size, NULL, NULL); free(wide_str); wide_str = NULL; _setmode(_fileno(stream), translation); if (len == 0) { return NULL; } return s; } #endif static FILE *open_file(const char *name, bool input) { if (input) { if (strcmp(name, "-") == 0) { return stdin; } else { return fopen(name, "rb"); } } else { if (strcmp(name, "-") == 0) { return stdout; } else { return fopen(name, "ab"); } } } static bool get_input_data(const char *name, uint8_t **out, size_t *len, cmd_format fmt) { const char *fname = strncasecmp(name, "file:", 5) ? name : name + 5; struct stat sb = {0}; int st_res = stat(fname, &sb); if (st_res == 0 && S_ISREG(sb.st_mode)) { *len = sb.st_size; } else { *len = ARGS_BUFFER_SIZE; } *out = calloc(*len + 1, 1); if (*out == 0) { fprintf(stderr, "Failed to allocate %zu bytes memory for %s\n", *len, fname); return false; } if (!strcmp(name, "-") || fname != name || (st_res == 0 && S_ISREG(sb.st_mode))) { bool ret = false; FILE *file = open_file(fname, true); if (!file) { return false; } if (file == stdin && fmt == fmt_password) { #ifndef __WIN32 // NOTE: we have to stop the timer around the call to // EVP_read_pw_string(), openssl gets sad if a signal hits while waiting // for input from the user. So we stop the timer and restore it when we're // done struct itimerval stoptimer, oldtimer; memset(&stoptimer, 0, sizeof(stoptimer)); if (setitimer(ITIMER_REAL, &stoptimer, &oldtimer) != 0) { fprintf(stderr, "Failed to setup timer\n"); return false; } #endif if (EVP_read_pw_string((char *) *out, *len - 1, "Enter password: ", 0) == 0) { *len = strlen((char *) *out); ret = true; } #ifndef __WIN32 if (setitimer(ITIMER_REAL, &oldtimer, NULL) != 0) { fprintf(stderr, "Failed to restore timer\n"); return false; } #endif } else if (read_file(file, *out, len)) { ret = true; } if (file != stdin) { fclose(file); } if (ret == false) { return ret; } } else { if (strlen(name) < *len) { memcpy(*out, name, strlen(name)); *len = strlen(name); } else { return false; } } switch (fmt) { case fmt_base64: if (base64_decode((char *) *out, *out, len)) { return true; } break; case fmt_hex: if (hex_decode((char *) *out, *out, len)) { return true; } break; case fmt_password: // If the password was read from a file, strip off \r\n if (*len > 0 && (*out)[*len - 1] == '\n') { (*len)--; } if (*len > 0 && (*out)[*len - 1] == '\r') { (*len)--; } (*out)[*len] = '\0'; return true; case fmt_binary: // these all require no extra work, just pass data on. case fmt_PEM: case fmt_ASCII: return true; case fmt_nofmt: default: return false; } return false; } static int validate_arg(yubihsm_context *ctx, char type, const char *value, Argument *parsed, cmd_format fmt) { switch (type) { case 'b': // byte case 'w': // word case 'e': // session case 'u': { // unsigned long uint32_t max = 0; if (type == 'b') { max = UCHAR_MAX; } else if (type == 'w' || type == 'e') { max = USHRT_MAX; } else if (type == 'u') { max = UINT_MAX; } // NOTE(adma): check that is a positive number in dec, hex or oct errno = 0; char *endptr; unsigned long num = strtoul(value, &endptr, 0); if ((errno == ERANGE || num > max) || (errno != 0 && num == 0)) { return -1; } if (endptr == value) { return -1; } if (type == 'b') { parsed->b = (uint8_t) num; } else if (type == 'e') { if (num >= sizeof(ctx->sessions) / sizeof(ctx->sessions[0]) || ctx->sessions[num] == NULL) { return -1; } parsed->e = ctx->sessions[num]; } else if (type == 'w') { parsed->w = (uint16_t) num; } else if (type == 'u') { parsed->d = (uint32_t) num; } parsed->len = 1; // NOTE(adma): doesn't really have a meaning } break; case 'F': parsed->s = value; parsed->len = strlen(value); ctx->out = open_file(value, false); if (!ctx->out) { return -1; } break; case 'i': if (get_input_data(value, &parsed->x, &parsed->len, fmt) == false) { return -1; } break; case 'I': case 's': // NOTE(adma): strings are pretty much always OK parsed->s = value; parsed->len = strlen(value); break; case 'd': if (yh_string_to_domains(value, &parsed->w) != YHR_SUCCESS) { return -1; } break; case 'c': if (yh_string_to_capabilities(value, &parsed->c) != YHR_SUCCESS) { return -1; } break; case 'a': if (yh_string_to_algo(value, &parsed->a) != YHR_SUCCESS) { return -1; } break; case 't': if (yh_string_to_type(value, &parsed->t) != YHR_SUCCESS) { return -1; } break; case 'o': if (yh_string_to_option(value, &parsed->o) != YHR_SUCCESS) { return -1; } break; default: // NOTE(adma): unknown type return -1; } return 0; } static int validate_and_call(yubihsm_context *ctx, CommandList l, const char *line) { int argc = 0; char *argv[64]; int i = 0; char data[ARGS_BUFFER_SIZE + 1]; char arg_data[ARGS_BUFFER_SIZE + 1] = {0}; Command *command = l; bool completing_args = false; const char *args = ""; Argument arguments[MAX_ARGUMENTS] = {{{0}, 0, 0}}; int n_arguments = 0; bool invalid_arg = false; int match; bool found = false; CommandFunction *func = NULL; memset(data, 0x0, sizeof(data)); memset(arg_data, 0x0, sizeof(data)); if (strlen(line) > ARGS_BUFFER_SIZE) { printf("Command too long\n"); return 0; } strcpy(data, line); argc = tokenize(data, argv, 64, NULL, NULL, SPACES); while (i < argc) { // NOTE(adma): match the first n-1 items if (completing_args == false) { // NOTE(adma): match subcommands match = strncmp(argv[i], command->name, strlen(argv[i])); if (match == 0) { if (command->subcommands != NULL) { // NOTE(adma): if we were matching subcommands, keep // matching subcommands if any command = command->subcommands; } else { // NOTE(adma): start matching arguments otherwise. Also keep // track of the function because that's the one we want to // call later on completing_args = true; func = command->func; if (command->args != NULL) { char *arg_toks[64]; args = command->args; strncpy(arg_data, args, ARGS_BUFFER_SIZE); // since tokenize() modifies the buffer.. int num_args = tokenize(arg_data, arg_toks, 64, NULL, NULL, ","); if (num_args + 1 + i != argc) { // some arguments might have default values for (int j = 0; j < num_args; j++) { if (j < argc - 1 - i) { continue; } char *str = strchr(arg_toks[j], '='); if (str == NULL) { break; } str++; argv[j + 1 + i] = str; argc++; } } } else { // NOTE(adma): there are no args for this command found = true; break; } } i++; // NOTE(adma): next word } else { // NOTE(adma): command not found command = command->next; if (match < 0 || command == NULL) { command = NULL; break; } } } else { // NOTE(adma): match arguments if (validate_arg(ctx, *args, argv[i], arguments + n_arguments++, g_in_fmt != fmt_nofmt ? g_in_fmt : command->in_fmt) != 0) { invalid_arg = true; break; } while (*args != '\0' && *args != ',') { args++; } if (*args == ',') { args++; i++; // NOTE(adma): next word } else { found = true; break; } } } if (found == true) { calling_device = true; func(ctx, arguments, g_in_fmt == fmt_nofmt ? command->in_fmt : g_in_fmt, g_out_fmt == fmt_nofmt ? command->out_fmt : g_out_fmt); calling_device = false; for (i = 0; i < n_arguments; i++) { if (arguments[i].x != NULL) { free(arguments[i].x); arguments[i].x = NULL; } } // NOTE: if ctx->in or ctx->out is changed, close and return state, // otherwise the next command that needs a file might get sad. if (ctx->out != stdout) { fclose(ctx->out); ctx->out = stdout; } } else { if (invalid_arg == true) { char arg[ARGS_BUFFER_SIZE + 1]; memset(arg, 0x0, sizeof(arg)); strncpy(arg, args, ARGS_BUFFER_SIZE); char *end = strchr(args, ','); if (end) { arg[end - args] = '\0'; } printf("Invalid argument %d: %s (%s)\n", i, argv[i], arg); } else if (command == NULL) { printf("Command %s%s%s not found\n", argv[0], i ? " " : "", i ? argv[1] : ""); } else if (*args != '\0' || argc - 1 == 0) { printf("Incomplete command\n"); for (i = 0; i < argc; i++) { arguments[i].s = argv[i]; } yh_com_help(NULL, arguments, fmt_nofmt, fmt_nofmt); } } return 0; } static void free_configured_connectors(yubihsm_context *ctx) { if (ctx->connector_list) { for (int i = 0; ctx->connector_list[i]; i++) { free(ctx->connector_list[i]); } free(ctx->connector_list); ctx->connector_list = NULL; } } static int parse_configured_connectors(yubihsm_context *ctx, char **connectors, int n_connectors) { ctx->connector_list = calloc(n_connectors + 1, sizeof(char *)); if (ctx->connector_list == NULL) { return -1; } for (int i = 0; i < n_connectors; i++) { ctx->connector_list[i] = strdup(connectors[i]); if (ctx->connector_list[i] == NULL) { free_configured_connectors(ctx); return -1; } } return 0; } static void free_configured_pubkeys(yubihsm_context *ctx) { if (ctx->device_pubkey_list) { for (int i = 0; ctx->device_pubkey_list[i]; i++) { free(ctx->device_pubkey_list[i]); } free(ctx->device_pubkey_list); ctx->device_pubkey_list = NULL; } } static int parse_configured_pubkeys(yubihsm_context *ctx, char **pubkeys, int n_pubkeys) { ctx->device_pubkey_list = calloc(n_pubkeys + 1, sizeof(uint8_t *)); if (ctx->device_pubkey_list == NULL) return -1; for (int i = 0; i < n_pubkeys; i++) { uint8_t pk[80]; size_t pk_len = sizeof(pk); hex_decode(pubkeys[i], pk, &pk_len); if (pk_len == YH_EC_P256_PUBKEY_LEN) { ctx->device_pubkey_list[i] = malloc(pk_len); } if (ctx->device_pubkey_list[i]) { memcpy(ctx->device_pubkey_list[i], pk, pk_len); } else { free_configured_pubkeys(ctx); return -1; } } return 0; } int main(int argc, char *argv[]) { yh_rc yrc; int comrc; int rc = EXIT_SUCCESS; struct gengetopt_args_info args_info; struct stat sb; struct cmdline_parser_params params; if (setlocale(LC_ALL, "") == NULL) { fprintf(stderr, "Warning, unable to reset locale\n"); } g_ctx.out = stdout; cmdline_parser_params_init(¶ms); params.initialize = 1; params.check_required = 0; if (cmdline_parser(argc, argv, &args_info) != 0) { return EXIT_FAILURE; } if (stat(args_info.config_file_arg, &sb) == 0) { if (S_ISREG(sb.st_mode) || S_ISLNK(sb.st_mode)) { params.initialize = 0; if (cmdline_parser_config_file(args_info.config_file_arg, &args_info, ¶ms) != 0) { return EXIT_FAILURE; } } } if (cmdline_parser_required(&args_info, argv[0]) != 0) { return EXIT_FAILURE; } switch (args_info.informat_arg) { case informat_arg_base64: g_in_fmt = fmt_base64; break; case informat_arg_binary: g_in_fmt = fmt_binary; break; case informat_arg_PEM: g_in_fmt = fmt_PEM; break; case informat_arg_password: g_in_fmt = fmt_password; break; case informat_arg_hex: g_in_fmt = fmt_hex; break; case informat__NULL: case informat_arg_default: default: g_in_fmt = fmt_nofmt; break; } switch (args_info.outformat_arg) { case outformat_arg_base64: g_out_fmt = fmt_base64; break; case outformat_arg_binary: g_out_fmt = fmt_binary; break; case outformat_arg_PEM: g_out_fmt = fmt_PEM; break; case outformat_arg_hex: g_out_fmt = fmt_hex; break; case outformat__NULL: case outformat_arg_default: default: g_out_fmt = fmt_nofmt; break; } if (parse_configured_connectors(&g_ctx, args_info.connector_arg, args_info.connector_given) == -1) { fprintf(stderr, "Unable to parse connector list\n"); rc = EXIT_FAILURE; goto main_exit; } if (parse_configured_pubkeys(&g_ctx, args_info.device_pubkey_arg, args_info.device_pubkey_given) == -1) { fprintf(stderr, "Unable to parse device pubkey list\n"); rc = EXIT_FAILURE; goto main_exit; } if (getenv("DEBUG") != NULL) { args_info.verbose_arg = YH_VERB_ALL; } yh_set_verbosity(g_ctx.connector, args_info.verbose_arg); yrc = yh_init(); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to initialize libyubihsm\n"); rc = EXIT_FAILURE; goto main_exit; } ykhsmauth_rc ykhsmauthrc; ykhsmauthrc = ykhsmauth_init(&g_ctx.state, 1); // TODO(adma): do something about verbosity if (ykhsmauthrc != YKHSMAUTHR_SUCCESS) { fprintf(stderr, "Failed to initialize libykhsmauth\n"); rc = EXIT_FAILURE; goto main_exit; } if (g_ctx.connector_list[0] == NULL) { fprintf(stderr, "Using default connector URL: %s\n", DEFAULT_CONNECTOR_URL); char *default_connector_url = DEFAULT_CONNECTOR_URL; free_configured_connectors(&g_ctx); parse_configured_connectors(&g_ctx, &default_connector_url, 1); } if (args_info.cacert_given) { g_ctx.cacert = strdup(args_info.cacert_arg); } if (args_info.cert_given) { g_ctx.cert = strdup(args_info.cert_arg); } if (args_info.key_given) { g_ctx.key = strdup(args_info.key_arg); } if (args_info.proxy_given) { g_ctx.proxy = strdup(args_info.proxy_arg); } if (args_info.noproxy_given) { g_ctx.noproxy = strdup(args_info.noproxy_arg); } #ifndef __WIN32 struct sigaction act; memset(&act, 0, sizeof(act)); act.sa_handler = timer_handler; act.sa_flags = SA_RESTART; sigaction(SIGALRM, &act, NULL); sigset_t set; sigemptyset(&set); sigaddset(&set, SIGALRM); sigprocmask(SIG_UNBLOCK, &set, NULL); #endif if (args_info.action_given) { g_ctx.out = open_file(args_info.out_arg, false); if (g_ctx.out == NULL) { fprintf(stderr, "Unable to open output file %s\n", args_info.out_arg); rc = EXIT_FAILURE; goto main_exit; } yh_com_connect(&g_ctx, NULL, fmt_nofmt, fmt_nofmt); bool requires_session = false; for (unsigned i = 0; i < args_info.action_given; i++) { switch (args_info.action_arg[i]) { case action_arg_getMINUS_deviceMINUS_info: case action_arg_getMINUS_deviceMINUS_pubkey: requires_session = false; break; default: requires_session = true; } if (requires_session == true) { break; } } Argument arg[11] = {0}; if (requires_session == true) { uint8_t *buf = 0; size_t pw_len = 0; arg[0].w = args_info.authkey_arg; if (get_input_data(args_info.password_given ? args_info.password_arg : "-", &buf, &pw_len, fmt_password) == false) { fprintf(stderr, "Failed to get password\n"); rc = EXIT_FAILURE; goto main_exit; } if (args_info.ykhsmauth_label_given) { arg[1].s = args_info.ykhsmauth_label_arg; arg[1].len = strlen(args_info.ykhsmauth_label_arg); arg[2].x = buf; arg[2].len = pw_len; arg[3].s = args_info.ykhsmauth_reader_arg; arg[3].len = strlen(args_info.ykhsmauth_reader_arg); comrc = yh_com_open_yksession(&g_ctx, arg, fmt_password, fmt_nofmt); } else { arg[1].x = buf; arg[1].len = pw_len; comrc = yh_com_open_session(&g_ctx, arg, fmt_password, fmt_nofmt); } insecure_memzero(buf, pw_len); free(buf); if (comrc != 0) { fprintf(stderr, "Failed to open session\n"); rc = EXIT_FAILURE; goto main_exit; } } for (size_t i = 0; i < sizeof(g_ctx.sessions) / sizeof(g_ctx.sessions[0]); i++) { if (g_ctx.sessions[i] != NULL) { arg[0].e = g_ctx.sessions[i]; break; } } calling_device = true; for (unsigned i = 0; i < args_info.action_given; i++) { switch (args_info.action_arg[i]) { case action_arg_decryptMINUS_pkcs1v15: { arg[1].w = args_info.object_id_arg; if (get_input_data(args_info.in_arg, &arg[2].x, &arg[2].len, g_in_fmt == fmt_nofmt ? fmt_binary : g_in_fmt) == false) { fprintf(stderr, "Failed to get input data\n"); rc = EXIT_FAILURE; break; } comrc = yh_com_decrypt_pkcs1v1_5(&g_ctx, arg, fmt_nofmt, g_out_fmt == fmt_nofmt ? fmt_binary : g_out_fmt); free(arg[2].x); COM_SUCCEED_OR_DIE(comrc, "Unable to decrypt data"); } break; case action_arg_decryptMINUS_oaep: { if (args_info.object_id_given == 0) { fprintf(stderr, "Missing object id\n"); rc = EXIT_FAILURE; break; } if (args_info.algorithm_given == 0) { fprintf(stderr, "Missing argument algorithm\n"); rc = EXIT_FAILURE; break; } arg[1].w = args_info.object_id_arg; yrc = yh_string_to_algo(args_info.algorithm_arg, &arg[2].a); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse algorithm: "); if (get_input_data(args_info.in_arg, &arg[3].x, &arg[3].len, g_in_fmt == fmt_nofmt ? fmt_binary : g_in_fmt) == false) { fprintf(stderr, "Failed to get input data\n"); rc = EXIT_FAILURE; break; } arg[4].s = args_info.label_arg; arg[4].len = strlen(args_info.label_arg); comrc = yh_com_decrypt_oaep(&g_ctx, arg, fmt_nofmt, g_out_fmt == fmt_nofmt ? fmt_binary : g_out_fmt); free(arg[3].x); COM_SUCCEED_OR_DIE(comrc, "Unable to decrypt data"); } break; case action_arg_deriveMINUS_ecdh: { arg[1].w = args_info.object_id_arg; if (get_input_data(args_info.in_arg, &arg[2].x, &arg[2].len, g_in_fmt == fmt_nofmt ? fmt_binary : g_in_fmt) == false) { fprintf(stderr, "Failed to get input data\n"); rc = EXIT_FAILURE; break; } comrc = yh_com_derive_ecdh(&g_ctx, arg, fmt_nofmt, g_out_fmt == fmt_nofmt ? fmt_hex : g_out_fmt); free(arg[2].x); COM_SUCCEED_OR_DIE(comrc, "Unable to perform ECDH key exchange"); } break; case action_arg_decryptMINUS_aesccm: case action_arg_encryptMINUS_aesccm: LIB_SUCCEED_OR_DIE(YHR_GENERIC_ERROR, "Command not implemented: "); case action_arg_encryptMINUS_aescbc: case action_arg_decryptMINUS_aescbc: { if (args_info.iv_given == 0) { fprintf(stderr, "Missing argument IV\n"); rc = EXIT_FAILURE; break; } arg[1].w = args_info.object_id_arg; arg[2].s = args_info.iv_arg; if (get_input_data(args_info.in_arg, &arg[3].x, &arg[3].len, g_in_fmt == fmt_nofmt ? fmt_binary : g_in_fmt) == false) { fprintf(stderr, "Failed to get input data\n"); rc = EXIT_FAILURE; break; } if (args_info.action_arg[i] == action_arg_encryptMINUS_aescbc) { comrc = yh_com_encrypt_aes_cbc(&g_ctx, arg, fmt_nofmt, g_out_fmt == fmt_nofmt ? fmt_binary : g_out_fmt); free(arg[3].x); COM_SUCCEED_OR_DIE(comrc, "Unable to encrypt input"); } else { comrc = yh_com_decrypt_aes_cbc(&g_ctx, arg, fmt_nofmt, g_out_fmt == fmt_nofmt ? fmt_binary : g_out_fmt); free(arg[3].x); COM_SUCCEED_OR_DIE(comrc, "Unable to decrypt input"); } } break; case action_arg_encryptMINUS_aesecb: case action_arg_decryptMINUS_aesecb: { arg[1].w = args_info.object_id_arg; if (get_input_data(args_info.in_arg, &arg[2].x, &arg[2].len, g_in_fmt == fmt_nofmt ? fmt_binary : g_in_fmt) == false) { fprintf(stderr, "Failed to get input data\n"); rc = EXIT_FAILURE; break; } if (args_info.action_arg[i] == action_arg_encryptMINUS_aesecb) { comrc = yh_com_encrypt_aes_ecb(&g_ctx, arg, fmt_nofmt, g_out_fmt == fmt_nofmt ? fmt_binary : g_out_fmt); free(arg[2].x); COM_SUCCEED_OR_DIE(comrc, "Unable to encrypt input"); } else { comrc = yh_com_decrypt_aes_ecb(&g_ctx, arg, fmt_nofmt, g_out_fmt == fmt_nofmt ? fmt_binary : g_out_fmt); free(arg[2].x); COM_SUCCEED_OR_DIE(comrc, "Unable to decrypt input"); } } break; case action_arg_generateMINUS_asymmetricMINUS_key: { if (args_info.algorithm_given == 0) { fprintf(stderr, "Missing argument algorithm\n"); rc = EXIT_FAILURE; break; } arg[1].w = args_info.object_id_arg; arg[2].s = args_info.label_arg; arg[2].len = strlen(args_info.label_arg); yrc = yh_string_to_domains(args_info.domains_arg, &arg[3].w); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse domains: "); memset(&arg[4].c, 0, sizeof(yh_capabilities)); yrc = yh_string_to_capabilities(args_info.capabilities_arg, &arg[4].c); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse capabilities: "); yrc = yh_string_to_algo(args_info.algorithm_arg, &arg[5].a); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse algorithm: "); comrc = yh_com_generate_asymmetric(&g_ctx, arg, fmt_nofmt, fmt_nofmt); COM_SUCCEED_OR_DIE(comrc, "Unable to generate asymmetric key"); } break; case action_arg_generateMINUS_hmacMINUS_key: { if (args_info.algorithm_given == 0) { fprintf(stderr, "Missing argument algorithm\n"); rc = EXIT_FAILURE; break; } arg[1].w = args_info.object_id_arg; arg[2].s = args_info.label_arg; arg[2].len = strlen(args_info.label_arg); yrc = yh_string_to_domains(args_info.domains_arg, &arg[3].w); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse domains: "); memset(&arg[4].c, 0, sizeof(yh_capabilities)); yrc = yh_string_to_capabilities(args_info.capabilities_arg, &arg[4].c); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse capabilities: "); yrc = yh_string_to_algo(args_info.algorithm_arg, &arg[5].a); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse algorithm: "); comrc = yh_com_generate_hmac(&g_ctx, arg, fmt_nofmt, fmt_nofmt); COM_SUCCEED_OR_DIE(comrc, "Unable to generate hmac key"); } break; case action_arg_generateMINUS_wrapMINUS_key: { if (args_info.algorithm_given == 0) { fprintf(stderr, "Missing argument algorithm\n"); rc = EXIT_FAILURE; break; } if (args_info.delegated_given == 0) { fprintf(stderr, "Missing delegated capabilities\n"); rc = EXIT_FAILURE; break; } arg[1].w = args_info.object_id_arg; arg[2].s = args_info.label_arg; arg[2].len = strlen(args_info.label_arg); yrc = yh_string_to_domains(args_info.domains_arg, &arg[3].w); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse domains: "); memset(&arg[4].c, 0, sizeof(yh_capabilities)); yrc = yh_string_to_capabilities(args_info.capabilities_arg, &arg[4].c); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse capabilities: "); memset(&arg[5].c, 0, sizeof(yh_capabilities)); yrc = yh_string_to_capabilities(args_info.delegated_arg, &arg[5].c); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse capabilities: "); yrc = yh_string_to_algo(args_info.algorithm_arg, &arg[6].a); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse algorithm: "); comrc = yh_com_generate_wrap(&g_ctx, arg, fmt_nofmt, fmt_nofmt); COM_SUCCEED_OR_DIE(comrc, "Unable to generate wrap key"); } break; case action_arg_generateMINUS_otpMINUS_aeadMINUS_key: { if (args_info.algorithm_given == 0) { fprintf(stderr, "Missing argument algorithm\n"); rc = EXIT_FAILURE; break; } if (args_info.nonce_given == 0) { fprintf(stderr, "Missing argument nonce\n"); rc = EXIT_FAILURE; break; } arg[1].w = args_info.object_id_arg; arg[2].s = args_info.label_arg; arg[2].len = strlen(args_info.label_arg); yrc = yh_string_to_domains(args_info.domains_arg, &arg[3].w); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse domains: "); memset(&arg[4].c, 0, sizeof(yh_capabilities)); yrc = yh_string_to_capabilities(args_info.capabilities_arg, &arg[4].c); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse capabilities: "); yrc = yh_string_to_algo(args_info.algorithm_arg, &arg[5].a); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse algorithm: "); arg[6].d = args_info.nonce_arg; comrc = yh_com_generate_otp_aead_key(&g_ctx, arg, fmt_nofmt, fmt_nofmt); COM_SUCCEED_OR_DIE(comrc, "Unable to generate otp key"); } break; case action_arg_generateMINUS_symmetricMINUS_key: { if (args_info.algorithm_given == 0) { fprintf(stderr, "Missing argument algorithm\n"); rc = EXIT_FAILURE; break; } arg[1].w = args_info.object_id_arg; arg[2].s = args_info.label_arg; arg[2].len = strlen(args_info.label_arg); yrc = yh_string_to_domains(args_info.domains_arg, &arg[3].w); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse domains: "); memset(&arg[4].c, 0, sizeof(yh_capabilities)); yrc = yh_string_to_capabilities(args_info.capabilities_arg, &arg[4].c); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse capabilities: "); yrc = yh_string_to_algo(args_info.algorithm_arg, &arg[5].a); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse algorithm: "); comrc = yh_com_generate_symmetric(&g_ctx, arg, fmt_nofmt, fmt_nofmt); COM_SUCCEED_OR_DIE(comrc, "Unable to generate symmetric key"); } break; case action_arg_getMINUS_opaque: { arg[1].w = args_info.object_id_arg; comrc = yh_com_get_opaque(&g_ctx, arg, fmt_nofmt, g_out_fmt == fmt_nofmt ? fmt_binary : g_out_fmt); COM_SUCCEED_OR_DIE(comrc, "Unable to get opaque object"); } break; case action_arg_getMINUS_pseudoMINUS_random: { arg[1].w = args_info.count_arg; comrc = yh_com_get_random(&g_ctx, arg, fmt_nofmt, g_out_fmt == fmt_nofmt ? fmt_hex : g_out_fmt); COM_SUCCEED_OR_DIE(comrc, "Unable to get random bytes"); } break; case action_arg_getMINUS_storageMINUS_info: comrc = yh_com_get_storage(&g_ctx, arg, fmt_nofmt, fmt_nofmt); COM_SUCCEED_OR_DIE(comrc, "Unable to get storage stats"); break; case action_arg_getMINUS_publicMINUS_key: { arg[1].w = args_info.object_id_arg; if(args_info.object_type_given) { yrc = yh_string_to_type(args_info.object_type_arg, &arg[2].t); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse type: "); } else { arg[2].t = YH_ASYMMETRIC_KEY; } arg[3].s = args_info.out_arg; arg[3].len = strlen(args_info.out_arg); comrc = yh_com_get_pubkey(&g_ctx, arg, fmt_nofmt, g_out_fmt == fmt_nofmt ? fmt_PEM : g_out_fmt); COM_SUCCEED_OR_DIE(comrc, "Unable to get public key"); } break; case action_arg_getMINUS_deviceMINUS_pubkey: comrc = yh_com_get_device_pubkey(&g_ctx, arg, fmt_nofmt, g_out_fmt == fmt_nofmt ? fmt_PEM : g_out_fmt); COM_SUCCEED_OR_DIE(comrc, "Unable to get device public key"); break; case action_arg_getMINUS_objectMINUS_info: { if (args_info.object_type_given == 0) { fprintf(stderr, "Missing argument object type\n"); rc = EXIT_FAILURE; break; } arg[1].w = args_info.object_id_arg; yrc = yh_string_to_type(args_info.object_type_arg, &arg[2].t); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse type: "); comrc = yh_com_get_object_info(&g_ctx, arg, fmt_nofmt, fmt_nofmt); COM_SUCCEED_OR_DIE(comrc, "Unable to get object info"); } break; case action_arg_getMINUS_wrapped: { if (args_info.object_type_given == 0) { fprintf(stderr, "Missing argument object-type\n"); rc = EXIT_FAILURE; break; } if (args_info.wrap_id_given == 0) { fprintf(stderr, "Missing argument wrap-id\n"); rc = EXIT_FAILURE; break; } arg[1].w = args_info.wrap_id_arg; yrc = yh_string_to_type(args_info.object_type_arg, &arg[2].t); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse type: "); arg[3].w = args_info.object_id_arg; arg[4].b = args_info.include_seed_given; arg[5].s = args_info.out_arg; arg[5].len = strlen(args_info.out_arg); comrc = yh_com_get_wrapped(&g_ctx, arg, fmt_nofmt, g_out_fmt == fmt_nofmt ? fmt_base64 : g_out_fmt); COM_SUCCEED_OR_DIE(comrc, "Unable to get wrapped object"); } break; case action_arg_getMINUS_rsaMINUS_wrapped: { if (args_info.object_type_given == 0) { fprintf(stderr, "Missing argument object-type\n"); rc = EXIT_FAILURE; break; } if (args_info.wrap_id_given == 0) { fprintf(stderr, "Missing argument wrap-id\n"); rc = EXIT_FAILURE; break; } arg[1].w = args_info.wrap_id_arg; yrc = yh_string_to_type(args_info.object_type_arg, &arg[2].t); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse type: "); arg[3].w = args_info.object_id_arg; yrc = yh_string_to_algo(args_info.algorithm_arg, &arg[4].a); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse algorithm: "); yrc = yh_string_to_algo(args_info.oaep_arg, &arg[5].a); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse OAEP algorithm: "); yrc = yh_string_to_algo(args_info.mgf1_arg, &arg[6].a); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse MGF1 algorithm: "); arg[7].s = args_info.out_arg; arg[7].len = strlen(args_info.out_arg); comrc = yh_com_get_rsa_wrapped(&g_ctx, arg, fmt_nofmt, g_out_fmt == fmt_nofmt ? fmt_binary : g_out_fmt); COM_SUCCEED_OR_DIE(comrc, "Unable to get wrapped object"); } break; case action_arg_getMINUS_rsaMINUS_wrappedMINUS_key: { if (args_info.object_type_given == 0) { fprintf(stderr, "Missing argument object-type\n"); rc = EXIT_FAILURE; break; } if (args_info.wrap_id_given == 0) { fprintf(stderr, "Missing argument wrap-id\n"); rc = EXIT_FAILURE; break; } arg[1].w = args_info.wrap_id_arg; yrc = yh_string_to_type(args_info.object_type_arg, &arg[2].t); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse type: "); arg[3].w = args_info.object_id_arg; yrc = yh_string_to_algo(args_info.algorithm_arg, &arg[4].a); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse algorithm: "); yrc = yh_string_to_algo(args_info.oaep_arg, &arg[5].a); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse OAEP algorithm: "); yrc = yh_string_to_algo(args_info.mgf1_arg, &arg[6].a); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse MGF1 algorithm: "); arg[7].s = args_info.out_arg; arg[7].len = strlen(args_info.out_arg); comrc = yh_com_get_rsa_wrapped_key(&g_ctx, arg, fmt_nofmt, g_out_fmt == fmt_nofmt ? fmt_binary : g_out_fmt); COM_SUCCEED_OR_DIE(comrc, "Unable to get wrapped object"); } break; case action_arg_getMINUS_deviceMINUS_info: comrc = yh_com_get_device_info(&g_ctx, arg, fmt_nofmt, fmt_nofmt); COM_SUCCEED_OR_DIE(comrc, "Unable to get device info"); break; case action_arg_getMINUS_template: { arg[1].w = args_info.object_id_arg; comrc = yh_com_get_template(&g_ctx, arg, fmt_nofmt, g_out_fmt == fmt_nofmt ? fmt_base64 : g_out_fmt); COM_SUCCEED_OR_DIE(comrc, "Unable to get template object"); } break; case action_arg_listMINUS_objects: { arg[1].w = args_info.object_id_arg; yrc = yh_string_to_type(args_info.object_type_arg, &arg[2].t); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse type: "); yrc = yh_string_to_domains(args_info.domains_arg, &arg[3].w); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse domains: "); memset(&arg[4].c, 0, sizeof(yh_capabilities)); yrc = yh_string_to_capabilities(args_info.capabilities_arg, &arg[4].c); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse capabilities: "); yrc = yh_string_to_algo(args_info.algorithm_arg, &arg[5].a); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse algorithm: "); arg[6].b = args_info.with_compression_given; arg[7].s = args_info.label_arg; arg[7].len = strlen(args_info.label_arg); comrc = yh_com_list_objects(&g_ctx, arg, fmt_nofmt, fmt_nofmt); COM_SUCCEED_OR_DIE(comrc, "Unable to list objects"); } break; case action_arg_putMINUS_authenticationMINUS_key: { if (args_info.new_password_given == 0) { fprintf(stderr, "Missing argument new-password\n"); rc = EXIT_FAILURE; break; } arg[1].w = args_info.object_id_arg; arg[2].s = args_info.label_arg; arg[2].len = strlen(args_info.label_arg); yrc = yh_string_to_domains(args_info.domains_arg, &arg[3].w); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse domains: "); memset(&arg[4].c, 0, sizeof(yh_capabilities)); yrc = yh_string_to_capabilities(args_info.capabilities_arg, &arg[4].c); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse capabilities: "); memset(&arg[5].c, 0, sizeof(yh_capabilities)); yrc = yh_string_to_capabilities(args_info.delegated_arg, &arg[5].c); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse capabilities: "); arg[6].x = (uint8_t *) args_info.new_password_arg; arg[6].len = strlen(args_info.new_password_arg); comrc = yh_com_put_authentication(&g_ctx, arg, fmt_nofmt, fmt_nofmt); COM_SUCCEED_OR_DIE(comrc, "Unable to store authentication key"); } break; case action_arg_putMINUS_asymmetricMINUS_key: { arg[1].w = args_info.object_id_arg; arg[2].s = args_info.label_arg; arg[2].len = strlen(args_info.label_arg); yrc = yh_string_to_domains(args_info.domains_arg, &arg[3].w); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse domains: "); memset(&arg[4].c, 0, sizeof(yh_capabilities)); yrc = yh_string_to_capabilities(args_info.capabilities_arg, &arg[4].c); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse capabilities: "); if (get_input_data(args_info.in_arg, &arg[5].x, &arg[5].len, g_in_fmt == fmt_nofmt ? fmt_PEM : g_in_fmt) == false) { fprintf(stderr, "Failed to get input data\n"); rc = EXIT_FAILURE; break; } comrc = yh_com_put_asymmetric(&g_ctx, arg, fmt_nofmt, fmt_nofmt); free(arg[5].x); COM_SUCCEED_OR_DIE(comrc, "Unable to store asymmetric key"); } break; case action_arg_putMINUS_opaque: { if (args_info.algorithm_given == 0) { fprintf(stderr, "Missing argument algorithm\n"); rc = EXIT_FAILURE; break; } arg[1].w = args_info.object_id_arg; arg[2].s = args_info.label_arg; arg[2].len = strlen(args_info.label_arg); yrc = yh_string_to_domains(args_info.domains_arg, &arg[3].w); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse domains: "); memset(&arg[4].c, 0, sizeof(yh_capabilities)); yrc = yh_string_to_capabilities(args_info.capabilities_arg, &arg[4].c); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse capabilities: "); yrc = yh_string_to_algo(args_info.algorithm_arg, &arg[5].a); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse algorithm: "); arg[6].b = args_info.with_compression_given; if (get_input_data(args_info.in_arg, &arg[7].x, &arg[7].len, g_in_fmt == fmt_nofmt ? fmt_binary : g_in_fmt) == false) { fprintf(stderr, "Failed to get input data\n"); rc = EXIT_FAILURE; break; } comrc = yh_com_put_opaque(&g_ctx, arg, g_in_fmt, fmt_nofmt); free(arg[6].x); COM_SUCCEED_OR_DIE(comrc, "Unable to store opaque object"); } break; case action_arg_putMINUS_option: { if (args_info.opt_name_given == 0) { fprintf(stderr, "Missing argument opt-name\n"); rc = EXIT_FAILURE; break; } if (args_info.opt_value_given == 0) { fprintf(stderr, "Missing argument opt-value\n"); rc = EXIT_FAILURE; break; } yrc = yh_string_to_option(args_info.opt_name_arg, &arg[1].o); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse option name: "); arg[2].x = calloc(ARGS_BUFFER_SIZE, 1); arg[2].len = ARGS_BUFFER_SIZE; if (hex_decode(args_info.opt_value_arg, arg[2].x, &arg[2].len) == false) { fprintf(stderr, "Unable to decode option value\n"); rc = EXIT_FAILURE; break; } comrc = yh_com_put_option(&g_ctx, arg, fmt_hex, fmt_nofmt); free(arg[2].x); COM_SUCCEED_OR_DIE(comrc, "Unable to put option"); } break; case action_arg_getMINUS_option: { if (args_info.opt_name_given == 0) { fprintf(stderr, "Missing argument opt-name\n"); rc = EXIT_FAILURE; break; } yrc = yh_string_to_option(args_info.opt_name_arg, &arg[1].o); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse option name: "); comrc = yh_com_get_option(&g_ctx, arg, fmt_nofmt, fmt_nofmt); COM_SUCCEED_OR_DIE(comrc, "Unable to get option"); } break; case action_arg_putMINUS_hmacMINUS_key: LIB_SUCCEED_OR_DIE(YHR_GENERIC_ERROR, "Command not implemented: "); // TODO(adma): this requires a hex parser case action_arg_putMINUS_wrapMINUS_key: { if (args_info.delegated_given == 0) { fprintf(stderr, "Missing delegated capabilities\n"); rc = EXIT_FAILURE; break; } arg[1].w = args_info.object_id_arg; arg[2].s = args_info.label_arg; arg[2].len = strlen(args_info.label_arg); yrc = yh_string_to_domains(args_info.domains_arg, &arg[3].w); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse domains: "); memset(&arg[4].c, 0, sizeof(yh_capabilities)); yrc = yh_string_to_capabilities(args_info.capabilities_arg, &arg[4].c); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse capabilities: "); memset(&arg[5].c, 0, sizeof(yh_capabilities)); yrc = yh_string_to_capabilities(args_info.delegated_arg, &arg[5].c); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse capabilities: "); if (get_input_data(args_info.in_arg, &arg[6].x, &arg[6].len, g_in_fmt == fmt_nofmt ? fmt_hex : g_in_fmt) == false) { fprintf(stderr, "Failed to get input data\n"); rc = EXIT_FAILURE; break; } comrc = yh_com_put_wrapkey(&g_ctx, arg, fmt_nofmt, fmt_nofmt); free(arg[6].x); COM_SUCCEED_OR_DIE(comrc, "Unable to put wrapkey"); } break; case action_arg_putMINUS_rsaMINUS_wrapkey: { if (args_info.delegated_given == 0) { fprintf(stderr, "Missing delegated capabilities\n"); rc = EXIT_FAILURE; break; } arg[1].w = args_info.object_id_arg; arg[2].s = args_info.label_arg; arg[2].len = strlen(args_info.label_arg); yrc = yh_string_to_domains(args_info.domains_arg, &arg[3].w); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse domains: "); memset(&arg[4].c, 0, sizeof(yh_capabilities)); yrc = yh_string_to_capabilities(args_info.capabilities_arg, &arg[4].c); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse capabilities: "); memset(&arg[5].c, 0, sizeof(yh_capabilities)); yrc = yh_string_to_capabilities(args_info.delegated_arg, &arg[5].c); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse capabilities: "); if (get_input_data(args_info.in_arg, &arg[6].x, &arg[6].len, g_in_fmt == fmt_nofmt ? fmt_PEM : g_in_fmt) == false) { fprintf(stderr, "Failed to get input data\n"); rc = EXIT_FAILURE; break; } comrc = yh_com_put_rsa_wrapkey(&g_ctx, arg, fmt_nofmt, fmt_nofmt); free(arg[6].x); COM_SUCCEED_OR_DIE(comrc, "Unable to put wrapkey"); } break; case action_arg_putMINUS_publicMINUS_wrapkey: { if (args_info.delegated_given == 0) { fprintf(stderr, "Missing delegated capabilities\n"); rc = EXIT_FAILURE; break; } arg[1].w = args_info.object_id_arg; arg[2].s = args_info.label_arg; arg[2].len = strlen(args_info.label_arg); yrc = yh_string_to_domains(args_info.domains_arg, &arg[3].w); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse domains: "); memset(&arg[4].c, 0, sizeof(yh_capabilities)); yrc = yh_string_to_capabilities(args_info.capabilities_arg, &arg[4].c); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse capabilities: "); memset(&arg[5].c, 0, sizeof(yh_capabilities)); yrc = yh_string_to_capabilities(args_info.delegated_arg, &arg[5].c); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse capabilities: "); if (get_input_data(args_info.in_arg, &arg[6].x, &arg[6].len, g_in_fmt == fmt_nofmt ? fmt_PEM : g_in_fmt) == false) { fprintf(stderr, "Failed to get input data\n"); rc = EXIT_FAILURE; break; } comrc = yh_com_put_public_wrapkey(&g_ctx, arg, fmt_nofmt, fmt_nofmt); free(arg[6].x); COM_SUCCEED_OR_DIE(comrc, "Unable to put wrapkey"); } break; case action_arg_putMINUS_symmetricMINUS_key: { if (args_info.algorithm_given == 0) { fprintf(stderr, "Missing argument algorithm\n"); rc = EXIT_FAILURE; break; } arg[1].w = args_info.object_id_arg; arg[2].s = args_info.label_arg; arg[2].len = strlen(args_info.label_arg); yrc = yh_string_to_domains(args_info.domains_arg, &arg[3].w); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse domains: "); memset(&arg[4].c, 0, sizeof(yh_capabilities)); yrc = yh_string_to_capabilities(args_info.capabilities_arg, &arg[4].c); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse capabilities: "); yrc = yh_string_to_algo(args_info.algorithm_arg, &arg[5].a); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse algorithm: "); if (get_input_data(args_info.in_arg, &arg[6].x, &arg[6].len, g_in_fmt == fmt_nofmt ? fmt_hex : g_in_fmt) == false) { fprintf(stderr, "Failed to get input data\n"); rc = EXIT_FAILURE; break; } comrc = yh_com_put_symmetric(&g_ctx, arg, fmt_nofmt, fmt_nofmt); free(arg[6].x); COM_SUCCEED_OR_DIE(comrc, "Unable to store symmetric key"); } break; case action_arg_putMINUS_wrapped: { if (args_info.wrap_id_given == 0) { fprintf(stderr, "Missing argument wrap-id\n"); rc = EXIT_FAILURE; break; } arg[1].w = args_info.wrap_id_arg; if (get_input_data(args_info.in_arg, &arg[2].x, &arg[2].len, g_in_fmt == fmt_nofmt ? fmt_base64 : g_in_fmt) == false) { fprintf(stderr, "Failed to get input data\n"); rc = EXIT_FAILURE; break; } comrc = yh_com_put_wrapped(&g_ctx, arg, fmt_nofmt, fmt_nofmt); free(arg[2].x); COM_SUCCEED_OR_DIE(comrc, "Unable to store wrapped object"); } break; case action_arg_putMINUS_rsaMINUS_wrapped: { if (args_info.wrap_id_given == 0) { fprintf(stderr, "Missing argument wrap-id\n"); rc = EXIT_FAILURE; break; } arg[1].w = args_info.wrap_id_arg; yrc = yh_string_to_algo(args_info.oaep_arg, &arg[2].a); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse OAEP algorithm: "); yrc = yh_string_to_algo(args_info.mgf1_arg, &arg[3].a); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse MGF1 algorithm: "); if (get_input_data(args_info.in_arg, &arg[4].x, &arg[4].len, g_in_fmt == fmt_nofmt ? fmt_binary : g_in_fmt) == false) { fprintf(stderr, "Failed to get input data\n"); rc = EXIT_FAILURE; break; } comrc = yh_com_put_rsa_wrapped(&g_ctx, arg, fmt_nofmt, fmt_nofmt); free(arg[4].x); COM_SUCCEED_OR_DIE(comrc, "Unable to store RSA wrapped object"); } break; case action_arg_putMINUS_rsaMINUS_wrappedMINUS_key: { if (args_info.wrap_id_given == 0) { fprintf(stderr, "Missing argument wrap-id\n"); rc = EXIT_FAILURE; break; } if (args_info.object_type_given == 0) { fprintf(stderr, "Missing argument type\n"); rc = EXIT_FAILURE; break; } if (args_info.algorithm_given == 0) { fprintf(stderr, "Missing argument key-algorithm\n"); rc = EXIT_FAILURE; break; } arg[1].w = args_info.wrap_id_arg; yrc = yh_string_to_type(args_info.object_type_arg, &arg[2].t); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse object type: "); arg[3].w = args_info.object_id_arg; yrc = yh_string_to_algo(args_info.algorithm_arg, &arg[4].a); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse key algorithm: "); arg[5].s = args_info.label_arg; arg[5].len = strlen(args_info.label_arg); yrc = yh_string_to_domains(args_info.domains_arg, &arg[6].w); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse domains: "); yrc = yh_string_to_capabilities(args_info.capabilities_arg, &arg[7].c); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse capabilities: "); yrc = yh_string_to_algo(args_info.oaep_arg, &arg[8].a); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse OAEP algorithm: "); yrc = yh_string_to_algo(args_info.mgf1_arg, &arg[9].a); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse MGF1 algorithm: "); if (get_input_data(args_info.in_arg, &arg[10].x, &arg[10].len, g_in_fmt == fmt_nofmt ? fmt_binary : g_in_fmt) == false) { fprintf(stderr, "Failed to get input data\n"); rc = EXIT_FAILURE; break; } comrc = yh_com_put_rsa_wrapped_key(&g_ctx, arg, fmt_nofmt, fmt_nofmt); free(arg[10].x); COM_SUCCEED_OR_DIE(comrc, "Unable to store RSA wrapped object"); } break; case action_arg_putMINUS_template: { if (args_info.algorithm_given == 0) { fprintf(stderr, "Missing argument algorithm\n"); rc = EXIT_FAILURE; break; } arg[1].w = args_info.object_id_arg; arg[2].s = args_info.label_arg; arg[2].len = strlen(args_info.label_arg); yrc = yh_string_to_domains(args_info.domains_arg, &arg[3].w); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse domains: "); memset(&arg[4].c, 0, sizeof(yh_capabilities)); yrc = yh_string_to_capabilities(args_info.capabilities_arg, &arg[4].c); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse capabilities: "); yrc = yh_string_to_algo(args_info.algorithm_arg, &arg[5].a); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse algorithm: "); if (get_input_data(args_info.in_arg, &arg[6].x, &arg[6].len, g_in_fmt == fmt_nofmt ? fmt_binary : g_in_fmt) == false) { fprintf(stderr, "Failed to get input data\n"); rc = EXIT_FAILURE; break; } comrc = yh_com_put_template(&g_ctx, arg, fmt_nofmt, fmt_nofmt); free(arg[6].x); COM_SUCCEED_OR_DIE(comrc, "Unable to store template object"); } break; case action_arg_putMINUS_otpMINUS_aeadMINUS_key: LIB_SUCCEED_OR_DIE(YHR_GENERIC_ERROR, "Command not implemented: "); // TODO(adma): this requires a hex parser case action_arg_signMINUS_eddsa: case action_arg_signMINUS_ecdsa: { if (args_info.algorithm_given == 0) { fprintf(stderr, "Missing argument algorithm\n"); rc = EXIT_FAILURE; break; } arg[1].w = args_info.object_id_arg; yrc = yh_string_to_algo(args_info.algorithm_arg, &arg[2].a); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse algorithm: "); if (get_input_data(args_info.in_arg, &arg[3].x, &arg[3].len, g_in_fmt == fmt_nofmt ? fmt_binary : g_in_fmt) == false) { fprintf(stderr, "Failed to get input data\n"); rc = EXIT_FAILURE; break; } if (args_info.action_arg[i] == action_arg_signMINUS_ecdsa) { comrc = yh_com_sign_ecdsa(&g_ctx, arg, fmt_nofmt, g_out_fmt == fmt_nofmt ? fmt_base64 : g_out_fmt); } else { comrc = yh_com_sign_eddsa(&g_ctx, arg, fmt_nofmt, g_out_fmt == fmt_nofmt ? fmt_base64 : g_out_fmt); } free(arg[3].x); COM_SUCCEED_OR_DIE(comrc, "Unable to sign data"); } break; case action_arg_signMINUS_pkcs1v15: { if (args_info.algorithm_given == 0) { fprintf(stderr, "Missing argument algorithm\n"); rc = EXIT_FAILURE; break; } arg[1].w = args_info.object_id_arg; yrc = yh_string_to_algo(args_info.algorithm_arg, &arg[2].a); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse algorithm: "); if (get_input_data(args_info.in_arg, &arg[3].x, &arg[3].len, g_in_fmt == fmt_nofmt ? fmt_binary : g_in_fmt) == false) { fprintf(stderr, "Failed to get input data\n"); rc = EXIT_FAILURE; break; } comrc = yh_com_sign_pkcs1v1_5(&g_ctx, arg, fmt_nofmt, g_out_fmt == fmt_nofmt ? fmt_base64 : g_out_fmt); free(arg[3].x); COM_SUCCEED_OR_DIE(comrc, "Unable to sign data"); } break; case action_arg_signMINUS_pss: { if (args_info.algorithm_given == 0) { fprintf(stderr, "Missing argument algorithm\n"); rc = EXIT_FAILURE; break; } arg[1].w = args_info.object_id_arg; yrc = yh_string_to_algo(args_info.algorithm_arg, &arg[2].a); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse algorithm: "); if (get_input_data(args_info.in_arg, &arg[3].x, &arg[3].len, g_in_fmt == fmt_nofmt ? fmt_binary : g_in_fmt) == false) { fprintf(stderr, "Failed to get input data\n"); rc = EXIT_FAILURE; break; } comrc = yh_com_sign_pss(&g_ctx, arg, fmt_nofmt, g_out_fmt == fmt_nofmt ? fmt_base64 : g_out_fmt); free(arg[3].x); COM_SUCCEED_OR_DIE(comrc, "Unable to sign data"); } break; case action_arg_signMINUS_hmac: LIB_SUCCEED_OR_DIE(YHR_GENERIC_ERROR, "Command not implemented: "); // TODO(adma): this requires a hex parser case action_arg_reset: { comrc = yh_com_reset(&g_ctx, arg, fmt_nofmt, fmt_nofmt); COM_SUCCEED_OR_DIE(comrc, "Unable to reset device"); } break; case action_arg_deleteMINUS_object: { if (args_info.object_type_given == 0) { fprintf(stderr, "Missing argument object type\n"); rc = EXIT_FAILURE; break; } yrc = yh_string_to_type(args_info.object_type_arg, &arg[2].t); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse type: "); arg[1].w = args_info.object_id_arg; comrc = yh_com_delete(&g_ctx, arg, fmt_nofmt, fmt_nofmt); COM_SUCCEED_OR_DIE(comrc, "Unable to delete object"); } break; case action_arg_signMINUS_sshMINUS_certificate: { if (args_info.template_id_given == 0) { fprintf(stderr, "Missing argument template-id\n"); rc = EXIT_FAILURE; break; } if (args_info.algorithm_given == 0) { fprintf(stderr, "Missing argument algorithm\n"); rc = EXIT_FAILURE; break; } arg[1].w = args_info.object_id_arg; arg[2].w = args_info.template_id_arg; yrc = yh_string_to_algo(args_info.algorithm_arg, &arg[3].a); LIB_SUCCEED_OR_DIE(yrc, "Unable to parse algorithm: "); if (get_input_data(args_info.in_arg, &arg[4].x, &arg[4].len, g_in_fmt == fmt_nofmt ? fmt_binary : g_in_fmt) == false) { // TODO: correct format? fprintf(stderr, "Failed to get input data\n"); rc = EXIT_FAILURE; break; } comrc = yh_com_sign_ssh_certificate(&g_ctx, arg, fmt_nofmt, g_out_fmt == fmt_nofmt ? fmt_binary : g_out_fmt); free(arg[4].x); COM_SUCCEED_OR_DIE(comrc, "Unable to get ssh certificate"); } break; case action_arg_benchmark: LIB_SUCCEED_OR_DIE(YHR_GENERIC_ERROR, "Command not implemented: "); case action_arg_createMINUS_otpMINUS_aead: LIB_SUCCEED_OR_DIE(YHR_GENERIC_ERROR, "Command not implemented: "); // TODO(adma): this requires a hex parser case action_arg_randomizeMINUS_otpMINUS_aead: { arg[1].w = args_info.object_id_arg; arg[2].s = args_info.out_arg; arg[2].len = strlen(args_info.out_arg); comrc = yh_com_otp_aead_random(&g_ctx, arg, fmt_nofmt, g_out_fmt == fmt_nofmt ? fmt_binary : g_out_fmt); COM_SUCCEED_OR_DIE(comrc, "Unable to get aead from random"); } break; case action_arg_decryptMINUS_otp: LIB_SUCCEED_OR_DIE(YHR_GENERIC_ERROR, "Command not implemented: "); // TODO(adma): this requires a hex parser case action_arg_signMINUS_attestationMINUS_certificate: { if (args_info.attestation_id_given == 0) { fprintf(stderr, "Missing argument attestation-id\n"); rc = EXIT_FAILURE; break; } arg[1].w = args_info.object_id_arg; arg[2].w = args_info.attestation_id_arg; comrc = yh_com_sign_attestation_certificate(&g_ctx, arg, fmt_nofmt, g_out_fmt == fmt_nofmt ? fmt_PEM : g_out_fmt); COM_SUCCEED_OR_DIE(comrc, "Unable to attest asymmetric key"); } break; case action_arg_getMINUS_logs: { comrc = yh_com_audit(&g_ctx, arg, fmt_nofmt, g_out_fmt == fmt_nofmt ? fmt_ASCII : g_out_fmt); COM_SUCCEED_OR_DIE(comrc, "Unable to extract logs"); } break; case action_arg_setMINUS_logMINUS_index: { if (args_info.log_index_given == 0) { fprintf(stderr, "Missing argument log-index\n"); rc = EXIT_FAILURE; break; } arg[1].w = args_info.log_index_arg; comrc = yh_com_set_log_index(&g_ctx, arg, fmt_nofmt, g_out_fmt == fmt_nofmt ? fmt_ASCII : g_out_fmt); COM_SUCCEED_OR_DIE(comrc, "Unable to set log index"); } break; case action_arg_blinkMINUS_device: { if (args_info.duration_arg < 0 || args_info.duration_arg > 0xff) { fprintf(stderr, "Duration must be in [0, 256]\n"); rc = EXIT_FAILURE; break; } arg[1].w = args_info.duration_arg; comrc = yh_com_blink(&g_ctx, arg, fmt_nofmt, fmt_nofmt); COM_SUCCEED_OR_DIE(comrc, "Unable to blink device"); } break; case action_arg_generateMINUS_csr: { if (args_info.object_id_given == 0) { fprintf(stderr, "Missing argument object ID\n"); rc = EXIT_FAILURE; break; } if (args_info.subject_given == 0) { fprintf(stderr, "Missing argument subject\n"); rc = EXIT_FAILURE; break; } arg[1].w = args_info.object_id_arg; arg[2].s = args_info.subject_arg; arg[2].len = strlen(args_info.subject_arg); arg[3].s = args_info.out_arg; arg[3].len = strlen(args_info.out_arg); comrc = yh_com_generate_csr(&g_ctx, arg, fmt_nofmt, g_out_fmt == fmt_nofmt ? fmt_PEM : g_out_fmt); COM_SUCCEED_OR_DIE(comrc, "Unable to generate certificate request"); } break; case action__NULL: printf("ERROR !%u \n", args_info.action_given); rc = EXIT_FAILURE; } if (rc == EXIT_FAILURE) { break; } } calling_device = false; } else { int num = 0; #ifndef __WIN32 EditLine *el; HistEvent ev; g_hist = history_init(); history(g_hist, &ev, H_SETSIZE, 1000); // NOTE(adma): 1000 history items el = el_init(*argv, stdin, stdout, stderr); el_set(el, EL_EDITOR, "emacs"); #ifdef EL_PROMPT_ESC el_set(el, EL_PROMPT_ESC, prompt, '\1'); /* Set the prompt function */ #else el_set(el, EL_PROMPT, prompt); /* Set the prompt function */ #endif /* EL_PROMPT_ESC */ el_set(el, EL_HIST, history, g_hist); /* enable ctrl-R for reverse history search */ el_set(el, EL_BIND, "^R", "em-inc-search-prev", NULL); /* Add a user-defined function */ el_set(el, EL_ADDFN, "yh_complete", "Complete argument", yubihsm_complete); /* Bind tab to it */ el_set(el, EL_BIND, "^I", "yh_complete", NULL); el_source(el, NULL); // NOTE(adma): source the user's defaults file #endif create_command_list(&g_commands); if (args_info.pre_connect_flag) { yh_com_connect(&g_ctx, NULL, fmt_nofmt, fmt_nofmt); } while (g_running == true) { #ifdef __WIN32 fprintf(stdout, PROMPT); char data[1025]; char *buf = converting_fgets(data, sizeof(data), stdin); if (buf) { num = strlen(buf); } #else const char *buf = el_gets(el, &num); #endif if (buf == NULL) { // NOTE(adma): got Ctrl-D yh_com_quit(NULL, NULL, fmt_nofmt, fmt_nofmt); fprintf(stdout, "\n"); } else if (num > 0 && buf[0] != '\n' && buf[0] != '\r') { #ifndef __WIN32 history(g_hist, &ev, H_ENTER, buf); #endif validate_and_call(&g_ctx, g_commands, buf); } } #ifndef __WIN32 el_end(el); history_end(g_hist); #endif } main_exit: calling_device = true; for (size_t i = 0; i < sizeof(g_ctx.sessions) / sizeof(g_ctx.sessions[0]); i++) { if (g_ctx.sessions[i]) { yh_util_close_session(g_ctx.sessions[i]); yh_destroy_session(&g_ctx.sessions[i]); } } yh_disconnect(g_ctx.connector); cmdline_parser_free(&args_info); if (g_ctx.out != stdout && g_ctx.out != NULL) { fclose(g_ctx.out); } if (g_ctx.cacert) { free(g_ctx.cacert); } if (g_ctx.cert) { free(g_ctx.cert); } if (g_ctx.key) { free(g_ctx.key); } if (g_ctx.proxy) { free(g_ctx.proxy); } if (g_ctx.noproxy) { free(g_ctx.noproxy); } yh_exit(); ykhsmauth_done(g_ctx.state); g_ctx.state = NULL; free_configured_pubkeys(&g_ctx); free_configured_connectors(&g_ctx); return rc; } yubihsm-shell-2.8.0/src/tests/0000755000175100017510000000000015221003515015637 5ustar runnerrunneryubihsm-shell-2.8.0/src/tests/data.txt0000644000175100017510000000001515221003515017305 0ustar runnerrunnerHello World! yubihsm-shell-2.8.0/src/tests/tests.sh0000755000175100017510000000612115221003515017340 0ustar runnerrunner#!/bin/bash # # Copyright 2015-2018 Yubico AB # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # set -e set -x TMPDIR=$(mktemp -d) #trap 'rm -rf "$TMPDIR"' INT TERM EXIT DATA="$TMPDIR/data" SIG="$TMPDIR/sig" BIN_SIG="$TMPDIR/bin_sig" PUBLIC_KEY="$TMPDIR/public" if [ -z ${DEFAULT_CONNECTOR_URL} ]; then DEFAULT_CONNECTOR_URL="http://localhost:12345" fi PROG="../yubihsm-shell --connector=${DEFAULT_CONNECTOR_URL}" if [ "x$(uname)" = "xFreeBSD" ]; then DECODE="b64decode -pr" else DECODE="base64 --decode -i" fi echo "Hello World!" >"$DATA" OUTPUT=$($PROG -a generate-asymmetric -A ecp256 -csign-ecdsa -p password 2>&1) OBJ_ID=$(echo "$OUTPUT" | grep -o -E '0x[a-f0-9]{4}$') $PROG -a sign-ecdsa -i $OBJ_ID -A ecdsa-sha256 --in "$DATA" --out "$SIG" -p password $DECODE "$SIG" >"$BIN_SIG" $PROG -a get-public-key -i $OBJ_ID --out "$PUBLIC_KEY" -p password openssl dgst -sha256 -verify "$PUBLIC_KEY" -signature "$BIN_SIG" "$DATA" truncate -s 0 "$SIG" truncate -s 0 "$PUBLIC_KEY" #$PROG -a generate-asymmetric -i 0x1234 -A ecp256 -csign_ecdsa $PROG -a sign-ecdsa -i $OBJ_ID -A ecdsa-sha1 --in "$DATA" --out "$SIG" -p password $DECODE "$SIG" >"$BIN_SIG" $PROG -a get-public-key -i $OBJ_ID --out "$PUBLIC_KEY" -p password openssl dgst -sha1 -verify "$PUBLIC_KEY" -signature "$BIN_SIG" "$DATA" truncate -s 0 "$SIG" truncate -s 0 "$PUBLIC_KEY" OUTPUT=$($PROG -a generate-asymmetric -A ecp384 -csign-ecdsa -p password 2>&1) OBJ_ID=$(echo "$OUTPUT" | grep -o -E '0x[a-f0-9]{4}$') $PROG -a sign-ecdsa -i $OBJ_ID -A ecdsa-sha384 --in "$DATA" --out "$SIG" -p password $DECODE "$SIG" >"$BIN_SIG" $PROG -a get-public-key -i $OBJ_ID --out "$PUBLIC_KEY" -p password openssl dgst -sha384 -verify "$PUBLIC_KEY" -signature "$BIN_SIG" "$DATA" truncate -s 0 "$SIG" truncate -s 0 "$PUBLIC_KEY" OUTPUT=$($PROG -a generate-asymmetric -A ecp521 -csign-ecdsa -p password 2>&1) OBJ_ID=$(echo "$OUTPUT" | grep -o -E '0x[a-f0-9]{4}$') $PROG -a sign-ecdsa -i $OBJ_ID -A ecdsa-sha512 --in "$DATA" --out "$SIG" -p password $DECODE "$SIG" >"$BIN_SIG" $PROG -a get-public-key -i $OBJ_ID --out "$PUBLIC_KEY" -p password openssl dgst -sha512 -verify "$PUBLIC_KEY" -signature "$BIN_SIG" "$DATA" $PROG -a blink-device -p password $PROG -a get-device-info $PROG -a get-storage-info -p password $PROG -a get-option -p password --opt-name command-audit $PROG -a put-option -p password --opt-name command-audit --opt-value 0101 $PROG -a get-option -p password --opt-name force-audit $PROG -a put-option -p password --opt-name force-audit --opt-value 00 $PROG -a get-option -p password --opt-name algorithm-toggle # no test for putting algorithm-toggle as that requires and empty device yubihsm-shell-2.8.0/src/tests/sig.out0000644000175100017510000000000015221003515017140 0ustar runnerrunneryubihsm-shell-2.8.0/src/tests/yubihsm_shell_tests.c0000644000175100017510000001332015221003515022073 0ustar runnerrunner/* * Copyright 2015-2018 Yubico AB * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #define EXIT_SKIPPED 77; yh_device **devices; uint16_t n_devices; yh_session *ses; typedef struct { uint16_t len; double min; double max; double tot; } repetition_stats; #define DEFAULT_KEY \ "\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f" #define N_REPS \ 8 // Data length for repetition i is 2^(1 + i) for i in [0, N_REPS-1] #define N_ITERATIONS 1000 #define ECHO_BYTE 0x0f int main() { yh_rc yrc; uint8_t key_enc[YH_KEY_LEN]; uint8_t key_mac[YH_KEY_LEN]; uint8_t key_dek[YH_KEY_LEN]; uint8_t host_challenge[YH_HOST_CHAL_LEN] = {0}; uint8_t yh_context[YH_CONTEXT_LEN]; struct timeval before, after; double this; repetition_stats rs[N_REPS], rs2[N_REPS]; uint8_t data[YH_MSG_BUF_SIZE]; uint8_t response[YH_MSG_BUF_SIZE]; uint16_t response_len; uint16_t len; uint8_t verbosity = 0; // YH_VERB_USB | YH_VERB_CRYPTO | YH_VERB_INTERMEDIATE // | YH_VERB_INFO | YH_VERB_ERR; yrc = yh_init(&devices, &n_devices); if (yrc != YH_SUCCESS) { fprintf(stderr, "Unable to initialize\n"); fprintf(stderr, "(Typically this happens if you don't have permissions to " "open the device\n"); fprintf(stderr, "try re-running as root/Administrator)\n"); return EXIT_SKIPPED; } if (n_devices == 0) { fprintf(stderr, "No suitable device found. Skipping this test\n"); return EXIT_SKIPPED; } yh_set_verbosity(verbosity); memset(data, ECHO_BYTE, 1024); // Plain commands len = 4; for (uint16_t rep = 0; rep < N_REPS; rep++) { len *= 2; rs[rep].len = len; fprintf(stderr, "now doing plain with len %d\n", len); for (uint16_t i = 0; i < N_ITERATIONS; i++) { response_len = sizeof(response); gettimeofday(&before, NULL); yrc = yh_send_plain_msg(devices[0], YHC_ECHO, data, rs[rep].len, response, &response_len); gettimeofday(&after, NULL); this = (after.tv_sec - before.tv_sec) * 1000; this += ((double) (after.tv_usec - before.tv_usec)) / 1000; if (i == 0) { rs[rep].max = rs[rep].min = this; rs[rep].tot = 0; } else { if (this > rs[rep].max) { rs[rep].max = this; } if (this < rs[rep].min) { rs[rep].min = this; } } rs[rep].tot += this; if (rs[rep].len != response_len || memcmp(data, response, rs[rep].len) != 0) { fprintf(stderr, "Data mismatch\n"); return EXIT_FAILURE; } } } // Auth commands memcpy(key_enc, DEFAULT_KEY, YH_KEY_LEN); // TODO: fix memcpy(key_mac, DEFAULT_KEY, YH_KEY_LEN); // TODO: fix memcpy(key_dek, DEFAULT_KEY, YH_KEY_LEN); // TODO: fix yrc = yh_open_device(devices[0]); if (yrc != YH_SUCCESS) { fprintf(stderr, "Unable to open device: %s\n", yh_strerror(yrc)); return EXIT_FAILURE; } yrc = yh_create_session(devices[0], 0, host_challenge, key_enc, 16, key_mac, 16, yh_context, &ses); if (yrc != YH_SUCCESS) { fprintf(stderr, "Failed to create session: %s\n", yh_strerror(yrc)); return EXIT_FAILURE; } len = 4; for (uint16_t rep = 0; rep < N_REPS; rep++) { len *= 2; rs2[rep].len = len; fprintf(stderr, "now doing auth with len %d\n", len); for (uint16_t i = 0; i < N_ITERATIONS; i++) { response_len = sizeof(response); gettimeofday(&before, NULL); yrc = yh_send_secure_msg(ses, YHC_ECHO, data, rs2[rep].len, response, &response_len); gettimeofday(&after, NULL); if (yrc != YH_SUCCESS) { fprintf(stderr, "Failed to send message: %d, %s\n", yrc, yh_strerror(yrc)); return EXIT_FAILURE; } this = (after.tv_sec - before.tv_sec) * 1000; this += ((double) (after.tv_usec - before.tv_usec)) / 1000; if (i == 0) { rs2[rep].max = rs2[rep].min = this; rs2[rep].tot = 0; } else { if (this > rs2[rep].max) { rs2[rep].max = this; } if (this < rs2[rep].min) { rs2[rep].min = this; } } rs2[rep].tot += this; if (rs2[rep].len != response_len || memcmp(data, response, rs2[rep].len) != 0) { fprintf(stderr, "Data mismatch\n"); return EXIT_FAILURE; } } } yh_exit(devices, n_devices); fprintf(stdout, "Iterations %d\n", N_ITERATIONS); fprintf(stdout, "| Len | min [ms] | max [ms] | avg [ms] | type |\n"); fprintf(stdout, "---------------------------------------------------\n"); for (uint16_t i = 0; i < N_REPS; i++) { fprintf(stdout, "| %6d | %8.02f | %8.02f | %8.02f | plain |\n", rs[i].len, rs[i].min, rs[i].max, rs[i].tot / N_ITERATIONS); } for (uint16_t i = 0; i < N_REPS; i++) { fprintf(stdout, "| %6d | %8.02f | %8.02f | %8.02f | auth |\n", rs2[i].len, rs2[i].min, rs2[i].max, rs2[i].tot / N_ITERATIONS); } return EXIT_SUCCESS; } yubihsm-shell-2.8.0/src/tests/wrapped_tests.sh0000755000175100017510000003711415221003515021070 0ustar runnerrunner#!/usr/bin/env bash # # Copyright 2015-2018 Yubico AB # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # if [[ ! -z "$DEBUG" ]]; then set -x fi set -eo pipefail if [ -z ${DEFAULT_CONNECTOR_URL} ]; then DEFAULT_CONNECTOR_URL="http://localhost:12345" fi readonly TMPDIR=$(mktemp -d) trap 'rm -rf "$TMPDIR"' INT TERM EXIT echo ">>> TMPDIR=$TMPDIR" readonly YHSHELL="../yubihsm-shell --connector=${DEFAULT_CONNECTOR_URL}" readonly YHWRAP="../../yhwrap/yubihsm-wrap" put_yhwrapped_authkey() { local -r wrapid="0xdead" local -r wrapkey="$TMPDIR/${FUNCNAME[0]}_wrapkey" local -r authid="0xbeef" local -r authkey="$TMPDIR/${FUNCNAME[0]}_authkey" local -r passfile="$TMPDIR/${FUNCNAME[0]}_passfile" $YHSHELL --action="get-object-info" --password="password" --authkey="1" \ --object-id="$wrapid" --object-type="wrap-key" && { echo "${FUNCNAME[0]}: delete wrapkey" $YHSHELL --action="delete-object" --password="password" --authkey="1" \ --object-id="$wrapid" --object-type="wrap-key" } echo "${FUNCNAME[0]}: put-wrap-key" openssl rand 32 > "$wrapkey" $YHSHELL --action="put-wrap-key" --password="password" --authkey="1" \ --object-id="$wrapid" --label="${FUNCNAME[0]}" --domains="all" \ --capabilities="all" --delegated="all" --in="$wrapkey" --informat="binary" echo "${FUNCNAME[0]}: creating authkey" echo "password" > "$passfile" $YHWRAP --algorithm="aes128-yubico-authentication" --capabilities="all" \ --delegated="all" --domains="all" --id="$authid" --in="$passfile" \ --out="$authkey" --label="${FUNCNAME[0]}" --wrapkey="$wrapkey" $YHSHELL --action="get-object-info" --password="password" --authkey="1" \ --object-id="$authid" --object-type="authentication-key" && { echo "${FUNCNAME[0]}: delete authkey" $YHSHELL --action="delete-object" --password="password" --authkey="1" \ --object-id="$authid" --object-type="authentication-key" } echo "${FUNCNAME[0]}: put-wrapped authkey" $YHSHELL --action="put-wrapped" --password="password" --authkey="1" \ --wrap-id="$wrapid" --in="$authkey" --informat="base64" echo "${FUNCNAME[0]}: using put-wrapped authkey" $YHSHELL --action="get-pseudo-random" --password="$passfile" --authkey="$authid" \ --count=1 --out=/dev/null } put_yhwrapped_authkey_fail_cap() { local -r wrapid="0xdead" local -r wrapkey="$TMPDIR/${FUNCNAME[0]}_wrapkey" local -r authid="0xbeef" local -r authkey="$TMPDIR/${FUNCNAME[0]}_authkey" local -r passfile="$TMPDIR/${FUNCNAME[0]}_passfile" $YHSHELL --action="get-object-info" --password="password" --authkey="1" \ --object-id="$wrapid" --object-type="wrap-key" && { echo "${FUNCNAME[0]}: delete wrapkey" $YHSHELL --action="delete-object" --password="password" --authkey="1" \ --object-id="$wrapid" --object-type="wrap-key" } openssl rand 16 > "$wrapkey" echo "${FUNCNAME[0]}: creating wrapkey" $YHSHELL --action="put-wrap-key" --password="password" --authkey="1" \ --object-id="$wrapid" --label="${FUNCNAME[0]}" --domains="all" \ --capabilities="all" --delegated="none" \ --in="$wrapkey" --informat="binary" echo "${FUNCNAME[0]}: creating authkey" echo "password" > "$passfile" $YHWRAP --algorith="aes128-yubico-authentication" \ --capabilities="all" --delegated="all" \ --domains="all" --id="$authid" --in="$passfile" --out="$authkey" \ --label="${FUNCNAME[0]}" --wrapkey="$wrapkey" echo "${FUNCNAME[0]}: put-wrapped authkey" ! $YHSHELL --action="put-wrapped" --password="password" --authkey="1" \ --wrap-id="$wrapid" --in="$authkey" --informat="base64" if [[ "${PIPESTATUS[0]}" != "1" ]]; then echo "put_yhwrapped_authkey_fail_caps: put-wrapped should have failed" exit 1 fi } put_yhwrapped_authkey_fail_domain() { local -r wrapid="0xdead" local -r wrapkey="$TMPDIR/${FUNCNAME[0]}_wrapkey" local -r authid="0xbeef" local -r authkey="$TMPDIR/${FUNCNAME[0]}_authkey" local -r passfile="$TMPDIR/${FUNCNAME[0]}_passfile" $YHSHELL --action="get-object-info" --password="password" --authkey="1" \ --object-id="$wrapid" --object-type="wrap-key" && { echo "${FUNCNAME[0]}: delete wrapkey" $YHSHELL --action="delete-object" --password="password" --authkey="1" \ --object-id="$wrapid" --object-type="wrap-key" } echo "${FUNCNAME[0]}: creating restricted wrapkey" openssl rand 24 > "$wrapkey" $YHSHELL --action="put-wrap-key" --password="password" --authkey="1" \ --object-id="$wrapid" --label="${FUNCNAME[0]}" --domains="2" \ --capabilities="all" --delegated="all" \ --in="$wrapkey" --informat="binary" echo "${FUNCNAME[0]}: creating authkey" echo "password" > "$passfile" $YHWRAP --algorith="aes128-yubico-authentication" \ --capabilities="all" --delegated="all" \ --domains="all" --id="$authid" --in="$passfile" --out="$authkey" \ --label="${FUNCNAME[0]}" --wrapkey="$wrapkey" $YHSHELL --action="get-object-info" --password="password" --authkey="1" \ --object-id="$authid" --object-type="authentication-key" && { echo "${FUNCNAME[0]}: delete authkey" $YHSHELL --action="delete-object" --password="password" --authkey="1" \ --object-id="$authid" --object-type="authentication-key" } echo "${FUNCNAME[0]}: put-wrapped authkey" $YHSHELL --action="put-wrapped" --password="password" --authkey="1" \ --wrap-id="$wrapid" --in="$authkey" --informat="base64" # NOTE(thorduri): Domains just get filtered. local domains domains="$( $YHSHELL --action="get-object-info" --password="password" \ --authkey="1" --object-type="authentication-key" --object-id="$authid" | grep "^id" \ | awk -F: '{print $7}' | awk -F, '{print $1}' | tr -d '[:space:]' )" if [[ "$domains" != "2" ]]; then echo "${FUNCNAME[0]}: domains not filtered: expected 2 got $domains" exit 1 fi } put_yhwrapped_asymmetric_rsa() { local -r wrapid="0xdead" local -r wrapkey="$TMPDIR/${FUNCNAME[0]}_wrapkey" local -r keyid="0xfefe" local -r keyfile="$TMPDIR/${FUNCNAME[0]}_keyfile.pem" local -r keyfilew="$TMPDIR/${FUNCNAME[0]}_keyfile.wrapped" local -r sigbuf="$TMPDIR/${FUNCNAME[0]}_sigbuf" local -r signature="$TMPDIR/${FUNCNAME[0]}_signature" $YHSHELL --action="get-object-info" --password="password" --authkey="1" \ --object-id="$wrapid" --object-type="wrap-key" && { echo "${FUNCNAME[0]}: delete wrapkey" $YHSHELL --action="delete-object" --password="password" --authkey="1" \ --object-id="$wrapid" --object-type="wrap-key" } echo "${FUNCNAME[0]}: creating wrapkey" openssl rand 16 > "$wrapkey" $YHSHELL --action="put-wrap-key" --password="password" --authkey="1" \ --object-id="$wrapid" --label="${FUNCNAME[0]}" --domains="all" \ --capabilities="all" --delegated="all" \ --in="$wrapkey" --informat="binary" local -r rsa=( "2048" "3072" "4096" ) for size in "${rsa[@]}"; do $YHSHELL --action="get-object-info" --password="password" --authkey="1" \ --object-id="$keyid" --object-type="asymmetric-key" && { echo "${FUNCNAME[0]}: delete rsa key" $YHSHELL --action="delete-object" --password="password" --authkey="1" \ --object-id="$keyid" --object-type="asymmetric-key" } echo "${FUNCNAME[0]}: creating rsa$size key" openssl genrsa -out "$keyfile.$size" $size $YHWRAP --algorithm="rsa$size" \ --capabilities="all" --delegated="all" \ --domains="all" --id="$keyid" --in="$keyfile.$size" \ --out="$keyfilew.$size" --label="${FUNCNAME[0]}" --wrapkey="$wrapkey" echo "${FUNCNAME[0]}: put-wrapped rsa$size asymmetric" $YHSHELL --action="put-wrapped" --password="password" --authkey="1" \ --wrap-id="$wrapid" --in="$keyfilew.$size" --informat="base64" echo "${FUNCNAME[0]}: comparing pubs rsa$size" openssl rsa -in "$keyfile.$size" -pubout > "$keyfile.$size.pub" $YHSHELL --action="get-public-key" --password="password" --authkey="1" \ --object-id="$keyid" --out="$keyfile.$size.pub.shell" diff -u "$keyfile.$size.pub" "$keyfile.$size.pub.shell" openssl rand 1024 > "$sigbuf" echo "${FUNCNAME[0]}: sign-pkcs1v15 rsa$size rsa-pkcs1-sha256" $YHSHELL --action="sign-pkcs1v15" --password="password" --authkey="1" \ --object-id="$keyid" --algorithm "rsa-pkcs1-sha256" --in="$sigbuf" --out "$signature.$size" --outformat="bin" echo "${FUNCNAME[0]}: verifying rsa$size sha256 signature" openssl dgst -sha256 -verify "$keyfile.$size.pub" -signature "$signature.$size" "$sigbuf" done } put_yhwrapped_asymmetric_ecdsa() { local -r wrapid="0xdead" local -r wrapkey="$TMPDIR/${FUNCNAME[0]}_wrapkey" local -r keyid="0xfefe" local -r keyfile="$TMPDIR/${FUNCNAME[0]}_keyfile.pem" local -r keyfilew="$TMPDIR/${FUNCNAME[0]}_keyfile.wrapped" $YHSHELL --action="get-object-info" --password="password" --authkey="1" \ --object-id="$wrapid" --object-type="wrap-key" && { echo "${FUNCNAME[0]}: delete wrapkey" $YHSHELL --action="delete-object" --password="password" --authkey="1" \ --object-id="$wrapid" --object-type="wrap-key" } echo "${FUNCNAME[0]}: creating wrapkey" openssl rand 16 > "$wrapkey" $YHSHELL --action="put-wrap-key" --password="password" --authkey="1" \ --object-id="$wrapid" --label="${FUNCNAME[0]}" --domains="all" \ --capabilities="all" --delegated="all" \ --in="$wrapkey" --informat="binary" curves="secp256k1 secp384r1 secp521r1 prime256v1" secp256k1=eck256 secp384r1=ecp384 secp521r1=ecp521 prime256v1=ecp256 if openssl ecparam -list_curves | grep -q brainpoolP256r1; then curves="$curves brainpoolP256r1 brainpoolP384r1 brainpoolP512r1" brainpoolP256r1=ecbp256 brainpoolP384r1=ecbp384 brainpoolP512r1=ecbp512 fi for curve in $curves; do $YHSHELL --action="get-object-info" --password="password" --authkey="1" \ --object-id="$keyid" --object-type="asymmetric-key" && { echo "${FUNCNAME[0]}: delete ec key" $YHSHELL --action="delete-object" --password="password" --authkey="1" \ --object-id="$keyid" --object-type="asymmetric-key" } echo "${FUNCNAME[0]}: creating ${!curve} key" openssl ecparam -genkey -noout -name $curve > "$keyfile.$curve" $YHWRAP --algorithm="${!curve}" \ --capabilities="all" --delegated="all" \ --domains="all" --id="$keyid" --in="$keyfile.$curve" \ --out="$keyfilew.$curve" --label="${FUNCNAME[0]}" --wrapkey="$wrapkey" echo "${FUNCNAME[0]}: put-wrapped ${!curve}" $YHSHELL --action="put-wrapped" --password="password" --authkey="1" \ --wrap-id="$wrapid" --in="$keyfilew.$curve" --informat="base64" echo "${FUNCNAME[0]}: comparing pubs ${!curve}" openssl ec -in "$keyfile.$curve" -pubout > "$keyfile.$curve.pub" $YHSHELL --action="get-public-key" --password="password" --authkey="1" \ --object-id="$keyid" --out="$keyfile.$curve.pub.shell" diff -u "$keyfile.$curve.pub" "$keyfile.$curve.pub.shell" done } put_yhwrapped_asymmetric_eddsa() { if [ $(openssl list -public-key-methods | grep -i ed25519 -c) -eq 0 ]; then echo "OpenSSL version without Ed25519, skipping put_yhwrapped_asymmetric_eddsa" return fi local -r edkeyid="0xeded" local -r wrapid="0xdead" local -r wrapkey="$TMPDIR/${FUNCNAME[0]}_wrapkey" local -r keyid="0xfefe" local -r keyfile="$TMPDIR/${FUNCNAME[0]}_keyfile.pem" local -r keyfilew="$TMPDIR/${FUNCNAME[0]}_keyfile.wrapped" local -r sigfile1="$TMPDIR/${FUNCNAME[0]}_sig_1" local -r sigfile2="$TMPDIR/${FUNCNAME[0]}_sig_2" $YHSHELL --action="get-object-info" --password="password" --authkey="1" \ --object-id="$wrapid" --object-type="wrap-key" && { echo "${FUNCNAME[0]}: delete wrapkey" $YHSHELL --action="delete-object" --password="password" --authkey="1" \ --object-id="$wrapid" --object-type="wrap-key" } echo "${FUNCNAME[0]}: creating wrapkey" openssl rand 16 > "$wrapkey" $YHSHELL --action="put-wrap-key" --password="password" --authkey="1" \ --object-id="$wrapid" --label="${FUNCNAME[0]}" --domains="all" \ --capabilities="all" --delegated="all" \ --in="$wrapkey" --informat="binary" $YHSHELL --action="get-object-info" --password="password" --authkey="1" \ --object-id="$keyid" --object-type="asymmetric-key" && { echo "${FUNCNAME[0]}: delete ed key" $YHSHELL --action="delete-object" --password="password" --authkey="1" \ --object-id="$keyid" --object-type="asymmetric-key" } echo "${FUNCNAME[0]}: creating ed key" openssl genpkey -algorithm Ed25519 -out "$keyfile" $YHSHELL --action="get-object-info" --password="password" --authkey="1" \ --object-id="$edkeyid" --object-type="asymmetric-key" && { echo "${FUNCNAME[0]}: delete imported ed key" $YHSHELL --action="delete-object" --password="password" --authkey="1" \ --object-id="$edkeyid" --object-type="asymmetric-key" } echo "${FUNCNAME[0]}: importing ed key" $YHSHELL --action="put-asymmetric-key" --password="password" --authkey="1" \ --object-id="$edkeyid" --label="${FUNCNAME[0]}" --domains="all" \ --capabilities="all" \ --in="$keyfile" --informat="binary" echo "${FUNCNAME[0]}: signing with ed key" rm -f $sigfile1 $YHSHELL --action="sign-eddsa" --object-id="$edkeyid" --algorithm="ed25519" --in="$wrapkey" --out="$sigfile1" --password="password" $YHWRAP --algorithm="ed25519" \ --capabilities="all" --delegated="all" \ --domains="all" --id="$keyid" --in="$keyfile" \ --out="$keyfilew" --label="${FUNCNAME[0]}" --wrapkey="$wrapkey" echo "${FUNCNAME[0]}: put-wrapped ed25519" $YHSHELL --action="put-wrapped" --password="password" --authkey="1" \ --wrap-id="$wrapid" --in="$keyfilew" --informat="base64" echo "${FUNCNAME[0]}: comparing pubs ed25519" openssl pkey -in "$keyfile" -pubout > "$keyfile.pub" $YHSHELL --action="get-public-key" --password="password" --authkey="1" \ --object-id="$keyid" --out="$keyfile.pub.shell" diff -u "$keyfile.pub" "$keyfile.pub.shell" echo "${FUNCNAME[0]}: signing with wrapped ed key" rm -f "$sigfile2" $YHSHELL --action="sign-eddsa" --object-id="$keyid" --algorithm="ed25519" --in="$wrapkey" --out="$sigfile2" --password="password" diff -u "$sigfile1" "$sigfile2" } main() { put_yhwrapped_authkey put_yhwrapped_authkey_fail_cap put_yhwrapped_authkey_fail_domain put_yhwrapped_asymmetric_rsa put_yhwrapped_asymmetric_ecdsa put_yhwrapped_asymmetric_eddsa } main "$@" yubihsm-shell-2.8.0/src/tests/CMakeLists.txt0000644000175100017510000000200515221003515020374 0ustar runnerrunner# # Copyright 2015-2018 Yubico AB # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # find_program (BASH_PROGRAM bash) configure_file ( ${CMAKE_CURRENT_SOURCE_DIR}/data.txt ${CMAKE_CURRENT_BINARY_DIR}/data.txt COPYONLY) configure_file ( ${CMAKE_CURRENT_SOURCE_DIR}/sig.out ${CMAKE_CURRENT_BINARY_DIR}/sig.out COPYONLY) add_test( NAME bash_tests COMMAND ${BASH_PROGRAM} ${CMAKE_CURRENT_SOURCE_DIR}/tests.sh ) add_test( NAME wrapped_tests COMMAND ${BASH_PROGRAM} ${CMAKE_CURRENT_SOURCE_DIR}/wrapped_tests.sh ) yubihsm-shell-2.8.0/src/cmd_util.c0000644000175100017510000001502215221003515016441 0ustar runnerrunner/* * Copyright 2025 Yubico AB * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include "yubihsm-shell.h" #include "cmd_util.h" static char *string_parser(char *str_orig, char delimiter, char *str_found) { char escape_char = '\\'; int f = 0; char *p = str_orig; while (*p == delimiter) { p++; } for (; *p; p++) { if (*p != delimiter) { str_found[f++] = *p; } else if (*p == delimiter) { if ((*(p - 1) == escape_char && *(p - 2) == escape_char)) { // The escape_char before the delimiter is escaped // => the delimiter is still in effect str_found[f - 1] = '\0'; return p + 1; } else if (*(p - 1) == escape_char && *(p - 2) != escape_char) { // the delimiter is escaped str_found[f - 1] = delimiter; } else { // nothing is escaped str_found[f] = '\0'; return p + 1; } } } str_found[f] = '\0'; return NULL; } X509_NAME *parse_subject_name(const char *orig_name) { char name[1025] = {0}; char part[1025] = {0}; X509_NAME *parsed = NULL; char *ptr = name; if (strlen(orig_name) > 1024) { fprintf(stderr, "Name is too long!\n"); return NULL; } strncpy(name, orig_name, sizeof(name)); name[sizeof(name) - 1] = 0; if (*name != '/' || name[strlen(name) - 1] != '/') { fprintf(stderr, "Name does not start or does not end with '/'!\n"); return NULL; } parsed = X509_NAME_new(); if (!parsed) { fprintf(stderr, "Failed to allocate memory\n"); return NULL; } while ((ptr = string_parser(ptr, '/', part))) { char *key; char *value; char *equals = strchr(part, '='); if (!equals) { fprintf(stderr, "The part '%s' doesn't seem to contain a =.\n", part); goto parse_err; } *equals++ = '\0'; value = equals; key = part; if (!key) { fprintf(stderr, "Malformed name (%s)\n", part); goto parse_err; } if (!value) { fprintf(stderr, "Malformed name (%s)\n", part); goto parse_err; } if (!X509_NAME_add_entry_by_txt(parsed, key, MBSTRING_UTF8, (unsigned char *) value, -1, -1, 0)) { fprintf(stderr, "Failed adding %s=%s to name.\n", key, value); goto parse_err; } } return parsed; parse_err: X509_NAME_free(parsed); return NULL; } static int ec_key_ex_data_idx = -1; struct internal_key { yh_session *session; uint16_t key_id; }; static int yk_rsa_meth_finish(RSA *rsa) { free(RSA_meth_get0_app_data(RSA_get_method(rsa))); return 1; } static int yk_rsa_meth_sign(int dtype, const unsigned char *m, unsigned int m_len, unsigned char *sig, unsigned int *sig_len, const RSA *rsa) { UNUSED(dtype); size_t yh_siglen = RSA_size(rsa); const RSA_METHOD *meth = RSA_get_method(rsa); const struct internal_key *key = RSA_meth_get0_app_data(meth); yh_rc yrc = yh_util_sign_pkcs1v1_5(key->session, key->key_id, true, m, m_len, sig, &yh_siglen); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to sign data with PKCS#1v1.5: %s\n", yh_strerror(yrc)); return 0; } *sig_len = (unsigned int) yh_siglen; return 1; } static void yk_ec_meth_finish(EC_KEY *ec) { free(EC_KEY_get_ex_data(ec, ec_key_ex_data_idx)); } static int yk_ec_meth_sign(int type, const unsigned char *m, int m_len, unsigned char *sig, unsigned int *sig_len, const BIGNUM *kinv, const BIGNUM *r, EC_KEY *ec) { UNUSED(type); UNUSED(kinv); UNUSED(r); size_t yh_siglen = ECDSA_size(ec); const struct internal_key *key = EC_KEY_get_ex_data(ec, ec_key_ex_data_idx); yh_rc yrc = yh_util_sign_ecdsa(key->session, key->key_id, m, m_len, sig, &yh_siglen); if (yrc != YHR_SUCCESS) { fprintf(stderr, "Failed to sign data with ECDSA: %s\n", yh_strerror(yrc)); return 0; } *sig_len = (unsigned int) yh_siglen; return 1; } EVP_PKEY *wrap_public_key(yh_session *session, yh_algorithm algorithm, EVP_PKEY *public_key, uint16_t key_id) { struct internal_key *int_key = malloc(sizeof(struct internal_key)); int_key->session = session; int_key->key_id = key_id; EVP_PKEY *pkey = EVP_PKEY_new(); if (yh_is_rsa(algorithm)) { const RSA *pk = EVP_PKEY_get0_RSA(public_key); RSA_METHOD *meth = RSA_meth_dup(RSA_get_default_method()); if (RSA_meth_set0_app_data(meth, int_key) != 1) { fprintf(stderr, "Failed to set RSA data\n"); return NULL; } if (RSA_meth_set_finish(meth, yk_rsa_meth_finish) != 1) { fprintf(stderr, "Failed to set RSA finish method\n"); return NULL; } if (RSA_meth_set_sign(meth, yk_rsa_meth_sign) != 1) { fprintf(stderr, "Failed to set RSA sign method\n"); return NULL; } RSA *sk = RSA_new(); RSA_set0_key(sk, BN_dup(RSA_get0_n(pk)), BN_dup(RSA_get0_e(pk)), NULL); if (RSA_set_method(sk, meth) != 1) { fprintf(stderr, "Failed to set RSA key method\n"); return NULL; } EVP_PKEY_assign_RSA(pkey, sk); } else if (yh_is_ec(algorithm)) { const EC_KEY *ec = EVP_PKEY_get0_EC_KEY(public_key); EC_KEY_METHOD *meth = EC_KEY_METHOD_new(EC_KEY_get_method(ec)); EC_KEY_METHOD_set_init(meth, NULL, yk_ec_meth_finish, NULL, NULL, NULL, NULL); EC_KEY_METHOD_set_sign(meth, yk_ec_meth_sign, NULL, NULL); EC_KEY *sk = EC_KEY_new(); EC_KEY_set_group(sk, EC_KEY_get0_group(ec)); EC_KEY_set_public_key(sk, EC_KEY_get0_public_key(ec)); if (ec_key_ex_data_idx == -1) ec_key_ex_data_idx = EC_KEY_get_ex_new_index(0, NULL, NULL, NULL, NULL); if (EC_KEY_set_ex_data(sk, ec_key_ex_data_idx, int_key) != 1) { fprintf(stderr, "Failed to set EC data\n"); return NULL; } if (EC_KEY_set_method(sk, meth) != 1) { fprintf(stderr, "Failed to wrap public EC key\n"); return NULL; } EVP_PKEY_assign_EC_KEY(pkey, sk); } return pkey; } yubihsm-shell-2.8.0/src/cmdline.h0000644000175100017510000006155515221003575016303 0ustar runnerrunner/** @file cmdline.h * @brief The header file for the command line option parser * generated by GNU Gengetopt version 2.23 * http://www.gnu.org/software/gengetopt. * DO NOT modify this file, since it can be overwritten * @author GNU Gengetopt */ #ifndef CMDLINE_H #define CMDLINE_H /* If we use autoconf. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include /* for FILE */ #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ #ifndef CMDLINE_PARSER_PACKAGE /** @brief the program name (used for printing errors) */ #define CMDLINE_PARSER_PACKAGE PACKAGE #endif #ifndef CMDLINE_PARSER_PACKAGE_NAME /** @brief the complete program name (used for help and version) */ #ifdef PACKAGE_NAME #define CMDLINE_PARSER_PACKAGE_NAME PACKAGE_NAME #else #define CMDLINE_PARSER_PACKAGE_NAME PACKAGE #endif #endif #ifndef CMDLINE_PARSER_VERSION /** @brief the program version */ #define CMDLINE_PARSER_VERSION VERSION #endif enum enum_action { action__NULL = -1, action_arg_benchmark = 0, action_arg_blinkMINUS_device, action_arg_createMINUS_otpMINUS_aead, action_arg_decryptMINUS_aesccm, action_arg_decryptMINUS_aescbc, action_arg_decryptMINUS_aesecb, action_arg_decryptMINUS_oaep, action_arg_decryptMINUS_otp, action_arg_decryptMINUS_pkcs1v15, action_arg_deleteMINUS_object, action_arg_deriveMINUS_ecdh, action_arg_encryptMINUS_aesccm, action_arg_encryptMINUS_aescbc, action_arg_encryptMINUS_aesecb, action_arg_generateMINUS_asymmetricMINUS_key, action_arg_generateMINUS_csr, action_arg_generateMINUS_hmacMINUS_key, action_arg_generateMINUS_otpMINUS_aeadMINUS_key, action_arg_generateMINUS_wrapMINUS_key, action_arg_generateMINUS_symmetricMINUS_key, action_arg_getMINUS_deviceMINUS_info, action_arg_getMINUS_logs, action_arg_getMINUS_objectMINUS_info, action_arg_getMINUS_opaque, action_arg_getMINUS_option, action_arg_getMINUS_pseudoMINUS_random, action_arg_getMINUS_publicMINUS_key, action_arg_getMINUS_storageMINUS_info, action_arg_getMINUS_template, action_arg_getMINUS_wrapped, action_arg_getMINUS_rsaMINUS_wrapped, action_arg_getMINUS_rsaMINUS_wrappedMINUS_key, action_arg_getMINUS_deviceMINUS_pubkey, action_arg_listMINUS_objects, action_arg_putMINUS_asymmetricMINUS_key, action_arg_putMINUS_authenticationMINUS_key, action_arg_putMINUS_hmacMINUS_key, action_arg_putMINUS_opaque, action_arg_putMINUS_option, action_arg_putMINUS_otpMINUS_aeadMINUS_key, action_arg_putMINUS_symmetricMINUS_key, action_arg_putMINUS_template, action_arg_putMINUS_wrapMINUS_key, action_arg_putMINUS_rsaMINUS_wrapkey, action_arg_putMINUS_publicMINUS_wrapkey, action_arg_putMINUS_wrapped, action_arg_putMINUS_rsaMINUS_wrapped, action_arg_putMINUS_rsaMINUS_wrappedMINUS_key, action_arg_randomizeMINUS_otpMINUS_aead, action_arg_reset, action_arg_setMINUS_logMINUS_index, action_arg_signMINUS_attestationMINUS_certificate, action_arg_signMINUS_ecdsa, action_arg_signMINUS_eddsa, action_arg_signMINUS_hmac, action_arg_signMINUS_pkcs1v15, action_arg_signMINUS_pss, action_arg_signMINUS_sshMINUS_certificate }; enum enum_informat { informat__NULL = -1, informat_arg_default = 0, informat_arg_base64, informat_arg_binary, informat_arg_PEM, informat_arg_password, informat_arg_hex, informat_arg_ASCII }; enum enum_outformat { outformat__NULL = -1, outformat_arg_default = 0, outformat_arg_base64, outformat_arg_binary, outformat_arg_PEM, outformat_arg_hex, outformat_arg_ASCII }; /** @brief Where the command line options are stored */ struct gengetopt_args_info { const char *help_help; /**< @brief Print help and exit help description. */ const char *version_help; /**< @brief Print version and exit help description. */ enum enum_action *action_arg; /**< @brief Action to perform. */ char ** action_orig; /**< @brief Action to perform original value given at command line. */ unsigned int action_min; /**< @brief Action to perform's minimum occurreces */ unsigned int action_max; /**< @brief Action to perform's maximum occurreces */ const char *action_help; /**< @brief Action to perform help description. */ char * password_arg; /**< @brief Authentication password. */ char * password_orig; /**< @brief Authentication password original value given at command line. */ const char *password_help; /**< @brief Authentication password help description. */ short authkey_arg; /**< @brief Authentication key (default='1'). */ char * authkey_orig; /**< @brief Authentication key original value given at command line. */ const char *authkey_help; /**< @brief Authentication key help description. */ short object_id_arg; /**< @brief Object ID (default='0'). */ char * object_id_orig; /**< @brief Object ID original value given at command line. */ const char *object_id_help; /**< @brief Object ID help description. */ char * label_arg; /**< @brief Object label (default=''). */ char * label_orig; /**< @brief Object label original value given at command line. */ const char *label_help; /**< @brief Object label help description. */ char * domains_arg; /**< @brief Object domains (default='1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16'). */ char * domains_orig; /**< @brief Object domains original value given at command line. */ const char *domains_help; /**< @brief Object domains help description. */ char * capabilities_arg; /**< @brief Capabilities for an object (default='0'). */ char * capabilities_orig; /**< @brief Capabilities for an object original value given at command line. */ const char *capabilities_help; /**< @brief Capabilities for an object help description. */ char * object_type_arg; /**< @brief Object type (default='any'). */ char * object_type_orig; /**< @brief Object type original value given at command line. */ const char *object_type_help; /**< @brief Object type help description. */ char * ykhsmauth_label_arg; /**< @brief Credential label on YubiKey (implicitly enables ykhsmauth). */ char * ykhsmauth_label_orig; /**< @brief Credential label on YubiKey (implicitly enables ykhsmauth) original value given at command line. */ const char *ykhsmauth_label_help; /**< @brief Credential label on YubiKey (implicitly enables ykhsmauth) help description. */ char * ykhsmauth_reader_arg; /**< @brief Only use a matching YubiKey reader name (default=''). */ char * ykhsmauth_reader_orig; /**< @brief Only use a matching YubiKey reader name original value given at command line. */ const char *ykhsmauth_reader_help; /**< @brief Only use a matching YubiKey reader name help description. */ char * delegated_arg; /**< @brief Delegated capabilities (default='0'). */ char * delegated_orig; /**< @brief Delegated capabilities original value given at command line. */ const char *delegated_help; /**< @brief Delegated capabilities help description. */ char * new_password_arg; /**< @brief New authentication password. */ char * new_password_orig; /**< @brief New authentication password original value given at command line. */ const char *new_password_help; /**< @brief New authentication password help description. */ char * algorithm_arg; /**< @brief Operation algorithm (default='any'). */ char * algorithm_orig; /**< @brief Operation algorithm original value given at command line. */ const char *algorithm_help; /**< @brief Operation algorithm help description. */ char * oaep_arg; /**< @brief OAEP algorithm. Used primarily with asymmetric wrap (default='rsa-oaep-sha256'). */ char * oaep_orig; /**< @brief OAEP algorithm. Used primarily with asymmetric wrap original value given at command line. */ const char *oaep_help; /**< @brief OAEP algorithm. Used primarily with asymmetric wrap help description. */ char * mgf1_arg; /**< @brief MGF1 algorithm. Used primarily with asymmetric wrap (default='mgf1-sha256'). */ char * mgf1_orig; /**< @brief MGF1 algorithm. Used primarily with asymmetric wrap original value given at command line. */ const char *mgf1_help; /**< @brief MGF1 algorithm. Used primarily with asymmetric wrap help description. */ int nonce_arg; /**< @brief OTP nonce. */ char * nonce_orig; /**< @brief OTP nonce original value given at command line. */ const char *nonce_help; /**< @brief OTP nonce help description. */ char * iv_arg; /**< @brief An initialization vector as a hexadecimal string. */ char * iv_orig; /**< @brief An initialization vector as a hexadecimal string original value given at command line. */ const char *iv_help; /**< @brief An initialization vector as a hexadecimal string help description. */ int count_arg; /**< @brief Number of bytes to request (default='256'). */ char * count_orig; /**< @brief Number of bytes to request original value given at command line. */ const char *count_help; /**< @brief Number of bytes to request help description. */ int duration_arg; /**< @brief Blink duration in seconds (default='10'). */ char * duration_orig; /**< @brief Blink duration in seconds original value given at command line. */ const char *duration_help; /**< @brief Blink duration in seconds help description. */ short wrap_id_arg; /**< @brief Wrap key ID. */ char * wrap_id_orig; /**< @brief Wrap key ID original value given at command line. */ const char *wrap_id_help; /**< @brief Wrap key ID help description. */ int include_seed_flag; /**< @brief Include seed when exporting an ED25519 key under wrap (default=off). */ const char *include_seed_help; /**< @brief Include seed when exporting an ED25519 key under wrap help description. */ short template_id_arg; /**< @brief Template ID. */ char * template_id_orig; /**< @brief Template ID original value given at command line. */ const char *template_id_help; /**< @brief Template ID help description. */ short attestation_id_arg; /**< @brief Attestation ID. */ char * attestation_id_orig; /**< @brief Attestation ID original value given at command line. */ const char *attestation_id_help; /**< @brief Attestation ID help description. */ int log_index_arg; /**< @brief Log index. */ char * log_index_orig; /**< @brief Log index original value given at command line. */ const char *log_index_help; /**< @brief Log index help description. */ char * opt_name_arg; /**< @brief Device option name. */ char * opt_name_orig; /**< @brief Device option name original value given at command line. */ const char *opt_name_help; /**< @brief Device option name help description. */ char * opt_value_arg; /**< @brief Device option value. */ char * opt_value_orig; /**< @brief Device option value original value given at command line. */ const char *opt_value_help; /**< @brief Device option value help description. */ int with_compression_flag; /**< @brief Compress a X509Certificate before importing it into the device or detect compressed certificates when listing objects (default=off). */ const char *with_compression_help; /**< @brief Compress a X509Certificate before importing it into the device or detect compressed certificates when listing objects help description. */ char * subject_arg; /**< @brief The subject to use for certificate request. The subject must be written as: /CN=host.example.com/OU=test/O=example.com/. */ char * subject_orig; /**< @brief The subject to use for certificate request. The subject must be written as: /CN=host.example.com/OU=test/O=example.com/ original value given at command line. */ const char *subject_help; /**< @brief The subject to use for certificate request. The subject must be written as: /CN=host.example.com/OU=test/O=example.com/ help description. */ char * in_arg; /**< @brief Input data (filename) (default='-'). */ char * in_orig; /**< @brief Input data (filename) original value given at command line. */ const char *in_help; /**< @brief Input data (filename) help description. */ char * out_arg; /**< @brief Output data (filename) (default='-'). */ char * out_orig; /**< @brief Output data (filename) original value given at command line. */ const char *out_help; /**< @brief Output data (filename) help description. */ enum enum_informat informat_arg; /**< @brief Input format (default='default'). */ char * informat_orig; /**< @brief Input format original value given at command line. */ const char *informat_help; /**< @brief Input format help description. */ enum enum_outformat outformat_arg; /**< @brief Input and output format (default='default'). */ char * outformat_orig; /**< @brief Input and output format original value given at command line. */ const char *outformat_help; /**< @brief Input and output format help description. */ char * config_file_arg; /**< @brief Configuration file to read (default=''). */ char * config_file_orig; /**< @brief Configuration file to read original value given at command line. */ const char *config_file_help; /**< @brief Configuration file to read help description. */ char ** connector_arg; /**< @brief List of connectors to use. */ char ** connector_orig; /**< @brief List of connectors to use original value given at command line. */ unsigned int connector_min; /**< @brief List of connectors to use's minimum occurreces */ unsigned int connector_max; /**< @brief List of connectors to use's maximum occurreces */ const char *connector_help; /**< @brief List of connectors to use help description. */ char * cacert_arg; /**< @brief HTTPS cacert for connector. */ char * cacert_orig; /**< @brief HTTPS cacert for connector original value given at command line. */ const char *cacert_help; /**< @brief HTTPS cacert for connector help description. */ char * cert_arg; /**< @brief HTTPS client certificate to authenticate with. */ char * cert_orig; /**< @brief HTTPS client certificate to authenticate with original value given at command line. */ const char *cert_help; /**< @brief HTTPS client certificate to authenticate with help description. */ char * key_arg; /**< @brief HTTPS client certificate key. */ char * key_orig; /**< @brief HTTPS client certificate key original value given at command line. */ const char *key_help; /**< @brief HTTPS client certificate key help description. */ char * proxy_arg; /**< @brief Proxy server to use for connector. */ char * proxy_orig; /**< @brief Proxy server to use for connector original value given at command line. */ const char *proxy_help; /**< @brief Proxy server to use for connector help description. */ char * noproxy_arg; /**< @brief Comma separated list of hosts ignore proxy for. */ char * noproxy_orig; /**< @brief Comma separated list of hosts ignore proxy for original value given at command line. */ const char *noproxy_help; /**< @brief Comma separated list of hosts ignore proxy for help description. */ int verbose_arg; /**< @brief Print more information (default='0'). */ char * verbose_orig; /**< @brief Print more information original value given at command line. */ const char *verbose_help; /**< @brief Print more information help description. */ int pre_connect_flag; /**< @brief Connect immediately in interactive mode (default=off). */ const char *pre_connect_help; /**< @brief Connect immediately in interactive mode help description. */ char ** device_pubkey_arg; /**< @brief List of device public keys allowed for asymmetric authentication. */ char ** device_pubkey_orig; /**< @brief List of device public keys allowed for asymmetric authentication original value given at command line. */ unsigned int device_pubkey_min; /**< @brief List of device public keys allowed for asymmetric authentication's minimum occurreces */ unsigned int device_pubkey_max; /**< @brief List of device public keys allowed for asymmetric authentication's maximum occurreces */ const char *device_pubkey_help; /**< @brief List of device public keys allowed for asymmetric authentication help description. */ unsigned int help_given ; /**< @brief Whether help was given. */ unsigned int version_given ; /**< @brief Whether version was given. */ unsigned int action_given ; /**< @brief Whether action was given. */ unsigned int password_given ; /**< @brief Whether password was given. */ unsigned int authkey_given ; /**< @brief Whether authkey was given. */ unsigned int object_id_given ; /**< @brief Whether object-id was given. */ unsigned int label_given ; /**< @brief Whether label was given. */ unsigned int domains_given ; /**< @brief Whether domains was given. */ unsigned int capabilities_given ; /**< @brief Whether capabilities was given. */ unsigned int object_type_given ; /**< @brief Whether object-type was given. */ unsigned int ykhsmauth_label_given ; /**< @brief Whether ykhsmauth-label was given. */ unsigned int ykhsmauth_reader_given ; /**< @brief Whether ykhsmauth-reader was given. */ unsigned int delegated_given ; /**< @brief Whether delegated was given. */ unsigned int new_password_given ; /**< @brief Whether new-password was given. */ unsigned int algorithm_given ; /**< @brief Whether algorithm was given. */ unsigned int oaep_given ; /**< @brief Whether oaep was given. */ unsigned int mgf1_given ; /**< @brief Whether mgf1 was given. */ unsigned int nonce_given ; /**< @brief Whether nonce was given. */ unsigned int iv_given ; /**< @brief Whether iv was given. */ unsigned int count_given ; /**< @brief Whether count was given. */ unsigned int duration_given ; /**< @brief Whether duration was given. */ unsigned int wrap_id_given ; /**< @brief Whether wrap-id was given. */ unsigned int include_seed_given ; /**< @brief Whether include-seed was given. */ unsigned int template_id_given ; /**< @brief Whether template-id was given. */ unsigned int attestation_id_given ; /**< @brief Whether attestation-id was given. */ unsigned int log_index_given ; /**< @brief Whether log-index was given. */ unsigned int opt_name_given ; /**< @brief Whether opt-name was given. */ unsigned int opt_value_given ; /**< @brief Whether opt-value was given. */ unsigned int with_compression_given ; /**< @brief Whether with-compression was given. */ unsigned int subject_given ; /**< @brief Whether subject was given. */ unsigned int in_given ; /**< @brief Whether in was given. */ unsigned int out_given ; /**< @brief Whether out was given. */ unsigned int informat_given ; /**< @brief Whether informat was given. */ unsigned int outformat_given ; /**< @brief Whether outformat was given. */ unsigned int config_file_given ; /**< @brief Whether config-file was given. */ unsigned int connector_given ; /**< @brief Whether connector was given. */ unsigned int cacert_given ; /**< @brief Whether cacert was given. */ unsigned int cert_given ; /**< @brief Whether cert was given. */ unsigned int key_given ; /**< @brief Whether key was given. */ unsigned int proxy_given ; /**< @brief Whether proxy was given. */ unsigned int noproxy_given ; /**< @brief Whether noproxy was given. */ unsigned int verbose_given ; /**< @brief Whether verbose was given. */ unsigned int pre_connect_given ; /**< @brief Whether pre-connect was given. */ unsigned int device_pubkey_given ; /**< @brief Whether device-pubkey was given. */ } ; /** @brief The additional parameters to pass to parser functions */ struct cmdline_parser_params { int override; /**< @brief whether to override possibly already present options (default 0) */ int initialize; /**< @brief whether to initialize the option structure gengetopt_args_info (default 1) */ int check_required; /**< @brief whether to check that all required options were provided (default 1) */ int check_ambiguity; /**< @brief whether to check for options already specified in the option structure gengetopt_args_info (default 0) */ int print_errors; /**< @brief whether getopt_long should print an error message for a bad option (default 1) */ } ; /** @brief the purpose string of the program */ extern const char *gengetopt_args_info_purpose; /** @brief the usage string of the program */ extern const char *gengetopt_args_info_usage; /** @brief the description string of the program */ extern const char *gengetopt_args_info_description; /** @brief all the lines making the help output */ extern const char *gengetopt_args_info_help[]; /** * The command line parser * @param argc the number of command line options * @param argv the command line options * @param args_info the structure where option information will be stored * @return 0 if everything went fine, NON 0 if an error took place */ int cmdline_parser (int argc, char **argv, struct gengetopt_args_info *args_info); /** * The command line parser (version with additional parameters - deprecated) * @param argc the number of command line options * @param argv the command line options * @param args_info the structure where option information will be stored * @param override whether to override possibly already present options * @param initialize whether to initialize the option structure my_args_info * @param check_required whether to check that all required options were provided * @return 0 if everything went fine, NON 0 if an error took place * @deprecated use cmdline_parser_ext() instead */ int cmdline_parser2 (int argc, char **argv, struct gengetopt_args_info *args_info, int override, int initialize, int check_required); /** * The command line parser (version with additional parameters) * @param argc the number of command line options * @param argv the command line options * @param args_info the structure where option information will be stored * @param params additional parameters for the parser * @return 0 if everything went fine, NON 0 if an error took place */ int cmdline_parser_ext (int argc, char **argv, struct gengetopt_args_info *args_info, struct cmdline_parser_params *params); /** * Save the contents of the option struct into an already open FILE stream. * @param outfile the stream where to dump options * @param args_info the option struct to dump * @return 0 if everything went fine, NON 0 if an error took place */ int cmdline_parser_dump(FILE *outfile, struct gengetopt_args_info *args_info); /** * Save the contents of the option struct into a (text) file. * This file can be read by the config file parser (if generated by gengetopt) * @param filename the file where to save * @param args_info the option struct to save * @return 0 if everything went fine, NON 0 if an error took place */ int cmdline_parser_file_save(const char *filename, struct gengetopt_args_info *args_info); /** * Print the help */ void cmdline_parser_print_help(void); /** * Print the version */ void cmdline_parser_print_version(void); /** * Initializes all the fields a cmdline_parser_params structure * to their default values * @param params the structure to initialize */ void cmdline_parser_params_init(struct cmdline_parser_params *params); /** * Allocates dynamically a cmdline_parser_params structure and initializes * all its fields to their default values * @return the created and initialized cmdline_parser_params structure */ struct cmdline_parser_params *cmdline_parser_params_create(void); /** * Initializes the passed gengetopt_args_info structure's fields * (also set default values for options that have a default) * @param args_info the structure to initialize */ void cmdline_parser_init (struct gengetopt_args_info *args_info); /** * Deallocates the string fields of the gengetopt_args_info structure * (but does not deallocate the structure itself) * @param args_info the structure to deallocate */ void cmdline_parser_free (struct gengetopt_args_info *args_info); /** * The config file parser (deprecated version) * @param filename the name of the config file * @param args_info the structure where option information will be stored * @param override whether to override possibly already present options * @param initialize whether to initialize the option structure my_args_info * @param check_required whether to check that all required options were provided * @return 0 if everything went fine, NON 0 if an error took place * @deprecated use cmdline_parser_config_file() instead */ int cmdline_parser_configfile (const char *filename, struct gengetopt_args_info *args_info, int override, int initialize, int check_required); /** * The config file parser * @param filename the name of the config file * @param args_info the structure where option information will be stored * @param params additional parameters for the parser * @return 0 if everything went fine, NON 0 if an error took place */ int cmdline_parser_config_file (const char *filename, struct gengetopt_args_info *args_info, struct cmdline_parser_params *params); /** * Checks that all the required options were specified * @param args_info the structure to check * @param prog_name the name of the program that will be used to print * possible errors * @return */ int cmdline_parser_required (struct gengetopt_args_info *args_info, const char *prog_name); extern const char *cmdline_parser_action_values[]; /**< @brief Possible values for action. */ extern const char *cmdline_parser_informat_values[]; /**< @brief Possible values for informat. */ extern const char *cmdline_parser_outformat_values[]; /**< @brief Possible values for outformat. */ #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* CMDLINE_H */ yubihsm-shell-2.8.0/src/cmdline.ggo0000644000175100017510000001713615221003515016616 0ustar runnerrunner# # Copyright 2015-2018 Yubico AB # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # option "action" a "Action to perform" values="benchmark", "blink-device", "create-otp-aead", "decrypt-aesccm", "decrypt-aescbc", "decrypt-aesecb", "decrypt-oaep", "decrypt-otp", "decrypt-pkcs1v15", "delete-object", "derive-ecdh", "encrypt-aesccm", "encrypt-aescbc", "encrypt-aesecb", "generate-asymmetric-key", "generate-csr", "generate-hmac-key", "generate-otp-aead-key", "generate-wrap-key", "generate-symmetric-key", "get-device-info", "get-logs", "get-object-info", "get-opaque", "get-option", "get-pseudo-random", "get-public-key", "get-storage-info", "get-template", "get-wrapped", "get-rsa-wrapped", "get-rsa-wrapped-key", "get-device-pubkey", "list-objects", "put-asymmetric-key", "put-authentication-key", "put-hmac-key", "put-opaque", "put-option", "put-otp-aead-key", "put-symmetric-key", "put-template", "put-wrap-key", "put-rsa-wrapkey", "put-public-wrapkey", "put-wrapped", "put-rsa-wrapped", "put-rsa-wrapped-key", "randomize-otp-aead", "reset", "set-log-index", "sign-attestation-certificate", "sign-ecdsa", "sign-eddsa", "sign-hmac", "sign-pkcs1v15", "sign-pss", "sign-ssh-certificate" enum optional multiple option "password" p "Authentication password" string optional option "authkey" - "Authentication key" short optional default="1" option "object-id" i "Object ID" short optional default="0" option "label" l "Object label" string optional default="" option "domains" d "Object domains" string optional default="1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16" option "capabilities" c "Capabilities for an object" string optional default="0" option "object-type" t "Object type" string optional default="any" option "ykhsmauth-label" y "Credential label on YubiKey (implicitly enables ykhsmauth)" string optional option "ykhsmauth-reader" r "Only use a matching YubiKey reader name" string optional default="" option "delegated" - "Delegated capabilities" string optional default="0" option "new-password" - "New authentication password" string optional option "algorithm" A "Operation algorithm" string optional default="any" option "oaep" - "OAEP algorithm. Used primarily with asymmetric wrap" string optional default="rsa-oaep-sha256" option "mgf1" - "MGF1 algorithm. Used primarily with asymmetric wrap" string optional default="mgf1-sha256" option "nonce" - "OTP nonce" int optional option "iv" - "An initialization vector as a hexadecimal string" string optional option "count" - "Number of bytes to request" int optional default="256" option "duration" - "Blink duration in seconds" int optional default="10" option "wrap-id" - "Wrap key ID" short optional option "include-seed" - "Include seed when exporting an ED25519 key under wrap" flag off option "template-id" - "Template ID" short optional option "attestation-id" - "Attestation ID" short optional option "log-index" - "Log index" int optional option "opt-name" - "Device option name" string optional option "opt-value" - "Device option value" string optional option "with-compression" - "Compress a X509Certificate before importing it into the device or detect compressed certificates when listing objects" flag off option "subject" S "The subject to use for certificate request. The subject must be written as: /CN=host.example.com/OU=test/O=example.com/" string optional option "in" - "Input data (filename)" string optional default="-" option "out" - "Output data (filename)" string optional default="-" option "informat" - "Input format" values="default","base64","binary","PEM","password","hex","ASCII" enum optional default="default" option "outformat" - "Input and output format" values="default","base64","binary","PEM","hex","ASCII" enum optional default="default" #option "enc-key" e "Encryption key to use" string optional default="404142434445464748494a4b4c4d4e4f" #option "mac-key" m "Mac key to use" string optional default="404142434445464748494a4b4c4d4e4f" option "config-file" f "Configuration file to read" string optional default="" option "connector" C "List of connectors to use" string optional multiple option "cacert" - "HTTPS cacert for connector" string optional option "cert" - "HTTPS client certificate to authenticate with" string optional option "key" - "HTTPS client certificate key" string optional option "proxy" - "Proxy server to use for connector" string optional option "noproxy" - "Comma separated list of hosts ignore proxy for" string optional option "verbose" v "Print more information" int optional default="0" option "pre-connect" P "Connect immediately in interactive mode" flag off option "device-pubkey" - "List of device public keys allowed for asymmetric authentication" string optional multiple yubihsm-shell-2.8.0/src/cmd_util.h0000644000175100017510000000154715221003515016455 0ustar runnerrunner/* * Copyright 2025 Yubico AB * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef YUBIHSM_SHELL_CMD_UTIL_H #define YUBIHSM_SHELL_CMD_UTIL_H EVP_PKEY *wrap_public_key(yh_session *session, yh_algorithm algorithm, EVP_PKEY *public_key, uint16_t key_id); X509_NAME *parse_subject_name(const char *orig_name); #endif // YUBIHSM_SHELL_CMD_UTIL_H yubihsm-shell-2.8.0/src/version.rc.in0000644000175100017510000000215015221003515017113 0ustar runnerrunner #include #define VER_FILEVERSION @yubihsm_shell_VERSION_MAJOR@,@yubihsm_shell_VERSION_MINOR@,@yubihsm_shell_VERSION_PATCH@,0 #define VER_FILEVERSION_STR "@yubihsm_shell_VERSION_MAJOR@.@yubihsm_shell_VERSION_MINOR@.@yubihsm_shell_VERSION_PATCH@.0" VS_VERSION_INFO VERSIONINFO FILEVERSION VER_FILEVERSION PRODUCTVERSION VER_FILEVERSION FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L #else FILEFLAGS 0x0L #endif FILEOS 0x40004L FILETYPE 0x2L FILESUBTYPE 0x0L BEGIN BLOCK "StringFileInfo" BEGIN BLOCK "040904b0" BEGIN VALUE "CompanyName", "Yubico AB" VALUE "FileDescription", "YubiHSM Shell" VALUE "FileVersion", VER_FILEVERSION_STR VALUE "InternalName", "yubihsm-shell.exe" VALUE "LegalCopyright", "\xa9 Yubico AB" VALUE "OriginalFilename", "yubihsm-shell.exe" VALUE "ProductName", "YubiHSM" VALUE "ProductVersion", VER_FILEVERSION_STR END END BLOCK "VarFileInfo" BEGIN VALUE "Translation", 0x409, 1200 END END yubihsm-shell-2.8.0/src/CMakeLists.txt0000644000175100017510000000617115221003515017242 0ustar runnerrunner# # Copyright 2015-2018 Yubico AB # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # include(${CMAKE_SOURCE_DIR}/cmake/openssl.cmake) find_libcrypto() set ( SOURCE commands.c main.c cmd_util.c ../common/util.c ../common/hash.c ../common/parsing.c ../common/openssl-compat.c ) if(WIN32) set(SOURCE ${SOURCE} cmdline.c) include(${CMAKE_SOURCE_DIR}/cmake/getopt.cmake) find_getopt() else(WIN32) include(gengetopt) find_gengetopt () add_gengetopt_files (cmdline "--conf-parser") set(SOURCE ${SOURCE} ${GGO_C}) endif(WIN32) include_directories ( ${LIBCRYPTO_INCLUDEDIR} ${LIBEDIT_INCLUDEDIR} ${CMAKE_CURRENT_SOURCE_DIR}/../lib ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/../common ) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../ykhsmauth) set(YKHSMAUTH_LIB ykhsmauth) set(YKHSMAUTH_LIB_STATIC ykhsmauth_static) if(WIN32) list(APPEND SOURCE ${CMAKE_CURRENT_BINARY_DIR}/version.rc) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/version.rc.in ${CMAKE_CURRENT_BINARY_DIR}/version.rc @ONLY) endif(WIN32) # NOTE(adma): required by gengetopt add_definitions (-DPACKAGE="yubihsm-shell") add_definitions (-DVERSION="${yubihsm_shell_VERSION_MAJOR}.${yubihsm_shell_VERSION_MINOR}.${yubihsm_shell_VERSION_PATCH}") list(APPEND LCOV_REMOVE_PATTERNS "'${PROJECT_SOURCE_DIR}/src/cmdline.c'") add_executable (yubihsm-shell ${SOURCE}) if (ENABLE_STATIC AND NOT FUZZING) add_executable (yubihsm-shell_static ${SOURCE}) set_target_properties (yubihsm-shell_static PROPERTIES COMPILE_FLAGS "-DSTATIC") target_link_libraries(yubihsm-shell_static ${LIBCRYPTO_LDFLAGS} ${LIBEDIT_LDFLAGS} ${GETOPT_LIBS} yubihsm_static ${YKHSMAUTH_LIB_STATIC}) add_coverage (yubihsm-shell_static) endif () target_link_libraries ( yubihsm-shell ${LIBCRYPTO_LDFLAGS} ${LIBEDIT_LDFLAGS} ${GETOPT_LIBS} yubihsm ${YKHSMAUTH_LIB}) # Set install RPATH (Darwin default from root CMakeLists.txt is correct for bin/ targets) if(NOT ${CMAKE_SYSTEM_NAME} MATCHES "Darwin") set_target_properties(yubihsm-shell PROPERTIES INSTALL_RPATH "${YUBIHSM_INSTALL_LIB_DIR}") endif() add_coverage (yubihsm-shell) install( TARGETS yubihsm-shell ARCHIVE DESTINATION "${YUBIHSM_INSTALL_LIB_DIR}" LIBRARY DESTINATION "${YUBIHSM_INSTALL_LIB_DIR}" RUNTIME DESTINATION "${YUBIHSM_INSTALL_BIN_DIR}") if (NOT WITHOUT_MANPAGES) include (help2man) add_help2man_manpage (yubihsm-shell.1 yubihsm-shell) add_custom_target (yubihsm-shell-man ALL DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/yubihsm-shell.1 ) install(FILES "${CMAKE_CURRENT_BINARY_DIR}/yubihsm-shell.1" DESTINATION "${YUBIHSM_INSTALL_MAN_DIR}/man1") endif() add_subdirectory (tests) yubihsm-shell-2.8.0/ykhsmauth/0000755000175100017510000000000015221003515015723 5ustar runnerrunneryubihsm-shell-2.8.0/ykhsmauth/error.c0000644000175100017510000000400315221003515017215 0ustar runnerrunner/* * Copyright 2015-2018 Yubico AB * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "ykhsmauth.h" #include #define ERR(name, desc) \ { name, #name, desc } typedef struct { ykhsmauth_rc rc; const char *name; const char *description; } err_t; static const err_t errors[] = { ERR(YKHSMAUTHR_SUCCESS, "Successful return"), ERR(YKHSMAUTHR_MEMORY_ERROR, "Device memory error"), ERR(YKHSMAUTHR_PCSC_ERROR, "Error in PCSC call"), ERR(YKHSMAUTHR_GENERIC_ERROR, "General device error"), ERR(YKHSMAUTHR_WRONG_PW, "Wrong Password/Authentication key"), ERR(YKHSMAUTHR_INVALID_PARAMS, "Invalid argument to a device command"), ERR(YKHSMAUTHR_ENTRY_NOT_FOUND, "Entry not found"), ERR(YKHSMAUTHR_STORAGE_FULL, "Device storage full"), ERR(YKHSMAUTHR_TOUCH_ERROR, "Device not touched"), ERR(YKHSMAUTHR_ENTRY_INVALID, "Entry invalid"), ERR(YKHSMAUTHR_DATA_INVALID, "Invalid authentication data"), ERR(YKHSMAUTHR_NOT_SUPPORTED, "Device command not supported"), }; const char *ykhsmauth_strerror(ykhsmauth_rc err) { static const char *unknown = "Unknown ykhsmauth error"; const char *p; if (-err < 0 || -err >= (int) (sizeof(errors) / sizeof(errors[0]))) { return unknown; } p = errors[-err].description; if (!p) { p = unknown; } return p; } const char *ykhsmauth_strerror_name(ykhsmauth_rc err) { if (-err < 0 || -err >= (int) (sizeof(errors) / sizeof(errors[0]))) { return NULL; } return errors[-err].name; } yubihsm-shell-2.8.0/ykhsmauth/internal.h0000644000175100017510000000243315221003515017712 0ustar runnerrunner/* * Copyright 2015-2018 Yubico AB * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef YKHSMAUTH_INTERNAL_H #define YKHSMAUTH_INTERNAL_H #include #include #if defined(_WIN32) #include #elif defined(__FreeBSD__) #include #include #else #include #include #endif #define READER_LEN 32 #define MAX_READERS 16 struct ykhsmauth_state { SCARDCONTEXT context; SCARDHANDLE card; int verbose; }; union u_APDU { struct { unsigned char cla; unsigned char ins; unsigned char p1; unsigned char p2; uint16_t lc; unsigned char data[512]; } st; unsigned char raw[512 + 7]; // +7 = CLA(1) + INS(1) + P1(1) + P2(1) + extended LC(3) }; typedef union u_APDU APDU; #endif yubihsm-shell-2.8.0/ykhsmauth/README.adoc0000644000175100017510000000063015221003515017507 0ustar runnerrunner== YkHSMAuth Library The YkHSMAuth C Library `libykhsmauth` is a native library to interact with the HSM auth application on a YubiKey. This application is meant to be used for having the HSM authentication keys on a YubiKey. The library exposes functions in the `ykhsmauth_` namespace. These all interact with the HSM auth application over PCSC and are meant for management and usage for the application. yubihsm-shell-2.8.0/ykhsmauth/ykhsmauth.pc.in0000644000175100017510000000041315221003515020667 0ustar runnerrunnerlibdir=-L@YUBIHSM_INSTALL_LIB_DIR@ includedir=@YUBIHSM_INSTALL_INC_DIR@ Name: ykhsmauth Description: Yubico YubiHSM application for YubiKey C Library URL: https://www.yubico.com/ Version: @VERSION@ Requires.private: libcrypto libpcsclite Libs: ${libdir} -lykhsmauth yubihsm-shell-2.8.0/ykhsmauth/version.rc.in0000644000175100017510000000210715221003515020343 0ustar runnerrunner #include #define VER_FILEVERSION @yubihsm_shell_VERSION_MAJOR@,@yubihsm_shell_VERSION_MINOR@,@yubihsm_shell_VERSION_PATCH@,0 #define VER_FILEVERSION_STR "@yubihsm_shell_VERSION_MAJOR@.@yubihsm_shell_VERSION_MINOR@.@yubihsm_shell_VERSION_PATCH@.0" VS_VERSION_INFO VERSIONINFO FILEVERSION VER_FILEVERSION PRODUCTVERSION VER_FILEVERSION FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L #else FILEFLAGS 0x0L #endif FILEOS 0x40004L FILETYPE 0x2L FILESUBTYPE 0x0L BEGIN BLOCK "StringFileInfo" BEGIN BLOCK "040904b0" BEGIN VALUE "CompanyName", "Yubico AB" VALUE "FileDescription", "YubiAuth Interface Library" VALUE "FileVersion", VER_FILEVERSION_STR VALUE "InternalName", "ykhsmauth.dll" VALUE "LegalCopyright", "\xa9 Yubico AB" VALUE "OriginalFilename", "ykhsmauth.dll" VALUE "ProductName", "YubiHSM" VALUE "ProductVersion", VER_FILEVERSION_STR END END BLOCK "VarFileInfo" BEGIN VALUE "Translation", 0x409, 1200 END END yubihsm-shell-2.8.0/ykhsmauth/ykhsmauth.c0000644000175100017510000005470615221003515020120 0ustar runnerrunner/* * Copyright 2015-2018 Yubico AB * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include "internal.h" #include "ykhsmauth.h" #ifdef _WIN32 #define strncasecmp _strnicmp #endif static uint16_t encode_len(uint8_t *buf, uint16_t len) { if (len > 0xff) { *buf++ = 0x82; *buf++ = len >> 8; *buf++ = len; return 3; } if (len > 0x7f) { *buf++ = 0x81; *buf++ = len; return 2; } *buf++ = len; return 1; } static void add_tag(APDU *apdu, uint8_t tag, const void *data, uint16_t len, uint16_t pad) { uint8_t *ptr = apdu->st.data + apdu->st.lc; *ptr++ = tag; ptr += encode_len(ptr, len + pad); memcpy(ptr, data, len); ptr += len; memset(ptr, 0, pad); ptr += pad; apdu->st.lc = ptr - apdu->st.data; } static ykhsmauth_rc translate_error(uint16_t sw, uint8_t *retries) { if ((sw & 0xfff0) == SW_AUTHENTICATION_FAILED) { if (retries != NULL) { *retries = sw & ~0xfff0; } return YKHSMAUTHR_WRONG_PW; } else if (sw == SW_FILE_FULL) { return YKHSMAUTHR_STORAGE_FULL; } else if (sw == SW_FILE_NOT_FOUND) { return YKHSMAUTHR_ENTRY_NOT_FOUND; } else if (sw == SW_WRONG_DATA) { return YKHSMAUTHR_INVALID_PARAMS; } else if (sw == SW_MEMORY_ERROR) { return YKHSMAUTHR_MEMORY_ERROR; } else if (sw == SW_SECURITY_STATUS_NOT_SATISFIED) { return YKHSMAUTHR_TOUCH_ERROR; } else if (sw == SW_FILE_INVALID) { return YKHSMAUTHR_ENTRY_INVALID; } else if (sw == SW_DATA_INVALID) { return YKHSMAUTHR_DATA_INVALID; } else if (sw == SW_INS_NOT_SUPPORTED) { return YKHSMAUTHR_NOT_SUPPORTED; } else { return YKHSMAUTHR_GENERIC_ERROR; } } ykhsmauth_rc ykhsmauth_init(ykhsmauth_state **state, int verbose) { if (state == NULL) { if (verbose) { fprintf(stderr, "Unable to initialize: %s\n", ykhsmauth_strerror(YKHSMAUTHR_INVALID_PARAMS)); } return YKHSMAUTHR_INVALID_PARAMS; } ykhsmauth_state *s = calloc(1, sizeof(ykhsmauth_state)); if (s == NULL) { if (verbose) { fprintf(stderr, "Unable to initialize: %s\n", ykhsmauth_strerror(YKHSMAUTHR_MEMORY_ERROR)); } return YKHSMAUTHR_MEMORY_ERROR; } s->verbose = verbose; *state = s; return YKHSMAUTHR_SUCCESS; } ykhsmauth_rc ykhsmauth_done(ykhsmauth_state *state) { ykhsmauth_disconnect(state); if (state == NULL) { return YKHSMAUTHR_INVALID_PARAMS; } SCardReleaseContext(state->context); state->context = 0; free(state); return YKHSMAUTHR_SUCCESS; } ykhsmauth_rc ykhsmauth_disconnect(ykhsmauth_state *state) { if (state == NULL) { return YKHSMAUTHR_INVALID_PARAMS; } if (state->card) { SCardDisconnect(state->card, SCARD_RESET_CARD); state->card = 0; } return YKHSMAUTHR_SUCCESS; } static void dump_hex(const unsigned char *buf, DWORD len) { for (DWORD i = 0; i < len; i++) { fprintf(stderr, "%02x ", buf[i]); } } static ykhsmauth_rc send_data(ykhsmauth_state *state, const APDU *apdu, unsigned char *data, LPDWORD recv_len, uint16_t *sw) { unsigned char apdu_bytes[sizeof(apdu->raw)] = {0}; DWORD send_len = 0; *sw = 0; if (apdu->st.lc > sizeof(apdu->st.data)) { if (state->verbose) { fprintf(stderr, "APDU too large: lc=%u\n", (unsigned) apdu->st.lc); } return YKHSMAUTHR_INVALID_PARAMS; } apdu_bytes[0] = apdu->st.cla; apdu_bytes[1] = apdu->st.ins; apdu_bytes[2] = apdu->st.p1; apdu_bytes[3] = apdu->st.p2; if (apdu->st.lc <= 255) { apdu_bytes[4] = (unsigned char) apdu->st.lc; memcpy(apdu_bytes + 5, apdu->st.data, apdu->st.lc); send_len = (DWORD) apdu->st.lc + 5; } else { apdu_bytes[4] = 0x00; // Extended length marker apdu_bytes[5] = (unsigned char) (apdu->st.lc >> 8); // Length high byte apdu_bytes[6] = (unsigned char) (apdu->st.lc & 0xff); // Length low byte memcpy(apdu_bytes + 7, apdu->st.data, apdu->st.lc); send_len = (DWORD) apdu->st.lc + 7; } if (state->verbose > 1) { fprintf(stderr, "> "); dump_hex(apdu_bytes, send_len); fprintf(stderr, "\n"); } int32_t rc = SCardTransmit(state->card, SCARD_PCI_T1, apdu_bytes, send_len, NULL, data, recv_len); if (rc != SCARD_S_SUCCESS) { if (state->verbose) { fprintf(stderr, "SCardTransmit failed, rc=%08x\n", rc); } return YKHSMAUTHR_PCSC_ERROR; } if (state->verbose > 1) { fprintf(stderr, "< "); dump_hex(data, *recv_len); fprintf(stderr, "\n"); } if (*recv_len >= 2) { *sw = (data[*recv_len - 2] << 8) | data[*recv_len - 1]; *recv_len -= 2; } return YKHSMAUTHR_SUCCESS; } ykhsmauth_rc ykhsmauth_connect(ykhsmauth_state *state, const char *wanted) { if (state == NULL) { return YKHSMAUTHR_INVALID_PARAMS; } char readers[2048] = {0}; size_t readers_len = sizeof(readers); ykhsmauth_rc ret = ykhsmauth_list_readers(state, readers, &readers_len); if (ret != YKHSMAUTHR_SUCCESS) { if (state->verbose) { fprintf(stderr, "Unable to list_readers: %s\n", ykhsmauth_strerror(ret)); } return ret; } for (char *reader_ptr = readers; *reader_ptr != '\0'; reader_ptr += strlen(reader_ptr) + 1) { if (wanted) { bool found = false; char *ptr = reader_ptr; while (strlen(ptr) >= strlen(wanted)) { if (strncasecmp(ptr, wanted, strlen(wanted)) == 0) { found = true; break; } ptr++; } if (found == false) { if (state->verbose) { fprintf(stderr, "Skipping reader '%s' since it doesn't match '%s'\n", reader_ptr, wanted); } continue; } } if (state->verbose) { fprintf(stderr, "Trying to connect to reader '%s'\n", reader_ptr); } DWORD active_protocol = 0; int32_t rc = SCardConnect(state->context, reader_ptr, SCARD_SHARE_SHARED, SCARD_PROTOCOL_T1, &state->card, &active_protocol); if (rc != SCARD_S_SUCCESS) { if (state->verbose) { fprintf(stderr, "SCardConnect failed, rc=%08x\n", rc); } continue; } APDU apdu = { {0, 0xa4, 0x04, 0, 8, {0xa0, 0x00, 0x00, 0x05, 0x27, 0x21, 0x07, 0x01}}}; unsigned char data[256] = {0}; DWORD recv_len = sizeof(data); uint16_t sw = 0; if ((ret = send_data(state, &apdu, data, &recv_len, &sw)) != YKHSMAUTHR_SUCCESS) { if (state->verbose) { fprintf(stderr, "Failed communicating with card: '%s'\n", ykhsmauth_strerror(ret)); } } else if (sw != SW_SUCCESS) { if (state->verbose) { fprintf(stderr, "Failed selecting application: %04x\n", sw); } } else { return YKHSMAUTHR_SUCCESS; } if (state->verbose) { fprintf(stderr, "Disconnecting reader '%s'\n", reader_ptr); } SCardDisconnect(state->card, SCARD_LEAVE_CARD); state->card = 0; } if (state->verbose) { fprintf(stderr, "No usable reader found\n"); } return YKHSMAUTHR_GENERIC_ERROR; } ykhsmauth_rc ykhsmauth_list_readers(ykhsmauth_state *state, char *readers, size_t *len) { if (state == NULL || readers == NULL) { return YKHSMAUTHR_INVALID_PARAMS; } if (SCardIsValidContext(state->context) != SCARD_S_SUCCESS) { state->card = 0; int32_t rc = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &state->context); if (rc != SCARD_S_SUCCESS) { if (state->verbose) { fprintf(stderr, "SCardEstablishContext failed, rc=%08x\n", rc); } return YKHSMAUTHR_PCSC_ERROR; } } DWORD readers_len = *len; int32_t rc = SCardListReaders(state->context, NULL, readers, &readers_len); if (rc != SCARD_S_SUCCESS) { if (state->verbose) { fprintf(stderr, "SCardListReaders failed rc=%08x\n", rc); } return YKHSMAUTHR_PCSC_ERROR; } *len = readers_len; return YKHSMAUTHR_SUCCESS; } ykhsmauth_rc ykhsmauth_get_version_ex(ykhsmauth_state *state, uint8_t *major, uint8_t *minor, uint8_t *patch) { if (state == NULL || major == NULL || minor == NULL || patch == NULL) { return YKHSMAUTHR_INVALID_PARAMS; } APDU apdu = {{0, YKHSMAUTH_INS_GET_VERSION, 0, 0, 0, {0}}}; unsigned char data[256] = {0}; DWORD recv_len = sizeof(data); uint16_t sw = 0; ykhsmauth_rc res; if ((res = send_data(state, &apdu, data, &recv_len, &sw)) != YKHSMAUTHR_SUCCESS) { return res; } else if (sw == SW_SUCCESS && recv_len == 3) { *major = data[0]; *minor = data[1]; *patch = data[2]; return YKHSMAUTHR_SUCCESS; } else { return translate_error(sw, NULL); } } ykhsmauth_rc ykhsmauth_get_version(ykhsmauth_state *state, char *version, size_t len) { if (version == NULL) { return YKHSMAUTHR_INVALID_PARAMS; } uint8_t v[3] = {0}; ykhsmauth_rc res = ykhsmauth_get_version_ex(state, &v[0], &v[1], &v[2]); if(res == YKHSMAUTHR_SUCCESS) { int result = snprintf(version, len, "%d.%d.%d", v[0], v[1], v[2]); if (result < 0) { if (state->verbose) { fprintf(stderr, "Version buffer too small\n"); } return YKHSMAUTHR_GENERIC_ERROR; } } return res; } ykhsmauth_rc ykhsmauth_put(ykhsmauth_state *state, const uint8_t *mgmkey, size_t mgmkey_len, const char *label, uint8_t algo, const uint8_t *key, size_t key_len, const uint8_t *cpw, size_t cpw_len, const uint8_t touch_policy, uint8_t *retries) { if (state == NULL || mgmkey == NULL || mgmkey_len != YKHSMAUTH_PW_LEN || label == NULL || strlen(label) < YKHSMAUTH_MIN_LABEL_LEN || strlen(label) > YKHSMAUTH_MAX_LABEL_LEN || key == NULL || key_len > YKHSMAUTH_YUBICO_ECP256_PRIVKEY_LEN || cpw == NULL || cpw_len > YKHSMAUTH_PW_LEN) { return YKHSMAUTHR_INVALID_PARAMS; } APDU apdu = {{0, YKHSMAUTH_INS_PUT, 0, 0, 0, {0}}}; add_tag(&apdu, YKHSMAUTH_TAG_MGMKEY, mgmkey, mgmkey_len, 0); add_tag(&apdu, YKHSMAUTH_TAG_LABEL, label, strlen(label), 0); add_tag(&apdu, YKHSMAUTH_TAG_ALGO, &algo, sizeof(algo), 0); if (algo == YKHSMAUTH_YUBICO_AES128_ALGO) { add_tag(&apdu, YKHSMAUTH_TAG_KEY_ENC, key, key_len / 2, 0); add_tag(&apdu, YKHSMAUTH_TAG_KEY_MAC, key + key_len / 2, key_len / 2, 0); } else if (algo == YKHSMAUTH_YUBICO_ECP256_ALGO) { add_tag(&apdu, YKHSMAUTH_TAG_PRIVKEY, key, key_len, 0); } add_tag(&apdu, YKHSMAUTH_TAG_PW, cpw, cpw_len, YKHSMAUTH_PW_LEN - cpw_len); add_tag(&apdu, YKHSMAUTH_TAG_TOUCH, &touch_policy, sizeof(touch_policy), 0); unsigned char data[256] = {0}; DWORD recv_len = sizeof(data); uint16_t sw = 0; ykhsmauth_rc rc = send_data(state, &apdu, data, &recv_len, &sw); if (rc != YKHSMAUTHR_SUCCESS) { return rc; } else if (sw != SW_SUCCESS) { if (state->verbose) { fprintf(stderr, "Unable to store credential: %04x\n", sw); } return translate_error(sw, retries); } return YKHSMAUTHR_SUCCESS; } ykhsmauth_rc ykhsmauth_delete(ykhsmauth_state *state, uint8_t *mgmkey, size_t mgmkey_len, char *label, uint8_t *retries) { if (state == NULL || mgmkey == NULL || mgmkey_len != YKHSMAUTH_PW_LEN || label == NULL || strlen(label) < YKHSMAUTH_MIN_LABEL_LEN || strlen(label) > YKHSMAUTH_MAX_LABEL_LEN) { return YKHSMAUTHR_INVALID_PARAMS; } APDU apdu = {{0, YKHSMAUTH_INS_DELETE, 0, 0, 0, {0}}}; add_tag(&apdu, YKHSMAUTH_TAG_MGMKEY, mgmkey, mgmkey_len, 0); add_tag(&apdu, YKHSMAUTH_TAG_LABEL, label, strlen(label), 0); unsigned char data[256] = {0}; DWORD recv_len = sizeof(data); uint16_t sw = 0; ykhsmauth_rc rc = send_data(state, &apdu, data, &recv_len, &sw); if (rc != YKHSMAUTHR_SUCCESS) { return rc; } else if (sw != SW_SUCCESS) { if (state->verbose) { fprintf(stderr, "Unable to delete credential: %04x\n", sw); } return translate_error(sw, retries); } return YKHSMAUTHR_SUCCESS; } ykhsmauth_rc ykhsmauth_calculate(ykhsmauth_state *state, const char *label, uint8_t *context, size_t context_len, const uint8_t *pw, size_t pw_len, uint8_t *key_s_enc, size_t key_s_enc_len, uint8_t *key_s_mac, size_t key_s_mac_len, uint8_t *key_s_rmac, size_t key_s_rmac_len, uint8_t *retries) { return ykhsmauth_calculate_ex(state, label, context, context_len, NULL, 0, NULL, 0, pw, pw_len, key_s_enc, key_s_enc_len, key_s_mac, key_s_mac_len, key_s_rmac, key_s_rmac_len, retries); } ykhsmauth_rc ykhsmauth_calculate_ex( ykhsmauth_state *state, const char *label, uint8_t *context, size_t context_len, uint8_t *card_pubkey, size_t card_pubkey_len, uint8_t *card_crypto, size_t card_crypto_len, const uint8_t *pw, size_t pw_len, uint8_t *key_s_enc, size_t key_s_enc_len, uint8_t *key_s_mac, size_t key_s_mac_len, uint8_t *key_s_rmac, size_t key_s_rmac_len, uint8_t *retries) { if (state == NULL || label == NULL || strlen(label) < YKHSMAUTH_MIN_LABEL_LEN || strlen(label) > YKHSMAUTH_MAX_LABEL_LEN || context == NULL || context_len > 2 * YKHSMAUTH_YUBICO_ECP256_PUBKEY_LEN || card_pubkey_len > YKHSMAUTH_YUBICO_ECP256_PUBKEY_LEN || card_crypto_len > YKHSMAUTH_SESSION_KEY_LEN || pw == NULL || pw_len > YKHSMAUTH_PW_LEN || key_s_enc == NULL || key_s_enc_len != YKHSMAUTH_SESSION_KEY_LEN || key_s_mac == NULL || key_s_mac_len != YKHSMAUTH_SESSION_KEY_LEN || key_s_rmac == NULL || key_s_rmac_len != YKHSMAUTH_SESSION_KEY_LEN) { return YKHSMAUTHR_INVALID_PARAMS; } APDU apdu = {{0, YKHSMAUTH_INS_CALCULATE, 0, 0, 0, {0}}}; add_tag(&apdu, YKHSMAUTH_TAG_LABEL, label, strlen(label), 0); add_tag(&apdu, YKHSMAUTH_TAG_CONTEXT, context, context_len, 0); if (card_pubkey && card_pubkey_len) { add_tag(&apdu, YKHSMAUTH_TAG_PUBKEY, card_pubkey, card_pubkey_len, 0); } // Only send card_crypto for asym auth if (card_crypto && card_crypto_len > YKHSMAUTH_CARD_CRYPTO_LEN) { add_tag(&apdu, YKHSMAUTH_TAG_RESPONSE, card_crypto, card_crypto_len, 0); } add_tag(&apdu, YKHSMAUTH_TAG_PW, pw, pw_len, YKHSMAUTH_PW_LEN - pw_len); unsigned char data[256] = {0}; DWORD recv_len = sizeof(data); uint16_t sw = 0; ykhsmauth_rc rc = send_data(state, &apdu, data, &recv_len, &sw); if (rc != YKHSMAUTHR_SUCCESS) { return rc; } else if (sw != SW_SUCCESS) { if (state->verbose) { fprintf(stderr, "Unable to derive keys: %04x\n", sw); } return translate_error(sw, retries); } if (recv_len != 3 * YKHSMAUTH_SESSION_KEY_LEN) { if (state->verbose) { fprintf(stderr, "Wrong length returned: %zu\n", (size_t) recv_len); } return YKHSMAUTHR_GENERIC_ERROR; } uint8_t *ptr = data; memcpy(key_s_enc, ptr, YKHSMAUTH_SESSION_KEY_LEN); ptr += YKHSMAUTH_SESSION_KEY_LEN; memcpy(key_s_mac, ptr, YKHSMAUTH_SESSION_KEY_LEN); ptr += YKHSMAUTH_SESSION_KEY_LEN; memcpy(key_s_rmac, ptr, YKHSMAUTH_SESSION_KEY_LEN); ptr += YKHSMAUTH_SESSION_KEY_LEN; // Ignore host crypto for now return YKHSMAUTHR_SUCCESS; } ykhsmauth_rc ykhsmauth_reset(ykhsmauth_state *state) { if (state == NULL) { return YKHSMAUTHR_INVALID_PARAMS; } APDU apdu = { {0, YKHSMAUTH_INS_RESET, YKHSMAUTH_P1_RESET, YKHSMAUTH_P2_RESET, 0, {0}}}; unsigned char data[256] = {0}; DWORD recv_len = sizeof(data); uint16_t sw = 0; ykhsmauth_rc res = send_data(state, &apdu, data, &recv_len, &sw); if (sw != SW_SUCCESS) { if (state->verbose) { fprintf(stderr, "Unable to reset: %s\n", ykhsmauth_strerror(res)); } return translate_error(sw, NULL); } return res; } ykhsmauth_rc ykhsmauth_list_keys(ykhsmauth_state *state, ykhsmauth_list_entry *list, size_t *list_items) { if (state == NULL || list_items == NULL) { return YKHSMAUTHR_INVALID_PARAMS; } APDU apdu = {{0, YKHSMAUTH_INS_LIST, 0, 0, 0, {0}}}; unsigned char data[1024] = {0}; DWORD recv_len = sizeof(data); uint16_t sw = 0; ykhsmauth_rc rc = send_data(state, &apdu, data, &recv_len, &sw); if (rc != YKHSMAUTHR_SUCCESS) { return rc; } else if (sw != SW_SUCCESS) { if (state->verbose) { fprintf(stderr, "Unable to list keys: %04x\n", sw); } return translate_error(sw, NULL); } size_t element = 0; size_t i = 0; // i + 1 here guarantees we can read tag and len while (i + 1 < recv_len) { if (data[i++] == YKHSMAUTH_TAG_LABEL_LIST) { size_t len = data[i++]; if (list != NULL) { if (element >= *list_items) { return YKHSMAUTHR_MEMORY_ERROR; } else if (i + len > recv_len || len < 3 || len - 3 > sizeof(list[element].label)) { if (state->verbose) { fprintf(stderr, "Length of element doesn't match expectations (%zu)\n", len); } return YKHSMAUTHR_GENERIC_ERROR; } list[element].algo = data[i++]; list[element].touch = data[i++]; memset(list[element].label, 0, sizeof(list[element].label)); memcpy(list[element].label, data + i, len - 3); i += len - 3; list[element].ctr = data[i++]; } else { i += len; } element++; } else { if (state->verbose) { fprintf(stderr, "Unexpected tag returned on list\n"); } return YKHSMAUTHR_GENERIC_ERROR; } } *list_items = element; if (i != recv_len) { return YKHSMAUTHR_GENERIC_ERROR; } return YKHSMAUTHR_SUCCESS; } ykhsmauth_rc ykhsmauth_get_challenge(ykhsmauth_state *state, const char *label, uint8_t *challenge, size_t *challenge_len) { return ykhsmauth_get_challenge_ex(state, label, NULL, 0, challenge, challenge_len); } ykhsmauth_rc ykhsmauth_get_challenge_ex(ykhsmauth_state *state, const char *label, const uint8_t *cpw, size_t cpw_len, uint8_t *challenge, size_t *challenge_len) { if (state == NULL || label == NULL || cpw_len > YKHSMAUTH_PW_LEN || strlen(label) < YKHSMAUTH_MIN_LABEL_LEN || strlen(label) > YKHSMAUTH_MAX_LABEL_LEN || challenge == NULL || challenge_len == NULL) { return YKHSMAUTHR_INVALID_PARAMS; } APDU apdu = {{0, YKHSMAUTH_INS_GET_CHALLENGE, 0, 0, 0, {0}}}; add_tag(&apdu, YKHSMAUTH_TAG_LABEL, label, strlen(label), 0); if(cpw && cpw_len) { add_tag(&apdu, YKHSMAUTH_TAG_PW, cpw, cpw_len, YKHSMAUTH_PW_LEN - cpw_len); } unsigned char data[256] = {0}; DWORD recv_len = sizeof(data); uint16_t sw = 0; ykhsmauth_rc rc = send_data(state, &apdu, data, &recv_len, &sw); if (rc != YKHSMAUTHR_SUCCESS) { return rc; } else if (sw != SW_SUCCESS) { if (state->verbose) { fprintf(stderr, "Unable to get challenge: %04x\n", sw); } return translate_error(sw, NULL); } if (*challenge_len < recv_len) { return YKHSMAUTHR_INVALID_PARAMS; } *challenge_len = recv_len; memcpy(challenge, data, recv_len); return YKHSMAUTHR_SUCCESS; } ykhsmauth_rc ykhsmauth_get_pubkey(ykhsmauth_state *state, const char *label, uint8_t *pubkey, size_t *pubkey_len) { if (state == NULL || label == NULL || strlen(label) < YKHSMAUTH_MIN_LABEL_LEN || strlen(label) > YKHSMAUTH_MAX_LABEL_LEN || pubkey == NULL || pubkey_len == NULL) { return YKHSMAUTHR_INVALID_PARAMS; } APDU apdu = {{0, YKHSMAUTH_INS_GET_PUBKEY, 0, 0, 0, {0}}}; add_tag(&apdu, YKHSMAUTH_TAG_LABEL, label, strlen(label), 0); unsigned char data[256] = {0}; DWORD recv_len = sizeof(data); uint16_t sw = 0; ykhsmauth_rc rc = send_data(state, &apdu, data, &recv_len, &sw); if (rc != YKHSMAUTHR_SUCCESS) { return rc; } else if (sw != SW_SUCCESS) { if (state->verbose) { fprintf(stderr, "Unable to get pubkey: %04x\n", sw); } return translate_error(sw, NULL); } if (*pubkey_len < recv_len) { return YKHSMAUTHR_INVALID_PARAMS; } *pubkey_len = recv_len; memcpy(pubkey, data, recv_len); return YKHSMAUTHR_SUCCESS; } ykhsmauth_rc ykhsmauth_get_mgmkey_retries(ykhsmauth_state *state, uint8_t *retries) { if (state == NULL || retries == NULL) { return YKHSMAUTHR_INVALID_PARAMS; } APDU apdu = {{0, YKHSMAUTH_INS_GET_MGMKEY_RETRIES, 0, 0, 0, {0}}}; unsigned char data[256] = {0}; DWORD recv_len = sizeof(data); uint16_t sw = 0; ykhsmauth_rc rc = send_data(state, &apdu, data, &recv_len, &sw); if (rc != YKHSMAUTHR_SUCCESS) { return rc; } else if (sw != SW_SUCCESS) { if (state->verbose) { fprintf(stderr, "Unable to get Management key retries: %04x\n", sw); } return translate_error(sw, NULL); } *retries = data[0]; return YKHSMAUTHR_SUCCESS; } ykhsmauth_rc ykhsmauth_put_mgmkey(ykhsmauth_state *state, uint8_t *mgmkey, size_t mgmkey_len, uint8_t *new_mgmkey, size_t new_mgmkey_len, uint8_t *retries) { if (state == NULL || mgmkey == NULL || mgmkey_len != YKHSMAUTH_PW_LEN || new_mgmkey == NULL || new_mgmkey_len != YKHSMAUTH_PW_LEN) { return YKHSMAUTHR_INVALID_PARAMS; } APDU apdu = {{0, YKHSMAUTH_INS_PUT_MGMKEY, 0, 0, 0, {0}}}; add_tag(&apdu, YKHSMAUTH_TAG_MGMKEY, mgmkey, mgmkey_len, 0); add_tag(&apdu, YKHSMAUTH_TAG_MGMKEY, new_mgmkey, new_mgmkey_len, 0); unsigned char data[256] = {0}; DWORD recv_len = sizeof(data); uint16_t sw = 0; ykhsmauth_rc rc = send_data(state, &apdu, data, &recv_len, &sw); if (rc != YKHSMAUTHR_SUCCESS) { return rc; } else if (sw != SW_SUCCESS) { if (state->verbose) { fprintf(stderr, "Unable to store Management key: %04x\n", sw); } return translate_error(sw, retries); } return YKHSMAUTHR_SUCCESS; } yubihsm-shell-2.8.0/ykhsmauth/CMakeLists.txt0000644000175100017510000000460115221003515020464 0ustar runnerrunner# # Copyright 2015-2018 Yubico AB # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # set ( SOURCE error.c ykhsmauth.c ) if(WIN32) set(SOURCE ${SOURCE} ${CMAKE_CURRENT_BINARY_DIR}/version.rc) endif(WIN32) add_library (ykhsmauth SHARED ${SOURCE}) #add_definitions (-DVERSION="${yubihsm_shell_VERSION_MAJOR}.${yubihsm_shell_VERSION_MINOR}.${yubihsm_shell_VERSION_PATCH}") target_include_directories (ykhsmauth PRIVATE ${LIBPCSC_INCLUDE_DIRS}) target_compile_options (ykhsmauth PRIVATE ${LIBPCSC_CFLAGS_OTHER}) target_link_libraries (ykhsmauth ${LIBPCSC_LDFLAGS}) set_target_properties (ykhsmauth PROPERTIES VERSION "${yubihsm_shell_VERSION_MAJOR}.${yubihsm_shell_VERSION_MINOR}.${yubihsm_shell_VERSION_PATCH}" SOVERSION ${yubihsm_shell_VERSION_MAJOR}) if(NOT ${CMAKE_SYSTEM_NAME} MATCHES "Darwin") set_target_properties(ykhsmauth PROPERTIES INSTALL_RPATH "${YUBIHSM_INSTALL_LIB_DIR}") endif() add_library (ykhsmauth_static STATIC ${SOURCE}) target_include_directories (ykhsmauth_static PRIVATE ${LIBPCSC_INCLUDE_DIRS}) target_compile_options (ykhsmauth_static PRIVATE ${LIBPCSC_CFLAGS_OTHER}) set_target_properties (ykhsmauth_static PROPERTIES POSITION_INDEPENDENT_CODE on OUTPUT_NAME ykhsmauth) set_target_properties (ykhsmauth_static PROPERTIES COMPILE_FLAGS "-DSTATIC") target_link_libraries (ykhsmauth_static ${LIBPCSC_LDFLAGS}) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/ykhsmauth.pc.in ${CMAKE_CURRENT_BINARY_DIR}/ykhsmauth.pc @ONLY) if(WIN32) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/version.rc.in ${CMAKE_CURRENT_BINARY_DIR}/version.rc @ONLY) endif(WIN32) install( TARGETS ykhsmauth ARCHIVE DESTINATION "${YUBIHSM_INSTALL_LIB_DIR}" LIBRARY DESTINATION "${YUBIHSM_INSTALL_LIB_DIR}" RUNTIME DESTINATION "${YUBIHSM_INSTALL_BIN_DIR}") install(FILES ykhsmauth.h DESTINATION ${YUBIHSM_INSTALL_INC_DIR}) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/ykhsmauth.pc DESTINATION ${YUBIHSM_INSTALL_PKGCONFIG_DIR}) yubihsm-shell-2.8.0/ykhsmauth/ykhsmauth.h0000644000175100017510000001614015221003515020113 0ustar runnerrunner/* * Copyright 2015-2018 Yubico AB * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef YKHSMAUTH_H #define YKHSMAUTH_H #include #include //#include #ifdef __cplusplus extern "C" { #endif // INS codes #define YKHSMAUTH_INS_PUT 0x01 #define YKHSMAUTH_INS_DELETE 0x02 #define YKHSMAUTH_INS_CALCULATE 0x03 #define YKHSMAUTH_INS_GET_CHALLENGE 0x04 #define YKHSMAUTH_INS_LIST 0x05 #define YKHSMAUTH_INS_RESET 0x06 #define YKHSMAUTH_INS_GET_VERSION 0x07 #define YKHSMAUTH_INS_PUT_MGMKEY 0x08 #define YKHSMAUTH_INS_GET_MGMKEY_RETRIES 0x09 #define YKHSMAUTH_INS_GET_PUBKEY 0x0a // P1 bytes #define YKHSMAUTH_P1_RESET 0xde // P2 bytes #define YKHSMAUTH_P2_RESET 0xad // Tag codes #define YKHSMAUTH_TAG_LABEL 0x71 #define YKHSMAUTH_TAG_LABEL_LIST 0x72 #define YKHSMAUTH_TAG_PW 0x73 #define YKHSMAUTH_TAG_ALGO 0x74 #define YKHSMAUTH_TAG_KEY_ENC 0x75 #define YKHSMAUTH_TAG_KEY_MAC 0x76 #define YKHSMAUTH_TAG_CONTEXT 0x77 #define YKHSMAUTH_TAG_RESPONSE 0x78 #define YKHSMAUTH_TAG_VERSION 0x79 #define YKHSMAUTH_TAG_TOUCH 0x7a #define YKHSMAUTH_TAG_MGMKEY 0x7b #define YKHSMAUTH_TAG_PUBKEY 0x7c #define YKHSMAUTH_TAG_PRIVKEY 0x7d // Algos #define YKHSMAUTH_YUBICO_AES128_ALGO 38 #define YKHSMAUTH_YUBICO_ECP256_ALGO 39 #define SW_SUCCESS 0x9000 #define SW_BYTES_REMAINING_00 0x6100 #define SW_WRONG_LENGTH 0x6700 #define SW_SECURITY_STATUS_NOT_SATISFIED 0x6982 #define SW_FILE_INVALID 0x6983 #define SW_DATA_INVALID 0x6984 #define SW_CONDITIONS_NOT_SATISFIED 0x6985 #define SW_COMMAND_NOT_ALLOWED 0x6986 #define SW_APPLET_SELECT_FAILED 0x6999 #define SW_WRONG_DATA 0x6A80 #define SW_FUNC_NOT_SUPPORTED 0x6A81 #define SW_FILE_NOT_FOUND 0x6A82 #define SW_RECORD_NOT_FOUND 0x6A83 #define SW_INCORRECT_P1P2 0x6A86 #define SW_WRONG_P1P2 0x6B00 #define SW_CORRECT_LENGTH_00 0x6C00 #define SW_INS_NOT_SUPPORTED 0x6D00 #define SW_CLA_NOT_SUPPORTED 0x6E00 #define SW_UNKNOWN 0x6F00 #define SW_FILE_FULL 0x6A84 #define SW_LOGICAL_CHANNEL_NOT_SUPPORTED 0x6881 #define SW_SECURE_MESSAGING_NOT_SUPPORTED 0x6882 #define SW_WARNING_STATE_UNCHANGED 0x6200 #define SW_LAST_COMMAND_EXPECTED 0x6883 #define SW_COMMAND_CHAINING_NOT_SUPPORTED 0x6884 #define SW_AUTHENTICATION_BLOCKED 0x6983 #define SW_AUTHENTICATION_FAILED 0x63C0 #define SW_MEMORY_ERROR 0x6581 // Lengths #define YKHSMAUTH_MIN_LABEL_LEN 1 #define YKHSMAUTH_MAX_LABEL_LEN 64 #define YKHSMAUTH_SESSION_KEY_LEN 16 #define YKHSMAUTH_CARD_CRYPTO_LEN 8 #define YKHSMAUTH_HOST_CRYPTO_LEN 8 #define YKHSMAUTH_YUBICO_AES128_KEY_LEN 32 #define YKHSMAUTH_PW_LEN 16 #define YKHSMAUTH_CONTEXT_LEN 16 #define YKHSMAUTH_YUBICO_ECP256_PUBKEY_LEN 65 #define YKHSMAUTH_YUBICO_ECP256_PRIVKEY_LEN 32 // PBKDF2 derivation parameters #define YKHSMAUTH_DEFAULT_SALT "Yubico" #define YKHSMAUTH_DEFAULT_ITERS 10000 typedef struct ykhsmauth_state ykhsmauth_state; typedef enum { YKHSMAUTHR_SUCCESS = 0, YKHSMAUTHR_MEMORY_ERROR = -1, YKHSMAUTHR_PCSC_ERROR = -2, YKHSMAUTHR_GENERIC_ERROR = -3, YKHSMAUTHR_WRONG_PW = -4, YKHSMAUTHR_INVALID_PARAMS = -5, YKHSMAUTHR_ENTRY_NOT_FOUND = -6, YKHSMAUTHR_STORAGE_FULL = -7, YKHSMAUTHR_TOUCH_ERROR = -8, YKHSMAUTHR_ENTRY_INVALID = -9, YKHSMAUTHR_DATA_INVALID = -10, YKHSMAUTHR_NOT_SUPPORTED = -11, } ykhsmauth_rc; typedef struct { uint8_t algo; uint8_t touch; char label[YKHSMAUTH_MAX_LABEL_LEN + 1]; uint8_t ctr; } ykhsmauth_list_entry; const char *ykhsmauth_strerror(ykhsmauth_rc err); const char *ykhsmauth_strerror_name(ykhsmauth_rc err); ykhsmauth_rc ykhsmauth_init(ykhsmauth_state **state, int verbose); ykhsmauth_rc ykhsmauth_done(ykhsmauth_state *state); ykhsmauth_rc ykhsmauth_connect(ykhsmauth_state *state, const char *wanted); ykhsmauth_rc ykhsmauth_list_readers(ykhsmauth_state *state, char *readers, size_t *len); ykhsmauth_rc ykhsmauth_disconnect(ykhsmauth_state *state); ykhsmauth_rc ykhsmauth_get_version_ex(ykhsmauth_state *state, uint8_t *major, uint8_t *minor, uint8_t *patch); ykhsmauth_rc ykhsmauth_get_version(ykhsmauth_state *state, char *version, size_t len); ykhsmauth_rc ykhsmauth_put(ykhsmauth_state *state, const uint8_t *mgmkey, size_t mgmkey_len, const char *label, uint8_t algo, const uint8_t *key, size_t key_len, const uint8_t *pw, size_t pw_len, const uint8_t touch_policy, uint8_t *retries); ykhsmauth_rc ykhsmauth_delete(ykhsmauth_state *state, uint8_t *mgmkey, size_t mgmkey_len, char *label, uint8_t *retries); ykhsmauth_rc ykhsmauth_calculate(ykhsmauth_state *state, const char *label, uint8_t *context, size_t context_len, const uint8_t *pw, size_t pw_len, uint8_t *key_s_enc, size_t key_s_enc_len, uint8_t *key_s_mac, size_t key_s_mac_len, uint8_t *key_s_rmac, size_t key_s_rmac_len, uint8_t *retries); ykhsmauth_rc ykhsmauth_calculate_ex( ykhsmauth_state *state, const char *label, uint8_t *context, size_t context_len, uint8_t *card_pubkey, size_t card_pubkey_len, uint8_t *card_crypto, size_t card_crypto_len, const uint8_t *pw, size_t pw_len, uint8_t *key_s_enc, size_t key_s_enc_len, uint8_t *key_s_mac, size_t key_s_mac_len, uint8_t *key_s_rmac, size_t key_s_rmac_len, uint8_t *retries); ykhsmauth_rc ykhsmauth_reset(ykhsmauth_state *state); ykhsmauth_rc ykhsmauth_list_keys(ykhsmauth_state *state, ykhsmauth_list_entry *list, size_t *list_items); ykhsmauth_rc ykhsmauth_get_challenge(ykhsmauth_state *state, const char *label, uint8_t *challenge, size_t *challenge_len); ykhsmauth_rc ykhsmauth_get_challenge_ex(ykhsmauth_state *state, const char *label, const uint8_t *cpw, size_t cpw_len, uint8_t *challenge, size_t *challenge_len); ykhsmauth_rc ykhsmauth_get_pubkey(ykhsmauth_state *state, const char *label, uint8_t *pubkey, size_t *pubkey_len); ykhsmauth_rc ykhsmauth_get_mgmkey_retries(ykhsmauth_state *state, uint8_t *retries); ykhsmauth_rc ykhsmauth_put_mgmkey(ykhsmauth_state *state, uint8_t *mgmkey, size_t mgmkey_len, uint8_t *new_mgmkey, size_t new_mgmkey_len, uint8_t *retries); #ifdef __cplusplus } #endif #ifdef _MSC_VER #pragma strict_gs_check(on) #endif #endif yubihsm-shell-2.8.0/LICENSE0000644000175100017510000002205615221003515014720 0ustar runnerrunnerApache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: You must give any other recipients of the Work or Derivative Works a copy of this License; and You must cause any modified files to carry prominent notices stating that You changed the files; and You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS yubihsm-shell-2.8.0/lib/0000755000175100017510000000000015221003515014454 5ustar runnerrunneryubihsm-shell-2.8.0/lib/version_winusb.rc.in0000644000175100017510000000217015221003515020463 0ustar runnerrunner #include #define VER_FILEVERSION @yubihsm_shell_VERSION_MAJOR@,@yubihsm_shell_VERSION_MINOR@,@yubihsm_shell_VERSION_PATCH@,0 #define VER_FILEVERSION_STR "@yubihsm_shell_VERSION_MAJOR@.@yubihsm_shell_VERSION_MINOR@.@yubihsm_shell_VERSION_PATCH@.0" VS_VERSION_INFO VERSIONINFO FILEVERSION VER_FILEVERSION PRODUCTVERSION VER_FILEVERSION FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L #else FILEFLAGS 0x0L #endif FILEOS 0x40004L FILETYPE 0x2L FILESUBTYPE 0x0L BEGIN BLOCK "StringFileInfo" BEGIN BLOCK "040904b0" BEGIN VALUE "CompanyName", "Yubico AB" VALUE "FileDescription", "YubiHSM USB backend Library" VALUE "FileVersion", VER_FILEVERSION_STR VALUE "InternalName", "libyubihsm_usb.dll" VALUE "LegalCopyright", "\xa9 Yubico AB" VALUE "OriginalFilename", "libyubihsm_usb.dll" VALUE "ProductName", "YubiHSM" VALUE "ProductVersion", VER_FILEVERSION_STR END END BLOCK "VarFileInfo" BEGIN VALUE "Translation", 0x409, 1200 END END yubihsm-shell-2.8.0/lib/version_winhttp.rc.in0000644000175100017510000000217315221003515020654 0ustar runnerrunner #include #define VER_FILEVERSION @yubihsm_shell_VERSION_MAJOR@,@yubihsm_shell_VERSION_MINOR@,@yubihsm_shell_VERSION_PATCH@,0 #define VER_FILEVERSION_STR "@yubihsm_shell_VERSION_MAJOR@.@yubihsm_shell_VERSION_MINOR@.@yubihsm_shell_VERSION_PATCH@.0" VS_VERSION_INFO VERSIONINFO FILEVERSION VER_FILEVERSION PRODUCTVERSION VER_FILEVERSION FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L #else FILEFLAGS 0x0L #endif FILEOS 0x40004L FILETYPE 0x2L FILESUBTYPE 0x0L BEGIN BLOCK "StringFileInfo" BEGIN BLOCK "040904b0" BEGIN VALUE "CompanyName", "Yubico AB" VALUE "FileDescription", "YubiHSM HTTP backend Library" VALUE "FileVersion", VER_FILEVERSION_STR VALUE "InternalName", "libyubihsm_http.dll" VALUE "LegalCopyright", "\xa9 Yubico AB" VALUE "OriginalFilename", "libyubihsm_http.dll" VALUE "ProductName", "YubiHSM" VALUE "ProductVersion", VER_FILEVERSION_STR END END BLOCK "VarFileInfo" BEGIN VALUE "Translation", 0x409, 1200 END END yubihsm-shell-2.8.0/lib/error.c0000644000175100017510000000600615221003515015753 0ustar runnerrunner/* * Copyright 2015-2018 Yubico AB * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #define ERR(name, desc) \ { name, desc } typedef struct { yh_rc rc; const char *description; } err_t; static const err_t errors[] = { ERR(YHR_SUCCESS, "Success"), ERR(YHR_MEMORY_ERROR, "Unable to allocate memory"), ERR(YHR_INIT_ERROR, "Unable to initialize libyubihsm"), ERR(YHR_CONNECTION_ERROR, "Connection error"), ERR(YHR_CONNECTOR_NOT_FOUND, "Unable to find a suitable connector"), ERR(YHR_INVALID_PARAMETERS, "Invalid argument to a function"), ERR(YHR_WRONG_LENGTH, "Mismatch between expected and received length"), ERR(YHR_BUFFER_TOO_SMALL, "Not enough space to store data"), ERR(YHR_CRYPTOGRAM_MISMATCH, "Unable to verify cryptogram"), ERR(YHR_SESSION_AUTHENTICATION_FAILED, "Unable to authenticate session"), ERR(YHR_MAC_MISMATCH, "Unable to verify MAC"), ERR(YHR_DEVICE_OK, "No error"), ERR(YHR_DEVICE_INVALID_COMMAND, "Unrecognized command"), ERR(YHR_DEVICE_INVALID_DATA, "Malformed command / invalid data"), ERR(YHR_DEVICE_INVALID_SESSION, "Invalid session"), ERR(YHR_DEVICE_AUTHENTICATION_FAILED, "Message encryption / verification failed"), ERR(YHR_DEVICE_SESSIONS_FULL, "All sessions are allocated"), ERR(YHR_DEVICE_SESSION_FAILED, "Session creation failed"), ERR(YHR_DEVICE_STORAGE_FAILED, "Storage failure"), ERR(YHR_DEVICE_WRONG_LENGTH, "Wrong length"), ERR(YHR_DEVICE_INSUFFICIENT_PERMISSIONS, "Wrong permissions for operation"), ERR(YHR_DEVICE_LOG_FULL, "Log buffer is full and forced audit is set"), ERR(YHR_DEVICE_OBJECT_NOT_FOUND, "Object not found"), ERR(YHR_DEVICE_INVALID_ID, "Invalid ID used"), ERR(YHR_DEVICE_INVALID_OTP, "Invalid OTP"), ERR(YHR_DEVICE_DEMO_MODE, "Demo mode, power cycle device"), ERR(YHR_DEVICE_COMMAND_UNEXECUTED, "The command execution has not terminated"), ERR(YHR_GENERIC_ERROR, "Generic error"), ERR(YHR_DEVICE_OBJECT_EXISTS, "An Object with that ID already exists"), ERR(YHR_CONNECTOR_ERROR, "Connector operation failed"), ERR(YHR_DEVICE_SSH_CA_CONSTRAINT_VIOLATION, "SSH CA constraint violation"), ERR(YHR_DEVICE_ALGORITHM_DISABLED, "Algorithm disabled"), }; const char *yh_strerror(yh_rc err) { static const char *unknown = "Unknown yubihsm error"; const char *p; if (-err < 0 || -err >= (int) (sizeof(errors) / sizeof(errors[0]))) { return unknown; } p = errors[-err].description; if (!p) { p = unknown; } return p; } yubihsm-shell-2.8.0/lib/Doxyfile0000644000175100017510000031732515221003515016175 0ustar runnerrunner# Doxyfile 1.8.11 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project. # # All text after a double hash (##) is considered a comment and is placed in # front of the TAG it is preceding. # # All text after a single hash (#) is considered a comment and will be ignored. # The format is: # TAG = value [value, ...] # For lists, items can also be appended using: # TAG += value [value, ...] # Values that contain spaces should be placed between quotes (\" \"). #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- # This tag specifies the encoding used for all characters in the config file # that follow. The default is UTF-8 which is also the encoding used for all text # before the first occurrence of this tag. Doxygen uses libiconv (or the iconv # built into libc) for the transcoding. See http://www.gnu.org/software/libiconv # for the list of possible encodings. # The default value is: UTF-8. DOXYFILE_ENCODING = UTF-8 # The PROJECT_NAME tag is a single word (or a sequence of words surrounded by # double-quotes, unless you are using Doxywizard) that should identify the # project for which the documentation is generated. This name is used in the # title of most generated pages and in a few other places. # The default value is: My Project. PROJECT_NAME = "libyubihsm" # The PROJECT_NUMBER tag can be used to enter a project or revision number. This # could be handy for archiving the generated documentation or if some version # control system is used. PROJECT_NUMBER = # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a # quick idea about the purpose of the project. Keep the description short. PROJECT_BRIEF = # With the PROJECT_LOGO tag one can specify a logo or an icon that is included # in the documentation. The maximum height of the logo should not exceed 55 # pixels and the maximum width should not exceed 200 pixels. Doxygen will copy # the logo to the output directory. PROJECT_LOGO = # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path # into which the generated documentation will be written. If a relative path is # entered, it will be relative to the location where doxygen was started. If # left blank the current directory will be used. OUTPUT_DIRECTORY = doxygen # If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub- # directories (in 2 levels) under the output directory of each output format and # will distribute the generated files over these directories. Enabling this # option can be useful when feeding doxygen a huge amount of source files, where # putting all generated files in the same directory would otherwise causes # performance problems for the file system. # The default value is: NO. CREATE_SUBDIRS = NO # If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII # characters to appear in the names of generated files. If set to NO, non-ASCII # characters will be escaped, for example _xE3_x81_x84 will be used for Unicode # U+3044. # The default value is: NO. ALLOW_UNICODE_NAMES = NO # The OUTPUT_LANGUAGE tag is used to specify the language in which all # documentation generated by doxygen is written. Doxygen will use this # information to generate all constant output in the proper language. # Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese, # Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States), # Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian, # Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages), # Korean, Korean-en (Korean with English messages), Latvian, Lithuanian, # Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian, # Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish, # Ukrainian and Vietnamese. # The default value is: English. OUTPUT_LANGUAGE = English # If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member # descriptions after the members that are listed in the file and class # documentation (similar to Javadoc). Set to NO to disable this. # The default value is: YES. BRIEF_MEMBER_DESC = YES # If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief # description of a member or function before the detailed description # # Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the # brief descriptions will be completely suppressed. # The default value is: YES. REPEAT_BRIEF = YES # This tag implements a quasi-intelligent brief description abbreviator that is # used to form the text in various listings. Each string in this list, if found # as the leading text of the brief description, will be stripped from the text # and the result, after processing the whole list, is used as the annotated # text. Otherwise, the brief description is used as-is. If left blank, the # following values are used ($name is automatically replaced with the name of # the entity):The $name class, The $name widget, The $name file, is, provides, # specifies, contains, represents, a, an and the. ABBREVIATE_BRIEF = # If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then # doxygen will generate a detailed section even if there is only a brief # description. # The default value is: NO. ALWAYS_DETAILED_SEC = NO # If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all # inherited members of a class in the documentation of that class as if those # members were ordinary class members. Constructors, destructors and assignment # operators of the base classes will not be shown. # The default value is: NO. INLINE_INHERITED_MEMB = NO # If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path # before files name in the file list and in the header files. If set to NO the # shortest path that makes the file name unique will be used # The default value is: YES. FULL_PATH_NAMES = YES # The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path. # Stripping is only done if one of the specified strings matches the left-hand # part of the path. The tag can be used to show relative paths in the file list. # If left blank the directory from which doxygen is run is used as the path to # strip. # # Note that you can specify absolute paths here, but also relative paths, which # will be relative from the directory where doxygen is started. # This tag requires that the tag FULL_PATH_NAMES is set to YES. STRIP_FROM_PATH = # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the # path mentioned in the documentation of a class, which tells the reader which # header file to include in order to use a class. If left blank only the name of # the header file containing the class definition is used. Otherwise one should # specify the list of include paths that are normally passed to the compiler # using the -I flag. STRIP_FROM_INC_PATH = # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but # less readable) file names. This can be useful is your file systems doesn't # support long names like on DOS, Mac, or CD-ROM. # The default value is: NO. SHORT_NAMES = NO # If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the # first line (until the first dot) of a Javadoc-style comment as the brief # description. If set to NO, the Javadoc-style will behave just like regular Qt- # style comments (thus requiring an explicit @brief command for a brief # description.) # The default value is: NO. JAVADOC_AUTOBRIEF = YES # If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first # line (until the first dot) of a Qt-style comment as the brief description. If # set to NO, the Qt-style will behave just like regular Qt-style comments (thus # requiring an explicit \brief command for a brief description.) # The default value is: NO. QT_AUTOBRIEF = NO # The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a # multi-line C++ special comment block (i.e. a block of //! or /// comments) as # a brief description. This used to be the default behavior. The new default is # to treat a multi-line C++ comment block as a detailed description. Set this # tag to YES if you prefer the old behavior instead. # # Note that setting this tag to YES also means that rational rose comments are # not recognized any more. # The default value is: NO. MULTILINE_CPP_IS_BRIEF = NO # If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the # documentation from any documented member that it re-implements. # The default value is: YES. INHERIT_DOCS = YES # If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new # page for each member. If set to NO, the documentation of a member will be part # of the file/class/namespace that contains it. # The default value is: NO. SEPARATE_MEMBER_PAGES = NO # The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen # uses this value to replace tabs by spaces in code fragments. # Minimum value: 1, maximum value: 16, default value: 4. TAB_SIZE = 4 # This tag can be used to specify a number of aliases that act as commands in # the documentation. An alias has the form: # name=value # For example adding # "sideeffect=@par Side Effects:\n" # will allow you to put the command \sideeffect (or @sideeffect) in the # documentation, which will result in a user-defined paragraph with heading # "Side Effects:". You can put \n's in the value part of an alias to insert # newlines. ALIASES = # This tag can be used to specify a number of word-keyword mappings (TCL only). # A mapping has the form "name=value". For example adding "class=itcl::class" # will allow you to use the command class in the itcl::class meaning. TCL_SUBST = # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources # only. Doxygen will then generate output that is more tailored for C. For # instance, some of the names that are used will be different. The list of all # members will be omitted, etc. # The default value is: NO. OPTIMIZE_OUTPUT_FOR_C = YES # Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or # Python sources only. Doxygen will then generate output that is more tailored # for that language. For instance, namespaces will be presented as packages, # qualified scopes will look different, etc. # The default value is: NO. OPTIMIZE_OUTPUT_JAVA = NO # Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran # sources. Doxygen will then generate output that is tailored for Fortran. # The default value is: NO. OPTIMIZE_FOR_FORTRAN = NO # Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL # sources. Doxygen will then generate output that is tailored for VHDL. # The default value is: NO. OPTIMIZE_OUTPUT_VHDL = NO # Doxygen selects the parser to use depending on the extension of the files it # parses. With this tag you can assign which parser to use for a given # extension. Doxygen has a built-in mapping, but you can override or extend it # using this tag. The format is ext=language, where ext is a file extension, and # language is one of the parsers supported by doxygen: IDL, Java, Javascript, # C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran: # FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran: # Fortran. In the later case the parser tries to guess whether the code is fixed # or free formatted code, this is the default for Fortran type files), VHDL. For # instance to make doxygen treat .inc files as Fortran files (default is PHP), # and .f files as C (default is Fortran), use: inc=Fortran f=C. # # Note: For files without extension you can use no_extension as a placeholder. # # Note that for custom extensions you also need to set FILE_PATTERNS otherwise # the files are not read by doxygen. EXTENSION_MAPPING = # If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments # according to the Markdown format, which allows for more readable # documentation. See http://daringfireball.net/projects/markdown/ for details. # The output of markdown processing is further processed by doxygen, so you can # mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in # case of backward compatibilities issues. # The default value is: YES. MARKDOWN_SUPPORT = YES # When enabled doxygen tries to link words that correspond to documented # classes, or namespaces to their corresponding documentation. Such a link can # be prevented in individual cases by putting a % sign in front of the word or # globally by setting AUTOLINK_SUPPORT to NO. # The default value is: YES. AUTOLINK_SUPPORT = YES # If you use STL classes (i.e. std::string, std::vector, etc.) but do not want # to include (a tag file for) the STL sources as input, then you should set this # tag to YES in order to let doxygen match functions declarations and # definitions whose arguments contain STL classes (e.g. func(std::string); # versus func(std::string) {}). This also make the inheritance and collaboration # diagrams that involve STL classes more complete and accurate. # The default value is: NO. BUILTIN_STL_SUPPORT = NO # If you use Microsoft's C++/CLI language, you should set this option to YES to # enable parsing support. # The default value is: NO. CPP_CLI_SUPPORT = NO # Set the SIP_SUPPORT tag to YES if your project consists of sip (see: # http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen # will parse them like normal C++ but will assume all classes use public instead # of private inheritance when no explicit protection keyword is present. # The default value is: NO. SIP_SUPPORT = NO # For Microsoft's IDL there are propget and propput attributes to indicate # getter and setter methods for a property. Setting this option to YES will make # doxygen to replace the get and set methods by a property in the documentation. # This will only work if the methods are indeed getting or setting a simple # type. If this is not the case, or you want to show the methods anyway, you # should set this option to NO. # The default value is: YES. IDL_PROPERTY_SUPPORT = YES # If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC # tag is set to YES then doxygen will reuse the documentation of the first # member in the group (if any) for the other members of the group. By default # all members of a group must be documented explicitly. # The default value is: NO. DISTRIBUTE_GROUP_DOC = NO # If one adds a struct or class to a group and this option is enabled, then also # any nested class or struct is added to the same group. By default this option # is disabled and one has to add nested compounds explicitly via \ingroup. # The default value is: NO. GROUP_NESTED_COMPOUNDS = NO # Set the SUBGROUPING tag to YES to allow class member groups of the same type # (for instance a group of public functions) to be put as a subgroup of that # type (e.g. under the Public Functions section). Set it to NO to prevent # subgrouping. Alternatively, this can be done per class using the # \nosubgrouping command. # The default value is: YES. SUBGROUPING = YES # When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions # are shown inside the group in which they are included (e.g. using \ingroup) # instead of on a separate page (for HTML and Man pages) or section (for LaTeX # and RTF). # # Note that this feature does not work in combination with # SEPARATE_MEMBER_PAGES. # The default value is: NO. INLINE_GROUPED_CLASSES = NO # When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions # with only public data fields or simple typedef fields will be shown inline in # the documentation of the scope in which they are defined (i.e. file, # namespace, or group documentation), provided this scope is documented. If set # to NO, structs, classes, and unions are shown on a separate page (for HTML and # Man pages) or section (for LaTeX and RTF). # The default value is: NO. INLINE_SIMPLE_STRUCTS = NO # When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or # enum is documented as struct, union, or enum with the name of the typedef. So # typedef struct TypeS {} TypeT, will appear in the documentation as a struct # with name TypeT. When disabled the typedef will appear as a member of a file, # namespace, or class. And the struct will be named TypeS. This can typically be # useful for C code in case the coding convention dictates that all compound # types are typedef'ed and only the typedef is referenced, never the tag name. # The default value is: NO. TYPEDEF_HIDES_STRUCT = NO # The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This # cache is used to resolve symbols given their name and scope. Since this can be # an expensive process and often the same symbol appears multiple times in the # code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small # doxygen will become slower. If the cache is too large, memory is wasted. The # cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range # is 0..9, the default is 0, corresponding to a cache size of 2^16=65536 # symbols. At the end of a run doxygen will report the cache usage and suggest # the optimal cache size from a speed point of view. # Minimum value: 0, maximum value: 9, default value: 0. LOOKUP_CACHE_SIZE = 0 #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- # If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in # documentation are documented, even if no documentation was available. Private # class members and static file members will be hidden unless the # EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. # Note: This will also disable the warnings about undocumented members that are # normally produced when WARNINGS is set to YES. # The default value is: NO. EXTRACT_ALL = NO # If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will # be included in the documentation. # The default value is: NO. EXTRACT_PRIVATE = NO # If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal # scope will be included in the documentation. # The default value is: NO. EXTRACT_PACKAGE = NO # If the EXTRACT_STATIC tag is set to YES, all static members of a file will be # included in the documentation. # The default value is: NO. EXTRACT_STATIC = NO # If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined # locally in source files will be included in the documentation. If set to NO, # only classes defined in header files are included. Does not have any effect # for Java sources. # The default value is: YES. EXTRACT_LOCAL_CLASSES = YES # This flag is only useful for Objective-C code. If set to YES, local methods, # which are defined in the implementation section but not in the interface are # included in the documentation. If set to NO, only methods in the interface are # included. # The default value is: NO. EXTRACT_LOCAL_METHODS = NO # If this flag is set to YES, the members of anonymous namespaces will be # extracted and appear in the documentation as a namespace called # 'anonymous_namespace{file}', where file will be replaced with the base name of # the file that contains the anonymous namespace. By default anonymous namespace # are hidden. # The default value is: NO. EXTRACT_ANON_NSPACES = NO # If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all # undocumented members inside documented classes or files. If set to NO these # members will be included in the various overviews, but no documentation # section is generated. This option has no effect if EXTRACT_ALL is enabled. # The default value is: NO. HIDE_UNDOC_MEMBERS = NO # If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all # undocumented classes that are normally visible in the class hierarchy. If set # to NO, these classes will be included in the various overviews. This option # has no effect if EXTRACT_ALL is enabled. # The default value is: NO. HIDE_UNDOC_CLASSES = NO # If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend # (class|struct|union) declarations. If set to NO, these declarations will be # included in the documentation. # The default value is: NO. HIDE_FRIEND_COMPOUNDS = NO # If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any # documentation blocks found inside the body of a function. If set to NO, these # blocks will be appended to the function's detailed documentation block. # The default value is: NO. HIDE_IN_BODY_DOCS = NO # The INTERNAL_DOCS tag determines if documentation that is typed after a # \internal command is included. If the tag is set to NO then the documentation # will be excluded. Set it to YES to include the internal documentation. # The default value is: NO. INTERNAL_DOCS = NO # If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file # names in lower-case letters. If set to YES, upper-case letters are also # allowed. This is useful if you have classes or files whose names only differ # in case and if your file system supports case sensitive file names. Windows # and Mac users are advised to set this option to NO. # The default value is: system dependent. CASE_SENSE_NAMES = YES # If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with # their full class and namespace scopes in the documentation. If set to YES, the # scope will be hidden. # The default value is: NO. HIDE_SCOPE_NAMES = NO # If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will # append additional text to a page's title, such as Class Reference. If set to # YES the compound reference will be hidden. # The default value is: NO. HIDE_COMPOUND_REFERENCE= NO # If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of # the files that are included by a file in the documentation of that file. # The default value is: YES. SHOW_INCLUDE_FILES = NO # If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each # grouped member an include statement to the documentation, telling the reader # which file to include in order to use the member. # The default value is: NO. SHOW_GROUPED_MEMB_INC = NO # If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include # files with double quotes in the documentation rather than with sharp brackets. # The default value is: NO. FORCE_LOCAL_INCLUDES = NO # If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the # documentation for inline members. # The default value is: YES. INLINE_INFO = YES # If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the # (detailed) documentation of file and class members alphabetically by member # name. If set to NO, the members will appear in declaration order. # The default value is: YES. SORT_MEMBER_DOCS = YES # If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief # descriptions of file, namespace and class members alphabetically by member # name. If set to NO, the members will appear in declaration order. Note that # this will also influence the order of the classes in the class list. # The default value is: NO. SORT_BRIEF_DOCS = NO # If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the # (brief and detailed) documentation of class members so that constructors and # destructors are listed first. If set to NO the constructors will appear in the # respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS. # Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief # member documentation. # Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting # detailed member documentation. # The default value is: NO. SORT_MEMBERS_CTORS_1ST = NO # If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy # of group names into alphabetical order. If set to NO the group names will # appear in their defined order. # The default value is: NO. SORT_GROUP_NAMES = NO # If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by # fully-qualified names, including namespaces. If set to NO, the class list will # be sorted only by class name, not including the namespace part. # Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. # Note: This option applies only to the class list, not to the alphabetical # list. # The default value is: NO. SORT_BY_SCOPE_NAME = NO # If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper # type resolution of all parameters of a function it will reject a match between # the prototype and the implementation of a member function even if there is # only one candidate or it is obvious which candidate to choose by doing a # simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still # accept a match between prototype and implementation in such cases. # The default value is: NO. STRICT_PROTO_MATCHING = YES # The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo # list. This list is created by putting \todo commands in the documentation. # The default value is: YES. GENERATE_TODOLIST = YES # The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test # list. This list is created by putting \test commands in the documentation. # The default value is: YES. GENERATE_TESTLIST = YES # The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug # list. This list is created by putting \bug commands in the documentation. # The default value is: YES. GENERATE_BUGLIST = YES # The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO) # the deprecated list. This list is created by putting \deprecated commands in # the documentation. # The default value is: YES. GENERATE_DEPRECATEDLIST= YES # The ENABLED_SECTIONS tag can be used to enable conditional documentation # sections, marked by \if ... \endif and \cond # ... \endcond blocks. ENABLED_SECTIONS = # The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the # initial value of a variable or macro / define can have for it to appear in the # documentation. If the initializer consists of more lines than specified here # it will be hidden. Use a value of 0 to hide initializers completely. The # appearance of the value of individual variables and macros / defines can be # controlled using \showinitializer or \hideinitializer command in the # documentation regardless of this setting. # Minimum value: 0, maximum value: 10000, default value: 30. MAX_INITIALIZER_LINES = 30 # Set the SHOW_USED_FILES tag to NO to disable the list of files generated at # the bottom of the documentation of classes and structs. If set to YES, the # list will mention the files that were used to generate the documentation. # The default value is: YES. SHOW_USED_FILES = YES # Set the SHOW_FILES tag to NO to disable the generation of the Files page. This # will remove the Files entry from the Quick Index and from the Folder Tree View # (if specified). # The default value is: YES. SHOW_FILES = YES # Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces # page. This will remove the Namespaces entry from the Quick Index and from the # Folder Tree View (if specified). # The default value is: YES. SHOW_NAMESPACES = YES # The FILE_VERSION_FILTER tag can be used to specify a program or script that # doxygen should invoke to get the current version for each file (typically from # the version control system). Doxygen will invoke the program by executing (via # popen()) the command command input-file, where command is the value of the # FILE_VERSION_FILTER tag, and input-file is the name of an input file provided # by doxygen. Whatever the program writes to standard output is used as the file # version. For an example see the documentation. FILE_VERSION_FILTER = # The LAYOUT_FILE tag can be used to specify a layout file which will be parsed # by doxygen. The layout file controls the global structure of the generated # output files in an output format independent way. To create the layout file # that represents doxygen's defaults, run doxygen with the -l option. You can # optionally specify a file name after the option, if omitted DoxygenLayout.xml # will be used as the name of the layout file. # # Note that if you run doxygen from a directory containing a file called # DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE # tag is left empty. LAYOUT_FILE = # The CITE_BIB_FILES tag can be used to specify one or more bib files containing # the reference definitions. This must be a list of .bib files. The .bib # extension is automatically appended if omitted. This requires the bibtex tool # to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info. # For LaTeX the style of the bibliography can be controlled using # LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the # search path. See also \cite for info how to create references. CITE_BIB_FILES = #--------------------------------------------------------------------------- # Configuration options related to warning and progress messages #--------------------------------------------------------------------------- # The QUIET tag can be used to turn on/off the messages that are generated to # standard output by doxygen. If QUIET is set to YES this implies that the # messages are off. # The default value is: NO. QUIET = YES # The WARNINGS tag can be used to turn on/off the warning messages that are # generated to standard error (stderr) by doxygen. If WARNINGS is set to YES # this implies that the warnings are on. # # Tip: Turn warnings on while writing the documentation. # The default value is: YES. WARNINGS = YES # If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate # warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag # will automatically be disabled. # The default value is: YES. WARN_IF_UNDOCUMENTED = YES # If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for # potential errors in the documentation, such as not documenting some parameters # in a documented function, or documenting parameters that don't exist or using # markup commands wrongly. # The default value is: YES. WARN_IF_DOC_ERROR = YES # This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that # are documented, but have no documentation for their parameters or return # value. If set to NO, doxygen will only warn about wrong or incomplete # parameter documentation, but not about the absence of documentation. # The default value is: NO. WARN_NO_PARAMDOC = YES # If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when # a warning is encountered. # The default value is: NO. WARN_AS_ERROR = NO # The WARN_FORMAT tag determines the format of the warning messages that doxygen # can produce. The string should contain the $file, $line, and $text tags, which # will be replaced by the file and line number from which the warning originated # and the warning text. Optionally the format may contain $version, which will # be replaced by the version of the file (if it could be obtained via # FILE_VERSION_FILTER) # The default value is: $file:$line: $text. WARN_FORMAT = "$file:$line: $text" # The WARN_LOGFILE tag can be used to specify a file to which warning and error # messages should be written. If left blank the output is written to standard # error (stderr). WARN_LOGFILE = #--------------------------------------------------------------------------- # Configuration options related to the input files #--------------------------------------------------------------------------- # The INPUT tag is used to specify the files and/or directories that contain # documented source files. You may enter file names like myfile.cpp or # directories like /usr/src/myproject. Separate the files or directories with # spaces. See also FILE_PATTERNS and EXTENSION_MAPPING # Note: If this tag is empty the current directory is searched. INPUT = yubihsm.h # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses # libiconv (or the iconv built into libc) for the transcoding. See the libiconv # documentation (see: http://www.gnu.org/software/libiconv) for the list of # possible encodings. # The default value is: UTF-8. INPUT_ENCODING = UTF-8 # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and # *.h) to filter out the source-files in the directories. # # Note that for custom extensions or not directly supported extensions you also # need to set EXTENSION_MAPPING for the extension otherwise the files are not # read by doxygen. # # If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp, # *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, # *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, # *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f, *.for, *.tcl, # *.vhd, *.vhdl, *.ucf, *.qsf, *.as and *.js. FILE_PATTERNS = # The RECURSIVE tag can be used to specify whether or not subdirectories should # be searched for input files as well. # The default value is: NO. RECURSIVE = NO # The EXCLUDE tag can be used to specify files and/or directories that should be # excluded from the INPUT source files. This way you can easily exclude a # subdirectory from a directory tree whose root is specified with the INPUT tag. # # Note that relative paths are relative to the directory from which doxygen is # run. EXCLUDE = # The EXCLUDE_SYMLINKS tag can be used to select whether or not files or # directories that are symbolic links (a Unix file system feature) are excluded # from the input. # The default value is: NO. EXCLUDE_SYMLINKS = NO # If the value of the INPUT tag contains directories, you can use the # EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude # certain files from those directories. # # Note that the wildcards are matched against the file with absolute path, so to # exclude all test directories for example use the pattern */test/* EXCLUDE_PATTERNS = # The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names # (namespaces, classes, functions, etc.) that should be excluded from the # output. The symbol name can be a fully qualified name, a word, or if the # wildcard * is used, a substring. Examples: ANamespace, AClass, # AClass::ANamespace, ANamespace::*Test # # Note that the wildcards are matched against the file with absolute path, so to # exclude all test directories use the pattern */test/* EXCLUDE_SYMBOLS = # The EXAMPLE_PATH tag can be used to specify one or more files or directories # that contain example code fragments that are included (see the \include # command). EXAMPLE_PATH = # If the value of the EXAMPLE_PATH tag contains directories, you can use the # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and # *.h) to filter out the source-files in the directories. If left blank all # files are included. EXAMPLE_PATTERNS = # If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be # searched for input files to be used with the \include or \dontinclude commands # irrespective of the value of the RECURSIVE tag. # The default value is: NO. EXAMPLE_RECURSIVE = NO # The IMAGE_PATH tag can be used to specify one or more files or directories # that contain images that are to be included in the documentation (see the # \image command). IMAGE_PATH = # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program # by executing (via popen()) the command: # # # # where is the value of the INPUT_FILTER tag, and is the # name of an input file. Doxygen will then use the output that the filter # program writes to standard output. If FILTER_PATTERNS is specified, this tag # will be ignored. # # Note that the filter must not add or remove lines; it is applied before the # code is scanned, but not when the output code is generated. If lines are added # or removed, the anchors will not be placed correctly. # # Note that for custom extensions or not directly supported extensions you also # need to set EXTENSION_MAPPING for the extension otherwise the files are not # properly processed by doxygen. INPUT_FILTER = # The FILTER_PATTERNS tag can be used to specify filters on a per file pattern # basis. Doxygen will compare the file name with each pattern and apply the # filter if there is a match. The filters are a list of the form: pattern=filter # (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how # filters are used. If the FILTER_PATTERNS tag is empty or if none of the # patterns match the file name, INPUT_FILTER is applied. # # Note that for custom extensions or not directly supported extensions you also # need to set EXTENSION_MAPPING for the extension otherwise the files are not # properly processed by doxygen. FILTER_PATTERNS = # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using # INPUT_FILTER) will also be used to filter the input files that are used for # producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES). # The default value is: NO. FILTER_SOURCE_FILES = NO # The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file # pattern. A pattern will override the setting for FILTER_PATTERN (if any) and # it is also possible to disable source filtering for a specific pattern using # *.ext= (so without naming a filter). # This tag requires that the tag FILTER_SOURCE_FILES is set to YES. FILTER_SOURCE_PATTERNS = # If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that # is part of the input, its contents will be placed on the main page # (index.html). This can be useful if you have a project on for instance GitHub # and want to reuse the introduction page also for the doxygen output. USE_MDFILE_AS_MAINPAGE = #--------------------------------------------------------------------------- # Configuration options related to source browsing #--------------------------------------------------------------------------- # If the SOURCE_BROWSER tag is set to YES then a list of source files will be # generated. Documented entities will be cross-referenced with these sources. # # Note: To get rid of all source code in the generated output, make sure that # also VERBATIM_HEADERS is set to NO. # The default value is: NO. SOURCE_BROWSER = NO # Setting the INLINE_SOURCES tag to YES will include the body of functions, # classes and enums directly into the documentation. # The default value is: NO. INLINE_SOURCES = NO # Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any # special comment blocks from generated source code fragments. Normal C, C++ and # Fortran comments will always remain visible. # The default value is: YES. STRIP_CODE_COMMENTS = YES # If the REFERENCED_BY_RELATION tag is set to YES then for each documented # function all documented functions referencing it will be listed. # The default value is: NO. REFERENCED_BY_RELATION = NO # If the REFERENCES_RELATION tag is set to YES then for each documented function # all documented entities called/used by that function will be listed. # The default value is: NO. REFERENCES_RELATION = NO # If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set # to YES then the hyperlinks from functions in REFERENCES_RELATION and # REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will # link to the documentation. # The default value is: YES. REFERENCES_LINK_SOURCE = YES # If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the # source code will show a tooltip with additional information such as prototype, # brief description and links to the definition and documentation. Since this # will make the HTML file larger and loading of large files a bit slower, you # can opt to disable this feature. # The default value is: YES. # This tag requires that the tag SOURCE_BROWSER is set to YES. SOURCE_TOOLTIPS = YES # If the USE_HTAGS tag is set to YES then the references to source code will # point to the HTML generated by the htags(1) tool instead of doxygen built-in # source browser. The htags tool is part of GNU's global source tagging system # (see http://www.gnu.org/software/global/global.html). You will need version # 4.8.6 or higher. # # To use it do the following: # - Install the latest version of global # - Enable SOURCE_BROWSER and USE_HTAGS in the config file # - Make sure the INPUT points to the root of the source tree # - Run doxygen as normal # # Doxygen will invoke htags (and that will in turn invoke gtags), so these # tools must be available from the command line (i.e. in the search path). # # The result: instead of the source browser generated by doxygen, the links to # source code will now point to the output of htags. # The default value is: NO. # This tag requires that the tag SOURCE_BROWSER is set to YES. USE_HTAGS = NO # If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a # verbatim copy of the header file for each class for which an include is # specified. Set to NO to disable this. # See also: Section \class. # The default value is: YES. VERBATIM_HEADERS = YES # If the CLANG_ASSISTED_PARSING tag is set to YES then doxygen will use the # clang parser (see: http://clang.llvm.org/) for more accurate parsing at the # cost of reduced performance. This can be particularly helpful with template # rich C++ code for which doxygen's built-in parser lacks the necessary type # information. # Note: The availability of this option depends on whether or not doxygen was # generated with the -Duse-libclang=ON option for CMake. # The default value is: NO. CLANG_ASSISTED_PARSING = NO # If clang assisted parsing is enabled you can provide the compiler with command # line options that you would normally use when invoking the compiler. Note that # the include paths will already be set by doxygen for the files and directories # specified with INPUT and INCLUDE_PATH. # This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES. CLANG_OPTIONS = #--------------------------------------------------------------------------- # Configuration options related to the alphabetical class index #--------------------------------------------------------------------------- # If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all # compounds will be generated. Enable this if the project contains a lot of # classes, structs, unions or interfaces. # The default value is: YES. ALPHABETICAL_INDEX = YES # The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in # which the alphabetical index list will be split. # Minimum value: 1, maximum value: 20, default value: 5. # This tag requires that the tag ALPHABETICAL_INDEX is set to YES. COLS_IN_ALPHA_INDEX = 5 # In case all classes in a project start with a common prefix, all classes will # be put under the same header in the alphabetical index. The IGNORE_PREFIX tag # can be used to specify a prefix (or a list of prefixes) that should be ignored # while generating the index headers. # This tag requires that the tag ALPHABETICAL_INDEX is set to YES. IGNORE_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the HTML output #--------------------------------------------------------------------------- # If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output # The default value is: YES. GENERATE_HTML = YES # The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a # relative path is entered the value of OUTPUT_DIRECTORY will be put in front of # it. # The default directory is: html. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_OUTPUT = html # The HTML_FILE_EXTENSION tag can be used to specify the file extension for each # generated HTML page (for example: .htm, .php, .asp). # The default value is: .html. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_FILE_EXTENSION = .html # The HTML_HEADER tag can be used to specify a user-defined HTML header file for # each generated HTML page. If the tag is left blank doxygen will generate a # standard header. # # To get valid HTML the header file that includes any scripts and style sheets # that doxygen needs, which is dependent on the configuration options used (e.g. # the setting GENERATE_TREEVIEW). It is highly recommended to start with a # default header using # doxygen -w html new_header.html new_footer.html new_stylesheet.css # YourConfigFile # and then modify the file new_header.html. See also section "Doxygen usage" # for information on how to generate the default header that doxygen normally # uses. # Note: The header is subject to change so you typically have to regenerate the # default header when upgrading to a newer version of doxygen. For a description # of the possible markers and block names see the documentation. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_HEADER = # The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each # generated HTML page. If the tag is left blank doxygen will generate a standard # footer. See HTML_HEADER for more information on how to generate a default # footer and what special commands can be used inside the footer. See also # section "Doxygen usage" for information on how to generate the default footer # that doxygen normally uses. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_FOOTER = # The HTML_STYLESHEET tag can be used to specify a user-defined cascading style # sheet that is used by each HTML page. It can be used to fine-tune the look of # the HTML output. If left blank doxygen will generate a default style sheet. # See also section "Doxygen usage" for information on how to generate the style # sheet that doxygen normally uses. # Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as # it is more robust and this tag (HTML_STYLESHEET) will in the future become # obsolete. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_STYLESHEET = # The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined # cascading style sheets that are included after the standard style sheets # created by doxygen. Using this option one can overrule certain style aspects. # This is preferred over using HTML_STYLESHEET since it does not replace the # standard style sheet and is therefore more robust against future updates. # Doxygen will copy the style sheet files to the output directory. # Note: The order of the extra style sheet files is of importance (e.g. the last # style sheet in the list overrules the setting of the previous ones in the # list). For an example see the documentation. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_EXTRA_STYLESHEET = # The HTML_EXTRA_FILES tag can be used to specify one or more extra images or # other source files which should be copied to the HTML output directory. Note # that these files will be copied to the base HTML output directory. Use the # $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these # files. In the HTML_STYLESHEET file, use the file name only. Also note that the # files will be copied as-is; there are no commands or markers available. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_EXTRA_FILES = # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen # will adjust the colors in the style sheet and background images according to # this color. Hue is specified as an angle on a colorwheel, see # http://en.wikipedia.org/wiki/Hue for more information. For instance the value # 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 # purple, and 360 is red again. # Minimum value: 0, maximum value: 359, default value: 220. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_COLORSTYLE_HUE = 220 # The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors # in the HTML output. For a value of 0 the output will use grayscales only. A # value of 255 will produce the most vivid colors. # Minimum value: 0, maximum value: 255, default value: 100. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_COLORSTYLE_SAT = 100 # The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the # luminance component of the colors in the HTML output. Values below 100 # gradually make the output lighter, whereas values above 100 make the output # darker. The value divided by 100 is the actual gamma applied, so 80 represents # a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not # change the gamma. # Minimum value: 40, maximum value: 240, default value: 80. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_COLORSTYLE_GAMMA = 80 # If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML # page will contain the date and time when the page was generated. Setting this # to YES can help to show when doxygen was last run and thus if the # documentation is up to date. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_TIMESTAMP = NO # If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML # documentation will contain sections that can be hidden and shown after the # page has loaded. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_DYNAMIC_SECTIONS = NO # With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries # shown in the various tree structured indices initially; the user can expand # and collapse entries dynamically later on. Doxygen will expand the tree to # such a level that at most the specified number of entries are visible (unless # a fully collapsed tree already exceeds this amount). So setting the number of # entries 1 will produce a full collapsed tree by default. 0 is a special value # representing an infinite number of entries and will result in a full expanded # tree by default. # Minimum value: 0, maximum value: 9999, default value: 100. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_INDEX_NUM_ENTRIES = 100 # If the GENERATE_DOCSET tag is set to YES, additional index files will be # generated that can be used as input for Apple's Xcode 3 integrated development # environment (see: http://developer.apple.com/tools/xcode/), introduced with # OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a # Makefile in the HTML output directory. Running make will produce the docset in # that directory and running make install will install the docset in # ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at # startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html # for more information. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_DOCSET = NO # This tag determines the name of the docset feed. A documentation feed provides # an umbrella under which multiple documentation sets from a single provider # (such as a company or product suite) can be grouped. # The default value is: Doxygen generated docs. # This tag requires that the tag GENERATE_DOCSET is set to YES. DOCSET_FEEDNAME = "Doxygen generated docs" # This tag specifies a string that should uniquely identify the documentation # set bundle. This should be a reverse domain-name style string, e.g. # com.mycompany.MyDocSet. Doxygen will append .docset to the name. # The default value is: org.doxygen.Project. # This tag requires that the tag GENERATE_DOCSET is set to YES. DOCSET_BUNDLE_ID = org.doxygen.Project # The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify # the documentation publisher. This should be a reverse domain-name style # string, e.g. com.mycompany.MyDocSet.documentation. # The default value is: org.doxygen.Publisher. # This tag requires that the tag GENERATE_DOCSET is set to YES. DOCSET_PUBLISHER_ID = org.doxygen.Publisher # The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher. # The default value is: Publisher. # This tag requires that the tag GENERATE_DOCSET is set to YES. DOCSET_PUBLISHER_NAME = Publisher # If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three # additional HTML index files: index.hhp, index.hhc, and index.hhk. The # index.hhp is a project file that can be read by Microsoft's HTML Help Workshop # (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on # Windows. # # The HTML Help Workshop contains a compiler that can convert all HTML output # generated by doxygen into a single compiled HTML file (.chm). Compiled HTML # files are now used as the Windows 98 help format, and will replace the old # Windows help format (.hlp) on all Windows platforms in the future. Compressed # HTML files also contain an index, a table of contents, and you can search for # words in the documentation. The HTML workshop also contains a viewer for # compressed HTML files. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_HTMLHELP = NO # The CHM_FILE tag can be used to specify the file name of the resulting .chm # file. You can add a path in front of the file if the result should not be # written to the html output directory. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. CHM_FILE = # The HHC_LOCATION tag can be used to specify the location (absolute path # including file name) of the HTML help compiler (hhc.exe). If non-empty, # doxygen will try to run the HTML help compiler on the generated index.hhp. # The file has to be specified with full path. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. HHC_LOCATION = # The GENERATE_CHI flag controls if a separate .chi index file is generated # (YES) or that it should be included in the main .chm file (NO). # The default value is: NO. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. GENERATE_CHI = NO # The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc) # and project file content. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. CHM_INDEX_ENCODING = # The BINARY_TOC flag controls whether a binary table of contents is generated # (YES) or a normal table of contents (NO) in the .chm file. Furthermore it # enables the Previous and Next buttons. # The default value is: NO. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. BINARY_TOC = NO # The TOC_EXPAND flag can be set to YES to add extra items for group members to # the table of contents of the HTML help documentation and to the tree view. # The default value is: NO. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. TOC_EXPAND = NO # If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and # QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that # can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help # (.qch) of the generated HTML documentation. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_QHP = NO # If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify # the file name of the resulting .qch file. The path specified is relative to # the HTML output folder. # This tag requires that the tag GENERATE_QHP is set to YES. QCH_FILE = # The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help # Project output. For more information please see Qt Help Project / Namespace # (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace). # The default value is: org.doxygen.Project. # This tag requires that the tag GENERATE_QHP is set to YES. QHP_NAMESPACE = org.doxygen.Project # The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt # Help Project output. For more information please see Qt Help Project / Virtual # Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual- # folders). # The default value is: doc. # This tag requires that the tag GENERATE_QHP is set to YES. QHP_VIRTUAL_FOLDER = doc # If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom # filter to add. For more information please see Qt Help Project / Custom # Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- # filters). # This tag requires that the tag GENERATE_QHP is set to YES. QHP_CUST_FILTER_NAME = # The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the # custom filter to add. For more information please see Qt Help Project / Custom # Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- # filters). # This tag requires that the tag GENERATE_QHP is set to YES. QHP_CUST_FILTER_ATTRS = # The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this # project's filter section matches. Qt Help Project / Filter Attributes (see: # http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes). # This tag requires that the tag GENERATE_QHP is set to YES. QHP_SECT_FILTER_ATTRS = # The QHG_LOCATION tag can be used to specify the location of Qt's # qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the # generated .qhp file. # This tag requires that the tag GENERATE_QHP is set to YES. QHG_LOCATION = # If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be # generated, together with the HTML files, they form an Eclipse help plugin. To # install this plugin and make it available under the help contents menu in # Eclipse, the contents of the directory containing the HTML and XML files needs # to be copied into the plugins directory of eclipse. The name of the directory # within the plugins directory should be the same as the ECLIPSE_DOC_ID value. # After copying Eclipse needs to be restarted before the help appears. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_ECLIPSEHELP = NO # A unique identifier for the Eclipse help plugin. When installing the plugin # the directory name containing the HTML and XML files should also have this # name. Each documentation set should have its own identifier. # The default value is: org.doxygen.Project. # This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES. ECLIPSE_DOC_ID = org.doxygen.Project # If you want full control over the layout of the generated HTML pages it might # be necessary to disable the index and replace it with your own. The # DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top # of each HTML page. A value of NO enables the index and the value YES disables # it. Since the tabs in the index contain the same information as the navigation # tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. DISABLE_INDEX = NO # The GENERATE_TREEVIEW tag is used to specify whether a tree-like index # structure should be generated to display hierarchical information. If the tag # value is set to YES, a side panel will be generated containing a tree-like # index structure (just like the one that is generated for HTML Help). For this # to work a browser that supports JavaScript, DHTML, CSS and frames is required # (i.e. any modern browser). Windows users are probably better off using the # HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can # further fine-tune the look of the index. As an example, the default style # sheet generated by doxygen has an example that shows how to put an image at # the root of the tree instead of the PROJECT_NAME. Since the tree basically has # the same information as the tab index, you could consider setting # DISABLE_INDEX to YES when enabling this option. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_TREEVIEW = NO # The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that # doxygen will group on one line in the generated HTML documentation. # # Note that a value of 0 will completely suppress the enum values from appearing # in the overview section. # Minimum value: 0, maximum value: 20, default value: 4. # This tag requires that the tag GENERATE_HTML is set to YES. ENUM_VALUES_PER_LINE = 4 # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used # to set the initial width (in pixels) of the frame in which the tree is shown. # Minimum value: 0, maximum value: 1500, default value: 250. # This tag requires that the tag GENERATE_HTML is set to YES. TREEVIEW_WIDTH = 250 # If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to # external symbols imported via tag files in a separate window. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. EXT_LINKS_IN_WINDOW = NO # Use this tag to change the font size of LaTeX formulas included as images in # the HTML documentation. When you change the font size after a successful # doxygen run you need to manually remove any form_*.png images from the HTML # output directory to force them to be regenerated. # Minimum value: 8, maximum value: 50, default value: 10. # This tag requires that the tag GENERATE_HTML is set to YES. FORMULA_FONTSIZE = 10 # Use the FORMULA_TRANPARENT tag to determine whether or not the images # generated for formulas are transparent PNGs. Transparent PNGs are not # supported properly for IE 6.0, but are supported on all modern browsers. # # Note that when changing this option you need to delete any form_*.png files in # the HTML output directory before the changes have effect. # The default value is: YES. # This tag requires that the tag GENERATE_HTML is set to YES. FORMULA_TRANSPARENT = YES # Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see # http://www.mathjax.org) which uses client side Javascript for the rendering # instead of using pre-rendered bitmaps. Use this if you do not have LaTeX # installed or if you want to formulas look prettier in the HTML output. When # enabled you may also need to install MathJax separately and configure the path # to it using the MATHJAX_RELPATH option. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. USE_MATHJAX = NO # When MathJax is enabled you can set the default output format to be used for # the MathJax output. See the MathJax site (see: # http://docs.mathjax.org/en/latest/output.html) for more details. # Possible values are: HTML-CSS (which is slower, but has the best # compatibility), NativeMML (i.e. MathML) and SVG. # The default value is: HTML-CSS. # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_FORMAT = HTML-CSS # When MathJax is enabled you need to specify the location relative to the HTML # output directory using the MATHJAX_RELPATH option. The destination directory # should contain the MathJax.js script. For instance, if the mathjax directory # is located at the same level as the HTML output directory, then # MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax # Content Delivery Network so you can quickly see the result without installing # MathJax. However, it is strongly recommended to install a local copy of # MathJax from http://www.mathjax.org before deployment. # The default value is: http://cdn.mathjax.org/mathjax/latest. # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest # The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax # extension names that should be enabled during MathJax rendering. For example # MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_EXTENSIONS = # The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces # of code that will be used on startup of the MathJax code. See the MathJax site # (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an # example see the documentation. # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_CODEFILE = # When the SEARCHENGINE tag is enabled doxygen will generate a search box for # the HTML output. The underlying search engine uses javascript and DHTML and # should work on any modern browser. Note that when using HTML help # (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET) # there is already a search function so this one should typically be disabled. # For large projects the javascript based search engine can be slow, then # enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to # search using the keyboard; to jump to the search box use + S # (what the is depends on the OS and browser, but it is typically # , /