Decided to take a short break from the work on QUIC
to implement a DTLS API. Very experimental at this
point but the basic API is there (inspired by the
QUIC API work).
The implementation is based on OpenSSL's built-in
DTLS support and no other dependencies are required.
DTLS is a datagram-based version of TLS that is used
for things like WebRTC and CoAP. It provides similar
security guarantees as TLS but is designed to work over
UDP instead of TCP.
This shouldn't be considered ready for production
but it is a good starting point for experimentation
and feedback.
```bash
./configure --experimental-dtls
make -j{nproc}
./node --experimental-dtls my-dtls-app.js
```
Signed-off-by: James M Snell <jasnell@gmail.com>
Assisted-by: Opencode:Opus 4.6
PR-URL: https://github.com/nodejs/node/pull/63182
Fixes: https://github.com/nodejs/node/issues/61630
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Stephen Belanger <admin@stephenbelanger.com>
Reviewed-By: Rafael Gonzaga <rafael.nunu@hotmail.com>
90 lines
2.2 KiB
JavaScript
90 lines
2.2 KiB
JavaScript
// Flags: --experimental-dtls --no-warnings
|
|
|
|
// Test: Basic DTLS handshake and bidirectional data exchange.
|
|
|
|
import { hasCrypto, skip, mustCall } from '../common/index.mjs';
|
|
import assert from 'node:assert';
|
|
import * as fixtures from '../common/fixtures.mjs';
|
|
|
|
const { ok, strictEqual, match } = assert;
|
|
const { readKey } = fixtures;
|
|
|
|
if (!hasCrypto) {
|
|
skip('missing crypto');
|
|
}
|
|
|
|
if (!process.features.dtls) {
|
|
skip('DTLS is not enabled');
|
|
}
|
|
|
|
const { listen, connect } = await import('node:dtls');
|
|
|
|
const serverCert = readKey('agent1-cert.pem');
|
|
const serverKey = readKey('agent1-key.pem');
|
|
const ca = readKey('ca1-cert.pem');
|
|
|
|
const serverReceivedData = Promise.withResolvers();
|
|
const clientReceivedData = Promise.withResolvers();
|
|
|
|
let serverHandshakeDone = false;
|
|
let clientHandshakeDone = false;
|
|
|
|
// Start server.
|
|
const endpoint = listen(mustCall((session) => {
|
|
session.onmessage = mustCall((data) => {
|
|
strictEqual(data.toString(), 'hello from client');
|
|
serverReceivedData.resolve();
|
|
|
|
// Send response back to client.
|
|
session.send('hello from server');
|
|
});
|
|
|
|
session.onhandshake = mustCall((protocol) => {
|
|
ok(protocol);
|
|
match(protocol, /DTLS/i);
|
|
serverHandshakeDone = true;
|
|
});
|
|
}), {
|
|
cert: serverCert.toString(),
|
|
key: serverKey.toString(),
|
|
port: 0,
|
|
host: '127.0.0.1',
|
|
});
|
|
|
|
const serverAddress = endpoint.address;
|
|
ok(serverAddress);
|
|
ok(serverAddress.port > 0);
|
|
|
|
// Connect client.
|
|
const clientSession = connect('127.0.0.1', serverAddress.port, {
|
|
ca: [ca.toString()],
|
|
rejectUnauthorized: false,
|
|
});
|
|
|
|
clientSession.onmessage = mustCall((data) => {
|
|
strictEqual(data.toString(), 'hello from server');
|
|
clientReceivedData.resolve();
|
|
});
|
|
|
|
clientSession.onhandshake = mustCall((protocol) => {
|
|
ok(protocol);
|
|
clientHandshakeDone = true;
|
|
});
|
|
|
|
// Wait for handshake.
|
|
const { protocol } = await clientSession.opened;
|
|
match(protocol, /DTLS/i);
|
|
|
|
// Send data.
|
|
clientSession.send('hello from client');
|
|
|
|
// Wait for bidirectional exchange.
|
|
await Promise.all([serverReceivedData.promise, clientReceivedData.promise]);
|
|
|
|
// Verify handshakes completed.
|
|
ok(clientHandshakeDone);
|
|
ok(serverHandshakeDone);
|
|
|
|
// Clean up.
|
|
await clientSession.close();
|
|
await endpoint.close();
|