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 theusocket
to allowussl
to determine if the socket is anSOCK_STREAM
orSOCK_DGRAM
.ussl
needs this to properly set up the mbedtls functionality. - Implementing
socket.accept()
forSOCK_DGRAM
sockets. Let me explain. This works by callingrecvfrom
on the listening socket withMSG_PEEK
to get the address, thenconnect
-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 forussl
This also allowsread
andwrite
calls fromussl
to work properly, because the UDP socket isconnect
-ed.socket.accept()
then modifies the listening socket, and re-binds it to the original listening IP/port withSO_REUSEADDR
ioctl set. Incidentally, the first bind of the listening socket also has to have this set, so I'm considering hard-coding that intosocket.bind()
.
Python code requirements:
- UDP sockets passed to
ussl.wrap_socket
must be the result ofsocket.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 haveaccept
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