microsoft / devicescript

TypeScript for Tiny IoT Devices (ESP32, RP2040, ...)
https://microsoft.github.io/devicescript/
MIT License
3.24k stars 112 forks source link

broaden crypto suite support on mbedTLS #482

Open num-lock opened 1 year ago

num-lock commented 1 year ago

Did some evaluation and fiddling with DeviceScript on a couple of ESP32 and ESP32-C3 boards. Upon testing the fetch API I noticed that the supported cipher suites compiled into mbedTLS seem pretty conservative? When testing against a couple of IIoT production environments I get mbedTLS handshake errors. It appears none of these are supported (which are the only ones supported server side):

TLS 1.2

TLS 1.3

Servers use 384 bit EC keys.

Works fine with ESP-IDF or even Arduino IDE (which for ESP32 is just an IDF wrapper anyway) on default builds, so I guess mbedTLS got stripped down quite a bit for size here? Unless I test against sites that also still try to support devices running Windows XP with Internet Explorer 6 (like github.com or google.com) I can't really get a working TLS connection.

mmoskal commented 1 year ago

This is somewhat surprising, the settings we have are just:

CONFIG_SSL_USING_MBEDTLS=y
CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_NONE=y
CONFIG_MBEDTLS_CUSTOM_CERTIFICATE_BUNDLE=y

We do not enable TLS 1.3 since it's experimental in mbedTLS and I think it also disables TLS 1.2. Could you share some addresses of servers that only accept these cipher suites so I can test it?

num-lock commented 1 year ago

I put together a little node script. This will run a server that supports said cipher suites only. Both key and DH curve are 384 bit as it's the case with our production systems. Make sure to add express and to create the key and certificate:

openssl ecparam -name secp384r1 -genkey -out key.pem
openssl req -new -x509 -key key.pem -sha256 -nodes -out cert.pem -days 7
const https = require('node:https')
const fs = require('node:fs')

const express = require('express')

const app = express()

app.get('/example', (_, res) => {
    console.log('request')
    res.status(200).send('ok')
})

const ciphers = [
    // TLSv1.3
    'TLS_CHACHA20_POLY1305_SHA256',
    'TLS_AES_256_GCM_SHA384',
    // TLSv1.2
    'ECDHE-ECDSA-CHACHA20-POLY1305',
    'ECDHE-ECDSA-AES256-GCM-SHA384',
].join(':')

https.createServer({
    key: fs.readFileSync('key.pem'),
    cert: fs.readFileSync('cert.pem'),
    ciphers,
    ecdhCurve: 'P-384',
}, app).listen(8443, '0.0.0.0', () => {
    console.log('listening ...')
})

This will listen on all interfaces and simply return ok on https://<ip>:8443/example. Modify as needed.