#!/usr/bin/env bash # pem.test # Copyright wolfSSL 2023-2023 tmp_file=./pem_test.$$ tmp_der_file=./pem_test_out_der.$$ tmp_pem_file=./pem_test_out_pem.$$ PEM_EXE=./examples/pem/pem ASN1_EXE=./examples/asn1/asn1 TEST_CNT=0 TEST_PASS_CNT=0 TEST_SKIP_CNT=0 TEST_FAIL_CNT=0 TEST_FAIL= TEST_CASES=() RUN_ALL="YES" CR=$'\n' ENC_STRING="encrypt" DER_TO_PEM_STRING="input is DER and output is PEM" # Check for pem example usability - can't test without it. if ! "$PEM_EXE" --help >/dev/null 2>&1; then echo "$PEM_EXE not found -- skipping pem.test." exit 77 fi # Check for asn1 example usability - can't test without it. if ! "$ASN1_EXE" --help >/dev/null 2>&1; then echo "$ASN1_EXE not found -- skipping pem.test." exit 77 fi SRC_DIR="$(dirname "$0")/.." if [ ! -d "${SRC_DIR}/certs" ]; then echo "certs not found at ${SRC_DIR}/certs -- skipping pem.test." exit 77 fi if grep -q -E '^#define HAVE_FIPS$' wolfssl/options.h; then HAVE_FIPS=1 fi if ! grep -q -E '^#define NO_DES3$' wolfssl/options.h; then HAVE_DES3=1 fi if ! grep -q -E '^#define NO_SHA$' wolfssl/options.h; then HAVE_SHA=1 fi if ! grep -q -E '^#define NO_MD5$' wolfssl/options.h; then HAVE_MD5=1 fi if grep -q -E '^#define WC_RC2$' wolfssl/options.h; then HAVE_RC2=1 fi if ! grep -q -E '^#define NO_RC4$' wolfssl/options.h; then HAVE_RC4=1 fi if ! grep -q -E '^#define NO_RSA$' wolfssl/options.h; then HAVE_RSA=1 fi if ! grep -q -E '^#define NO_DH$' wolfssl/options.h; then HAVE_DH=1 fi if ! grep -q -E '^#define NO_DSA$' wolfssl/options.h; then HAVE_DSA=1 fi if grep -q -E '^#define HAVE_ECC$' wolfssl/options.h; then HAVE_ECC=1 fi if grep -q -E '^#define HAVE_ED25519$' wolfssl/options.h; then HAVE_ED25519=1 fi if grep -q -E '^#define HAVE_ED448$' wolfssl/options.h; then HAVE_ED448=1 fi if grep -q -E '^#define WOLFSSL_CERT_REQ$' wolfssl/options.h; then WOLFSSL_CERT_REQ=1 fi if grep -q -E '^#define WOLFSSL_KEY_GEN$' wolfssl/options.h; then WOLFSSL_KEY_GEN=1 fi if grep -q -E '^#define WOLFSSL_CERT_GEN$' wolfssl/options.h; then WOLFSSL_CERT_GEN=1 fi if grep -q -E '^#define OPENSSL_EXTRA$' wolfssl/options.h; then OPENSSL_EXTRA=1 fi if [ "$WOLFSSL_KEY_GEN" != 1 ] && [ "$WOLFSSL_CERT_GEN" != 1 ] && [ "$OPENSSL_EXTRA" != 1 ]; then WOLFSSL_NO_DER_TO_PEM=1 fi if grep -q -E '^#define WOLFSSL_NO_PEM$' wolfssl/options.h; then WOLFSSL_NO_PEM=1 fi if grep -q -E '^#define NO_CODING$' wolfssl/options.h; then NO_CODING=1 fi if [ "$WOLFSSL_NO_PEM" = 1 ]; then echo "WOLFSSL_NO_PEM is configured -- skipping pem.test." exit 77 fi if [ "$NO_CODING" = 1 ]; then echo "NO_CODING is configured -- skipping pem.test." exit 77 fi # Cleanup temporaries created during testing. do_cleanup() { echo echo "in cleanup" if [ -e "$tmp_der_file" ]; then echo -e "removing existing temporary DER output file $tmp_der_file" rm "$tmp_der_file" fi if [ -e "$tmp_pem_file" ]; then echo -e "removing existing temporary PEM output file $tmp_pem_file" rm "$tmp_pem_file" fi if [ -e "$tmp_file" ]; then echo -e "removing existing temporary output file $tmp_file" rm "$tmp_file" fi } # Called when a signal is trapped. do_trap() { echo echo "got trap" do_cleanup exit 1 } # Trap keyboard interrupt and termination signal. trap do_trap INT TERM # Check the usage text for a string to determine feature support. # # @param [in] $1 String to search for, # @return 1 when string is found. # @return 0 otherwise. check_usage_string() { $PEM_EXE -? | grep "$1" >$tmp_file 2>&1 if [ "$?" = "0" ]; then return 1 fi return 0 } # Check whether the test case is to be run. # When command line parameters given - only run those. # # @return 1 when test case is to be run. # @return 0 otherwise. check_run() { # When RUN_ALL set them all test cases are run. if [ "$RUN_ALL" != "" ]; then return 1 else # Check if test case number in list. for T in "${TEST_CASE[@]}"; do if [ "$T" = "$TEST_CNT" ]; then return 1 fi done return 0 fi } # Setup for new test case. # # @param [in] $* Name of test case. test_setup() { TEST_CNT=$((TEST_CNT+1)) TEST_DESC="$TEST_CNT: $*" FAILED= SKIP= if [ "$USAGE_STRING" != "" ]; then # Check usage output for string to see whether we have to skip test case # due to wolfSSL missing features. check_usage_string "$USAGE_STRING" if [ "$?" = "0" ] ; then echo echo "$TEST_DESC" echo "SKIPPED" SKIP="missing feature" fi USAGE_STRING= fi if [ "$SKIP" = "" ]; then # Check whether this test case is to be run. check_run if [ "$?" = "1" ]; then echo echo "$TEST_DESC" TEST_PASS_CNT=$((TEST_PASS_CNT+1)) else SKIP="not requested" fi fi # Handle skipping if [ "$SKIP" != "" ]; then TEST_SKIP_CNT=$((TEST_SKIP_CNT+1)) fi } # Handle when a test case failed. test_fail() { if [ "$SKIP" = "" -a "$FAILED" = "" ]; then TEST_PASS_CNT=$((TEST_PASS_CNT-1)) TEST_FAIL_CNT=$((TEST_FAIL_CNT+1)) TEST_FAIL="$TEST_FAIL$CR $TEST_DESC" FAILED=yes fi } # Use asn1 to check DER produced is valid. check_der() { $ASN1_EXE $tmp_der_file >$tmp_file 2>&1 local ret=$? if [ "$ret" != "0" ]; then echo echo " DER result bad" test_fail return $ret fi } # Convert PEM file to DER # # @param [in] $* Command line parameters to pem example. convert_to_der() { if [ "$SKIP" = "" -a "$FAILED" = "" ]; then echo " $PEM_EXE $* -out $tmp_pem_file" $PEM_EXE "$@" -out $tmp_der_file local ret=$? if [ "$ret" != "0" ]; then echo " Failed to convert to DER" test_fail return $ret fi check_der fi } # Compare generated DER file to existing file. # # @param [in] $1 File to compare to. compare_der() { diff $tmp_der_file $1 if [ "$?" != "0" ]; then echo " Created DER file different from expected" test_fail fi } # Convert DER file to PEM # # PEM_TYPE contains PEM header to encode. # # @param [in] $* Command line parameters to pem example. convert_to_pem() { if [ "$WOLFSSL_NO_DER_TO_PEM" = 1 ]; then echo ' Skipping -- WOLFSSL_NO_DER_TO_PEM' TEST_SKIP_CNT=$((TEST_SKIP_CNT+1)) TEST_PASS_CNT=$((TEST_PASS_CNT-1)) return 0 fi if [ "$SKIP" = "" -a "$FAILED" = "" ]; then echo " $PEM_EXE --der -t \"$PEM_TYPE\" $* -out $tmp_pem_file" $PEM_EXE --der "$@" -t "$PEM_TYPE" -out $tmp_pem_file local ret=$? if [ "$ret" != "0" ]; then test_fail fi return $ret fi } # Compare generated PEM file to existing file. compare_pem() { diff $tmp_pem_file $1 >$tmp_file 2>&1 if [ "$?" != "0" ]; then cat $tmp_file echo echo " Created PEM file different from expected" test_fail fi } # Convert to and from PEM and DER and compare to file containing expected DER. # # @param [in] $1 Name of PEM file to read. # @param [in] $2 Name of DER file to compare to. # @param [in] $3 PEM type expected in PEM file and to place in created PEM # file. pem_der_exp() { if [ "$WOLFSSL_NO_DER_TO_PEM" = 1 ]; then echo ' Skipping -- WOLFSSL_NO_DER_TO_PEM' TEST_SKIP_CNT=$((TEST_SKIP_CNT+1)) TEST_PASS_CNT=$((TEST_PASS_CNT-1)) return 0 fi if [ "$SKIP" = "" -a "$FAILED" = "" ]; then PEM_FILE=$1 DER_FILE=$2 PEM_TYPE="$3" # Convert PEM to DER convert_to_der -in $PEM_FILE if [ "$FAILED" = "" ]; then # On success, compare to DER file. compare_der $DER_FILE fi # Check if converting from DER to PEM is supported. check_usage_string $DER_TO_PEM_STRING if [ "$?" = "1" ]; then if [ "$FAILED" = "" ]; then # Convert expected DER file to PEM convert_to_pem -in $DER_FILE fi if [ "$FAILED" = "" ]; then # On success, compare to original PEM file. compare_pem $PEM_FILE fi fi fi } # Convert DER to encrypted PEM. # # @param [in] $@ Command line parameters to pem example when encrypting. der_pem_enc() { if [ "$WOLFSSL_NO_DER_TO_PEM" = 1 ]; then echo ' Skipping -- WOLFSSL_NO_DER_TO_PEM' TEST_SKIP_CNT=$((TEST_SKIP_CNT+1)) TEST_PASS_CNT=$((TEST_PASS_CNT-1)) return 0 fi PEM_TYPE="ENCRYPTED PRIVATE KEY" convert_to_pem -in "${SRC_DIR}/certs/server-key.der" -p yassl123 "$@" || return $? convert_to_der -in $tmp_pem_file -p yassl123 || return $? } ################################################################################ # Check the available features compiled into pem example. echo "wolfSSL features:" check_usage_string $DER_TO_PEM_STRING if [ "$?" = "1" ]; then echo " Conversion from DER to PEM support compiled in." else echo " Conversion from DER to PEM support NOT compiled in." fi check_usage_string $ENC_STRING if [ "$?" = "1" ]; then echo " Encryption support compiled in." else echo " Encryption support NOT compiled in." fi echo # Command line parameters are test cases to run. while [ $# -gt 0 ]; do TEST_CASE[${#TEST_CASE[@]}]=$1 RUN_ALL= shift 1 done test_setup "Convert PEM certificate (first of many) to DER" convert_to_der -in "${SRC_DIR}/certs/server-cert.pem" test_setup "Convert PEM certificate (second of many) to DER" convert_to_der -in "${SRC_DIR}/certs/server-cert.pem" --offset 6000 if [ "$HAVE_RSA" = 1 ]; then test_setup "RSA private key" pem_der_exp "${SRC_DIR}/certs/server-key.pem" \ "${SRC_DIR}/certs/server-key.der" "RSA PRIVATE KEY" else echo -e '\nSkipping RSA test' TEST_CNT=$((TEST_CNT+1)) TEST_SKIP_CNT=$((TEST_SKIP_CNT+1)) fi # failing 20260417: # # test_setup "RSA public key" # pem_der_exp "${SRC_DIR}/certs/server-keyPub.pem" \ # "${SRC_DIR}/certs/server-keyPub.der" "RSA PUBLIC KEY" if [ "$HAVE_DH" = 1 ]; then test_setup "DH parameters" pem_der_exp "${SRC_DIR}/certs/dh3072.pem" \ "${SRC_DIR}/certs/dh3072.der" "DH PARAMETERS" test_setup "X9.42 parameters" pem_der_exp "${SRC_DIR}/certs/x942dh2048.pem" \ "${SRC_DIR}/certs/x942dh2048.der" "X9.42 DH PARAMETERS" else echo -e '\nSkipping DH tests' TEST_CNT=$((TEST_CNT+2)) TEST_SKIP_CNT=$((TEST_SKIP_CNT+2)) fi if [ "$HAVE_DSA" = 1 ]; then USAGE_STRING=" DSA PARAMETERS" test_setup "DSA parameters" pem_der_exp "${SRC_DIR}/certs/dsaparams.pem" \ "${SRC_DIR}/certs/dsaparams.der" "DSA PARAMETERS" USAGE_STRING=" DSA PRIVATE KEY" test_setup "DSA private key" pem_der_exp "${SRC_DIR}/certs/1024/dsa1024.pem" \ "${SRC_DIR}/certs/1024/dsa1024.der" "DSA PRIVATE KEY" else echo -e '\nSkipping DSA tests' TEST_CNT=$((TEST_CNT+2)) TEST_SKIP_CNT=$((TEST_SKIP_CNT+2)) fi if [ "$HAVE_ECC" = 1 ]; then USAGE_STRING=" EC PRIVATE KEY" test_setup "ECC private key" pem_der_exp "${SRC_DIR}/certs/ecc-keyPkcs8.pem" \ "${SRC_DIR}/certs/ecc-keyPkcs8.der" "PRIVATE KEY" USAGE_STRING=" EC PRIVATE KEY" test_setup "EC PRIVATE KEY" pem_der_exp "${SRC_DIR}/certs/ecc-privkey.pem" \ "${SRC_DIR}/certs/ecc-privkey.der" "EC PRIVATE KEY" USAGE_STRING=" EC PARAMETERS" test_setup "ECC parameters" pem_der_exp "${SRC_DIR}/certs/ecc-params.pem" \ "${SRC_DIR}/certs/ecc-params.der" "EC PARAMETERS" test_setup "ECC public key" pem_der_exp "${SRC_DIR}/certs/ecc-keyPub.pem" \ "${SRC_DIR}/certs/ecc-keyPub.der" "PUBLIC KEY" else echo -e '\nSkipping ECC tests' TEST_CNT=$((TEST_CNT+4)) TEST_SKIP_CNT=$((TEST_SKIP_CNT+4)) fi if [ "$HAVE_ED25519" = 1 ]; then test_setup "Ed25519 public key" pem_der_exp "${SRC_DIR}/certs/ed25519/client-ed25519-key.pem" \ "${SRC_DIR}/certs/ed25519/client-ed25519-key.der" 'PUBLIC KEY' test_setup "Ed25519 private key" pem_der_exp "${SRC_DIR}/certs/ed25519/client-ed25519-priv.pem" \ "${SRC_DIR}/certs/ed25519/client-ed25519-priv.der" 'PRIVATE KEY' USAGE_STRING=" EDDSA PRIVATE KEY" test_setup "EdDSA private key" pem_der_exp "${SRC_DIR}/certs/ed25519/eddsa-ed25519.pem" \ "${SRC_DIR}/certs/ed25519/eddsa-ed25519.der" 'EDDSA PRIVATE KEY' else echo -e '\nSkipping ED25519 tests' TEST_CNT=$((TEST_CNT+3)) TEST_SKIP_CNT=$((TEST_SKIP_CNT+3)) fi if [ "$HAVE_ED448" = 1 ]; then test_setup "Ed448 public key" pem_der_exp "${SRC_DIR}/certs/ed448/client-ed448-key.pem" \ "${SRC_DIR}/certs/ed448/client-ed448-key.der" 'PUBLIC KEY' test_setup "Ed448 private key" pem_der_exp "${SRC_DIR}/certs/ed448/client-ed448-priv.pem" \ "${SRC_DIR}/certs/ed448/client-ed448-priv.der" 'PRIVATE KEY' else echo -e '\nSkipping ED448 tests' TEST_CNT=$((TEST_CNT+2)) TEST_SKIP_CNT=$((TEST_SKIP_CNT+2)) fi if [ "$WOLFSSL_CERT_REQ" = 1 ]; then USAGE_STRING=" CERTIFICATE REQUEST" test_setup "Certificate Request" pem_der_exp "${SRC_DIR}/certs/csr.dsa.pem" \ "${SRC_DIR}/certs/csr.dsa.der" 'CERTIFICATE REQUEST' else echo -e '\nSkipping certificate request test' TEST_CNT=$((TEST_CNT+1)) TEST_SKIP_CNT=$((TEST_SKIP_CNT+1)) fi # failing 20260417: # # USAGE_STRING=" X509 CRL" # test_setup "X509 CRL" # pem_der_exp "${SRC_DIR}/certs/crl/caEccCrl.pem" \ # "${SRC_DIR}/certs/crl/caEccCrl.der" 'X509 CRL' if [ "$HAVE_FIPS" != 1 ] && [ "$HAVE_DES3" = 1 ]; then if [ "$HAVE_RSA" = 1 ]; then USAGE_STRING=$ENC_STRING test_setup "Encrypted Key with header" convert_to_der -in "${SRC_DIR}/certs/server-keyEnc.pem" -p yassl123 --padding else echo -e '\nSkipping DES && RSA test' TEST_CNT=$((TEST_CNT+1)) TEST_SKIP_CNT=$((TEST_SKIP_CNT+1)) fi if [ "$HAVE_MD5" = 1 ] && [ "$HAVE_RSA" = 1 ]; then USAGE_STRING=$ENC_STRING test_setup "Encrypted Key - PKCS#8" convert_to_der -in "${SRC_DIR}/certs/server-keyPkcs8Enc.pem" -p yassl123 USAGE_STRING=$ENC_STRING test_setup "Encrypted Key - PKCS#8 (PKCS#12 PBE)" convert_to_der -in "${SRC_DIR}/certs/server-keyPkcs8Enc12.pem" -p yassl123 else echo -e '\nSkipping DES && MD5 && RSA tests' TEST_CNT=$((TEST_CNT+2)) TEST_SKIP_CNT=$((TEST_SKIP_CNT+2)) fi if [ "$HAVE_MD5" = 1 ]; then USAGE_STRING="PBES1_MD5_DES" test_setup "Encrypted Key - PKCS#8 (PKCS#5 PBES1-MD5-DES)" convert_to_der -in "${SRC_DIR}/certs/ecc-keyPkcs8Enc.pem" -p yassl123 else echo -e '\nSkipping DES && MD5 test' TEST_CNT=$((TEST_CNT+1)) TEST_SKIP_CNT=$((TEST_SKIP_CNT+1)) fi if [ "$HAVE_SHA" = 1 ]; then USAGE_STRING=" DES3" test_setup "Encrypted Key - PKCS#8 (PKCS#5v2 PBE-SHA1-DES3)" convert_to_der -in "${SRC_DIR}/certs/server-keyPkcs8Enc2.pem" -p yassl123 else echo -e '\nSkipping DES && SHA-1 test' TEST_CNT=$((TEST_CNT+1)) TEST_SKIP_CNT=$((TEST_SKIP_CNT+1)) fi else echo -e '\nSkipping DES tests' TEST_CNT=$((TEST_CNT+5)) TEST_SKIP_CNT=$((TEST_SKIP_CNT+5)) fi # failing 20260417: # # USAGE_STRING="AES-256-CBC" # PEM_TYPE="ENCRYPTED PRIVATE KEY" # test_setup "Encrypt Key - PKCS#8 (Default: PKCS#5 PBES2 AES-256-CBC)" # der_pem_enc # # USAGE_STRING="AES-256-CBC" # PEM_TYPE="ENCRYPTED PRIVATE KEY" # test_setup "Encrypt Key - PKCS#8 - Large salt" # der_pem_enc -s 16 # # USAGE_STRING="AES-256-CBC" # PEM_TYPE="ENCRYPTED PRIVATE KEY" # test_setup "Encrypt Key - PKCS#8 - 10000 iterations (DER encoding check)" # der_pem_enc -i 10000 # # USAGE_STRING="AES-256-CBC" # PEM_TYPE="ENCRYPTED PRIVATE KEY" # test_setup "Encrypt Key - PKCS#8 - 100 iterations (DER encoding check)" # der_pem_enc -i 100 # # USAGE_STRING="AES-128-CBC" # PEM_TYPE="ENCRYPTED PRIVATE KEY" # test_setup "Encrypt Key - PKCS#8 (PKCS#5 PBES2 AES-128-CBC)" # der_pem_enc --pbe-alg AES-128-CBC # # USAGE_STRING="DES" # PEM_TYPE="ENCRYPTED PRIVATE KEY" # test_setup "Encrypt Key - PKCS#8 (PKCS#5 PBES2 DES)" # der_pem_enc --pbe-alg DES # # USAGE_STRING="DES3" # PEM_TYPE="ENCRYPTED PRIVATE KEY" # test_setup "Encrypt Key - PKCS#8 (PKCS#5 PBES2 DES3)" # der_pem_enc --pbe-alg DES3 if [ "$HAVE_FIPS" != 1 ]; then if [ "$HAVE_DES3" = 1 ] && [ "$HAVE_MD5" = 1 ]; then USAGE_STRING="PBES1_MD5_DES" PEM_TYPE="ENCRYPTED PRIVATE KEY" test_setup "Encrypt Key - PKCS#8 (PKCS#5 PBES1-MD5-DES)" der_pem_enc --pbe PBES1_MD5_DES else echo -e '\nSkipping DES && MD5 DER-to-PEM test' TEST_CNT=$((TEST_CNT+1)) TEST_SKIP_CNT=$((TEST_SKIP_CNT+1)) fi if [ "$HAVE_DES3" = 1 ] && [ "$HAVE_SHA" = 1 ]; then USAGE_STRING="PBES1_SHA1_DES" PEM_TYPE="ENCRYPTED PRIVATE KEY" test_setup "Encrypt Key - PKCS#8 (PKCS#5 PBES1-SHA1-DES)" der_pem_enc --pbe PBES1_SHA1_DES USAGE_STRING=" SHA1_DES3" PEM_TYPE="ENCRYPTED PRIVATE KEY" test_setup "Encrypt Key - PKCS#8 (PKCS#12 PBE-SHA1-DES3)" der_pem_enc --pbe-ver PKCS12 --pbe SHA1_DES3 else echo -e '\nSkipping DES && SHA-1 DER-to-PEM tests' TEST_CNT=$((TEST_CNT+2)) TEST_SKIP_CNT=$((TEST_SKIP_CNT+2)) fi if [ "$HAVE_RC4" = 1 ] && [ "$HAVE_SHA" = 1 ]; then USAGE_STRING=" SHA1_RC4_128" PEM_TYPE="ENCRYPTED PRIVATE KEY" test_setup "Encrypt Key - PKCS#8 (PKCS#12 PBE-SHA1-RC4-128)" der_pem_enc --pbe-ver PKCS12 --pbe SHA1_RC4_128 else echo -e '\nSkipping RC4 && SHA-1 DER-to-PEM test' TEST_CNT=$((TEST_CNT+1)) TEST_SKIP_CNT=$((TEST_SKIP_CNT+1)) fi if [ "$HAVE_RC2" = 1 ] && [ "$HAVE_SHA" = 1 ]; then USAGE_STRING="SHA1_40RC2_CBC" PEM_TYPE="ENCRYPTED PRIVATE KEY" test_setup "Encrypt Key - PKCS#8 (PKCS#12 PBE-SHA1-40RC2-CBC)" der_pem_enc --pbe-ver PKCS12 --pbe SHA1_40RC2_CBC else echo -e '\nSkipping RC2 && SHA-1 DER-to-PEM test' TEST_CNT=$((TEST_CNT+1)) TEST_SKIP_CNT=$((TEST_SKIP_CNT+1)) fi else echo -e '\nSkipping DES/RC4/RC2 DER-to-PEM tests' TEST_CNT=$((TEST_CNT+5)) TEST_SKIP_CNT=$((TEST_SKIP_CNT+5)) fi # Note: PKCS#12 with SHA1_DES doesn't work as we encode as PKCS#5 SHA1_DES as # ids are the same # Report results echo if [ "$TEST_SKIP_CNT" = "0" ]; then echo "RESULT: $TEST_PASS_CNT/$TEST_FAIL_CNT/$TEST_CNT (pass/fail/total)" else echo "RESULT: $TEST_PASS_CNT/$TEST_SKIP_CNT/$TEST_FAIL_CNT/$TEST_CNT (pass/skip/fail/total)" fi if [ "$TEST_FAIL_CNT" != "0" ]; then echo "FAILURES ($TEST_FAIL_CNT):$TEST_FAIL" else echo "PASSED" fi # Cleanup temporaries do_cleanup if [ "$TEST_FAIL_CNT" = "0" ]; then exit 0 else exit 1 fi