https://github.com/mercurytechnologies/tls-sslkeylogfile
`SSLKEYLOGFILE`-based TLS session key extraction for Haskell
https://github.com/mercurytechnologies/tls-sslkeylogfile
haskell tls
Last synced: 4 months ago
JSON representation
`SSLKEYLOGFILE`-based TLS session key extraction for Haskell
- Host: GitHub
- URL: https://github.com/mercurytechnologies/tls-sslkeylogfile
- Owner: MercuryTechnologies
- Created: 2025-03-07T01:37:28.000Z (over 1 year ago)
- Default Branch: main
- Last Pushed: 2025-03-14T17:00:52.000Z (over 1 year ago)
- Last Synced: 2025-09-04T06:52:01.370Z (10 months ago)
- Topics: haskell, tls
- Language: Haskell
- Homepage:
- Size: 22.5 KB
- Stars: 0
- Watchers: 4
- Forks: 1
- Open Issues: 2
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSES/BSD-3-Clause.txt
Awesome Lists containing this project
README
# tls-sslkeylogfile
This package adds support for the [`SSLKEYLOGFILE` standard](https://www.ietf.org/archive/id/draft-thomson-tls-keylogfile-00.html) to Haskell programs using the `tls` and/or `http-client` libraries.
This packages uses the functionality built into the Haskell `tls` library to extract the *session keys* of TLS sessions and store them in the `SSLKEYLOGFILE` format.
In TLS, the session keys are ephemeral *symmetric* keys used to encrypt just the data for each session.
They are generated and exchanged during the TLS handshake, and with modern TLS cipher suites with [Perfect Forward Secrecy], are handled via completely separate machinery (Diffie-Hellman) from the server's private key, the latter only being used to sign the handshake.
As far as key material is concerned, session keys are not very sensitive: they are generated for every session and grabbing them for debugging only allows access to the traffic for which the keys are known.
[Perfect Forward Secrecy]: https://en.wikipedia.org/wiki/Forward_secrecy
Using session keys allows for (relatively) easy debugging of HTTPS traffic using commonly-available packet sniffers like Wireshark *without altering the traffic at all*, and without wider security impacts like e.g. adding local TLS certification authorities to the system keyring.
For more details on TLS interception using session keys, see: .
## Related work
- [mitmproxy](https://mitmproxy.org/) - an intercepting TLS proxy with a lot of features.
It can operate as a proxy with fake certificates in various modes including capturing raw traffic and tampering with it, acting as a traditional HTTPS proxy, and more.
It's really cool.
However, the fake certificates mode can be unfortunate since they require certificate configuration in the application and are not transparent: you can't use mitmproxy to debug TLS implementation bugs, for instance, since it changes the traffic to intercept it.
- [clipper](https://github.com/lf-/clipper) - a fully integrated TLS session-key-log based packet sniffer for Linux by the same author as this package.
Clipper does the same thing as this package for rustls and OpenSSL with no application-level changes, implemented by injecting code into the process.
It captures traffic transparently and can either generate pcapng files with included keys or decode traffic on-the-fly to display it in Chrome DevTools.
However, it does not support either extracting keys from Haskell or capturing traffic on macOS.
## Usage
Set up tls-sslkeylogfile on a simple program (see [examples/demo/Demo.hs](./examples/demo/Demo.hs)):
```haskell
import Network.TLS.SSLKeyLogFile
import Network.HTTP.Client (parseRequest, httpLbs, Response (..))
main :: IO ()
main = do
man <- makeManager
req <- parseRequest "https://example.com/index.html"
resp <- httpLbs req man
putStrLn $ "The status code was: " ++ show (responseStatus resp)
```
Then run it with some interception:
In one terminal, capture some packets (tcpdump can equally be used):
```
$ tshark -w pakits.pcapng -i en9 'port 443'
Capturing on 'REDACTED: en9'
322 ^C
```
In another, run the program with `SSLKEYLOGFILE` set:
```
$ SSLKEYLOGFILE=keys.log cabal run keylogfile-demo
The status code was: Status {statusCode = 200, statusMessage = "OK"}
```
After the debugee finishes, the `tshark` command should be CTRL-C'd.
`keys.log` will look like the following:
```
SERVER_HANDSHAKE_TRAFFIC_SECRET aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
CLIENT_HANDSHAKE_TRAFFIC_SECRET aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
SERVER_TRAFFIC_SECRET_0 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
CLIENT_TRAFFIC_SECRET_0 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
```
The actual keys are replaced with placeholders here for readability.
This is a TLS 1.3 session because there are lines that are not tagged `CLIENT_RANDOM`.
Put the keys into the pcapng so the analysis tools work nicely:
```
$ editcap --inject-secrets tls,keys.log pakits.pcapng pakits2.pcapng
```
Then, look at the packets with tshark:
```
$ tshark -r pakits2.pcapng -T fields -e '_ws.col.Info' --display-filter http
GET /index.html HTTP/1.1
HTTP/1.1 200 OK (text/html)
```
Here's our traffic! If you wanted a nicer UX of looking at it, just open the pcapng file in Wireshark, the encrypted traffic will be right there decrypted for you.