-
Notifications
You must be signed in to change notification settings - Fork 21
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(communicator): separate certificate verification logic for linux…
… agent and windows agent
- Loading branch information
Showing
5 changed files
with
202 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
17 changes: 17 additions & 0 deletions
17
src/agent/communicator/include/https_socket_verify_utils.hpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
#include <boost/asio/ssl.hpp> | ||
|
||
#include <string> | ||
|
||
namespace https_socket_verify_utils | ||
{ | ||
/// @brief Verifies the certificate of the HTTPS connection | ||
/// @param preverified The result of the pre-verification | ||
/// @param ctx The verification context | ||
/// @param mode The verification mode to use | ||
/// @param host The hostname to verify against | ||
/// @return True if the certificate is valid, false otherwise | ||
bool VerifyCertificate(bool preverified, | ||
boost::asio::ssl::verify_context& ctx, | ||
const std::string& mode, | ||
const std::string& host); | ||
} // namespace https_socket_verify_utils |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
24 changes: 24 additions & 0 deletions
24
src/agent/communicator/src/https_socket_verify_utils_lin.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
#include <boost/asio/ssl.hpp> | ||
#include <https_socket_verify_utils.hpp> | ||
|
||
#include <string> | ||
|
||
namespace https_socket_verify_utils | ||
{ | ||
bool VerifyCertificate(bool preverified, | ||
boost::asio::ssl::verify_context& ctx, | ||
const std::string& mode, | ||
const std::string& host) | ||
{ | ||
if (mode == "certificate") | ||
{ | ||
return preverified; | ||
} | ||
else if (mode == "full") | ||
{ | ||
boost::asio::ssl::rfc2818_verification verifier(host); | ||
return verifier(preverified, ctx); | ||
} | ||
return false; | ||
} | ||
} // namespace https_socket_verify_utils |
135 changes: 135 additions & 0 deletions
135
src/agent/communicator/src/https_socket_verify_utils_win.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,135 @@ | ||
#include <https_socket_verify_utils.hpp> | ||
#include <logger.hpp> | ||
|
||
#include <boost/asio/ssl.hpp> | ||
#include <wincrypt.h> | ||
#include <windows.h> | ||
|
||
namespace https_socket_verify_utils | ||
{ | ||
bool VerifyCertificate([[maybe_unused]] bool preverified, | ||
boost::asio::ssl::verify_context& ctx, | ||
const std::string& mode, | ||
const std::string& host) | ||
{ | ||
X509* cert = X509_STORE_CTX_get_current_cert(ctx.native_handle()); | ||
if (!cert) | ||
{ | ||
LogError("The server certificate could not be obtained."); | ||
return false; | ||
} | ||
|
||
// Convert certificate to DER format | ||
unsigned char* der = nullptr; | ||
int derLen = i2d_X509(cert, &der); | ||
if (derLen <= 0) | ||
{ | ||
LogError("Certificate conversion to DER failed."); | ||
return false; | ||
} | ||
|
||
// Create the certificate context | ||
PCCERT_CONTEXT certCtx = CertCreateCertificateContext(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, der, derLen); | ||
OPENSSL_free(der); | ||
|
||
if (!certCtx) | ||
{ | ||
LogError("The certificate context could not be created."); | ||
return false; | ||
} | ||
|
||
// Open the Windows certificate store | ||
HCERTSTORE hStore = CertOpenSystemStoreA(NULL, "ROOT"); | ||
if (!hStore) | ||
{ | ||
LogError("The Windows certificate store could not be opened."); | ||
CertFreeCertificateContext(certCtx); | ||
return false; | ||
} | ||
|
||
// Create the certificate chain context | ||
CERT_CHAIN_PARA chainPara = {sizeof(CERT_CHAIN_PARA)}; | ||
PCCERT_CHAIN_CONTEXT chainCtx = nullptr; | ||
|
||
bool result = CertGetCertificateChain(NULL, certCtx, NULL, hStore, &chainPara, 0, NULL, &chainCtx); | ||
|
||
if (!result || !chainCtx) | ||
{ | ||
LogError("The certificate chain could not be verified."); | ||
} | ||
|
||
// Validate the SSL policy of the chain | ||
CERT_CHAIN_POLICY_PARA policyPara = {sizeof(CERT_CHAIN_POLICY_PARA)}; | ||
CERT_CHAIN_POLICY_STATUS policyStatus = {sizeof(CERT_CHAIN_POLICY_STATUS)}; | ||
policyPara.dwFlags = 0; | ||
|
||
if (!CertVerifyCertificateChainPolicy(CERT_CHAIN_POLICY_BASE, chainCtx, &policyPara, &policyStatus)) | ||
{ | ||
LogError("Error verifying certificate chain policy."); | ||
result = false; | ||
} | ||
else if (policyStatus.dwError != 0) | ||
{ | ||
LogError("Certification policy error: {}", policyStatus.dwError); | ||
result = false; | ||
} | ||
|
||
if (result && mode == "full") | ||
{ | ||
// Obtain SAN from the certificate | ||
STACK_OF(GENERAL_NAME)* sanNames = | ||
static_cast<STACK_OF(GENERAL_NAME)*>(X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL)); | ||
bool hostValidated = false; | ||
|
||
if (sanNames) | ||
{ | ||
int sanCount = sk_GENERAL_NAME_num(sanNames); | ||
for (int i = 0; i < sanCount; ++i) | ||
{ | ||
const GENERAL_NAME* san = sk_GENERAL_NAME_value(sanNames, i); | ||
if (san->type == GEN_DNS) | ||
{ | ||
const char* dnsName = reinterpret_cast<const char*>(ASN1_STRING_get0_data(san->d.dNSName)); | ||
if (host == dnsName) | ||
{ | ||
hostValidated = true; | ||
break; | ||
} | ||
} | ||
} | ||
GENERAL_NAMES_free(sanNames); | ||
} | ||
|
||
// If no SAN was found, check the CN | ||
if (!hostValidated) | ||
{ | ||
X509_NAME* subjectName = X509_get_subject_name(cert); | ||
char cn[256] = {0}; | ||
if (X509_NAME_get_text_by_NID(subjectName, NID_commonName, cn, sizeof(cn)) > 0) | ||
{ | ||
if (host == cn) | ||
{ | ||
hostValidated = true; | ||
} | ||
} | ||
} | ||
|
||
if (!hostValidated) | ||
{ | ||
LogError("The host name does not match the SAN or the CN."); | ||
result = false; | ||
} | ||
} | ||
|
||
// Free resources | ||
if (chainCtx) | ||
{ | ||
CertFreeCertificateChain(chainCtx); | ||
} | ||
CertCloseStore(hStore, 0); | ||
CertFreeCertificateContext(certCtx); | ||
|
||
return result; | ||
} | ||
|
||
} // namespace https_socket_verify_utils |