Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions ports/zephyr-cp/boards/raspberrypi/rpi_pico2_w_zephyr/board.conf
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@ CONFIG_NET_IPV4=y
CONFIG_NET_DHCPV4=y
CONFIG_NET_SOCKETS=y

# TCP. Nothing in the port or the SoC defaults turns it on, so until now every
# SOCK_STREAM socket on these boards failed inside net_context_get() with
# EPROTOTYPE -- surfaced by socketpool as "Out of sockets" -- which also means
# the web workflow's listener never opened. HTTP(S) clients and servers need it.
CONFIG_NET_TCP=y

CONFIG_WIFI=y
CONFIG_WIFI_NM_WPA_SUPPLICANT_LEGACY_CRYPTO=n
CONFIG_NET_L2_WIFI_MGMT=y
Expand All @@ -19,6 +25,21 @@ CONFIG_MBEDTLS_CIPHERSUITE_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256=y
CONFIG_MBEDTLS_ENTROPY_C=y
CONFIG_MBEDTLS_CTR_DRBG_C=y

# The collector's captive portal serves HTTPS from a PEM certificate chain
# (fullchain.pem / key.pem via ssl.SSLContext.load_cert_chain); mbedTLS only
# parses DER unless PEM decoding is compiled in.
CONFIG_MBEDTLS_PEM_PARSE_C=y

# TLS 1.2 ECDHE. Zephyr's mbedTLS 4 default serves secp256r1 through the p256-m
# PSA driver and leaves the builtin ECP module out. mbedTLS then defines a dummy
# MBEDTLS_ECP_MAX_BITS of 1, and ssl.h sizes the TLS 1.2 premaster buffer
# (union mbedtls_ssl_premaster_secret._pms_ecdh[MBEDTLS_ECP_MAX_BYTES]) from
# it, so every ECDHE key agreement fails with PSA_ERROR_BUFFER_TOO_SMALL -- a
# 1-byte buffer for a 32-byte shared secret -- and surfaces as OSError 138 on
# the first read of any TLS connection, client or server. Keep the builtin
# ECP module (p256-m off) until the header sizes that buffer from PSA.
CONFIG_MBEDTLS_PSA_P256M_DRIVER_ENABLED=n

# Bluetooth over the shared gSPI bus (CONFIG_BT itself comes from the
# zephyr,bt-hci chosen node in the overlay).
#
Expand Down Expand Up @@ -46,8 +67,16 @@ CONFIG_BT_EXT_ADV=n
CONFIG_NET_MAX_CONTEXTS=12
CONFIG_NET_MAX_CONN=16

# File descriptors. Zephyr sizes the fd table from the subsystems' declared
# needs (ZVFS_OPEN_ADD_SIZE_*), which came to 4 here; the DHCPv4 server takes
# one socket plus the socket-service eventfd, leaving a program two, and
# socketpool.socket() then fails with "Out of sockets" at the first TLS
# listener. Give sockets a real ceiling (each fd entry is ~12 bytes).
CONFIG_ZVFS_OPEN_MAX=16

# Zephyr defaults BT_MAX_CONN to 1, which would limit the hub to a single
# peer and force a connectionless (advertisement-only) node protocol. The
# CYW43439 controller is not the constraint; raise it so nodes can connect
# and sync data. Costs RAM per connection.
CONFIG_BT_MAX_CONN=4

28 changes: 28 additions & 0 deletions ports/zephyr-cp/boards/raspberrypi/rpi_pico_w_zephyr/board.conf
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@ CONFIG_NET_IPV4=y
CONFIG_NET_DHCPV4=y
CONFIG_NET_SOCKETS=y

# TCP. Nothing in the port or the SoC defaults turns it on, so until now every
# SOCK_STREAM socket on these boards failed inside net_context_get() with
# EPROTOTYPE -- surfaced by socketpool as "Out of sockets" -- which also means
# the web workflow's listener never opened. HTTP(S) clients and servers need it.
CONFIG_NET_TCP=y

CONFIG_WIFI=y
CONFIG_WIFI_NM_WPA_SUPPLICANT_LEGACY_CRYPTO=n
CONFIG_NET_L2_WIFI_MGMT=y
Expand All @@ -19,6 +25,28 @@ CONFIG_MBEDTLS_CIPHERSUITE_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256=y
CONFIG_MBEDTLS_ENTROPY_C=y
CONFIG_MBEDTLS_CTR_DRBG_C=y

# The collector's captive portal serves HTTPS from a PEM certificate chain
# (fullchain.pem / key.pem via ssl.SSLContext.load_cert_chain); mbedTLS only
# parses DER unless PEM decoding is compiled in.
CONFIG_MBEDTLS_PEM_PARSE_C=y

# TLS 1.2 ECDHE. Zephyr's mbedTLS 4 default serves secp256r1 through the p256-m
# PSA driver and leaves the builtin ECP module out. mbedTLS then defines a dummy
# MBEDTLS_ECP_MAX_BITS of 1, and ssl.h sizes the TLS 1.2 premaster buffer
# (union mbedtls_ssl_premaster_secret._pms_ecdh[MBEDTLS_ECP_MAX_BYTES]) from
# it, so every ECDHE key agreement fails with PSA_ERROR_BUFFER_TOO_SMALL -- a
# 1-byte buffer for a 32-byte shared secret -- and surfaces as OSError 138 on
# the first read of any TLS connection, client or server. Keep the builtin
# ECP module (p256-m off) until the header sizes that buffer from PSA.
CONFIG_MBEDTLS_PSA_P256M_DRIVER_ENABLED=n

# File descriptors. Zephyr sizes the fd table from the subsystems' declared
# needs (ZVFS_OPEN_ADD_SIZE_*), which came to 4 here; the DHCPv4 server takes
# one socket plus the socket-service eventfd, leaving a program two, and
# socketpool.socket() then fails with "Out of sockets" at the first TLS
# listener. Give sockets a real ceiling (each fd entry is ~12 bytes).
CONFIG_ZVFS_OPEN_MAX=16

CONFIG_TEST_RANDOM_GENERATOR=y

# Bluetooth over the shared gSPI bus (CONFIG_BT itself comes from the
Expand Down
28 changes: 28 additions & 0 deletions ports/zephyr-cp/common-hal/socketpool/Socket.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include "shared/runtime/interrupt_char.h"
#include "py/mperrno.h"
#include "py/runtime.h"
#include "bindings/zephyr_kernel/__init__.h"
#include "shared-bindings/socketpool/SocketPool.h"
#include "common-hal/socketpool/__init__.h"
#include "common-hal/wifi/__init__.h"
Expand Down Expand Up @@ -156,6 +157,13 @@ static bool _socketpool_socket(socketpool_socketpool_obj_t *self,
sock->ipproto = ipproto;
sock->pool = self;
sock->timeout_ms = (uint)-1;
// The object was allocated with a finaliser and zeroed, so until a socket
// exists it must read as closed (num < 0). Left at 0 after a failed
// zsock_socket(), the finaliser later called zsock_shutdown(0) -- fd 0
// belongs to the socket service's eventfd, whose shorter vtable has no
// shutdown slot -- and the CPU branched into cdc_acm_1's data (usage
// fault, halt).
sock->num = -1;

int socknum = zsock_socket(sock->family, sock->type, sock->ipproto);
if (socknum < 0) {
Expand Down Expand Up @@ -205,6 +213,11 @@ socketpool_socket_obj_t *common_hal_socketpool_socket(socketpool_socketpool_obj_
socketpool_socket_obj_t *sock = mp_obj_malloc_with_finaliser(socketpool_socket_obj_t, &socketpool_socket_type);

if (!_socketpool_socket(self, family, type, proto, sock)) {
// Say which limit was hit (ENOMEM: net_contexts, ENFILE/EMFILE: the
// fd table) rather than a generic message.
if (errno != 0) {
raise_zephyr_error(-errno);
}
mp_raise_RuntimeError(MP_ERROR_TEXT("Out of sockets"));
}
return sock;
Expand Down Expand Up @@ -255,6 +268,13 @@ int socketpool_socket_accept(socketpool_socket_obj_t *self, mp_obj_t *peer_out,
accepted->pool = self->pool;
accepted->connected = true;
accepted->type = self->type;
accepted->family = self->family;
accepted->ipproto = self->ipproto;
// Inherit the listener's timeout, as the other ports do. A freshly
// allocated socket object reads as timeout 0 (non-blocking), which made
// the first ssl recv on an accepted connection raise EAGAIN before the
// TLS handshake had a chance to complete.
accepted->timeout_ms = self->timeout_ms;
}

if (peer_out) {
Expand All @@ -277,6 +297,14 @@ socketpool_socket_obj_t *common_hal_socketpool_socket_accept(socketpool_socket_o
sock->pool = self->pool;
sock->connected = true;
sock->type = self->type;
sock->family = self->family;
sock->ipproto = self->ipproto;
// Inherit the listener's timeout, as the other ports do. A freshly
// allocated object reads as timeout 0 (non-blocking), and ssl's
// recv_into relies on the plain socket's recv blocking for it: the
// first read on an accepted TLS connection raised EAGAIN before the
// handshake could complete.
sock->timeout_ms = self->timeout_ms;

return sock;
} else {
Expand Down
11 changes: 10 additions & 1 deletion shared-module/ssl/SSLSocket.c
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,16 @@ ssl_sslsocket_obj_t *common_hal_ssl_sslcontext_wrap_socket(ssl_sslcontext_obj_t
goto cleanup;
}

if (self->crt_bundle_attach != NULL) {
if (server_side && !(self->cacert_buf && self->cacert_bytes)) {
// On a server the CA store is about authenticating *clients*. A
// context that only had load_cert_chain() called on it -- the normal
// HTTPS-server setup -- must not demand a client certificate, which is
// what the default root bundle turned into: every handshake failed
// with MBEDTLS_ERR_SSL_NO_CLIENT_CERTIFICATE. Match CPython, where a
// server-side context defaults to CERT_NONE; a program that loads its
// own CA with load_verify_locations() still gets client verification.
mbedtls_ssl_conf_authmode(&o->conf, MBEDTLS_SSL_VERIFY_NONE);
} else if (self->crt_bundle_attach != NULL) {
mbedtls_ssl_conf_authmode(&o->conf, MBEDTLS_SSL_VERIFY_REQUIRED);
self->crt_bundle_attach(&o->conf);
} else if (self->cacert_buf && self->cacert_bytes) {
Expand Down
Loading