Rework TLS to OpenSSL-native style (memory BIOs, explicit status codes)#8002
Conversation
Co-authored-by: achamayou <4016369+achamayou@users.noreply.github.com>
Co-authored-by: achamayou <4016369+achamayou@users.noreply.github.com>
Co-authored-by: achamayou <4016369+achamayou@users.noreply.github.com>
|
@copilot check previous CI runs, find out what failed and fix it. |
Co-authored-by: achamayou <4016369+achamayou@users.noreply.github.com>
Investigated the failing runs (ACI SNP Genoa/Milan + VMSS Virtual C): all hung in Root cause: in the new memory-BIO design, Fix (3a8... commit): drain outbound with |
OpenSSL requires the thread-local error queue to be empty before SSL_get_error is used. Clear stale errors at each TLS operation boundary so unrelated crypto validation failures cannot close healthy sessions. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
Diagnosed and fixed the remaining The invalid X.509 policy check leaves ASN.1 entries on OpenSSL's thread-local error queue. Because The fix clears stale errors before handshake/read/write/shutdown operations and adds a regression test that reproduces the misclassification. I also merged the latest |
There was a problem hiding this comment.
Pull request overview
This PR modernises CCF’s TLS stack to follow OpenSSL-native patterns now that the MbedTLS compatibility layer is gone. It replaces the callback-based I/O emulation with in-memory BIOs and makes TLS APIs return explicit OpenSSL SSL_ERROR_* status codes (with byte counts via out-params), simplifying control flow in TLSSession and related components.
Changes:
- Replace BIO callbacks with explicit in-memory BIO pump APIs (
Context::recv/pending_write/send) and updateTLSSessionto drive them. - Split status and byte counts for
handshake/read/write/close, removing the previous negative/overloaded return scheme (keepingTLS_ERR_X509_VERIFYas a sentinel). - Update unit tests and docs to reflect the new memory-BIO design and status-code contract.
Custom instructions used:
.github/copilot-instructions.md.github/instructions/reviewing.instructions.md
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
| src/tls/context.h | Switch Context to memory BIOs and explicit OpenSSL-style status codes. |
| src/enclave/tls_session.h | Update session drive loop to feed/drain BIOs and switch on SSL_ERROR_* results. |
| src/tls/plaintext_server.h | Adapt the non-TLS passthrough server to the new BIO-driven virtual interface. |
| src/tls/tls.h | Remove legacy error macros; keep TLS_ERR_X509_VERIFY sentinel. |
| src/tls/test/main.cpp | Rework TLS tests to a single-threaded “BIO pump” model; add stale-error coverage. |
| src/tls/README.md | Update TLS design documentation to describe the new OpenSSL-native approach. |
| doc/architecture/tls_internals.rst | Update architecture docs to describe BIO-driven I/O and status-code contract. |
Comments suppressed due to low confidence (1)
src/tls/tls.h:14
- tls.h uses INT_MIN for TLS_ERR_X509_VERIFY but doesn’t include . Relying on transitive includes is brittle; include (or switch to std::numeric_limits::min()) so this header is self-contained.
// Specific error to flag a certificate validation failure during the handshake.
// This is not emitted by OpenSSL itself (its handshake failures surface as
// SSL_ERROR_SSL), but is set by Context so the caller can distinguish an
// authentication failure from a generic error. We use a bogus negative value
// that won't match any OpenSSL SSL_ERROR_* code.
#define TLS_ERR_X509_VERIFY INT_MIN
#include "ccf/crypto/openssl/openssl_wrappers.h"
#include <string>
Use size_t-safe BIO APIs and include SSL statuses in error diagnostics. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Now that MbedTLS is gone from the tree, the TLS layer no longer needs to emulate its style. This reworks
ccf::tls::ContextandTLSSessionto use OpenSSL idioms directly, removing the callback machinery and the "negative return" overloading. Net ~330 fewer lines.Changes
context.h):set_bio()attaches plainBIO_s_memread/write BIOs to theSSL.TLSSessionfeeds inbound ciphertext viarecv()and drains outbound ciphertext viapending_write()/send()after each SSL operation. No moresend_callback/recv_callbackindirection.context.h,tls.h):handshake/read/write/closereturn0on success or an OpenSSLSSL_ERROR_*code (fromSSL_get_error); bytes transferred are reported through an out-param. Removes the negative-return hack. OnlyTLS_ERR_X509_VERIFYremains as a CCF-specific sentinel to distinguish a handshake cert-verification failure (reported by OpenSSL as a genericSSL_ERROR_SSL) so callers can treat it as an auth failure.context.h): each SSL operation clears unrelated thread-local errors before calling OpenSSL, as required for reliableSSL_get_error()classification.tls_session.h):read/flush/do_handshake/closeswitch onSSL_ERROR_WANT_READ/WANT_WRITE/ZERO_RETURN/etc. instead of inspecting negated/overloaded returns. Outbound ciphertext is drained intopending_outand retried on ring-buffer backpressure. Deletes the obsoletehandle_send/handle_recv/*_callback_openssl/write_somepaths.PlaintextServer(plaintext_server.h): updated to the new virtual signatures over its own pair of memory BIOs.tls/test/main.cpp): rewritten from a threaded socketpair + callback BIOs to a single-threaded BIO pump; all existing cases preserved. Added coverage for stale errors from unrelated OpenSSL operations, which must be cleared before calls interpreted bySSL_get_error().tls/README.md,architecture/tls_internals.rst): describe the memory-BIO design and status-code contract; drop the MbedTLS-emulation and "future pure-OpenSSL" sections.Read path, before/after
Notes for reviewers
peer_cert_ok()onSSL_ERROR_SSL) is the one place where OpenSSL's status is reinterpreted.tls_test, andprogrammability_and_jwtpass locally.scripts/ci-checks.shand all required PR CI jobs are green.