2121
2222#include " P_OCSPStapling.h"
2323
24+ #include " tsutil/Bravo.h"
25+
2426#include < openssl/ssl.h>
2527#include < openssl/x509v3.h>
2628#include < openssl/asn1.h>
@@ -279,17 +281,38 @@ namespace
279281
280282// Cached info stored in SSL_CTX ex_info
281283struct certinfo {
282- unsigned char idx[20 ]; // Index in session cache SHA1 hash of certificate
283- TS_OCSP_CERTID *cid; // Certificate ID for OCSP requests or nullptr if ID cannot be determined
284- char *uri; // Responder details
285- char *certname;
286- char *user_agent;
287- ink_mutex stapling_mutex;
288- unsigned char resp_der[MAX_STAPLING_DER];
289- unsigned int resp_derlen;
290- bool is_prefetched;
291- bool is_expire;
292- time_t expire_time;
284+ unsigned char idx[20 ] = {}; // Index in session cache SHA1 hash of certificate
285+ TS_OCSP_CERTID *cid = nullptr ; // Certificate ID for OCSP requests
286+ char *uri = nullptr ; // Responder details
287+ char *certname = nullptr ;
288+ char *user_agent = nullptr ;
289+ bool is_prefetched = false ;
290+
291+ // OCSP response data, protected by resp_mutex.
292+ // Readers take a shared lock; the updater takes an exclusive lock.
293+ unsigned char resp_der[MAX_STAPLING_DER] = {};
294+ unsigned int resp_derlen = 0 ;
295+ bool is_expire = true ;
296+ time_t expire_time = 0 ;
297+ mutable ts::bravo::shared_mutex resp_mutex;
298+
299+ ~certinfo ()
300+ {
301+ if (cid) {
302+ TS_OCSP_CERTID_free (cid);
303+ }
304+ if (uri) {
305+ OPENSSL_free (uri);
306+ }
307+ ats_free (certname);
308+ ats_free (user_agent);
309+ }
310+
311+ certinfo () = default ;
312+ certinfo (const certinfo &) = delete ;
313+ certinfo &operator =(const certinfo &) = delete ;
314+ certinfo (certinfo &&) = delete ;
315+ certinfo &operator =(certinfo &&) = delete ;
293316};
294317
295318class HTTPRequest : public Continuation
@@ -736,16 +759,10 @@ certinfo_map_free(void * /*parent*/, void *ptr, CRYPTO_EX_DATA * /*ad*/, int /*i
736759 }
737760
738761 for (auto &iter : *map) {
739- certinfo *cinf = iter.second ;
740- if (cinf->uri ) {
741- OPENSSL_free (cinf->uri );
742- }
743-
744- ats_free (cinf->certname );
745- ats_free (cinf->user_agent );
746-
747- ink_mutex_destroy (&cinf->stapling_mutex );
748- OPENSSL_free (cinf);
762+ #ifdef OPENSSL_IS_BORINGSSL
763+ X509_free (iter.first );
764+ #endif
765+ delete iter.second ;
749766 }
750767 delete map;
751768}
@@ -831,12 +848,13 @@ stapling_cache_response(TS_OCSP_RESPONSE *rsp, certinfo *cinf)
831848 return false ;
832849 }
833850
834- ink_mutex_acquire (&cinf->stapling_mutex );
835- memcpy (cinf->resp_der , resp_der, resp_derlen);
836- cinf->resp_derlen = resp_derlen;
837- cinf->is_expire = false ;
838- cinf->expire_time = time (nullptr ) + SSLConfigParams::ssl_ocsp_cache_timeout;
839- ink_mutex_release (&cinf->stapling_mutex );
851+ {
852+ std::lock_guard lock (cinf->resp_mutex );
853+ memcpy (cinf->resp_der , resp_der, resp_derlen);
854+ cinf->resp_derlen = resp_derlen;
855+ cinf->is_expire = false ;
856+ cinf->expire_time = time (nullptr ) + SSLConfigParams::ssl_ocsp_cache_timeout;
857+ }
840858
841859 Dbg (dbg_ctl_ssl_ocsp, " stapling_cache_response: success to cache response" );
842860 return true ;
@@ -860,28 +878,20 @@ ssl_stapling_init_cert(SSL_CTX *ctx, X509 *cert, const char *certname, const cha
860878 return false ;
861879 }
862880
881+ bool map_is_new = false ;
863882 if (!map) {
864- map = new certinfo_map;
865- }
866- certinfo *cinf = static_cast <certinfo *>(OPENSSL_malloc (sizeof (certinfo)));
867- if (!cinf) {
868- Error (" error allocating memory for %s" , certname);
869- delete map;
870- return false ;
883+ map = new certinfo_map;
884+ map_is_new = true ;
871885 }
886+ auto cinf_ptr = std::make_unique<certinfo>();
887+ certinfo *cinf = cinf_ptr.get ();
872888
873889 // Initialize certinfo
874- cinf->cid = nullptr ;
875- cinf->uri = nullptr ;
876890 cinf->certname = ats_strdup (certname);
877891 if (SSLConfigParams::ssl_ocsp_user_agent != nullptr ) {
878892 cinf->user_agent = ats_strdup (SSLConfigParams::ssl_ocsp_user_agent);
879893 }
880- cinf->resp_derlen = 0 ;
881- ink_mutex_init (&cinf->stapling_mutex );
882894 cinf->is_prefetched = rsp_file ? true : false ;
883- cinf->is_expire = true ;
884- cinf->expire_time = 0 ;
885895
886896 if (cinf->is_prefetched ) {
887897 Dbg (dbg_ctl_ssl_ocsp, " using OCSP prefetched response file %s" , rsp_file);
@@ -949,24 +959,15 @@ ssl_stapling_init_cert(SSL_CTX *ctx, X509 *cert, const char *certname, const cha
949959 X509_up_ref (cert);
950960#endif
951961
952- map->insert (std::make_pair (cert, cinf ));
962+ map->insert (std::make_pair (cert, cinf_ptr. release () ));
953963 SSL_CTX_set_ex_data (ctx, ssl_stapling_index, map);
954964
955965 Note (" successfully initialized stapling for %s into SSL_CTX: %p uri=%s" , certname, ctx, cinf->uri );
956966 return true ;
957967
958968err:
959- if (cinf->cid ) {
960- TS_OCSP_CERTID_free (cinf->cid );
961- }
962-
963- ats_free (cinf->certname );
964- ats_free (cinf->user_agent );
965-
966- if (cinf) {
967- OPENSSL_free (cinf);
968- }
969- if (map) {
969+ // cinf_ptr destructor handles certinfo member cleanup
970+ if (map_is_new) {
970971 delete map;
971972 }
972973
@@ -1327,20 +1328,21 @@ ocsp_update()
13271328 if (map) {
13281329 // Walk over all certs associated with this CTX
13291330 for (auto &iter : *map) {
1330- cinf = iter.second ;
1331- ink_mutex_acquire (&cinf->stapling_mutex );
1331+ cinf = iter.second ;
13321332 current_time = time (nullptr );
1333- if (cinf->resp_derlen == 0 || cinf->is_expire || cinf->expire_time < current_time) {
1334- ink_mutex_release (&cinf->stapling_mutex );
1333+ bool needs_refresh;
1334+ {
1335+ ts::bravo::shared_lock lock (cinf->resp_mutex );
1336+ needs_refresh = cinf->resp_derlen == 0 || cinf->is_expire || cinf->expire_time < current_time;
1337+ }
1338+ if (needs_refresh) {
13351339 if (stapling_refresh_response (cinf, &resp)) {
13361340 Dbg (dbg_ctl_ssl_ocsp, " Successfully refreshed OCSP for %s certificate. url=%s" , cinf->certname , cinf->uri );
13371341 Metrics::Counter::increment (ssl_rsb.ocsp_refreshed_cert );
13381342 } else {
13391343 Error (" Failed to refresh OCSP for %s certificate. url=%s" , cinf->certname , cinf->uri );
13401344 Metrics::Counter::increment (ssl_rsb.ocsp_refresh_cert_failure );
13411345 }
1342- } else {
1343- ink_mutex_release (&cinf->stapling_mutex );
13441346 }
13451347 }
13461348 }
@@ -1370,56 +1372,69 @@ ssl_callback_ocsp_stapling(SSL *ssl, void *)
13701372 return SSL_TLSEXT_ERR_NOACK;
13711373 }
13721374
1373- // Fetch the specific certificate used in this negotiation
1374- X509 *cert = SSL_get_certificate (ssl);
1375- if (!cert) {
1376- Error (" ssl_callback_ocsp_stapling: failed to get certificate" );
1377- return SSL_TLSEXT_ERR_NOACK;
1378- }
1379-
13801375 certinfo *cinf = nullptr ;
1381- # if HAVE_NATIVE_DUAL_CERT_SUPPORT
1382- certinfo_map::iterator iter = map-> find (cert);
1383- if (iter != map->end () ) {
1384- cinf = iter ->second ;
1385- }
1386- # else
1387- for (certinfo_map::iterator iter = map-> begin (); iter != map-> end (); ++iter) {
1388- X509 *key = iter-> first ;
1389- if (key == nullptr ) {
1390- continue ;
1376+
1377+ // Fast path: if only one certificate in the map, skip SSL_get_certificate() lookup
1378+ if (map->size () == 1 ) {
1379+ cinf = map-> begin () ->second ;
1380+ } else {
1381+ // Fetch the specific certificate used in this negotiation
1382+ X509 *cert = SSL_get_certificate (ssl);
1383+ if (!cert) {
1384+ Error ( " ssl_callback_ocsp_stapling: failed to get certificate " );
1385+ return SSL_TLSEXT_ERR_NOACK ;
13911386 }
13921387
1393- if (X509_cmp (key, cert) == 0 ) {
1388+ #if HAVE_NATIVE_DUAL_CERT_SUPPORT
1389+ certinfo_map::iterator iter = map->find (cert);
1390+ if (iter != map->end ()) {
13941391 cinf = iter->second ;
1395- break ;
13961392 }
1397- }
1393+ #else
1394+ for (certinfo_map::iterator iter = map->begin (); iter != map->end (); ++iter) {
1395+ X509 *key = iter->first ;
1396+ if (key == nullptr ) {
1397+ continue ;
1398+ }
1399+
1400+ if (X509_cmp (key, cert) == 0 ) {
1401+ cinf = iter->second ;
1402+ break ;
1403+ }
1404+ }
13981405#endif
1406+ }
13991407
14001408 if (cinf == nullptr ) {
14011409 Error (" ssl_callback_ocsp_stapling: failed to get certificate information for ssl=%p" , ssl);
14021410 return SSL_TLSEXT_ERR_NOACK;
14031411 }
14041412
1405- ink_mutex_acquire (&cinf->stapling_mutex );
1406- time_t current_time = time (nullptr );
1407- if ((cinf->resp_derlen == 0 || cinf->is_expire ) || (cinf->expire_time < current_time && !cinf->is_prefetched )) {
1408- ink_mutex_release (&cinf->stapling_mutex );
1409- Error (" ssl_callback_ocsp_stapling: failed to get certificate status for %s" , cinf->certname );
1410- return SSL_TLSEXT_ERR_NOACK;
1411- } else {
1412- unsigned char *p = static_cast <unsigned char *>(OPENSSL_malloc (cinf->resp_derlen ));
1413- if (p == nullptr ) {
1414- ink_mutex_release (&cinf->stapling_mutex );
1415- Dbg (dbg_ctl_ssl_ocsp, " ssl_callback_ocsp_stapling: failed to allocate memory for %s" , cinf->certname );
1413+ unsigned char resp_copy[MAX_STAPLING_DER];
1414+ unsigned int resp_copylen;
1415+
1416+ {
1417+ ts::bravo::shared_lock lock (cinf->resp_mutex );
1418+
1419+ time_t current_time = time (nullptr );
1420+ if (cinf->resp_derlen == 0 || cinf->is_expire || (cinf->expire_time < current_time && !cinf->is_prefetched )) {
1421+ Error (" ssl_callback_ocsp_stapling: failed to get certificate status for %s" , cinf->certname );
14161422 return SSL_TLSEXT_ERR_NOACK;
14171423 }
1418- memcpy (p, cinf->resp_der , cinf->resp_derlen );
1419- ink_mutex_release (&cinf->stapling_mutex );
1420- SSL_set_tlsext_status_ocsp_resp (ssl, p, cinf->resp_derlen );
1421- Dbg (dbg_ctl_ssl_ocsp, " ssl_callback_ocsp_stapling: successfully got certificate status for %s" , cinf->certname );
1422- Dbg (dbg_ctl_ssl_ocsp, " is_prefetched:%d uri:%s" , cinf->is_prefetched , cinf->uri );
1423- return SSL_TLSEXT_ERR_OK;
1424+
1425+ resp_copylen = cinf->resp_derlen ;
1426+ memcpy (resp_copy, cinf->resp_der , resp_copylen);
1427+ }
1428+
1429+ unsigned char *p = static_cast <unsigned char *>(OPENSSL_malloc (resp_copylen));
1430+ if (p == nullptr ) {
1431+ Dbg (dbg_ctl_ssl_ocsp, " ssl_callback_ocsp_stapling: failed to allocate memory for %s" , cinf->certname );
1432+ return SSL_TLSEXT_ERR_NOACK;
14241433 }
1434+ memcpy (p, resp_copy, resp_copylen);
1435+ SSL_set_tlsext_status_ocsp_resp (ssl, p, resp_copylen);
1436+
1437+ Dbg (dbg_ctl_ssl_ocsp, " ssl_callback_ocsp_stapling: successfully got certificate status for %s" , cinf->certname );
1438+ Dbg (dbg_ctl_ssl_ocsp, " is_prefetched:%d uri:%s" , cinf->is_prefetched , cinf->uri );
1439+ return SSL_TLSEXT_ERR_OK;
14251440}
0 commit comments