Masaori makes a good point. The API tradeoff between our two discussed options is:
1. The currently implemented approach Jasmine worked on: expose the client hello items through an object. The upside to this is a cleaner TS API: no proliferation of functions as the current and new items are desired from the client hello. Just update the object so plugins can access the data. The downside (as Masoari pointed out) is that the various values are copied into the object regardless of whether they are needed. 2. My initial suggestion from earlier in this thread: add a separate function to the TS API for each desired item: ciphers, version, extensions, etc. And if there are other items desired, add more functions. The downside to this is that it adds a lot of noise to the API, but it avoids copies. You only pay for what you use because the overhead is a one to one mapping between TS API call and client hello item desired. Neither option is wonderful. My thought on Jasmine's implementation was to address the copy issue via a lazy loading and caching mechanism, only populating values as they get used: https://github.com/apache/trafficserver/pull/12790#discussion_r2723219183 Masakazu pointed out, helpfully and correctly, that caching could be tricky because of limitations on when this is called. Maybe we can revisit that idea: use his input and be very clear in the documentation that this new API is only available during the invocation of certain hooks? If we can make that work, it would seem to address our various concerns and provide a helpful solution for the plugins. Other ideas? Again, thank you Jasmine for working on a solution for this. On Wed, Feb 4, 2026 at 8:29 PM Masaori Koshiba <[email protected]> wrote: > Hi Jasmine, > > Thank you for working on this. I like this new approach of hiding the > differences between OpenSSL and BoringSSL behind an abstraction layer. > > However, I have a concern about performance. Looking at the > implementation, when `TSVConnClientHelloGet` is called, it performs > two heap allocations (`std::make_unique<tsapi_ssl_client_hello>` and > `new TSClientHelloImpl`). Since this API will be called on every TLS > handshake when the ja4_fingerprint plugin is widely enabled, I don't > think this overhead is negligible. In contrast, the original proposal > and patch don't have these extra heap allocations. > > From my understanding, the main motivation is to provide an > abstraction layer, so I would prefer Brian's proposal of adding TS > APIs that works for OpenSSL and BoringSSL. It achieves the same goal > without the heap allocation overhead. > > Best, > Masaori > > On Thu, Feb 5, 2026 at 9:37 AM Jasmine Emanouel > <[email protected]> wrote: > > > > Hi ATS Community, > > > > > > TLDR; I've revised the proposal to use a TSClientHello type that > abstracts > > OpenSSL/BoringSSL differences, providing a consistent API for accessing > > ClientHello data. > > > > > > Updated Design: > > > > > > TSClientHello TSVConnClientHelloGet(TSVConn sslp); > > > > void TSClientHelloDestroy(TSClientHello ch); > > > > TSReturnCode TSClientHelloExtensionGet(TSClientHello ch, unsigned int > > type, const unsigned char **out, size_t *outlen); > > > > > > Key Changes from Original Proposal: > > > > - Opaque type instead of direct SSL_CLIENT_HELLO exposure - provides > > library-agnostic interface > > > > - Accessor methods on TSClientHello for version, cipher suites, > extensions > > > > - Helper function TSClientHelloExtensionGet() for retrieving specific > > extensions (e.g., ALPN, SNI) > > > > - Memory management - caller must free with TSClientHelloDestroy() > > > > > > Benefits: > > > > - Works identically with OpenSSL and BoringSSL > > > > - Hides implementation details from plugin authors > > > > - Non-breaking - existing plugins continue to work unchanged > > > > - Enables ja4_fingerprint plugin to support both SSL libraries > > > > > > PR: https://github.com/apache/trafficserver/pull/12790 > > > > > > Thanks > > Jasmine > > > > On Fri, 9 Jan 2026 at 11:55, Masakazu Kitajo <[email protected]> wrote: > > > > > I have a mixed opinion. > > > > > > I tend to agree with Brian. I think the necessity of ifdef made the > plugin > > > only support OpenSSL. Similar things can happen on any plugins that > rely on > > > TLS info. In that sense, providing those APIs which Brian suggested > would > > > be nicer. However, those APIs are basically a compat layer for TLS > > > libraries, and we may end up having a lot of those if we take that > route. > > > > > > Also, this may be a discussion topic on the PR rather than API proposal > > > but, I'm wondering if SSL_CLIENT_INFO stays available even after > leaving > > > the callback function. Receiving a TSVConn may be a safer interface, > > > although it is doable to keep a copy of everything that plugins might > need. > > > > > > -- Masakazu > > > > > > > > > > > > > > > On Thu, Jan 8, 2026 at 4:34 PM Brian Neradt <[email protected]> > > > wrote: > > > > > > > Thank you for working on this, Jasmine. > > > > > > > > It is unfortunate to have an API that is half-boringssl-only that > the > > > > plugin then needs to #ifdef around: TSVConnClientHelloGet is > > > > boringssl-only, but TSClientHello is for both openssl and boringssl. > > > > > > > > What do you think of encapsulating the details behind the API by > > > providing > > > > the following instead: > > > > > > > > TSReturnCode TSClientHelloExtensionGet(TSVConn sslp, int > extension_type, > > > > const uint8_t **out_data, > size_t > > > > *out_len); > > > > > > > > TSReturnCode TSClientHelloCiphersGet(TSVConn sslp, > > > > const uint8_t **out_data, size_t > > > > *out_len); > > > > > > > > uint16_t TSClientHelloVersionGet(TSVConn sslp); > > > > > > > > TSReturnCode TSClientHelloSessionIdGet(TSVConn sslp, > > > > const uint8_t **out_data, > size_t > > > > *out_len); > > > > > > > > TSReturnCode TSClientHelloExtensionTypesGet(TSVConn sslp, > > > > uint16_t **out_types, > size_t > > > > *out_count); > > > > > > > > > > > > Then the plugin code works for both boringssl and openssl. The > downside, > > > of > > > > course, is adding 5 functions to the API instead of 1, but I think I > > > prefer > > > > that tradeoff to the alternative complexity required by the plugin. > > > > > > > > On Wed, Jan 7, 2026 at 10:14 PM Jasmine Emanouel < > > > > [email protected]> > > > > wrote: > > > > > > > > > Hi ATS Community, > > > > > > > > > > > > > > > TLDR; I propose a new TSAPI TSVConnClientHelloGet that will return > the > > > > > SSL_CLIENT_HELLO object, allowing plugins to access extension data > when > > > > > using boringssl. > > > > > > > > > > > > > > > > > > > > > > > > > *Problem:* > > > > > > > > > > OpenSSL provides SSL_client_hello_get0_ext(), > > > > > SSL_client_hello_get0_ciphers() and > > > > > SSL_client_hello_get1_extensions_present() to get client hello data > > > from > > > > > an SSL object. BoringSSL doesn't have comparable functions. It > requires > > > > the > > > > > SSL_CLIENT_HELLO object via SSL_early_callback_ctx_extension_get(). > > > > > Currently, there's no way to get the SSL_CLIENT_HELLO object in > > > plugins, > > > > > which causes friction when writing SSL-related plugins that need to > > > work > > > > > with both libraries. > > > > > > > > > > > > > > > *Proposed Solution:* > > > > > > > > > > > > > > > TSClientHello TSVConnClientHelloGet(TSVConn sslp); > > > > > > > > > > > > > > > This API provides access to the SSL_CLIENT_HELLO object within > plugins > > > > and > > > > > is usable during SSL hooks > > > > > (TS_SSL_CLIENT_HELLO_HOOK, TS_SSL_SERVERNAME_HOOK). > > > > > > > > > > > > > > > *Use Case:* This enables plugins to access ClientHello data (cipher > > > > suites, > > > > > extensions, SNI, ALPN, supported TLS versions) when using > BoringSSL. > > > > > Currently, the ja4_fingerprint plugin only works for openssl, this > > > change > > > > > allows us to add boringssl support. > > > > > > > > > > > > > > > *Implementation Notes:* > > > > > > > > > > - The SSL_CLIENT_HELLO is captured during the client hello > callback > > > > and > > > > > stored in TLSSNISupport > > > > > - The data is valid during SSL handshake hooks > > > > > - For OpenSSL, plugins can continue using > > > > > existing TSSslConnectionGet() approach > > > > > > > > > > > > > > > This is a non-breaking addition. Existing OpenSSL-based plugins > > > continue > > > > to > > > > > work unchanged. > > > > > > > > > > > > > > > > > > > > Here is the PR: https://github.com/apache/trafficserver/pull/12790 > > > > > > > > > > > > > > > Thanks, > > > > > > > > > > Jasmine > > > > > > > > > > > > > > > > > -- > > > > "Come to Me, all who are weary and heavy-laden, and I will > > > > give you rest. Take My yoke upon you and learn from Me, for > > > > I am gentle and humble in heart, and you will find rest for > > > > your souls. For My yoke is easy and My burden is light." > > > > > > > > ~ Matthew 11:28-30 > > > > > > > > -- "Come to Me, all who are weary and heavy-laden, and I will give you rest. Take My yoke upon you and learn from Me, for I am gentle and humble in heart, and you will find rest for your souls. For My yoke is easy and My burden is light." ~ Matthew 11:28-30
