make various test CA certs RFC 5280 compliant w.r.t. X509 extensions
[openssl.git] / test / certs / mkcert.sh
1 #! /bin/bash
2 #
3 # Copyright 2016-2020 The OpenSSL Project Authors. All Rights Reserved.
4 # Copyright (c) 2016 Viktor Dukhovni <openssl-users@dukhovni.org>.
5 # All rights reserved.
6 #
7 # Licensed under the Apache License 2.0 (the "License").  You may not use
8 # this file except in compliance with the License.  You can obtain a copy
9 # in the file LICENSE in the source distribution or at
10 # https://www.openssl.org/source/license.html
11
12 # This file is dual-licensed and is also available under other terms.
13 # Please contact the author.
14
15 # 100 years should be enough for now
16 if [ -z "$DAYS" ]; then
17     DAYS=36525
18 fi
19
20 if [ -z "$OPENSSL_SIGALG" ]; then
21     OPENSSL_SIGALG=sha256
22 fi
23
24 if [ -z "$REQMASK" ]; then
25     REQMASK=utf8only
26 fi
27
28 stderr_onerror() {
29     (
30         err=$("$@" >&3 2>&1) || {
31             printf "%s\n" "$err" >&2
32             exit 1
33         }
34     ) 3>&1
35 }
36
37 key() {
38     local key=$1; shift
39
40     local alg=rsa
41     if [ -n "$OPENSSL_KEYALG" ]; then
42         alg=$OPENSSL_KEYALG
43     fi
44
45     local bits=2048
46     if [ -n "$OPENSSL_KEYBITS" ]; then
47         bits=$OPENSSL_KEYBITS
48     fi
49
50     if [ ! -f "${key}.pem" ]; then
51         args=(-algorithm "$alg")
52         case $alg in
53         rsa) args=("${args[@]}" -pkeyopt rsa_keygen_bits:$bits );;
54         ec)  args=("${args[@]}" -pkeyopt "ec_paramgen_curve:$bits")
55                args=("${args[@]}" -pkeyopt ec_param_enc:named_curve);;
56         dsa)  args=(-paramfile "$bits");;
57         ed25519)  ;;
58         ed448)  ;;
59         *) printf "Unsupported key algorithm: %s\n" "$alg" >&2; return 1;;
60         esac
61         stderr_onerror \
62             openssl genpkey "${args[@]}" -out "${key}.pem"
63     fi
64 }
65
66 # Usage: $0 req keyname dn1 dn2 ...
67 req() {
68     local key=$1; shift
69
70     key "$key"
71     local errs
72
73     stderr_onerror \
74         openssl req -new -"${OPENSSL_SIGALG}" -key "${key}.pem" \
75             -config <(printf "string_mask=%s\n[req]\n%s\n%s\n[dn]\n" \
76               "$REQMASK" "prompt = no" "distinguished_name = dn"
77                       for dn in "$@"; do echo "$dn"; done)
78 }
79
80 req_nocn() {
81     local key=$1; shift
82
83     key "$key"
84     stderr_onerror \
85         openssl req -new -"${OPENSSL_SIGALG}" -subj / -key "${key}.pem" \
86             -config <(printf "[req]\n%s\n[dn]\nCN_default =\n" \
87                       "distinguished_name = dn")
88 }
89
90 cert() {
91     local cert=$1; shift
92     local exts=$1; shift
93
94     stderr_onerror \
95         openssl x509 -req -"${OPENSSL_SIGALG}" -out "${cert}.pem" \
96             -extfile <(printf "%s\n" "$exts") "$@"
97 }
98
99 genroot() {
100     local cn=$1; shift
101     local key=$1; shift
102     local cert=$1; shift
103     local bcon="basicConstraints = critical,CA:true"
104     local ku="keyUsage = keyCertSign,cRLSign"
105     local skid="subjectKeyIdentifier = hash"
106     local akid="authorityKeyIdentifier = keyid"
107
108     exts=$(printf "%s\n%s\n%s\n" "$bcon" "$ku" "$skid" "$akid")
109     for eku in "$@"
110     do
111         exts=$(printf "%s\nextendedKeyUsage = %s\n" "$exts" "$eku")
112     done
113     csr=$(req "$key" "CN = $cn") || return 1
114     echo "$csr" |
115        cert "$cert" "$exts" -signkey "${key}.pem" -set_serial 1 -days "${DAYS}"
116 }
117
118 genca() {
119     local cn=$1; shift
120     local key=$1; shift
121     local cert=$1; shift
122     local cakey=$1; shift
123     local cacert=$1; shift
124     local bcon="basicConstraints = critical,CA:true"
125     local ku="keyUsage = keyCertSign,cRLSign"
126     local skid="subjectKeyIdentifier = hash"
127     local akid="authorityKeyIdentifier = keyid"
128
129     exts=$(printf "%s\n%s\n%s\n" "$bcon" "$ku" "$skid" "$akid")
130     for eku in "$@"
131     do
132         exts=$(printf "%s\nextendedKeyUsage = %s\n" "$exts" "$eku")
133     done
134     if [ -n "$NC" ]; then
135         exts=$(printf "%s\nnameConstraints = %s\n" "$exts" "$NC")
136     fi
137     csr=$(req "$key" "CN = $cn") || return 1
138     echo "$csr" |
139         cert "$cert" "$exts" -CA "${cacert}.pem" -CAkey "${cakey}.pem" \
140             -set_serial 2 -days "${DAYS}"
141 }
142
143 gen_nonbc_ca() {
144     local cn=$1; shift
145     local key=$1; shift
146     local cert=$1; shift
147     local cakey=$1; shift
148     local cacert=$1; shift
149     local skid="subjectKeyIdentifier = hash"
150     local akid="authorityKeyIdentifier = keyid"
151
152     exts=$(printf "%s\n%s\n%s\n" "$skid" "$akid")
153     exts=$(printf "%s\nkeyUsage = %s\n" "$exts" "keyCertSign, cRLSign")
154     for eku in "$@"
155     do
156         exts=$(printf "%s\nextendedKeyUsage = %s\n" "$exts" "$eku")
157     done
158     csr=$(req "$key" "CN = $cn") || return 1
159     echo "$csr" |
160         cert "$cert" "$exts" -CA "${cacert}.pem" -CAkey "${cakey}.pem" \
161             -set_serial 2 -days "${DAYS}"
162 }
163
164 # Usage: $0 genpc keyname certname eekeyname eecertname pcext1 pcext2 ...
165 #
166 # Note: takes csr on stdin, so must be used with $0 req like this:
167 #
168 # $0 req keyname dn | $0 genpc keyname certname eekeyname eecertname pcext ...
169 genpc() {
170     local key=$1; shift
171     local cert=$1; shift
172     local cakey=$1; shift
173     local ca=$1; shift
174
175     exts=$(printf "%s\n%s\n%s\n%s\n" \
176             "subjectKeyIdentifier = hash" \
177             "authorityKeyIdentifier = keyid, issuer:always" \
178             "basicConstraints = CA:false" \
179             "proxyCertInfo = critical, @pcexts";
180            echo "[pcexts]";
181            for x in "$@"; do echo $x; done)
182     cert "$cert" "$exts" -CA "${ca}.pem" -CAkey "${cakey}.pem" \
183          -set_serial 2 -days "${DAYS}"
184 }
185
186 # Usage: $0 geneealt keyname certname eekeyname eecertname alt1 alt2 ...
187 #
188 # Note: takes csr on stdin, so must be used with $0 req like this:
189 #
190 # $0 req keyname dn | $0 geneealt keyname certname eekeyname eecertname alt ...
191 geneealt() {
192     local key=$1; shift
193     local cert=$1; shift
194     local cakey=$1; shift
195     local ca=$1; shift
196
197     exts=$(printf "%s\n%s\n%s\n%s\n" \
198             "subjectKeyIdentifier = hash" \
199             "authorityKeyIdentifier = keyid" \
200             "basicConstraints = CA:false" \
201             "subjectAltName = @alts";
202            echo "[alts]";
203            for x in "$@"; do echo $x; done)
204     cert "$cert" "$exts" -CA "${ca}.pem" -CAkey "${cakey}.pem" \
205          -set_serial 2 -days "${DAYS}"
206 }
207
208 genee() {
209     local OPTIND=1
210     local purpose=serverAuth
211
212     while getopts p: o
213     do
214         case $o in
215         p) purpose="$OPTARG";;
216         *) echo "Usage: $0 genee [-p EKU] cn keyname certname cakeyname cacertname" >&2
217            return 1;;
218         esac
219     done
220
221     shift $((OPTIND - 1))
222     local cn=$1; shift
223     local key=$1; shift
224     local cert=$1; shift
225     local cakey=$1; shift
226     local ca=$1; shift
227
228     exts=$(printf "%s\n%s\n%s\n%s\n%s\n[alts]\n%s\n" \
229             "subjectKeyIdentifier = hash" \
230             "authorityKeyIdentifier = keyid, issuer" \
231             "basicConstraints = CA:false" \
232             "extendedKeyUsage = $purpose" \
233             "subjectAltName = @alts" "DNS=${cn}")
234     csr=$(req "$key" "CN = $cn") || return 1
235     echo "$csr" |
236         cert "$cert" "$exts" -CA "${ca}.pem" -CAkey "${cakey}.pem" \
237             -set_serial 2 -days "${DAYS}" "$@"
238 }
239
240 geneeextra() {
241     local OPTIND=1
242     local purpose=serverAuth
243
244     while getopts p: o
245     do
246         case $o in
247         p) purpose="$OPTARG";;
248         *) echo "Usage: $0 geneeextra [-p EKU] cn keyname certname cakeyname cacertname extraext" >&2
249            return 1;;
250         esac
251     done
252
253     shift $((OPTIND - 1))
254     local cn=$1; shift
255     local key=$1; shift
256     local cert=$1; shift
257     local cakey=$1; shift
258     local ca=$1; shift
259     local extraext=$1; shift
260
261     exts=$(printf "%s\n%s\n%s\n%s\n%s\n%s\n[alts]\n%s\n" \
262             "subjectKeyIdentifier = hash" \
263             "authorityKeyIdentifier = keyid, issuer" \
264             "basicConstraints = CA:false" \
265             "extendedKeyUsage = $purpose" \
266             "subjectAltName = @alts"\
267             "$extraext" "DNS=${cn}")
268     csr=$(req "$key" "CN = $cn") || return 1
269     echo "$csr" |
270         cert "$cert" "$exts" -CA "${ca}.pem" -CAkey "${cakey}.pem" \
271             -set_serial 2 -days "${DAYS}" "$@"
272 }
273
274 geneenocsr() {
275     local OPTIND=1
276     local purpose=serverAuth
277
278     while getopts p: o
279     do
280         case $o in
281         p) purpose="$OPTARG";;
282         *) echo "Usage: $0 geneenocsr [-p EKU] cn certname cakeyname cacertname" >&2
283            return 1;;
284         esac
285     done
286
287     shift $((OPTIND - 1))
288     local cn=$1; shift
289     local cert=$1; shift
290     local cakey=$1; shift
291     local ca=$1; shift
292
293     exts=$(printf "%s\n%s\n%s\n%s\n%s\n[alts]\n%s\n" \
294             "subjectKeyIdentifier = hash" \
295             "authorityKeyIdentifier = keyid, issuer" \
296             "basicConstraints = CA:false" \
297             "extendedKeyUsage = $purpose" \
298             "subjectAltName = @alts" "DNS=${cn}")
299         cert "$cert" "$exts" -CA "${ca}.pem" -CAkey "${cakey}.pem" \
300             -set_serial 2 -days "${DAYS}" "$@"
301 }
302
303 genss() {
304     local cn=$1; shift
305     local key=$1; shift
306     local cert=$1; shift
307
308     exts=$(printf "%s\n%s\n%s\n%s\n%s\n[alts]\n%s\n" \
309             "subjectKeyIdentifier   = hash" \
310             "authorityKeyIdentifier = keyid, issuer" \
311             "basicConstraints = CA:false" \
312             "extendedKeyUsage = serverAuth" \
313             "subjectAltName = @alts" "DNS=${cn}")
314     csr=$(req "$key" "CN = $cn") || return 1
315     echo "$csr" |
316         cert "$cert" "$exts" -signkey "${key}.pem" \
317             -set_serial 1 -days "${DAYS}" "$@"
318 }
319
320 gennocn() {
321     local key=$1; shift
322     local cert=$1; shift
323
324     csr=$(req_nocn "$key") || return 1
325     echo "$csr" |
326         cert "$cert" "" -signkey "${key}.pem" -set_serial 1 -days -1 "$@"
327 }
328
329 genct() {
330     local OPTIND=1
331     local purpose=serverAuth
332
333     while getopts p: o
334     do
335         case $o in
336         p) purpose="$OPTARG";;
337         *) echo "Usage: $0 genct [-p EKU] cn keyname certname cakeyname cacertname ctlogkey" >&2
338            return 1;;
339         esac
340     done
341
342     shift $((OPTIND - 1))
343     local cn=$1; shift
344     local key=$1; shift
345     local cert=$1; shift
346     local cakey=$1; shift
347     local ca=$1; shift
348     local logkey=$1; shift
349
350     exts=$(printf "%s\n%s\n%s\n%s\n%s\n%s\n[alts]\n%s\n" \
351             "subjectKeyIdentifier = hash" \
352             "authorityKeyIdentifier = keyid, issuer" \
353             "basicConstraints = CA:false" \
354             "extendedKeyUsage = $purpose" \
355             "1.3.6.1.4.1.11129.2.4.3 = critical,ASN1:NULL"\
356             "subjectAltName = @alts" "DNS=${cn}")
357     csr=$(req "$key" "CN = $cn") || return 1
358     echo "$csr" |
359         cert "$cert" "$exts" -CA "${ca}.pem" -CAkey "${cakey}.pem" \
360             -set_serial 2 -days "${DAYS}" "$@"
361     cat ${cert}.pem ${ca}.pem > ${cert}-chain.pem
362     go run github.com/google/certificate-transparency-go/ctutil/sctgen \
363        --log_private_key ${logkey}.pem \
364        --timestamp="2020-01-01T00:00:00Z" \
365        --cert_chain ${cert}-chain.pem \
366        --tls_out ${cert}.tlssct
367     rm ${cert}-chain.pem
368     filesize=$(wc -c <${cert}.tlssct)
369     exts=$(printf "%s\n%s\n%s\n%s\n%s%04X%04X%s\n%s\n[alts]\n%s\n" \
370             "subjectKeyIdentifier = hash" \
371             "authorityKeyIdentifier = keyid, issuer" \
372             "basicConstraints = CA:false" \
373             "extendedKeyUsage = $purpose" \
374             "1.3.6.1.4.1.11129.2.4.2 = ASN1:FORMAT:HEX,OCT:" $((filesize+2)) $filesize `xxd -p ${cert}.tlssct | tr -d '\n'` \
375             "subjectAltName = @alts" "DNS=${cn}")
376     echo "$csr" |
377         cert "$cert" "$exts" -CA "${ca}.pem" -CAkey "${cakey}.pem" \
378             -set_serial 2 -days "${DAYS}" "$@"
379 }
380
381 "$@"