diff --git a/CMakeLists.txt b/CMakeLists.txt index 483e406a02..84611ae9a1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3340,6 +3340,39 @@ if(WOLFSSL_FALLBACK_SCSV) ) endif() +add_option("WOLFSSL_CXET_HFT" + "Enable the CXET Linux x86-64 HFT transport profile (default: disabled)" + "no" "yes;no") +if(WOLFSSL_CXET_HFT) + if(NOT CMAKE_SYSTEM_NAME STREQUAL "Linux") + message(FATAL_ERROR "WOLFSSL_CXET_HFT supports Linux only") + endif() + if(NOT CMAKE_SYSTEM_PROCESSOR MATCHES "^(x86_64|amd64|AMD64)$") + message(FATAL_ERROR "WOLFSSL_CXET_HFT supports x86-64 only") + endif() + if(NOT CMAKE_C_COMPILER_ID MATCHES "^(GNU|Clang)$") + message(FATAL_ERROR + "WOLFSSL_CXET_HFT requires GCC or Clang atomic builtins") + endif() + if(WOLFSSL_SINGLE_THREADED) + message(FATAL_ERROR + "WOLFSSL_CXET_HFT requires normal threaded lifetime handling") + endif() + if(WOLFSSL_DTLS OR WOLFSSL_DTLS13) + message(FATAL_ERROR "WOLFSSL_CXET_HFT does not support DTLS") + endif() + if(WOLFSSL_POSTAUTH) + message(FATAL_ERROR + "WOLFSSL_CXET_HFT does not support post-handshake authentication") + endif() + if(WOLFSSL_QUIC) + message(FATAL_ERROR "WOLFSSL_CXET_HFT does not support QUIC") + endif() + + force_option(WOLFSSL_WRITEDUP "yes") + list(APPEND WOLFSSL_DEFINITIONS "-DWOLFSSL_CXET_HFT") +endif() + add_option("WOLFSSL_WRITEDUP" "Enable write duplication of SSL objects (default: disabled)" "no" "yes;no") diff --git a/cmake/options.h.in b/cmake/options.h.in index 431f2545d6..685940b4fb 100644 --- a/cmake/options.h.in +++ b/cmake/options.h.in @@ -497,6 +497,14 @@ extern "C" { #cmakedefine HAVE_FALLBACK_SCSV #undef HAVE_WRITE_DUP #cmakedefine HAVE_WRITE_DUP +#undef WOLFSSL_CXET_HFT +#cmakedefine WOLFSSL_CXET_HFT + +#undef WOLFSSL_AESNI +#cmakedefine WOLFSSL_AESNI + +#undef WOLFSSL_SP_X86_64_ASM +#cmakedefine WOLFSSL_SP_X86_64_ASM #undef ATOMIC_USER #cmakedefine ATOMIC_USER #undef WOLFSSL_USE_RWLOCK diff --git a/doc/cxet-hft-profile.md b/doc/cxet-hft-profile.md new file mode 100644 index 0000000000..62c730a7cb --- /dev/null +++ b/doc/cxet-hft-profile.md @@ -0,0 +1,38 @@ +# CXET HFT transport profile + +`WOLFSSL_CXET_HFT` is an opt-in profile for the CXET Linux x86-64 transport +build. It preserves the normal wolfSSL certificate, SNI, hostname-verification, +record, cipher and socket-I/O behavior. + +The profile changes only the bounded read-to-write mailbox used after +`wolfSSL_write_dup()`: + +- fatal read errors and close notifications use acquire/release atomics; +- TLS 1.3 `KeyUpdate(update_requested)` uses a one-byte atomic mailbox; +- the existing mutex remains the owner of cold duplicate lifetime/refcount + destruction. + +The application must quiesce both duplicate sides before either side is freed. +The profile does not make concurrent destruction safe. + +The CMake profile is fail-closed. It supports Linux x86-64 with GCC or Clang, +enables `WOLFSSL_WRITEDUP`, and rejects `SINGLE_THREADED`, DTLS, QUIC and TLS +1.3 post-handshake authentication. + +Configure with: + +```sh +cmake -S . -B build-cxet \ + -DWOLFSSL_CXET_HFT=yes \ + -DWOLFSSL_DTLS=no \ + -DWOLFSSL_DTLS13=no \ + -DWOLFSSL_POSTAUTH=no \ + -DWOLFSSL_QUIC=no +``` + +The profile build exports `wolfSSL_CXET_hft_profile_version()` and defines +`WOLFSSL_CXET_HFT` in generated `wolfssl/options.h`. CXET's build/staging gates +require both markers and reject a profile-off or stale shared library. + +This profile is a latency candidate until the CXET end-to-end transport gates +have been run. The source change alone is not evidence of an improvement. diff --git a/src/ssl.c b/src/ssl.c index 5368c107fa..26c56bc349 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -1042,6 +1042,12 @@ WOLFSSL* wolfSSL_write_dup(WOLFSSL* ssl) */ int NotifyWriteSide(WOLFSSL* ssl, int err) { +#ifdef WOLFSSL_CXET_HFT + WOLFSSL_ENTER("NotifyWriteSide"); + + WriteDupStoreError(ssl->dupWrite, err); + return 0; +#else int ret; WOLFSSL_ENTER("NotifyWriteSide"); @@ -1053,6 +1059,7 @@ int NotifyWriteSide(WOLFSSL* ssl, int err) } return ret; +#endif } @@ -5898,6 +5905,13 @@ const char* wolfSSL_lib_version(void) return LIBWOLFSSL_VERSION_STRING; } +#ifdef WOLFSSL_CXET_HFT +unsigned int wolfSSL_CXET_hft_profile_version(void) +{ + return WOLFSSL_CXET_HFT_PROFILE_VERSION; +} +#endif + #ifdef OPENSSL_EXTRA #if defined(OPENSSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x10100000L const char* wolfSSL_OpenSSL_version(int a) diff --git a/src/ssl_api_rw.c b/src/ssl_api_rw.c index b1621019f1..175a6836b5 100644 --- a/src/ssl_api_rw.c +++ b/src/ssl_api_rw.c @@ -70,6 +70,16 @@ static int wolfSSL_write_internal(WOLFSSL* ssl, const void* data, size_t sz) * with handling async data and other edge case errors. */ if (ssl->dupWrite != NULL && ssl->error == 0) { int dupErr = 0; /* local copy */ +#ifdef WOLFSSL_CXET_HFT + dupErr = WriteDupLoadError(ssl->dupWrite); +#ifdef WOLFSSL_TLS13 + if (IsAtLeastTLSv1_3(ssl->version)) { + /* The read side publishes only a bounded KeyUpdate bit. */ + ssl->keys.keyUpdateRespond |= + WriteDupTakeKeyUpdate(ssl->dupWrite); + } +#endif /* WOLFSSL_TLS13 */ +#else /* Lock ssl->dupWrite to gather what needs to be done. */ if (wc_LockMutex(&ssl->dupWrite->dupMutex) != 0) return BAD_MUTEX_E; @@ -145,6 +155,7 @@ static int wolfSSL_write_internal(WOLFSSL* ssl, const void* data, size_t sz) } #endif /* WOLFSSL_TLS13 */ wc_UnLockMutex(&ssl->dupWrite->dupMutex); +#endif /* WOLFSSL_CXET_HFT */ if (dupErr != 0) { WOLFSSL_MSG("Write dup error from other side"); diff --git a/src/tls13.c b/src/tls13.c index 5b785e7eb4..70b456c8a3 100644 --- a/src/tls13.c +++ b/src/tls13.c @@ -12612,10 +12612,14 @@ static int DoTls13KeyUpdate(WOLFSSL* ssl, const byte* input, word32* inOutIdx, #if defined(HAVE_WRITE_DUP) && defined(WOLFSSL_TLS13) /* Read side cannot write; delegate the response to the write side. */ if (ssl->dupWrite != NULL && ssl->dupSide == READ_DUP_SIDE) { +#ifdef WOLFSSL_CXET_HFT + WriteDupPostKeyUpdate(ssl->dupWrite); +#else if (wc_LockMutex(&ssl->dupWrite->dupMutex) != 0) return BAD_MUTEX_E; ssl->dupWrite->keyUpdateRespond = 1; wc_UnLockMutex(&ssl->dupWrite->dupMutex); +#endif ssl->keys.keyUpdateRespond = 0; return 0; } diff --git a/wolfssl/internal.h b/wolfssl/internal.h index f351093c34..66af0ce01e 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -5998,7 +5998,7 @@ typedef struct BuildMsgArgs { typedef struct WriteDup { wolfSSL_Mutex dupMutex; /* field access mutex */ int dupCount; /* reference count */ - int dupErr; /* under dupMutex, pass to other side */ + int dupErr; /* pass fatal state to write side */ #ifdef WOLFSSL_DTLS13 struct Dtls13RecordNumber* sendAckList; /* ownership transferred */ /* Key update ACK tracking: write side stores the (epoch, seq) of its @@ -6032,13 +6032,45 @@ typedef struct BuildMsgArgs { #ifdef WOLFSSL_TLS13 /* TLS 1.3 (and DTLS 1.3): read side received a KeyUpdate(update_requested) * but cannot send the response; write side handles it. */ +#ifdef WOLFSSL_CXET_HFT + byte keyUpdateRespond; /* atomic CXET read-to-write mailbox */ +#else WC_BITFIELD keyUpdateRespond:1; /* write side must send a KeyUpdate response */ +#endif #ifdef WOLFSSL_POST_HANDSHAKE_AUTH WC_BITFIELD postHandshakeAuthPending:1; /* write side must respond */ #endif /* WOLFSSL_POST_HANDSHAKE_AUTH */ #endif /* WOLFSSL_TLS13 */ } WriteDup; +#ifdef WOLFSSL_CXET_HFT + static WC_INLINE int WriteDupLoadError(const WriteDup* state) + { + return __atomic_load_n(&state->dupErr, __ATOMIC_ACQUIRE); + } + + static WC_INLINE void WriteDupStoreError(WriteDup* state, int error) + { + __atomic_store_n(&state->dupErr, error, __ATOMIC_RELEASE); + } + +#ifdef WOLFSSL_TLS13 + static WC_INLINE byte WriteDupTakeKeyUpdate(WriteDup* state) + { + if (__atomic_load_n(&state->keyUpdateRespond, __ATOMIC_ACQUIRE) == 0) + return 0; + + return __atomic_exchange_n(&state->keyUpdateRespond, 0, + __ATOMIC_ACQ_REL); + } + + static WC_INLINE void WriteDupPostKeyUpdate(WriteDup* state) + { + __atomic_store_n(&state->keyUpdateRespond, 1, __ATOMIC_RELEASE); + } +#endif /* WOLFSSL_TLS13 */ +#endif /* WOLFSSL_CXET_HFT */ + WOLFSSL_LOCAL void FreeWriteDup(WOLFSSL* ssl); WOLFSSL_LOCAL int NotifyWriteSide(WOLFSSL* ssl, int err); #endif /* HAVE_WRITE_DUP */ diff --git a/wolfssl/ssl.h b/wolfssl/ssl.h index 423f027c74..4fea56f839 100644 --- a/wolfssl/ssl.h +++ b/wolfssl/ssl.h @@ -1450,6 +1450,11 @@ WOLFSSL_API WOLFSSL_X509_VERIFY_PARAM* wolfSSL_get0_param(WOLFSSL* ssl); WOLFSSL_API int wolfSSL_CTX_set1_param(WOLFSSL_CTX* ctx, WOLFSSL_X509_VERIFY_PARAM *vpm); WOLFSSL_API int wolfSSL_is_server(WOLFSSL* ssl); WOLFSSL_API WOLFSSL* wolfSSL_write_dup(WOLFSSL* ssl); +#define WOLFSSL_CXET_HFT_PROFILE_VERSION 1U +#ifdef WOLFSSL_CXET_HFT +WOLFSSL_ABI WOLFSSL_API unsigned int + wolfSSL_CXET_hft_profile_version(void); +#endif WOLFSSL_ABI WOLFSSL_API int wolfSSL_set_fd(WOLFSSL* ssl, int fd); #ifdef WOLFSSL_DTLS WOLFSSL_API int wolfSSL_set_dtls_fd_connected(WOLFSSL* ssl, int fd); diff --git a/wolfssl/wolfcrypt/settings.h b/wolfssl/wolfcrypt/settings.h index 49ea49b0b8..bfd89e5e16 100644 --- a/wolfssl/wolfcrypt/settings.h +++ b/wolfssl/wolfcrypt/settings.h @@ -3290,6 +3290,27 @@ #error "WRITE DUP and SECURE RENEGOTIATION cannot both be on" #endif +#ifdef WOLFSSL_CXET_HFT + #if !defined(__GNUC__) && !defined(__clang__) + #error "WOLFSSL_CXET_HFT requires GCC or Clang atomic builtins" + #endif + #ifdef SINGLE_THREADED + #error "WOLFSSL_CXET_HFT requires threaded lifetime handling" + #endif + #ifndef HAVE_WRITE_DUP + #error "WOLFSSL_CXET_HFT requires HAVE_WRITE_DUP" + #endif + #if defined(WOLFSSL_DTLS) || defined(WOLFSSL_DTLS13) + #error "WOLFSSL_CXET_HFT does not support DTLS" + #endif + #ifdef WOLFSSL_POST_HANDSHAKE_AUTH + #error "WOLFSSL_CXET_HFT does not support post-handshake authentication" + #endif + #ifdef WOLFSSL_QUIC + #error "WOLFSSL_CXET_HFT does not support QUIC" + #endif +#endif /* WOLFSSL_CXET_HFT */ + #ifdef WOLFSSL_SGX #ifdef _MSC_VER #define NO_RC4