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