Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DTLS Discussion #2398

Closed
jasnell opened this issue Aug 16, 2015 · 80 comments
Closed

DTLS Discussion #2398

jasnell opened this issue Aug 16, 2015 · 80 comments
Labels
dgram Issues and PRs related to the dgram subsystem / UDP. tls Issues and PRs related to the tls subsystem.

Comments

@jasnell
Copy link
Member

jasnell commented Aug 16, 2015

There's been an ongoing, unresolved discussion around adding DTLS support to joyent/node.
The original PR (nodejs/node-v0.x-archive#6704) is not going to be able to land and needs to continue here. Discussion also happening here: nodejs/node-v0.x-archive#25354. I am closing the original PR but want to make sure the conversation is not lost.

@indutny @rgillan @natbro @migounette

@mscdex mscdex added tls Issues and PRs related to the tls subsystem. dgram Issues and PRs related to the dgram subsystem / UDP. labels Aug 16, 2015
@natbro
Copy link

natbro commented Aug 17, 2015

so @migounette, implicit answer to your question is: here in the io.js fork :) i have time this week to help move your PR (joyent/node#6704) over here if you want to share a branch? or just let me know and i can help test & work on samples + documentation for now. happy to give API feedback as well when you're ready.
looking through the original PR, it seems like getting ipv6 and DTLS 1.2 wired up would be useful (i might even suggest ditching DTLS 1.0. io.js uses >= OpenSSL 1.0.2 and may be worth leaving DTLS 1.0 cruft behind).
I'm USA west-coast time-zone, UTC−08:00. lmk if you prefer email or glitter chat to chatting here.

@jasnell
Copy link
Member Author

jasnell commented Aug 17, 2015

Well... it's not technically an io.js fork any more ;-). But updating this would be awesome.

@natbro
Copy link

natbro commented Aug 17, 2015

sorry, trigger word :) let's just say HEAD

@migounette
Copy link

@natbro GMT+1 :) but working late
I agree DTLS 1.2 will be the target
I will re-start the activity Thursday or Friday

@jorangreef
Copy link
Contributor

I don't think adding DTLS to core would be as profitable as improving UDP performance and adding support for userspace networking (skipping the kernel control plane to avoid unnecessary memcopies, system calls etc.).

DTLS is also quite old now compared to a protocol such as QUIC, which has advantages over DTLS (e.g. packet-aligned encryption), although QUIC is also complex.

I have been working on a simpler protocol taking many ideas from Dan Bernstein's protocols, QUIC etc. and combining these. Improving UDP performance and Crypto performance would really help.

@YurySolovyov
Copy link

I think DTLS is used in WebRTC, which is quite popular in messaging/communications apps.

@jorangreef
Copy link
Contributor

@YuriSolovyov thanks, then it would be good to do I guess.

@rgillan
Copy link

rgillan commented Aug 18, 2015

Hello,

DTLS is a requirement for many IoT applications and it isn't relevant whether people have opinions on how efficient it is. Standards fora such as oneM2M and LWM2M have already decided to use DTLS, as well as WebRTC. Always happy to have constructive involvement but please read back through the thread before adding to this discussion

Cheers Rob

On Aug 18, 2015, at 5:36 AM, Joran Dirk Greef notifications@github.com wrote:

@YuriSolovyov thanks, then it would be good to do I guess.


Reply to this email directly or view it on GitHub.

@Rantanen
Copy link
Contributor

Yes. While DTLS is not "optimal" or "best" - it's used which makes it important and required for many scenarios, the main ones for Node are WebRTC and IoT as stated above.

Also tying DTLS directly to UDP will make it challenging to implement WebRTC on top of it. WebRTC multiplexes different protocols on top of the same UDP socket - some of which use DTLS and some which don't use.

Essentially WebRTC would require a DTLS implementation similar to the TLSSocket that can be invoked from JS code with user defined packets. This way the user code can first resolve whether the packets use DTLS or not according to WebRTC specification and then pass the DTLS packets to the DTLS implementation.

I've been a bit silent on this front lately seeing where and how the feature gets momentum. While I still want to finish the node-dtls project I started, I'm having difficulties figuring out what to do next given there's just so many different things that would need improvement.

If @migounette is continuing the native DTLS implementation, you can count me in for whatever resources. Be it code (to some extent anyway), API design, test cases - either for unit testing or integration for WebRTC purposes. I'm happy as long as Node gets some way to use DTLS.

@avesus
Copy link

avesus commented Aug 18, 2015

👍 Shure, DTLS support for WebRTC will be market-changer for Node.

@mcollina
Copy link
Member

Just adding that DTLS is needed for the CoAP protocol see coapjs/node-coap#11.

The need for DTLS to be in core comes from OpenSSL. Maintaining another version of OpenSSL inside an user-land module is extremely complicated.

I'm 👍 in having a separate module, plus maybe a stream-like interface for DTLS over UDP (but that can be on NPM).

@ohord
Copy link

ohord commented Aug 19, 2015

+1 DTLS will enable ability to implement secure IoT servers and clients in node.js

@natbro
Copy link

natbro commented Aug 20, 2015

@mcollina - when you say "stream-like interface for DTLS over UDP" what do you mean? in terms of writing without specifying a destination host+port as currently required with dgram.send? in terms of in-order delivery/re-assembly of longer-than-MTU sized buffers?

@mcollina
Copy link
Member

DTLS maintains the concept of a connection/stream. It needs to do packet
reordering and the like, because it works like TLS.

If anybody interested in this comes to nodeconfeu, let's meet up!

I can confirm I will have time to spend on this starting from October.
Il giorno gio 20 ago 2015 alle 20:23 Nat Brown notifications@github.com
ha scritto:

@mcollina https://github.com/mcollina - when you say "stream-like
interface for DTLS over UDP" what do you mean? in terms of writing without
specifying a destination host+port as currently required with dgram.send?
in terms of in-order delivery/re-assembly of longer-than-MTU sized buffers?


Reply to this email directly or view it on GitHub
#2398 (comment).

@Rantanen
Copy link
Contributor

Just to clear this up: DTLS maintains the concept of a session, but not stream. It doesn't do payload packet reordering or even guarantee that all payload packets are received and decrypted.

Once the security parameters are negotiated and confirmed, every individual packet in the session can be decrypted independent of other packets in the same epoch.

Still, an objectMode Node stream should match the DTLS behavior even if there is no guarantee that the packets are read in order - or even that all packets are read in case of packet loss.

Essentially initializing a client-mode DTLSSocket should emit the initial handshake datagrams just the same as in the case the socket is bound to an UDP socket. Feeding these packets to the server-mode DTLSSocket should cause the server socket to emit the datagrams required to continue the handshake and so on.

@natbro
Copy link

natbro commented Aug 20, 2015

+1 thanks, @Rantanen - exactly, that's why i asked what @mcollina meant :) there should definitely no in-order or guaranteed delivery happening in a dtls implementation.
but from an API-perspective there are perhaps two ways to go:

  1. both your Rantanen/node-dtls and @migounette's joyent/node#6704 offer up an equivalent objectMode stream object (dtls.connectand dtls.createServer equivalents to tls.connect and tls.createServer). this effectively contextualizes the security negotiation (and renegotiation/reconnect) in these paired objects under the covers. it does somewhat confuse the unreliable/non-delivery/out-of-order nature of datagram, though; some people may think it's just a typical stream. could get around this with warnings in the documentation.
  2. another (or additional) approach might be to allow flowing dtls security context objects into/through dgram and bubble up security negotiation into events that could be over-ridden on the client & the server. for example, some kind of dtls.context object containing ciphers, etc that could be passed into dgram.send and would flow to a server and whose negotiation might be over-ridable or hookable with new baked-in dtls events or parameters ala dgram.on('message', function(message, context). this approach doesn't conflate streams/reliability and might give servers a bit more flexibility to host multiple services with different DTLS security contexts multiplexed on the same port.

@migounette
Copy link

@Rantanen great job done on the js side. But I have a concern with this
approach, I prefer a native approach because a native implementation can
inherit of security fixes from OpenSSL main stream. We see how TLS/SSL
protocol needs to be improved and how some implementations have to be
patched for bugs found after years -
https://www.openssl.org/news/vulnerabilities.html#y2015
So maintaining a DTLS library at the js level is not the best thing for
node (my point of view)

Regarding the point 2, it's a good point, but a bit more difficult to
implement...

Happy to see discussion on this topic, waiting for a while 😴

My 2 cents

On Thu, Aug 20, 2015 at 11:48 PM, Nat Brown notifications@github.com
wrote:

+1 thanks, @Rantanen https://github.com/rantanen - exactly, that's why
i asked what @mcollina https://github.com/mcollina meant :) there
should definitely no in-order or guaranteed delivery happening in a dtls
implementation.
but from an API-perspective there are perhaps two ways to go:

  1. both your Rantanen/node-dtls https://github.com/Rantanen/node-dtls
    and @migounette https://github.com/migounette's DTLS - Draft approach node-v0.x-archive#6704
    DTLS - Draft approach node-v0.x-archive#6704 offer up an equivalent
    objectMode stream object (dtls.connectand dtls.createServer
    equivalents to tls.connect and tls.createServer). this effectively
    contextualizes the security negotiation (and renegotiation/reconnect) in
    these paired objects under the covers. it does somewhat confuse the
    unreliable/non-delivery/out-of-order nature of datagram, though; some
    people may think it's just a typical stream. could get around this with
    warnings in the documentation.
  2. another (or additional) approach might be to allow flowing dtls
    security context objects into/through dgram and bubble up security
    negotiation into events that could be over-ridden on the client & the
    server. for example, some kind of dtls.context object containing
    ciphers, etc that could be passed into dgram.send and would flow to a
    server and whose negotiation might be over-ridable or hookable with new
    baked-in dtls events or parameters ala dgram.on('message',
    function(message, context). this approach doesn't conflate
    streams/reliability and might give servers a bit more flexibility to host
    multiple services with different DTLS security contexts multiplexed on the
    same port.


Reply to this email directly or view it on GitHub
#2398 (comment).

@mcollina
Copy link
Member

Some more thoughts:

  1. I don't like the dgram API, and I think it's simplicistic. It does not
    support pairing sockets for example. Also, it does a dns lookup for every
    message sent. It also allocates a lot of callbacks, and it's not that
    performant. I would not add functionality there, nor I would recommend
    using it as the basis for any other work.

  2. Ideally we should rethink the whole UDP business on node, with a focus
    on performance. As far as I know, there is no UDP wg, but I might be wrong.

  3. As far as I understand it, DTLS offers message reordering, meaning that
    a stream interface might be a good fit:
    https://tools.ietf.org/html/rfc4347#section-3.2.2. The problem is that it
    would create a complete discrepancy between the dgram and the dtls API. But
    DTLS is really different, so I think that's ok to mimic the tls module.

What's the purpose of the security context API? Is that needed somewhere?

Il giorno ven 21 ago 2015 alle 00:39 Yann Stephan notifications@github.com
ha scritto:

@Rantanen great job done on the js side. But I have a concern with this
approach, I prefer a native approach because a native implementation can
inherit of security fixes from OpenSSL main stream. We see how TLS/SSL
protocol needs to be improved and how some implementations have to be
patched for bugs found after years -
https://www.openssl.org/news/vulnerabilities.html#y2015
So maintaining a DTLS library at the js level is not the best thing for
node (my point of view)

Regarding the point 2, it's a good point, but a bit more difficult to
implement...

Happy to see discussion on this topic, waiting for a while 😴

My 2 cents

On Thu, Aug 20, 2015 at 11:48 PM, Nat Brown notifications@github.com
wrote:

+1 thanks, @Rantanen https://github.com/rantanen - exactly, that's why
i asked what @mcollina https://github.com/mcollina meant :) there
should definitely no in-order or guaranteed delivery happening in a dtls
implementation.
but from an API-perspective there are perhaps two ways to go:

  1. both your Rantanen/node-dtls https://github.com/Rantanen/node-dtls
    and @migounette https://github.com/migounette's DTLS - Draft approach node-v0.x-archive#6704
    DTLS - Draft approach node-v0.x-archive#6704 offer up an equivalent
    objectMode stream object (dtls.connectand dtls.createServer
    equivalents to tls.connect and tls.createServer). this effectively
    contextualizes the security negotiation (and renegotiation/reconnect) in
    these paired objects under the covers. it does somewhat confuse the
    unreliable/non-delivery/out-of-order nature of datagram, though; some
    people may think it's just a typical stream. could get around this with
    warnings in the documentation.
  2. another (or additional) approach might be to allow flowing dtls
    security context objects into/through dgram and bubble up security
    negotiation into events that could be over-ridden on the client & the
    server. for example, some kind of dtls.context object containing
    ciphers, etc that could be passed into dgram.send and would flow to a
    server and whose negotiation might be over-ridable or hookable with new
    baked-in dtls events or parameters ala dgram.on('message',
    function(message, context). this approach doesn't conflate
    streams/reliability and might give servers a bit more flexibility to host
    multiple services with different DTLS security contexts multiplexed on
    the
    same port.


Reply to this email directly or view it on GitHub
#2398 (comment).


Reply to this email directly or view it on GitHub
#2398 (comment).

@natbro
Copy link

natbro commented Aug 21, 2015

totally agree doing it native makes the most sense (and i think @Rantanen has also said it's his preference, he just began building his JS version since no native was pending) - i was just commenting on the API choice you both made is similar (dtls.createServer).
agree 2 is harder, exposing the negotiation stages. but the multiplexing of security may be useful for some folks. i just wanted to bring it up as one option and describe the tradeoffs i see. i might take a look at the cost/potential once you've got a branch/PR going - looking forward to it :)

@Rantanen
Copy link
Contributor

@migounette - Yes, I prefer native - but given node was in a bit of a turmoil back when I wanted DTLS, I decided to go with a JS module that could be released on NPM instead of waiting for a PR merge and Node release.

@mcollina, that reordering only affects the handshake messages. The actual encrypted content is not reordered or resent in case of packet loss. The main benefit of UDP is to get packets with as little delay as possible across the network after all. :) Given the handshake messages shouldn't be something the user needs to care about anyway, the fact that they are reordered shouldn't be a consideration when designing the API. Node's TLS module manages to abstract these away - same should be attempted with DTLS.

@natbro, I think abstracting DTLS away from dgram would allow multiplexing different services over single dgram socket with more flexibility as it would allow using DTLS with non-UDP transports in theory. Isn't dgram in Node currently limited to UDP?

However at the same time I believe the DTLSSocket (or whatever its name would be) should implement the same API as dgram.Socket so that it can easily be used as a drop in replacement in places that currently use dgram.Socket. @mcollina raised concern over that API, but I don't see what's the problem in the actual API. I know the implementation is quite iffy given the problems with DNS lookups, etc, but I don't remember any choices there that would prevent it from being improved. Though haven't really looked at it that much.

@mcollina
Copy link
Member

Let me rephrase, if dtls is going to base itself on dgram, than probably might be a good thing to refactor/revise that implementation. One thing that might be problematic is the use of a lot of positional arguments, that makes the API difficult to change.

From a client perspective, a DTLS context pairs something local to something remote: it is stateful. Currently all of dgram is stateless, it can be used to send and receive messages to multiple peers.
This is similar to the missing connect API from C for UDP (it allows to send messages without specifying the address). I think what we are missing is the concept of an 'udp pair', which it encapsulates the context in DTLS, but should probably support non-encrypted data as well. Having the same API is a good thing.

From a personal taste, I don't like that you need the rsinfo object to reply, and pass data back to send(). This means moving two objects around to send a reply (the server and the rsinfo): adding the DTLS context would mean moving around three objects. Then, the context would need to be one added parameter to send().

To my best understanding of the problem, this are the changes needed to have the less impact in the API:

  1. Change socket.send(buf, offset, length, port, address, cb) to socket.send(buf, offset, length, { port: port, address: address }, cb). This allows to pass the rsinfo object as is when replying.
  2. Make dtls.on('message') emit the DTLS context as rsinfo, so replying would just mean passing that to send.
  3. Add a dtls.createContext() for the client to use to fulfill the handshake.

Another completely different API is:

  1. introducing the concept of a UDP pair, with a send() method without a destination, this should probably be the result of a udp.connect() method
  2. adding a udp.createServer() thing to support that paired concept
  3. implement DTLS upon that pair, by wrapping it.

@holsted
Copy link

holsted commented Dec 6, 2015

I just started playing around with a streaming IoT application in Node and it seemed like udp + dtls might fit the bill quite nicely. I was sad to see the discussion died in August. Any updates or progress on this issue? I don't have much bandwidth but would be open to lending a hand when I can.

@nickdesaulniers
Copy link

@jvermillard
Copy link

@mcollina DTLS is reodering/unfragmenting packets only in the handshake/re-handshake phase not in the application phase, so a datagram based attraction fit in most language (because the handshake phase is hidden). This make easier to move non DTLS UDP code to DTLS.
The tricky API part is to "attach" the identity/security level used for DTLS message.
You can trigger the handshake when the first UDP message is sent to a ip/port pair.

@mcollina
Copy link
Member

@jvermillard yes, I agree.

Attaching the context can be easy API-wise:

var dtls = require('dtls')
var socket = dtls.createSocket()
var context = dtls.createContext(url) // or socket.createContext(url)

dtls.send(new Buffer('mybuf'), context, (err) => console.log('err', err))
const dtls = require('dtls');
const server = dtls.createSocket('udp4', {
  key: mykey,
  cert: mycert
});

server.on('error', (err) => {
  console.log(`server error:\n${err.stack}`);
  server.close();
});

server.on('message', (msg, rinfo) => {
  server.send(msg, rinfo, () => console.log('reply sent'))
});

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

server.bind(41234);

@feross
Copy link
Contributor

feross commented Feb 19, 2016

Nice! I just found this thread. Sounds like the general consensus is that DTLS is a reasonable addition to node core. Excellent!

It's required for IoT and WebRTC use cases, it's super difficult to do in user-land, and it's already implemented in OpenSSL so it just needs to be exposed via a JavaScript API.

What are the next steps? Sounds like someone should take the old PR and rebase it onto master to get things going again.

I'm happy to help with testing, code review, however I can.

@bnoordhuis
Copy link
Member

@mcollina You don't need any special linker flags, the challenge is the include path for openssl's headers. They're in a different location when you build against a node source tree vs. the headers tarball that node-gyp downloads. I don't think that's currently documented.

@eljefedelrodeodeljefe Thank you. :) What I mean is, the module can live under the nodejs GitHub organization and be published by the Node.js Foundation. That will give it the veneer of officialness and trustworthiness that you want, but it will be much easier to prototype and iterate on than if it was in core out of the gate.

@eljefedelrodeodeljefe
Copy link
Contributor

@bnoordhuis sounds good to me. Thx for clarifying.

@Trott
Copy link
Member

Trott commented Jul 27, 2017

Should this remain open?

@mcollina
Copy link
Member

Yes. It is still a major lack in Node.js.

@eljefedelrodeodeljefe
Copy link
Contributor

Is this something recent additions to libuv might be helpful with. E.g. libuv-extras (didn't have a look yet)

@bnoordhuis
Copy link
Member

It could, it would make it useful to a larger audience, but you'd still need some glue code for node.js.

@mcollina
Copy link
Member

@eljefedelrodeodeljefe @bnoordhuis can you add a link?

@bnoordhuis
Copy link
Member

@mcollina https://github.com/libuv/libuv-extras - the idea is to have a place for things that can be layered on top of libuv but don't belong in libuv proper (like TLS / DTLS; a C cluster implementation would be another example.)

Not much in there yet, though.

@mcollina
Copy link
Member

Not much in there yet, though.

@bnoordhuis yeah, I see that. I do not think there is anything we can use here, or maybe I am mistaken.

@eljefedelrodeodeljefe
Copy link
Contributor

dragging in @saghul. Context: Whether it would be interesting to have DTLS in libuv-extras to enable Node community easy access.

@migounette
Copy link

The main issue remains the API, who can drive the discussion in order to get the right API for node (Stream, TLS, UDP) and libuv
I will be happy to participate to the discussion (IOT and webRTC require it) but core team leaders are required
@saghul @mcollina @bnoordhuis

you can close the thread

@mcollina
Copy link
Member

mcollina commented Aug 2, 2017

I am happy to join a biweekly team, if someone has time to put into the implementation.

@saghul
Copy link
Member

saghul commented Aug 3, 2017

I'm happy to participate in discussions or code review, but I'm afraid I won't be able to contribute code myself. Agreed with Ben, libuv-extras seems like the right place for it.

@LinusU
Copy link
Contributor

LinusU commented Nov 21, 2017

Would absolutely love to see this happen. I think it would help a lot since IoT is becoming very popular, especially in connection with Node.js.

@migounette
Copy link

It's time for DTLS !!! @saghul you have a project but seems to be empty: https://github.com/libuv/libuv-extras
Any clue for starting ?

@saghul
Copy link
Member

saghul commented Mar 29, 2018

@migounette Creating the source and header files, together with a simple Makefile should be enough to get the ball rolling. We'll see where we go from there :-) (I've been afk for some time, so I don't know if any decisions have been made regarding the extras repo in the mean time.)

@reklatsmasters
Copy link
Contributor

reklatsmasters commented Jun 9, 2018

Few month ago i`m started working on pure js dtls implementation. Here is my experimental work:
https://github.com/nodertc/dtls. AEAD, ECDSA, mtu, reordering, defragmentation already implemented.

@bu5hm4nn
Copy link

Hello everyone. Needing to bridge this gap ASAP we at Krekeltronics have looked for a solution. The best we have found so far is Spark's module for inclusion of mbedtls library into node. Since we did not get the impression that there was any maintaining or further development going on in that repo or in others downstream, we have decided to take on further developing the module.

We would appreciate any input you may have toward getting this code production ready. Feel free to comment on the roadmap and the tickets, help us test the code or submit pull requests.

Take a look at the project: https://github.com/krekeltronics/node-mbed-dtls

Join the discussion on Gitter: Gitter

@jasnell
Copy link
Member Author

jasnell commented Oct 25, 2018

Closing due to lack of activity

@jasnell jasnell closed this as completed Oct 25, 2018
@soyuka
Copy link

soyuka commented Oct 26, 2018

Has this been implemented? Isn't it considered as an option to add it to the core?

@AndreMaz
Copy link

@jasnell @mcollina @bnoordhuis @saghul is there any chance of reopening this? DTLS continues to be a missing piece to secure IoT

@migounette
Copy link

I am eager to pariticapte to DTLS implementation
But currently it's not very clear where changes.

I have a native implementation of DTLS on top of nodejs 10 (NAPI) for our WebRTC product
DTLS is widely used by WebRTC and IO-T, in java the need is covered with COaP but in Node.JS no efficient solution.

DTLS (UDP) uses 80% of TLS code and it requires only a few hooks in order to support key exchange (such as https://tools.ietf.org/html/rfc5764)

LibUV/No LibUV, in Core/No Core.... pushing our work to community will be great just let us know where to push it and how we can discuss API changes, impacts and documentation.

The real question, we have stuff to push but we need some to lead the job in order to take decisions where it can be put.

My 2 cents

@mcollina
Copy link
Member

@migounette It would be good if you could issue a PR adding DTLS to Node Core. Why would you need changes in libuv?

@AndreMaz
Copy link

Wow @migounette ! It would be amazing if you could create a PR with DTLS

@AndreMaz
Copy link

I have a native implementation of DTLS on top of nodejs 10 (NAPI) for our WebRTC product

LibUV/No LibUV, in Core/No Core.... pushing our work to community will be great just let us know where to push it and how we can discuss API changes, impacts and documentation.

@migounette I think that the official guide "Contributing a new API to N-API" can provide some guidance

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
dgram Issues and PRs related to the dgram subsystem / UDP. tls Issues and PRs related to the tls subsystem.
Projects
None yet
Development

No branches or pull requests