-
Notifications
You must be signed in to change notification settings - Fork 10
/
make-master-secret-log
executable file
·218 lines (211 loc) · 7.35 KB
/
make-master-secret-log
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
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
#!/bin/sh
# make-master-secret-log (part of ossobv/vcutil) // wdoekes/2022
# // Public Domain
#
# Makes a "(pre)-master-secret log" file, readable by Wireshark.
#
# If you want Wireshark to decrypt TLS traffic, you need to record the
# TLS secrets when they are used. This script documents how to do so for
# haproxy and simplifies creating a valid keylog file.
#
# Usage:
#
# cat webserver.log | make-master-secret-log -u
#
# Input is fed through stdin, and should contain key value pairs with
# TLS or TLSv1.3 secrets, like SI=<sessionid> and SK=<sessionkey>.
#
# Output looks like this for TLS:
#
# RSA Session-ID:<session_id> Master-Key:<session_key>
#
# Output looks like this for TLSv1.3:
#
# CLIENT_HANDSHAKE_TRAFFIC_SECRET <client_random> <client_secret>
# SERVER_HANDSHAKE_TRAFFIC_SECRET <client_random> <server_secret>
# CLIENT_TRAFFIC_SECRET_0 <client_random> <client_secret_0>
# SERVER_TRAFFIC_SECRET_0 <client_random> <server_secret_0>
# EXPORTER_SECRET <client_random> <exporter_secret>
#
# Expected log format:
#
# ... TLSK=+ SI=<sessionid> SK=<sessionkey> ... CHTS=<client_secret> ...
#
# Expected invocation:
#
# cat webserver.log | sed -ne 's/.* TLSK=+ \(.*\)/\1/p' | sort -u |
# make-master-secret-log | uniq
#
# Alternative invocation (shorthand for above):
#
# cat webserver.log | make-master-secret-log -u
#
# See also:
# - https://firefox-source-docs.mozilla.org/security/nss/legacy/key_log_format/
# - https://wiki.wireshark.org/TLS#using-the-pre-master-secret
# - https://cbonte.github.io/haproxy-dconv/2.2/configuration.html#
# 3.2-tune.ssl.keylog
#
#
# LOG FORMAT
# ----------
#
# OBSERVE: For haproxy, you need 'tune.ssl.keylog on' in the global
# section. Otherwise none of these variables are available.
#
# make-master-secret-log expects the following variable to be set as a simple
# sentinel (this is only to avoid dupes). The relevant key-value pairs are
# expected to come _after_ this.
#
# key-value haproxy log-format
# --------- ------------------
# TLSK=+ TLSK=+
#
# These should be set for TLS:
#
# key-value haproxy log-format
# --------- ------------------
# SI=<session_id> SI=%[ssl_fc_session_id,hex]
# SK=<session_key> SK=%[ssl_fc_session_key,hex]
#
# These should be set for TLSv1.3 (some appear optional):
#
# key-value haproxy log-format
# --------- ------------------
# CR=<client_random> CR=%[ssl_fc_client_random,hex]
# CETS=<client_early> (opt.) CETS=%[ssl_fc_client_early_traffic_secret]
# CHTS=<client_secret> CHTS=%[ssl_fc_client_handshake_traffic_secret]
# SHTS=<server_secret> SHTS=%[ssl_fc_server_handshake_traffic_secret]
# CTS0=<client_server_0> CTS0=%[ssl_fc_client_traffic_secret_0]
# STS0= STS0=%[ssl_fc_server_traffic_secret_0]
# ES= ES=%[ssl_fc_exporter_secret]
# EES= (opt.) EES=%[ssl_fc_early_exporter_secret]
#
# For haproxy, you can add both sets to the log-format. Unset variables get
# a '-'.
#
#
# HAPROXY LOG FORMAT
# ------------------
#
# haproxy.cfg:
#
# global
# log global
# tune.ssl.keylog on
#
# frontend https-in
# # If you use template unit files, for haproxy@, you'll also want this:
# # [Service]
# # SyslogIdentifier=haproxy@%i
# log stdout format short daemon info
# # The log format (make sure the '...' gets other info as well).
# log-format %ci:%cp\ ... TLSK=+\ SI=%[ssl_fc_session_id,hex]\
# SK=%[ssl_fc_session_key,hex]\ CR=%[ssl_fc_client_random,hex]\
# CETS=%[ssl_fc_client_early_traffic_secret]\
# CHTS=%[ssl_fc_client_handshake_traffic_secret]\
# SHTS=%[ssl_fc_server_handshake_traffic_secret]\
# CTS0=%[ssl_fc_client_traffic_secret_0]\
# STS0=%[ssl_fc_server_traffic_secret_0]\
# ES=%[ssl_fc_exporter_secret]\ EES=%[ssl_fc_early_exporter_secret]
#
#
# EXAMPLES
# -------------
EXAMPLE_INPUT="\
mei 25 22:35:35 load-balancer-1 haproxy@...[25399]: 1.2.3.4:42734 \
[25/May/2022:22:35:35.542] https-in~ bk_k8s/node2.zl-ingress-http \
32/0/1/1/34 403 279 - - ---- 248/248/1/0/0 0/0 {curl/7.68.0} \
\"POST /webservice HTTP/1.1\" \
TLSK=+ SI=C69A SK=8032 CR=- CETS=- CHTS=- SHTS=- CTS0=- STS0=- ES=- EES=-
mei 25 22:35:36 load-balancer-1 haproxy@...[25399]: 5.5.5.5:42735 \
[25/May/2022:22:35:36.542] https-in~ bk_k8s/node2.zl-ingress-http \
32/0/1/1/34 403 279 - - ---- 248/248/1/0/0 0/0 {curl/7.69.0} \
\"POST /webservice HTTP/1.1\" \
TLSK=+ SI=- SK=- CR=36A2 CETS=- CHTS=0f SHTS=5d CTS0=45 STS0=1e ES=db EES=-"
EXAMPLE_OUTPUT="\
RSA Session-ID:C69A Master-Key:8032
CLIENT_HANDSHAKE_TRAFFIC_SECRET 36A2 0f
SERVER_HANDSHAKE_TRAFFIC_SECRET 36A2 5d
CLIENT_TRAFFIC_SECRET_0 36A2 45
SERVER_TRAFFIC_SECRET_0 36A2 1e
EXPORTER_SECRET 36A2 db"
set -eu
if test $# -eq 1 && test "$1" = "-u"; then
test -t 0 && echo "(expecting input on stdin; ^D when done)" >&2 || true
# NOTE: This still causes dupes for TLS ("RSA") when SESSION_ID and
# SESSION_KEY are the same, but CLIENT_RANDOM is different.
# Therefore a uniq at the end.
sed -ne 's/.*TLSK=+ \(.*\)/\1/p' | sort -u | "$0" | uniq
exit $?
elif test $# -ge 1; then
echo "Usage: cat webserver.log | $0 -u" >&2
echo >&2
echo "Example input:" >&2
echo >&2
echo "$EXAMPLE_INPUT" | sed -e 's/^/ /'
echo >&2
echo "Example output:" >&2
echo >&2
CREATED_OUTPUT=$(printf '%s\n' "$EXAMPLE_INPUT" | "$0")
echo "$CREATED_OUTPUT" | sed -e 's/^/ /' >&2
echo >&2
if test "$CREATED_OUTPUT" != "$EXAMPLE_OUTPUT"; then
echo "ERROR: self-test failed" >&2
exit 2
fi
exit 1
fi
while read -r line; do
SESSION_ID=
SESSION_KEY=
#
CLIENT_RANDOM=
#
CLIENT_HANDSHAKE_TRAFFIC_SECRET=
SERVER_HANDSHAKE_TRAFFIC_SECRET=
CLIENT_TRAFFIC_SECRET_0=
SERVER_TRAFFIC_SECRET_0=
EXPORTER_SECRET=
#
CLIENT_EARLY_TRAFFIC_SECRET=
EARLY_EXPORTER_SECRET=
for arg in $line; do
if test "${arg#*=}" != "$arg"; then
key=${arg%%=*}
value=${arg#*=}
if test -n "$value" && test "$value" != "-"; then
case $key in
# TLSv1.3:
CR) CLIENT_RANDOM=$value;;
CETS) CLIENT_EARLY_TRAFFIC_SECRET=$value;;
CHTS) CLIENT_HANDSHAKE_TRAFFIC_SECRET=$value;;
SHTS) SERVER_HANDSHAKE_TRAFFIC_SECRET=$value;;
CTS0) CLIENT_TRAFFIC_SECRET_0=$value;;
STS0) SERVER_TRAFFIC_SECRET_0=$value;;
ES) EXPORTER_SECRET=$value;;
EES) EARLY_EXPORTER_SECRET=$value;;
# Older TLS:
SI) SESSION_ID=$value;;
SK) SESSION_KEY=$value;;
esac
fi
fi
done
if test -n "$SESSION_ID"; then
echo "RSA Session-ID:$SESSION_ID Master-Key:$SESSION_KEY"
fi
if test -n "$CLIENT_RANDOM"; then
for key in \
CLIENT_HANDSHAKE_TRAFFIC_SECRET \
SERVER_HANDSHAKE_TRAFFIC_SECRET \
CLIENT_TRAFFIC_SECRET_0 SERVER_TRAFFIC_SECRET_0 \
EXPORTER_SECRET \
CLIENT_EARLY_TRAFFIC_SECRET EARLY_EXPORTER_SECRET; do
eval value='$'${key}
if test -n "$value"; then
echo "$key $CLIENT_RANDOM $value"
fi
done
fi
done