This is an automated email from the ASF dual-hosted git repository.
bneradt pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/trafficserver.git
The following commit(s) were added to refs/heads/master by this push:
new c660866a1d proxy.config.ssl.client.CA.cert.filename: overridable
(#13174)
c660866a1d is described below
commit c660866a1d2478df226e3e7645c47a4636f92e82
Author: Brian Neradt <[email protected]>
AuthorDate: Mon Jun 1 14:58:19 2026 -0500
proxy.config.ssl.client.CA.cert.filename: overridable (#13174)
This adds proxy.config.ssl.client.CA.cert.filename, the client CA
certificate path, to the overridable config.
Co-authored-by: bneradt <[email protected]>
---
doc/admin-guide/files/records.yaml.en.rst | 1 +
.../api/functions/TSHttpOverridableConfig.en.rst | 1 +
.../api/types/TSOverridableConfigKey.en.rst | 1 +
include/cripts/Configs.hpp | 1 +
include/proxy/http/HttpConfig.h | 2 ++
include/proxy/http/OverridableConfigDefs.h | 3 ++-
include/ts/apidefs.h.in | 1 +
src/api/InkAPI.cc | 9 +++++++
src/iocore/net/SSLNetVConnection.cc | 30 +++++++++++++++++-----
src/proxy/http/HttpSM.cc | 1 +
src/proxy/http/PreWarmManager.cc | 1 +
.../gold_tests/tls/tls_verify_ca_override.test.py | 25 +++++++++++-------
12 files changed, 59 insertions(+), 17 deletions(-)
diff --git a/doc/admin-guide/files/records.yaml.en.rst
b/doc/admin-guide/files/records.yaml.en.rst
index b319c15b1b..9ea67b7ccd 100644
--- a/doc/admin-guide/files/records.yaml.en.rst
+++ b/doc/admin-guide/files/records.yaml.en.rst
@@ -4407,6 +4407,7 @@ Client-Related Configuration
.. ts:cv:: CONFIG proxy.config.ssl.client.CA.cert.path STRING NULL
:reloadable:
+ :overridable:
Specifies the location of the certificate authority file against
which the origin server will be verified.
diff --git a/doc/developer-guide/api/functions/TSHttpOverridableConfig.en.rst
b/doc/developer-guide/api/functions/TSHttpOverridableConfig.en.rst
index 9a175f4e15..623b40f3a1 100644
--- a/doc/developer-guide/api/functions/TSHttpOverridableConfig.en.rst
+++ b/doc/developer-guide/api/functions/TSHttpOverridableConfig.en.rst
@@ -190,6 +190,7 @@ TSOverridableConfigKey Value
Config
:enumerator:`TS_CONFIG_SSL_CLIENT_CERT_FILENAME`
:ts:cv:`proxy.config.ssl.client.cert.filename`
:enumerator:`TS_CONFIG_SSL_CLIENT_PRIVATE_KEY_FILENAME`
:ts:cv:`proxy.config.ssl.client.private_key.filename`
:enumerator:`TS_CONFIG_SSL_CLIENT_CA_CERT_FILENAME`
:ts:cv:`proxy.config.ssl.client.CA.cert.filename`
+:enumerator:`TS_CONFIG_SSL_CLIENT_CA_CERT_PATH`
:ts:cv:`proxy.config.ssl.client.CA.cert.path`
:enumerator:`TS_CONFIG_HTTP_HOST_RESOLUTION_PREFERENCE`
:ts:cv:`proxy.config.hostdb.ip_resolve`
:enumerator:`TS_CONFIG_PLUGIN_VC_DEFAULT_BUFFER_INDEX`
:ts:cv:`proxy.config.plugin.vc.default_buffer_index`
:enumerator:`TS_CONFIG_PLUGIN_VC_DEFAULT_BUFFER_WATER_MARK`
:ts:cv:`proxy.config.plugin.vc.default_buffer_water_mark`
diff --git a/doc/developer-guide/api/types/TSOverridableConfigKey.en.rst
b/doc/developer-guide/api/types/TSOverridableConfigKey.en.rst
index 56d325e619..9d200845c6 100644
--- a/doc/developer-guide/api/types/TSOverridableConfigKey.en.rst
+++ b/doc/developer-guide/api/types/TSOverridableConfigKey.en.rst
@@ -154,6 +154,7 @@ Enumeration Members
.. enumerator:: TS_CONFIG_SSL_CLIENT_SNI_POLICY
.. enumerator:: TS_CONFIG_SSL_CLIENT_PRIVATE_KEY_FILENAME
.. enumerator:: TS_CONFIG_SSL_CLIENT_CA_CERT_FILENAME
+.. enumerator:: TS_CONFIG_SSL_CLIENT_CA_CERT_PATH
.. enumerator:: TS_CONFIG_HTTP_HOST_RESOLUTION_PREFERENCE
.. enumerator:: TS_CONFIG_PLUGIN_VC_DEFAULT_BUFFER_INDEX
.. enumerator:: TS_CONFIG_PLUGIN_VC_DEFAULT_BUFFER_WATER_MARK
diff --git a/include/cripts/Configs.hpp b/include/cripts/Configs.hpp
index 6826f64247..c2f4597a6a 100644
--- a/include/cripts/Configs.hpp
+++ b/include/cripts/Configs.hpp
@@ -357,6 +357,7 @@ private:
{
public:
cripts::StringConfig
filename{"proxy.config.ssl.client.CA.cert.filename"};
+ cripts::StringConfig path{"proxy.config.ssl.client.CA.cert.path"};
}; // End class Cert
public:
diff --git a/include/proxy/http/HttpConfig.h b/include/proxy/http/HttpConfig.h
index 05a7cc511f..c5989c3620 100644
--- a/include/proxy/http/HttpConfig.h
+++ b/include/proxy/http/HttpConfig.h
@@ -773,6 +773,7 @@ struct OverridableHttpConfigParams {
char *ssl_client_cert_filename = nullptr;
char *ssl_client_private_key_filename = nullptr;
char *ssl_client_ca_cert_filename = nullptr;
+ char *ssl_client_ca_cert_path = nullptr;
char *ssl_client_alpn_protocols = nullptr;
// Host Resolution order
@@ -1031,6 +1032,7 @@ inline HttpConfigParams::~HttpConfigParams()
ats_free(oride.ssl_client_cert_filename);
ats_free(oride.ssl_client_private_key_filename);
ats_free(oride.ssl_client_ca_cert_filename);
+ ats_free(oride.ssl_client_ca_cert_path);
ats_free(connect_ports_string);
ats_free(reverse_proxy_no_host_redirect);
ats_free(redirect_actions_string);
diff --git a/include/proxy/http/OverridableConfigDefs.h
b/include/proxy/http/OverridableConfigDefs.h
index d70c4c54ca..a21e57d70a 100644
--- a/include/proxy/http/OverridableConfigDefs.h
+++ b/include/proxy/http/OverridableConfigDefs.h
@@ -250,6 +250,7 @@
X(HTTP_CONNECT_ATTEMPTS_RETRY_BACKOFF_BASE,
connect_attempts_retry_backoff_base,
"proxy.config.http.connect_attempts_retry_backoff_base", INT,
GENERIC) \
X(HTTP_NEGATIVE_REVALIDATING_LIST,
negative_revalidating_list,
"proxy.config.http.negative_revalidating_list", STRING,
HttpStatusCodeList_Conv) \
X(HTTP_CACHE_POST_METHOD, cache_post_method,
"proxy.config.http.cache.post_method",
INT, GENERIC) \
- X(HTTP_CACHE_TARGETED_CACHE_CONTROL_HEADERS,
targeted_cache_control_headers,
"proxy.config.http.cache.targeted_cache_control_headers", STRING,
TargetedCacheControlHeaders_Conv)
+ X(HTTP_CACHE_TARGETED_CACHE_CONTROL_HEADERS,
targeted_cache_control_headers,
"proxy.config.http.cache.targeted_cache_control_headers", STRING,
TargetedCacheControlHeaders_Conv) \
+ X(SSL_CLIENT_CA_CERT_PATH, ssl_client_ca_cert_path,
"proxy.config.ssl.client.CA.cert.path",
STRING, NONE)
// clang-format on
diff --git a/include/ts/apidefs.h.in b/include/ts/apidefs.h.in
index f458884779..bce145c8a4 100644
--- a/include/ts/apidefs.h.in
+++ b/include/ts/apidefs.h.in
@@ -916,6 +916,7 @@ enum TSOverridableConfigKey {
TS_CONFIG_HTTP_NEGATIVE_REVALIDATING_LIST,
TS_CONFIG_HTTP_CACHE_POST_METHOD,
TS_CONFIG_HTTP_CACHE_TARGETED_CACHE_CONTROL_HEADERS,
+ TS_CONFIG_SSL_CLIENT_CA_CERT_PATH,
TS_CONFIG_LAST_ENTRY,
};
diff --git a/src/api/InkAPI.cc b/src/api/InkAPI.cc
index c5f80b6ef1..22ec85e8cb 100644
--- a/src/api/InkAPI.cc
+++ b/src/api/InkAPI.cc
@@ -7574,6 +7574,11 @@ TSHttpTxnConfigStringSet(TSHttpTxn txnp,
TSOverridableConfigKey conf, const char
s->t_state.my_txn_conf().ssl_client_ca_cert_filename = const_cast<char
*>(value);
}
break;
+ case TS_CONFIG_SSL_CLIENT_CA_CERT_PATH:
+ if (value && length > 0) {
+ s->t_state.my_txn_conf().ssl_client_ca_cert_path = const_cast<char
*>(value);
+ }
+ break;
case TS_CONFIG_SSL_CLIENT_ALPN_PROTOCOLS:
if (value && length > 0) {
s->t_state.my_txn_conf().ssl_client_alpn_protocols = const_cast<char
*>(value);
@@ -7653,6 +7658,10 @@ TSHttpTxnConfigStringGet(TSHttpTxn txnp,
TSOverridableConfigKey conf, const char
*value = sm->t_state.txn_conf->server_session_sharing_match_str;
*length = *value ? strlen(*value) : 0;
break;
+ case TS_CONFIG_SSL_CLIENT_CA_CERT_PATH:
+ *value = sm->t_state.txn_conf->ssl_client_ca_cert_path;
+ *length = *value ? strlen(*value) : 0;
+ break;
default: {
MgmtConverter const *conv;
const void *src = _conf_to_memberp(conf, sm->t_state.txn_conf,
conv);
diff --git a/src/iocore/net/SSLNetVConnection.cc
b/src/iocore/net/SSLNetVConnection.cc
index ab5eb9d32b..43f945176e 100644
--- a/src/iocore/net/SSLNetVConnection.cc
+++ b/src/iocore/net/SSLNetVConnection.cc
@@ -92,6 +92,17 @@ DbgCtl dbg_ctl_ssl_alpn{"ssl_alpn"};
DbgCtl dbg_ctl_ssl_origin_session_cache{"ssl.origin_session_cache"};
DbgCtl dbg_ctl_proxyprotocol{"proxyprotocol"};
+const char *
+resolve_client_ca_cert_path(const SSLConfigParams *params, const char *path,
std::string &storage)
+{
+ if (path == nullptr) {
+ return params->clientCACertPath;
+ }
+
+ storage = Layout::get()->relative_to(Layout::get()->prefix, path);
+ return storage.c_str();
+}
+
} // namespace
//
@@ -1129,6 +1140,8 @@ SSLNetVConnection::_sslStartHandShake(int event, int &err)
auto nps = sniParam->get_property_config(serverKey);
shared_SSL_CTX sharedCTX = nullptr;
SSL_CTX *clientCTX = nullptr;
+ std::string caCertPathStorage;
+ const char *caCertPath = resolve_client_ca_cert_path(params,
options.ssl_client_ca_cert_path, caCertPathStorage);
// First Look to see if there are override parameters
Dbg(dbg_ctl_ssl, "Checking for outbound client cert override [%p]",
options.ssl_client_cert_name.get());
@@ -1144,18 +1157,21 @@ SSLNetVConnection::_sslStartHandShake(int event, int
&err)
keyFilePath =
Layout::get()->relative_to(params->clientKeyPathOnly,
options.ssl_client_private_key_name);
}
if (options.ssl_client_ca_cert_name) {
- caCertFilePath =
Layout::get()->relative_to(params->clientCACertPath,
options.ssl_client_ca_cert_name);
+ caCertFilePath = Layout::get()->relative_to(caCertPath,
options.ssl_client_ca_cert_name);
}
Dbg(dbg_ctl_ssl, "Using outbound client cert `%s'",
options.ssl_client_cert_name.get());
} else {
Dbg(dbg_ctl_ssl, "Clearing outbound client cert");
}
- sharedCTX =
- params->getCTX(certFilePath, keyFilePath, caCertFilePath.empty() ?
params->clientCACertFilename : caCertFilePath.c_str(),
- params->clientCACertPath);
- } else if (options.ssl_client_ca_cert_name) {
- std::string caCertFilePath =
Layout::get()->relative_to(params->clientCACertPath,
options.ssl_client_ca_cert_name);
- sharedCTX = params->getCTX(params->clientCertPath,
params->clientKeyPath, caCertFilePath.c_str(), params->clientCACertPath);
+ sharedCTX = params->getCTX(certFilePath, keyFilePath,
+ caCertFilePath.empty() ?
params->clientCACertFilename : caCertFilePath.c_str(), caCertPath);
+ } else if (options.ssl_client_ca_cert_name ||
options.ssl_client_ca_cert_path) {
+ std::string caCertFilePath;
+ if (options.ssl_client_ca_cert_name) {
+ caCertFilePath = Layout::get()->relative_to(caCertPath,
options.ssl_client_ca_cert_name);
+ }
+ sharedCTX = params->getCTX(params->clientCertPath,
params->clientKeyPath,
+ caCertFilePath.empty() ?
params->clientCACertFilename : caCertFilePath.c_str(), caCertPath);
} else if (nps && !nps->client_cert_file.empty()) {
// If no overrides available, try the available nextHopProperty by
reading from context mappings
sharedCTX =
diff --git a/src/proxy/http/HttpSM.cc b/src/proxy/http/HttpSM.cc
index 7b69aaed8a..09c3a46c0e 100644
--- a/src/proxy/http/HttpSM.cc
+++ b/src/proxy/http/HttpSM.cc
@@ -5877,6 +5877,7 @@ HttpSM::do_http_server_open(bool raw, bool only_direct)
opt.set_ssl_client_cert_name(t_state.txn_conf->ssl_client_cert_filename);
opt.ssl_client_private_key_name =
t_state.txn_conf->ssl_client_private_key_filename;
opt.ssl_client_ca_cert_name =
t_state.txn_conf->ssl_client_ca_cert_filename;
+ opt.ssl_client_ca_cert_path = t_state.txn_conf->ssl_client_ca_cert_path;
if (is_private()) {
// If the connection to origin is private, don't try to negotiate the
higher overhead H2
opt.alpn_protocols_array_size = -1;
diff --git a/src/proxy/http/PreWarmManager.cc b/src/proxy/http/PreWarmManager.cc
index 5fca803091..594fc24223 100644
--- a/src/proxy/http/PreWarmManager.cc
+++ b/src/proxy/http/PreWarmManager.cc
@@ -576,6 +576,7 @@ PreWarmSM::_connect(const IpEndpoint &addr)
opt.ssl_client_cert_name =
http_conf_params->oride.ssl_client_cert_filename;
opt.ssl_client_private_key_name =
http_conf_params->oride.ssl_client_private_key_filename;
opt.ssl_client_ca_cert_name =
http_conf_params->oride.ssl_client_ca_cert_filename;
+ opt.ssl_client_ca_cert_path =
http_conf_params->oride.ssl_client_ca_cert_path;
SCOPED_MUTEX_LOCK(lock, mutex, this_ethread());
connect_action_handle = sslNetProcessor.connect_re(this, &addr.sa, opt);
diff --git a/tests/gold_tests/tls/tls_verify_ca_override.test.py
b/tests/gold_tests/tls/tls_verify_ca_override.test.py
index 610bc01603..1774f18150 100644
--- a/tests/gold_tests/tls/tls_verify_ca_override.test.py
+++ b/tests/gold_tests/tls/tls_verify_ca_override.test.py
@@ -17,7 +17,7 @@
# limitations under the License.
Test.Summary = '''
-Test tls server certificate verification options. Exercise conf_remap for ca
bundle
+Test tls server certificate verification options. Exercise conf_remap for ca
bundle path and file.
'''
# Define default ATS
@@ -58,18 +58,25 @@ ts.addSSLfile("ssl/signer.key")
ts.addSSLfile("ssl/signer2.pem")
ts.addSSLfile("ssl/signer2.key")
+
+def ca_cert_overrides(filename):
+ return (
+ f'@pparam=proxy.config.ssl.client.CA.cert.path={ts.Variables.SSLDir} '
+ f'@pparam=proxy.config.ssl.client.CA.cert.filename={filename}')
+
+
ts.Disk.remap_config.AddLine(
- 'map /case1 https://127.0.0.1:{0}/ @plugin=conf_remap.so
@pparam=proxy.config.ssl.client.CA.cert.filename={1}/{2}'.format(
- server1.Variables.SSL_Port, ts.Variables.SSLDir, "signer.pem"))
+ f'map /case1 https://127.0.0.1:{server1.Variables.SSL_Port}/ '
+ f'@plugin=conf_remap.so {ca_cert_overrides("signer.pem")}')
ts.Disk.remap_config.AddLine(
- 'map /badcase1 https://127.0.0.1:{0}/ @plugin=conf_remap.so
@pparam=proxy.config.ssl.client.CA.cert.filename={1}/{2}'.format(
- server1.Variables.SSL_Port, ts.Variables.SSLDir, "signer2.pem"))
+ f'map /badcase1 https://127.0.0.1:{server1.Variables.SSL_Port}/ '
+ f'@plugin=conf_remap.so {ca_cert_overrides("signer2.pem")}')
ts.Disk.remap_config.AddLine(
- 'map /case2 https://127.0.0.1:{0}/ @plugin=conf_remap.so
@pparam=proxy.config.ssl.client.CA.cert.filename={1}/{2}'.format(
- server2.Variables.SSL_Port, ts.Variables.SSLDir, "signer2.pem"))
+ f'map /case2 https://127.0.0.1:{server2.Variables.SSL_Port}/ '
+ f'@plugin=conf_remap.so {ca_cert_overrides("signer2.pem")}')
ts.Disk.remap_config.AddLine(
- 'map /badcase2 https://127.0.0.1:{0}/ @plugin=conf_remap.so
@pparam=proxy.config.ssl.client.CA.cert.filename={1}/{2}'.format(
- server2.Variables.SSL_Port, ts.Variables.SSLDir, "signer.pem"))
+ f'map /badcase2 https://127.0.0.1:{server2.Variables.SSL_Port}/ '
+ f'@plugin=conf_remap.so {ca_cert_overrides("signer.pem")}')
ts.Disk.ssl_multicert_yaml.AddLines(
"""