1#! /bin/bash 2# 3# Copyright 2016-2021 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 OpenSSL license (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 16if [ -z "$DAYS" ]; then 17 DAYS=36525 18fi 19 20if [ -z "$OPENSSL_SIGALG" ]; then 21 OPENSSL_SIGALG=sha256 22fi 23 24if [ -z "$REQMASK" ]; then 25 REQMASK=utf8only 26fi 27 28stderr_onerror() { 29 ( 30 err=$("$@" >&3 2>&1) || { 31 printf "%s\n" "$err" >&2 32 exit 1 33 } 34 ) 3>&1 35} 36 37key() { 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 ... 67req() { 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 80req_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 90cert() { 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 99genroot() { 100 local cn=$1; shift 101 local key=$1; shift 102 local cert=$1; shift 103 local skid="subjectKeyIdentifier = hash" 104 local akid="authorityKeyIdentifier = keyid" 105 106 exts=$(printf "%s\n%s\n%s\n" "$skid" "$akid" "basicConstraints = critical,CA:true") 107 for eku in "$@" 108 do 109 exts=$(printf "%s\nextendedKeyUsage = %s\n" "$exts" "$eku") 110 done 111 csr=$(req "$key" "CN = $cn") || return 1 112 echo "$csr" | 113 cert "$cert" "$exts" -signkey "${key}.pem" -set_serial 1 -days "${DAYS}" 114} 115 116genca() { 117 local OPTIND=1 118 local purpose= 119 120 while getopts p: o 121 do 122 case $o in 123 p) purpose="$OPTARG";; 124 *) echo "Usage: $0 genca [-p EKU] cn keyname certname cakeyname cacertname" >&2 125 return 1;; 126 esac 127 done 128 129 shift $((OPTIND - 1)) 130 local cn=$1; shift 131 local key=$1; shift 132 local cert=$1; shift 133 local cakey=$1; shift 134 local cacert=$1; shift 135 local skid="subjectKeyIdentifier = hash" 136 local akid="authorityKeyIdentifier = keyid" 137 138 exts=$(printf "%s\n%s\n%s\n" "$skid" "$akid" "basicConstraints = critical,CA:true") 139 if [ -n "$purpose" ]; then 140 exts=$(printf "%s\nextendedKeyUsage = %s\n" "$exts" "$purpose") 141 fi 142 if [ -n "$NC" ]; then 143 exts=$(printf "%s\nnameConstraints = %s\n" "$exts" "$NC") 144 fi 145 csr=$(req "$key" "CN = $cn") || return 1 146 echo "$csr" | 147 cert "$cert" "$exts" -CA "${cacert}.pem" -CAkey "${cakey}.pem" \ 148 -set_serial 2 -days "${DAYS}" "$@" 149} 150 151gen_nonbc_ca() { 152 local cn=$1; shift 153 local key=$1; shift 154 local cert=$1; shift 155 local cakey=$1; shift 156 local cacert=$1; shift 157 local skid="subjectKeyIdentifier = hash" 158 local akid="authorityKeyIdentifier = keyid" 159 160 exts=$(printf "%s\n%s\n%s\n" "$skid" "$akid") 161 exts=$(printf "%s\nkeyUsage = %s\n" "$exts" "keyCertSign, cRLSign") 162 for eku in "$@" 163 do 164 exts=$(printf "%s\nextendedKeyUsage = %s\n" "$exts" "$eku") 165 done 166 csr=$(req "$key" "CN = $cn") || return 1 167 echo "$csr" | 168 cert "$cert" "$exts" -CA "${cacert}.pem" -CAkey "${cakey}.pem" \ 169 -set_serial 2 -days "${DAYS}" 170} 171 172# Usage: $0 genpc keyname certname eekeyname eecertname pcext1 pcext2 ... 173# 174# Note: takes csr on stdin, so must be used with $0 req like this: 175# 176# $0 req keyname dn | $0 genpc keyname certname eekeyname eecertname pcext ... 177genpc() { 178 local key=$1; shift 179 local cert=$1; shift 180 local cakey=$1; shift 181 local ca=$1; shift 182 183 exts=$(printf "%s\n%s\n%s\n%s\n" \ 184 "subjectKeyIdentifier = hash" \ 185 "authorityKeyIdentifier = keyid, issuer:always" \ 186 "basicConstraints = CA:false" \ 187 "proxyCertInfo = critical, @pcexts"; 188 echo "[pcexts]"; 189 for x in "$@"; do echo $x; done) 190 cert "$cert" "$exts" -CA "${ca}.pem" -CAkey "${cakey}.pem" \ 191 -set_serial 2 -days "${DAYS}" 192} 193 194# Usage: $0 geneealt keyname certname eekeyname eecertname alt1 alt2 ... 195# 196# Note: takes csr on stdin, so must be used with $0 req like this: 197# 198# $0 req keyname dn | $0 geneealt keyname certname eekeyname eecertname alt ... 199geneealt() { 200 local key=$1; shift 201 local cert=$1; shift 202 local cakey=$1; shift 203 local ca=$1; shift 204 205 exts=$(printf "%s\n%s\n%s\n%s\n" \ 206 "subjectKeyIdentifier = hash" \ 207 "authorityKeyIdentifier = keyid" \ 208 "basicConstraints = CA:false" \ 209 "subjectAltName = @alts"; 210 echo "[alts]"; 211 for x in "$@"; do echo $x; done) 212 cert "$cert" "$exts" -CA "${ca}.pem" -CAkey "${cakey}.pem" \ 213 -set_serial 2 -days "${DAYS}" 214} 215 216genee() { 217 local OPTIND=1 218 local purpose=serverAuth 219 220 while getopts p: o 221 do 222 case $o in 223 p) purpose="$OPTARG";; 224 *) echo "Usage: $0 genee [-p EKU] cn keyname certname cakeyname cacertname" >&2 225 return 1;; 226 esac 227 done 228 229 shift $((OPTIND - 1)) 230 local cn=$1; shift 231 local key=$1; shift 232 local cert=$1; shift 233 local cakey=$1; shift 234 local ca=$1; shift 235 236 exts=$(printf "%s\n%s\n%s\n%s\n%s\n[alts]\n%s\n" \ 237 "subjectKeyIdentifier = hash" \ 238 "authorityKeyIdentifier = keyid, issuer" \ 239 "basicConstraints = CA:false" \ 240 "extendedKeyUsage = $purpose" \ 241 "subjectAltName = @alts" "DNS=${cn}") 242 csr=$(req "$key" "CN = $cn") || return 1 243 echo "$csr" | 244 cert "$cert" "$exts" -CA "${ca}.pem" -CAkey "${cakey}.pem" \ 245 -set_serial 2 -days "${DAYS}" "$@" 246} 247 248geneenocsr() { 249 local OPTIND=1 250 local purpose=serverAuth 251 252 while getopts p: o 253 do 254 case $o in 255 p) purpose="$OPTARG";; 256 *) echo "Usage: $0 genee [-p EKU] cn certname cakeyname cacertname" >&2 257 return 1;; 258 esac 259 done 260 261 shift $((OPTIND - 1)) 262 local cn=$1; shift 263 local cert=$1; shift 264 local cakey=$1; shift 265 local ca=$1; shift 266 267 exts=$(printf "%s\n%s\n%s\n%s\n%s\n[alts]\n%s\n" \ 268 "subjectKeyIdentifier = hash" \ 269 "authorityKeyIdentifier = keyid, issuer" \ 270 "basicConstraints = CA:false" \ 271 "extendedKeyUsage = $purpose" \ 272 "subjectAltName = @alts" "DNS=${cn}") 273 cert "$cert" "$exts" -CA "${ca}.pem" -CAkey "${cakey}.pem" \ 274 -set_serial 2 -days "${DAYS}" "$@" 275} 276 277genss() { 278 local cn=$1; shift 279 local key=$1; shift 280 local cert=$1; shift 281 282 exts=$(printf "%s\n%s\n%s\n%s\n%s\n[alts]\n%s\n" \ 283 "subjectKeyIdentifier = hash" \ 284 "authorityKeyIdentifier = keyid, issuer" \ 285 "basicConstraints = CA:false" \ 286 "extendedKeyUsage = serverAuth" \ 287 "subjectAltName = @alts" "DNS=${cn}") 288 csr=$(req "$key" "CN = $cn") || return 1 289 echo "$csr" | 290 cert "$cert" "$exts" -signkey "${key}.pem" \ 291 -set_serial 1 -days "${DAYS}" "$@" 292} 293 294gennocn() { 295 local key=$1; shift 296 local cert=$1; shift 297 298 csr=$(req_nocn "$key") || return 1 299 echo "$csr" | 300 cert "$cert" "" -signkey "${key}.pem" -set_serial 1 -days -1 "$@" 301} 302 303"$@" 304