Copilot commented on code in PR #12683:
URL: https://github.com/apache/trafficserver/pull/12683#discussion_r2548115286
##########
plugins/lua/ts_lua_client_cert_helpers.h:
##########
@@ -0,0 +1,190 @@
+// Helper functions for certificate data extraction
+static std::string
+get_x509_name_string(X509_NAME *name)
+{
+ if (!name) {
+ return "";
+ }
+
+ BIO *bio = BIO_new(BIO_s_mem());
+ if (!bio) {
+ return "";
+ }
+
+ X509_NAME_print_ex(bio, name, 0, XN_FLAG_RFC2253);
+
+ char *data = nullptr;
+ long length = BIO_get_mem_data(bio, &data);
+ std::string result(data, length);
+
+ BIO_free(bio);
+ return result;
+}
+
+static std::string
+get_x509_serial_string(X509 *cert)
+{
+ if (!cert) {
+ return "";
+ }
+
+ ASN1_INTEGER *serial = X509_get_serialNumber(cert);
+ if (!serial) {
+ return "";
+ }
+
+ BIO *bio = BIO_new(BIO_s_mem());
+ if (!bio) {
+ return "";
+ }
+
+ i2a_ASN1_INTEGER(bio, serial);
+
+ char *data = nullptr;
+ long length = BIO_get_mem_data(bio, &data);
+ std::string result(data, length);
+
+ BIO_free(bio);
+ return result;
+}
+
+static std::string
+get_x509_time_string(ASN1_TIME *time)
+{
+ if (!time) {
+ return "";
+ }
+
+ BIO *bio = BIO_new(BIO_s_mem());
+ if (!bio) {
+ return "";
+ }
+
+ ASN1_TIME_print(bio, time);
+
+ char *data = nullptr;
+ long length = BIO_get_mem_data(bio, &data);
+ std::string result(data, length);
+
+ BIO_free(bio);
+ return result;
+}
+
+static std::string
+get_x509_pem_string(X509 *cert)
+{
+ if (!cert) {
+ return "";
+ }
+
+ BIO *bio = BIO_new(BIO_s_mem());
+ if (!bio) {
+ return "";
+ }
+
+ PEM_write_bio_X509(bio, cert);
+
+ char *data = nullptr;
+ long length = BIO_get_mem_data(bio, &data);
+ std::string result(data, length);
+
+ BIO_free(bio);
+ return result;
+}
+
+static std::string
+get_x509_signature_string(X509 *cert)
+{
+ if (!cert) {
+ return "";
+ }
+
+ const ASN1_BIT_STRING *sig = nullptr;
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+ X509_get0_signature(&sig, nullptr, cert);
+#else
+ sig = cert->signature;
+#endif
+
+ if (!sig) {
+ return "";
+ }
+
+ BIO *bio = BIO_new(BIO_s_mem());
+ if (!bio) {
+ return "";
+ }
+
+ for (int i = 0; i < sig->length; i++) {
+ BIO_printf(bio, "%02x", sig->data[i]);
+ if (i < sig->length - 1) {
+ BIO_printf(bio, ":");
+ }
+ }
+
+ char *data = nullptr;
+ long length = BIO_get_mem_data(bio, &data);
+ std::string result(data, length);
+
+ BIO_free(bio);
+ return result;
+}
+
+static std::vector<std::string>
+get_x509_san_strings(X509 *cert, int san_type)
+{
+ std::vector<std::string> results;
+
+ if (!cert) {
+ return results;
+ }
+
+ GENERAL_NAMES *names = static_cast<GENERAL_NAMES *>(X509_get_ext_d2i(cert,
NID_subject_alt_name, nullptr, nullptr));
+ if (!names) {
+ return results;
+ }
+
+ int num_names = sk_GENERAL_NAME_num(names);
+ for (int i = 0; i < num_names; i++) {
+ GENERAL_NAME *name = sk_GENERAL_NAME_value(names, i);
+ if (!name || name->type != san_type) {
+ continue;
+ }
+
+ switch (san_type) {
+ case GEN_DNS:
+ case GEN_EMAIL:
+ case GEN_URI: {
+ ASN1_STRING *str = name->d.ia5;
+ if (str) {
+ const unsigned char *data = ASN1_STRING_get0_data(str);
+ int len = ASN1_STRING_length(str);
+ if (data && len > 0) {
+ results.emplace_back(reinterpret_cast<const char *>(data), len);
+ }
+ }
+ break;
+ }
+ case GEN_IPADD: {
+ ASN1_OCTET_STRING *ip = name->d.iPAddress;
+ if (ip) {
+ const unsigned char *data = ASN1_STRING_get0_data(ip);
+ int len = ASN1_STRING_length(ip);
+ char ip_str[INET6_ADDRSTRLEN];
+
+ if (len == 4) { // IPv4
+ inet_ntop(AF_INET, data, ip_str, sizeof(ip_str));
+ results.emplace_back(ip_str);
+ } else if (len == 16) { // IPv6
+ inet_ntop(AF_INET6, data, ip_str, sizeof(ip_str));
+ results.emplace_back(ip_str);
+ }
Review Comment:
Missing error handling for `inet_ntop` failures. The function `inet_ntop`
can fail and return NULL (e.g., if the address family is invalid or the buffer
is too small). When this happens, pushing the uninitialized `ip_str` buffer to
the results vector could lead to undefined behavior.
Add error checking:
```cpp
if (len == 4) { // IPv4
if (inet_ntop(AF_INET, data, ip_str, sizeof(ip_str)) != nullptr) {
results.emplace_back(ip_str);
}
} else if (len == 16) { // IPv6
if (inet_ntop(AF_INET6, data, ip_str, sizeof(ip_str)) != nullptr) {
results.emplace_back(ip_str);
}
}
```
```suggestion
if (inet_ntop(AF_INET, data, ip_str, sizeof(ip_str)) != nullptr) {
results.emplace_back(ip_str);
}
} else if (len == 16) { // IPv6
if (inet_ntop(AF_INET6, data, ip_str, sizeof(ip_str)) != nullptr) {
results.emplace_back(ip_str);
}
```
##########
doc/admin-guide/plugins/lua.en.rst:
##########
@@ -1256,6 +1256,353 @@ Here is an example:
end
+:ref:`TOP <admin-plugins-ts-lua>`
+
+ts.client_request.client_cert_get_pem
+-----------------------------------------------
+**syntax:** *ts.client_request.client_cert_get_pem()*
+
+**context:** do_remap/do_os_response or do_global_* or later
+
+**description**: Get the PEM-encoded client certificate (for mTLS connections).
+
+Returns the client certificate in PEM format, or nil if no client certificate
is present.
+
+Here is an example:
+
+::
+
+ function do_global_read_request()
+ pem = ts.client_request.client_cert_get_pem()
+ if pem then
+ ts.debug('Client cert PEM: ' .. pem)
+ end
+ end
+
+
+:ref:`TOP <admin-plugins-ts-lua>`
+
+ts.client_request.client_cert_get_subject
+-----------------------------------------------
+**syntax:** *ts.client_request.client_cert_get_subject()*
+
+**context:** do_remap/do_os_response or do_global_* or later
+
+**description**: Get the subject DN from the client certificate.
+
+Returns the subject distinguished name in RFC2253 format, or nil if not
available.
+
+Here is an example:
+
+::
+
+ function do_global_read_request()
+ subject = ts.client_request.client_cert_get_subject()
+ if subject then
+ ts.debug('Client cert subject: ' .. subject)
+ end
+ end
+
+
+:ref:`TOP <admin-plugins-ts-lua>`
+
+ts.client_request.client_cert_get_issuer
+-----------------------------------------------
+**syntax:** *ts.client_request.client_cert_get_issuer()*
+
+**context:** do_remap/do_os_response or do_global_* or later
+
+**description**: Get the issuer DN from the client certificate.
+
+Returns the issuer distinguished name in RFC2253 format, or nil if not
available.
+
+
Review Comment:
[nitpick] Missing usage example for `client_cert_get_issuer`. Unlike other
similar functions in the documentation (e.g., `client_cert_get_subject`,
`client_cert_get_pem`), the `client_cert_get_issuer` function lacks a usage
example. For consistency and completeness, consider adding an example similar
to the other certificate functions.
```suggestion
Here is an example:
::
function do_global_read_request()
issuer = ts.client_request.client_cert_get_issuer()
if issuer then
ts.debug('Client cert issuer: ' .. issuer)
end
end
```
##########
plugins/lua/ts_lua_client_cert_helpers.h:
##########
@@ -0,0 +1,190 @@
+// Helper functions for certificate data extraction
+static std::string
+get_x509_name_string(X509_NAME *name)
+{
+ if (!name) {
+ return "";
+ }
+
+ BIO *bio = BIO_new(BIO_s_mem());
+ if (!bio) {
+ return "";
+ }
+
+ X509_NAME_print_ex(bio, name, 0, XN_FLAG_RFC2253);
+
+ char *data = nullptr;
+ long length = BIO_get_mem_data(bio, &data);
+ std::string result(data, length);
+
+ BIO_free(bio);
+ return result;
+}
+
+static std::string
+get_x509_serial_string(X509 *cert)
+{
+ if (!cert) {
+ return "";
+ }
+
+ ASN1_INTEGER *serial = X509_get_serialNumber(cert);
+ if (!serial) {
+ return "";
+ }
+
+ BIO *bio = BIO_new(BIO_s_mem());
+ if (!bio) {
+ return "";
+ }
+
+ i2a_ASN1_INTEGER(bio, serial);
+
+ char *data = nullptr;
+ long length = BIO_get_mem_data(bio, &data);
+ std::string result(data, length);
+
+ BIO_free(bio);
+ return result;
+}
+
+static std::string
+get_x509_time_string(ASN1_TIME *time)
+{
+ if (!time) {
+ return "";
+ }
+
+ BIO *bio = BIO_new(BIO_s_mem());
+ if (!bio) {
+ return "";
+ }
+
+ ASN1_TIME_print(bio, time);
+
+ char *data = nullptr;
+ long length = BIO_get_mem_data(bio, &data);
+ std::string result(data, length);
+
+ BIO_free(bio);
+ return result;
+}
+
+static std::string
+get_x509_pem_string(X509 *cert)
+{
+ if (!cert) {
+ return "";
+ }
+
+ BIO *bio = BIO_new(BIO_s_mem());
+ if (!bio) {
+ return "";
+ }
+
+ PEM_write_bio_X509(bio, cert);
+
+ char *data = nullptr;
+ long length = BIO_get_mem_data(bio, &data);
+ std::string result(data, length);
+
+ BIO_free(bio);
+ return result;
+}
+
+static std::string
+get_x509_signature_string(X509 *cert)
+{
+ if (!cert) {
+ return "";
+ }
+
+ const ASN1_BIT_STRING *sig = nullptr;
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+ X509_get0_signature(&sig, nullptr, cert);
+#else
+ sig = cert->signature;
+#endif
+
+ if (!sig) {
+ return "";
+ }
+
+ BIO *bio = BIO_new(BIO_s_mem());
+ if (!bio) {
+ return "";
+ }
+
+ for (int i = 0; i < sig->length; i++) {
+ BIO_printf(bio, "%02x", sig->data[i]);
+ if (i < sig->length - 1) {
+ BIO_printf(bio, ":");
+ }
+ }
+
+ char *data = nullptr;
+ long length = BIO_get_mem_data(bio, &data);
+ std::string result(data, length);
+
+ BIO_free(bio);
+ return result;
Review Comment:
Potential null pointer dereference. The helper functions in this file do not
check if `BIO_get_mem_data` returns a valid pointer before using it to
construct a `std::string`. While `BIO_get_mem_data` typically returns a valid
pointer when the BIO is successfully created, defensive programming would
suggest checking the return value or at minimum verifying that `length > 0`
before constructing the string.
For example, in `get_x509_name_string`, `get_x509_serial_string`,
`get_x509_time_string`, `get_x509_pem_string`, and `get_x509_signature_string`,
consider adding a check:
```cpp
if (data && length > 0) {
std::string result(data, length);
}
```
##########
plugins/lua/ts_lua_client_cert_helpers.h:
##########
@@ -0,0 +1,190 @@
+// Helper functions for certificate data extraction
+static std::string
+get_x509_name_string(X509_NAME *name)
+{
+ if (!name) {
+ return "";
+ }
+
+ BIO *bio = BIO_new(BIO_s_mem());
+ if (!bio) {
+ return "";
+ }
+
+ X509_NAME_print_ex(bio, name, 0, XN_FLAG_RFC2253);
+
+ char *data = nullptr;
+ long length = BIO_get_mem_data(bio, &data);
+ std::string result(data, length);
+
+ BIO_free(bio);
+ return result;
+}
+
+static std::string
+get_x509_serial_string(X509 *cert)
+{
+ if (!cert) {
+ return "";
+ }
+
+ ASN1_INTEGER *serial = X509_get_serialNumber(cert);
+ if (!serial) {
+ return "";
+ }
+
+ BIO *bio = BIO_new(BIO_s_mem());
+ if (!bio) {
+ return "";
+ }
+
+ i2a_ASN1_INTEGER(bio, serial);
+
+ char *data = nullptr;
+ long length = BIO_get_mem_data(bio, &data);
+ std::string result(data, length);
+
+ BIO_free(bio);
+ return result;
+}
+
+static std::string
+get_x509_time_string(ASN1_TIME *time)
+{
+ if (!time) {
+ return "";
+ }
+
+ BIO *bio = BIO_new(BIO_s_mem());
+ if (!bio) {
+ return "";
+ }
+
+ ASN1_TIME_print(bio, time);
+
+ char *data = nullptr;
+ long length = BIO_get_mem_data(bio, &data);
+ std::string result(data, length);
+
+ BIO_free(bio);
+ return result;
+}
+
+static std::string
+get_x509_pem_string(X509 *cert)
+{
+ if (!cert) {
+ return "";
+ }
+
+ BIO *bio = BIO_new(BIO_s_mem());
+ if (!bio) {
+ return "";
+ }
+
+ PEM_write_bio_X509(bio, cert);
+
+ char *data = nullptr;
+ long length = BIO_get_mem_data(bio, &data);
+ std::string result(data, length);
+
+ BIO_free(bio);
+ return result;
+}
+
+static std::string
+get_x509_signature_string(X509 *cert)
+{
+ if (!cert) {
+ return "";
+ }
+
+ const ASN1_BIT_STRING *sig = nullptr;
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+ X509_get0_signature(&sig, nullptr, cert);
+#else
Review Comment:
[nitpick] Direct access to OpenSSL struct members is deprecated. The code
uses `cert->signature` for OpenSSL versions prior to 1.1.0, which directly
accesses internal structure members. This approach is deprecated and may not
work with newer OpenSSL versions that are built with opaque structures.
While the `#if` directive handles this for OpenSSL 1.1.0+, consider adding a
comment explaining that the `#else` branch is for legacy OpenSSL versions and
may have compatibility issues with some builds.
```suggestion
#else
// Legacy OpenSSL versions (<1.1.0): direct access to struct members is
deprecated and may not work
// if OpenSSL is built with opaque structures. Use with caution.
```
##########
plugins/lua/ts_lua_client_cert_helpers.h:
##########
@@ -0,0 +1,190 @@
+// Helper functions for certificate data extraction
Review Comment:
Missing Apache License header. All header files in the plugins/lua directory
include the standard Apache Software Foundation license header. This new header
file should include the same license header for consistency with the rest of
the codebase.
Add the Apache License header at the beginning of the file (before `#pragma
once`), following the pattern seen in other files like
`ts_lua_cached_response.h`.
##########
plugins/lua/ts_lua_client_cert_helpers.h:
##########
@@ -0,0 +1,190 @@
+// Helper functions for certificate data extraction
+static std::string
+get_x509_name_string(X509_NAME *name)
+{
+ if (!name) {
+ return "";
+ }
+
+ BIO *bio = BIO_new(BIO_s_mem());
+ if (!bio) {
+ return "";
+ }
+
+ X509_NAME_print_ex(bio, name, 0, XN_FLAG_RFC2253);
+
+ char *data = nullptr;
+ long length = BIO_get_mem_data(bio, &data);
+ std::string result(data, length);
+
+ BIO_free(bio);
+ return result;
+}
+
+static std::string
+get_x509_serial_string(X509 *cert)
+{
+ if (!cert) {
+ return "";
+ }
+
+ ASN1_INTEGER *serial = X509_get_serialNumber(cert);
+ if (!serial) {
+ return "";
+ }
+
+ BIO *bio = BIO_new(BIO_s_mem());
+ if (!bio) {
+ return "";
+ }
+
+ i2a_ASN1_INTEGER(bio, serial);
+
+ char *data = nullptr;
+ long length = BIO_get_mem_data(bio, &data);
+ std::string result(data, length);
+
+ BIO_free(bio);
+ return result;
+}
+
+static std::string
+get_x509_time_string(ASN1_TIME *time)
+{
+ if (!time) {
+ return "";
+ }
+
+ BIO *bio = BIO_new(BIO_s_mem());
+ if (!bio) {
+ return "";
+ }
+
+ ASN1_TIME_print(bio, time);
+
+ char *data = nullptr;
+ long length = BIO_get_mem_data(bio, &data);
+ std::string result(data, length);
+
+ BIO_free(bio);
+ return result;
+}
+
+static std::string
+get_x509_pem_string(X509 *cert)
+{
+ if (!cert) {
+ return "";
+ }
+
+ BIO *bio = BIO_new(BIO_s_mem());
+ if (!bio) {
+ return "";
+ }
+
+ PEM_write_bio_X509(bio, cert);
+
+ char *data = nullptr;
+ long length = BIO_get_mem_data(bio, &data);
+ std::string result(data, length);
+
+ BIO_free(bio);
+ return result;
+}
Review Comment:
Missing error checking for OpenSSL write operations. Functions like
`X509_NAME_print_ex`, `i2a_ASN1_INTEGER`, `ASN1_TIME_print`, and
`PEM_write_bio_X509` can fail and return error codes (typically 0 or negative
values on failure). These failures are not checked, which could result in
incomplete or invalid data being returned.
For example, in `get_x509_name_string`:
```cpp
if (X509_NAME_print_ex(bio, name, 0, XN_FLAG_RFC2253) <= 0) {
BIO_free(bio);
return "";
}
```
Similar checks should be added for the other helper functions.
##########
plugins/lua/ts_lua_client_cert_helpers.h:
##########
@@ -0,0 +1,190 @@
+// Helper functions for certificate data extraction
Review Comment:
Missing header guard. The header file lacks a header guard (either `#pragma
once` or traditional include guards). Based on the codebase convention seen in
other header files (e.g., `ts_lua_cached_response.h`,
`ts_lua_client_request.h`), this file should use `#pragma once` at the
beginning.
Add at the top of the file:
```cpp
#pragma once
```
##########
plugins/lua/ts_lua_client_request.cc:
##########
@@ -1139,3 +1174,924 @@ ts_lua_client_request_get_ssl_curve(lua_State *L)
return 1;
}
+
+// Certificate API Functions
+static void
+ts_lua_inject_client_request_cert_api(lua_State *L)
+{
+ // Client certificate functions
+ lua_pushcfunction(L, ts_lua_client_request_client_cert_get_pem);
+ lua_setfield(L, -2, "client_cert_get_pem");
+
+ lua_pushcfunction(L, ts_lua_client_request_client_cert_get_subject);
+ lua_setfield(L, -2, "client_cert_get_subject");
+
+ lua_pushcfunction(L, ts_lua_client_request_client_cert_get_issuer);
+ lua_setfield(L, -2, "client_cert_get_issuer");
+
+ lua_pushcfunction(L, ts_lua_client_request_client_cert_get_serial);
+ lua_setfield(L, -2, "client_cert_get_serial");
+
+ lua_pushcfunction(L, ts_lua_client_request_client_cert_get_signature);
+ lua_setfield(L, -2, "client_cert_get_signature");
+
+ lua_pushcfunction(L, ts_lua_client_request_client_cert_get_not_before);
+ lua_setfield(L, -2, "client_cert_get_not_before");
+
+ lua_pushcfunction(L, ts_lua_client_request_client_cert_get_not_after);
+ lua_setfield(L, -2, "client_cert_get_not_after");
+
+ lua_pushcfunction(L, ts_lua_client_request_client_cert_get_version);
+ lua_setfield(L, -2, "client_cert_get_version");
+
+ lua_pushcfunction(L, ts_lua_client_request_client_cert_get_san_dns);
+ lua_setfield(L, -2, "client_cert_get_san_dns");
+
+ lua_pushcfunction(L, ts_lua_client_request_client_cert_get_san_ip);
+ lua_setfield(L, -2, "client_cert_get_san_ip");
+
+ lua_pushcfunction(L, ts_lua_client_request_client_cert_get_san_email);
+ lua_setfield(L, -2, "client_cert_get_san_email");
+
+ lua_pushcfunction(L, ts_lua_client_request_client_cert_get_san_uri);
+ lua_setfield(L, -2, "client_cert_get_san_uri");
+
+ // Server certificate functions
+ lua_pushcfunction(L, ts_lua_client_request_server_cert_get_pem);
+ lua_setfield(L, -2, "server_cert_get_pem");
+
+ lua_pushcfunction(L, ts_lua_client_request_server_cert_get_subject);
+ lua_setfield(L, -2, "server_cert_get_subject");
+
+ lua_pushcfunction(L, ts_lua_client_request_server_cert_get_issuer);
+ lua_setfield(L, -2, "server_cert_get_issuer");
+
+ lua_pushcfunction(L, ts_lua_client_request_server_cert_get_serial);
+ lua_setfield(L, -2, "server_cert_get_serial");
+
+ lua_pushcfunction(L, ts_lua_client_request_server_cert_get_signature);
+ lua_setfield(L, -2, "server_cert_get_signature");
+
+ lua_pushcfunction(L, ts_lua_client_request_server_cert_get_not_before);
+ lua_setfield(L, -2, "server_cert_get_not_before");
+
+ lua_pushcfunction(L, ts_lua_client_request_server_cert_get_not_after);
+ lua_setfield(L, -2, "server_cert_get_not_after");
+
+ lua_pushcfunction(L, ts_lua_client_request_server_cert_get_version);
+ lua_setfield(L, -2, "server_cert_get_version");
+
+ lua_pushcfunction(L, ts_lua_client_request_server_cert_get_san_dns);
+ lua_setfield(L, -2, "server_cert_get_san_dns");
+
+ lua_pushcfunction(L, ts_lua_client_request_server_cert_get_san_ip);
+ lua_setfield(L, -2, "server_cert_get_san_ip");
+
+ lua_pushcfunction(L, ts_lua_client_request_server_cert_get_san_email);
+ lua_setfield(L, -2, "server_cert_get_san_email");
+
+ lua_pushcfunction(L, ts_lua_client_request_server_cert_get_san_uri);
+ lua_setfield(L, -2, "server_cert_get_san_uri");
+}
+
+// Client Certificate Functions
+static int
+ts_lua_client_request_client_cert_get_pem(lua_State *L)
+{
+ ts_lua_http_ctx *http_ctx;
+ TSHttpSsn ssnp;
+ TSVConn client_conn;
+
+ GET_HTTP_CONTEXT(http_ctx, L);
+
+ ssnp = TSHttpTxnSsnGet(http_ctx->txnp);
+ client_conn = TSHttpSsnClientVConnGet(ssnp);
+
+ if (TSVConnIsSsl(client_conn)) {
+ TSSslConnection ssl_conn = TSVConnSslConnectionGet(client_conn);
+ if (ssl_conn) {
+ SSL *ssl = reinterpret_cast<SSL *>(ssl_conn);
+#ifdef OPENSSL_IS_OPENSSL3
+ X509 *cert = SSL_get1_peer_certificate(ssl);
+#else
+ X509 *cert = SSL_get_peer_certificate(ssl);
+#endif
+ if (cert) {
+ std::string pem = get_x509_pem_string(cert);
+ X509_free(cert);
+ if (!pem.empty()) {
+ lua_pushlstring(L, pem.c_str(), pem.length());
+ return 1;
+ }
+ }
+ }
+ }
+
+ lua_pushnil(L);
+ return 1;
+}
+
+static int
+ts_lua_client_request_client_cert_get_subject(lua_State *L)
+{
+ ts_lua_http_ctx *http_ctx;
+ TSHttpSsn ssnp;
+ TSVConn client_conn;
+
+ GET_HTTP_CONTEXT(http_ctx, L);
+
+ ssnp = TSHttpTxnSsnGet(http_ctx->txnp);
+ client_conn = TSHttpSsnClientVConnGet(ssnp);
+
+ if (TSVConnIsSsl(client_conn)) {
+ TSSslConnection ssl_conn = TSVConnSslConnectionGet(client_conn);
+ if (ssl_conn) {
+ SSL *ssl = reinterpret_cast<SSL *>(ssl_conn);
+#ifdef OPENSSL_IS_OPENSSL3
+ X509 *cert = SSL_get1_peer_certificate(ssl);
+#else
+ X509 *cert = SSL_get_peer_certificate(ssl);
+#endif
+ if (cert) {
+ std::string subject =
get_x509_name_string(X509_get_subject_name(cert));
+ X509_free(cert);
+ if (!subject.empty()) {
+ lua_pushlstring(L, subject.c_str(), subject.length());
+ return 1;
+ }
+ }
+ }
+ }
+
+ lua_pushnil(L);
+ return 1;
+}
+
+static int
+ts_lua_client_request_client_cert_get_issuer(lua_State *L)
+{
+ ts_lua_http_ctx *http_ctx;
+ TSHttpSsn ssnp;
+ TSVConn client_conn;
+
+ GET_HTTP_CONTEXT(http_ctx, L);
+
+ ssnp = TSHttpTxnSsnGet(http_ctx->txnp);
+ client_conn = TSHttpSsnClientVConnGet(ssnp);
+
+ if (TSVConnIsSsl(client_conn)) {
+ TSSslConnection ssl_conn = TSVConnSslConnectionGet(client_conn);
+ if (ssl_conn) {
+ SSL *ssl = reinterpret_cast<SSL *>(ssl_conn);
+#ifdef OPENSSL_IS_OPENSSL3
+ X509 *cert = SSL_get1_peer_certificate(ssl);
+#else
+ X509 *cert = SSL_get_peer_certificate(ssl);
+#endif
+ if (cert) {
+ std::string issuer = get_x509_name_string(X509_get_issuer_name(cert));
+ X509_free(cert);
+ if (!issuer.empty()) {
+ lua_pushlstring(L, issuer.c_str(), issuer.length());
+ return 1;
+ }
+ }
+ }
+ }
+
+ lua_pushnil(L);
+ return 1;
+}
+
+static int
+ts_lua_client_request_client_cert_get_serial(lua_State *L)
+{
+ ts_lua_http_ctx *http_ctx;
+ TSHttpSsn ssnp;
+ TSVConn client_conn;
+
+ GET_HTTP_CONTEXT(http_ctx, L);
+
+ ssnp = TSHttpTxnSsnGet(http_ctx->txnp);
+ client_conn = TSHttpSsnClientVConnGet(ssnp);
+
+ if (TSVConnIsSsl(client_conn)) {
+ TSSslConnection ssl_conn = TSVConnSslConnectionGet(client_conn);
+ if (ssl_conn) {
+ SSL *ssl = reinterpret_cast<SSL *>(ssl_conn);
+#ifdef OPENSSL_IS_OPENSSL3
+ X509 *cert = SSL_get1_peer_certificate(ssl);
+#else
+ X509 *cert = SSL_get_peer_certificate(ssl);
+#endif
+ if (cert) {
+ std::string serial = get_x509_serial_string(cert);
+ X509_free(cert);
+ if (!serial.empty()) {
+ lua_pushlstring(L, serial.c_str(), serial.length());
+ return 1;
+ }
+ }
+ }
+ }
+
+ lua_pushnil(L);
+ return 1;
+}
+
+static int
+ts_lua_client_request_client_cert_get_signature(lua_State *L)
+{
+ ts_lua_http_ctx *http_ctx;
+ TSHttpSsn ssnp;
+ TSVConn client_conn;
+
+ GET_HTTP_CONTEXT(http_ctx, L);
+
+ ssnp = TSHttpTxnSsnGet(http_ctx->txnp);
+ client_conn = TSHttpSsnClientVConnGet(ssnp);
+
+ if (TSVConnIsSsl(client_conn)) {
+ TSSslConnection ssl_conn = TSVConnSslConnectionGet(client_conn);
+ if (ssl_conn) {
+ SSL *ssl = reinterpret_cast<SSL *>(ssl_conn);
+#ifdef OPENSSL_IS_OPENSSL3
+ X509 *cert = SSL_get1_peer_certificate(ssl);
+#else
+ X509 *cert = SSL_get_peer_certificate(ssl);
+#endif
+ if (cert) {
+ std::string sig = get_x509_signature_string(cert);
+ X509_free(cert);
+ if (!sig.empty()) {
+ lua_pushlstring(L, sig.c_str(), sig.length());
+ return 1;
+ }
+ }
+ }
+ }
+
+ lua_pushnil(L);
+ return 1;
+}
+
+static int
+ts_lua_client_request_client_cert_get_not_before(lua_State *L)
+{
+ ts_lua_http_ctx *http_ctx;
+ TSHttpSsn ssnp;
+ TSVConn client_conn;
+
+ GET_HTTP_CONTEXT(http_ctx, L);
+
+ ssnp = TSHttpTxnSsnGet(http_ctx->txnp);
+ client_conn = TSHttpSsnClientVConnGet(ssnp);
+
+ if (TSVConnIsSsl(client_conn)) {
+ TSSslConnection ssl_conn = TSVConnSslConnectionGet(client_conn);
+ if (ssl_conn) {
+ SSL *ssl = reinterpret_cast<SSL *>(ssl_conn);
+#ifdef OPENSSL_IS_OPENSSL3
+ X509 *cert = SSL_get1_peer_certificate(ssl);
+#else
+ X509 *cert = SSL_get_peer_certificate(ssl);
+#endif
+ if (cert) {
+ std::string not_before =
get_x509_time_string(X509_get_notBefore(cert));
+ X509_free(cert);
+ if (!not_before.empty()) {
+ lua_pushlstring(L, not_before.c_str(), not_before.length());
+ return 1;
+ }
+ }
+ }
+ }
+
+ lua_pushnil(L);
+ return 1;
+}
+
+static int
+ts_lua_client_request_client_cert_get_not_after(lua_State *L)
+{
+ ts_lua_http_ctx *http_ctx;
+ TSHttpSsn ssnp;
+ TSVConn client_conn;
+
+ GET_HTTP_CONTEXT(http_ctx, L);
+
+ ssnp = TSHttpTxnSsnGet(http_ctx->txnp);
+ client_conn = TSHttpSsnClientVConnGet(ssnp);
+
+ if (TSVConnIsSsl(client_conn)) {
+ TSSslConnection ssl_conn = TSVConnSslConnectionGet(client_conn);
+ if (ssl_conn) {
+ SSL *ssl = reinterpret_cast<SSL *>(ssl_conn);
+#ifdef OPENSSL_IS_OPENSSL3
+ X509 *cert = SSL_get1_peer_certificate(ssl);
+#else
+ X509 *cert = SSL_get_peer_certificate(ssl);
+#endif
+ if (cert) {
+ std::string not_after = get_x509_time_string(X509_get_notAfter(cert));
+ X509_free(cert);
+ if (!not_after.empty()) {
+ lua_pushlstring(L, not_after.c_str(), not_after.length());
+ return 1;
+ }
+ }
+ }
+ }
+
+ lua_pushnil(L);
+ return 1;
+}
+
+static int
+ts_lua_client_request_client_cert_get_version(lua_State *L)
+{
+ ts_lua_http_ctx *http_ctx;
+ TSHttpSsn ssnp;
+ TSVConn client_conn;
+
+ GET_HTTP_CONTEXT(http_ctx, L);
+
+ ssnp = TSHttpTxnSsnGet(http_ctx->txnp);
+ client_conn = TSHttpSsnClientVConnGet(ssnp);
+
+ if (TSVConnIsSsl(client_conn)) {
+ TSSslConnection ssl_conn = TSVConnSslConnectionGet(client_conn);
+ if (ssl_conn) {
+ SSL *ssl = reinterpret_cast<SSL *>(ssl_conn);
+#ifdef OPENSSL_IS_OPENSSL3
+ X509 *cert = SSL_get1_peer_certificate(ssl);
+#else
+ X509 *cert = SSL_get_peer_certificate(ssl);
+#endif
+ if (cert) {
+ long version = X509_get_version(cert);
+ X509_free(cert);
+ lua_pushinteger(L, version);
+ return 1;
+ }
+ }
+ }
+
+ lua_pushnil(L);
+ return 1;
+}
+
+static int
+ts_lua_client_request_client_cert_get_san_dns(lua_State *L)
+{
+ ts_lua_http_ctx *http_ctx;
+ TSHttpSsn ssnp;
+ TSVConn client_conn;
+
+ GET_HTTP_CONTEXT(http_ctx, L);
+
+ ssnp = TSHttpTxnSsnGet(http_ctx->txnp);
+ client_conn = TSHttpSsnClientVConnGet(ssnp);
+
+ if (TSVConnIsSsl(client_conn)) {
+ TSSslConnection ssl_conn = TSVConnSslConnectionGet(client_conn);
+ if (ssl_conn) {
+ SSL *ssl = reinterpret_cast<SSL *>(ssl_conn);
+#ifdef OPENSSL_IS_OPENSSL3
+ X509 *cert = SSL_get1_peer_certificate(ssl);
+#else
+ X509 *cert = SSL_get_peer_certificate(ssl);
+#endif
+ if (cert) {
+ std::vector<std::string> dns_names = get_x509_san_strings(cert,
GEN_DNS);
+ X509_free(cert);
+
+ if (!dns_names.empty()) {
+ lua_newtable(L);
+ for (size_t i = 0; i < dns_names.size(); i++) {
+ lua_pushlstring(L, dns_names[i].c_str(), dns_names[i].length());
+ lua_rawseti(L, -2, i + 1);
+ }
+ return 1;
+ }
+ }
+ }
+ }
+
+ lua_pushnil(L);
+ return 1;
+}
+
+static int
+ts_lua_client_request_client_cert_get_san_ip(lua_State *L)
+{
+ ts_lua_http_ctx *http_ctx;
+ TSHttpSsn ssnp;
+ TSVConn client_conn;
+
+ GET_HTTP_CONTEXT(http_ctx, L);
+
+ ssnp = TSHttpTxnSsnGet(http_ctx->txnp);
+ client_conn = TSHttpSsnClientVConnGet(ssnp);
+
+ if (TSVConnIsSsl(client_conn)) {
+ TSSslConnection ssl_conn = TSVConnSslConnectionGet(client_conn);
+ if (ssl_conn) {
+ SSL *ssl = reinterpret_cast<SSL *>(ssl_conn);
+#ifdef OPENSSL_IS_OPENSSL3
+ X509 *cert = SSL_get1_peer_certificate(ssl);
+#else
+ X509 *cert = SSL_get_peer_certificate(ssl);
+#endif
+ if (cert) {
+ std::vector<std::string> ip_addrs = get_x509_san_strings(cert,
GEN_IPADD);
+ X509_free(cert);
+
+ if (!ip_addrs.empty()) {
+ lua_newtable(L);
+ for (size_t i = 0; i < ip_addrs.size(); i++) {
+ lua_pushlstring(L, ip_addrs[i].c_str(), ip_addrs[i].length());
+ lua_rawseti(L, -2, i + 1);
+ }
+ return 1;
+ }
+ }
+ }
+ }
+
+ lua_pushnil(L);
+ return 1;
+}
+
+static int
+ts_lua_client_request_client_cert_get_san_email(lua_State *L)
+{
+ ts_lua_http_ctx *http_ctx;
+ TSHttpSsn ssnp;
+ TSVConn client_conn;
+
+ GET_HTTP_CONTEXT(http_ctx, L);
+
+ ssnp = TSHttpTxnSsnGet(http_ctx->txnp);
+ client_conn = TSHttpSsnClientVConnGet(ssnp);
+
+ if (TSVConnIsSsl(client_conn)) {
+ TSSslConnection ssl_conn = TSVConnSslConnectionGet(client_conn);
+ if (ssl_conn) {
+ SSL *ssl = reinterpret_cast<SSL *>(ssl_conn);
+#ifdef OPENSSL_IS_OPENSSL3
+ X509 *cert = SSL_get1_peer_certificate(ssl);
+#else
+ X509 *cert = SSL_get_peer_certificate(ssl);
+#endif
+ if (cert) {
+ std::vector<std::string> emails = get_x509_san_strings(cert,
GEN_EMAIL);
+ X509_free(cert);
+
+ if (!emails.empty()) {
+ lua_newtable(L);
+ for (size_t i = 0; i < emails.size(); i++) {
+ lua_pushlstring(L, emails[i].c_str(), emails[i].length());
+ lua_rawseti(L, -2, i + 1);
+ }
+ return 1;
+ }
+ }
+ }
+ }
+
+ lua_pushnil(L);
+ return 1;
+}
+
+static int
+ts_lua_client_request_client_cert_get_san_uri(lua_State *L)
+{
+ ts_lua_http_ctx *http_ctx;
+ TSHttpSsn ssnp;
+ TSVConn client_conn;
+
+ GET_HTTP_CONTEXT(http_ctx, L);
+
+ ssnp = TSHttpTxnSsnGet(http_ctx->txnp);
+ client_conn = TSHttpSsnClientVConnGet(ssnp);
+
+ if (TSVConnIsSsl(client_conn)) {
+ TSSslConnection ssl_conn = TSVConnSslConnectionGet(client_conn);
+ if (ssl_conn) {
+ SSL *ssl = reinterpret_cast<SSL *>(ssl_conn);
+#ifdef OPENSSL_IS_OPENSSL3
+ X509 *cert = SSL_get1_peer_certificate(ssl);
+#else
+ X509 *cert = SSL_get_peer_certificate(ssl);
+#endif
+ if (cert) {
+ std::vector<std::string> uris = get_x509_san_strings(cert, GEN_URI);
+ X509_free(cert);
+
+ if (!uris.empty()) {
+ lua_newtable(L);
+ for (size_t i = 0; i < uris.size(); i++) {
+ lua_pushlstring(L, uris[i].c_str(), uris[i].length());
+ lua_rawseti(L, -2, i + 1);
+ }
+ return 1;
+ }
+ }
+ }
+ }
+
+ lua_pushnil(L);
+ return 1;
+}
+
+// Server Certificate Functions
+static int
+ts_lua_client_request_server_cert_get_pem(lua_State *L)
+{
+ ts_lua_http_ctx *http_ctx;
+ TSHttpSsn ssnp;
+ TSVConn client_conn;
+
+ GET_HTTP_CONTEXT(http_ctx, L);
+
+ ssnp = TSHttpTxnSsnGet(http_ctx->txnp);
+ client_conn = TSHttpSsnClientVConnGet(ssnp);
+
+ if (TSVConnIsSsl(client_conn)) {
+ TSSslConnection ssl_conn = TSVConnSslConnectionGet(client_conn);
+ if (ssl_conn) {
+ SSL *ssl = reinterpret_cast<SSL *>(ssl_conn);
+ X509 *cert = SSL_get_certificate(ssl);
+ if (cert) {
+ std::string pem = get_x509_pem_string(cert);
+ if (!pem.empty()) {
+ lua_pushlstring(L, pem.c_str(), pem.length());
+ return 1;
+ }
+ }
+ }
+ }
+
+ lua_pushnil(L);
+ return 1;
+}
+
+static int
+ts_lua_client_request_server_cert_get_subject(lua_State *L)
+{
+ ts_lua_http_ctx *http_ctx;
+ TSHttpSsn ssnp;
+ TSVConn client_conn;
+
+ GET_HTTP_CONTEXT(http_ctx, L);
+
+ ssnp = TSHttpTxnSsnGet(http_ctx->txnp);
+ client_conn = TSHttpSsnClientVConnGet(ssnp);
+
+ if (TSVConnIsSsl(client_conn)) {
+ TSSslConnection ssl_conn = TSVConnSslConnectionGet(client_conn);
+ if (ssl_conn) {
+ SSL *ssl = reinterpret_cast<SSL *>(ssl_conn);
+ X509 *cert = SSL_get_certificate(ssl);
+ if (cert) {
+ std::string subject =
get_x509_name_string(X509_get_subject_name(cert));
+ if (!subject.empty()) {
+ lua_pushlstring(L, subject.c_str(), subject.length());
+ return 1;
+ }
+ }
+ }
+ }
+
+ lua_pushnil(L);
+ return 1;
+}
+
+static int
+ts_lua_client_request_server_cert_get_issuer(lua_State *L)
+{
+ ts_lua_http_ctx *http_ctx;
+ TSHttpSsn ssnp;
+ TSVConn client_conn;
+
+ GET_HTTP_CONTEXT(http_ctx, L);
+
+ ssnp = TSHttpTxnSsnGet(http_ctx->txnp);
+ client_conn = TSHttpSsnClientVConnGet(ssnp);
+
+ if (TSVConnIsSsl(client_conn)) {
+ TSSslConnection ssl_conn = TSVConnSslConnectionGet(client_conn);
+ if (ssl_conn) {
+ SSL *ssl = reinterpret_cast<SSL *>(ssl_conn);
+ X509 *cert = SSL_get_certificate(ssl);
+ if (cert) {
+ std::string issuer = get_x509_name_string(X509_get_issuer_name(cert));
+ if (!issuer.empty()) {
+ lua_pushlstring(L, issuer.c_str(), issuer.length());
+ return 1;
+ }
+ }
+ }
+ }
+
+ lua_pushnil(L);
+ return 1;
+}
+
+static int
+ts_lua_client_request_server_cert_get_serial(lua_State *L)
+{
+ ts_lua_http_ctx *http_ctx;
+ TSHttpSsn ssnp;
+ TSVConn client_conn;
+
+ GET_HTTP_CONTEXT(http_ctx, L);
+
+ ssnp = TSHttpTxnSsnGet(http_ctx->txnp);
+ client_conn = TSHttpSsnClientVConnGet(ssnp);
+
+ if (TSVConnIsSsl(client_conn)) {
+ TSSslConnection ssl_conn = TSVConnSslConnectionGet(client_conn);
+ if (ssl_conn) {
+ SSL *ssl = reinterpret_cast<SSL *>(ssl_conn);
+ X509 *cert = SSL_get_certificate(ssl);
+ if (cert) {
+ std::string serial = get_x509_serial_string(cert);
+ if (!serial.empty()) {
+ lua_pushlstring(L, serial.c_str(), serial.length());
+ return 1;
+ }
+ }
+ }
+ }
+
+ lua_pushnil(L);
+ return 1;
+}
+
+static int
+ts_lua_client_request_server_cert_get_signature(lua_State *L)
+{
+ ts_lua_http_ctx *http_ctx;
+ TSHttpSsn ssnp;
+ TSVConn client_conn;
+
+ GET_HTTP_CONTEXT(http_ctx, L);
+
+ ssnp = TSHttpTxnSsnGet(http_ctx->txnp);
+ client_conn = TSHttpSsnClientVConnGet(ssnp);
+
+ if (TSVConnIsSsl(client_conn)) {
+ TSSslConnection ssl_conn = TSVConnSslConnectionGet(client_conn);
+ if (ssl_conn) {
+ SSL *ssl = reinterpret_cast<SSL *>(ssl_conn);
+ X509 *cert = SSL_get_certificate(ssl);
+ if (cert) {
+ std::string sig = get_x509_signature_string(cert);
+ if (!sig.empty()) {
+ lua_pushlstring(L, sig.c_str(), sig.length());
+ return 1;
+ }
+ }
+ }
+ }
+
+ lua_pushnil(L);
+ return 1;
+}
+
+static int
+ts_lua_client_request_server_cert_get_not_before(lua_State *L)
+{
+ ts_lua_http_ctx *http_ctx;
+ TSHttpSsn ssnp;
+ TSVConn client_conn;
+
+ GET_HTTP_CONTEXT(http_ctx, L);
+
+ ssnp = TSHttpTxnSsnGet(http_ctx->txnp);
+ client_conn = TSHttpSsnClientVConnGet(ssnp);
+
+ if (TSVConnIsSsl(client_conn)) {
+ TSSslConnection ssl_conn = TSVConnSslConnectionGet(client_conn);
+ if (ssl_conn) {
+ SSL *ssl = reinterpret_cast<SSL *>(ssl_conn);
+ X509 *cert = SSL_get_certificate(ssl);
+ if (cert) {
+ std::string not_before =
get_x509_time_string(X509_get_notBefore(cert));
+ if (!not_before.empty()) {
+ lua_pushlstring(L, not_before.c_str(), not_before.length());
+ return 1;
+ }
+ }
+ }
+ }
+
+ lua_pushnil(L);
+ return 1;
+}
+
+static int
+ts_lua_client_request_server_cert_get_not_after(lua_State *L)
+{
+ ts_lua_http_ctx *http_ctx;
+ TSHttpSsn ssnp;
+ TSVConn client_conn;
+
+ GET_HTTP_CONTEXT(http_ctx, L);
+
+ ssnp = TSHttpTxnSsnGet(http_ctx->txnp);
+ client_conn = TSHttpSsnClientVConnGet(ssnp);
+
+ if (TSVConnIsSsl(client_conn)) {
+ TSSslConnection ssl_conn = TSVConnSslConnectionGet(client_conn);
+ if (ssl_conn) {
+ SSL *ssl = reinterpret_cast<SSL *>(ssl_conn);
+ X509 *cert = SSL_get_certificate(ssl);
+ if (cert) {
+ std::string not_after = get_x509_time_string(X509_get_notAfter(cert));
+ if (!not_after.empty()) {
+ lua_pushlstring(L, not_after.c_str(), not_after.length());
+ return 1;
+ }
+ }
+ }
+ }
+
+ lua_pushnil(L);
+ return 1;
+}
+
+static int
+ts_lua_client_request_server_cert_get_version(lua_State *L)
+{
+ ts_lua_http_ctx *http_ctx;
+ TSHttpSsn ssnp;
+ TSVConn client_conn;
+
+ GET_HTTP_CONTEXT(http_ctx, L);
+
+ ssnp = TSHttpTxnSsnGet(http_ctx->txnp);
+ client_conn = TSHttpSsnClientVConnGet(ssnp);
+
+ if (TSVConnIsSsl(client_conn)) {
+ TSSslConnection ssl_conn = TSVConnSslConnectionGet(client_conn);
+ if (ssl_conn) {
+ SSL *ssl = reinterpret_cast<SSL *>(ssl_conn);
+ X509 *cert = SSL_get_certificate(ssl);
+ if (cert) {
+ long version = X509_get_version(cert);
+ lua_pushinteger(L, version);
+ return 1;
+ }
+ }
+ }
+
+ lua_pushnil(L);
+ return 1;
+}
+
+static int
+ts_lua_client_request_server_cert_get_san_dns(lua_State *L)
+{
+ ts_lua_http_ctx *http_ctx;
+ TSHttpSsn ssnp;
+ TSVConn client_conn;
+
+ GET_HTTP_CONTEXT(http_ctx, L);
+
+ ssnp = TSHttpTxnSsnGet(http_ctx->txnp);
+ client_conn = TSHttpSsnClientVConnGet(ssnp);
+
+ if (TSVConnIsSsl(client_conn)) {
+ TSSslConnection ssl_conn = TSVConnSslConnectionGet(client_conn);
+ if (ssl_conn) {
+ SSL *ssl = reinterpret_cast<SSL *>(ssl_conn);
+ X509 *cert = SSL_get_certificate(ssl);
+ if (cert) {
+ std::vector<std::string> dns_names = get_x509_san_strings(cert,
GEN_DNS);
+
+ if (!dns_names.empty()) {
+ lua_newtable(L);
+ for (size_t i = 0; i < dns_names.size(); i++) {
+ lua_pushlstring(L, dns_names[i].c_str(), dns_names[i].length());
+ lua_rawseti(L, -2, i + 1);
+ }
+ return 1;
+ }
+ }
+ }
+ }
+
+ lua_pushnil(L);
+ return 1;
+}
+
+static int
+ts_lua_client_request_server_cert_get_san_ip(lua_State *L)
+{
+ ts_lua_http_ctx *http_ctx;
+ TSHttpSsn ssnp;
+ TSVConn client_conn;
+
+ GET_HTTP_CONTEXT(http_ctx, L);
+
+ ssnp = TSHttpTxnSsnGet(http_ctx->txnp);
+ client_conn = TSHttpSsnClientVConnGet(ssnp);
+
+ if (TSVConnIsSsl(client_conn)) {
+ TSSslConnection ssl_conn = TSVConnSslConnectionGet(client_conn);
+ if (ssl_conn) {
+ SSL *ssl = reinterpret_cast<SSL *>(ssl_conn);
+ X509 *cert = SSL_get_certificate(ssl);
+ if (cert) {
+ std::vector<std::string> ip_addrs = get_x509_san_strings(cert,
GEN_IPADD);
+
+ if (!ip_addrs.empty()) {
+ lua_newtable(L);
+ for (size_t i = 0; i < ip_addrs.size(); i++) {
+ lua_pushlstring(L, ip_addrs[i].c_str(), ip_addrs[i].length());
+ lua_rawseti(L, -2, i + 1);
+ }
+ return 1;
+ }
+ }
+ }
+ }
+
+ lua_pushnil(L);
+ return 1;
+}
+
+static int
+ts_lua_client_request_server_cert_get_san_email(lua_State *L)
+{
+ ts_lua_http_ctx *http_ctx;
+ TSHttpSsn ssnp;
+ TSVConn client_conn;
+
+ GET_HTTP_CONTEXT(http_ctx, L);
+
+ ssnp = TSHttpTxnSsnGet(http_ctx->txnp);
+ client_conn = TSHttpSsnClientVConnGet(ssnp);
+
+ if (TSVConnIsSsl(client_conn)) {
+ TSSslConnection ssl_conn = TSVConnSslConnectionGet(client_conn);
+ if (ssl_conn) {
+ SSL *ssl = reinterpret_cast<SSL *>(ssl_conn);
+ X509 *cert = SSL_get_certificate(ssl);
+ if (cert) {
+ std::vector<std::string> emails = get_x509_san_strings(cert,
GEN_EMAIL);
+
+ if (!emails.empty()) {
+ lua_newtable(L);
+ for (size_t i = 0; i < emails.size(); i++) {
+ lua_pushlstring(L, emails[i].c_str(), emails[i].length());
+ lua_rawseti(L, -2, i + 1);
+ }
+ return 1;
+ }
+ }
+ }
+ }
+
+ lua_pushnil(L);
+ return 1;
+}
+
+static int
+ts_lua_client_request_server_cert_get_san_uri(lua_State *L)
+{
+ ts_lua_http_ctx *http_ctx;
+ TSHttpSsn ssnp;
+ TSVConn client_conn;
+
+ GET_HTTP_CONTEXT(http_ctx, L);
+
+ ssnp = TSHttpTxnSsnGet(http_ctx->txnp);
+ client_conn = TSHttpSsnClientVConnGet(ssnp);
+
+ if (TSVConnIsSsl(client_conn)) {
+ TSSslConnection ssl_conn = TSVConnSslConnectionGet(client_conn);
+ if (ssl_conn) {
+ SSL *ssl = reinterpret_cast<SSL *>(ssl_conn);
+ X509 *cert = SSL_get_certificate(ssl);
+ if (cert) {
+ std::vector<std::string> uris = get_x509_san_strings(cert, GEN_URI);
+
+ if (!uris.empty()) {
+ lua_newtable(L);
+ for (size_t i = 0; i < uris.size(); i++) {
+ lua_pushlstring(L, uris[i].c_str(), uris[i].length());
+ lua_rawseti(L, -2, i + 1);
+ }
+ return 1;
+ }
+ }
+ }
+ }
+
+ lua_pushnil(L);
+ return 1;
+}
Review Comment:
The client and server certificate functions contain significant code
duplication. Each pair of functions (e.g., `client_cert_get_pem` and
`server_cert_get_pem`) follows nearly identical logic with only a difference in
how the certificate is retrieved
(`SSL_get1_peer_certificate`/`SSL_get_peer_certificate` vs
`SSL_get_certificate`).
Consider refactoring to reduce duplication by:
1. Creating a helper function that accepts the certificate retrieval logic
as a parameter
2. Or creating a common implementation that takes a certificate pointer
directly
This would improve maintainability and reduce the risk of inconsistencies
when making future changes.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]