1#!/bin/ksh
2
3#
4# Copyright (c) 2020 Joel Sing <jsing@openbsd.org>
5#
6# Permission to use, copy, modify, and distribute this software for any
7# purpose with or without fee is hereby granted, provided that the above
8# copyright notice and this permission notice appear in all copies.
9#
10# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17#
18
19set -e
20set -u
21set -x
22
23readonly SUBJECT="/CN=LibreSSL Test"
24
25readonly TMPDIR=$(mktemp -d)
26
27cleanup() {
28        rm -rf "${TMPDIR}"
29}
30
31trap cleanup EXIT INT
32
33reset() {
34	echo '100001' > ${TMPDIR}/certserial
35	cat /dev/null > ${TMPDIR}/certindex
36}
37
38setup() {
39	reset
40
41	cat > ${TMPDIR}/openssl.cnf <<EOF
42[ca]
43default_ca = test_ca
44
45[test_ca]
46new_certs_dir = ${TMPDIR}/
47database = ${TMPDIR}/certindex
48default_days = 365
49default_md = sha256
50policy = test_policy
51serial = ${TMPDIR}/certserial
52
53[test_policy]
54countryName             = optional
55stateOrProvinceName     = optional
56localityName            = optional
57organizationName        = optional
58organizationalUnitName  = optional
59commonName              = supplied
60emailAddress            = optional
61
62[v3_ca_root]
63subjectKeyIdentifier = hash
64authorityKeyIdentifier = keyid:always,issuer
65basicConstraints = critical, CA:true
66keyUsage = critical, cRLSign, keyCertSign
67
68[v3_ca_int]
69subjectKeyIdentifier = hash
70authorityKeyIdentifier = keyid:always,issuer
71basicConstraints = critical, CA:true
72keyUsage = critical, cRLSign, keyCertSign
73
74[v3_other]
75subjectKeyIdentifier = hash
76authorityKeyIdentifier = keyid:always,issuer
77basicConstraints = critical, CA:false
78keyUsage = critical, digitalSignature
79
80[req]
81distinguished_name      = req_distinguished_name
82
83[ req_distinguished_name ]
84EOF
85}
86
87create_root() {
88	local name=$1 file=$2
89
90	openssl req -new -days 3650 -nodes -newkey rsa:2048 -sha256 -x509 \
91	    -subj "${SUBJECT} ${name}" -keyout "${TMPDIR}/${file}.key" \
92	    -config ${TMPDIR}/openssl.cnf -extensions v3_ca_root \
93	    -out "${TMPDIR}/${file}.crt"
94}
95
96create_expired_root() {
97	local name=$1 file=$2
98
99	openssl req -new -days 3650 -nodes -newkey rsa:2048 -sha256 \
100	    -subj "${SUBJECT} ${name}" -keyout "${TMPDIR}/${file}.key" \
101	    -config ${TMPDIR}/openssl.cnf -extensions v3_ca_root \
102	    -out "${TMPDIR}/${file}.csr"
103	openssl ca -batch -notext -selfsign \
104	    -keyfile "${TMPDIR}/${file}.key" \
105	    -startdate 20100101000000Z -enddate 20200101000000Z \
106	    -config ${TMPDIR}/openssl.cnf -extensions v3_ca_root \
107	    -in "${TMPDIR}/${file}.csr" -out "${TMPDIR}/${file}.crt"
108}
109
110create_intermediate() {
111	local name=$1 file=$2 issuer_file=$3
112
113	openssl req -new -days 3650 -nodes -newkey rsa:2048 -sha256 \
114	    -subj "${SUBJECT} ${name}" -keyout "${TMPDIR}/${file}.key" \
115	    -out "${TMPDIR}/${file}.csr"
116	openssl x509 -req -days 3650 -CA "${TMPDIR}/${issuer_file}.crt" \
117	    -CAkey "${TMPDIR}/${issuer_file}.key" -CAcreateserial \
118	    -extfile ${TMPDIR}/openssl.cnf -extensions v3_ca_int \
119	    -in "${TMPDIR}/${file}.csr" -out "${TMPDIR}/${file}.crt"
120}
121
122create_expired_intermediate() {
123	local name=$1 file=$2 issuer_file=$3
124
125	openssl req -new -days 3650 -nodes -newkey rsa:2048 -sha256 \
126	    -subj "${SUBJECT} ${name}" -keyout "${TMPDIR}/${file}.key" \
127	    -out "${TMPDIR}/${file}.csr"
128	openssl ca -batch -notext -cert "${TMPDIR}/${issuer_file}.crt" \
129	    -keyfile "${TMPDIR}/${issuer_file}.key" \
130	    -startdate 20100101000000Z -enddate 20200101000000Z \
131	    -config ${TMPDIR}/openssl.cnf -extensions v3_ca_int \
132	    -in "${TMPDIR}/${file}.csr" -out "${TMPDIR}/${file}.crt"
133}
134
135create_leaf() {
136	local name=$1 file=$2 issuer_file=$3
137
138	openssl req -new -days 3650 -nodes -newkey rsa:2048 -sha256 \
139	    -subj "${SUBJECT} ${name}" -keyout "${TMPDIR}/${file}.key" \
140	    -out "${TMPDIR}/${file}.csr"
141	openssl x509 -req -days 3650 -CA "${TMPDIR}/${issuer_file}.crt" \
142	    -CAkey "${TMPDIR}/${issuer_file}.key" -CAcreateserial \
143	    -extfile ${TMPDIR}/openssl.cnf -extensions v3_other \
144	    -in "${TMPDIR}/${file}.csr" -out "${TMPDIR}/${file}.crt"
145}
146
147create_expired_leaf() {
148	local name=$1 file=$2 issuer_file=$3
149
150	openssl req -new -days 3650 -nodes -newkey rsa:2048 -sha256 \
151	    -subj "${SUBJECT} ${name}" -keyout "${TMPDIR}/${file}.key" \
152	    -out "${TMPDIR}/${file}.csr"
153	openssl ca -batch -notext -cert "${TMPDIR}/${issuer_file}.crt" \
154	    -keyfile "${TMPDIR}/${issuer_file}.key" \
155	    -config ${TMPDIR}/openssl.cnf -extensions v3_other \
156	    -startdate 20100101000000Z -enddate 20200101000000Z \
157	    -in "${TMPDIR}/${file}.csr" -out "${TMPDIR}/${file}.crt"
158}
159
160create_cross_signed() {
161	local file=$1 csr_file=$2 issuer_file=$3
162
163	openssl x509 -req -days 3650 -CA "${TMPDIR}/${issuer_file}.crt" \
164	    -CAkey "${TMPDIR}/${issuer_file}.key" -CAcreateserial \
165	    -extfile ${TMPDIR}/openssl.cnf -extensions v3_ca_int \
166	    -in "${TMPDIR}/${csr_file}.csr" -out "${TMPDIR}/${file}.crt"
167}
168
169create_expired_cross_signed() {
170	local file=$1 csr_file=$2 issuer_file=$3
171
172	openssl ca -batch -notext -cert "${TMPDIR}/${issuer_file}.crt" \
173	    -keyfile "${TMPDIR}/${issuer_file}.key" \
174	    -startdate 20100101000000Z -enddate 20200101000000Z \
175	    -config ${TMPDIR}/openssl.cnf -extensions v3_ca_int \
176	    -in "${TMPDIR}/${csr_file}.csr" -out "${TMPDIR}/${file}.crt"
177}
178
179create_bundle() {
180	local bundle_file=$1
181	shift
182
183	mkdir -p $(dirname ${bundle_file})
184	cat /dev/null > ${bundle_file}
185
186	for _cert_file in $@; do
187		openssl x509 -nameopt oneline -subject -issuer -noout \
188		    -in "${TMPDIR}/${_cert_file}.crt" >> ${bundle_file}
189	done
190	for _cert_file in $@; do
191		cat "${TMPDIR}/${_cert_file}.crt" >> ${bundle_file}
192	done
193}
194
195create_root_bundle() {
196	local bundle_file=$1
197	shift
198
199	mkdir -p $(dirname ${bundle_file})
200	cat /dev/null > ${bundle_file}
201
202	for _cert_file in $@; do
203		openssl x509 -nameopt oneline -subject -issuer \
204		    -in "${TMPDIR}/${_cert_file}.crt" >> ${bundle_file}
205	done
206}
207
208setup
209
210# Scenario 1a.
211reset
212create_root "Root CA 1" "ca-root"
213create_leaf "Server 1" "server-1" "ca-root"
214create_root_bundle "./1a/roots.pem" "ca-root"
215create_bundle "./1a/bundle.pem" "server-1"
216
217# Scenarios 2a and 2b.
218reset
219create_root "Root CA 1" "ca-root"
220create_intermediate "Intermediate CA 1" "ca-int-1" "ca-root"
221create_leaf "Server 1" "server-1" "ca-int-1"
222create_root_bundle "./2a/roots.pem" "ca-root"
223create_bundle "./2a/bundle.pem" "server-1" "ca-int-1"
224create_root_bundle "./2b/roots.pem" "ca-root"
225create_bundle "./2b/bundle.pem" "server-1"
226create_root_bundle "./2c/roots.pem" "ca-root"
227create_bundle "./2c/bundle.pem" "server-1" "ca-root" "ca-int-1"
228
229# Scenarios 3a, 3b, 3c, 3d and 3e.
230reset
231create_root "Root CA 1" "ca-root"
232create_intermediate "Intermediate CA 1" "ca-int-1" "ca-root"
233create_intermediate "Intermediate CA 2" "ca-int-2" "ca-int-1"
234create_intermediate "Intermediate CA 3" "ca-int-3" "ca-int-2"
235create_leaf "Server 1" "server-1" "ca-int-3"
236create_root_bundle "./3a/roots.pem" "ca-root"
237create_bundle "./3a/bundle.pem" "server-1" "ca-int-3" "ca-int-2" "ca-int-1"
238create_root_bundle "./3b/roots.pem" "ca-root"
239create_bundle "./3b/bundle.pem" "server-1" "ca-int-3" "ca-int-2"
240create_root_bundle "./3c/roots.pem" "ca-root"
241create_bundle "./3c/bundle.pem" "server-1" "ca-int-3" "ca-int-1"
242create_root_bundle "./3d/roots.pem" "ca-root"
243create_bundle "./3d/bundle.pem" "server-1" "ca-int-2" "ca-int-1"
244create_root_bundle "./3e/roots.pem" "ca-root"
245create_bundle "./3e/bundle.pem" "server-1" "ca-int-1" "ca-int-2" "ca-int-3"
246
247# Scenarios 4a, 4b, 4c, 4d, 4e, 4f, 4g and 4h.
248reset
249create_root "Root CA 1" "ca-root-1"
250create_root "Root CA 2" "ca-root-2"
251create_intermediate "Intermediate CA 1" "ca-int-1" "ca-root-1"
252create_cross_signed "ca-int-1-xs" "ca-int-1" "ca-root-2"
253create_leaf "Server 1" "server-1" "ca-int-1"
254create_root_bundle "./4a/roots.pem" "ca-root-1" "ca-root-2"
255create_bundle "./4a/bundle.pem" "server-1" "ca-int-1" "ca-int-1-xs"
256create_root_bundle "./4b/roots.pem" "ca-root-1"
257create_bundle "./4b/bundle.pem" "server-1" "ca-int-1" "ca-int-1-xs"
258create_root_bundle "./4c/roots.pem" "ca-root-2"
259create_bundle "./4c/bundle.pem" "server-1" "ca-int-1" "ca-int-1-xs"
260create_root_bundle "./4d/roots.pem" "ca-root-1" "ca-root-2"
261create_bundle "./4d/bundle.pem" "server-1" "ca-int-1"
262create_root_bundle "./4e/roots.pem" "ca-root-1" "ca-root-2"
263create_bundle "./4e/bundle.pem" "server-1" "ca-int-1-xs"
264create_root_bundle "./4f/roots.pem" "ca-root-1" "ca-root-2"
265create_bundle "./4f/bundle.pem" "server-1" "ca-int-1-xs" "ca-int-1"
266create_root_bundle "./4g/roots.pem" "ca-root-1"
267create_bundle "./4g/bundle.pem" "server-1" "ca-int-1-xs" "ca-int-1"
268create_root_bundle "./4h/roots.pem" "ca-root-2"
269create_bundle "./4h/bundle.pem" "server-1" "ca-int-1-xs" "ca-int-1"
270
271# Scenario 5a, 5b, 5c, 5d, 5e, 5f, 5g, 5h and 5i.
272reset
273create_root "Root CA 1" "ca-root-1"
274create_intermediate "Intermediate CA 1" "ca-int-1" "ca-root-1"
275create_intermediate "Intermediate CA 2" "ca-int-2" "ca-int-1"
276create_root "Root CA 2" "ca-root-2"
277create_cross_signed "ca-int-2-xs" "ca-int-2" "ca-root-2"
278create_leaf "Server 1" "server-1" "ca-int-2"
279create_root_bundle "./5a/roots.pem" "ca-root-1" "ca-root-2"
280create_bundle "./5a/bundle.pem" "server-1" "ca-int-2" "ca-int-2-xs" "ca-int-1"
281create_root_bundle "./5b/roots.pem" "ca-root-2"
282create_bundle "./5b/bundle.pem" "server-1" "ca-int-2" "ca-int-2-xs" "ca-int-1"
283create_root_bundle "./5c/roots.pem" "ca-root-1"
284create_bundle "./5c/bundle.pem" "server-1" "ca-int-2" "ca-int-2-xs" "ca-int-1"
285create_root_bundle "./5d/roots.pem" "ca-root-1" "ca-root-2"
286create_bundle "./5d/bundle.pem" "server-1" "ca-int-2-xs" "ca-int-1"
287create_root_bundle "./5e/roots.pem" "ca-root-1" "ca-root-2"
288create_bundle "./5e/bundle.pem" "server-1" "ca-int-2" "ca-int-2-xs"
289create_root_bundle "./5f/roots.pem" "ca-root-1" "ca-root-2"
290create_bundle "./5f/bundle.pem" "server-1" "ca-int-2" "ca-int-1"
291create_root_bundle "./5g/roots.pem" "ca-root-1" "ca-root-2"
292create_bundle "./5g/bundle.pem" "server-1" "ca-int-2-xs" "ca-int-2" "ca-int-1"
293create_root_bundle "./5h/roots.pem" "ca-root-2"
294create_bundle "./5h/bundle.pem" "server-1" "ca-int-2-xs" "ca-int-2" "ca-int-1"
295create_root_bundle "./5i/roots.pem" "ca-root-1"
296create_bundle "./5i/bundle.pem" "server-1" "ca-int-2-xs" "ca-int-2" "ca-int-1"
297
298# Scenarios 6a and 6b.
299reset
300create_root "Root CA 1" "ca-root-1"
301create_intermediate "Intermediate CA 1" "ca-int-1" "ca-root-1"
302create_intermediate "Intermediate CA 2" "ca-int-2" "ca-int-1"
303create_expired_root "Root CA 2" "ca-root-2"
304create_cross_signed "ca-int-2-xs" "ca-int-2" "ca-root-2"
305create_leaf "Server 1" "server-1" "ca-int-2"
306create_root_bundle "./6a/roots.pem" "ca-root-1" "ca-root-2"
307create_bundle "./6a/bundle.pem" "server-1" "ca-int-2" "ca-int-2-xs" "ca-int-1"
308create_root_bundle "./6b/roots.pem" "ca-root-1" "ca-root-2"
309create_bundle "./6b/bundle.pem" "server-1" "ca-int-2-xs" "ca-int-2" "ca-int-1"
310
311# Scenarios 7a and 7b.
312reset
313create_expired_root "Root CA 1" "ca-root-1"
314create_intermediate "Intermediate CA 1" "ca-int-1" "ca-root-1"
315create_intermediate "Intermediate CA 2" "ca-int-2" "ca-int-1"
316create_root "Root CA 2" "ca-root-2"
317create_cross_signed "ca-int-2-xs" "ca-int-2" "ca-root-2"
318create_leaf "Server 1" "server-1" "ca-int-2"
319create_root_bundle "./7a/roots.pem" "ca-root-1" "ca-root-2"
320create_bundle "./7a/bundle.pem" "server-1" "ca-int-2" "ca-int-2-xs" "ca-int-1"
321create_root_bundle "./7b/roots.pem" "ca-root-1" "ca-root-2"
322create_bundle "./7b/bundle.pem" "server-1" "ca-int-2-xs" "ca-int-2" "ca-int-1"
323
324# Scenario 8a.
325reset
326create_root "Root CA 1" "ca-root"
327create_intermediate "Intermediate CA 1" "ca-int-1" "ca-root"
328create_expired_leaf "Server 1" "server-1" "ca-int-1"
329create_root_bundle "./8a/roots.pem" "ca-root"
330create_bundle "./8a/bundle.pem" "server-1" "ca-int-1"
331
332# Scenario 9a.
333reset
334create_root "Root CA 1" "ca-root"
335create_expired_intermediate "Intermediate CA 1" "ca-int-1" "ca-root"
336create_leaf "Server 1" "server-1" "ca-int-1"
337create_root_bundle "./9a/roots.pem" "ca-root"
338create_bundle "./9a/bundle.pem" "server-1" "ca-int-1"
339
340# Scenarios 10a and 10b.
341reset
342create_root "Root CA 1" "ca-root-1"
343create_root "Root CA 2" "ca-root-2"
344create_expired_intermediate "Intermediate CA 1" "ca-int-1" "ca-root-1"
345create_cross_signed "ca-int-1-xs" "ca-int-1" "ca-root-2"
346create_leaf "Server 1" "server-1" "ca-int-1"
347create_root_bundle "./10a/roots.pem" "ca-root-1" "ca-root-2"
348create_bundle "./10a/bundle.pem" "server-1" "ca-int-1" "ca-int-1-xs"
349create_root_bundle "./10b/roots.pem" "ca-root-1" "ca-root-2"
350create_bundle "./10b/bundle.pem" "server-1" "ca-int-1-xs" "ca-int-1"
351
352# Scenarios 11a and 11b.
353reset
354create_root "Root CA 1" "ca-root-1"
355create_expired_intermediate "Intermediate CA 1" "ca-int-1" "ca-root-1"
356create_intermediate "Intermediate CA 2" "ca-int-2" "ca-int-1"
357create_root "Root CA 2" "ca-root-2"
358create_cross_signed "ca-int-2-xs" "ca-int-2" "ca-root-2"
359create_leaf "Server 1" "server-1" "ca-int-2"
360create_root_bundle "./11a/roots.pem" "ca-root-1" "ca-root-2"
361create_bundle "./11a/bundle.pem" "server-1" "ca-int-2" "ca-int-2-xs" "ca-int-1"
362create_root_bundle "./11b/roots.pem" "ca-root-1" "ca-root-2"
363create_bundle "./11b/bundle.pem" "server-1" "ca-int-2-xs" "ca-int-2" "ca-int-1"
364
365# Scenario 12a.
366reset
367create_root "Root CA 1" "ca-root-1"
368create_expired_intermediate "Intermediate CA 1" "ca-int-1" "ca-root-1"
369create_cross_signed "ca-root-2" "ca-int-1" "ca-root-1"
370create_intermediate "Intermediate CA 2" "ca-int-2" "ca-int-1"
371create_leaf "Server 1" "server-1" "ca-int-2"
372create_root_bundle "./12a/roots.pem" "ca-root-1" "ca-root-2"
373create_bundle "./12a/bundle.pem" "server-1" "ca-int-2" "ca-int-1"
374
375# Scenario 13a.
376reset
377create_root "Root CA 1" "ca-root-1"
378create_intermediate "Intermediate CA 1" "ca-int-1" "ca-root-1"
379create_expired_cross_signed "ca-root-2" "ca-int-1" "ca-root-1"
380create_intermediate "Intermediate CA 2" "ca-int-2" "ca-int-1"
381create_leaf "Server 1" "server-1" "ca-int-2"
382create_root_bundle "./13a/roots.pem" "ca-root-1" "ca-root-2"
383create_bundle "./13a/bundle.pem" "server-1" "ca-int-2" "ca-int-1"
384