Browse Source

includes existing cert on -c option

pull/1/head
srvrco 10 years ago
parent
commit
b15c2e898e
2 changed files with 52 additions and 42 deletions
  1. +1
    -1
      README.md
  2. +51
    -41
      getssl

+ 1
- 1
README.md View File

@ -3,7 +3,7 @@ get an SSL certificate via LetsEncryot. Suitable for automating the process in
This was written as an addition to checkssl for servers to automatically renew certifictes. In addition it allows the running of this script in standard bash ( on a desktop computer, or even virtualbox) and add the checks, and certificates to a remote server ( providing you have an ssh key on the remote server with access). Potentially I can include FTP as an option for uploading as well. This was written as an addition to checkssl for servers to automatically renew certifictes. In addition it allows the running of this script in standard bash ( on a desktop computer, or even virtualbox) and add the checks, and certificates to a remote server ( providing you have an ssh key on the remote server with access). Potentially I can include FTP as an option for uploading as well.
getssl ver. 0.1
getssl ver. 0.2
To obtain a letsencrypt SSL cert To obtain a letsencrypt SSL cert
Usage: getssl [-h|--help] [-d|--debug] [-c] [-w working_dir] domain Usage: getssl [-h|--help] [-d|--debug] [-c] [-w working_dir] domain


+ 51
- 41
getssl View File

@ -18,10 +18,11 @@
# Revision history: # Revision history:
# 2016-01-08 Created (v0.1) # 2016-01-08 Created (v0.1)
# 2016-01-11 type correction and upload to github (v0.2) # 2016-01-11 type correction and upload to github (v0.2)
# 2016-01-11 added import of any existing cert on -c option (v0.3)
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
PROGNAME=${0##*/} PROGNAME=${0##*/}
VERSION="0.2"
VERSION="0.3"
# defaults # defaults
#umask 077 # paranoid umask, as we're creating private keys #umask 077 # paranoid umask, as we're creating private keys
@ -119,10 +120,10 @@ send_signed_request() {
sig=$(echo -n "$protected64.$payload64" | openssl dgst -sha256 -sign $ACCOUNT_KEY | base64 -w 0 | _b64) sig=$(echo -n "$protected64.$payload64" | openssl dgst -sha256 -sign $ACCOUNT_KEY | base64 -w 0 | _b64)
debug sig "$sig" debug sig "$sig"
body="{\"header\": $HEADER, \"protected\": \"$protected64\", \"payload\": \"$payload64\", \"signature\": \"$sig\"}" body="{\"header\": $HEADER, \"protected\": \"$protected64\", \"payload\": \"$payload64\", \"signature\": \"$sig\"}"
debug body "$body" debug body "$body"
if [ "$needbase64" ] ; then if [ "$needbase64" ] ; then
response="$($CURL -X POST --data "$body" $url | base64 -w 0)" response="$($CURL -X POST --data "$body" $url | base64 -w 0)"
else else
@ -130,7 +131,7 @@ send_signed_request() {
fi fi
responseHeaders="$(sed 's/\r//g' $CURL_HEADER)" responseHeaders="$(sed 's/\r//g' $CURL_HEADER)"
debug responseHeaders "$responseHeaders" debug responseHeaders "$responseHeaders"
debug response "$response" debug response "$response"
code="$(grep ^HTTP $CURL_HEADER | tail -1 | cut -d " " -f 2)" code="$(grep ^HTTP $CURL_HEADER | tail -1 | cut -d " " -f 2)"
@ -154,7 +155,7 @@ copy_file_to_location() {
cp $from $to cp $from $to
fi fi
debug "copied $from to $to" debug "copied $from to $to"
fi
fi
} }
getcr() { getcr() {
@ -169,7 +170,7 @@ getcr() {
} }
_requires() { _requires() {
result=$(which $1)
result=$(which $1 2>/dev/null)
debug checking for required $1 ... $result debug checking for required $1 ... $result
if [ -z "$result" ]; then if [ -z "$result" ]; then
echo "This script requires $1 installed" echo "This script requires $1 installed"
@ -257,16 +258,16 @@ CA=\"https://acme-staging.api.letsencrypt.org\"
AGREEMENT=\"https://letsencrypt.org/documents/LE-SA-v1.0.1-July-27-2015.pdf\" AGREEMENT=\"https://letsencrypt.org/documents/LE-SA-v1.0.1-July-27-2015.pdf\"
#set an email address associated with your account
#set an email address associated with your account
#ACCOUNT_EMAIL=\"me@example.com\" #ACCOUNT_EMAIL=\"me@example.com\"
ACCOUNT_KEY_LENGTH=4096 ACCOUNT_KEY_LENGTH=4096
#The default directory for all your certs to be stored within ( in subdirectories by domain name )
#The default directory for all your certs to be stored within ( in subdirectories by domain name )
WORKING_DIR=~/.getssl WORKING_DIR=~/.getssl
# the command needed to reload apache / gninx or whatever you use # the command needed to reload apache / gninx or whatever you use
#RELOAD_CMD=\"\" #RELOAD_CMD=\"\"
#The time period within which you want to allow renewal of a certificate - this prevents hitting some of the rate limits.
#The time period within which you want to allow renewal of a certificate - this prevents hitting some of the rate limits.
RENEW_ALLOW=\"30\" RENEW_ALLOW=\"30\"
" >> $WORKING_DIR/getssl.cfg " >> $WORKING_DIR/getssl.cfg
fi fi
@ -278,6 +279,15 @@ RENEW_ALLOW=\"30\"
info "domain config already exists $DOMAIN_DIR/getssl.cfg" info "domain config already exists $DOMAIN_DIR/getssl.cfg"
else else
info "creating domain config file in $DOMAIN_DIR/getssl.cfg" info "creating domain config file in $DOMAIN_DIR/getssl.cfg"
EX_CERT=$(echo | openssl s_client -servername ${DOMAIN} -connect ${DOMAIN}:443 2>/dev/null | openssl x509 2>/dev/null)
EX_SANS="www.${DOMAIN}"
if [ ! -z "${EX_CERT}" ]; then
if [ ! -f $DOMAIN_DIR/domain.crt ]; then
echo $EX_CERT > $DOMAIN_DIR/domain.crt
fi
EX_SANS=$(echo "$EX_CERT" | openssl x509 -noout -text 2>/dev/null| grep "Subject Alternative Name" -A2 \
| grep -Eo "DNS:[a-zA-Z 0-9.]*" |sed "s@DNS:$DOMAIN@@g"| cut -c 5-)
fi
echo "# uncomment and modify any variables you need echo "# uncomment and modify any variables you need
# The staging server is best for testing # The staging server is best for testing
#CA=\"https://acme-staging.api.letsencrypt.org\" #CA=\"https://acme-staging.api.letsencrypt.org\"
@ -286,12 +296,12 @@ RENEW_ALLOW=\"30\"
#AGREEMENT=\"https://letsencrypt.org/documents/LE-SA-v1.0.1-July-27-2015.pdf\" #AGREEMENT=\"https://letsencrypt.org/documents/LE-SA-v1.0.1-July-27-2015.pdf\"
#set an email address associated with your account - generally set at account level rather than domain.
#set an email address associated with your account - generally set at account level rather than domain.
#ACCOUNT_EMAIL=\"me@example.com\" #ACCOUNT_EMAIL=\"me@example.com\"
#ACCOUNT_KEY_LENGTH=4096 #ACCOUNT_KEY_LENGTH=4096
# additional domains - this could be multiple domains / subdomains in a comma separated list # additional domains - this could be multiple domains / subdomains in a comma separated list
SANS=www.${DOMAIN}
SANS=${EX_SANS}
#Acme Challenge Location. The first line for the domain, the following ones for each additional domain #Acme Challenge Location. The first line for the domain, the following ones for each additional domain
#if these start with ssh: then the next variable is assumed to be the hostname and the rest the location. #if these start with ssh: then the next variable is assumed to be the hostname and the rest the location.
@ -305,10 +315,10 @@ SANS=www.${DOMAIN}
#CA_CERT_LOCATION=\"/etc/ssl/chain.crt\" #CA_CERT_LOCATION=\"/etc/ssl/chain.crt\"
# the command needed to reload apache / gninx or whatever you use # the command needed to reload apache / gninx or whatever you use
#RELOAD_CMD=\"\" #RELOAD_CMD=\"\"
#The time period within which you want to allow renewal of a certificate - this prevents hitting some of the rate limits.
#The time period within which you want to allow renewal of a certificate - this prevents hitting some of the rate limits.
#RENEW_ALLOW=\"30\" #RENEW_ALLOW=\"30\"
" >> $DOMAIN_DIR/getssl.cfg " >> $DOMAIN_DIR/getssl.cfg
fi fi
graceful_exit graceful_exit
fi fi
@ -391,34 +401,34 @@ else
<(cat $SSLCONF <(printf "$SANLIST")) > $DOMAIN_DIR/${DOMAIN}.csr <(cat $SSLCONF <(printf "$SANLIST")) > $DOMAIN_DIR/${DOMAIN}.csr
fi fi
# use account key to register with CA
# use account key to register with CA
pub_exp=$(openssl rsa -in $ACCOUNT_KEY -noout -text | grep "^publicExponent:"| cut -d '(' -f 2 | cut -d 'x' -f 2 | cut -d ')' -f 1) pub_exp=$(openssl rsa -in $ACCOUNT_KEY -noout -text | grep "^publicExponent:"| cut -d '(' -f 2 | cut -d 'x' -f 2 | cut -d ')' -f 1)
if [ "${#pub_exp}" == "5" ] ; then if [ "${#pub_exp}" == "5" ] ; then
pub_exp=0$pub_exp pub_exp=0$pub_exp
fi fi
debug pub_exp "$pub_exp" debug pub_exp "$pub_exp"
e=$(echo $pub_exp | xxd -r -p | base64) e=$(echo $pub_exp | xxd -r -p | base64)
debug e "$e" debug e "$e"
modulus=$(openssl rsa -in $ACCOUNT_KEY -modulus -noout | cut -d '=' -f 2 ) modulus=$(openssl rsa -in $ACCOUNT_KEY -modulus -noout | cut -d '=' -f 2 )
n=$(echo $modulus| xxd -r -p | base64 -w 0 | _b64 ) n=$(echo $modulus| xxd -r -p | base64 -w 0 | _b64 )
jwk='{"e": "'$e'", "kty": "RSA", "n": "'$n'"}' jwk='{"e": "'$e'", "kty": "RSA", "n": "'$n'"}'
HEADER='{"alg": "RS256", "jwk": '$jwk'}' HEADER='{"alg": "RS256", "jwk": '$jwk'}'
HEADERPLACE='{"nonce": "NONCE", "alg": "RS256", "jwk": '$jwk'}' HEADERPLACE='{"nonce": "NONCE", "alg": "RS256", "jwk": '$jwk'}'
debug HEADER "$HEADER" debug HEADER "$HEADER"
accountkey_json=$(echo -n "$jwk" | sed "s/ //g") accountkey_json=$(echo -n "$jwk" | sed "s/ //g")
thumbprint=$(echo -n "$accountkey_json" | sha256sum | xxd -r -p | base64 -w 0 | _b64) thumbprint=$(echo -n "$accountkey_json" | sha256sum | xxd -r -p | base64 -w 0 | _b64)
info "Registering account" info "Registering account"
regjson='{"resource": "new-reg", "agreement": "'$AGREEMENT'"}' regjson='{"resource": "new-reg", "agreement": "'$AGREEMENT'"}'
if [ "$ACCOUNT_EMAIL" ] ; then if [ "$ACCOUNT_EMAIL" ] ; then
regjson='{"resource": "new-reg", "contact": ["mailto: '$ACCOUNT_EMAIL'"], "agreement": "'$AGREEMENT'"}' regjson='{"resource": "new-reg", "contact": ["mailto: '$ACCOUNT_EMAIL'"], "agreement": "'$AGREEMENT'"}'
fi
fi
send_signed_request "$CA/acme/new-reg" "$regjson" send_signed_request "$CA/acme/new-reg" "$regjson"
if [ "$code" == "" ] || [ "$code" == '201' ] ; then if [ "$code" == "" ] || [ "$code" == '201' ] ; then
@ -436,7 +446,7 @@ info "Verify each domain"
alldomains=$(echo "$DOMAIN,$SANS" | sed "s/,/ /g") alldomains=$(echo "$DOMAIN,$SANS" | sed "s/,/ /g")
dn=0 dn=0
for d in $alldomains; do
for d in $alldomains; do
info "Verifing $d" info "Verifing $d"
debug "domain $d has location ${ACL[$dn]}" debug "domain $d has location ${ACL[$dn]}"
if [ -z "${ACL[$dn]}" ]; then if [ -z "${ACL[$dn]}" ]; then
@ -452,16 +462,16 @@ for d in $alldomains; do
http01=$(echo $response | egrep -o '{[^{]*"type":"http-01"[^}]*') http01=$(echo $response | egrep -o '{[^{]*"type":"http-01"[^}]*')
debug http01 "$http01" debug http01 "$http01"
token=$(echo "$http01" | sed 's/,/\n'/g| grep '"token":'| cut -d : -f 2|sed 's/"//g') token=$(echo "$http01" | sed 's/,/\n'/g| grep '"token":'| cut -d : -f 2|sed 's/"//g')
debug token $token debug token $token
uri=$(echo "$http01" | sed 's/,/\n'/g| grep '"uri":'| cut -d : -f 2,3|sed 's/"//g') uri=$(echo "$http01" | sed 's/,/\n'/g| grep '"uri":'| cut -d : -f 2,3|sed 's/"//g')
debug uri $uri debug uri $uri
keyauthorization="$token.$thumbprint" keyauthorization="$token.$thumbprint"
debug keyauthorization "$keyauthorization" debug keyauthorization "$keyauthorization"
echo -n "$keyauthorization" > $DOMAIN_DIR/tmp/$token echo -n "$keyauthorization" > $DOMAIN_DIR/tmp/$token
chmod 755 $DOMAIN_DIR/tmp/$token chmod 755 $DOMAIN_DIR/tmp/$token
@ -470,14 +480,14 @@ for d in $alldomains; do
wellknown_url="http://$d/.well-known/acme-challenge/$token" wellknown_url="http://$d/.well-known/acme-challenge/$token"
debug wellknown_url "$wellknown_url" debug wellknown_url "$wellknown_url"
if [ ! "$(curl --silent $wellknown_url)" == "$keyauthorization" ]; then if [ ! "$(curl --silent $wellknown_url)" == "$keyauthorization" ]; then
error_exit "for some reason could not reach $wellknown_url - please check it manually" error_exit "for some reason could not reach $wellknown_url - please check it manually"
fi fi
debug challenge "$challenge" debug challenge "$challenge"
send_signed_request $uri "{\"resource\": \"challenge\", \"keyAuthorization\": \"$keyauthorization\"}" send_signed_request $uri "{\"resource\": \"challenge\", \"keyAuthorization\": \"$keyauthorization\"}"
if [ ! -z "$code" ] && [ ! "$code" == '202' ] ; then if [ ! -z "$code" ] && [ ! "$code" == '202' ] ; then
error_exit "$d:Challenge error: $resource" error_exit "$d:Challenge error: $resource"
fi fi
@ -487,27 +497,27 @@ for d in $alldomains; do
if ! getcr $uri ; then if ! getcr $uri ; then
error_exit "$d:Verify error:$resource" error_exit "$d:Verify error:$resource"
fi fi
status=$(echo $response | egrep -o '"status":"[^"]+"' | cut -d : -f 2 | sed 's/"//g') status=$(echo $response | egrep -o '"status":"[^"]+"' | cut -d : -f 2 | sed 's/"//g')
if [ "$status" == "valid" ] ; then if [ "$status" == "valid" ] ; then
info "Verified $d" info "Verified $d"
break; break;
fi fi
if [ "$status" == "invalid" ] ; then if [ "$status" == "invalid" ] ; then
error=$(echo $response | egrep -o '"error":{[^}]*}' | grep -o '"detail":"[^"]*"' | cut -d '"' -f 4) error=$(echo $response | egrep -o '"error":{[^}]*}' | grep -o '"detail":"[^"]*"' | cut -d '"' -f 4)
error_exit "$d:Verify error:$error" error_exit "$d:Verify error:$error"
fi fi
if [ "$status" == "pending" ] ; then if [ "$status" == "pending" ] ; then
info "Pending" info "Pending"
else else
error_exit "$d:Verify error:$response"
fi
error_exit "$d:Verify error:$response"
fi
debug "sleep 5 secs berfore testiing verify again" debug "sleep 5 secs berfore testiing verify again"
sleep 5 sleep 5
done done
debug "remove token from ${ACL[$dn]}" debug "remove token from ${ACL[$dn]}"
if [[ "${ACL[$dn]:0:4}" == "ssh:" ]] ; then if [[ "${ACL[$dn]:0:4}" == "ssh:" ]] ; then
sshhost=$(echo "${ACL[$dn]}"| awk -F: '{print $2}') sshhost=$(echo "${ACL[$dn]}"| awk -F: '{print $2}')
@ -519,29 +529,29 @@ for d in $alldomains; do
else else
rm -f ${ACL[$dn]} rm -f ${ACL[$dn]}
fi fi
done
done
info "Verification completed, obtaining certificate." info "Verification completed, obtaining certificate."
der="$(openssl req -in $DOMAIN_DIR/${DOMAIN}.csr -outform DER | base64 -w 0 | _b64)" der="$(openssl req -in $DOMAIN_DIR/${DOMAIN}.csr -outform DER | base64 -w 0 | _b64)"
send_signed_request "$CA/acme/new-cert" "{\"resource\": \"new-cert\", \"csr\": \"$der\"}" "needbase64" send_signed_request "$CA/acme/new-cert" "{\"resource\": \"new-cert\", \"csr\": \"$der\"}" "needbase64"
CertData="$(grep -i -o '^Location.*' $CURL_HEADER |sed 's/\r//g'| cut -d " " -f 2)" CertData="$(grep -i -o '^Location.*' $CURL_HEADER |sed 's/\r//g'| cut -d " " -f 2)"
if [ "$CertData" ] ; then if [ "$CertData" ] ; then
echo -----BEGIN CERTIFICATE----- > "$CERT_FILE" echo -----BEGIN CERTIFICATE----- > "$CERT_FILE"
curl --silent "$CertData" | base64 >> "$CERT_FILE" curl --silent "$CertData" | base64 >> "$CERT_FILE"
echo -----END CERTIFICATE----- >> "$CERT_FILE" echo -----END CERTIFICATE----- >> "$CERT_FILE"
info "Certificate saved in $CERT_FILE" info "Certificate saved in $CERT_FILE"
fi fi
if [ -z "$CertData" ] ; then if [ -z "$CertData" ] ; then
response="$(echo $response | base64 -d)" response="$(echo $response | base64 -d)"
error_exit "Sign failed: $(echo "$response" | grep -o '"detail":"[^"]*"')" error_exit "Sign failed: $(echo "$response" | grep -o '"detail":"[^"]*"')"
fi fi
IssuerData=$(grep -i '^Link' $CURL_HEADER | cut -d " " -f 2| cut -d ';' -f 1 | sed 's/<//g' | sed 's/>//g') IssuerData=$(grep -i '^Link' $CURL_HEADER | cut -d " " -f 2| cut -d ';' -f 1 | sed 's/<//g' | sed 's/>//g')
if [ "$IssuerData" ] ; then if [ "$IssuerData" ] ; then
echo -----BEGIN CERTIFICATE----- > "$CA_CERT" echo -----BEGIN CERTIFICATE----- > "$CA_CERT"
curl --silent "$IssuerData" | base64 >> "$CA_CERT" curl --silent "$IssuerData" | base64 >> "$CA_CERT"
@ -560,7 +570,7 @@ copy_file_to_location $DOMAIN_DIR/${DOMAIN}.key $DOMAIN_KEY_LOCATION
info "copying CA certificate to $CA_CERT_LOCATION" info "copying CA certificate to $CA_CERT_LOCATION"
copy_file_to_location $CA_CERT $CA_CERT_LOCATION copy_file_to_location $CA_CERT $CA_CERT_LOCATION
# Run reload command to restart apache / gninx or whatever system
# Run reload command to restart apache / gninx or whatever system
if [ ! -z "$RELOAD_CMD" ]; then if [ ! -z "$RELOAD_CMD" ]; then
info "reloading SSL services" info "reloading SSL services"


Loading…
Cancel
Save