diff -uNr a/ffa/MANIFEST.TXT b/ffa/MANIFEST.TXT --- a/ffa/MANIFEST.TXT fc1bdea6ee6bf8bb8c53a2012690cf585f482216a44fc7e0aaad542064a9f1b0c9f6f060cb539dda8b54759544a7f12aa87ac46121628a02eb3a43711741cb17 +++ b/ffa/MANIFEST.TXT e4fa89865bad0ea9b29e23b5ebb420afac679f375eb6d093a1118c7018d70709071117b4656bb9a7f817353b22ad8e668a89763c74e399ae7fc38ca70aad9f34 @@ -24,3 +24,4 @@ 612828 ffa_ch20d_litmus_nested_fix "Fix for bug where nested 'clearsigned' sigs were rejected." 629424 ffa_ch21a_bis_fix_ch15_gcd "Fix for lethal flaw in Ch.15's Greatest Common Divisor." 659788 ffa_ch21a_ter_ch14_ch20_errata "Fix for false alarm in Ch.14; Removal of two mutually-canceling bugs in Litmus." + 837101 ffa_litmus_width_fix_and_posix "Support for short signatures in Litmus and POSIX compatibility." diff -uNr a/ffa/contrib/litmus/litmus.sh b/ffa/contrib/litmus/litmus.sh --- a/ffa/contrib/litmus/litmus.sh f0d41124d72a3b364f70ea8dd1f9a434230f9ba965c89c3c48dd78071d7ac59c68ba407ef4818f326339bce5a3261c5ba10b8de8612e7c0778513b928e681988 +++ b/ffa/contrib/litmus/litmus.sh c5f8ace09860fa82446b4d3201c71975f5d2726881f1caaa6c5b9e763f11e91551eac60a5f759ece2b89609d2d4e87ab5faee0b74c88db687e20afa76975676c @@ -40,7 +40,7 @@ RET_BAD_SIG=1 # All Other Cases: -RET_EGGOG=-1 +RET_EGGOG=255 # Verify that all of the necessary external programs in fact exist: for i in $EXTERNALS @@ -155,8 +155,9 @@ PEH_RNG_DEV="/dev/random" # Verify that each of the given input files exists: -FILES=($PUBFILE $SIGFILE $DATAFILE) -for f in ${FILES[@]}; do +FILES="$PUBFILE $SIGFILE $DATAFILE" +for f in $FILES +do if ! [ -f $f ]; then echo "$f does not exist!" >&2 exit $RET_EGGOG @@ -195,7 +196,7 @@ peh_life=$(($tape_len * 2)) # Execute the tape: - peh_res=$((cat $PUBFILE; echo $tape) | \ + peh_res=$(echo $tape | cat $PUBFILE - | \ peh $peh_width $peh_height $tape_len $peh_life $PEH_RNG_DEV); peh_code=$? @@ -232,7 +233,7 @@ end_ln=$(grep -m 1 -n "$END_MARKER" $SIGFILE | cut -d ':' -f1) # Both start and end markers must exist : -if [ "$start_ln" == "" ] || [ "$end_ln" == "" ] +if [ "$start_ln" = "" ] || [ "$end_ln" = "" ] then echo "$SIGFILE does not contain ASCII-armoured PGP Signature!" >&2 exit $RET_EGGOG @@ -259,7 +260,7 @@ fi # Obtain the sig bytes: -sig_bytes=($(echo $sig_payload | base64 -d | hexdump -ve '1/1 "%.2x "')) +sig_bytes=$(echo $sig_payload | base64 -d | hexdump -ve '1/1 "%.2x "') # If eggog -- abort: if [ $? -ne 0 ] @@ -270,14 +271,14 @@ # If we are operating on a 'clearsigned' text file, $DATAFILE will be # an empty temporary file, and the payload is to be extracted to it, # with certain munges (see http://tools.ietf.org/html/rfc4880#section-7.1) -if [ $CLEARSIGN_MODE == true ] +if [ $CLEARSIGN_MODE = true ] then # Find position of 'clearsign' payload start marker: CLEAR_MARKER="^\-\-\-\-\-BEGIN PGP SIGNED MESSAGE\-\-\-\-\-" start_clr=$(grep -m 1 -n "$CLEAR_MARKER" $SIGFILE | cut -d ':' -f1) # If payload start marker was not found: - if [ "$start_clr" == "" ] + if [ "$start_clr" = "" ] then eggog_broken_clearsigned fi @@ -316,7 +317,7 @@ # Number of bytes in the sig file -sig_len=${#sig_bytes[@]} +sig_len=$(echo $sig_bytes | wc -w) # Test that certain fields in the Sig have their mandatory value @@ -342,7 +343,8 @@ count=$1 # Result: $count bytes from current $sig_pos (contiguous hex string) - r=$(echo ${sig_bytes[@]:$sig_pos:$count} | sed "s/ //g" | tr 'a-z' 'A-Z') + r=$(echo $sig_bytes | cut -d\ -f$(($sig_pos + 1))-$(($sig_pos + $count)) \ + | sed "s/ //g" | tr 'a-z' 'A-Z') # Advance $sig_pos by $count: sig_pos=$(($sig_pos + $count)) @@ -357,7 +359,7 @@ # Convert the current sig component to integer hex_to_int() { - r=$((16#$r)) + r=$((0x$r)) } # Turd to be composed of certain values from the sig, per RFC4880. @@ -378,26 +380,26 @@ # Version (only Version 4 -- what GPG 1.4.x outputs -- is supported) get_sig_bytes 1 -turd+=$r +turd="${turd}${r}" sig_version=$r sig_field_mandatory "Version" $sig_version 04 # Class (must be 'detached' or 'clearsign') get_sig_bytes 1 -turd+=$r +turd="${turd}${r}" hex_to_int sig_class=$r sig_field_mandatory "Class" $sig_class $expect_sig_class # Public Key Algo (only RSA is supported) get_sig_bytes 1 -turd+=$r +turd="${turd}${r}" sig_pk_algo=$r sig_field_mandatory "Public Key Algo" $sig_pk_algo 01 # Digest Algo (only certain hash algos are supported) get_sig_bytes 1 -turd+=$r +turd="${turd}${r}" hex_to_int sig_digest_algo=$r @@ -461,13 +463,13 @@ # Hashed Section Length get_sig_bytes 2 -turd+=$r +turd="${turd}${r}" hex_to_int sig_hashed_len=$r # Hashed Section (typically: timestamp) get_sig_bytes $sig_hashed_len -turd+=$r +turd="${turd}${r}" sig_hashed=$r # Unhashed Section Length @@ -482,12 +484,10 @@ hashed_header_len=$((${#turd} / 2)) # Final section of the hashed turd (not counted in hashed_header_len) -turd+=$sig_version -turd+="FF" -turd+=$(printf "%08x" $hashed_header_len) +turd="${turd}${sig_version}FF$(printf "%08x" $hashed_header_len)" # Compute the hash of data file and the hashed appendix from sig : -hash=$((cat $DATAFILE; xxd -r -p <<< $turd) | $HASHER | cut -d ' ' -f1) +hash=$(echo $turd | xxd -r -p | cat $DATAFILE - | $HASHER | cut -d ' ' -f1) # Convert to upper case hash=$(echo $hash | tr 'a-z' 'A-Z') @@ -517,7 +517,12 @@ rsa_byteness=$((($rsa_bitness + 7) / 8)) # RSA Bitness for use in determining required Peh width: -rsa_width=$(($rsa_byteness * 8)) +rsa_width=$((rsa_bitness - 1)) +rsa_width=$((rsa_width | rsa_width >> 1)) +rsa_width=$((rsa_width | rsa_width >> 2)) +rsa_width=$((rsa_width | rsa_width >> 4)) +rsa_width=$((rsa_width | rsa_width >> 8)) +rsa_width=$((rsa_width + 1)) # Only traditional GPG RSA widths are supported: if [ $rsa_width != 2048 ] && [ $rsa_width != 4096 ] && [ $rsa_width != 8192 ] @@ -538,21 +543,23 @@ pkcs="0001" # Compute necessary number of padding FF bytes : -pkcs_pad_bytes=$(($rsa_byteness - $MD_LEN - $ASN_LEN - 3)) +pkcs_pad_bytes=$(($rsa_width / 8 - $MD_LEN - $ASN_LEN - 3)) # Attach the padding bytes: -for ((x=1; x<=$pkcs_pad_bytes; x++)); do - pkcs+="FF" +x=1 +while [ $x -le $pkcs_pad_bytes ]; do + pkcs="${pkcs}FF" + x=$((x + 1)) done # Attach the 00 separator between the padding and the ASN: -pkcs+="00" +pkcs="${pkcs}00" # Attach the ASN ('magic' corresponding to the hash algo) : -pkcs+=$ASN +pkcs="${pkcs}${ASN}" # Finally, attach the computed (from Data file) hash itself : -pkcs+=$hash +pkcs="${pkcs}${hash}" # Generate a Peh tape which will attempt to verify $rsa_sig against the pubkey, # computing the expression $rsa_sig ^ PUB_E mod PUB_M and comparing to $pkcs. @@ -564,7 +571,7 @@ # 'Belt and suspenders' -- test both output and return code: # If verification succeeded, return code will be 1, and output 'Valid': -if [ $peh_code -eq $PEH_YES ] && [ "$peh_res" == "Valid" ] +if [ $peh_code -eq $PEH_YES ] && [ "$peh_res" = "Valid" ] then # Valid RSA signature: done_sig_valid