From 5753795c8b64d56ba64f3b5fa0ab8ddfc8a4eb02 Mon Sep 17 00:00:00 2001 From: fbt Date: Fri, 27 May 2016 13:26:08 +0300 Subject: [PATCH] le --- le | 143 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ le-renew | 90 ++++++++++++++++++++++++++++++++++ 2 files changed, 233 insertions(+) create mode 100755 le create mode 100755 le-renew diff --git a/le b/le new file mode 100755 index 0000000..42d10fd --- /dev/null +++ b/le @@ -0,0 +1,143 @@ +#!/usr/bin/env bash + +err() { + printf '%s\n' "$*" >&2 +} + +msg() { + printf '%s\n' "$*" +} + +set_default() { + declare -n _vref=$1 + + if ! [[ "$_vref" ]]; then + _vref=$2 + fi +} + +gen_san_string() { + declare d + declare -a argv + + argv=( "$@" ) + + printf '[SAN]\nsubjectAltName=' + + for d in "${argv[@]}"; do + printf 'DNS:%s' "$d" + if ! [[ "$d" == "${argv[-1]}" ]]; then + printf ',' + fi + done +} + +gen_renew_config() { + declare d + + printf 'domains=(\n' + for d in "$@"; do + printf " %s\n" "$d" + done + printf ')\n' +} + +main() { + declare cfg_dir + declare -a domains + + while (( $# )); do + case $1 in + -c) + cfg_dir=$2 + shift;; + + -a) + challenge_dir=$2 + shift;; + + -d) + domains+=( "$2" ) + shift;; + + --) + shift + break;; + + *) break;; + esac + + shift + done + + if ! (( ${#domains[@]} )); then + err "Use -d, luke" + return 1 + fi + + set_default cfg_dir "$HOME/.acme" + set_default challenge_dir '/tmp/acme/challenges' + + if ! [[ -d "$cfg_dir" ]]; then + err "Config dir ($cfg_dir) not found, creating." + if ! mkdir -m700 "$cfg_dir"; then + err "Can't create config dir: $cfg_dir" + return 1 + fi + fi + + if ! [[ -f "$cfg_dir/account.key" ]]; then + err "Account key not found, generating a new one." + openssl genrsa 4096 > "$cfg_dir/account.key" + fi + + if ! [[ -d "$cfg_dir/domains/${domains[0]}" ]]; then + mkdir -p "$cfg_dir/domains/${domains[0]}" + fi + + if ! [[ -f "$cfg_dir/domains/${domains[0]}/privkey.pem" ]]; then + err "Generating a new key for ${domains[0]}." + openssl genrsa 4096 > "$cfg_dir/domains/${domains[0]}/privkey.pem" + fi + + if ! [[ -d "$challenge_dir" ]]; then + err "Challenge dir does not exist: $challenge_dir" + return 1 + fi + + err "Generating a certificate request for: ${domains[@]}." + if (( ${#domains[@]} > 1 )); then + openssl req -new -sha256 \ + -key "$cfg_dir/domains/${domains[0]}/privkey.pem" \ + -subj "/" \ + -reqexts SAN \ + -config <(cat /etc/ssl/openssl.cnf <(gen_san_string "${domains[@]}")) > "$cfg_dir/domains/${domains[0]}/request.csr" + else + openssl req -new -sha256 \ + -key "$cfg_dir/domains/${domains[0]}/privkey.pem" \ + -subj "/CN=${domains[0]}" > "$cfg_dir/domains/${domains[0]}/request.csr" + fi + + err "Getting a signed certificate." + acme-tiny \ + --account-key "$cfg_dir/account.key" \ + --csr "$cfg_dir/domains/${domains[0]}/request.csr" \ + --acme-dir "$challenge_dir" > "$cfg_dir/domains/${domains[0]}/certificate.pem" + + if (( $? )); then + return 1 + fi + + gen_renew_config "${domains[@]}" > "$cfg_dir/domains/${domains[0]}/renew.cfg" + + if ! [[ -f "$cfg_dir/chain.pem" ]]; then + err "Intermediate certificate not found, downloading." + curl "https://letsencrypt.org/certs/lets-encrypt-x3-cross-signed.pem" > "$cfg_dir/letsencrypt.pem" + fi + + cat "$cfg_dir/domains/${domains[0]}/certificate.pem" "$cfg_dir/letsencrypt.pem" > "$cfg_dir/domains/${domains[0]}/fullchain.pem" + + err "Your certificate is available at $cfg_dir/domains/${domains[0]}/fullchain.pem" +} + +main "$@" diff --git a/le-renew b/le-renew new file mode 100755 index 0000000..7252615 --- /dev/null +++ b/le-renew @@ -0,0 +1,90 @@ +#!/usr/bin/env bash + +err() { + printf '%s\n' "$*" >&2 +} + +msg() { + printf '%s\n' "$*" +} + +set_default() { + declare -n _vref=$1 + + if ! [[ "$_vref" ]]; then + _vref=$2 + fi +} + +gen_san_string() { + declare d + declare -a argv + + argv=( "$@" ) + + printf '[SAN]\nsubjectAltName=' + + for d in "${argv[@]}"; do + printf 'DNS:%s' "$d" + if ! [[ "$d" == "${argv[-1]}" ]]; then + printf ',' + fi + done +} + +main() { + declare cfg_dir + declare -a domains le_args + + while (( $# )); do + case $1 in + -c) + cfg_dir=$2 + shift;; + + -t) + checkend_seconds=$2 + shift;; + + -d) + domains+=( "$2" ) + shift;; + + --) + shift + break;; + + *) break;; + esac + + shift + done + + set_default cfg_dir "$HOME/.acme" + set_default checkend_seconds 259200 + + certname=$1 + + if ! [[ "$certname" ]]; then + err "Please tell me what to do!" + return 1 + fi + + if ! openssl x509 -checkend "$checkend_seconds" < "$cfg_dir/domains/$certname/certificate.pem"; then + if ! (( "${#domains[@]}" )); then + if [[ -f "$cfg_dir/domains/$certname/renew.cfg" ]]; then + source "$cfg_dir/domains/$certname/renew.cfg" + else + domains=( "$certname" ) + fi + fi + + for d in "${domains[@]}"; do + le_args+=( '-d' "$d" ) + done + + echo "le ${le_args[@]}" + fi +} + +main "$@"