From 545a989d99f4b22c2d78f8ea29da5b2d8bb12ea4 Mon Sep 17 00:00:00 2001 From: Alba Mendez Date: Sun, 2 Jun 2019 02:07:16 +0200 Subject: [PATCH] Update documentation, CHANGELOG and example --- CHANGELOG.md | 10 +++ README.md | 184 ++++++++++++++++++++++++++++++++++++++------- examples/server.js | 10 +-- 3 files changed, 173 insertions(+), 31 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 265978a..fc879a2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,16 @@ # Changelog All notable changes will be documented in this file. +## next + +- use SSLKEYLOGFILE env var as default +- replace `update_log`/`get_session_key` with new `hook*` API +- TLSv1.3 support + implement polyfill for keylog API introduced in Node 12.3 +- add compatibility with Node 10.0-10.7 and 12+ +- native module no longer built for Node 12.3+ +- some refactoring and changes to the build process and C++ +- minor API improvements, rename to camel case + ## [0.1.1] - 2018-11-23 - testing npm release with Travis-CI diff --git a/README.md b/README.md index 23649ac..1232af7 100644 --- a/README.md +++ b/README.md @@ -4,20 +4,130 @@ [![NPM](https://nodei.co/npm/sslkeylog.png)](https://nodei.co/npm/sslkeylog/) -**sslkeylog** is a Node.js module for generating SSLKEYLOG, which can be used later by Wireshark to decrypt SSL connections. This method works with any TLS cipher suite including elliptic curves crypto. +**sslkeylog** is a module for easy generation of SSLKEYLOG files, which can be used later by Wireshark to decrypt SSL connections. This method works with any TLS cipher suite including elliptic curves crypto, and works regardless of the TLS version. + +**sslkeylog** also allows one to use the [keylog API](https://nodejs.org/docs/latest/api/tls.html#tls_event_keylog_1) introduced in Node.JS 12.3.0, in earlier versions of Node (up to v10). See [use as a polyfill](#use-as-a-polyfill). Further reading about SSLKEYLOG: * [SSL/TLS Decryption: uncovering secrets](https://sharkfesteurope.wireshark.org/assets/presentations17eu/15.pdf) (PDF, SharkFest'17) * [Decrypting TLS browser traffic with Wireshark: the easy way](https://jimshaver.net/2015/02/11/decrypting-tls-browser-traffic-with-wireshark-the-easy-way/) -### Installation +[Node.js](https://nodejs.org/) v10+ is **required**. Tested on v10 (LTS) and v11 (CURRENT), OS X and Linux. + + +## Usage + +### Getting started + +Install the module: + +~~~ bash +npm install -g sslkeylog +~~~ + +Set the `SSLKEYLOGFILE` environment variable as usual: + +~~~ bash +export SSLKEYLOGFILE=/tmp/keys.log +~~~ + +Then in your code, call the `hookAll` function at startup: + +~~~ js +require('sslkeylog').hookAll(); +~~~ + +That's it! Run your code and decryption keys will be logged to the specified file. + +### Setting log file + +If you don't want to use `SSLKEYLOGFILE` or want to override it, you can use `setLog`: + +~~~ js +sslkeylog.setLog('/tmp/otherkeys.log').hookAll(); +~~~ + +### Logging specific connections + +`hookAll` will log decryption keys for *every TLS connection initiated or received by the Node.JS process*. This is okay for quick debugging, but is bad practice and may fail (because it patches Node.JS internals) or may be inconvenient if you have lots of connections. + +Instead of calling `hookAll`, you may use (a combination of) other functions to log only certain connections: + +#### Incoming connections to a server + +To log all incoming connections to a `tls.Server` (or derivates such as `https.Server` +or `http2.Server`), use `hookServer`: + +~~~ js +const myServer = https.createServer(...); + +// ... + +myServer.listen(...); +sslkeylog.hookServer(myServer); +~~~ + +#### HTTPS requests + +To log outgoing connections for HTTPS requests made by your code, use `hookAgent`: + +~~~ js +sslkeylog.hookAgent(); +~~~ + +This will only work for requests that use the default agent. If the requests you're interested in specify a custom `agent`, you must hook this agent instead: + +~~~ js +const myAgent = new Agent(...); +sslkeylog.hookAgent(myAgent); + +// ... + +https.request({ ..., agent: myAgent, ... }) + +// ... +~~~ + +#### Specific connections + +For more advanced use cases where you want to log a particular connection, +you can pass the created `TLSSocket` to `hookSocket`. For example, with `tls.connect`: + +~~~ js +const mySocket = tls.connect(...); +sslkeylog.hookSocket(mySocket); + +// ... +~~~ -[Node.js](https://nodejs.org/) v10+ is required. Tested on v10 (LTS) and v11 (CURRENT), OS X and Linux. +With `http2.connect`: + +~~~ js +const http2Session = http2.connect(...); +sslkeylog.hookSocket(http2Session.socket); + +// ... +~~~ + +Note that you **must** call `hookSocket` as soon as the `TLSSocket` is created (in +the same loop tick), otherwise keys may not be logged properly. + +### Use as a polyfill + +For more advanced use cases, you can use the [keylog API](https://nodejs.org/docs/latest/api/tls.html#tls_event_keylog_1) directly: + + - If you are using Node.JS 12.3.0 or earlier, you don't need this module at all. + - If you are using an earlier version of Node.JS, just doing `require('sslkeylog')` will activate the polyfill. Then you can use the API as usual. + + +## Installation + +If you are using Node 12.2.x or earlier, make sure usual compiling tools (`make`, `g++`, etc.) are installed; on Ubuntu / Debian, `sudo apt-get install build-essentials` should suffice. To use in your project, install as usual: -```$ npm install sslkeylog``` +```$ npm install --save-dev sslkeylog``` ...or add to `package.json` and use npm/yarn to do the work. @@ -31,28 +141,6 @@ $ npm install $ cd examples ``` -### Usage - -When you have connected `TLSSocket`, you may call `get_sesion_key()` to get session key for this connection: - -```javascript -let server = https.createServer({key, cert}); -server.on('secureConnection', tls_socket=>{ - const {client_random, master_key} = sslkeylog.get_session_key(tls_socket); - const hex1 = client_random.toString('hex'); - const hex2 = master_key.toString('hex'); - fs.appendFileSync('/tmp/sslkeylog.txt', `CLIENT_RANDOM ${hex1} ${hex2}\n`); -}; -``` - -Or just use `set_log()` and `update_log()` to do exactly the same: - -```javascript -sslkeylog.set_log('sslkeylog.txt'); -server = https.createServer({key, cert}); -server.on('secureConnection', sslkeylog.update_log); -``` - ### Demo Clone the repository, build with `npm install` and go to `examples/` subdir. Open few terminal tabs or tmux/screen windows. @@ -70,6 +158,50 @@ Now you can see decrypted packets: ![wireshark screenshot](https://cdn.jsdelivr.net/gh/kolontsov/node-sslkeylog/wireshark.png) + +## API reference + +### setLog(filename) + + - `filename` (String): Set filename at which (future) decryption keys will be logged. + +Sets the log filename. +Returns the module object. + +### hookSocket(socket) + + - `socket` (`tls.TLSSocket`): Socket to log decryption keys for. + +Log keys for a particular socket. This method must be called after creating +the socket (i.e. at the same event loop tick) to guarantee that all keys are +logged. Logging the same socket multiple times has no effect. + +Returns the passed socket. + +### hookServer(server) + + - `server` (`tls.Server`): Server to log decryption keys for. + +Log keys for all (future) incoming connections to the passed server. +Returns the passed server. + +### hookAgent(agent) + + - `agent` (`https.Agent | undefined`): Agent to log decryption keys for. + +Log keys for all (future) outgoing connections created by the passed agent. +If no agent is passed, `https.globalAgent` will be used. +Returns the patched agent. + +### hookAll() + +Log every TLS socket that is created. This relies on patching `TLSSocket#_init`, +so it may break and is not guaranteed to remain compatible with future Node.JS releases. +Calling this method multiple times has no effect. + + +## Project status + ### TODO - windows support? diff --git a/examples/server.js b/examples/server.js index bcbd67b..d0d7641 100644 --- a/examples/server.js +++ b/examples/server.js @@ -1,6 +1,6 @@ const https = require('https'); const fs = require('fs'); -const sslkeylog = require('../index.js'); +const sslkeylog = require('..'); const port = 8000; const test_dir = `${__dirname}/../test`; const ssl_opt = { @@ -14,8 +14,8 @@ const req_handler = (req, res)=>{ res.end('Hello from SSL server\n'); }; -sslkeylog.set_log('sslkeylog.txt'); +sslkeylog.setLog('sslkeylog.txt'); -https.createServer(ssl_opt, req_handler) - .on('secureConnection', sock=>sslkeylog.update_log(sock)) - .listen(port, ()=>console.log(`Started on port ${port}`)); +const server = https.createServer(ssl_opt, req_handler); +sslkeylog.hookServer(server); +server.listen(port, ()=>console.log(`Started on port ${port}`));