summaryrefslogtreecommitdiff
path: root/src/components/security_manager/src
diff options
context:
space:
mode:
authorAndriy Byzhynar <AByzhynar@luxoft.com>2018-02-23 17:54:43 +0200
committerAndriy Byzhynar <AByzhynar@luxoft.com>2018-04-06 11:18:31 +0300
commit546cd986780759dd5eee64998f99bc66099a3b32 (patch)
treecb769a5a625b29ed1e8982c8543594e826e8d31c /src/components/security_manager/src
parent3ba8a85c7fa6b9f7d2c9dca3e102168b3df6a00a (diff)
downloadsdl_core-546cd986780759dd5eee64998f99bc66099a3b32.tar.gz
Implement fully functional GetSystemTime feature
Implemented fully working GetSystemTime feature Fixed UT in the security manager due to code changes Disable randomly failed test
Diffstat (limited to 'src/components/security_manager/src')
-rw-r--r--src/components/security_manager/src/crypto_manager_impl.cc67
-rw-r--r--src/components/security_manager/src/security_manager_impl.cc175
-rw-r--r--src/components/security_manager/src/ssl_context_impl.cc96
3 files changed, 272 insertions, 66 deletions
diff --git a/src/components/security_manager/src/crypto_manager_impl.cc b/src/components/security_manager/src/crypto_manager_impl.cc
index 6bee28a976..8db1d633a7 100644
--- a/src/components/security_manager/src/crypto_manager_impl.cc
+++ b/src/components/security_manager/src/crypto_manager_impl.cc
@@ -63,7 +63,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)
@@ -264,24 +269,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;
@@ -331,8 +329,6 @@ bool CryptoManagerImpl::set_certificate(const std::string& cert_data) {
return false;
}
- asn1_time_to_tm(X509_get_notAfter(cert));
-
if (!SSL_CTX_use_PrivateKey(context_, pkey)) {
LOG4CXX_ERROR(logger_, "Could not use key: " << LastError());
return false;
@@ -359,7 +355,8 @@ bool CryptoManagerImpl::set_certificate(const std::string& cert_data) {
return true;
}
-int CryptoManagerImpl::pull_number_from_buf(char* buf, int* idx) {
+int CryptoManagerImpl::SSLContextImpl::get_number_from_char_buf(
+ char* buf, int* idx) const {
if (!idx) {
return 0;
}
@@ -368,40 +365,6 @@ int CryptoManagerImpl::pull_number_from_buf(char* buf, int* idx) {
return val;
}
-void CryptoManagerImpl::asn1_time_to_tm(ASN1_TIME* time) {
- char* buf = (char*)time->data;
- int index = 0;
- const int year = pull_number_from_buf(buf, &index);
- if (V_ASN1_GENERALIZEDTIME == time->type) {
- expiration_time_.tm_year =
- (year * 100 - 1900) + pull_number_from_buf(buf, &index);
- } else {
- expiration_time_.tm_year = year < 50 ? year + 100 : year;
- }
-
- const int mon = pull_number_from_buf(buf, &index);
- const int day = pull_number_from_buf(buf, &index);
- const int hour = pull_number_from_buf(buf, &index);
- const int mn = pull_number_from_buf(buf, &index);
-
- expiration_time_.tm_mon = mon - 1;
- expiration_time_.tm_mday = day;
- expiration_time_.tm_hour = hour;
- expiration_time_.tm_min = mn;
-
- if (buf[index] == 'Z') {
- expiration_time_.tm_sec = 0;
- }
- if ((buf[index] == '+') || (buf[index] == '-')) {
- const int mn = pull_number_from_buf(buf, &index);
- const int mn1 = pull_number_from_buf(buf, &index);
- expiration_time_.tm_sec = (mn * 3600) + (mn1 * 60);
- } else {
- const int sec = pull_number_from_buf(buf, &index);
- expiration_time_.tm_sec = sec;
- }
-}
-
void CryptoManagerImpl::InitCertExpTime() {
strptime("1 Jan 1970 00:00:00", "%d %b %Y %H:%M:%S", &expiration_time_);
}
diff --git a/src/components/security_manager/src/security_manager_impl.cc b/src/components/security_manager/src/security_manager_impl.cc
index 1853b218b4..d68e6b456e 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,16 +149,20 @@ 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;
+ security_manager::SSLContext* ssl_context = NULL;
+ 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();
@@ -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 (!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;
+ 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()) {
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);
+ NotifyOnCertififcateUpdateRequired();
+ 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));
+
+ std::set<uint32_t>().swap(awaiting_certificate_connections_);
+ 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));
+
+ std::set<uint32_t>().swap(awaiting_time_connections_);
+}
+
void SecurityManagerImpl::NotifyListenersOnHandshakeDone(
const uint32_t& connection_key, SSLContext::HandshakeResult error) {
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 5be5ff8363..69e22dc44e 100644
--- a/src/components/security_manager/src/ssl_context_impl.cc
+++ b/src/components/security_manager/src/ssl_context_impl.cc
@@ -77,6 +77,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);
}
@@ -174,6 +175,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 +208,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,12 +220,42 @@ 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);
+
+ time_t start = convert_asn1_time_to_time_t(notBefore);
+ time_t end = convert_asn1_time_to_time_t(notAfter);
+
+ 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 (end_seconds < 0) {
+ LOG4CXX_ERROR(logger_,
+ "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);
@@ -247,6 +280,47 @@ CryptoManagerImpl::SSLContextImpl::CheckCertContext() {
return Handshake_Result_Success;
}
+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;
+ }
+
+ return mktime(&cert_time);
+}
+
bool CryptoManagerImpl::SSLContextImpl::ReadHandshakeData(
const uint8_t** const out_data, size_t* out_data_size) {
LOG4CXX_AUTO_TRACE(logger_);
@@ -288,7 +362,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 +383,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;
@@ -447,6 +524,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_);