json::value get_cert_chain_information(boost::asio::ssl::verify_context &verifyCtx) { X509_STORE_CTX *storeContext = verifyCtx.native_handle(); STACK_OF(X509) *certStack = X509_STORE_CTX_get_chain(storeContext); const int numCerts = sk_X509_num(certStack); if (numCerts < 0) { return {}; } json::value certChainInformation; for (int index = 0; index < numCerts; ++index) { X509 *cert = sk_X509_value(certStack, index); json::value certInformation; certInformation[U("Issuer")] = json::value::string(get_issuer_from_cert(cert)); certInformation[U("Subject")] = json::value::string(get_subject_from_cert(cert)); certInformation[U("FingerPrint")] = json::value::string(get_fingerprint_from_cert(cert)); utility::stringstream_t countInfo; countInfo << "Certificate: " << index; certChainInformation[countInfo.str()] = certInformation; } return certChainInformation; }
bool ssl_options_t::has_fingerprint(boost::asio::ssl::verify_context &ctx) const { // can we check the certificate against a list of fingerprints? if (!fingerprints_.empty()) { X509_STORE_CTX *sctx = ctx.native_handle(); if (!sctx) { MERROR("Error getting verify_context handle"); return false; } X509* cert = nullptr; const STACK_OF(X509)* chain = X509_STORE_CTX_get_chain(sctx); if (!chain || sk_X509_num(chain) < 1 || !(cert = sk_X509_value(chain, 0))) { MERROR("No certificate found in verify_context"); return false; } // buffer for the certificate digest and the size of the result std::vector<uint8_t> digest(EVP_MAX_MD_SIZE); unsigned int size{ 0 }; // create the digest from the certificate if (!X509_digest(cert, EVP_sha256(), digest.data(), &size)) { MERROR("Failed to create certificate fingerprint"); return false; } // strip unnecessary bytes from the digest digest.resize(size); return std::binary_search(fingerprints_.begin(), fingerprints_.end(), digest); }
bool verify_cert_chain_platform_specific(boost::asio::ssl::verify_context& verifyCtx, const std::string& hostName) { X509_STORE_CTX* storeContext = verifyCtx.native_handle(); int currentDepth = X509_STORE_CTX_get_error_depth(storeContext); if (currentDepth != 0) { return true; } #if (OPENSSL_VERSION_NUMBER < 0x10100000L) STACK_OF(X509)* certStack = X509_STORE_CTX_get_chain(storeContext); #else STACK_OF(X509)* certStack = X509_STORE_CTX_get0_chain(storeContext); #endif const int numCerts = sk_X509_num(certStack); if (numCerts < 0) { return false; } std::vector<std::string> certChain; certChain.reserve(numCerts); for (int i = 0; i < numCerts; ++i) { X509* cert = sk_X509_value(certStack, i); // Encode into DER format into raw memory. int len = i2d_X509(cert, nullptr); if (len < 0) { return false; } std::string certData; certData.resize(len); unsigned char* buffer = reinterpret_cast<unsigned char*>(&certData[0]); len = i2d_X509(cert, &buffer); if (len < 0) { return false; } certChain.push_back(std::move(certData)); } auto verify_result = verify_X509_cert_chain(certChain, hostName); // The Windows Crypto APIs don't do host name checks, use Boost's implementation. #if defined(_WIN32) if (verify_result) { boost::asio::ssl::rfc2818_verification rfc2818(hostName); verify_result = rfc2818(verify_result, verifyCtx); } #endif return verify_result; }
static bool verify_certificate(bool preverified, boost::asio::ssl::verify_context& ctx, log::logger_t& lg) { // In this example we will simply print the certificate's subject name. char subject_name[256]; X509* cert = X509_STORE_CTX_get_current_cert(ctx.native_handle()); X509_NAME_oneline(X509_get_subject_name(cert), subject_name, 256); //GCE_INFO(lg) << "Verifying " << subject_name; return preverified; }
bool SSLClient::verifyCertificateBySubject(bool blPreverified, boost::asio::ssl::verify_context& vctx) { // In this example we will simply print the certificate's subject name. char acSubjectName[256]; X509* pX509Certificate = X509_STORE_CTX_get_current_cert( vctx.native_handle() ); X509_NAME_oneline( X509_get_subject_name(pX509Certificate), acSubjectName, 256 ); std::cout << "Verifying " << acSubjectName << "\n"; return blPreverified; // All is OK if the current certificate was verified OK. }
bool nano::rpc_secure::on_verify_certificate (bool preverified, boost::asio::ssl::verify_context & ctx) { X509_STORE_CTX * cts = ctx.native_handle (); auto error (X509_STORE_CTX_get_error (cts)); switch (error) { case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT: logger.always_log ("TLS: Unable to get issuer"); break; case X509_V_ERR_CERT_NOT_YET_VALID: case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD: logger.always_log ("TLS: Certificate not yet valid"); break; case X509_V_ERR_CERT_HAS_EXPIRED: case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD: logger.always_log ("TLS: Certificate expired"); break; case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN: if (config.secure.verbose_logging) { logger.always_log ("TLS: self signed certificate in chain"); } // Allow self-signed certificates preverified = true; break; case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT: logger.always_log ("TLS: Self signed certificate not in the list of trusted certs (forgot to subject-hash certificate filename?)"); break; default: break; } if (config.secure.verbose_logging) { if (error != 0) { logger.always_log ("TLS: Error: ", X509_verify_cert_error_string (error)); logger.always_log ("TLS: Error chain depth : ", X509_STORE_CTX_get_error_depth (cts)); } X509 * cert = X509_STORE_CTX_get_current_cert (cts); char subject_name[512]; X509_NAME_oneline (X509_get_subject_name (cert), subject_name, sizeof (subject_name) - 1); logger.always_log ("TLS: Verifying: ", subject_name); logger.always_log ("TLS: Verification: ", preverified); } else if (!preverified) { logger.always_log ("TLS: Pre-verification failed. Turn on verbose logging for more information."); } return preverified; }
// Custom verifier to search for a CN name and set member variable if found. bool verify_certificate(bool preverified, boost::asio::ssl::verify_context& ctx) { char subject_name[256]; X509* cert = X509_STORE_CTX_get_current_cert(ctx.native_handle()); X509_NAME_oneline(X509_get_subject_name(cert), subject_name, 256); std::string s(subject_name); std::string pattern = "/CN=" + cert_hostname_; bool b = s.find(pattern) != std::string::npos; if (b) { found_cert_ = true; } return true; }
bool TcpSslConnection::VerifyCertificate(bool preverified, boost::asio::ssl::verify_context& ctx) { std::cout << "Verifying certificate, pre-verified: " << std::string(preverified ? "true" : "false"); // FIX ME - verify. char subject_name[256]; X509* cert = X509_STORE_CTX_get_current_cert(ctx.native_handle()); X509_NAME_oneline(X509_get_subject_name(cert), subject_name, 256); std::cout << "Verifying, subject: " << subject_name << "\n"; char issuer_name[256]; X509_NAME_oneline(X509_get_issuer_name(cert), issuer_name, 256); std::cout << "Verifying, issuer: " << issuer_name << "\n"; return preverified; }
bool verify_certificate(bool preverified, boost::asio::ssl::verify_context& ctx) { // The verify callback can be used to check whether the certificate that is // being presented is valid for the peer. For example, RFC 2818 describes // the steps involved in doing this for HTTPS. Consult the OpenSSL // documentation for more details. Note that the callback is called once // for each certificate in the certificate chain, starting from the root // certificate authority. // In this example we will simply print the certificate's subject name. char subject_name[256]; X509* cert = X509_STORE_CTX_get_current_cert(ctx.native_handle()); X509_NAME_oneline(X509_get_subject_name(cert), subject_name, 256); std::cout << "Verifying certificate: " << subject_name << "\n"; return preverified; }
bool verify_certificate(bool preverified, boost::asio::ssl::verify_context& ctx) { // The verify callback can be used to check whether the certificate that is // being presented is valid for the peer. For example, RFC 2818 describes // the steps involved in doing this for HTTPS. Consult the OpenSSL // documentation for more details. Note that the callback is called once // for each certificate in the certificate chain, starting from the root // certificate authority. // In this example we will simply print the certificate's subject name. #ifdef _DEBUG char subject_name[256]; std::stringstream ss; std::string str; X509* cert = X509_STORE_CTX_get_current_cert(ctx.native_handle()); X509_NAME_oneline(X509_get_subject_name(cert), subject_name, 256); //std::cout << "Verifying " << subject_name << "\n"; ss << "name: " << subject_name << "\nversion: " << X509_get_version(cert); str = ss.str(); std::copy(str.begin(), str.end(), std::back_inserter(extern_info)); //X509_NAME_oneline(X509_get_issuer_name(cert), subject_name, 256); //std::cout << "issuer_name " << subject_name << "\n"; //auto p = X509_get1_email(cert); //auto n = X509_get_serialNumber(cert); //auto v = X509_get_version(cert); //auto k = X509_get_pubkey(cert); #endif //return preverified; return true; }
std::vector<std::string> get_cert_chain_public_keys(boost::asio::ssl::verify_context &verifyCtx) { std::vector<std::string> certChain; X509_STORE_CTX *storeContext = verifyCtx.native_handle(); STACK_OF(X509) *certStack = X509_STORE_CTX_get_chain(storeContext); const int numCerts = sk_X509_num(certStack); if (numCerts < 0) { return certChain; } certChain.reserve(numCerts); for (int i = 0; i < numCerts; ++i) { X509 *cert = sk_X509_value(certStack, i); certChain.push_back(get_public_key_from_cert(cert)); } return certChain; }
bool CertificateVerifier::operator() (bool preverified, boost::asio::ssl::verify_context& ctx) const { // We're only interested in checking the certificate at the end of the chain. int depth = X509_STORE_CTX_get_error_depth(ctx.native_handle()); if (depth > 0) return OverrideResult_(true); // Read the cert and convert it to a raw DER-format which we can hand off to Windows. X509* cert = X509_STORE_CTX_get_current_cert(ctx.native_handle()); BIO* bio = BIO_new(BIO_s_mem()); // Convert the certificate from the internal structure to a DER structure in memory ('bio'). if (i2d_X509_bio(bio,cert) != 1) { ErrorManager::Instance()->ReportError(ErrorManager::Medium, 5512, "CertificateVerifier::operator()", "Failed to convert OpenSSL internal X509 to DER-format."); BIO_free(bio); return OverrideResult_(false); } // Read the cert from the BIO structure in memory to a char array. int raw_size = BIO_pending(bio); unsigned char *raw_certificate = new unsigned char[raw_size]; int actual_read = BIO_read(bio, raw_certificate, raw_size); if (raw_size != actual_read) { String errorMessage = Formatter::Format(_T("BIO_read returned an unexpected number of characters. Expected: {0}, Returned: {1}"), raw_size, actual_read); ErrorManager::Instance()->ReportError(ErrorManager::Medium, 5513, "CertificateVerifier::operator()", errorMessage); BIO_free(bio); delete[] raw_certificate; return OverrideResult_(false); } // Create a Windows certificate context, using the raw DER data. PCCERT_CONTEXT context = CertCreateCertificateContext(X509_ASN_ENCODING, (BYTE*) raw_certificate, raw_size); if (context == NULL) { String errorMessage = Formatter::Format(_T("Call to CertCreateCertificateContext failed. Error: {0}"), (int) GetLastError()); ErrorManager::Instance()->ReportError(ErrorManager::Medium, 5513, "CertificateVerifier::operator()", errorMessage); BIO_free(bio); delete[] raw_certificate; return OverrideResult_(false); } String expected_host_name = host_name_; int windows_error_code = 0; if (VerifyCertificate_(context, expected_host_name.GetBuffer(-1), windows_error_code)) { LOG_DEBUG(Formatter::Format("Certificate verification succeeded for session {0}.", session_id_)); BIO_free(bio); delete[] raw_certificate; CertFreeCertificateContext(context); return OverrideResult_(true); } else { String windows_error_text = ErrorManager::Instance()->GetWindowsErrorText(windows_error_code); String formattedDebugMessage = Formatter::Format("Certificate verification failed for session {0}. Expected host: {1}, Windows error code: {2}, Windows error message: {3}", session_id_, host_name_, windows_error_code, windows_error_text); LOG_DEBUG(formattedDebugMessage); BIO_free(bio); delete[] raw_certificate; CertFreeCertificateContext(context); return OverrideResult_(false); } }