Compare commits
No commits in common. "0aea46dd7bc0e4e2723d09b76dbdbab24beda18f" and "2219ce7538aa7624d4495438f3783d983fd47b8f" have entirely different histories.
0aea46dd7b
...
2219ce7538
145
mkcerts.sh
145
mkcerts.sh
@ -19,7 +19,7 @@ function hex2bin { cat | sed 's/\([0-9a-f]\{2\}\)/\\\\\\x\1/g' | xargs printf; }
|
|||||||
|
|
||||||
# UTILS
|
# UTILS
|
||||||
|
|
||||||
function get_CA_URLs
|
function getCAURLs
|
||||||
{
|
{
|
||||||
declare -A CAs
|
declare -A CAs
|
||||||
CAs[LE]=https://acme-v02.api.letsencrypt.org/directory
|
CAs[LE]=https://acme-v02.api.letsencrypt.org/directory
|
||||||
@ -31,13 +31,11 @@ function get_CA_URLs
|
|||||||
CAs[sslcom_ecc]=https://acme.ssl.com/sslcom-dv-ecc
|
CAs[sslcom_ecc]=https://acme.ssl.com/sslcom-dv-ecc
|
||||||
CAs[jewgle]=https://dv.acme-v02.api.pki.goog/directory
|
CAs[jewgle]=https://dv.acme-v02.api.pki.goog/directory
|
||||||
CAs[jewgletest]=https://dv.acme-v02.test-api.pki.goog/directory
|
CAs[jewgletest]=https://dv.acme-v02.test-api.pki.goog/directory
|
||||||
CA=$1
|
endpoints=$(curl -s ${CAs[$1]})
|
||||||
endpoints=$(curl -s ${CAs[$CA]})
|
export endpoints # I don't know if this works
|
||||||
export CA
|
|
||||||
export endpoints # I don't know if this works, or if it matters
|
|
||||||
} # $1=LE
|
} # $1=LE
|
||||||
|
|
||||||
function read_ACME
|
function readACME
|
||||||
{
|
{
|
||||||
# Extract signature info from key:
|
# Extract signature info from key:
|
||||||
read hex exp <<< $(openssl rsa -in account.key -noout -text | tr -d ': \r\n' | sed -E 's/^.*modulus00([a-f0-9]+)publicExponent[0-9]+\(0x([0-9a-f]+)\).*$/\1 \2/')
|
read hex exp <<< $(openssl rsa -in account.key -noout -text | tr -d ': \r\n' | sed -E 's/^.*modulus00([a-f0-9]+)publicExponent[0-9]+\(0x([0-9a-f]+)\).*$/\1 \2/')
|
||||||
@ -50,16 +48,16 @@ function read_ACME
|
|||||||
thumb=$(echo -n "$jerk" | tr -d ' ' | short256 | hex2bin | b64u) # How many times can you b64 a bowl of ramen before it begins questioning its existence
|
thumb=$(echo -n "$jerk" | tr -d ' ' | short256 | hex2bin | b64u) # How many times can you b64 a bowl of ramen before it begins questioning its existence
|
||||||
}
|
}
|
||||||
|
|
||||||
function load_kid
|
function loadkid
|
||||||
{
|
{
|
||||||
kid=$1
|
kid=$1
|
||||||
if [ -z "$kid" -a -e "$CA.kid" ]; then kid=$(cat $CA.kid); fi
|
if [ -z "$kid" -a -e "kid" ]; then kid=$(cat kid); fi
|
||||||
if [ -n "$kid" ]; then
|
if [ -n "$kid" ]; then
|
||||||
sig='{"alg": "RS256", "kid": "'$kid'"}'
|
sig='{"alg": "RS256", "kid": "'$kid'"}'
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
function get_nonce
|
function getNonce
|
||||||
{
|
{
|
||||||
# Get a nonce (nigger):
|
# Get a nonce (nigger):
|
||||||
nonce_resp=$1
|
nonce_resp=$1
|
||||||
@ -69,127 +67,86 @@ function get_nonce
|
|||||||
grep -i 'replay-nonce' <<< "$nonce_resp" | tr -d "\r" | grep -Eo '[0-9a-zA-Z_\-]+$' # Fucking Windows line endings
|
grep -i 'replay-nonce' <<< "$nonce_resp" | tr -d "\r" | grep -Eo '[0-9a-zA-Z_\-]+$' # Fucking Windows line endings
|
||||||
}
|
}
|
||||||
|
|
||||||
# ZONEFILE UTILS
|
|
||||||
function czf { sed -i '/_ACME-CHALLENGE/d' "$1"; } # clear zone file
|
|
||||||
function szf # setup zone file
|
|
||||||
{
|
|
||||||
file=$1
|
|
||||||
shift
|
|
||||||
for tok in $@; do
|
|
||||||
echo _ACME-CHALLENGE 300 TXT $(echo -n "$tok.$thumb" | short256 | hex2bin | b64u) >> $file
|
|
||||||
done
|
|
||||||
}
|
|
||||||
function usoa # update SOA
|
|
||||||
{
|
|
||||||
inc=$(grep -Eo 'SOA [^ ]+ [^ ]+ [0-9]+' $1 | grep -Eo '[0-9]+$')
|
|
||||||
sed -ie 's/SOA\t\([^\t]*\)\t\([^\t]*\)\t[0-9]*/SOA \1 \2 '$((inc+1))'/' $1
|
|
||||||
}
|
|
||||||
|
|
||||||
# CHALLENGES
|
# CHALLENGES
|
||||||
|
|
||||||
function complete_challenges
|
function order
|
||||||
{
|
{
|
||||||
read_ACME # get thumb. It fucks up sig but I don't care, send_req fixes it.
|
readACME # get thumb. It fucks up sig but I don't care, sendreq fixes it.
|
||||||
declare -A chals toks
|
declare -a urls
|
||||||
urls=$(jq -r '.[]' <<< "$1")
|
i=0
|
||||||
while read url; do
|
doms=$(jq -r '.[]' <<< "$1")
|
||||||
read dom chalurl tok <<< "$(send_req $url | jq -r '.identifier.value+" "+(.challenges | .[] | select(.type == "dns-01") | .url+" "+.token)')"
|
while read dom; do
|
||||||
chals[$dom]="${chals[$dom]}$(base64 -w 0 <<< "$chalurl");"
|
urls[$i]=$(challenge "$(sendreq $dom)") # this is meant to be signed but it seems to work without it...? But sign it just in case it's a test-only thing.
|
||||||
toks[$dom]="${toks[$dom]}$(base64 -w 0 <<< "$tok");"
|
i=$((i+1))
|
||||||
done <<< "$urls"
|
done <<< "$doms"
|
||||||
for dom in ${!toks[@]}; do
|
|
||||||
apply_challenge $dom ${toks[$dom]}
|
|
||||||
done
|
|
||||||
systemctl reload named # Actually update DNS for real final7
|
systemctl reload named # Actually update DNS for real final7
|
||||||
declare -a pending
|
sleep 120 # Wait for DNS to update. Generally it won't have been requested in ages so it won't be in any caches.
|
||||||
for dom in ${!chals[@]}; do
|
for url in ${urls[@]}; do
|
||||||
IFS=';' read -a chalurls <<< ${chals[$dom]}
|
sendreq $url '{}' | jq '(.validationRecord | map(.hostname) | join(" "))+" "+.status' # need empty dict to tell server to validate challenge, empty body only checks status. Just another certified ACME moment.
|
||||||
for chalurl in ${chalurls[@]}; do
|
|
||||||
sleep 1 # Spam a bit less
|
|
||||||
rurl=$(base64 -d <<< $chalurl)
|
|
||||||
send_req $rurl '{}' > /dev/null # need empty dict to tell server to validate challenge, empty body only checks status. Just another certified ACME moment.
|
|
||||||
pending+=("$rurl")
|
|
||||||
done
|
|
||||||
done
|
done
|
||||||
# now we wait for validations
|
sleep 30 # Wait for challenges to complete - the previous call can return before the challenge completes.
|
||||||
dirty=1
|
for url in ${urls[@]}; do
|
||||||
timer=10
|
sendreq $url | jq '(.validationRecord | map(.hostname) | join(" "))+" "+.status'
|
||||||
backoff=1
|
|
||||||
tick=0
|
|
||||||
while [ $dirty -gt 0 ]; do
|
|
||||||
dirty=0
|
|
||||||
for url in ${pending[@]}; do
|
|
||||||
sleep 1
|
|
||||||
oof=$(send_req $url)
|
|
||||||
oof2=$(jq -r .status <<< "$oof")
|
|
||||||
nonce=$(get_nonce) # For some reason checking status doesn't come back with a nonce, or comes back with same nonce.
|
|
||||||
if [ $oof2 != valid ]; then dirty=1; fi
|
|
||||||
done
|
|
||||||
sleep $timer # This gets slower each iteration, to spam the server less
|
|
||||||
timer=$(($timer+$backoff))
|
|
||||||
tick=$(($tick+1))
|
|
||||||
if [ $tick -eq $backoff ]; then tick=0; backoff=$(($backoff+1)); fi
|
|
||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
function apply_challenge
|
function challenge
|
||||||
{
|
{
|
||||||
dnsname="/var/named/$(ifsrev $1 .).zone"
|
read dom url tok <<< $(jq -r '.identifier.value+" "+(.challenges | .[] | select(.type == "dns-01") | .url+" "+.token)' <<< "$1")
|
||||||
czf $dnsname
|
tik=$(echo -n "$tok.$thumb" | short256 | hex2bin | b64u)
|
||||||
szf $dnsname $(tr ';' '\n' <<< $2 | base64 -d | tr '\n' ' ') # Actually update the DNS
|
dnsname="/var/named/$(ifsrev $dom .).zone"
|
||||||
usoa $dnsname # And don't forget to update the SOA number
|
inc=$(grep -Eo 'SOA [^ ]+ [^ ]+ [0-9]+' $dnsname | grep -Eo '[0-9]+$')
|
||||||
|
if ! grep -i _ACME-CHALLENGE $dnsname > /dev/null; then echo >> $dnsname; echo "_ACME-CHALLENGE 300 TXT aa" >> $dnsname; fi
|
||||||
|
sed -i -e 's/^_ACME-CHALLENGE 300 TXT .*$/_ACME-CHALLENGE 300 TXT '$tik'/' -e 's/SOA\t\([^\t]*\)\t\([^\t]*\)\t[0-9]*/SOA \1 \2 '$((inc+1))'/' $dnsname # Actually update the DNS
|
||||||
|
echo $url # Then give back the verification URL to be used later
|
||||||
}
|
}
|
||||||
|
|
||||||
# CORE ACTIONS
|
# CORE ACTIONS
|
||||||
|
|
||||||
function gen_ACME_key { openssl genrsa -traditional 2048 > account.key; }
|
function genACMEkey { openssl genrsa -traditional 2048 > account.key; }
|
||||||
|
|
||||||
function register_acc
|
function registerAcc
|
||||||
{
|
{
|
||||||
# Create account:
|
# Create account:
|
||||||
read_ACME
|
readACME
|
||||||
url=$(echo $endpoints | jq -r .newAccount)
|
url=$(echo $endpoints | jq -r .newAccount)
|
||||||
req='{"termsOfServiceAgreed": true, "contact": ["mailto:zerglingman@fedora.email"], "externalAccountBinding":"zerglingman@fedora.email"}'
|
req='{"termsOfServiceAgreed": true, "contact": ["mailto:zerglingman@fedora.email"]}'
|
||||||
out=$(send_req "$url" "$req" yes)
|
out=$(sendreq "$url" "$req" yes)
|
||||||
echo $out >&2
|
|
||||||
loc=$(grep -i 'location' <<< "$out" | grep -io http.*$)
|
loc=$(grep -i 'location' <<< "$out" | grep -io http.*$)
|
||||||
load_kid $loc
|
loadkid $loc
|
||||||
echo $loc
|
echo $loc
|
||||||
}
|
}
|
||||||
|
|
||||||
function get_cert
|
function getcert
|
||||||
{
|
{
|
||||||
conf=$1
|
conf=$1
|
||||||
shift
|
shift
|
||||||
url=$(echo $endpoints | jq -r .newOrder)
|
url=$(echo $endpoints | jq -r .newOrder)
|
||||||
req='{"identifiers": ['
|
req='{"identifiers": ['
|
||||||
for n in $@; do
|
for n in $@; do
|
||||||
req=$req'{"type": "dns", "value": "'$n'"}, {"type": "dns", "value": "*.'$n'"}, ' # Do not put wildcard domains in; this will do it automatically. You still need to put them in the nuconf.
|
req=$req'{"type": "dns", "value": "'$n'"}, '
|
||||||
done
|
done
|
||||||
req=${req:0:-2}']}'
|
req=${req:0:-2}']}'
|
||||||
order=$(send_req $url "$req" yes)
|
order=$(sendreq $url "$req")
|
||||||
headers=$(sed -n 1,/^$/p <<< "$order")
|
|
||||||
order=$(sed 1,/^$/d <<< "$order")
|
|
||||||
# I can just access the headers lol
|
# I can just access the headers lol
|
||||||
# No I can't, assfucked by subshells again
|
orderurl=$(grep -i location <<< "$req_heads" | grep -io http.*$)
|
||||||
orderurl=$(grep -i location <<< "$headers" | grep -io http.*$)
|
|
||||||
auths=$(jq '.authorizations' <<< "$order")
|
auths=$(jq '.authorizations' <<< "$order")
|
||||||
finalise=$(jq -r '.finalize' <<< "$order")
|
finalise=$(jq -r '.finalize' <<< "$order")
|
||||||
complete_challenges "$auths"
|
order "$auths"
|
||||||
openssl req -new -key live.key -out live.csr -sha256 -noenc -config $conf -outform DER
|
openssl req -new -key live.key -out live.csr -sha256 -noenc -config $conf -outform DER
|
||||||
# I guess I should just include the conf file
|
# I guess I should just include the conf file
|
||||||
send_req $finalise '{"csr":"'$(cat live.csr | b64u)'"}'
|
sendreq $finalise '{"csr":"'$(cat live.csr | b64u)'"}'
|
||||||
certurl=$(send_req $orderurl | jq -r .certificate)
|
certurl=$(sendreq $orderurl | jq -r .certificate)
|
||||||
curl $certurl > out.crt
|
curl $certurl > out.crt
|
||||||
}
|
}
|
||||||
|
|
||||||
# SERVER COMMUNICATION
|
# SERVER COMMUNICATION
|
||||||
|
|
||||||
function send_req
|
function sendreq
|
||||||
{
|
{
|
||||||
load_kid # Just to make sure the sig is set correctly. It won't overwrite it unless it should be.
|
loadkid # Just to make sure the sig is set correctly. It won't overwrite it unless it should be.
|
||||||
url=$1; if [ -n "$2" ]; then req=$(b64u <<< "$2"); else req=""; fi
|
url=$1; if [ -n "$2" ]; then req=$(b64u <<< "$2"); else req=""; fi
|
||||||
if [ -z "$nonce" ]; then nonce=$(get_nonce); fi
|
if [ -z "$nonce" ]; then nonce=$(getNonce); fi
|
||||||
data=$(jq '.+{"nonce":"'$nonce'","url":"'$url'"}' <<< "$sig" | tr -d '\r\n' | tr -s ' ' ' ' | sed -e 's/{ /{/g' -e 's/ }/}/g') # Keys don't need to be sorted here, but they still are.
|
data=$(jq '.+{"nonce":"'$nonce'","url":"'$url'"}' <<< "$sig" | tr -d '\r\n' | tr -s ' ' ' ' | sed -e 's/{ /{/g' -e 's/ }/}/g') # Keys don't need to be sorted here, but they still are.
|
||||||
# I don't know why the URL has to be in the body that is sent to the URL.
|
# I don't know why the URL has to be in the body that is sent to the URL.
|
||||||
# ACME is a terrible protocol.
|
# ACME is a terrible protocol.
|
||||||
@ -199,14 +156,14 @@ function send_req
|
|||||||
req_resp=$(curl -isH "Content-type:application/jose+json" $url --data "$mexican" | tr -d "\r") # Here is the line that does the work
|
req_resp=$(curl -isH "Content-type:application/jose+json" $url --data "$mexican" | tr -d "\r") # Here is the line that does the work
|
||||||
req_heads=$(sed -n 1,/^$/p <<< "$req_resp")
|
req_heads=$(sed -n 1,/^$/p <<< "$req_resp")
|
||||||
req_resp=$(sed 1,/^$/d <<< "$req_resp")
|
req_resp=$(sed 1,/^$/d <<< "$req_resp")
|
||||||
nonce=$(get_nonce "$req_heads")
|
nonce=$(getNonce "$req_heads")
|
||||||
if [ -n "$3" ]; then printf "$req_heads"; echo; echo; fi
|
if [ -n "$3" ]; then echo "$req_heads"; fi
|
||||||
echo $req_resp
|
echo $req_resp
|
||||||
}
|
}
|
||||||
|
|
||||||
# MAIN
|
# MAIN
|
||||||
|
|
||||||
get_CA_URLs $1
|
getCAURLs $1
|
||||||
shift
|
shift
|
||||||
load_kid
|
loadkid
|
||||||
$@
|
$*
|
49
nuconf
49
nuconf
@ -1,49 +0,0 @@
|
|||||||
#This bit doesn't work for some reason, it complains about xmppAddr already existing, but then generates errors below because it doesn't exist, so fuck it, magic number.
|
|
||||||
#oid_section = new_oids
|
|
||||||
#[ new_oids ]
|
|
||||||
# RFC 6120 section 13.7.1.4 defines this OID
|
|
||||||
#xmppAddr = 1.3.6.1.5.5.7.8.5
|
|
||||||
|
|
||||||
[ req ]
|
|
||||||
|
|
||||||
default_bits = 2048
|
|
||||||
distinguished_name = distinguished_name
|
|
||||||
req_extensions = v3_extensions
|
|
||||||
x509_extensions = v3_extensions
|
|
||||||
|
|
||||||
# don't ask about the DN
|
|
||||||
prompt = no
|
|
||||||
|
|
||||||
[ distinguished_name ]
|
|
||||||
|
|
||||||
countryName = AU
|
|
||||||
stateOrProvinceName = TAS
|
|
||||||
|
|
||||||
commonName = rakka.au
|
|
||||||
|
|
||||||
[ v3_extensions ]
|
|
||||||
|
|
||||||
# for certificate requests (req_extensions)
|
|
||||||
# and self-signed certificates (x509_extensions)
|
|
||||||
|
|
||||||
keyUsage = digitalSignature,keyEncipherment
|
|
||||||
extendedKeyUsage = serverAuth
|
|
||||||
subjectAltName = @subject_alternative_name
|
|
||||||
|
|
||||||
[ subject_alternative_name ]
|
|
||||||
|
|
||||||
DNS.0 = rakka.au
|
|
||||||
otherName.0 = 1.3.6.1.5.5.7.8.5;UTF8:rakka.au
|
|
||||||
|
|
||||||
#Append the following for a server which handles multiple domain names:
|
|
||||||
DNS.1 = harpy.faith
|
|
||||||
otherName.1 = 1.3.6.1.5.5.7.8.5;UTF8:harpy.faith
|
|
||||||
DNS.2 = botegirl.parts
|
|
||||||
otherName.2 = 1.3.6.1.5.5.7.8.5;UTF8:botegirl.parts
|
|
||||||
|
|
||||||
DNS.3 = *.rakka.au
|
|
||||||
otherName.3 = 1.3.6.1.5.5.7.8.5;UTF8:*.rakka.au
|
|
||||||
DNS.4 = *.harpy.faith
|
|
||||||
otherName.4 = 1.3.6.1.5.5.7.8.5;UTF8:*.harpy.faith
|
|
||||||
DNS.5 = *.botegirl.parts
|
|
||||||
otherName.5 = 1.3.6.1.5.5.7.8.5;UTF8:*.botegirl.parts
|
|
Loading…
Reference in New Issue
Block a user