1
1
#! /usr/bin/env bash
2
2
3
- die () { printf " $@ " >&2 ; exit 1; }
3
+ warn () { printf " $@ " >&2 ; }
4
+ die () { warn " $@ " ; exit 1; }
4
5
if [[ $# != 1 ]]; then die ' Usage: %s <zipfile>\n' " $0 " ; fi
6
+ xxd -p < /dev/null || die ' Missing xxd command\n'
7
+
8
+ case $( openssl version -v) in
9
+ " OpenSSL 3.5" .* ) : ;;
10
+ * ) die ' Unsupported OpenSSL version\n' ;;
11
+ esac
12
+
13
+ set -o pipefail
14
+ shopt -s nullglob
5
15
6
16
tmp=$( mktemp -t -d)
7
17
trap ' e=$?; rm -rf ${tmp}; exit $e' EXIT HUP INT TERM
8
18
unzip -qq -j -d " $tmp " " $1 " || die ' Error unzipping %s\n' " $1 "
9
19
10
20
ptext=" ${tmp} /plaintext"
11
21
printf " Attack at dawn\n" > " $ptext "
12
- sigfile=" ${tmp} /sig.dat"
22
+
23
+ check_keys () {
24
+ local oid=$1
25
+ local -a pubs
26
+ if [[ $# -lt 2 ]]; then warn ' Usage: check_keys <oid> <form> ...\n' ; return 1; fi
27
+ shift
28
+
29
+ for form in " $@ "
30
+ do
31
+ case $form in
32
+ priv|ee|ta) set -- " $tmp " /* -" ${oid} _${form} .der" ;;
33
+ ss|ciphertext) set -- " $tmp " /* -" ${oid} _${form} .bin" ;;
34
+ pubs) set -- pubs;;
35
+ * ) set -- " $tmp " /* -" ${oid} _${form} _priv.der" ;;
36
+ esac
37
+ if [[ $# -eq 0 ]]; then continue ; fi
38
+ if [[ $# -ne 1 ]]; then
39
+ warn ' Too many inputs match %s for %s\n' \
40
+ " $form " " ${oid} "
41
+ continue
42
+ fi
43
+ obj=$1
44
+ pubout=" $tmp /${oid} _${form} _pub.der"
45
+ /bin/rm -f " $pubout "
46
+ case $form in
47
+ ss) ss_file=$obj ;;
48
+ ciphertext) ct_file=$obj ;;
49
+ pubs)
50
+ if [[ " ${# pubs[@]} " -gt 1 ]]; then
51
+ uniq=$( for dgst in " ${pubs[@]} " ; do printf " %s\n" " $dgst " ; done | sort -u | wc -l) &&
52
+ [[ $uniq -eq 1 ]] &&
53
+ printf " %s,%s,%s\n" " ${oid} " " consistent" " Y" ||
54
+ printf " %s,%s,%s\n" " ${oid} " " consistent" " N"
55
+ fi ;;
56
+ ta) openssl x509 -in " $obj " -pubkey -noout |
57
+ openssl pkey -pubin -pubout -outform DER -out " $pubout " &&
58
+ openssl verify -verify_depth 0 -trusted " $obj " " $obj " > /dev/null &&
59
+ ta_file=" $obj " &&
60
+ dgst=$( openssl dgst -sha256 -binary < " $pubout " | xxd -p -c32) &&
61
+ pubs=(" ${pubs[@]} " " $dgst " ) &&
62
+ printf " %s,%s,%s\n" " ${oid} " " cert" " Y" ||
63
+ printf " %s,%s,%s\n" " ${oid} " " cert" " N" ;;
64
+ ee) openssl x509 -in " $obj " -pubkey -noout |
65
+ openssl pkey -pubin -pubout -outform DER -out " $pubout " &&
66
+ openssl verify -verify_depth 0 -trusted " $ta_file " " $obj " > /dev/null &&
67
+ dgst=$( openssl dgst -sha256 -binary < " $pubout " | xxd -p -c32) &&
68
+ pubs=(" ${pubs[@]} " " $dgst " ) &&
69
+ printf " %s,%s,%s\n" " ${oid} " " cert" " Y" ||
70
+ printf " %s,%s,%s\n" " ${oid} " " cert" " N" ;;
71
+ * ) openssl pkey -in " $obj " -pubout -outform DER -out " $pubout " &&
72
+ if [[ -n " $sigfile " ]]; then
73
+ openssl pkeyutl -sign -rawin -inkey " $obj " -in " $ptext " -out " $sigfile " &&
74
+ openssl pkeyutl -verify -rawin -in " $ptext " -pubin -inkey " $pubout " \
75
+ -sigfile " $sigfile " > /dev/null
76
+ elif [[ -n " $ct_file " && -n " $ss_file " ]]; then
77
+ cmp -s " $ss_file " <(
78
+ openssl pkeyutl -decap -inkey " $obj " -in " $ct_file " -secret /dev/stdout)
79
+ fi &&
80
+ dgst=$( openssl dgst -sha256 -binary < " $pubout " | xxd -p -c32) &&
81
+ pubs=(" ${pubs[@]} " " $dgst " ) &&
82
+ printf " %s,%s,%s\n" " ${oid} " " $form " " Y" ||
83
+ printf " %s,%s,%s\n" " ${oid} " " $form " " N"
84
+ ;;
85
+ esac
86
+ done
87
+ }
13
88
14
89
mldsa_oids=(2.16.840.1.101.3.4.3.{17,18,19})
15
90
mlkem_oids=(2.16.840.1.101.3.4.4.{1,2,3})
@@ -19,185 +94,24 @@ slh3s_oids=(2.16.840.1.101.3.4.3.{26,28,30})
19
94
slh3f_oids=(2.16.840.1.101.3.4.3.{27,29,31})
20
95
while [[ ${# mldsa_oids[@]} -gt 0 ]]
21
96
do
22
- #
23
- # ML-DSA
24
- #
25
- (
26
- set -e
27
- set -o pipefail
28
- shopt -s nullglob
29
- pubs=()
30
- set -- " $tmp " /* -" ${mldsa_oids[0]} " _* .der
31
- if [[ $# -eq 0 ]]; then exit 2; fi
32
- for form in seed expandedkey both ta
33
- do
34
- pubout=" $tmp /${mldsa_oids[0]} _${form} _pub.der"
35
- /bin/rm -f " $pubout "
36
- count=0
37
- for obj in " $tmp " /* -" ${mldsa_oids[0]} _${form} " * .der
38
- do
39
- if [[ $count > 0 ]]; then
40
- die ' Too many inputs match %s for %s\n'
41
- " $form " " ${mldsa_oids[0]} "
42
- fi
43
- case $form in
44
- ta) openssl x509 -in " $obj " -pubkey -noout |
45
- openssl pkey -pubin -pubout -outform DER -out " $pubout "
46
- openssl verify -verify_depth 0 -trusted " $obj " " $obj " > /dev/null
47
- ;;
48
- * ) openssl pkey -in " $obj " -pubout -outform DER -out " $pubout "
49
- openssl pkeyutl -sign -rawin -inkey " $obj " -in " $ptext " -out " $sigfile "
50
- openssl pkeyutl -verify -rawin -in " $ptext " -pubin -inkey " $pubout " \
51
- -sigfile " $sigfile " > /dev/null ||
52
- die ' Signature verification failed for %s %s\n' \
53
- " $form " " ${mldsa_oids[0]} "
54
- ;;
55
- esac
56
- dgst=$( openssl dgst -sha256 -binary < " $pubout " | xxd -p -c32)
57
- pubs=(" ${pubs[@]} " " $dgst " )
58
- count=$(( count + 1 ))
59
- done
60
- if [[ $count -ne 1 ]]; then
61
- die ' Missing key form %s for %s\n' \
62
- " $form " " ${mldsa_oids[0]} "
63
- fi
64
- done
65
- uniq=$( for dgst in " ${pubs[@]} " ; do printf " %s\n" " $dgst " ; done | sort -u | wc -l)
66
- if [[ $uniq -ne 1 ]]; then
67
- die ' Multiple distinct pubkeys for %s\n' \
68
- " ${mldsa_oids[0]} "
69
- fi
70
- )
71
- case $? in
72
- 0) printf " %s,%s\n" " ${mldsa_oids[0]} " " Y" ;;
73
- 1) printf " %s,%s\n" " ${mldsa_oids[0]} " " N" ;;
74
- * ) : ignored ;;
75
- esac
97
+ ta_file=
98
+ ss_file=
99
+ ct_file=
100
+ sigfile=" ${tmp} /sig.dat"
76
101
77
- #
78
- # SLH-DSA
79
- #
80
- for oid in \
81
- " ${slh2f_oids[0]} " " ${slh2s_oids[0]} " \
82
- " ${slh3f_oids[0]} " " ${slh3s_oids[0]} "
83
- do
84
- (
85
- set -e
86
- set -o pipefail
87
- shopt -s nullglob
88
- count=0
89
- for obj in " $tmp " /* -" ${oid} _ta.der"
90
- do
91
- if [[ $count > 0 ]]; then
92
- die ' Too many inputs for %s\n' " ${oid} "
93
- fi
94
- openssl verify -verify_depth 0 -trusted " $obj " " $obj " > /dev/null
95
- count=$(( count + 1 ))
96
- done
97
- if [[ $count -eq 0 ]]; then exit 2; fi
98
- )
99
- case $? in
100
- 0) printf " %s,%s\n" " ${oid} " " Y" ;;
101
- 1) printf " %s,%s\n" " ${oid} " " N" ;;
102
- * ) : ignored ;;
103
- esac
104
- done
102
+ for oid in " ${slh2f_oids[0]} " " ${slh2s_oids[0]} " \
103
+ " ${slh3f_oids[0]} " " ${slh3s_oids[0]} "
104
+ do check_keys " $oid " priv ta pubs; done
105
105
106
- #
107
- # ML-KEM
108
- #
109
- (
110
- set -e
111
- set -o pipefail
112
- shopt -s nullglob
113
- set -- " $tmp " /* -" ${mlkem_oids[0]} " _* .der
114
- if [[ $# -eq 0 ]]; then exit 2; fi
115
- count=0; for ta in " $tmp " /* -" ${mldsa_oids[0]} _ta.der"
116
- do
117
- if [[ $count > 0 ]]; then
118
- die ' Too many TA files for %s\n' \
119
- " ${mldsa_oids[0]} "
120
- fi
121
- count=$(( count + 1 ))
122
- done
123
- count=0; for ct in " $tmp " /* -" ${mlkem_oids[0]} _ciphertext.bin"
124
- do
125
- if [[ $count > 0 ]]; then
126
- die ' Too many ciphertext files for %s\n' \
127
- " ${mlkem_oids[0]} "
128
- fi
129
- count=$(( count + 1 ))
130
- done
131
- if [[ $count -ne 1 ]]; then
132
- die ' No ciphertext file for %s\n' \
133
- " ${mlkem_oids[0]} "
134
- fi
135
- count=0; for ss in " $tmp " /* -" ${mlkem_oids[0]} _ss.bin"
136
- do
137
- if [[ $count > 0 ]]; then
138
- die ' Too many shared secret files for %s\n' \
139
- " ${mlkem_oids[0]} "
140
- fi
141
- count=$(( count + 1 ))
142
- done
143
- if [[ $count -ne 1 ]]; then
144
- die ' No shared secret file for %s\n' \
145
- " ${mlkem_oids[0]} "
146
- fi
147
- pubs=()
148
- for form in seed expandedkey both ee
149
- do
150
- pubout=" $tmp /${mlkem_oids[0]} _${form} _pub.der"
151
- /bin/rm -f " $pubout "
152
- count=0; for obj in " $tmp " /* -" ${mlkem_oids[0]} _${form} " * .der
153
- do
154
- if [[ $count > 0 ]]; then
155
- die ' Too many inputs match %s for %s\n' \
156
- " $form " " ${mlkem_oids[0]} "
157
- fi
158
- case $form in
159
- ee) openssl x509 -in " $obj " -pubkey -noout |
160
- openssl pkey -pubin -pubout -outform DER -out " $pubout "
161
- openssl verify -verify_depth 0 -trusted " $ta " " $obj " > /dev/null
162
- ;;
163
- * ) openssl pkey -in " $obj " -pubout -outform DER -out " $pubout "
164
- cmp -s " $ss " <(
165
- openssl pkeyutl -decap -inkey " $obj " -in " $ct " -secret /dev/stdout) ||
166
- die ' Shared secret mismatch for %s of %s\n' \
167
- " $form " " ${mlkem_names[0]} "
168
- ;;
169
- esac
170
- dgst=$( openssl dgst -sha256 -binary < " $pubout " | xxd -p -c32)
171
- pubs=(" ${pubs[@]} " " $dgst " )
172
- count=$(( count + 1 ))
173
- done
174
- if [[ $count -ne 1 ]]; then
175
- die ' Missing key form %s for %s\n' \
176
- " $form " " ${mlkem_oids[0]} "
177
- fi
178
- done
179
- uniq=$( for dgst in " ${pubs[@]} " ; do printf " %s\n" " $dgst " ; done | sort -u | wc -l)
180
- if [[ $uniq -ne 1 ]]; then
181
- die ' Multiple distinct pubkeys for %s\n' \
182
- " ${mlkem_oids[0]} "
183
- fi
184
- )
185
- case $? in
186
- 0) printf " %s,%s\n" " ${mldsa_oids[0]} " " Y" ;;
187
- 1) printf " %s,%s\n" " ${mldsa_oids[0]} " " N" ;;
188
- * ) : ignored ;;
189
- esac
106
+ # Must run just before ML-KEM to set correct ta_file
107
+ check_keys " ${mldsa_oids[0]} " seed expandedkey both ta pubs
108
+ sigfile=
109
+ check_keys " ${mlkem_oids[0]} " ss ciphertext seed expandedkey both ee pubs
190
110
191
- unset " mldsa_oids[0]"
192
- unset " mlkem_oids[0]"
193
- unset " slh2f_oids[0]"
194
- unset " slh2s_oids[0]"
195
- unset " slh3f_oids[0]"
196
- unset " slh3s_oids[0]"
197
- mldsa_oids=( " ${mldsa_oids[@]} " )
198
- mlkem_oids=( " ${mlkem_oids[@]} " )
199
- slh2f_oids=( " ${slh2f_oids[@]} " )
200
- slh2s_oids=( " ${slh2s_oids[@]} " )
201
- slh3f_oids=( " ${slh3f_oids[@]} " )
202
- slh3s_oids=( " ${slh3s_oids[@]} " )
111
+ unset " mldsa_oids[0]" ; mldsa_oids=(" ${mldsa_oids[@]} " )
112
+ unset " mlkem_oids[0]" ; mlkem_oids=(" ${mlkem_oids[@]} " )
113
+ unset " slh2f_oids[0]" ; slh2f_oids=(" ${slh2f_oids[@]} " )
114
+ unset " slh2s_oids[0]" ; slh2s_oids=(" ${slh2s_oids[@]} " )
115
+ unset " slh3f_oids[0]" ; slh3f_oids=(" ${slh3f_oids[@]} " )
116
+ unset " slh3s_oids[0]" ; slh3s_oids=(" ${slh3s_oids[@]} " )
203
117
done
0 commit comments