diff options
Diffstat (limited to 'src/components/security_manager')
10 files changed, 1146 insertions, 539 deletions
diff --git a/src/components/security_manager/include/security_manager/crypto_manager_impl.h b/src/components/security_manager/include/security_manager/crypto_manager_impl.h index 4e48858e5c..aa3be0f430 100644 --- a/src/components/security_manager/include/security_manager/crypto_manager_impl.h +++ b/src/components/security_manager/include/security_manager/crypto_manager_impl.h @@ -71,6 +71,8 @@ class CryptoManagerImpl : public CryptoManager { size_t* out_data_size) OVERRIDE; bool IsInitCompleted() const OVERRIDE; bool IsHandshakePending() const OVERRIDE; + bool GetCertificateDueDate(time_t& due_date) const OVERRIDE; + bool HasCertificate() const OVERRIDE; size_t get_max_block_size(size_t mtu) const OVERRIDE; std::string LastError() const OVERRIDE; void ResetConnection() OVERRIDE; @@ -101,6 +103,22 @@ class CryptoManagerImpl : public CryptoManager { std::string GetTextBy(X509_NAME* name, int object) const; + /** + * @brief Pulls number stored in buffer of chars + * and returns it as integer + * @param buf where symbols stored + * @param idx index of required char to be converted + * @return number in integer representation + */ + int get_number_from_char_buf(char* buf, int* idx) const; + /** + * @brief Converts time from ASN1 format (used in OpenSSL) + * to time_t data type + * @param time_to_convert time to be converted + * @return time in time_t format + */ + time_t convert_asn1_time_to_time_t(ASN1_TIME* time_to_convert) const; + SSL* connection_; BIO* bioIn_; BIO* bioOut_; @@ -128,23 +146,65 @@ class CryptoManagerImpl : public CryptoManager { SSLContext* CreateSSLContext() OVERRIDE; void ReleaseSSLContext(SSLContext* context) OVERRIDE; std::string LastError() const OVERRIDE; - virtual bool IsCertificateUpdateRequired() const OVERRIDE; + bool IsCertificateUpdateRequired( + const time_t system_time, const time_t certificates_time) const OVERRIDE; virtual const CryptoManagerSettings& get_settings() const OVERRIDE; private: + bool AreForceProtectionSettingsCorrect() const; bool set_certificate(const std::string& cert_data); - int pull_number_from_buf(char* buf, int* idx); - void asn1_time_to_tm(ASN1_TIME* time); + /** + * @brief Saves new certificate data on the file system + * @param cert_data certificate data in PEM format + * @return true if new certificate data was successfully saved on the file + * system, otherwise returns false + */ + bool SaveCertificateData(const std::string& cert_data) const; + + /** + * @brief Updates certificate and private key for the current SSL context + * @param certificate new certificate to update + * @param key new private key to update + * @return true if certificate and private key were updated successfully, + * otherwise returns false + */ + bool UpdateModuleCertificateData(X509* certificate, EVP_PKEY* key); + + /** + * @brief Loads X509 certificate from file specified in CryptoManagerSettings + * @return returns pointer to the loaded X509 certificate in case of success + * otherwise returns NULL + */ + X509* LoadModuleCertificateFromFile(); + + /** + * @brief Loads private key from file specified in CryptoManagerSettings + * @return returns pointer to the loaded private key in case of success + * otherwise returns NULL + */ + EVP_PKEY* LoadModulePrivateKeyFromFile(); + + /** + * @brief Saves new X509 certificate data to file specified in + * CryptoManagerSettings + * @param certificate new X509 certificate data + * @return true if certificate data was saved to the file system otherwise + * returns false + */ + bool SaveModuleCertificateToFile(X509* certificate) const; /** - * @brief Sets initial certificate datetime + * @brief Saves new private key data to file specified in + * CryptoManagerSettings + * @param key new private key data + * @return true if private key data was saved to the file system otherwise + * returns false */ - void InitCertExpTime(); + bool SaveModuleKeyToFile(EVP_PKEY* key) const; const utils::SharedPtr<const CryptoManagerSettings> settings_; SSL_CTX* context_; - mutable struct tm expiration_time_; static uint32_t instance_count_; static sync_primitives::Lock instance_lock_; DISALLOW_COPY_AND_ASSIGN(CryptoManagerImpl); diff --git a/src/components/security_manager/include/security_manager/crypto_manager_settings_impl.h b/src/components/security_manager/include/security_manager/crypto_manager_settings_impl.h index 1e4699b77a..f20d3e4034 100644 --- a/src/components/security_manager/include/security_manager/crypto_manager_settings_impl.h +++ b/src/components/security_manager/include/security_manager/crypto_manager_settings_impl.h @@ -17,6 +17,7 @@ class CryptoManagerSettingsImpl : public CryptoManagerSettings { return profile_.ssl_mode() == "SERVER" ? security_manager::SERVER : security_manager::CLIENT; } + Protocol security_manager_protocol_name() const OVERRIDE { CREATE_LOGGERPTR_LOCAL(logger_, "SecurityManager") @@ -33,33 +34,59 @@ class CryptoManagerSettingsImpl : public CryptoManagerSettings { if (protocol_str == "SSLv3") { return security_manager::SSLv3; } + if (protocol_str == "DTLSv1.0") { + return security_manager::DTLSv1; + } + LOG4CXX_ERROR( logger_, "Unknown protocol: " << profile_.security_manager_protocol_name()); return static_cast<security_manager::Protocol>(-1); } + bool verify_peer() const OVERRIDE { return profile_.verify_peer(); } + const std::string& certificate_data() const OVERRIDE { return certificate_data_; } + const std::string& ciphers_list() const OVERRIDE { return profile_.ciphers_list(); } + const std::string& ca_cert_path() const OVERRIDE { return profile_.ca_cert_path(); } + + const std::string& module_cert_path() const OVERRIDE { + return profile_.cert_path(); + } + + const std::string& module_key_path() const OVERRIDE { + return profile_.key_path(); + } + size_t update_before_hours() const OVERRIDE { return profile_.update_before_hours(); } + size_t maximum_payload_size() const OVERRIDE { return profile_.maximum_payload_size(); } + const std::vector<int>& force_protected_service() const { + return profile_.force_protected_service(); + } + + const std::vector<int>& force_unprotected_service() const { + return profile_.force_unprotected_service(); + } + private: const profile::Profile& profile_; const std::string certificate_data_; }; -} +} // namespace security_manager #endif // SRC_COMPONENTS_SECURITY_MANAGER_INCLUDE_SECURITY_MANAGER_CRYPTO_MANAGER_SETTINGS_IMPL_H_ diff --git a/src/components/security_manager/include/security_manager/security_manager_impl.h b/src/components/security_manager/include/security_manager/security_manager_impl.h index 469b97d1e1..70b87de0ef 100644 --- a/src/components/security_manager/include/security_manager/security_manager_impl.h +++ b/src/components/security_manager/include/security_manager/security_manager_impl.h @@ -35,6 +35,8 @@ #include <list> #include <string> +#include <set> +#include <memory> #include "utils/macro.h" #include "utils/message_queue.h" @@ -44,6 +46,7 @@ #include "security_manager/security_query.h" #include "protocol_handler/protocol_handler.h" #include "protocol/common.h" +#include "utils/system_time_handler.h" namespace security_manager { /** @@ -67,12 +70,21 @@ typedef threads::MessageLoopThread<SecurityMessageQueue> SecurityMessageLoop; * \brief SecurityManagerImpl class implements SecurityManager interface */ class SecurityManagerImpl : public SecurityManager, - public SecurityMessageLoop::Handler { + public SecurityMessageLoop::Handler, + public utils::SystemTimeListener { public: /** * \brief Constructor + * \param system_time_handler allows to work with system time. */ - SecurityManagerImpl(); + explicit SecurityManagerImpl( + std::unique_ptr<utils::SystemTimeHandler>&& system_time_handler); + + /** + * \brief Destructor + */ + ~SecurityManagerImpl(); + /** * \brief Add received from Mobile Application message * Overriden ProtocolObserver::OnMessageReceived method @@ -131,9 +143,11 @@ class SecurityManagerImpl : public SecurityManager, * Do not notify listeners, send security error on occure * \param connection_key Unique key used by other components as session * identifier + * @param cc_strategy - SSL context creation strategy * @return new \c SSLContext or \c NULL on any error */ - SSLContext* CreateSSLContext(const uint32_t& connection_key) OVERRIDE; + SSLContext* CreateSSLContext(const uint32_t& connection_key, + ContextCreationStrategy cc_strategy) OVERRIDE; /** * \brief Start handshake as SSL client @@ -141,16 +155,33 @@ class SecurityManagerImpl : public SecurityManager, void StartHandshake(uint32_t connection_key) OVERRIDE; /** + * @brief PostponeHandshake allows to postpone handshake. It notifies + * cryptomanager that certificate should be updated and adds specified + * connection key to the list of the certificate awaiting connections. + * @param connection_key the identifier for connection to postpone handshake. + */ + void PostponeHandshake(const uint32_t connection_key) OVERRIDE; + + /** * @brief Checks whether certificate should be updated + * @param connection_key the connection identifier to check certificate for. * @return true if certificate should be updated otherwise false */ - bool IsCertificateUpdateRequired() OVERRIDE; + bool IsCertificateUpdateRequired(const uint32_t connection_key) OVERRIDE; + + /** + * @brief Checks whether system time ready notification + * was received from hmi + * @return true if received otherwise false + */ + bool IsSystemTimeProviderReady() const OVERRIDE; /** * \brief Add/Remove for SecurityManagerListener */ void AddListener(SecurityManagerListener* const listener) OVERRIDE; void RemoveListener(SecurityManagerListener* const listener) OVERRIDE; + /** * \brief Notifiers for listeners * \param connection_key Unique key used by other components as session @@ -173,6 +204,11 @@ class SecurityManagerImpl : public SecurityManager, void NotifyOnCertificateUpdateRequired() OVERRIDE; /** + * @brief Notify all listeners that handshake was failed + */ + void NotifyListenersOnHandshakeFailed() OVERRIDE; + + /** * @brief Check is policy certificate data is empty * @return true if policy certificate data is not empty otherwise false */ @@ -217,6 +253,39 @@ class SecurityManagerImpl : public SecurityManager, */ void SendQuery(const SecurityQuery& query, const uint32_t connection_key); + /** + * @brief OnCertificateUpdated allows to obtain notification when certificate + * has been updated with policy table update. Pass this certificate to crypto + * manager for further processing. Also process postopnes handshake for the + * certain connection key. + * + * @param data the certificates content. + * @return always true. + */ + bool OnCertificateUpdated(const std::string& data) OVERRIDE; + + /** + * @brief ResumeHandshake allows to resume handshake after certificate has + * been updated. + * @param connection_key the connection identifier to start handshake. + */ + void ResumeHandshake(uint32_t connection_key); + + /** + * @brief ProceedHandshake starts the handshake process. + * @param ssl_context ssl context for the handshake. COntains certificate, + * keys, etc. + * @param connection_key the connection identifier to process handshake. + */ + void ProceedHandshake(SSLContext* ssl_context, uint32_t connection_key); + + /** + * @brief OnSystemTimeArrived method which notifies + * crypto manager with updated time in order to check certificate validity + * @param utc_time the current system time. + */ + void OnSystemTimeArrived(const time_t utc_time) OVERRIDE; + // Thread that pumps handshake data SecurityMessageLoop security_messages_; @@ -235,7 +304,17 @@ class SecurityManagerImpl : public SecurityManager, /** *\brief List of listeners for notify handshake done result */ + std::list<SecurityManagerListener*> listeners_; + + std::unique_ptr<utils::SystemTimeHandler> system_time_handler_; + sync_primitives::Lock connections_lock_; + std::set<uint32_t> awaiting_certificate_connections_; + std::set<uint32_t> awaiting_time_connections_; + + mutable sync_primitives::Lock waiters_lock_; + volatile bool waiting_for_certificate_; + volatile bool waiting_for_time_; DISALLOW_COPY_AND_ASSIGN(SecurityManagerImpl); }; } // namespace security_manager diff --git a/src/components/security_manager/src/crypto_manager_impl.cc b/src/components/security_manager/src/crypto_manager_impl.cc index f3dfa8bb1d..1506382bce 100644 --- a/src/components/security_manager/src/crypto_manager_impl.cc +++ b/src/components/security_manager/src/crypto_manager_impl.cc @@ -41,6 +41,7 @@ #include <iostream> #include <stdio.h> #include <ctime> +#include <algorithm> #include "security_manager/security_manager.h" #include "utils/logger.h" @@ -63,7 +64,12 @@ namespace { int debug_callback(int preverify_ok, X509_STORE_CTX* ctx) { if (!preverify_ok) { const int error = X509_STORE_CTX_get_error(ctx); - UNUSED(error); + if (error == X509_V_ERR_CERT_NOT_YET_VALID || + error == X509_V_ERR_CERT_HAS_EXPIRED) { + // return success result code instead of error because start + // and expiration cert dates will be checked by SDL + return 1; + } LOG4CXX_WARN(logger_, "Certificate verification failed with error " << error << " \"" << X509_verify_cert_error_string(error) @@ -93,7 +99,6 @@ CryptoManagerImpl::CryptoManagerImpl( OpenSSL_add_all_algorithms(); SSL_library_init(); } - InitCertExpTime(); } CryptoManagerImpl::~CryptoManagerImpl() { @@ -113,10 +118,35 @@ CryptoManagerImpl::~CryptoManagerImpl() { } } +bool CryptoManagerImpl::AreForceProtectionSettingsCorrect() const { + LOG4CXX_AUTO_TRACE(logger_); + const std::vector<int>& forced_unprotected_services = + get_settings().force_unprotected_service(); + const std::vector<int>& forced_protected_services = + get_settings().force_protected_service(); + + for (auto& item : forced_protected_services) { + if (0 == item) { + continue; + } + + if (std::find(forced_unprotected_services.begin(), + forced_unprotected_services.end(), + item) != forced_unprotected_services.end()) { + return false; + } + } + return true; +} + bool CryptoManagerImpl::Init() { LOG4CXX_AUTO_TRACE(logger_); const Mode mode = get_settings().security_manager_mode(); + if (!AreForceProtectionSettingsCorrect()) { + LOG4CXX_DEBUG(logger_, "Force protection settings of ini file are wrong!"); + return false; + } const bool is_server = (mode == SERVER); if (is_server) { LOG4CXX_DEBUG(logger_, "Server mode"); @@ -133,7 +163,7 @@ bool CryptoManagerImpl::Init() { #if OPENSSL_VERSION_NUMBER < CONST_SSL_METHOD_MINIMAL_VERSION SSL_METHOD* method; #else - const SSL_METHOD* method; + const SSL_METHOD* method = NULL; #endif switch (get_settings().security_manager_protocol_name()) { case SSLv3: @@ -141,13 +171,16 @@ bool CryptoManagerImpl::Init() { LOG4CXX_WARN(logger_, "OpenSSL does not support SSL3 protocol"); return false; #else + LOG4CXX_DEBUG(logger_, "SSLv3 is used"); method = is_server ? SSLv3_server_method() : SSLv3_client_method(); break; #endif case TLSv1: + LOG4CXX_DEBUG(logger_, "TLSv1 is used"); method = is_server ? TLSv1_server_method() : TLSv1_client_method(); break; case TLSv1_1: + LOG4CXX_DEBUG(logger_, "TLSv1_1 is used"); #if OPENSSL_VERSION_NUMBER < TLS1_1_MINIMAL_VERSION LOG4CXX_WARN( logger_, @@ -158,6 +191,7 @@ bool CryptoManagerImpl::Init() { #endif break; case TLSv1_2: + LOG4CXX_DEBUG(logger_, "TLSv1_2 is used"); #if OPENSSL_VERSION_NUMBER < TLS1_1_MINIMAL_VERSION LOG4CXX_WARN( logger_, @@ -167,6 +201,10 @@ bool CryptoManagerImpl::Init() { method = is_server ? TLSv1_2_server_method() : TLSv1_2_client_method(); #endif break; + case DTLSv1: + LOG4CXX_DEBUG(logger_, "DTLSv1 is used"); + method = is_server ? DTLSv1_server_method() : DTLSv1_client_method(); + break; default: LOG4CXX_ERROR(logger_, "Unknown protocol: " @@ -183,7 +221,7 @@ bool CryptoManagerImpl::Init() { // Disable SSL2 as deprecated SSL_CTX_set_options(context_, SSL_OP_NO_SSLv2); - set_certificate(get_settings().certificate_data()); + SaveCertificateData(get_settings().certificate_data()); if (get_settings().ciphers_list().empty()) { LOG4CXX_WARN(logger_, "Empty ciphers list"); @@ -216,6 +254,21 @@ bool CryptoManagerImpl::Init() { << '"'); } + LOG4CXX_DEBUG(logger_, "Setting up module certificate and private key"); + + X509* module_certificate = LoadModuleCertificateFromFile(); + utils::ScopeGuard certificate_guard = + utils::MakeGuard(X509_free, module_certificate); + UNUSED(certificate_guard); + + EVP_PKEY* module_key = LoadModulePrivateKeyFromFile(); + utils::ScopeGuard key_guard = utils::MakeGuard(EVP_PKEY_free, module_key); + UNUSED(key_guard); + + if (!UpdateModuleCertificateData(module_certificate, module_key)) { + LOG4CXX_WARN(logger_, "Failed to update module key and certificate"); + } + guard.Dismiss(); const int verify_mode = @@ -235,17 +288,33 @@ bool CryptoManagerImpl::OnCertificateUpdated(const std::string& data) { return false; } - return set_certificate(data); + if (!SaveCertificateData(data)) { + LOG4CXX_ERROR(logger_, "Failed to save certificate data"); + return false; + } + + X509* module_certificate = LoadModuleCertificateFromFile(); + EVP_PKEY* module_key = LoadModulePrivateKeyFromFile(); + + utils::ScopeGuard certificate_guard = + utils::MakeGuard(X509_free, module_certificate); + UNUSED(certificate_guard); + + utils::ScopeGuard key_guard = utils::MakeGuard(EVP_PKEY_free, module_key); + UNUSED(key_guard); + + return UpdateModuleCertificateData(module_certificate, module_key); } SSLContext* CryptoManagerImpl::CreateSSLContext() { - if (context_ == NULL) { + if (NULL == context_) { return NULL; } SSL* conn = SSL_new(context_); - if (conn == NULL) + if (NULL == conn) { return NULL; + } if (get_settings().security_manager_mode() == SERVER) { SSL_set_accept_state(conn); @@ -269,24 +338,17 @@ std::string CryptoManagerImpl::LastError() const { return std::string(reason ? reason : ""); } -bool CryptoManagerImpl::IsCertificateUpdateRequired() const { +bool CryptoManagerImpl::IsCertificateUpdateRequired( + const time_t system_time, const time_t certificates_time) const { LOG4CXX_AUTO_TRACE(logger_); - const time_t cert_date = mktime(&expiration_time_); + const double seconds = difftime(certificates_time, system_time); - if (cert_date == -1) { - LOG4CXX_WARN(logger_, - "The certifiacte expiration time cannot be represented."); - return false; - } - const time_t now = time(NULL); - const double seconds = difftime(cert_date, now); + LOG4CXX_DEBUG( + logger_, "Certificate UTC time: " << asctime(gmtime(&certificates_time))); - LOG4CXX_DEBUG(logger_, - "Certificate expiration time: " << asctime(&expiration_time_)); - LOG4CXX_DEBUG(logger_, - "Host time: " << asctime(localtime(&now)) - << ". Seconds before expiration: " << seconds); + LOG4CXX_DEBUG(logger_, "Host UTC time: " << asctime(gmtime(&system_time))); + LOG4CXX_DEBUG(logger_, "Seconds before expiration: " << seconds); if (seconds < 0) { LOG4CXX_WARN(logger_, "Certificate is already expired."); return true; @@ -300,7 +362,8 @@ const CryptoManagerSettings& CryptoManagerImpl::get_settings() const { return *settings_; } -bool CryptoManagerImpl::set_certificate(const std::string& cert_data) { +bool CryptoManagerImpl::SaveCertificateData( + const std::string& cert_data) const { LOG4CXX_AUTO_TRACE(logger_); if (cert_data.empty()) { @@ -315,100 +378,162 @@ bool CryptoManagerImpl::set_certificate(const std::string& cert_data) { UNUSED(bio_guard) X509* cert = NULL; - PEM_read_bio_X509(bio_cert, &cert, 0, 0); + if (!PEM_read_bio_X509(bio_cert, &cert, 0, 0)) { + LOG4CXX_WARN(logger_, "Could not read certificate data: " << LastError()); + return false; + } - EVP_PKEY* pkey = NULL; - if (1 == BIO_reset(bio_cert)) { - PEM_read_bio_PrivateKey(bio_cert, &pkey, 0, 0); - } else { + utils::ScopeGuard cert_guard = utils::MakeGuard(X509_free, cert); + UNUSED(cert_guard); + + if (1 != BIO_reset(bio_cert)) { LOG4CXX_WARN(logger_, "Unabled to reset BIO in order to read private key, " << LastError()); } - if (NULL == cert || NULL == pkey) { - LOG4CXX_WARN(logger_, "Either certificate or key not valid."); + EVP_PKEY* pkey = NULL; + if (!PEM_read_bio_PrivateKey(bio_cert, &pkey, 0, 0)) { + LOG4CXX_WARN(logger_, "Could not read private key data: " << LastError()); return false; } - if (!SSL_CTX_use_certificate(context_, cert)) { - LOG4CXX_WARN(logger_, "Could not use certificate: " << LastError()); - return false; - } + utils::ScopeGuard key_guard = utils::MakeGuard(EVP_PKEY_free, pkey); + UNUSED(key_guard); - asn1_time_to_tm(X509_get_notAfter(cert)); + return SaveModuleCertificateToFile(cert) && SaveModuleKeyToFile(pkey); +} - if (!SSL_CTX_use_PrivateKey(context_, pkey)) { - LOG4CXX_ERROR(logger_, "Could not use key: " << LastError()); - return false; +bool CryptoManagerImpl::UpdateModuleCertificateData(X509* certificate, + EVP_PKEY* key) { + LOG4CXX_AUTO_TRACE(logger_); + if (certificate) { + if (!SSL_CTX_use_certificate(context_, certificate)) { + LOG4CXX_WARN(logger_, "Could not use certificate: " << LastError()); + return false; + } } - if (!SSL_CTX_check_private_key(context_)) { - LOG4CXX_ERROR(logger_, "Could not use certificate: " << LastError()); - return false; - } + if (key) { + if (!SSL_CTX_use_PrivateKey(context_, key)) { + LOG4CXX_ERROR(logger_, "Could not use key: " << LastError()); + return false; + } - X509_STORE* store = SSL_CTX_get_cert_store(context_); - if (store) { - X509* extra_cert = NULL; - while ((extra_cert = PEM_read_bio_X509(bio_cert, NULL, 0, 0))) { - if (extra_cert != cert) { - LOG4CXX_DEBUG(logger_, - "Added new certificate to store: " << extra_cert); - X509_STORE_add_cert(store, extra_cert); - } + if (!SSL_CTX_check_private_key(context_)) { + LOG4CXX_ERROR(logger_, "Private key is invalid: " << LastError()); + return false; } } - LOG4CXX_DEBUG(logger_, "Certificate and key successfully updated"); + LOG4CXX_DEBUG(logger_, "Certificate and key are successfully updated"); return true; } -int CryptoManagerImpl::pull_number_from_buf(char* buf, int* idx) { - if (!idx) { - return 0; +X509* CryptoManagerImpl::LoadModuleCertificateFromFile() { + LOG4CXX_AUTO_TRACE(logger_); + + const std::string cert_path = get_settings().module_cert_path(); + BIO* bio_cert = BIO_new_file(cert_path.c_str(), "r"); + if (!bio_cert) { + LOG4CXX_WARN(logger_, + "Failed to open " << cert_path << " file: " << LastError()); + return NULL; + } + + utils::ScopeGuard bio_guard = utils::MakeGuard(BIO_free, bio_cert); + UNUSED(bio_guard); + + X509* module_certificate = NULL; + if (!PEM_read_bio_X509(bio_cert, &module_certificate, NULL, NULL)) { + LOG4CXX_ERROR(logger_, + "Failed to read certificate data from file: " << LastError()); + return NULL; } - const int val = ((buf[*idx] - '0') * 10) + buf[(*idx) + 1] - '0'; - *idx = *idx + 2; - return val; + LOG4CXX_DEBUG(logger_, + "Module certificate was loaded: " << module_certificate); + + return module_certificate; } -void CryptoManagerImpl::asn1_time_to_tm(ASN1_TIME* time) { - char* buf = (char*)time->data; - int index = 0; - const int year = pull_number_from_buf(buf, &index); - if (V_ASN1_GENERALIZEDTIME == time->type) { - expiration_time_.tm_year = - (year * 100 - 1900) + pull_number_from_buf(buf, &index); - } else { - expiration_time_.tm_year = year < 50 ? year + 100 : year; +EVP_PKEY* CryptoManagerImpl::LoadModulePrivateKeyFromFile() { + LOG4CXX_AUTO_TRACE(logger_); + + const std::string key_path = get_settings().module_key_path(); + BIO* bio_key = BIO_new_file(key_path.c_str(), "r"); + if (!bio_key) { + LOG4CXX_WARN(logger_, + "Failed to open " << key_path << " file: " << LastError()); + return NULL; + } + + utils::ScopeGuard bio_guard = utils::MakeGuard(BIO_free, bio_key); + UNUSED(bio_guard); + + EVP_PKEY* module_key = NULL; + if (!PEM_read_bio_PrivateKey(bio_key, &module_key, NULL, NULL)) { + LOG4CXX_ERROR(logger_, + "Failed to read private key data from file: " << LastError()); + return NULL; } + LOG4CXX_DEBUG(logger_, "Module private key was loaded: " << module_key); - const int mon = pull_number_from_buf(buf, &index); - const int day = pull_number_from_buf(buf, &index); - const int hour = pull_number_from_buf(buf, &index); - const int mn = pull_number_from_buf(buf, &index); + return module_key; +} - expiration_time_.tm_mon = mon - 1; - expiration_time_.tm_mday = day; - expiration_time_.tm_hour = hour; - expiration_time_.tm_min = mn; +bool CryptoManagerImpl::SaveModuleCertificateToFile(X509* certificate) const { + LOG4CXX_AUTO_TRACE(logger_); - if (buf[index] == 'Z') { - expiration_time_.tm_sec = 0; + if (!certificate) { + LOG4CXX_WARN(logger_, "Empty certificate. Saving will be skipped"); + return false; } - if ((buf[index] == '+') || (buf[index] == '-')) { - const int mn = pull_number_from_buf(buf, &index); - const int mn1 = pull_number_from_buf(buf, &index); - expiration_time_.tm_sec = (mn * 3600) + (mn1 * 60); - } else { - const int sec = pull_number_from_buf(buf, &index); - expiration_time_.tm_sec = sec; + + const std::string cert_path = get_settings().module_cert_path(); + BIO* bio_cert = BIO_new_file(cert_path.c_str(), "w"); + if (!bio_cert) { + LOG4CXX_ERROR(logger_, + "Failed to open " << cert_path << " file: " << LastError()); + return false; + } + + utils::ScopeGuard bio_guard = utils::MakeGuard(BIO_free, bio_cert); + UNUSED(bio_guard); + + if (!PEM_write_bio_X509(bio_cert, certificate)) { + LOG4CXX_ERROR(logger_, + "Failed to write certificate to file: " << LastError()); + return false; } + + return true; } -void CryptoManagerImpl::InitCertExpTime() { - strptime("1 Jan 1970 00:00:00", "%d %b %Y %H:%M:%S", &expiration_time_); +bool CryptoManagerImpl::SaveModuleKeyToFile(EVP_PKEY* key) const { + LOG4CXX_AUTO_TRACE(logger_); + + if (!key) { + LOG4CXX_WARN(logger_, "Empty private key. Saving will be skipped"); + return false; + } + + const std::string key_path = get_settings().module_key_path(); + BIO* bio_key = BIO_new_file(key_path.c_str(), "w"); + if (!bio_key) { + LOG4CXX_ERROR(logger_, + "Failed to open " << key_path << " file: " << LastError()); + return false; + } + + utils::ScopeGuard bio_guard = utils::MakeGuard(BIO_free, bio_key); + UNUSED(bio_guard); + + if (!PEM_write_bio_PrivateKey(bio_key, key, NULL, NULL, 0, NULL, NULL)) { + LOG4CXX_ERROR(logger_, "Failed to write key to file: " << LastError()); + return false; + } + + return true; } } // namespace security_manager diff --git a/src/components/security_manager/src/security_manager_impl.cc b/src/components/security_manager/src/security_manager_impl.cc index 1853b218b4..1faaddee1c 100644 --- a/src/components/security_manager/src/security_manager_impl.cc +++ b/src/components/security_manager/src/security_manager_impl.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Ford Motor Company + * Copyright (c) 2018, Ford Motor Company * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -31,11 +31,13 @@ */ #include "security_manager/security_manager_impl.h" +#include <functional> #include "security_manager/crypto_manager_impl.h" #include "protocol_handler/protocol_packet.h" #include "utils/logger.h" #include "utils/byte_order.h" #include "json/json.h" +#include "utils/helpers.h" namespace security_manager { @@ -44,11 +46,22 @@ CREATE_LOGGERPTR_GLOBAL(logger_, "SecurityManager") static const char* kErrId = "id"; static const char* kErrText = "text"; -SecurityManagerImpl::SecurityManagerImpl() +SecurityManagerImpl::SecurityManagerImpl( + std::unique_ptr<utils::SystemTimeHandler>&& system_time_handler) : security_messages_("SecurityManager", this) , session_observer_(NULL) , crypto_manager_(NULL) - , protocol_handler_(NULL) {} + , protocol_handler_(NULL) + , system_time_handler_(std::move(system_time_handler)) + , waiting_for_certificate_(false) + , waiting_for_time_(false) { + DCHECK(system_time_handler_); + system_time_handler_->SubscribeOnSystemTime(this); +} + +SecurityManagerImpl::~SecurityManagerImpl() { + system_time_handler_->UnsubscribeFromSystemTime(this); +} void SecurityManagerImpl::OnMessageReceived( const ::protocol_handler::RawMessagePtr message) { @@ -136,19 +149,23 @@ void SecurityManagerImpl::Handle(const SecurityMessage message) { } security_manager::SSLContext* SecurityManagerImpl::CreateSSLContext( - const uint32_t& connection_key) { + const uint32_t& connection_key, ContextCreationStrategy cc_strategy) { LOG4CXX_INFO(logger_, "ProtectService processing"); DCHECK(session_observer_); DCHECK(crypto_manager_); - security_manager::SSLContext* ssl_context = session_observer_->GetSSLContext( - connection_key, protocol_handler::kControl); - // return exists SSLCOntext for current connection/session - if (ssl_context) { - return ssl_context; + if (kUseExisting == cc_strategy) { + security_manager::SSLContext* ssl_context = + session_observer_->GetSSLContext(connection_key, + protocol_handler::kControl); + // If SSLContext for current connection/session exists - return it + if (ssl_context) { + return ssl_context; + } } - ssl_context = crypto_manager_->CreateSSLContext(); + security_manager::SSLContext* ssl_context = + crypto_manager_->CreateSSLContext(); if (!ssl_context) { const std::string error_text("CryptoManager could not create SSL context."); LOG4CXX_ERROR(logger_, error_text); @@ -172,6 +189,40 @@ security_manager::SSLContext* SecurityManagerImpl::CreateSSLContext( return ssl_context; } +void SecurityManagerImpl::PostponeHandshake(const uint32_t connection_key) { + LOG4CXX_TRACE(logger_, "Handshake postponed"); + sync_primitives::AutoLock lock(connections_lock_); + if (waiting_for_certificate_) { + awaiting_certificate_connections_.insert(connection_key); + } + if (waiting_for_time_) { + awaiting_time_connections_.insert(connection_key); + } +} + +void SecurityManagerImpl::ResumeHandshake(uint32_t connection_key) { + LOG4CXX_TRACE(logger_, "Handshake resumed"); + + security_manager::SSLContext* ssl_context = + CreateSSLContext(connection_key, kForceRecreation); + + if (!ssl_context) { + LOG4CXX_WARN(logger_, + "Unable to resume handshake. No SSL context for key " + << connection_key); + return; + } + + ssl_context->ResetConnection(); + if (!waiting_for_certificate_ && !ssl_context->HasCertificate()) { + NotifyListenersOnHandshakeDone(connection_key, + SSLContext::Handshake_Result_Fail); + return; + } + + ProceedHandshake(ssl_context, connection_key); +} + void SecurityManagerImpl::StartHandshake(uint32_t connection_key) { DCHECK(session_observer_); LOG4CXX_INFO(logger_, "StartHandshake: connection_key " << connection_key); @@ -187,6 +238,35 @@ void SecurityManagerImpl::StartHandshake(uint32_t connection_key) { SSLContext::Handshake_Result_Fail); return; } + if (!ssl_context->HasCertificate()) { + LOG4CXX_ERROR(logger_, "Security certificate is absent"); + sync_primitives::AutoLock lock(waiters_lock_); + waiting_for_certificate_ = true; + NotifyOnCertificateUpdateRequired(); + } + + { + sync_primitives::AutoLock lock(waiters_lock_); + waiting_for_time_ = true; + } + + PostponeHandshake(connection_key); + system_time_handler_->QuerySystemTime(); +} + +bool SecurityManagerImpl::IsSystemTimeProviderReady() const { + return system_time_handler_->system_time_can_be_received(); +} + +void SecurityManagerImpl::ProceedHandshake( + security_manager::SSLContext* ssl_context, uint32_t connection_key) { + LOG4CXX_AUTO_TRACE(logger_); + if (!ssl_context) { + LOG4CXX_WARN(logger_, + "Unable to process handshake. No SSL context for key " + << connection_key); + return; + } if (ssl_context->IsInitCompleted()) { NotifyListenersOnHandshakeDone(connection_key, @@ -194,8 +274,33 @@ void SecurityManagerImpl::StartHandshake(uint32_t connection_key) { return; } - ssl_context->SetHandshakeContext( - session_observer_->GetHandshakeContext(connection_key)); + time_t cert_due_date; + if (!ssl_context->GetCertificateDueDate(cert_due_date)) { + LOG4CXX_ERROR(logger_, "Failed to get certificate due date!"); + return; + } + + if (crypto_manager_->IsCertificateUpdateRequired( + system_time_handler_->GetUTCTime(), cert_due_date)) { + LOG4CXX_DEBUG(logger_, "Host certificate update required"); + if (helpers::in_range(awaiting_certificate_connections_, connection_key)) { + NotifyListenersOnHandshakeDone(connection_key, + SSLContext::Handshake_Result_CertExpired); + return; + } + { + sync_primitives::AutoLock lock(waiters_lock_); + waiting_for_certificate_ = true; + } + PostponeHandshake(connection_key); + NotifyOnCertificateUpdateRequired(); + return; + } + + SSLContext::HandshakeContext handshake_context = + session_observer_->GetHandshakeContext(connection_key); + handshake_context.system_time = system_time_handler_->GetUTCTime(); + ssl_context->SetHandshakeContext(handshake_context); size_t data_size = 0; const uint8_t* data = NULL; @@ -216,9 +321,21 @@ void SecurityManagerImpl::StartHandshake(uint32_t connection_key) { } } -bool SecurityManagerImpl::IsCertificateUpdateRequired() { +bool SecurityManagerImpl::IsCertificateUpdateRequired( + const uint32_t connection_key) { LOG4CXX_AUTO_TRACE(logger_); - return crypto_manager_->IsCertificateUpdateRequired(); + security_manager::SSLContext* ssl_context = + CreateSSLContext(connection_key, kUseExisting); + DCHECK_OR_RETURN(ssl_context, true); + LOG4CXX_DEBUG(logger_, + "Set SSL context to connection_key " << connection_key); + time_t cert_due_date; + if (!ssl_context->GetCertificateDueDate(cert_due_date)) { + LOG4CXX_ERROR(logger_, "Failed to get certificate due date!"); + return true; + } + return crypto_manager_->IsCertificateUpdateRequired( + system_time_handler_->GetUTCTime(), cert_due_date); } void SecurityManagerImpl::AddListener(SecurityManagerListener* const listener) { @@ -227,7 +344,6 @@ void SecurityManagerImpl::AddListener(SecurityManagerListener* const listener) { "Invalid (NULL) pointer to SecurityManagerListener."); return; } - LOG4CXX_DEBUG(logger_, "Adding listener " << listener); listeners_.push_back(listener); } @@ -241,6 +357,37 @@ void SecurityManagerImpl::RemoveListener( listeners_.remove(listener); } +bool SecurityManagerImpl::OnCertificateUpdated(const std::string& data) { + LOG4CXX_AUTO_TRACE(logger_); + { + sync_primitives::AutoLock lock(waiters_lock_); + waiting_for_certificate_ = false; + } + crypto_manager_->OnCertificateUpdated(data); + std::for_each( + awaiting_certificate_connections_.begin(), + awaiting_certificate_connections_.end(), + std::bind1st(std::mem_fun(&SecurityManagerImpl::ResumeHandshake), this)); + + awaiting_certificate_connections_.clear(); + return true; +} + +void SecurityManagerImpl::OnSystemTimeArrived(const time_t utc_time) { + LOG4CXX_AUTO_TRACE(logger_); + { + sync_primitives::AutoLock lock(waiters_lock_); + waiting_for_time_ = false; + } + + std::for_each( + awaiting_time_connections_.begin(), + awaiting_time_connections_.end(), + std::bind1st(std::mem_fun(&SecurityManagerImpl::ResumeHandshake), this)); + + awaiting_time_connections_.clear(); +} + void SecurityManagerImpl::NotifyListenersOnHandshakeDone( const uint32_t& connection_key, SSLContext::HandshakeResult error) { LOG4CXX_AUTO_TRACE(logger_); @@ -269,6 +416,20 @@ void SecurityManagerImpl::NotifyOnCertificateUpdateRequired() { } } +void SecurityManagerImpl::NotifyListenersOnHandshakeFailed() { + LOG4CXX_AUTO_TRACE(logger_); + std::list<SecurityManagerListener*>::iterator it = listeners_.begin(); + while (it != listeners_.end()) { + if ((*it)->OnHandshakeFailed()) { + LOG4CXX_DEBUG(logger_, "Destroying listener: " << *it); + delete (*it); + it = listeners_.erase(it); + } else { + ++it; + } + } +} + bool SecurityManagerImpl::IsPolicyCertificateDataEmpty() { LOG4CXX_AUTO_TRACE(logger_); diff --git a/src/components/security_manager/src/ssl_context_impl.cc b/src/components/security_manager/src/ssl_context_impl.cc index 0b30198f4c..67be17db63 100644 --- a/src/components/security_manager/src/ssl_context_impl.cc +++ b/src/components/security_manager/src/ssl_context_impl.cc @@ -36,6 +36,7 @@ #include <map> #include <algorithm> #include <vector> +#include <time.h> #include <openssl/bio.h> #include <openssl/ssl.h> @@ -77,6 +78,7 @@ bool CryptoManagerImpl::SSLContextImpl::IsInitCompleted() const { SSLContext::HandshakeResult CryptoManagerImpl::SSLContextImpl::StartHandshake( const uint8_t** const out_data, size_t* out_data_size) { + LOG4CXX_AUTO_TRACE(logger_); is_handshake_pending_ = true; return DoHandshakeStep(NULL, 0, out_data, out_data_size); } @@ -112,6 +114,12 @@ size_t des_cbc3_sha_max_block_size(size_t mtu) { return 0; return ((mtu - 29) & 0xfffffff8) - 5; } +time_t get_time_zone_offset(time_t in_time) { + tm gmt_cert_tm = *gmtime(&in_time); + tm local_cert_tm = *localtime(&in_time); + + return mktime(&local_cert_tm) - mktime(&gmt_cert_tm); +} } // namespace std::map<std::string, CryptoManagerImpl::SSLContextImpl::BlockSizeGetter> @@ -174,6 +182,7 @@ const std::string CryptoManagerImpl::SSLContextImpl::RemoveDisallowedInfo( void CryptoManagerImpl::SSLContextImpl::PrintCertData( X509* cert, const std::string& cert_owner) { + LOG4CXX_AUTO_TRACE(logger_); if (!cert) { LOG4CXX_DEBUG(logger_, "Empty certificate data"); return; @@ -206,6 +215,7 @@ void CryptoManagerImpl::SSLContextImpl::PrintCertData( } void CryptoManagerImpl::SSLContextImpl::PrintCertInfo() { + LOG4CXX_AUTO_TRACE(logger_); PrintCertData(SSL_get_certificate(connection_), "HU's"); STACK_OF(X509)* peer_certs = SSL_get_peer_cert_chain(connection_); @@ -217,26 +227,47 @@ void CryptoManagerImpl::SSLContextImpl::PrintCertInfo() { SSLContext::HandshakeResult CryptoManagerImpl::SSLContextImpl::CheckCertContext() { + LOG4CXX_AUTO_TRACE(logger_); X509* cert = SSL_get_peer_certificate(connection_); if (!cert) { // According to the openssl documentation the peer certificate // might be ommitted for the SERVER but required for the cient. return CLIENT == mode_ ? Handshake_Result_Fail : Handshake_Result_Success; } + ASN1_TIME* notBefore = X509_get_notBefore(cert); + ASN1_TIME* notAfter = X509_get_notAfter(cert); - X509_NAME* subj_name = X509_get_subject_name(cert); + time_t start = convert_asn1_time_to_time_t(notBefore); + time_t end = convert_asn1_time_to_time_t(notAfter); - const std::string& cn = GetTextBy(subj_name, NID_commonName); - const std::string& sn = GetTextBy(subj_name, NID_serialNumber); + const double start_seconds = difftime(hsh_context_.system_time, start); + const double end_seconds = difftime(end, hsh_context_.system_time); + + if (start_seconds < 0) { + LOG4CXX_ERROR(logger_, + "Certificate is not yet valid. Time before validity " + << start_seconds << " seconds"); + return Handshake_Result_NotYetValid; + } else { + LOG4CXX_DEBUG(logger_, + "Time since certificate validity " << start_seconds + << "seconds"); + } - if (!(hsh_context_.expected_cn.CompareIgnoreCase(cn.c_str()))) { + if (end_seconds < 0) { LOG4CXX_ERROR(logger_, - "Trying to run handshake with wrong app name: " - << cn << ". Expected app name: " - << hsh_context_.expected_cn.AsMBString()); - return Handshake_Result_AppNameMismatch; + "Certificate already expired. Time after expiration " + << end_seconds << " seconds"); + return Handshake_Result_CertExpired; + } else { + LOG4CXX_DEBUG(logger_, + "Time until expiration " << end_seconds << "seconds"); } + X509_NAME* subj_name = X509_get_subject_name(cert); + + const std::string& sn = GetTextBy(subj_name, NID_serialNumber); + if (!(hsh_context_.expected_sn.CompareIgnoreCase(sn.c_str()))) { LOG4CXX_ERROR(logger_, "Trying to run handshake with wrong app id: " @@ -247,6 +278,60 @@ CryptoManagerImpl::SSLContextImpl::CheckCertContext() { return Handshake_Result_Success; } +int CryptoManagerImpl::SSLContextImpl::get_number_from_char_buf( + char* buf, int* idx) const { + if (!idx) { + return 0; + } + const int val = ((buf[*idx] - '0') * 10) + buf[(*idx) + 1] - '0'; + *idx = *idx + 2; + return val; +} + +time_t CryptoManagerImpl::SSLContextImpl::convert_asn1_time_to_time_t( + ASN1_TIME* time_to_convert) const { + struct tm cert_time; + memset(&cert_time, 0, sizeof(struct tm)); + // the minimum value for day of month is 1, otherwise exception will be thrown + cert_time.tm_mday = 1; + char* buf = reinterpret_cast<char*>(time_to_convert->data); + int index = 0; + const int year = get_number_from_char_buf(buf, &index); + if (V_ASN1_GENERALIZEDTIME == time_to_convert->type) { + cert_time.tm_year = + (year * 100 - 1900) + get_number_from_char_buf(buf, &index); + } else { + cert_time.tm_year = year < 50 ? year + 100 : year; + } + + const int mon = get_number_from_char_buf(buf, &index); + const int day = get_number_from_char_buf(buf, &index); + const int hour = get_number_from_char_buf(buf, &index); + const int mn = get_number_from_char_buf(buf, &index); + + cert_time.tm_mon = mon - 1; + cert_time.tm_mday = day; + cert_time.tm_hour = hour; + cert_time.tm_min = mn; + + if (buf[index] == 'Z') { + cert_time.tm_sec = 0; + } + if ((buf[index] == '+') || (buf[index] == '-')) { + const int mn = get_number_from_char_buf(buf, &index); + const int mn1 = get_number_from_char_buf(buf, &index); + cert_time.tm_sec = (mn * 3600) + (mn1 * 60); + } else { + const int sec = get_number_from_char_buf(buf, &index); + cert_time.tm_sec = sec; + } + + const time_t local_cert_time = mktime(&cert_time); + const time_t time_offset = get_time_zone_offset(local_cert_time); + + return local_cert_time + time_offset; +} + bool CryptoManagerImpl::SSLContextImpl::ReadHandshakeData( const uint8_t** const out_data, size_t* out_data_size) { LOG4CXX_AUTO_TRACE(logger_); @@ -288,7 +373,9 @@ bool CryptoManagerImpl::SSLContextImpl::WriteHandshakeData( SSLContext::HandshakeResult CryptoManagerImpl::SSLContextImpl::PerformHandshake() { + LOG4CXX_AUTO_TRACE(logger_); const int handshake_result = SSL_do_handshake(connection_); + LOG4CXX_TRACE(logger_, "Handshake result: " << handshake_result); if (handshake_result == 1) { const HandshakeResult result = CheckCertContext(); if (result != Handshake_Result_Success) { @@ -307,6 +394,7 @@ CryptoManagerImpl::SSLContextImpl::PerformHandshake() { is_handshake_pending_ = false; } else if (handshake_result == 0) { + LOG4CXX_DEBUG(logger_, "SSL handshake failed"); SSL_clear(connection_); is_handshake_pending_ = false; return Handshake_Result_Fail; @@ -403,25 +491,32 @@ bool CryptoManagerImpl::SSLContextImpl::Decrypt(const uint8_t* const in_data, size_t in_data_size, const uint8_t** const out_data, size_t* out_data_size) { + LOG4CXX_AUTO_TRACE(logger_); sync_primitives::AutoLock locker(bio_locker); if (!SSL_is_init_finished(connection_)) { + LOG4CXX_ERROR(logger_, "SSL initilization is not finished"); return false; } - if (!in_data || !in_data_size) { + if (!in_data || (0 == in_data_size)) { + LOG4CXX_ERROR(logger_, "IN data ptr or IN data size is 0"); return false; } + BIO_write(bioIn_, in_data, in_data_size); int len = BIO_ctrl_pending(bioFilter_); + ptrdiff_t offset = 0; *out_data_size = 0; - while (len) { + *out_data = NULL; + while (len > 0) { EnsureBufferSizeEnough(len + offset); len = BIO_read(bioFilter_, buffer_ + offset, len); // TODO(EZamakhov): investigate BIO_read return 0, -1 and -2 meanings if (len <= 0) { // Reset filter and connection deinitilization instead + LOG4CXX_ERROR(logger_, "Read error occured. Read data lenght : " << len); BIO_ctrl(bioFilter_, BIO_CTRL_RESET, 0, NULL); return false; } @@ -447,6 +542,25 @@ bool CryptoManagerImpl::SSLContextImpl::IsHandshakePending() const { return is_handshake_pending_; } +bool CryptoManagerImpl::SSLContextImpl::GetCertificateDueDate( + time_t& due_date) const { + LOG4CXX_AUTO_TRACE(logger_); + + X509* cert = SSL_get_certificate(connection_); + if (!cert) { + LOG4CXX_DEBUG(logger_, "Get certificate failed."); + return false; + } + + due_date = convert_asn1_time_to_time_t(X509_get_notAfter(cert)); + + return true; +} + +bool CryptoManagerImpl::SSLContextImpl::HasCertificate() const { + return SSL_get_certificate(connection_) != NULL; +} + CryptoManagerImpl::SSLContextImpl::~SSLContextImpl() { SSL_shutdown(connection_); SSL_free(connection_); diff --git a/src/components/security_manager/test/crypto_manager_impl_test.cc b/src/components/security_manager/test/crypto_manager_impl_test.cc index b30684e5f6..74b071793d 100644 --- a/src/components/security_manager/test/crypto_manager_impl_test.cc +++ b/src/components/security_manager/test/crypto_manager_impl_test.cc @@ -52,6 +52,10 @@ namespace { const size_t kUpdatesBeforeHour = 24; const std::string kAllCiphers = "ALL"; const std::string kCaCertPath = ""; +const uint32_t kServiceNumber = 2u; +const size_t kMaxSizeVector = 1u; +const std::string kCertPath = "certificate.crt"; +const std::string kPrivateKeyPath = "private.key"; #ifdef __QNXNTO__ const std::string kFordCipher = SSL3_TXT_RSA_DES_192_CBC3_SHA; @@ -89,6 +93,8 @@ class CryptoManagerTest : public testing::Test { utils::MakeShared<MockCryptoManagerSettings>(); crypto_manager_ = utils::MakeShared<CryptoManagerImpl>(mock_security_manager_settings_); + forced_protected_services_.reserve(kMaxSizeVector); + forced_unprotected_services_.reserve(kMaxSizeVector); } void InitSecurityManager() { @@ -101,6 +107,10 @@ class CryptoManagerTest : public testing::Test { void SetInitialValues(security_manager::Mode mode, security_manager::Protocol protocol, const std::string& cipher) { + ON_CALL(*mock_security_manager_settings_, force_unprotected_service()) + .WillByDefault(ReturnRef(forced_unprotected_services_)); + ON_CALL(*mock_security_manager_settings_, force_protected_service()) + .WillByDefault(ReturnRef(forced_protected_services_)); ON_CALL(*mock_security_manager_settings_, security_manager_mode()) .WillByDefault(Return(mode)); ON_CALL(*mock_security_manager_settings_, security_manager_protocol_name()) @@ -111,6 +121,10 @@ class CryptoManagerTest : public testing::Test { .WillByDefault(ReturnRef(cipher)); ON_CALL(*mock_security_manager_settings_, ca_cert_path()) .WillByDefault(ReturnRef(kCaCertPath)); + ON_CALL(*mock_security_manager_settings_, module_cert_path()) + .WillByDefault(ReturnRef(kCertPath)); + ON_CALL(*mock_security_manager_settings_, module_key_path()) + .WillByDefault(ReturnRef(kPrivateKeyPath)); ON_CALL(*mock_security_manager_settings_, verify_peer()) .WillByDefault(Return(false)); } @@ -118,7 +132,10 @@ class CryptoManagerTest : public testing::Test { utils::SharedPtr<CryptoManagerImpl> crypto_manager_; utils::SharedPtr<MockCryptoManagerSettings> mock_security_manager_settings_; static std::string certificate_data_base64_; + std::vector<int> forced_protected_services_; + std::vector<int> forced_unprotected_services_; }; + std::string CryptoManagerTest::certificate_data_base64_; TEST_F(CryptoManagerTest, UsingBeforeInit) { @@ -133,16 +150,15 @@ TEST_F(CryptoManagerTest, WrongInit) { // Unknown protocol version security_manager::Protocol UNKNOWN = static_cast<security_manager::Protocol>(-1); + // Unexistent cipher value + const std::string invalid_cipher = "INVALID_UNKNOWN_CIPHER"; + const security_manager::Mode mode = security_manager::SERVER; - EXPECT_CALL(*mock_security_manager_settings_, security_manager_mode()) - .WillRepeatedly(Return(security_manager::SERVER)); - EXPECT_CALL(*mock_security_manager_settings_, - security_manager_protocol_name()).WillOnce(Return(UNKNOWN)); - EXPECT_FALSE(crypto_manager_->Init()); + SetInitialValues(mode, UNKNOWN, invalid_cipher); + EXPECT_FALSE(crypto_manager_->Init()); EXPECT_NE(std::string(), crypto_manager_->LastError()); - // Unexistent cipher value - const std::string invalid_cipher = "INVALID_UNKNOWN_CIPHER"; + EXPECT_CALL(*mock_security_manager_settings_, security_manager_protocol_name()) .WillOnce(Return(security_manager::TLSv1_2)); @@ -151,7 +167,6 @@ TEST_F(CryptoManagerTest, WrongInit) { EXPECT_CALL(*mock_security_manager_settings_, ciphers_list()) .WillRepeatedly(ReturnRef(invalid_cipher)); EXPECT_FALSE(crypto_manager_->Init()); - EXPECT_NE(std::string(), crypto_manager_->LastError()); } @@ -176,10 +191,18 @@ TEST_F(CryptoManagerTest, CorrectInit) { security_manager::CLIENT, security_manager::TLSv1_1, kFordCipher); EXPECT_TRUE(crypto_manager_->Init()); + SetInitialValues( + security_manager::CLIENT, security_manager::DTLSv1, kFordCipher); + EXPECT_TRUE(crypto_manager_->Init()); + // Cipher value SetInitialValues( security_manager::SERVER, security_manager::TLSv1_2, kAllCiphers); EXPECT_TRUE(crypto_manager_->Init()); + + SetInitialValues( + security_manager::SERVER, security_manager::DTLSv1, kAllCiphers); + EXPECT_TRUE(crypto_manager_->Init()); } // #endif // __QNX__ @@ -198,7 +221,6 @@ TEST_F(CryptoManagerTest, CreateReleaseSSLContext) { EXPECT_CALL(*mock_security_manager_settings_, maximum_payload_size()) .Times(1) .WillRepeatedly(Return(max_payload_size)); - security_manager::SSLContext* context = crypto_manager_->CreateSSLContext(); EXPECT_TRUE(context); EXPECT_NO_THROW(crypto_manager_->ReleaseSSLContext(context)); @@ -210,7 +232,10 @@ TEST_F(CryptoManagerTest, OnCertificateUpdated) { } TEST_F(CryptoManagerTest, OnCertificateUpdated_UpdateNotRequired) { + time_t system_time = 0; + time_t certificates_time = 1; size_t updates_before = 0; + SetInitialValues( security_manager::CLIENT, security_manager::TLSv1_2, kAllCiphers); ASSERT_TRUE(crypto_manager_->Init()); @@ -218,7 +243,8 @@ TEST_F(CryptoManagerTest, OnCertificateUpdated_UpdateNotRequired) { EXPECT_CALL(*mock_security_manager_settings_, update_before_hours()) .WillOnce(Return(updates_before)); - EXPECT_FALSE(crypto_manager_->IsCertificateUpdateRequired()); + EXPECT_FALSE(crypto_manager_->IsCertificateUpdateRequired(system_time, + certificates_time)); size_t max_updates_ = std::numeric_limits<size_t>::max(); SetInitialValues( @@ -227,7 +253,8 @@ TEST_F(CryptoManagerTest, OnCertificateUpdated_UpdateNotRequired) { .WillOnce(Return(max_updates_)); ASSERT_TRUE(crypto_manager_->Init()); - EXPECT_TRUE(crypto_manager_->IsCertificateUpdateRequired()); + EXPECT_TRUE(crypto_manager_->IsCertificateUpdateRequired(system_time, + certificates_time)); } TEST_F(CryptoManagerTest, OnCertificateUpdated_NotInitialized) { diff --git a/src/components/security_manager/test/security_manager_test.cc b/src/components/security_manager/test/security_manager_test.cc index b334e78e19..3523bb7f44 100644 --- a/src/components/security_manager/test/security_manager_test.cc +++ b/src/components/security_manager/test/security_manager_test.cc @@ -44,6 +44,7 @@ #include "security_manager/mock_ssl_context.h" #include "security_manager/mock_crypto_manager.h" #include "security_manager/mock_security_manager_listener.h" +#include "utils/mock_system_time_handler.h" #include "utils/make_shared.h" #include "utils/test_async_waiter.h" @@ -76,11 +77,11 @@ using ::testing::_; namespace { // Sample data for handshake data emulation -const int32_t key = 0x1; -const int32_t seq_number = 0x2; -const ServiceType secureServiceType = kControl; -const uint32_t protocolVersion = PROTOCOL_VERSION_2; -const bool is_final = false; +const int32_t kKey = 0x1; +const int32_t kSeqNumber = 0x2; +const ServiceType kSecureServiceType = kControl; +const uint32_t kProtocolVersion = PROTOCOL_VERSION_2; +const bool kIsFinal = false; const uint8_t handshake_data[] = {0x1, 0x2, 0x3, 0x4, 0x5}; const size_t handshake_data_size = @@ -95,8 +96,12 @@ const uint32_t kAsyncExpectationsTimeout = 10000u; class SecurityManagerTest : public ::testing::Test { protected: + SecurityManagerTest() + : mock_system_time_handler( + std::unique_ptr<MockSystemTimeHandler>(new MockSystemTimeHandler())) + , security_manager_( + new SecurityManagerImpl(std::move(mock_system_time_handler))) {} void SetUp() OVERRIDE { - security_manager_.reset(new SecurityManagerImpl()); security_manager_->set_session_observer(&mock_session_observer); security_manager_->set_protocol_handler(&mock_protocol_handler); mock_sm_listener.reset(new testing::StrictMock< @@ -105,7 +110,7 @@ class SecurityManagerTest : public ::testing::Test { } void SetMockCryptoManager() { - EXPECT_CALL(mock_crypto_manager, IsCertificateUpdateRequired()) + EXPECT_CALL(mock_crypto_manager, IsCertificateUpdateRequired(_, _)) .WillRepeatedly(Return(false)); security_manager_->set_crypto_manager(&mock_crypto_manager); } @@ -116,7 +121,7 @@ class SecurityManagerTest : public ::testing::Test { uint32_t dataSize, const ServiceType serviceType) { const RawMessagePtr rawMessagePtr(utils::MakeShared<RawMessage>( - key, protocolVersion, data, dataSize, serviceType)); + kKey, kProtocolVersion, data, dataSize, serviceType)); security_manager_->OnMessageReceived(rawMessagePtr); } /* @@ -147,13 +152,14 @@ class SecurityManagerTest : public ::testing::Test { const int repeat_count = 1) { const SecurityQuery::QueryHeader header(SecurityQuery::NOTIFICATION, SecurityQuery::SEND_HANDSHAKE_DATA, - seq_number); + kSeqNumber); for (int c = 0; c < repeat_count; ++c) { EmulateMobileMessage(header, data, data_size); } } - ::utils::SharedPtr<SecurityManagerImpl> security_manager_; + // Strict mocks (same as all methods EXPECT_CALL().Times(0)) + testing::StrictMock<protocol_handler_test::MockSessionObserver> mock_session_observer; testing::StrictMock<protocol_handler_test::MockProtocolHandler> @@ -166,6 +172,8 @@ class SecurityManagerTest : public ::testing::Test { mock_ssl_context_exists; std::unique_ptr<testing::StrictMock< security_manager_test::MockSecurityManagerListener> > mock_sm_listener; + std::unique_ptr<MockSystemTimeHandler> mock_system_time_handler; + std::shared_ptr<SecurityManagerImpl> security_manager_; }; // Test Bodies @@ -174,7 +182,6 @@ class SecurityManagerTest : public ::testing::Test { * and shall not call any methodes */ TEST_F(SecurityManagerTest, SetNULL_Intefaces) { - security_manager_.reset(new SecurityManagerImpl()); security_manager_->set_session_observer(NULL); security_manager_->set_protocol_handler(NULL); security_manager_->set_crypto_manager(NULL); @@ -209,9 +216,9 @@ TEST_F(SecurityManagerTest, Listeners_NoListeners) { security_manager_->RemoveListener(&mock_listener2); security_manager_->NotifyListenersOnHandshakeDone( - key, SSLContext::Handshake_Result_Success); + kKey, SSLContext::Handshake_Result_Success); security_manager_->NotifyListenersOnHandshakeDone( - key, SSLContext::Handshake_Result_Fail); + kKey, SSLContext::Handshake_Result_Fail); } /* * Notifying two listeners @@ -228,11 +235,11 @@ TEST_F(SecurityManagerTest, Listeners_Notifying) { const SSLContext::HandshakeResult first_call_value = SSLContext::Handshake_Result_Success; // Expect call both listeners on 1st call - EXPECT_CALL(*mock_listener1, OnHandshakeDone(key, first_call_value)) + EXPECT_CALL(*mock_listener1, OnHandshakeDone(kKey, first_call_value)) . // Emulate false (reject) result WillOnce(Return(false)); - EXPECT_CALL(*mock_listener2, OnHandshakeDone(key, first_call_value)) + EXPECT_CALL(*mock_listener2, OnHandshakeDone(kKey, first_call_value)) . // Emulate true (accept) result WillOnce(Return(true)); @@ -244,7 +251,7 @@ TEST_F(SecurityManagerTest, Listeners_Notifying) { const SSLContext::HandshakeResult second_call_value = SSLContext::Handshake_Result_Fail; // Expect call last listener on 2d call - EXPECT_CALL(*mock_listener1, OnHandshakeDone(key, second_call_value)) + EXPECT_CALL(*mock_listener1, OnHandshakeDone(kKey, second_call_value)) . // Emulate false (reject) result WillOnce(Return(true)); @@ -254,14 +261,14 @@ TEST_F(SecurityManagerTest, Listeners_Notifying) { security_manager_->AddListener(mock_listener1); security_manager_->AddListener(mock_listener2); // 1st call - security_manager_->NotifyListenersOnHandshakeDone(key, first_call_value); + security_manager_->NotifyListenersOnHandshakeDone(kKey, first_call_value); security_manager_->NotifyOnCertificateUpdateRequired(); // 2nd call - security_manager_->NotifyListenersOnHandshakeDone(key, second_call_value); + security_manager_->NotifyListenersOnHandshakeDone(kKey, second_call_value); security_manager_->NotifyOnCertificateUpdateRequired(); // 3nd call security_manager_->NotifyListenersOnHandshakeDone( - key, SSLContext::Handshake_Result_Fail); + kKey, SSLContext::Handshake_Result_Fail); security_manager_->NotifyOnCertificateUpdateRequired(); } @@ -275,7 +282,7 @@ TEST_F(SecurityManagerTest, SecurityManager_NULLCryptoManager) { uint8_t session_id = 0; TestAsyncWaiter waiter; - EXPECT_CALL(mock_session_observer, PairFromKey(key, _, _)); + EXPECT_CALL(mock_session_observer, PairFromKey(kKey, _, _)); EXPECT_CALL(mock_session_observer, ProtocolVersionUsed(connection_id, session_id, _)) .WillOnce(Return(true)); @@ -283,7 +290,7 @@ TEST_F(SecurityManagerTest, SecurityManager_NULLCryptoManager) { EXPECT_CALL(mock_protocol_handler, SendMessageToMobileApp( InternalErrorWithErrId(SecurityManager::ERROR_NOT_SUPPORTED), - is_final)).WillOnce(NotifyTestAsyncWaiter(&waiter)); + kIsFinal)).WillOnce(NotifyTestAsyncWaiter(&waiter)); const SecurityQuery::QueryHeader header(SecurityQuery::REQUEST, // It could be any query id SecurityQuery::INVALID_QUERY_ID); @@ -298,7 +305,7 @@ TEST_F(SecurityManagerTest, SecurityManager_NULLCryptoManager) { TEST_F(SecurityManagerTest, OnMobileMessageSent) { const uint8_t* data_param = NULL; const RawMessagePtr rawMessagePtr( - utils::MakeShared<RawMessage>(key, protocolVersion, data_param, 0)); + utils::MakeShared<RawMessage>(kKey, kProtocolVersion, data_param, 0)); security_manager_->OnMobileMessageSent(rawMessagePtr); } /* @@ -319,7 +326,7 @@ TEST_F(SecurityManagerTest, GetEmptyQuery) { uint32_t connection_id = 0; uint8_t session_id = 0; // uint8_t protocol_version = 0; - EXPECT_CALL(mock_session_observer, PairFromKey(key, _, _)); + EXPECT_CALL(mock_session_observer, PairFromKey(kKey, _, _)); EXPECT_CALL(mock_session_observer, ProtocolVersionUsed(connection_id, session_id, _)) .WillOnce(Return(true)); @@ -328,9 +335,9 @@ TEST_F(SecurityManagerTest, GetEmptyQuery) { mock_protocol_handler, SendMessageToMobileApp( InternalErrorWithErrId(SecurityManager::ERROR_INVALID_QUERY_SIZE), - is_final)); + kIsFinal)); // Call with NULL data - call_OnMessageReceived(NULL, 0, secureServiceType); + call_OnMessageReceived(NULL, 0, kSecureServiceType); } /* * Shall send InternallError on null data recieved @@ -340,7 +347,7 @@ TEST_F(SecurityManagerTest, GetWrongJSONSize) { uint32_t connection_id = 0; uint8_t session_id = 0; // uint8_t protocol_version = 0; - EXPECT_CALL(mock_session_observer, PairFromKey(key, _, _)); + EXPECT_CALL(mock_session_observer, PairFromKey(kKey, _, _)); EXPECT_CALL(mock_session_observer, ProtocolVersionUsed(connection_id, session_id, _)) .WillOnce(Return(true)); @@ -349,7 +356,7 @@ TEST_F(SecurityManagerTest, GetWrongJSONSize) { mock_protocol_handler, SendMessageToMobileApp( InternalErrorWithErrId(SecurityManager::ERROR_INVALID_QUERY_SIZE), - is_final)); + kIsFinal)); SecurityQuery::QueryHeader header(SecurityQuery::REQUEST, SecurityQuery::INVALID_QUERY_ID); header.json_size = 0x0FFFFFFF; @@ -365,7 +372,7 @@ TEST_F(SecurityManagerTest, GetInvalidQueryId) { TestAsyncWaiter waiter; uint32_t times = 0; - EXPECT_CALL(mock_session_observer, PairFromKey(key, _, _)) + EXPECT_CALL(mock_session_observer, PairFromKey(kKey, _, _)) .WillOnce(NotifyTestAsyncWaiter(&waiter)); times++; EXPECT_CALL(mock_session_observer, @@ -378,7 +385,7 @@ TEST_F(SecurityManagerTest, GetInvalidQueryId) { mock_protocol_handler, SendMessageToMobileApp( InternalErrorWithErrId(SecurityManager::ERROR_INVALID_QUERY_ID), - is_final)).WillOnce(NotifyTestAsyncWaiter(&waiter)); + kIsFinal)).WillOnce(NotifyTestAsyncWaiter(&waiter)); times++; const SecurityQuery::QueryHeader header(SecurityQuery::REQUEST, SecurityQuery::INVALID_QUERY_ID); @@ -395,10 +402,12 @@ TEST_F(SecurityManagerTest, CreateSSLContext_ServiceAlreadyProtected) { SetMockCryptoManager(); // Return mock SSLContext - EXPECT_CALL(mock_session_observer, GetSSLContext(key, kControl)) + EXPECT_CALL(mock_session_observer, GetSSLContext(kKey, kControl)) .WillOnce(Return(&mock_ssl_context_new)); - const SSLContext* result = security_manager_->CreateSSLContext(key); + const SSLContext* result = security_manager_->CreateSSLContext( + kKey, + security_manager::SecurityManager::ContextCreationStrategy::kUseExisting); EXPECT_EQ(&mock_ssl_context_new, result); } /* @@ -410,21 +419,23 @@ TEST_F(SecurityManagerTest, CreateSSLContext_ErrorCreateSSL) { uint32_t connection_id = 0; uint8_t session_id = 0; // uint8_t protocol_version = 0; - EXPECT_CALL(mock_session_observer, PairFromKey(key, _, _)); + EXPECT_CALL(mock_session_observer, PairFromKey(kKey, _, _)); EXPECT_CALL(mock_session_observer, ProtocolVersionUsed(connection_id, session_id, _)) .WillOnce(Return(true)); EXPECT_CALL( mock_protocol_handler, SendMessageToMobileApp( - InternalErrorWithErrId(SecurityManager::ERROR_INTERNAL), is_final)); + InternalErrorWithErrId(SecurityManager::ERROR_INTERNAL), kIsFinal)); // Emulate SessionObserver and CryptoManager result - EXPECT_CALL(mock_session_observer, GetSSLContext(key, kControl)) + EXPECT_CALL(mock_session_observer, GetSSLContext(kKey, kControl)) .WillOnce(ReturnNull()); EXPECT_CALL(mock_crypto_manager, CreateSSLContext()).WillOnce(ReturnNull()); - const SSLContext* result = security_manager_->CreateSSLContext(key); + const SSLContext* result = security_manager_->CreateSSLContext( + kKey, + security_manager::SecurityManager::ContextCreationStrategy::kUseExisting); EXPECT_EQ(NULL, result); } /* @@ -437,7 +448,7 @@ TEST_F(SecurityManagerTest, CreateSSLContext_SetSSLContextError) { uint32_t connection_id = 0; uint8_t session_id = 0; // uint8_t protocol_version = 0; - EXPECT_CALL(mock_session_observer, PairFromKey(key, _, _)); + EXPECT_CALL(mock_session_observer, PairFromKey(kKey, _, _)); EXPECT_CALL(mock_session_observer, ProtocolVersionUsed(connection_id, session_id, _)) .WillOnce(Return(true)); @@ -446,18 +457,20 @@ TEST_F(SecurityManagerTest, CreateSSLContext_SetSSLContextError) { mock_protocol_handler, SendMessageToMobileApp( InternalErrorWithErrId(SecurityManager::ERROR_UNKNOWN_INTERNAL_ERROR), - is_final)); + kIsFinal)); // Emulate SessionObserver and CryptoManager result - EXPECT_CALL(mock_session_observer, GetSSLContext(key, kControl)) + EXPECT_CALL(mock_session_observer, GetSSLContext(kKey, kControl)) .WillOnce(ReturnNull()); EXPECT_CALL(mock_crypto_manager, CreateSSLContext()) .WillOnce(Return(&mock_ssl_context_new)); EXPECT_CALL(mock_crypto_manager, ReleaseSSLContext(&mock_ssl_context_new)); - EXPECT_CALL(mock_session_observer, SetSSLContext(key, &mock_ssl_context_new)) + EXPECT_CALL(mock_session_observer, SetSSLContext(kKey, &mock_ssl_context_new)) .WillOnce(Return(SecurityManager::ERROR_UNKNOWN_INTERNAL_ERROR)); - const SSLContext* result = security_manager_->CreateSSLContext(key); + const SSLContext* result = security_manager_->CreateSSLContext( + kKey, + security_manager::SecurityManager::ContextCreationStrategy::kUseExisting); EXPECT_EQ(NULL, result); } /* @@ -469,17 +482,17 @@ TEST_F(SecurityManagerTest, CreateSSLContext_Success) { // Expect no notifying listeners - it will be done after handshake // Emulate SessionObserver and CryptoManager result - EXPECT_CALL(mock_session_observer, GetSSLContext(key, kControl)) - .WillOnce(ReturnNull()) - . - // additional check for debug code - WillOnce(Return(&mock_ssl_context_exists)); + EXPECT_CALL(mock_session_observer, GetSSLContext(kKey, kControl)) + .WillOnce(Return(&mock_ssl_context_exists)); EXPECT_CALL(mock_crypto_manager, CreateSSLContext()) .WillOnce(Return(&mock_ssl_context_new)); - EXPECT_CALL(mock_session_observer, SetSSLContext(key, &mock_ssl_context_new)) + EXPECT_CALL(mock_session_observer, SetSSLContext(kKey, &mock_ssl_context_new)) .WillOnce(Return(SecurityManager::ERROR_SUCCESS)); - const SSLContext* result = security_manager_->CreateSSLContext(key); + const SSLContext* result = security_manager_->CreateSSLContext( + kKey, + security_manager::SecurityManager::ContextCreationStrategy:: + kForceRecreation); EXPECT_EQ(&mock_ssl_context_new, result); } /* @@ -490,7 +503,7 @@ TEST_F(SecurityManagerTest, StartHandshake_ServiceStillUnprotected) { uint32_t connection_id = 0; uint8_t session_id = 0; // uint8_t protocol_version = 0; - EXPECT_CALL(mock_session_observer, PairFromKey(key, _, _)); + EXPECT_CALL(mock_session_observer, PairFromKey(kKey, _, _)); EXPECT_CALL(mock_session_observer, ProtocolVersionUsed(connection_id, session_id, _)) .WillOnce(Return(true)); @@ -498,17 +511,17 @@ TEST_F(SecurityManagerTest, StartHandshake_ServiceStillUnprotected) { EXPECT_CALL( mock_protocol_handler, SendMessageToMobileApp( - InternalErrorWithErrId(SecurityManager::ERROR_INTERNAL), is_final)); + InternalErrorWithErrId(SecurityManager::ERROR_INTERNAL), kIsFinal)); // Expect notifying listeners (unsuccess) EXPECT_CALL(*mock_sm_listener, - OnHandshakeDone(key, SSLContext::Handshake_Result_Fail)) + OnHandshakeDone(kKey, SSLContext::Handshake_Result_Fail)) .WillOnce(Return(true)); // Emulate SessionObserver result - EXPECT_CALL(mock_session_observer, GetSSLContext(key, kControl)) + EXPECT_CALL(mock_session_observer, GetSSLContext(kKey, kControl)) .WillOnce(ReturnNull()); - security_manager_->StartHandshake(key); + security_manager_->StartHandshake(kKey); // Listener was destroyed after OnHandshakeDone call mock_sm_listener.release(); @@ -521,109 +534,27 @@ TEST_F(SecurityManagerTest, StartHandshake_SSLInternalError) { uint32_t connection_id = 0; uint8_t session_id = 0; - // uint8_t protocol_version = 0; - EXPECT_CALL(mock_session_observer, PairFromKey(key, _, _)); - EXPECT_CALL(mock_session_observer, GetHandshakeContext(key)) - .WillOnce(Return(SSLContext::HandshakeContext())); + + EXPECT_CALL(mock_session_observer, PairFromKey(kKey, _, _)); EXPECT_CALL(mock_session_observer, ProtocolVersionUsed(connection_id, session_id, _)) .WillOnce(Return(true)); - + // Expect notifying listeners (unsuccess) + EXPECT_CALL(*mock_sm_listener, + OnHandshakeDone(kKey, SSLContext::Handshake_Result_Fail)) + .WillOnce(Return(true)); + EXPECT_CALL(mock_session_observer, GetSSLContext(kKey, kControl)) + .WillOnce(ReturnNull()); // Expect InternalError with ERROR_ID EXPECT_CALL( mock_protocol_handler, SendMessageToMobileApp( - InternalErrorWithErrId(SecurityManager::ERROR_INTERNAL), is_final)); - // Expect notifying listeners (unsuccess) - EXPECT_CALL(*mock_sm_listener, - OnHandshakeDone(key, SSLContext::Handshake_Result_Fail)) - .WillOnce(Return(true)); + InternalErrorWithErrId(SecurityManager::ERROR_INTERNAL), kIsFinal)); - // Emulate SessionObserver result - EXPECT_CALL(mock_session_observer, GetSSLContext(key, kControl)) - .WillOnce(Return(&mock_ssl_context_exists)); - EXPECT_CALL(mock_ssl_context_exists, IsInitCompleted()) - .WillOnce(Return(false)); - EXPECT_CALL(mock_ssl_context_exists, SetHandshakeContext(_)); - EXPECT_CALL(mock_ssl_context_exists, StartHandshake(_, _)) - .WillOnce(DoAll(SetArgPointee<0>(handshake_data_out_pointer), - SetArgPointee<1>(handshake_data_out_size), - Return(SSLContext::Handshake_Result_Fail))); - - security_manager_->StartHandshake(key); - - // Listener was destroyed after OnHandshakeDone call + security_manager_->StartHandshake(kKey); mock_sm_listener.release(); } -/* - * Shall send data on call StartHandshake - */ -TEST_F(SecurityManagerTest, StartHandshake_SSLInitIsNotComplete) { - SetMockCryptoManager(); - uint32_t connection_id = 0; - uint8_t session_id = 0; - // uint8_t protocol_version = 0; - EXPECT_CALL(mock_session_observer, PairFromKey(key, _, _)); - EXPECT_CALL(mock_session_observer, GetHandshakeContext(key)) - .Times(3) - .WillRepeatedly(Return(SSLContext::HandshakeContext())); - EXPECT_CALL(mock_session_observer, - ProtocolVersionUsed(connection_id, session_id, _)) - .WillOnce(Return(true)); - - // Expect send one message (with correct pointer and size data) - EXPECT_CALL(mock_protocol_handler, SendMessageToMobileApp(_, is_final)); - - // Return mock SSLContext - EXPECT_CALL(mock_session_observer, GetSSLContext(key, kControl)) - .Times(3) - .WillRepeatedly(Return(&mock_ssl_context_exists)); - // Expect initialization check on each call StartHandshake - EXPECT_CALL(mock_ssl_context_exists, IsInitCompleted()) - .Times(3) - .WillRepeatedly(Return(false)); - EXPECT_CALL(mock_ssl_context_exists, SetHandshakeContext(_)).Times(3); - - // Emulate SSLContext::StartHandshake with different parameters - // Only on both correct - data and size shall be send message to mobile app - EXPECT_CALL(mock_ssl_context_exists, StartHandshake(_, _)) - .WillOnce(DoAll(SetArgPointee<0>(handshake_data_out_pointer), - SetArgPointee<1>(0), - Return(SSLContext::Handshake_Result_Success))) - .WillOnce(DoAll(SetArgPointee<0>((uint8_t*)NULL), - SetArgPointee<1>(handshake_data_out_size), - Return(SSLContext::Handshake_Result_Success))) - .WillOnce(DoAll(SetArgPointee<0>(handshake_data_out_pointer), - SetArgPointee<1>(handshake_data_out_size), - Return(SSLContext::Handshake_Result_Success))); - security_manager_->StartHandshake(key); - security_manager_->StartHandshake(key); - security_manager_->StartHandshake(key); -} -/* - * Shall notify listeners on call StartHandshake after SSLContext initialization - * complete - */ -TEST_F(SecurityManagerTest, StartHandshake_SSLInitIsComplete) { - SetMockCryptoManager(); - // Expect no message send - // Expect notifying listeners (success) - EXPECT_CALL(*mock_sm_listener, - OnHandshakeDone(key, SSLContext::Handshake_Result_Success)) - .WillOnce(Return(true)); - - // Emulate SessionObserver result - EXPECT_CALL(mock_session_observer, GetSSLContext(key, kControl)) - .WillOnce(Return(&mock_ssl_context_exists)); - EXPECT_CALL(mock_ssl_context_exists, IsInitCompleted()) - .WillOnce(Return(true)); - - security_manager_->StartHandshake(key); - - // Listener was destroyed after OnHandshakeDone call - mock_sm_listener.release(); -} /* * Shall send InternallError on * getting SEND_HANDSHAKE_DATA with NULL data @@ -634,7 +565,7 @@ TEST_F(SecurityManagerTest, ProccessHandshakeData_WrongDataSize) { uint8_t session_id = 0; TestAsyncWaiter waiter; - EXPECT_CALL(mock_session_observer, PairFromKey(key, _, _)); + EXPECT_CALL(mock_session_observer, PairFromKey(kKey, _, _)); EXPECT_CALL(mock_session_observer, ProtocolVersionUsed(connection_id, session_id, _)) .WillOnce(Return(true)); @@ -644,7 +575,7 @@ TEST_F(SecurityManagerTest, ProccessHandshakeData_WrongDataSize) { mock_protocol_handler, SendMessageToMobileApp( InternalErrorWithErrId(SecurityManager::ERROR_INVALID_QUERY_SIZE), - is_final)).WillOnce(NotifyTestAsyncWaiter(&waiter)); + kIsFinal)).WillOnce(NotifyTestAsyncWaiter(&waiter)); EmulateMobileMessageHandshake(NULL, 0); @@ -664,7 +595,7 @@ TEST_F(SecurityManagerTest, TestAsyncWaiter waiter; uint32_t times = 0; - EXPECT_CALL(mock_session_observer, PairFromKey(key, _, _)) + EXPECT_CALL(mock_session_observer, PairFromKey(kKey, _, _)) .WillOnce(NotifyTestAsyncWaiter(&waiter)); times++; EXPECT_CALL(mock_session_observer, @@ -675,17 +606,17 @@ TEST_F(SecurityManagerTest, mock_protocol_handler, SendMessageToMobileApp( InternalErrorWithErrId(SecurityManager::ERROR_SERVICE_NOT_PROTECTED), - is_final)).WillOnce(NotifyTestAsyncWaiter(&waiter)); + kIsFinal)).WillOnce(NotifyTestAsyncWaiter(&waiter)); times++; // Expect notifying listeners (unsuccess) EXPECT_CALL(*mock_sm_listener, - OnHandshakeDone(key, SSLContext::Handshake_Result_Fail)) + OnHandshakeDone(kKey, SSLContext::Handshake_Result_Fail)) .WillOnce(DoAll(NotifyTestAsyncWaiter(&waiter), Return(true))); times++; // Emulate SessionObserver result - EXPECT_CALL(mock_session_observer, GetSSLContext(key, kControl)) + EXPECT_CALL(mock_session_observer, GetSSLContext(kKey, kControl)) .WillOnce(DoAll(NotifyTestAsyncWaiter(&waiter), ReturnNull())); times++; @@ -713,7 +644,7 @@ TEST_F(SecurityManagerTest, ProccessHandshakeData_InvalidData) { TestAsyncWaiter waiter; uint32_t times = 0; - EXPECT_CALL(mock_session_observer, PairFromKey(key, _, _)) + EXPECT_CALL(mock_session_observer, PairFromKey(kKey, _, _)) .Times(handshake_emulates) .WillRepeatedly(NotifyTestAsyncWaiter(&waiter)); times += handshake_emulates; @@ -728,18 +659,18 @@ TEST_F(SecurityManagerTest, ProccessHandshakeData_InvalidData) { mock_protocol_handler, SendMessageToMobileApp( InternalErrorWithErrId(SecurityManager::ERROR_SSL_INVALID_DATA), - is_final)) + kIsFinal)) .Times(handshake_emulates) .WillRepeatedly(NotifyTestAsyncWaiter(&waiter)); times += handshake_emulates; // Expect notifying listeners (unsuccess) EXPECT_CALL(*mock_sm_listener, - OnHandshakeDone(key, SSLContext::Handshake_Result_Fail)) + OnHandshakeDone(kKey, SSLContext::Handshake_Result_Fail)) .WillOnce(DoAll(NotifyTestAsyncWaiter(&waiter), Return(true))); times++; // Emulate SessionObserver and CryptoManager result - EXPECT_CALL(mock_session_observer, GetSSLContext(key, kControl)) + EXPECT_CALL(mock_session_observer, GetSSLContext(kKey, kControl)) .Times(handshake_emulates) .WillRepeatedly(Return(&mock_ssl_context_exists)); @@ -794,7 +725,7 @@ TEST_F(SecurityManagerTest, ProccessHandshakeData_Answer) { TestAsyncWaiter waiter; uint32_t times = 0; - EXPECT_CALL(mock_session_observer, PairFromKey(key, _, _)) + EXPECT_CALL(mock_session_observer, PairFromKey(kKey, _, _)) .Times(handshake_emulates) .WillRepeatedly(NotifyTestAsyncWaiter(&waiter)); times += handshake_emulates; @@ -808,14 +739,14 @@ TEST_F(SecurityManagerTest, ProccessHandshakeData_Answer) { const size_t raw_message_size = 15; EXPECT_CALL( mock_protocol_handler, - SendMessageToMobileApp(RawMessageEqSize(raw_message_size), is_final)) + SendMessageToMobileApp(RawMessageEqSize(raw_message_size), kIsFinal)) .Times(handshake_emulates) .WillRepeatedly(NotifyTestAsyncWaiter(&waiter)); times += handshake_emulates; // Expect notifying listeners (unsuccess) EXPECT_CALL(*mock_sm_listener, - OnHandshakeDone(key, SSLContext::Handshake_Result_Fail)) + OnHandshakeDone(kKey, SSLContext::Handshake_Result_Fail)) .WillOnce(DoAll(NotifyTestAsyncWaiter(&waiter), Return(true))); times++; @@ -824,7 +755,7 @@ TEST_F(SecurityManagerTest, ProccessHandshakeData_Answer) { .Times(handshake_emulates) .WillRepeatedly(DoAll(NotifyTestAsyncWaiter(&waiter), Return(false))); times += handshake_emulates; - EXPECT_CALL(mock_session_observer, GetSSLContext(key, kControl)) + EXPECT_CALL(mock_session_observer, GetSSLContext(kKey, kControl)) .Times(handshake_emulates) .WillRepeatedly(DoAll(NotifyTestAsyncWaiter(&waiter), Return(&mock_ssl_context_exists))); @@ -870,12 +801,12 @@ TEST_F(SecurityManagerTest, ProccessHandshakeData_HandshakeFinished) { // Expect no errors // Expect notifying listeners (success) EXPECT_CALL(*mock_sm_listener, - OnHandshakeDone(key, SSLContext::Handshake_Result_Success)) + OnHandshakeDone(kKey, SSLContext::Handshake_Result_Success)) .WillOnce(DoAll(NotifyTestAsyncWaiter(&waiter), Return(true))); times++; // Emulate SessionObserver and CryptoManager result - EXPECT_CALL(mock_session_observer, GetSSLContext(key, kControl)) + EXPECT_CALL(mock_session_observer, GetSSLContext(kKey, kControl)) .Times(handshake_emulates) .WillRepeatedly(DoAll(NotifyTestAsyncWaiter(&waiter), Return(&mock_ssl_context_exists))); @@ -928,14 +859,14 @@ TEST_F(SecurityManagerTest, ProccessHandshakeData_HandshakeFinished) { uint32_t connection_id = 0; uint8_t session_id = 0; // uint8_t protocol_version = 0; - EXPECT_CALL(mock_session_observer, PairFromKey(key, _, _)).Times(2); + EXPECT_CALL(mock_session_observer, PairFromKey(kKey, _, _)).Times(2); EXPECT_CALL(mock_session_observer, ProtocolVersionUsed(connection_id, session_id, _)) .Times(2) .WillRepeatedly(DoAll(NotifyTestAsyncWaiter(&waiter), Return(true))); times += 2; // matches to the number above - EXPECT_CALL(mock_protocol_handler, SendMessageToMobileApp(_, is_final)) + EXPECT_CALL(mock_protocol_handler, SendMessageToMobileApp(_, kIsFinal)) .Times(2) .WillRepeatedly(NotifyTestAsyncWaiter(&waiter)); times += 2; // matches to the number above diff --git a/src/components/security_manager/test/ssl_certificate_handshake_test.cc b/src/components/security_manager/test/ssl_certificate_handshake_test.cc index dc335c8da2..83ffa33b44 100644 --- a/src/components/security_manager/test/ssl_certificate_handshake_test.cc +++ b/src/components/security_manager/test/ssl_certificate_handshake_test.cc @@ -56,6 +56,10 @@ namespace custom_str = utils::custom_string; namespace { const std::string server_ca_cert_filename = "server"; const std::string client_ca_cert_filename = "client"; +const std::string client_cert_filename = "client.crt"; +const std::string server_cert_filename = "server.crt"; +const std::string client_key_filename = "client_private.key"; +const std::string server_key_filename = "server_private.key"; const std::string client_certificate = "client/client_credential.pem"; const std::string server_certificate = "server/spt_credential.pem"; const std::string server_unsigned_cert_file = @@ -66,36 +70,42 @@ const std::string server_expired_cert_file = const bool verify_peer = true; const bool skip_peer_verification = false; -const size_t updates_before_hour = 24; - } // namespace +struct Protocol { + security_manager::Protocol server_protocol; + security_manager::Protocol client_protocol; + + Protocol(security_manager::Protocol s_protocol, + security_manager::Protocol c_protocol) + : server_protocol(s_protocol), client_protocol(c_protocol) {} +}; -class SSLHandshakeTest : public testing::Test { +class SSLHandshakeTest : public testing::TestWithParam<Protocol> { protected: void SetUp() OVERRIDE { - mock_server_manager_settings = new testing::NiceMock< + mock_server_manager_settings_ = new testing::NiceMock< security_manager_test::MockCryptoManagerSettings>(); - server_manager = new security_manager::CryptoManagerImpl( + server_manager_ = new security_manager::CryptoManagerImpl( utils::SharedPtr<security_manager::CryptoManagerSettings>( - mock_server_manager_settings)); - ASSERT_TRUE(server_manager); - mock_client_manager_settings = new testing::NiceMock< + mock_server_manager_settings_)); + ASSERT_TRUE(server_manager_); + mock_client_manager_settings_ = new testing::NiceMock< security_manager_test::MockCryptoManagerSettings>(); - client_manager = new security_manager::CryptoManagerImpl( + client_manager_ = new security_manager::CryptoManagerImpl( utils::SharedPtr<security_manager::CryptoManagerSettings>( - mock_client_manager_settings)); - ASSERT_TRUE(client_manager); - server_ctx = NULL; - client_ctx = NULL; + mock_client_manager_settings_)); + ASSERT_TRUE(client_manager_); + server_ctx_ = NULL; + client_ctx_ = NULL; } void TearDown() OVERRIDE { - server_manager->ReleaseSSLContext(server_ctx); - delete server_manager; - client_manager->ReleaseSSLContext(client_ctx); - delete client_manager; + server_manager_->ReleaseSSLContext(server_ctx_); + delete server_manager_; + client_manager_->ReleaseSSLContext(client_ctx_); + delete client_manager_; } void SetServerInitialValues(const security_manager::Protocol protocol, @@ -106,18 +116,25 @@ class SSLHandshakeTest : public testing::Test { server_certificate_ = cert; server_ciphers_list_ = server_ciphers_list; server_ca_certificate_path_ = ca_certificate_path; - - ON_CALL(*mock_server_manager_settings, security_manager_mode()) + ON_CALL(*mock_server_manager_settings_, force_unprotected_service()) + .WillByDefault(ReturnRef(forced_unprotected_service_)); + ON_CALL(*mock_server_manager_settings_, force_protected_service()) + .WillByDefault(ReturnRef(forced_protected_service_)); + ON_CALL(*mock_server_manager_settings_, security_manager_mode()) .WillByDefault(Return(security_manager::SERVER)); - ON_CALL(*mock_server_manager_settings, security_manager_protocol_name()) + ON_CALL(*mock_server_manager_settings_, security_manager_protocol_name()) .WillByDefault(Return(protocol)); - ON_CALL(*mock_server_manager_settings, certificate_data()) + ON_CALL(*mock_server_manager_settings_, certificate_data()) .WillByDefault(ReturnRef(server_certificate_)); - ON_CALL(*mock_server_manager_settings, ciphers_list()) + ON_CALL(*mock_server_manager_settings_, ciphers_list()) .WillByDefault(ReturnRef(server_ciphers_list_)); - ON_CALL(*mock_server_manager_settings, ca_cert_path()) + ON_CALL(*mock_server_manager_settings_, ca_cert_path()) .WillByDefault(ReturnRef(server_ca_certificate_path_)); - ON_CALL(*mock_server_manager_settings, verify_peer()) + ON_CALL(*mock_server_manager_settings_, module_cert_path()) + .WillByDefault(ReturnRef(server_cert_filename)); + ON_CALL(*mock_server_manager_settings_, module_key_path()) + .WillByDefault(ReturnRef(server_key_filename)); + ON_CALL(*mock_server_manager_settings_, verify_peer()) .WillByDefault(Return(verify_peer)); } void SetClientInitialValues(const security_manager::Protocol protocol, @@ -129,17 +146,25 @@ class SSLHandshakeTest : public testing::Test { client_ciphers_list_ = client_ciphers_list; client_ca_certificate_path_ = ca_certificate_path; - ON_CALL(*mock_client_manager_settings, security_manager_mode()) + ON_CALL(*mock_client_manager_settings_, force_unprotected_service()) + .WillByDefault(ReturnRef(forced_unprotected_service_)); + ON_CALL(*mock_client_manager_settings_, force_protected_service()) + .WillByDefault(ReturnRef(forced_protected_service_)); + ON_CALL(*mock_client_manager_settings_, security_manager_mode()) .WillByDefault(Return(security_manager::CLIENT)); - ON_CALL(*mock_client_manager_settings, security_manager_protocol_name()) + ON_CALL(*mock_client_manager_settings_, security_manager_protocol_name()) .WillByDefault(Return(protocol)); - ON_CALL(*mock_client_manager_settings, certificate_data()) + ON_CALL(*mock_client_manager_settings_, certificate_data()) .WillByDefault(ReturnRef(client_certificate_)); - ON_CALL(*mock_client_manager_settings, ciphers_list()) + ON_CALL(*mock_client_manager_settings_, ciphers_list()) .WillByDefault(ReturnRef(client_ciphers_list_)); - ON_CALL(*mock_client_manager_settings, ca_cert_path()) + ON_CALL(*mock_client_manager_settings_, ca_cert_path()) .WillByDefault(ReturnRef(client_ca_certificate_path_)); - ON_CALL(*mock_client_manager_settings, verify_peer()) + ON_CALL(*mock_client_manager_settings_, module_cert_path()) + .WillByDefault(ReturnRef(client_cert_filename)); + ON_CALL(*mock_client_manager_settings_, module_key_path()) + .WillByDefault(ReturnRef(client_key_filename)); + ON_CALL(*mock_client_manager_settings_, verify_peer()) .WillByDefault(Return(verify_peer)); } @@ -156,19 +181,19 @@ class SSLHandshakeTest : public testing::Test { cert.close(); SetServerInitialValues( protocol, ss.str(), ciphers_list, verify_peer, ca_certificate_path); - const bool initialized = server_manager->Init(); + const bool initialized = server_manager_->Init(); if (!initialized) { return false; } - server_ctx = server_manager->CreateSSLContext(); + server_ctx_ = server_manager_->CreateSSLContext(); - if (!server_ctx) { + if (!server_ctx_) { return false; } - server_ctx->SetHandshakeContext( + server_ctx_->SetHandshakeContext( security_manager::SSLContext::HandshakeContext( custom_str::CustomString("SPT"), custom_str::CustomString("client"))); @@ -192,17 +217,17 @@ class SSLHandshakeTest : public testing::Test { ciphers_list, verify_peer, ca_certificate_path); - const bool initialized = client_manager->Init(); + const bool initialized = client_manager_->Init(); if (!initialized) { return false; } - client_ctx = client_manager->CreateSSLContext(); - if (!client_ctx) { + client_ctx_ = client_manager_->CreateSSLContext(); + if (!client_ctx_) { return false; } - client_ctx->SetHandshakeContext( + client_ctx_->SetHandshakeContext( security_manager::SSLContext::HandshakeContext( custom_str::CustomString("SPT"), custom_str::CustomString("server"))); @@ -211,17 +236,17 @@ class SSLHandshakeTest : public testing::Test { } void ResetConnections() { - ASSERT_NO_THROW(server_ctx->ResetConnection()); - ASSERT_NO_THROW(client_ctx->ResetConnection()); + ASSERT_NO_THROW(server_ctx_->ResetConnection()); + ASSERT_NO_THROW(client_ctx_->ResetConnection()); } void StartHandshake() { using security_manager::SSLContext; ASSERT_EQ(SSLContext::Handshake_Result_Success, - client_ctx->StartHandshake(&client_buf, &client_buf_len)); - ASSERT_FALSE(client_buf == NULL); - ASSERT_GT(client_buf_len, 0u); + client_ctx_->StartHandshake(&client_buf_, &client_buf_len_)); + ASSERT_FALSE(client_buf_ == NULL); + ASSERT_GT(client_buf_len_, 0u); } void HandshakeProcedure_Success() { @@ -229,23 +254,25 @@ class SSLHandshakeTest : public testing::Test { StartHandshake(); while (true) { - ASSERT_EQ(SSLContext::Handshake_Result_Success, - server_ctx->DoHandshakeStep( - client_buf, client_buf_len, &server_buf, &server_buf_len)) + ASSERT_EQ( + SSLContext::Handshake_Result_Success, + server_ctx_->DoHandshakeStep( + client_buf_, client_buf_len_, &server_buf_, &server_buf_len_)) << ERR_reason_error_string(ERR_get_error()); - ASSERT_FALSE(server_buf == NULL); - ASSERT_GT(server_buf_len, 0u); + ASSERT_FALSE(server_buf_ == NULL); + ASSERT_GT(server_buf_len_, 0u); - ASSERT_EQ(SSLContext::Handshake_Result_Success, - client_ctx->DoHandshakeStep( - server_buf, server_buf_len, &client_buf, &client_buf_len)) + ASSERT_EQ( + SSLContext::Handshake_Result_Success, + client_ctx_->DoHandshakeStep( + server_buf_, server_buf_len_, &client_buf_, &client_buf_len_)) << ERR_reason_error_string(ERR_get_error()); - if (server_ctx->IsInitCompleted()) { + if (server_ctx_->IsInitCompleted()) { break; } - ASSERT_FALSE(client_buf == NULL); - ASSERT_GT(client_buf_len, 0u); + ASSERT_FALSE(client_buf_ == NULL); + ASSERT_GT(client_buf_len_, 0u); } } @@ -255,9 +282,9 @@ class SSLHandshakeTest : public testing::Test { StartHandshake(); while (true) { - const SSLContext::HandshakeResult result = server_ctx->DoHandshakeStep( - client_buf, client_buf_len, &server_buf, &server_buf_len); - ASSERT_FALSE(server_ctx->IsInitCompleted()) + const SSLContext::HandshakeResult result = server_ctx_->DoHandshakeStep( + client_buf_, client_buf_len_, &server_buf_, &server_buf_len_); + ASSERT_FALSE(server_ctx_->IsInitCompleted()) << "Expected server side handshake fail"; // First few handshake will be successful @@ -265,18 +292,19 @@ class SSLHandshakeTest : public testing::Test { // Test successfully passed with handshake fail return; } - ASSERT_FALSE(server_buf == NULL); - ASSERT_GT(server_buf_len, 0u); + ASSERT_FALSE(server_buf_ == NULL); + ASSERT_GT(server_buf_len_, 0u); - ASSERT_EQ(SSLContext::Handshake_Result_Success, - client_ctx->DoHandshakeStep( - server_buf, server_buf_len, &client_buf, &client_buf_len)) + ASSERT_EQ( + SSLContext::Handshake_Result_Success, + client_ctx_->DoHandshakeStep( + server_buf_, server_buf_len_, &client_buf_, &client_buf_len_)) << ERR_reason_error_string(ERR_get_error()); - ASSERT_FALSE(client_ctx->IsInitCompleted()) + ASSERT_FALSE(client_ctx_->IsInitCompleted()) << "Expected server side handshake fail"; - ASSERT_FALSE(client_buf == NULL); - ASSERT_GT(client_buf_len, 0u); + ASSERT_FALSE(client_buf_ == NULL); + ASSERT_GT(client_buf_len_, 0u); } FAIL() << "Expected server side handshake fail"; } @@ -288,17 +316,18 @@ class SSLHandshakeTest : public testing::Test { StartHandshake(); while (true) { - ASSERT_EQ(SSLContext::Handshake_Result_Success, - server_ctx->DoHandshakeStep( - client_buf, client_buf_len, &server_buf, &server_buf_len)) + ASSERT_EQ( + SSLContext::Handshake_Result_Success, + server_ctx_->DoHandshakeStep( + client_buf_, client_buf_len_, &server_buf_, &server_buf_len_)) << ERR_reason_error_string(ERR_get_error()); - ASSERT_FALSE(server_buf == NULL); - ASSERT_GT(server_buf_len, 0u); + ASSERT_FALSE(server_buf_ == NULL); + ASSERT_GT(server_buf_len_, 0u); - const SSLContext::HandshakeResult result = client_ctx->DoHandshakeStep( - server_buf, server_buf_len, &client_buf, &client_buf_len); - ASSERT_FALSE(client_ctx->IsInitCompleted()) + const SSLContext::HandshakeResult result = client_ctx_->DoHandshakeStep( + server_buf_, server_buf_len_, &client_buf_, &client_buf_len_); + ASSERT_FALSE(client_ctx_->IsInitCompleted()) << "Expected client side handshake fail"; // First few handsahke will be successful @@ -308,25 +337,25 @@ class SSLHandshakeTest : public testing::Test { return; } - ASSERT_FALSE(client_buf == NULL); - ASSERT_GT(client_buf_len, 0u); + ASSERT_FALSE(client_buf_ == NULL); + ASSERT_GT(client_buf_len_, 0u); } FAIL() << "Expected client side handshake fail"; } - security_manager::CryptoManager* server_manager; - security_manager::CryptoManager* client_manager; - security_manager::SSLContext* server_ctx; - security_manager::SSLContext* client_ctx; + security_manager::CryptoManager* server_manager_; + security_manager::CryptoManager* client_manager_; + security_manager::SSLContext* server_ctx_; + security_manager::SSLContext* client_ctx_; testing::NiceMock<security_manager_test::MockCryptoManagerSettings>* - mock_server_manager_settings; + mock_server_manager_settings_; testing::NiceMock<security_manager_test::MockCryptoManagerSettings>* - mock_client_manager_settings; + mock_client_manager_settings_; - const uint8_t* server_buf; - const uint8_t* client_buf; - size_t server_buf_len; - size_t client_buf_len; + const uint8_t* server_buf_; + const uint8_t* client_buf_; + size_t server_buf_len_; + size_t client_buf_len_; std::string server_certificate_; std::string server_ciphers_list_; @@ -335,188 +364,175 @@ class SSLHandshakeTest : public testing::Test { std::string client_certificate_; std::string client_ciphers_list_; std::string client_ca_certificate_path_; + + const std::vector<int> forced_protected_service_; + const std::vector<int> forced_unprotected_service_; }; -TEST_F(SSLHandshakeTest, NoVerification) { - ASSERT_TRUE(InitServerManagers(security_manager::TLSv1_2, +INSTANTIATE_TEST_CASE_P( + CorrectProtocol, + SSLHandshakeTest, + ::testing::Values( + Protocol(security_manager::TLSv1, security_manager::TLSv1), + Protocol(security_manager::TLSv1_1, security_manager::TLSv1_1), + Protocol(security_manager::TLSv1_2, security_manager::TLSv1_2), + Protocol(security_manager::DTLSv1, security_manager::DTLSv1))); + +TEST_P(SSLHandshakeTest, NoVerification) { + ASSERT_TRUE(InitServerManagers(GetParam().server_protocol, server_certificate, "ALL", skip_peer_verification, "")) - << server_manager->LastError(); - ASSERT_TRUE(InitClientManagers(security_manager::TLSv1_2, + << server_manager_->LastError(); + + ASSERT_TRUE(InitClientManagers(GetParam().client_protocol, client_certificate, "ALL", skip_peer_verification, "")) - << client_manager->LastError(); + << client_manager_->LastError(); GTEST_TRACE(HandshakeProcedure_Success()); } -TEST_F(SSLHandshakeTest, CAVerification_ServerSide) { - ASSERT_TRUE(InitServerManagers(security_manager::TLSv1_2, +TEST_P(SSLHandshakeTest, CAVerification_ServerSide) { + ASSERT_TRUE(InitServerManagers(GetParam().server_protocol, server_certificate, "ALL", verify_peer, client_ca_cert_filename)) - << server_manager->LastError(); - ASSERT_TRUE(InitClientManagers(security_manager::TLSv1_2, + << server_manager_->LastError(); + ASSERT_TRUE(InitClientManagers(GetParam().client_protocol, client_certificate, "ALL", skip_peer_verification, "")) - << client_manager->LastError(); + << client_manager_->LastError(); GTEST_TRACE(HandshakeProcedure_Success()); } -TEST_F(SSLHandshakeTest, CAVerification_ServerSide_NoCACertificate) { +TEST_P(SSLHandshakeTest, CAVerification_ServerSide_NoCACertificate) { ASSERT_TRUE(InitServerManagers( - security_manager::TLSv1_2, "", "ALL", verify_peer, "unex")) - << server_manager->LastError(); - ASSERT_TRUE(InitClientManagers(security_manager::TLSv1_2, + GetParam().server_protocol, "", "ALL", verify_peer, "unex")) + << server_manager_->LastError(); + ASSERT_TRUE(InitClientManagers(GetParam().client_protocol, client_certificate, "ALL", skip_peer_verification, "")) - << client_manager->LastError(); + << client_manager_->LastError(); GTEST_TRACE(HandshakeProcedure_ServerSideFail()); - ASSERT_TRUE(InitServerManagers(security_manager::TLSv1_2, + ASSERT_TRUE(InitServerManagers(GetParam().server_protocol, server_certificate, "ALL", verify_peer, client_ca_cert_filename)) - << server_manager->LastError(); + << server_manager_->LastError(); GTEST_TRACE(ResetConnections()); GTEST_TRACE(HandshakeProcedure_Success()); } -TEST_F(SSLHandshakeTest, CAVerification_ClientSide) { - ASSERT_TRUE(InitServerManagers(security_manager::TLSv1_2, - server_certificate, - "ALL", - verify_peer, - client_ca_cert_filename)) - << server_manager->LastError(); - ASSERT_TRUE(InitClientManagers(security_manager::TLSv1_2, - client_certificate, - "ALL", - verify_peer, - server_ca_cert_filename)) - << client_manager->LastError(); - - GTEST_TRACE(HandshakeProcedure_Success()); -} - -TEST_F(SSLHandshakeTest, CAVerification_ClientSide_NoCACertificate) { - ASSERT_TRUE(InitServerManagers(security_manager::TLSv1_2, +TEST_P(SSLHandshakeTest, CAVerification_ClientSide_NoCACertificate) { + ASSERT_TRUE(InitServerManagers(GetParam().server_protocol, server_certificate, "ALL", skip_peer_verification, "")) - << server_manager->LastError(); - ASSERT_TRUE(InitClientManagers(security_manager::TLSv1_2, + << server_manager_->LastError(); + ASSERT_TRUE(InitClientManagers(GetParam().client_protocol, "", "ALL", verify_peer, "client_ca_cert_filename")) - << client_manager->LastError(); + << client_manager_->LastError(); GTEST_TRACE(HandshakeProcedure_ClientSideFail( security_manager::SSLContext::Handshake_Result_Fail)); - ASSERT_TRUE(InitClientManagers(security_manager::TLSv1_2, + ASSERT_TRUE(InitClientManagers(GetParam().client_protocol, client_certificate, "ALL", verify_peer, server_ca_cert_filename)) - << client_manager->LastError(); + << client_manager_->LastError(); GTEST_TRACE(ResetConnections()); GTEST_TRACE(HandshakeProcedure_Success()); } -TEST_F(SSLHandshakeTest, CAVerification_BothSides) { - ASSERT_TRUE(InitServerManagers(security_manager::TLSv1_2, +TEST_P(SSLHandshakeTest, CAVerification_BothSides) { + ASSERT_TRUE(InitServerManagers(GetParam().server_protocol, server_certificate, "ALL", verify_peer, client_ca_cert_filename)) - << server_manager->LastError(); - ASSERT_TRUE(InitClientManagers(security_manager::TLSv1_2, + << server_manager_->LastError(); + ASSERT_TRUE(InitClientManagers(GetParam().client_protocol, client_certificate, "ALL", verify_peer, server_ca_cert_filename)) - << client_manager->LastError(); + << client_manager_->LastError(); GTEST_TRACE(HandshakeProcedure_Success()); } -TEST_F(SSLHandshakeTest, UnsignedCert) { - ASSERT_TRUE(InitServerManagers(security_manager::TLSv1_2, +TEST_P(SSLHandshakeTest, UnsignedCert) { + ASSERT_TRUE(InitServerManagers(GetParam().server_protocol, server_unsigned_cert_file, "ALL", skip_peer_verification, "")) - << server_manager->LastError(); - ASSERT_TRUE(InitClientManagers(security_manager::TLSv1_2, + << server_manager_->LastError(); + ASSERT_TRUE(InitClientManagers(GetParam().client_protocol, client_certificate, "ALL", verify_peer, client_ca_cert_filename)) - << client_manager->LastError(); + << client_manager_->LastError(); GTEST_TRACE(HandshakeProcedure_ClientSideFail( security_manager::SSLContext::Handshake_Result_CertNotSigned)); } -TEST_F(SSLHandshakeTest, ExpiredCert) { - ASSERT_TRUE(InitServerManagers(security_manager::TLSv1_2, +TEST_P(SSLHandshakeTest, ExpiredCert) { + ASSERT_TRUE(InitServerManagers(GetParam().server_protocol, server_expired_cert_file, "ALL", verify_peer, client_ca_cert_filename)) - << server_manager->LastError(); - ASSERT_TRUE(InitClientManagers(security_manager::TLSv1_2, + << server_manager_->LastError(); + ASSERT_TRUE(InitClientManagers(GetParam().client_protocol, client_certificate, "ALL", verify_peer, server_ca_cert_filename)) - << client_manager->LastError(); + << client_manager_->LastError(); GTEST_TRACE(HandshakeProcedure_ClientSideFail( security_manager::SSLContext::Handshake_Result_CertExpired)); } -TEST_F(SSLHandshakeTest, AppNameAndAppIDInvalid) { - ASSERT_TRUE(InitServerManagers(security_manager::TLSv1_2, +TEST_P(SSLHandshakeTest, AppNameAndAppIDInvalid) { + ASSERT_TRUE(InitServerManagers(GetParam().server_protocol, server_certificate, "ALL", verify_peer, client_ca_cert_filename)) - << server_manager->LastError(); - ASSERT_TRUE(InitClientManagers(security_manager::TLSv1_2, + << server_manager_->LastError(); + ASSERT_TRUE(InitClientManagers(GetParam().client_protocol, client_certificate, "ALL", verify_peer, server_ca_cert_filename)) - << client_manager->LastError(); + << client_manager_->LastError(); - client_ctx->SetHandshakeContext( - security_manager::SSLContext::HandshakeContext( - custom_str::CustomString("server"), - custom_str::CustomString("Wrong"))); - - GTEST_TRACE(HandshakeProcedure_ClientSideFail( - security_manager::SSLContext::Handshake_Result_AppNameMismatch)); - - ResetConnections(); - client_ctx->SetHandshakeContext( + client_ctx_->SetHandshakeContext( security_manager::SSLContext::HandshakeContext( custom_str::CustomString("Wrong"), custom_str::CustomString("server"))); @@ -525,19 +541,19 @@ TEST_F(SSLHandshakeTest, AppNameAndAppIDInvalid) { security_manager::SSLContext::Handshake_Result_AppIDMismatch)); } -TEST_F(SSLHandshakeTest, NoVerification_ResetConnection) { - ASSERT_TRUE(InitServerManagers(security_manager::TLSv1_2, +TEST_P(SSLHandshakeTest, NoVerification_ResetConnection) { + ASSERT_TRUE(InitServerManagers(GetParam().server_protocol, server_certificate, "ALL", skip_peer_verification, "")) - << server_manager->LastError(); - ASSERT_TRUE(InitClientManagers(security_manager::TLSv1_2, + << server_manager_->LastError(); + ASSERT_TRUE(InitClientManagers(GetParam().client_protocol, client_certificate, "ALL", skip_peer_verification, "")) - << client_manager->LastError(); + << client_manager_->LastError(); const int times = 100; for (int i = 0; i < times; ++i) { @@ -549,19 +565,19 @@ TEST_F(SSLHandshakeTest, NoVerification_ResetConnection) { } } -TEST_F(SSLHandshakeTest, CAVerification_BothSides_ResetConnection) { - ASSERT_TRUE(InitServerManagers(security_manager::TLSv1_2, +TEST_P(SSLHandshakeTest, CAVerification_BothSides_ResetConnection) { + ASSERT_TRUE(InitServerManagers(GetParam().server_protocol, server_certificate, "ALL", verify_peer, client_ca_cert_filename)) - << server_manager->LastError(); - ASSERT_TRUE(InitClientManagers(security_manager::TLSv1_2, + << server_manager_->LastError(); + ASSERT_TRUE(InitClientManagers(GetParam().client_protocol, client_certificate, "ALL", skip_peer_verification, server_ca_cert_filename)) - << client_manager->LastError(); + << client_manager_->LastError(); const int times = 100; for (int i = 0; i < times; ++i) { @@ -572,7 +588,6 @@ TEST_F(SSLHandshakeTest, CAVerification_BothSides_ResetConnection) { GTEST_TRACE(ResetConnections()); } } - // TODO(EZamakhov): add fail tests -broken or not full ca certificate chain } // namespace ssl_handshake_test diff --git a/src/components/security_manager/test/ssl_context_test.cc b/src/components/security_manager/test/ssl_context_test.cc index a77cd98b27..20e509ebc6 100644 --- a/src/components/security_manager/test/ssl_context_test.cc +++ b/src/components/security_manager/test/ssl_context_test.cc @@ -49,8 +49,11 @@ using ::testing::ReturnRef; using ::testing::NiceMock; namespace { -const size_t kUpdatesBeforeHour = 24; const std::string kCaPath = ""; +const std::string kClientCertPath = "client_certificate.crt"; +const std::string kClientPrivateKeyPath = "client_private.key"; +const std::string kServerCertPath = "server_certificate.crt"; +const std::string kServerPrivateKeyPath = "server_private.key"; const uint8_t* kServerBuf; const uint8_t* kClientBuf; const std::string kAllCiphers = "ALL"; @@ -70,19 +73,19 @@ namespace ssl_context_test { namespace custom_str = utils::custom_string; struct ProtocolAndCipher { - security_manager::Protocol server_protocol; - security_manager::Protocol client_protocol; - std::string server_ciphers_list; - std::string client_ciphers_list; + security_manager::Protocol server_protocol_; + security_manager::Protocol client_protocol_; + std::string server_ciphers_list_; + std::string client_ciphers_list_; ProtocolAndCipher(security_manager::Protocol s_protocol, security_manager::Protocol c_protocol, std::string s_ciphers_list, std::string c_ciphers_list) - : server_protocol(s_protocol) - , client_protocol(c_protocol) - , server_ciphers_list(s_ciphers_list) - , client_ciphers_list(c_ciphers_list) {} + : server_protocol_(s_protocol) + , client_protocol_(c_protocol) + , server_ciphers_list_(s_ciphers_list) + , client_ciphers_list_(c_ciphers_list) {} }; class SSLTest : public testing::Test { @@ -127,6 +130,16 @@ class SSLTest : public testing::Test { .WillRepeatedly(ReturnRef(kCaPath)); EXPECT_CALL(*mock_crypto_manager_settings_, verify_peer()) .WillOnce(Return(false)); + + ON_CALL(*mock_crypto_manager_settings_, force_unprotected_service()) + .WillByDefault(ReturnRef(forced_unprotected_service_)); + ON_CALL(*mock_crypto_manager_settings_, force_protected_service()) + .WillByDefault(ReturnRef(forced_protected_service_)); + ON_CALL(*mock_crypto_manager_settings_, module_cert_path()) + .WillByDefault(ReturnRef(kServerCertPath)); + ON_CALL(*mock_crypto_manager_settings_, module_key_path()) + .WillByDefault(ReturnRef(kServerPrivateKeyPath)); + const bool crypto_manager_initialization = crypto_manager_->Init(); EXPECT_TRUE(crypto_manager_initialization); @@ -150,6 +163,16 @@ class SSLTest : public testing::Test { .WillRepeatedly(ReturnRef(kCaPath)); EXPECT_CALL(*mock_client_manager_settings_, verify_peer()) .WillOnce(Return(false)); + + ON_CALL(*mock_client_manager_settings_, force_unprotected_service()) + .WillByDefault(ReturnRef(forced_unprotected_service_)); + ON_CALL(*mock_client_manager_settings_, force_protected_service()) + .WillByDefault(ReturnRef(forced_protected_service_)); + ON_CALL(*mock_client_manager_settings_, module_cert_path()) + .WillByDefault(ReturnRef(kClientCertPath)); + ON_CALL(*mock_client_manager_settings_, module_key_path()) + .WillByDefault(ReturnRef(kClientPrivateKeyPath)); + const bool client_manager_initialization = client_manager_->Init(); EXPECT_TRUE(client_manager_initialization); @@ -159,19 +182,19 @@ class SSLTest : public testing::Test { .WillByDefault(Return(kMaximumPayloadSize)); EXPECT_CALL(*mock_crypto_manager_settings_, security_manager_mode()) .WillRepeatedly(Return(security_manager::SERVER)); - server_ctx = crypto_manager_->CreateSSLContext(); + server_ctx_ = crypto_manager_->CreateSSLContext(); EXPECT_CALL(*mock_client_manager_settings_, security_manager_mode()) .Times(2) .WillRepeatedly(Return(security_manager::CLIENT)); - client_ctx = client_manager_->CreateSSLContext(); + client_ctx_ = client_manager_->CreateSSLContext(); using custom_str::CustomString; security_manager::SSLContext::HandshakeContext ctx(CustomString("SPT"), CustomString("client")); - server_ctx->SetHandshakeContext(ctx); + server_ctx_->SetHandshakeContext(ctx); ctx.expected_cn = "server"; - client_ctx->SetHandshakeContext(ctx); + client_ctx_->SetHandshakeContext(ctx); kServerBuf = NULL; kClientBuf = NULL; @@ -180,8 +203,8 @@ class SSLTest : public testing::Test { } void TearDown() OVERRIDE { - crypto_manager_->ReleaseSSLContext(server_ctx); - client_manager_->ReleaseSSLContext(client_ctx); + crypto_manager_->ReleaseSSLContext(server_ctx_); + client_manager_->ReleaseSSLContext(client_ctx_); delete crypto_manager_; delete client_manager_; @@ -194,11 +217,14 @@ class SSLTest : public testing::Test { mock_crypto_manager_settings_; utils::SharedPtr<NiceMock<security_manager_test::MockCryptoManagerSettings> > mock_client_manager_settings_; - security_manager::SSLContext* server_ctx; - security_manager::SSLContext* client_ctx; + security_manager::SSLContext* server_ctx_; + security_manager::SSLContext* client_ctx_; static std::string client_certificate_data_base64_; static std::string server_certificate_data_base64_; + + const std::vector<int> forced_unprotected_service_; + const std::vector<int> forced_protected_service_; }; std::string SSLTest::client_certificate_data_base64_; std::string SSLTest::server_certificate_data_base64_; @@ -222,37 +248,38 @@ class SSLTestParam : public testing::TestWithParam<ProtocolAndCipher> { NiceMock<security_manager_test::MockCryptoManagerSettings> >(); utils::SharedPtr<security_manager::CryptoManagerSettings> server_crypto( mock_crypto_manager_settings_); - crypto_manager = new security_manager::CryptoManagerImpl(server_crypto); + crypto_manager_ = new security_manager::CryptoManagerImpl(server_crypto); - SetServerInitialValues(GetParam().server_protocol, - GetParam().server_ciphers_list); + SetServerInitialValues(GetParam().server_protocol_, + GetParam().server_ciphers_list_); - const bool crypto_manager_initialization = crypto_manager->Init(); - ASSERT_TRUE(crypto_manager_initialization); + const bool crypto_manager_initialization = crypto_manager_->Init(); + EXPECT_TRUE(crypto_manager_initialization); mock_client_manager_settings_ = utils::MakeShared< NiceMock<security_manager_test::MockCryptoManagerSettings> >(); utils::SharedPtr<security_manager::CryptoManagerSettings> client_crypto( mock_client_manager_settings_); - client_manager = new security_manager::CryptoManagerImpl(client_crypto); + client_manager_ = new security_manager::CryptoManagerImpl(client_crypto); - SetClientInitialValues(GetParam().client_protocol, - GetParam().client_ciphers_list); + SetClientInitialValues(GetParam().client_protocol_, + GetParam().client_ciphers_list_); - const bool client_manager_initialization = client_manager->Init(); - ASSERT_TRUE(client_manager_initialization); + const bool client_manager_initialization = client_manager_->Init(); + EXPECT_TRUE(client_manager_initialization); - server_ctx = crypto_manager->CreateSSLContext(); - client_ctx = client_manager->CreateSSLContext(); + server_ctx_ = crypto_manager_->CreateSSLContext(); + client_ctx_ = client_manager_->CreateSSLContext(); using custom_str::CustomString; - security_manager::SSLContext::HandshakeContext ctx(CustomString("SPT"), - CustomString("client")); - server_ctx->SetHandshakeContext(ctx); - ctx.expected_cn = "server"; - client_ctx->SetHandshakeContext(ctx); + server_ctx_->SetHandshakeContext( + security_manager::SSLContext::HandshakeContext(CustomString("SPT"), + CustomString("client"))); + client_ctx_->SetHandshakeContext( + security_manager::SSLContext::HandshakeContext(CustomString("SPT"), + CustomString("server"))); kServerBuf = NULL; kClientBuf = NULL; @@ -261,18 +288,19 @@ class SSLTestParam : public testing::TestWithParam<ProtocolAndCipher> { } void TearDown() OVERRIDE { - if (crypto_manager) { - crypto_manager->ReleaseSSLContext(server_ctx); - } - if (client_manager) { - client_manager->ReleaseSSLContext(client_ctx); - } - delete crypto_manager; - delete client_manager; + crypto_manager_->ReleaseSSLContext(server_ctx_); + client_manager_->ReleaseSSLContext(client_ctx_); + + delete crypto_manager_; + delete client_manager_; } void SetServerInitialValues(security_manager::Protocol protocol, const std::string& server_ciphers_list) { + ON_CALL(*mock_crypto_manager_settings_, force_unprotected_service()) + .WillByDefault(ReturnRef(forced_unprotected_service_)); + ON_CALL(*mock_crypto_manager_settings_, force_protected_service()) + .WillByDefault(ReturnRef(forced_protected_service_)); ON_CALL(*mock_crypto_manager_settings_, security_manager_mode()) .WillByDefault(Return(security_manager::SERVER)); ON_CALL(*mock_crypto_manager_settings_, security_manager_protocol_name()) @@ -285,9 +313,18 @@ class SSLTestParam : public testing::TestWithParam<ProtocolAndCipher> { .WillByDefault(ReturnRef(kCaPath)); ON_CALL(*mock_crypto_manager_settings_, verify_peer()) .WillByDefault(Return(false)); + ON_CALL(*mock_crypto_manager_settings_, module_cert_path()) + .WillByDefault(ReturnRef(kServerCertPath)); + ON_CALL(*mock_crypto_manager_settings_, module_key_path()) + .WillByDefault(ReturnRef(kServerPrivateKeyPath)); } + void SetClientInitialValues(security_manager::Protocol protocol, const std::string& client_ciphers_list) { + ON_CALL(*mock_client_manager_settings_, force_unprotected_service()) + .WillByDefault(ReturnRef(forced_unprotected_service_)); + ON_CALL(*mock_client_manager_settings_, force_protected_service()) + .WillByDefault(ReturnRef(forced_protected_service_)); ON_CALL(*mock_client_manager_settings_, security_manager_mode()) .WillByDefault(Return(security_manager::CLIENT)); ON_CALL(*mock_client_manager_settings_, security_manager_protocol_name()) @@ -300,17 +337,23 @@ class SSLTestParam : public testing::TestWithParam<ProtocolAndCipher> { .WillByDefault(ReturnRef(kCaPath)); ON_CALL(*mock_client_manager_settings_, verify_peer()) .WillByDefault(Return(false)); + ON_CALL(*mock_client_manager_settings_, module_cert_path()) + .WillByDefault(ReturnRef(kClientCertPath)); + ON_CALL(*mock_client_manager_settings_, module_key_path()) + .WillByDefault(ReturnRef(kClientPrivateKeyPath)); } utils::SharedPtr<NiceMock<security_manager_test::MockCryptoManagerSettings> > mock_crypto_manager_settings_; utils::SharedPtr<NiceMock<security_manager_test::MockCryptoManagerSettings> > mock_client_manager_settings_; - security_manager::CryptoManager* crypto_manager = NULL; - security_manager::CryptoManager* client_manager = NULL; - security_manager::SSLContext* server_ctx = NULL; - security_manager::SSLContext* client_ctx = NULL; + security_manager::CryptoManager* crypto_manager_; + security_manager::CryptoManager* client_manager_; + security_manager::SSLContext* server_ctx_; + security_manager::SSLContext* client_ctx_; std::string certificate_data_base64_; + const std::vector<int> forced_unprotected_service_; + const std::vector<int> forced_protected_service_; }; class SSLTestForTLS1_2 : public SSLTestParam {}; @@ -319,7 +362,7 @@ class SSLTestForTLS1_2 : public SSLTestParam {}; INSTANTIATE_TEST_CASE_P( CorrectProtocolAndCiphers, SSLTestParam, - ::testing::Values(ProtocolAndCipher(security_manager::TLSv1, + ::testing::Values(ProtocolAndCipher(security_manager::TLSv1_1, security_manager::TLSv1, kFordCipher, kFordCipher), @@ -334,7 +377,11 @@ INSTANTIATE_TEST_CASE_P( kFordCipher, kFordCipher) #endif - )); + , + ProtocolAndCipher(security_manager::DTLSv1, + security_manager::DTLSv1, + kFordCipher, + kFordCipher))); INSTANTIATE_TEST_CASE_P( IncorrectProtocolAndCiphers, @@ -365,6 +412,22 @@ INSTANTIATE_TEST_CASE_P( security_manager::SSLv3, kFordCipher, kFordCipher), + ProtocolAndCipher(security_manager::TLSv1, + security_manager::DTLSv1, + kFordCipher, + kFordCipher), + ProtocolAndCipher(security_manager::DTLSv1, + security_manager::TLSv1_1, + kFordCipher, + kFordCipher), + ProtocolAndCipher(security_manager::TLSv1_2, + security_manager::DTLSv1, + kFordCipher, + kFordCipher), + ProtocolAndCipher(security_manager::TLSv1_1, + security_manager::DTLSv1, + kFordCipher, + kFordCipher), ProtocolAndCipher(security_manager::TLSv1_2, security_manager::SSLv3, kFordCipher, @@ -382,7 +445,8 @@ INSTANTIATE_TEST_CASE_P( TEST_F(SSLTest, OnTSL2Protocol_BrokenHandshake) { ASSERT_EQ(security_manager::SSLContext::Handshake_Result_Success, - client_ctx->StartHandshake(&kClientBuf, &client_buf_len)); + client_ctx_->StartHandshake(&kClientBuf, &client_buf_len)); + ASSERT_FALSE(NULL == kClientBuf); ASSERT_LT(0u, client_buf_len); // Broke 3 bytes for get abnormal fail of handshake @@ -390,26 +454,26 @@ TEST_F(SSLTest, OnTSL2Protocol_BrokenHandshake) { const_cast<uint8_t*>(kClientBuf)[client_buf_len / 2] ^= 0xFF; const_cast<uint8_t*>(kClientBuf)[client_buf_len - 1] ^= 0xFF; ASSERT_EQ(security_manager::SSLContext::Handshake_Result_AbnormalFail, - server_ctx->DoHandshakeStep( + server_ctx_->DoHandshakeStep( kClientBuf, client_buf_len, &kServerBuf, &server_buf_len)); - EXPECT_EQ("Initialization is not completed", server_ctx->LastError()); - EXPECT_EQ("Initialization is not completed", client_ctx->LastError()); + EXPECT_EQ("Initialization is not completed", server_ctx_->LastError()); + EXPECT_EQ("Initialization is not completed", client_ctx_->LastError()); } // TODO {AKozoriz} : Unexpected uncomplited init of SSL component. // In this and next tests. // Must be fixed after merge to develop. TEST_F(SSLTest, OnTSL2Protocol_Positive) { - ASSERT_EQ(client_ctx->StartHandshake(&kClientBuf, &client_buf_len), + ASSERT_EQ(client_ctx_->StartHandshake(&kClientBuf, &client_buf_len), security_manager::SSLContext::Handshake_Result_Success); - EXPECT_FALSE(server_ctx->IsInitCompleted()); + EXPECT_FALSE(server_ctx_->IsInitCompleted()); while (true) { ASSERT_TRUE(NULL != kClientBuf); ASSERT_LT(0u, client_buf_len); const security_manager::SSLContext::HandshakeResult server_result = - server_ctx->DoHandshakeStep( + server_ctx_->DoHandshakeStep( kClientBuf, client_buf_len, &kServerBuf, &server_buf_len); ASSERT_EQ(security_manager::SSLContext::Handshake_Result_Success, server_result); @@ -417,11 +481,11 @@ TEST_F(SSLTest, OnTSL2Protocol_Positive) { ASSERT_LT(0u, server_buf_len); const security_manager::SSLContext::HandshakeResult client_result = - client_ctx->DoHandshakeStep( + client_ctx_->DoHandshakeStep( kServerBuf, server_buf_len, &kClientBuf, &client_buf_len); ASSERT_EQ(security_manager::SSLContext::Handshake_Result_Success, client_result); - if (server_ctx->IsInitCompleted()) { + if (server_ctx_->IsInitCompleted()) { break; } @@ -432,22 +496,22 @@ TEST_F(SSLTest, OnTSL2Protocol_Positive) { ASSERT_TRUE(NULL == kClientBuf); ASSERT_EQ(0u, client_buf_len); // expect both side initialization complete - EXPECT_TRUE(client_ctx->IsInitCompleted()); - EXPECT_TRUE(server_ctx->IsInitCompleted()); + EXPECT_TRUE(client_ctx_->IsInitCompleted()); + EXPECT_TRUE(server_ctx_->IsInitCompleted()); // Encrypt text on client side const uint8_t* text = reinterpret_cast<const uint8_t*>("abra"); const uint8_t* encrypted_text = 0; size_t text_len = 4; size_t encrypted_text_len; - EXPECT_TRUE(client_ctx->Encrypt( + EXPECT_TRUE(client_ctx_->Encrypt( text, text_len, &encrypted_text, &encrypted_text_len)); ASSERT_NE(reinterpret_cast<void*>(NULL), encrypted_text); ASSERT_LT(0u, encrypted_text_len); // Decrypt text on server side - EXPECT_TRUE(server_ctx->Decrypt( + EXPECT_TRUE(server_ctx_->Decrypt( encrypted_text, encrypted_text_len, &text, &text_len)); ASSERT_NE(reinterpret_cast<void*>(NULL), text); ASSERT_LT(0u, text_len); @@ -457,34 +521,34 @@ TEST_F(SSLTest, OnTSL2Protocol_Positive) { TEST_F(SSLTest, OnTSL2Protocol_EcncryptionFail) { ASSERT_EQ(security_manager::SSLContext::Handshake_Result_Success, - client_ctx->StartHandshake(&kClientBuf, &client_buf_len)); + client_ctx_->StartHandshake(&kClientBuf, &client_buf_len)); - while (!server_ctx->IsInitCompleted()) { + while (!server_ctx_->IsInitCompleted()) { ASSERT_FALSE(NULL == kClientBuf); ASSERT_LT(0u, client_buf_len); ASSERT_EQ(security_manager::SSLContext::Handshake_Result_Success, - server_ctx->DoHandshakeStep( + server_ctx_->DoHandshakeStep( kClientBuf, client_buf_len, &kServerBuf, &server_buf_len)); ASSERT_FALSE(NULL == kServerBuf); ASSERT_LT(0u, server_buf_len); ASSERT_EQ(security_manager::SSLContext::Handshake_Result_Success, - client_ctx->DoHandshakeStep( + client_ctx_->DoHandshakeStep( kServerBuf, server_buf_len, &kClientBuf, &client_buf_len)); } // Expect empty buffers after init complete ASSERT_TRUE(NULL == kClientBuf); ASSERT_EQ(0u, client_buf_len); // Expect both side initialization complete - EXPECT_TRUE(client_ctx->IsInitCompleted()); - EXPECT_TRUE(server_ctx->IsInitCompleted()); + EXPECT_TRUE(client_ctx_->IsInitCompleted()); + EXPECT_TRUE(server_ctx_->IsInitCompleted()); // Encrypt text on client side const uint8_t* text = reinterpret_cast<const uint8_t*>("abra"); const uint8_t* encrypted_text = 0; size_t text_len = 4; size_t encrypted_text_len; - EXPECT_TRUE(client_ctx->Encrypt( + EXPECT_TRUE(client_ctx_->Encrypt( text, text_len, &encrypted_text, &encrypted_text_len)); ASSERT_NE(reinterpret_cast<void*>(NULL), encrypted_text); ASSERT_LT(0u, encrypted_text_len); @@ -497,29 +561,30 @@ TEST_F(SSLTest, OnTSL2Protocol_EcncryptionFail) { const uint8_t* out_text; size_t out_text_size; // Decrypt broken text on server side - EXPECT_FALSE(server_ctx->Decrypt( + EXPECT_FALSE(server_ctx_->Decrypt( &broken[0], broken.size(), &out_text, &out_text_size)); // Check after broken message that server encryption and decryption fail // Encrypte message on server side - EXPECT_FALSE(server_ctx->Decrypt( + EXPECT_FALSE(server_ctx_->Decrypt( encrypted_text, encrypted_text_len, &out_text, &out_text_size)); - EXPECT_FALSE(server_ctx->Encrypt( + EXPECT_FALSE(server_ctx_->Encrypt( text, text_len, &encrypted_text, &encrypted_text_len)); } TEST_P(SSLTestParam, ClientAndServerNotTLSv1_2_HandshakeFailed) { ASSERT_EQ(security_manager::SSLContext::Handshake_Result_AbnormalFail, - client_ctx->StartHandshake(&kClientBuf, &client_buf_len)); + client_ctx_->StartHandshake(&kClientBuf, &client_buf_len)); + EXPECT_TRUE(NULL == kClientBuf); EXPECT_EQ(0u, client_buf_len); ASSERT_EQ(security_manager::SSLContext::Handshake_Result_Success, - server_ctx->DoHandshakeStep( + server_ctx_->DoHandshakeStep( kClientBuf, client_buf_len, &kServerBuf, &server_buf_len)); EXPECT_TRUE(NULL == kServerBuf); EXPECT_EQ(0u, server_buf_len); - EXPECT_FALSE(server_ctx->IsInitCompleted()); + EXPECT_FALSE(server_ctx_->IsInitCompleted()); } INSTANTIATE_TEST_CASE_P( @@ -544,16 +609,19 @@ INSTANTIATE_TEST_CASE_P( TEST_P(SSLTestForTLS1_2, HandshakeFailed) { ASSERT_EQ(security_manager::SSLContext::Handshake_Result_Success, - client_ctx->StartHandshake(&kClientBuf, &client_buf_len)); + client_ctx_->StartHandshake(&kClientBuf, &client_buf_len)); EXPECT_FALSE(NULL == kClientBuf); ASSERT_LT(0u, client_buf_len); + ASSERT_EQ(security_manager::SSLContext::Handshake_Result_AbnormalFail, - server_ctx->DoHandshakeStep( - kClientBuf, client_buf_len, &kServerBuf, &server_buf_len)); + server_ctx_->DoHandshakeStep( + kClientBuf, client_buf_len, &kServerBuf, &server_buf_len)) + << ERR_reason_error_string(ERR_get_error()); + EXPECT_TRUE(NULL == kServerBuf); EXPECT_EQ(0u, server_buf_len); - EXPECT_FALSE(server_ctx->IsInitCompleted()); + EXPECT_FALSE(server_ctx_->IsInitCompleted()); } } // namespace ssl_context_test |