micropython/micropython-esp32

Using DTLS, with UDP, and generalized packet objects

MrSurly opened this issue · 8 comments

End Goal

Using DTLS for LoRa data. Why? Because I'm using the RFM95 (sx1276) module that doesn't appear to have encryption, and the RFM69 (sx1231)modules (that do have encryption) are using AES ECB, which is bad for the highly repetitive nature of my packets.

Intermediate Goal

Enable DTLS for ordinary UDP sockets, using mbedtls, which is already used in ussl.

Doing this for UDP sockets seems relatively straight-forward, as all µPy sockets implement an underlying "stream" protocol, thus the ussl module will work, with some modification.

It would be nice if there were a generic µPy "stream" protocol class that could be subclassed (to talk to LoRa, which is very UDP-like), and handed directly to (modified for DTLS) ussl for wrapping -- or is there already?

It would be nice if there were a generic µPy "stream" protocol class that could be subclassed

Do you mean on the C or Python side? On the C side you just make an mp_stream_p_t struct for your type. But I guess you are asking about how to do that on the Python side. In that case you may want to look at micropython/micropython#3034 which adds an io.IOBase class for this purpose.

But I guess you are asking about how to do that on the Python side. In that case you may want to look at micropython/micropython#3034 which adds an io.IOBase class for this purpose.

Yes, this is exactly what I had in mind. Since ussl expects something stream-like, and calls mp_get_stream_raise(), it requires the underlying class to implement mp_stream_p_t. I just want something that implements mp_stream_p_t, but allows me to overload read, write, and ioctl (in Python), allowing me to pass an object to ussl that actually implements datagrams over LoRa.

Ok. That IOBase class allows you to implement read/write on the Python side, but not ioctl (but not hard to add the latter).

Also, I should mention, I have DTLS working for plain-vanilla UDP sockets, with the exception that hello verify cookies aren't working for me.

Implementation is somewhat involved -- there are a lot of things that have to be just right. But that's the nature of socket programming.

C code changes:

  • Adding an ioctl call to the usocket to allow ussl to determine if the socket is an SOCK_STREAM or SOCK_DGRAM. ussl needs this to properly set up the mbedtls functionality.
  • Implementing socket.accept() for SOCK_DGRAM sockets. Let me explain. This works by calling recvfrom on the listening socket with MSG_PEEK to get the address, then connect-ing the listening socket to the remote host, and returning the listening socket as the connected client socket. This means the returned socket still has that first UDP message queued up for ussl This also allows read and write calls from ussl to work properly, because the UDP socket is connect-ed. socket.accept() then modifies the listening socket, and re-binds it to the original listening IP/port with SO_REUSEADDR ioctl set. Incidentally, the first bind of the listening socket also has to have this set, so I'm considering hard-coding that into socket.bind().

Python code requirements:

  • UDP sockets passed to ussl.wrap_socket must be the result of socket.accept() for the reasons listed above. Additionally, they must be made non-blocking before being passed, because that's a requirement for DTLS to work. I might just have accept set returned UDP client sockets as already non-blocking.

Ok. That IOBase class allows you to implement read/write on the Python side, but not ioctl (but not hard to add the latter).

Yeah, that's something I was considering implementing (though I'd have to ask you how to do it!), for this use-case.

And, yes, I'd need ioctl.

Is that going to be merged?

It's worth noting that this is only to support my end goal of robust encryption over LoRa. I'm not even sure if it will work properly given the max LoRa payload size, and other factors (such as filtering on client MAC, etc). But I figure if it can be made to work for UDP (as intended), then there's a good shot at using that as a stepping stone to other transports.

Hmmm, this is also interesting to me as I'm looking at ESP-Now which passes small messages around in an ad-hoc manner (see #176)

It has a send method and a recv callback and I'd like to expose that as a generic datagram transport.

I haven't abandoned this. I'm juggling several work projects right now. This is required for one of them, and I'll revisit when I'm working again on that project.

Curious if you made any progress. I'm doing some similar work on the ESP8266 mbedtls DTLS and hitting handshake problems