diff --git a/UNOR4USBBridge/at_handler.cpp b/UNOR4USBBridge/at_handler.cpp index 433902c..fc08c75 100644 --- a/UNOR4USBBridge/at_handler.cpp +++ b/UNOR4USBBridge/at_handler.cpp @@ -8,11 +8,11 @@ #include "cmds_wifi_station.h" #include "cmds_wifi_softAP.h" #include "cmds_wifi_netif.h" +#include "cmds_preferences.h" #include "cmds_wifi_SSL.h" #include "cmds_wifi_udp.h" #include "cmds_ble_bridge.h" #include "cmds_ota.h" -#include "cmds_preferences.h" #include "cmds_se.h" using namespace SudoMaker; @@ -92,6 +92,9 @@ CAtHandler::CAtHandler(HardwareSerial *s) : last_server_client_sock(0) { for(int i = 0; i < MAX_CLIENT_AVAILABLE; i++) { sslclients[i] = nullptr; + clients_ca[i].clear(); + clients_cert_pem[i].clear(); + clients_key_pem[i].clear(); } /* set up serial */ diff --git a/UNOR4USBBridge/at_handler.h b/UNOR4USBBridge/at_handler.h index 765a682..a47588b 100644 --- a/UNOR4USBBridge/at_handler.h +++ b/UNOR4USBBridge/at_handler.h @@ -63,6 +63,9 @@ class CAtHandler { WiFiClient * clients[MAX_CLIENT_AVAILABLE]; CServerClient serverClients[MAX_CLIENT_AVAILABLE]; WiFiClientSecure * sslclients[MAX_CLIENT_AVAILABLE]; + std::vector clients_ca[MAX_CLIENT_AVAILABLE]; + std::vector clients_cert_pem[MAX_CLIENT_AVAILABLE]; + std::vector clients_key_pem[MAX_CLIENT_AVAILABLE]; int udps_num = 0; int servers_num = 0; int clientsToServer_num = 0; @@ -85,8 +88,15 @@ class CAtHandler { void add_cmds_preferences(); void add_cmds_se(); public: - std::vector cert_buf; + /* Used by cmds_se */ std::vector se_buf; + + /* Used by cmds_ota */ + std::vector ota_cert_buf; + + /* Used by cmds_preferences */ + std::vector pref_buf; + CAtHandler(HardwareSerial *s); CAtHandler() = delete ; static void onWiFiEvent(WiFiEvent_t event); diff --git a/UNOR4USBBridge/cmds_ota.h b/UNOR4USBBridge/cmds_ota.h index 8b2ce11..de1f7f7 100644 --- a/UNOR4USBBridge/cmds_ota.h +++ b/UNOR4USBBridge/cmds_ota.h @@ -27,15 +27,15 @@ void CAtHandler::add_cmds_ota() { return chAT::CommandStatus::ERROR; } - cert_buf = srv.inhibit_read(ca_root_size); - size_t offset = cert_buf.size(); + ota_cert_buf = srv.inhibit_read(ca_root_size); + size_t offset = ota_cert_buf.size(); if(offset < ca_root_size) { - cert_buf.resize(ca_root_size); + ota_cert_buf.resize(ca_root_size); do { - offset += serial->read(cert_buf.data() + offset, ca_root_size - offset); + offset += serial->read(ota_cert_buf.data() + offset, ca_root_size - offset); } while (offset < ca_root_size); } - OTA.setCACert((const char *)cert_buf.data()); + OTA.setCACert((const char *)ota_cert_buf.data()); srv.continue_read(); return chAT::CommandStatus::OK; } diff --git a/UNOR4USBBridge/cmds_preferences.h b/UNOR4USBBridge/cmds_preferences.h index 0c6e4c0..c8c1e38 100644 --- a/UNOR4USBBridge/cmds_preferences.h +++ b/UNOR4USBBridge/cmds_preferences.h @@ -171,16 +171,16 @@ void CAtHandler::add_cmds_preferences() { break; case PreferenceType::PT_BLOB: { int value = atoi(parser.args[2].c_str()); - cert_buf = srv.inhibit_read(value); - size_t offset = cert_buf.size(); + pref_buf = srv.inhibit_read(value); + size_t offset = pref_buf.size(); if(offset < value) { - cert_buf.resize(value); + pref_buf.resize(value); do { - offset += serial->read(cert_buf.data() + offset, value - offset); + offset += serial->read(pref_buf.data() + offset, value - offset); } while (offset < value); } srv.continue_read(); - error = String(pref.putBytes(key.c_str(), cert_buf.data(), value)) + "\r\n"; + error = String(pref.putBytes(key.c_str(), pref_buf.data(), value)) + "\r\n"; } break; default: diff --git a/UNOR4USBBridge/cmds_wifi_SSL.h b/UNOR4USBBridge/cmds_wifi_SSL.h index eff4912..79535c0 100644 --- a/UNOR4USBBridge/cmds_wifi_SSL.h +++ b/UNOR4USBBridge/cmds_wifi_SSL.h @@ -11,6 +11,8 @@ INCBIN(x509_crt_bundle, PATH_CERT_BUNDLE); #endif #include "at_handler.h" +#include "mbedtls/pem.h" +#include "SSE.h" #ifndef WIFI_CLIENT_DEF_CONN_TIMEOUT_MS #define WIFI_CLIENT_DEF_CONN_TIMEOUT_MS (3000) @@ -66,6 +68,11 @@ void CAtHandler::add_cmds_wifi_SSL() { return chAT::CommandStatus::ERROR; } + const int internal_sock = the_client.can_delete; + if (internal_sock == -1) { + return chAT::CommandStatus::ERROR; + } + bool ca_root_custom = false; int ca_root_size = 0; if (parser.args.size() >= 2){ @@ -78,19 +85,17 @@ void CAtHandler::add_cmds_wifi_SSL() { } if(ca_root_custom) { - - - cert_buf = srv.inhibit_read(ca_root_size); - size_t offset = cert_buf.size(); + clients_ca[internal_sock] = srv.inhibit_read(ca_root_size); + size_t offset = clients_ca[internal_sock].size(); if(offset < ca_root_size) { - cert_buf.resize(ca_root_size); + clients_ca[internal_sock].resize(ca_root_size); do { - offset += serial->read(cert_buf.data() + offset, ca_root_size - offset); + offset += serial->read(clients_ca[internal_sock].data() + offset, ca_root_size - offset); } while (offset < ca_root_size); } - the_client.sslclient->setCACert((const char *)cert_buf.data()); + the_client.sslclient->setCACert((const char *)clients_ca[internal_sock].data()); srv.continue_read(); } else { #ifdef BUNDLED_CA_ROOT_CRT @@ -110,6 +115,120 @@ void CAtHandler::add_cmds_wifi_SSL() { return chAT::CommandStatus::ERROR; } }; + + /* ....................................................................... */ + command_table[_SETECCSLOT] = [this](auto & srv, auto & parser) { + /* ....................................................................... */ + switch (parser.cmd_mode) { + case chAT::CommandMode::Write: { + if (parser.args.size() != 3) { + return chAT::CommandStatus::ERROR; + } + + auto &sock_num = parser.args[0]; + auto &slot_num = parser.args[1]; + auto &cert_len = parser.args[2]; + if (sock_num.empty() || slot_num.empty() || cert_len.empty()) { + return chAT::CommandStatus::ERROR; + } + + int sock = atoi(sock_num.c_str()); + int size = atoi(cert_len.c_str()); + + CClientWrapper the_client = getClient(sock); + if (the_client.sslclient == nullptr) { + return chAT::CommandStatus::ERROR; + } + + const int internal_sock = the_client.can_delete; + if (internal_sock == -1) { + return chAT::CommandStatus::ERROR; + } + + std::vector client_cert_der; + client_cert_der = srv.inhibit_read(size); + size_t offset = client_cert_der.size(); + + if(offset < size) { + client_cert_der.resize(size); + do { + offset += serial->read(client_cert_der.data() + offset, size - offset); + } while (offset < size); + } + srv.continue_read(); + +#if ECC_DEBUG_ENABLED + log_v("_SETECCSLOT: input cert"); + log_buf_v((const uint8_t *)client_cert_der.data(), size); +#endif + + /* Convert client certificate DER buffer into PEM */ + clients_cert_pem[internal_sock].resize(1024); + size_t olen; + int ret = -1; + if ((ret = mbedtls_pem_write_buffer("-----BEGIN CERTIFICATE-----\n", + "-----END CERTIFICATE-----\n", + client_cert_der.data(), size, + clients_cert_pem[internal_sock].data(), 1024, + &olen)) != 0) + { + log_e(" failed\n ! mbedtls_pem_write_buffer returned -0x%04x", (unsigned int) -ret); + clients_cert_pem[internal_sock].clear(); + return chAT::CommandStatus::ERROR; + } + clients_cert_pem[internal_sock].resize(olen); + +#if ECC_DEBUG_ENABLED + log_v("_SETECCSLOT: output cert"); + log_v("\n%s", clients_cert_pem[internal_sock].data()); +#endif + + /* Set client certificate */ + the_client.sslclient->setCertificate((const char *)clients_cert_pem[internal_sock].data()); + + /* Read private key from non volatile storage in DER format */ + std::vector client_key_der; + int len = sse.getBytesLength(slot_num.c_str()); + client_key_der.resize(len); + if ((ret = sse.getBytes(slot_num.c_str(), client_key_der.data(), len)) < len) { + log_e(" failed\n ! sse.getBytes returned -0x%04x", (unsigned int) -ret); + return chAT::CommandStatus::ERROR; + } + +#if ECC_DEBUG_ENABLED + log_v("_SETECCSLOT: input key"); + log_buf_v((const uint8_t *)client_key_der.data(), ret); +#endif + + /* Convert private key in PEM format */ + clients_key_pem[internal_sock].resize(1024); + if ((ret = mbedtls_pem_write_buffer("-----BEGIN EC PRIVATE KEY-----\n", + "-----END EC PRIVATE KEY-----\n", + client_key_der.data(), len, + clients_key_pem[internal_sock].data(), 1024, + &olen)) != 0) + { + log_e(" failed\n ! mbedtls_pem_write_buffer returned -0x%04x", (unsigned int) -ret); + clients_cert_pem[internal_sock].clear(); + return chAT::CommandStatus::ERROR; + } + clients_key_pem[internal_sock].resize(olen); + +#if ECC_DEBUG_ENABLED + log_v("_SETECCSLOT: output key"); + log_v("\n%s", clients_key_pem[internal_sock].data()); +#endif + + /* Set client key */ + the_client.sslclient->setPrivateKey((const char *)clients_key_pem[internal_sock].data()); + + return chAT::CommandStatus::OK; + } + default: + return chAT::CommandStatus::ERROR; + } + }; + /* ....................................................................... */ command_table[_SSLCLIENTSTATE] = [this](auto & srv, auto & parser) { /* ....................................................................... */ @@ -166,6 +285,11 @@ void CAtHandler::add_cmds_wifi_SSL() { return chAT::CommandStatus::ERROR; } + const int internal_sock = the_client.can_delete; + if (internal_sock == -1) { + return chAT::CommandStatus::ERROR; + } + auto &host = parser.args[1]; if (host.empty()) { return chAT::CommandStatus::ERROR; @@ -176,6 +300,21 @@ void CAtHandler::add_cmds_wifi_SSL() { return chAT::CommandStatus::ERROR; } + /* Set custom root ca */ + if (clients_ca[internal_sock].size()) { + the_client.sslclient->setCACert((const char *)clients_ca[internal_sock].data()); + } + /* Default ca bundle is configured automatically on connect by the WiFiSSLClient */ + + if (clients_cert_pem[internal_sock].size()) { + /* Set client certificate */ + the_client.sslclient->setCertificate((const char *)clients_cert_pem[internal_sock].data()); + } + if (clients_key_pem[internal_sock].size()) { + /* Set client key */ + the_client.sslclient->setPrivateKey((const char *)clients_key_pem[internal_sock].data()); + } + if (!the_client.sslclient->connect(host.c_str(), atoi(port.c_str()))) { return chAT::CommandStatus::ERROR; } @@ -210,6 +349,11 @@ void CAtHandler::add_cmds_wifi_SSL() { return chAT::CommandStatus::ERROR; } + const int internal_sock = the_client.can_delete; + if (internal_sock == -1) { + return chAT::CommandStatus::ERROR; + } + auto &hostip = parser.args[1]; if (hostip.empty()) { return chAT::CommandStatus::ERROR; @@ -225,6 +369,21 @@ void CAtHandler::add_cmds_wifi_SSL() { return chAT::CommandStatus::ERROR; } + /* Set custom root ca */ + if (clients_ca[internal_sock].size()) { + the_client.sslclient->setCACert((const char *)clients_ca[internal_sock].data()); + } + /* Default ca bundle is configured automatically on connect by the WiFiSSLClient */ + + if (clients_cert_pem[internal_sock].size()) { + /* Set client certificate */ + the_client.sslclient->setCertificate((const char *)clients_cert_pem[internal_sock].data()); + } + if (clients_key_pem[internal_sock].size()) { + /* Set client key */ + the_client.sslclient->setPrivateKey((const char *)clients_key_pem[internal_sock].data()); + } + if (!the_client.sslclient->connect(address, atoi(hostport.c_str()))) { return chAT::CommandStatus::ERROR; } @@ -258,6 +417,11 @@ void CAtHandler::add_cmds_wifi_SSL() { return chAT::CommandStatus::ERROR; } + const int internal_sock = the_client.can_delete; + if (internal_sock == -1) { + return chAT::CommandStatus::ERROR; + } + auto &host = parser.args[1]; if (host.empty()) { return chAT::CommandStatus::ERROR; @@ -280,6 +444,21 @@ void CAtHandler::add_cmds_wifi_SSL() { } } + /* Set custom root ca */ + if (clients_ca[internal_sock].size()) { + the_client.sslclient->setCACert((const char *)clients_ca[internal_sock].data()); + } + /* Default ca bundle is configured automatically on connect by the WiFiSSLClient */ + + if (clients_cert_pem[internal_sock].size()) { + /* Set client certificate */ + the_client.sslclient->setCertificate((const char *)clients_cert_pem[internal_sock].data()); + } + if (clients_key_pem[internal_sock].size()) { + /* Set client key */ + the_client.sslclient->setPrivateKey((const char *)clients_key_pem[internal_sock].data()); + } + if (!the_client.sslclient->connect(host.c_str(), atoi(port.c_str()), timeout)) { return chAT::CommandStatus::ERROR; } @@ -397,6 +576,9 @@ void CAtHandler::add_cmds_wifi_SSL() { if(the_client.can_delete >= 0) { delete sslclients[the_client.can_delete]; sslclients[the_client.can_delete] = nullptr; + clients_ca[the_client.can_delete].clear(); + clients_cert_pem[the_client.can_delete].clear(); + clients_key_pem[the_client.can_delete].clear(); sslclients_num--; } } diff --git a/UNOR4USBBridge/commands.h b/UNOR4USBBridge/commands.h index b1b7ba3..ffa9555 100644 --- a/UNOR4USBBridge/commands.h +++ b/UNOR4USBBridge/commands.h @@ -58,6 +58,7 @@ enum file_op { #define _CLIENTCONNECTED "+CLIENTCONNECTED" #define _SSLBEGINCLIENT "+SSLBEGINCLIENT" #define _SETCAROOT "+SETCAROOT" +#define _SETECCSLOT "+SETECCSLOT" #define _SSLCLIENTSTATE "+SSLCLIENTSTATE" #define _SSLCLIENTCONNECTNAME "+SSLCLIENTCONNECTNAME" #define _SSLCLIENTCONNECT "+SSLCLIENTCONNECT"