Git Product home page Git Product logo

dtls's Introduction

@nodertc/dtls

stability-experimental Build Status npm node license downloads Gitter chat

Secure UDP communications using Datagram Transport Layer Security protocol version 1.2 in pure js. Follow RFC6347, RFC7627.

asciicast

Support

Buy Me A Coffee

Features

  • no native dependecies!
  • modern secure ciphers (by default)
  • in-out fragmentation / in-out retransmission
  • merge outgoing handshakes

Usage

npm i @nodertc/dtls
const dtls = require('@nodertc/dtls');

const socket = dtls.connect({
  type: 'udp4',
  remotePort: 4444,
  remoteAddress: '127.0.0.1',
});

socket.on('error', err => {
  console.error(err);
});

socket.on('data', data => {
  console.log('got message "%s"', data.toString('ascii'));
  socket.close();
});

socket.once('connect', () => {
  socket.write('Hello from Node.js!');
});

Suppored ciphers:

  • TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 (nodejs v11.2+ only)
  • TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 (nodejs v11.2+ only)
  • TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
  • TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
  • TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
  • TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
  • TLS_RSA_WITH_AES_128_GCM_SHA256
  • TLS_RSA_WITH_AES_256_GCM_SHA384
  • TLS_PSK_WITH_CHACHA20_POLY1305_SHA256 (nodejs v11.2+ only)
  • TLS_PSK_WITH_AES_128_GCM_SHA256
  • TLS_PSK_WITH_AES_256_GCM_SHA384
  • TLS_ECDHE_PSK_WITH_AES_128_GCM_SHA256
  • TLS_ECDHE_PSK_WITH_AES_256_GCM_SHA384
  • TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256

API

  • dtls.connect(options: Options [, callback: function]) : Socket

Creates an esteblished connection to remote dtls server. A connect() function also accept all options for unicast.createSocket() or dgram.createSocket(). If options.socket is provided, these options will be ignored.

The callback function, if specified, will be added as a listener for the 'connect' event.

  • options.socket

A duplex stream in a common case. It is also unicast or dgram socket instance. Used if you want a low level control of your connection.

  • options.extendedMasterSecret: bool, [default=true]

This option enable the use Extended Master Secret extension. Enabled by default.

  • options.checkServerIdentity: function(certificate): bool

Optional certificate verify function.

  • options.certificate: Buffer

PEM-encoded client certificate, optional. Supports RSASSA-PKCS1-v1_5 and ECDSA certificates.

  • options.certificatePrivateKey: Buffer

PEM-encoded private key for client certificate.

  • options.maxHandshakeRetransmissions: number

The number of retransmissions during on handshake stage.

  • options.alpn: string | string[]

The list of the supported ALPN protocols.

  • options.pskIdentity: String|Buffer

Identity string for PSK key exchange, see RFC4279.

  • options.pskSecret: String|Buffer

Secret data for the identity string of PSK key exchange.

  • options.ignorePSKIdentityHint: boolean, default=true

Both clients and servers may have pre-shared keys with several different parties. The client indicates which key to use by including a "PSK identity" (see options.pskIdentity above) in the ClientKeyExchange message. To help the client in selecting which identity to use, the server can provide a "PSK identity hint" in the ServerKeyExchange message.

  • options.cipherSuites: number[]|string[]

List of supported by client cipher suites. Default cipher suites:

  • TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 (in nodejs v11+ only)
  • TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 (in nodejs v11+ only)
  • TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
  • TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
  • TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
  • TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384

See above a full list of supported cipher suites.

  • class Socket

A Socket is also a duplex stream, so it can be both readable and writable, and it is also a EventEmitter.

  • Socket.setMTU(mtu: number): void

Set MTU (minimal transfer unit) for this socket, 1420 bytes maximal.

  • Socket.getMTU(): number

Return MTU (minimal transfer unit) for this socket, 1200 bytes by default.

  • Socket.setTimeout(timeout: number[, callback: function()])

Sets the socket to timeout after timeout milliseconds of inactivity on the socket. By default dtls.Socket do not have a timeout.

The optional callback parameter will be added as a one-time listener for the 'timeout' event.

  • Socket.close(): void

Close socket, stop listening for socket. Do not emit data events anymore.

  • Socket.alpnProtocol: string

Get a string that contains the selected ALPN protocol.

  • Event: connect

The 'connect' event is emitted after the handshaking process for a new connection has successfully completed.

  • Event: timeout

Emitted if the socket times out from inactivity. This is only to notify that the socket has been idle.

  • dtls.constants: Object
    • cipherSuites: Object A full list supported cipher suites. See above for detailes.

How to debug?

Start dtls server:

docker run -it --name dtlsd --rm -e "GNUTLS_DEBUG_LEVEL=2" -e "PRIORITY=NORMAL:+AEAD:+ECDHE-RSA:+VERS-DTLS1.2" -e "KEYFILE=key-rsa.pem" -e "CERTFILE=cert-rsa.pem" -p 4444:4444/udp nodertc/dtls-server:1

Start default client:

npm start

License

MIT, 2018 - 2019 © Dmitriy Tsvettsikh

dtls's People

Contributors

reklatsmasters avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

dtls's Issues

Specified custom port doesn't seem to work

Hi, I'm trying to bind the process to a specific port however, the port is ignored when creating a new socket.

(Truncated) sample code

const dtls = require('@nodertc/dtls');
const dgram = require('dgram');
const udp = dgram.createSocket('udp4');

const socket = dtls.connect({
  socket: udp,
  remotePort: 4445,
  remoteAddress: '127.0.0.1',
});

udp.on('listening', () => {
  const address = udp.address();
  console.log(`UDP server listening at ${address.address}:${address.port}`);
});

Running the code above (code is truncated) outputs this in the console: UDP server listening at 0.0.0.0:59102. In other words, a random port is used. To verify, I used $ netstat -plun and it shows a random port is used.

Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
udp        0      0 0.0.0.0:59102           0.0.0.0:*                           24098/node /var/www

Looking at the dgram documentation, the following is written:
When address and port are not passed to socket.bind() the method will bind the socket to the "all interfaces" address on a random port (it does the right thing for both udp4 and udp6 sockets)"

This made me try the following, binding a port on the udp object like so

udp.bind(41234);

Doing so generates the following error:

0|index  | AssertionError [ERR_ASSERTION]: Forbidden transition from 5633 to 5633
0|index  |     at Protocol12ReaderClient.next (/var/www/ws/node_modules/@nodertc/dtls/src/node_modules/fsm/protocol.js:175:7)
0|index  |     at Protocol12ReaderClient._write (/var/www/ws/node_modules/@nodertc/dtls/src/node_modules/fsm/protocol.js:208:12)
0|index  |     at doWrite (/var/www/ws/node_modules/readable-stream/lib/_stream_writable.js:429:139)
0|index  |     at writeOrBuffer (/var/www/ws/node_modules/readable-stream/lib/_stream_writable.js:418:5)
0|index  |     at Protocol12ReaderClient.Writable.write (/var/www/ws/node_modules/readable-stream/lib/_stream_writable.js:327:11)
0|index  |     at Defragmentation.ondata (/var/www/ws/node_modules/readable-stream/lib/_stream_readable.js:635:20)
0|index  |     at Defragmentation.emit (events.js:182:13)
0|index  |     at Defragmentation.EventEmitter.emit (domain.js:442:20)
0|index  |     at addChunk (/var/www/ws/node_modules/readable-stream/lib/_stream_readable.js:301:12)
0|index  |     at readableAddChunk (/var/www/ws/node_modules/readable-stream/lib/_stream_readable.js:283:11)

I had a look at the example.js file you provided, but that doesn't seem to work for me as well.

const socket = dtls.connect({
  type: 'udp4',
  remotePort: 4444,
  remoteAddress: '127.0.0.1',
});

Running this piece of code also assigns a random port.

Node version: v10.13.0

OS Version:
Distributor ID: Ubuntu
Description: Ubuntu 18.04.1 LTS
Release: 18.04
Codename: bionic

Client connection to openssl server fails

I have tested client with docker and it seems to work, but when trying to connect openssl server it fails.

Following openssl client can connec to server.
openssl s_client -dtls -cert client.crt.pem -key client.key.pem -connect localhost:4445

SSL-Session: Protocol : DTLSv1.2 Cipher : ECDHE-ECDSA-AES256-GCM-SHA384

But in clien code, follwong is not working.
const socket = dtls.connect({
type: 'udp4',
remotePort: 4445,
remoteAddress: '127.0.0.1',
maxHandshakeRetransmissions: 4,
cipherSuites: 'TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384',
certificatePrivateKey: readFileSync(join(__dirname, 'client.key.pem')),
certificate: readFileSync(join(__dirname, 'client.crt.pem')),
});

Server end is reporting following error
Error: error:1417A0C1:SSL routines:tls_post_process_client_hello:no shared cipher

Can I connect to openssl based DTLS server?
Is my format incorrect for socket or what might be the issue?

Resume session

  • export / import session parameters
  • session storage api?

doesnt work

Hey there,

I cant make the example working.

I am getting this error:

TypeError: dtls.createServer is not a function

Am I missing something?

I saw that there is no server implementation. So how do you test the code is working in the first place..

I would have bought you 10 coffees for real but it just doesnt work

Add use_srtp extension

It would be super cool if the Socket class would include:

  • Ability to negotiate SRTP keys.
  • An API to send SRTP packets (and events for receiving them).

Of course, a Node RTP parser/factory library would aso be needed. I've found this one (which seems to be unmaintained). SRTP encryption/decryption capabilities would also be needed obviously (and that would be a hard work).

Error: Invalid key length when TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 cipher selected

Error: Invalid key length
    at Cipheriv.createCipherBase (internal/crypto/cipher.js:79:18)
    at Cipheriv.createCipherWithIV (internal/crypto/cipher.js:119:20)
    at new Cipheriv (internal/crypto/cipher.js:225:22)
    at Object.createCipheriv (crypto.js:105:10)
    at AEADCipher.encrypt (/home/dtsvet/develop/projects/dtls/src/node_modules/cipher/aead.js:93:27)
    at ClientSession.encrypt (/home/dtsvet/develop/projects/dtls/src/node_modules/session/abstract.js:286:30)
    at Sender.sendRecord (/home/dtsvet/develop/projects/dtls/src/node_modules/lib/sender.js:188:20)
    at EncodeStream.Sender.output.handshake.on.packet (/home/dtsvet/develop/projects/dtls/src/node_modules/lib/sender.js:113:14)
    at EncodeStream.emit (events.js:182:13)
    at addChunk (_stream_readable.js:283:12)
    at readableAddChunk (_stream_readable.js:264:11)
    at EncodeStream.Readable.push (_stream_readable.js:219:10)
    at EncodeStream.Transform.push (_stream_transform.js:151:32)
    at EncodeStream.afterTransform (_stream_transform.js:92:10)
    at EncodeStream.transformEncode [as _transform] (/home/dtsvet/develop/projects/dtls/node_modules/binary-data/src/index.js:78:5)
    at EncodeStream.Transform._read (_stream_transform.js:190:10)
    at EncodeStream.Transform._write (_stream_transform.js:178:12)
    at doWrite (_stream_writable.js:410:12)
    at writeOrBuffer (_stream_writable.js:394:5)
    at EncodeStream.Writable.write (_stream_writable.js:294:11)
    at Sender.sendHandshake (/home/dtsvet/develop/projects/dtls/src/node_modules/lib/sender.js:232:29)
    at Sender.[_finished] (/home/dtsvet/develop/projects/dtls/src/node_modules/lib/sender.js:415:10)
    at ClientSession.Sender.session.on.state (/home/dtsvet/develop/projects/dtls/src/node_modules/lib/sender.js:127:53)
    at ClientSession.emit (events.js:182:13)
    at ClientSession.send (/home/dtsvet/develop/projects/dtls/src/node_modules/session/abstract.js:82:10)
    at Protocol12ReaderClient.[_client_finished] (/home/dtsvet/develop/projects/dtls/src/node_modules/fsm/protocol.js:580:18)
    at Protocol12ReaderClient.next (/home/dtsvet/develop/projects/dtls/src/node_modules/fsm/protocol.js:180:26)
    at Protocol12ReaderClient.[_client_change_cipher_spec] (/home/dtsvet/develop/projects/dtls/src/node_modules/fsm/protocol.js:570:10)
    at Protocol12ReaderClient.next (/home/dtsvet/develop/projects/dtls/src/node_modules/fsm/protocol.js:180:26)
    at Protocol12ReaderClient.[_client_key_exchange] (/home/dtsvet/develop/projects/dtls/src/node_modules/fsm/protocol.js:547:10)
    at Protocol12ReaderClient.next (/home/dtsvet/develop/projects/dtls/src/node_modules/fsm/protocol.js:180:26)
    at session.createPreMasterSecret (/home/dtsvet/develop/projects/dtls/src/node_modules/fsm/protocol.js:484:51)
    at process._tickCallback (internal/process/next_tick.js:61:11)
eve

DTLS Server Side implementation

Hello,

I see some code to createServer in the master branch, but was not able to get the example server creation working. I was wondering how to create the DTLS server properly, so that DTLS clients could communicate with it.

-Thanks!

Add ECDHE_ECDSA key exchange

Ciphers

  • TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 {0xC0,0x2B}
  • TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 {0xC0,0x2C}
  • TLS_ECDHE_ECDSA_WITH_AES_128_CCM {0xC0,0xAC}
  • TLS_ECDHE_ECDSA_WITH_AES_256_CCM {0xC0,0xAD}

see also #11

Add changelog

Changelog affects to the quality metric from npm search.

Cannnot connect to the server with client certificate

Extended Master Secret should not include CertificateVerify message, RFC7627, sec.3:

When a full TLS handshake takes place, we define

      session_hash = Hash(handshake_messages)

where "handshake_messages" refers to all handshake messages sent or
received, starting at the ClientHello up to and including the
ClientKeyExchange message, including the type and length fields of
the handshake messages.

RFC7905: ChaCha20-Poly1305 Cipher Suites for Transport Layer Security (TLS)

  • TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
  • TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256

if #16 will resolved before:

  • TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256

NodeJSv10 only.

The advantage is that no per-record, explicit nonce need be transmitted,
which saves eight bytes per record and prevents implementations from
mistakenly using a random nonce.


Connecting to IPv6 address does not work

When trying to connect to a peer using an IPv6 address like so

dtls.connect({
    type: 'udp6',
    remotePort: 5684,
    remoteAddress: 'fe80::260a:c4ff:feea:20f0'
});

I get the following error:

node:events:356
      throw er; // Unhandled 'error' event
      ^

Error: bind EINVAL 0.0.0.0
    at node:dgram:341:20
    at processTicksAndRejections (node:internal/process/task_queues:82:21)
Emitted 'error' event on Socket instance at:
    at node:dgram:343:14
    at processTicksAndRejections (node:internal/process/task_queues:82:21) {
  errno: -4071,
  code: 'EINVAL',
  syscall: 'bind',
  address: '0.0.0.0'
}

It seems to me as if the library does not bind to :: in the IPv6 case but uses IPv4's 0.0.0.0 instead.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.