mirror of
https://github.com/yhirose/cpp-httplib.git
synced 2026-10-19 11:19:36 +00:00
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:
1 parent
9bfd2ddf1c
commit
30879bb48b
2 files changed
+87
-12
No files matched your search
+63
-6
@@ -16194,11 +16194,14 @@ TEST(SSLClientServerTest, SSLErrorNotCarriedToLaterRequest) {
|
||||
EXPECT_EQ(0UL, res.ssl_backend_error());
|
||||
}
|
||||
|
||||
// PEM memory-based constructor tests (works with all TLS backends)
|
||||
// PEM memory-based constructor tests (works with all TLS backends).
|
||||
// exact_size passes each PEM in a buffer of its own size, with no NUL
|
||||
// terminator after it.
|
||||
void PemMemoryClientCertPresent(
|
||||
const std::string &client_cert_file,
|
||||
const std::string &client_private_key_file,
|
||||
const std::string &client_encrypted_private_key_pass = std::string()) {
|
||||
const std::string &client_encrypted_private_key_pass = std::string(),
|
||||
bool exact_size = false) {
|
||||
// Read PEM files into memory
|
||||
std::string server_cert_pem, server_key_pem;
|
||||
std::string client_ca_pem;
|
||||
@@ -16210,13 +16213,20 @@ void PemMemoryClientCertPresent(
|
||||
read_file(client_cert_file, client_cert_pem);
|
||||
read_file(client_private_key_file, client_key_pem);
|
||||
|
||||
std::list<std::vector<char>> exact_copies;
|
||||
auto data = [&](const std::string &pem) -> const char * {
|
||||
if (!exact_size) { return pem.c_str(); }
|
||||
exact_copies.emplace_back(pem.begin(), pem.end());
|
||||
return exact_copies.back().data();
|
||||
};
|
||||
|
||||
// Create server with PEM memory
|
||||
SSLServer::PemMemory server_pem = {
|
||||
server_cert_pem.c_str(),
|
||||
data(server_cert_pem),
|
||||
server_cert_pem.size(),
|
||||
server_key_pem.c_str(),
|
||||
data(server_key_pem),
|
||||
server_key_pem.size(),
|
||||
client_ca_pem.c_str(),
|
||||
data(client_ca_pem),
|
||||
client_ca_pem.size(),
|
||||
nullptr // no password for server key
|
||||
};
|
||||
@@ -16245,7 +16255,7 @@ void PemMemoryClientCertPresent(
|
||||
? nullptr
|
||||
: client_encrypted_private_key_pass.c_str();
|
||||
SSLClient::PemMemory client_pem = {
|
||||
client_cert_pem.c_str(), client_cert_pem.size(), client_key_pem.c_str(),
|
||||
data(client_cert_pem), client_cert_pem.size(), data(client_key_pem),
|
||||
client_key_pem.size(), password};
|
||||
SSLClient cli(HOST, PORT, client_pem);
|
||||
cli.enable_server_certificate_verification(false);
|
||||
@@ -16287,6 +16297,36 @@ TEST(SSLClientServerTest, PemMemoryClientCertMissing) {
|
||||
RejectsClientWithoutCert(svr);
|
||||
}
|
||||
|
||||
// The PemMemory lengths are honoured, so the PEM needs no NUL terminator
|
||||
TEST(SSLClientServerTest, PemMemoryExactSizeBuffers) {
|
||||
PemMemoryClientCertPresent(CLIENT_CERT_FILE, CLIENT_PRIVATE_KEY_FILE, "",
|
||||
true);
|
||||
}
|
||||
|
||||
// A length shorter than the PEM cuts it short, so it no longer loads
|
||||
TEST(SSLClientServerTest, PemMemoryShortLengthCutsThePem) {
|
||||
std::string cert, key;
|
||||
read_file(SERVER_CERT_FILE, cert);
|
||||
read_file(SERVER_PRIVATE_KEY_FILE, key);
|
||||
|
||||
for (auto cut_cert : {true, false}) {
|
||||
auto cert_len = cut_cert ? cert.size() / 2 : cert.size();
|
||||
auto key_len = cut_cert ? key.size() : key.size() / 2;
|
||||
|
||||
SSLServer::PemMemory server_pem = {
|
||||
cert.c_str(), cert_len, key.c_str(), key_len, nullptr, 0, nullptr};
|
||||
EXPECT_FALSE(SSLServer(server_pem).is_valid());
|
||||
|
||||
SSLClient::PemMemory client_pem = {cert.c_str(), cert_len, key.c_str(),
|
||||
key_len, nullptr};
|
||||
EXPECT_FALSE(SSLClient(HOST, PORT, client_pem).is_valid());
|
||||
|
||||
ws::WebSocketClient::PemMemory ws_pem = {cert.c_str(), cert_len,
|
||||
key.c_str(), key_len, nullptr};
|
||||
EXPECT_FALSE(ws::WebSocketClient("wss://localhost/", ws_pem).is_valid());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(SSLClientServerTest, SSLConnectTimeout) {
|
||||
class NoListenSSLServer : public SSLServer {
|
||||
public:
|
||||
@@ -28483,6 +28523,10 @@ protected:
|
||||
ws::WebSocketClient::PemMemory pem = {cert_pem.c_str(), cert_pem.size(),
|
||||
key_pem.c_str(), key_pem.size(),
|
||||
private_key_password};
|
||||
ConnectWithPem(pem);
|
||||
}
|
||||
|
||||
void ConnectWithPem(const ws::WebSocketClient::PemMemory &pem) {
|
||||
ws::WebSocketClient client(url(), pem);
|
||||
ASSERT_TRUE(client.is_valid());
|
||||
client.enable_server_certificate_verification(false);
|
||||
@@ -28520,6 +28564,19 @@ TEST_F(WebSocketSSLPemMemoryTest, EncryptedClientCertAccepted) {
|
||||
CLIENT_ENCRYPTED_PRIVATE_KEY_FILE,
|
||||
CLIENT_ENCRYPTED_PRIVATE_KEY_PASS);
|
||||
}
|
||||
|
||||
// The PemMemory lengths are honoured, so the PEM needs no NUL terminator
|
||||
TEST_F(WebSocketSSLPemMemoryTest, ExactSizeBuffersAccepted) {
|
||||
std::string cert_pem, key_pem;
|
||||
read_file(CLIENT_CERT_FILE, cert_pem);
|
||||
read_file(CLIENT_PRIVATE_KEY_FILE, key_pem);
|
||||
std::vector<char> cert(cert_pem.begin(), cert_pem.end());
|
||||
std::vector<char> key(key_pem.begin(), key_pem.end());
|
||||
|
||||
ws::WebSocketClient::PemMemory pem = {cert.data(), cert.size(), key.data(),
|
||||
key.size(), nullptr};
|
||||
ConnectWithPem(pem);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !defined(_WIN32)
|
||||
|
||||
Reference in new issue
Block a user