jawj / subtls

A proof-of-concept TypeScript TLS 1.3 client
https://bytebybyte.dev
MIT License
351 stars 15 forks source link
certificate crypto javascript ssl tls tls13 typescript

subtls

A TypeScript TLS 1.3 client with limited scope.

Current scope

Fundamentally, there’s not much of a state machine here: we just expect a mostly predictable sequence of messages, and throw if we don’t get what we expect.

Features

How could this ever be useful?

Why would we need a JS implementation of TLS? On Node.js, there’s tls.connect(). In browsers, TLS-secured connections are easy using WebSockets and the fetch API ... and in any case, there’s no TCP!

Well, this library arose out of wanting to speak TCP-based protocols (e.g. Postgres) from V8 isolate-based serverless environments which don’t do TCP.

It’s pretty easy to tunnel TCP traffic over WebSockets. But if you need that traffic encrypted, either you need secure wss: WebSockets to the proxy (plus something to keep the onward TCP traffic safe), or you need a userspace TLS implementation to encrypt the data before you pass it to the WebSocket and on through the proxy. This could be that userspace TLS implementation.

There’s also some potential pedagogical value, which we build on by optionally producing beautifully annotated and indented binary data.

Note: there are some annoying roadblocks to using this in web browsers. From an https: page you can’t open an insecure ws: WebSocket, and from an http: page there’s no access to SubtleCrypto.

Crypto

Thankfully, almost no actual crypto is implemented here: SubtleCrypto covers almost everything we need.

The one exception is the HKDF functions in src/tls/hkdf.ts. SubtleCrypto’s documentation is not very good, but from what I could make out its HKDF support is not quite flexible enough to use here (please tell me if I'm wrong, which is very possible).

Of course, my HKDF implementation leans heavily on HMAC calculations which are themselves punted to SubtleCrypto.

Testing

This code really needs auditing and testing. As a start, it's a shame that https://badssl.com doesn't yet support TLS 1.3.

SubtleCrypto wishlist

Things that would be nice to see in SubtleCrypto in future:

There are also some interesting differences between SubtleCrypto implementations across platforms. In particular, successive calls to encrypt and decrypt return Promise objects that, on some platforms (e.g. Chrome), appear to always resolve in the same order that they were returned but, on other platforms (e.g. Node), occasionally resolve out of order.

Navigating the code

For an outline of the code, start in src/tls/startTls.ts, which orchestrates most of it.

You’ll notice heavy use of the Bytes class (found in src/util/bytes.ts) throughout. This is used for writing and parsing binary data, and is a wrapper around a Uint8Array and a DataView, offering three key additional features:

Finally, there’s also an ASN1Bytes subclass of Bytes that adds various methods for reading ASN.1-specific data types, as used in X.509 certificates, such as lengths, OIDs, and BitStrings.

Alternatives

The only alternative JS TLS implementation I’m aware of is Forge. This is pure JS, without SubtleCrypto, making it somewhat slow. More importantly, its TLS parts are not very actively maintained. The main project supports up to TLS 1.1. There’s a fork that supports up to TLS 1.2, but even that supports none of the modern and secure ciphers you’d want to use.

Name

The name subtls is a play on SubtleCrypto + TLS, and perhaps also conveys the idea that this is less than TLS: an incomplete and non-conformant implementation.

How to use it

First of all: don’t. This code is not ready to be used in production.

Second, there are example uses in src/https.ts and src/postgres.ts.

Essentially, you call startTls with a hostname, one or more PEM-format root certificates, and functions it can use to read and write unencrypted data to and from the network.

It gives you back a Promise of two functions, which you can use to read and write data via the TLS connection. Note that the TLS connection will not be fully established until you call one of these.

Useful resources

TLS 1.3

x509

HKDF

SubtleCrypto

Testing

TODO

Licence

Copyright © 2022 – 2024 George MacKerron.

Licenced under the MIT licence.

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.