xref: /netbsd-src/external/ibm-public/postfix/dist/src/tls/mkcert.sh (revision f3bc92a4f25066883a5d85d66df30605583c883c)
1#! /bin/bash
2#
3# Copyright (c) 2016 Viktor Dukhovni <openssl-users@dukhovni.org>.
4# All rights reserved.
5#
6# Licensed under the terms of the Postfix SECURE MAILER license
7# included with the Postfix source code.
8#
9# This file is dual-licensed and is also available under other terms.
10# Please contact the author.
11
12# 100 years should be enough for now
13if [ -z "$DAYS" ]; then
14    DAYS=36525
15fi
16
17if [ -z "$OPENSSL_SIGALG" ]; then
18    OPENSSL_SIGALG=sha256
19fi
20
21case ${OPENSSL_SIGALG} in
22  null) dopts=();;
23  *) dopts=(-"${OPENSSL_SIGALG}");;
24esac
25
26if [ -z "$REQMASK" ]; then
27    REQMASK=utf8only
28fi
29
30stderr_onerror() {
31    (
32        err=$("$@" >&3 2>&1) || {
33            printf "%s\n" "$err" >&2
34            exit 1
35        }
36    ) 3>&1
37}
38
39key() {
40    local key=$1; shift
41
42    local alg=rsa
43    if [ -n "$OPENSSL_KEYALG" ]; then
44        alg=$OPENSSL_KEYALG
45    fi
46
47    local bits=2048
48    if [ -n "$OPENSSL_KEYBITS" ]; then
49        bits=$OPENSSL_KEYBITS
50    fi
51
52    if [ ! -f "${key}.pem" ]; then
53        args=(-algorithm "$alg")
54        case $alg in
55        rsa) args=("${args[@]}" -pkeyopt rsa_keygen_bits:$bits );;
56        ec)  args=("${args[@]}" -pkeyopt "ec_paramgen_curve:$bits")
57               args=("${args[@]}" -pkeyopt ec_param_enc:named_curve);;
58        dsa)  args=(-paramfile "$bits");;
59        ed25519)  ;;
60        ed448)  ;;
61        *) printf "Unsupported key algorithm: %s\n" "$alg" >&2; return 1;;
62        esac
63        stderr_onerror \
64            openssl genpkey "${args[@]}" -out "${key}.pem"
65    fi
66}
67
68# Usage: $0 req keyname dn1 dn2 ...
69req() {
70    local key=$1; shift
71
72    key "$key"
73    local errs
74
75    stderr_onerror \
76        openssl req "${dopts[@]}" -new -key "${key}.pem" \
77            -config <(printf "string_mask=%s\n[req]\n%s\n%s\n[dn]\n" \
78                      "$REQMASK" "prompt = no" "distinguished_name = dn"
79                      for dn in "$@"; do echo "$dn"; done)
80}
81
82req_nocn() {
83    local key=$1; shift
84
85    key "$key"
86    stderr_onerror \
87        openssl req "${dopts[@]}" -new -subj / -key "${key}.pem" \
88            -config <(printf "[req]\n%s\n[dn]\nCN_default =\n" \
89		      "distinguished_name = dn")
90}
91
92cert() {
93    local cert=$1; shift
94    local exts=$1; shift
95
96    stderr_onerror \
97        openssl x509 "${dopts[@]}" -req -out "${cert}.pem" \
98            -extfile <(printf "%s\n" "$exts") "$@"
99}
100
101genroot() {
102    local cn=$1; shift
103    local key=$1; shift
104    local cert=$1; shift
105    local skid="subjectKeyIdentifier = hash"
106    local akid="authorityKeyIdentifier = keyid"
107
108    exts=$(printf "%s\n%s\n%s\n" "$skid" "$akid" "basicConstraints = critical,CA:true")
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
118genca() {
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 skid="subjectKeyIdentifier = hash"
125    local akid="authorityKeyIdentifier = keyid"
126
127    exts=$(printf "%s\n%s\n%s\n" "$skid" "$akid" "basicConstraints = critical,CA:true")
128    for eku in "$@"
129    do
130        exts=$(printf "%s\nextendedKeyUsage = %s\n" "$exts" "$eku")
131    done
132    if [ -n "$NC" ]; then
133        exts=$(printf "%s\nnameConstraints = %s\n" "$exts" "$NC")
134    fi
135    csr=$(req "$key" "CN = $cn") || return 1
136    echo "$csr" |
137        cert "$cert" "$exts" -CA "${cacert}.pem" -CAkey "${cakey}.pem" \
138	    -set_serial 2 -days "${DAYS}"
139}
140
141gen_nonbc_ca() {
142    local cn=$1; shift
143    local key=$1; shift
144    local cert=$1; shift
145    local cakey=$1; shift
146    local cacert=$1; shift
147    local skid="subjectKeyIdentifier = hash"
148    local akid="authorityKeyIdentifier = keyid"
149
150    exts=$(printf "%s\n%s\n%s\n" "$skid" "$akid")
151    exts=$(printf "%s\nkeyUsage = %s\n" "$exts" "keyCertSign, cRLSign")
152    for eku in "$@"
153    do
154        exts=$(printf "%s\nextendedKeyUsage = %s\n" "$exts" "$eku")
155    done
156    csr=$(req "$key" "CN = $cn") || return 1
157    echo "$csr" |
158        cert "$cert" "$exts" -CA "${cacert}.pem" -CAkey "${cakey}.pem" \
159	    -set_serial 2 -days "${DAYS}"
160}
161
162# Usage: $0 genpc keyname certname eekeyname eecertname pcext1 pcext2 ...
163#
164# Note: takes csr on stdin, so must be used with $0 req like this:
165#
166# $0 req keyname dn | $0 genpc keyname certname eekeyname eecertname pcext ...
167genpc() {
168    local key=$1; shift
169    local cert=$1; shift
170    local cakey=$1; shift
171    local ca=$1; shift
172
173    exts=$(printf "%s\n%s\n%s\n%s\n" \
174	    "subjectKeyIdentifier = hash" \
175	    "authorityKeyIdentifier = keyid, issuer:always" \
176	    "basicConstraints = CA:false" \
177	    "proxyCertInfo = critical, @pcexts";
178           echo "[pcexts]";
179           for x in "$@"; do echo $x; done)
180    cert "$cert" "$exts" -CA "${ca}.pem" -CAkey "${cakey}.pem" \
181	 -set_serial 2 -days "${DAYS}"
182}
183
184# Usage: $0 geneealt keyname certname eekeyname eecertname alt1 alt2 ...
185#
186# Note: takes csr on stdin, so must be used with $0 req like this:
187#
188# $0 req keyname dn | $0 geneealt keyname certname eekeyname eecertname alt ...
189geneealt() {
190    local key=$1; shift
191    local cert=$1; shift
192    local cakey=$1; shift
193    local ca=$1; shift
194
195    exts=$(printf "%s\n%s\n%s\n%s\n" \
196	    "subjectKeyIdentifier = hash" \
197	    "authorityKeyIdentifier = keyid" \
198	    "basicConstraints = CA:false" \
199	    "subjectAltName = @alts";
200           echo "[alts]";
201           for x in "$@"; do echo $x; done)
202    cert "$cert" "$exts" -CA "${ca}.pem" -CAkey "${cakey}.pem" \
203	 -set_serial 2 -days "${DAYS}"
204}
205
206genee() {
207    local OPTIND=1
208    local purpose=serverAuth
209
210    while getopts p: o
211    do
212        case $o in
213        p) purpose="$OPTARG";;
214        *) echo "Usage: $0 genee [-p EKU] cn keyname certname cakeyname cacertname" >&2
215           return 1;;
216        esac
217    done
218
219    shift $((OPTIND - 1))
220    local cn=$1; shift
221    local key=$1; shift
222    local cert=$1; shift
223    local cakey=$1; shift
224    local ca=$1; shift
225
226    exts=$(printf "%s\n%s\n%s\n%s\n%s\n[alts]\n%s\n" \
227	    "subjectKeyIdentifier = hash" \
228	    "authorityKeyIdentifier = keyid, issuer" \
229	    "basicConstraints = CA:false" \
230	    "extendedKeyUsage = $purpose" \
231	    "subjectAltName = @alts" "DNS=${cn}")
232    csr=$(req "$key" "CN = $cn") || return 1
233    echo "$csr" |
234	cert "$cert" "$exts" -CA "${ca}.pem" -CAkey "${cakey}.pem" \
235	    -set_serial 2 -days "${DAYS}" "$@"
236}
237
238genss() {
239    local cn=$1; shift
240    local key=$1; shift
241    local cert=$1; shift
242
243    exts=$(printf "%s\n%s\n%s\n%s\n%s\n[alts]\n%s\n" \
244	    "subjectKeyIdentifier   = hash" \
245	    "authorityKeyIdentifier = keyid, issuer" \
246	    "basicConstraints = CA:false" \
247	    "extendedKeyUsage = serverAuth" \
248	    "subjectAltName = @alts" "DNS=${cn}")
249    csr=$(req "$key" "CN = $cn") || return 1
250    echo "$csr" |
251        cert "$cert" "$exts" -signkey "${key}.pem" \
252            -set_serial 1 -days "${DAYS}" "$@"
253}
254
255gennocn() {
256    local key=$1; shift
257    local cert=$1; shift
258
259    csr=$(req_nocn "$key") || return 1
260    echo "$csr" |
261	cert "$cert" "" -signkey "${key}.pem" -set_serial 1 -days -1 "$@"
262}
263
264"$@"
265