/* */ #include "WinTLSContext.h" #include #include "BufferedFile.h" #include "LogFactory.h" #include "Logger.h" #include "fmt.h" #include "message.h" #include "util.h" #ifndef SP_PROT_TLS1_1_CLIENT #define SP_PROT_TLS1_1_CLIENT 0x00000200 #endif #ifndef SP_PROT_TLS1_1_SERVER #define SP_PROT_TLS1_1_SERVER 0x00000100 #endif #ifndef SP_PROT_TLS1_2_CLIENT #define SP_PROT_TLS1_2_CLIENT 0x00000800 #endif #ifndef SP_PROT_TLS1_2_SERVER #define SP_PROT_TLS1_2_SERVER 0x00000400 #endif #ifndef SCH_USE_STRONG_CRYPTO #define SCH_USE_STRONG_CRYPTO 0x00400000 #endif namespace aria2 { WinTLSContext::WinTLSContext(TLSSessionSide side) : side_(side), store_(0) { memset(&credentials_, 0, sizeof(credentials_)); credentials_.dwVersion = SCHANNEL_CRED_VERSION; if (side_ == TLS_CLIENT) { credentials_.grbitEnabledProtocols = SP_PROT_SSL3_CLIENT | SP_PROT_TLS1_CLIENT | SP_PROT_TLS1_1_CLIENT | SP_PROT_TLS1_2_CLIENT; } else { credentials_.grbitEnabledProtocols = SP_PROT_SSL3_SERVER | SP_PROT_TLS1_SERVER | SP_PROT_TLS1_1_SERVER | SP_PROT_TLS1_2_SERVER; } credentials_.dwMinimumCipherStrength = 128; // bit setVerifyPeer(side_ == TLS_CLIENT); } TLSContext* TLSContext::make(TLSSessionSide side) { return new WinTLSContext(side); } WinTLSContext::~WinTLSContext() { if (store_) { ::CertCloseStore(store_, 0); store_ = 0; } } bool WinTLSContext::getVerifyPeer() const { return credentials_.dwFlags & SCH_CRED_AUTO_CRED_VALIDATION; } void WinTLSContext::setVerifyPeer(bool verify) { if (side_ == TLS_CLIENT && verify) { credentials_.dwFlags = SCH_CRED_NO_DEFAULT_CREDS | SCH_CRED_AUTO_CRED_VALIDATION | SCH_CRED_REVOCATION_CHECK_CHAIN | SCH_CRED_IGNORE_NO_REVOCATION_CHECK | SCH_USE_STRONG_CRYPTO; } else { credentials_.dwFlags = SCH_CRED_NO_DEFAULT_CREDS | SCH_CRED_MANUAL_CRED_VALIDATION | SCH_CRED_IGNORE_NO_REVOCATION_CHECK | SCH_CRED_IGNORE_REVOCATION_OFFLINE | SCH_CRED_NO_SERVERNAME_CHECK | SCH_USE_STRONG_CRYPTO; } cred_.reset(); } CredHandle* WinTLSContext::getCredHandle() { if (cred_) { return cred_.get(); } TimeStamp ts; cred_.reset(new CredHandle()); const CERT_CONTEXT* ctx = nullptr; if (store_) { ctx = ::CertEnumCertificatesInStore(store_, nullptr); if (!ctx) { throw DL_ABORT_EX("Failed to load certificate"); } credentials_.cCreds = 1; credentials_.paCred = &ctx; } else { credentials_.cCreds = 0; credentials_.paCred = nullptr; } SECURITY_STATUS status = ::AcquireCredentialsHandleW( nullptr, (SEC_WCHAR*)UNISP_NAME_W, side_ == TLS_CLIENT ? SECPKG_CRED_OUTBOUND : SECPKG_CRED_INBOUND, nullptr, &credentials_, nullptr, nullptr, cred_.get(), &ts); if (ctx) { ::CertFreeCertificateContext(ctx); } if (status != SEC_E_OK) { cred_.reset(); throw DL_ABORT_EX("Failed to initialize WinTLS context handle"); } return cred_.get(); } bool WinTLSContext::addCredentialFile(const std::string& certfile, const std::string& keyfile) { std::stringstream ss; BufferedFile(certfile.c_str(), "rb").transfer(ss); auto data = ss.str(); CRYPT_DATA_BLOB blob = { (DWORD)data.length(), (BYTE*)data.c_str() }; if (!::PFXIsPFXBlob(&blob)) { A2_LOG_ERROR("Not a valid PKCS12 file"); return false; } HCERTSTORE store = ::PFXImportCertStore(&blob, L"", CRYPT_EXPORTABLE | CRYPT_USER_KEYSET); if (!store_) { store = ::PFXImportCertStore(&blob, nullptr, CRYPT_EXPORTABLE | CRYPT_USER_KEYSET); } if (!store) { A2_LOG_ERROR("Failed to import PKCS12 store"); return false; } auto ctx = ::CertEnumCertificatesInStore(store, nullptr); if (!ctx) { A2_LOG_ERROR("PKCS12 file does not contain certificates"); ::CertCloseStore(store, 0); return false; } ::CertFreeCertificateContext(ctx); if (store_) { ::CertCloseStore(store_, 0); } store_ = store; cred_.reset(); return true; } bool WinTLSContext::addTrustedCACertFile(const std::string& certfile) { A2_LOG_WARN("TLS CA bundle files are not supported. " "The system trust store will be used."); return false; } } // namespace aria2