diff options
Diffstat (limited to 'src/components/security_manager')
19 files changed, 2865 insertions, 1736 deletions
diff --git a/src/components/security_manager/CMakeLists.txt b/src/components/security_manager/CMakeLists.txt index 6973a98e07..3cc6178931 100644 --- a/src/components/security_manager/CMakeLists.txt +++ b/src/components/security_manager/CMakeLists.txt @@ -33,7 +33,9 @@ include_directories( include/ ${COMPONENTS_DIR}/protocol_handler/include/ ${COMPONENTS_DIR}/connection_handler/include + ${COMPONENTS_DIR}/config_profile/include/ ${COMPONENTS_DIR}/utils/include/ + ${COMPONENTS_DIR}/application_manager/include/ ${JSONCPP_INCLUDE_DIRECTORY} ${CMAKE_SOURCE_DIR}/src/thirdPartyLibs/jsoncpp/include ${APR_INCLUDE_DIRECTORY} @@ -51,4 +53,4 @@ target_link_libraries(SecurityManager crypto ssl ProtocolHandler jsoncpp Protoco if(BUILD_TESTS) add_subdirectory(test) -endif()
\ No newline at end of file +endif() 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 43bb63ef67..6aea2e28b1 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 @@ -42,66 +42,97 @@ #include "security_manager/crypto_manager.h" #include "security_manager/ssl_context.h" +#include "security_manager/security_manager_settings.h" + #include "utils/macro.h" #include "utils/lock.h" +#include "utils/shared_ptr.h" namespace security_manager { class CryptoManagerImpl : public CryptoManager { private: class SSLContextImpl : public SSLContext { public: - SSLContextImpl(SSL *conn, Mode mode); + SSLContextImpl(SSL* conn, Mode mode, size_t maximum_payload_size); + ~SSLContextImpl(); virtual HandshakeResult StartHandshake(const uint8_t** const out_data, - size_t *out_data_size); - virtual HandshakeResult DoHandshakeStep(const uint8_t *const in_data, + size_t* out_data_size); + virtual HandshakeResult DoHandshakeStep(const uint8_t* const in_data, size_t in_data_size, const uint8_t** const out_data, - size_t *out_data_size); - virtual bool Encrypt(const uint8_t *const in_data, size_t in_data_size, - const uint8_t ** const out_data, size_t *out_data_size); - virtual bool Decrypt(const uint8_t *const in_data, size_t in_data_size, - const uint8_t ** const out_data, size_t *out_data_size); - virtual bool IsInitCompleted() const; - virtual bool IsHandshakePending() const; - virtual size_t get_max_block_size(size_t mtu) const; - virtual std::string LastError() const; - virtual ~SSLContextImpl(); + size_t* out_data_size) OVERRIDE; + bool Encrypt(const uint8_t* const in_data, + size_t in_data_size, + const uint8_t** const out_data, + size_t* out_data_size) OVERRIDE; + bool Decrypt(const uint8_t* const in_data, + size_t in_data_size, + const uint8_t** const out_data, + size_t* out_data_size) OVERRIDE; + bool IsInitCompleted() const OVERRIDE; + bool IsHandshakePending() const OVERRIDE; + size_t get_max_block_size(size_t mtu) const OVERRIDE; + std::string LastError() const OVERRIDE; + void ResetConnection() OVERRIDE; + void SetHandshakeContext(const HandshakeContext& hsh_ctx) OVERRIDE; + + void PrintCertData(X509* cert, const std::string& cert_owner); private: - typedef size_t(*BlockSizeGetter)(size_t); + void PrintCertInfo(); + HandshakeResult CheckCertContext(); + bool ReadHandshakeData(const uint8_t** const out_data, + size_t* out_data_size); + bool WriteHandshakeData(const uint8_t* const in_data, size_t in_data_size); + HandshakeResult PerformHandshake(); + typedef size_t (*BlockSizeGetter)(size_t); void EnsureBufferSizeEnough(size_t size); - SSL *connection_; - BIO *bioIn_; - BIO *bioOut_; - BIO *bioFilter_; + void SetHandshakeError(const int error); + HandshakeResult openssl_error_convert_to_internal(const long error); + + std::string GetTextBy(X509_NAME* name, int object) const; + + SSL* connection_; + BIO* bioIn_; + BIO* bioOut_; + BIO* bioFilter_; mutable sync_primitives::Lock bio_locker; size_t buffer_size_; - uint8_t *buffer_; + uint8_t* buffer_; bool is_handshake_pending_; Mode mode_; + mutable std::string last_error_; BlockSizeGetter max_block_size_; static std::map<std::string, BlockSizeGetter> max_block_sizes; static std::map<std::string, BlockSizeGetter> create_max_block_sizes(); + HandshakeContext hsh_context_; DISALLOW_COPY_AND_ASSIGN(SSLContextImpl); }; public: - CryptoManagerImpl(); - virtual bool Init(Mode mode, - Protocol protocol, - const std::string &cert_filename, - const std::string &key_filename, - const std::string &ciphers_list, - bool verify_peer); - virtual void Finish(); - virtual SSLContext *CreateSSLContext(); - virtual void ReleaseSSLContext(SSLContext *context); - virtual std::string LastError() const; + explicit CryptoManagerImpl( + const utils::SharedPtr<const CryptoManagerSettings> set); + ~CryptoManagerImpl(); + + bool Init() OVERRIDE; + bool OnCertificateUpdated(const std::string& data) OVERRIDE; + SSLContext* CreateSSLContext() OVERRIDE; + void ReleaseSSLContext(SSLContext* context) OVERRIDE; + std::string LastError() const OVERRIDE; + virtual bool IsCertificateUpdateRequired() const OVERRIDE; + virtual const CryptoManagerSettings& get_settings() const OVERRIDE; private: - SSL_CTX *context_; - Mode mode_; + 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); + + 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); }; } // namespace security_manager 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 new file mode 100644 index 0000000000..1e4699b77a --- /dev/null +++ b/src/components/security_manager/include/security_manager/crypto_manager_settings_impl.h @@ -0,0 +1,65 @@ + +#ifndef SRC_COMPONENTS_SECURITY_MANAGER_INCLUDE_SECURITY_MANAGER_CRYPTO_MANAGER_SETTINGS_IMPL_H_ +#define SRC_COMPONENTS_SECURITY_MANAGER_INCLUDE_SECURITY_MANAGER_CRYPTO_MANAGER_SETTINGS_IMPL_H_ +#include "security_manager/security_manager_settings.h" +#include "config_profile/profile.h" + +namespace security_manager { + +class CryptoManagerSettingsImpl : public CryptoManagerSettings { + public: + CryptoManagerSettingsImpl(const profile::Profile& profile, + const std::string& certificate_data) + : profile_(profile), certificate_data_(certificate_data) {} + + // CryptoManagerSettings interface + Mode security_manager_mode() const OVERRIDE { + return profile_.ssl_mode() == "SERVER" ? security_manager::SERVER + : security_manager::CLIENT; + } + Protocol security_manager_protocol_name() const OVERRIDE { + CREATE_LOGGERPTR_LOCAL(logger_, "SecurityManager") + + const std::string& protocol_str = profile_.security_manager_protocol_name(); + if (protocol_str == "TLSv1.0") { + return security_manager::TLSv1; + } + if (protocol_str == "TLSv1.1") { + return security_manager::TLSv1_1; + } + if (protocol_str == "TLSv1.2") { + return security_manager::TLSv1_2; + } + if (protocol_str == "SSLv3") { + return security_manager::SSLv3; + } + 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(); + } + size_t update_before_hours() const OVERRIDE { + return profile_.update_before_hours(); + } + size_t maximum_payload_size() const OVERRIDE { + return profile_.maximum_payload_size(); + } + + private: + const profile::Profile& profile_; + const std::string certificate_data_; +}; +} +#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 2aa03087eb..d4231ffaa0 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 @@ -51,9 +51,10 @@ namespace security_manager { * \brief SecurityMessageQueue and SecurityMessageLoop are support typedefs * for thread working */ -struct SecurityMessage: public SecurityQueryPtr { - explicit SecurityMessage(const SecurityQueryPtr &message) - : SecurityQueryPtr(message) {} +struct SecurityMessage : public SecurityQueryPtr { + SecurityMessage() {} + explicit SecurityMessage(const SecurityQueryPtr& message) + : SecurityQueryPtr(message) {} // PrioritizedQueue requires this method to decide which priority to assign size_t PriorityOrder() const { return 0; @@ -65,9 +66,8 @@ typedef threads::MessageLoopThread<SecurityMessageQueue> SecurityMessageLoop; /** * \brief SecurityManagerImpl class implements SecurityManager interface */ -class SecurityManagerImpl - : public SecurityManager, - public SecurityMessageLoop::Handler { +class SecurityManagerImpl : public SecurityManager, + public SecurityMessageLoop::Handler { public: /** * \brief Constructor @@ -78,7 +78,8 @@ class SecurityManagerImpl * Overriden ProtocolObserver::OnMessageReceived method * \param message Message with supporting params received */ - void OnMessageReceived(const ::protocol_handler::RawMessagePtr message) OVERRIDE; + void OnMessageReceived( + const ::protocol_handler::RawMessagePtr message) OVERRIDE; /** * \brief Post message to Mobile Application * Empty *overriden ProtocolObserver::OnMessageReceived method @@ -91,28 +92,29 @@ class SecurityManagerImpl * \param session_observer pointer to object of the class implementing */ void set_session_observer( - protocol_handler::SessionObserver *observer) OVERRIDE; + protocol_handler::SessionObserver* observer) OVERRIDE; /** * \brief Sets pointer for Protocol Handler layer for sending * \param protocol_handler pointer to object of the class implementing */ void set_protocol_handler( - protocol_handler::ProtocolHandler *protocol_handler_) OVERRIDE; + protocol_handler::ProtocolHandler* protocol_handler_) OVERRIDE; /** * \brief Sets pointer for CryptoManager for handling SSLContext * \param crypto_manager pointer to object of the class implementing */ - void set_crypto_manager(CryptoManager *crypto_manager) OVERRIDE; + void set_crypto_manager(CryptoManager* crypto_manager) OVERRIDE; /** * \brief Sends InternallError with text message to mobile application - * \param connection_key Unique key used by other components as session identifier + * \param connection_key Unique key used by other components as session + * identifier * \param error_id unique error identifier * \param erorr_text SSL impelmentation error text * \param seq_number received from Mobile Application */ void SendInternalError(const uint32_t connection_key, - const uint8_t &error_id, - const std::string &erorr_text, + const uint8_t& error_id, + const std::string& erorr_text, const uint32_t seq_number) OVERRIDE; using SecurityManager::SendInternalError; @@ -127,10 +129,11 @@ class SecurityManagerImpl /** * \brief Create new SSLContext for connection or return exists * Do not notify listeners, send security error on occure - * \param connection_key Unique key used by other components as session identifier + * \param connection_key Unique key used by other components as session + * identifier * @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) OVERRIDE; /** * \brief Start handshake as SSL client @@ -140,50 +143,61 @@ class SecurityManagerImpl /** * \brief Add/Remove for SecurityManagerListener */ - void AddListener(SecurityManagerListener *const listener) OVERRIDE; - void RemoveListener(SecurityManagerListener *const listener) OVERRIDE; + 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 identifier + * \param connection_key Unique key used by other components as session + * identifier * \param success result of connection protection */ - void NotifyListenersOnHandshakeDone(const uint32_t &connection_key, - const bool success); + void NotifyListenersOnHandshakeDone(const uint32_t& connection_key, + SSLContext::HandshakeResult error); + + /** + * @brief Notifiers for listeners. + * Allows to notify that certificate should be updated + */ + void NotifyOnCertififcateUpdateRequired(); + /** * @brief SecurityConfigSection * @return Session name in config file */ - static const char *ConfigSection(); + static const char* ConfigSection(); + private: /** * \brief Sends Handshake binary data to mobile application - * \param connection_key Unique key used by other components as session identifier + * \param connection_key Unique key used by other components as session + * identifier * \param data pointer to binary data array * \param data_size size of binary data array * \param seq_number received from Mobile Application */ void SendHandshakeBinData(const uint32_t connection_key, - const uint8_t *const data, + const uint8_t* const data, const size_t data_size, const uint32_t seq_number = 0); /** * \brief Parse SecurityMessage as HandshakeData request * \param inMessage SecurityMessage with binary data of handshake */ - bool ProccessHandshakeData(const SecurityMessage &inMessage); + bool ProccessHandshakeData(const SecurityMessage& inMessage); /** * \brief Parse InternalError from mobile side * \param inMessage SecurityMessage with binary data of handshake */ - bool ProccessInternalError(const SecurityMessage &inMessage); + bool ProccessInternalError(const SecurityMessage& inMessage); /** * \brief Sends security query * Create new array as concatenation of header and binary data * \param query SecurityQuery for sending via Control service - * \param connection_key Unique key used by other components as session identifier + * \param connection_key Unique key used by other components as session + * identifier */ - void SendQuery(const SecurityQuery &query, const uint32_t connection_key); + void SendQuery(const SecurityQuery& query, const uint32_t connection_key); // Thread that pumps handshake data SecurityMessageLoop security_messages_; @@ -191,19 +205,19 @@ class SecurityManagerImpl /** *\brief Pointer on instance of class implementing SessionObserver */ - protocol_handler::SessionObserver *session_observer_; + protocol_handler::SessionObserver* session_observer_; /** *\brief Pointer on instance of class implementing CryptoManager */ - security_manager::CryptoManager *crypto_manager_; + security_manager::CryptoManager* crypto_manager_; /** *\brief Pointer on instance of class implementing ProtocolHandler */ - protocol_handler::ProtocolHandler *protocol_handler_; + protocol_handler::ProtocolHandler* protocol_handler_; /** *\brief List of listeners for notify handshake done result */ - std::list<SecurityManagerListener *> listeners_; + std::list<SecurityManagerListener*> listeners_; DISALLOW_COPY_AND_ASSIGN(SecurityManagerImpl); }; } // namespace security_manager diff --git a/src/components/security_manager/include/security_manager/security_query.h b/src/components/security_manager/include/security_manager/security_query.h deleted file mode 100644 index c9f0b5843f..0000000000 --- a/src/components/security_manager/include/security_manager/security_query.h +++ /dev/null @@ -1,186 +0,0 @@ -/* - * Copyright (c) 2014, Ford Motor Company - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following - * disclaimer in the documentation and/or other materials provided with the - * distribution. - * - * Neither the name of the Ford Motor Company nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef SRC_COMPONENTS_SECURITY_MANAGER_INCLUDE_SECURITY_MANAGER_SECURITY_QUERY_H_ -#define SRC_COMPONENTS_SECURITY_MANAGER_INCLUDE_SECURITY_MANAGER_SECURITY_QUERY_H_ - -#include <stdint.h> -#include <cstddef> -#include <vector> -#include <string> -#include "utils/shared_ptr.h" - -namespace security_manager { -/** - * \brief SecurityQuery is wrapper for handling Mobile messages - * as security queries - */ -class SecurityQuery { - public: - /** - * \brief QueryType is 1 byte type of income query - * Equal RPC Type (Ford Binary Header Definition) - */ - enum QueryType { - REQUEST = 0x00, - RESPONSE = 0x10, - NOTIFICATION = 0x20, - INVALID_QUERY_TYPE = 0xFF - }; - /** - * \brief QueryId is 3 byte identifier of income query - * Equal RPC Function ID (Ford Binary Header Definition) - */ - enum QueryId { - SEND_HANDSHAKE_DATA = 0x1, - SEND_INTERNAL_ERROR = 0x2, - INVALID_QUERY_ID = 0xFFFFFF - }; - /** - * \brief QueryHeader is 12 byte header of security query - * Equal Ford Binary Header Definition - */ - struct QueryHeader { - QueryHeader(); - QueryHeader(uint8_t queryType, uint32_t queryId, - uint32_t seqNumber = 0, uint32_t jsonSize= 0); - // TODO(EZamakhov): check bitfield correctness on other endianness platform - uint32_t query_type:8; - uint32_t query_id:24; // API function identifier - uint32_t seq_number; // request sequential number - uint32_t json_size; - }; - - /** - * \brief Constructor - */ - SecurityQuery(); - /** - * \brief Constructor with header and connection_key - * \param connection_key Unique key used by other components as session identifier - * \param header QueryHeader - */ - SecurityQuery(const QueryHeader &header, const uint32_t connection_key); - /** - * \brief Constructor with header, connection_key and query binary data - * \param connection_key Unique key used by other components as session identifier - * \param raw_data pointer to binary data array - * \param raw_data_size size of binary data array - * \param header QueryHeader - */ - SecurityQuery(const QueryHeader &header, const uint32_t connection_key, - const uint8_t *const raw_data, const size_t raw_data_size); - /** - * \brief Serialize income from Mobile Application data - * as query with header and binary data or json message - * \param raw_data pointer to binary data array - * \param raw_data_size size of binary data array - * \return \c true on correct parse and \c false on wrong size of data - */ - bool SerializeQuery(const uint8_t *const raw_data, const size_t raw_data_size); - /** - * \brief Deserialize query for sending to Mobile Application - * \return \c vector of uint8_t data (serialized header data and send_data)) - */ - const std::vector<uint8_t> DeserializeQuery() const; - /** - * \brief Set binary data. (No header modification) - * \param binary_data pointer to binary data array - * \param bin_data_size size of binary data array - */ - void set_data(const uint8_t *const binary_data, const size_t bin_data_size); - /** - * \brief Set json data. (No header modification) - * \param json_message string with json error - */ - void set_json_message(const std::string &json_message); - /** - * \brief Set connection key - * \param connection_key Unique key used by other components as session identifier - */ - void set_connection_key(const uint32_t connection_key); - /** - * \brief Set query header - * \param header of query - */ - void set_header(const QueryHeader &header); - /** - * \brief Get query header - * \return header of query - */ - const QueryHeader &get_header() const; - /** - * \brief Get query binary data (without header data) - * \return const pointer to const binary data - */ - const uint8_t *get_data() const; - /** - * \brief Get query binary data size - * \return size of binary data - */ - size_t get_data_size() const; - /** - * \brief Get json string data (without header data) - * \return const pointer to const binary data - */ - const std::string &get_json_message() const; - /** - * \brief Get connection key - * \return Unique key used by other components as session identifier - */ - uint32_t get_connection_key() const; - - private: - /** - *\brief 12 byte header of security query - * Equal Ford Binary Header Definition - */ - QueryHeader header_; - /** - *\brief nique key used by other components as session identifier - */ - uint32_t connection_key_; - /** - *\brief Binary data of query (without header info) - */ - std::vector<uint8_t> data_; - /** - *\brief JSON (string) value of query - */ - std::string json_message_; -}; -/** -*\brief SmartPointer wrapper -*/ -typedef utils::SharedPtr<SecurityQuery> SecurityQueryPtr; -} // namespace security_manager -#endif // SRC_COMPONENTS_SECURITY_MANAGER_INCLUDE_SECURITY_MANAGER_SECURITY_QUERY_H_ diff --git a/src/components/security_manager/src/crypto_manager_impl.cc b/src/components/security_manager/src/crypto_manager_impl.cc index 69121a7b19..f44198953b 100644 --- a/src/components/security_manager/src/crypto_manager_impl.cc +++ b/src/components/security_manager/src/crypto_manager_impl.cc @@ -31,143 +31,205 @@ */ #include "security_manager/crypto_manager_impl.h" + #include <openssl/bio.h> #include <openssl/ssl.h> #include <openssl/err.h> +#include <openssl/pkcs12.h> + +#include <fstream> +#include <iostream> +#include <stdio.h> +#include <ctime> #include "security_manager/security_manager.h" + #include "utils/logger.h" #include "utils/atomic.h" +#include "utils/macro.h" +#include "utils/scope_guard.h" +#include "utils/date_time.h" -#define TLS1_1_MINIMAL_VERSION 0x1000103fL -#define CONST_SSL_METHOD_MINIMAL_VERSION 0x00909000L +#define TLS1_1_MINIMAL_VERSION 0x1000103fL +#define CONST_SSL_METHOD_MINIMAL_VERSION 0x00909000L namespace security_manager { -CREATE_LOGGERPTR_GLOBAL(logger_, "CryptoManagerImpl") +CREATE_LOGGERPTR_GLOBAL(logger_, "SecurityManager") uint32_t CryptoManagerImpl::instance_count_ = 0; +sync_primitives::Lock CryptoManagerImpl::instance_lock_; -CryptoManagerImpl::CryptoManagerImpl() - : context_(NULL), mode_(CLIENT) { +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); + LOG4CXX_WARN(logger_, + "Certificate verification failed with error " + << error << " \"" << X509_verify_cert_error_string(error) + << '"'); + } + return preverify_ok; } -bool CryptoManagerImpl::Init(Mode mode, - Protocol protocol, - const std::string &cert_filename, - const std::string &key_filename, - const std::string &ciphers_list, - bool verify_peer) { - if (atomic_post_inc(&instance_count_) == 0) { +void free_ctx(SSL_CTX** ctx) { + if (ctx) { + SSL_CTX_free(*ctx); + *ctx = NULL; + } +} +} + +CryptoManagerImpl::CryptoManagerImpl( + const utils::SharedPtr<const CryptoManagerSettings> set) + : settings_(set), context_(NULL) { + LOG4CXX_AUTO_TRACE(logger_); + sync_primitives::AutoLock lock(instance_lock_); + instance_count_++; + if (instance_count_ == 1) { + LOG4CXX_DEBUG(logger_, "Openssl engine initialization"); SSL_load_error_strings(); ERR_load_BIO_strings(); OpenSSL_add_all_algorithms(); SSL_library_init(); } +} - mode_ = mode; +CryptoManagerImpl::~CryptoManagerImpl() { + LOG4CXX_AUTO_TRACE(logger_); + sync_primitives::AutoLock lock(instance_lock_); + LOG4CXX_DEBUG(logger_, "Deinitilization"); + if (!context_) { + LOG4CXX_WARN(logger_, "Manager is not initialized"); + } else { + SSL_CTX_free(context_); + } + instance_count_--; + if (instance_count_ == 0) { + LOG4CXX_DEBUG(logger_, "Openssl engine deinitialization"); + EVP_cleanup(); + ERR_free_strings(); + } +} + +bool CryptoManagerImpl::Init() { + LOG4CXX_AUTO_TRACE(logger_); + + const Mode mode = get_settings().security_manager_mode(); const bool is_server = (mode == SERVER); + if (is_server) { + LOG4CXX_DEBUG(logger_, "Server mode"); + } else { + LOG4CXX_DEBUG(logger_, "Client mode"); + } + LOG4CXX_DEBUG(logger_, + "Peer verification " + << (get_settings().verify_peer() ? "enabled" : "disabled")); + LOG4CXX_DEBUG(logger_, + "CA certificate file is \"" << get_settings().ca_cert_path() + << '"'); + #if OPENSSL_VERSION_NUMBER < CONST_SSL_METHOD_MINIMAL_VERSION - SSL_METHOD *method; + SSL_METHOD* method; #else - const SSL_METHOD *method; + const SSL_METHOD* method; #endif - switch (protocol) { + switch (get_settings().security_manager_protocol_name()) { case SSLv3: - method = is_server ? - SSLv3_server_method() : - SSLv3_client_method(); + method = is_server ? SSLv3_server_method() : SSLv3_client_method(); break; case TLSv1: - method = is_server ? - TLSv1_server_method() : - TLSv1_client_method(); + method = is_server ? TLSv1_server_method() : TLSv1_client_method(); break; case TLSv1_1: #if OPENSSL_VERSION_NUMBER < TLS1_1_MINIMAL_VERSION - LOG4CXX_WARN(logger_, - "OpenSSL has no TLSv1.1 with version lower 1.0.1, set TLSv1.0"); - method = is_server ? - TLSv1_server_method() : - TLSv1_client_method(); + LOG4CXX_WARN( + logger_, + "OpenSSL has no TLSv1.1 with version lower 1.0.1, set TLSv1.0"); + method = is_server ? TLSv1_server_method() : TLSv1_client_method(); #else - method = is_server ? - TLSv1_1_server_method() : - TLSv1_1_client_method(); + method = is_server ? TLSv1_1_server_method() : TLSv1_1_client_method(); #endif break; case TLSv1_2: #if OPENSSL_VERSION_NUMBER < TLS1_1_MINIMAL_VERSION - LOG4CXX_WARN(logger_, - "OpenSSL has no TLSv1.2 with version lower 1.0.1, set TLSv1.0"); - method = is_server ? - TLSv1_server_method() : - TLSv1_client_method(); + LOG4CXX_WARN( + logger_, + "OpenSSL has no TLSv1.2 with version lower 1.0.1, set TLSv1.0"); + method = is_server ? TLSv1_server_method() : TLSv1_client_method(); #else - method = is_server ? - TLSv1_2_server_method() : - TLSv1_2_client_method(); + method = is_server ? TLSv1_2_server_method() : TLSv1_2_client_method(); #endif break; default: - LOG4CXX_ERROR(logger_, "Unknown protocol: " << protocol); + LOG4CXX_ERROR(logger_, + "Unknown protocol: " + << get_settings().security_manager_protocol_name()); return false; } + if (context_) { + free_ctx(&context_); + } context_ = SSL_CTX_new(method); + utils::ScopeGuard guard = utils::MakeGuard(free_ctx, &context_); + // Disable SSL2 as deprecated SSL_CTX_set_options(context_, SSL_OP_NO_SSLv2); - if (cert_filename.empty()) { - LOG4CXX_WARN(logger_, "Empty certificate path"); + set_certificate(get_settings().certificate_data()); + + if (get_settings().ciphers_list().empty()) { + LOG4CXX_WARN(logger_, "Empty ciphers list"); } else { - LOG4CXX_INFO(logger_, "Certificate path: " << cert_filename); - if (!SSL_CTX_use_certificate_file(context_, cert_filename.c_str(), - SSL_FILETYPE_PEM)) { - LOG4CXX_ERROR(logger_, "Could not use certificate " << cert_filename); + LOG4CXX_DEBUG(logger_, "Cipher list: " << get_settings().ciphers_list()); + if (!SSL_CTX_set_cipher_list(context_, + get_settings().ciphers_list().c_str())) { + LOG4CXX_ERROR( + logger_, + "Could not set cipher list: " << get_settings().ciphers_list()); return false; } } - if (key_filename.empty()) { - LOG4CXX_WARN(logger_, "Empty key path"); - } else { - LOG4CXX_INFO(logger_, "Key path: " << key_filename); - if (!SSL_CTX_use_PrivateKey_file(context_, key_filename.c_str(), - SSL_FILETYPE_PEM)) { - LOG4CXX_ERROR(logger_, "Could not use key " << key_filename); - return false; - } - if (!SSL_CTX_check_private_key(context_)) { - LOG4CXX_ERROR(logger_, "Could not use certificate " << cert_filename); - return false; - } + if (get_settings().ca_cert_path().empty()) { + LOG4CXX_WARN(logger_, "Setting up empty CA certificate location"); } - if (ciphers_list.empty()) { - LOG4CXX_WARN(logger_, "Empty ciphers list"); - } else { - LOG4CXX_INFO(logger_, "Cipher list: " << ciphers_list); - if (!SSL_CTX_set_cipher_list(context_, ciphers_list.c_str())) { - LOG4CXX_ERROR(logger_, "Could not set cipher list: " << ciphers_list); - return false; - } + LOG4CXX_DEBUG(logger_, "Setting up CA certificate location"); + const int result = SSL_CTX_load_verify_locations( + context_, NULL, get_settings().ca_cert_path().c_str()); + + if (!result) { + const unsigned long error = ERR_get_error(); + UNUSED(error); + LOG4CXX_WARN(logger_, + "Wrong certificate file '" + << get_settings().ca_cert_path() << "', err 0x" << std::hex + << error << " \"" << ERR_reason_error_string(error) + << '"'); } - // TODO(EZamakhov): add loading SSL_VERIFY_FAIL_IF_NO_PEER_CERT from INI - const int verify_mode = verify_peer - ? SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT - : SSL_VERIFY_NONE; - SSL_CTX_set_verify(context_, verify_mode, NULL); + guard.Dismiss(); + const int verify_mode = + get_settings().verify_peer() + ? SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT + : SSL_VERIFY_NONE; + LOG4CXX_DEBUG(logger_, + "Setting up peer verification in mode: " << verify_mode); + SSL_CTX_set_verify(context_, verify_mode, &debug_callback); return true; } -void CryptoManagerImpl::Finish() { - SSL_CTX_free(context_); - if (atomic_post_dec(&instance_count_) == 1) { - EVP_cleanup(); - ERR_free_strings(); +bool CryptoManagerImpl::OnCertificateUpdated(const std::string& data) { + LOG4CXX_AUTO_TRACE(logger_); + if (!context_) { + LOG4CXX_WARN(logger_, "Not initialized"); + return false; } + + return set_certificate(data); } SSLContext* CryptoManagerImpl::CreateSSLContext() { @@ -175,19 +237,21 @@ SSLContext* CryptoManagerImpl::CreateSSLContext() { return NULL; } - SSL *conn = SSL_new(context_); + SSL* conn = SSL_new(context_); if (conn == NULL) return NULL; - if (mode_ == SERVER) { + if (get_settings().security_manager_mode() == SERVER) { SSL_set_accept_state(conn); } else { SSL_set_connect_state(conn); } - return new SSLContextImpl(conn, mode_); + return new SSLContextImpl(conn, + get_settings().security_manager_mode(), + get_settings().maximum_payload_size()); } -void CryptoManagerImpl::ReleaseSSLContext(SSLContext *context) { +void CryptoManagerImpl::ReleaseSSLContext(SSLContext* context) { delete context; } @@ -195,8 +259,142 @@ std::string CryptoManagerImpl::LastError() const { if (!context_) { return std::string("Initialization is not completed"); } - const char *reason = ERR_reason_error_string(ERR_get_error()); + const char* reason = ERR_reason_error_string(ERR_get_error()); return std::string(reason ? reason : ""); } +bool CryptoManagerImpl::IsCertificateUpdateRequired() const { + LOG4CXX_AUTO_TRACE(logger_); + + const time_t cert_date = mktime(&expiration_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 expiration time: " << asctime(&expiration_time_)); + LOG4CXX_DEBUG(logger_, + "Host time: " << asctime(localtime(&now)) + << ". Seconds before expiration: " << seconds); + if (seconds < 0) { + LOG4CXX_WARN(logger_, "Certificate is already expired."); + return true; + } + + return seconds <= (get_settings().update_before_hours() * + date_time::DateTime::SECONDS_IN_HOUR); +} + +const CryptoManagerSettings& CryptoManagerImpl::get_settings() const { + return *settings_; +} + +bool CryptoManagerImpl::set_certificate(const std::string& cert_data) { + if (cert_data.empty()) { + LOG4CXX_WARN(logger_, "Empty certificate"); + return false; + } + + BIO* bio = BIO_new(BIO_f_base64()); + BIO* bmem = BIO_new_mem_buf((char*)cert_data.c_str(), cert_data.length()); + bmem = BIO_push(bio, bmem); + + char* buf = new char[cert_data.length()]; + int len = BIO_read(bmem, buf, cert_data.length()); + + BIO* bio_cert = BIO_new(BIO_s_mem()); + if (NULL == bio_cert) { + LOG4CXX_WARN(logger_, "Unable to update certificate. BIO not created"); + return false; + } + + utils::ScopeGuard bio_guard = utils::MakeGuard(BIO_free, bio_cert); + UNUSED(bio_guard) + int k = 0; + if ((k = BIO_write(bio_cert, buf, len)) <= 0) { + LOG4CXX_WARN(logger_, "Unable to write into BIO"); + return false; + } + + PKCS12* p12 = d2i_PKCS12_bio(bio_cert, NULL); + if (NULL == p12) { + LOG4CXX_ERROR(logger_, "Unable to parse certificate"); + return false; + } + + EVP_PKEY* pkey = NULL; + X509* cert = NULL; + PKCS12_parse(p12, NULL, &pkey, &cert, NULL); + + if (NULL == cert || NULL == pkey) { + LOG4CXX_WARN(logger_, "Either certificate or key not valid."); + return false; + } + + if (!SSL_CTX_use_certificate(context_, cert)) { + LOG4CXX_WARN(logger_, "Could not use certificate"); + return false; + } + + asn1_time_to_tm(X509_get_notAfter(cert)); + + if (!SSL_CTX_use_PrivateKey(context_, pkey)) { + LOG4CXX_ERROR(logger_, "Could not use key"); + return false; + } + if (!SSL_CTX_check_private_key(context_)) { + LOG4CXX_ERROR(logger_, "Could not use certificate "); + return false; + } + return true; +} + +int CryptoManagerImpl::pull_number_from_buf(char* buf, int* idx) { + if (!idx) { + return 0; + } + const int val = ((buf[*idx] - '0') * 10) + buf[(*idx) + 1] - '0'; + *idx = *idx + 2; + return val; +} + +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; + } + + 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); + + expiration_time_.tm_mon = mon - 1; + expiration_time_.tm_mday = day; + expiration_time_.tm_hour = hour; + expiration_time_.tm_min = mn; + + if (buf[index] == 'Z') { + expiration_time_.tm_sec = 0; + } + 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; + } +} + } // 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 dee1770e70..556cc291d1 100644 --- a/src/components/security_manager/src/security_manager_impl.cc +++ b/src/components/security_manager/src/security_manager_impl.cc @@ -45,9 +45,10 @@ static const char* kErrId = "id"; static const char* kErrText = "text"; SecurityManagerImpl::SecurityManagerImpl() - : security_messages_("SecurityManager", this), - session_observer_(NULL), crypto_manager_(NULL), protocol_handler_(NULL) { -} + : security_messages_("SecurityManager", this) + , session_observer_(NULL) + , crypto_manager_(NULL) + , protocol_handler_(NULL) {} void SecurityManagerImpl::OnMessageReceived( const ::protocol_handler::RawMessagePtr message) { @@ -56,14 +57,14 @@ void SecurityManagerImpl::OnMessageReceived( } SecurityMessage securityMessagePtr(new SecurityQuery()); - const bool result = securityMessagePtr->SerializeQuery( - message->data(), message->data_size()); + const bool result = + securityMessagePtr->SerializeQuery(message->data(), message->data_size()); if (!result) { // result will be false only if data less then query header const std::string error_text("Incorrect message received"); LOG4CXX_ERROR(logger_, error_text); - SendInternalError(message->connection_key(), - ERROR_INVALID_QUERY_SIZE, error_text); + SendInternalError( + message->connection_key(), ERROR_INVALID_QUERY_SIZE, error_text); return; } securityMessagePtr->set_connection_key(message->connection_key()); @@ -73,11 +74,10 @@ void SecurityManagerImpl::OnMessageReceived( } void SecurityManagerImpl::OnMobileMessageSent( - const ::protocol_handler::RawMessagePtr ) { -} + const ::protocol_handler::RawMessagePtr) {} void SecurityManagerImpl::set_session_observer( - protocol_handler::SessionObserver *observer) { + protocol_handler::SessionObserver* observer) { if (!observer) { LOG4CXX_ERROR(logger_, "Invalid (NULL) pointer to SessionObserver."); return; @@ -86,7 +86,7 @@ void SecurityManagerImpl::set_session_observer( } void SecurityManagerImpl::set_protocol_handler( - protocol_handler::ProtocolHandler *handler) { + protocol_handler::ProtocolHandler* handler) { if (!handler) { LOG4CXX_ERROR(logger_, "Invalid (NULL) pointer to ProtocolHandler."); return; @@ -94,7 +94,7 @@ void SecurityManagerImpl::set_protocol_handler( protocol_handler_ = handler; } -void SecurityManagerImpl::set_crypto_manager(CryptoManager *crypto_manager) { +void SecurityManagerImpl::set_crypto_manager(CryptoManager* crypto_manager) { if (!crypto_manager) { LOG4CXX_ERROR(logger_, "Invalid (NULL) pointer to CryptoManager."); return; @@ -105,11 +105,11 @@ void SecurityManagerImpl::set_crypto_manager(CryptoManager *crypto_manager) { void SecurityManagerImpl::Handle(const SecurityMessage message) { DCHECK(message); LOG4CXX_INFO(logger_, "Received Security message from Mobile side"); - if (!crypto_manager_) { + if (!crypto_manager_) { const std::string error_text("Invalid (NULL) CryptoManager."); LOG4CXX_ERROR(logger_, error_text); - SendInternalError(message->get_connection_key(), - ERROR_NOT_SUPPORTED, error_text); + SendInternalError( + message->get_connection_key(), ERROR_NOT_SUPPORTED, error_text); return; } switch (message->get_header().query_id) { @@ -128,21 +128,21 @@ void SecurityManagerImpl::Handle(const SecurityMessage message) { const std::string error_text("Unknown query identifier."); LOG4CXX_ERROR(logger_, error_text); SendInternalError(message->get_connection_key(), - ERROR_INVALID_QUERY_ID, error_text, + ERROR_INVALID_QUERY_ID, + error_text, message->get_header().seq_number); - } - break; - } + } break; + } } -security_manager::SSLContext *SecurityManagerImpl::CreateSSLContext( - const uint32_t &connection_key) { +security_manager::SSLContext* SecurityManagerImpl::CreateSSLContext( + const uint32_t& connection_key) { LOG4CXX_INFO(logger_, "ProtectService processing"); DCHECK(session_observer_); DCHECK(crypto_manager_); - security_manager::SSLContext *ssl_context = - session_observer_->GetSSLContext(connection_key, protocol_handler::kControl); + 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; @@ -153,12 +153,12 @@ security_manager::SSLContext *SecurityManagerImpl::CreateSSLContext( const std::string error_text("CryptoManager could not create SSL context."); LOG4CXX_ERROR(logger_, error_text); // Generate response query and post to security_messages_ - SendInternalError(connection_key, ERROR_INTERNAL, - error_text); + SendInternalError(connection_key, ERROR_INTERNAL, error_text); return NULL; } - const int result = session_observer_->SetSSLContext(connection_key, ssl_context); + const int result = + session_observer_->SetSSLContext(connection_key, ssl_context); if (ERROR_SUCCESS != result) { // delete SSLContext on any error crypto_manager_->ReleaseSSLContext(ssl_context); @@ -167,38 +167,51 @@ security_manager::SSLContext *SecurityManagerImpl::CreateSSLContext( } DCHECK(session_observer_->GetSSLContext(connection_key, protocol_handler::kControl)); - LOG4CXX_DEBUG(logger_, "Set SSL context to connection_key " << connection_key); + LOG4CXX_DEBUG(logger_, + "Set SSL context to connection_key " << connection_key); return ssl_context; } void SecurityManagerImpl::StartHandshake(uint32_t connection_key) { DCHECK(session_observer_); LOG4CXX_INFO(logger_, "StartHandshake: connection_key " << connection_key); - security_manager::SSLContext *ssl_context = - session_observer_->GetSSLContext(connection_key, - protocol_handler::kControl); + security_manager::SSLContext* ssl_context = session_observer_->GetSSLContext( + connection_key, protocol_handler::kControl); if (!ssl_context) { - const std::string error_text("StartHandshake failed, " - "connection is not protected"); + const std::string error_text( + "StartHandshake failed, " + "connection is not protected"); LOG4CXX_ERROR(logger_, error_text); SendInternalError(connection_key, ERROR_INTERNAL, error_text); - NotifyListenersOnHandshakeDone(connection_key, false); + NotifyListenersOnHandshakeDone(connection_key, + SSLContext::Handshake_Result_Fail); return; } + if (crypto_manager_->IsCertificateUpdateRequired()) { + NotifyOnCertififcateUpdateRequired(); + } + if (ssl_context->IsInitCompleted()) { - NotifyListenersOnHandshakeDone(connection_key, true); + NotifyListenersOnHandshakeDone(connection_key, + SSLContext::Handshake_Result_Success); return; } + + ssl_context->SetHandshakeContext( + session_observer_->GetHandshakeContext(connection_key)); + size_t data_size = 0; - const uint8_t *data = NULL; + const uint8_t* data = NULL; + const security_manager::SSLContext::HandshakeResult result = ssl_context->StartHandshake(&data, &data_size); if (security_manager::SSLContext::Handshake_Result_Success != result) { const std::string error_text("StartHandshake failed, handshake step fail"); LOG4CXX_ERROR(logger_, error_text); SendInternalError(connection_key, ERROR_INTERNAL, error_text); - NotifyListenersOnHandshakeDone(connection_key, false); + NotifyListenersOnHandshakeDone(connection_key, + SSLContext::Handshake_Result_Fail); return; } // for client mode will be generated output data @@ -206,26 +219,29 @@ void SecurityManagerImpl::StartHandshake(uint32_t connection_key) { SendHandshakeBinData(connection_key, data, data_size); } } -void SecurityManagerImpl::AddListener(SecurityManagerListener *const listener) { +void SecurityManagerImpl::AddListener(SecurityManagerListener* const listener) { if (!listener) { - LOG4CXX_ERROR(logger_, "Invalid (NULL) pointer to SecurityManagerListener."); + LOG4CXX_ERROR(logger_, + "Invalid (NULL) pointer to SecurityManagerListener."); return; } listeners_.push_back(listener); } -void SecurityManagerImpl::RemoveListener(SecurityManagerListener *const listener) { +void SecurityManagerImpl::RemoveListener( + SecurityManagerListener* const listener) { if (!listener) { - LOG4CXX_ERROR(logger_, "Invalid (NULL) pointer to SecurityManagerListener."); + LOG4CXX_ERROR(logger_, + "Invalid (NULL) pointer to SecurityManagerListener."); return; } listeners_.remove(listener); } -void SecurityManagerImpl::NotifyListenersOnHandshakeDone(const uint32_t &connection_key, - const bool success) { - LOG4CXX_TRACE(logger_, "NotifyListenersOnHandshakeDone"); +void SecurityManagerImpl::NotifyListenersOnHandshakeDone( + const uint32_t& connection_key, SSLContext::HandshakeResult error) { + LOG4CXX_AUTO_TRACE(logger_); std::list<SecurityManagerListener*>::iterator it = listeners_.begin(); while (it != listeners_.end()) { - if ((*it)->OnHandshakeDone(connection_key, success)) { + if ((*it)->OnHandshakeDone(connection_key, error)) { // On get notification remove listener it = listeners_.erase(it); } else { @@ -234,140 +250,166 @@ void SecurityManagerImpl::NotifyListenersOnHandshakeDone(const uint32_t &connect } } -bool SecurityManagerImpl::ProccessHandshakeData(const SecurityMessage &inMessage) { +void SecurityManagerImpl::NotifyOnCertififcateUpdateRequired() { + LOG4CXX_AUTO_TRACE(logger_); + std::list<SecurityManagerListener*>::iterator it = listeners_.begin(); + while (it != listeners_.end()) { + (*it)->OnCertificateUpdateRequired(); + ++it; + } +} + +bool SecurityManagerImpl::ProccessHandshakeData( + const SecurityMessage& inMessage) { LOG4CXX_INFO(logger_, "SendHandshakeData processing"); DCHECK(inMessage); - DCHECK(inMessage->get_header().query_id == SecurityQuery::SEND_HANDSHAKE_DATA); + DCHECK(inMessage->get_header().query_id == + SecurityQuery::SEND_HANDSHAKE_DATA); const uint32_t seqNumber = inMessage->get_header().seq_number; const uint32_t connection_key = inMessage->get_connection_key(); - LOG4CXX_DEBUG(logger_, "Received " << inMessage->get_data_size() - << " bytes handshake data "); + LOG4CXX_DEBUG(logger_, + "Received " << inMessage->get_data_size() + << " bytes handshake data "); if (!inMessage->get_data_size()) { const std::string error_text("SendHandshakeData: null arguments size."); LOG4CXX_ERROR(logger_, error_text); - SendInternalError(connection_key, ERROR_INVALID_QUERY_SIZE, - error_text, seqNumber); + SendInternalError( + connection_key, ERROR_INVALID_QUERY_SIZE, error_text, seqNumber); return false; } DCHECK(session_observer_); - SSLContext *sslContext = - session_observer_->GetSSLContext(connection_key, - protocol_handler::kControl); + SSLContext* sslContext = session_observer_->GetSSLContext( + connection_key, protocol_handler::kControl); if (!sslContext) { const std::string error_text("SendHandshakeData: No ssl context."); LOG4CXX_ERROR(logger_, error_text); - SendInternalError(connection_key, ERROR_SERVICE_NOT_PROTECTED, - error_text, seqNumber); - NotifyListenersOnHandshakeDone(connection_key, false); + SendInternalError( + connection_key, ERROR_SERVICE_NOT_PROTECTED, error_text, seqNumber); + NotifyListenersOnHandshakeDone(connection_key, + SSLContext::Handshake_Result_Fail); return false; } size_t out_data_size; - const uint8_t *out_data; + const uint8_t* out_data; const SSLContext::HandshakeResult handshake_result = - sslContext->DoHandshakeStep(inMessage->get_data(), inMessage->get_data_size(), - &out_data, &out_data_size); + sslContext->DoHandshakeStep(inMessage->get_data(), + inMessage->get_data_size(), + &out_data, + &out_data_size); if (handshake_result == SSLContext::Handshake_Result_AbnormalFail) { // Do not return handshake data on AbnormalFail or null returned values const std::string erorr_text(sslContext->LastError()); - LOG4CXX_ERROR(logger_, "SendHandshakeData: Handshake failed: " << erorr_text); - SendInternalError(connection_key, - ERROR_SSL_INVALID_DATA, erorr_text, seqNumber); - NotifyListenersOnHandshakeDone(connection_key, false); + LOG4CXX_ERROR(logger_, + "SendHandshakeData: Handshake failed: " << erorr_text); + SendInternalError( + connection_key, ERROR_SSL_INVALID_DATA, erorr_text, seqNumber); + NotifyListenersOnHandshakeDone(connection_key, + SSLContext::Handshake_Result_Fail); // no handshake data to send return false; } if (sslContext->IsInitCompleted()) { // On handshake success LOG4CXX_DEBUG(logger_, "SSL initialization finished success."); - NotifyListenersOnHandshakeDone(connection_key, true); - } else if (handshake_result == SSLContext::Handshake_Result_Fail) { + NotifyListenersOnHandshakeDone(connection_key, + SSLContext::Handshake_Result_Success); + } else if (handshake_result != SSLContext::Handshake_Result_Success) { // On handshake fail LOG4CXX_WARN(logger_, "SSL initialization finished with fail."); - NotifyListenersOnHandshakeDone(connection_key, false); + NotifyListenersOnHandshakeDone(connection_key, handshake_result); } if (out_data && out_data_size) { // answer with the same seqNumber as income message - SendHandshakeBinData(connection_key, out_data, out_data_size, - seqNumber); + SendHandshakeBinData(connection_key, out_data, out_data_size, seqNumber); } return true; } -bool SecurityManagerImpl::ProccessInternalError(const SecurityMessage &inMessage) { - LOG4CXX_INFO(logger_, "Received InternalError with Json message" - << inMessage->get_json_message()); +bool SecurityManagerImpl::ProccessInternalError( + const SecurityMessage& inMessage) { + LOG4CXX_INFO(logger_, + "Received InternalError with Json message" + << inMessage->get_json_message()); Json::Value root; Json::Reader reader; const bool parsingSuccessful = reader.parse(inMessage->get_json_message(), root); if (!parsingSuccessful) return false; - LOG4CXX_DEBUG(logger_, "Received InternalError id " << root[kErrId].asString() - << ", text: " << root[kErrText].asString()); + LOG4CXX_DEBUG(logger_, + "Received InternalError id " + << root[kErrId].asString() + << ", text: " << root[kErrText].asString()); return true; } -void SecurityManagerImpl::SendHandshakeBinData( - const uint32_t connection_key, const uint8_t *const data, - const size_t data_size, const uint32_t seq_number) { - const SecurityQuery::QueryHeader header( - SecurityQuery::NOTIFICATION, - SecurityQuery::SEND_HANDSHAKE_DATA, seq_number); - DCHECK(data_size < 1024 * 1024 *1024 ); - const SecurityQuery query = SecurityQuery(header, connection_key, data, data_size); +void SecurityManagerImpl::SendHandshakeBinData(const uint32_t connection_key, + const uint8_t* const data, + const size_t data_size, + const uint32_t seq_number) { + const SecurityQuery::QueryHeader header(SecurityQuery::NOTIFICATION, + SecurityQuery::SEND_HANDSHAKE_DATA, + seq_number); + DCHECK(data_size < 1024 * 1024 * 1024); + const SecurityQuery query = + SecurityQuery(header, connection_key, data, data_size); SendQuery(query, connection_key); LOG4CXX_DEBUG(logger_, "Sent " << data_size << " bytes handshake data "); } void SecurityManagerImpl::SendInternalError(const uint32_t connection_key, - const uint8_t &error_id, - const std::string &erorr_text, - const uint32_t seq_number) { + const uint8_t& error_id, + const std::string& erorr_text, + const uint32_t seq_number) { Json::Value value; - value[kErrId] = error_id; + value[kErrId] = error_id; value[kErrText] = erorr_text; const std::string error_str = value.toStyledString(); - SecurityQuery::QueryHeader header(SecurityQuery::NOTIFICATION, - SecurityQuery::SEND_INTERNAL_ERROR, - // header save json size only (exclude last byte) - seq_number, error_str.size()); + SecurityQuery::QueryHeader header( + SecurityQuery::NOTIFICATION, + SecurityQuery::SEND_INTERNAL_ERROR, + // header save json size only (exclude last byte) + seq_number, + error_str.size()); // Raw data is json string and error id at last byte std::vector<uint8_t> data_sending(error_str.size() + 1); memcpy(&data_sending[0], error_str.c_str(), error_str.size()); - data_sending[data_sending.size()-1] = error_id; + data_sending[data_sending.size() - 1] = error_id; - const SecurityQuery query(header, connection_key, - &data_sending[0], data_sending.size()); + const SecurityQuery query( + header, connection_key, &data_sending[0], data_sending.size()); SendQuery(query, connection_key); - LOG4CXX_DEBUG(logger_, "Sent Internal error id " << static_cast<int>(error_id) - << " : \"" << erorr_text << "\"."); + LOG4CXX_DEBUG(logger_, + "Sent Internal error id " << static_cast<int>(error_id) + << " : \"" << erorr_text << "\"."); } void SecurityManagerImpl::SendQuery(const SecurityQuery& query, - const uint32_t connection_key) { + const uint32_t connection_key) { const std::vector<uint8_t> data_sending = query.DeserializeQuery(); uint32_t connection_handle = 0; uint8_t sessionID = 0; uint8_t protocol_version; - session_observer_->PairFromKey(connection_key, &connection_handle, - &sessionID); - if (session_observer_->ProtocolVersionUsed(connection_handle, sessionID, - protocol_version)) { + session_observer_->PairFromKey( + connection_key, &connection_handle, &sessionID); + if (session_observer_->ProtocolVersionUsed( + connection_handle, sessionID, protocol_version)) { const ::protocol_handler::RawMessagePtr rawMessagePtr( - new protocol_handler::RawMessage(connection_key, - protocol_version, - &data_sending[0], data_sending.size(), - protocol_handler::kControl)); + new protocol_handler::RawMessage(connection_key, + protocol_version, + &data_sending[0], + data_sending.size(), + protocol_handler::kControl)); DCHECK(protocol_handler_); // Add RawMessage to ProtocolHandler message query protocol_handler_->SendMessageToMobileApp(rawMessagePtr, false); } } -const char *SecurityManagerImpl::ConfigSection() { +const char* SecurityManagerImpl::ConfigSection() { return "Security Manager"; } diff --git a/src/components/security_manager/src/security_query.cc b/src/components/security_manager/src/security_query.cc index cd4da03c15..60233dde5e 100644 --- a/src/components/security_manager/src/security_query.cc +++ b/src/components/security_manager/src/security_query.cc @@ -38,35 +38,37 @@ namespace security_manager { SecurityQuery::QueryHeader::QueryHeader() - : query_type(INVALID_QUERY_TYPE), query_id(INVALID_QUERY_ID), - seq_number(0), json_size(0) { -} - -SecurityQuery::QueryHeader::QueryHeader(uint8_t queryType, uint32_t queryId, - uint32_t seqNumber, uint32_t jsonSize) - : query_type(queryType), query_id(queryId), - seq_number(seqNumber), json_size(jsonSize) { -} + : query_type(INVALID_QUERY_TYPE) + , query_id(INVALID_QUERY_ID) + , seq_number(0) + , json_size(0) {} + +SecurityQuery::QueryHeader::QueryHeader(uint8_t queryType, + uint32_t queryId, + uint32_t seqNumber, + uint32_t jsonSize) + : query_type(queryType) + , query_id(queryId) + , seq_number(seqNumber) + , json_size(jsonSize) {} SecurityQuery::SecurityQuery() - : header_(INVALID_QUERY_TYPE, INVALID_QUERY_ID, 0), connection_key_(0) { -} + : header_(INVALID_QUERY_TYPE, INVALID_QUERY_ID, 0), connection_key_(0) {} -SecurityQuery::SecurityQuery(const SecurityQuery::QueryHeader &header, +SecurityQuery::SecurityQuery(const SecurityQuery::QueryHeader& header, const uint32_t connection_key, - const uint8_t *const raw_data, + const uint8_t* const raw_data, const size_t raw_data_size) - : header_(header), connection_key_(connection_key), - data_(raw_data, raw_data + raw_data_size) { -} + : header_(header) + , connection_key_(connection_key) + , data_(raw_data, raw_data + raw_data_size) {} -SecurityQuery::SecurityQuery(const SecurityQuery::QueryHeader &header, +SecurityQuery::SecurityQuery(const SecurityQuery::QueryHeader& header, const uint32_t connection_key) - : header_(header), connection_key_(connection_key) { -} + : header_(header), connection_key_(connection_key) {} -bool SecurityQuery::SerializeQuery(const uint8_t *const raw_data, - const size_t raw_data_size) { +bool SecurityQuery::SerializeQuery(const uint8_t* const raw_data, + const size_t raw_data_size) { const size_t header_size = sizeof(QueryHeader); if (raw_data_size < header_size || !raw_data) { return false; @@ -74,21 +76,21 @@ bool SecurityQuery::SerializeQuery(const uint8_t *const raw_data, const uint8_t query_type = raw_data[0]; switch (query_type) { case REQUEST: - header_.query_type = REQUEST; + header_.query_type = REQUEST; break; case RESPONSE: - header_.query_type = RESPONSE; + header_.query_type = RESPONSE; break; case NOTIFICATION: - header_.query_type = NOTIFICATION; + header_.query_type = NOTIFICATION; break; default: header_.query_type = INVALID_QUERY_TYPE; break; } // Convert to Little-Endian and clean high byte - const uint32_t query_id = 0x00FFFFFF & - BE_TO_LE32(*reinterpret_cast<const uint32_t*>(raw_data)); + const uint32_t query_id = + 0x00FFFFFF & BE_TO_LE32(*reinterpret_cast<const uint32_t*>(raw_data)); switch (query_id) { case SEND_HANDSHAKE_DATA: header_.query_id = SEND_HANDSHAKE_DATA; @@ -100,22 +102,25 @@ bool SecurityQuery::SerializeQuery(const uint8_t *const raw_data, header_.query_id = INVALID_QUERY_ID; break; } - header_.seq_number = BE_TO_LE32(*reinterpret_cast<const uint32_t*>(raw_data + 4)); - header_.json_size = BE_TO_LE32(*reinterpret_cast<const uint32_t*>(raw_data + 8)); + header_.seq_number = + BE_TO_LE32(*reinterpret_cast<const uint32_t*>(raw_data + 4)); + header_.json_size = + BE_TO_LE32(*reinterpret_cast<const uint32_t*>(raw_data + 8)); if (header_.json_size > raw_data_size - header_size) return false; if (header_.json_size > 0) { - const char *const json_data = + const char* const json_data = reinterpret_cast<const char*>(raw_data + header_size); json_message_.assign(json_data, json_data + header_.json_size); } - const uint32_t bin_data_size = raw_data_size - (header_size + header_.json_size); + const uint32_t bin_data_size = + raw_data_size - (header_size + header_.json_size); if (bin_data_size > 0) { - const char *const bin_data = - reinterpret_cast<const char*>(raw_data + header_size + header_.json_size); + const char* const bin_data = reinterpret_cast<const char*>( + raw_data + header_size + header_.json_size); data_.assign(bin_data, bin_data + bin_data_size); } return true; @@ -124,31 +129,33 @@ bool SecurityQuery::SerializeQuery(const uint8_t *const raw_data, const std::vector<uint8_t> SecurityQuery::DeserializeQuery() const { SecurityQuery::QueryHeader deserialize_header(header_); const uint32_t tmp = deserialize_header.query_id << 8; - deserialize_header.query_id = LE_TO_BE32(tmp); + deserialize_header.query_id = LE_TO_BE32(tmp); deserialize_header.seq_number = LE_TO_BE32(deserialize_header.seq_number); - deserialize_header.json_size = LE_TO_BE32(deserialize_header.json_size); + deserialize_header.json_size = LE_TO_BE32(deserialize_header.json_size); const size_t header_size = sizeof(deserialize_header); // vector of header and raw_data - std::vector<uint8_t> data_sending(header_size + data_.size() + json_message_.size()); + std::vector<uint8_t> data_sending(header_size + data_.size() + + json_message_.size()); // copy header memcpy(&data_sending[0], &deserialize_header, header_size); // copy binary data std::copy(data_.begin(), data_.end(), data_sending.begin() + header_size); // copy text (json) data - std::copy(json_message_.begin(), json_message_.end(), + std::copy(json_message_.begin(), + json_message_.end(), data_sending.begin() + header_size + data_.size()); return data_sending; } -void SecurityQuery::set_data(const uint8_t *const binary_data, - const size_t bin_data_size) { - DCHECK(binary_data); - DCHECK(bin_data_size); - data_.assign(binary_data, binary_data + bin_data_size); +void SecurityQuery::set_data(const uint8_t* const binary_data, + const size_t bin_data_size) { + DCHECK(binary_data); + DCHECK(bin_data_size); + data_.assign(binary_data, binary_data + bin_data_size); } -void SecurityQuery::set_json_message(const std::string &json_message) { +void SecurityQuery::set_json_message(const std::string& json_message) { json_message_ = json_message; } @@ -156,11 +163,11 @@ void SecurityQuery::set_connection_key(const uint32_t connection_key) { connection_key_ = connection_key; } -void SecurityQuery::set_header(const SecurityQuery::QueryHeader &header) { +void SecurityQuery::set_header(const SecurityQuery::QueryHeader& header) { header_ = header; } -const SecurityQuery::QueryHeader &SecurityQuery::get_header() const { +const SecurityQuery::QueryHeader& SecurityQuery::get_header() const { return header_; } @@ -172,7 +179,7 @@ size_t SecurityQuery::get_data_size() const { return data_.size(); } -const std::string &SecurityQuery::get_json_message() const { +const std::string& SecurityQuery::get_json_message() const { return json_message_; } diff --git a/src/components/security_manager/src/ssl_context_impl.cc b/src/components/security_manager/src/ssl_context_impl.cc index 09c2efd196..6f53234867 100644 --- a/src/components/security_manager/src/ssl_context_impl.cc +++ b/src/components/security_manager/src/ssl_context_impl.cc @@ -37,22 +37,25 @@ #include <openssl/err.h> #include <memory.h> #include <map> +#include <algorithm> #include "utils/macro.h" namespace security_manager { -CryptoManagerImpl::SSLContextImpl::SSLContextImpl(SSL *conn, Mode mode) - : connection_(conn), - bioIn_(BIO_new(BIO_s_mem())), - bioOut_(BIO_new(BIO_s_mem())), - bioFilter_(NULL), - // TODO(EZamakhov): get MTU by parameter (from transport) - // default buffer size is TCP MTU - buffer_size_(1500), - buffer_(new uint8_t[buffer_size_]), - is_handshake_pending_(false), - mode_(mode) { +CREATE_LOGGERPTR_GLOBAL(logger_, "SecurityManager") + +CryptoManagerImpl::SSLContextImpl::SSLContextImpl(SSL* conn, + Mode mode, + size_t maximum_payload_size) + : connection_(conn) + , bioIn_(BIO_new(BIO_s_mem())) + , bioOut_(BIO_new(BIO_s_mem())) + , bioFilter_(NULL) + , buffer_size_(maximum_payload_size) + , buffer_(new uint8_t[buffer_size_]) + , is_handshake_pending_(false) + , mode_(mode) { SSL_set_bio(connection_, bioIn_, bioOut_); } @@ -60,7 +63,7 @@ std::string CryptoManagerImpl::SSLContextImpl::LastError() const { if (!IsInitCompleted()) { return std::string("Initialization is not completed"); } - const char *reason = ERR_reason_error_string(ERR_get_error()); + const char* reason = ERR_reason_error_string(ERR_get_error()); return std::string(reason ? reason : ""); } @@ -69,137 +72,273 @@ bool CryptoManagerImpl::SSLContextImpl::IsInitCompleted() const { return SSL_is_init_finished(connection_); } -SSLContext::HandshakeResult CryptoManagerImpl::SSLContextImpl:: -StartHandshake(const uint8_t** const out_data, size_t *out_data_size) { +SSLContext::HandshakeResult CryptoManagerImpl::SSLContextImpl::StartHandshake( + const uint8_t** const out_data, size_t* out_data_size) { is_handshake_pending_ = true; return DoHandshakeStep(NULL, 0, out_data, out_data_size); } namespace { - size_t aes128_gcm_sha256_max_block_size(size_t mtu) { - if (mtu < 29) - return 0; - return mtu - 29; - } - size_t rc4_md5_max_block_size(size_t mtu) { - if (mtu < 21) - return 0; - return mtu - 21; - } - size_t rc4_sha_max_block_size(size_t mtu) { - if (mtu < 25) - return 0; - return mtu - 25; - } - size_t seed_sha_max_block_size(size_t mtu) { - if (mtu < 53) - return 0; - return ((mtu - 37) & 0xfffffff0) - 5; - } - size_t aes128_sha256_max_block_size(size_t mtu) { - if (mtu < 69) - return 0; - return ((mtu - 53) & 0xfffffff0) - 1; - } - size_t des_cbc3_sha_max_block_size(size_t mtu) { - if (mtu < 37) - return 0; - return ((mtu - 29) & 0xfffffff8) - 5; - } +size_t aes128_gcm_sha256_max_block_size(size_t mtu) { + if (mtu < 29) + return 0; + return mtu - 29; +} +size_t rc4_md5_max_block_size(size_t mtu) { + if (mtu < 21) + return 0; + return mtu - 21; +} +size_t rc4_sha_max_block_size(size_t mtu) { + if (mtu < 25) + return 0; + return mtu - 25; +} +size_t seed_sha_max_block_size(size_t mtu) { + if (mtu < 53) + return 0; + return ((mtu - 37) & 0xfffffff0) - 5; +} +size_t aes128_sha256_max_block_size(size_t mtu) { + if (mtu < 69) + return 0; + return ((mtu - 53) & 0xfffffff0) - 1; +} +size_t des_cbc3_sha_max_block_size(size_t mtu) { + if (mtu < 37) + return 0; + return ((mtu - 29) & 0xfffffff8) - 5; +} } // namespace std::map<std::string, CryptoManagerImpl::SSLContextImpl::BlockSizeGetter> CryptoManagerImpl::SSLContextImpl::create_max_block_sizes() { std::map<std::string, CryptoManagerImpl::SSLContextImpl::BlockSizeGetter> rc; - rc.insert(std::make_pair("AES128-GCM-SHA256", aes128_gcm_sha256_max_block_size)); - rc.insert(std::make_pair("AES128-SHA256", aes128_sha256_max_block_size)); - rc.insert(std::make_pair("AES128-SHA", seed_sha_max_block_size)); - rc.insert(std::make_pair("AES256-GCM-SHA384", aes128_gcm_sha256_max_block_size)); - rc.insert(std::make_pair("AES256-SHA256", aes128_sha256_max_block_size)); - rc.insert(std::make_pair("AES256-SHA", seed_sha_max_block_size)); - rc.insert(std::make_pair("CAMELLIA128-SHA", seed_sha_max_block_size)); - rc.insert(std::make_pair("CAMELLIA256-SHA", seed_sha_max_block_size)); - rc.insert(std::make_pair("DES-CBC3-SHA", des_cbc3_sha_max_block_size)); - rc.insert(std::make_pair("DES-CBC-SHA", des_cbc3_sha_max_block_size)); - rc.insert(std::make_pair("RC4-MD5", rc4_md5_max_block_size)); - rc.insert(std::make_pair("RC4-SHA", rc4_sha_max_block_size)); - rc.insert(std::make_pair("SEED-SHA", seed_sha_max_block_size)); + rc.insert( + std::make_pair("AES128-GCM-SHA256", aes128_gcm_sha256_max_block_size)); + rc.insert(std::make_pair("AES128-SHA256", aes128_sha256_max_block_size)); + rc.insert(std::make_pair("AES128-SHA", seed_sha_max_block_size)); + rc.insert( + std::make_pair("AES256-GCM-SHA384", aes128_gcm_sha256_max_block_size)); + rc.insert(std::make_pair("AES256-SHA256", aes128_sha256_max_block_size)); + rc.insert(std::make_pair("AES256-SHA", seed_sha_max_block_size)); + rc.insert(std::make_pair("CAMELLIA128-SHA", seed_sha_max_block_size)); + rc.insert(std::make_pair("CAMELLIA256-SHA", seed_sha_max_block_size)); + rc.insert(std::make_pair("DES-CBC3-SHA", des_cbc3_sha_max_block_size)); + rc.insert(std::make_pair("DES-CBC-SHA", des_cbc3_sha_max_block_size)); + rc.insert(std::make_pair("RC4-MD5", rc4_md5_max_block_size)); + rc.insert(std::make_pair("RC4-SHA", rc4_sha_max_block_size)); + rc.insert(std::make_pair("SEED-SHA", seed_sha_max_block_size)); return rc; } std::map<std::string, CryptoManagerImpl::SSLContextImpl::BlockSizeGetter> -CryptoManagerImpl::SSLContextImpl::max_block_sizes = - CryptoManagerImpl::SSLContextImpl::create_max_block_sizes(); + CryptoManagerImpl::SSLContextImpl::max_block_sizes = + CryptoManagerImpl::SSLContextImpl::create_max_block_sizes(); + +void CryptoManagerImpl::SSLContextImpl::PrintCertData( + X509* cert, const std::string& cert_owner) { + if (cert) { + X509_NAME* subj_name = X509_get_subject_name(cert); + char* subj = X509_NAME_oneline(subj_name, NULL, 0); + if (subj) { + std::replace(subj, subj + strlen(subj), '/', ' '); + LOG4CXX_DEBUG(logger_, cert_owner << " subject:" << subj); + OPENSSL_free(subj); + } + char* issuer = X509_NAME_oneline(X509_get_issuer_name(cert), NULL, 0); + if (issuer) { + std::replace(issuer, issuer + strlen(issuer), '/', ' '); + LOG4CXX_DEBUG(logger_, cert_owner << " issuer:" << issuer); + OPENSSL_free(issuer); + } -SSLContext::HandshakeResult CryptoManagerImpl::SSLContextImpl:: -DoHandshakeStep(const uint8_t* const in_data, size_t in_data_size, - const uint8_t** const out_data, size_t* out_data_size) { - DCHECK(out_data); - DCHECK(out_data_size); - *out_data = NULL; - *out_data_size = 0; - // TODO(Ezamakhov): add test - hanshake fail -> restart StartHandshake - sync_primitives::AutoLock locker(bio_locker); - if (SSL_is_init_finished(connection_)) { - is_handshake_pending_ = false; - return SSLContext::Handshake_Result_Success; + ASN1_TIME* notBefore = X509_get_notBefore(cert); + ASN1_TIME* notAfter = X509_get_notAfter(cert); + + if (notBefore) { + LOG4CXX_DEBUG(logger_, " Start date: " << (char*)notBefore->data); + } + if (notAfter) { + LOG4CXX_DEBUG(logger_, " End date: " << (char*)notAfter->data); + } } +} + +void CryptoManagerImpl::SSLContextImpl::PrintCertInfo() { + PrintCertData(SSL_get_certificate(connection_), "HU's"); + + STACK_OF(X509)* peer_certs = SSL_get_peer_cert_chain(connection_); + while (sk_X509_num(peer_certs) > 0) { + X509* cert = sk_X509_pop(peer_certs); + PrintCertData(cert, "SERVERS"); + } +} + +SSLContext::HandshakeResult +CryptoManagerImpl::SSLContextImpl::CheckCertContext() { + 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; + } + + X509_NAME* subj_name = X509_get_subject_name(cert); + + const std::string& cn = GetTextBy(subj_name, NID_commonName); + const std::string& sn = GetTextBy(subj_name, NID_serialNumber); + + if (!(hsh_context_.expected_cn.CompareIgnoreCase(cn.c_str()))) { + LOG4CXX_ERROR(logger_, + "Trying to run handshake with wrong app name: " + << cn << ". Expected app name: " + << hsh_context_.expected_cn.AsMBString()); + return Handshake_Result_AppNameMismatch; + } + + if (!(hsh_context_.expected_sn.CompareIgnoreCase(sn.c_str()))) { + LOG4CXX_ERROR(logger_, + "Trying to run handshake with wrong app id: " + << sn << ". Expected app id: " + << hsh_context_.expected_sn.AsMBString()); + return Handshake_Result_AppIDMismatch; + } + return Handshake_Result_Success; +} + +bool CryptoManagerImpl::SSLContextImpl::ReadHandshakeData( + const uint8_t** const out_data, size_t* out_data_size) { + LOG4CXX_AUTO_TRACE(logger_); + const size_t pend = BIO_ctrl_pending(bioOut_); + LOG4CXX_DEBUG(logger_, "Available " << pend << " bytes for handshake"); + + if (pend > 0) { + LOG4CXX_DEBUG(logger_, "Reading handshake data"); + EnsureBufferSizeEnough(pend); + + const int read_count = BIO_read(bioOut_, buffer_, pend); + if (read_count == static_cast<int>(pend)) { + *out_data_size = read_count; + *out_data = buffer_; + } else { + LOG4CXX_WARN(logger_, "BIO read fail"); + is_handshake_pending_ = false; + ResetConnection(); + return false; + } + } + + return true; +} +bool CryptoManagerImpl::SSLContextImpl::WriteHandshakeData( + const uint8_t* const in_data, size_t in_data_size) { + LOG4CXX_AUTO_TRACE(logger_); if (in_data && in_data_size) { const int ret = BIO_write(bioIn_, in_data, in_data_size); if (ret <= 0) { is_handshake_pending_ = false; - SSL_clear(connection_); - return SSLContext::Handshake_Result_AbnormalFail; + ResetConnection(); + return Handshake_Result_AbnormalFail; } } + return true; +} +SSLContext::HandshakeResult +CryptoManagerImpl::SSLContextImpl::PerformHandshake() { const int handshake_result = SSL_do_handshake(connection_); if (handshake_result == 1) { + const HandshakeResult result = CheckCertContext(); + if (result != Handshake_Result_Success) { + ResetConnection(); + is_handshake_pending_ = false; + return result; + } + + LOG4CXX_DEBUG(logger_, "SSL handshake successfully finished"); // Handshake is successful bioFilter_ = BIO_new(BIO_f_ssl()); BIO_set_ssl(bioFilter_, connection_, BIO_NOCLOSE); - const SSL_CIPHER *cipher = SSL_get_current_cipher(connection_); + const SSL_CIPHER* cipher = SSL_get_current_cipher(connection_); max_block_size_ = max_block_sizes[SSL_CIPHER_get_name(cipher)]; is_handshake_pending_ = false; + } else if (handshake_result == 0) { SSL_clear(connection_); is_handshake_pending_ = false; - return SSLContext::Handshake_Result_Fail; - } else if (SSL_get_error(connection_, handshake_result) != SSL_ERROR_WANT_READ) { - SSL_clear(connection_); - is_handshake_pending_ = false; - return SSLContext::Handshake_Result_AbnormalFail; + return Handshake_Result_Fail; + } else { + const int error = SSL_get_error(connection_, handshake_result); + if (error != SSL_ERROR_WANT_READ) { + const long error = SSL_get_verify_result(connection_); + SetHandshakeError(error); + LOG4CXX_WARN(logger_, + "Handshake failed with error " + << " -> " << SSL_get_error(connection_, error) << " \"" + << LastError() << '"'); + ResetConnection(); + is_handshake_pending_ = false; + + // In case error happened but ssl verification shows OK + // method will return AbnormalFail. + if (X509_V_OK == error) { + return Handshake_Result_AbnormalFail; + } + return openssl_error_convert_to_internal(error); + } } + return Handshake_Result_Success; +} - const size_t pend = BIO_ctrl_pending(bioOut_); +SSLContext::HandshakeResult CryptoManagerImpl::SSLContextImpl::DoHandshakeStep( + 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_); + DCHECK(out_data); + DCHECK(out_data_size); + *out_data = NULL; + *out_data_size = 0; - if (pend) { - EnsureBufferSizeEnough(pend); + // TODO(Ezamakhov): add test - hanshake fail -> restart StartHandshake + { + sync_primitives::AutoLock locker(bio_locker); - const int read_count = BIO_read(bioOut_, buffer_, pend); - if (read_count == static_cast<int>(pend)) { - *out_data_size = read_count; - *out_data = buffer_; - } else { + if (SSL_is_init_finished(connection_)) { + LOG4CXX_DEBUG(logger_, "SSL initilization is finished"); is_handshake_pending_ = false; - SSL_clear(connection_); - return SSLContext::Handshake_Result_AbnormalFail; + return Handshake_Result_Success; } } - return SSLContext::Handshake_Result_Success; -} + if (!WriteHandshakeData(in_data, in_data_size)) { + return Handshake_Result_AbnormalFail; + } -bool CryptoManagerImpl::SSLContextImpl::Encrypt( - const uint8_t * const in_data, size_t in_data_size, - const uint8_t ** const out_data, size_t *out_data_size) { + PrintCertInfo(); + const HandshakeResult res = PerformHandshake(); + if (res != Handshake_Result_Success) { + return res; + } + + if (!ReadHandshakeData(out_data, out_data_size)) { + return Handshake_Result_AbnormalFail; + } + + return res; +} + +bool CryptoManagerImpl::SSLContextImpl::Encrypt(const uint8_t* const in_data, + size_t in_data_size, + const uint8_t** const out_data, + size_t* out_data_size) { sync_primitives::AutoLock locker(bio_locker); - if (!SSL_is_init_finished(connection_) || - !in_data || - !in_data_size) { + if (!SSL_is_init_finished(connection_) || !in_data || !in_data_size) { return false; } @@ -220,10 +359,10 @@ bool CryptoManagerImpl::SSLContextImpl::Encrypt( return true; } -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) { - +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) { sync_primitives::AutoLock locker(bio_locker); if (!SSL_is_init_finished(connection_)) { return false; @@ -274,14 +413,94 @@ CryptoManagerImpl::SSLContextImpl::~SSLContextImpl() { delete[] buffer_; } +void CryptoManagerImpl::SSLContextImpl::SetHandshakeError(const int error) { + const char* error_str = X509_verify_cert_error_string(error); + if (error_str) { + last_error_ = error_str; + } else { + // Error will be updated with the next LastError call + last_error_.clear(); + } +} + +void CryptoManagerImpl::SSLContextImpl::ResetConnection() { + LOG4CXX_AUTO_TRACE(logger_); + const int shutdown_result = SSL_shutdown(connection_); + if (shutdown_result != 1) { + const size_t pend = BIO_ctrl_pending(bioOut_); + LOG4CXX_DEBUG(logger_, "Available " << pend << " bytes for shutdown"); + if (pend > 0) { + LOG4CXX_DEBUG(logger_, "Reading shutdown data"); + EnsureBufferSizeEnough(pend); + BIO_read(bioOut_, buffer_, pend); + } + SSL_shutdown(connection_); + } + LOG4CXX_DEBUG(logger_, "SSL connection recreation"); + SSL_CTX* ssl_context = connection_->ctx; + SSL_free(connection_); + connection_ = SSL_new(ssl_context); + if (mode_ == SERVER) { + SSL_set_accept_state(connection_); + } else { + SSL_set_connect_state(connection_); + } + bioIn_ = BIO_new(BIO_s_mem()); + bioOut_ = BIO_new(BIO_s_mem()); + SSL_set_bio(connection_, bioIn_, bioOut_); +} + +void CryptoManagerImpl::SSLContextImpl::SetHandshakeContext( + const SSLContext::HandshakeContext& hsh_ctx) { + hsh_context_ = hsh_ctx; +} + void CryptoManagerImpl::SSLContextImpl::EnsureBufferSizeEnough(size_t size) { if (buffer_size_ < size) { delete[] buffer_; - buffer_ = new(std::nothrow) uint8_t[size]; + buffer_ = new (std::nothrow) uint8_t[size]; if (buffer_) { buffer_size_ = size; } } } +SSLContext::HandshakeResult +CryptoManagerImpl::SSLContextImpl::openssl_error_convert_to_internal( + const long error) { + switch (error) { + case X509_V_ERR_CERT_HAS_EXPIRED: + return Handshake_Result_CertExpired; + case X509_V_ERR_CERT_NOT_YET_VALID: + return Handshake_Result_NotYetValid; + case X509_V_ERR_SUBJECT_ISSUER_MISMATCH: + case X509_V_ERR_CERT_SIGNATURE_FAILURE: + case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT: + case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT: + return Handshake_Result_CertNotSigned; + default: + return Handshake_Result_Fail; + } +} + +std::string CryptoManagerImpl::SSLContextImpl::GetTextBy(X509_NAME* name, + int object) const { + const int req_len = X509_NAME_get_text_by_NID(name, object, NULL, 0); + + if (-1 == req_len) { + LOG4CXX_WARN(logger_, + "Unable to obtain object: " << object << " from certificate"); + return std::string(); + } + + std::vector<char> data; + data.resize(req_len + 1); + X509_NAME_get_text_by_NID(name, object, &data.front(), data.size()); + + std::string str(data.begin(), data.end() - 1); + + std::transform(str.begin(), str.end(), str.begin(), ::tolower); + return str; +} + } // namespace security_manager diff --git a/src/components/security_manager/test/CMakeLists.txt b/src/components/security_manager/test/CMakeLists.txt index 6554bb797f..6707e5ea5a 100644 --- a/src/components/security_manager/test/CMakeLists.txt +++ b/src/components/security_manager/test/CMakeLists.txt @@ -35,14 +35,17 @@ include_directories( ${COMPONENTS_DIR}/protocol_handler/test/include ${COMPONENTS_DIR}/transport_manager/test/include ${COMPONENTS_DIR}/security_manager/include - include + ${COMPONENTS_DIR}/resumption/include + ${JSONCPP_INCLUDE_DIRECTORY} ) set(SOURCES - #${COMPONENTS_DIR}/security_manager/test/crypto_manager_impl_test.cc - #${COMPONENTS_DIR}/security_manager/test/security_manager_test.cc - #${COMPONENTS_DIR}/security_manager/test/security_query_test.cc + ${COMPONENTS_DIR}/security_manager/test/crypto_manager_impl_test.cc + ${COMPONENTS_DIR}/security_manager/test/security_manager_test.cc + ${COMPONENTS_DIR}/security_manager/test/security_query_test.cc ${COMPONENTS_DIR}/security_manager/test/security_query_matcher.cc + ${COMPONENTS_DIR}/security_manager/test/ssl_context_test.cc + ${COMPONENTS_DIR}/security_manager/test/ssl_certificate_handshake_test.cc ) set(LIBRARIES @@ -55,12 +58,17 @@ set(CERT_LIST ${CMAKE_SOURCE_DIR}/mykey.pem ) +add_custom_target(generate_certificates + COMMAND ${CMAKE_SOURCE_DIR}/tools/Utils/generate_test_certificates.py + -d=${CMAKE_CURRENT_BINARY_DIR} -s + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} +) + foreach( file_i ${CERT_LIST}) file(COPY ${file_i} DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) endforeach( file_i ) -add_library (test_security_manager ${SOURCES}) -target_link_libraries (test_security_manager ${LIBRARIES} ) create_test (security_manager_test "${SOURCES}" "${LIBRARIES}") +add_dependencies(security_manager_test generate_certificates) endif () 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 52ac42b418..27f91866ac 100644 --- a/src/components/security_manager/test/crypto_manager_impl_test.cc +++ b/src/components/security_manager/test/crypto_manager_impl_test.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Ford Motor Company + * Copyright (c) 2016, Ford Motor Company * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -30,433 +30,239 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#include <gtest/gtest.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <unistd.h> - -#include "security_manager/crypto_manager.h" -#include "security_manager/crypto_manager_impl.h" -#include "security_manager/ssl_context.h" - #ifdef __QNXNTO__ #include <openssl/ssl3.h> #else -#include <openssl/tls1.h> -#endif +#include <openssl/ssl.h> +#endif //__QNXNTO__ +#include <limits> +#include <fstream> +#include <sstream> + +#include "gtest/gtest.h" +#include "security_manager/crypto_manager_impl.h" +#include "security_manager/mock_security_manager_settings.h" + +using ::testing::Return; +using ::testing::ReturnRef; +using ::testing::NiceMock; + +namespace { +const size_t kUpdatesBeforeHour = 24; +const std::string kAllCiphers = "ALL"; +const std::string kCaCertPath = ""; #ifdef __QNXNTO__ -#define FORD_CIPHER SSL3_TXT_RSA_DES_192_CBC3_SHA +const std::string kFordCipher = SSL3_TXT_RSA_DES_192_CBC3_SHA; #else // Used cipher from ford protocol requirement -#define FORD_CIPHER TLS1_TXT_RSA_WITH_AES_256_GCM_SHA384 +const std::string kFordCipher = TLS1_TXT_RSA_WITH_AES_256_GCM_SHA384; #endif - -#define ALL_CIPHERS "ALL" +} namespace test { namespace components { -namespace security_manager_test { +namespace crypto_manager_test { -namespace { -bool isErrorFatal(SSL *connection, int res) { - const int error = SSL_get_error(connection, res); - return (error != SSL_ERROR_WANT_READ && error != SSL_ERROR_WANT_WRITE); -} -} -// TODO(EZamakhov): May be split to SSLContext and Cryptomanager tests (separate files) -// TODO(EZamakhov): add test for EnsureBufferSizeEnough -class SSLTest : public testing::Test { +class CryptoManagerTest : public testing::Test { protected: static void SetUpTestCase() { - crypto_manager = new security_manager::CryptoManagerImpl(); - const bool crypto_manager_initialization = crypto_manager->Init( - security_manager::SERVER, security_manager::TLSv1_2, "mycert.pem", - "mykey.pem", FORD_CIPHER, false); - EXPECT_TRUE(crypto_manager_initialization); - - client_manager = new security_manager::CryptoManagerImpl(); - const bool client_manager_initialization = client_manager->Init( - security_manager::CLIENT, security_manager::TLSv1_2, "", "", - FORD_CIPHER, - false); - EXPECT_TRUE(client_manager_initialization); + std::ifstream certificate_file("server/spt_credential.p12.enc"); + ASSERT_TRUE(certificate_file.is_open()) + << "Could not open certificate data file"; + + const std::string certificate( + (std::istreambuf_iterator<char>(certificate_file)), + std::istreambuf_iterator<char>()); + ASSERT_FALSE(certificate.empty()) << "Certificate data file is empty"; + certificate_data_base64_ = certificate; } - static void TearDownTestCase() { - crypto_manager->Finish(); - client_manager->Finish(); - delete crypto_manager; - delete client_manager; + void SetUp() OVERRIDE { + ASSERT_FALSE(certificate_data_base64_.empty()); + mock_security_manager_settings_ = + new NiceMock<security_manager_test::MockCryptoManagerSettings>(); + utils::SharedPtr<security_manager::CryptoManagerSettings> scrypto = + utils::SharedPtr<security_manager::CryptoManagerSettings>:: + static_pointer_cast<security_manager::CryptoManagerSettings>( + mock_security_manager_settings_); + crypto_manager_ = new security_manager::CryptoManagerImpl(scrypto); } - virtual void SetUp() { - server_ctx = crypto_manager->CreateSSLContext(); - client_ctx = client_manager->CreateSSLContext(); + void TearDown() OVERRIDE { + delete mock_security_manager_settings_; + testing::Mock::AsyncVerifyAndClearExpectations(1000); } - virtual void TearDown() { - crypto_manager->ReleaseSSLContext(server_ctx); - client_manager->ReleaseSSLContext(client_ctx); + void InitSecurityManager() { + SetInitialValues( + security_manager::CLIENT, security_manager::TLSv1_2, kAllCiphers); + const bool crypto_manager_initialization = crypto_manager_->Init(); + ASSERT_TRUE(crypto_manager_initialization); } - static security_manager::CryptoManager* crypto_manager; - static security_manager::CryptoManager* client_manager; - security_manager::SSLContext *server_ctx; - security_manager::SSLContext *client_ctx; -}; + void SetInitialValues(security_manager::Mode mode, + security_manager::Protocol protocol, + const std::string& cipher) { + ON_CALL(*mock_security_manager_settings_, security_manager_mode()) + .WillByDefault(Return(mode)); + ON_CALL(*mock_security_manager_settings_, security_manager_protocol_name()) + .WillByDefault(Return(protocol)); + ON_CALL(*mock_security_manager_settings_, certificate_data()) + .WillByDefault(ReturnRef(certificate_data_base64_)); + ON_CALL(*mock_security_manager_settings_, ciphers_list()) + .WillByDefault(ReturnRef(cipher)); + ON_CALL(*mock_security_manager_settings_, ca_cert_path()) + .WillByDefault(ReturnRef(kCaCertPath)); + ON_CALL(*mock_security_manager_settings_, verify_peer()) + .WillByDefault(Return(false)); + } + + security_manager::CryptoManager* crypto_manager_; + static std::string certificate_data_base64_; -security_manager::CryptoManager* SSLTest::crypto_manager; -security_manager::CryptoManager* SSLTest::client_manager; + NiceMock<security_manager_test::MockCryptoManagerSettings>* + mock_security_manager_settings_; +}; +std::string CryptoManagerTest::certificate_data_base64_; -TEST(CryptoManagerTest, UsingBeforeInit) { - security_manager::CryptoManager *crypto_manager = new security_manager::CryptoManagerImpl(); - EXPECT_TRUE(crypto_manager->CreateSSLContext() == NULL); - EXPECT_EQ(crypto_manager->LastError(), std::string ("Initialization is not completed")); - delete crypto_manager; +TEST_F(CryptoManagerTest, UsingBeforeInit) { + EXPECT_TRUE(crypto_manager_->CreateSSLContext() == NULL); + EXPECT_EQ(std::string("Initialization is not completed"), + crypto_manager_->LastError()); } -TEST(CryptoManagerTest, WrongInit) { - security_manager::CryptoManager *crypto_manager = new security_manager::CryptoManagerImpl(); +TEST_F(CryptoManagerTest, WrongInit) { + // We have to cast (-1) to security_manager::Protocol Enum to be accepted by + // crypto_manager_->Init(...) + // Unknown protocol version + security_manager::Protocol UNKNOWN = + static_cast<security_manager::Protocol>(-1); - //We have to cast (-1) to security_manager::Protocol Enum to be accepted by crypto_manager->Init(...) - security_manager::Protocol UNKNOWN = static_cast<security_manager::Protocol>(-1); + 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()); - // Unknown protocol version - EXPECT_FALSE(crypto_manager->Init(security_manager::SERVER, UNKNOWN, - "mycert.pem", "mykey.pem", FORD_CIPHER, false)); - - EXPECT_FALSE(crypto_manager->LastError().empty()); - // Unexistent cert file - EXPECT_FALSE(crypto_manager->Init(security_manager::SERVER, security_manager::TLSv1_2, - "unexists_file.pem", "mykey.pem", FORD_CIPHER, false)); - EXPECT_FALSE(crypto_manager->LastError().empty()); - // Unexistent key file - EXPECT_FALSE(crypto_manager->Init(security_manager::SERVER, security_manager::TLSv1_2, - "mycert.pem", "unexists_file.pem", FORD_CIPHER, false)); - EXPECT_FALSE(crypto_manager->LastError().empty()); + EXPECT_NE(std::string(), crypto_manager_->LastError()); // Unexistent cipher value - EXPECT_FALSE(crypto_manager->Init(security_manager::SERVER, security_manager::TLSv1_2, - "mycert.pem", "mykey.pem", "INVALID_UNKNOWN_CIPHER", false)); - EXPECT_FALSE(crypto_manager->LastError().empty()); + const std::string invalid_cipher = "INVALID_UNKNOWN_CIPHER"; + EXPECT_CALL(*mock_security_manager_settings_, + security_manager_protocol_name()) + .WillOnce(Return(security_manager::TLSv1_2)); + EXPECT_CALL(*mock_security_manager_settings_, certificate_data()) + .WillOnce(ReturnRef(certificate_data_base64_)); + EXPECT_CALL(*mock_security_manager_settings_, ciphers_list()) + .WillRepeatedly(ReturnRef(invalid_cipher)); + EXPECT_FALSE(crypto_manager_->Init()); + + EXPECT_NE(std::string(), crypto_manager_->LastError()); +} - delete crypto_manager; +// #ifndef __QNXNTO__ +TEST_F(CryptoManagerTest, CorrectInit) { + // Empty cert and key values for SERVER + SetInitialValues( + security_manager::SERVER, security_manager::TLSv1_2, kFordCipher); + EXPECT_TRUE(crypto_manager_->Init()); + + // Recall init + SetInitialValues( + security_manager::CLIENT, security_manager::TLSv1_2, kFordCipher); + EXPECT_TRUE(crypto_manager_->Init()); + + // Recall init with other protocols + SetInitialValues( + security_manager::CLIENT, security_manager::TLSv1_2, kFordCipher); + EXPECT_TRUE(crypto_manager_->Init()); + + SetInitialValues( + security_manager::CLIENT, security_manager::TLSv1_1, kFordCipher); + EXPECT_TRUE(crypto_manager_->Init()); + + // Cipher value + SetInitialValues( + security_manager::SERVER, security_manager::TLSv1_2, kAllCiphers); + EXPECT_TRUE(crypto_manager_->Init()); } +// #endif // __QNX__ -//TEST(CryptoManagerTest, CorrectInit) { -// security_manager::CryptoManager *crypto_manager = new security_manager::CryptoManagerImpl(); -// // Empty cert and key values for SERVER -// EXPECT_TRUE(crypto_manager->Init(security_manager::SERVER, security_manager::TLSv1_2, -// "", "", FORD_CIPHER, false)); -// EXPECT_TRUE(crypto_manager->LastError().empty()); -// // Recall init -// EXPECT_TRUE(crypto_manager->Init(security_manager::CLIENT, security_manager::TLSv1_2, -// "", "", FORD_CIPHER, false)); -// EXPECT_TRUE(crypto_manager->LastError().empty()); -// // Recall init with other protocols -// EXPECT_TRUE(crypto_manager->Init(security_manager::CLIENT, security_manager::TLSv1_1, -// "", "", FORD_CIPHER, false)); -// EXPECT_TRUE(crypto_manager->LastError().empty()); -// EXPECT_TRUE(crypto_manager->Init(security_manager::CLIENT, security_manager::TLSv1, -// "", "", FORD_CIPHER, false)); -// EXPECT_TRUE(crypto_manager->LastError().empty()); - -// // Cipher value -// EXPECT_TRUE(crypto_manager->Init(security_manager::SERVER, security_manager::TLSv1_2, -// "mycert.pem", "mykey.pem", ALL_CIPHERS, false)); -// EXPECT_TRUE(crypto_manager->LastError().empty()); -// delete crypto_manager; -//} - -TEST(CryptoManagerTest, ReleaseNull) { - using security_manager::CryptoManager; - using security_manager::CryptoManagerImpl; - - CryptoManager *cm = new CryptoManagerImpl(); - EXPECT_NO_THROW(cm->ReleaseSSLContext(NULL)); - delete cm; +TEST_F(CryptoManagerTest, ReleaseSSLContext_Null) { + EXPECT_NO_THROW(crypto_manager_->ReleaseSSLContext(NULL)); } -TEST_F(SSLTest, BrokenHandshake) { - const uint8_t *server_buf; - const uint8_t *client_buf; - size_t server_buf_len; - size_t client_buf_len; - ASSERT_EQ(security_manager::SSLContext::Handshake_Result_Success, - client_ctx->StartHandshake(&client_buf, - &client_buf_len)); - ASSERT_FALSE(client_buf == NULL); - ASSERT_GT(client_buf_len, 0u); - // Broke 3 bytes for get abnormal fail of handshake - const_cast<uint8_t*>(client_buf)[0] ^= 0xFF; - const_cast<uint8_t*>(client_buf)[client_buf_len / 2] ^= 0xFF; - const_cast<uint8_t*>(client_buf)[client_buf_len - 1] ^= 0xFF; - ASSERT_EQ(security_manager::SSLContext::Handshake_Result_AbnormalFail, - server_ctx->DoHandshakeStep(client_buf, - client_buf_len, - &server_buf, - &server_buf_len)); +TEST_F(CryptoManagerTest, CreateReleaseSSLContext) { + const size_t max_payload_size = 1000u; + SetInitialValues( + security_manager::CLIENT, security_manager::TLSv1_2, kAllCiphers); + EXPECT_TRUE(crypto_manager_->Init()); + EXPECT_CALL(*mock_security_manager_settings_, security_manager_mode()) + .Times(2) + .WillRepeatedly(Return(security_manager::CLIENT)); + 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)); } -// TODO(EZamakhov): split to SSL/TLS1/1.1/1.2 tests -// TODO{ALeshin}: APPLINK-10846 -//TEST_F(SSLTest, Positive) { - -// const uint8_t *server_buf; -// const uint8_t *client_buf; -// size_t server_buf_len; -// size_t client_buf_len; -// ASSERT_EQ(client_ctx->StartHandshake(&client_buf, -// &client_buf_len), -// security_manager::SSLContext::Handshake_Result_Success); -// ASSERT_FALSE(client_buf == NULL); -// ASSERT_GT(client_buf_len, 0u); - -// for (;;) { -// ASSERT_EQ(server_ctx->DoHandshakeStep(client_buf, -// client_buf_len, -// &server_buf, -// &server_buf_len), -// security_manager::SSLContext::Handshake_Result_Success); -// ASSERT_FALSE(server_buf == NULL); -// ASSERT_GT(server_buf_len, 0u); - -// ASSERT_EQ(client_ctx->DoHandshakeStep(server_buf, -// server_buf_len, -// &client_buf, -// &client_buf_len), -// security_manager::SSLContext::Handshake_Result_Success); -// if (server_ctx->IsInitCompleted()) { -// break; -// } - -// ASSERT_FALSE(client_buf == NULL); -// ASSERT_GT(client_buf_len, 0u); -// } -// // expect empty buffers after init complete -// ASSERT_TRUE(client_buf == NULL); -// ASSERT_EQ(client_buf_len, 0u); -// // expect both side initialization complete -// 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(text, text_len, &encrypted_text, &encrypted_text_len)); - -// ASSERT_NE(encrypted_text, (void*)NULL); -// ASSERT_GT(encrypted_text_len, 0u); - -// // Decrypt text on server side -// EXPECT_TRUE(server_ctx->Decrypt(encrypted_text, encrypted_text_len, &text, &text_len)); -// ASSERT_NE(text, (void*)NULL); -// ASSERT_GT(text_len, 0u); - -// ASSERT_EQ(strncmp(reinterpret_cast<const char*>(text), -// "abra", -// 4), 0); -//} - -//TODO{Aleshin}: APPLINK-10846 -//TEST_F(SSLTest, EcncryptionFail) { - -// const uint8_t *server_buf; -// const uint8_t *client_buf; -// size_t server_buf_len; -// size_t client_buf_len; -// ASSERT_EQ(client_ctx->StartHandshake(&client_buf, -// &client_buf_len), -// security_manager::SSLContext::Handshake_Result_Success); - -// while (!server_ctx->IsInitCompleted()) { -// ASSERT_FALSE(client_buf == NULL); -// ASSERT_GT(client_buf_len, 0u); -// ASSERT_EQ(server_ctx->DoHandshakeStep(client_buf, client_buf_len, -// &server_buf, &server_buf_len), -// security_manager::SSLContext::Handshake_Result_Success); -// ASSERT_FALSE(server_buf == NULL); -// ASSERT_GT(server_buf_len, 0u); - -// ASSERT_EQ(client_ctx->DoHandshakeStep(server_buf, server_buf_len, -// &client_buf, &client_buf_len), -// security_manager::SSLContext::Handshake_Result_Success); -// } -// // expect empty buffers after init complete -// ASSERT_TRUE(client_buf == NULL); -// ASSERT_EQ(client_buf_len, 0u); -// // expect both side initialization complete -// 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(text, text_len, &encrypted_text, &encrypted_text_len)); -// ASSERT_NE(encrypted_text, (void*)NULL); -// ASSERT_GT(encrypted_text_len, 0u); - -// std::vector<uint8_t> broken(encrypted_text, encrypted_text + encrypted_text_len); -// // Broke message -// broken[encrypted_text_len / 2] ^= 0xFF; - -// const uint8_t *out_text; -// size_t out_text_size; -// // Decrypt broken text on server side -// 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(encrypted_text, encrypted_text_len, &out_text, &out_text_size)); -// EXPECT_FALSE(server_ctx->Encrypt(text, text_len, &encrypted_text, &encrypted_text_len)); -//} +TEST_F(CryptoManagerTest, OnCertificateUpdated) { + InitSecurityManager(); + EXPECT_TRUE(crypto_manager_->OnCertificateUpdated(certificate_data_base64_)); +} -/* - TEST_F(SSLTest, DISABLED_BadData) { - using security_manager::LastError; - int res = 0; - - uint8_t *outBuf = new uint8_t[1024 * 1024]; - const uint8_t *inBuf; - - for(;;) { - res = SSL_do_handshake(connection); - if (res >= 0) { - break; - } - - if (isErrorFatal(connection, res)) { - break; - } - - size_t outLen = BIO_ctrl_pending(bioOut); - if (outLen) { - BIO_read(bioOut, outBuf, outLen); - } - size_t inLen; - server_ctx->DoHandshakeStep(outBuf, outLen, &inBuf, &inLen); - EXPECT_TRUE(inBuf != NULL); - - if (inLen) { - BIO_write(bioIn, inBuf, inLen); - } - } - delete[] outBuf; - - EXPECT_EQ(res, 1); - - BIO *bioF = BIO_new(BIO_f_ssl()); - BIO_set_ssl(bioF, connection, BIO_NOCLOSE); - - const char *text = "Hello, it's the text to be encrypted"; - uint8_t *encryptedText = new uint8_t[1024]; - const uint8_t *decryptedText; - size_t text_len; - - // Encrypt text on client side - BIO_write(bioF, text, sizeof(text)); - text_len = BIO_ctrl_pending(bioOut); - size_t len = BIO_read(bioOut, encryptedText, text_len); - - // Make improvements - encryptedText[len / 3] ^= 0x80; - - // Decrypt text on server - server_ctx->Decrypt(encryptedText, len, &decryptedText, &text_len); - - delete[] encryptedText; - - EXPECT_FALSE(decryptedText == NULL); - EXPECT_GT(LastError().length(), 0u); - delete[] encryptedText; - } - - - - TEST_F(SSLTest, Positive2) { - using security_manager::LastError; - int res = 0; - - uint8_t *outBuf = new uint8_t[1024 * 1024]; - const uint8_t *inBuf; - - for(;;) { - res = SSL_do_handshake(connection); - if (res >= 0) { - break; - } - - if (isErrorFatal(connection, res)) { - break; - } - - size_t outLen = BIO_ctrl_pending(bioOut); - if (outLen) { - BIO_read(bioOut, outBuf, outLen); - } - size_t inLen; - server_ctx->DoHandshakeStep(outBuf, outLen, &inBuf, &inLen); - EXPECT_TRUE(inBuf != NULL); - - if (inLen) { - BIO_write(bioIn, inBuf, inLen); - } - } - delete[] outBuf; - - EXPECT_EQ(res, 1); - - EXPECT_NE(SSL_is_init_finished(connection), 0u); - - BIO *bioF = BIO_new(BIO_f_ssl()); - BIO_set_ssl(bioF, connection, BIO_NOCLOSE); - - const int N =1000; - int last_max = 0; - int min_oh = N , max_oh = 0; - for (int l = 1; l < N; ++l) { - char *text = new char[l+1]; - text[l]='\0'; - uint8_t *encryptedText = new uint8_t[1024*N]; - const uint8_t *decryptedText; - size_t text_len; - // Encrypt text on client side - BIO_write(bioF, text, l); - text_len = BIO_ctrl_pending(bioOut); - size_t len = BIO_read(bioOut, encryptedText, text_len); - const int temp = len - l; - min_oh = temp < min_oh ? temp : min_oh; - max_oh = temp > max_oh ? temp : max_oh; - if (last_max < len) { - std::cout << l << "->" << len; - if (l > 1) { - std::cout << ", last overhead = " << last_max << "-" << l-1 - << " = " << last_max - (l - 1) << "bytes || "; - std::cout << " overhead = " << len << "-" << l - << " = " << len - l << "bytes"; - } - std::cout << std::endl; - last_max = len; - - // Decrypt text on server - server_ctx->Decrypt(encryptedText, len, &decryptedText, &text_len); - const_cast<uint8_t*>(decryptedText)[text_len] = 0; - - EXPECT_TRUE(decryptedText != NULL); - EXPECT_EQ(strcmp(reinterpret_cast<const char*>(decryptedText), text), 0u); - delete[] text; - } - std::cout << " min = " << min_oh << ", max = " << max_oh << std::endl; - } - //*/ +TEST_F(CryptoManagerTest, OnCertificateUpdated_UpdateNotRequired) { + size_t updates_before = 0; + SetInitialValues( + security_manager::CLIENT, security_manager::TLSv1_2, kAllCiphers); + ASSERT_TRUE(crypto_manager_->Init()); + + EXPECT_CALL(*mock_security_manager_settings_, update_before_hours()) + .WillOnce(Return(updates_before)); + + EXPECT_FALSE(crypto_manager_->IsCertificateUpdateRequired()); + size_t max_updates_ = std::numeric_limits<size_t>::max(); + SetInitialValues( + security_manager::CLIENT, security_manager::TLSv1_2, kAllCiphers); + EXPECT_CALL(*mock_security_manager_settings_, update_before_hours()) + .WillOnce(Return(max_updates_)); + ASSERT_TRUE(crypto_manager_->Init()); + + EXPECT_TRUE(crypto_manager_->IsCertificateUpdateRequired()); } - // namespace crypto_manager_test -} // namespace components -} // namespace test +TEST_F(CryptoManagerTest, OnCertificateUpdated_NotInitialized) { + EXPECT_FALSE(crypto_manager_->OnCertificateUpdated(certificate_data_base64_)); +} + +TEST_F(CryptoManagerTest, OnCertificateUpdated_NullString) { + InitSecurityManager(); + EXPECT_FALSE(crypto_manager_->OnCertificateUpdated(std::string())); +} + +TEST_F(CryptoManagerTest, OnCertificateUpdated_MalformedSign) { + InitSecurityManager(); + // Corrupt the middle symbol + certificate_data_base64_[certificate_data_base64_.size() / 2] = '?'; + + EXPECT_FALSE(crypto_manager_->OnCertificateUpdated(certificate_data_base64_)); +} + +TEST_F(CryptoManagerTest, OnCertificateUpdated_WrongInitFolder) { + SetInitialValues( + security_manager::CLIENT, security_manager::TLSv1_2, kAllCiphers); + ASSERT_TRUE(crypto_manager_->Init()); + + const std::string certificate = "wrong_data"; + ASSERT_FALSE(certificate.empty()); + + EXPECT_FALSE(crypto_manager_->OnCertificateUpdated(certificate)); +} + +} // namespace crypto_manager_test +} // namespace components +} // namespace test diff --git a/src/components/security_manager/test/include/security_manager_mock.h b/src/components/security_manager/test/include/security_manager_mock.h deleted file mode 100644 index 886b022c37..0000000000 --- a/src/components/security_manager/test/include/security_manager_mock.h +++ /dev/null @@ -1,311 +0,0 @@ -/* - * Copyright (c) 2014, Ford Motor Company - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following - * disclaimer in the documentation and/or other materials provided with the - * distribution. - * - * Neither the name of the Ford Motor Company nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef TEST_COMPONENTS_SECURITY_MANAGER_INCLUDE_SECURITY_MANAGER_SECURITY_MANAGER_MOCK_H_ -#define TEST_COMPONENTS_SECURITY_MANAGER_INCLUDE_SECURITY_MANAGER_SECURITY_MANAGER_MOCK_H_ - -#include <gmock/gmock.h> -#include <string> -#include <list> -#include "utils/byte_order.h" -#include "security_manager/security_manager.h" -#include "security_manager/ssl_context.h" -#include "security_manager/security_query.h" - -namespace test { -namespace components { -namespace security_manager_test { - -/* - * MOCK implementation of ::security_manager::SecurityManager - */ -class SecurityManagerMock : public ::security_manager::SecurityManager { - public: - MOCK_METHOD1(set_session_observer, - void(::protocol_handler::SessionObserver *)); - MOCK_METHOD1(set_protocol_handler, - void(::protocol_handler::ProtocolHandler *)); - MOCK_METHOD1(set_crypto_manager, - void(::security_manager::CryptoManager *)); - MOCK_METHOD4(SendInternalError, - void(const uint32_t , - const uint8_t &, - const std::string &, - const uint32_t)); - MOCK_METHOD1(CreateSSLContext, - ::security_manager::SSLContext * (const uint32_t &)); - MOCK_METHOD1(StartHandshake, - void(uint32_t)); - MOCK_METHOD1(AddListener, - void(::security_manager::SecurityManagerListener *)); - MOCK_METHOD1(RemoveListener, - void(::security_manager::SecurityManagerListener *)); - // protocol_handler::ProtocolObserver part - MOCK_METHOD1(OnMessageReceived, - void(const ::protocol_handler::RawMessagePtr)); - MOCK_METHOD1(OnMobileMessageSent, - void(const ::protocol_handler::RawMessagePtr)); -}; - -/* - * MOCK implementation of protocol_handler::SessionObserver interface - */ -class SessionObserverMock : public protocol_handler::SessionObserver { - public: - MOCK_METHOD2(SetSSLContext, - int (const uint32_t& key, - security_manager::SSLContext* context)); - MOCK_METHOD2(GetSSLContext, - security_manager::SSLContext* ( - const uint32_t& key, - const protocol_handler::ServiceType& service_type)); - MOCK_METHOD2(SetProtectionFlag, - void( - const uint32_t& key, - const protocol_handler::ServiceType& service_type)); - MOCK_METHOD5(OnSessionStartedCallback, - - uint32_t( - const transport_manager::ConnectionUID &connection_handle, - const uint8_t session_id, - const ::protocol_handler::ServiceType &service_type, - const bool is_protected, uint32_t* hash_id)); - - MOCK_METHOD4(OnSessionEndedCallback, - uint32_t( - const transport_manager::ConnectionUID& connection_handle, - const uint8_t sessionId, - const uint32_t& hashCode, - const protocol_handler::ServiceType& service_type)); - - MOCK_METHOD1(OnApplicationFloodCallBack, - void(const uint32_t&)); - - MOCK_METHOD1(OnMalformedMessageCallback, - void(const uint32_t&)); - - MOCK_METHOD2(KeyFromPair, - uint32_t( - transport_manager::ConnectionUID connection_handle, - uint8_t sessionId)); - MOCK_METHOD3(PairFromKey, - void( - uint32_t key, - transport_manager::ConnectionUID* connection_handle, - uint8_t* sessionId)); - MOCK_METHOD4(GetDataOnSessionKey, - int32_t(uint32_t key, - uint32_t* app_id, - std::list<int32_t>* sessions_list, - uint32_t* device_id)); - - MOCK_METHOD4(GetDataOnDeviceID, - int32_t( - uint32_t device_handle, - std::string* device_name, - std::list<uint32_t>* applications_list, - std::string* mac_address)); - - MOCK_METHOD5(GetDataOnDeviceID, - int32_t( - uint32_t device_handle, - std::string *device_name, - std::list<uint32_t> *applications_list, - std::string *mac_address, - std::string *connection_type)); - - MOCK_METHOD2(IsHeartBeatSupported, - bool( transport_manager::ConnectionUID connection_handle, - uint8_t session_id)); - - MOCK_METHOD3(ProtocolVersionUsed, - bool(uint32_t connection_id, uint8_t session_id, - uint8_t& protocol_version)); -}; -/* - * MOCK implementation of protocol_handler::ProtocolObserver interface - */ -class ProtocoloObserverMock : public protocol_handler::ProtocolHandler { - public: - MOCK_METHOD2(SendMessageToMobileApp, - void(const protocol_handler::RawMessagePtr message, - bool final_message)); - MOCK_METHOD1(AddProtocolObserver, - void(protocol_handler::ProtocolObserver* observer)); - MOCK_METHOD1(RemoveProtocolObserver, - void(protocol_handler::ProtocolObserver* observer)); - MOCK_METHOD2(SendFramesNumber, - void(uint32_t connection_key, int32_t number_of_frames)); - MOCK_METHOD2(SendHeartBeat, - void(int32_t connection_id, uint8_t session_id)); - MOCK_METHOD2(SendEndSession, - void(int32_t connection_id, uint8_t session_id)); -}; -/* - * MOCK implementation of security_manager::SSLContext interface - */ -class CryptoManagerMock : public security_manager::CryptoManager { - public: - MOCK_METHOD6(Init, - bool (security_manager::Mode mode, - security_manager::Protocol protocol, - const std::string& cert_filename, - const std::string& key_filename, - const std::string& ciphers_list, - bool verify_peer)); - MOCK_METHOD0(Finish, - void ()); - MOCK_METHOD0(CreateSSLContext, - security_manager::SSLContext* ()); - MOCK_METHOD1(ReleaseSSLContext, - void(security_manager::SSLContext*)); - MOCK_CONST_METHOD0(LastError, - std::string()); -}; -/* - * MOCK implementation of security_manager::SSLContext interface - */ -class SSLContextMock : public security_manager::SSLContext { - public: - MOCK_CONST_METHOD0(mode, int ()); - MOCK_METHOD2(StartHandshake, - security_manager::SSLContext::HandshakeResult ( - const uint8_t** const, size_t*)); - MOCK_METHOD4(DoHandshakeStep, - security_manager::SSLContext::HandshakeResult ( - const uint8_t* const, size_t, - const uint8_t** const, size_t*)); - MOCK_METHOD4(Encrypt, - bool (const uint8_t* const, size_t, - const uint8_t** const, size_t*)); - MOCK_METHOD4(Decrypt, - bool (const uint8_t* const, size_t, - const uint8_t** const, size_t*)); - MOCK_CONST_METHOD1(get_max_block_size, size_t (size_t)); - MOCK_CONST_METHOD0(IsInitCompleted, bool()); - MOCK_CONST_METHOD0(IsHandshakePending, bool()); - MOCK_CONST_METHOD0(LastError, - std::string()); -}; -/* - * MOCK implementation of security_manager::SecurityManagerListener - */ -class SMListenerMock : public security_manager::SecurityManagerListener { - public: - MOCK_METHOD2(OnHandshakeDone, - bool(uint32_t connection_key, - bool success)); -}; - -/* - * Matcher for RawMessages - * Check binary data of RawMessages - */ -MATCHER_P2(RawMessageEq, exp_data, exp_data_size, - std::string(negation ? "is not" : "is") + " RawMessages "){ - const size_t arg_data_size = arg->data_size(); - if (arg_data_size != exp_data_size) { - *result_listener << "Got " << arg_data_size << " bytes " - << " expected " << exp_data_size << " bytes"; - return false; - } - const uint8_t *arg_data = arg->data(); - for (int i = 0; i < arg_data_size; ++i) { - if (arg_data[i] != exp_data[i]) { - *result_listener << "Fail in " << i << " byte"; - return false; - } - } - return true; -} - -/* - * Matcher for checking RawMessage with InternalError Query - * Check error id - */ -MATCHER_P(InternalErrorWithErrId, expectedErrorId, - std::string(negation ? "is not" : "is") - + " InternalError with selected error" ){ - const size_t header_size = sizeof(security_manager::SecurityQuery::QueryHeader); - if (arg->data_size() <= header_size) { - *result_listener << "Size " << arg->data_size() - << " bytes less or equal sizeof(QueryHeader)=" - << header_size; - return false; - } - const uint8_t *data = arg->data(); - const uint8_t query_type = data[0]; - if (security_manager::SecurityQuery::NOTIFICATION != query_type) { - *result_listener << "RawMessage is not notification, type=0x" - << std::hex << static_cast<int>(query_type); - return false; - } - // Read Big-Endian number - const uint32_t query_id = data[1] << 16 | - data[2] << 8 | - data[3]; - if (security_manager::SecurityQuery::SEND_INTERNAL_ERROR != query_id) { - *result_listener << "Notification is not InternalError, id=0x" - << std::hex << query_id; - return false; - } - const uint32_t json_size = data[8] << 24 | - data[9] << 16 | - data[10] << 8 | - data[11]; - if (header_size + json_size >= arg->data_size()) { - *result_listener << "InternalError contains only JSON data."; - return false; - } - // Read err_id as bin data number - const uint8_t* err_id = - reinterpret_cast<const uint8_t*>(data + header_size + json_size); - if (expectedErrorId != *err_id) { - *result_listener << "InternalError id " << static_cast<int>(*err_id) - << " and not equal error " << expectedErrorId; - return false; - } - return true; -} - -} // namespace security_manager_test -} // namespace components -} // namespace test -/* - * Matcher for checking QueryHeader equal in GTests - */ -::testing::AssertionResult QueryHeader_EQ( - const char* m_expr, const char* n_expr, - const ::security_manager::SecurityQuery::QueryHeader& q1, - const ::security_manager::SecurityQuery::QueryHeader& q2); - -#endif // TEST_COMPONENTS_SECURITY_MANAGER_INCLUDE_SECURITY_MANAGER_SECURITY_MANAGER_MOCK_H_ diff --git a/src/components/security_manager/test/mycert.pem b/src/components/security_manager/test/mycert.pem new file mode 100644 index 0000000000..fe8be6970e --- /dev/null +++ b/src/components/security_manager/test/mycert.pem @@ -0,0 +1,22 @@ +-----BEGIN CERTIFICATE----- +MIIDlDCCAnwCCQDIe7AwFpWRlDANBgkqhkiG9w0BAQUFADCBizELMAkGA1UEBhMC +UlUxEzARBgNVBAgMClNvbWUtU3RhdGUxGTAXBgNVBAcMEFNhaW50LVBldGVyc2J1 +cmcxDzANBgNVBAoMBkx1eG9mdDEXMBUGA1UEAwwORG1pdHJ5IENobWVyZXYxIjAg +BgkqhkiG9w0BCQEWE2RjaG1lcmV2QGx1eG9mdC5jb20wHhcNMTQwMjI1MDkxODUz +WhcNMTYxMTIyMDkxODUzWjCBizELMAkGA1UEBhMCUlUxEzARBgNVBAgMClNvbWUt +U3RhdGUxGTAXBgNVBAcMEFNhaW50LVBldGVyc2J1cmcxDzANBgNVBAoMBkx1eG9m +dDEXMBUGA1UEAwwORG1pdHJ5IENobWVyZXYxIjAgBgkqhkiG9w0BCQEWE2RjaG1l +cmV2QGx1eG9mdC5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCn +Mu9wNmXKaKOnefSv5iT8G2ESLjq+eYlxys/XAnDfkmnlgGYAcPno+XMhRj/lNV/c +3A0L/R4631GFJA8vaM8m9Bn47FrPP4AXIHEQh9acA4qXiLfhhA8+9PPt4xVkjQYj +bmexBLqDvRgT3MJwwFecUn/UABBlVZRCspn+6DkjiodbgmBOqyi1p0ng8BFeUbEH ++fLQVILCX3pjnMiP2bBtvq/7njgZT2luVtAAcOdRwRTuZT0YbgaXrHYsOa6VYDl1 +I0uOcdD8qENBXtBnykEqH+jZtKu6Rej1DsGOYWqz3AAaGiR1GJauNBxh+4v+i/eB +0aCIA8T8qUqyuVVg48S/AgMBAAEwDQYJKoZIhvcNAQEFBQADggEBACliraOJYijK +yS+Sl6S6pFRqdF/evPdYF6zDJlM3P+/9qHoEy751vbBTzRkVbC/azyiZLwQMuyED +6oCpkI7MqnrRip1ZelGx9K7ChaHOpX/QRN+3eqiDhzvMTGd2nPJf9np4xi8SJpGP +UUROYI5fToIY5MaOKuOIR2a6c8xIuLWMG1XKJxXrRetLJZDgBqQPkuqaZIjYCY+q +HQRjNUFNX4Mc453tKd90gFLGI3fxs1fJDIRSGfKJsj0qc+amSz4Sgiz4QUBcUQKd +hJxUpStYhliZGZchEopLsShtIGfKKFaaPCIOTpVAwSr1oIDm9lpkdxeuQfedKT5f +ZZmkez2pAF8= +-----END CERTIFICATE----- diff --git a/src/components/security_manager/test/mykey.pem b/src/components/security_manager/test/mykey.pem new file mode 100644 index 0000000000..20c89546b4 --- /dev/null +++ b/src/components/security_manager/test/mykey.pem @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEowIBAAKCAQEApzLvcDZlymijp3n0r+Yk/BthEi46vnmJccrP1wJw35Jp5YBm +AHD56PlzIUY/5TVf3NwNC/0eOt9RhSQPL2jPJvQZ+Oxazz+AFyBxEIfWnAOKl4i3 +4YQPPvTz7eMVZI0GI25nsQS6g70YE9zCcMBXnFJ/1AAQZVWUQrKZ/ug5I4qHW4Jg +TqsotadJ4PARXlGxB/ny0FSCwl96Y5zIj9mwbb6v+544GU9pblbQAHDnUcEU7mU9 +GG4Gl6x2LDmulWA5dSNLjnHQ/KhDQV7QZ8pBKh/o2bSrukXo9Q7BjmFqs9wAGhok +dRiWrjQcYfuL/ov3gdGgiAPE/KlKsrlVYOPEvwIDAQABAoIBAQCAjkNXzhuZ87bR +UI34qUYKqaqLZgw45A3v9naz5OaQoGzXz0+eSz98CECjdvYt8EoS8Qb/DtGthoOR +kVYzp6yPUOSfZmu0Kij8ny8P/MHgF0D6nl50ASwPxhu/7vhF5cCwgXUswGwAWuYm +b3j5ZIp4YV5zzNDOeWyTk+uf+UHltqFD7Ae4M9z58r17/OWhva5mtusTuuEYjzC6 +AE/fsOC0gLNSM4+SfclfCkHpH+GikzNMSQ2H0hlXllPmR73BoC6N6aoY5hQWBLV7 +LxtYbJqx7TAqRyypBQekjJe36roRetXtzy3i6V/y69045td5kk70cVjmFhl79475 +82rnRLHBAoGBANgq4axr5OotTUmPkGd0afoaWSRPJfiTTdNeMkqTzM6zIcVLSKhB +78ERwdDD9FOu+Bgivg4DlpmH7ArWn8QNDtdkhmPfKYfTqX6qH7AK4cybvYICMlct +EdW4TvKm/ZB3mrVOP9JVPjdyFMp+Je6N+qp1w+ui9mxX8pWnrC/+DfTvAoGBAMYC +GFjnw/O9hjF2Mb00qUarmM+reJZMXv/pVik+cm0eAiYvgGvKbAYkIXwdb7rLBw9k +baJmxP0PrAoXy5TpPdfROqPwrRCyReKymKkEZeTpONgD0s8MbX167ovZu1OQVKQo +IyJeUzWa0kpglnbL2lLVu49x8jWHDJdYhmkDNE0xAoGAR4ux07qGMoe5693rYoJi +TRgJZv4XSDWg7ZNgu9Q9VjBtvfoT2zSvoMw6xNkGdegUTxC4rLS9VKVrF48/o8ja +n6my3T1QZpdEoxq1kDOZ1nm5eF03wii1nXH6F0/z3qvndZingPsbs4g7n2WvMkyl +qWN+6++s9eEJ9kRftia1AdsCgYAUnU05nE97RcT9y0dcYmopMF5FaJ2yUBsn23wb +6SNylsg0f4eIMVfTv9k4mbvzH4YJpTQAz2A81G/d0SJhy3Kj0GWhgcIS1eyOsHdS +SWHuVhWT77n30lxnzu+c4bst9P3K5V7bCiTxlL/F/I5NqeV98ECJq5xC1F+MNiww +LKQ6UQKBgC2zL59Vf8QnRkRN0gOUfs3ejrLcxFRzTXvcKqcHtbaqzCs3qSNC6UvV +wjBazEwQCo1wnM81X8uT5fLhnjXebWtnYexQo5P38PiaqTQDgrbAdhP5P8NwRCXM +G3SNEz0XeL27jmWjf0VJdwD0LuHXYhcwAWq4alhJ024rjgVHwOze +-----END RSA PRIVATE KEY----- diff --git a/src/components/security_manager/test/security_manager_test.cc b/src/components/security_manager/test/security_manager_test.cc index 30f81ee62e..b5f9ae2e78 100644 --- a/src/components/security_manager/test/security_manager_test.cc +++ b/src/components/security_manager/test/security_manager_test.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Ford Motor Company + * Copyright (c) 2015, Ford Motor Company * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -30,30 +30,47 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#include <gtest/gtest.h> #include <string> +#include "gtest/gtest.h" #include "utils/byte_order.h" #include "protocol/common.h" #include "security_manager/security_manager_impl.h" -#include "protocol_handler_mock.h" -#include "protocol_observer_mock.h" -#include "include/security_manager_mock.h" -#include "transport_manager_mock.h" - -// TODO(EZamakhov): add test on get correct/wrong InternalError -// TODO(EZamakhov): check connection_key the same and seq_number -// TODO(EZamakhov): check ::SendData with correct query_id and query_type +#include "protocol_handler/mock_protocol_handler.h" +#include "protocol_handler/mock_session_observer.h" +#include "security_manager/mock_security_manager.h" +#include "security_manager/mock_ssl_context.h" +#include "security_manager/mock_crypto_manager.h" +#include "security_manager/mock_security_manager_listener.h" +#include "utils/make_shared.h" namespace test { namespace components { namespace security_manager_test { -using namespace ::protocol_handler; -using ::protocol_handler::ServiceType; -using namespace ::transport_manager; -using namespace ::security_manager; +using protocol_handler::PROTOCOL_VERSION_2; +using protocol_handler::ServiceType; +using protocol_handler::kControl; +using protocol_handler::kRpc; +using protocol_handler::kAudio; +using protocol_handler::kMobileNav; +using protocol_handler::kBulk; +using protocol_handler::kInvalidServiceType; +using protocol_handler::RawMessagePtr; +using protocol_handler::RawMessage; + +using security_manager::SecurityQuery; +using security_manager::SSLContext; +using security_manager::SecurityManager; +using security_manager::SecurityManagerImpl; + +using security_manager_test::InternalErrorWithErrId; +using ::testing::Return; +using ::testing::ReturnNull; +using ::testing::DoAll; +using ::testing::SetArgPointee; +using ::testing::_; // Sample data for handshake data emulation const int32_t key = 0x1; @@ -62,24 +79,14 @@ const ServiceType secureServiceType = kControl; const uint32_t protocolVersion = PROTOCOL_VERSION_2; const bool is_final = false; -const uint8_t handshake_data[] = { 0x1, 0x2, 0x3, 0x4, 0x5 }; -const size_t handshake_data_size = sizeof(handshake_data) - / sizeof(handshake_data[0]); - -uint8_t handshake_data_out[] = { 0x6, 0x7, 0x8 }; -uint8_t *handshake_data_out_pointer = handshake_data_out; -const size_t handshake_data_out_size = sizeof(handshake_data_out) - / sizeof(handshake_data_out[0]); +const uint8_t handshake_data[] = {0x1, 0x2, 0x3, 0x4, 0x5}; +const size_t handshake_data_size = + sizeof(handshake_data) / sizeof(handshake_data[0]); -using ::security_manager::SecurityQuery; -using security_manager_test::InternalErrorWithErrId; -using ::testing::Return; -using ::testing::ReturnNull; -using ::testing::DoAll; -using ::testing::SetArgPointee; -using ::testing::_; -using ::security_manager::SecurityManager; -using ::security_manager::SecurityManagerImpl; +uint8_t handshake_data_out[] = {0x6, 0x7, 0x8}; +uint8_t* handshake_data_out_pointer = handshake_data_out; +const size_t handshake_data_out_size = + sizeof(handshake_data_out) / sizeof(handshake_data_out[0]); class SecurityManagerTest : public ::testing::Test { protected: @@ -91,20 +98,22 @@ class SecurityManagerTest : public ::testing::Test { } void TearDown() OVERRIDE { // Wait call methods in thread - usleep(100000); + testing::Mock::AsyncVerifyAndClearExpectations(1000); } - void SetMockCryptoManger() { + void SetMockCryptoManager() { + EXPECT_CALL(mock_crypto_manager, IsCertificateUpdateRequired()) + .WillRepeatedly(Return(false)); security_manager_->set_crypto_manager(&mock_crypto_manager); } /* * Wrapper for fast emulate recieve SecurityManager::OnMessageReceived */ - void call_OnMessageReceived(const uint8_t* const data, uint32_t dataSize, + void call_OnMessageReceived(const uint8_t* const data, + uint32_t dataSize, const ServiceType serviceType) { - const ::protocol_handler::RawMessagePtr rawMessagePtr( - new ::protocol_handler::RawMessage(key, protocolVersion, data, dataSize, - serviceType)); + const RawMessagePtr rawMessagePtr(utils::MakeShared<RawMessage>( + key, protocolVersion, data, dataSize, serviceType)); security_manager_->OnMessageReceived(rawMessagePtr); } /* @@ -130,7 +139,7 @@ class SecurityManagerTest : public ::testing::Test { /* * Wrapper for fast emulate recieve Handshake */ - void EmulateMobileMessageHandShake(const uint8_t* const data, + void EmulateMobileMessageHandshake(const uint8_t* const data, const uint32_t data_size, const int repeat_count = 1) { const SecurityQuery::QueryHeader header(SecurityQuery::NOTIFICATION, @@ -142,12 +151,18 @@ class SecurityManagerTest : public ::testing::Test { } ::utils::SharedPtr<SecurityManagerImpl> security_manager_; // Strict mocks (same as all methods EXPECT_CALL().Times(0)) - testing::StrictMock<protocol_handler_test::SessionObserverMock> mock_session_observer; - testing::StrictMock<protocol_handler_test::ProtocolHandlerMock> mock_protocol_handler; - testing::StrictMock<security_manager_test::CryptoManagerMock> mock_crypto_manager; - testing::StrictMock<security_manager_test::SSLContextMock> mock_ssl_context_new; - testing::StrictMock<security_manager_test::SSLContextMock> mock_ssl_context_exists; - testing::StrictMock<security_manager_test::SMListenerMock> mock_sm_listener; + testing::StrictMock<protocol_handler_test::MockSessionObserver> + mock_session_observer; + testing::StrictMock<protocol_handler_test::MockProtocolHandler> + mock_protocol_handler; + testing::StrictMock<security_manager_test::MockCryptoManager> + mock_crypto_manager; + testing::StrictMock<security_manager_test::MockSSLContext> + mock_ssl_context_new; + testing::StrictMock<security_manager_test::MockSSLContext> + mock_ssl_context_exists; + testing::StrictMock<security_manager_test::MockSecurityManagerListener> + mock_sm_listener; }; // Test Bodies @@ -186,12 +201,14 @@ TEST_F(SecurityManagerTest, Listeners_NoListeners) { security_manager_->RemoveListener(&mock_sm_listener); // Expect no calls - testing::StrictMock<SMListenerMock> mock_listener2; + testing::StrictMock<MockSecurityManagerListener> mock_listener2; security_manager_->AddListener(&mock_listener2); security_manager_->RemoveListener(&mock_listener2); - security_manager_->NotifyListenersOnHandshakeDone(key, true); - security_manager_->NotifyListenersOnHandshakeDone(key, false); + security_manager_->NotifyListenersOnHandshakeDone( + key, SSLContext::Handshake_Result_Success); + security_manager_->NotifyListenersOnHandshakeDone( + key, SSLContext::Handshake_Result_Fail); } /* * Notifying two listeners @@ -200,23 +217,32 @@ TEST_F(SecurityManagerTest, Listeners_Notifying) { // Check correct removing listener security_manager_->RemoveListener(&mock_sm_listener); - testing::StrictMock<SMListenerMock> mock_listener1; - testing::StrictMock<SMListenerMock> mock_listener2; + testing::StrictMock<MockSecurityManagerListener> mock_listener1; + testing::StrictMock<MockSecurityManagerListener> mock_listener2; - const bool first_call_value = true; + 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)). - // Emulate false (reject) result - WillOnce(Return(false)); - EXPECT_CALL(mock_listener2, OnHandshakeDone(key, first_call_value)). - // Emulate true (accept) result - WillOnce(Return(true)); - - const bool second_call_value = false; + EXPECT_CALL(mock_listener1, OnHandshakeDone(key, first_call_value)) + . + // Emulate false (reject) result + WillOnce(Return(false)); + EXPECT_CALL(mock_listener2, OnHandshakeDone(key, first_call_value)) + . + // Emulate true (accept) result + WillOnce(Return(true)); + + // First listener was not removed from listener list + // So this callback wil lbe either call. + EXPECT_CALL(mock_listener1, OnCertificateUpdateRequired()); + + 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)). - // Emulate false (reject) result - WillOnce(Return(true)); + EXPECT_CALL(mock_listener1, OnHandshakeDone(key, second_call_value)) + . + // Emulate false (reject) result + WillOnce(Return(true)); // Expect no call 3d call @@ -224,11 +250,16 @@ TEST_F(SecurityManagerTest, Listeners_Notifying) { security_manager_->AddListener(&mock_listener2); // 1st call security_manager_->NotifyListenersOnHandshakeDone(key, first_call_value); + security_manager_->NotifyOnCertififcateUpdateRequired(); // 2nd call security_manager_->NotifyListenersOnHandshakeDone(key, second_call_value); + security_manager_->NotifyOnCertififcateUpdateRequired(); // 3nd call - security_manager_->NotifyListenersOnHandshakeDone(key, false); + security_manager_->NotifyListenersOnHandshakeDone( + key, SSLContext::Handshake_Result_Fail); + security_manager_->NotifyOnCertififcateUpdateRequired(); } + /* * SecurityManager with NULL CryptoManager shall send * InternallError (ERROR_NOT_SUPPORTED) on any Query @@ -237,14 +268,16 @@ TEST_F(SecurityManagerTest, SecurityManager_NULLCryptoManager) { // Expect InternalError with ERROR_ID uint32_t connection_id = 0; uint8_t session_id = 0; - //uint8_t protocol_version = 0; + // uint8_t protocol_version = 0; EXPECT_CALL(mock_session_observer, PairFromKey(key, _, _)); - EXPECT_CALL(mock_session_observer, ProtocolVersionUsed(connection_id, session_id,_)). - WillOnce(Return(true)); + EXPECT_CALL(mock_session_observer, + ProtocolVersionUsed(connection_id, session_id, _)) + .WillOnce(Return(true)); - EXPECT_CALL( - mock_protocol_handler, - SendMessageToMobileApp( InternalErrorWithErrId( SecurityManager::ERROR_NOT_SUPPORTED), is_final)); + EXPECT_CALL(mock_protocol_handler, + SendMessageToMobileApp( + InternalErrorWithErrId(SecurityManager::ERROR_NOT_SUPPORTED), + is_final)); const SecurityQuery::QueryHeader header(SecurityQuery::REQUEST, // It could be any query id SecurityQuery::INVALID_QUERY_ID); @@ -255,8 +288,9 @@ TEST_F(SecurityManagerTest, SecurityManager_NULLCryptoManager) { * Shall skip all OnMobileMessageSent */ TEST_F(SecurityManagerTest, OnMobileMessageSent) { - const ::protocol_handler::RawMessagePtr rawMessagePtr( - new ::protocol_handler::RawMessage(key, protocolVersion, NULL, 0)); + const uint8_t* data_param = NULL; + const RawMessagePtr rawMessagePtr( + utils::MakeShared<RawMessage>(key, protocolVersion, data_param, 0)); security_manager_->OnMobileMessageSent(rawMessagePtr); } /* @@ -276,14 +310,17 @@ TEST_F(SecurityManagerTest, GetWrongServiceType) { TEST_F(SecurityManagerTest, GetEmptyQuery) { uint32_t connection_id = 0; uint8_t session_id = 0; - //uint8_t protocol_version = 0; + // uint8_t protocol_version = 0; EXPECT_CALL(mock_session_observer, PairFromKey(key, _, _)); - EXPECT_CALL(mock_session_observer, ProtocolVersionUsed(connection_id, session_id,_)). - WillOnce(Return(true)); + EXPECT_CALL(mock_session_observer, + ProtocolVersionUsed(connection_id, session_id, _)) + .WillOnce(Return(true)); - EXPECT_CALL( - mock_protocol_handler, - SendMessageToMobileApp( InternalErrorWithErrId( SecurityManager::ERROR_INVALID_QUERY_SIZE), is_final)); + EXPECT_CALL( + mock_protocol_handler, + SendMessageToMobileApp( + InternalErrorWithErrId(SecurityManager::ERROR_INVALID_QUERY_SIZE), + is_final)); // Call with NULL data call_OnMessageReceived(NULL, 0, secureServiceType); } @@ -291,20 +328,22 @@ TEST_F(SecurityManagerTest, GetEmptyQuery) { * Shall send InternallError on null data recieved */ TEST_F(SecurityManagerTest, GetWrongJSONSize) { - SetMockCryptoManger(); + SetMockCryptoManager(); uint32_t connection_id = 0; uint8_t session_id = 0; - //uint8_t protocol_version = 0; + // uint8_t protocol_version = 0; EXPECT_CALL(mock_session_observer, PairFromKey(key, _, _)); - EXPECT_CALL(mock_session_observer, ProtocolVersionUsed(connection_id, session_id,_)). - WillOnce(Return(true)); + EXPECT_CALL(mock_session_observer, + ProtocolVersionUsed(connection_id, session_id, _)) + .WillOnce(Return(true)); // Expect InternalError with ERROR_ID EXPECT_CALL( - mock_protocol_handler, - SendMessageToMobileApp( InternalErrorWithErrId( SecurityManager::ERROR_INVALID_QUERY_SIZE), is_final)); - SecurityQuery::QueryHeader header( - SecurityQuery::REQUEST, - SecurityQuery::INVALID_QUERY_ID); + mock_protocol_handler, + SendMessageToMobileApp( + InternalErrorWithErrId(SecurityManager::ERROR_INVALID_QUERY_SIZE), + is_final)); + SecurityQuery::QueryHeader header(SecurityQuery::REQUEST, + SecurityQuery::INVALID_QUERY_ID); header.json_size = 0x0FFFFFFF; EmulateMobileMessage(header, NULL, 0); } @@ -312,20 +351,22 @@ TEST_F(SecurityManagerTest, GetWrongJSONSize) { * Shall send InternallError on INVALID_QUERY_ID */ TEST_F(SecurityManagerTest, GetInvalidQueryId) { - SetMockCryptoManger(); + SetMockCryptoManager(); uint32_t connection_id = 0; uint8_t session_id = 0; - //uint8_t protocol_version = 0; + // uint8_t protocol_version = 0; EXPECT_CALL(mock_session_observer, PairFromKey(key, _, _)); - EXPECT_CALL(mock_session_observer, ProtocolVersionUsed(connection_id, session_id,_)). - WillOnce(Return(true)); + EXPECT_CALL(mock_session_observer, + ProtocolVersionUsed(connection_id, session_id, _)) + .WillOnce(Return(true)); // Expect InternalError with ERROR_ID EXPECT_CALL( - mock_protocol_handler, - SendMessageToMobileApp( InternalErrorWithErrId( SecurityManager::ERROR_INVALID_QUERY_ID), is_final)); - const SecurityQuery::QueryHeader header( - SecurityQuery::REQUEST, - SecurityQuery::INVALID_QUERY_ID); + mock_protocol_handler, + SendMessageToMobileApp( + InternalErrorWithErrId(SecurityManager::ERROR_INVALID_QUERY_ID), + is_final)); + const SecurityQuery::QueryHeader header(SecurityQuery::REQUEST, + SecurityQuery::INVALID_QUERY_ID); const uint8_t data = 0; EmulateMobileMessage(header, &data, 1); } @@ -334,111 +375,121 @@ TEST_F(SecurityManagerTest, GetInvalidQueryId) { * CreateSSLContext for already protected connections */ TEST_F(SecurityManagerTest, CreateSSLContext_ServiceAlreadyProtected) { - SetMockCryptoManger(); + SetMockCryptoManager(); // Return mock SSLContext - EXPECT_CALL(mock_session_observer, GetSSLContext(key, kControl)). - WillOnce(Return(&mock_ssl_context_new)); + EXPECT_CALL(mock_session_observer, GetSSLContext(key, kControl)) + .WillOnce(Return(&mock_ssl_context_new)); - const security_manager::SSLContext* rezult = security_manager_->CreateSSLContext(key); - EXPECT_EQ(rezult, &mock_ssl_context_new); + const SSLContext* result = security_manager_->CreateSSLContext(key); + EXPECT_EQ(&mock_ssl_context_new, result); } /* * Shall send Internall Error on error create SSL */ TEST_F(SecurityManagerTest, CreateSSLContext_ErrorCreateSSL) { - SetMockCryptoManger(); + SetMockCryptoManager(); // Expect InternalError with ERROR_ID uint32_t connection_id = 0; uint8_t session_id = 0; - //uint8_t protocol_version = 0; + // uint8_t protocol_version = 0; EXPECT_CALL(mock_session_observer, PairFromKey(key, _, _)); - EXPECT_CALL(mock_session_observer, ProtocolVersionUsed(connection_id, session_id,_)). - WillOnce(Return(true)); + 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)); + mock_protocol_handler, + SendMessageToMobileApp( + InternalErrorWithErrId(SecurityManager::ERROR_INTERNAL), is_final)); // Emulate SessionObserver and CryptoManager result - EXPECT_CALL(mock_session_observer, GetSSLContext(key, kControl)). - WillOnce(ReturnNull()); - EXPECT_CALL(mock_crypto_manager, CreateSSLContext()). - WillOnce(ReturnNull()); + EXPECT_CALL(mock_session_observer, GetSSLContext(key, kControl)) + .WillOnce(ReturnNull()); + EXPECT_CALL(mock_crypto_manager, CreateSSLContext()).WillOnce(ReturnNull()); - const bool rezult = security_manager_->CreateSSLContext(key); - EXPECT_FALSE(rezult); + const SSLContext* result = security_manager_->CreateSSLContext(key); + EXPECT_EQ(NULL, result); } /* * Shall send InternalError with SERVICE_NOT_FOUND * on getting any Error with call SetSSLContext */ TEST_F(SecurityManagerTest, CreateSSLContext_SetSSLContextError) { - SetMockCryptoManger(); + SetMockCryptoManager(); // Expect InternalError with ERROR_ID uint32_t connection_id = 0; uint8_t session_id = 0; - //uint8_t protocol_version = 0; + // uint8_t protocol_version = 0; EXPECT_CALL(mock_session_observer, PairFromKey(key, _, _)); - EXPECT_CALL(mock_session_observer, ProtocolVersionUsed(connection_id, session_id,_)). - WillOnce(Return(true)); + EXPECT_CALL(mock_session_observer, + ProtocolVersionUsed(connection_id, session_id, _)) + .WillOnce(Return(true)); EXPECT_CALL( - mock_protocol_handler, - SendMessageToMobileApp( InternalErrorWithErrId( SecurityManager::ERROR_UNKWOWN_INTERNAL_ERROR), is_final)); + mock_protocol_handler, + SendMessageToMobileApp( + InternalErrorWithErrId(SecurityManager::ERROR_UNKNOWN_INTERNAL_ERROR), + is_final)); // Emulate SessionObserver and CryptoManager result - EXPECT_CALL(mock_session_observer, GetSSLContext(key, kControl)). - WillOnce(ReturnNull()); - EXPECT_CALL(mock_crypto_manager, CreateSSLContext()). - WillOnce(Return(&mock_ssl_context_new)); + EXPECT_CALL(mock_session_observer, GetSSLContext(key, 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)). - WillOnce(Return(SecurityManager::ERROR_UNKWOWN_INTERNAL_ERROR)); + EXPECT_CALL(mock_session_observer, SetSSLContext(key, &mock_ssl_context_new)) + .WillOnce(Return(SecurityManager::ERROR_UNKNOWN_INTERNAL_ERROR)); - const bool rezult = security_manager_->CreateSSLContext(key); - EXPECT_FALSE(rezult); + const SSLContext* result = security_manager_->CreateSSLContext(key); + EXPECT_EQ(NULL, result); } /* * Shall protect connection on correct call CreateSSLContext */ TEST_F(SecurityManagerTest, CreateSSLContext_Success) { - SetMockCryptoManger(); + SetMockCryptoManager(); // Expect no Errors // 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()). + EXPECT_CALL(mock_session_observer, GetSSLContext(key, kControl)) + .WillOnce(ReturnNull()) + . // additional check for debug code 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)). - WillOnce(Return(SecurityManager::ERROR_SUCCESS)); + EXPECT_CALL(mock_crypto_manager, CreateSSLContext()) + .WillOnce(Return(&mock_ssl_context_new)); + EXPECT_CALL(mock_session_observer, SetSSLContext(key, &mock_ssl_context_new)) + .WillOnce(Return(SecurityManager::ERROR_SUCCESS)); - const bool rezult = security_manager_->CreateSSLContext(key); - EXPECT_TRUE(rezult); + const SSLContext* result = security_manager_->CreateSSLContext(key); + EXPECT_EQ(&mock_ssl_context_new, result); } /* * Shall send InternallError on call StartHandshake for uprotected service */ TEST_F(SecurityManagerTest, StartHandshake_ServiceStillUnprotected) { - SetMockCryptoManger(); + SetMockCryptoManager(); uint32_t connection_id = 0; uint8_t session_id = 0; - //uint8_t protocol_version = 0; + // uint8_t protocol_version = 0; EXPECT_CALL(mock_session_observer, PairFromKey(key, _, _)); - EXPECT_CALL(mock_session_observer, ProtocolVersionUsed(connection_id, session_id,_)). - WillOnce(Return(true)); + EXPECT_CALL(mock_session_observer, + ProtocolVersionUsed(connection_id, session_id, _)) + .WillOnce(Return(true)); // Expect InternalError with ERROR_INTERNAL - EXPECT_CALL(mock_protocol_handler, - SendMessageToMobileApp( InternalErrorWithErrId( SecurityManager::ERROR_INTERNAL), is_final)); + EXPECT_CALL( + mock_protocol_handler, + SendMessageToMobileApp( + InternalErrorWithErrId(SecurityManager::ERROR_INTERNAL), is_final)); // Expect notifying listeners (unsuccess) - EXPECT_CALL(mock_sm_listener, OnHandshakeDone(key, false)).WillOnce(Return(true)); + EXPECT_CALL(mock_sm_listener, + OnHandshakeDone(key, SSLContext::Handshake_Result_Fail)) + .WillOnce(Return(true)); // Emulate SessionObserver result - EXPECT_CALL(mock_session_observer, GetSSLContext(key, kControl)). - WillOnce(ReturnNull()); + EXPECT_CALL(mock_session_observer, GetSSLContext(key, kControl)) + .WillOnce(ReturnNull()); security_manager_->StartHandshake(key); } @@ -446,32 +497,38 @@ TEST_F(SecurityManagerTest, StartHandshake_ServiceStillUnprotected) { * Shall send InternallError on SSL error and notify listeners */ TEST_F(SecurityManagerTest, StartHandshake_SSLInternalError) { - SetMockCryptoManger(); + SetMockCryptoManager(); uint32_t connection_id = 0; uint8_t session_id = 0; - //uint8_t protocol_version = 0; + // uint8_t protocol_version = 0; EXPECT_CALL(mock_session_observer, PairFromKey(key, _, _)); - EXPECT_CALL(mock_session_observer, ProtocolVersionUsed(connection_id, session_id,_)). - WillOnce(Return(true)); + EXPECT_CALL(mock_session_observer, GetHandshakeContext(key)) + .WillOnce(Return(SSLContext::HandshakeContext())); + EXPECT_CALL(mock_session_observer, + ProtocolVersionUsed(connection_id, session_id, _)) + .WillOnce(Return(true)); // Expect InternalError with ERROR_ID EXPECT_CALL( - mock_protocol_handler, - SendMessageToMobileApp( InternalErrorWithErrId( SecurityManager::ERROR_INTERNAL), is_final)); + mock_protocol_handler, + SendMessageToMobileApp( + InternalErrorWithErrId(SecurityManager::ERROR_INTERNAL), is_final)); // Expect notifying listeners (unsuccess) - EXPECT_CALL(mock_sm_listener, OnHandshakeDone(key, false)).WillOnce(Return(true)); + EXPECT_CALL(mock_sm_listener, + OnHandshakeDone(key, SSLContext::Handshake_Result_Fail)) + .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(false)); - EXPECT_CALL(mock_ssl_context_exists, StartHandshake(_, _)). - WillOnce(DoAll(SetArgPointee<0>(handshake_data_out_pointer), - SetArgPointee<1>(handshake_data_out_size), - Return(security_manager::SSLContext:: - Handshake_Result_Fail))); + 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); } @@ -479,59 +536,67 @@ TEST_F(SecurityManagerTest, StartHandshake_SSLInternalError) { * Shall send data on call StartHandshake */ TEST_F(SecurityManagerTest, StartHandshake_SSLInitIsNotComplete) { - SetMockCryptoManger(); + SetMockCryptoManager(); uint32_t connection_id = 0; uint8_t session_id = 0; - //uint8_t protocol_version = 0; + // uint8_t protocol_version = 0; EXPECT_CALL(mock_session_observer, PairFromKey(key, _, _)); - EXPECT_CALL(mock_session_observer, ProtocolVersionUsed(connection_id, session_id,_)). - WillOnce(Return(true)); + 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_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, 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(security_manager::SSLContext:: - Handshake_Result_Success))). - WillOnce(DoAll(SetArgPointee<0>((uint8_t*)NULL), - SetArgPointee<1>(handshake_data_out_size), - Return(security_manager::SSLContext:: - Handshake_Result_Success))). - WillOnce(DoAll(SetArgPointee<0>(handshake_data_out_pointer), - SetArgPointee<1>(handshake_data_out_size), - Return(security_manager::SSLContext:: - Handshake_Result_Success))); + 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 + * Shall notify listeners on call StartHandshake after SSLContext initialization + * complete */ TEST_F(SecurityManagerTest, StartHandshake_SSLInitIsComplete) { - SetMockCryptoManger(); + SetMockCryptoManager(); // Expect no message send // Expect notifying listeners (success) - EXPECT_CALL(mock_sm_listener, OnHandshakeDone(key, true)). - WillOnce(Return(true)); + 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)); + EXPECT_CALL(mock_session_observer, GetSSLContext(key, kControl)) + .WillOnce(Return(&mock_ssl_context_exists)); + EXPECT_CALL(mock_ssl_context_exists, IsInitCompleted()) + .WillOnce(Return(true)); + EXPECT_CALL(mock_crypto_manager, IsCertificateUpdateRequired()) + .WillOnce(Return(false)); security_manager_->StartHandshake(key); } @@ -540,19 +605,22 @@ TEST_F(SecurityManagerTest, StartHandshake_SSLInitIsComplete) { * getting SEND_HANDSHAKE_DATA with NULL data */ TEST_F(SecurityManagerTest, ProccessHandshakeData_WrongDataSize) { - SetMockCryptoManger(); + SetMockCryptoManager(); uint32_t connection_id = 0; uint8_t session_id = 0; - //uint8_t protocol_version = 0; + // uint8_t protocol_version = 0; EXPECT_CALL(mock_session_observer, PairFromKey(key, _, _)); - EXPECT_CALL(mock_session_observer, ProtocolVersionUsed(connection_id, session_id,_)). - WillOnce(Return(true)); + EXPECT_CALL(mock_session_observer, + ProtocolVersionUsed(connection_id, session_id, _)) + .WillOnce(Return(true)); // Expect InternalError with ERROR_ID EXPECT_CALL( - mock_protocol_handler, - SendMessageToMobileApp( InternalErrorWithErrId( SecurityManager::ERROR_INVALID_QUERY_SIZE), is_final)); - EmulateMobileMessageHandShake(NULL, 0); + mock_protocol_handler, + SendMessageToMobileApp( + InternalErrorWithErrId(SecurityManager::ERROR_INVALID_QUERY_SIZE), + is_final)); + EmulateMobileMessageHandshake(NULL, 0); } /* * Shall send InternallError on @@ -560,28 +628,32 @@ TEST_F(SecurityManagerTest, ProccessHandshakeData_WrongDataSize) { * for service which is not protected */ TEST_F(SecurityManagerTest, ProccessHandshakeData_ServiceNotProtected) { - SetMockCryptoManger(); + SetMockCryptoManager(); // Expect InternalError with ERROR_ID uint32_t connection_id = 0; uint8_t session_id = 0; - //uint8_t protocol_version = 0; + // uint8_t protocol_version = 0; EXPECT_CALL(mock_session_observer, PairFromKey(key, _, _)); - EXPECT_CALL(mock_session_observer, ProtocolVersionUsed(connection_id, session_id,_)). - WillOnce(Return(true)); + EXPECT_CALL(mock_session_observer, + ProtocolVersionUsed(connection_id, session_id, _)) + .WillOnce(Return(true)); EXPECT_CALL( - mock_protocol_handler, - SendMessageToMobileApp( InternalErrorWithErrId( SecurityManager::ERROR_SERVICE_NOT_PROTECTED), is_final)); + mock_protocol_handler, + SendMessageToMobileApp( + InternalErrorWithErrId(SecurityManager::ERROR_SERVICE_NOT_PROTECTED), + is_final)); // Expect notifying listeners (unsuccess) - EXPECT_CALL(mock_sm_listener, OnHandshakeDone(key, false)). - WillOnce(Return(true)); + EXPECT_CALL(mock_sm_listener, + OnHandshakeDone(key, SSLContext::Handshake_Result_Fail)) + .WillOnce(Return(true)); // Emulate SessionObserver result - EXPECT_CALL(mock_session_observer, GetSSLContext(key, kControl)). - WillOnce(ReturnNull()); + EXPECT_CALL(mock_session_observer, GetSSLContext(key, kControl)) + .WillOnce(ReturnNull()); const uint8_t data[] = {0x1, 0x2}; - EmulateMobileMessageHandShake(data, sizeof(data)/sizeof(data[0])); + EmulateMobileMessageHandshake(data, sizeof(data) / sizeof(data[0])); } /* * Shall send InternallError on getting @@ -589,235 +661,237 @@ TEST_F(SecurityManagerTest, ProccessHandshakeData_ServiceNotProtected) { * data (DoHandshakeStep return NULL pointer) */ TEST_F(SecurityManagerTest, ProccessHandshakeData_InvalidData) { - SetMockCryptoManger(); + SetMockCryptoManager(); // Count handshake calls const int handshake_emulates = 4; uint32_t connection_id = 0; uint8_t session_id = 0; - //uint8_t protocol_version = 0; - EXPECT_CALL(mock_session_observer, PairFromKey(key, _, _)). - Times(handshake_emulates); - EXPECT_CALL(mock_session_observer, ProtocolVersionUsed(connection_id, session_id,_)). - Times(handshake_emulates). - WillRepeatedly(Return(true)); + // uint8_t protocol_version = 0; + EXPECT_CALL(mock_session_observer, PairFromKey(key, _, _)) + .Times(handshake_emulates); + EXPECT_CALL(mock_session_observer, + ProtocolVersionUsed(connection_id, session_id, _)) + .Times(handshake_emulates) + .WillRepeatedly(Return(true)); // Expect InternalError with ERROR_ID EXPECT_CALL( - mock_protocol_handler, - SendMessageToMobileApp( InternalErrorWithErrId( SecurityManager::ERROR_SSL_INVALID_DATA), is_final)). - Times(handshake_emulates); + mock_protocol_handler, + SendMessageToMobileApp( + InternalErrorWithErrId(SecurityManager::ERROR_SSL_INVALID_DATA), + is_final)).Times(handshake_emulates); // Expect notifying listeners (unsuccess) - EXPECT_CALL(mock_sm_listener, OnHandshakeDone(key, false)). - WillOnce(Return(true)); + EXPECT_CALL(mock_sm_listener, + OnHandshakeDone(key, SSLContext::Handshake_Result_Fail)) + .WillOnce(Return(true)); // Emulate SessionObserver and CryptoManager result - EXPECT_CALL(mock_session_observer, GetSSLContext(key, kControl)). - Times(handshake_emulates). - WillRepeatedly(Return(&mock_ssl_context_exists)); + EXPECT_CALL(mock_session_observer, GetSSLContext(key, kControl)) + .Times(handshake_emulates) + .WillRepeatedly(Return(&mock_ssl_context_exists)); // Emulate DoHandshakeStep fail logics EXPECT_CALL( - mock_ssl_context_exists, DoHandshakeStep(_, handshake_data_size, _, _)). - WillOnce(DoAll(SetArgPointee<2>(handshake_data_out_pointer), - SetArgPointee<3>(handshake_data_out_size), - Return(security_manager::SSLContext:: - Handshake_Result_AbnormalFail))). - WillOnce(DoAll(SetArgPointee<2>((uint8_t*)NULL), - SetArgPointee<3>(handshake_data_out_size), - Return(security_manager::SSLContext:: - Handshake_Result_AbnormalFail))). - WillOnce(DoAll(SetArgPointee<2>(handshake_data_out_pointer), - SetArgPointee<3>(0), - Return(security_manager::SSLContext:: - Handshake_Result_AbnormalFail))). - WillOnce(DoAll(SetArgPointee<2>((uint8_t*)NULL), - SetArgPointee<3>(0), - Return(security_manager::SSLContext:: - Handshake_Result_AbnormalFail))); - + mock_ssl_context_exists, + DoHandshakeStep(HandshakeStepEq(handshake_data, handshake_data_size), + handshake_data_size, + _, + _)) + .WillOnce(DoAll(SetArgPointee<2>(handshake_data_out_pointer), + SetArgPointee<3>(handshake_data_out_size), + Return(SSLContext::Handshake_Result_AbnormalFail))) + .WillOnce(DoAll(SetArgPointee<2>((uint8_t*)NULL), + SetArgPointee<3>(handshake_data_out_size), + Return(SSLContext::Handshake_Result_AbnormalFail))) + .WillOnce(DoAll(SetArgPointee<2>(handshake_data_out_pointer), + SetArgPointee<3>(0), + Return(SSLContext::Handshake_Result_AbnormalFail))) + .WillOnce(DoAll(SetArgPointee<2>((uint8_t*)NULL), + SetArgPointee<3>(0), + Return(SSLContext::Handshake_Result_AbnormalFail))); // On each wrong handshake will be asked error - EXPECT_CALL(mock_ssl_context_exists, LastError()). - Times(handshake_emulates); + EXPECT_CALL(mock_ssl_context_exists, LastError()).Times(handshake_emulates); // Emulate handshare #handshake_emulates times for 5 cases - EmulateMobileMessageHandShake(handshake_data, handshake_data_size, - handshake_emulates); + EmulateMobileMessageHandshake( + handshake_data, handshake_data_size, handshake_emulates); } /* * Shall send HandshakeData on getting SEND_HANDSHAKE_DATA from mobile side * with correct handshake data Check Fail and sussecc states */ TEST_F(SecurityManagerTest, ProccessHandshakeData_Answer) { - SetMockCryptoManger(); + SetMockCryptoManager(); // Count handshake calls const int handshake_emulates = 2; uint32_t connection_id = 0; uint8_t session_id = 0; - //uint8_t protocol_version = 0; - EXPECT_CALL(mock_session_observer, PairFromKey(key, _, _)). - Times(handshake_emulates); - EXPECT_CALL(mock_session_observer, ProtocolVersionUsed(connection_id, session_id,_)). - Times(handshake_emulates). - WillRepeatedly(Return(true)); - - // Expect InternalError with ERROR_ID - EXPECT_CALL(mock_protocol_handler, SendMessageToMobileApp( - // FIXME : !!! - _, is_final)). - Times(handshake_emulates); + // uint8_t protocol_version = 0; + EXPECT_CALL(mock_session_observer, PairFromKey(key, _, _)) + .Times(handshake_emulates); + EXPECT_CALL(mock_session_observer, + ProtocolVersionUsed(connection_id, session_id, _)) + .Times(handshake_emulates) + .WillRepeatedly(Return(true)); + + // Get size of raw message after + const size_t raw_message_size = 15; + EXPECT_CALL(mock_protocol_handler, + SendMessageToMobileApp(RawMessageEqSize(raw_message_size), + is_final)).Times(handshake_emulates); // Expect notifying listeners (unsuccess) - EXPECT_CALL(mock_sm_listener, OnHandshakeDone(key, false)). - WillOnce(Return(true)); + EXPECT_CALL(mock_sm_listener, + OnHandshakeDone(key, SSLContext::Handshake_Result_Fail)) + .WillOnce(Return(true)); // Emulate SessionObserver and CryptoManager result - EXPECT_CALL(mock_ssl_context_exists, IsInitCompleted()). - Times(handshake_emulates). - WillRepeatedly(Return(false)); - EXPECT_CALL( - mock_session_observer, GetSSLContext(key, kControl)). - Times(handshake_emulates). - WillRepeatedly(Return(&mock_ssl_context_exists)); + EXPECT_CALL(mock_ssl_context_exists, IsInitCompleted()) + .Times(handshake_emulates) + .WillRepeatedly(Return(false)); + EXPECT_CALL(mock_session_observer, GetSSLContext(key, kControl)) + .Times(handshake_emulates) + .WillRepeatedly(Return(&mock_ssl_context_exists)); // Emulate DoHandshakeStep correct logics EXPECT_CALL( - mock_ssl_context_exists, DoHandshakeStep(_, handshake_data_size, _, _)). - WillOnce(DoAll(SetArgPointee<2>(handshake_data_out_pointer), - SetArgPointee<3>(handshake_data_out_size), - Return(security_manager::SSLContext:: - Handshake_Result_Success))). - WillOnce(DoAll(SetArgPointee<2>(handshake_data_out_pointer), - SetArgPointee<3>(handshake_data_out_size), - Return(security_manager::SSLContext:: - Handshake_Result_Fail))); - - EmulateMobileMessageHandShake(handshake_data, handshake_data_size, - handshake_emulates); + mock_ssl_context_exists, + DoHandshakeStep(HandshakeStepEq(handshake_data, handshake_data_size), + handshake_data_size, + _, + _)) + .WillOnce(DoAll(SetArgPointee<2>(handshake_data_out_pointer), + SetArgPointee<3>(handshake_data_out_size), + Return(SSLContext::Handshake_Result_Success))) + .WillOnce(DoAll(SetArgPointee<2>(handshake_data_out_pointer), + SetArgPointee<3>(handshake_data_out_size), + Return(SSLContext::Handshake_Result_Fail))); + + EmulateMobileMessageHandshake( + handshake_data, handshake_data_size, handshake_emulates); } /* * Shall call all listeners on success end handshake * and return handshake data * Check Fail and sussecc states */ -TEST_F(SecurityManagerTest, ProccessHandshakeData_HandShakeFinished) { - SetMockCryptoManger(); +TEST_F(SecurityManagerTest, ProccessHandshakeData_HandshakeFinished) { + SetMockCryptoManager(); // Count handshake calls const int handshake_emulates = 6; // Expect no errors // Expect notifying listeners (success) - EXPECT_CALL(mock_sm_listener, OnHandshakeDone(key, true)). - WillOnce(Return(true)); + EXPECT_CALL(mock_sm_listener, + OnHandshakeDone(key, SSLContext::Handshake_Result_Success)) + .WillOnce(Return(true)); // Emulate SessionObserver and CryptoManager result + EXPECT_CALL(mock_session_observer, GetSSLContext(key, kControl)) + .Times(handshake_emulates) + .WillRepeatedly(Return(&mock_ssl_context_exists)); + EXPECT_CALL(mock_ssl_context_exists, IsInitCompleted()) + .Times(handshake_emulates) + .WillRepeatedly(Return(true)); + EXPECT_CALL( - mock_session_observer, GetSSLContext(key, kControl)). - Times(handshake_emulates). - WillRepeatedly(Return(&mock_ssl_context_exists)); - EXPECT_CALL( - mock_ssl_context_exists, IsInitCompleted()). - Times(handshake_emulates). - WillRepeatedly(Return(true)); - // FIXME(EZamakhov): add DoHandshakeStep matcher for compare handshake data - EXPECT_CALL( - mock_ssl_context_exists, DoHandshakeStep(_, handshake_data_size, _, _)). - // two states with correct out data - WillOnce(DoAll(SetArgPointee<2>(handshake_data_out_pointer), - SetArgPointee<3>(handshake_data_out_size), - Return(security_manager::SSLContext:: - Handshake_Result_Success))). - WillOnce(DoAll(SetArgPointee<2>(handshake_data_out_pointer), - SetArgPointee<3>(handshake_data_out_size), - Return(security_manager::SSLContext:: - Handshake_Result_Fail))). - // two states with with null pointer data - WillOnce(DoAll(SetArgPointee<2>((uint8_t*)NULL), - SetArgPointee<3>(handshake_data_out_size), - Return(security_manager::SSLContext:: - Handshake_Result_Success))). - WillOnce(DoAll(SetArgPointee<2>((uint8_t*)NULL), - SetArgPointee<3>(handshake_data_out_size), - Return(security_manager::SSLContext:: - Handshake_Result_Fail))). - // two states with with null data size - WillOnce(DoAll(SetArgPointee<2>(handshake_data_out_pointer), - SetArgPointee<3>(0), - Return(security_manager::SSLContext:: - Handshake_Result_Success))). - WillOnce(DoAll(SetArgPointee<2>(handshake_data_out_pointer), - SetArgPointee<3>(0), - Return(security_manager::SSLContext:: - Handshake_Result_Success))); + mock_ssl_context_exists, + DoHandshakeStep(HandshakeStepEq(handshake_data, handshake_data_size), + handshake_data_size, + _, + _)) + . + // two states with correct out data + WillOnce(DoAll(SetArgPointee<2>(handshake_data_out_pointer), + SetArgPointee<3>(handshake_data_out_size), + Return(SSLContext::Handshake_Result_Success))) + .WillOnce(DoAll(SetArgPointee<2>(handshake_data_out_pointer), + SetArgPointee<3>(handshake_data_out_size), + Return(SSLContext::Handshake_Result_Fail))) + . + // two states with with null pointer data + WillOnce(DoAll(SetArgPointee<2>((uint8_t*)NULL), + SetArgPointee<3>(handshake_data_out_size), + Return(SSLContext::Handshake_Result_Success))) + .WillOnce(DoAll(SetArgPointee<2>((uint8_t*)NULL), + SetArgPointee<3>(handshake_data_out_size), + Return(SSLContext::Handshake_Result_Fail))) + . + // two states with with null data size + WillOnce(DoAll(SetArgPointee<2>(handshake_data_out_pointer), + SetArgPointee<3>(0), + Return(SSLContext::Handshake_Result_Success))) + .WillOnce(DoAll(SetArgPointee<2>(handshake_data_out_pointer), + SetArgPointee<3>(0), + Return(SSLContext::Handshake_Result_Success))); // Expect send two message (with correct pointer and size data) 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, ProtocolVersionUsed(connection_id, session_id,_)). - Times(2). - WillRepeatedly(Return(true)); + // uint8_t protocol_version = 0; + EXPECT_CALL(mock_session_observer, PairFromKey(key, _, _)).Times(2); + EXPECT_CALL(mock_session_observer, + ProtocolVersionUsed(connection_id, session_id, _)) + .Times(2) + .WillRepeatedly(Return(true)); - EXPECT_CALL( - mock_protocol_handler, SendMessageToMobileApp(_, is_final)). - Times(2); + EXPECT_CALL(mock_protocol_handler, SendMessageToMobileApp(_, is_final)) + .Times(2); // Expect NO InternalError with ERROR_ID - EmulateMobileMessageHandShake(handshake_data, handshake_data_size, handshake_emulates); + EmulateMobileMessageHandshake( + handshake_data, handshake_data_size, handshake_emulates); } /* * Shall not any query on getting empty SEND_INTERNAL_ERROR */ TEST_F(SecurityManagerTest, GetInternalError_NullData) { - SetMockCryptoManger(); + SetMockCryptoManager(); - const SecurityQuery::QueryHeader header( SecurityQuery::NOTIFICATION, - SecurityQuery::SEND_INTERNAL_ERROR, 0); + const SecurityQuery::QueryHeader header( + SecurityQuery::NOTIFICATION, SecurityQuery::SEND_INTERNAL_ERROR, 0); EmulateMobileMessage(header, NULL, 0); } /* * Shall not send any query on getting SEND_INTERNAL_ERROR */ TEST_F(SecurityManagerTest, GetInternalError) { - SetMockCryptoManger(); + SetMockCryptoManager(); - const SecurityQuery::QueryHeader header( SecurityQuery::NOTIFICATION, - SecurityQuery::SEND_INTERNAL_ERROR, 0); + const SecurityQuery::QueryHeader header( + SecurityQuery::NOTIFICATION, SecurityQuery::SEND_INTERNAL_ERROR, 0); const uint8_t data[] = {0x1, 0x2}; - EmulateMobileMessage(header, data, sizeof(data)/sizeof(data[0])); + EmulateMobileMessage(header, data, sizeof(data) / sizeof(data[0])); } /* * Shall not send any query on getting SEND_INTERNAL_ERROR with error string */ TEST_F(SecurityManagerTest, GetInternalError_WithErrText) { - SetMockCryptoManger(); + SetMockCryptoManager(); - SecurityQuery::QueryHeader header( SecurityQuery::NOTIFICATION, - SecurityQuery::SEND_INTERNAL_ERROR, 0); + SecurityQuery::QueryHeader header( + SecurityQuery::NOTIFICATION, SecurityQuery::SEND_INTERNAL_ERROR, 0); std::string error("JSON wrong string"); header.json_size = error.size(); - EmulateMobileMessage(header, - reinterpret_cast<const uint8_t*>(error.c_str()), - error.size()); + EmulateMobileMessage( + header, reinterpret_cast<const uint8_t*>(error.c_str()), error.size()); } /* * Shall not send any query on getting SEND_INTERNAL_ERROR with error string */ TEST_F(SecurityManagerTest, GetInternalError_WithErrJSONText) { - SetMockCryptoManger(); + SetMockCryptoManager(); - SecurityQuery::QueryHeader header( SecurityQuery::NOTIFICATION, - SecurityQuery::SEND_INTERNAL_ERROR, 0); + SecurityQuery::QueryHeader header( + SecurityQuery::NOTIFICATION, SecurityQuery::SEND_INTERNAL_ERROR, 0); std::string error(" { \"id\": 1 } "); header.json_size = error.size(); - EmulateMobileMessage(header, - reinterpret_cast<const uint8_t*>(error.c_str()), - error.size()); + EmulateMobileMessage( + header, reinterpret_cast<const uint8_t*>(error.c_str()), error.size()); } -} // namespace security_manager_test -} // namespace components -} // namespace test +} // namespace security_manager_test +} // namespace components +} // namespace test diff --git a/src/components/security_manager/test/security_query_matcher.cc b/src/components/security_manager/test/security_query_matcher.cc index 2320e83439..3b7f4dd298 100644 --- a/src/components/security_manager/test/security_query_matcher.cc +++ b/src/components/security_manager/test/security_query_matcher.cc @@ -30,8 +30,9 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#include <gmock/gmock.h> #include <string> + +#include "gmock/gmock.h" #include "utils/byte_order.h" #include "security_manager/security_query.h" @@ -43,81 +44,80 @@ namespace security_manager_test { * Matcher for checking RawMessage with InternalError Query * Check error id */ -MATCHER_P(InternalErrorWithErrId, expectedErrorId, - std::string(negation ? "is not" : "is") - + " InternalError with selected error" ){ +MATCHER_P(InternalErrorWithErrId, + expectedErrorId, + std::string(negation ? "is not" : "is") + + " InternalError with selected error") { const size_t header_size = - sizeof(security_manager::SecurityQuery::QueryHeader); + sizeof(security_manager::SecurityQuery::QueryHeader); if (arg->data_size() <= header_size) { *result_listener << "Size " << arg->data_size() - << " bytes less or equal sizeof(QueryHeader)=" - << header_size; + << " bytes less or equal sizeof(QueryHeader)=" + << header_size; return false; } - const uint8_t *data = arg->data(); + const uint8_t* data = arg->data(); const uint8_t query_type = data[0]; if (security_manager::SecurityQuery::NOTIFICATION != query_type) { - *result_listener << "RawMessage is not notification, type=0x" - << std::hex << static_cast<int>(query_type); + *result_listener << "RawMessage is not notification, type=0x" << std::hex + << static_cast<int>(query_type); return false; } // Read Big-Endian number - const uint32_t query_id = data[1] << 16 | - data[2] << 8 | - data[3]; + const uint32_t query_id = data[1] << 16 | data[2] << 8 | data[3]; if (security_manager::SecurityQuery::SEND_INTERNAL_ERROR != query_id) { - *result_listener << "Notification is not InternalError, id=0x" - << std::hex << query_id; + *result_listener << "Notification is not InternalError, id=0x" << std::hex + << query_id; return false; } - const uint32_t json_size = data[8] << 24 | - data[9] << 16 | - data[10] << 8 | - data[11]; + const uint32_t json_size = + data[8] << 24 | data[9] << 16 | data[10] << 8 | data[11]; if (header_size + json_size >= arg->data_size()) { *result_listener << "InternalError contains only JSON data."; return false; } // Read err_id as bin data number - const uint8_t *err_id = - reinterpret_cast<const uint8_t *>(data + header_size + json_size); + const uint8_t* err_id = + reinterpret_cast<const uint8_t*>(data + header_size + json_size); if (expectedErrorId != *err_id) { *result_listener << "InternalError id " << static_cast<int>(*err_id) - << " and not equal error " << expectedErrorId; + << " and not equal error " << expectedErrorId; return false; } return true; } -} // namespace security_manager_test -} // namespace components -} // namespace test -/* - * Matcher for checking QueryHeader equal in GTests - */ +} // namespace security_manager_test +} // namespace components +} // namespace test + /* + * Matcher for checking QueryHeader equal in GTests + */ ::testing::AssertionResult QueryHeader_EQ( - const char *m_expr, const char *n_expr, - const ::security_manager::SecurityQuery::QueryHeader &q1, - const ::security_manager::SecurityQuery::QueryHeader &q2); + const char* m_expr, + const char* n_expr, + const ::security_manager::SecurityQuery::QueryHeader& q1, + const ::security_manager::SecurityQuery::QueryHeader& q2); ::testing::AssertionResult QueryHeader_EQ( - const char* m_expr, const char* n_expr, - const ::security_manager::SecurityQuery::QueryHeader& q1, - const ::security_manager::SecurityQuery::QueryHeader& q2) { + const char* m_expr, + const char* n_expr, + const ::security_manager::SecurityQuery::QueryHeader& q1, + const ::security_manager::SecurityQuery::QueryHeader& q2) { ::testing::AssertionResult fail_result = ::testing::AssertionFailure(); fail_result << "(\"" << m_expr << " and \"" << n_expr << "\") are not equal " << " : different "; if (q1.json_size != q2.json_size) - return fail_result << "json_size_1=" << q1.json_size << ", json_size_2=" - << q2.json_size; + return fail_result << "json_size_1=" << q1.json_size + << ", json_size_2=" << q2.json_size; if (q1.query_id != q2.query_id) - return fail_result << "query_id_1=" << q1.query_id << ", query_id_2=" - << q2.query_id; + return fail_result << "query_id_1=" << q1.query_id + << ", query_id_2=" << q2.query_id; if (q1.query_type != q2.query_type) - return fail_result << "query_type_1=" << q1.query_type << ", query_type_2=" - << q2.query_type; + return fail_result << "query_type_1=" << q1.query_type + << ", query_type_2=" << q2.query_type; if (q1.seq_number != q2.seq_number) - return fail_result << "seq_number_1=" << q1.seq_number << ", seq_number_2=" - << q2.seq_number; + return fail_result << "seq_number_1=" << q1.seq_number + << ", seq_number_2=" << q2.seq_number; return ::testing::AssertionSuccess(); } diff --git a/src/components/security_manager/test/security_query_test.cc b/src/components/security_manager/test/security_query_test.cc index 6db076fd52..80da10ea72 100644 --- a/src/components/security_manager/test/security_query_test.cc +++ b/src/components/security_manager/test/security_query_test.cc @@ -30,16 +30,17 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#include <gtest/gtest.h> #include <vector> #include <string> + +#include "gtest/gtest.h" #include "security_manager/security_query.h" #include "protocol_handler/protocol_payload.h" #include "utils/byte_order.h" -#include "include/security_manager_mock.h" +#include "security_manager/mock_security_manager.h" // Test values for compare after serialization and byteorder conversion -#define SEQ_NUMBER 0x12345678u +#define SEQ_NUMBER 0x12345678u #define CONNECTION_KEY 0xABCDEF0u namespace test { @@ -68,7 +69,7 @@ class SecurityQueryTest : public ::testing::Test { * Used for handling header and data array to byte array for serialization */ std::vector<uint8_t> DeserializeData(SecurityQuery::QueryHeader header, - const uint8_t * const binary_data, + const uint8_t* const binary_data, const size_t bin_data_size) const { // convert to Big-Endian (network) order const uint32_t query_id = header.query_id << 8; @@ -91,8 +92,8 @@ class SecurityQueryTest : public ::testing::Test { * for correct working on Mobile side (3*8 byte) */ TEST_F(SecurityQueryTest, Equal_RPCHeader) { - ASSERT_EQ(sizeof(SecurityQuery::QueryHeader)*8, - ::protocol_handler::ProtocolPayloadV2SizeBits()); + ASSERT_EQ(sizeof(SecurityQuery::QueryHeader) * 8, + ::protocol_handler::ProtocolPayloadV2SizeBits()); } /* * Security QueryHeader default construction @@ -107,16 +108,16 @@ TEST_F(SecurityQueryTest, QueryHeaderConstructor) { */ TEST_F(SecurityQueryTest, QueryHeaderConstructor2) { SecurityQuery::QueryHeader new_header(SecurityQuery::NOTIFICATION, - SecurityQuery::SEND_HANDSHAKE_DATA, - SEQ_NUMBER); + SecurityQuery::SEND_HANDSHAKE_DATA, + SEQ_NUMBER); ASSERT_EQ(new_header.query_type, SecurityQuery::NOTIFICATION); ASSERT_EQ(new_header.query_id, SecurityQuery::SEND_HANDSHAKE_DATA); ASSERT_EQ(new_header.seq_number, SEQ_NUMBER); ASSERT_EQ(new_header.json_size, 0u); SecurityQuery::QueryHeader new_header2(SecurityQuery::RESPONSE, - SecurityQuery::SEND_INTERNAL_ERROR, - SEQ_NUMBER + 1); + SecurityQuery::SEND_INTERNAL_ERROR, + SEQ_NUMBER + 1); ASSERT_EQ(new_header2.query_type, SecurityQuery::RESPONSE); ASSERT_EQ(new_header2.query_id, SecurityQuery::SEND_INTERNAL_ERROR); ASSERT_EQ(new_header2.seq_number, SEQ_NUMBER + 1); @@ -138,7 +139,7 @@ TEST_F(SecurityQueryTest, QueryConstructor) { ASSERT_EQ(query.get_connection_key(), 0u); ASSERT_EQ(query.get_data_size(), 0u); - ASSERT_EQ(query.get_data(), reinterpret_cast<uint8_t *>(NULL)); + ASSERT_EQ(query.get_data(), reinterpret_cast<uint8_t*>(NULL)); ASSERT_TRUE(query.get_json_message().empty()); EXPECT_PRED_FORMAT2(QueryHeader_EQ, query.get_header(), invalid_header); @@ -155,7 +156,7 @@ TEST_F(SecurityQueryTest, QueryConstructor2) { ASSERT_EQ(query.get_connection_key(), CONNECTION_KEY); ASSERT_EQ(query.get_data_size(), 0u); - ASSERT_EQ(query.get_data(), reinterpret_cast<uint8_t *>(NULL)); + ASSERT_EQ(query.get_data(), reinterpret_cast<uint8_t*>(NULL)); ASSERT_TRUE(query.get_json_message().empty()); EXPECT_PRED_FORMAT2(QueryHeader_EQ, query.get_header(), init_header); @@ -169,17 +170,14 @@ TEST_F(SecurityQueryTest, QueryConstructor2) { */ TEST_F(SecurityQueryTest, QueryConstructor3) { uint8_t raw_data[] = {0x0, 0x1, 0x2}; - const size_t raw_data_size = - sizeof(raw_data)/sizeof(raw_data[0]); + const size_t raw_data_size = sizeof(raw_data) / sizeof(raw_data[0]); - SecurityQuery query(init_header, - CONNECTION_KEY, - raw_data, raw_data_size); + SecurityQuery query(init_header, CONNECTION_KEY, raw_data, raw_data_size); ASSERT_EQ(query.get_connection_key(), CONNECTION_KEY); ASSERT_EQ(query.get_data_size(), raw_data_size); // query shall handle own array of byte data - ASSERT_NE(query.get_data(), reinterpret_cast<uint8_t *>(NULL)); + ASSERT_NE(query.get_data(), reinterpret_cast<uint8_t*>(NULL)); for (size_t i = 0; i < raw_data_size; ++i) { ASSERT_EQ(query.get_data()[i], raw_data[i]); } @@ -188,7 +186,7 @@ TEST_F(SecurityQueryTest, QueryConstructor3) { // Deserialization shall return vector equal header + data array const std::vector<uint8_t> vector = - DeserializeData(init_header, raw_data, raw_data_size); + DeserializeData(init_header, raw_data, raw_data_size); const std::vector<uint8_t> deserialize_vector = query.DeserializeQuery(); ASSERT_EQ(deserialize_vector, vector); } @@ -198,8 +196,7 @@ TEST_F(SecurityQueryTest, QueryConstructor3) { TEST_F(SecurityQueryTest, Setters) { const std::string str = "test example string"; uint8_t raw_data[] = {0x6, 0x7, 0x8}; - const size_t raw_data_size = - sizeof(raw_data)/sizeof(raw_data[0]); + const size_t raw_data_size = sizeof(raw_data) / sizeof(raw_data[0]); SecurityQuery query; query.set_connection_key(CONNECTION_KEY); @@ -210,7 +207,7 @@ TEST_F(SecurityQueryTest, Setters) { ASSERT_EQ(query.get_connection_key(), CONNECTION_KEY); ASSERT_EQ(query.get_data_size(), raw_data_size); // query shall handle own array of byte data - ASSERT_NE(query.get_data(), reinterpret_cast<uint8_t *>(NULL)); + ASSERT_NE(query.get_data(), reinterpret_cast<uint8_t*>(NULL)); for (size_t i = 0; i < raw_data_size; ++i) { ASSERT_EQ(query.get_data()[i], raw_data[i]); } @@ -228,7 +225,7 @@ TEST_F(SecurityQueryTest, Parse_NullData) { // check side-effects ASSERT_EQ(query.get_connection_key(), 0u); ASSERT_EQ(query.get_data_size(), 0u); - ASSERT_EQ(query.get_data(), reinterpret_cast<uint8_t *>(NULL)); + ASSERT_EQ(query.get_data(), reinterpret_cast<uint8_t*>(NULL)); ASSERT_TRUE(query.get_json_message().empty()); EXPECT_PRED_FORMAT2(QueryHeader_EQ, query.get_header(), invalid_header); } @@ -245,7 +242,7 @@ TEST_F(SecurityQueryTest, Parse_LessHeaderData) { // check side-effects ASSERT_EQ(query.get_connection_key(), 0u); ASSERT_EQ(query.get_data_size(), 0u); - ASSERT_EQ(query.get_data(), reinterpret_cast<uint8_t *>(NULL)); + ASSERT_EQ(query.get_data(), reinterpret_cast<uint8_t*>(NULL)); ASSERT_TRUE(query.get_json_message().empty()); EXPECT_PRED_FORMAT2(QueryHeader_EQ, query.get_header(), invalid_header); } @@ -253,8 +250,7 @@ TEST_F(SecurityQueryTest, Parse_LessHeaderData) { * SecurityQuery serializes data equal header size */ TEST_F(SecurityQueryTest, Parse_HeaderData) { - const std::vector<uint8_t> vector = - DeserializeData(init_header, NULL, 0u); + const std::vector<uint8_t> vector = DeserializeData(init_header, NULL, 0u); SecurityQuery query; const bool result = query.SerializeQuery(&vector[0], vector.size()); @@ -263,7 +259,7 @@ TEST_F(SecurityQueryTest, Parse_HeaderData) { // check side-effects ASSERT_EQ(query.get_connection_key(), 0u); ASSERT_EQ(query.get_data_size(), 0u); - ASSERT_EQ(query.get_data(), reinterpret_cast<uint8_t *>(NULL)); + ASSERT_EQ(query.get_data(), reinterpret_cast<uint8_t*>(NULL)); ASSERT_TRUE(query.get_json_message().empty()); EXPECT_PRED_FORMAT2(QueryHeader_EQ, query.get_header(), init_header); @@ -277,8 +273,7 @@ TEST_F(SecurityQueryTest, Parse_HeaderData) { TEST_F(SecurityQueryTest, Parse_HeaderDataWrong) { // Wrong json size init_header.json_size = 0x0FFFFFFF; - const std::vector<uint8_t> vector = - DeserializeData(init_header, NULL, 0u); + const std::vector<uint8_t> vector = DeserializeData(init_header, NULL, 0u); SecurityQuery query; const bool result = query.SerializeQuery(&vector[0], vector.size()); @@ -287,7 +282,7 @@ TEST_F(SecurityQueryTest, Parse_HeaderDataWrong) { // check side-effects ASSERT_EQ(query.get_connection_key(), 0u); ASSERT_EQ(query.get_data_size(), 0u); - ASSERT_EQ(query.get_data(), reinterpret_cast<uint8_t *>(NULL)); + ASSERT_EQ(query.get_data(), reinterpret_cast<uint8_t*>(NULL)); ASSERT_TRUE(query.get_json_message().empty()); EXPECT_PRED_FORMAT2(QueryHeader_EQ, query.get_header(), init_header); @@ -307,11 +302,10 @@ TEST_F(SecurityQueryTest, Parse_InvalidQuery) { // some sample data uint8_t raw_data[] = {0x6, 0x7, 0x8}; - const size_t raw_data_size = - sizeof(raw_data)/sizeof(raw_data[0]); + const size_t raw_data_size = sizeof(raw_data) / sizeof(raw_data[0]); const std::vector<uint8_t> vector = - DeserializeData(invalid_query_header, raw_data, raw_data_size); + DeserializeData(invalid_query_header, raw_data, raw_data_size); SecurityQuery query; const bool result = query.SerializeQuery(&vector[0], vector.size()); @@ -320,9 +314,9 @@ TEST_F(SecurityQueryTest, Parse_InvalidQuery) { EXPECT_PRED_FORMAT2(QueryHeader_EQ, query.get_header(), invalid_query_header); ASSERT_EQ(query.get_data_size(), raw_data_size); // query shall handle own array of byte data - ASSERT_NE(query.get_data(), reinterpret_cast<uint8_t *>(NULL)); + ASSERT_NE(query.get_data(), reinterpret_cast<uint8_t*>(NULL)); for (size_t i = 0; i < raw_data_size; ++i) { - ASSERT_EQ(query.get_data()[i], raw_data[+ i]); + ASSERT_EQ(query.get_data()[i], raw_data[+i]); } // check side-effects ASSERT_EQ(query.get_connection_key(), 0u); @@ -344,7 +338,7 @@ TEST_F(SecurityQueryTest, Parse_InvalidQuery_UnknownTypeId) { SEQ_NUMBER); const std::vector<uint8_t> vector = - DeserializeData(invalid_type_id_header, NULL, 0u); + DeserializeData(invalid_type_id_header, NULL, 0u); SecurityQuery query; const bool result = query.SerializeQuery(&vector[0], vector.size()); @@ -352,10 +346,11 @@ TEST_F(SecurityQueryTest, Parse_InvalidQuery_UnknownTypeId) { // Parse set all unknown types and ids to INVALID_QUERY_ID invalid_type_id_header.query_type = SecurityQuery::INVALID_QUERY_TYPE; invalid_type_id_header.query_id = SecurityQuery::INVALID_QUERY_ID; - EXPECT_PRED_FORMAT2(QueryHeader_EQ, query.get_header(), invalid_type_id_header); + EXPECT_PRED_FORMAT2( + QueryHeader_EQ, query.get_header(), invalid_type_id_header); // check side-effects ASSERT_EQ(query.get_data_size(), 0u); - ASSERT_EQ(query.get_data(), reinterpret_cast<uint8_t *>(NULL)); + ASSERT_EQ(query.get_data(), reinterpret_cast<uint8_t*>(NULL)); ASSERT_EQ(query.get_connection_key(), 0u); ASSERT_TRUE(query.get_json_message().empty()); } @@ -370,7 +365,7 @@ TEST_F(SecurityQueryTest, Parse_InvalidQuery_UnknownId_Response) { SecurityQuery::INVALID_QUERY_ID - 2, SEQ_NUMBER); const std::vector<uint8_t> vector = - DeserializeData(invalid_id_header, NULL, 0u); + DeserializeData(invalid_id_header, NULL, 0u); SecurityQuery query; const bool result = query.SerializeQuery(&vector[0], vector.size()); @@ -380,7 +375,7 @@ TEST_F(SecurityQueryTest, Parse_InvalidQuery_UnknownId_Response) { EXPECT_PRED_FORMAT2(QueryHeader_EQ, query.get_header(), invalid_id_header); // check side-effects ASSERT_EQ(query.get_data_size(), 0u); - ASSERT_EQ(query.get_data(), reinterpret_cast<uint8_t *>(NULL)); + ASSERT_EQ(query.get_data(), reinterpret_cast<uint8_t*>(NULL)); ASSERT_EQ(query.get_connection_key(), 0u); ASSERT_TRUE(query.get_json_message().empty()); } @@ -395,11 +390,10 @@ TEST_F(SecurityQueryTest, Parse_Handshake) { SEQ_NUMBER); // some sample data uint8_t raw_data[] = {0x6, 0x7, 0x8}; - const size_t raw_data_size = - sizeof(raw_data)/sizeof(raw_data[0]); + const size_t raw_data_size = sizeof(raw_data) / sizeof(raw_data[0]); const std::vector<uint8_t> vector = - DeserializeData(handshake_header, raw_data, raw_data_size); + DeserializeData(handshake_header, raw_data, raw_data_size); SecurityQuery query; const bool result = query.SerializeQuery(&vector[0], vector.size()); @@ -407,9 +401,9 @@ TEST_F(SecurityQueryTest, Parse_Handshake) { EXPECT_PRED_FORMAT2(QueryHeader_EQ, query.get_header(), handshake_header); ASSERT_EQ(query.get_data_size(), raw_data_size); // query shall handle own array of byte data - ASSERT_NE(query.get_data(), reinterpret_cast<uint8_t *>(NULL)); + ASSERT_NE(query.get_data(), reinterpret_cast<uint8_t*>(NULL)); for (size_t i = 0; i < raw_data_size; ++i) { - ASSERT_EQ(query.get_data()[i], raw_data[+ i]); + ASSERT_EQ(query.get_data()[i], raw_data[+i]); } // check side-effects ASSERT_EQ(query.get_connection_key(), 0u); @@ -426,23 +420,22 @@ TEST_F(SecurityQueryTest, Parse_Handshake) { TEST_F(SecurityQueryTest, Parse_InternalError) { std::string error_str = "{some error}"; SecurityQuery::QueryHeader internal_error_header( - SecurityQuery::REQUEST, - SecurityQuery::SEND_INTERNAL_ERROR, - SEQ_NUMBER); + SecurityQuery::REQUEST, SecurityQuery::SEND_INTERNAL_ERROR, SEQ_NUMBER); internal_error_header.json_size = error_str.size(); const uint8_t* raw_data = reinterpret_cast<const uint8_t*>(error_str.c_str()); const std::vector<uint8_t> vector = - DeserializeData(internal_error_header, raw_data, error_str.size()); + DeserializeData(internal_error_header, raw_data, error_str.size()); SecurityQuery query; const bool result = query.SerializeQuery(&vector[0], vector.size()); ASSERT_TRUE(result); - EXPECT_PRED_FORMAT2(QueryHeader_EQ, query.get_header(), internal_error_header); + EXPECT_PRED_FORMAT2( + QueryHeader_EQ, query.get_header(), internal_error_header); // check side-effects ASSERT_EQ(query.get_data_size(), 0u); - ASSERT_EQ(query.get_data(), reinterpret_cast<uint8_t *>(NULL)); + ASSERT_EQ(query.get_data(), reinterpret_cast<uint8_t*>(NULL)); ASSERT_EQ(query.get_connection_key(), 0u); ASSERT_EQ(query.get_json_message(), error_str); @@ -451,6 +444,6 @@ TEST_F(SecurityQueryTest, Parse_InternalError) { ASSERT_EQ(deserialize_vector, vector); } -} // namespace security_manager_test -} // namespace components -} // namespace test +} // namespace security_manager_test +} // namespace components +} // namespace test diff --git a/src/components/security_manager/test/ssl_certificate_handshake_test.cc b/src/components/security_manager/test/ssl_certificate_handshake_test.cc new file mode 100644 index 0000000000..3d62dd5d6a --- /dev/null +++ b/src/components/security_manager/test/ssl_certificate_handshake_test.cc @@ -0,0 +1,583 @@ +/* + * Copyright (c) 2015, Ford Motor Company + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of the Ford Motor Company nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <fstream> +#include <sstream> + +#include "gtest/gtest.h" +#include "security_manager/crypto_manager_impl.h" +#include "security_manager/mock_security_manager_settings.h" +#include "utils/custom_string.h" + +using ::testing::Return; +using ::testing::ReturnRef; + +namespace test { +namespace components { +namespace ssl_handshake_test { +namespace custom_str = utils::custom_string; +// Use this macro for correct line printing +// in case of fail insize of the #method +#define GTEST_TRACE(method) \ + do { \ + SCOPED_TRACE(""); \ + method; \ + } while (false) + +namespace { +const std::string server_ca_cert_filename = "server"; +const std::string client_ca_cert_filename = "client"; +const std::string client_certificate = "client/client_credential.p12.enc"; +const std::string server_certificate = "server/spt_credential.p12.enc"; +const std::string server_unsigned_cert_file = + "server/spt_credential_unsigned.p12.enc"; +const std::string server_expired_cert_file = + "server/spt_credential_expired.p12.enc"; + +const bool verify_peer = true; +const bool skip_peer_verification = false; + +const size_t updates_before_hour = 24; + +} // namespace + +class SSLHandshakeTest : public testing::Test { + protected: + void SetUp() OVERRIDE { + mock_server_manager_settings = new testing::NiceMock< + security_manager_test::MockCryptoManagerSettings>(); + + 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< + security_manager_test::MockCryptoManagerSettings>(); + + 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; + } + + void TearDown() OVERRIDE { + server_manager->ReleaseSSLContext(server_ctx); + delete server_manager; + client_manager->ReleaseSSLContext(client_ctx); + delete client_manager; + } + + void SetServerInitialValues(const security_manager::Protocol protocol, + const std::string cert, + const std::string server_ciphers_list, + const bool verify_peer, + const std::string& ca_certificate_path) { + 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()) + .WillByDefault(Return(security_manager::SERVER)); + ON_CALL(*mock_server_manager_settings, security_manager_protocol_name()) + .WillByDefault(Return(protocol)); + ON_CALL(*mock_server_manager_settings, certificate_data()) + .WillByDefault(ReturnRef(server_certificate_)); + ON_CALL(*mock_server_manager_settings, ciphers_list()) + .WillByDefault(ReturnRef(server_ciphers_list_)); + ON_CALL(*mock_server_manager_settings, ca_cert_path()) + .WillByDefault(ReturnRef(server_ca_certificate_path_)); + ON_CALL(*mock_server_manager_settings, verify_peer()) + .WillByDefault(Return(verify_peer)); + } + void SetClientInitialValues(const security_manager::Protocol protocol, + const std::string certificate, + const std::string client_ciphers_list, + const bool verify_peer, + const std::string& ca_certificate_path) { + client_certificate_ = certificate; + client_ciphers_list_ = client_ciphers_list; + client_ca_certificate_path_ = ca_certificate_path; + + ON_CALL(*mock_client_manager_settings, security_manager_mode()) + .WillByDefault(Return(security_manager::CLIENT)); + ON_CALL(*mock_client_manager_settings, security_manager_protocol_name()) + .WillByDefault(Return(protocol)); + ON_CALL(*mock_client_manager_settings, certificate_data()) + .WillByDefault(ReturnRef(client_certificate_)); + ON_CALL(*mock_client_manager_settings, ciphers_list()) + .WillByDefault(ReturnRef(client_ciphers_list_)); + ON_CALL(*mock_client_manager_settings, ca_cert_path()) + .WillByDefault(ReturnRef(client_ca_certificate_path_)); + ON_CALL(*mock_client_manager_settings, verify_peer()) + .WillByDefault(Return(verify_peer)); + } + + bool InitServerManagers(security_manager::Protocol protocol, + const std::string& cert_filename, + const std::string& ciphers_list, + const bool verify_peer, + const std::string& ca_certificate_path) { + std::ifstream cert(cert_filename); + std::stringstream ss; + if (cert.is_open()) { + ss << cert.rdbuf(); + } + cert.close(); + SetServerInitialValues( + protocol, ss.str(), ciphers_list, verify_peer, ca_certificate_path); + const bool initialized = server_manager->Init(); + + if (!initialized) { + return false; + } + + server_ctx = server_manager->CreateSSLContext(); + + if (!server_ctx) { + return false; + } + + server_ctx->SetHandshakeContext( + security_manager::SSLContext::HandshakeContext( + custom_str::CustomString("SPT"), + custom_str::CustomString("client"))); + + return true; + } + + bool InitClientManagers(security_manager::Protocol protocol, + const std::string& cert_filename, + const std::string& ciphers_list, + const bool verify_peer, + const std::string& ca_certificate_path) { + std::ifstream cert(cert_filename); + std::stringstream certificate; + if (cert.is_open()) { + certificate << cert.rdbuf(); + } + cert.close(); + SetClientInitialValues(protocol, + certificate.str(), + ciphers_list, + verify_peer, + ca_certificate_path); + const bool initialized = client_manager->Init(); + if (!initialized) { + return false; + } + + client_ctx = client_manager->CreateSSLContext(); + if (!client_ctx) { + return false; + } + + client_ctx->SetHandshakeContext( + security_manager::SSLContext::HandshakeContext( + custom_str::CustomString("SPT"), + custom_str::CustomString("server"))); + + return true; + } + + void ResetConnections() { + 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); + } + + void HandshakeProcedure_Success() { + using security_manager::SSLContext; + StartHandshake(); + + while (true) { + 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_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()) { + break; + } + + ASSERT_FALSE(client_buf == NULL); + ASSERT_GT(client_buf_len, 0u); + } + } + + void HandshakeProcedure_ServerSideFail() { + using security_manager::SSLContext; + + 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()) + << "Expected server side handshake fail"; + + // First few handshake will be successful + if (result != SSLContext::Handshake_Result_Success) { + // Test successfully passed with handshake fail + return; + } + 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)) + << ERR_reason_error_string(ERR_get_error()); + ASSERT_FALSE(client_ctx->IsInitCompleted()) + << "Expected server side handshake fail"; + + ASSERT_FALSE(client_buf == NULL); + ASSERT_GT(client_buf_len, 0u); + } + FAIL() << "Expected server side handshake fail"; + } + + void HandshakeProcedure_ClientSideFail( + security_manager::SSLContext::HandshakeResult expected_result) { + using security_manager::SSLContext; + + StartHandshake(); + + while (true) { + 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); + + 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 + if (result != SSLContext::Handshake_Result_Success) { + // Test successfully passed with handshake fail + ASSERT_EQ(expected_result, result); + return; + } + + 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; + testing::NiceMock<security_manager_test::MockCryptoManagerSettings>* + mock_server_manager_settings; + testing::NiceMock<security_manager_test::MockCryptoManagerSettings>* + mock_client_manager_settings; + + 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_; + std::string server_ca_certificate_path_; + + std::string client_certificate_; + std::string client_ciphers_list_; + std::string client_ca_certificate_path_; +}; + +TEST_F(SSLHandshakeTest, NoVerification) { + ASSERT_TRUE(InitServerManagers(security_manager::TLSv1_2, + server_certificate, + "ALL", + skip_peer_verification, + "")) + << server_manager->LastError(); + ASSERT_TRUE(InitClientManagers(security_manager::TLSv1_2, + client_certificate, + "ALL", + skip_peer_verification, + "")) + << client_manager->LastError(); + + GTEST_TRACE(HandshakeProcedure_Success()); +} + +TEST_F(SSLHandshakeTest, CAVerification_ServerSide) { + 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", + skip_peer_verification, + "")) + << client_manager->LastError(); + + GTEST_TRACE(HandshakeProcedure_Success()); +} + +TEST_F(SSLHandshakeTest, CAVerification_ServerSide_NoCACertificate) { + ASSERT_TRUE(InitServerManagers(security_manager::TLSv1_2, + server_certificate, + "ALL", + verify_peer, + "unex")) + << server_manager->LastError(); + ASSERT_TRUE(InitClientManagers(security_manager::TLSv1_2, + client_certificate, + "ALL", + skip_peer_verification, + "")) + << client_manager->LastError(); + + GTEST_TRACE(HandshakeProcedure_ServerSideFail()); + ASSERT_TRUE(InitServerManagers(security_manager::TLSv1_2, + server_certificate, + "ALL", + verify_peer, + client_ca_cert_filename)) + << 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, + server_certificate, + "ALL", + skip_peer_verification, + "")) + << server_manager->LastError(); + ASSERT_TRUE(InitClientManagers(security_manager::TLSv1_2, + client_certificate, + "ALL", + verify_peer, + "client_ca_cert_filename")) + << client_manager->LastError(); + + GTEST_TRACE(HandshakeProcedure_ClientSideFail( + security_manager::SSLContext::Handshake_Result_Fail)); + + ASSERT_TRUE(InitClientManagers(security_manager::TLSv1_2, + client_certificate, + "ALL", + verify_peer, + server_ca_cert_filename)) + << client_manager->LastError(); + + GTEST_TRACE(ResetConnections()); + + GTEST_TRACE(HandshakeProcedure_Success()); +} + +TEST_F(SSLHandshakeTest, CAVerification_BothSides) { + 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, UnsignedCert) { + ASSERT_TRUE(InitServerManagers(security_manager::TLSv1_2, + server_unsigned_cert_file, + "ALL", + skip_peer_verification, + "")) + << server_manager->LastError(); + ASSERT_TRUE(InitClientManagers(security_manager::TLSv1_2, + client_certificate, + "ALL", + verify_peer, + client_ca_cert_filename)) + << client_manager->LastError(); + GTEST_TRACE(HandshakeProcedure_ClientSideFail( + security_manager::SSLContext::Handshake_Result_CertNotSigned)); +} + +TEST_F(SSLHandshakeTest, ExpiredCert) { + ASSERT_TRUE(InitServerManagers(security_manager::TLSv1_2, + server_expired_cert_file, + "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_ClientSideFail( + security_manager::SSLContext::Handshake_Result_CertExpired)); +} + +TEST_F(SSLHandshakeTest, AppNameAndAppIDInvalid) { + 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(); + + 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( + security_manager::SSLContext::HandshakeContext( + custom_str::CustomString("Wrong"), + custom_str::CustomString("server"))); + + GTEST_TRACE(HandshakeProcedure_ClientSideFail( + security_manager::SSLContext::Handshake_Result_AppIDMismatch)); +} + +TEST_F(SSLHandshakeTest, NoVerification_ResetConnection) { + ASSERT_TRUE(InitServerManagers(security_manager::TLSv1_2, + server_certificate, + "ALL", + skip_peer_verification, + "")) + << server_manager->LastError(); + ASSERT_TRUE(InitClientManagers(security_manager::TLSv1_2, + client_certificate, + "ALL", + skip_peer_verification, + "")) + << client_manager->LastError(); + + const int times = 100; + for (int i = 0; i < times; ++i) { + // Expect success handshake + GTEST_TRACE(HandshakeProcedure_Success()); + + // Reset SSl connections + GTEST_TRACE(ResetConnections()); + } +} + +TEST_F(SSLHandshakeTest, CAVerification_BothSides_ResetConnection) { + 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", + skip_peer_verification, + server_ca_cert_filename)) + << client_manager->LastError(); + + const int times = 100; + for (int i = 0; i < times; ++i) { + // Expect success handshake + GTEST_TRACE(HandshakeProcedure_Success()); + + // Reset SSl connections + GTEST_TRACE(ResetConnections()); + } +} + +// TODO(EZamakhov): add fail tests -broken or not full ca certificate chain + +} // namespace ssl_handshake_test +} // namespace components +} // namespace test diff --git a/src/components/security_manager/test/ssl_context_test.cc b/src/components/security_manager/test/ssl_context_test.cc new file mode 100644 index 0000000000..b35da3fc61 --- /dev/null +++ b/src/components/security_manager/test/ssl_context_test.cc @@ -0,0 +1,535 @@ +/* + * Copyright (c) 2016, Ford Motor Company + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * Neither the name of the Ford Motor Company nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "gtest/gtest.h" +#include <fstream> +#include <sstream> +#include <string> +#include <openssl/ssl.h> + +#include "security_manager/crypto_manager.h" +#include "security_manager/crypto_manager_impl.h" +#include "security_manager/ssl_context.h" +#include "utils/custom_string.h" +#include "security_manager/mock_security_manager_settings.h" +#include "utils/shared_ptr.h" +#include "utils/make_shared.h" + +using ::testing::Return; +using ::testing::ReturnRef; +using ::testing::NiceMock; + +namespace { +const size_t kUpdatesBeforeHour = 24; +const std::string kCaPath = ""; +const uint8_t* kServerBuf; +const uint8_t* kClientBuf; +const std::string kAllCiphers = "ALL"; +size_t server_buf_len; +size_t client_buf_len; +#ifdef __QNXNTO__ +const std::string kFordCipher = SSL3_TXT_RSA_DES_192_CBC3_SHA; +#else +// Used cipher from ford protocol requirement +const std::string kFordCipher = TLS1_TXT_RSA_WITH_AES_256_GCM_SHA384; +#endif +} // namespace + +namespace test { +namespace components { +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; + + 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) {} +}; + +class SSLTest : public testing::Test { + protected: + static void SetUpTestCase() { + std::ifstream certificate_file("server/spt_credential_unsigned.p12"); + std::stringstream certificate; + if (certificate_file.is_open()) { + certificate << certificate_file.rdbuf(); + } + certificate_file.close(); + certificate_data_base64_ = certificate.str(); + ASSERT_FALSE(certificate_data_base64_.empty()) + << "Certificate data file is empty"; + } + + virtual void SetUp() OVERRIDE { + mock_crypto_manager_settings_ = utils::MakeShared< + NiceMock<security_manager_test::MockCryptoManagerSettings>>(); + utils::SharedPtr<security_manager::CryptoManagerSettings> crypto_set( + mock_crypto_manager_settings_); + crypto_manager_ = new security_manager::CryptoManagerImpl(crypto_set); + + EXPECT_CALL(*mock_crypto_manager_settings_, security_manager_mode()) + .WillOnce(Return(security_manager::SERVER)); + EXPECT_CALL(*mock_crypto_manager_settings_, + security_manager_protocol_name()) + .WillOnce(Return(security_manager::TLSv1_2)); + EXPECT_CALL(*mock_crypto_manager_settings_, certificate_data()) + .WillOnce(ReturnRef(certificate_data_base64_)); + EXPECT_CALL(*mock_crypto_manager_settings_, ciphers_list()) + .WillRepeatedly(ReturnRef(kAllCiphers)); + EXPECT_CALL(*mock_crypto_manager_settings_, ca_cert_path()) + .WillRepeatedly(ReturnRef(kCaPath)); + EXPECT_CALL(*mock_crypto_manager_settings_, verify_peer()) + .WillOnce(Return(false)); + 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); + + EXPECT_CALL(*mock_client_manager_settings_, security_manager_mode()) + .WillOnce(Return(security_manager::CLIENT)); + EXPECT_CALL(*mock_client_manager_settings_, + security_manager_protocol_name()) + .WillOnce(Return(security_manager::TLSv1_2)); + EXPECT_CALL(*mock_client_manager_settings_, certificate_data()) + .WillOnce(ReturnRef(certificate_data_base64_)); + EXPECT_CALL(*mock_client_manager_settings_, ciphers_list()) + .WillRepeatedly(ReturnRef(kAllCiphers)); + EXPECT_CALL(*mock_client_manager_settings_, ca_cert_path()) + .Times(2) + .WillRepeatedly(ReturnRef(kCaPath)); + EXPECT_CALL(*mock_client_manager_settings_, verify_peer()) + .WillOnce(Return(false)); + const bool client_manager_initialization = client_manager_->Init(); + EXPECT_TRUE(client_manager_initialization); + + ON_CALL(*mock_crypto_manager_settings_, maximum_payload_size()) + .WillByDefault(Return(kMaximumPayloadSize)); + ON_CALL(*mock_client_manager_settings_, maximum_payload_size()) + .WillByDefault(Return(kMaximumPayloadSize)); + EXPECT_CALL(*mock_crypto_manager_settings_, security_manager_mode()) + .WillRepeatedly(Return(security_manager::SERVER)); + 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(); + + 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); + + kServerBuf = NULL; + kClientBuf = NULL; + server_buf_len = 0u; + client_buf_len = 0u; + } + + void TearDown() OVERRIDE { + crypto_manager_->ReleaseSSLContext(server_ctx); + client_manager_->ReleaseSSLContext(client_ctx); + + delete crypto_manager_; + delete client_manager_; + } + + const size_t kMaximumPayloadSize = 1000u; + security_manager::CryptoManager* crypto_manager_; + security_manager::CryptoManager* client_manager_; + utils::SharedPtr<NiceMock<security_manager_test::MockCryptoManagerSettings>> + 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; + + static std::string certificate_data_base64_; +}; +std::string SSLTest::certificate_data_base64_; + +// StartHandshake() fails when client and server protocols are not TLSv1_2 +class SSLTestParam : public testing::TestWithParam<ProtocolAndCipher> { + protected: + virtual void SetUp() OVERRIDE { + std::ifstream certificate_file("server/spt_credential.p12"); + ASSERT_TRUE(certificate_file.is_open()) + << "Could not open certificate data file"; + + const std::string certificate( + (std::istreambuf_iterator<char>(certificate_file)), + std::istreambuf_iterator<char>()); + certificate_file.close(); + ASSERT_FALSE(certificate.empty()) << "Certificate data file is empty"; + certificate_data_base64_ = certificate; + + mock_crypto_manager_settings_ = utils::MakeShared< + NiceMock<security_manager_test::MockCryptoManagerSettings>>(); + utils::SharedPtr<security_manager::CryptoManagerSettings> server_crypto( + mock_crypto_manager_settings_); + crypto_manager = new security_manager::CryptoManagerImpl(server_crypto); + + SetServerInitialValues(GetParam().server_protocol, + GetParam().server_ciphers_list); + + 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); + + SetClientInitialValues(GetParam().client_protocol, + GetParam().client_ciphers_list); + + const bool client_manager_initialization = client_manager->Init(); + EXPECT_TRUE(client_manager_initialization); + + 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); + + kServerBuf = NULL; + kClientBuf = NULL; + server_buf_len = 0u; + client_buf_len = 0u; + } + + void TearDown() OVERRIDE { + 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_, security_manager_mode()) + .WillByDefault(Return(security_manager::SERVER)); + ON_CALL(*mock_crypto_manager_settings_, security_manager_protocol_name()) + .WillByDefault(Return(protocol)); + ON_CALL(*mock_crypto_manager_settings_, certificate_data()) + .WillByDefault(ReturnRef(certificate_data_base64_)); + ON_CALL(*mock_crypto_manager_settings_, ciphers_list()) + .WillByDefault(ReturnRef(server_ciphers_list)); + ON_CALL(*mock_crypto_manager_settings_, ca_cert_path()) + .WillByDefault(ReturnRef(kCaPath)); + ON_CALL(*mock_crypto_manager_settings_, verify_peer()) + .WillByDefault(Return(false)); + } + void SetClientInitialValues(security_manager::Protocol protocol, + const std::string& client_ciphers_list) { + ON_CALL(*mock_client_manager_settings_, security_manager_mode()) + .WillByDefault(Return(security_manager::CLIENT)); + ON_CALL(*mock_client_manager_settings_, security_manager_protocol_name()) + .WillByDefault(Return(protocol)); + ON_CALL(*mock_client_manager_settings_, certificate_data()) + .WillByDefault(ReturnRef(certificate_data_base64_)); + ON_CALL(*mock_client_manager_settings_, ciphers_list()) + .WillByDefault(ReturnRef(client_ciphers_list)); + ON_CALL(*mock_client_manager_settings_, ca_cert_path()) + .WillByDefault(ReturnRef(kCaPath)); + ON_CALL(*mock_client_manager_settings_, verify_peer()) + .WillByDefault(Return(false)); + } + + 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; + security_manager::CryptoManager* client_manager; + security_manager::SSLContext* server_ctx; + security_manager::SSLContext* client_ctx; + std::string certificate_data_base64_; +}; + +class SSLTestForTLS1_2 : public SSLTestParam {}; + +// This case fails starting because we can handshake only with TLSv1_2 protocol. +INSTANTIATE_TEST_CASE_P( + CorrectProtocolAndCiphers, + SSLTestParam, + ::testing::Values(ProtocolAndCipher(security_manager::TLSv1, + security_manager::TLSv1, + kFordCipher, + kFordCipher), + ProtocolAndCipher(security_manager::TLSv1_1, + security_manager::TLSv1_1, + kFordCipher, + kFordCipher), + ProtocolAndCipher(security_manager::SSLv3, + security_manager::SSLv3, + kFordCipher, + kFordCipher))); + +INSTANTIATE_TEST_CASE_P( + IncorrectProtocolAndCiphers, + SSLTestParam, + ::testing::Values(ProtocolAndCipher(security_manager::TLSv1, + security_manager::TLSv1_1, + kFordCipher, + kFordCipher), + ProtocolAndCipher(security_manager::TLSv1, + security_manager::SSLv3, + kFordCipher, + kFordCipher), + ProtocolAndCipher(security_manager::TLSv1_1, + security_manager::TLSv1, + kFordCipher, + kFordCipher), + ProtocolAndCipher(security_manager::TLSv1_1, + security_manager::SSLv3, + kFordCipher, + kFordCipher), + ProtocolAndCipher(security_manager::TLSv1_2, + security_manager::TLSv1, + kFordCipher, + kFordCipher), + ProtocolAndCipher(security_manager::TLSv1_2, + security_manager::TLSv1_1, + kFordCipher, + kFordCipher), + ProtocolAndCipher(security_manager::TLSv1_2, + security_manager::SSLv3, + kFordCipher, + kFordCipher), + ProtocolAndCipher(security_manager::SSLv3, + security_manager::TLSv1, + kFordCipher, + kFordCipher), + ProtocolAndCipher(security_manager::SSLv3, + security_manager::TLSv1_1, + kFordCipher, + kFordCipher))); + +TEST_F(SSLTest, OnTSL2Protocol_BrokenHandshake) { + ASSERT_EQ(security_manager::SSLContext::Handshake_Result_Success, + 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 + const_cast<uint8_t*>(kClientBuf)[0] ^= 0xFF; + 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( + 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()); +} + +// TODO {AKozoriz} : Unexpected uncomplited init of SSL component. +// In this and next tests. +// Must be fixed after merge to develop. +TEST_F(SSLTest, DISABLED_OnTSL2Protocol_Positive) { + ASSERT_EQ(client_ctx->StartHandshake(&kClientBuf, &client_buf_len), + security_manager::SSLContext::Handshake_Result_Success); + ASSERT_FALSE(NULL == kClientBuf); + ASSERT_LT(0u, client_buf_len); + EXPECT_TRUE(server_ctx->IsInitCompleted()); + + while (true) { + const security_manager::SSLContext::HandshakeResult server_result = + server_ctx->DoHandshakeStep( + kClientBuf, client_buf_len, &kServerBuf, &server_buf_len); + ASSERT_EQ(security_manager::SSLContext::Handshake_Result_Success, + server_result); + ASSERT_FALSE(NULL == kServerBuf); + ASSERT_LT(0u, server_buf_len); + + const security_manager::SSLContext::HandshakeResult client_result = + 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()) { + break; + } + + ASSERT_FALSE(NULL == kClientBuf); + ASSERT_LT(0u, 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()); + + // 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( + 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( + encrypted_text, encrypted_text_len, &text, &text_len)); + ASSERT_NE(reinterpret_cast<void*>(NULL), text); + ASSERT_LT(0u, text_len); + + ASSERT_EQ(strncmp(reinterpret_cast<const char*>(text), "abra", 4), 0); +} + +TEST_F(SSLTest, DISABLED_OnTSL2Protocol_EcncryptionFail) { + ASSERT_EQ(security_manager::SSLContext::Handshake_Result_Success, + client_ctx->StartHandshake(&kClientBuf, &client_buf_len)); + + 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( + 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( + 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()); + + // 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( + text, text_len, &encrypted_text, &encrypted_text_len)); + ASSERT_NE(reinterpret_cast<void*>(NULL), encrypted_text); + ASSERT_LT(0u, encrypted_text_len); + + std::vector<uint8_t> broken(encrypted_text, + encrypted_text + encrypted_text_len); + // Broke message + broken[encrypted_text_len / 2] ^= 0xFF; + + const uint8_t* out_text; + size_t out_text_size; + // Decrypt broken text on server side + 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( + encrypted_text, encrypted_text_len, &out_text, &out_text_size)); + 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)); + EXPECT_TRUE(NULL == kClientBuf); + EXPECT_EQ(0u, client_buf_len); + ASSERT_EQ(security_manager::SSLContext::Handshake_Result_Success, + 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()); +} + +INSTANTIATE_TEST_CASE_P( + ServerProtocolTLSv12, + SSLTestForTLS1_2, + ::testing::Values(ProtocolAndCipher(security_manager::TLSv1, + security_manager::TLSv1_2, + kFordCipher, + kFordCipher), + ProtocolAndCipher(security_manager::TLSv1_1, + security_manager::TLSv1_2, + kFordCipher, + kFordCipher), + ProtocolAndCipher(security_manager::SSLv3, + security_manager::TLSv1_2, + kFordCipher, + kFordCipher))); + +TEST_P(SSLTestForTLS1_2, HandshakeFailed) { + ASSERT_EQ(security_manager::SSLContext::Handshake_Result_Success, + 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)); + EXPECT_TRUE(NULL == kServerBuf); + EXPECT_EQ(0u, server_buf_len); + + EXPECT_FALSE(server_ctx->IsInitCompleted()); +} + +} // namespace ssl_context_test +} // namespace components +} // namespace test |