]> git.proxmox.com Git - efi-boot-shim.git/blame - make-certs
Add Debian SBAT data to the shim build
[efi-boot-shim.git] / make-certs
CommitLineData
07de085d 1#!/usr/bin/env bash
6d50f87a
MG
2#
3# Generate a root CA cert for signing, and then a subject cert.
4# Usage: make-certs.sh hostname [user[@domain]] [more ...]
5# For testing only, probably still has some bugs in it.
6#
7
07de085d
BF
8set -e
9
6d50f87a
MG
10DOMAIN=xn--u4h.net
11DAYS=365
12KEYTYPE=RSA
13KEYSIZE=2048
14DIGEST=SHA256
15CRLHOURS=24
16CRLDAYS=
17
18# Cleanup temporary files at exit.
19touch openssl.cnf
20newcertdir=`mktemp -d`
21cleanup() {
22 test -f openssl.cnf && rm -f openssl.cnf
23 test -f ca.txt && rm -f ca.txt
24 test -f ocsp.txt && rm -f ocsp.txt
25 test -n "$newcertdir" && rm -fr "$newcertdir"
26}
27trap cleanup EXIT
28
29# The first argument is either a common name value or a flag indicating that
30# we're doing something other than issuing a cert.
31commonname="$1"
32refresh_crl=false
33revoke_cert=false
34ocsp_serve=false
35if test "x$commonname" = "x-refresh-crl" ; then
36 refresh_crl=true
37 commonname="$1"
38fi
39if test "x$commonname" = "x-refresh_crl" ; then
40 refresh_crl=true
41 commonname="$1"
42fi
43if test "x$commonname" = "x-revoke" ; then
44 revoke_cert=true
45 shift
46 commonname="$1"
47fi
48if test "x$commonname" = "x-ocsp" ; then
49 ocsp_serve=true
50 commonname="$1"
51fi
52if test "x$commonname" = x ; then
53 echo Usage: `basename $0` 'commonname' user'[@domain]' '[more [...]]'
54 echo Usage: `basename $0` -revoke 'commonname'
55 echo Usage: `basename $0` -ocsp
56 echo Usage: `basename $0` -refresh-crl
57 echo More:
58 echo -e \\tKey usage: "[sign|signing|encrypt|encryption|all]"
59 echo -e \\tAuthority Access Info OCSP responder: "ocsp:URI"
60 echo -e \\tCRL distribution point: "crl:URI"
61 echo -e \\tSubject Alternative Name:
62 echo -e \\t\\tHostname: "*"
63 echo -e \\t\\tIP address: w.x.y.z
64 echo -e \\t\\tEmail address: "*@*.com/edu/net/org/local"
65 echo -e \\t\\tKerberos principal name: "*@*.COM/EDU/NET/ORG/LOCAL"
66 echo -e \\tExtended key usage:
67 echo -e \\t\\t1....
68 echo -e \\t\\t2....
69 echo -e \\t\\tid-kp-server-auth \| tls-server
70 echo -e \\t\\tid-kp-client-auth \| tls-client
71 echo -e \\t\\tid-kp-email-protection \| email
72 echo -e \\t\\tid-ms-kp-sc-logon \| id-ms-sc-logon
73 echo -e \\t\\tid-pkinit-kp-client-auth \| id-pkinit-client
74 echo -e \\t\\tid-pkinit-kp-kdc \| id-pkinit-kdc
75 echo -e \\t\\tca \| CA
76 exit 1
77fi
78
79# Choose a user name part for email attributes.
80GIVENUSER=$2
81test x"$GIVENUSER" = x && GIVENUSER=$USER
82echo "$GIVENUSER" | grep -q @ || GIVENUSER="$GIVENUSER"@$DOMAIN
83DOMAIN=`echo "$GIVENUSER" | cut -f2- -d@`
84
85shift || true
86shift || true
87
88# Done already?
89done=:
90
91keygen() {
92 case "$KEYTYPE" in
93 DSA)
94 openssl dsaparam -out "$1".param $KEYSIZE
95 openssl gendsa "$1".param
96 ;;
97 RSA|*)
98 #openssl genrsa $KEYSIZE -passout pass:qweqwe
99 openssl genrsa $KEYSIZE
100 #openssl genrsa $KEYSIZE -nodes
101 ;;
102 esac
103}
104
105# Set some defaults.
106CA=FALSE
107if test -s ca.crldp.uri.txt ; then
108 crlval="`cat ca.crldp.uri.txt`"
109 crl="URI:$crlval"
110fi
111if test -s ca.ocsp.uri.txt ; then
112 aiaval="`cat ca.ocsp.uri.txt`"
113 aia="OCSP;URI:$aiaval"
114fi
115if test -s ca.domain.txt ; then
116 domval="`cat ca.domain.txt`"
117 if test -n "$domval" ; then
118 DOMAIN="$domval"
119 fi
120fi
121
122# Parse the arguments which indicate what sort of information we want.
123while test $# -gt 0 ; do
124 type=
125 value="$1"
126 case "$value" in
127 RSA|rsa)
128 KEYTYPE=RSA
129 ;;
130 DSA|dsa)
131 KEYTYPE=DSA
132 ;;
133 OCSP:*|ocsp:*)
134 aiaval=`echo "$value" | cut -f2- -d:`
135 aia="OCSP;URI:$aiaval"
136 ;;
137 CRL:*|crl:*)
138 crlval=`echo "$value" | cut -f2- -d:`
139 crl="URI:$crlval"
140 ;;
141 signing|sign)
142 keyusage="${keyusage:+${keyusage},}nonRepudiation,digitalSignature"
143 ;;
144 encryption|encrypt)
145 keyusage="${keyusage:+${keyusage},}keyEncipherment,dataEncipherment"
146 ;;
147 all)
148 keyusage="digitalSignature,nonRepudiation,keyEncipherment,dataEncipherment,keyAgreement,keyCertSign,cRLSign,encipherOnly,decipherOnly"
149 ;;
150 ca|CA)
151 CA=TRUE
152 keyusage="${keyusage:+${keyusage},}nonRepudiation,digitalSignature,keyEncipherment,dataEncipherment,keyAgreement,keyCertSign,cRLSign"
153 ;;
154 1.*|2.*|id-*|tls-*|email|mail|codesign)
155 ekuval=`echo "$value" | tr '[A-Z]' '[a-z]' | sed 's,\-,,g'`
156 case "$ekuval" in
157 idkpserverauth|tlsserver) ekuval=1.3.6.1.5.5.7.3.1;;
158 idkpclientauth|tlsclient) ekuval=1.3.6.1.5.5.7.3.2;;
159 idkpemailprotection|email|mail) ekuval=1.3.6.1.5.5.7.3.4;;
160 idkpcodesign|codesign) ekuval=1.3.6.1.5.5.7.3.3;;
161 idmskpsclogon|idmssclogon) ekuval=1.3.6.1.4.1.311.20.2.2;;
162 idpkinitkpclientauth|idpkinitclient) ekuval=1.3.6.1.5.2.3.4;;
163 idpkinitkpkdc|idpkinitkdc) ekuval=1.3.6.1.5.2.3.5;;
164 esac
165 if test -z "$eku" ; then
166 eku="$ekuval"
167 else
168 eku="$eku,$ekuval"
169 fi
170 ;;
171 *@*.COM|*@*.EDU|*@*.NET|*@*.ORG|*@*.LOCAL)
172 luser=`echo "$value" | tr '[A-Z]' '[a-z]'`
173 if test "$luser" = "$value" ; then
174 luser=
175 fi
176 type="otherName:1.3.6.1.5.2.2;SEQUENCE:$value,${luser:+otherName:1.3.6.1.4.1.311.20.2.3;UTF8:${luser},}otherName:1.3.6.1.4.1.311.20.2.3;UTF8"
177 unset luser
178 principals="$principals $value"
179 ;;
180 *@*.com|*@*.edu|*@*.net|*@*.org|*@*.local) type=email;;
181 [0-9]*.[0-9]*.[0-9]*.[0-9]*) type=IP;;
182 *) type=DNS;;
183 esac
184 if test -n "$type" ; then
185 newvalue="${type}:$value"
186 if test -z "$altnames" ; then
187 altnames="${newvalue}"
188 else
189 altnames="${altnames},${newvalue}"
190 fi
191 fi
192 shift
193done
194
195# Build the configuration file, including bits on how to construct the CA
196# certificate, an OCSP responder certificate, and the issued certificate.
197cat > openssl.cnf <<- EOF
198[ca]
199default_ca = issuer
200
201[issuer]
202private_key = `pwd`/ca.key
203certificate = `pwd`/ca.crt
204database = `pwd`/ca.db
205serial = `pwd`/ca.srl
206default_md = $DIGEST
207new_certs_dir = $newcertdir
208policy = no_policy
209
210[no_policy]
211
212[req_oids]
213domainComponent = 0.9.2342.19200300.100.1.25
214
215[req_ca]
216prompt = no
217oid_section = req_oids
218distinguished_name = req_ca_name
219default_md = $DIGEST
220subjectKeyIdentifier=hash
221
222[req_ca_name]
223C=US
224#stateOrProvinceName=SomeState
225localityName=SomeCity
226O=SomeOrg
227EOF
228#echo $DOMAIN | awk 'BEGIN {FS="."}{for(i=NF;i>0;i--){print NF-i ".domainComponent="$i;}}' >> openssl.cnf
229cat >> openssl.cnf <<- EOF
230#commonName = Test Certifying CA
231
232[v3_ca]
233subjectKeyIdentifier=hash
234authorityKeyIdentifier=keyid:always
235#authorityKeyIdentifier=keyid:always,issuer:always
236keyUsage=nonRepudiation,digitalSignature,keyEncipherment,dataEncipherment,keyAgreement,keyCertSign,cRLSign
237basicConstraints=critical,CA:TRUE
238nsComment="Testing CA Certificate"
239EOF
240if test -n "$aia" ; then
241 echo "authorityInfoAccess = ${aia}" >> openssl.cnf
242 echo -n "$aiaval" > ca.ocsp.uri.txt
243fi
244if test -n "$crl" ; then
245 echo "crlDistributionPoints = ${crl}" >> openssl.cnf
246 echo -n "$crlval" > ca.crldp.uri.txt
247fi
248echo "$DOMAIN" > ca.domain.txt
249cat >> openssl.cnf <<- EOF
250
251[req_ocsp]
252prompt = no
253oid_section = req_oids
254distinguished_name = req_ocsp_name
255default_md = $DIGEST
256
257[req_ocsp_name]
258C=US
259#stateOrProvinceName=SomeState
260localityName=SomeOrg
261O=SomeOrg
262EOF
263#echo $DOMAIN | awk 'BEGIN {FS="."}{for(i=NF;i>0;i--){print NF-i ".domainComponent="$i;}}' >> openssl.cnf
264cat >> openssl.cnf <<- EOF
265#commonName = OCSP Signer for Test Certifying CA
266
267[v3_ocsp]
268subjectKeyIdentifier=hash
269#authorityKeyIdentifier=keyid:always,issuer:always
270authorityKeyIdentifier=keyid:always
271keyUsage=digitalSignature,nonRepudiation,keyEncipherment,dataEncipherment,keyAgreement,keyCertSign,cRLSign
272extendedKeyUsage=1.3.6.1.5.5.7.3.9
273#basicConstraints=CA:FALSE
274basicConstraints=CA:TRUE
275nsComment="Testing OCSP Certificate"
2761.3.6.1.5.5.7.48.1.5=ASN1:NULL
277EOF
278if test -n "$aia" ; then
279 echo "authorityInfoAccess = ${aia}" >> openssl.cnf
280fi
281if test -n "$crl" ; then
282 echo "crlDistributionPoints = ${crl}" >> openssl.cnf
283fi
284cat >> openssl.cnf <<- EOF
285
286[req_issued]
287prompt = no
288oid_section = req_oids
289distinguished_name = req_issued_name
290default_md = $DIGEST
291
292[req_issued_name]
293C=US
294#stateOrProvinceName=SomeState
295localityName=SomeCity
296O=SomeOrg
297EOF
298#echo $DOMAIN | awk 'BEGIN {FS="."}{for(i=NF;i>0;i--){print NF-i ".domainComponent="$i;}}' >> openssl.cnf
299#mail = $GIVENUSER
300cat >> openssl.cnf <<- EOF
301commonName = $commonname
302
303[v3_issued]
304#certificatePolicies=2.5.29.32.0${eku:+,${eku}}
305subjectKeyIdentifier=hash
306authorityKeyIdentifier=keyid:always
307#authorityKeyIdentifier=keyid:always,issuer:always
308EOF
309if test -n "$aia" ; then
310 echo "authorityInfoAccess = ${aia}" >> openssl.cnf
311fi
312if test -n "$crl" ; then
313 echo "crlDistributionPoints = ${crl}" >> openssl.cnf
314fi
315if test -n "$keyusage" ; then
316 echo "keyUsage = critical,${keyusage}" >> openssl.cnf
317fi
318if test -n "$altnames" ; then
319 echo "subjectAltName = ${altnames}" >> openssl.cnf
320fi
321if test -n "$eku" ; then
322 echo "extendedKeyUsage = ${eku}" >> openssl.cnf
323 :
324fi
325if test "x$CA" = xTRUE ; then
326 echo "basicConstraints=critical,CA:TRUE" >> openssl.cnf
327 echo 'nsComment="Testing CA Certificate for '"$commonname"'"' >> openssl.cnf
328else
329 echo "basicConstraints=CA:FALSE" >> openssl.cnf
330 echo 'nsComment="Testing Certificate for '"$commonname"'"' >> openssl.cnf
331fi
332for value in $principals; do
333 user=`echo "$value" | cut -f1 -d@`
334 realm=`echo "$value" | cut -f2- -d@`
335 echo "" >> openssl.cnf
336 echo "[$value]" >> openssl.cnf
337 echo "realm=EXPLICIT:0,GeneralString:$realm" >> openssl.cnf
338 echo "kerberosname=EXPLICIT:1,SEQUENCE:krb5$user" >> openssl.cnf
339
340 echo "" >> openssl.cnf
341 echo "[krb5$user]" >> openssl.cnf
342 echo "nametype=EXPLICIT:0,INTEGER:1" >> openssl.cnf
343 echo "namelist=EXPLICIT:1,SEQUENCE:krb5basic$user" >> openssl.cnf
344
345 echo "[krb5basic$user]" >> openssl.cnf
346 count=0
347 for part in `echo "$user" | sed 's,/, ,g'` ; do
348 echo "$count.part=GeneralString:$part" >> openssl.cnf
349 count=`expr "$count" + 1`
350 done
351done
352
353# Create the data files for a new CA.
354if ! test -s ca.srl ; then
355 (dd if=/dev/urandom bs=8 count=1 2> /dev/null) | od -t x1c | head -n 1 | awk '{$1="00";OFS="";print}' > ca.srl
356else
357 echo "You already have a ca.srl file; not replacing."
358fi
359if ! test -s ca.db ; then
360 touch ca.db
361else
362 echo "You already have a ca.db file; not replacing."
363fi
364if ! test -s ca.db.attr ; then
365 touch ca.db.attr
366else
367 echo "You already have a ca.db.attr file; not replacing."
368fi
369
370# If we need a CA key, generate one.
371if ! test -s ca.key ; then
372 umask=`umask -p`
373 umask 077
374 keygen ca > ca.key 2> /dev/null
375 $umask
376else
377 echo "You already have a ca.key file; not replacing."
378 done=echo
379fi
380
381# If we need a CA certificate, generate one.
382if ! test -s ca.crt ; then
383 sed -i -e 's,^\[req_ca\]$,\[req\],g' `pwd`/openssl.cnf
384 openssl req -config `pwd`/openssl.cnf -new -key ca.key > ca.csr 2> /dev/null -passin pass:shim
385 sed -i -e 's,^\[req\]$,\[req_ca\],g' `pwd`/openssl.cnf
386 openssl x509 -extfile `pwd`/openssl.cnf -CAserial ca.srl -signkey ca.key -extensions v3_ca -req -in ca.csr -days $DAYS -out ca.crt ; : 2> /dev/null
387 openssl x509 -noout -text -in ca.crt > ca.txt
388 cat ca.crt >> ca.txt
389 cat ca.txt > ca.crt
390 rm ca.txt
391 cat ca.crt > ca.chain.crt
392else
393 echo "You already have a ca.crt file; not replacing."
394 done=echo
395fi
396
397# If we need an OCSP key, generate one.
398if ! test -s ocsp.key ; then
399 umask=`umask -p`
400 umask 077
401 keygen ocsp > ocsp.key 2> /dev/null
402 $umask
403else
404 echo "You already have an ocsp.key file; not replacing."
405 done=echo
406fi
407
408# Generate the OCSP signing cert. Set the X.509v3 basic constraints and EKU.
409if ! test -s ocsp.crt ; then
410 sed -i -e 's,^\[req_ocsp\]$,\[req\],g' `pwd`/openssl.cnf
411 openssl req -config `pwd`/openssl.cnf -new -key ocsp.key > ocsp.csr 2> /dev/null
412 sed -i -e 's,^\[req\]$,\[req_ocsp\],g' `pwd`/openssl.cnf
413 openssl ca -batch -config `pwd`/openssl.cnf -extensions v3_ocsp -preserveDN -in ocsp.csr -days $DAYS -out ocsp.crt 2> /dev/null
414 openssl x509 -noout -text -in ocsp.crt > ocsp.txt
415 cat ocsp.crt >> ocsp.txt
416 cat ocsp.txt > ocsp.crt
417 rm ocsp.txt
418else
419 echo "You already have an ocsp.crt file; not replacing."
420 done=echo
421fi
422
423# If we were told to revoke the certificate with the specified common name,
424# do so.
425if $revoke_cert ; then
426 openssl ca -config `pwd`/openssl.cnf -revoke "$commonname".crt
427fi
428
429# Always refresh the CRL.
430openssl ca -config `pwd`/openssl.cnf -gencrl ${CRLHOURS:+-crlhours ${CRLHOURS}} ${CRLDAYS:+-crldays ${CRLDAYS}} -out ca.crl.pem
431openssl crl -in ca.crl.pem -outform der -out ca.crl
432openssl crl -in ca.crl -inform der -noout -text > ca.crl.pem
433openssl crl -in ca.crl -inform der >> ca.crl.pem
434
435# If we were told to start up the mini OCSP server, do so.
436if $ocsp_serve ; then
437 openssl ocsp -text -index `pwd`/ca.db -CA `pwd`/ca.crt -rsigner `pwd`/ocsp.crt -rkey `pwd`/ocsp.key -rother `pwd`/ocsp.crt -port "`cut -f3 -d/ ca.ocsp.uri.txt | sed -r 's,(^[^:]*),0.0.0.0,g'`"
438 exit 0
439fi
440
441# If we're just here to do a revocation or refresh the CRL, we're done.
442if $revoke_cert || $refresh_crl ; then
443 exit 0
444fi
445
446# Create a new serial number and whatnot if this is a new sub-CA.
447if test "x$CA" = xTRUE ; then
448 if ! test -d "$commonname" ; then
449 mkdir "$commonname"
450 fi
451 if ! test -s "$commonname/ca.srl" ; then
452 (dd if=/dev/urandom bs=8 count=1 2> /dev/null) | od -t x1c | head -n 1 | awk '{$1="00";OFS="";print}' > "$commonname/ca.srl"
453 else
454 echo "You already have a $commonname/ca.srl file; not replacing."
455 fi
456 if test -n "$aia" ; then
457 echo -n "$aiaval" > "$commonname/ca.ocsp.uri.txt"
458 fi
459 if test -n "$crl" ; then
460 echo -n "$crlval" > "$commonname/ca.crldp.uri.txt"
461 fi
462 echo "$DOMAIN" > "$commonname/ca.domain.txt"
463 touch "$commonname/ca.db" "$commonname/ca.db.attr"
464 cert="$commonname/ca.crt"
465 csr="$commonname/ca.csr"
466 key="$commonname/ca.key"
467 pem="$commonname/ca.pem"
468 pfx="$commonname/ca.p12"
469 ln -s ../`basename $0` "$commonname"/
470else
471 cert="$commonname.crt"
472 csr="$commonname.csr"
473 key="$commonname.key"
474 pem="$commonname.pem"
475 pfx="$commonname.p12"
476fi
477
478# Generate the subject's certificate. Set the X.509v3 basic constraints.
479if ! test -s "$cert" ; then
480 # Generate another key, unless we have a key or CSR.
481 if ! test -s "$key" && ! test -s "$csr" ; then
482 umask=`umask -p`
483 umask 077
484 keygen "$commonname" > "$key" 2> /dev/null
485 $umask
486 else
487 echo "You already have a $key or $csr file; not replacing."
488 done=echo
489 fi
490
491 if ! test -s "$csr" ; then
492 sed -i -e 's,^\[req_issued\]$,\[req\],g' `pwd`/openssl.cnf
493 openssl req -config `pwd`/openssl.cnf -new -key "$key" > "$csr" 2> /dev/null
494 sed -i -e 's,^\[req\]$,\[req_issued\],g' `pwd`/openssl.cnf
495 fi
496 openssl ca -batch -config `pwd`/openssl.cnf -extensions v3_issued -preserveDN -in "$csr" -days $DAYS -out "$cert" 2> /dev/null
497 openssl x509 -noout -text -in "$cert" > "$cert.txt"
498 cat "$cert" >> "$cert.txt"
499 cat "$cert.txt" > "$cert"
500 rm -f "$cert.txt"
501else
502 echo "You already have a $cert file; not replacing."
503 done=echo
504fi
505
506if test -s ca.chain.crt ; then
507 chain=ca.chain.crt
508else
509 chain=ca.crt
510fi
511if test "x$CA" = xTRUE ; then
512 cat "$chain" "$cert" > "$commonname/ca.chain.crt"
513fi
514
515# Create ca.pem and the subject's name.pem for the benefit of applications
516# which expect both the private key and the certificate in one file.
517umask=`umask -p`
518umask 077
519if ! test -s ca.pem ; then
520 cat ca.key ca.crt > ca.pem
521else
522 echo "You already have a ca.pem file; not replacing."
523 done=echo
524fi
525if ! test -s "$pem" ; then
526 cat "$key" "$cert" > "$pem"
527else
528 echo "You already have a $pem file; not replacing."
529 done=echo
530fi
531if ! test -s "$pfx" ; then
532 #openssl pkcs12 -export -inkey "$key" -in "$cert" -name "$commonname" -out "$pfx" -nodes -passout pass:qweqwe
533 openssl pkcs12 -export -inkey "$key" -in "$cert" -name "$commonname" -out "$pfx" -nodes -passout pass:
534else
535 echo "You already have a $pfx file; not replacing."
536 done=echo
537fi
538$umask
539$done
540
541echo CA certificate:
542openssl x509 -noout -issuer -in ca.crt | sed s,=\ ,\ ,g
543openssl x509 -noout -subject -in ca.crt | sed s,=\ ,\ ,g
544echo
545echo End entity certificate:
546openssl x509 -noout -issuer -in "$cert" | sed s,=\ ,\ ,g
547openssl x509 -noout -subject -in "$cert" | sed s,=\ ,\ ,g
548openssl x509 -noout -serial -in "$cert" | sed s,=,\ ,g
549echo
550echo PKCS12 bag:
551openssl pkcs12 -in "$pfx" -nodes -nokeys -nocerts -info -passin pass:
552#openssl pkcs12 -in "$pfx" -nodes -nokeys -nocerts -info -passin pass:qweqwe
553echo
554echo Verifying:
555echo + openssl verify -CAfile "$chain" "$cert"
556openssl verify -CAfile "$chain" "$cert"