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