OpenJBOD / software

MIT License
0 stars 1 forks source link

SSL Support #1

Open TheGuyDanish opened 4 weeks ago

TheGuyDanish commented 4 weeks ago

The software stack in use can support TLS using the built-in support for MbedTLS. Implementing this wouldn't be a big deal except that the current TLS implementation expects DER-formatted certificates and keys, which are not as easily copied into text as normal RSA/PEM-formatted certificates/keys.

The key and certificate can be created with these three commands:

openssl req -x509 -newkey rsa:4096 -nodes -out cert.pem -keyout key.pem -days 365
openssl x509 -in cert.pem -out cert.der -outform DER
openssl rsa -in key.pem -out key.der -outform DER

Current ideas for implementing this are:

1. Leave it to the user

It would be trivial to code a hard check for cert.der/key.der, stat it and, if it exists, engage TLS. This would however rely on the user to create certificates, format them and upload them to the board. We could help the user by providing file upload functions to get them on the board.

Inspiration from Microdot samples

2. Store the certificates in hex

The binascii.hexlify() function can interpret any byte variable as a hexadecimal string, making it safe and trivial to store in config.json. It can then reverse it with binascii.hexlify() and passing the resulting byte object to the to the TLS code. This would require some kind of ingest procedure, which could be uploading the DER through the interface, then saving it from there.

3. Use a default certificate

The most "out of the box" option. Include a default, self-signed certificate with an openjbod.local CN. Either of the above options can still be considered in this.


Code suggestions

Following the example in the Microdot repo, it would be possible to use a CONFIG['web']['use_tls'] variable to decide whether to start in TLS or non-TLS mode. For example:

import ssl
# ...
if CONFIG['web']['use_tls']:
  sslctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
  sslctx.load_cert_chain('cert.der', 'key.der')
  app.run(port=443, ssl=sslctx)
else:
  app.run(port=80)
TheGuyDanish commented 3 weeks ago

Basic SSL support implemented using DER-formatted EC keys. Specifically:

openssl ecparam -name prime256v1 -genkey -noout -out key.der -outform DER
openssl req -new -x509 -key key.der -out cert.der -outform DER -days 365 -nodes

It appears RSA certs are not supported in the version of MbedTLS used in v1.23.0 of MicroPython.

A different issue now is that the server throws exceptions when handling HTTPS requests:

Task exception wasn't retrieved
future: <Task> coro= <generator object 'serve' at 20010500>
Traceback (most recent call last):
  File "asyncio/core.py", line 1, in run_until_complete
  File "/lib/microdot/microdot.py", line 1224, in serve
  File "/lib/microdot/microdot.py", line 1336, in handle_request
  File "/lib/microdot/microdot.py", line 641, in write
  File "asyncio/stream.py", line 1, in stream_awrite
  File "asyncio/stream.py", line 1, in write
OSError: -30592

It does not crash the webserver, but it can occasionally result in requests failing with an ECONNRESET error. It appears this is discussed in: https://github.com/miguelgrinberg/microdot/discussions/205.