diff options
author | conlain-k <conlain.k@gmail.com> | 2018-06-25 11:12:56 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-06-25 11:12:56 -0400 |
commit | 7e4768b922fe7693c3fa552c08ced456306cb103 (patch) | |
tree | 9caffb7d534bd3b428b3388cb97ff55cf864350a /src | |
parent | ccf9073578e5c43f99ca9c8db09a15382129e0bd (diff) | |
parent | a79341d7a35b7d97e239d4908a34b72978d5a821 (diff) | |
download | sdl_core-7e4768b922fe7693c3fa552c08ced456306cb103.tar.gz |
Merge branch 'develop' into feature/boost_datetime_implementation
Diffstat (limited to 'src')
90 files changed, 3202 insertions, 846 deletions
diff --git a/src/3rd_party/CMakeLists.txt b/src/3rd_party/CMakeLists.txt index 6752f30227..54bfdb022b 100644 --- a/src/3rd_party/CMakeLists.txt +++ b/src/3rd_party/CMakeLists.txt @@ -227,7 +227,8 @@ if (HMIADAPTER STREQUAL "messagebroker") SOURCE_DIR ${BOOST_LIB_SOURCE_DIRECTORY} CONFIGURE_COMMAND ./bootstrap.sh --with-libraries=system,thread,date_time --prefix=${3RD_PARTY_INSTALL_PREFIX} BUILD_COMMAND ./b2 - INSTALL_COMMAND ${BOOST_INSTALL_COMMAND} --with-system --with-thread --with-date_time --prefix=${3RD_PARTY_INSTALL_PREFIX} + INSTALL_COMMAND ${BOOST_INSTALL_COMMAND} --with-system --with-thread --with-date_time --prefix=${3RD_PARTY_INSTALL_PREFIX} > boost_install.log + INSTALL_DIR ${3RD_PARTY_INSTALL_PREFIX} BUILD_IN_SOURCE true ) diff --git a/src/appMain/CMakeLists.txt b/src/appMain/CMakeLists.txt index 2acc0bf3ae..06738713bd 100644 --- a/src/appMain/CMakeLists.txt +++ b/src/appMain/CMakeLists.txt @@ -109,7 +109,9 @@ set(LIBRARIES jsoncpp ConfigProfile Resumption + SystemTimeLibrary ) + if(REMOTE_CONTROL) SET (LIBRARIES ${LIBRARIES} diff --git a/src/appMain/life_cycle.cc b/src/appMain/life_cycle.cc index fc8441f28c..90a23465be 100644 --- a/src/appMain/life_cycle.cc +++ b/src/appMain/life_cycle.cc @@ -34,6 +34,7 @@ #include "utils/signals.h" #include "utils/make_shared.h" #include "config_profile/profile.h" +#include "application_manager/system_time/system_time_handler_impl.h" #include "resumption/last_state_impl.h" #ifdef ENABLE_SECURITY @@ -119,7 +120,11 @@ bool LifeCycle::StartComponents() { } #ifdef ENABLE_SECURITY - security_manager_ = new security_manager::SecurityManagerImpl(); + auto system_time_handler = + std::unique_ptr<application_manager::SystemTimeHandlerImpl>( + new application_manager::SystemTimeHandlerImpl(*app_manager_)); + security_manager_ = + new security_manager::SecurityManagerImpl(std::move(system_time_handler)); crypto_manager_ = new security_manager::CryptoManagerImpl( utils::MakeShared<security_manager::CryptoManagerSettingsImpl>( profile_, app_manager_->GetPolicyHandler().RetrieveCertificate())); @@ -131,7 +136,7 @@ bool LifeCycle::StartComponents() { security_manager_->set_crypto_manager(crypto_manager_); security_manager_->AddListener(app_manager_); - app_manager_->AddPolicyObserver(crypto_manager_); + app_manager_->AddPolicyObserver(security_manager_); app_manager_->AddPolicyObserver(protocol_handler_); if (!crypto_manager_->Init()) { LOG4CXX_ERROR(logger_, "CryptoManager initialization fail."); diff --git a/src/appMain/life_cycle.h b/src/appMain/life_cycle.h index db18892cd3..e37da3fa1d 100644 --- a/src/appMain/life_cycle.h +++ b/src/appMain/life_cycle.h @@ -33,8 +33,9 @@ #ifndef SRC_APPMAIN_LIFE_CYCLE_H_ #define SRC_APPMAIN_LIFE_CYCLE_H_ #include <thread> +#include <unistd.h> #include "utils/macro.h" -#include "unistd.h" +#include "utils/shared_ptr.h" #include "config_profile/profile.h" #include "hmi_message_handler/hmi_message_handler_impl.h" @@ -65,6 +66,10 @@ class SecurityManagerImpl; } // namespace security_manager #endif // ENABLE_SECURITY +namespace utils { +class SystemTimeHandler; +} // namespace utils + namespace main_namespace { class LifeCycle { public: diff --git a/src/appMain/smartDeviceLink.ini b/src/appMain/smartDeviceLink.ini index d201a0736e..e128bc1a2e 100644 --- a/src/appMain/smartDeviceLink.ini +++ b/src/appMain/smartDeviceLink.ini @@ -152,7 +152,8 @@ HelpCommand = Help AppInfoStorage = app_info.dat [Security Manager] -Protocol = TLSv1.2 +;Protocol = TLSv1.2 +Protocol = DTLSv1.0 ; Certificate and key path to pem file CertificatePath = mycert.pem KeyPath = mykey.pem diff --git a/src/components/application_manager/CMakeLists.txt b/src/components/application_manager/CMakeLists.txt index e9f2f8ec7b..966dbee353 100644 --- a/src/components/application_manager/CMakeLists.txt +++ b/src/components/application_manager/CMakeLists.txt @@ -52,6 +52,7 @@ include_directories ( ${COMPONENTS_DIR}/config_profile/include ${COMPONENTS_DIR}/request_watchdog/include ${COMPONENTS_DIR}/resumption/include + ${COMPONENTS_DIR}/system_time/ ${COMPONENTS_DIR}/rpc_base/include ${COMPONENTS_DIR}/interfaces ${POLICY_PATH}/include/ @@ -85,6 +86,9 @@ set (MESSAGE_HELPER_PATHS ) collect_sources(MESSAGE_HELPER_SOURCES "${MESSAGE_HELPER_PATHS}") +set (SYSTEM_TIME_SOURCES + ${AM_SOURCE_DIR}/src/system_time/system_time_handler_impl.cc +) set (POLICIES_SOURCE_DIR ${AM_SOURCE_DIR}/src/policies @@ -146,6 +150,9 @@ set (HMI_COMMANDS_SOURCES ${COMMANDS_SOURCE_DIR}/hmi/activate_app_response.cc ${COMMANDS_SOURCE_DIR}/hmi/get_system_info_request.cc ${COMMANDS_SOURCE_DIR}/hmi/get_system_info_response.cc + ${COMMANDS_SOURCE_DIR}/hmi/basic_communication_get_system_time_request.cc + ${COMMANDS_SOURCE_DIR}/hmi/basic_communication_get_system_time_response.cc + ${COMMANDS_SOURCE_DIR}/hmi/on_system_time_ready_notification.cc ${COMMANDS_SOURCE_DIR}/hmi/sdl_get_list_of_permissions_request.cc ${COMMANDS_SOURCE_DIR}/hmi/sdl_get_list_of_permissions_response.cc ${COMMANDS_SOURCE_DIR}/hmi/sdl_get_user_friendly_message_request.cc @@ -447,6 +454,10 @@ target_link_libraries("AMHMICommandsLibrary" ${LIBRARIES} AMEventEngine) add_library("MessageHelper" ${MESSAGE_HELPER_SOURCES}) target_link_libraries("MessageHelper" ${LIBRARIES}) +add_library("SystemTimeLibrary" ${SYSTEM_TIME_SOURCES}) +target_link_libraries("SystemTimeLibrary" ${LIBRARIES} AMEventEngine) +add_dependencies("MessageHelper" HMI_API MOBILE_API) + add_library("AMMobileCommandsLibrary" ${MOBILE_COMMANDS_SOURCES} ) target_link_libraries("AMMobileCommandsLibrary" ${LIBRARIES} AMEventEngine) diff --git a/src/components/application_manager/include/application_manager/application_manager_impl.h b/src/components/application_manager/include/application_manager/application_manager_impl.h index 89a2de96f5..5dcaaaaaa7 100644 --- a/src/components/application_manager/include/application_manager/application_manager_impl.h +++ b/src/components/application_manager/include/application_manager/application_manager_impl.h @@ -815,6 +815,12 @@ class ApplicationManagerImpl security_manager::SSLContext::HandshakeResult result) OVERRIDE; /** + * @brief Notification about handshake failure + * @return true on success notification handling or false otherwise + */ + bool OnHandshakeFailed() OVERRIDE; + + /** * @brief Notification that certificate update is required. */ void OnCertificateUpdateRequired() OVERRIDE; diff --git a/src/components/application_manager/include/application_manager/commands/hmi/basic_communication_get_system_time_request.h b/src/components/application_manager/include/application_manager/commands/hmi/basic_communication_get_system_time_request.h new file mode 100644 index 0000000000..1dd0d8c6bb --- /dev/null +++ b/src/components/application_manager/include/application_manager/commands/hmi/basic_communication_get_system_time_request.h @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2018, 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_APPLICATION_MANAGER_INCLUDE_APPLICATION_MANAGER_COMMANDS_HMI_BASIC_COMMUNICATION_GET_SYSTEM_TIME_REQUEST_H_ +#define SRC_COMPONENTS_APPLICATION_MANAGER_INCLUDE_APPLICATION_MANAGER_COMMANDS_HMI_BASIC_COMMUNICATION_GET_SYSTEM_TIME_REQUEST_H_ + +#include "application_manager/commands/hmi/request_to_hmi.h" +#include "utils/macro.h" + +namespace application_manager { +namespace commands { + +/** + * @brief The BasicCommunicationGetSystemTimeRequest class sends the request + * to the HMI in order to receive current system time. + */ +class BasicCommunicationGetSystemTimeRequest : public RequestToHMI { + public: + /** + * @brief BasicCommunicationGetSystemTimeRequest does nothing except of + * initializing base class with the passed parameters. + * @param message the message to send to HMI + * @param application_manager application manager. Location service which + * is provides neccessary api to send the request. + */ + BasicCommunicationGetSystemTimeRequest( + const MessageSharedPtr& message, ApplicationManager& application_manager); + + /** + * @brief onTimeOut allows to handle case when + * system does not respond for certain request in + * appropriate time window. + */ + void onTimeOut() FINAL; +}; + +} // namespace commands +} // namespace application_manager +#endif // SRC_COMPONENTS_APPLICATION_MANAGER_INCLUDE_APPLICATION_MANAGER_COMMANDS_HMI_BASIC_COMMUNICATION_GET_SYSTEM_TIME_REQUEST_H_ diff --git a/src/components/application_manager/include/application_manager/commands/hmi/basic_communication_get_system_time_response.h b/src/components/application_manager/include/application_manager/commands/hmi/basic_communication_get_system_time_response.h new file mode 100644 index 0000000000..5e9ae4b1bb --- /dev/null +++ b/src/components/application_manager/include/application_manager/commands/hmi/basic_communication_get_system_time_response.h @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2018, 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_APPLICATION_MANAGER_INCLUDE_APPLICATION_MANAGER_COMMANDS_HMI_BASIC_COMMUNICATION_GET_SYSTEM_TIME_RESPONSE_H_ +#define SRC_COMPONENTS_APPLICATION_MANAGER_INCLUDE_APPLICATION_MANAGER_COMMANDS_HMI_BASIC_COMMUNICATION_GET_SYSTEM_TIME_RESPONSE_H_ + +#include "application_manager/commands/hmi/response_from_hmi.h" + +#include "utils/macro.h" +#include "application_manager/application_manager_impl.h" + +namespace application_manager { + +namespace commands { + +/** + * @brief The BasicCommunicationGetSystemTimeResponse class represents the + * HMI response which is contains data obtained from HMI. + */ +class BasicCommunicationGetSystemTimeResponse : public ResponseFromHMI { + public: + /** + * @brief BasicCommunicationGetSystemTimeResponse does nothing except of + * initializing base class with the passed parameters. + * @param message the message to send to HMI + * @param application_manager Location service which which is provides + * neccessary api to send the request. + */ + BasicCommunicationGetSystemTimeResponse( + const MessageSharedPtr& message, ApplicationManager& application_manager); + + /** + * @brief Run takes the message obtained from the HMI and + * sends this data to the subscribed on certain event class + */ + void Run() FINAL; +}; + +} // namespace commands +} // namespace application_manager + +#endif // SRC_COMPONENTS_APPLICATION_MANAGER_INCLUDE_APPLICATION_MANAGER_COMMANDS_HMI_BASIC_COMMUNICATION_GET_SYSTEM_TIME_RESPONSE_H_ diff --git a/src/components/application_manager/include/application_manager/commands/hmi/on_system_time_ready_notification.h b/src/components/application_manager/include/application_manager/commands/hmi/on_system_time_ready_notification.h new file mode 100644 index 0000000000..c3031da809 --- /dev/null +++ b/src/components/application_manager/include/application_manager/commands/hmi/on_system_time_ready_notification.h @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2018, 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_APPLICATION_MANAGER_INCLUDE_APPLICATION_MANAGER_COMMANDS_HMI_ON_SYSTEM_TIME_READY_NOTIFICATION_H_ +#define SRC_COMPONENTS_APPLICATION_MANAGER_INCLUDE_APPLICATION_MANAGER_COMMANDS_HMI_ON_SYSTEM_TIME_READY_NOTIFICATION_H_ + +#include "application_manager/commands/hmi/notification_from_hmi.h" +#include "application_manager/application_manager_impl.h" + +namespace application_manager { + +namespace commands { + +/** + * @brief OnSystemTimeReadyNotification command class. + * Notifies SDL whenever system time module is ready. + * It could be GPS or any other module which is allows + * to obtain system time. Once SDL receive this notification + * it is allowed to use GetSystemTimeRequest to rerieve system time. + */ +class OnSystemTimeReadyNotification : public NotificationFromHMI { + public: + /** + * @brief OnSystemTimeReadyNotification create the command. + * @param message content of the command. Passed directy to base class. + */ + OnSystemTimeReadyNotification(const MessageSharedPtr& message, + ApplicationManager& application_manager); + + /** + * @brief ~OnSystemTimeReadyNotification destroys the command object. + */ + ~OnSystemTimeReadyNotification(); + + /** + * @brief Run creates SystemTimeReady event + * and notifies all the subscribers. + */ + void Run() FINAL; +}; + +} // namespace commands +} // namespace application_manager + +#endif // SRC_COMPONENTS_APPLICATION_MANAGER_INCLUDE_APPLICATION_MANAGER_COMMANDS_HMI_ON_SYSTEM_TIME_READY_NOTIFICATION_H_ diff --git a/src/components/application_manager/include/application_manager/commands/mobile/register_app_interface_request.h b/src/components/application_manager/include/application_manager/commands/mobile/register_app_interface_request.h index 5713e2e814..a88789bc73 100644 --- a/src/components/application_manager/include/application_manager/commands/mobile/register_app_interface_request.h +++ b/src/components/application_manager/include/application_manager/commands/mobile/register_app_interface_request.h @@ -210,7 +210,7 @@ class RegisterAppInterfaceRequest : public CommandRequestImpl { private: std::string response_info_; - mobile_apis::Result::eType result_checking_app_hmi_type_; + mobile_apis::Result::eType result_code_; policy::PolicyHandlerInterface& GetPolicyHandler(); DISALLOW_COPY_AND_ASSIGN(RegisterAppInterfaceRequest); diff --git a/src/components/application_manager/include/application_manager/message_helper.h b/src/components/application_manager/include/application_manager/message_helper.h index b94609c01b..4cd18b3c36 100644 --- a/src/components/application_manager/include/application_manager/message_helper.h +++ b/src/components/application_manager/include/application_manager/message_helper.h @@ -107,6 +107,15 @@ class MessageHelper { static void SendDecryptCertificateToHMI(const std::string& file_name, ApplicationManager& app_mngr); + /** + * @brief SendGetSystemTimeRequest sends mentioned request to HMI. + * @param correlation_id the message correlation id, required for proper + * response processing. + * @param app_mngr + */ + static void SendGetSystemTimeRequest(const uint32_t correlation_id, + ApplicationManager& app_mngr); + /* * @brief Retrieve vehicle data map for param name in mobile request * to VehicleDataType @@ -549,6 +558,37 @@ class MessageHelper { int32_t result_code); /** + * @brief Get the full file path of an app file + * + * @param file_name The relative path of an application file + * @param app Current application + * @param app_mngr Application manager + * + * @return The full file path of the application file if valid, + * empty string otherwise + */ + static std::string GetAppFilePath(std::string file_name, + ApplicationConstSharedPtr app, + ApplicationManager& app_mngr); + + /** + * @brief Verify that all ttsChunks with FILE type + * in an array include an existing file and set full path + * + * @param tts_chunks SmartObject with an array of TTSChunks + * @param app Current application + * @param app_mngr Application manager + * + * @return FILE_NOT_FOUND if one of the TTSChunks + * included a file which wasn't present on disk, + * SUCCESS otherwise + */ + static mobile_apis::Result::eType VerifyTtsFiles( + smart_objects::SmartObject& tts_chunks, + ApplicationConstSharedPtr app, + ApplicationManager& app_mngr); + + /** * @brief Verify image and add image file full path * and add path, although the image doesn't exist * @param SmartObject with image diff --git a/src/components/application_manager/include/application_manager/smart_object_keys.h b/src/components/application_manager/include/application_manager/smart_object_keys.h index ce5b68ee3c..50d70591c9 100644 --- a/src/components/application_manager/include/application_manager/smart_object_keys.h +++ b/src/components/application_manager/include/application_manager/smart_object_keys.h @@ -422,7 +422,19 @@ extern const char* kFull; extern const char* kLimited; extern const char* kBackground; extern const char* kNone; -} +} // namespace hmi_levels + +namespace time_keys { +extern const char* millisecond; +extern const char* second; +extern const char* minute; +extern const char* hour; +extern const char* day; +extern const char* month; +extern const char* year; +extern const char* tz_hour; +extern const char* tz_minute; +} // namespace time_keys namespace hmi_request { extern const char* parent_id; @@ -495,7 +507,7 @@ extern const char* num_custom_presets_available; extern const char* urls; extern const char* policy_app_id; extern const char* enabled; - +extern const char* system_time; } // namespace hmi_response namespace hmi_notification { diff --git a/src/components/application_manager/include/application_manager/system_time/system_time_handler_impl.h b/src/components/application_manager/include/application_manager/system_time/system_time_handler_impl.h new file mode 100644 index 0000000000..add440ad80 --- /dev/null +++ b/src/components/application_manager/include/application_manager/system_time/system_time_handler_impl.h @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2018, 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_APPLICATION_MANAGER_INCLUDE_APPLICATION_MANAGER_SYSTEM_TIME_SYSTEM_TIME_HANDLER_IMPL_H_ +#define SRC_COMPONENTS_APPLICATION_MANAGER_INCLUDE_APPLICATION_MANAGER_SYSTEM_TIME_SYSTEM_TIME_HANDLER_IMPL_H_ + +#include <time.h> +#include <vector> + +#include "utils/lock.h" +#include "utils/macro.h" +#include "utils/system_time_handler.h" +#include "application_manager/application_manager_impl.h" +#include "application_manager/event_engine/event_observer.h" + +namespace application_manager { + +/** + * @brief The SystemTimeHandlerImpl class. + * Responsible for the system time notification. It keeps the list + * of system time listeners, sends appropriate request to the system + * and notifies the listeners with new time right after response has appeared. + */ +class SystemTimeHandlerImpl : public utils::SystemTimeHandler, + public event_engine::EventObserver { + public: + /** + * @brief SystemTimeHandlerImpl creates the instance of the class. + */ + explicit SystemTimeHandlerImpl(ApplicationManager& application_manager); + + /** + * @brief ~SystemTimeHandlerImpl + */ + ~SystemTimeHandlerImpl(); + + private: + /** + * @brief on_event allows to process certain events from the system. + * Event which are handles within this methods are: OnSystemTimeReady + * in order to send system time query and GetSystemTimeResponse in order + * to retrieve utc time and notify all the listeners with new time value. + */ + void on_event(const application_manager::event_engine::Event& event) FINAL; + + /** + * @brief DoSystemTimeQuery sends the appropriate request to the system + * and subscribes the class to the response. This is asynchronous request + * thus it won't block until the system respond and returns immediately. + */ + void DoSystemTimeQuery() FINAL; + + /** + * @brief DoSubscribe allows to subscribe certain listener for + * SystemTime. This certain implementation does not maintain + * listeners collection instead it save the pointer to listener. + * @note the class is not reponsible for the pointer's lifecycle. + * So consider to explicitly unsibsscribe from event when listener + * is going to be destroyed. + * @param listener the listener which will be notified + * in case of SystemTime appeared. + */ + void DoSubscribe(utils::SystemTimeListener* listener) FINAL; + + /** + * @brief DoUnsubscribe assigns the pointer to listener to NULL. + * This certain implementation ignores passed parameter. + * @param listener pointer to the object which should be + * unsubscribed from events. + */ + void DoUnsubscribe(utils::SystemTimeListener* listener) FINAL; + + /** + * @brief FetchSystemTime this method allows to obtain + * recently received utc time. + * @note it is up to user to check whether the returned + * argument is valid + * @return the time value returned by system. + */ + time_t FetchSystemTime() FINAL; + + /** + * @brief SendTimeRequest sends the request to the system + * and subscribes for response. + */ + void SendTimeRequest(); + + /** + * @brief ProcessSystemTimeResponse allows to process GetSystemTimeResponse + * @param event contains response parameters aka "systemTime". + */ + void ProcessSystemTimeResponse( + const application_manager::event_engine::Event& event); + + /** + * @brief ProcessSystemTimeReadyNotification allows to process + * OnSystemTimeready notification + * from HMI. It unsubscribes from the mentioned notification and sends + * GetSystemTimeRequest to HMI in order to obtain system time + */ + void ProcessSystemTimeReadyNotification(); + + /** + * @brief Checks if UTC time is ready to provided by HMI + * and can be requested by GetSystemTime request + * @return True if HMI is ready to provide UTC time + * otherwise False + */ + bool utc_time_can_be_received() const FINAL; + + mutable sync_primitives::Lock state_lock_; + // Variable means HMI readiness to provide system time by request + volatile bool utc_time_can_be_received_; + + /** + * @brief Flag used to control that only GetSystemTime request at time could + * be sent to HMI + */ + volatile bool awaiting_get_system_time_; + + // Varible used to store result for GetSystemTime request + time_t last_time_; + + sync_primitives::Lock system_time_listener_lock_; + utils::SystemTimeListener* system_time_listener_; + ApplicationManager& app_manager_; +}; + +} // namespace application_manager + +#endif // SRC_COMPONENTS_APPLICATION_MANAGER_INCLUDE_APPLICATION_MANAGER_SYSTEM_TIME_SYSTEM_TIME_HANDLER_IMPL_H_ diff --git a/src/components/application_manager/src/application_manager_impl.cc b/src/components/application_manager/src/application_manager_impl.cc index df350d13f0..1d7f233b49 100644 --- a/src/components/application_manager/src/application_manager_impl.cc +++ b/src/components/application_manager/src/application_manager_impl.cc @@ -1700,6 +1700,11 @@ bool ApplicationManagerImpl::OnHandshakeDone( return false; } +bool ApplicationManagerImpl::OnHandshakeFailed() { + LOG4CXX_AUTO_TRACE(logger_); + return false; +} + void ApplicationManagerImpl::OnCertificateUpdateRequired() { LOG4CXX_AUTO_TRACE(logger_); GetPolicyHandler().OnPTExchangeNeeded(); diff --git a/src/components/application_manager/src/commands/hmi/basic_communication_get_system_time_request.cc b/src/components/application_manager/src/commands/hmi/basic_communication_get_system_time_request.cc new file mode 100644 index 0000000000..215b0404a7 --- /dev/null +++ b/src/components/application_manager/src/commands/hmi/basic_communication_get_system_time_request.cc @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2018, 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 + * distribut wiion. + * + * 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 "application_manager/commands/hmi/basic_communication_get_system_time_request.h" + +namespace application_manager { + +namespace commands { + +BasicCommunicationGetSystemTimeRequest::BasicCommunicationGetSystemTimeRequest( + const MessageSharedPtr& message, ApplicationManager& application_manager) + : RequestToHMI(message, application_manager) {} + +void BasicCommunicationGetSystemTimeRequest::onTimeOut() { + LOG4CXX_AUTO_TRACE(logger_); + application_manager_.protocol_handler().NotifyOnFailedHandshake(); +} + +} // namespace commands +} // namespace application_manager diff --git a/src/components/application_manager/src/commands/hmi/basic_communication_get_system_time_response.cc b/src/components/application_manager/src/commands/hmi/basic_communication_get_system_time_response.cc new file mode 100644 index 0000000000..26dd115d1a --- /dev/null +++ b/src/components/application_manager/src/commands/hmi/basic_communication_get_system_time_response.cc @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2018, 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 "application_manager/commands/hmi/basic_communication_get_system_time_response.h" +#include "utils/logger.h" + +CREATE_LOGGERPTR_GLOBAL(logger_, "Commands") + +namespace application_manager { +namespace commands { + +BasicCommunicationGetSystemTimeResponse:: + BasicCommunicationGetSystemTimeResponse( + const MessageSharedPtr& message, + ApplicationManager& application_manager) + : ResponseFromHMI(message, application_manager) {} + +void BasicCommunicationGetSystemTimeResponse::Run() { + LOG4CXX_AUTO_TRACE(logger_); + + event_engine::Event event( + hmi_apis::FunctionID::BasicCommunication_GetSystemTime); + event.set_smart_object(*message_); + event.raise(application_manager_.event_dispatcher()); +} + +} // namespace commands +} // namespace application_manager diff --git a/src/components/application_manager/src/commands/hmi/on_system_time_ready_notification.cc b/src/components/application_manager/src/commands/hmi/on_system_time_ready_notification.cc new file mode 100644 index 0000000000..d2376e6dfe --- /dev/null +++ b/src/components/application_manager/src/commands/hmi/on_system_time_ready_notification.cc @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2018, 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 "application_manager/commands/hmi/on_system_time_ready_notification.h" + +#include "application_manager/event_engine/event.h" +#include "interfaces/HMI_API.h" + +namespace application_manager { + +namespace commands { + +OnSystemTimeReadyNotification::OnSystemTimeReadyNotification( + const MessageSharedPtr& message, ApplicationManager& application_manager) + : NotificationFromHMI(message, application_manager) {} + +OnSystemTimeReadyNotification::~OnSystemTimeReadyNotification() {} + +void OnSystemTimeReadyNotification::Run() { + event_engine::Event event( + hmi_apis::FunctionID::BasicCommunication_OnSystemTimeReady); + event.set_smart_object(*message_); + event.raise(application_manager_.event_dispatcher()); +} + +} // namespace commands +} // namespace application_manager diff --git a/src/components/application_manager/src/commands/hmi/request_to_hmi.cc b/src/components/application_manager/src/commands/hmi/request_to_hmi.cc index 6905e7cdef..23c020bca2 100644 --- a/src/components/application_manager/src/commands/hmi/request_to_hmi.cc +++ b/src/components/application_manager/src/commands/hmi/request_to_hmi.cc @@ -74,7 +74,9 @@ bool RequestToHMI::CleanUp() { return true; } -void RequestToHMI::Run() {} +void RequestToHMI::Run() { + SendRequest(); +} void RequestToHMI::SendRequest() { (*message_)[strings::params][strings::protocol_type] = hmi_protocol_type_; diff --git a/src/components/application_manager/src/commands/mobile/alert_maneuver_request.cc b/src/components/application_manager/src/commands/mobile/alert_maneuver_request.cc index d5767690d7..dee364cb99 100644 --- a/src/components/application_manager/src/commands/mobile/alert_maneuver_request.cc +++ b/src/components/application_manager/src/commands/mobile/alert_maneuver_request.cc @@ -92,6 +92,21 @@ void AlertManeuverRequest::Run() { // check TTSChunk parameter if ((*message_)[strings::msg_params].keyExists(strings::tts_chunks)) { + smart_objects::SmartObject& tts_chunks = + (*message_)[strings::msg_params][strings::tts_chunks]; + mobile_apis::Result::eType verification_result = + MessageHelper::VerifyTtsFiles(tts_chunks, app, application_manager_); + + if (mobile_apis::Result::FILE_NOT_FOUND == verification_result) { + LOG4CXX_ERROR(logger_, + "MessageHelper::VerifyTtsFiles return " + << verification_result); + SendResponse(false, + mobile_apis::Result::FILE_NOT_FOUND, + "One or more files needed for tts_chunks are not present"); + return; + } + if (0 < (*message_)[strings::msg_params][strings::tts_chunks].length()) { pending_requests_.Add(hmi_apis::FunctionID::TTS_Speak); tts_is_ok = true; diff --git a/src/components/application_manager/src/commands/mobile/alert_request.cc b/src/components/application_manager/src/commands/mobile/alert_request.cc index 3c42e43767..e0cbe9e600 100644 --- a/src/components/application_manager/src/commands/mobile/alert_request.cc +++ b/src/components/application_manager/src/commands/mobile/alert_request.cc @@ -281,6 +281,23 @@ bool AlertRequest::Validate(uint32_t app_id) { return false; } + if ((*message_)[strings::msg_params].keyExists(strings::tts_chunks)) { + smart_objects::SmartObject& tts_chunks = + (*message_)[strings::msg_params][strings::tts_chunks]; + mobile_apis::Result::eType verification_result = + MessageHelper::VerifyTtsFiles(tts_chunks, app, application_manager_); + + if (mobile_apis::Result::FILE_NOT_FOUND == verification_result) { + LOG4CXX_ERROR(logger_, + "MessageHelper::VerifyTtsFiles return " + << verification_result); + SendResponse(false, + mobile_apis::Result::FILE_NOT_FOUND, + "One or more files needed for tts_chunks are not present"); + return false; + } + } + return true; } diff --git a/src/components/application_manager/src/commands/mobile/change_registration_request.cc b/src/components/application_manager/src/commands/mobile/change_registration_request.cc index f55767c723..06027a42db 100644 --- a/src/components/application_manager/src/commands/mobile/change_registration_request.cc +++ b/src/components/application_manager/src/commands/mobile/change_registration_request.cc @@ -178,6 +178,23 @@ void ChangeRegistrationRequest::Run() { return; } + if ((*message_)[strings::msg_params].keyExists(strings::tts_name)) { + smart_objects::SmartObject& tts_name = + (*message_)[strings::msg_params][strings::tts_name]; + mobile_apis::Result::eType verification_result = + MessageHelper::VerifyTtsFiles(tts_name, app, application_manager_); + + if (mobile_apis::Result::FILE_NOT_FOUND == verification_result) { + LOG4CXX_ERROR(logger_, + "MessageHelper::VerifyTtsFiles return " + << verification_result); + SendResponse(false, + mobile_apis::Result::FILE_NOT_FOUND, + "One or more files needed for tts_name are not present"); + return; + } + } + const HmiInterfaces& hmi_interfaces = application_manager_.hmi_interfaces(); const HmiInterfaces::InterfaceState vr_state = diff --git a/src/components/application_manager/src/commands/mobile/on_hmi_status_notification.cc b/src/components/application_manager/src/commands/mobile/on_hmi_status_notification.cc index 5225002652..a7453686e6 100644 --- a/src/components/application_manager/src/commands/mobile/on_hmi_status_notification.cc +++ b/src/components/application_manager/src/commands/mobile/on_hmi_status_notification.cc @@ -57,6 +57,15 @@ void OnHMIStatusNotification::Run() { return; } + // If the response has no hmi level, return and don't send the notification + if (!(*message_)[strings::msg_params].keyExists(strings::hmi_level)) { + // our notification clearly isn't well-formed + LOG4CXX_ERROR(logger_, "OnHMIStatusNotification has no hmiLevel field"); + return; + } + + // NOTE c++ maps default-construct on the [] operator, so if there is no + // hmiLevel field this will create one that is invalid mobile_apis::HMILevel::eType hmi_level = static_cast<mobile_apis::HMILevel::eType>( (*message_)[strings::msg_params][strings::hmi_level].asInt()); diff --git a/src/components/application_manager/src/commands/mobile/perform_audio_pass_thru_request.cc b/src/components/application_manager/src/commands/mobile/perform_audio_pass_thru_request.cc index 20076ac50c..a758f04aac 100644 --- a/src/components/application_manager/src/commands/mobile/perform_audio_pass_thru_request.cc +++ b/src/components/application_manager/src/commands/mobile/perform_audio_pass_thru_request.cc @@ -96,8 +96,24 @@ void PerformAudioPassThruRequest::Run() { // need set flag before sending to hmi StartAwaitForInterface(HmiInterfaces::HMI_INTERFACE_UI); - if ((*message_)[str::msg_params].keyExists(str::initial_prompt) && - (0 < (*message_)[str::msg_params][str::initial_prompt].length())) { + if ((*message_)[str::msg_params].keyExists(str::initial_prompt)) { + smart_objects::SmartObject& initial_prompt = + (*message_)[strings::msg_params][strings::initial_prompt]; + mobile_apis::Result::eType verification_result = + MessageHelper::VerifyTtsFiles( + initial_prompt, app, application_manager_); + + if (mobile_apis::Result::FILE_NOT_FOUND == verification_result) { + LOG4CXX_ERROR(logger_, + "MessageHelper::VerifyTtsFiles return " + << verification_result); + SendResponse( + false, + mobile_apis::Result::FILE_NOT_FOUND, + "One or more files needed for initial_prompt are not present"); + return; + } + // In case TTS Speak, subscribe on notification SendSpeakRequest(); SendPerformAudioPassThruRequest(); diff --git a/src/components/application_manager/src/commands/mobile/perform_interaction_request.cc b/src/components/application_manager/src/commands/mobile/perform_interaction_request.cc index 68940158b9..86ab0a97c0 100644 --- a/src/components/application_manager/src/commands/mobile/perform_interaction_request.cc +++ b/src/components/application_manager/src/commands/mobile/perform_interaction_request.cc @@ -31,6 +31,7 @@ POSSIBILITY OF SUCH DAMAGE. */ +#include <numeric> #include <string.h> #include <string> #include "application_manager/commands/mobile/perform_interaction_request.h" @@ -536,9 +537,21 @@ void PerformInteractionRequest::SendVRPerformInteractionRequest( } } + std::vector<std::string> invalid_params; if ((*message_)[strings::msg_params].keyExists(strings::help_prompt)) { - msg_params[strings::help_prompt] = + smart_objects::SmartObject& help_prompt = (*message_)[strings::msg_params][strings::help_prompt]; + mobile_apis::Result::eType verification_result = + MessageHelper::VerifyTtsFiles(help_prompt, app, application_manager_); + + if (mobile_apis::Result::FILE_NOT_FOUND == verification_result) { + LOG4CXX_WARN(logger_, + "MessageHelper::VerifyTtsFiles return " + << verification_result); + invalid_params.push_back("help_prompt"); + } else { + msg_params[strings::help_prompt] = help_prompt; + } } else { if (choice_list.length() != 0) { msg_params[strings::help_prompt] = @@ -573,8 +586,20 @@ void PerformInteractionRequest::SendVRPerformInteractionRequest( } if ((*message_)[strings::msg_params].keyExists(strings::timeout_prompt)) { - msg_params[strings::timeout_prompt] = + smart_objects::SmartObject& timeout_prompt = (*message_)[strings::msg_params][strings::timeout_prompt]; + mobile_apis::Result::eType verification_result = + MessageHelper::VerifyTtsFiles( + timeout_prompt, app, application_manager_); + + if (mobile_apis::Result::FILE_NOT_FOUND == verification_result) { + LOG4CXX_WARN(logger_, + "MessageHelper::VerifyTtsFiles return " + << verification_result); + invalid_params.push_back("timeout_prompt"); + } else { + msg_params[strings::timeout_prompt] = timeout_prompt; + } } else { if (msg_params.keyExists(strings::help_prompt)) { msg_params[strings::timeout_prompt] = msg_params[strings::help_prompt]; @@ -582,8 +607,34 @@ void PerformInteractionRequest::SendVRPerformInteractionRequest( } if ((*message_)[strings::msg_params].keyExists(strings::initial_prompt)) { - msg_params[strings::initial_prompt] = + smart_objects::SmartObject& initial_prompt = (*message_)[strings::msg_params][strings::initial_prompt]; + mobile_apis::Result::eType verification_result = + MessageHelper::VerifyTtsFiles( + initial_prompt, app, application_manager_); + + if (mobile_apis::Result::FILE_NOT_FOUND == verification_result) { + LOG4CXX_WARN(logger_, + "MessageHelper::VerifyTtsFiles return " + << verification_result); + invalid_params.push_back("initial_prompt"); + } else { + msg_params[strings::initial_prompt] = initial_prompt; + } + } + + if (!invalid_params.empty()) { + const std::string params_list = + std::accumulate(std::begin(invalid_params), + std::end(invalid_params), + std::string(""), + [](std::string& first, std::string& second) { + return first.empty() ? second : first + ", " + second; + }); + const std::string info = + "One or more files needed for " + params_list + " are not present"; + SendResponse(false, mobile_apis::Result::FILE_NOT_FOUND, info.c_str()); + return; } mobile_apis::InteractionMode::eType mode = diff --git a/src/components/application_manager/src/commands/mobile/register_app_interface_request.cc b/src/components/application_manager/src/commands/mobile/register_app_interface_request.cc index 3a8a2de4ab..ff0d0d3622 100644 --- a/src/components/application_manager/src/commands/mobile/register_app_interface_request.cc +++ b/src/components/application_manager/src/commands/mobile/register_app_interface_request.cc @@ -179,7 +179,7 @@ namespace commands { RegisterAppInterfaceRequest::RegisterAppInterfaceRequest( const MessageSharedPtr& message, ApplicationManager& application_manager) : CommandRequestImpl(message, application_manager) - , result_checking_app_hmi_type_(mobile_apis::Result::INVALID_ENUM) {} + , result_code_(mobile_apis::Result::INVALID_ENUM) {} RegisterAppInterfaceRequest::~RegisterAppInterfaceRequest() {} @@ -320,7 +320,20 @@ void RegisterAppInterfaceRequest::Run() { } if (msg_params.keyExists(strings::tts_name)) { - application->set_tts_name(msg_params[strings::tts_name]); + smart_objects::SmartObject& tts_name = + (*message_)[strings::msg_params][strings::tts_name]; + mobile_apis::Result::eType verification_result = + MessageHelper::VerifyTtsFiles( + tts_name, application, application_manager_); + + if (mobile_apis::Result::FILE_NOT_FOUND == verification_result) { + LOG4CXX_WARN(logger_, + "MessageHelper::VerifyTtsFiles return " + << verification_result); + response_info_ = "One or more files needed for tts_name are not present"; + result_code_ = mobile_apis::Result::WARNINGS; + } + application->set_tts_name(tts_name); } if (msg_params.keyExists(strings::app_hmi_type)) { @@ -713,9 +726,9 @@ void RegisterAppInterfaceRequest::SendRegisterAppInterfaceResponseToMobile( } } if ((mobile_apis::Result::SUCCESS == result_code) && - (mobile_apis::Result::INVALID_ENUM != result_checking_app_hmi_type_)) { + (mobile_apis::Result::INVALID_ENUM != result_code_)) { add_info += response_info_; - result_code = result_checking_app_hmi_type_; + result_code = result_code_; } // in case application exist in resumption we need to send resumeVrgrammars @@ -1066,7 +1079,7 @@ mobile_apis::Result::eType RegisterAppInterfaceRequest::CheckWithPolicyData() { "Following AppHmiTypes are not present in policy " "table:" + log; - result_checking_app_hmi_type_ = mobile_apis::Result::WARNINGS; + result_code_ = mobile_apis::Result::WARNINGS; } } // Replace AppHmiTypes in request with values allowed by policy table diff --git a/src/components/application_manager/src/commands/mobile/set_global_properties_request.cc b/src/components/application_manager/src/commands/mobile/set_global_properties_request.cc index e811f5d154..621aa90447 100644 --- a/src/components/application_manager/src/commands/mobile/set_global_properties_request.cc +++ b/src/components/application_manager/src/commands/mobile/set_global_properties_request.cc @@ -31,6 +31,7 @@ */ #include <string.h> +#include <numeric> #include <algorithm> #include "application_manager/commands/mobile/set_global_properties_request.h" @@ -185,14 +186,54 @@ void SetGlobalPropertiesRequest::Run() { smart_objects::SmartObject params = smart_objects::SmartObject(smart_objects::SmartType_Map); + std::vector<std::string> invalid_params; if (is_help_prompt_present) { - app->set_help_prompt(msg_params.getElement(strings::help_prompt)); - params[strings::help_prompt] = (*app->help_prompt()); + smart_objects::SmartObject& help_prompt = + (*message_)[strings::msg_params][strings::help_prompt]; + mobile_apis::Result::eType verification_result = + MessageHelper::VerifyTtsFiles(help_prompt, app, application_manager_); + + if (mobile_apis::Result::FILE_NOT_FOUND == verification_result) { + LOG4CXX_ERROR(logger_, + "MessageHelper::VerifyTtsFiles return " + << verification_result); + invalid_params.push_back("help_prompt"); + } else { + app->set_help_prompt(help_prompt); + params[strings::help_prompt] = (*app->help_prompt()); + } } if (is_timeout_prompt_present) { - app->set_timeout_prompt(msg_params.getElement(strings::timeout_prompt)); - params[strings::timeout_prompt] = (*app->timeout_prompt()); + smart_objects::SmartObject& timeout_prompt = + (*message_)[strings::msg_params][strings::timeout_prompt]; + mobile_apis::Result::eType verification_result = + MessageHelper::VerifyTtsFiles( + timeout_prompt, app, application_manager_); + + if (mobile_apis::Result::FILE_NOT_FOUND == verification_result) { + LOG4CXX_ERROR(logger_, + "MessageHelper::VerifyTtsFiles return " + << verification_result); + invalid_params.push_back("timeout_prompt"); + } else { + app->set_timeout_prompt(timeout_prompt); + params[strings::timeout_prompt] = (*app->timeout_prompt()); + } + } + + if (!invalid_params.empty()) { + std::string params_list = std::accumulate( + std::begin(invalid_params), + std::end(invalid_params), + std::string(""), + [](std::string& first, std::string& second) { + return first.empty() ? second : first + ", " + second; + }); + const std::string info = + "One or more files needed for " + params_list + " are not present"; + SendResponse(false, mobile_apis::Result::FILE_NOT_FOUND, info.c_str()); + return; } params[strings::app_id] = app->app_id(); diff --git a/src/components/application_manager/src/commands/mobile/speak_request.cc b/src/components/application_manager/src/commands/mobile/speak_request.cc index 1954cde181..6da6b482b3 100644 --- a/src/components/application_manager/src/commands/mobile/speak_request.cc +++ b/src/components/application_manager/src/commands/mobile/speak_request.cc @@ -69,6 +69,21 @@ void SpeakRequest::Run() { return; } + smart_objects::SmartObject& tts_chunks = + (*message_)[strings::msg_params][strings::tts_chunks]; + mobile_apis::Result::eType verification_result = + MessageHelper::VerifyTtsFiles(tts_chunks, app, application_manager_); + + if (mobile_apis::Result::FILE_NOT_FOUND == verification_result) { + LOG4CXX_ERROR(logger_, + "MessageHelper::VerifyTtsFiles return " + << verification_result); + SendResponse(false, + mobile_apis::Result::FILE_NOT_FOUND, + "One or more files needed for tts_chunks are not present"); + return; + } + (*message_)[strings::msg_params][strings::app_id] = app->app_id(); (*message_)[strings::msg_params][hmi_request::speak_type] = hmi_apis::Common_MethodName::SPEAK; diff --git a/src/components/application_manager/src/hmi_capabilities_impl.cc b/src/components/application_manager/src/hmi_capabilities_impl.cc index f64b80a088..d00fc2ae19 100644 --- a/src/components/application_manager/src/hmi_capabilities_impl.cc +++ b/src/components/application_manager/src/hmi_capabilities_impl.cc @@ -93,6 +93,8 @@ void InitCapabilities() { hmi_apis::Common_SpeechCapabilities::PRE_RECORDED)); tts_enum_capabilities.insert(std::make_pair( std::string("SILENCE"), hmi_apis::Common_SpeechCapabilities::SILENCE)); + tts_enum_capabilities.insert(std::make_pair( + std::string("FILE"), hmi_apis::Common_SpeechCapabilities::FILE)); button_enum_name.insert( std::make_pair(std::string("OK"), hmi_apis::Common_ButtonName::OK)); diff --git a/src/components/application_manager/src/hmi_command_factory.cc b/src/components/application_manager/src/hmi_command_factory.cc index a7f3ce7e6b..5ef8605999 100644 --- a/src/components/application_manager/src/hmi_command_factory.cc +++ b/src/components/application_manager/src/hmi_command_factory.cc @@ -224,6 +224,7 @@ #include "application_manager/commands/hmi/navi_get_way_points_request.h" #include "application_manager/commands/hmi/navi_get_way_points_response.h" #include "application_manager/commands/hmi/on_ready_notification.h" +#include "application_manager/commands/hmi/on_system_time_ready_notification.h" #include "application_manager/commands/hmi/on_device_chosen_notification.h" #include "application_manager/commands/hmi/on_file_removed_notification.h" #include "application_manager/commands/hmi/on_system_context_notification.h" @@ -269,6 +270,8 @@ #include "application_manager/commands/hmi/on_system_error_notification.h" #include "application_manager/commands/hmi/basic_communication_system_request.h" #include "application_manager/commands/hmi/basic_communication_system_response.h" +#include "application_manager/commands/hmi/basic_communication_get_system_time_request.h" +#include "application_manager/commands/hmi/basic_communication_get_system_time_response.h" #include "application_manager/commands/hmi/basic_communication_on_awake_sdl.h" #include "application_manager/commands/hmi/sdl_policy_update.h" #include "application_manager/commands/hmi/sdl_policy_update_response.h" @@ -1285,6 +1288,11 @@ CommandSharedPtr HMICommandFactory::CreateCommand( new commands::OnReadyNotification(message, application_manager)); break; } + case hmi_apis::FunctionID::BasicCommunication_OnSystemTimeReady: { + command.reset(new commands::OnSystemTimeReadyNotification( + message, application_manager)); + break; + } case hmi_apis::FunctionID::BasicCommunication_OnDeviceChosen: { command.reset(new commands::OnDeviceChosenNotification( message, application_manager)); @@ -2221,6 +2229,16 @@ CommandSharedPtr HMICommandFactory::CreateCommand( } break; } + case hmi_apis::FunctionID::BasicCommunication_GetSystemTime: { + if (is_response) { + command.reset(new commands::BasicCommunicationGetSystemTimeResponse( + message, application_manager)); + } else { + command.reset(new commands::BasicCommunicationGetSystemTimeRequest( + message, application_manager)); + } + break; + } case hmi_apis::FunctionID::Navigation_SendLocation: { if (is_response) { command.reset(new commands::NaviSendLocationResponse( diff --git a/src/components/application_manager/src/message_helper/message_helper.cc b/src/components/application_manager/src/message_helper/message_helper.cc index d3af65effa..b854d83c6e 100644 --- a/src/components/application_manager/src/message_helper/message_helper.cc +++ b/src/components/application_manager/src/message_helper/message_helper.cc @@ -368,6 +368,20 @@ void MessageHelper::SendDecryptCertificateToHMI(const std::string& file_name, app_mngr.ManageHMICommand(message); } +void MessageHelper::SendGetSystemTimeRequest(const uint32_t correlation_id, + ApplicationManager& app_mngr) { + using namespace smart_objects; + SmartObjectSPtr message = + CreateMessageForHMI(hmi_apis::messageType::request, correlation_id); + + DCHECK(message); + + (*message)[strings::params][strings::function_id] = + hmi_apis::FunctionID::BasicCommunication_GetSystemTime; + + app_mngr.ManageHMICommand(message); +} + void MessageHelper::SendHashUpdateNotification(const uint32_t app_id, ApplicationManager& app_mngr) { LOG4CXX_AUTO_TRACE(logger_); @@ -2756,11 +2770,23 @@ mobile_apis::Result::eType MessageHelper::VerifyImageApplyPath( } const std::string& file_name = image[strings::value].asString(); + const std::string& full_file_path = GetAppFilePath(file_name, app, app_mngr); + + image[strings::value] = full_file_path; + if (file_system::FileExists(full_file_path)) { + return mobile_apis::Result::SUCCESS; + } + return mobile_apis::Result::INVALID_DATA; +} +std::string MessageHelper::GetAppFilePath(std::string file_name, + ApplicationConstSharedPtr app, + ApplicationManager& app_mngr) { std::string str = file_name; + // Verify that file name is not only space characters str.erase(remove(str.begin(), str.end(), ' '), str.end()); if (0 == str.size()) { - return mobile_apis::Result::INVALID_DATA; + return ""; } std::string full_file_path; @@ -2786,12 +2812,25 @@ mobile_apis::Result::eType MessageHelper::VerifyImageApplyPath( full_file_path += file_name; } - image[strings::value] = full_file_path; - if (!file_system::FileExists(full_file_path)) { - return mobile_apis::Result::INVALID_DATA; - } + return full_file_path; +} - return mobile_apis::Result::SUCCESS; +mobile_apis::Result::eType MessageHelper::VerifyTtsFiles( + smart_objects::SmartObject& tts_chunks, + ApplicationConstSharedPtr app, + ApplicationManager& app_mngr) { + mobile_apis::Result::eType result = mobile_apis::Result::SUCCESS; + for (auto& tts_chunk : *(tts_chunks.asArray())) { + if (tts_chunk[strings::type] == mobile_apis::SpeechCapabilities::FILE) { + const std::string full_file_path = + GetAppFilePath(tts_chunk[strings::text].asString(), app, app_mngr); + tts_chunk[strings::text] = full_file_path; + if (!file_system::FileExists(full_file_path)) { + result = mobile_apis::Result::FILE_NOT_FOUND; + } + } + } + return result; } mobile_apis::Result::eType MessageHelper::VerifyImage( @@ -3035,4 +3074,4 @@ bool MessageHelper::PrintSmartObject(const smart_objects::SmartObject& object) { return true; } -} // namespace application_manager +} // namespace application_manager
\ No newline at end of file diff --git a/src/components/application_manager/src/policies/policy_handler.cc b/src/components/application_manager/src/policies/policy_handler.cc index b0f52ba227..7cfb2c7ff2 100644 --- a/src/components/application_manager/src/policies/policy_handler.cc +++ b/src/components/application_manager/src/policies/policy_handler.cc @@ -1250,12 +1250,15 @@ void PolicyHandler::OnAllowSDLFunctionalityNotification( if (is_allowed) { // Send HMI status notification to mobile // Put application in full - AudioStreamingState::eType state = app->is_audio() - ? AudioStreamingState::AUDIBLE - : AudioStreamingState::NOT_AUDIBLE; + AudioStreamingState::eType audio_state = + app->IsAudioApplication() ? AudioStreamingState::AUDIBLE + : AudioStreamingState::NOT_AUDIBLE; + VideoStreamingState::eType video_state = + app->IsVideoApplication() ? VideoStreamingState::STREAMABLE + : VideoStreamingState::NOT_STREAMABLE; application_manager_.state_controller().SetRegularState( - app, mobile_apis::HMILevel::HMI_FULL, state, true); + app, mobile_apis::HMILevel::HMI_FULL, audio_state, video_state, true); last_activated_app_id_ = 0; } else { DeactivateApplication deactivate_notification( diff --git a/src/components/application_manager/src/smart_object_keys.cc b/src/components/application_manager/src/smart_object_keys.cc index a55696524c..e4e89c6e1f 100644 --- a/src/components/application_manager/src/smart_object_keys.cc +++ b/src/components/application_manager/src/smart_object_keys.cc @@ -367,7 +367,7 @@ const char* instance_follow_redirect = "InstanceFollowRedirect"; const char* charset = "charset"; const char* content_lenght = "Content_Lenght"; const char* GET = "GET"; -} // http_request +} // namespace http_request namespace mobile_notification { const char* state = "state"; @@ -380,7 +380,17 @@ const char* kFull = "FULL"; const char* kLimited = "LIMITED"; const char* kBackground = "BACKGROUND"; const char* kNone = "NONE"; -} +} // namespace hmi_levels + +namespace time_keys { +const char* millisecond = "millisecond"; +const char* second = "second"; +const char* minute = "minute"; +const char* hour = "hour"; +const char* day = "day"; +const char* month = "month"; +const char* year = "year"; +} // namespace time_keys namespace hmi_request { const char* parent_id = "parentID"; @@ -453,7 +463,7 @@ const char* num_custom_presets_available = "numCustomPresetsAvailable"; const char* urls = "urls"; const char* policy_app_id = "policyAppID"; const char* enabled = "enabled"; - +const char* system_time = "systemTime"; } // namespace hmi_response namespace hmi_notification { @@ -468,7 +478,6 @@ const char* policyfile = "policyfile"; const char* is_active = "isActive"; const char* is_deactivated = "isDeactivated"; const char* event_name = "eventName"; - } // namespace hmi_notification } // namespace application_manager diff --git a/src/components/application_manager/src/system_time/system_time_handler_impl.cc b/src/components/application_manager/src/system_time/system_time_handler_impl.cc new file mode 100644 index 0000000000..6ae6d3e901 --- /dev/null +++ b/src/components/application_manager/src/system_time/system_time_handler_impl.cc @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2018, 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 "application_manager/system_time/system_time_handler_impl.h" + +#include <algorithm> + +#include "application_manager/message_helper.h" +#include "application_manager/smart_object_keys.h" +#include "interfaces/HMI_API.h" +#include "utils/logger.h" + +namespace application_manager { + +SystemTimeHandlerImpl::SystemTimeHandlerImpl( + ApplicationManager& application_manager) + : event_engine::EventObserver(application_manager.event_dispatcher()) + , utc_time_can_be_received_(false) + , awaiting_get_system_time_(false) + , system_time_listener_(NULL) + , app_manager_(application_manager) { + LOG4CXX_AUTO_TRACE(logger_); + subscribe_on_event( + hmi_apis::FunctionID::BasicCommunication_OnSystemTimeReady); +} + +SystemTimeHandlerImpl::~SystemTimeHandlerImpl() { + LOG4CXX_AUTO_TRACE(logger_); + unsubscribe_from_all_events(); +} + +void SystemTimeHandlerImpl::DoSystemTimeQuery() { + LOG4CXX_AUTO_TRACE(logger_); + using namespace application_manager; + + sync_primitives::AutoLock lock(state_lock_); + if (!utc_time_can_be_received_) { + LOG4CXX_INFO(logger_, + "Navi module is not yet ready." + << "Will process request once it became ready."); + return; + } + SendTimeRequest(); +} + +void SystemTimeHandlerImpl::DoSubscribe(utils::SystemTimeListener* listener) { + LOG4CXX_AUTO_TRACE(logger_); + DCHECK(listener); + sync_primitives::AutoLock lock(system_time_listener_lock_); + system_time_listener_ = listener; +} + +void SystemTimeHandlerImpl::DoUnsubscribe(utils::SystemTimeListener* listener) { + LOG4CXX_AUTO_TRACE(logger_); + sync_primitives::AutoLock lock(system_time_listener_lock_); + system_time_listener_ = NULL; +} + +time_t SystemTimeHandlerImpl::FetchSystemTime() { + LOG4CXX_AUTO_TRACE(logger_); + return last_time_; +} + +bool SystemTimeHandlerImpl::utc_time_can_be_received() const { + LOG4CXX_AUTO_TRACE(logger_); + sync_primitives::AutoLock lock(state_lock_); + return utc_time_can_be_received_; +} + +void SystemTimeHandlerImpl::SendTimeRequest() { + LOG4CXX_AUTO_TRACE(logger_); + + if (awaiting_get_system_time_) { + LOG4CXX_WARN(logger_, "Another GetSystemTime request in progress. Skipped"); + return; + } + + using namespace application_manager; + uint32_t correlation_id = app_manager_.GetNextHMICorrelationID(); + subscribe_on_event(hmi_apis::FunctionID::BasicCommunication_GetSystemTime, + correlation_id); + MessageHelper::SendGetSystemTimeRequest(correlation_id, app_manager_); + awaiting_get_system_time_ = true; +} + +void SystemTimeHandlerImpl::on_event( + const application_manager::event_engine::Event& event) { + LOG4CXX_AUTO_TRACE(logger_); + using namespace application_manager; + using namespace hmi_apis::FunctionID; + switch (event.id()) { + case BasicCommunication_OnSystemTimeReady: + ProcessSystemTimeReadyNotification(); + break; + case BasicCommunication_GetSystemTime: + ProcessSystemTimeResponse(event); + break; + default: + LOG4CXX_ERROR(logger_, "Unknown Event received"); + break; + } +} + +void SystemTimeHandlerImpl::ProcessSystemTimeReadyNotification() { + LOG4CXX_AUTO_TRACE(logger_); + sync_primitives::AutoLock lock(state_lock_); + utc_time_can_be_received_ = true; + unsubscribe_from_event( + hmi_apis::FunctionID::BasicCommunication_OnSystemTimeReady); +} + +void SystemTimeHandlerImpl::ProcessSystemTimeResponse( + const application_manager::event_engine::Event& event) { + LOG4CXX_AUTO_TRACE(logger_); + const smart_objects::SmartObject& message = event.smart_object(); + const smart_objects::SmartObject& system_time_so = + message[strings::msg_params][hmi_response::system_time]; + + struct tm system_time; + memset(&system_time, 0, sizeof(struct tm)); + + system_time.tm_sec = system_time_so[time_keys::second].asInt(); + system_time.tm_min = system_time_so[time_keys::minute].asInt(); + // According to tm specification of tm type hour should be decreased by 1 + system_time.tm_hour = system_time_so[time_keys::hour].asInt() - 1; + system_time.tm_mday = system_time_so[time_keys::day].asInt(); + // According to tm specification of tm type mon should be decreased by 1 + system_time.tm_mon = system_time_so[time_keys::month].asInt() - 1; + // According to tm specification of tm type + // tm_year - number of years since 1900 + system_time.tm_year = system_time_so[time_keys::year].asInt() - 1900; + + // Normalize and convert time from 'tm' format to 'time_t' + last_time_ = mktime(&system_time); + + sync_primitives::AutoLock lock(system_time_listener_lock_); + if (system_time_listener_) { + system_time_listener_->OnSystemTimeArrived(last_time_); + } + sync_primitives::AutoLock state_lock(state_lock_); + awaiting_get_system_time_ = false; +} + +} // namespace application_manager diff --git a/src/components/application_manager/test/commands/hmi/activate_app_request_test.cc b/src/components/application_manager/test/commands/hmi/activate_app_request_test.cc index 7f7911a01d..ff309d444a 100644 --- a/src/components/application_manager/test/commands/hmi/activate_app_request_test.cc +++ b/src/components/application_manager/test/commands/hmi/activate_app_request_test.cc @@ -105,8 +105,7 @@ TEST_F(ActivateAppRequestTest, Run_SUCCESS) { EXPECT_CALL(app_mngr_, SendMessageToHMI(CheckMessage(mobile_apis::HMILevel::HMI_FULL))); #else - EXPECT_CALL(app_mngr_, - SendMessageToHMI(msg))); + EXPECT_CALL(app_mngr_, SendMessageToHMI(msg)); #endif command->Run(); diff --git a/src/components/application_manager/test/commands/hmi/basic_communication_get_system_time_request_test.cc b/src/components/application_manager/test/commands/hmi/basic_communication_get_system_time_request_test.cc new file mode 100644 index 0000000000..e6a6bf0365 --- /dev/null +++ b/src/components/application_manager/test/commands/hmi/basic_communication_get_system_time_request_test.cc @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2018 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 names of the copyright holders 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 "application_manager/commands/hmi/basic_communication_get_system_time_request.h" + +#include "gtest/gtest.h" +#include "utils/shared_ptr.h" +#include "application_manager/commands/command_request_test.h" +#include "protocol_handler/mock_protocol_handler.h" + +namespace test { +namespace components { +namespace commands_test { +namespace hmi_commands_test { +namespace basic_communication_get_system_time_request { + +using ::testing::ReturnRef; +namespace am = ::application_manager; +using am::commands::MessageSharedPtr; +using am::commands::BasicCommunicationGetSystemTimeRequest; +using namespace ::protocol_handler; + +class BasicCommunicationGetSystemTimeRequestTest + : public CommandRequestTest<CommandsTestMocks::kIsNice> {}; + +TEST_F(BasicCommunicationGetSystemTimeRequestTest, OnTimeout) { + MessageSharedPtr msg = CreateMessage(); + protocol_handler_test::MockProtocolHandler mock_protocol_handler; + + auto command = CreateCommand<BasicCommunicationGetSystemTimeRequest>(msg); + + ON_CALL(app_mngr_, protocol_handler()) + .WillByDefault(ReturnRef(mock_protocol_handler)); + EXPECT_CALL(mock_protocol_handler, NotifyOnFailedHandshake()); + + command->onTimeOut(); +} + +} // namespace basic_communication_get_system_time_request +} // namespace hmi_commands_test +} // namespace commands_test +} // namespace components +} // namespace test diff --git a/src/components/application_manager/test/commands/hmi/basic_communication_get_system_time_response_test.cc b/src/components/application_manager/test/commands/hmi/basic_communication_get_system_time_response_test.cc new file mode 100644 index 0000000000..e4d4572bc1 --- /dev/null +++ b/src/components/application_manager/test/commands/hmi/basic_communication_get_system_time_response_test.cc @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2018 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 names of the copyright holders 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 "application_manager/commands/commands_test.h" +#include "application_manager/commands/hmi/basic_communication_get_system_time_response.h" +#include "application_manager/mock_application_manager.h" +#include "application_manager/mock_event_dispatcher.h" +#include "application_manager/smart_object_keys.h" +#include "interfaces/HMI_API.h" + +namespace test { +namespace components { +namespace commands_test { +namespace hmi_commands_test { +namespace basic_communication_get_system_time_response { + +using application_manager::commands::BasicCommunicationGetSystemTimeResponse; +using test::components::event_engine_test::MockEventDispatcher; +using testing::ReturnRef; + +ACTION_P(GetEventId, event_id) { + *event_id = arg0.id(); +} + +class BasicCommunicationGetSystemTimeResponseTest + : public CommandsTest<CommandsTestMocks::kIsNice> {}; + +TEST_F(BasicCommunicationGetSystemTimeResponseTest, Run_SUCCESS) { + MessageSharedPtr msg = CreateMessage(); + MockEventDispatcher mock_event_dispatcher; + int32_t event_id = hmi_apis::FunctionID::INVALID_ENUM; + + auto command(CreateCommand<BasicCommunicationGetSystemTimeResponse>(msg)); + + EXPECT_CALL(app_mngr_, event_dispatcher()) + .WillOnce(ReturnRef(mock_event_dispatcher)); + EXPECT_CALL(mock_event_dispatcher, raise_event(_)) + .WillOnce(GetEventId(&event_id)); + + command->Run(); + + EXPECT_EQ(hmi_apis::FunctionID::BasicCommunication_GetSystemTime, event_id); +} + +} // namespace basic_communication_get_system_time_response +} // namespace hmi_commands_test +} // namespace commands_test +} // namespace components +} // namespace test diff --git a/src/components/application_manager/test/commands/hmi/on_system_time_ready_notification_test.cc b/src/components/application_manager/test/commands/hmi/on_system_time_ready_notification_test.cc new file mode 100644 index 0000000000..35750496c8 --- /dev/null +++ b/src/components/application_manager/test/commands/hmi/on_system_time_ready_notification_test.cc @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2018 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 names of the copyright holders 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 "application_manager/commands/commands_test.h" +#include "application_manager/commands/hmi/on_system_time_ready_notification.h" +#include "application_manager/mock_application_manager.h" +#include "application_manager/mock_event_dispatcher.h" +#include "application_manager/smart_object_keys.h" +#include "interfaces/HMI_API.h" + +namespace test { +namespace components { +namespace commands_test { +namespace hmi_commands_test { +namespace on_system_time_ready_notification { + +using application_manager::commands::OnSystemTimeReadyNotification; +using test::components::event_engine_test::MockEventDispatcher; +using testing::ReturnRef; + +class OnSystemTimeReadyNotificationTest + : public CommandsTest<CommandsTestMocks::kIsNice> {}; + +ACTION_P(GetEventId, event_id) { + *event_id = arg0.id(); +} + +TEST_F(OnSystemTimeReadyNotificationTest, Run_SUCCESS) { + int32_t event_id = hmi_apis::FunctionID::INVALID_ENUM; + MessageSharedPtr msg = CreateMessage(); + MockEventDispatcher mock_event_dispatcher; + + auto command(CreateCommand<OnSystemTimeReadyNotification>(msg)); + + EXPECT_CALL(app_mngr_, event_dispatcher()) + .WillOnce(ReturnRef(mock_event_dispatcher)); + EXPECT_CALL(mock_event_dispatcher, raise_event(_)) + .WillOnce(GetEventId(&event_id)); + + command->Run(); + + EXPECT_EQ(hmi_apis::FunctionID::BasicCommunication_OnSystemTimeReady, + event_id); +} + +} // namespace on_system_time_ready_notification +} // namespace hmi_commands_test +} // namespace commands_test +} // namespace components +} // namespace test diff --git a/src/components/application_manager/test/commands/mobile/alert_request_test.cc b/src/components/application_manager/test/commands/mobile/alert_request_test.cc index 5d9e507511..f4ad62f29a 100644 --- a/src/components/application_manager/test/commands/mobile/alert_request_test.cc +++ b/src/components/application_manager/test/commands/mobile/alert_request_test.cc @@ -382,6 +382,12 @@ TEST_F(AlertRequestTest, Run_SUCCESS) { SubscribeApplicationToSoftButton( (*msg_)[am::strings::msg_params], _, kFunctionId)); + EXPECT_CALL( + mock_message_helper_, + VerifyTtsFiles( + (*msg_)[am::strings::msg_params][am::strings::tts_chunks], _, _)) + .WillOnce(Return(mobile_apis::Result::SUCCESS)); + ExpectManageHmiCommandTTSAndUI(); CommandPtr command(CreateCommand<AlertRequest>(msg_)); command->Run(); @@ -435,6 +441,11 @@ TEST_F(AlertRequestTest, OnEvent_UIAlertHasHmiResponsesToWait_UNSUCCESS) { EXPECT_CALL(mock_message_helper_, ProcessSoftButtons((*msg_)[am::strings::msg_params], _, _, _)) .WillOnce(Return(mobile_apis::Result::SUCCESS)); + EXPECT_CALL( + mock_message_helper_, + VerifyTtsFiles( + (*msg_)[am::strings::msg_params][am::strings::tts_chunks], _, _)) + .WillOnce(Return(mobile_apis::Result::SUCCESS)); ExpectManageHmiCommandTTSAndUI(); @@ -465,6 +476,12 @@ TEST_F(AlertRequestTest, DISABLED_OnEvent_TTSWarnings_SUCCESS) { .WillOnce(Return(mobile_apis::Result::SUCCESS)); EXPECT_CALL( + mock_message_helper_, + VerifyTtsFiles( + (*msg_)[am::strings::msg_params][am::strings::tts_chunks], _, _)) + .WillOnce(Return(mobile_apis::Result::SUCCESS)); + + EXPECT_CALL( app_mngr_, ManageHMICommand(HMIResultCodeIs(hmi_apis::FunctionID::TTS_Speak))) .WillOnce(Return(true)); @@ -492,6 +509,11 @@ TEST_F(AlertRequestTest, DISABLED_OnEvent_TTSUnsupportedResource_SUCCESS) { ProcessSoftButtons((*msg_)[am::strings::msg_params], _, _, _)) .WillOnce(Return(mobile_apis::Result::SUCCESS)); EXPECT_CALL( + mock_message_helper_, + VerifyTtsFiles( + (*msg_)[am::strings::msg_params][am::strings::tts_chunks], _, _)) + .WillOnce(Return(mobile_apis::Result::SUCCESS)); + EXPECT_CALL( app_mngr_, ManageHMICommand(HMIResultCodeIs(hmi_apis::FunctionID::TTS_Speak))) .WillOnce(Return(true)); @@ -524,6 +546,11 @@ TEST_F(AlertRequestTest, EXPECT_CALL(mock_message_helper_, ProcessSoftButtons((*msg_)[am::strings::msg_params], _, _, _)) .WillOnce(Return(mobile_apis::Result::SUCCESS)); + EXPECT_CALL( + mock_message_helper_, + VerifyTtsFiles( + (*msg_)[am::strings::msg_params][am::strings::tts_chunks], _, _)) + .WillOnce(Return(mobile_apis::Result::SUCCESS)); EXPECT_CALL(mock_message_helper_, SubscribeApplicationToSoftButton( (*msg_)[am::strings::msg_params], _, kFunctionId)); @@ -566,6 +593,11 @@ TEST_F(AlertRequestTest, OnEvent_TTSUnsupportedResourceUiAlertSuccess_SUCCESS) { EXPECT_CALL(mock_message_helper_, ProcessSoftButtons((*msg_)[am::strings::msg_params], _, _, _)) .WillOnce(Return(mobile_apis::Result::SUCCESS)); + EXPECT_CALL( + mock_message_helper_, + VerifyTtsFiles( + (*msg_)[am::strings::msg_params][am::strings::tts_chunks], _, _)) + .WillOnce(Return(mobile_apis::Result::SUCCESS)); EXPECT_CALL(mock_message_helper_, SubscribeApplicationToSoftButton( (*msg_)[am::strings::msg_params], _, kFunctionId)); @@ -611,6 +643,11 @@ TEST_F(AlertRequestTest, OnEvent_TTSSuccesUiAlertInvalidEnum_SUCCESS) { ProcessSoftButtons((*msg_)[am::strings::msg_params], _, _, _)) .WillOnce(Return(mobile_apis::Result::SUCCESS)); EXPECT_CALL( + mock_message_helper_, + VerifyTtsFiles( + (*msg_)[am::strings::msg_params][am::strings::tts_chunks], _, _)) + .WillOnce(Return(mobile_apis::Result::SUCCESS)); + EXPECT_CALL( app_mngr_, ManageHMICommand(HMIResultCodeIs(hmi_apis::FunctionID::TTS_Speak))) .WillOnce(Return(true)); @@ -656,6 +693,11 @@ TEST_F(AlertRequestTest, DISABLED_OnEvent_TTSAbortedUiAlertNotSent_SUCCESS) { ProcessSoftButtons((*msg_)[am::strings::msg_params], _, _, _)) .WillOnce(Return(mobile_apis::Result::SUCCESS)); EXPECT_CALL( + mock_message_helper_, + VerifyTtsFiles( + (*msg_)[am::strings::msg_params][am::strings::tts_chunks], _, _)) + .WillOnce(Return(mobile_apis::Result::SUCCESS)); + EXPECT_CALL( app_mngr_, ManageHMICommand(HMIResultCodeIs(hmi_apis::FunctionID::TTS_Speak))) .WillOnce(Return(true)); diff --git a/src/components/application_manager/test/commands/mobile/perform_audio_pass_thru_test.cc b/src/components/application_manager/test/commands/mobile/perform_audio_pass_thru_test.cc index a27bac970c..ad15dca7eb 100644 --- a/src/components/application_manager/test/commands/mobile/perform_audio_pass_thru_test.cc +++ b/src/components/application_manager/test/commands/mobile/perform_audio_pass_thru_test.cc @@ -247,6 +247,12 @@ TEST_F(PerformAudioPassThruRequestTest, ManageMobileCommand(_, am::commands::Command::CommandOrigin::ORIGIN_SDL)) .WillOnce(DoAll(SaveArg<0>(&response_to_mobile), Return(true))); + EXPECT_CALL(mock_message_helper_, + VerifyTtsFiles((*mobile_request)[am::strings::msg_params] + [am::strings::initial_prompt], + _, + _)).WillOnce(Return(mobile_apis::Result::SUCCESS)); + command->Run(); command->on_event(event_tts); command->on_event(event_ui); @@ -320,6 +326,10 @@ TEST_F(PerformAudioPassThruRequestTest, kCorrectPrompt; msg_params_[am::strings::initial_prompt][0][am::strings::type] = kCorrectType; + EXPECT_CALL(mock_message_helper_, + VerifyTtsFiles(msg_params_[am::strings::initial_prompt], _, _)) + .WillOnce(Return(mobile_apis::Result::SUCCESS)); + MessageSharedPtr speak_reqeust_result_msg; MessageSharedPtr perform_result_msg; { @@ -405,6 +415,10 @@ TEST_F(PerformAudioPassThruRequestTest, msg_params_[am::strings::audio_pass_display_text1] = kCorrectDisplayText1; msg_params_[am::strings::audio_pass_display_text2] = kCorrectDisplayText2; + EXPECT_CALL(mock_message_helper_, + VerifyTtsFiles(msg_params_[am::strings::initial_prompt], _, _)) + .WillOnce(Return(mobile_apis::Result::SUCCESS)); + MessageSharedPtr speak_reqeust_result_msg; MessageSharedPtr perform_result_msg; { @@ -469,6 +483,10 @@ TEST_F(PerformAudioPassThruRequestTest, kCorrectPrompt; msg_params_[am::strings::initial_prompt][0][am::strings::type] = kCorrectType; + EXPECT_CALL(mock_message_helper_, + VerifyTtsFiles(msg_params_[am::strings::initial_prompt], _, _)) + .WillOnce(Return(mobile_apis::Result::SUCCESS)); + const bool muted = false; msg_params_[am::strings::mute_audio] = muted; @@ -743,6 +761,11 @@ TEST_F(PerformAudioPassThruRequestTest, msg_params_[am::strings::initial_prompt][0][am::strings::text] = kCorrectPrompt; msg_params_[am::strings::initial_prompt][0][am::strings::type] = kCorrectType; + + EXPECT_CALL(mock_message_helper_, + VerifyTtsFiles(msg_params_[am::strings::initial_prompt], _, _)) + .WillOnce(Return(mobile_apis::Result::SUCCESS)); + MessageSharedPtr speak_reqeust_result_msg; MessageSharedPtr perform_result_msg; ON_CALL(app_mngr_, GetNextHMICorrelationID()) diff --git a/src/components/application_manager/test/commands/mobile/set_global_properties_test.cc b/src/components/application_manager/test/commands/mobile/set_global_properties_test.cc index 641e5636a9..9ed459f799 100644 --- a/src/components/application_manager/test/commands/mobile/set_global_properties_test.cc +++ b/src/components/application_manager/test/commands/mobile/set_global_properties_test.cc @@ -154,6 +154,10 @@ class SetGlobalPropertiesRequestTest EXPECT_CALL(app_mngr_, application(kConnectionKey)) .WillOnce(Return(mock_app_)); EXPECT_CALL(mock_message_helper_, VerifyImageVrHelpItems(_, _, _)).Times(0); + EXPECT_CALL(mock_message_helper_, VerifyTtsFiles(help_prompt, _, _)) + .WillOnce(Return(mobile_apis::Result::SUCCESS)); + EXPECT_CALL(mock_message_helper_, VerifyTtsFiles(timeout_prompt, _, _)) + .WillOnce(Return(mobile_apis::Result::SUCCESS)); EXPECT_CALL(app_mngr_, RemoveAppFromTTSGlobalPropertiesList(kConnectionKey)); SmartObject vr_help_title("title"); @@ -288,6 +292,12 @@ TEST_F(SetGlobalPropertiesRequestTest, ON_CALL(mock_message_helper_, VerifyImage(_, _, _)) .WillByDefault(Return(mobile_apis::Result::SUCCESS)); + EXPECT_CALL( + mock_message_helper_, + VerifyTtsFiles( + (*msg_vr)[am::strings::msg_params][am::strings::help_prompt], _, _)) + .WillOnce(Return(mobile_apis::Result::SUCCESS)); + (*msg_vr)[am::strings::params][am::hmi_response::code] = hmi_apis::Common_Result::SUCCESS; Event event_vr(hmi_apis::FunctionID::TTS_SetGlobalProperties); @@ -763,6 +773,10 @@ TEST_F(SetGlobalPropertiesRequestTest, Run_TTSHelpAndTimeout_SUCCESS) { EXPECT_CALL(app_mngr_, application(kConnectionKey)) .WillOnce(Return(mock_app_)); EXPECT_CALL(mock_message_helper_, VerifyImageVrHelpItems(_, _, _)).Times(0); + EXPECT_CALL(mock_message_helper_, VerifyTtsFiles(help_prompt, _, _)) + .WillOnce(Return(mobile_apis::Result::SUCCESS)); + EXPECT_CALL(mock_message_helper_, VerifyTtsFiles(timeout_prompt, _, _)) + .WillOnce(Return(mobile_apis::Result::SUCCESS)); EXPECT_CALL(app_mngr_, RemoveAppFromTTSGlobalPropertiesList(kConnectionKey)); SmartObject vr_help_title("title"); EXPECT_CALL(*mock_app_, vr_help_title()).WillOnce(Return(&vr_help_title)); @@ -795,6 +809,8 @@ TEST_F(SetGlobalPropertiesRequestTest, Run_TTSOnlyHelp_SUCCESS) { EXPECT_CALL(app_mngr_, application(kConnectionKey)) .WillOnce(Return(mock_app_)); EXPECT_CALL(mock_message_helper_, VerifyImageVrHelpItems(_, _, _)).Times(0); + EXPECT_CALL(mock_message_helper_, VerifyTtsFiles(help_prompt, _, _)) + .WillOnce(Return(mobile_apis::Result::SUCCESS)); EXPECT_CALL(app_mngr_, RemoveAppFromTTSGlobalPropertiesList(kConnectionKey)); SmartObject vr_help_title("title"); EXPECT_CALL(*mock_app_, vr_help_title()).WillOnce(Return(&vr_help_title)); @@ -825,6 +841,8 @@ TEST_F(SetGlobalPropertiesRequestTest, Run_TTSOnlyTimeout_SUCCESS) { EXPECT_CALL(app_mngr_, application(kConnectionKey)) .WillOnce(Return(mock_app_)); EXPECT_CALL(mock_message_helper_, VerifyImageVrHelpItems(_, _, _)).Times(0); + EXPECT_CALL(mock_message_helper_, VerifyTtsFiles(timeout_prompt, _, _)) + .WillOnce(Return(mobile_apis::Result::SUCCESS)); EXPECT_CALL(app_mngr_, RemoveAppFromTTSGlobalPropertiesList(kConnectionKey)); SmartObject vr_help_title("title"); EXPECT_CALL(*mock_app_, vr_help_title()).WillOnce(Return(&vr_help_title)); diff --git a/src/components/application_manager/test/commands/mobile/speak_request_test.cc b/src/components/application_manager/test/commands/mobile/speak_request_test.cc index f07012d315..36a9b85c6a 100644 --- a/src/components/application_manager/test/commands/mobile/speak_request_test.cc +++ b/src/components/application_manager/test/commands/mobile/speak_request_test.cc @@ -286,6 +286,11 @@ TEST_F(SpeakRequestTest, Run_MsgWithEmptyString_Success) { [am::strings::text] = ""; CommandPtr command(CreateCommand<SpeakRequest>(request_)); + EXPECT_CALL( + mock_message_helper_, + VerifyTtsFiles( + (*request_)[am::strings::msg_params][am::strings::tts_chunks], _, _)) + .WillOnce(Return(mobile_apis::Result::SUCCESS)); ON_CALL(app_mngr_, application(_)).WillByDefault(Return(app_)); ON_CALL(*app_, app_id()).WillByDefault(Return(kAppId)); @@ -301,6 +306,11 @@ TEST_F(SpeakRequestTest, Run_MsgCorrect_Success) { [am::strings::text] = "asda"; CommandPtr command(CreateCommand<SpeakRequest>(request_)); + EXPECT_CALL( + mock_message_helper_, + VerifyTtsFiles( + (*request_)[am::strings::msg_params][am::strings::tts_chunks], _, _)) + .WillOnce(Return(mobile_apis::Result::SUCCESS)); ON_CALL(app_mngr_, application(_)).WillByDefault(Return(app_)); ON_CALL(*app_, app_id()).WillByDefault(Return(kAppId)); diff --git a/src/components/application_manager/test/include/application_manager/mock_message_helper.h b/src/components/application_manager/test/include/application_manager/mock_message_helper.h index 93db0d9795..e8a969718d 100644 --- a/src/components/application_manager/test/include/application_manager/mock_message_helper.h +++ b/src/components/application_manager/test/include/application_manager/mock_message_helper.h @@ -176,6 +176,10 @@ class MockMessageHelper { MOCK_METHOD1(SendGlobalPropertiesToHMI, void(ApplicationConstSharedPtr app)); MOCK_METHOD1(GetIVISubscriptionRequests, smart_objects::SmartObjectList(ApplicationSharedPtr app)); + MOCK_METHOD3(VerifyTtsFiles, + mobile_apis::Result::eType(smart_objects::SmartObject& message, + ApplicationConstSharedPtr app, + ApplicationManager& app_mngr)); MOCK_METHOD3(VerifyImageFiles, mobile_apis::Result::eType(smart_objects::SmartObject& message, ApplicationConstSharedPtr app, diff --git a/src/components/application_manager/test/mock_message_helper.cc b/src/components/application_manager/test/mock_message_helper.cc index 24bba63e71..8b0ec5b854 100644 --- a/src/components/application_manager/test/mock_message_helper.cc +++ b/src/components/application_manager/test/mock_message_helper.cc @@ -315,6 +315,14 @@ smart_objects::SmartObjectList MessageHelper::GetIVISubscriptionRequests( app); } +mobile_apis::Result::eType MessageHelper::VerifyTtsFiles( + smart_objects::SmartObject& message, + ApplicationConstSharedPtr app, + ApplicationManager& app_mngr) { + return MockMessageHelper::message_helper_mock()->VerifyTtsFiles( + message, app, app_mngr); +} + mobile_apis::Result::eType MessageHelper::VerifyImage( smart_objects::SmartObject& message, ApplicationConstSharedPtr app, diff --git a/src/components/connection_handler/include/connection_handler/connection_handler_impl.h b/src/components/connection_handler/include/connection_handler/connection_handler_impl.h index 66b2d7cf16..e270d9faeb 100644 --- a/src/components/connection_handler/include/connection_handler/connection_handler_impl.h +++ b/src/components/connection_handler/include/connection_handler/connection_handler_impl.h @@ -503,20 +503,6 @@ class ConnectionHandlerImpl std::list<int32_t>* sessions_list, connection_handler::DeviceHandle* device_id) const OVERRIDE; - /** - * DEPRECATED - * \brief information about given Connection Key. - * \param key Unique key used by other components as session identifier - * \param app_id Returned: ApplicationID - * \param sessions_list Returned: List of session keys - * \param device_id Returned: DeviceID - * \return int32_t -1 in case of error or 0 in case of success - */ - int32_t GetDataOnSessionKey(uint32_t key, - uint32_t* app_id, - std::list<int32_t>* sessions_list, - uint32_t* device_id) const OVERRIDE; - const ConnectionHandlerSettings& get_settings() const OVERRIDE; const protocol_handler::SessionObserver& get_session_observer(); diff --git a/src/components/connection_handler/src/connection_handler_impl.cc b/src/components/connection_handler/src/connection_handler_impl.cc index 5b26304302..83d80d9696 100644 --- a/src/components/connection_handler/src/connection_handler_impl.cc +++ b/src/components/connection_handler/src/connection_handler_impl.cc @@ -316,6 +316,7 @@ void ConnectionHandlerImpl::RemoveConnection( bool AllowProtection(const ConnectionHandlerSettings& settings, const protocol_handler::ServiceType& service_type, const bool is_protected) { + LOG4CXX_AUTO_TRACE(logger_); const std::vector<int>& force_unprotected_list = is_protected ? settings.force_unprotected_service() : settings.force_protected_service(); @@ -466,14 +467,6 @@ void ConnectionHandlerImpl::OnSessionStartedCallback( const uint32_t session_key = KeyFromPair(connection_handle, context.new_session_id_); - uint32_t app_id = 0; - GetDataOnSessionKey( - session_key, &app_id, NULL, static_cast<DeviceHandle*>(NULL)); - if (app_id > 0) { - context.is_ptu_required_ = - !connection_handler_observer_->CheckAppIsNavi(app_id); - } - { sync_primitives::AutoLock auto_lock(start_service_context_map_lock_); start_service_context_map_[session_key] = context; @@ -716,18 +709,6 @@ int32_t ConnectionHandlerImpl::GetDataOnSessionKey( return 0; } -int32_t ConnectionHandlerImpl::GetDataOnSessionKey( - uint32_t key, - uint32_t* app_id, - std::list<int32_t>* sessions_list, - uint32_t* device_id) const { - LOG4CXX_AUTO_TRACE(logger_); - DeviceHandle handle; - int32_t result = GetDataOnSessionKey(key, app_id, sessions_list, &handle); - *device_id = static_cast<uint32_t>(handle); - return result; -} - const ConnectionHandlerSettings& ConnectionHandlerImpl::get_settings() const { return settings_; } diff --git a/src/components/connection_handler/test/connection_handler_impl_test.cc b/src/components/connection_handler/test/connection_handler_impl_test.cc index d0b9ce4ae4..56dbf6b9de 100644 --- a/src/components/connection_handler/test/connection_handler_impl_test.cc +++ b/src/components/connection_handler/test/connection_handler_impl_test.cc @@ -1273,9 +1273,6 @@ TEST_F(ConnectionHandlerTest, SessionStarted_WithRpc) { true, ByRef(empty))); - EXPECT_CALL(mock_connection_handler_observer, CheckAppIsNavi(_)) - .WillOnce(Return(true)); - connection_handler_->set_protocol_handler(&mock_protocol_handler_); EXPECT_CALL(mock_protocol_handler_, NotifySessionStarted(_, _)) .WillOnce(SaveArg<0>(&out_context_)); @@ -1312,8 +1309,6 @@ TEST_F(ConnectionHandlerTest, ServiceStarted_Video_SUCCESS) { session_key, true, ByRef(empty))); - EXPECT_CALL(mock_connection_handler_observer, CheckAppIsNavi(_)) - .WillOnce(Return(true)); // confirm that NotifySessionStarted() is called connection_handler_->set_protocol_handler(&mock_protocol_handler_); @@ -1354,8 +1349,6 @@ TEST_F(ConnectionHandlerTest, ServiceStarted_Video_FAILURE) { session_key, false, ByRef(empty))); - EXPECT_CALL(mock_connection_handler_observer, CheckAppIsNavi(_)) - .WillOnce(Return(true)); // confirm that NotifySessionStarted() is called connection_handler_->set_protocol_handler(&mock_protocol_handler_); @@ -1446,9 +1439,6 @@ TEST_F(ConnectionHandlerTest, ServiceStarted_Video_Multiple) { session_key1, true, ByRef(empty)))); - EXPECT_CALL(mock_connection_handler_observer, CheckAppIsNavi(_)) - .Times(2) - .WillRepeatedly(Return(true)); // verify that connection handler will not mix up the two results SessionContext new_context_first, new_context_second; diff --git a/src/components/hmi_message_handler/src/websocket_session.cc b/src/components/hmi_message_handler/src/websocket_session.cc index 26f15695c9..a148f48661 100644 --- a/src/components/hmi_message_handler/src/websocket_session.cc +++ b/src/components/hmi_message_handler/src/websocket_session.cc @@ -319,4 +319,4 @@ void WebsocketSession::LoopThreadDelegate::SetShutdown() { message_queue_.Shutdown(); } } -}
\ No newline at end of file +} diff --git a/src/components/include/connection_handler/connection_handler.h b/src/components/include/connection_handler/connection_handler.h index 1fcf5e4477..352f886aed 100644 --- a/src/components/include/connection_handler/connection_handler.h +++ b/src/components/include/connection_handler/connection_handler.h @@ -183,21 +183,6 @@ class ConnectionHandler { connection_handler::DeviceHandle* device_id) const = 0; /** - * DEPRECATED - * \brief information about given Connection Key. - * \param key Unique key used by other components as session identifier - * \param app_id Returned: ApplicationID - * \param sessions_list Returned: List of session keys - * \param device_id Returned: DeviceID - * \return int32_t -1 in case of error or 0 in case of success - */ - DEPRECATED virtual int32_t GetDataOnSessionKey( - uint32_t key, - uint32_t* app_id, - std::list<int32_t>* sessions_list, - uint32_t* device_id) const = 0; - - /** * @brief GetConnectedDevicesMAC allows to obtain MAC adresses for all * currently connected devices. * diff --git a/src/components/include/protocol_handler/protocol_handler.h b/src/components/include/protocol_handler/protocol_handler.h index 6aafd7d53f..1da8d61e52 100644 --- a/src/components/include/protocol_handler/protocol_handler.h +++ b/src/components/include/protocol_handler/protocol_handler.h @@ -103,6 +103,12 @@ class ProtocolHandler { virtual void SendEndService(int32_t connection_id, uint8_t session_id, uint8_t service_type) = 0; + + /** + * \brief Called to notify all handsheke handlers about handshake failure. + */ + virtual void NotifyOnFailedHandshake() = 0; + /** * \brief Protocol handler settings getter * \return pointer to protocol handler settings class diff --git a/src/components/include/protocol_handler/session_observer.h b/src/components/include/protocol_handler/session_observer.h index 3482c6569c..7a5dcf287c 100644 --- a/src/components/include/protocol_handler/session_observer.h +++ b/src/components/include/protocol_handler/session_observer.h @@ -66,7 +66,6 @@ struct SessionContext { uint32_t hash_id_; bool is_protected_; bool is_new_service_; - bool is_ptu_required_; /** * @brief Constructor @@ -78,8 +77,7 @@ struct SessionContext { , service_type_(protocol_handler::kInvalidServiceType) , hash_id_(0) , is_protected_(false) - , is_new_service_(false) - , is_ptu_required_(false) {} + , is_new_service_(false) {} /** * @brief Constructor @@ -105,8 +103,7 @@ struct SessionContext { , service_type_(service_type) , hash_id_(hash_id) , is_protected_(is_protected) - , is_new_service_(false) - , is_ptu_required_(false) {} + , is_new_service_(false) {} }; /** @@ -231,20 +228,6 @@ class SessionObserver { uint8_t* sessionId) const = 0; /** - * DEPRECATED - * \brief information about given Connection Key. - * \param key Unique key used by other components as session identifier - * \param app_id Returned: ApplicationID - * \param sessions_list Returned: List of session keys - * \param device_id Returned: DeviceID - * \return int32_t -1 in case of error or 0 in case of success - */ - virtual int32_t GetDataOnSessionKey(uint32_t key, - uint32_t* app_id, - std::list<int32_t>* sessions_list, - uint32_t* device_id) const = 0; - - /** * \brief information about given Connection Key. * \param key Unique key used by other components as session identifier * \param app_id Returned: ApplicationID diff --git a/src/components/include/security_manager/crypto_manager.h b/src/components/include/security_manager/crypto_manager.h index 18c06ffe06..486b6da64f 100644 --- a/src/components/include/security_manager/crypto_manager.h +++ b/src/components/include/security_manager/crypto_manager.h @@ -33,6 +33,7 @@ #ifndef SRC_COMPONENTS_INCLUDE_SECURITY_MANAGER_CRYPTO_MANAGER_H_ #define SRC_COMPONENTS_INCLUDE_SECURITY_MANAGER_CRYPTO_MANAGER_H_ +#include <time.h> #include "application_manager/policies/policy_handler_observer.h" #include "security_manager/security_manager_settings.h" @@ -65,8 +66,16 @@ class CryptoManager : public policy::PolicyHandlerObserver { virtual bool OnCertificateUpdated(const std::string& data) = 0; virtual void ReleaseSSLContext(SSLContext* context) = 0; virtual std::string LastError() const = 0; - - virtual bool IsCertificateUpdateRequired() const = 0; + /** + * @brief IsCertificateUpdateRequired checks if certificate update is needed + * @param system_time - time with which certificate expiration time + * should be compared + * @param certificates_time - certificate expiration time + * @return True if certificate expired and need to be updated + * otherwise False + */ + virtual bool IsCertificateUpdateRequired( + const time_t system_time, const time_t certificates_time) const = 0; /** * \brief Crypto manager settings getter * \return pointer to crypto manager settings class diff --git a/src/components/include/security_manager/security_manager.h b/src/components/include/security_manager/security_manager.h index 8f772f6a13..61ba43c74f 100644 --- a/src/components/include/security_manager/security_manager.h +++ b/src/components/include/security_manager/security_manager.h @@ -41,6 +41,7 @@ #include "protocol_handler/session_observer.h" #include "security_manager/security_manager_listener.h" +#include "application_manager/policies/policy_handler_observer.h" namespace security_manager { @@ -50,7 +51,8 @@ class CryptoManager; * protocol_handler::ProtocolObserver * and provide interface for handling Security queries from mobile side */ -class SecurityManager : public protocol_handler::ProtocolObserver { +class SecurityManager : public protocol_handler::ProtocolObserver, + public policy::PolicyHandlerObserver { public: /** * \brief InternalErrors is 1 byte identifier of internal error @@ -70,6 +72,10 @@ class SecurityManager : public protocol_handler::ProtocolObserver { ERROR_INTERNAL = 0xFF, ERROR_UNKNOWN_INTERNAL_ERROR = 0xFE // error value for testing }; + + // SSL context creation strategy + enum ContextCreationStrategy { kUseExisting = 0, kForceRecreation }; + /** * \brief Sets pointer for Connection Handler layer for managing sessions * \param session_observer pointer to object of the class implementing @@ -114,13 +120,15 @@ class SecurityManager : public protocol_handler::ProtocolObserver { } /** - * \brief Create new SSLContext for connection or return exists + * @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 + * @param connection_key Unique key used by other components as session * identifier + * @param cc_strategy - SSL context creation strategy * @return new \c SSLContext or \c NULL on any error */ - virtual SSLContext* CreateSSLContext(const uint32_t& connection_key) = 0; + virtual SSLContext* CreateSSLContext(const uint32_t& connection_key, + ContextCreationStrategy cc_strategy) = 0; /** * \brief Start handshake as SSL client @@ -128,10 +136,26 @@ class SecurityManager : public protocol_handler::ProtocolObserver { virtual void StartHandshake(uint32_t connection_key) = 0; /** + * @brief PostponeHandshake allows to postpone handshake. It notifies + * cryptomanager that certificate should be updated and adds specified + * connection key to the list of the certificate awaiting connections. + * @param connection_key the identifier for connection to postpone handshake. + */ + virtual void PostponeHandshake(const uint32_t connection_key) = 0; + + /** * @brief Check whether certificate should be updated + * @param connection_key the connection identifier to check certificate for. * @return true if certificate should be updated otherwise false */ - virtual bool IsCertificateUpdateRequired() = 0; + virtual bool IsCertificateUpdateRequired(const uint32_t connection_key) = 0; + + /** + * @brief Checks whether system time ready notification + * was received from hmi + * @return true if received otherwise false + */ + virtual bool IsSystemTimeProviderReady() const = 0; /** * @brief Notify all listeners that certificate update required @@ -140,6 +164,11 @@ class SecurityManager : public protocol_handler::ProtocolObserver { virtual void NotifyOnCertificateUpdateRequired() = 0; /** + * @brief Notify all listeners that handshake was failed + */ + virtual void NotifyListenersOnHandshakeFailed() = 0; + + /** * @brief Check if policy certificate data is empty * @return true if policy certificate data is empty otherwise false */ @@ -150,6 +179,18 @@ class SecurityManager : public protocol_handler::ProtocolObserver { */ virtual void AddListener(SecurityManagerListener* const listener) = 0; virtual void RemoveListener(SecurityManagerListener* const listener) = 0; + + /** + * @brief OnCertificateUpdated allows to obtain notification when certificate + * has been updated with policy table update. Pass this certificate to crypto + * manager for further processing. Also process postopnes handshake for the + * certain connection key. + * + * @param data the certificates content. + * + * @return always true. + */ + virtual bool OnCertificateUpdated(const std::string& data) = 0; }; } // namespace security_manager #endif // SRC_COMPONENTS_INCLUDE_SECURITY_MANAGER_SECURITY_MANAGER_H_ diff --git a/src/components/include/security_manager/security_manager_listener.h b/src/components/include/security_manager/security_manager_listener.h index aeb3334a56..00a4c68134 100644 --- a/src/components/include/security_manager/security_manager_listener.h +++ b/src/components/include/security_manager/security_manager_listener.h @@ -47,6 +47,13 @@ class SecurityManagerListener { */ virtual bool OnHandshakeDone(uint32_t connection_key, SSLContext::HandshakeResult result) = 0; + + /** + * @brief Notification about handshake failure + * @return true on success notification handling or false otherwise + */ + virtual bool OnHandshakeFailed() = 0; + /** * @brief Notify listeners that certificate update is required. */ diff --git a/src/components/include/security_manager/security_manager_settings.h b/src/components/include/security_manager/security_manager_settings.h index c6b97f85cc..0bbe0f4f96 100644 --- a/src/components/include/security_manager/security_manager_settings.h +++ b/src/components/include/security_manager/security_manager_settings.h @@ -33,12 +33,16 @@ #ifndef SRC_COMPONENTS_INCLUDE_SECURITY_MANAGER_SECURITY_MANAGER_SETTINGS_H_ #define SRC_COMPONENTS_INCLUDE_SECURITY_MANAGER_SECURITY_MANAGER_SETTINGS_H_ +#include <stddef.h> +#include <string> +#include <vector> + namespace security_manager { enum Mode { CLIENT, SERVER }; -enum Protocol { SSLv3, TLSv1, TLSv1_1, TLSv1_2 }; +enum Protocol { SSLv3, TLSv1, TLSv1_1, TLSv1_2, DTLSv1 }; /** - * \class ConnectionHandlerSettings - * \brief Interface for connection handler component settings. + * \class CryptoManagerSettings + * \brief Interface for crypto manager component settings. */ class CryptoManagerSettings { public: @@ -50,8 +54,12 @@ class CryptoManagerSettings { virtual const std::string& certificate_data() const = 0; virtual const std::string& ciphers_list() const = 0; virtual const std::string& ca_cert_path() const = 0; + virtual const std::string& module_cert_path() const = 0; + virtual const std::string& module_key_path() const = 0; virtual size_t update_before_hours() const = 0; virtual size_t maximum_payload_size() const = 0; + virtual const std::vector<int>& force_protected_service() const = 0; + virtual const std::vector<int>& force_unprotected_service() const = 0; }; } // namespace security_manager diff --git a/src/components/include/security_manager/ssl_context.h b/src/components/include/security_manager/ssl_context.h index 86997edbd9..9d66e1af2f 100644 --- a/src/components/include/security_manager/ssl_context.h +++ b/src/components/include/security_manager/ssl_context.h @@ -81,10 +81,11 @@ class SSLContext { HandshakeContext(const custom_str::CustomString& exp_sn, const custom_str::CustomString& exp_cn) - : expected_sn(exp_sn), expected_cn(exp_cn) {} + : expected_sn(exp_sn), expected_cn(exp_cn), system_time(time(NULL)) {} custom_str::CustomString expected_sn; custom_str::CustomString expected_cn; + time_t system_time; }; virtual HandshakeResult StartHandshake(const uint8_t** const out_data, @@ -103,6 +104,14 @@ class SSLContext { size_t* out_data_size) = 0; virtual bool IsInitCompleted() const = 0; virtual bool IsHandshakePending() const = 0; + /** + * @brief GetCertificateDueDate gets certificate expiration date + * @param due_date - certificate expiration time to be received + * @return True if certificate expiration date received + * otherwise False + */ + virtual bool GetCertificateDueDate(time_t& due_date) const = 0; + virtual bool HasCertificate() const = 0; virtual size_t get_max_block_size(size_t mtu) const = 0; virtual std::string LastError() const = 0; diff --git a/src/components/include/test/policy/policy_regular/policy/mock_cache_manager.h b/src/components/include/test/policy/policy_regular/policy/mock_cache_manager.h index cf20dcb666..d216957eb0 100644 --- a/src/components/include/test/policy/policy_regular/policy/mock_cache_manager.h +++ b/src/components/include/test/policy/policy_regular/policy/mock_cache_manager.h @@ -206,7 +206,6 @@ class MockCacheManagerInterface : public CacheManagerInterface { MOCK_METHOD1(GetHMITypes, const policy_table::AppHMITypes*(const std::string& app_id)); MOCK_CONST_METHOD0(GetCertificate, std::string()); - MOCK_METHOD1(SetDecryptedCertificate, void(const std::string&)); MOCK_METHOD1(GetGroups, const policy_table::Strings&(const PTString& app_id)); MOCK_CONST_METHOD2(AppHasHMIType, bool(const std::string& application_id, diff --git a/src/components/include/test/policy/policy_regular/policy/mock_policy_manager.h b/src/components/include/test/policy/policy_regular/policy/mock_policy_manager.h index 0b8823d307..e0214934ee 100644 --- a/src/components/include/test/policy/policy_regular/policy/mock_policy_manager.h +++ b/src/components/include/test/policy/policy_regular/policy/mock_policy_manager.h @@ -186,7 +186,6 @@ class MockPolicyManager : public PolicyManager { MOCK_CONST_METHOD0(GetMetaInfo, const policy::MetaInfo()); MOCK_CONST_METHOD0(RetrieveCertificate, std::string()); MOCK_CONST_METHOD0(HasCertificate, bool()); - MOCK_METHOD1(SetDecryptedCertificate, void(const std::string&)); MOCK_METHOD0(ExceededIgnitionCycles, bool()); MOCK_METHOD0(ExceededDays, bool()); MOCK_METHOD0(StartPTExchange, void()); diff --git a/src/components/include/test/protocol_handler/mock_protocol_handler.h b/src/components/include/test/protocol_handler/mock_protocol_handler.h index 79c2188cdf..e667911944 100644 --- a/src/components/include/test/protocol_handler/mock_protocol_handler.h +++ b/src/components/include/test/protocol_handler/mock_protocol_handler.h @@ -72,6 +72,7 @@ class MockProtocolHandler : public ::protocol_handler::ProtocolHandler { MOCK_METHOD2(NotifySessionStarted, void(const ::protocol_handler::SessionContext& context, std::vector<std::string>& rejected_params)); + MOCK_METHOD0(NotifyOnFailedHandshake, void()); }; } // namespace protocol_handler_test } // namespace components diff --git a/src/components/include/test/security_manager/mock_crypto_manager.h b/src/components/include/test/security_manager/mock_crypto_manager.h index 55c364bd89..61ec5183e4 100644 --- a/src/components/include/test/security_manager/mock_crypto_manager.h +++ b/src/components/include/test/security_manager/mock_crypto_manager.h @@ -52,7 +52,9 @@ class MockCryptoManager : public ::security_manager::CryptoManager { MOCK_METHOD0(CreateSSLContext, ::security_manager::SSLContext*()); MOCK_METHOD1(ReleaseSSLContext, void(::security_manager::SSLContext*)); MOCK_CONST_METHOD0(LastError, std::string()); - MOCK_CONST_METHOD0(IsCertificateUpdateRequired, bool()); + MOCK_CONST_METHOD2(IsCertificateUpdateRequired, + bool(const time_t system_time, + const time_t certificates_time)); }; } // namespace security_manager_test } // namespace components diff --git a/src/components/include/test/security_manager/mock_security_manager.h b/src/components/include/test/security_manager/mock_security_manager.h index 11890cb071..b2c2e3bf17 100644 --- a/src/components/include/test/security_manager/mock_security_manager.h +++ b/src/components/include/test/security_manager/mock_security_manager.h @@ -54,8 +54,9 @@ class MockSecurityManager : public ::security_manager::SecurityManager { 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_METHOD2(CreateSSLContext, + ::security_manager::SSLContext*(const uint32_t&, + ContextCreationStrategy)); MOCK_METHOD1(StartHandshake, void(uint32_t)); MOCK_METHOD1(AddListener, void(::security_manager::SecurityManagerListener*)); MOCK_METHOD1(RemoveListener, @@ -65,9 +66,13 @@ class MockSecurityManager : public ::security_manager::SecurityManager { void(const ::protocol_handler::RawMessagePtr)); MOCK_METHOD1(OnMobileMessageSent, void(const ::protocol_handler::RawMessagePtr)); - MOCK_METHOD0(IsCertificateUpdateRequired, bool()); + MOCK_METHOD1(IsCertificateUpdateRequired, bool(const uint32_t)); MOCK_METHOD0(NotifyOnCertificateUpdateRequired, void()); + MOCK_METHOD0(NotifyListenersOnHandshakeFailed, void()); MOCK_METHOD0(IsPolicyCertificateDataEmpty, bool()); + MOCK_METHOD1(OnCertificateUpdated, bool(const std::string&)); + MOCK_METHOD1(PostponeHandshake, void(const uint32_t)); + MOCK_CONST_METHOD0(IsSystemTimeProviderReady, bool()); }; /* diff --git a/src/components/include/test/security_manager/mock_security_manager_listener.h b/src/components/include/test/security_manager/mock_security_manager_listener.h index a06762a09d..7a7714d299 100644 --- a/src/components/include/test/security_manager/mock_security_manager_listener.h +++ b/src/components/include/test/security_manager/mock_security_manager_listener.h @@ -49,6 +49,7 @@ class MockSecurityManagerListener ::security_manager::SSLContext::HandshakeResult result)); MOCK_METHOD0(OnCertificateUpdateRequired, void()); MOCK_CONST_METHOD1(GetPolicyCertificateData, bool(std::string& data)); + MOCK_METHOD0(OnHandshakeFailed, bool()); }; } // namespace security_manager_test } // namespace components diff --git a/src/components/include/test/security_manager/mock_security_manager_settings.h b/src/components/include/test/security_manager/mock_security_manager_settings.h index 6ac194ced4..b1c869cd1b 100644 --- a/src/components/include/test/security_manager/mock_security_manager_settings.h +++ b/src/components/include/test/security_manager/mock_security_manager_settings.h @@ -50,8 +50,12 @@ class MockCryptoManagerSettings MOCK_CONST_METHOD0(certificate_data, const std::string&()); MOCK_CONST_METHOD0(ciphers_list, const std::string&()); MOCK_CONST_METHOD0(ca_cert_path, const std::string&()); + MOCK_CONST_METHOD0(module_cert_path, const std::string&()); + MOCK_CONST_METHOD0(module_key_path, const std::string&()); MOCK_CONST_METHOD0(update_before_hours, size_t()); MOCK_CONST_METHOD0(maximum_payload_size, size_t()); + MOCK_CONST_METHOD0(force_protected_service, const std::vector<int>&()); + MOCK_CONST_METHOD0(force_unprotected_service, const std::vector<int>&()); }; } // namespace security_manager_test diff --git a/src/components/include/test/security_manager/mock_ssl_context.h b/src/components/include/test/security_manager/mock_ssl_context.h index 6b6a26a226..02198d1d22 100644 --- a/src/components/include/test/security_manager/mock_ssl_context.h +++ b/src/components/include/test/security_manager/mock_ssl_context.h @@ -68,6 +68,8 @@ class MockSSLContext : public ::security_manager::SSLContext { MOCK_CONST_METHOD0(LastError, std::string()); MOCK_METHOD0(ResetConnection, void()); MOCK_METHOD1(SetHandshakeContext, void(const HandshakeContext& hsh_ctx)); + MOCK_CONST_METHOD0(HasCertificate, bool()); + MOCK_CONST_METHOD1(GetCertificateDueDate, bool(time_t& due_date)); }; } // namespace security_manager_test } // namespace components diff --git a/src/components/include/test/utils/mock_system_time_handler.h b/src/components/include/test/utils/mock_system_time_handler.h new file mode 100644 index 0000000000..7bb2a7f0a5 --- /dev/null +++ b/src/components/include/test/utils/mock_system_time_handler.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2018, 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_INCLUDE_TEST_SECURITY_MANAGER_MOCK_SYSTEM_TIME_HANDLER_H +#define SRC_COMPONENTS_INCLUDE_TEST_SECURITY_MANAGER_MOCK_SYSTEM_TIME_HANDLER_H + +#include "gmock/gmock.h" +#include "utils/system_time_handler.h" + +namespace test { +namespace components { +namespace security_manager_test { + +class MockSystemTimeHandler : public ::utils::SystemTimeHandler { + public: + MockSystemTimeHandler() {} + MOCK_METHOD0(QuerySystemTime, void()); + MOCK_METHOD1(SubscribeOnSystemTime, + void(utils::SystemTimeListener* listener)); + MOCK_METHOD1(UnsubscribeFromSystemTime, + void(utils::SystemTimeListener* listener)); + MOCK_METHOD0(GetUTCTime, time_t()); + MOCK_CONST_METHOD0(system_time_can_be_received, bool()); + ~MockSystemTimeHandler() {} + + private: + void DoSubscribe(utils::SystemTimeListener*) {} + void DoSystemTimeQuery() {} + void DoUnsubscribe(utils::SystemTimeListener* listener) {} + bool utc_time_can_be_received() const { + return true; + } + time_t FetchSystemTime() { + return 0; + } +}; +} // namespace security_manager_test +} // namespace components +} // namespace test +#endif // SRC_COMPONENTS_INCLUDE_TEST_SECURITY_MANAGER_MOCK_SYSTEM_TIME_HANDLER_H diff --git a/src/components/interfaces/HMI_API.xml b/src/components/interfaces/HMI_API.xml index def5d22933..65cc9bea5b 100644 --- a/src/components/interfaces/HMI_API.xml +++ b/src/components/interfaces/HMI_API.xml @@ -371,6 +371,7 @@ <element name="LHPLUS_PHONEMES" /> <element name="PRE_RECORDED" /> <element name="SILENCE" /> + <element name="FILE" /> </enum> <enum name="VrCapabilities"> @@ -1927,12 +1928,12 @@ </struct> <struct name="TTSChunk"> - <description>A TTS chunk, that consists of the text/phonemes to be spoken</description> + <description>A TTS chunk, that consists of text/phonemes to speak or the name of a file to play, and a TTS type (like text or SAPI)</description> <param name="text" type="String" mandatory="true" maxlength="500"> - <description>The text or phonemes to be spoken.</description> + <description>The text or phonemes to be spoken, or the name of an audio file to play.</description> </param> <param name="type" type="Common.SpeechCapabilities" mandatory="true"> - <description>Describes, whether it is text or a specific phoneme set. See SpeechCapabilities.</description> + <description>Describes whether the TTS chunk is plain text, a specific phoneme set, or an audio file. See SpeechCapabilities.</description> </param> </struct> @@ -2853,6 +2854,17 @@ </interface> <interface name="BasicCommunication" version="1.2.1" date="2017-08-02"> + <function name="GetSystemTime" messagetype="request"> + <description>Request from SDL to HMI to obtain current UTC time.</description> + </function> + <function name="GetSystemTime" messagetype="response"> + <param name="systemTime" type="Common.DateTime" mandatory="true"> + <description>Current UTC system time</description> + </param> + </function> + <function name="OnSystemTimeReady" messagetype="notification"> + <description>HMI must notify SDL about readiness to provide system time.</description> + </function> <function name="OnReady" messagetype="notification"> <description>HMI must notify SDL about its readiness to start communication. In fact, this has to be the first message between SDL and HMI.</description> </function> @@ -3348,10 +3360,10 @@ <description>Method is invoked at system start-up. SDL requests the information about all supported hardware and their capabilities</description> </function> <function name="GetCapabilities" messagetype="response"> - <param name="speechCapabilities" type="Common.SpeechCapabilities" minsize="1" maxsize="5" array="true" mandatory="true"> + <param name="speechCapabilities" type="Common.SpeechCapabilities" minsize="1" maxsize="100" array="true" mandatory="true"> <description>See SpeechCapabilities</description> </param> - <param name="prerecordedSpeechCapabilities" type="Common.PrerecordedSpeech" minsize="1" maxsize="5" array="true" mandatory="true"> + <param name="prerecordedSpeechCapabilities" type="Common.PrerecordedSpeech" minsize="1" maxsize="100" array="true" mandatory="true"> <description>See PrerecordedSpeech</description> </param> </function> diff --git a/src/components/interfaces/MOBILE_API.xml b/src/components/interfaces/MOBILE_API.xml index a5504916ba..8b8da6a63a 100644 --- a/src/components/interfaces/MOBILE_API.xml +++ b/src/components/interfaces/MOBILE_API.xml @@ -447,6 +447,7 @@ <element name="LHPLUS_PHONEMES" /> <element name="PRE_RECORDED" /> <element name="SILENCE" /> + <element name="FILE" /> </enum> <enum name="VrCapabilities"> @@ -2103,15 +2104,15 @@ </param> </struct> <struct name="TTSChunk"> - <description>A TTS chunk, that consists of the text/phonemes to speak and the type (like text or SAPI)</description> + <description>A TTS chunk, that consists of text/phonemes to speak or the name of a file to play, and a TTS type (like text or SAPI)</description> <param name="text" minlength="0" maxlength="500" type="String" mandatory="true"> <description> - The text or phonemes to speak. + The text or phonemes to speak, or the name of the audio file to play. May not be empty. </description> </param> <param name="type" type="SpeechCapabilities" mandatory="true"> - <description>Describes, whether it is text or a specific phoneme set. See SpeechCapabilities</description> + <description>Describes whether the TTS chunk is plain text, a specific phoneme set, or an audio file. See SpeechCapabilities</description> </param> </struct> <struct name="Turn"> diff --git a/src/components/policy/policy_external/src/policy_manager_impl.cc b/src/components/policy/policy_external/src/policy_manager_impl.cc index 07afb2fe22..84705978d4 100644 --- a/src/components/policy/policy_external/src/policy_manager_impl.cc +++ b/src/components/policy/policy_external/src/policy_manager_impl.cc @@ -1790,11 +1790,6 @@ StatusNotifier PolicyManagerImpl::AddApplication( device_consent); } else { PromoteExistedApplication(application_id, device_consent); - if (helpers::in_range(hmi_types, policy_table::AHT_NAVIGATION) && - !HasCertificate()) { - LOG4CXX_DEBUG(logger_, "Certificate does not exist, scheduling update."); - update_status_manager_.ScheduleUpdate(); - } return utils::MakeShared<utils::CallNothing>(); } } diff --git a/src/components/policy/policy_regular/src/policy_manager_impl.cc b/src/components/policy/policy_regular/src/policy_manager_impl.cc index 5bdfdaf3bb..ba850efde5 100644 --- a/src/components/policy/policy_regular/src/policy_manager_impl.cc +++ b/src/components/policy/policy_regular/src/policy_manager_impl.cc @@ -219,10 +219,8 @@ bool PolicyManagerImpl::LoadPT(const std::string& file, return false; } - if (pt_update->policy_table.module_config.certificate.is_initialized()) { - listener_->OnCertificateUpdated( - *(pt_update->policy_table.module_config.certificate)); - } + listener_->OnCertificateUpdated( + *(pt_update->policy_table.module_config.certificate)); std::map<std::string, StringArray> app_hmi_types; cache_->GetHMIAppTypeAfterUpdate(app_hmi_types); @@ -1075,13 +1073,6 @@ StatusNotifier PolicyManagerImpl::AddApplication( device_consent); } else { PromoteExistedApplication(application_id, device_consent); - const policy_table::AppHMIType type = policy_table::AHT_NAVIGATION; - if (helpers::in_range(hmi_types, - (rpc::Enum<policy_table::AppHMIType>)type) && - !HasCertificate()) { - LOG4CXX_DEBUG(logger_, "Certificate does not exist, scheduling update."); - update_status_manager_.ScheduleUpdate(); - } return utils::MakeShared<utils::CallNothing>(); } } @@ -1159,6 +1150,10 @@ bool PolicyManagerImpl::InitPT(const std::string& file_name, if (ret) { RefreshRetrySequence(); update_status_manager_.OnPolicyInit(cache_->UpdateRequired()); + const std::string certificate_data = cache_->GetCertificate(); + if (!certificate_data.empty()) { + listener_->OnCertificateUpdated(certificate_data); + } } return ret; } diff --git a/src/components/protocol_handler/include/protocol_handler/handshake_handler.h b/src/components/protocol_handler/include/protocol_handler/handshake_handler.h index 0ef40290f2..8b7f28d50e 100644 --- a/src/components/protocol_handler/include/protocol_handler/handshake_handler.h +++ b/src/components/protocol_handler/include/protocol_handler/handshake_handler.h @@ -61,14 +61,14 @@ class HandshakeHandler : public security_manager::SecurityManagerListener { const std::vector<int>& force_protected_service, const bool is_new_service, ProtocolPacket::ProtocolVersion& full_version, - std::shared_ptr<uint8_t> payload); + std::shared_ptr<BsonObject> payload); HandshakeHandler(ProtocolHandlerImpl& protocol_handler, SessionObserver& session_observer, ProtocolPacket::ProtocolVersion& full_version, const SessionContext& context, const uint8_t protocol_version, - std::shared_ptr<uint8_t> payload); + std::shared_ptr<BsonObject> payload); ~HandshakeHandler(); @@ -90,6 +90,12 @@ class HandshakeHandler : public security_manager::SecurityManagerListener { security_manager::SSLContext::HandshakeResult result) OVERRIDE; /** + * @brief Notification about handshake failure + * @return true on success notification handling or false otherwise + */ + bool OnHandshakeFailed() OVERRIDE; + + /** * @brief Notification that certificate update is required. */ void OnCertificateUpdateRequired() OVERRIDE; @@ -120,7 +126,7 @@ class HandshakeHandler : public security_manager::SecurityManagerListener { SessionContext context_; ProtocolPacket::ProtocolVersion full_version_; const uint8_t protocol_version_; - std::shared_ptr<uint8_t> payload_; + std::shared_ptr<BsonObject> payload_; }; } // namespace protocol_handler diff --git a/src/components/protocol_handler/include/protocol_handler/protocol_handler_impl.h b/src/components/protocol_handler/include/protocol_handler/protocol_handler_impl.h index 0efb81cdd7..99f03b1c04 100644 --- a/src/components/protocol_handler/include/protocol_handler/protocol_handler_impl.h +++ b/src/components/protocol_handler/include/protocol_handler/protocol_handler_impl.h @@ -235,6 +235,8 @@ class ProtocolHandlerImpl uint8_t session_id, uint8_t service_type); + void NotifyOnFailedHandshake() OVERRIDE; + // TODO(Ezamakhov): move Ack/Nack as interface for StartSessionHandler /** * \brief Sends acknowledgement of starting session to mobile application @@ -473,14 +475,6 @@ class ProtocolHandlerImpl const transport_manager::ConnectionUID connection_id) OVERRIDE; /** - * @brief OnPTUFinished the callback which signals PTU has finished - * - * @param ptu_result the result from the PTU - true if successful, - * otherwise false. - */ - void OnPTUFinished(const bool ptu_result) OVERRIDE; - - /** * @brief Notifies subscribers about message * received from mobile device. * @param message Message with already parsed header. @@ -683,10 +677,6 @@ class ProtocolHandlerImpl #ifdef ENABLE_SECURITY security_manager::SecurityManager* security_manager_; - - bool is_ptu_triggered_; - std::list<std::shared_ptr<HandshakeHandler> > ptu_pending_handlers_; - sync_primitives::Lock ptu_handlers_lock_; #endif // ENABLE_SECURITY // Thread that pumps non-parsed messages coming from mobile side. diff --git a/src/components/protocol_handler/include/protocol_handler/protocol_packet.h b/src/components/protocol_handler/include/protocol_handler/protocol_packet.h index 1c427533e6..b6c05d4c46 100644 --- a/src/components/protocol_handler/include/protocol_handler/protocol_packet.h +++ b/src/components/protocol_handler/include/protocol_handler/protocol_packet.h @@ -252,6 +252,12 @@ class ProtocolPacket { const size_t messageSize); /** + * @brief Calculates FIRST_FRAME data for further handling of consecutive + * frames + */ + void HandleRawFirstFrameData(const uint8_t* message); + + /** * \brief Getter of protocol version. */ uint8_t protocol_version() const; diff --git a/src/components/protocol_handler/src/handshake_handler.cc b/src/components/protocol_handler/src/handshake_handler.cc index 055ff2cf45..8db551cfd6 100644 --- a/src/components/protocol_handler/src/handshake_handler.cc +++ b/src/components/protocol_handler/src/handshake_handler.cc @@ -55,7 +55,7 @@ HandshakeHandler::HandshakeHandler( const std::vector<int>& force_protected_service, const bool is_new_service, ProtocolPacket::ProtocolVersion& full_version, - std::shared_ptr<uint8_t> payload) + std::shared_ptr<BsonObject> payload) : protocol_handler_(protocol_handler) , session_observer_(session_observer) , context_() @@ -69,7 +69,7 @@ HandshakeHandler::HandshakeHandler( ProtocolPacket::ProtocolVersion& full_version, const SessionContext& context, const uint8_t protocol_version, - std::shared_ptr<uint8_t> payload) + std::shared_ptr<BsonObject> payload) : protocol_handler_(protocol_handler) , session_observer_(session_observer) , context_(context) @@ -92,6 +92,19 @@ bool HandshakeHandler::GetPolicyCertificateData(std::string& data) const { void HandshakeHandler::OnCertificateUpdateRequired() {} +bool HandshakeHandler::OnHandshakeFailed() { + if (payload_) { + ProcessFailedHandshake(*payload_); + } else { + BsonObject params; + bson_object_initialize_default(¶ms); + ProcessFailedHandshake(params); + bson_object_deinitialize(¶ms); + } + + return true; +} + bool HandshakeHandler::OnHandshakeDone( uint32_t connection_key, security_manager::SSLContext::HandshakeResult result) { @@ -110,20 +123,23 @@ bool HandshakeHandler::OnHandshakeDone( const bool success = result == security_manager::SSLContext::Handshake_Result_Success; - BsonObject params; if (payload_) { - params = bson_object_from_bytes(payload_.get()); + if (success) { + ProcessSuccessfulHandshake(connection_key, *payload_); + } else { + ProcessFailedHandshake(*payload_); + } } else { + BsonObject params; bson_object_initialize_default(¶ms); + if (success) { + ProcessSuccessfulHandshake(connection_key, params); + } else { + ProcessFailedHandshake(params); + } + bson_object_deinitialize(¶ms); } - if (success) { - ProcessSuccessfulHandshake(connection_key, params); - } else { - ProcessFailedHandshake(params); - } - - bson_object_deinitialize(¶ms); return true; } diff --git a/src/components/protocol_handler/src/multiframe_builder.cc b/src/components/protocol_handler/src/multiframe_builder.cc index d554c1843c..487d1f8d73 100644 --- a/src/components/protocol_handler/src/multiframe_builder.cc +++ b/src/components/protocol_handler/src/multiframe_builder.cc @@ -91,6 +91,8 @@ bool MultiFrameBuilder::RemoveConnection(const ConnectionID connection_id) { ProtocolFramePtrList MultiFrameBuilder::PopMultiframes() { LOG4CXX_AUTO_TRACE(logger_); LOG4CXX_DEBUG(logger_, "Current state is: " << multiframes_map_); + LOG4CXX_DEBUG(logger_, + "Current multiframe map size is: " << multiframes_map_.size()); ProtocolFramePtrList outpute_frame_list; for (MultiFrameMap::iterator connection_it = multiframes_map_.begin(); connection_it != multiframes_map_.end(); diff --git a/src/components/protocol_handler/src/protocol_handler_impl.cc b/src/components/protocol_handler/src/protocol_handler_impl.cc index 16cc814f8a..ee94f2f39b 100644 --- a/src/components/protocol_handler/src/protocol_handler_impl.cc +++ b/src/components/protocol_handler/src/protocol_handler_impl.cc @@ -39,6 +39,7 @@ #include "connection_handler/connection_handler_impl.h" #include "protocol_handler/session_observer.h" #include "utils/byte_order.h" +#include "utils/helpers.h" #include "protocol/common.h" #ifdef ENABLE_SECURITY @@ -75,7 +76,6 @@ ProtocolHandlerImpl::ProtocolHandlerImpl( , #ifdef ENABLE_SECURITY security_manager_(NULL) - , is_ptu_triggered_(false) , #endif // ENABLE_SECURITY raw_ford_messages_from_mobile_( @@ -279,16 +279,28 @@ void ProtocolHandlerImpl::SendStartSessionAck( if (ack_protocol_version >= PROTOCOL_VERSION_5) { ServiceType serviceTypeValue = ServiceTypeFromByte(service_type); - bson_object_put_int64( + const bool mtu_written = bson_object_put_int64( ¶ms, strings::mtu, static_cast<int64_t>( protocol_header_validator_.max_payload_size_by_service_type( serviceTypeValue))); + LOG4CXX_DEBUG(logger_, + "MTU parameter was written to bson params: " + << mtu_written << "; Value: " + << static_cast<int32_t>( + bson_object_get_int64(¶ms, strings::mtu))); + if (serviceTypeValue == kRpc) { // Hash ID is only used in RPC case - bson_object_put_int32( + const bool hash_written = bson_object_put_int32( ¶ms, strings::hash_id, static_cast<int32_t>(hash_id)); + LOG4CXX_DEBUG(logger_, + "Hash parameter was written to bson params: " + << hash_written << "; Value: " + << static_cast<int32_t>(bson_object_get_int32( + ¶ms, strings::hash_id))); + // Minimum protocol version supported by both ProtocolPacket::ProtocolVersion* minVersion = (full_version.majorVersion < PROTOCOL_VERSION_5) @@ -297,8 +309,14 @@ void ProtocolHandlerImpl::SendStartSessionAck( defaultProtocolVersion); char protocolVersionString[256]; strncpy(protocolVersionString, (*minVersion).to_string().c_str(), 255); - bson_object_put_string( + + const bool protocol_ver_written = bson_object_put_string( ¶ms, strings::protocol_version, protocolVersionString); + LOG4CXX_DEBUG( + logger_, + "Protocol version parameter was written to bson params: " + << protocol_ver_written << "; Value: " + << bson_object_get_string(¶ms, strings::protocol_version)); } uint8_t* payloadBytes = bson_object_to_bytes(¶ms); ptr->set_data(payloadBytes, bson_object_size(¶ms)); @@ -839,56 +857,10 @@ void ProtocolHandlerImpl::OnConnectionClosed( multiframe_builder_.RemoveConnection(connection_id); } -void ProtocolHandlerImpl::OnPTUFinished(const bool ptu_result) { +void ProtocolHandlerImpl::NotifyOnFailedHandshake() { LOG4CXX_AUTO_TRACE(logger_); - #ifdef ENABLE_SECURITY - sync_primitives::AutoLock lock(ptu_handlers_lock_); - - if (!is_ptu_triggered_) { - LOG4CXX_ERROR(logger_, - "PTU was not triggered by service starting. Ignored"); - return; - } - - const bool is_cert_expired = security_manager_->IsCertificateUpdateRequired(); - for (auto handler : ptu_pending_handlers_) { - security_manager::SSLContext* ssl_context = - is_cert_expired - ? NULL - : security_manager_->CreateSSLContext(handler->connection_key()); - - if (!ssl_context) { - const std::string error("CreateSSLContext failed"); - LOG4CXX_ERROR(logger_, error); - security_manager_->SendInternalError( - handler->connection_key(), - security_manager::SecurityManager::ERROR_INTERNAL, - error); - - handler->OnHandshakeDone( - handler->connection_key(), - security_manager::SSLContext::Handshake_Result_Fail); - - continue; - } - - if (ssl_context->IsInitCompleted()) { - handler->OnHandshakeDone( - handler->connection_key(), - security_manager::SSLContext::Handshake_Result_Success); - } else { - security_manager_->AddListener(new HandshakeHandler(*handler)); - if (!ssl_context->IsHandshakePending()) { - // Start handshake process - security_manager_->StartHandshake(handler->connection_key()); - } - } - } - - LOG4CXX_DEBUG(logger_, "Handshake handlers were notified"); - ptu_pending_handlers_.clear(); - is_ptu_triggered_ = false; + security_manager_->NotifyListenersOnHandshakeFailed(); #endif // ENABLE_SECURITY } @@ -1286,7 +1258,8 @@ RESULT_CODE ProtocolHandlerImpl::HandleControlMessageStartSession( session_observer_.KeyFromPair(connection_id, session_id); security_manager::SSLContext* ssl_context = - security_manager_->CreateSSLContext(connection_key); + security_manager_->CreateSSLContext( + connection_key, security_manager::SecurityManager::kUseExisting); if (!ssl_context) { const std::string error("CreateSSLContext failed"); LOG4CXX_ERROR(logger_, error); @@ -1416,11 +1389,11 @@ RESULT_CODE ProtocolHandlerImpl::HandleControlMessageStartSession( } #ifdef ENABLE_SECURITY + const uint8_t protocol_version = packet->protocol_version(); const bool protection = - // Protocol version 1 is not support protection - (packet->protocol_version() > PROTOCOL_VERSION_1) - ? packet->protection_flag() - : false; + // Protocol version 1 does not support protection + (protocol_version > PROTOCOL_VERSION_1) ? packet->protection_flag() + : false; #else const bool protection = false; #endif // ENABLE_SECURITY @@ -1552,51 +1525,19 @@ void ProtocolHandlerImpl::NotifySessionStarted( const uint32_t connection_key = session_observer_.KeyFromPair( context.connection_id_, context.new_session_id_); - std::shared_ptr<uint8_t> bson_object_bytes( - bson_object_to_bytes(start_session_ack_params.get()), - [](uint8_t* p) { delete[] p; }); - std::shared_ptr<HandshakeHandler> handler = std::make_shared<HandshakeHandler>(*this, session_observer_, *fullVersion, context, packet->protocol_version(), - bson_object_bytes); - - const bool is_certificate_empty = - security_manager_->IsPolicyCertificateDataEmpty(); - - const bool is_certificate_expired = - is_certificate_empty || - security_manager_->IsCertificateUpdateRequired(); - - if (context.is_ptu_required_ && is_certificate_empty) { - LOG4CXX_DEBUG(logger_, - "PTU for StartSessionHandler " - << handler.get() - << " is required and certificate data is empty"); - - sync_primitives::AutoLock lock(ptu_handlers_lock_); - if (!is_ptu_triggered_) { - LOG4CXX_DEBUG(logger_, - "PTU is not triggered yet. " - << "Starting PTU and postponing SSL handshake"); - - ptu_pending_handlers_.push_back(handler); - is_ptu_triggered_ = true; - security_manager_->NotifyOnCertificateUpdateRequired(); - } else { - LOG4CXX_DEBUG(logger_, "PTU has been triggered. Added to pending."); - ptu_pending_handlers_.push_back(handler); - } - return; - } + start_session_ack_params); security_manager::SSLContext* ssl_context = - is_certificate_expired - ? NULL - : security_manager_->CreateSSLContext(connection_key); + security_manager_->CreateSSLContext( + connection_key, + security_manager::SecurityManager::ContextCreationStrategy:: + kUseExisting); if (!ssl_context) { const std::string error("CreateSSLContext failed"); LOG4CXX_ERROR(logger_, error); @@ -1630,12 +1571,27 @@ void ProtocolHandlerImpl::NotifySessionStarted( *fullVersion, *start_session_ack_params); } else { - security_manager_->AddListener(new HandshakeHandler(*handler)); + LOG4CXX_DEBUG(logger_, + "Adding Handshake handler to listeners: " << handler.get()); + security_manager::SecurityManagerListener* listener = + new HandshakeHandler(*handler); + security_manager_->AddListener(listener); + if (!ssl_context->IsHandshakePending()) { // Start handshake process security_manager_->StartHandshake(connection_key); + + if (!security_manager_->IsSystemTimeProviderReady()) { + security_manager_->RemoveListener(listener); + SendStartSessionNAck(context.connection_id_, + packet->session_id(), + protocol_version, + packet->service_type(), + rejected_params); + } } } + LOG4CXX_DEBUG(logger_, "Protection establishing for connection " << connection_key << " is in progress"); @@ -1688,6 +1644,7 @@ RESULT_CODE ProtocolHandlerImpl::HandleControlMessageHeartBeat( } void ProtocolHandlerImpl::PopValideAndExpirateMultiframes() { + LOG4CXX_AUTO_TRACE(logger_); const ProtocolFramePtrList& frame_list = multiframe_builder_.PopMultiframes(); for (ProtocolFramePtrList::const_iterator it = frame_list.begin(); it != frame_list.end(); @@ -1845,7 +1802,9 @@ RESULT_CODE ProtocolHandlerImpl::EncryptFrame(ProtocolFramePtr packet) { DCHECK(packet); // Control frames and data over control service shall be unprotected if (packet->service_type() == kControl || - packet->frame_type() == FRAME_TYPE_CONTROL) { + // For protocol v5 control frames could be protected + (packet->frame_type() == FRAME_TYPE_CONTROL && + packet->protocol_version() < PROTOCOL_VERSION_5)) { return RESULT_OK; } if (!security_manager_) { @@ -1888,12 +1847,30 @@ RESULT_CODE ProtocolHandlerImpl::EncryptFrame(ProtocolFramePtr packet) { RESULT_CODE ProtocolHandlerImpl::DecryptFrame(ProtocolFramePtr packet) { DCHECK(packet); - if (!packet->protection_flag() || - // Control frames and data over control service shall be unprotected - packet->service_type() == kControl || - packet->frame_type() == FRAME_TYPE_CONTROL) { + + bool shoud_not_decrypt; + if (packet->protocol_version() >= PROTOCOL_VERSION_5) { + // For v5 protocol control frames except StartService could be encrypted + shoud_not_decrypt = + !packet->protection_flag() || packet->service_type() == kControl || + (FRAME_TYPE_CONTROL == packet->frame_type() && + helpers::Compare<ServiceType, helpers::EQ, helpers::ONE>( + static_cast<ServiceType>(packet->service_type()), + kMobileNav, + kAudio, + kRpc)); + } else { + // Control frames and data over control service shall be unprotected + shoud_not_decrypt = !packet->protection_flag() || + packet->service_type() == kControl || + packet->frame_type() == FRAME_TYPE_CONTROL; + } + + if (shoud_not_decrypt) { + LOG4CXX_DEBUG(logger_, "Frame will not be decrypted"); return RESULT_OK; } + if (!security_manager_) { LOG4CXX_WARN(logger_, "No security_manager_ set."); return RESULT_FAIL; @@ -1934,6 +1911,11 @@ RESULT_CODE ProtocolHandlerImpl::DecryptFrame(ProtocolFramePtr packet) { << out_data_size << " bytes"); DCHECK(out_data); DCHECK(out_data_size); + // Special handling for decrypted FIRST_FRAME + if (packet->frame_type() == FRAME_TYPE_FIRST && packet->protection_flag()) { + packet->HandleRawFirstFrameData(out_data); + return RESULT_OK; + } packet->set_data(out_data, out_data_size); return RESULT_OK; } diff --git a/src/components/protocol_handler/src/protocol_packet.cc b/src/components/protocol_handler/src/protocol_packet.cc index ae52849de6..a490916c99 100644 --- a/src/components/protocol_handler/src/protocol_packet.cc +++ b/src/components/protocol_handler/src/protocol_packet.cc @@ -520,6 +520,17 @@ bool ProtocolPacket::operator==(const ProtocolPacket& other) const { return false; } +void ProtocolPacket::HandleRawFirstFrameData(const uint8_t* message) { + LOG4CXX_AUTO_TRACE(logger_); + payload_size_ = 0; + const uint8_t* data = message; + uint32_t total_data_bytes = data[0] << 24; + total_data_bytes |= data[1] << 16; + total_data_bytes |= data[2] << 8; + total_data_bytes |= data[3]; + set_total_data_bytes(total_data_bytes); +} + RESULT_CODE ProtocolPacket::deserializePacket(const uint8_t* message, const size_t messageSize) { LOG4CXX_AUTO_TRACE(logger_); @@ -532,18 +543,15 @@ RESULT_CODE ProtocolPacket::deserializePacket(const uint8_t* message, packet_data_.totalDataBytes = packet_header_.dataSize; uint32_t dataPayloadSize = 0; - if ((offset < messageSize) && packet_header_.frameType != FRAME_TYPE_FIRST) { + if ((offset < messageSize)) { dataPayloadSize = messageSize - offset; } - if (packet_header_.frameType == FRAME_TYPE_FIRST) { + if (packet_header_.frameType == FRAME_TYPE_FIRST && + !packet_header_.protection_flag) { payload_size_ = 0; const uint8_t* data = message + offset; - uint32_t total_data_bytes = data[0] << 24; - total_data_bytes |= data[1] << 16; - total_data_bytes |= data[2] << 8; - total_data_bytes |= data[3]; - set_total_data_bytes(total_data_bytes); + HandleRawFirstFrameData(data); if (0 == packet_data_.data) { return RESULT_FAIL; } @@ -602,6 +610,8 @@ uint8_t* ProtocolPacket::data() const { } void ProtocolPacket::set_total_data_bytes(size_t dataBytes) { + LOG4CXX_AUTO_TRACE(logger_); + LOG4CXX_DEBUG(logger_, "Data bytes : " << dataBytes); if (dataBytes) { delete[] packet_data_.data; packet_data_.data = new (std::nothrow) uint8_t[dataBytes]; diff --git a/src/components/protocol_handler/test/protocol_handler_tm_test.cc b/src/components/protocol_handler/test/protocol_handler_tm_test.cc index 8525b1c5b9..0cb8e155d0 100644 --- a/src/components/protocol_handler/test/protocol_handler_tm_test.cc +++ b/src/components/protocol_handler/test/protocol_handler_tm_test.cc @@ -46,6 +46,7 @@ #include "security_manager/mock_ssl_context.h" #endif // ENABLE_SECURITY #include "transport_manager/mock_transport_manager.h" +#include "utils/mock_system_time_handler.h" #include "utils/make_shared.h" #include "utils/test_async_waiter.h" #include <bson_object.h> @@ -95,8 +96,14 @@ using protocol_handler::kBulk; using protocol_handler::kInvalidServiceType; // For TM states using transport_manager::TransportManagerListener; +using test::components::security_manager_test::MockSystemTimeHandler; using transport_manager::E_SUCCESS; using transport_manager::DeviceInfo; +#ifdef ENABLE_SECURITY +// For security +using ContextCreationStrategy = + security_manager::SecurityManager::ContextCreationStrategy; +#endif // ENABLE_SECURITY // For CH entities using connection_handler::DeviceHandle; // Google Testing Framework Entities @@ -618,6 +625,18 @@ TEST_F(ProtocolHandlerImplTest, const ::transport_manager::ConnectionUID connection_id2 = 0xBu; const uint8_t session_id2 = 2u; +#ifdef ENABLE_SECURITY + AddSecurityManager(); + + EXPECT_CALL(session_observer_mock, KeyFromPair(connection_id2, session_id2)) + .WillOnce(Return(connection_key)); + + EXPECT_CALL(session_observer_mock, + GetSSLContext(connection_key, start_service)) + .Times(2) + .WillRepeatedly(ReturnNull()); +#endif // ENABLE_SECURITY + EXPECT_CALL(session_observer_mock, IsHeartBeatSupported(connection_id1, _)) .WillRepeatedly(Return(false)); EXPECT_CALL(session_observer_mock, IsHeartBeatSupported(connection_id2, _)) @@ -987,7 +1006,10 @@ TEST_F(ProtocolHandlerImplTest, SecurityEnable_StartSessionProtected_Fail) { SetProtocolVersion2(); // Expect start protection for unprotected session - EXPECT_CALL(security_manager_mock, CreateSSLContext(connection_key)) + EXPECT_CALL(security_manager_mock, + CreateSSLContext(connection_key, + security_manager::SecurityManager:: + ContextCreationStrategy::kUseExisting)) . // Return fail protection WillOnce(DoAll(NotifyTestAsyncWaiter(&waiter), ReturnNull())); @@ -1042,7 +1064,7 @@ TEST_F(ProtocolHandlerImplTest, SetProtocolVersion2(); // call new SSLContext creation - EXPECT_CALL(security_manager_mock, CreateSSLContext(connection_key)) + EXPECT_CALL(security_manager_mock, CreateSSLContext(connection_key, _)) . // Return new SSLContext WillOnce( @@ -1119,7 +1141,7 @@ TEST_F(ProtocolHandlerImplTest, .WillOnce(ReturnRefOfCopy(services)); // call new SSLContext creation - EXPECT_CALL(security_manager_mock, CreateSSLContext(connection_key)) + EXPECT_CALL(security_manager_mock, CreateSSLContext(connection_key, _)) . // Return new SSLContext WillOnce(Return(&ssl_context_mock)); @@ -1198,7 +1220,7 @@ TEST_F(ProtocolHandlerImplTest, times++; // call new SSLContext creation - EXPECT_CALL(security_manager_mock, CreateSSLContext(connection_key)) + EXPECT_CALL(security_manager_mock, CreateSSLContext(connection_key, _)) . // Return new SSLContext WillOnce( @@ -1296,7 +1318,7 @@ TEST_F( times++; // call new SSLContext creation - EXPECT_CALL(security_manager_mock, CreateSSLContext(connection_key)) + EXPECT_CALL(security_manager_mock, CreateSSLContext(connection_key, _)) . // Return new SSLContext WillOnce( @@ -1392,7 +1414,10 @@ TEST_F(ProtocolHandlerImplTest, times++; // call new SSLContext creation - EXPECT_CALL(security_manager_mock, CreateSSLContext(connection_key)) + EXPECT_CALL(security_manager_mock, + CreateSSLContext(connection_key, + security_manager::SecurityManager:: + ContextCreationStrategy::kUseExisting)) . // Return new SSLContext WillOnce( @@ -1420,27 +1445,37 @@ TEST_F(ProtocolHandlerImplTest, // Expect add listener for handshake result EXPECT_CALL(security_manager_mock, AddListener(_)) - // Emulate handshake fail - .WillOnce(Invoke(OnHandshakeDoneFunctor( - connection_key, - security_manager::SSLContext::Handshake_Result_Success))); + // Emulate handshake + .WillOnce( + DoAll(NotifyTestAsyncWaiter(&waiter), + Invoke(OnHandshakeDoneFunctor( + connection_key, + security_manager::SSLContext::Handshake_Result_Success)))); + times++; // Listener check SSLContext EXPECT_CALL(session_observer_mock, GetSSLContext(connection_key, start_service)) . // Emulate protection for service is not enabled - WillOnce(ReturnNull()); + WillOnce(DoAll(NotifyTestAsyncWaiter(&waiter), ReturnNull())); + times++; + + EXPECT_CALL(security_manager_mock, IsSystemTimeProviderReady()) + .WillOnce(DoAll(NotifyTestAsyncWaiter(&waiter), Return(true))); + times++; - // Expect service protection enable EXPECT_CALL(session_observer_mock, - SetProtectionFlag(connection_key, start_service)); + SetProtectionFlag(connection_key, start_service)) + .WillOnce(NotifyTestAsyncWaiter(&waiter)); + times++; - // Expect send Ack with PROTECTION_OFF (on fail handshake) + // Expect send Ack with PROTECTION_ON (on successfull handshake) EXPECT_CALL(transport_manager_mock, SendMessageToDevice( ControlMessage(FRAME_DATA_START_SERVICE_ACK, PROTECTION_ON))) .WillOnce(DoAll(NotifyTestAsyncWaiter(&waiter), Return(E_SUCCESS))); + times++; SendControlMessage( diff --git a/src/components/security_manager/include/security_manager/crypto_manager_impl.h b/src/components/security_manager/include/security_manager/crypto_manager_impl.h index 4e48858e5c..aa3be0f430 100644 --- a/src/components/security_manager/include/security_manager/crypto_manager_impl.h +++ b/src/components/security_manager/include/security_manager/crypto_manager_impl.h @@ -71,6 +71,8 @@ class CryptoManagerImpl : public CryptoManager { size_t* out_data_size) OVERRIDE; bool IsInitCompleted() const OVERRIDE; bool IsHandshakePending() const OVERRIDE; + bool GetCertificateDueDate(time_t& due_date) const OVERRIDE; + bool HasCertificate() const OVERRIDE; size_t get_max_block_size(size_t mtu) const OVERRIDE; std::string LastError() const OVERRIDE; void ResetConnection() OVERRIDE; @@ -101,6 +103,22 @@ class CryptoManagerImpl : public CryptoManager { std::string GetTextBy(X509_NAME* name, int object) const; + /** + * @brief Pulls number stored in buffer of chars + * and returns it as integer + * @param buf where symbols stored + * @param idx index of required char to be converted + * @return number in integer representation + */ + int get_number_from_char_buf(char* buf, int* idx) const; + /** + * @brief Converts time from ASN1 format (used in OpenSSL) + * to time_t data type + * @param time_to_convert time to be converted + * @return time in time_t format + */ + time_t convert_asn1_time_to_time_t(ASN1_TIME* time_to_convert) const; + SSL* connection_; BIO* bioIn_; BIO* bioOut_; @@ -128,23 +146,65 @@ class CryptoManagerImpl : public CryptoManager { SSLContext* CreateSSLContext() OVERRIDE; void ReleaseSSLContext(SSLContext* context) OVERRIDE; std::string LastError() const OVERRIDE; - virtual bool IsCertificateUpdateRequired() const OVERRIDE; + bool IsCertificateUpdateRequired( + const time_t system_time, const time_t certificates_time) const OVERRIDE; virtual const CryptoManagerSettings& get_settings() const OVERRIDE; private: + bool AreForceProtectionSettingsCorrect() const; bool set_certificate(const std::string& cert_data); - int pull_number_from_buf(char* buf, int* idx); - void asn1_time_to_tm(ASN1_TIME* time); + /** + * @brief Saves new certificate data on the file system + * @param cert_data certificate data in PEM format + * @return true if new certificate data was successfully saved on the file + * system, otherwise returns false + */ + bool SaveCertificateData(const std::string& cert_data) const; + + /** + * @brief Updates certificate and private key for the current SSL context + * @param certificate new certificate to update + * @param key new private key to update + * @return true if certificate and private key were updated successfully, + * otherwise returns false + */ + bool UpdateModuleCertificateData(X509* certificate, EVP_PKEY* key); + + /** + * @brief Loads X509 certificate from file specified in CryptoManagerSettings + * @return returns pointer to the loaded X509 certificate in case of success + * otherwise returns NULL + */ + X509* LoadModuleCertificateFromFile(); + + /** + * @brief Loads private key from file specified in CryptoManagerSettings + * @return returns pointer to the loaded private key in case of success + * otherwise returns NULL + */ + EVP_PKEY* LoadModulePrivateKeyFromFile(); + + /** + * @brief Saves new X509 certificate data to file specified in + * CryptoManagerSettings + * @param certificate new X509 certificate data + * @return true if certificate data was saved to the file system otherwise + * returns false + */ + bool SaveModuleCertificateToFile(X509* certificate) const; /** - * @brief Sets initial certificate datetime + * @brief Saves new private key data to file specified in + * CryptoManagerSettings + * @param key new private key data + * @return true if private key data was saved to the file system otherwise + * returns false */ - void InitCertExpTime(); + bool SaveModuleKeyToFile(EVP_PKEY* key) const; const utils::SharedPtr<const CryptoManagerSettings> settings_; SSL_CTX* context_; - mutable struct tm expiration_time_; static uint32_t instance_count_; static sync_primitives::Lock instance_lock_; DISALLOW_COPY_AND_ASSIGN(CryptoManagerImpl); diff --git a/src/components/security_manager/include/security_manager/crypto_manager_settings_impl.h b/src/components/security_manager/include/security_manager/crypto_manager_settings_impl.h index 1e4699b77a..f20d3e4034 100644 --- a/src/components/security_manager/include/security_manager/crypto_manager_settings_impl.h +++ b/src/components/security_manager/include/security_manager/crypto_manager_settings_impl.h @@ -17,6 +17,7 @@ class CryptoManagerSettingsImpl : public CryptoManagerSettings { return profile_.ssl_mode() == "SERVER" ? security_manager::SERVER : security_manager::CLIENT; } + Protocol security_manager_protocol_name() const OVERRIDE { CREATE_LOGGERPTR_LOCAL(logger_, "SecurityManager") @@ -33,33 +34,59 @@ class CryptoManagerSettingsImpl : public CryptoManagerSettings { if (protocol_str == "SSLv3") { return security_manager::SSLv3; } + if (protocol_str == "DTLSv1.0") { + return security_manager::DTLSv1; + } + LOG4CXX_ERROR( logger_, "Unknown protocol: " << profile_.security_manager_protocol_name()); return static_cast<security_manager::Protocol>(-1); } + bool verify_peer() const OVERRIDE { return profile_.verify_peer(); } + const std::string& certificate_data() const OVERRIDE { return certificate_data_; } + const std::string& ciphers_list() const OVERRIDE { return profile_.ciphers_list(); } + const std::string& ca_cert_path() const OVERRIDE { return profile_.ca_cert_path(); } + + const std::string& module_cert_path() const OVERRIDE { + return profile_.cert_path(); + } + + const std::string& module_key_path() const OVERRIDE { + return profile_.key_path(); + } + size_t update_before_hours() const OVERRIDE { return profile_.update_before_hours(); } + size_t maximum_payload_size() const OVERRIDE { return profile_.maximum_payload_size(); } + const std::vector<int>& force_protected_service() const { + return profile_.force_protected_service(); + } + + const std::vector<int>& force_unprotected_service() const { + return profile_.force_unprotected_service(); + } + private: const profile::Profile& profile_; const std::string certificate_data_; }; -} +} // namespace security_manager #endif // SRC_COMPONENTS_SECURITY_MANAGER_INCLUDE_SECURITY_MANAGER_CRYPTO_MANAGER_SETTINGS_IMPL_H_ diff --git a/src/components/security_manager/include/security_manager/security_manager_impl.h b/src/components/security_manager/include/security_manager/security_manager_impl.h index 469b97d1e1..70b87de0ef 100644 --- a/src/components/security_manager/include/security_manager/security_manager_impl.h +++ b/src/components/security_manager/include/security_manager/security_manager_impl.h @@ -35,6 +35,8 @@ #include <list> #include <string> +#include <set> +#include <memory> #include "utils/macro.h" #include "utils/message_queue.h" @@ -44,6 +46,7 @@ #include "security_manager/security_query.h" #include "protocol_handler/protocol_handler.h" #include "protocol/common.h" +#include "utils/system_time_handler.h" namespace security_manager { /** @@ -67,12 +70,21 @@ typedef threads::MessageLoopThread<SecurityMessageQueue> SecurityMessageLoop; * \brief SecurityManagerImpl class implements SecurityManager interface */ class SecurityManagerImpl : public SecurityManager, - public SecurityMessageLoop::Handler { + public SecurityMessageLoop::Handler, + public utils::SystemTimeListener { public: /** * \brief Constructor + * \param system_time_handler allows to work with system time. */ - SecurityManagerImpl(); + explicit SecurityManagerImpl( + std::unique_ptr<utils::SystemTimeHandler>&& system_time_handler); + + /** + * \brief Destructor + */ + ~SecurityManagerImpl(); + /** * \brief Add received from Mobile Application message * Overriden ProtocolObserver::OnMessageReceived method @@ -131,9 +143,11 @@ class SecurityManagerImpl : public SecurityManager, * Do not notify listeners, send security error on occure * \param connection_key Unique key used by other components as session * identifier + * @param cc_strategy - SSL context creation strategy * @return new \c SSLContext or \c NULL on any error */ - SSLContext* CreateSSLContext(const uint32_t& connection_key) OVERRIDE; + SSLContext* CreateSSLContext(const uint32_t& connection_key, + ContextCreationStrategy cc_strategy) OVERRIDE; /** * \brief Start handshake as SSL client @@ -141,16 +155,33 @@ class SecurityManagerImpl : public SecurityManager, void StartHandshake(uint32_t connection_key) OVERRIDE; /** + * @brief PostponeHandshake allows to postpone handshake. It notifies + * cryptomanager that certificate should be updated and adds specified + * connection key to the list of the certificate awaiting connections. + * @param connection_key the identifier for connection to postpone handshake. + */ + void PostponeHandshake(const uint32_t connection_key) OVERRIDE; + + /** * @brief Checks whether certificate should be updated + * @param connection_key the connection identifier to check certificate for. * @return true if certificate should be updated otherwise false */ - bool IsCertificateUpdateRequired() OVERRIDE; + bool IsCertificateUpdateRequired(const uint32_t connection_key) OVERRIDE; + + /** + * @brief Checks whether system time ready notification + * was received from hmi + * @return true if received otherwise false + */ + bool IsSystemTimeProviderReady() const OVERRIDE; /** * \brief Add/Remove for SecurityManagerListener */ void AddListener(SecurityManagerListener* const listener) OVERRIDE; void RemoveListener(SecurityManagerListener* const listener) OVERRIDE; + /** * \brief Notifiers for listeners * \param connection_key Unique key used by other components as session @@ -173,6 +204,11 @@ class SecurityManagerImpl : public SecurityManager, void NotifyOnCertificateUpdateRequired() OVERRIDE; /** + * @brief Notify all listeners that handshake was failed + */ + void NotifyListenersOnHandshakeFailed() OVERRIDE; + + /** * @brief Check is policy certificate data is empty * @return true if policy certificate data is not empty otherwise false */ @@ -217,6 +253,39 @@ class SecurityManagerImpl : public SecurityManager, */ void SendQuery(const SecurityQuery& query, const uint32_t connection_key); + /** + * @brief OnCertificateUpdated allows to obtain notification when certificate + * has been updated with policy table update. Pass this certificate to crypto + * manager for further processing. Also process postopnes handshake for the + * certain connection key. + * + * @param data the certificates content. + * @return always true. + */ + bool OnCertificateUpdated(const std::string& data) OVERRIDE; + + /** + * @brief ResumeHandshake allows to resume handshake after certificate has + * been updated. + * @param connection_key the connection identifier to start handshake. + */ + void ResumeHandshake(uint32_t connection_key); + + /** + * @brief ProceedHandshake starts the handshake process. + * @param ssl_context ssl context for the handshake. COntains certificate, + * keys, etc. + * @param connection_key the connection identifier to process handshake. + */ + void ProceedHandshake(SSLContext* ssl_context, uint32_t connection_key); + + /** + * @brief OnSystemTimeArrived method which notifies + * crypto manager with updated time in order to check certificate validity + * @param utc_time the current system time. + */ + void OnSystemTimeArrived(const time_t utc_time) OVERRIDE; + // Thread that pumps handshake data SecurityMessageLoop security_messages_; @@ -235,7 +304,17 @@ class SecurityManagerImpl : public SecurityManager, /** *\brief List of listeners for notify handshake done result */ + std::list<SecurityManagerListener*> listeners_; + + std::unique_ptr<utils::SystemTimeHandler> system_time_handler_; + sync_primitives::Lock connections_lock_; + std::set<uint32_t> awaiting_certificate_connections_; + std::set<uint32_t> awaiting_time_connections_; + + mutable sync_primitives::Lock waiters_lock_; + volatile bool waiting_for_certificate_; + volatile bool waiting_for_time_; DISALLOW_COPY_AND_ASSIGN(SecurityManagerImpl); }; } // namespace security_manager diff --git a/src/components/security_manager/src/crypto_manager_impl.cc b/src/components/security_manager/src/crypto_manager_impl.cc index f3dfa8bb1d..1506382bce 100644 --- a/src/components/security_manager/src/crypto_manager_impl.cc +++ b/src/components/security_manager/src/crypto_manager_impl.cc @@ -41,6 +41,7 @@ #include <iostream> #include <stdio.h> #include <ctime> +#include <algorithm> #include "security_manager/security_manager.h" #include "utils/logger.h" @@ -63,7 +64,12 @@ namespace { int debug_callback(int preverify_ok, X509_STORE_CTX* ctx) { if (!preverify_ok) { const int error = X509_STORE_CTX_get_error(ctx); - UNUSED(error); + if (error == X509_V_ERR_CERT_NOT_YET_VALID || + error == X509_V_ERR_CERT_HAS_EXPIRED) { + // return success result code instead of error because start + // and expiration cert dates will be checked by SDL + return 1; + } LOG4CXX_WARN(logger_, "Certificate verification failed with error " << error << " \"" << X509_verify_cert_error_string(error) @@ -93,7 +99,6 @@ CryptoManagerImpl::CryptoManagerImpl( OpenSSL_add_all_algorithms(); SSL_library_init(); } - InitCertExpTime(); } CryptoManagerImpl::~CryptoManagerImpl() { @@ -113,10 +118,35 @@ CryptoManagerImpl::~CryptoManagerImpl() { } } +bool CryptoManagerImpl::AreForceProtectionSettingsCorrect() const { + LOG4CXX_AUTO_TRACE(logger_); + const std::vector<int>& forced_unprotected_services = + get_settings().force_unprotected_service(); + const std::vector<int>& forced_protected_services = + get_settings().force_protected_service(); + + for (auto& item : forced_protected_services) { + if (0 == item) { + continue; + } + + if (std::find(forced_unprotected_services.begin(), + forced_unprotected_services.end(), + item) != forced_unprotected_services.end()) { + return false; + } + } + return true; +} + bool CryptoManagerImpl::Init() { LOG4CXX_AUTO_TRACE(logger_); const Mode mode = get_settings().security_manager_mode(); + if (!AreForceProtectionSettingsCorrect()) { + LOG4CXX_DEBUG(logger_, "Force protection settings of ini file are wrong!"); + return false; + } const bool is_server = (mode == SERVER); if (is_server) { LOG4CXX_DEBUG(logger_, "Server mode"); @@ -133,7 +163,7 @@ bool CryptoManagerImpl::Init() { #if OPENSSL_VERSION_NUMBER < CONST_SSL_METHOD_MINIMAL_VERSION SSL_METHOD* method; #else - const SSL_METHOD* method; + const SSL_METHOD* method = NULL; #endif switch (get_settings().security_manager_protocol_name()) { case SSLv3: @@ -141,13 +171,16 @@ bool CryptoManagerImpl::Init() { LOG4CXX_WARN(logger_, "OpenSSL does not support SSL3 protocol"); return false; #else + LOG4CXX_DEBUG(logger_, "SSLv3 is used"); method = is_server ? SSLv3_server_method() : SSLv3_client_method(); break; #endif case TLSv1: + LOG4CXX_DEBUG(logger_, "TLSv1 is used"); method = is_server ? TLSv1_server_method() : TLSv1_client_method(); break; case TLSv1_1: + LOG4CXX_DEBUG(logger_, "TLSv1_1 is used"); #if OPENSSL_VERSION_NUMBER < TLS1_1_MINIMAL_VERSION LOG4CXX_WARN( logger_, @@ -158,6 +191,7 @@ bool CryptoManagerImpl::Init() { #endif break; case TLSv1_2: + LOG4CXX_DEBUG(logger_, "TLSv1_2 is used"); #if OPENSSL_VERSION_NUMBER < TLS1_1_MINIMAL_VERSION LOG4CXX_WARN( logger_, @@ -167,6 +201,10 @@ bool CryptoManagerImpl::Init() { method = is_server ? TLSv1_2_server_method() : TLSv1_2_client_method(); #endif break; + case DTLSv1: + LOG4CXX_DEBUG(logger_, "DTLSv1 is used"); + method = is_server ? DTLSv1_server_method() : DTLSv1_client_method(); + break; default: LOG4CXX_ERROR(logger_, "Unknown protocol: " @@ -183,7 +221,7 @@ bool CryptoManagerImpl::Init() { // Disable SSL2 as deprecated SSL_CTX_set_options(context_, SSL_OP_NO_SSLv2); - set_certificate(get_settings().certificate_data()); + SaveCertificateData(get_settings().certificate_data()); if (get_settings().ciphers_list().empty()) { LOG4CXX_WARN(logger_, "Empty ciphers list"); @@ -216,6 +254,21 @@ bool CryptoManagerImpl::Init() { << '"'); } + LOG4CXX_DEBUG(logger_, "Setting up module certificate and private key"); + + X509* module_certificate = LoadModuleCertificateFromFile(); + utils::ScopeGuard certificate_guard = + utils::MakeGuard(X509_free, module_certificate); + UNUSED(certificate_guard); + + EVP_PKEY* module_key = LoadModulePrivateKeyFromFile(); + utils::ScopeGuard key_guard = utils::MakeGuard(EVP_PKEY_free, module_key); + UNUSED(key_guard); + + if (!UpdateModuleCertificateData(module_certificate, module_key)) { + LOG4CXX_WARN(logger_, "Failed to update module key and certificate"); + } + guard.Dismiss(); const int verify_mode = @@ -235,17 +288,33 @@ bool CryptoManagerImpl::OnCertificateUpdated(const std::string& data) { return false; } - return set_certificate(data); + if (!SaveCertificateData(data)) { + LOG4CXX_ERROR(logger_, "Failed to save certificate data"); + return false; + } + + X509* module_certificate = LoadModuleCertificateFromFile(); + EVP_PKEY* module_key = LoadModulePrivateKeyFromFile(); + + utils::ScopeGuard certificate_guard = + utils::MakeGuard(X509_free, module_certificate); + UNUSED(certificate_guard); + + utils::ScopeGuard key_guard = utils::MakeGuard(EVP_PKEY_free, module_key); + UNUSED(key_guard); + + return UpdateModuleCertificateData(module_certificate, module_key); } SSLContext* CryptoManagerImpl::CreateSSLContext() { - if (context_ == NULL) { + if (NULL == context_) { return NULL; } SSL* conn = SSL_new(context_); - if (conn == NULL) + if (NULL == conn) { return NULL; + } if (get_settings().security_manager_mode() == SERVER) { SSL_set_accept_state(conn); @@ -269,24 +338,17 @@ std::string CryptoManagerImpl::LastError() const { return std::string(reason ? reason : ""); } -bool CryptoManagerImpl::IsCertificateUpdateRequired() const { +bool CryptoManagerImpl::IsCertificateUpdateRequired( + const time_t system_time, const time_t certificates_time) const { LOG4CXX_AUTO_TRACE(logger_); - const time_t cert_date = mktime(&expiration_time_); + const double seconds = difftime(certificates_time, system_time); - if (cert_date == -1) { - LOG4CXX_WARN(logger_, - "The certifiacte expiration time cannot be represented."); - return false; - } - const time_t now = time(NULL); - const double seconds = difftime(cert_date, now); + LOG4CXX_DEBUG( + logger_, "Certificate UTC time: " << asctime(gmtime(&certificates_time))); - LOG4CXX_DEBUG(logger_, - "Certificate expiration time: " << asctime(&expiration_time_)); - LOG4CXX_DEBUG(logger_, - "Host time: " << asctime(localtime(&now)) - << ". Seconds before expiration: " << seconds); + LOG4CXX_DEBUG(logger_, "Host UTC time: " << asctime(gmtime(&system_time))); + LOG4CXX_DEBUG(logger_, "Seconds before expiration: " << seconds); if (seconds < 0) { LOG4CXX_WARN(logger_, "Certificate is already expired."); return true; @@ -300,7 +362,8 @@ const CryptoManagerSettings& CryptoManagerImpl::get_settings() const { return *settings_; } -bool CryptoManagerImpl::set_certificate(const std::string& cert_data) { +bool CryptoManagerImpl::SaveCertificateData( + const std::string& cert_data) const { LOG4CXX_AUTO_TRACE(logger_); if (cert_data.empty()) { @@ -315,100 +378,162 @@ bool CryptoManagerImpl::set_certificate(const std::string& cert_data) { UNUSED(bio_guard) X509* cert = NULL; - PEM_read_bio_X509(bio_cert, &cert, 0, 0); + if (!PEM_read_bio_X509(bio_cert, &cert, 0, 0)) { + LOG4CXX_WARN(logger_, "Could not read certificate data: " << LastError()); + return false; + } - EVP_PKEY* pkey = NULL; - if (1 == BIO_reset(bio_cert)) { - PEM_read_bio_PrivateKey(bio_cert, &pkey, 0, 0); - } else { + utils::ScopeGuard cert_guard = utils::MakeGuard(X509_free, cert); + UNUSED(cert_guard); + + if (1 != BIO_reset(bio_cert)) { LOG4CXX_WARN(logger_, "Unabled to reset BIO in order to read private key, " << LastError()); } - if (NULL == cert || NULL == pkey) { - LOG4CXX_WARN(logger_, "Either certificate or key not valid."); + EVP_PKEY* pkey = NULL; + if (!PEM_read_bio_PrivateKey(bio_cert, &pkey, 0, 0)) { + LOG4CXX_WARN(logger_, "Could not read private key data: " << LastError()); return false; } - if (!SSL_CTX_use_certificate(context_, cert)) { - LOG4CXX_WARN(logger_, "Could not use certificate: " << LastError()); - return false; - } + utils::ScopeGuard key_guard = utils::MakeGuard(EVP_PKEY_free, pkey); + UNUSED(key_guard); - asn1_time_to_tm(X509_get_notAfter(cert)); + return SaveModuleCertificateToFile(cert) && SaveModuleKeyToFile(pkey); +} - if (!SSL_CTX_use_PrivateKey(context_, pkey)) { - LOG4CXX_ERROR(logger_, "Could not use key: " << LastError()); - return false; +bool CryptoManagerImpl::UpdateModuleCertificateData(X509* certificate, + EVP_PKEY* key) { + LOG4CXX_AUTO_TRACE(logger_); + if (certificate) { + if (!SSL_CTX_use_certificate(context_, certificate)) { + LOG4CXX_WARN(logger_, "Could not use certificate: " << LastError()); + return false; + } } - if (!SSL_CTX_check_private_key(context_)) { - LOG4CXX_ERROR(logger_, "Could not use certificate: " << LastError()); - return false; - } + if (key) { + if (!SSL_CTX_use_PrivateKey(context_, key)) { + LOG4CXX_ERROR(logger_, "Could not use key: " << LastError()); + return false; + } - X509_STORE* store = SSL_CTX_get_cert_store(context_); - if (store) { - X509* extra_cert = NULL; - while ((extra_cert = PEM_read_bio_X509(bio_cert, NULL, 0, 0))) { - if (extra_cert != cert) { - LOG4CXX_DEBUG(logger_, - "Added new certificate to store: " << extra_cert); - X509_STORE_add_cert(store, extra_cert); - } + if (!SSL_CTX_check_private_key(context_)) { + LOG4CXX_ERROR(logger_, "Private key is invalid: " << LastError()); + return false; } } - LOG4CXX_DEBUG(logger_, "Certificate and key successfully updated"); + LOG4CXX_DEBUG(logger_, "Certificate and key are successfully updated"); return true; } -int CryptoManagerImpl::pull_number_from_buf(char* buf, int* idx) { - if (!idx) { - return 0; +X509* CryptoManagerImpl::LoadModuleCertificateFromFile() { + LOG4CXX_AUTO_TRACE(logger_); + + const std::string cert_path = get_settings().module_cert_path(); + BIO* bio_cert = BIO_new_file(cert_path.c_str(), "r"); + if (!bio_cert) { + LOG4CXX_WARN(logger_, + "Failed to open " << cert_path << " file: " << LastError()); + return NULL; + } + + utils::ScopeGuard bio_guard = utils::MakeGuard(BIO_free, bio_cert); + UNUSED(bio_guard); + + X509* module_certificate = NULL; + if (!PEM_read_bio_X509(bio_cert, &module_certificate, NULL, NULL)) { + LOG4CXX_ERROR(logger_, + "Failed to read certificate data from file: " << LastError()); + return NULL; } - const int val = ((buf[*idx] - '0') * 10) + buf[(*idx) + 1] - '0'; - *idx = *idx + 2; - return val; + LOG4CXX_DEBUG(logger_, + "Module certificate was loaded: " << module_certificate); + + return module_certificate; } -void CryptoManagerImpl::asn1_time_to_tm(ASN1_TIME* time) { - char* buf = (char*)time->data; - int index = 0; - const int year = pull_number_from_buf(buf, &index); - if (V_ASN1_GENERALIZEDTIME == time->type) { - expiration_time_.tm_year = - (year * 100 - 1900) + pull_number_from_buf(buf, &index); - } else { - expiration_time_.tm_year = year < 50 ? year + 100 : year; +EVP_PKEY* CryptoManagerImpl::LoadModulePrivateKeyFromFile() { + LOG4CXX_AUTO_TRACE(logger_); + + const std::string key_path = get_settings().module_key_path(); + BIO* bio_key = BIO_new_file(key_path.c_str(), "r"); + if (!bio_key) { + LOG4CXX_WARN(logger_, + "Failed to open " << key_path << " file: " << LastError()); + return NULL; + } + + utils::ScopeGuard bio_guard = utils::MakeGuard(BIO_free, bio_key); + UNUSED(bio_guard); + + EVP_PKEY* module_key = NULL; + if (!PEM_read_bio_PrivateKey(bio_key, &module_key, NULL, NULL)) { + LOG4CXX_ERROR(logger_, + "Failed to read private key data from file: " << LastError()); + return NULL; } + LOG4CXX_DEBUG(logger_, "Module private key was loaded: " << module_key); - const int mon = pull_number_from_buf(buf, &index); - const int day = pull_number_from_buf(buf, &index); - const int hour = pull_number_from_buf(buf, &index); - const int mn = pull_number_from_buf(buf, &index); + return module_key; +} - expiration_time_.tm_mon = mon - 1; - expiration_time_.tm_mday = day; - expiration_time_.tm_hour = hour; - expiration_time_.tm_min = mn; +bool CryptoManagerImpl::SaveModuleCertificateToFile(X509* certificate) const { + LOG4CXX_AUTO_TRACE(logger_); - if (buf[index] == 'Z') { - expiration_time_.tm_sec = 0; + if (!certificate) { + LOG4CXX_WARN(logger_, "Empty certificate. Saving will be skipped"); + return false; } - if ((buf[index] == '+') || (buf[index] == '-')) { - const int mn = pull_number_from_buf(buf, &index); - const int mn1 = pull_number_from_buf(buf, &index); - expiration_time_.tm_sec = (mn * 3600) + (mn1 * 60); - } else { - const int sec = pull_number_from_buf(buf, &index); - expiration_time_.tm_sec = sec; + + const std::string cert_path = get_settings().module_cert_path(); + BIO* bio_cert = BIO_new_file(cert_path.c_str(), "w"); + if (!bio_cert) { + LOG4CXX_ERROR(logger_, + "Failed to open " << cert_path << " file: " << LastError()); + return false; + } + + utils::ScopeGuard bio_guard = utils::MakeGuard(BIO_free, bio_cert); + UNUSED(bio_guard); + + if (!PEM_write_bio_X509(bio_cert, certificate)) { + LOG4CXX_ERROR(logger_, + "Failed to write certificate to file: " << LastError()); + return false; } + + return true; } -void CryptoManagerImpl::InitCertExpTime() { - strptime("1 Jan 1970 00:00:00", "%d %b %Y %H:%M:%S", &expiration_time_); +bool CryptoManagerImpl::SaveModuleKeyToFile(EVP_PKEY* key) const { + LOG4CXX_AUTO_TRACE(logger_); + + if (!key) { + LOG4CXX_WARN(logger_, "Empty private key. Saving will be skipped"); + return false; + } + + const std::string key_path = get_settings().module_key_path(); + BIO* bio_key = BIO_new_file(key_path.c_str(), "w"); + if (!bio_key) { + LOG4CXX_ERROR(logger_, + "Failed to open " << key_path << " file: " << LastError()); + return false; + } + + utils::ScopeGuard bio_guard = utils::MakeGuard(BIO_free, bio_key); + UNUSED(bio_guard); + + if (!PEM_write_bio_PrivateKey(bio_key, key, NULL, NULL, 0, NULL, NULL)) { + LOG4CXX_ERROR(logger_, "Failed to write key to file: " << LastError()); + return false; + } + + return true; } } // namespace security_manager diff --git a/src/components/security_manager/src/security_manager_impl.cc b/src/components/security_manager/src/security_manager_impl.cc index 1853b218b4..1faaddee1c 100644 --- a/src/components/security_manager/src/security_manager_impl.cc +++ b/src/components/security_manager/src/security_manager_impl.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Ford Motor Company + * Copyright (c) 2018, Ford Motor Company * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -31,11 +31,13 @@ */ #include "security_manager/security_manager_impl.h" +#include <functional> #include "security_manager/crypto_manager_impl.h" #include "protocol_handler/protocol_packet.h" #include "utils/logger.h" #include "utils/byte_order.h" #include "json/json.h" +#include "utils/helpers.h" namespace security_manager { @@ -44,11 +46,22 @@ CREATE_LOGGERPTR_GLOBAL(logger_, "SecurityManager") static const char* kErrId = "id"; static const char* kErrText = "text"; -SecurityManagerImpl::SecurityManagerImpl() +SecurityManagerImpl::SecurityManagerImpl( + std::unique_ptr<utils::SystemTimeHandler>&& system_time_handler) : security_messages_("SecurityManager", this) , session_observer_(NULL) , crypto_manager_(NULL) - , protocol_handler_(NULL) {} + , protocol_handler_(NULL) + , system_time_handler_(std::move(system_time_handler)) + , waiting_for_certificate_(false) + , waiting_for_time_(false) { + DCHECK(system_time_handler_); + system_time_handler_->SubscribeOnSystemTime(this); +} + +SecurityManagerImpl::~SecurityManagerImpl() { + system_time_handler_->UnsubscribeFromSystemTime(this); +} void SecurityManagerImpl::OnMessageReceived( const ::protocol_handler::RawMessagePtr message) { @@ -136,19 +149,23 @@ void SecurityManagerImpl::Handle(const SecurityMessage message) { } security_manager::SSLContext* SecurityManagerImpl::CreateSSLContext( - const uint32_t& connection_key) { + const uint32_t& connection_key, ContextCreationStrategy cc_strategy) { LOG4CXX_INFO(logger_, "ProtectService processing"); DCHECK(session_observer_); DCHECK(crypto_manager_); - security_manager::SSLContext* ssl_context = session_observer_->GetSSLContext( - connection_key, protocol_handler::kControl); - // return exists SSLCOntext for current connection/session - if (ssl_context) { - return ssl_context; + if (kUseExisting == cc_strategy) { + security_manager::SSLContext* ssl_context = + session_observer_->GetSSLContext(connection_key, + protocol_handler::kControl); + // If SSLContext for current connection/session exists - return it + if (ssl_context) { + return ssl_context; + } } - ssl_context = crypto_manager_->CreateSSLContext(); + security_manager::SSLContext* ssl_context = + crypto_manager_->CreateSSLContext(); if (!ssl_context) { const std::string error_text("CryptoManager could not create SSL context."); LOG4CXX_ERROR(logger_, error_text); @@ -172,6 +189,40 @@ security_manager::SSLContext* SecurityManagerImpl::CreateSSLContext( return ssl_context; } +void SecurityManagerImpl::PostponeHandshake(const uint32_t connection_key) { + LOG4CXX_TRACE(logger_, "Handshake postponed"); + sync_primitives::AutoLock lock(connections_lock_); + if (waiting_for_certificate_) { + awaiting_certificate_connections_.insert(connection_key); + } + if (waiting_for_time_) { + awaiting_time_connections_.insert(connection_key); + } +} + +void SecurityManagerImpl::ResumeHandshake(uint32_t connection_key) { + LOG4CXX_TRACE(logger_, "Handshake resumed"); + + security_manager::SSLContext* ssl_context = + CreateSSLContext(connection_key, kForceRecreation); + + if (!ssl_context) { + LOG4CXX_WARN(logger_, + "Unable to resume handshake. No SSL context for key " + << connection_key); + return; + } + + ssl_context->ResetConnection(); + if (!waiting_for_certificate_ && !ssl_context->HasCertificate()) { + NotifyListenersOnHandshakeDone(connection_key, + SSLContext::Handshake_Result_Fail); + return; + } + + ProceedHandshake(ssl_context, connection_key); +} + void SecurityManagerImpl::StartHandshake(uint32_t connection_key) { DCHECK(session_observer_); LOG4CXX_INFO(logger_, "StartHandshake: connection_key " << connection_key); @@ -187,6 +238,35 @@ void SecurityManagerImpl::StartHandshake(uint32_t connection_key) { SSLContext::Handshake_Result_Fail); return; } + if (!ssl_context->HasCertificate()) { + LOG4CXX_ERROR(logger_, "Security certificate is absent"); + sync_primitives::AutoLock lock(waiters_lock_); + waiting_for_certificate_ = true; + NotifyOnCertificateUpdateRequired(); + } + + { + sync_primitives::AutoLock lock(waiters_lock_); + waiting_for_time_ = true; + } + + PostponeHandshake(connection_key); + system_time_handler_->QuerySystemTime(); +} + +bool SecurityManagerImpl::IsSystemTimeProviderReady() const { + return system_time_handler_->system_time_can_be_received(); +} + +void SecurityManagerImpl::ProceedHandshake( + security_manager::SSLContext* ssl_context, uint32_t connection_key) { + LOG4CXX_AUTO_TRACE(logger_); + if (!ssl_context) { + LOG4CXX_WARN(logger_, + "Unable to process handshake. No SSL context for key " + << connection_key); + return; + } if (ssl_context->IsInitCompleted()) { NotifyListenersOnHandshakeDone(connection_key, @@ -194,8 +274,33 @@ void SecurityManagerImpl::StartHandshake(uint32_t connection_key) { return; } - ssl_context->SetHandshakeContext( - session_observer_->GetHandshakeContext(connection_key)); + time_t cert_due_date; + if (!ssl_context->GetCertificateDueDate(cert_due_date)) { + LOG4CXX_ERROR(logger_, "Failed to get certificate due date!"); + return; + } + + if (crypto_manager_->IsCertificateUpdateRequired( + system_time_handler_->GetUTCTime(), cert_due_date)) { + LOG4CXX_DEBUG(logger_, "Host certificate update required"); + if (helpers::in_range(awaiting_certificate_connections_, connection_key)) { + NotifyListenersOnHandshakeDone(connection_key, + SSLContext::Handshake_Result_CertExpired); + return; + } + { + sync_primitives::AutoLock lock(waiters_lock_); + waiting_for_certificate_ = true; + } + PostponeHandshake(connection_key); + NotifyOnCertificateUpdateRequired(); + return; + } + + SSLContext::HandshakeContext handshake_context = + session_observer_->GetHandshakeContext(connection_key); + handshake_context.system_time = system_time_handler_->GetUTCTime(); + ssl_context->SetHandshakeContext(handshake_context); size_t data_size = 0; const uint8_t* data = NULL; @@ -216,9 +321,21 @@ void SecurityManagerImpl::StartHandshake(uint32_t connection_key) { } } -bool SecurityManagerImpl::IsCertificateUpdateRequired() { +bool SecurityManagerImpl::IsCertificateUpdateRequired( + const uint32_t connection_key) { LOG4CXX_AUTO_TRACE(logger_); - return crypto_manager_->IsCertificateUpdateRequired(); + security_manager::SSLContext* ssl_context = + CreateSSLContext(connection_key, kUseExisting); + DCHECK_OR_RETURN(ssl_context, true); + LOG4CXX_DEBUG(logger_, + "Set SSL context to connection_key " << connection_key); + time_t cert_due_date; + if (!ssl_context->GetCertificateDueDate(cert_due_date)) { + LOG4CXX_ERROR(logger_, "Failed to get certificate due date!"); + return true; + } + return crypto_manager_->IsCertificateUpdateRequired( + system_time_handler_->GetUTCTime(), cert_due_date); } void SecurityManagerImpl::AddListener(SecurityManagerListener* const listener) { @@ -227,7 +344,6 @@ void SecurityManagerImpl::AddListener(SecurityManagerListener* const listener) { "Invalid (NULL) pointer to SecurityManagerListener."); return; } - LOG4CXX_DEBUG(logger_, "Adding listener " << listener); listeners_.push_back(listener); } @@ -241,6 +357,37 @@ void SecurityManagerImpl::RemoveListener( listeners_.remove(listener); } +bool SecurityManagerImpl::OnCertificateUpdated(const std::string& data) { + LOG4CXX_AUTO_TRACE(logger_); + { + sync_primitives::AutoLock lock(waiters_lock_); + waiting_for_certificate_ = false; + } + crypto_manager_->OnCertificateUpdated(data); + std::for_each( + awaiting_certificate_connections_.begin(), + awaiting_certificate_connections_.end(), + std::bind1st(std::mem_fun(&SecurityManagerImpl::ResumeHandshake), this)); + + awaiting_certificate_connections_.clear(); + return true; +} + +void SecurityManagerImpl::OnSystemTimeArrived(const time_t utc_time) { + LOG4CXX_AUTO_TRACE(logger_); + { + sync_primitives::AutoLock lock(waiters_lock_); + waiting_for_time_ = false; + } + + std::for_each( + awaiting_time_connections_.begin(), + awaiting_time_connections_.end(), + std::bind1st(std::mem_fun(&SecurityManagerImpl::ResumeHandshake), this)); + + awaiting_time_connections_.clear(); +} + void SecurityManagerImpl::NotifyListenersOnHandshakeDone( const uint32_t& connection_key, SSLContext::HandshakeResult error) { LOG4CXX_AUTO_TRACE(logger_); @@ -269,6 +416,20 @@ void SecurityManagerImpl::NotifyOnCertificateUpdateRequired() { } } +void SecurityManagerImpl::NotifyListenersOnHandshakeFailed() { + LOG4CXX_AUTO_TRACE(logger_); + std::list<SecurityManagerListener*>::iterator it = listeners_.begin(); + while (it != listeners_.end()) { + if ((*it)->OnHandshakeFailed()) { + LOG4CXX_DEBUG(logger_, "Destroying listener: " << *it); + delete (*it); + it = listeners_.erase(it); + } else { + ++it; + } + } +} + bool SecurityManagerImpl::IsPolicyCertificateDataEmpty() { LOG4CXX_AUTO_TRACE(logger_); diff --git a/src/components/security_manager/src/ssl_context_impl.cc b/src/components/security_manager/src/ssl_context_impl.cc index 0b30198f4c..67be17db63 100644 --- a/src/components/security_manager/src/ssl_context_impl.cc +++ b/src/components/security_manager/src/ssl_context_impl.cc @@ -36,6 +36,7 @@ #include <map> #include <algorithm> #include <vector> +#include <time.h> #include <openssl/bio.h> #include <openssl/ssl.h> @@ -77,6 +78,7 @@ bool CryptoManagerImpl::SSLContextImpl::IsInitCompleted() const { SSLContext::HandshakeResult CryptoManagerImpl::SSLContextImpl::StartHandshake( const uint8_t** const out_data, size_t* out_data_size) { + LOG4CXX_AUTO_TRACE(logger_); is_handshake_pending_ = true; return DoHandshakeStep(NULL, 0, out_data, out_data_size); } @@ -112,6 +114,12 @@ size_t des_cbc3_sha_max_block_size(size_t mtu) { return 0; return ((mtu - 29) & 0xfffffff8) - 5; } +time_t get_time_zone_offset(time_t in_time) { + tm gmt_cert_tm = *gmtime(&in_time); + tm local_cert_tm = *localtime(&in_time); + + return mktime(&local_cert_tm) - mktime(&gmt_cert_tm); +} } // namespace std::map<std::string, CryptoManagerImpl::SSLContextImpl::BlockSizeGetter> @@ -174,6 +182,7 @@ const std::string CryptoManagerImpl::SSLContextImpl::RemoveDisallowedInfo( void CryptoManagerImpl::SSLContextImpl::PrintCertData( X509* cert, const std::string& cert_owner) { + LOG4CXX_AUTO_TRACE(logger_); if (!cert) { LOG4CXX_DEBUG(logger_, "Empty certificate data"); return; @@ -206,6 +215,7 @@ void CryptoManagerImpl::SSLContextImpl::PrintCertData( } void CryptoManagerImpl::SSLContextImpl::PrintCertInfo() { + LOG4CXX_AUTO_TRACE(logger_); PrintCertData(SSL_get_certificate(connection_), "HU's"); STACK_OF(X509)* peer_certs = SSL_get_peer_cert_chain(connection_); @@ -217,26 +227,47 @@ void CryptoManagerImpl::SSLContextImpl::PrintCertInfo() { SSLContext::HandshakeResult CryptoManagerImpl::SSLContextImpl::CheckCertContext() { + LOG4CXX_AUTO_TRACE(logger_); X509* cert = SSL_get_peer_certificate(connection_); if (!cert) { // According to the openssl documentation the peer certificate // might be ommitted for the SERVER but required for the cient. return CLIENT == mode_ ? Handshake_Result_Fail : Handshake_Result_Success; } + ASN1_TIME* notBefore = X509_get_notBefore(cert); + ASN1_TIME* notAfter = X509_get_notAfter(cert); - X509_NAME* subj_name = X509_get_subject_name(cert); + time_t start = convert_asn1_time_to_time_t(notBefore); + time_t end = convert_asn1_time_to_time_t(notAfter); - const std::string& cn = GetTextBy(subj_name, NID_commonName); - const std::string& sn = GetTextBy(subj_name, NID_serialNumber); + const double start_seconds = difftime(hsh_context_.system_time, start); + const double end_seconds = difftime(end, hsh_context_.system_time); + + if (start_seconds < 0) { + LOG4CXX_ERROR(logger_, + "Certificate is not yet valid. Time before validity " + << start_seconds << " seconds"); + return Handshake_Result_NotYetValid; + } else { + LOG4CXX_DEBUG(logger_, + "Time since certificate validity " << start_seconds + << "seconds"); + } - if (!(hsh_context_.expected_cn.CompareIgnoreCase(cn.c_str()))) { + if (end_seconds < 0) { LOG4CXX_ERROR(logger_, - "Trying to run handshake with wrong app name: " - << cn << ". Expected app name: " - << hsh_context_.expected_cn.AsMBString()); - return Handshake_Result_AppNameMismatch; + "Certificate already expired. Time after expiration " + << end_seconds << " seconds"); + return Handshake_Result_CertExpired; + } else { + LOG4CXX_DEBUG(logger_, + "Time until expiration " << end_seconds << "seconds"); } + X509_NAME* subj_name = X509_get_subject_name(cert); + + const std::string& sn = GetTextBy(subj_name, NID_serialNumber); + if (!(hsh_context_.expected_sn.CompareIgnoreCase(sn.c_str()))) { LOG4CXX_ERROR(logger_, "Trying to run handshake with wrong app id: " @@ -247,6 +278,60 @@ CryptoManagerImpl::SSLContextImpl::CheckCertContext() { return Handshake_Result_Success; } +int CryptoManagerImpl::SSLContextImpl::get_number_from_char_buf( + char* buf, int* idx) const { + if (!idx) { + return 0; + } + const int val = ((buf[*idx] - '0') * 10) + buf[(*idx) + 1] - '0'; + *idx = *idx + 2; + return val; +} + +time_t CryptoManagerImpl::SSLContextImpl::convert_asn1_time_to_time_t( + ASN1_TIME* time_to_convert) const { + struct tm cert_time; + memset(&cert_time, 0, sizeof(struct tm)); + // the minimum value for day of month is 1, otherwise exception will be thrown + cert_time.tm_mday = 1; + char* buf = reinterpret_cast<char*>(time_to_convert->data); + int index = 0; + const int year = get_number_from_char_buf(buf, &index); + if (V_ASN1_GENERALIZEDTIME == time_to_convert->type) { + cert_time.tm_year = + (year * 100 - 1900) + get_number_from_char_buf(buf, &index); + } else { + cert_time.tm_year = year < 50 ? year + 100 : year; + } + + const int mon = get_number_from_char_buf(buf, &index); + const int day = get_number_from_char_buf(buf, &index); + const int hour = get_number_from_char_buf(buf, &index); + const int mn = get_number_from_char_buf(buf, &index); + + cert_time.tm_mon = mon - 1; + cert_time.tm_mday = day; + cert_time.tm_hour = hour; + cert_time.tm_min = mn; + + if (buf[index] == 'Z') { + cert_time.tm_sec = 0; + } + if ((buf[index] == '+') || (buf[index] == '-')) { + const int mn = get_number_from_char_buf(buf, &index); + const int mn1 = get_number_from_char_buf(buf, &index); + cert_time.tm_sec = (mn * 3600) + (mn1 * 60); + } else { + const int sec = get_number_from_char_buf(buf, &index); + cert_time.tm_sec = sec; + } + + const time_t local_cert_time = mktime(&cert_time); + const time_t time_offset = get_time_zone_offset(local_cert_time); + + return local_cert_time + time_offset; +} + bool CryptoManagerImpl::SSLContextImpl::ReadHandshakeData( const uint8_t** const out_data, size_t* out_data_size) { LOG4CXX_AUTO_TRACE(logger_); @@ -288,7 +373,9 @@ bool CryptoManagerImpl::SSLContextImpl::WriteHandshakeData( SSLContext::HandshakeResult CryptoManagerImpl::SSLContextImpl::PerformHandshake() { + LOG4CXX_AUTO_TRACE(logger_); const int handshake_result = SSL_do_handshake(connection_); + LOG4CXX_TRACE(logger_, "Handshake result: " << handshake_result); if (handshake_result == 1) { const HandshakeResult result = CheckCertContext(); if (result != Handshake_Result_Success) { @@ -307,6 +394,7 @@ CryptoManagerImpl::SSLContextImpl::PerformHandshake() { is_handshake_pending_ = false; } else if (handshake_result == 0) { + LOG4CXX_DEBUG(logger_, "SSL handshake failed"); SSL_clear(connection_); is_handshake_pending_ = false; return Handshake_Result_Fail; @@ -403,25 +491,32 @@ bool CryptoManagerImpl::SSLContextImpl::Decrypt(const uint8_t* const in_data, size_t in_data_size, const uint8_t** const out_data, size_t* out_data_size) { + LOG4CXX_AUTO_TRACE(logger_); sync_primitives::AutoLock locker(bio_locker); if (!SSL_is_init_finished(connection_)) { + LOG4CXX_ERROR(logger_, "SSL initilization is not finished"); return false; } - if (!in_data || !in_data_size) { + if (!in_data || (0 == in_data_size)) { + LOG4CXX_ERROR(logger_, "IN data ptr or IN data size is 0"); return false; } + BIO_write(bioIn_, in_data, in_data_size); int len = BIO_ctrl_pending(bioFilter_); + ptrdiff_t offset = 0; *out_data_size = 0; - while (len) { + *out_data = NULL; + while (len > 0) { EnsureBufferSizeEnough(len + offset); len = BIO_read(bioFilter_, buffer_ + offset, len); // TODO(EZamakhov): investigate BIO_read return 0, -1 and -2 meanings if (len <= 0) { // Reset filter and connection deinitilization instead + LOG4CXX_ERROR(logger_, "Read error occured. Read data lenght : " << len); BIO_ctrl(bioFilter_, BIO_CTRL_RESET, 0, NULL); return false; } @@ -447,6 +542,25 @@ bool CryptoManagerImpl::SSLContextImpl::IsHandshakePending() const { return is_handshake_pending_; } +bool CryptoManagerImpl::SSLContextImpl::GetCertificateDueDate( + time_t& due_date) const { + LOG4CXX_AUTO_TRACE(logger_); + + X509* cert = SSL_get_certificate(connection_); + if (!cert) { + LOG4CXX_DEBUG(logger_, "Get certificate failed."); + return false; + } + + due_date = convert_asn1_time_to_time_t(X509_get_notAfter(cert)); + + return true; +} + +bool CryptoManagerImpl::SSLContextImpl::HasCertificate() const { + return SSL_get_certificate(connection_) != NULL; +} + CryptoManagerImpl::SSLContextImpl::~SSLContextImpl() { SSL_shutdown(connection_); SSL_free(connection_); diff --git a/src/components/security_manager/test/crypto_manager_impl_test.cc b/src/components/security_manager/test/crypto_manager_impl_test.cc index b30684e5f6..74b071793d 100644 --- a/src/components/security_manager/test/crypto_manager_impl_test.cc +++ b/src/components/security_manager/test/crypto_manager_impl_test.cc @@ -52,6 +52,10 @@ namespace { const size_t kUpdatesBeforeHour = 24; const std::string kAllCiphers = "ALL"; const std::string kCaCertPath = ""; +const uint32_t kServiceNumber = 2u; +const size_t kMaxSizeVector = 1u; +const std::string kCertPath = "certificate.crt"; +const std::string kPrivateKeyPath = "private.key"; #ifdef __QNXNTO__ const std::string kFordCipher = SSL3_TXT_RSA_DES_192_CBC3_SHA; @@ -89,6 +93,8 @@ class CryptoManagerTest : public testing::Test { utils::MakeShared<MockCryptoManagerSettings>(); crypto_manager_ = utils::MakeShared<CryptoManagerImpl>(mock_security_manager_settings_); + forced_protected_services_.reserve(kMaxSizeVector); + forced_unprotected_services_.reserve(kMaxSizeVector); } void InitSecurityManager() { @@ -101,6 +107,10 @@ class CryptoManagerTest : public testing::Test { void SetInitialValues(security_manager::Mode mode, security_manager::Protocol protocol, const std::string& cipher) { + ON_CALL(*mock_security_manager_settings_, force_unprotected_service()) + .WillByDefault(ReturnRef(forced_unprotected_services_)); + ON_CALL(*mock_security_manager_settings_, force_protected_service()) + .WillByDefault(ReturnRef(forced_protected_services_)); ON_CALL(*mock_security_manager_settings_, security_manager_mode()) .WillByDefault(Return(mode)); ON_CALL(*mock_security_manager_settings_, security_manager_protocol_name()) @@ -111,6 +121,10 @@ class CryptoManagerTest : public testing::Test { .WillByDefault(ReturnRef(cipher)); ON_CALL(*mock_security_manager_settings_, ca_cert_path()) .WillByDefault(ReturnRef(kCaCertPath)); + ON_CALL(*mock_security_manager_settings_, module_cert_path()) + .WillByDefault(ReturnRef(kCertPath)); + ON_CALL(*mock_security_manager_settings_, module_key_path()) + .WillByDefault(ReturnRef(kPrivateKeyPath)); ON_CALL(*mock_security_manager_settings_, verify_peer()) .WillByDefault(Return(false)); } @@ -118,7 +132,10 @@ class CryptoManagerTest : public testing::Test { utils::SharedPtr<CryptoManagerImpl> crypto_manager_; utils::SharedPtr<MockCryptoManagerSettings> mock_security_manager_settings_; static std::string certificate_data_base64_; + std::vector<int> forced_protected_services_; + std::vector<int> forced_unprotected_services_; }; + std::string CryptoManagerTest::certificate_data_base64_; TEST_F(CryptoManagerTest, UsingBeforeInit) { @@ -133,16 +150,15 @@ TEST_F(CryptoManagerTest, WrongInit) { // Unknown protocol version security_manager::Protocol UNKNOWN = static_cast<security_manager::Protocol>(-1); + // Unexistent cipher value + const std::string invalid_cipher = "INVALID_UNKNOWN_CIPHER"; + const security_manager::Mode mode = security_manager::SERVER; - EXPECT_CALL(*mock_security_manager_settings_, security_manager_mode()) - .WillRepeatedly(Return(security_manager::SERVER)); - EXPECT_CALL(*mock_security_manager_settings_, - security_manager_protocol_name()).WillOnce(Return(UNKNOWN)); - EXPECT_FALSE(crypto_manager_->Init()); + SetInitialValues(mode, UNKNOWN, invalid_cipher); + EXPECT_FALSE(crypto_manager_->Init()); EXPECT_NE(std::string(), crypto_manager_->LastError()); - // Unexistent cipher value - const std::string invalid_cipher = "INVALID_UNKNOWN_CIPHER"; + EXPECT_CALL(*mock_security_manager_settings_, security_manager_protocol_name()) .WillOnce(Return(security_manager::TLSv1_2)); @@ -151,7 +167,6 @@ TEST_F(CryptoManagerTest, WrongInit) { EXPECT_CALL(*mock_security_manager_settings_, ciphers_list()) .WillRepeatedly(ReturnRef(invalid_cipher)); EXPECT_FALSE(crypto_manager_->Init()); - EXPECT_NE(std::string(), crypto_manager_->LastError()); } @@ -176,10 +191,18 @@ TEST_F(CryptoManagerTest, CorrectInit) { security_manager::CLIENT, security_manager::TLSv1_1, kFordCipher); EXPECT_TRUE(crypto_manager_->Init()); + SetInitialValues( + security_manager::CLIENT, security_manager::DTLSv1, kFordCipher); + EXPECT_TRUE(crypto_manager_->Init()); + // Cipher value SetInitialValues( security_manager::SERVER, security_manager::TLSv1_2, kAllCiphers); EXPECT_TRUE(crypto_manager_->Init()); + + SetInitialValues( + security_manager::SERVER, security_manager::DTLSv1, kAllCiphers); + EXPECT_TRUE(crypto_manager_->Init()); } // #endif // __QNX__ @@ -198,7 +221,6 @@ TEST_F(CryptoManagerTest, CreateReleaseSSLContext) { EXPECT_CALL(*mock_security_manager_settings_, maximum_payload_size()) .Times(1) .WillRepeatedly(Return(max_payload_size)); - security_manager::SSLContext* context = crypto_manager_->CreateSSLContext(); EXPECT_TRUE(context); EXPECT_NO_THROW(crypto_manager_->ReleaseSSLContext(context)); @@ -210,7 +232,10 @@ TEST_F(CryptoManagerTest, OnCertificateUpdated) { } TEST_F(CryptoManagerTest, OnCertificateUpdated_UpdateNotRequired) { + time_t system_time = 0; + time_t certificates_time = 1; size_t updates_before = 0; + SetInitialValues( security_manager::CLIENT, security_manager::TLSv1_2, kAllCiphers); ASSERT_TRUE(crypto_manager_->Init()); @@ -218,7 +243,8 @@ TEST_F(CryptoManagerTest, OnCertificateUpdated_UpdateNotRequired) { EXPECT_CALL(*mock_security_manager_settings_, update_before_hours()) .WillOnce(Return(updates_before)); - EXPECT_FALSE(crypto_manager_->IsCertificateUpdateRequired()); + EXPECT_FALSE(crypto_manager_->IsCertificateUpdateRequired(system_time, + certificates_time)); size_t max_updates_ = std::numeric_limits<size_t>::max(); SetInitialValues( @@ -227,7 +253,8 @@ TEST_F(CryptoManagerTest, OnCertificateUpdated_UpdateNotRequired) { .WillOnce(Return(max_updates_)); ASSERT_TRUE(crypto_manager_->Init()); - EXPECT_TRUE(crypto_manager_->IsCertificateUpdateRequired()); + EXPECT_TRUE(crypto_manager_->IsCertificateUpdateRequired(system_time, + certificates_time)); } TEST_F(CryptoManagerTest, OnCertificateUpdated_NotInitialized) { diff --git a/src/components/security_manager/test/security_manager_test.cc b/src/components/security_manager/test/security_manager_test.cc index b334e78e19..3523bb7f44 100644 --- a/src/components/security_manager/test/security_manager_test.cc +++ b/src/components/security_manager/test/security_manager_test.cc @@ -44,6 +44,7 @@ #include "security_manager/mock_ssl_context.h" #include "security_manager/mock_crypto_manager.h" #include "security_manager/mock_security_manager_listener.h" +#include "utils/mock_system_time_handler.h" #include "utils/make_shared.h" #include "utils/test_async_waiter.h" @@ -76,11 +77,11 @@ using ::testing::_; namespace { // Sample data for handshake data emulation -const int32_t key = 0x1; -const int32_t seq_number = 0x2; -const ServiceType secureServiceType = kControl; -const uint32_t protocolVersion = PROTOCOL_VERSION_2; -const bool is_final = false; +const int32_t kKey = 0x1; +const int32_t kSeqNumber = 0x2; +const ServiceType kSecureServiceType = kControl; +const uint32_t kProtocolVersion = PROTOCOL_VERSION_2; +const bool kIsFinal = false; const uint8_t handshake_data[] = {0x1, 0x2, 0x3, 0x4, 0x5}; const size_t handshake_data_size = @@ -95,8 +96,12 @@ const uint32_t kAsyncExpectationsTimeout = 10000u; class SecurityManagerTest : public ::testing::Test { protected: + SecurityManagerTest() + : mock_system_time_handler( + std::unique_ptr<MockSystemTimeHandler>(new MockSystemTimeHandler())) + , security_manager_( + new SecurityManagerImpl(std::move(mock_system_time_handler))) {} void SetUp() OVERRIDE { - security_manager_.reset(new SecurityManagerImpl()); security_manager_->set_session_observer(&mock_session_observer); security_manager_->set_protocol_handler(&mock_protocol_handler); mock_sm_listener.reset(new testing::StrictMock< @@ -105,7 +110,7 @@ class SecurityManagerTest : public ::testing::Test { } void SetMockCryptoManager() { - EXPECT_CALL(mock_crypto_manager, IsCertificateUpdateRequired()) + EXPECT_CALL(mock_crypto_manager, IsCertificateUpdateRequired(_, _)) .WillRepeatedly(Return(false)); security_manager_->set_crypto_manager(&mock_crypto_manager); } @@ -116,7 +121,7 @@ class SecurityManagerTest : public ::testing::Test { uint32_t dataSize, const ServiceType serviceType) { const RawMessagePtr rawMessagePtr(utils::MakeShared<RawMessage>( - key, protocolVersion, data, dataSize, serviceType)); + kKey, kProtocolVersion, data, dataSize, serviceType)); security_manager_->OnMessageReceived(rawMessagePtr); } /* @@ -147,13 +152,14 @@ class SecurityManagerTest : public ::testing::Test { const int repeat_count = 1) { const SecurityQuery::QueryHeader header(SecurityQuery::NOTIFICATION, SecurityQuery::SEND_HANDSHAKE_DATA, - seq_number); + kSeqNumber); for (int c = 0; c < repeat_count; ++c) { EmulateMobileMessage(header, data, data_size); } } - ::utils::SharedPtr<SecurityManagerImpl> security_manager_; + // Strict mocks (same as all methods EXPECT_CALL().Times(0)) + testing::StrictMock<protocol_handler_test::MockSessionObserver> mock_session_observer; testing::StrictMock<protocol_handler_test::MockProtocolHandler> @@ -166,6 +172,8 @@ class SecurityManagerTest : public ::testing::Test { mock_ssl_context_exists; std::unique_ptr<testing::StrictMock< security_manager_test::MockSecurityManagerListener> > mock_sm_listener; + std::unique_ptr<MockSystemTimeHandler> mock_system_time_handler; + std::shared_ptr<SecurityManagerImpl> security_manager_; }; // Test Bodies @@ -174,7 +182,6 @@ class SecurityManagerTest : public ::testing::Test { * and shall not call any methodes */ TEST_F(SecurityManagerTest, SetNULL_Intefaces) { - security_manager_.reset(new SecurityManagerImpl()); security_manager_->set_session_observer(NULL); security_manager_->set_protocol_handler(NULL); security_manager_->set_crypto_manager(NULL); @@ -209,9 +216,9 @@ TEST_F(SecurityManagerTest, Listeners_NoListeners) { security_manager_->RemoveListener(&mock_listener2); security_manager_->NotifyListenersOnHandshakeDone( - key, SSLContext::Handshake_Result_Success); + kKey, SSLContext::Handshake_Result_Success); security_manager_->NotifyListenersOnHandshakeDone( - key, SSLContext::Handshake_Result_Fail); + kKey, SSLContext::Handshake_Result_Fail); } /* * Notifying two listeners @@ -228,11 +235,11 @@ TEST_F(SecurityManagerTest, Listeners_Notifying) { const SSLContext::HandshakeResult first_call_value = SSLContext::Handshake_Result_Success; // Expect call both listeners on 1st call - EXPECT_CALL(*mock_listener1, OnHandshakeDone(key, first_call_value)) + EXPECT_CALL(*mock_listener1, OnHandshakeDone(kKey, first_call_value)) . // Emulate false (reject) result WillOnce(Return(false)); - EXPECT_CALL(*mock_listener2, OnHandshakeDone(key, first_call_value)) + EXPECT_CALL(*mock_listener2, OnHandshakeDone(kKey, first_call_value)) . // Emulate true (accept) result WillOnce(Return(true)); @@ -244,7 +251,7 @@ TEST_F(SecurityManagerTest, Listeners_Notifying) { const SSLContext::HandshakeResult second_call_value = SSLContext::Handshake_Result_Fail; // Expect call last listener on 2d call - EXPECT_CALL(*mock_listener1, OnHandshakeDone(key, second_call_value)) + EXPECT_CALL(*mock_listener1, OnHandshakeDone(kKey, second_call_value)) . // Emulate false (reject) result WillOnce(Return(true)); @@ -254,14 +261,14 @@ TEST_F(SecurityManagerTest, Listeners_Notifying) { security_manager_->AddListener(mock_listener1); security_manager_->AddListener(mock_listener2); // 1st call - security_manager_->NotifyListenersOnHandshakeDone(key, first_call_value); + security_manager_->NotifyListenersOnHandshakeDone(kKey, first_call_value); security_manager_->NotifyOnCertificateUpdateRequired(); // 2nd call - security_manager_->NotifyListenersOnHandshakeDone(key, second_call_value); + security_manager_->NotifyListenersOnHandshakeDone(kKey, second_call_value); security_manager_->NotifyOnCertificateUpdateRequired(); // 3nd call security_manager_->NotifyListenersOnHandshakeDone( - key, SSLContext::Handshake_Result_Fail); + kKey, SSLContext::Handshake_Result_Fail); security_manager_->NotifyOnCertificateUpdateRequired(); } @@ -275,7 +282,7 @@ TEST_F(SecurityManagerTest, SecurityManager_NULLCryptoManager) { uint8_t session_id = 0; TestAsyncWaiter waiter; - EXPECT_CALL(mock_session_observer, PairFromKey(key, _, _)); + EXPECT_CALL(mock_session_observer, PairFromKey(kKey, _, _)); EXPECT_CALL(mock_session_observer, ProtocolVersionUsed(connection_id, session_id, _)) .WillOnce(Return(true)); @@ -283,7 +290,7 @@ TEST_F(SecurityManagerTest, SecurityManager_NULLCryptoManager) { EXPECT_CALL(mock_protocol_handler, SendMessageToMobileApp( InternalErrorWithErrId(SecurityManager::ERROR_NOT_SUPPORTED), - is_final)).WillOnce(NotifyTestAsyncWaiter(&waiter)); + kIsFinal)).WillOnce(NotifyTestAsyncWaiter(&waiter)); const SecurityQuery::QueryHeader header(SecurityQuery::REQUEST, // It could be any query id SecurityQuery::INVALID_QUERY_ID); @@ -298,7 +305,7 @@ TEST_F(SecurityManagerTest, SecurityManager_NULLCryptoManager) { TEST_F(SecurityManagerTest, OnMobileMessageSent) { const uint8_t* data_param = NULL; const RawMessagePtr rawMessagePtr( - utils::MakeShared<RawMessage>(key, protocolVersion, data_param, 0)); + utils::MakeShared<RawMessage>(kKey, kProtocolVersion, data_param, 0)); security_manager_->OnMobileMessageSent(rawMessagePtr); } /* @@ -319,7 +326,7 @@ TEST_F(SecurityManagerTest, GetEmptyQuery) { uint32_t connection_id = 0; uint8_t session_id = 0; // uint8_t protocol_version = 0; - EXPECT_CALL(mock_session_observer, PairFromKey(key, _, _)); + EXPECT_CALL(mock_session_observer, PairFromKey(kKey, _, _)); EXPECT_CALL(mock_session_observer, ProtocolVersionUsed(connection_id, session_id, _)) .WillOnce(Return(true)); @@ -328,9 +335,9 @@ TEST_F(SecurityManagerTest, GetEmptyQuery) { mock_protocol_handler, SendMessageToMobileApp( InternalErrorWithErrId(SecurityManager::ERROR_INVALID_QUERY_SIZE), - is_final)); + kIsFinal)); // Call with NULL data - call_OnMessageReceived(NULL, 0, secureServiceType); + call_OnMessageReceived(NULL, 0, kSecureServiceType); } /* * Shall send InternallError on null data recieved @@ -340,7 +347,7 @@ TEST_F(SecurityManagerTest, GetWrongJSONSize) { uint32_t connection_id = 0; uint8_t session_id = 0; // uint8_t protocol_version = 0; - EXPECT_CALL(mock_session_observer, PairFromKey(key, _, _)); + EXPECT_CALL(mock_session_observer, PairFromKey(kKey, _, _)); EXPECT_CALL(mock_session_observer, ProtocolVersionUsed(connection_id, session_id, _)) .WillOnce(Return(true)); @@ -349,7 +356,7 @@ TEST_F(SecurityManagerTest, GetWrongJSONSize) { mock_protocol_handler, SendMessageToMobileApp( InternalErrorWithErrId(SecurityManager::ERROR_INVALID_QUERY_SIZE), - is_final)); + kIsFinal)); SecurityQuery::QueryHeader header(SecurityQuery::REQUEST, SecurityQuery::INVALID_QUERY_ID); header.json_size = 0x0FFFFFFF; @@ -365,7 +372,7 @@ TEST_F(SecurityManagerTest, GetInvalidQueryId) { TestAsyncWaiter waiter; uint32_t times = 0; - EXPECT_CALL(mock_session_observer, PairFromKey(key, _, _)) + EXPECT_CALL(mock_session_observer, PairFromKey(kKey, _, _)) .WillOnce(NotifyTestAsyncWaiter(&waiter)); times++; EXPECT_CALL(mock_session_observer, @@ -378,7 +385,7 @@ TEST_F(SecurityManagerTest, GetInvalidQueryId) { mock_protocol_handler, SendMessageToMobileApp( InternalErrorWithErrId(SecurityManager::ERROR_INVALID_QUERY_ID), - is_final)).WillOnce(NotifyTestAsyncWaiter(&waiter)); + kIsFinal)).WillOnce(NotifyTestAsyncWaiter(&waiter)); times++; const SecurityQuery::QueryHeader header(SecurityQuery::REQUEST, SecurityQuery::INVALID_QUERY_ID); @@ -395,10 +402,12 @@ TEST_F(SecurityManagerTest, CreateSSLContext_ServiceAlreadyProtected) { SetMockCryptoManager(); // Return mock SSLContext - EXPECT_CALL(mock_session_observer, GetSSLContext(key, kControl)) + EXPECT_CALL(mock_session_observer, GetSSLContext(kKey, kControl)) .WillOnce(Return(&mock_ssl_context_new)); - const SSLContext* result = security_manager_->CreateSSLContext(key); + const SSLContext* result = security_manager_->CreateSSLContext( + kKey, + security_manager::SecurityManager::ContextCreationStrategy::kUseExisting); EXPECT_EQ(&mock_ssl_context_new, result); } /* @@ -410,21 +419,23 @@ TEST_F(SecurityManagerTest, CreateSSLContext_ErrorCreateSSL) { uint32_t connection_id = 0; uint8_t session_id = 0; // uint8_t protocol_version = 0; - EXPECT_CALL(mock_session_observer, PairFromKey(key, _, _)); + EXPECT_CALL(mock_session_observer, PairFromKey(kKey, _, _)); EXPECT_CALL(mock_session_observer, ProtocolVersionUsed(connection_id, session_id, _)) .WillOnce(Return(true)); EXPECT_CALL( mock_protocol_handler, SendMessageToMobileApp( - InternalErrorWithErrId(SecurityManager::ERROR_INTERNAL), is_final)); + InternalErrorWithErrId(SecurityManager::ERROR_INTERNAL), kIsFinal)); // Emulate SessionObserver and CryptoManager result - EXPECT_CALL(mock_session_observer, GetSSLContext(key, kControl)) + EXPECT_CALL(mock_session_observer, GetSSLContext(kKey, kControl)) .WillOnce(ReturnNull()); EXPECT_CALL(mock_crypto_manager, CreateSSLContext()).WillOnce(ReturnNull()); - const SSLContext* result = security_manager_->CreateSSLContext(key); + const SSLContext* result = security_manager_->CreateSSLContext( + kKey, + security_manager::SecurityManager::ContextCreationStrategy::kUseExisting); EXPECT_EQ(NULL, result); } /* @@ -437,7 +448,7 @@ TEST_F(SecurityManagerTest, CreateSSLContext_SetSSLContextError) { uint32_t connection_id = 0; uint8_t session_id = 0; // uint8_t protocol_version = 0; - EXPECT_CALL(mock_session_observer, PairFromKey(key, _, _)); + EXPECT_CALL(mock_session_observer, PairFromKey(kKey, _, _)); EXPECT_CALL(mock_session_observer, ProtocolVersionUsed(connection_id, session_id, _)) .WillOnce(Return(true)); @@ -446,18 +457,20 @@ TEST_F(SecurityManagerTest, CreateSSLContext_SetSSLContextError) { mock_protocol_handler, SendMessageToMobileApp( InternalErrorWithErrId(SecurityManager::ERROR_UNKNOWN_INTERNAL_ERROR), - is_final)); + kIsFinal)); // Emulate SessionObserver and CryptoManager result - EXPECT_CALL(mock_session_observer, GetSSLContext(key, kControl)) + EXPECT_CALL(mock_session_observer, GetSSLContext(kKey, kControl)) .WillOnce(ReturnNull()); EXPECT_CALL(mock_crypto_manager, CreateSSLContext()) .WillOnce(Return(&mock_ssl_context_new)); EXPECT_CALL(mock_crypto_manager, ReleaseSSLContext(&mock_ssl_context_new)); - EXPECT_CALL(mock_session_observer, SetSSLContext(key, &mock_ssl_context_new)) + EXPECT_CALL(mock_session_observer, SetSSLContext(kKey, &mock_ssl_context_new)) .WillOnce(Return(SecurityManager::ERROR_UNKNOWN_INTERNAL_ERROR)); - const SSLContext* result = security_manager_->CreateSSLContext(key); + const SSLContext* result = security_manager_->CreateSSLContext( + kKey, + security_manager::SecurityManager::ContextCreationStrategy::kUseExisting); EXPECT_EQ(NULL, result); } /* @@ -469,17 +482,17 @@ TEST_F(SecurityManagerTest, CreateSSLContext_Success) { // Expect no notifying listeners - it will be done after handshake // Emulate SessionObserver and CryptoManager result - EXPECT_CALL(mock_session_observer, GetSSLContext(key, kControl)) - .WillOnce(ReturnNull()) - . - // additional check for debug code - WillOnce(Return(&mock_ssl_context_exists)); + EXPECT_CALL(mock_session_observer, GetSSLContext(kKey, kControl)) + .WillOnce(Return(&mock_ssl_context_exists)); EXPECT_CALL(mock_crypto_manager, CreateSSLContext()) .WillOnce(Return(&mock_ssl_context_new)); - EXPECT_CALL(mock_session_observer, SetSSLContext(key, &mock_ssl_context_new)) + EXPECT_CALL(mock_session_observer, SetSSLContext(kKey, &mock_ssl_context_new)) .WillOnce(Return(SecurityManager::ERROR_SUCCESS)); - const SSLContext* result = security_manager_->CreateSSLContext(key); + const SSLContext* result = security_manager_->CreateSSLContext( + kKey, + security_manager::SecurityManager::ContextCreationStrategy:: + kForceRecreation); EXPECT_EQ(&mock_ssl_context_new, result); } /* @@ -490,7 +503,7 @@ TEST_F(SecurityManagerTest, StartHandshake_ServiceStillUnprotected) { uint32_t connection_id = 0; uint8_t session_id = 0; // uint8_t protocol_version = 0; - EXPECT_CALL(mock_session_observer, PairFromKey(key, _, _)); + EXPECT_CALL(mock_session_observer, PairFromKey(kKey, _, _)); EXPECT_CALL(mock_session_observer, ProtocolVersionUsed(connection_id, session_id, _)) .WillOnce(Return(true)); @@ -498,17 +511,17 @@ TEST_F(SecurityManagerTest, StartHandshake_ServiceStillUnprotected) { EXPECT_CALL( mock_protocol_handler, SendMessageToMobileApp( - InternalErrorWithErrId(SecurityManager::ERROR_INTERNAL), is_final)); + InternalErrorWithErrId(SecurityManager::ERROR_INTERNAL), kIsFinal)); // Expect notifying listeners (unsuccess) EXPECT_CALL(*mock_sm_listener, - OnHandshakeDone(key, SSLContext::Handshake_Result_Fail)) + OnHandshakeDone(kKey, SSLContext::Handshake_Result_Fail)) .WillOnce(Return(true)); // Emulate SessionObserver result - EXPECT_CALL(mock_session_observer, GetSSLContext(key, kControl)) + EXPECT_CALL(mock_session_observer, GetSSLContext(kKey, kControl)) .WillOnce(ReturnNull()); - security_manager_->StartHandshake(key); + security_manager_->StartHandshake(kKey); // Listener was destroyed after OnHandshakeDone call mock_sm_listener.release(); @@ -521,109 +534,27 @@ TEST_F(SecurityManagerTest, StartHandshake_SSLInternalError) { uint32_t connection_id = 0; uint8_t session_id = 0; - // uint8_t protocol_version = 0; - EXPECT_CALL(mock_session_observer, PairFromKey(key, _, _)); - EXPECT_CALL(mock_session_observer, GetHandshakeContext(key)) - .WillOnce(Return(SSLContext::HandshakeContext())); + + EXPECT_CALL(mock_session_observer, PairFromKey(kKey, _, _)); EXPECT_CALL(mock_session_observer, ProtocolVersionUsed(connection_id, session_id, _)) .WillOnce(Return(true)); - + // Expect notifying listeners (unsuccess) + EXPECT_CALL(*mock_sm_listener, + OnHandshakeDone(kKey, SSLContext::Handshake_Result_Fail)) + .WillOnce(Return(true)); + EXPECT_CALL(mock_session_observer, GetSSLContext(kKey, kControl)) + .WillOnce(ReturnNull()); // Expect InternalError with ERROR_ID EXPECT_CALL( mock_protocol_handler, SendMessageToMobileApp( - InternalErrorWithErrId(SecurityManager::ERROR_INTERNAL), is_final)); - // Expect notifying listeners (unsuccess) - EXPECT_CALL(*mock_sm_listener, - OnHandshakeDone(key, SSLContext::Handshake_Result_Fail)) - .WillOnce(Return(true)); + InternalErrorWithErrId(SecurityManager::ERROR_INTERNAL), kIsFinal)); - // Emulate SessionObserver result - EXPECT_CALL(mock_session_observer, GetSSLContext(key, kControl)) - .WillOnce(Return(&mock_ssl_context_exists)); - EXPECT_CALL(mock_ssl_context_exists, IsInitCompleted()) - .WillOnce(Return(false)); - EXPECT_CALL(mock_ssl_context_exists, SetHandshakeContext(_)); - EXPECT_CALL(mock_ssl_context_exists, StartHandshake(_, _)) - .WillOnce(DoAll(SetArgPointee<0>(handshake_data_out_pointer), - SetArgPointee<1>(handshake_data_out_size), - Return(SSLContext::Handshake_Result_Fail))); - - security_manager_->StartHandshake(key); - - // Listener was destroyed after OnHandshakeDone call + security_manager_->StartHandshake(kKey); mock_sm_listener.release(); } -/* - * Shall send data on call StartHandshake - */ -TEST_F(SecurityManagerTest, StartHandshake_SSLInitIsNotComplete) { - SetMockCryptoManager(); - uint32_t connection_id = 0; - uint8_t session_id = 0; - // uint8_t protocol_version = 0; - EXPECT_CALL(mock_session_observer, PairFromKey(key, _, _)); - EXPECT_CALL(mock_session_observer, GetHandshakeContext(key)) - .Times(3) - .WillRepeatedly(Return(SSLContext::HandshakeContext())); - EXPECT_CALL(mock_session_observer, - ProtocolVersionUsed(connection_id, session_id, _)) - .WillOnce(Return(true)); - - // Expect send one message (with correct pointer and size data) - EXPECT_CALL(mock_protocol_handler, SendMessageToMobileApp(_, is_final)); - - // Return mock SSLContext - EXPECT_CALL(mock_session_observer, GetSSLContext(key, kControl)) - .Times(3) - .WillRepeatedly(Return(&mock_ssl_context_exists)); - // Expect initialization check on each call StartHandshake - EXPECT_CALL(mock_ssl_context_exists, IsInitCompleted()) - .Times(3) - .WillRepeatedly(Return(false)); - EXPECT_CALL(mock_ssl_context_exists, SetHandshakeContext(_)).Times(3); - - // Emulate SSLContext::StartHandshake with different parameters - // Only on both correct - data and size shall be send message to mobile app - EXPECT_CALL(mock_ssl_context_exists, StartHandshake(_, _)) - .WillOnce(DoAll(SetArgPointee<0>(handshake_data_out_pointer), - SetArgPointee<1>(0), - Return(SSLContext::Handshake_Result_Success))) - .WillOnce(DoAll(SetArgPointee<0>((uint8_t*)NULL), - SetArgPointee<1>(handshake_data_out_size), - Return(SSLContext::Handshake_Result_Success))) - .WillOnce(DoAll(SetArgPointee<0>(handshake_data_out_pointer), - SetArgPointee<1>(handshake_data_out_size), - Return(SSLContext::Handshake_Result_Success))); - security_manager_->StartHandshake(key); - security_manager_->StartHandshake(key); - security_manager_->StartHandshake(key); -} -/* - * Shall notify listeners on call StartHandshake after SSLContext initialization - * complete - */ -TEST_F(SecurityManagerTest, StartHandshake_SSLInitIsComplete) { - SetMockCryptoManager(); - // Expect no message send - // Expect notifying listeners (success) - EXPECT_CALL(*mock_sm_listener, - OnHandshakeDone(key, SSLContext::Handshake_Result_Success)) - .WillOnce(Return(true)); - - // Emulate SessionObserver result - EXPECT_CALL(mock_session_observer, GetSSLContext(key, kControl)) - .WillOnce(Return(&mock_ssl_context_exists)); - EXPECT_CALL(mock_ssl_context_exists, IsInitCompleted()) - .WillOnce(Return(true)); - - security_manager_->StartHandshake(key); - - // Listener was destroyed after OnHandshakeDone call - mock_sm_listener.release(); -} /* * Shall send InternallError on * getting SEND_HANDSHAKE_DATA with NULL data @@ -634,7 +565,7 @@ TEST_F(SecurityManagerTest, ProccessHandshakeData_WrongDataSize) { uint8_t session_id = 0; TestAsyncWaiter waiter; - EXPECT_CALL(mock_session_observer, PairFromKey(key, _, _)); + EXPECT_CALL(mock_session_observer, PairFromKey(kKey, _, _)); EXPECT_CALL(mock_session_observer, ProtocolVersionUsed(connection_id, session_id, _)) .WillOnce(Return(true)); @@ -644,7 +575,7 @@ TEST_F(SecurityManagerTest, ProccessHandshakeData_WrongDataSize) { mock_protocol_handler, SendMessageToMobileApp( InternalErrorWithErrId(SecurityManager::ERROR_INVALID_QUERY_SIZE), - is_final)).WillOnce(NotifyTestAsyncWaiter(&waiter)); + kIsFinal)).WillOnce(NotifyTestAsyncWaiter(&waiter)); EmulateMobileMessageHandshake(NULL, 0); @@ -664,7 +595,7 @@ TEST_F(SecurityManagerTest, TestAsyncWaiter waiter; uint32_t times = 0; - EXPECT_CALL(mock_session_observer, PairFromKey(key, _, _)) + EXPECT_CALL(mock_session_observer, PairFromKey(kKey, _, _)) .WillOnce(NotifyTestAsyncWaiter(&waiter)); times++; EXPECT_CALL(mock_session_observer, @@ -675,17 +606,17 @@ TEST_F(SecurityManagerTest, mock_protocol_handler, SendMessageToMobileApp( InternalErrorWithErrId(SecurityManager::ERROR_SERVICE_NOT_PROTECTED), - is_final)).WillOnce(NotifyTestAsyncWaiter(&waiter)); + kIsFinal)).WillOnce(NotifyTestAsyncWaiter(&waiter)); times++; // Expect notifying listeners (unsuccess) EXPECT_CALL(*mock_sm_listener, - OnHandshakeDone(key, SSLContext::Handshake_Result_Fail)) + OnHandshakeDone(kKey, SSLContext::Handshake_Result_Fail)) .WillOnce(DoAll(NotifyTestAsyncWaiter(&waiter), Return(true))); times++; // Emulate SessionObserver result - EXPECT_CALL(mock_session_observer, GetSSLContext(key, kControl)) + EXPECT_CALL(mock_session_observer, GetSSLContext(kKey, kControl)) .WillOnce(DoAll(NotifyTestAsyncWaiter(&waiter), ReturnNull())); times++; @@ -713,7 +644,7 @@ TEST_F(SecurityManagerTest, ProccessHandshakeData_InvalidData) { TestAsyncWaiter waiter; uint32_t times = 0; - EXPECT_CALL(mock_session_observer, PairFromKey(key, _, _)) + EXPECT_CALL(mock_session_observer, PairFromKey(kKey, _, _)) .Times(handshake_emulates) .WillRepeatedly(NotifyTestAsyncWaiter(&waiter)); times += handshake_emulates; @@ -728,18 +659,18 @@ TEST_F(SecurityManagerTest, ProccessHandshakeData_InvalidData) { mock_protocol_handler, SendMessageToMobileApp( InternalErrorWithErrId(SecurityManager::ERROR_SSL_INVALID_DATA), - is_final)) + kIsFinal)) .Times(handshake_emulates) .WillRepeatedly(NotifyTestAsyncWaiter(&waiter)); times += handshake_emulates; // Expect notifying listeners (unsuccess) EXPECT_CALL(*mock_sm_listener, - OnHandshakeDone(key, SSLContext::Handshake_Result_Fail)) + OnHandshakeDone(kKey, SSLContext::Handshake_Result_Fail)) .WillOnce(DoAll(NotifyTestAsyncWaiter(&waiter), Return(true))); times++; // Emulate SessionObserver and CryptoManager result - EXPECT_CALL(mock_session_observer, GetSSLContext(key, kControl)) + EXPECT_CALL(mock_session_observer, GetSSLContext(kKey, kControl)) .Times(handshake_emulates) .WillRepeatedly(Return(&mock_ssl_context_exists)); @@ -794,7 +725,7 @@ TEST_F(SecurityManagerTest, ProccessHandshakeData_Answer) { TestAsyncWaiter waiter; uint32_t times = 0; - EXPECT_CALL(mock_session_observer, PairFromKey(key, _, _)) + EXPECT_CALL(mock_session_observer, PairFromKey(kKey, _, _)) .Times(handshake_emulates) .WillRepeatedly(NotifyTestAsyncWaiter(&waiter)); times += handshake_emulates; @@ -808,14 +739,14 @@ TEST_F(SecurityManagerTest, ProccessHandshakeData_Answer) { const size_t raw_message_size = 15; EXPECT_CALL( mock_protocol_handler, - SendMessageToMobileApp(RawMessageEqSize(raw_message_size), is_final)) + SendMessageToMobileApp(RawMessageEqSize(raw_message_size), kIsFinal)) .Times(handshake_emulates) .WillRepeatedly(NotifyTestAsyncWaiter(&waiter)); times += handshake_emulates; // Expect notifying listeners (unsuccess) EXPECT_CALL(*mock_sm_listener, - OnHandshakeDone(key, SSLContext::Handshake_Result_Fail)) + OnHandshakeDone(kKey, SSLContext::Handshake_Result_Fail)) .WillOnce(DoAll(NotifyTestAsyncWaiter(&waiter), Return(true))); times++; @@ -824,7 +755,7 @@ TEST_F(SecurityManagerTest, ProccessHandshakeData_Answer) { .Times(handshake_emulates) .WillRepeatedly(DoAll(NotifyTestAsyncWaiter(&waiter), Return(false))); times += handshake_emulates; - EXPECT_CALL(mock_session_observer, GetSSLContext(key, kControl)) + EXPECT_CALL(mock_session_observer, GetSSLContext(kKey, kControl)) .Times(handshake_emulates) .WillRepeatedly(DoAll(NotifyTestAsyncWaiter(&waiter), Return(&mock_ssl_context_exists))); @@ -870,12 +801,12 @@ TEST_F(SecurityManagerTest, ProccessHandshakeData_HandshakeFinished) { // Expect no errors // Expect notifying listeners (success) EXPECT_CALL(*mock_sm_listener, - OnHandshakeDone(key, SSLContext::Handshake_Result_Success)) + OnHandshakeDone(kKey, SSLContext::Handshake_Result_Success)) .WillOnce(DoAll(NotifyTestAsyncWaiter(&waiter), Return(true))); times++; // Emulate SessionObserver and CryptoManager result - EXPECT_CALL(mock_session_observer, GetSSLContext(key, kControl)) + EXPECT_CALL(mock_session_observer, GetSSLContext(kKey, kControl)) .Times(handshake_emulates) .WillRepeatedly(DoAll(NotifyTestAsyncWaiter(&waiter), Return(&mock_ssl_context_exists))); @@ -928,14 +859,14 @@ TEST_F(SecurityManagerTest, ProccessHandshakeData_HandshakeFinished) { uint32_t connection_id = 0; uint8_t session_id = 0; // uint8_t protocol_version = 0; - EXPECT_CALL(mock_session_observer, PairFromKey(key, _, _)).Times(2); + EXPECT_CALL(mock_session_observer, PairFromKey(kKey, _, _)).Times(2); EXPECT_CALL(mock_session_observer, ProtocolVersionUsed(connection_id, session_id, _)) .Times(2) .WillRepeatedly(DoAll(NotifyTestAsyncWaiter(&waiter), Return(true))); times += 2; // matches to the number above - EXPECT_CALL(mock_protocol_handler, SendMessageToMobileApp(_, is_final)) + EXPECT_CALL(mock_protocol_handler, SendMessageToMobileApp(_, kIsFinal)) .Times(2) .WillRepeatedly(NotifyTestAsyncWaiter(&waiter)); times += 2; // matches to the number above diff --git a/src/components/security_manager/test/ssl_certificate_handshake_test.cc b/src/components/security_manager/test/ssl_certificate_handshake_test.cc index dc335c8da2..83ffa33b44 100644 --- a/src/components/security_manager/test/ssl_certificate_handshake_test.cc +++ b/src/components/security_manager/test/ssl_certificate_handshake_test.cc @@ -56,6 +56,10 @@ namespace custom_str = utils::custom_string; namespace { const std::string server_ca_cert_filename = "server"; const std::string client_ca_cert_filename = "client"; +const std::string client_cert_filename = "client.crt"; +const std::string server_cert_filename = "server.crt"; +const std::string client_key_filename = "client_private.key"; +const std::string server_key_filename = "server_private.key"; const std::string client_certificate = "client/client_credential.pem"; const std::string server_certificate = "server/spt_credential.pem"; const std::string server_unsigned_cert_file = @@ -66,36 +70,42 @@ const std::string server_expired_cert_file = const bool verify_peer = true; const bool skip_peer_verification = false; -const size_t updates_before_hour = 24; - } // namespace +struct Protocol { + security_manager::Protocol server_protocol; + security_manager::Protocol client_protocol; + + Protocol(security_manager::Protocol s_protocol, + security_manager::Protocol c_protocol) + : server_protocol(s_protocol), client_protocol(c_protocol) {} +}; -class SSLHandshakeTest : public testing::Test { +class SSLHandshakeTest : public testing::TestWithParam<Protocol> { protected: void SetUp() OVERRIDE { - mock_server_manager_settings = new testing::NiceMock< + mock_server_manager_settings_ = new testing::NiceMock< security_manager_test::MockCryptoManagerSettings>(); - server_manager = new security_manager::CryptoManagerImpl( + server_manager_ = new security_manager::CryptoManagerImpl( utils::SharedPtr<security_manager::CryptoManagerSettings>( - mock_server_manager_settings)); - ASSERT_TRUE(server_manager); - mock_client_manager_settings = new testing::NiceMock< + mock_server_manager_settings_)); + ASSERT_TRUE(server_manager_); + mock_client_manager_settings_ = new testing::NiceMock< security_manager_test::MockCryptoManagerSettings>(); - client_manager = new security_manager::CryptoManagerImpl( + client_manager_ = new security_manager::CryptoManagerImpl( utils::SharedPtr<security_manager::CryptoManagerSettings>( - mock_client_manager_settings)); - ASSERT_TRUE(client_manager); - server_ctx = NULL; - client_ctx = NULL; + mock_client_manager_settings_)); + ASSERT_TRUE(client_manager_); + server_ctx_ = NULL; + client_ctx_ = NULL; } void TearDown() OVERRIDE { - server_manager->ReleaseSSLContext(server_ctx); - delete server_manager; - client_manager->ReleaseSSLContext(client_ctx); - delete client_manager; + server_manager_->ReleaseSSLContext(server_ctx_); + delete server_manager_; + client_manager_->ReleaseSSLContext(client_ctx_); + delete client_manager_; } void SetServerInitialValues(const security_manager::Protocol protocol, @@ -106,18 +116,25 @@ class SSLHandshakeTest : public testing::Test { server_certificate_ = cert; server_ciphers_list_ = server_ciphers_list; server_ca_certificate_path_ = ca_certificate_path; - - ON_CALL(*mock_server_manager_settings, security_manager_mode()) + ON_CALL(*mock_server_manager_settings_, force_unprotected_service()) + .WillByDefault(ReturnRef(forced_unprotected_service_)); + ON_CALL(*mock_server_manager_settings_, force_protected_service()) + .WillByDefault(ReturnRef(forced_protected_service_)); + ON_CALL(*mock_server_manager_settings_, security_manager_mode()) .WillByDefault(Return(security_manager::SERVER)); - ON_CALL(*mock_server_manager_settings, security_manager_protocol_name()) + ON_CALL(*mock_server_manager_settings_, security_manager_protocol_name()) .WillByDefault(Return(protocol)); - ON_CALL(*mock_server_manager_settings, certificate_data()) + ON_CALL(*mock_server_manager_settings_, certificate_data()) .WillByDefault(ReturnRef(server_certificate_)); - ON_CALL(*mock_server_manager_settings, ciphers_list()) + ON_CALL(*mock_server_manager_settings_, ciphers_list()) .WillByDefault(ReturnRef(server_ciphers_list_)); - ON_CALL(*mock_server_manager_settings, ca_cert_path()) + ON_CALL(*mock_server_manager_settings_, ca_cert_path()) .WillByDefault(ReturnRef(server_ca_certificate_path_)); - ON_CALL(*mock_server_manager_settings, verify_peer()) + ON_CALL(*mock_server_manager_settings_, module_cert_path()) + .WillByDefault(ReturnRef(server_cert_filename)); + ON_CALL(*mock_server_manager_settings_, module_key_path()) + .WillByDefault(ReturnRef(server_key_filename)); + ON_CALL(*mock_server_manager_settings_, verify_peer()) .WillByDefault(Return(verify_peer)); } void SetClientInitialValues(const security_manager::Protocol protocol, @@ -129,17 +146,25 @@ class SSLHandshakeTest : public testing::Test { client_ciphers_list_ = client_ciphers_list; client_ca_certificate_path_ = ca_certificate_path; - ON_CALL(*mock_client_manager_settings, security_manager_mode()) + ON_CALL(*mock_client_manager_settings_, force_unprotected_service()) + .WillByDefault(ReturnRef(forced_unprotected_service_)); + ON_CALL(*mock_client_manager_settings_, force_protected_service()) + .WillByDefault(ReturnRef(forced_protected_service_)); + ON_CALL(*mock_client_manager_settings_, security_manager_mode()) .WillByDefault(Return(security_manager::CLIENT)); - ON_CALL(*mock_client_manager_settings, security_manager_protocol_name()) + ON_CALL(*mock_client_manager_settings_, security_manager_protocol_name()) .WillByDefault(Return(protocol)); - ON_CALL(*mock_client_manager_settings, certificate_data()) + ON_CALL(*mock_client_manager_settings_, certificate_data()) .WillByDefault(ReturnRef(client_certificate_)); - ON_CALL(*mock_client_manager_settings, ciphers_list()) + ON_CALL(*mock_client_manager_settings_, ciphers_list()) .WillByDefault(ReturnRef(client_ciphers_list_)); - ON_CALL(*mock_client_manager_settings, ca_cert_path()) + ON_CALL(*mock_client_manager_settings_, ca_cert_path()) .WillByDefault(ReturnRef(client_ca_certificate_path_)); - ON_CALL(*mock_client_manager_settings, verify_peer()) + ON_CALL(*mock_client_manager_settings_, module_cert_path()) + .WillByDefault(ReturnRef(client_cert_filename)); + ON_CALL(*mock_client_manager_settings_, module_key_path()) + .WillByDefault(ReturnRef(client_key_filename)); + ON_CALL(*mock_client_manager_settings_, verify_peer()) .WillByDefault(Return(verify_peer)); } @@ -156,19 +181,19 @@ class SSLHandshakeTest : public testing::Test { cert.close(); SetServerInitialValues( protocol, ss.str(), ciphers_list, verify_peer, ca_certificate_path); - const bool initialized = server_manager->Init(); + const bool initialized = server_manager_->Init(); if (!initialized) { return false; } - server_ctx = server_manager->CreateSSLContext(); + server_ctx_ = server_manager_->CreateSSLContext(); - if (!server_ctx) { + if (!server_ctx_) { return false; } - server_ctx->SetHandshakeContext( + server_ctx_->SetHandshakeContext( security_manager::SSLContext::HandshakeContext( custom_str::CustomString("SPT"), custom_str::CustomString("client"))); @@ -192,17 +217,17 @@ class SSLHandshakeTest : public testing::Test { ciphers_list, verify_peer, ca_certificate_path); - const bool initialized = client_manager->Init(); + const bool initialized = client_manager_->Init(); if (!initialized) { return false; } - client_ctx = client_manager->CreateSSLContext(); - if (!client_ctx) { + client_ctx_ = client_manager_->CreateSSLContext(); + if (!client_ctx_) { return false; } - client_ctx->SetHandshakeContext( + client_ctx_->SetHandshakeContext( security_manager::SSLContext::HandshakeContext( custom_str::CustomString("SPT"), custom_str::CustomString("server"))); @@ -211,17 +236,17 @@ class SSLHandshakeTest : public testing::Test { } void ResetConnections() { - ASSERT_NO_THROW(server_ctx->ResetConnection()); - ASSERT_NO_THROW(client_ctx->ResetConnection()); + ASSERT_NO_THROW(server_ctx_->ResetConnection()); + ASSERT_NO_THROW(client_ctx_->ResetConnection()); } void StartHandshake() { using security_manager::SSLContext; ASSERT_EQ(SSLContext::Handshake_Result_Success, - client_ctx->StartHandshake(&client_buf, &client_buf_len)); - ASSERT_FALSE(client_buf == NULL); - ASSERT_GT(client_buf_len, 0u); + client_ctx_->StartHandshake(&client_buf_, &client_buf_len_)); + ASSERT_FALSE(client_buf_ == NULL); + ASSERT_GT(client_buf_len_, 0u); } void HandshakeProcedure_Success() { @@ -229,23 +254,25 @@ class SSLHandshakeTest : public testing::Test { StartHandshake(); while (true) { - ASSERT_EQ(SSLContext::Handshake_Result_Success, - server_ctx->DoHandshakeStep( - client_buf, client_buf_len, &server_buf, &server_buf_len)) + ASSERT_EQ( + SSLContext::Handshake_Result_Success, + server_ctx_->DoHandshakeStep( + client_buf_, client_buf_len_, &server_buf_, &server_buf_len_)) << ERR_reason_error_string(ERR_get_error()); - ASSERT_FALSE(server_buf == NULL); - ASSERT_GT(server_buf_len, 0u); + ASSERT_FALSE(server_buf_ == NULL); + ASSERT_GT(server_buf_len_, 0u); - ASSERT_EQ(SSLContext::Handshake_Result_Success, - client_ctx->DoHandshakeStep( - server_buf, server_buf_len, &client_buf, &client_buf_len)) + ASSERT_EQ( + SSLContext::Handshake_Result_Success, + client_ctx_->DoHandshakeStep( + server_buf_, server_buf_len_, &client_buf_, &client_buf_len_)) << ERR_reason_error_string(ERR_get_error()); - if (server_ctx->IsInitCompleted()) { + if (server_ctx_->IsInitCompleted()) { break; } - ASSERT_FALSE(client_buf == NULL); - ASSERT_GT(client_buf_len, 0u); + ASSERT_FALSE(client_buf_ == NULL); + ASSERT_GT(client_buf_len_, 0u); } } @@ -255,9 +282,9 @@ class SSLHandshakeTest : public testing::Test { StartHandshake(); while (true) { - const SSLContext::HandshakeResult result = server_ctx->DoHandshakeStep( - client_buf, client_buf_len, &server_buf, &server_buf_len); - ASSERT_FALSE(server_ctx->IsInitCompleted()) + const SSLContext::HandshakeResult result = server_ctx_->DoHandshakeStep( + client_buf_, client_buf_len_, &server_buf_, &server_buf_len_); + ASSERT_FALSE(server_ctx_->IsInitCompleted()) << "Expected server side handshake fail"; // First few handshake will be successful @@ -265,18 +292,19 @@ class SSLHandshakeTest : public testing::Test { // Test successfully passed with handshake fail return; } - ASSERT_FALSE(server_buf == NULL); - ASSERT_GT(server_buf_len, 0u); + ASSERT_FALSE(server_buf_ == NULL); + ASSERT_GT(server_buf_len_, 0u); - ASSERT_EQ(SSLContext::Handshake_Result_Success, - client_ctx->DoHandshakeStep( - server_buf, server_buf_len, &client_buf, &client_buf_len)) + ASSERT_EQ( + SSLContext::Handshake_Result_Success, + client_ctx_->DoHandshakeStep( + server_buf_, server_buf_len_, &client_buf_, &client_buf_len_)) << ERR_reason_error_string(ERR_get_error()); - ASSERT_FALSE(client_ctx->IsInitCompleted()) + ASSERT_FALSE(client_ctx_->IsInitCompleted()) << "Expected server side handshake fail"; - ASSERT_FALSE(client_buf == NULL); - ASSERT_GT(client_buf_len, 0u); + ASSERT_FALSE(client_buf_ == NULL); + ASSERT_GT(client_buf_len_, 0u); } FAIL() << "Expected server side handshake fail"; } @@ -288,17 +316,18 @@ class SSLHandshakeTest : public testing::Test { StartHandshake(); while (true) { - ASSERT_EQ(SSLContext::Handshake_Result_Success, - server_ctx->DoHandshakeStep( - client_buf, client_buf_len, &server_buf, &server_buf_len)) + ASSERT_EQ( + SSLContext::Handshake_Result_Success, + server_ctx_->DoHandshakeStep( + client_buf_, client_buf_len_, &server_buf_, &server_buf_len_)) << ERR_reason_error_string(ERR_get_error()); - ASSERT_FALSE(server_buf == NULL); - ASSERT_GT(server_buf_len, 0u); + ASSERT_FALSE(server_buf_ == NULL); + ASSERT_GT(server_buf_len_, 0u); - const SSLContext::HandshakeResult result = client_ctx->DoHandshakeStep( - server_buf, server_buf_len, &client_buf, &client_buf_len); - ASSERT_FALSE(client_ctx->IsInitCompleted()) + const SSLContext::HandshakeResult result = client_ctx_->DoHandshakeStep( + server_buf_, server_buf_len_, &client_buf_, &client_buf_len_); + ASSERT_FALSE(client_ctx_->IsInitCompleted()) << "Expected client side handshake fail"; // First few handsahke will be successful @@ -308,25 +337,25 @@ class SSLHandshakeTest : public testing::Test { return; } - ASSERT_FALSE(client_buf == NULL); - ASSERT_GT(client_buf_len, 0u); + ASSERT_FALSE(client_buf_ == NULL); + ASSERT_GT(client_buf_len_, 0u); } FAIL() << "Expected client side handshake fail"; } - security_manager::CryptoManager* server_manager; - security_manager::CryptoManager* client_manager; - security_manager::SSLContext* server_ctx; - security_manager::SSLContext* client_ctx; + security_manager::CryptoManager* server_manager_; + security_manager::CryptoManager* client_manager_; + security_manager::SSLContext* server_ctx_; + security_manager::SSLContext* client_ctx_; testing::NiceMock<security_manager_test::MockCryptoManagerSettings>* - mock_server_manager_settings; + mock_server_manager_settings_; testing::NiceMock<security_manager_test::MockCryptoManagerSettings>* - mock_client_manager_settings; + mock_client_manager_settings_; - const uint8_t* server_buf; - const uint8_t* client_buf; - size_t server_buf_len; - size_t client_buf_len; + const uint8_t* server_buf_; + const uint8_t* client_buf_; + size_t server_buf_len_; + size_t client_buf_len_; std::string server_certificate_; std::string server_ciphers_list_; @@ -335,188 +364,175 @@ class SSLHandshakeTest : public testing::Test { std::string client_certificate_; std::string client_ciphers_list_; std::string client_ca_certificate_path_; + + const std::vector<int> forced_protected_service_; + const std::vector<int> forced_unprotected_service_; }; -TEST_F(SSLHandshakeTest, NoVerification) { - ASSERT_TRUE(InitServerManagers(security_manager::TLSv1_2, +INSTANTIATE_TEST_CASE_P( + CorrectProtocol, + SSLHandshakeTest, + ::testing::Values( + Protocol(security_manager::TLSv1, security_manager::TLSv1), + Protocol(security_manager::TLSv1_1, security_manager::TLSv1_1), + Protocol(security_manager::TLSv1_2, security_manager::TLSv1_2), + Protocol(security_manager::DTLSv1, security_manager::DTLSv1))); + +TEST_P(SSLHandshakeTest, NoVerification) { + ASSERT_TRUE(InitServerManagers(GetParam().server_protocol, server_certificate, "ALL", skip_peer_verification, "")) - << server_manager->LastError(); - ASSERT_TRUE(InitClientManagers(security_manager::TLSv1_2, + << server_manager_->LastError(); + + ASSERT_TRUE(InitClientManagers(GetParam().client_protocol, client_certificate, "ALL", skip_peer_verification, "")) - << client_manager->LastError(); + << client_manager_->LastError(); GTEST_TRACE(HandshakeProcedure_Success()); } -TEST_F(SSLHandshakeTest, CAVerification_ServerSide) { - ASSERT_TRUE(InitServerManagers(security_manager::TLSv1_2, +TEST_P(SSLHandshakeTest, CAVerification_ServerSide) { + ASSERT_TRUE(InitServerManagers(GetParam().server_protocol, server_certificate, "ALL", verify_peer, client_ca_cert_filename)) - << server_manager->LastError(); - ASSERT_TRUE(InitClientManagers(security_manager::TLSv1_2, + << server_manager_->LastError(); + ASSERT_TRUE(InitClientManagers(GetParam().client_protocol, client_certificate, "ALL", skip_peer_verification, "")) - << client_manager->LastError(); + << client_manager_->LastError(); GTEST_TRACE(HandshakeProcedure_Success()); } -TEST_F(SSLHandshakeTest, CAVerification_ServerSide_NoCACertificate) { +TEST_P(SSLHandshakeTest, CAVerification_ServerSide_NoCACertificate) { ASSERT_TRUE(InitServerManagers( - security_manager::TLSv1_2, "", "ALL", verify_peer, "unex")) - << server_manager->LastError(); - ASSERT_TRUE(InitClientManagers(security_manager::TLSv1_2, + GetParam().server_protocol, "", "ALL", verify_peer, "unex")) + << server_manager_->LastError(); + ASSERT_TRUE(InitClientManagers(GetParam().client_protocol, client_certificate, "ALL", skip_peer_verification, "")) - << client_manager->LastError(); + << client_manager_->LastError(); GTEST_TRACE(HandshakeProcedure_ServerSideFail()); - ASSERT_TRUE(InitServerManagers(security_manager::TLSv1_2, + ASSERT_TRUE(InitServerManagers(GetParam().server_protocol, server_certificate, "ALL", verify_peer, client_ca_cert_filename)) - << server_manager->LastError(); + << server_manager_->LastError(); GTEST_TRACE(ResetConnections()); GTEST_TRACE(HandshakeProcedure_Success()); } -TEST_F(SSLHandshakeTest, CAVerification_ClientSide) { - ASSERT_TRUE(InitServerManagers(security_manager::TLSv1_2, - server_certificate, - "ALL", - verify_peer, - client_ca_cert_filename)) - << server_manager->LastError(); - ASSERT_TRUE(InitClientManagers(security_manager::TLSv1_2, - client_certificate, - "ALL", - verify_peer, - server_ca_cert_filename)) - << client_manager->LastError(); - - GTEST_TRACE(HandshakeProcedure_Success()); -} - -TEST_F(SSLHandshakeTest, CAVerification_ClientSide_NoCACertificate) { - ASSERT_TRUE(InitServerManagers(security_manager::TLSv1_2, +TEST_P(SSLHandshakeTest, CAVerification_ClientSide_NoCACertificate) { + ASSERT_TRUE(InitServerManagers(GetParam().server_protocol, server_certificate, "ALL", skip_peer_verification, "")) - << server_manager->LastError(); - ASSERT_TRUE(InitClientManagers(security_manager::TLSv1_2, + << server_manager_->LastError(); + ASSERT_TRUE(InitClientManagers(GetParam().client_protocol, "", "ALL", verify_peer, "client_ca_cert_filename")) - << client_manager->LastError(); + << client_manager_->LastError(); GTEST_TRACE(HandshakeProcedure_ClientSideFail( security_manager::SSLContext::Handshake_Result_Fail)); - ASSERT_TRUE(InitClientManagers(security_manager::TLSv1_2, + ASSERT_TRUE(InitClientManagers(GetParam().client_protocol, client_certificate, "ALL", verify_peer, server_ca_cert_filename)) - << client_manager->LastError(); + << client_manager_->LastError(); GTEST_TRACE(ResetConnections()); GTEST_TRACE(HandshakeProcedure_Success()); } -TEST_F(SSLHandshakeTest, CAVerification_BothSides) { - ASSERT_TRUE(InitServerManagers(security_manager::TLSv1_2, +TEST_P(SSLHandshakeTest, CAVerification_BothSides) { + ASSERT_TRUE(InitServerManagers(GetParam().server_protocol, server_certificate, "ALL", verify_peer, client_ca_cert_filename)) - << server_manager->LastError(); - ASSERT_TRUE(InitClientManagers(security_manager::TLSv1_2, + << server_manager_->LastError(); + ASSERT_TRUE(InitClientManagers(GetParam().client_protocol, client_certificate, "ALL", verify_peer, server_ca_cert_filename)) - << client_manager->LastError(); + << client_manager_->LastError(); GTEST_TRACE(HandshakeProcedure_Success()); } -TEST_F(SSLHandshakeTest, UnsignedCert) { - ASSERT_TRUE(InitServerManagers(security_manager::TLSv1_2, +TEST_P(SSLHandshakeTest, UnsignedCert) { + ASSERT_TRUE(InitServerManagers(GetParam().server_protocol, server_unsigned_cert_file, "ALL", skip_peer_verification, "")) - << server_manager->LastError(); - ASSERT_TRUE(InitClientManagers(security_manager::TLSv1_2, + << server_manager_->LastError(); + ASSERT_TRUE(InitClientManagers(GetParam().client_protocol, client_certificate, "ALL", verify_peer, client_ca_cert_filename)) - << client_manager->LastError(); + << client_manager_->LastError(); GTEST_TRACE(HandshakeProcedure_ClientSideFail( security_manager::SSLContext::Handshake_Result_CertNotSigned)); } -TEST_F(SSLHandshakeTest, ExpiredCert) { - ASSERT_TRUE(InitServerManagers(security_manager::TLSv1_2, +TEST_P(SSLHandshakeTest, ExpiredCert) { + ASSERT_TRUE(InitServerManagers(GetParam().server_protocol, server_expired_cert_file, "ALL", verify_peer, client_ca_cert_filename)) - << server_manager->LastError(); - ASSERT_TRUE(InitClientManagers(security_manager::TLSv1_2, + << server_manager_->LastError(); + ASSERT_TRUE(InitClientManagers(GetParam().client_protocol, client_certificate, "ALL", verify_peer, server_ca_cert_filename)) - << client_manager->LastError(); + << client_manager_->LastError(); GTEST_TRACE(HandshakeProcedure_ClientSideFail( security_manager::SSLContext::Handshake_Result_CertExpired)); } -TEST_F(SSLHandshakeTest, AppNameAndAppIDInvalid) { - ASSERT_TRUE(InitServerManagers(security_manager::TLSv1_2, +TEST_P(SSLHandshakeTest, AppNameAndAppIDInvalid) { + ASSERT_TRUE(InitServerManagers(GetParam().server_protocol, server_certificate, "ALL", verify_peer, client_ca_cert_filename)) - << server_manager->LastError(); - ASSERT_TRUE(InitClientManagers(security_manager::TLSv1_2, + << server_manager_->LastError(); + ASSERT_TRUE(InitClientManagers(GetParam().client_protocol, client_certificate, "ALL", verify_peer, server_ca_cert_filename)) - << client_manager->LastError(); + << client_manager_->LastError(); - client_ctx->SetHandshakeContext( - security_manager::SSLContext::HandshakeContext( - custom_str::CustomString("server"), - custom_str::CustomString("Wrong"))); - - GTEST_TRACE(HandshakeProcedure_ClientSideFail( - security_manager::SSLContext::Handshake_Result_AppNameMismatch)); - - ResetConnections(); - client_ctx->SetHandshakeContext( + client_ctx_->SetHandshakeContext( security_manager::SSLContext::HandshakeContext( custom_str::CustomString("Wrong"), custom_str::CustomString("server"))); @@ -525,19 +541,19 @@ TEST_F(SSLHandshakeTest, AppNameAndAppIDInvalid) { security_manager::SSLContext::Handshake_Result_AppIDMismatch)); } -TEST_F(SSLHandshakeTest, NoVerification_ResetConnection) { - ASSERT_TRUE(InitServerManagers(security_manager::TLSv1_2, +TEST_P(SSLHandshakeTest, NoVerification_ResetConnection) { + ASSERT_TRUE(InitServerManagers(GetParam().server_protocol, server_certificate, "ALL", skip_peer_verification, "")) - << server_manager->LastError(); - ASSERT_TRUE(InitClientManagers(security_manager::TLSv1_2, + << server_manager_->LastError(); + ASSERT_TRUE(InitClientManagers(GetParam().client_protocol, client_certificate, "ALL", skip_peer_verification, "")) - << client_manager->LastError(); + << client_manager_->LastError(); const int times = 100; for (int i = 0; i < times; ++i) { @@ -549,19 +565,19 @@ TEST_F(SSLHandshakeTest, NoVerification_ResetConnection) { } } -TEST_F(SSLHandshakeTest, CAVerification_BothSides_ResetConnection) { - ASSERT_TRUE(InitServerManagers(security_manager::TLSv1_2, +TEST_P(SSLHandshakeTest, CAVerification_BothSides_ResetConnection) { + ASSERT_TRUE(InitServerManagers(GetParam().server_protocol, server_certificate, "ALL", verify_peer, client_ca_cert_filename)) - << server_manager->LastError(); - ASSERT_TRUE(InitClientManagers(security_manager::TLSv1_2, + << server_manager_->LastError(); + ASSERT_TRUE(InitClientManagers(GetParam().client_protocol, client_certificate, "ALL", skip_peer_verification, server_ca_cert_filename)) - << client_manager->LastError(); + << client_manager_->LastError(); const int times = 100; for (int i = 0; i < times; ++i) { @@ -572,7 +588,6 @@ TEST_F(SSLHandshakeTest, CAVerification_BothSides_ResetConnection) { GTEST_TRACE(ResetConnections()); } } - // TODO(EZamakhov): add fail tests -broken or not full ca certificate chain } // namespace ssl_handshake_test diff --git a/src/components/security_manager/test/ssl_context_test.cc b/src/components/security_manager/test/ssl_context_test.cc index a77cd98b27..20e509ebc6 100644 --- a/src/components/security_manager/test/ssl_context_test.cc +++ b/src/components/security_manager/test/ssl_context_test.cc @@ -49,8 +49,11 @@ using ::testing::ReturnRef; using ::testing::NiceMock; namespace { -const size_t kUpdatesBeforeHour = 24; const std::string kCaPath = ""; +const std::string kClientCertPath = "client_certificate.crt"; +const std::string kClientPrivateKeyPath = "client_private.key"; +const std::string kServerCertPath = "server_certificate.crt"; +const std::string kServerPrivateKeyPath = "server_private.key"; const uint8_t* kServerBuf; const uint8_t* kClientBuf; const std::string kAllCiphers = "ALL"; @@ -70,19 +73,19 @@ namespace ssl_context_test { namespace custom_str = utils::custom_string; struct ProtocolAndCipher { - security_manager::Protocol server_protocol; - security_manager::Protocol client_protocol; - std::string server_ciphers_list; - std::string client_ciphers_list; + security_manager::Protocol server_protocol_; + security_manager::Protocol client_protocol_; + std::string server_ciphers_list_; + std::string client_ciphers_list_; ProtocolAndCipher(security_manager::Protocol s_protocol, security_manager::Protocol c_protocol, std::string s_ciphers_list, std::string c_ciphers_list) - : server_protocol(s_protocol) - , client_protocol(c_protocol) - , server_ciphers_list(s_ciphers_list) - , client_ciphers_list(c_ciphers_list) {} + : server_protocol_(s_protocol) + , client_protocol_(c_protocol) + , server_ciphers_list_(s_ciphers_list) + , client_ciphers_list_(c_ciphers_list) {} }; class SSLTest : public testing::Test { @@ -127,6 +130,16 @@ class SSLTest : public testing::Test { .WillRepeatedly(ReturnRef(kCaPath)); EXPECT_CALL(*mock_crypto_manager_settings_, verify_peer()) .WillOnce(Return(false)); + + ON_CALL(*mock_crypto_manager_settings_, force_unprotected_service()) + .WillByDefault(ReturnRef(forced_unprotected_service_)); + ON_CALL(*mock_crypto_manager_settings_, force_protected_service()) + .WillByDefault(ReturnRef(forced_protected_service_)); + ON_CALL(*mock_crypto_manager_settings_, module_cert_path()) + .WillByDefault(ReturnRef(kServerCertPath)); + ON_CALL(*mock_crypto_manager_settings_, module_key_path()) + .WillByDefault(ReturnRef(kServerPrivateKeyPath)); + const bool crypto_manager_initialization = crypto_manager_->Init(); EXPECT_TRUE(crypto_manager_initialization); @@ -150,6 +163,16 @@ class SSLTest : public testing::Test { .WillRepeatedly(ReturnRef(kCaPath)); EXPECT_CALL(*mock_client_manager_settings_, verify_peer()) .WillOnce(Return(false)); + + ON_CALL(*mock_client_manager_settings_, force_unprotected_service()) + .WillByDefault(ReturnRef(forced_unprotected_service_)); + ON_CALL(*mock_client_manager_settings_, force_protected_service()) + .WillByDefault(ReturnRef(forced_protected_service_)); + ON_CALL(*mock_client_manager_settings_, module_cert_path()) + .WillByDefault(ReturnRef(kClientCertPath)); + ON_CALL(*mock_client_manager_settings_, module_key_path()) + .WillByDefault(ReturnRef(kClientPrivateKeyPath)); + const bool client_manager_initialization = client_manager_->Init(); EXPECT_TRUE(client_manager_initialization); @@ -159,19 +182,19 @@ class SSLTest : public testing::Test { .WillByDefault(Return(kMaximumPayloadSize)); EXPECT_CALL(*mock_crypto_manager_settings_, security_manager_mode()) .WillRepeatedly(Return(security_manager::SERVER)); - server_ctx = crypto_manager_->CreateSSLContext(); + server_ctx_ = crypto_manager_->CreateSSLContext(); EXPECT_CALL(*mock_client_manager_settings_, security_manager_mode()) .Times(2) .WillRepeatedly(Return(security_manager::CLIENT)); - client_ctx = client_manager_->CreateSSLContext(); + client_ctx_ = client_manager_->CreateSSLContext(); using custom_str::CustomString; security_manager::SSLContext::HandshakeContext ctx(CustomString("SPT"), CustomString("client")); - server_ctx->SetHandshakeContext(ctx); + server_ctx_->SetHandshakeContext(ctx); ctx.expected_cn = "server"; - client_ctx->SetHandshakeContext(ctx); + client_ctx_->SetHandshakeContext(ctx); kServerBuf = NULL; kClientBuf = NULL; @@ -180,8 +203,8 @@ class SSLTest : public testing::Test { } void TearDown() OVERRIDE { - crypto_manager_->ReleaseSSLContext(server_ctx); - client_manager_->ReleaseSSLContext(client_ctx); + crypto_manager_->ReleaseSSLContext(server_ctx_); + client_manager_->ReleaseSSLContext(client_ctx_); delete crypto_manager_; delete client_manager_; @@ -194,11 +217,14 @@ class SSLTest : public testing::Test { mock_crypto_manager_settings_; utils::SharedPtr<NiceMock<security_manager_test::MockCryptoManagerSettings> > mock_client_manager_settings_; - security_manager::SSLContext* server_ctx; - security_manager::SSLContext* client_ctx; + security_manager::SSLContext* server_ctx_; + security_manager::SSLContext* client_ctx_; static std::string client_certificate_data_base64_; static std::string server_certificate_data_base64_; + + const std::vector<int> forced_unprotected_service_; + const std::vector<int> forced_protected_service_; }; std::string SSLTest::client_certificate_data_base64_; std::string SSLTest::server_certificate_data_base64_; @@ -222,37 +248,38 @@ class SSLTestParam : public testing::TestWithParam<ProtocolAndCipher> { NiceMock<security_manager_test::MockCryptoManagerSettings> >(); utils::SharedPtr<security_manager::CryptoManagerSettings> server_crypto( mock_crypto_manager_settings_); - crypto_manager = new security_manager::CryptoManagerImpl(server_crypto); + crypto_manager_ = new security_manager::CryptoManagerImpl(server_crypto); - SetServerInitialValues(GetParam().server_protocol, - GetParam().server_ciphers_list); + SetServerInitialValues(GetParam().server_protocol_, + GetParam().server_ciphers_list_); - const bool crypto_manager_initialization = crypto_manager->Init(); - ASSERT_TRUE(crypto_manager_initialization); + const bool crypto_manager_initialization = crypto_manager_->Init(); + EXPECT_TRUE(crypto_manager_initialization); mock_client_manager_settings_ = utils::MakeShared< NiceMock<security_manager_test::MockCryptoManagerSettings> >(); utils::SharedPtr<security_manager::CryptoManagerSettings> client_crypto( mock_client_manager_settings_); - client_manager = new security_manager::CryptoManagerImpl(client_crypto); + client_manager_ = new security_manager::CryptoManagerImpl(client_crypto); - SetClientInitialValues(GetParam().client_protocol, - GetParam().client_ciphers_list); + SetClientInitialValues(GetParam().client_protocol_, + GetParam().client_ciphers_list_); - const bool client_manager_initialization = client_manager->Init(); - ASSERT_TRUE(client_manager_initialization); + const bool client_manager_initialization = client_manager_->Init(); + EXPECT_TRUE(client_manager_initialization); - server_ctx = crypto_manager->CreateSSLContext(); - client_ctx = client_manager->CreateSSLContext(); + server_ctx_ = crypto_manager_->CreateSSLContext(); + client_ctx_ = client_manager_->CreateSSLContext(); using custom_str::CustomString; - security_manager::SSLContext::HandshakeContext ctx(CustomString("SPT"), - CustomString("client")); - server_ctx->SetHandshakeContext(ctx); - ctx.expected_cn = "server"; - client_ctx->SetHandshakeContext(ctx); + server_ctx_->SetHandshakeContext( + security_manager::SSLContext::HandshakeContext(CustomString("SPT"), + CustomString("client"))); + client_ctx_->SetHandshakeContext( + security_manager::SSLContext::HandshakeContext(CustomString("SPT"), + CustomString("server"))); kServerBuf = NULL; kClientBuf = NULL; @@ -261,18 +288,19 @@ class SSLTestParam : public testing::TestWithParam<ProtocolAndCipher> { } void TearDown() OVERRIDE { - if (crypto_manager) { - crypto_manager->ReleaseSSLContext(server_ctx); - } - if (client_manager) { - client_manager->ReleaseSSLContext(client_ctx); - } - delete crypto_manager; - delete client_manager; + crypto_manager_->ReleaseSSLContext(server_ctx_); + client_manager_->ReleaseSSLContext(client_ctx_); + + delete crypto_manager_; + delete client_manager_; } void SetServerInitialValues(security_manager::Protocol protocol, const std::string& server_ciphers_list) { + ON_CALL(*mock_crypto_manager_settings_, force_unprotected_service()) + .WillByDefault(ReturnRef(forced_unprotected_service_)); + ON_CALL(*mock_crypto_manager_settings_, force_protected_service()) + .WillByDefault(ReturnRef(forced_protected_service_)); ON_CALL(*mock_crypto_manager_settings_, security_manager_mode()) .WillByDefault(Return(security_manager::SERVER)); ON_CALL(*mock_crypto_manager_settings_, security_manager_protocol_name()) @@ -285,9 +313,18 @@ class SSLTestParam : public testing::TestWithParam<ProtocolAndCipher> { .WillByDefault(ReturnRef(kCaPath)); ON_CALL(*mock_crypto_manager_settings_, verify_peer()) .WillByDefault(Return(false)); + ON_CALL(*mock_crypto_manager_settings_, module_cert_path()) + .WillByDefault(ReturnRef(kServerCertPath)); + ON_CALL(*mock_crypto_manager_settings_, module_key_path()) + .WillByDefault(ReturnRef(kServerPrivateKeyPath)); } + void SetClientInitialValues(security_manager::Protocol protocol, const std::string& client_ciphers_list) { + ON_CALL(*mock_client_manager_settings_, force_unprotected_service()) + .WillByDefault(ReturnRef(forced_unprotected_service_)); + ON_CALL(*mock_client_manager_settings_, force_protected_service()) + .WillByDefault(ReturnRef(forced_protected_service_)); ON_CALL(*mock_client_manager_settings_, security_manager_mode()) .WillByDefault(Return(security_manager::CLIENT)); ON_CALL(*mock_client_manager_settings_, security_manager_protocol_name()) @@ -300,17 +337,23 @@ class SSLTestParam : public testing::TestWithParam<ProtocolAndCipher> { .WillByDefault(ReturnRef(kCaPath)); ON_CALL(*mock_client_manager_settings_, verify_peer()) .WillByDefault(Return(false)); + ON_CALL(*mock_client_manager_settings_, module_cert_path()) + .WillByDefault(ReturnRef(kClientCertPath)); + ON_CALL(*mock_client_manager_settings_, module_key_path()) + .WillByDefault(ReturnRef(kClientPrivateKeyPath)); } utils::SharedPtr<NiceMock<security_manager_test::MockCryptoManagerSettings> > mock_crypto_manager_settings_; utils::SharedPtr<NiceMock<security_manager_test::MockCryptoManagerSettings> > mock_client_manager_settings_; - security_manager::CryptoManager* crypto_manager = NULL; - security_manager::CryptoManager* client_manager = NULL; - security_manager::SSLContext* server_ctx = NULL; - security_manager::SSLContext* client_ctx = NULL; + security_manager::CryptoManager* crypto_manager_; + security_manager::CryptoManager* client_manager_; + security_manager::SSLContext* server_ctx_; + security_manager::SSLContext* client_ctx_; std::string certificate_data_base64_; + const std::vector<int> forced_unprotected_service_; + const std::vector<int> forced_protected_service_; }; class SSLTestForTLS1_2 : public SSLTestParam {}; @@ -319,7 +362,7 @@ class SSLTestForTLS1_2 : public SSLTestParam {}; INSTANTIATE_TEST_CASE_P( CorrectProtocolAndCiphers, SSLTestParam, - ::testing::Values(ProtocolAndCipher(security_manager::TLSv1, + ::testing::Values(ProtocolAndCipher(security_manager::TLSv1_1, security_manager::TLSv1, kFordCipher, kFordCipher), @@ -334,7 +377,11 @@ INSTANTIATE_TEST_CASE_P( kFordCipher, kFordCipher) #endif - )); + , + ProtocolAndCipher(security_manager::DTLSv1, + security_manager::DTLSv1, + kFordCipher, + kFordCipher))); INSTANTIATE_TEST_CASE_P( IncorrectProtocolAndCiphers, @@ -365,6 +412,22 @@ INSTANTIATE_TEST_CASE_P( security_manager::SSLv3, kFordCipher, kFordCipher), + ProtocolAndCipher(security_manager::TLSv1, + security_manager::DTLSv1, + kFordCipher, + kFordCipher), + ProtocolAndCipher(security_manager::DTLSv1, + security_manager::TLSv1_1, + kFordCipher, + kFordCipher), + ProtocolAndCipher(security_manager::TLSv1_2, + security_manager::DTLSv1, + kFordCipher, + kFordCipher), + ProtocolAndCipher(security_manager::TLSv1_1, + security_manager::DTLSv1, + kFordCipher, + kFordCipher), ProtocolAndCipher(security_manager::TLSv1_2, security_manager::SSLv3, kFordCipher, @@ -382,7 +445,8 @@ INSTANTIATE_TEST_CASE_P( TEST_F(SSLTest, OnTSL2Protocol_BrokenHandshake) { ASSERT_EQ(security_manager::SSLContext::Handshake_Result_Success, - client_ctx->StartHandshake(&kClientBuf, &client_buf_len)); + client_ctx_->StartHandshake(&kClientBuf, &client_buf_len)); + ASSERT_FALSE(NULL == kClientBuf); ASSERT_LT(0u, client_buf_len); // Broke 3 bytes for get abnormal fail of handshake @@ -390,26 +454,26 @@ TEST_F(SSLTest, OnTSL2Protocol_BrokenHandshake) { const_cast<uint8_t*>(kClientBuf)[client_buf_len / 2] ^= 0xFF; const_cast<uint8_t*>(kClientBuf)[client_buf_len - 1] ^= 0xFF; ASSERT_EQ(security_manager::SSLContext::Handshake_Result_AbnormalFail, - server_ctx->DoHandshakeStep( + server_ctx_->DoHandshakeStep( kClientBuf, client_buf_len, &kServerBuf, &server_buf_len)); - EXPECT_EQ("Initialization is not completed", server_ctx->LastError()); - EXPECT_EQ("Initialization is not completed", client_ctx->LastError()); + EXPECT_EQ("Initialization is not completed", server_ctx_->LastError()); + EXPECT_EQ("Initialization is not completed", client_ctx_->LastError()); } // TODO {AKozoriz} : Unexpected uncomplited init of SSL component. // In this and next tests. // Must be fixed after merge to develop. TEST_F(SSLTest, OnTSL2Protocol_Positive) { - ASSERT_EQ(client_ctx->StartHandshake(&kClientBuf, &client_buf_len), + ASSERT_EQ(client_ctx_->StartHandshake(&kClientBuf, &client_buf_len), security_manager::SSLContext::Handshake_Result_Success); - EXPECT_FALSE(server_ctx->IsInitCompleted()); + EXPECT_FALSE(server_ctx_->IsInitCompleted()); while (true) { ASSERT_TRUE(NULL != kClientBuf); ASSERT_LT(0u, client_buf_len); const security_manager::SSLContext::HandshakeResult server_result = - server_ctx->DoHandshakeStep( + server_ctx_->DoHandshakeStep( kClientBuf, client_buf_len, &kServerBuf, &server_buf_len); ASSERT_EQ(security_manager::SSLContext::Handshake_Result_Success, server_result); @@ -417,11 +481,11 @@ TEST_F(SSLTest, OnTSL2Protocol_Positive) { ASSERT_LT(0u, server_buf_len); const security_manager::SSLContext::HandshakeResult client_result = - client_ctx->DoHandshakeStep( + client_ctx_->DoHandshakeStep( kServerBuf, server_buf_len, &kClientBuf, &client_buf_len); ASSERT_EQ(security_manager::SSLContext::Handshake_Result_Success, client_result); - if (server_ctx->IsInitCompleted()) { + if (server_ctx_->IsInitCompleted()) { break; } @@ -432,22 +496,22 @@ TEST_F(SSLTest, OnTSL2Protocol_Positive) { ASSERT_TRUE(NULL == kClientBuf); ASSERT_EQ(0u, client_buf_len); // expect both side initialization complete - EXPECT_TRUE(client_ctx->IsInitCompleted()); - EXPECT_TRUE(server_ctx->IsInitCompleted()); + EXPECT_TRUE(client_ctx_->IsInitCompleted()); + EXPECT_TRUE(server_ctx_->IsInitCompleted()); // Encrypt text on client side const uint8_t* text = reinterpret_cast<const uint8_t*>("abra"); const uint8_t* encrypted_text = 0; size_t text_len = 4; size_t encrypted_text_len; - EXPECT_TRUE(client_ctx->Encrypt( + EXPECT_TRUE(client_ctx_->Encrypt( text, text_len, &encrypted_text, &encrypted_text_len)); ASSERT_NE(reinterpret_cast<void*>(NULL), encrypted_text); ASSERT_LT(0u, encrypted_text_len); // Decrypt text on server side - EXPECT_TRUE(server_ctx->Decrypt( + EXPECT_TRUE(server_ctx_->Decrypt( encrypted_text, encrypted_text_len, &text, &text_len)); ASSERT_NE(reinterpret_cast<void*>(NULL), text); ASSERT_LT(0u, text_len); @@ -457,34 +521,34 @@ TEST_F(SSLTest, OnTSL2Protocol_Positive) { TEST_F(SSLTest, OnTSL2Protocol_EcncryptionFail) { ASSERT_EQ(security_manager::SSLContext::Handshake_Result_Success, - client_ctx->StartHandshake(&kClientBuf, &client_buf_len)); + client_ctx_->StartHandshake(&kClientBuf, &client_buf_len)); - while (!server_ctx->IsInitCompleted()) { + while (!server_ctx_->IsInitCompleted()) { ASSERT_FALSE(NULL == kClientBuf); ASSERT_LT(0u, client_buf_len); ASSERT_EQ(security_manager::SSLContext::Handshake_Result_Success, - server_ctx->DoHandshakeStep( + server_ctx_->DoHandshakeStep( kClientBuf, client_buf_len, &kServerBuf, &server_buf_len)); ASSERT_FALSE(NULL == kServerBuf); ASSERT_LT(0u, server_buf_len); ASSERT_EQ(security_manager::SSLContext::Handshake_Result_Success, - client_ctx->DoHandshakeStep( + client_ctx_->DoHandshakeStep( kServerBuf, server_buf_len, &kClientBuf, &client_buf_len)); } // Expect empty buffers after init complete ASSERT_TRUE(NULL == kClientBuf); ASSERT_EQ(0u, client_buf_len); // Expect both side initialization complete - EXPECT_TRUE(client_ctx->IsInitCompleted()); - EXPECT_TRUE(server_ctx->IsInitCompleted()); + EXPECT_TRUE(client_ctx_->IsInitCompleted()); + EXPECT_TRUE(server_ctx_->IsInitCompleted()); // Encrypt text on client side const uint8_t* text = reinterpret_cast<const uint8_t*>("abra"); const uint8_t* encrypted_text = 0; size_t text_len = 4; size_t encrypted_text_len; - EXPECT_TRUE(client_ctx->Encrypt( + EXPECT_TRUE(client_ctx_->Encrypt( text, text_len, &encrypted_text, &encrypted_text_len)); ASSERT_NE(reinterpret_cast<void*>(NULL), encrypted_text); ASSERT_LT(0u, encrypted_text_len); @@ -497,29 +561,30 @@ TEST_F(SSLTest, OnTSL2Protocol_EcncryptionFail) { const uint8_t* out_text; size_t out_text_size; // Decrypt broken text on server side - EXPECT_FALSE(server_ctx->Decrypt( + EXPECT_FALSE(server_ctx_->Decrypt( &broken[0], broken.size(), &out_text, &out_text_size)); // Check after broken message that server encryption and decryption fail // Encrypte message on server side - EXPECT_FALSE(server_ctx->Decrypt( + EXPECT_FALSE(server_ctx_->Decrypt( encrypted_text, encrypted_text_len, &out_text, &out_text_size)); - EXPECT_FALSE(server_ctx->Encrypt( + EXPECT_FALSE(server_ctx_->Encrypt( text, text_len, &encrypted_text, &encrypted_text_len)); } TEST_P(SSLTestParam, ClientAndServerNotTLSv1_2_HandshakeFailed) { ASSERT_EQ(security_manager::SSLContext::Handshake_Result_AbnormalFail, - client_ctx->StartHandshake(&kClientBuf, &client_buf_len)); + client_ctx_->StartHandshake(&kClientBuf, &client_buf_len)); + EXPECT_TRUE(NULL == kClientBuf); EXPECT_EQ(0u, client_buf_len); ASSERT_EQ(security_manager::SSLContext::Handshake_Result_Success, - server_ctx->DoHandshakeStep( + server_ctx_->DoHandshakeStep( kClientBuf, client_buf_len, &kServerBuf, &server_buf_len)); EXPECT_TRUE(NULL == kServerBuf); EXPECT_EQ(0u, server_buf_len); - EXPECT_FALSE(server_ctx->IsInitCompleted()); + EXPECT_FALSE(server_ctx_->IsInitCompleted()); } INSTANTIATE_TEST_CASE_P( @@ -544,16 +609,19 @@ INSTANTIATE_TEST_CASE_P( TEST_P(SSLTestForTLS1_2, HandshakeFailed) { ASSERT_EQ(security_manager::SSLContext::Handshake_Result_Success, - client_ctx->StartHandshake(&kClientBuf, &client_buf_len)); + client_ctx_->StartHandshake(&kClientBuf, &client_buf_len)); EXPECT_FALSE(NULL == kClientBuf); ASSERT_LT(0u, client_buf_len); + ASSERT_EQ(security_manager::SSLContext::Handshake_Result_AbnormalFail, - server_ctx->DoHandshakeStep( - kClientBuf, client_buf_len, &kServerBuf, &server_buf_len)); + server_ctx_->DoHandshakeStep( + kClientBuf, client_buf_len, &kServerBuf, &server_buf_len)) + << ERR_reason_error_string(ERR_get_error()); + EXPECT_TRUE(NULL == kServerBuf); EXPECT_EQ(0u, server_buf_len); - EXPECT_FALSE(server_ctx->IsInitCompleted()); + EXPECT_FALSE(server_ctx_->IsInitCompleted()); } } // namespace ssl_context_test diff --git a/src/components/utils/CMakeLists.txt b/src/components/utils/CMakeLists.txt index 98f3c74145..d4b7dc928f 100644 --- a/src/components/utils/CMakeLists.txt +++ b/src/components/utils/CMakeLists.txt @@ -38,6 +38,7 @@ include_directories ( ${COMPONENTS_DIR}/config_profile/include ${COMPONENTS_DIR}/media_manager/include ${COMPONENTS_DIR}/protocol_handler/include + ${JSONCPP_INCLUDE_DIRECTORY} ${LOG4CXX_INCLUDE_DIRECTORY} ) diff --git a/src/components/utils/include/utils/system_time_handler.h b/src/components/utils/include/utils/system_time_handler.h new file mode 100644 index 0000000000..15b2dd0cca --- /dev/null +++ b/src/components/utils/include/utils/system_time_handler.h @@ -0,0 +1,151 @@ +/* + * Copyright (c) 2018, 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_UTILS_INCLUDE_UTILS_SYSTEM_TIME_HANDLER_H_ +#define SRC_COMPONENTS_UTILS_INCLUDE_UTILS_SYSTEM_TIME_HANDLER_H_ + +#include <time.h> + +namespace utils { + +/** + * @brief The SystemTimeListener interface. + * This interface allows to get notifications whenever + * system time appears or fails to appear. + */ +class SystemTimeListener { + public: + /** + * @brief OnSystemTimeArrived Notify about system time + * in utc format + * @param utc_time current system time. + */ + virtual void OnSystemTimeArrived(const time_t utc_time) = 0; +}; + +/** + * @brief SystemTimeHandler the interface which provides the necessary + * public API to work with system time. The class does not implement + * any logic it's public api forwards call to the private virtual + * methods which are suppose to be defined within specific implementation. + */ +class SystemTimeHandler { + public: + /** + * @brief SystemTimeHandler creates an instance + * for this class. + */ + SystemTimeHandler(); + + /** + * @brief QuerySystemTime provides the public interface + * to retrieve the system time. Interface uses private implementation + * hence the logic will be defined within descendant class. + */ + void QuerySystemTime(); + + /** + * @brief SubscribeOnSystemTime allows to subscribe listener + * to the certain event. This class does not provide such storage. + * It rather uses private pure virtual function. So the final behaviour + * should be defined within the descendant class + */ + void SubscribeOnSystemTime(SystemTimeListener* listener); + + /** + * @brief UnsubscribeFromSystemTime allows to unsubscribe listener + * from the certain event. This class does not manipulate with storage. + * It rather uses private pure virtual function. So the final behaviour + * should be defined within the descendant class + */ + void UnsubscribeFromSystemTime(SystemTimeListener* listener); + + /** + * @brief GetUTCTime allows to obtain cached result for the + * GetSystemTime request + * @return utc time. + */ + time_t GetUTCTime(); + + /** + * @brief Checks if system time is ready + * and can be requested by GetSystemTime request + * @return True if HMI is ready to provide UTC time + * otherwise False + */ + bool system_time_can_be_received() const; + + /** + * @brief ~SystemTimeHandler destroys the object + */ + virtual ~SystemTimeHandler(); + + private: + /** + * @brief DoSystemTimeQuery responsible for the system time querying. + * It is up to implementator how exactly system is going to receive this time. + */ + virtual void DoSystemTimeQuery() = 0; + + /** + * @brief DoSubscribe implements the logic which allows to handle + * subscription process. The handling logic should be defined within + * descendant class. + */ + virtual void DoSubscribe(SystemTimeListener* listener) = 0; + + /** + * @brief DoUnsubscribe implements the logic which allows to handle + * unsubscription process. The handling logic should be defined within + * descendant class. + */ + virtual void DoUnsubscribe(SystemTimeListener* listener) = 0; + + /** + * @brief FetchSystemTime allows to obtain the cached result + * for the GetSystemTime request. + * @return utc time. + */ + virtual time_t FetchSystemTime() = 0; + + /** + * @brief Checks if UTC time is ready to provided by HMI + * and can be requested by GetSystemTime request + * @return True if HMI is ready to provide UTC time + * otherwise False + */ + virtual bool utc_time_can_be_received() const = 0; +}; + +} // namespace utils + +#endif // SRC_COMPONENTS_UTILS_INCLUDE_UTILS_SYSTEM_TIME_HANDLER_H_ diff --git a/src/components/utils/src/system_time_handler.cc b/src/components/utils/src/system_time_handler.cc new file mode 100644 index 0000000000..0c3c62cc53 --- /dev/null +++ b/src/components/utils/src/system_time_handler.cc @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2018, 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 "utils/system_time_handler.h" + +namespace utils { + +SystemTimeHandler::SystemTimeHandler() {} + +SystemTimeHandler::~SystemTimeHandler() {} + +void SystemTimeHandler::QuerySystemTime() { + DoSystemTimeQuery(); +} + +void SystemTimeHandler::SubscribeOnSystemTime(SystemTimeListener* listener) { + DoSubscribe(listener); +} + +void SystemTimeHandler::UnsubscribeFromSystemTime( + SystemTimeListener* listener) { + DoUnsubscribe(listener); +} + +time_t SystemTimeHandler::GetUTCTime() { + return FetchSystemTime(); +} + +bool SystemTimeHandler::system_time_can_be_received() const { + return utc_time_can_be_received(); +} + +} // namespace utils |