summaryrefslogtreecommitdiffstats
path: root/certs/gencerts.sh
blob: b25a7d36a85cd81e5e717808c0cefa74e67d457b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
#!/bin/sh

set -ue
PATH=/usr/bin:/bin

if [ -n "${GNUPGBIN:-}" ]; then
    GPG="$GNUPGBIN"
else
    GPG=gpg
fi
GPG_OPTS='--no-auto-check-trustdb --batch --no-verbose --yes'

usage() {
    echo "Usage: $0 /path/to/certs.asc" >&2
    exit 1
}

header() {
    local i hdr
    [ "$typ" = mdwn ] && printf '\n### %s ###\n' "$*" \
                      || printf '\n%s\n%s\n' "$*" "$(for i in $(seq 1 ${#*}); do printf '%c' =; done)"
}

x509fpr() {
    local msg="$1" host pub h spki
    host="${msg%%,*}"; host="${host%% *}"; host="${host#\`}"
    pub="$DIR/${host%%:*}.pub"
    spki=$(openssl pkey -pubin -outform DER <"$pub" | openssl dgst -sha256 | sed -nr 's/^[^=]+=\s*//p')
    [ "$typ" = mdwn ] && printf '\n[%s](https://crt.sh/?spkisha256=%s&iCAID=16418&exclude=expired)\n\n' "$msg" "$spki" \
                      || printf '\n%s\n\n:   X.509: https://crt.sh/?spkisha256=%s&iCAID=16418&exclude=expired\n    SPKI:\n' \
                                "$(printf '%s' "$msg" | tr -d '`' )" "$spki"
    [ "$typ" = mdwn ] && indent=":${indent#?}"
    for h in sha1 sha256; do
        x509fpr2 "$h" "$pub"
    done

    local backup=$(find "$DIR" -maxdepth 1 -type f -name "${host%%:*}.pub.back*")
    if [ "$backup" -a "$typ" != mdwn ]; then
        echo "    Backup SPKI:"
        for pub in $backup; do
            x509fpr2 sha256 "$pub"
        done
    fi
}
x509fpr2() {
    local h="$1" pub="$2" str dgst
    [ "$typ" = mdwn ] && str= || str='  '
    str="$str$(printf '%-6s' "$h" | tr '[a-z]' '[A-Z]')"
    dgst="$(openssl pkey -pubin -outform DER <"$pub" | openssl dgst -"$h" -binary | base64)"
    hd=$(printf '%s' "$dgst" | base64 -d | xxd -c256 -p | tr '[a-f]' '[A-F]' | sed -e 's/../&:/g' -e 's/:$//')
    if [ $((${#str} + 1 + ${#hd})) -le 72 ]; then
        printf '%s %s\n' "$indent$str" "$hd"
    else
        printf '%s %s\n' "$indent$str" "$dgst"
    fi
    indent=" ${indent#?}"
}

sshfpr() {
    local msg="$1" host h fpr str
    host="${msg%%,*}"; host="${host%% *}"; host="${host#*@}"; host="${host#\`}"; host="${host%\`}"
    [ "$typ" = mdwn ] && printf '\n%s\n\n' "$msg" || { printf '\n%s\n\n' "$msg" | tr -d '`'; }
    [ "${host#*:}" != 22 ] || host="${host%%:*}"
    indent=":${indent#?}"
    [ "$typ" = mdwn ] && str= || str='  '
    for h in MD5 SHA256; do
        ssh-keygen -E "$h" -f "$DIR/../ssh_known_hosts" -lF "${host#*@}"
    done | sed -nr 's/^[^ #]+\s+//p' | sed -r 's/^\S+\s+([^:]+):/\1 /' |
    while read h fpr; do
        str2="$str$(printf '%-6s' "$h" | tr '[a-z]' '[A-Z]')"
        printf '%s %s\n' "$indent$str2" "$fpr"
        indent=" ${indent#?}"
    done
}

allfpr() {
    local typ="$1"
    [ "$typ" = mdwn ] && indent='        ' || indent='    '

    header 'IMAP server'
    x509fpr '`imap.fripost.org:993` (IMAP over SSL), `sieve.fripost.org:4190` (ManageSieve, `STARTTLS`)'

    header 'SMTP servers'
    x509fpr '`smtp.fripost.org:587` (Mail Submission Agent, `STARTTLS`)'
    x509fpr '`mx1.fripost.org:25` (1st Mail eXchange, `STARTTLS`)'
    x509fpr '`mx2.fripost.org:25` (2nd Mail eXchange, `STARTTLS`)'

    header 'Web servers'
    x509fpr '`fripost.org:443`, `www.fripost.org:443` (website), `wiki.fripost.org:443` (wiki)'
    x509fpr '`mail.fripost.org:443`, `webmail.fripost.org:443` (webmail)'
    x509fpr '`lists.fripost.org:443` (list manager)'
    x509fpr '`git.fripost.org:443` (git server and its web interface)'

    header 'SSH server'
    sshfpr '`gitolite@git.fripost.org:22`'
}


[ $# -eq 1 ] || usage

asc="$1"
asc2=$(mktemp --tmpdir)
src=$(mktemp --tmpdir)
src2=$(mktemp --tmpdir)
mdwn="${asc%.asc}.mdwn"
mdwn2=$(mktemp --tmpdir)
DIR="$(dirname "$0")/public"
VCS_BROWSER='https://git.fripost.org/fripost-ansible'
trap 'rm -f "$src" "$src2" "$asc2" "$mdwn2"' EXIT

if [ -s "$asc" ]; then
    "$GPG" $GPG_OPTS --logger-file=/dev/null --output="$src" -- "$asc"
fi


# Generate ASCII file to be clearsigned
cat >"$src2" << EOF
The following is an up-to date list of SHA-1 and SHA-256 fingerprints of
all SPKI (Subject Public Key Info) of each X.509 certificate Fripost
uses on its publicly available services.  Please consider any mismatch
as a man-in-the-middle attack, and let us know immediately! --
admin@fripost.org


These certificates are all issued by the Let's Encrypt Certificate
Authority, and are submitted to Certificate Transparency logs. You can
view all issued Let's Encrypt certificates at crt.sh:

    https://crt.sh/?Identity=%25fripost.org&iCAID=16418

The SPKI of our X.509 certificates are also available in PEM format at:

    $VCS_BROWSER/tree/certs/public ,

Git repository from which this fingerprint list was generated, at commit ID
$(git --no-pager --git-dir="$DIR/../../.git" --work-tree="$DIR" log -1 --pretty=format:'%h from %aD' -- "$DIR").

EOF
allfpr asc >>"$src2"


# Generate markdown file
cat >"$mdwn2" << EOF
# Certificates at Fripost

The following is an up-to date list of SHA-1 and SHA-256 fingerprints of
all SPKI (Subject Public Key Info) of each X.509 certificate Fripost
uses on its publicly available services.  Please consider any mismatch
as a man-in-the-middle attack, and let us know immediately!  (See also
the [signed version of this page](/certs.asc).)
-- [the admin team](mailto:admin@fripost.org)


These certificates are all issued by the [Let's Encrypt Certificate
Authority](https://letsencrypt.org), and are submitted to [Certificate
Transparency logs](https://www.certificate-transparency.org).
You can view all issued Let's Encrypt certificates at
[crt.sh](https://crt.sh/?Identity=%25fripost.org&iCAID=16418).
The SPKI of our X.509 certificates are also available in PEM format
under our [Git repository]($VCS_BROWSER/tree/certs/public),
from which this fingerprint list was [generated]($VCS_BROWSER/tree/certs/gencerts.sh), at
$(git --no-pager --git-dir="$DIR/../../.git" --work-tree="$DIR" log -1 --pretty=format:"[Commit ID %h from %aD]($VCS_BROWSER/tree/certs/public?id=%H)" -- "$DIR").

EOF
allfpr mdwn >>"$mdwn2"
echo >>"$src2"


if diff -u --color=auto --label "a/${asc%.asc}" --label "b/${asc%.asc}" -- "$src" "$src2" &&
   diff -q -- "$mdwn" "$mdwn2" >/dev/null; then
    echo 'The fingerprint list is up to date.'
else
    "$GPG" $GPG_OPTS --output="$asc2" --clearsign -- "$src2"
    cp -f "$asc2" "$asc"
    cp -f "$mdwn2" "$mdwn"
    echo ================================ 
    echo "The fingerprint lists ($asc and $mdwn) have been updated!"
    echo '/!\ You should now push the changes to the wiki. /!\'
fi