|  | #! /bin/bash | 
|  | # | 
|  | # Copyright 2016-2021 The OpenSSL Project Authors. All Rights Reserved. | 
|  | # Copyright (c) 2016 Viktor Dukhovni <openssl-users@dukhovni.org>. | 
|  | # All rights reserved. | 
|  | # | 
|  | # Licensed under the Apache License 2.0 (the "License").  You may not use | 
|  | # this file except in compliance with the License.  You can obtain a copy | 
|  | # in the file LICENSE in the source distribution or at | 
|  | # https://www.openssl.org/source/license.html | 
|  |  | 
|  | # This file is dual-licensed and is also available under other terms. | 
|  | # Please contact the author. | 
|  |  | 
|  | # 100 years should be enough for now | 
|  | if [ -z "$DAYS" ]; then | 
|  | DAYS=36525 | 
|  | fi | 
|  |  | 
|  | if [ -z "$OPENSSL_SIGALG" ]; then | 
|  | OPENSSL_SIGALG=sha256 | 
|  | fi | 
|  |  | 
|  | if [ -z "$REQMASK" ]; then | 
|  | REQMASK=utf8only | 
|  | fi | 
|  |  | 
|  | stderr_onerror() { | 
|  | ( | 
|  | err=$("$@" >&3 2>&1) || { | 
|  | printf "%s\n" "$err" >&2 | 
|  | exit 1 | 
|  | } | 
|  | ) 3>&1 | 
|  | } | 
|  |  | 
|  | key() { | 
|  | local key=$1; shift | 
|  |  | 
|  | local alg=rsa | 
|  | if [ -n "$OPENSSL_KEYALG" ]; then | 
|  | alg=$OPENSSL_KEYALG | 
|  | fi | 
|  |  | 
|  | local bits=2048 | 
|  | if [ -n "$OPENSSL_KEYBITS" ]; then | 
|  | bits=$OPENSSL_KEYBITS | 
|  | fi | 
|  |  | 
|  | if [ ! -f "${key}.pem" ]; then | 
|  | args=(-algorithm "$alg") | 
|  | case $alg in | 
|  | rsa) args=("${args[@]}" -pkeyopt rsa_keygen_bits:$bits );; | 
|  | ec)  args=("${args[@]}" -pkeyopt "ec_paramgen_curve:$bits") | 
|  | args=("${args[@]}" -pkeyopt ec_param_enc:named_curve);; | 
|  | dsa)  args=(-paramfile "$bits");; | 
|  | ed25519)  ;; | 
|  | ed448)  ;; | 
|  | *) printf "Unsupported key algorithm: %s\n" "$alg" >&2; return 1;; | 
|  | esac | 
|  | stderr_onerror \ | 
|  | openssl genpkey "${args[@]}" -out "${key}.pem" | 
|  | fi | 
|  | } | 
|  |  | 
|  | # Usage: $0 req keyname dn1 dn2 ... | 
|  | req() { | 
|  | local key=$1; shift | 
|  |  | 
|  | key "$key" | 
|  | local errs | 
|  |  | 
|  | stderr_onerror \ | 
|  | openssl req -new -"${OPENSSL_SIGALG}" -key "${key}.pem" \ | 
|  | -config <(printf "string_mask=%s\n[req]\n%s\n%s\n[dn]\n" \ | 
|  | "$REQMASK" "prompt = no" "distinguished_name = dn" | 
|  | for dn in "$@"; do echo "$dn"; done) | 
|  | } | 
|  |  | 
|  | req_nocn() { | 
|  | local key=$1; shift | 
|  |  | 
|  | key "$key" | 
|  | stderr_onerror \ | 
|  | openssl req -new -"${OPENSSL_SIGALG}" -subj / -key "${key}.pem" \ | 
|  | -config <(printf "[req]\n%s\n[dn]\nCN_default =\n" \ | 
|  | "distinguished_name = dn") | 
|  | } | 
|  |  | 
|  | cert() { | 
|  | local cert=$1; shift | 
|  | local exts=$1; shift | 
|  |  | 
|  | stderr_onerror \ | 
|  | openssl x509 -req -"${OPENSSL_SIGALG}" -out "${cert}.pem" \ | 
|  | -extfile <(printf "%s\n" "$exts") "$@" | 
|  | } | 
|  |  | 
|  | genroot() { | 
|  | local cn=$1; shift | 
|  | local key=$1; shift | 
|  | local cert=$1; shift | 
|  | local bcon="basicConstraints = critical,CA:true" | 
|  | local ku="keyUsage = keyCertSign,cRLSign" | 
|  | local skid="subjectKeyIdentifier = hash" | 
|  | local akid="authorityKeyIdentifier = keyid" | 
|  |  | 
|  | exts=$(printf "%s\n%s\n%s\n" "$bcon" "$ku" "$skid" "$akid") | 
|  | for eku in "$@" | 
|  | do | 
|  | exts=$(printf "%s\nextendedKeyUsage = %s\n" "$exts" "$eku") | 
|  | done | 
|  | csr=$(req "$key" "CN = $cn") || return 1 | 
|  | echo "$csr" | | 
|  | cert "$cert" "$exts" -signkey "${key}.pem" -set_serial 1 -days "${DAYS}" | 
|  | } | 
|  |  | 
|  | genca() { | 
|  | local OPTIND=1 | 
|  | local purpose= | 
|  |  | 
|  | while getopts p: o | 
|  | do | 
|  | case $o in | 
|  | p) purpose="$OPTARG";; | 
|  | *) echo "Usage: $0 genca [-p EKU] cn keyname certname cakeyname cacertname" >&2 | 
|  | return 1;; | 
|  | esac | 
|  | done | 
|  |  | 
|  | shift $((OPTIND - 1)) | 
|  | local cn=$1; shift | 
|  | local key=$1; shift | 
|  | local cert=$1; shift | 
|  | local cakey=$1; shift | 
|  | local cacert=$1; shift | 
|  | local bcon="basicConstraints = critical,CA:true" | 
|  | local ku="keyUsage = keyCertSign,cRLSign" | 
|  | local skid="subjectKeyIdentifier = hash" | 
|  | local akid="authorityKeyIdentifier = keyid" | 
|  |  | 
|  | exts=$(printf "%s\n%s\n%s\n" "$bcon" "$ku" "$skid" "$akid") | 
|  | if [ -n "$purpose" ]; then | 
|  | exts=$(printf "%s\nextendedKeyUsage = %s\n" "$exts" "$purpose") | 
|  | fi | 
|  | if [ -n "$NC" ]; then | 
|  | exts=$(printf "%s\nnameConstraints = %s\n" "$exts" "$NC") | 
|  | fi | 
|  | csr=$(req "$key" "CN = $cn") || return 1 | 
|  | echo "$csr" | | 
|  | cert "$cert" "$exts" -CA "${cacert}.pem" -CAkey "${cakey}.pem" \ | 
|  | -set_serial 2 -days "${DAYS}" "$@" | 
|  | } | 
|  |  | 
|  | gen_nonbc_ca() { | 
|  | local cn=$1; shift | 
|  | local key=$1; shift | 
|  | local cert=$1; shift | 
|  | local cakey=$1; shift | 
|  | local cacert=$1; shift | 
|  | local skid="subjectKeyIdentifier = hash" | 
|  | local akid="authorityKeyIdentifier = keyid" | 
|  |  | 
|  | exts=$(printf "%s\n%s\n%s\n" "$skid" "$akid") | 
|  | exts=$(printf "%s\nkeyUsage = %s\n" "$exts" "keyCertSign, cRLSign") | 
|  | for eku in "$@" | 
|  | do | 
|  | exts=$(printf "%s\nextendedKeyUsage = %s\n" "$exts" "$eku") | 
|  | done | 
|  | csr=$(req "$key" "CN = $cn") || return 1 | 
|  | echo "$csr" | | 
|  | cert "$cert" "$exts" -CA "${cacert}.pem" -CAkey "${cakey}.pem" \ | 
|  | -set_serial 2 -days "${DAYS}" | 
|  | } | 
|  |  | 
|  | # Usage: $0 genpc keyname certname eekeyname eecertname pcext1 pcext2 ... | 
|  | # | 
|  | # Note: takes csr on stdin, so must be used with $0 req like this: | 
|  | # | 
|  | # $0 req keyname dn | $0 genpc keyname certname eekeyname eecertname pcext ... | 
|  | genpc() { | 
|  | local key=$1; shift | 
|  | local cert=$1; shift | 
|  | local cakey=$1; shift | 
|  | local ca=$1; shift | 
|  |  | 
|  | exts=$(printf "%s\n%s\n%s\n%s\n" \ | 
|  | "subjectKeyIdentifier = hash" \ | 
|  | "authorityKeyIdentifier = keyid, issuer:always" \ | 
|  | "basicConstraints = CA:false" \ | 
|  | "proxyCertInfo = critical, @pcexts"; | 
|  | echo "[pcexts]"; | 
|  | for x in "$@"; do echo $x; done) | 
|  | cert "$cert" "$exts" -CA "${ca}.pem" -CAkey "${cakey}.pem" \ | 
|  | -set_serial 2 -days "${DAYS}" | 
|  | } | 
|  |  | 
|  | geneeconfig() { | 
|  | local key=$1; shift | 
|  | local cert=$1; shift | 
|  | local cakey=$1; shift | 
|  | local ca=$1; shift | 
|  | local conf=$1; shift | 
|  |  | 
|  | exts=$(printf "%s\n%s\n%s\n%s\n" \ | 
|  | "subjectKeyIdentifier = hash" \ | 
|  | "authorityKeyIdentifier = keyid" \ | 
|  | "basicConstraints = CA:false"; \ | 
|  | echo "$conf") | 
|  |  | 
|  | cert "$cert" "$exts" -CA "${ca}.pem" -CAkey "${cakey}.pem" \ | 
|  | -set_serial 2 -days "${DAYS}" | 
|  | } | 
|  |  | 
|  | # Usage: $0 geneealt keyname certname cakeyname cacertname alt1 alt2 ... | 
|  | # | 
|  | # Note: takes csr on stdin, so must be used with $0 req like this: | 
|  | # | 
|  | # $0 req keyname dn | $0 geneealt keyname certname cakeyname cacertname alt ... | 
|  | geneealt() { | 
|  | local key=$1; shift | 
|  | local cert=$1; shift | 
|  | local cakey=$1; shift | 
|  | local ca=$1; shift | 
|  |  | 
|  | conf=$(echo "subjectAltName = @alts" | 
|  | echo "[alts]"; | 
|  | for x in "$@"; do echo "$x"; done) | 
|  |  | 
|  | geneeconfig $key $cert $cakey $ca "$conf" | 
|  | } | 
|  |  | 
|  | genee() { | 
|  | local OPTIND=1 | 
|  | local purpose=serverAuth | 
|  |  | 
|  | while getopts p: o | 
|  | do | 
|  | case $o in | 
|  | p) purpose="$OPTARG";; | 
|  | *) echo "Usage: $0 genee [-p EKU] cn keyname certname cakeyname cacertname" >&2 | 
|  | return 1;; | 
|  | esac | 
|  | done | 
|  |  | 
|  | shift $((OPTIND - 1)) | 
|  | local cn=$1; shift | 
|  | local key=$1; shift | 
|  | local cert=$1; shift | 
|  | local cakey=$1; shift | 
|  | local ca=$1; shift | 
|  |  | 
|  | exts=$(printf "%s\n%s\n%s\n%s\n%s\n[alts]\n%s\n" \ | 
|  | "subjectKeyIdentifier = hash" \ | 
|  | "authorityKeyIdentifier = keyid, issuer" \ | 
|  | "basicConstraints = CA:false" \ | 
|  | "extendedKeyUsage = $purpose" \ | 
|  | "subjectAltName = @alts" "DNS=${cn}") | 
|  | csr=$(req "$key" "CN = $cn") || return 1 | 
|  | echo "$csr" | | 
|  | cert "$cert" "$exts" -CA "${ca}.pem" -CAkey "${cakey}.pem" \ | 
|  | -set_serial 2 -days "${DAYS}" "$@" | 
|  | } | 
|  |  | 
|  | geneeextra() { | 
|  | local OPTIND=1 | 
|  | local purpose=serverAuth | 
|  |  | 
|  | while getopts p: o | 
|  | do | 
|  | case $o in | 
|  | p) purpose="$OPTARG";; | 
|  | *) echo "Usage: $0 geneeextra [-p EKU] cn keyname certname cakeyname cacertname extraext" >&2 | 
|  | return 1;; | 
|  | esac | 
|  | done | 
|  |  | 
|  | shift $((OPTIND - 1)) | 
|  | local cn=$1; shift | 
|  | local key=$1; shift | 
|  | local cert=$1; shift | 
|  | local cakey=$1; shift | 
|  | local ca=$1; shift | 
|  | local extraext=$1; shift | 
|  |  | 
|  | exts=$(printf "%s\n%s\n%s\n%s\n%s\n%s\n[alts]\n%s\n" \ | 
|  | "subjectKeyIdentifier = hash" \ | 
|  | "authorityKeyIdentifier = keyid, issuer" \ | 
|  | "basicConstraints = CA:false" \ | 
|  | "extendedKeyUsage = $purpose" \ | 
|  | "subjectAltName = @alts"\ | 
|  | "$extraext" "DNS=${cn}") | 
|  | csr=$(req "$key" "CN = $cn") || return 1 | 
|  | echo "$csr" | | 
|  | cert "$cert" "$exts" -CA "${ca}.pem" -CAkey "${cakey}.pem" \ | 
|  | -set_serial 2 -days "${DAYS}" "$@" | 
|  | } | 
|  |  | 
|  | geneenocsr() { | 
|  | local OPTIND=1 | 
|  | local purpose=serverAuth | 
|  |  | 
|  | while getopts p: o | 
|  | do | 
|  | case $o in | 
|  | p) purpose="$OPTARG";; | 
|  | *) echo "Usage: $0 geneenocsr [-p EKU] cn certname cakeyname cacertname" >&2 | 
|  | return 1;; | 
|  | esac | 
|  | done | 
|  |  | 
|  | shift $((OPTIND - 1)) | 
|  | local cn=$1; shift | 
|  | local cert=$1; shift | 
|  | local cakey=$1; shift | 
|  | local ca=$1; shift | 
|  |  | 
|  | exts=$(printf "%s\n%s\n%s\n%s\n%s\n[alts]\n%s\n" \ | 
|  | "subjectKeyIdentifier = hash" \ | 
|  | "authorityKeyIdentifier = keyid, issuer" \ | 
|  | "basicConstraints = CA:false" \ | 
|  | "extendedKeyUsage = $purpose" \ | 
|  | "subjectAltName = @alts" "DNS=${cn}") | 
|  | cert "$cert" "$exts" -CA "${ca}.pem" -CAkey "${cakey}.pem" \ | 
|  | -set_serial 2 -days "${DAYS}" "$@" | 
|  | } | 
|  |  | 
|  | genss() { | 
|  | local cn=$1; shift | 
|  | local key=$1; shift | 
|  | local cert=$1; shift | 
|  |  | 
|  | exts=$(printf "%s\n%s\n%s\n%s\n%s\n[alts]\n%s\n" \ | 
|  | "subjectKeyIdentifier   = hash" \ | 
|  | "authorityKeyIdentifier = keyid, issuer" \ | 
|  | "basicConstraints = CA:false" \ | 
|  | "extendedKeyUsage = serverAuth" \ | 
|  | "subjectAltName = @alts" "DNS=${cn}") | 
|  | csr=$(req "$key" "CN = $cn") || return 1 | 
|  | echo "$csr" | | 
|  | cert "$cert" "$exts" -signkey "${key}.pem" \ | 
|  | -set_serial 1 -days "${DAYS}" "$@" | 
|  | } | 
|  |  | 
|  | gennocn() { | 
|  | local key=$1; shift | 
|  | local cert=$1; shift | 
|  |  | 
|  | csr=$(req_nocn "$key") || return 1 | 
|  | echo "$csr" | | 
|  | cert "$cert" "" -signkey "${key}.pem" -set_serial 1 -days -1 "$@" | 
|  | } | 
|  |  | 
|  | genct() { | 
|  | local OPTIND=1 | 
|  | local purpose=serverAuth | 
|  |  | 
|  | while getopts p: o | 
|  | do | 
|  | case $o in | 
|  | p) purpose="$OPTARG";; | 
|  | *) echo "Usage: $0 genct [-p EKU] cn keyname certname cakeyname cacertname ctlogkey" >&2 | 
|  | return 1;; | 
|  | esac | 
|  | done | 
|  |  | 
|  | shift $((OPTIND - 1)) | 
|  | local cn=$1; shift | 
|  | local key=$1; shift | 
|  | local cert=$1; shift | 
|  | local cakey=$1; shift | 
|  | local ca=$1; shift | 
|  | local logkey=$1; shift | 
|  |  | 
|  | exts=$(printf "%s\n%s\n%s\n%s\n%s\n%s\n[alts]\n%s\n" \ | 
|  | "subjectKeyIdentifier = hash" \ | 
|  | "authorityKeyIdentifier = keyid, issuer" \ | 
|  | "basicConstraints = CA:false" \ | 
|  | "extendedKeyUsage = $purpose" \ | 
|  | "1.3.6.1.4.1.11129.2.4.3 = critical,ASN1:NULL"\ | 
|  | "subjectAltName = @alts" "DNS=${cn}") | 
|  | csr=$(req "$key" "CN = $cn") || return 1 | 
|  | echo "$csr" | | 
|  | cert "$cert" "$exts" -CA "${ca}.pem" -CAkey "${cakey}.pem" \ | 
|  | -set_serial 2 -days "${DAYS}" "$@" | 
|  | cat ${cert}.pem ${ca}.pem > ${cert}-chain.pem | 
|  | go run github.com/google/certificate-transparency-go/ctutil/sctgen \ | 
|  | --log_private_key ${logkey}.pem \ | 
|  | --timestamp="2020-01-01T00:00:00Z" \ | 
|  | --cert_chain ${cert}-chain.pem \ | 
|  | --tls_out ${cert}.tlssct | 
|  | rm ${cert}-chain.pem | 
|  | filesize=$(wc -c <${cert}.tlssct) | 
|  | exts=$(printf "%s\n%s\n%s\n%s\n%s%04X%04X%s\n%s\n[alts]\n%s\n" \ | 
|  | "subjectKeyIdentifier = hash" \ | 
|  | "authorityKeyIdentifier = keyid, issuer" \ | 
|  | "basicConstraints = CA:false" \ | 
|  | "extendedKeyUsage = $purpose" \ | 
|  | "1.3.6.1.4.1.11129.2.4.2 = ASN1:FORMAT:HEX,OCT:" $((filesize+2)) $filesize `xxd -p ${cert}.tlssct | tr -d '\n'` \ | 
|  | "subjectAltName = @alts" "DNS=${cn}") | 
|  | echo "$csr" | | 
|  | cert "$cert" "$exts" -CA "${ca}.pem" -CAkey "${cakey}.pem" \ | 
|  | -set_serial 2 -days "${DAYS}" "$@" | 
|  | } | 
|  |  | 
|  | "$@" |