tree checksum vpatch file split hunks
all signers: bvt diana_coman asciilifeform
antecedents: ffa_ch20b_litmus_legacy_hashes.kv
press order:
patch:
(20 . 3)(20 . 4)
5 578827 ffa_ch19_peh_tuning_and_demos "Peh Tuning and Demo Tapes."
6 611618 ffa_ch20_litmus "A Peh-powered verifier for traditional GPG signatures."
7 611775 ffa_ch20b_litmus_legacy_hashes "Support for certain ancient hash algos in Litmus."
8 612395 ffa_ch20c_litmus_clearsigned "Support for 'clearsigned' GPG texts in Litmus."
- E53145647493DD0343293F522C93FE9668147DD05B5AD4C3AF763856126ED03BD6A53C51ED76CEB233678EB480E73175ADA59AF4A71A0D3DA4FBC32392F2C5BD(5 . 8)(5 . 9)
13 # #
14 # Usage: ./litmus.sh publickey.peh signature.sig datafile #
15 # #
16 # Currently, supports only RSA 'detached' sigs made with the following #
17 # hashes: SHA1 (warns: known-breakable!), SHA224, SHA256, SHA384, SHA512. #
18 # Currently, supports RSA 'clearsigned' and 'detached' sigs made with the #
19 # following hashes: #
20 # SHA1 (warns: known-breakable!), SHA224, SHA256, SHA384, SHA512. #
21 # #
22 # See instructions re: converting traditional GPG public keys for use with #
23 # this program. #
(27 . 8)(28 . 8)
25 ############################################################################
26
27 # External programs that are required (if not found, will eggog) :
28 EXTERNALS="peh xxd hexdump base64 shasum cut tr sed wc grep printf"
29
30 EXTERNALS="peh xxd hexdump base64 shasum cut tr sed wc grep printf
31 mktemp awk truncate"
32
33 # Return Codes:
34
(75 . 6)(76 . 12)
36 exit $RET_EGGOG
37 }
38
39 # Malformed 'clearsigned' text file:
40 eggog_broken_clearsigned() {
41 echo "$SIGFILE does not contain a clearsigned PGP message!" >&2
42 exit $RET_EGGOG
43 }
44
45 # Failure from bad Peh :
46 eggog_peh() {
47 echo "EGGOG in executing Peh tape! Please check Public Key." >&2
(87 . 31)(94 . 59)
49 }
50
51
52 # Number of Arguments required by this program:
53 REQD_ARGS=3
54 # First argument is always the given public key file (a Peh tape, see docs)
55 PUBFILE=$1
56
57 # The given Detached GPG Signature file to be verified.
58 # In 'clearsigned' mode, contains both signature and payload to be verified.
59 SIGFILE=$2
60
61 # If invalid arg count, print usage and abort:
62 if [ "$#" -ne $REQD_ARGS ]; then
63 echo "Usage: $0 publickey.peh signature.sig datafile"
64 exit $RET_EGGOG
65 fi
66 # Get total number of arguments on command line:
67 ARGCOUNT="$#"
68
69 # On exit (if in 'clearsign' mode) :
70 remove_temp_file() {
71 rm -f $DATAFILE
72 }
73
74 # Whether we are working on a 'clearsigned text'
75 CLEARSIGN_MODE=false
76
77 # Set up in the selected mode:
78 case $ARGCOUNT in
79 2) # If given two arguments, verify a 'clearsigned' text file:
80 CLEARSIGN_MODE=true
81 # The processed payload will end up in a temporary file:
82 DATAFILE=$(mktemp) || { echo "Failed to create temp file!" >&2; \
83 exit $RET_EGGOG; }
84 # On exit, if in 'clearsign' mode, remove temporary file with payload:
85 trap remove_temp_file EXIT
86 # Expect 'Canonical Text Signature' in GPG sig packet turd
87 expect_sig_class=1
88 ;;
89 3) # Verify Detached Signature on given Data File (third argument is path):
90 # The given Data file to be verified against the Signature
91 DATAFILE=$3 # i.e. path given on command line
92 # Expect 'Detached Binary Signature' in GPG sig packet turd
93 expect_sig_class=0
94 ;;
95 *) # If invalid arg count -- print usage and abort:
96 echo "Usage: $0 publickey.peh signature.sig datafile"
97 echo " or: $0 publickey.peh clearsigned.txt"
98 exit $RET_EGGOG
99 ;;
100 esac
101
102
103 # Minimal Peh Width (used for non-arithmetical ops, e.g. 'Owner')
104 MIN_PEH_WIDTH=256
105
106 # Peh data stack height for public key operations
107 PEH_HEIGHT=3
108
109 # Peh RNG (NOT USED in verifications, but needed to silence warning)
110 PEH_RNG_DEV="/dev/random"
111
112 # The given public key file (a Peh tape, see docs)
113 PUBFILE=$1
114
115 # The given Detached GPG Signature file to be verified
116 SIGFILE=$2
117
118 # The given Data file to be verified against the Signature
119 DATAFILE=$3
120
121 # Verify that each of the given input files exists:
122 FILES=($PUBFILE $SIGFILE $DATAFILE)
123 for f in ${FILES[@]}; do
(185 . 7)(220 . 7)
125 for i in $EXTERNALS
126 do
127 command -v $i >/dev/null && continue || \
128 { echo "$i is required but was not found! Please install it."; \
129 { echo "$i is required but was not found! Please install it." >&2 ; \
130 exit $RET_EGGOG; }
131 done
132
(233 . 6)(268 . 54)
134 eggog_sig_armour
135 fi
136
137 # If we are operating on a 'clearsigned' text file, $DATAFILE will be
138 # an empty temporary file, and the payload is to be extracted to it,
139 # with certain munges (see http://tools.ietf.org/html/rfc4880#section-7.1)
140 if [ $CLEARSIGN_MODE == true ]
141 then
142 # Find position of 'clearsign' payload start marker:
143 CLEAR_MARKER="\-\-\-\-\-BEGIN PGP SIGNED MESSAGE\-\-\-\-\-"
144 start_clr=$(grep -m 1 -n "$CLEAR_MARKER" $SIGFILE | cut -d ':' -f1)
145
146 # If payload start marker was not found:
147 if [ "$start_clr" == "" ]
148 then
149 eggog_broken_clearsigned
150 fi
151
152 # Discard the start marker:
153 start_clr=$(($start_clr + 1))
154
155 # The payload ends with the line preceding the sig start:
156 end_clr=$((start_ln - 2))
157
158 # Find any 'Hash:' headers:
159 start_body=$(tail -n "+$start_clr" $SIGFILE | \
160 grep -v -n -m 1 "^Hash:" | cut -d ':' -f1)
161
162 # Skip the above headers and mandatory empty line:
163 start_clr=$(($start_clr + $start_body))
164
165 # If there is no payload, or the markers are misplaced, abort:
166 if [ $start_clr -ge $end_clr ]
167 then
168 eggog_broken_clearsigned
169 fi
170
171 # Extract the 'clearsign' payload to the temporary file:
172 cat $SIGFILE | sed -n "$start_clr,$end_clr p" | \
173 sed 's/[ \t]*$//; s/^- //' | \
174 awk '{printf("%s\r\n",$0)}' \
175 > $DATAFILE
176
177 # Remove the trailing CR,LF ending:
178 truncate -s -2 $DATAFILE
179
180 # After this, proceed exactly like with 'detached' sigs, but
181 # with the expected 'class' being 1 rather than 0.
182 fi
183
184
185 # Number of bytes in the sig file
186 sig_len=${#sig_bytes[@]}
187
(300 . 11)(383 . 12)
189 sig_version=$r
190 sig_field_mandatory "Version" $sig_version 04
191
192 # Class (only class 0 is supported)
193 # Class (must be 'detached' or 'clearsign')
194 get_sig_bytes 1
195 turd+=$r
196 hex_to_int
197 sig_class=$r
198 sig_field_mandatory "Class" $sig_class 00
199 sig_field_mandatory "Class" $sig_class $expect_sig_class
200
201 # Public Key Algo (only RSA is supported)
202 get_sig_bytes 1
(485 . 7)(569 . 7)
204 tape=".$rsa_sig@Public-Op!.$pkcs={[Valid]QY}{[Invalid]QN}_"
205
206 # Execute the tape:
207 run_peh_tape $tape $rsa_width 3
208 run_peh_tape $tape $rsa_width $PEH_HEIGHT
209
210 # 'Belt and suspenders' -- test both output and return code:
211 # If verification succeeded, return code will be 1, and output 'Valid':