summaryrefslogtreecommitdiff
path: root/src/components/security_manager/src/security_manager_impl.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/components/security_manager/src/security_manager_impl.cc')
-rw-r--r--src/components/security_manager/src/security_manager_impl.cc214
1 files changed, 197 insertions, 17 deletions
diff --git a/src/components/security_manager/src/security_manager_impl.cc b/src/components/security_manager/src/security_manager_impl.cc
index 556cc291d1..70f835fb93 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) {
@@ -56,7 +69,7 @@ void SecurityManagerImpl::OnMessageReceived(
return;
}
- SecurityMessage securityMessagePtr(new SecurityQuery());
+ SecurityMessage securityMessagePtr(std::make_shared<SecurityQuery>());
const bool result =
securityMessagePtr->SerializeQuery(message->data(), message->data_size());
if (!result) {
@@ -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,9 +238,34 @@ 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();
+ }
- if (crypto_manager_->IsCertificateUpdateRequired()) {
- NotifyOnCertififcateUpdateRequired();
+ {
+ 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()) {
@@ -198,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;
@@ -219,6 +320,24 @@ void SecurityManagerImpl::StartHandshake(uint32_t connection_key) {
SendHandshakeBinData(connection_key, data, data_size);
}
}
+
+bool SecurityManagerImpl::IsCertificateUpdateRequired(
+ const uint32_t connection_key) {
+ LOG4CXX_AUTO_TRACE(logger_);
+ 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) {
if (!listener) {
LOG4CXX_ERROR(logger_,
@@ -227,6 +346,7 @@ void SecurityManagerImpl::AddListener(SecurityManagerListener* const listener) {
}
listeners_.push_back(listener);
}
+
void SecurityManagerImpl::RemoveListener(
SecurityManagerListener* const listener) {
if (!listener) {
@@ -236,13 +356,46 @@ 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_);
std::list<SecurityManagerListener*>::iterator it = listeners_.begin();
while (it != listeners_.end()) {
if ((*it)->OnHandshakeDone(connection_key, error)) {
- // On get notification remove listener
+ LOG4CXX_DEBUG(logger_, "Destroying listener: " << *it);
+ delete (*it);
it = listeners_.erase(it);
} else {
++it;
@@ -250,7 +403,7 @@ void SecurityManagerImpl::NotifyListenersOnHandshakeDone(
}
}
-void SecurityManagerImpl::NotifyOnCertififcateUpdateRequired() {
+void SecurityManagerImpl::NotifyOnCertificateUpdateRequired() {
LOG4CXX_AUTO_TRACE(logger_);
std::list<SecurityManagerListener*>::iterator it = listeners_.begin();
while (it != listeners_.end()) {
@@ -259,6 +412,33 @@ void SecurityManagerImpl::NotifyOnCertififcateUpdateRequired() {
}
}
+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_);
+
+ std::string certificate_data;
+ for (auto it = listeners_.begin(); it != listeners_.end(); ++it) {
+ if ((*it)->GetPolicyCertificateData(certificate_data)) {
+ LOG4CXX_DEBUG(logger_, "Certificate data received from listener");
+ return certificate_data.empty();
+ }
+ }
+ return false;
+}
+
bool SecurityManagerImpl::ProccessHandshakeData(
const SecurityMessage& inMessage) {
LOG4CXX_INFO(logger_, "SendHandshakeData processing");