Honor the PEM lengths in PemMemory

SSLServer, SSLClient and WebSocketClient take a PemMemory with
cert_pem_len and key_pem_len, but the lengths were never read: every
backend read the PEM up to a NUL, so a buffer holding exactly the PEM,
such as a std::vector<char> read from a file, was read past its end.
Hand on a NUL-terminated copy of the given number of bytes instead.

A length of 0 still means a NUL-terminated string, which is what
callers got before. The client CA already honored its length.
This commit is contained in:
yhirose committed 2026-10-18 12:41:23 -04:00
1 parent 9bfd2ddf1c
commit 30879bb48b
2 files changed
+87 -12

No files matched your search

+24 -6
View File
@@ -11241,6 +11241,14 @@ inline std::string ca_certs_to_pem(tls::ctx_t ctx) {
return pem;
}
// Returns a PemMemory field as a NUL-terminated string: its first len bytes,
// copied to buf, or pem itself when len is 0.
inline const char *pem_c_str(const char *pem, size_t len, std::string &buf) {
if (!pem || len == 0) { return pem; }
buf.assign(pem, len);
return buf.c_str();
}
// The parts of session setup that only SSLClient needs, plus the handful
// WebSocketClient also exposes; everything else takes the defaults, which is
// what keeps the two clients on one implementation.
@@ -18746,8 +18754,11 @@ inline SSLServer::SSLServer(const PemMemory &pem) {
using namespace tls;
ctx_ = create_server_context();
if (ctx_) {
if (!set_server_cert_pem(ctx_, pem.cert_pem, pem.key_pem,
pem.private_key_password)) {
std::string cert_buf, key_buf;
if (!set_server_cert_pem(
ctx_, detail::pem_c_str(pem.cert_pem, pem.cert_pem_len, cert_buf),
detail::pem_c_str(pem.key_pem, pem.key_pem_len, key_buf),
pem.private_key_password)) {
last_ssl_error_ = static_cast<int>(get_error());
free_context(ctx_);
ctx_ = nullptr;
@@ -19132,8 +19143,11 @@ inline SSLClient::SSLClient(const std::string &host, int port,
if (!ctx_) { return; }
if (pem.cert_pem && pem.key_pem) {
if (!tls::set_client_cert_pem(ctx_, pem.cert_pem, pem.key_pem,
pem.private_key_password)) {
std::string cert_buf, key_buf;
if (!tls::set_client_cert_pem(
ctx_, detail::pem_c_str(pem.cert_pem, pem.cert_pem_len, cert_buf),
detail::pem_c_str(pem.key_pem, pem.key_pem_len, key_buf),
pem.private_key_password)) {
reset_ctx_on_error();
}
}
@@ -23517,8 +23531,12 @@ inline WebSocketClient::WebSocketClient(
// For ws:// URLs the client certificate is silently ignored, consistent
// with the TLS-only setters such as set_ca_cert_path().
if (is_valid_ && is_ssl_ && pem.cert_pem && pem.key_pem) {
if (!tls::set_client_cert_pem(tls_ctx_, pem.cert_pem, pem.key_pem,
pem.private_key_password)) {
std::string cert_buf, key_buf;
if (!tls::set_client_cert_pem(
tls_ctx_,
detail::pem_c_str(pem.cert_pem, pem.cert_pem_len, cert_buf),
detail::pem_c_str(pem.key_pem, pem.key_pem_len, key_buf),
pem.private_key_password)) {
tls::free_context(tls_ctx_);
tls_ctx_ = nullptr;
is_valid_ = false;