# Certificate installation and post-issuance notification

# at least one of 'certificate' or 'certificate-chain' is required
cat >"/etc/lacme/lacme-certs.conf.d/bad1.conf" <<- EOF
	[bad1]
	certificate-key = /etc/lacme/bad1.key
	subject = /CN=bad1.$DOMAINNAME
EOF
! lacme newOrder bad1 2>"$STDERR" || fail newOrder bad1
grepstderr -Fxq "[bad1] Warning: Missing 'certificate' and 'certificate-chain', skipping"

# 'subject' is required
cat >"/etc/lacme/lacme-certs.conf.d/bad2.conf" <<- EOF
	[bad2]
	certificate-key = /etc/lacme/bad2.key
	certificate = /etc/lacme/bad2.crt
EOF
! lacme newOrder bad2 2>"$STDERR" || fail newOrder bad2
grepstderr -Fxq "[bad2] Warning: Couldn't generate CSR, skipping"

# 'certificate-key' is required
cat >"/etc/lacme/lacme-certs.conf.d/bad3.conf" <<- EOF
	[bad3]
	certificate = /etc/lacme/bad3.crt
	subject = /CN=bad3.$DOMAINNAME
EOF
! lacme newOrder bad3 2>"$STDERR" || fail newOrder bad3
grepstderr -Fxq "[bad3] Warning: Couldn't generate CSR, skipping"


check_spki() {
    local p1="$1" p2="$2" s1 s2
    s1="$(openssl x509 -in "$p1" -noout -pubkey \
        | openssl pkey -pubin -outform DER \
        | openssl dgst -sha256 \
        | sed 's/.*=\s*//')"
    s2="$(openssl pkey -in "$p2" -pubout -outform DER \
        | openssl dgst -sha256 \
        | sed 's/.*=\s*//')"
    if [ -n "$s1" ] && [ "$s1" = "$s2" ]; then
        return 0
    else
        printf "%s != %s\\n" "$s1" "$s2" >&2
        return 1
    fi
}
check_chain() {
    local priv="$1" chain="$2" leaf="${3-}" pem0

    csplit -f "${chain%.crt}.chain.pem" "$chain" \
        "/-----BEGIN CERTIFICATE-----/" "{*}"

    pem0="${chain%.crt}.chain.pem00"
    if [ ! -s "$pem0" ]; then
        # 00 is empty, leaf cert is at 01
        rm -f -- "$pem0"
        pem0="${chain%.crt}.chain.pem01"
    fi
    test -s "$pem0" || return 1
    check_spki "$pem0" "$priv"

    if [ -n "$leaf" ]; then
        diff --ignore-blank-lines --unified "$pem0" "$leaf" || return 1
    fi

    leaf="${chain%.crt}.leaf.pem"
    mv -T -- "$pem0" "$leaf"

    intermediates="${chain%.crt}.intermediates.pem"
    sed "/^$/d" "${chain%.crt}.chain.pem"[0-9]* >"$intermediates"
    test -s "$intermediates" || return 1 # ensure there is at least one intermediate

    openssl verify -trusted /usr/share/lacme/ca-certificates.crt \
        -untrusted "$intermediates" \
        -purpose sslserver -x509_strict \
        -show_chain \
        -- "$leaf" || return 1
}

# 'certificate' installs only the leaf certificate
openssl genpkey -algorithm RSA -out /etc/lacme/test1.key
subject="/CN=$(head -c10 /dev/urandom | base32 -w0 | tr "A-Z" "a-z").$DOMAINNAME"
cat >"/etc/lacme/lacme-certs.conf.d/test1.conf" <<- EOF
	[test1]
	certificate-key = /etc/lacme/test1.key
	certificate = /etc/lacme/test1.crt
	subject = $subject
EOF

lacme newOrder test1 2>"$STDERR" || fail newOrder test1
test /etc/lacme/test1.crt -nt /etc/lacme/test1.key
sed -n "0,/^-----END CERTIFICATE-----$/ p" /etc/lacme/test1.crt >/etc/lacme/test1.pem
diff --unified /etc/lacme/test1.crt /etc/lacme/test1.pem
check_spki /etc/lacme/test1.crt /etc/lacme/test1.key


# 'certificate-chain' appends the chain of trust
openssl genpkey -algorithm RSA -out /etc/lacme/test2.key
cat >"/etc/lacme/lacme-certs.conf.d/test2.conf" <<- EOF
	[test2]
	certificate-key = /etc/lacme/test2.key
	certificate-chain = /etc/lacme/test2.crt
	subject = $subject
EOF

lacme newOrder test2 2>"$STDERR" || fail newOrder test2
test /etc/lacme/test2.crt -nt /etc/lacme/test2.key
check_chain /etc/lacme/test2.key /etc/lacme/test2.crt

# 'certificate' + 'certificate-chain'
openssl genpkey -algorithm RSA -out /etc/lacme/test3.key
cat >"/etc/lacme/lacme-certs.conf.d/test3.conf" <<- EOF
	[test3]
	certificate-key = /etc/lacme/test3.key
	certificate = /etc/lacme/test3.pem
	certificate-chain = /etc/lacme/test3.crt
	subject = $subject
EOF

lacme newOrder test3 2>"$STDERR" || fail newOrder test3
test /etc/lacme/test3.pem -nt /etc/lacme/test3.key
test /etc/lacme/test3.crt -nt /etc/lacme/test3.key
check_chain /etc/lacme/test3.key /etc/lacme/test3.crt /etc/lacme/test3.pem

st="$(stat -c "%U:%G %#a" /etc/lacme/test3.pem)"
[ "$st" = "root:root 0644" ]
st="$(stat -c "%U:%G %#a" /etc/lacme/test3.crt)"
[ "$st" = "root:root 0644" ]

# owner user
openssl genpkey -algorithm RSA -out /etc/lacme/test4.key
cat >"/etc/lacme/lacme-certs.conf.d/test4.conf" <<- EOF
	[test4]
	certificate-key = /etc/lacme/test4.key
	certificate = /etc/lacme/test4.pem
	certificate-chain = /etc/lacme/test4.crt
	owner = nonexistent-user
	subject = $subject
EOF

! lacme newOrder test4 2>"$STDERR" || fail newOrder test4
grepstderr -Fxq "getpwnam(nonexistent-user)"
! test -e /etc/lacme/test4.pem
! test -e /etc/lacme/test4.crt

sed -ri "s/^owner\\s*=.*/owner = nobody/" /etc/lacme/lacme-certs.conf.d/test4.conf
lacme newOrder test4 2>"$STDERR" || fail newOrder test4
st="$(stat -c "%U:%G %#a" /etc/lacme/test4.pem)"
[ "$st" = "nobody:root 0644" ]
st="$(stat -c "%U:%G %#a" /etc/lacme/test4.crt)"
[ "$st" = "nobody:root 0644" ]

# owner user:group
openssl genpkey -algorithm RSA -out /etc/lacme/test5.key
cat >"/etc/lacme/lacme-certs.conf.d/test5.conf" <<- EOF
	[test5]
	certificate-key = /etc/lacme/test5.key
	certificate = /etc/lacme/test5.pem
	certificate-chain = /etc/lacme/test5.crt
	owner = nobody:nonexistent-group
	subject = $subject
EOF

! lacme newOrder test5 2>"$STDERR" || fail newOrder test5
grepstderr -Fxq "getgrnam(nonexistent-group)"
! test -e /etc/lacme/test5.pem
! test -e /etc/lacme/test5.crt

sed -ri "s/^owner\\s*=.*/owner = nobody:nogroup/" /etc/lacme/lacme-certs.conf.d/test5.conf
lacme newOrder test5 2>"$STDERR" || fail newOrder test5
st="$(stat -c "%U:%G %#a" /etc/lacme/test5.pem)"
[ "$st" = "nobody:nogroup 0644" ]
st="$(stat -c "%U:%G %#a" /etc/lacme/test5.crt)"
[ "$st" = "nobody:nogroup 0644" ]

# umask restrictions (also test empty values)
openssl genpkey -algorithm RSA -out /etc/lacme/test6.key
cat >"/etc/lacme/lacme-certs.conf.d/test6.conf" <<- EOF
	[test6]
	certificate-key = /etc/lacme/test6.key
	certificate-chain = /etc/lacme/test6.crt
	certificate =
	mode =
	owner =
	subject = $subject
EOF

( umask 0077 && lacme newOrder test6 2>"$STDERR" || fail newOrder test6 )
! test -e /etc/lacme/test6.pem
st="$(stat -c "%U:%G %#a" /etc/lacme/test6.crt)"
[ "$st" = "root:root 0600" ]

# mode
openssl genpkey -algorithm RSA -out /etc/lacme/test7.key
cat >"/etc/lacme/lacme-certs.conf.d/test7.conf" <<- EOF
	[test7]
	certificate-key = /etc/lacme/test7.key
	certificate = /etc/lacme/test7.pem
	certificate-chain = /etc/lacme/test7.crt
	mode = 0400
	subject = $subject
EOF

lacme newOrder test7 2>"$STDERR" || fail newOrder test7
st="$(stat -c "%U:%G %#a" /etc/lacme/test7.pem)"
[ "$st" = "root:root 0400" ]
st="$(stat -c "%U:%G %#a" /etc/lacme/test7.crt)"
[ "$st" = "root:root 0400" ]

# post-issuance notification
openssl genpkey -algorithm RSA -out /etc/lacme/test8.key
cat >"/etc/lacme/lacme-certs.conf.d/test8.conf" <<- EOF
	[test8]
	certificate-key = /etc/lacme/test8.key
	certificate-chain = /etc/lacme/test8.crt
	subject = $subject
	notify = touch /tmp/test8.notify
EOF

lacme newOrder test8 2>"$STDERR" || fail newOrder test8
grepstderr -Fxq "Running notification command \`touch /tmp/test8.notify\`"
test -e /tmp/test8.notify

rm -f /tmp/test8.notify
lacme newOrder test8 2>"$STDERR" || fail newOrder test8
ngrepstderr -Fq "Running notification command"
! test -e /tmp/test8.notify

# vim: set filetype=sh :