summaryrefslogtreecommitdiff
path: root/src/components/security_manager/src
diff options
context:
space:
mode:
authorJacob Keeler <jacob.keeler@livioradio.com>2016-09-20 11:44:51 -0400
committerJacob Keeler <jacob.keeler@livioradio.com>2016-09-20 14:37:25 -0400
commit039581419749dbdd32590804e8b14a77fcaf9636 (patch)
treeced927fc4bef4686f7373a5f45dd692bd9fc9de0 /src/components/security_manager/src
parent1b96b7c02d2e338b846a7314c6fa0bdaa31f7c5e (diff)
parentaff7f09a4ec07becfb64dc78992580061d3342ff (diff)
downloadsdl_core-039581419749dbdd32590804e8b14a77fcaf9636.tar.gz
Merge branch 'master'
Diffstat (limited to 'src/components/security_manager/src')
-rw-r--r--src/components/security_manager/src/crypto_manager_impl.cc360
-rw-r--r--src/components/security_manager/src/security_manager_impl.cc250
-rw-r--r--src/components/security_manager/src/security_query.cc97
-rw-r--r--src/components/security_manager/src/ssl_context_impl.cc425
4 files changed, 799 insertions, 333 deletions
diff --git a/src/components/security_manager/src/crypto_manager_impl.cc b/src/components/security_manager/src/crypto_manager_impl.cc
index 69121a7b19..f44198953b 100644
--- a/src/components/security_manager/src/crypto_manager_impl.cc
+++ b/src/components/security_manager/src/crypto_manager_impl.cc
@@ -31,143 +31,205 @@
*/
#include "security_manager/crypto_manager_impl.h"
+
#include <openssl/bio.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
+#include <openssl/pkcs12.h>
+
+#include <fstream>
+#include <iostream>
+#include <stdio.h>
+#include <ctime>
#include "security_manager/security_manager.h"
+
#include "utils/logger.h"
#include "utils/atomic.h"
+#include "utils/macro.h"
+#include "utils/scope_guard.h"
+#include "utils/date_time.h"
-#define TLS1_1_MINIMAL_VERSION 0x1000103fL
-#define CONST_SSL_METHOD_MINIMAL_VERSION 0x00909000L
+#define TLS1_1_MINIMAL_VERSION 0x1000103fL
+#define CONST_SSL_METHOD_MINIMAL_VERSION 0x00909000L
namespace security_manager {
-CREATE_LOGGERPTR_GLOBAL(logger_, "CryptoManagerImpl")
+CREATE_LOGGERPTR_GLOBAL(logger_, "SecurityManager")
uint32_t CryptoManagerImpl::instance_count_ = 0;
+sync_primitives::Lock CryptoManagerImpl::instance_lock_;
-CryptoManagerImpl::CryptoManagerImpl()
- : context_(NULL), mode_(CLIENT) {
+namespace {
+int debug_callback(int preverify_ok, X509_STORE_CTX* ctx) {
+ if (!preverify_ok) {
+ const int error = X509_STORE_CTX_get_error(ctx);
+ UNUSED(error);
+ LOG4CXX_WARN(logger_,
+ "Certificate verification failed with error "
+ << error << " \"" << X509_verify_cert_error_string(error)
+ << '"');
+ }
+ return preverify_ok;
}
-bool CryptoManagerImpl::Init(Mode mode,
- Protocol protocol,
- const std::string &cert_filename,
- const std::string &key_filename,
- const std::string &ciphers_list,
- bool verify_peer) {
- if (atomic_post_inc(&instance_count_) == 0) {
+void free_ctx(SSL_CTX** ctx) {
+ if (ctx) {
+ SSL_CTX_free(*ctx);
+ *ctx = NULL;
+ }
+}
+}
+
+CryptoManagerImpl::CryptoManagerImpl(
+ const utils::SharedPtr<const CryptoManagerSettings> set)
+ : settings_(set), context_(NULL) {
+ LOG4CXX_AUTO_TRACE(logger_);
+ sync_primitives::AutoLock lock(instance_lock_);
+ instance_count_++;
+ if (instance_count_ == 1) {
+ LOG4CXX_DEBUG(logger_, "Openssl engine initialization");
SSL_load_error_strings();
ERR_load_BIO_strings();
OpenSSL_add_all_algorithms();
SSL_library_init();
}
+}
- mode_ = mode;
+CryptoManagerImpl::~CryptoManagerImpl() {
+ LOG4CXX_AUTO_TRACE(logger_);
+ sync_primitives::AutoLock lock(instance_lock_);
+ LOG4CXX_DEBUG(logger_, "Deinitilization");
+ if (!context_) {
+ LOG4CXX_WARN(logger_, "Manager is not initialized");
+ } else {
+ SSL_CTX_free(context_);
+ }
+ instance_count_--;
+ if (instance_count_ == 0) {
+ LOG4CXX_DEBUG(logger_, "Openssl engine deinitialization");
+ EVP_cleanup();
+ ERR_free_strings();
+ }
+}
+
+bool CryptoManagerImpl::Init() {
+ LOG4CXX_AUTO_TRACE(logger_);
+
+ const Mode mode = get_settings().security_manager_mode();
const bool is_server = (mode == SERVER);
+ if (is_server) {
+ LOG4CXX_DEBUG(logger_, "Server mode");
+ } else {
+ LOG4CXX_DEBUG(logger_, "Client mode");
+ }
+ LOG4CXX_DEBUG(logger_,
+ "Peer verification "
+ << (get_settings().verify_peer() ? "enabled" : "disabled"));
+ LOG4CXX_DEBUG(logger_,
+ "CA certificate file is \"" << get_settings().ca_cert_path()
+ << '"');
+
#if OPENSSL_VERSION_NUMBER < CONST_SSL_METHOD_MINIMAL_VERSION
- SSL_METHOD *method;
+ SSL_METHOD* method;
#else
- const SSL_METHOD *method;
+ const SSL_METHOD* method;
#endif
- switch (protocol) {
+ switch (get_settings().security_manager_protocol_name()) {
case SSLv3:
- method = is_server ?
- SSLv3_server_method() :
- SSLv3_client_method();
+ method = is_server ? SSLv3_server_method() : SSLv3_client_method();
break;
case TLSv1:
- method = is_server ?
- TLSv1_server_method() :
- TLSv1_client_method();
+ method = is_server ? TLSv1_server_method() : TLSv1_client_method();
break;
case TLSv1_1:
#if OPENSSL_VERSION_NUMBER < TLS1_1_MINIMAL_VERSION
- LOG4CXX_WARN(logger_,
- "OpenSSL has no TLSv1.1 with version lower 1.0.1, set TLSv1.0");
- method = is_server ?
- TLSv1_server_method() :
- TLSv1_client_method();
+ LOG4CXX_WARN(
+ logger_,
+ "OpenSSL has no TLSv1.1 with version lower 1.0.1, set TLSv1.0");
+ method = is_server ? TLSv1_server_method() : TLSv1_client_method();
#else
- method = is_server ?
- TLSv1_1_server_method() :
- TLSv1_1_client_method();
+ method = is_server ? TLSv1_1_server_method() : TLSv1_1_client_method();
#endif
break;
case TLSv1_2:
#if OPENSSL_VERSION_NUMBER < TLS1_1_MINIMAL_VERSION
- LOG4CXX_WARN(logger_,
- "OpenSSL has no TLSv1.2 with version lower 1.0.1, set TLSv1.0");
- method = is_server ?
- TLSv1_server_method() :
- TLSv1_client_method();
+ LOG4CXX_WARN(
+ logger_,
+ "OpenSSL has no TLSv1.2 with version lower 1.0.1, set TLSv1.0");
+ method = is_server ? TLSv1_server_method() : TLSv1_client_method();
#else
- method = is_server ?
- TLSv1_2_server_method() :
- TLSv1_2_client_method();
+ method = is_server ? TLSv1_2_server_method() : TLSv1_2_client_method();
#endif
break;
default:
- LOG4CXX_ERROR(logger_, "Unknown protocol: " << protocol);
+ LOG4CXX_ERROR(logger_,
+ "Unknown protocol: "
+ << get_settings().security_manager_protocol_name());
return false;
}
+ if (context_) {
+ free_ctx(&context_);
+ }
context_ = SSL_CTX_new(method);
+ utils::ScopeGuard guard = utils::MakeGuard(free_ctx, &context_);
+
// Disable SSL2 as deprecated
SSL_CTX_set_options(context_, SSL_OP_NO_SSLv2);
- if (cert_filename.empty()) {
- LOG4CXX_WARN(logger_, "Empty certificate path");
+ set_certificate(get_settings().certificate_data());
+
+ if (get_settings().ciphers_list().empty()) {
+ LOG4CXX_WARN(logger_, "Empty ciphers list");
} else {
- LOG4CXX_INFO(logger_, "Certificate path: " << cert_filename);
- if (!SSL_CTX_use_certificate_file(context_, cert_filename.c_str(),
- SSL_FILETYPE_PEM)) {
- LOG4CXX_ERROR(logger_, "Could not use certificate " << cert_filename);
+ LOG4CXX_DEBUG(logger_, "Cipher list: " << get_settings().ciphers_list());
+ if (!SSL_CTX_set_cipher_list(context_,
+ get_settings().ciphers_list().c_str())) {
+ LOG4CXX_ERROR(
+ logger_,
+ "Could not set cipher list: " << get_settings().ciphers_list());
return false;
}
}
- if (key_filename.empty()) {
- LOG4CXX_WARN(logger_, "Empty key path");
- } else {
- LOG4CXX_INFO(logger_, "Key path: " << key_filename);
- if (!SSL_CTX_use_PrivateKey_file(context_, key_filename.c_str(),
- SSL_FILETYPE_PEM)) {
- LOG4CXX_ERROR(logger_, "Could not use key " << key_filename);
- return false;
- }
- if (!SSL_CTX_check_private_key(context_)) {
- LOG4CXX_ERROR(logger_, "Could not use certificate " << cert_filename);
- return false;
- }
+ if (get_settings().ca_cert_path().empty()) {
+ LOG4CXX_WARN(logger_, "Setting up empty CA certificate location");
}
- if (ciphers_list.empty()) {
- LOG4CXX_WARN(logger_, "Empty ciphers list");
- } else {
- LOG4CXX_INFO(logger_, "Cipher list: " << ciphers_list);
- if (!SSL_CTX_set_cipher_list(context_, ciphers_list.c_str())) {
- LOG4CXX_ERROR(logger_, "Could not set cipher list: " << ciphers_list);
- return false;
- }
+ LOG4CXX_DEBUG(logger_, "Setting up CA certificate location");
+ const int result = SSL_CTX_load_verify_locations(
+ context_, NULL, get_settings().ca_cert_path().c_str());
+
+ if (!result) {
+ const unsigned long error = ERR_get_error();
+ UNUSED(error);
+ LOG4CXX_WARN(logger_,
+ "Wrong certificate file '"
+ << get_settings().ca_cert_path() << "', err 0x" << std::hex
+ << error << " \"" << ERR_reason_error_string(error)
+ << '"');
}
- // TODO(EZamakhov): add loading SSL_VERIFY_FAIL_IF_NO_PEER_CERT from INI
- const int verify_mode = verify_peer
- ? SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT
- : SSL_VERIFY_NONE;
- SSL_CTX_set_verify(context_, verify_mode, NULL);
+ guard.Dismiss();
+ const int verify_mode =
+ get_settings().verify_peer()
+ ? SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT
+ : SSL_VERIFY_NONE;
+ LOG4CXX_DEBUG(logger_,
+ "Setting up peer verification in mode: " << verify_mode);
+ SSL_CTX_set_verify(context_, verify_mode, &debug_callback);
return true;
}
-void CryptoManagerImpl::Finish() {
- SSL_CTX_free(context_);
- if (atomic_post_dec(&instance_count_) == 1) {
- EVP_cleanup();
- ERR_free_strings();
+bool CryptoManagerImpl::OnCertificateUpdated(const std::string& data) {
+ LOG4CXX_AUTO_TRACE(logger_);
+ if (!context_) {
+ LOG4CXX_WARN(logger_, "Not initialized");
+ return false;
}
+
+ return set_certificate(data);
}
SSLContext* CryptoManagerImpl::CreateSSLContext() {
@@ -175,19 +237,21 @@ SSLContext* CryptoManagerImpl::CreateSSLContext() {
return NULL;
}
- SSL *conn = SSL_new(context_);
+ SSL* conn = SSL_new(context_);
if (conn == NULL)
return NULL;
- if (mode_ == SERVER) {
+ if (get_settings().security_manager_mode() == SERVER) {
SSL_set_accept_state(conn);
} else {
SSL_set_connect_state(conn);
}
- return new SSLContextImpl(conn, mode_);
+ return new SSLContextImpl(conn,
+ get_settings().security_manager_mode(),
+ get_settings().maximum_payload_size());
}
-void CryptoManagerImpl::ReleaseSSLContext(SSLContext *context) {
+void CryptoManagerImpl::ReleaseSSLContext(SSLContext* context) {
delete context;
}
@@ -195,8 +259,142 @@ std::string CryptoManagerImpl::LastError() const {
if (!context_) {
return std::string("Initialization is not completed");
}
- const char *reason = ERR_reason_error_string(ERR_get_error());
+ const char* reason = ERR_reason_error_string(ERR_get_error());
return std::string(reason ? reason : "");
}
+bool CryptoManagerImpl::IsCertificateUpdateRequired() const {
+ LOG4CXX_AUTO_TRACE(logger_);
+
+ const time_t cert_date = mktime(&expiration_time_);
+
+ if (cert_date == -1) {
+ LOG4CXX_WARN(logger_,
+ "The certifiacte expiration time cannot be represented.");
+ return false;
+ }
+ const time_t now = time(NULL);
+ const double seconds = difftime(cert_date, now);
+
+ LOG4CXX_DEBUG(logger_,
+ "Certificate expiration time: " << asctime(&expiration_time_));
+ LOG4CXX_DEBUG(logger_,
+ "Host time: " << asctime(localtime(&now))
+ << ". Seconds before expiration: " << seconds);
+ if (seconds < 0) {
+ LOG4CXX_WARN(logger_, "Certificate is already expired.");
+ return true;
+ }
+
+ return seconds <= (get_settings().update_before_hours() *
+ date_time::DateTime::SECONDS_IN_HOUR);
+}
+
+const CryptoManagerSettings& CryptoManagerImpl::get_settings() const {
+ return *settings_;
+}
+
+bool CryptoManagerImpl::set_certificate(const std::string& cert_data) {
+ if (cert_data.empty()) {
+ LOG4CXX_WARN(logger_, "Empty certificate");
+ return false;
+ }
+
+ BIO* bio = BIO_new(BIO_f_base64());
+ BIO* bmem = BIO_new_mem_buf((char*)cert_data.c_str(), cert_data.length());
+ bmem = BIO_push(bio, bmem);
+
+ char* buf = new char[cert_data.length()];
+ int len = BIO_read(bmem, buf, cert_data.length());
+
+ BIO* bio_cert = BIO_new(BIO_s_mem());
+ if (NULL == bio_cert) {
+ LOG4CXX_WARN(logger_, "Unable to update certificate. BIO not created");
+ return false;
+ }
+
+ utils::ScopeGuard bio_guard = utils::MakeGuard(BIO_free, bio_cert);
+ UNUSED(bio_guard)
+ int k = 0;
+ if ((k = BIO_write(bio_cert, buf, len)) <= 0) {
+ LOG4CXX_WARN(logger_, "Unable to write into BIO");
+ return false;
+ }
+
+ PKCS12* p12 = d2i_PKCS12_bio(bio_cert, NULL);
+ if (NULL == p12) {
+ LOG4CXX_ERROR(logger_, "Unable to parse certificate");
+ return false;
+ }
+
+ EVP_PKEY* pkey = NULL;
+ X509* cert = NULL;
+ PKCS12_parse(p12, NULL, &pkey, &cert, NULL);
+
+ if (NULL == cert || NULL == pkey) {
+ LOG4CXX_WARN(logger_, "Either certificate or key not valid.");
+ return false;
+ }
+
+ if (!SSL_CTX_use_certificate(context_, cert)) {
+ LOG4CXX_WARN(logger_, "Could not use certificate");
+ return false;
+ }
+
+ asn1_time_to_tm(X509_get_notAfter(cert));
+
+ if (!SSL_CTX_use_PrivateKey(context_, pkey)) {
+ LOG4CXX_ERROR(logger_, "Could not use key");
+ return false;
+ }
+ if (!SSL_CTX_check_private_key(context_)) {
+ LOG4CXX_ERROR(logger_, "Could not use certificate ");
+ return false;
+ }
+ return true;
+}
+
+int CryptoManagerImpl::pull_number_from_buf(char* buf, int* idx) {
+ if (!idx) {
+ return 0;
+ }
+ const int val = ((buf[*idx] - '0') * 10) + buf[(*idx) + 1] - '0';
+ *idx = *idx + 2;
+ return val;
+}
+
+void CryptoManagerImpl::asn1_time_to_tm(ASN1_TIME* time) {
+ char* buf = (char*)time->data;
+ int index = 0;
+ const int year = pull_number_from_buf(buf, &index);
+ if (V_ASN1_GENERALIZEDTIME == time->type) {
+ expiration_time_.tm_year =
+ (year * 100 - 1900) + pull_number_from_buf(buf, &index);
+ } else {
+ expiration_time_.tm_year = year < 50 ? year + 100 : year;
+ }
+
+ const int mon = pull_number_from_buf(buf, &index);
+ const int day = pull_number_from_buf(buf, &index);
+ const int hour = pull_number_from_buf(buf, &index);
+ const int mn = pull_number_from_buf(buf, &index);
+
+ expiration_time_.tm_mon = mon - 1;
+ expiration_time_.tm_mday = day;
+ expiration_time_.tm_hour = hour;
+ expiration_time_.tm_min = mn;
+
+ if (buf[index] == 'Z') {
+ expiration_time_.tm_sec = 0;
+ }
+ if ((buf[index] == '+') || (buf[index] == '-')) {
+ const int mn = pull_number_from_buf(buf, &index);
+ const int mn1 = pull_number_from_buf(buf, &index);
+ expiration_time_.tm_sec = (mn * 3600) + (mn1 * 60);
+ } else {
+ const int sec = pull_number_from_buf(buf, &index);
+ expiration_time_.tm_sec = sec;
+ }
+}
+
} // namespace security_manager
diff --git a/src/components/security_manager/src/security_manager_impl.cc b/src/components/security_manager/src/security_manager_impl.cc
index dee1770e70..556cc291d1 100644
--- a/src/components/security_manager/src/security_manager_impl.cc
+++ b/src/components/security_manager/src/security_manager_impl.cc
@@ -45,9 +45,10 @@ static const char* kErrId = "id";
static const char* kErrText = "text";
SecurityManagerImpl::SecurityManagerImpl()
- : security_messages_("SecurityManager", this),
- session_observer_(NULL), crypto_manager_(NULL), protocol_handler_(NULL) {
-}
+ : security_messages_("SecurityManager", this)
+ , session_observer_(NULL)
+ , crypto_manager_(NULL)
+ , protocol_handler_(NULL) {}
void SecurityManagerImpl::OnMessageReceived(
const ::protocol_handler::RawMessagePtr message) {
@@ -56,14 +57,14 @@ void SecurityManagerImpl::OnMessageReceived(
}
SecurityMessage securityMessagePtr(new SecurityQuery());
- const bool result = securityMessagePtr->SerializeQuery(
- message->data(), message->data_size());
+ const bool result =
+ securityMessagePtr->SerializeQuery(message->data(), message->data_size());
if (!result) {
// result will be false only if data less then query header
const std::string error_text("Incorrect message received");
LOG4CXX_ERROR(logger_, error_text);
- SendInternalError(message->connection_key(),
- ERROR_INVALID_QUERY_SIZE, error_text);
+ SendInternalError(
+ message->connection_key(), ERROR_INVALID_QUERY_SIZE, error_text);
return;
}
securityMessagePtr->set_connection_key(message->connection_key());
@@ -73,11 +74,10 @@ void SecurityManagerImpl::OnMessageReceived(
}
void SecurityManagerImpl::OnMobileMessageSent(
- const ::protocol_handler::RawMessagePtr ) {
-}
+ const ::protocol_handler::RawMessagePtr) {}
void SecurityManagerImpl::set_session_observer(
- protocol_handler::SessionObserver *observer) {
+ protocol_handler::SessionObserver* observer) {
if (!observer) {
LOG4CXX_ERROR(logger_, "Invalid (NULL) pointer to SessionObserver.");
return;
@@ -86,7 +86,7 @@ void SecurityManagerImpl::set_session_observer(
}
void SecurityManagerImpl::set_protocol_handler(
- protocol_handler::ProtocolHandler *handler) {
+ protocol_handler::ProtocolHandler* handler) {
if (!handler) {
LOG4CXX_ERROR(logger_, "Invalid (NULL) pointer to ProtocolHandler.");
return;
@@ -94,7 +94,7 @@ void SecurityManagerImpl::set_protocol_handler(
protocol_handler_ = handler;
}
-void SecurityManagerImpl::set_crypto_manager(CryptoManager *crypto_manager) {
+void SecurityManagerImpl::set_crypto_manager(CryptoManager* crypto_manager) {
if (!crypto_manager) {
LOG4CXX_ERROR(logger_, "Invalid (NULL) pointer to CryptoManager.");
return;
@@ -105,11 +105,11 @@ void SecurityManagerImpl::set_crypto_manager(CryptoManager *crypto_manager) {
void SecurityManagerImpl::Handle(const SecurityMessage message) {
DCHECK(message);
LOG4CXX_INFO(logger_, "Received Security message from Mobile side");
- if (!crypto_manager_) {
+ if (!crypto_manager_) {
const std::string error_text("Invalid (NULL) CryptoManager.");
LOG4CXX_ERROR(logger_, error_text);
- SendInternalError(message->get_connection_key(),
- ERROR_NOT_SUPPORTED, error_text);
+ SendInternalError(
+ message->get_connection_key(), ERROR_NOT_SUPPORTED, error_text);
return;
}
switch (message->get_header().query_id) {
@@ -128,21 +128,21 @@ void SecurityManagerImpl::Handle(const SecurityMessage message) {
const std::string error_text("Unknown query identifier.");
LOG4CXX_ERROR(logger_, error_text);
SendInternalError(message->get_connection_key(),
- ERROR_INVALID_QUERY_ID, error_text,
+ ERROR_INVALID_QUERY_ID,
+ error_text,
message->get_header().seq_number);
- }
- break;
- }
+ } break;
+ }
}
-security_manager::SSLContext *SecurityManagerImpl::CreateSSLContext(
- const uint32_t &connection_key) {
+security_manager::SSLContext* SecurityManagerImpl::CreateSSLContext(
+ const uint32_t& connection_key) {
LOG4CXX_INFO(logger_, "ProtectService processing");
DCHECK(session_observer_);
DCHECK(crypto_manager_);
- security_manager::SSLContext *ssl_context =
- session_observer_->GetSSLContext(connection_key, protocol_handler::kControl);
+ security_manager::SSLContext* ssl_context = session_observer_->GetSSLContext(
+ connection_key, protocol_handler::kControl);
// return exists SSLCOntext for current connection/session
if (ssl_context) {
return ssl_context;
@@ -153,12 +153,12 @@ security_manager::SSLContext *SecurityManagerImpl::CreateSSLContext(
const std::string error_text("CryptoManager could not create SSL context.");
LOG4CXX_ERROR(logger_, error_text);
// Generate response query and post to security_messages_
- SendInternalError(connection_key, ERROR_INTERNAL,
- error_text);
+ SendInternalError(connection_key, ERROR_INTERNAL, error_text);
return NULL;
}
- const int result = session_observer_->SetSSLContext(connection_key, ssl_context);
+ const int result =
+ session_observer_->SetSSLContext(connection_key, ssl_context);
if (ERROR_SUCCESS != result) {
// delete SSLContext on any error
crypto_manager_->ReleaseSSLContext(ssl_context);
@@ -167,38 +167,51 @@ security_manager::SSLContext *SecurityManagerImpl::CreateSSLContext(
}
DCHECK(session_observer_->GetSSLContext(connection_key,
protocol_handler::kControl));
- LOG4CXX_DEBUG(logger_, "Set SSL context to connection_key " << connection_key);
+ LOG4CXX_DEBUG(logger_,
+ "Set SSL context to connection_key " << connection_key);
return ssl_context;
}
void SecurityManagerImpl::StartHandshake(uint32_t connection_key) {
DCHECK(session_observer_);
LOG4CXX_INFO(logger_, "StartHandshake: connection_key " << connection_key);
- security_manager::SSLContext *ssl_context =
- session_observer_->GetSSLContext(connection_key,
- protocol_handler::kControl);
+ security_manager::SSLContext* ssl_context = session_observer_->GetSSLContext(
+ connection_key, protocol_handler::kControl);
if (!ssl_context) {
- const std::string error_text("StartHandshake failed, "
- "connection is not protected");
+ const std::string error_text(
+ "StartHandshake failed, "
+ "connection is not protected");
LOG4CXX_ERROR(logger_, error_text);
SendInternalError(connection_key, ERROR_INTERNAL, error_text);
- NotifyListenersOnHandshakeDone(connection_key, false);
+ NotifyListenersOnHandshakeDone(connection_key,
+ SSLContext::Handshake_Result_Fail);
return;
}
+ if (crypto_manager_->IsCertificateUpdateRequired()) {
+ NotifyOnCertififcateUpdateRequired();
+ }
+
if (ssl_context->IsInitCompleted()) {
- NotifyListenersOnHandshakeDone(connection_key, true);
+ NotifyListenersOnHandshakeDone(connection_key,
+ SSLContext::Handshake_Result_Success);
return;
}
+
+ ssl_context->SetHandshakeContext(
+ session_observer_->GetHandshakeContext(connection_key));
+
size_t data_size = 0;
- const uint8_t *data = NULL;
+ const uint8_t* data = NULL;
+
const security_manager::SSLContext::HandshakeResult result =
ssl_context->StartHandshake(&data, &data_size);
if (security_manager::SSLContext::Handshake_Result_Success != result) {
const std::string error_text("StartHandshake failed, handshake step fail");
LOG4CXX_ERROR(logger_, error_text);
SendInternalError(connection_key, ERROR_INTERNAL, error_text);
- NotifyListenersOnHandshakeDone(connection_key, false);
+ NotifyListenersOnHandshakeDone(connection_key,
+ SSLContext::Handshake_Result_Fail);
return;
}
// for client mode will be generated output data
@@ -206,26 +219,29 @@ void SecurityManagerImpl::StartHandshake(uint32_t connection_key) {
SendHandshakeBinData(connection_key, data, data_size);
}
}
-void SecurityManagerImpl::AddListener(SecurityManagerListener *const listener) {
+void SecurityManagerImpl::AddListener(SecurityManagerListener* const listener) {
if (!listener) {
- LOG4CXX_ERROR(logger_, "Invalid (NULL) pointer to SecurityManagerListener.");
+ LOG4CXX_ERROR(logger_,
+ "Invalid (NULL) pointer to SecurityManagerListener.");
return;
}
listeners_.push_back(listener);
}
-void SecurityManagerImpl::RemoveListener(SecurityManagerListener *const listener) {
+void SecurityManagerImpl::RemoveListener(
+ SecurityManagerListener* const listener) {
if (!listener) {
- LOG4CXX_ERROR(logger_, "Invalid (NULL) pointer to SecurityManagerListener.");
+ LOG4CXX_ERROR(logger_,
+ "Invalid (NULL) pointer to SecurityManagerListener.");
return;
}
listeners_.remove(listener);
}
-void SecurityManagerImpl::NotifyListenersOnHandshakeDone(const uint32_t &connection_key,
- const bool success) {
- LOG4CXX_TRACE(logger_, "NotifyListenersOnHandshakeDone");
+void SecurityManagerImpl::NotifyListenersOnHandshakeDone(
+ const uint32_t& connection_key, SSLContext::HandshakeResult error) {
+ LOG4CXX_AUTO_TRACE(logger_);
std::list<SecurityManagerListener*>::iterator it = listeners_.begin();
while (it != listeners_.end()) {
- if ((*it)->OnHandshakeDone(connection_key, success)) {
+ if ((*it)->OnHandshakeDone(connection_key, error)) {
// On get notification remove listener
it = listeners_.erase(it);
} else {
@@ -234,140 +250,166 @@ void SecurityManagerImpl::NotifyListenersOnHandshakeDone(const uint32_t &connect
}
}
-bool SecurityManagerImpl::ProccessHandshakeData(const SecurityMessage &inMessage) {
+void SecurityManagerImpl::NotifyOnCertififcateUpdateRequired() {
+ LOG4CXX_AUTO_TRACE(logger_);
+ std::list<SecurityManagerListener*>::iterator it = listeners_.begin();
+ while (it != listeners_.end()) {
+ (*it)->OnCertificateUpdateRequired();
+ ++it;
+ }
+}
+
+bool SecurityManagerImpl::ProccessHandshakeData(
+ const SecurityMessage& inMessage) {
LOG4CXX_INFO(logger_, "SendHandshakeData processing");
DCHECK(inMessage);
- DCHECK(inMessage->get_header().query_id == SecurityQuery::SEND_HANDSHAKE_DATA);
+ DCHECK(inMessage->get_header().query_id ==
+ SecurityQuery::SEND_HANDSHAKE_DATA);
const uint32_t seqNumber = inMessage->get_header().seq_number;
const uint32_t connection_key = inMessage->get_connection_key();
- LOG4CXX_DEBUG(logger_, "Received " << inMessage->get_data_size()
- << " bytes handshake data ");
+ LOG4CXX_DEBUG(logger_,
+ "Received " << inMessage->get_data_size()
+ << " bytes handshake data ");
if (!inMessage->get_data_size()) {
const std::string error_text("SendHandshakeData: null arguments size.");
LOG4CXX_ERROR(logger_, error_text);
- SendInternalError(connection_key, ERROR_INVALID_QUERY_SIZE,
- error_text, seqNumber);
+ SendInternalError(
+ connection_key, ERROR_INVALID_QUERY_SIZE, error_text, seqNumber);
return false;
}
DCHECK(session_observer_);
- SSLContext *sslContext =
- session_observer_->GetSSLContext(connection_key,
- protocol_handler::kControl);
+ SSLContext* sslContext = session_observer_->GetSSLContext(
+ connection_key, protocol_handler::kControl);
if (!sslContext) {
const std::string error_text("SendHandshakeData: No ssl context.");
LOG4CXX_ERROR(logger_, error_text);
- SendInternalError(connection_key, ERROR_SERVICE_NOT_PROTECTED,
- error_text, seqNumber);
- NotifyListenersOnHandshakeDone(connection_key, false);
+ SendInternalError(
+ connection_key, ERROR_SERVICE_NOT_PROTECTED, error_text, seqNumber);
+ NotifyListenersOnHandshakeDone(connection_key,
+ SSLContext::Handshake_Result_Fail);
return false;
}
size_t out_data_size;
- const uint8_t *out_data;
+ const uint8_t* out_data;
const SSLContext::HandshakeResult handshake_result =
- sslContext->DoHandshakeStep(inMessage->get_data(), inMessage->get_data_size(),
- &out_data, &out_data_size);
+ sslContext->DoHandshakeStep(inMessage->get_data(),
+ inMessage->get_data_size(),
+ &out_data,
+ &out_data_size);
if (handshake_result == SSLContext::Handshake_Result_AbnormalFail) {
// Do not return handshake data on AbnormalFail or null returned values
const std::string erorr_text(sslContext->LastError());
- LOG4CXX_ERROR(logger_, "SendHandshakeData: Handshake failed: " << erorr_text);
- SendInternalError(connection_key,
- ERROR_SSL_INVALID_DATA, erorr_text, seqNumber);
- NotifyListenersOnHandshakeDone(connection_key, false);
+ LOG4CXX_ERROR(logger_,
+ "SendHandshakeData: Handshake failed: " << erorr_text);
+ SendInternalError(
+ connection_key, ERROR_SSL_INVALID_DATA, erorr_text, seqNumber);
+ NotifyListenersOnHandshakeDone(connection_key,
+ SSLContext::Handshake_Result_Fail);
// no handshake data to send
return false;
}
if (sslContext->IsInitCompleted()) {
// On handshake success
LOG4CXX_DEBUG(logger_, "SSL initialization finished success.");
- NotifyListenersOnHandshakeDone(connection_key, true);
- } else if (handshake_result == SSLContext::Handshake_Result_Fail) {
+ NotifyListenersOnHandshakeDone(connection_key,
+ SSLContext::Handshake_Result_Success);
+ } else if (handshake_result != SSLContext::Handshake_Result_Success) {
// On handshake fail
LOG4CXX_WARN(logger_, "SSL initialization finished with fail.");
- NotifyListenersOnHandshakeDone(connection_key, false);
+ NotifyListenersOnHandshakeDone(connection_key, handshake_result);
}
if (out_data && out_data_size) {
// answer with the same seqNumber as income message
- SendHandshakeBinData(connection_key, out_data, out_data_size,
- seqNumber);
+ SendHandshakeBinData(connection_key, out_data, out_data_size, seqNumber);
}
return true;
}
-bool SecurityManagerImpl::ProccessInternalError(const SecurityMessage &inMessage) {
- LOG4CXX_INFO(logger_, "Received InternalError with Json message"
- << inMessage->get_json_message());
+bool SecurityManagerImpl::ProccessInternalError(
+ const SecurityMessage& inMessage) {
+ LOG4CXX_INFO(logger_,
+ "Received InternalError with Json message"
+ << inMessage->get_json_message());
Json::Value root;
Json::Reader reader;
const bool parsingSuccessful =
reader.parse(inMessage->get_json_message(), root);
if (!parsingSuccessful)
return false;
- LOG4CXX_DEBUG(logger_, "Received InternalError id " << root[kErrId].asString()
- << ", text: " << root[kErrText].asString());
+ LOG4CXX_DEBUG(logger_,
+ "Received InternalError id "
+ << root[kErrId].asString()
+ << ", text: " << root[kErrText].asString());
return true;
}
-void SecurityManagerImpl::SendHandshakeBinData(
- const uint32_t connection_key, const uint8_t *const data,
- const size_t data_size, const uint32_t seq_number) {
- const SecurityQuery::QueryHeader header(
- SecurityQuery::NOTIFICATION,
- SecurityQuery::SEND_HANDSHAKE_DATA, seq_number);
- DCHECK(data_size < 1024 * 1024 *1024 );
- const SecurityQuery query = SecurityQuery(header, connection_key, data, data_size);
+void SecurityManagerImpl::SendHandshakeBinData(const uint32_t connection_key,
+ const uint8_t* const data,
+ const size_t data_size,
+ const uint32_t seq_number) {
+ const SecurityQuery::QueryHeader header(SecurityQuery::NOTIFICATION,
+ SecurityQuery::SEND_HANDSHAKE_DATA,
+ seq_number);
+ DCHECK(data_size < 1024 * 1024 * 1024);
+ const SecurityQuery query =
+ SecurityQuery(header, connection_key, data, data_size);
SendQuery(query, connection_key);
LOG4CXX_DEBUG(logger_, "Sent " << data_size << " bytes handshake data ");
}
void SecurityManagerImpl::SendInternalError(const uint32_t connection_key,
- const uint8_t &error_id,
- const std::string &erorr_text,
- const uint32_t seq_number) {
+ const uint8_t& error_id,
+ const std::string& erorr_text,
+ const uint32_t seq_number) {
Json::Value value;
- value[kErrId] = error_id;
+ value[kErrId] = error_id;
value[kErrText] = erorr_text;
const std::string error_str = value.toStyledString();
- SecurityQuery::QueryHeader header(SecurityQuery::NOTIFICATION,
- SecurityQuery::SEND_INTERNAL_ERROR,
- // header save json size only (exclude last byte)
- seq_number, error_str.size());
+ SecurityQuery::QueryHeader header(
+ SecurityQuery::NOTIFICATION,
+ SecurityQuery::SEND_INTERNAL_ERROR,
+ // header save json size only (exclude last byte)
+ seq_number,
+ error_str.size());
// Raw data is json string and error id at last byte
std::vector<uint8_t> data_sending(error_str.size() + 1);
memcpy(&data_sending[0], error_str.c_str(), error_str.size());
- data_sending[data_sending.size()-1] = error_id;
+ data_sending[data_sending.size() - 1] = error_id;
- const SecurityQuery query(header, connection_key,
- &data_sending[0], data_sending.size());
+ const SecurityQuery query(
+ header, connection_key, &data_sending[0], data_sending.size());
SendQuery(query, connection_key);
- LOG4CXX_DEBUG(logger_, "Sent Internal error id " << static_cast<int>(error_id)
- << " : \"" << erorr_text << "\".");
+ LOG4CXX_DEBUG(logger_,
+ "Sent Internal error id " << static_cast<int>(error_id)
+ << " : \"" << erorr_text << "\".");
}
void SecurityManagerImpl::SendQuery(const SecurityQuery& query,
- const uint32_t connection_key) {
+ const uint32_t connection_key) {
const std::vector<uint8_t> data_sending = query.DeserializeQuery();
uint32_t connection_handle = 0;
uint8_t sessionID = 0;
uint8_t protocol_version;
- session_observer_->PairFromKey(connection_key, &connection_handle,
- &sessionID);
- if (session_observer_->ProtocolVersionUsed(connection_handle, sessionID,
- protocol_version)) {
+ session_observer_->PairFromKey(
+ connection_key, &connection_handle, &sessionID);
+ if (session_observer_->ProtocolVersionUsed(
+ connection_handle, sessionID, protocol_version)) {
const ::protocol_handler::RawMessagePtr rawMessagePtr(
- new protocol_handler::RawMessage(connection_key,
- protocol_version,
- &data_sending[0], data_sending.size(),
- protocol_handler::kControl));
+ new protocol_handler::RawMessage(connection_key,
+ protocol_version,
+ &data_sending[0],
+ data_sending.size(),
+ protocol_handler::kControl));
DCHECK(protocol_handler_);
// Add RawMessage to ProtocolHandler message query
protocol_handler_->SendMessageToMobileApp(rawMessagePtr, false);
}
}
-const char *SecurityManagerImpl::ConfigSection() {
+const char* SecurityManagerImpl::ConfigSection() {
return "Security Manager";
}
diff --git a/src/components/security_manager/src/security_query.cc b/src/components/security_manager/src/security_query.cc
index cd4da03c15..60233dde5e 100644
--- a/src/components/security_manager/src/security_query.cc
+++ b/src/components/security_manager/src/security_query.cc
@@ -38,35 +38,37 @@
namespace security_manager {
SecurityQuery::QueryHeader::QueryHeader()
- : query_type(INVALID_QUERY_TYPE), query_id(INVALID_QUERY_ID),
- seq_number(0), json_size(0) {
-}
-
-SecurityQuery::QueryHeader::QueryHeader(uint8_t queryType, uint32_t queryId,
- uint32_t seqNumber, uint32_t jsonSize)
- : query_type(queryType), query_id(queryId),
- seq_number(seqNumber), json_size(jsonSize) {
-}
+ : query_type(INVALID_QUERY_TYPE)
+ , query_id(INVALID_QUERY_ID)
+ , seq_number(0)
+ , json_size(0) {}
+
+SecurityQuery::QueryHeader::QueryHeader(uint8_t queryType,
+ uint32_t queryId,
+ uint32_t seqNumber,
+ uint32_t jsonSize)
+ : query_type(queryType)
+ , query_id(queryId)
+ , seq_number(seqNumber)
+ , json_size(jsonSize) {}
SecurityQuery::SecurityQuery()
- : header_(INVALID_QUERY_TYPE, INVALID_QUERY_ID, 0), connection_key_(0) {
-}
+ : header_(INVALID_QUERY_TYPE, INVALID_QUERY_ID, 0), connection_key_(0) {}
-SecurityQuery::SecurityQuery(const SecurityQuery::QueryHeader &header,
+SecurityQuery::SecurityQuery(const SecurityQuery::QueryHeader& header,
const uint32_t connection_key,
- const uint8_t *const raw_data,
+ const uint8_t* const raw_data,
const size_t raw_data_size)
- : header_(header), connection_key_(connection_key),
- data_(raw_data, raw_data + raw_data_size) {
-}
+ : header_(header)
+ , connection_key_(connection_key)
+ , data_(raw_data, raw_data + raw_data_size) {}
-SecurityQuery::SecurityQuery(const SecurityQuery::QueryHeader &header,
+SecurityQuery::SecurityQuery(const SecurityQuery::QueryHeader& header,
const uint32_t connection_key)
- : header_(header), connection_key_(connection_key) {
-}
+ : header_(header), connection_key_(connection_key) {}
-bool SecurityQuery::SerializeQuery(const uint8_t *const raw_data,
- const size_t raw_data_size) {
+bool SecurityQuery::SerializeQuery(const uint8_t* const raw_data,
+ const size_t raw_data_size) {
const size_t header_size = sizeof(QueryHeader);
if (raw_data_size < header_size || !raw_data) {
return false;
@@ -74,21 +76,21 @@ bool SecurityQuery::SerializeQuery(const uint8_t *const raw_data,
const uint8_t query_type = raw_data[0];
switch (query_type) {
case REQUEST:
- header_.query_type = REQUEST;
+ header_.query_type = REQUEST;
break;
case RESPONSE:
- header_.query_type = RESPONSE;
+ header_.query_type = RESPONSE;
break;
case NOTIFICATION:
- header_.query_type = NOTIFICATION;
+ header_.query_type = NOTIFICATION;
break;
default:
header_.query_type = INVALID_QUERY_TYPE;
break;
}
// Convert to Little-Endian and clean high byte
- const uint32_t query_id = 0x00FFFFFF &
- BE_TO_LE32(*reinterpret_cast<const uint32_t*>(raw_data));
+ const uint32_t query_id =
+ 0x00FFFFFF & BE_TO_LE32(*reinterpret_cast<const uint32_t*>(raw_data));
switch (query_id) {
case SEND_HANDSHAKE_DATA:
header_.query_id = SEND_HANDSHAKE_DATA;
@@ -100,22 +102,25 @@ bool SecurityQuery::SerializeQuery(const uint8_t *const raw_data,
header_.query_id = INVALID_QUERY_ID;
break;
}
- header_.seq_number = BE_TO_LE32(*reinterpret_cast<const uint32_t*>(raw_data + 4));
- header_.json_size = BE_TO_LE32(*reinterpret_cast<const uint32_t*>(raw_data + 8));
+ header_.seq_number =
+ BE_TO_LE32(*reinterpret_cast<const uint32_t*>(raw_data + 4));
+ header_.json_size =
+ BE_TO_LE32(*reinterpret_cast<const uint32_t*>(raw_data + 8));
if (header_.json_size > raw_data_size - header_size)
return false;
if (header_.json_size > 0) {
- const char *const json_data =
+ const char* const json_data =
reinterpret_cast<const char*>(raw_data + header_size);
json_message_.assign(json_data, json_data + header_.json_size);
}
- const uint32_t bin_data_size = raw_data_size - (header_size + header_.json_size);
+ const uint32_t bin_data_size =
+ raw_data_size - (header_size + header_.json_size);
if (bin_data_size > 0) {
- const char *const bin_data =
- reinterpret_cast<const char*>(raw_data + header_size + header_.json_size);
+ const char* const bin_data = reinterpret_cast<const char*>(
+ raw_data + header_size + header_.json_size);
data_.assign(bin_data, bin_data + bin_data_size);
}
return true;
@@ -124,31 +129,33 @@ bool SecurityQuery::SerializeQuery(const uint8_t *const raw_data,
const std::vector<uint8_t> SecurityQuery::DeserializeQuery() const {
SecurityQuery::QueryHeader deserialize_header(header_);
const uint32_t tmp = deserialize_header.query_id << 8;
- deserialize_header.query_id = LE_TO_BE32(tmp);
+ deserialize_header.query_id = LE_TO_BE32(tmp);
deserialize_header.seq_number = LE_TO_BE32(deserialize_header.seq_number);
- deserialize_header.json_size = LE_TO_BE32(deserialize_header.json_size);
+ deserialize_header.json_size = LE_TO_BE32(deserialize_header.json_size);
const size_t header_size = sizeof(deserialize_header);
// vector of header and raw_data
- std::vector<uint8_t> data_sending(header_size + data_.size() + json_message_.size());
+ std::vector<uint8_t> data_sending(header_size + data_.size() +
+ json_message_.size());
// copy header
memcpy(&data_sending[0], &deserialize_header, header_size);
// copy binary data
std::copy(data_.begin(), data_.end(), data_sending.begin() + header_size);
// copy text (json) data
- std::copy(json_message_.begin(), json_message_.end(),
+ std::copy(json_message_.begin(),
+ json_message_.end(),
data_sending.begin() + header_size + data_.size());
return data_sending;
}
-void SecurityQuery::set_data(const uint8_t *const binary_data,
- const size_t bin_data_size) {
- DCHECK(binary_data);
- DCHECK(bin_data_size);
- data_.assign(binary_data, binary_data + bin_data_size);
+void SecurityQuery::set_data(const uint8_t* const binary_data,
+ const size_t bin_data_size) {
+ DCHECK(binary_data);
+ DCHECK(bin_data_size);
+ data_.assign(binary_data, binary_data + bin_data_size);
}
-void SecurityQuery::set_json_message(const std::string &json_message) {
+void SecurityQuery::set_json_message(const std::string& json_message) {
json_message_ = json_message;
}
@@ -156,11 +163,11 @@ void SecurityQuery::set_connection_key(const uint32_t connection_key) {
connection_key_ = connection_key;
}
-void SecurityQuery::set_header(const SecurityQuery::QueryHeader &header) {
+void SecurityQuery::set_header(const SecurityQuery::QueryHeader& header) {
header_ = header;
}
-const SecurityQuery::QueryHeader &SecurityQuery::get_header() const {
+const SecurityQuery::QueryHeader& SecurityQuery::get_header() const {
return header_;
}
@@ -172,7 +179,7 @@ size_t SecurityQuery::get_data_size() const {
return data_.size();
}
-const std::string &SecurityQuery::get_json_message() const {
+const std::string& SecurityQuery::get_json_message() const {
return json_message_;
}
diff --git a/src/components/security_manager/src/ssl_context_impl.cc b/src/components/security_manager/src/ssl_context_impl.cc
index 877b0d8093..e387739015 100644
--- a/src/components/security_manager/src/ssl_context_impl.cc
+++ b/src/components/security_manager/src/ssl_context_impl.cc
@@ -37,23 +37,26 @@
#include <openssl/err.h>
#include <memory.h>
#include <map>
+#include <algorithm>
#include "utils/macro.h"
namespace security_manager {
-CryptoManagerImpl::SSLContextImpl::SSLContextImpl(SSL *conn, Mode mode)
- : connection_(conn),
- bioIn_(BIO_new(BIO_s_mem())),
- bioOut_(BIO_new(BIO_s_mem())),
- bioFilter_(NULL),
- // TODO(EZamakhov): get MTU by parameter (from transport)
- // default buffer size is TCP MTU
- buffer_size_(1500),
- buffer_(new uint8_t[buffer_size_]),
- is_handshake_pending_(false),
- mode_(mode),
- max_block_size_(0) {
+CREATE_LOGGERPTR_GLOBAL(logger_, "SecurityManager")
+
+CryptoManagerImpl::SSLContextImpl::SSLContextImpl(SSL* conn,
+ Mode mode,
+ size_t maximum_payload_size)
+ : connection_(conn)
+ , bioIn_(BIO_new(BIO_s_mem()))
+ , bioOut_(BIO_new(BIO_s_mem()))
+ , bioFilter_(NULL)
+ , buffer_size_(maximum_payload_size)
+ , buffer_(new uint8_t[buffer_size_])
+ , is_handshake_pending_(false)
+ , mode_(mode)
+ , max_block_size_(0) {
SSL_set_bio(connection_, bioIn_, bioOut_);
}
@@ -61,7 +64,7 @@ std::string CryptoManagerImpl::SSLContextImpl::LastError() const {
if (!IsInitCompleted()) {
return std::string("Initialization is not completed");
}
- const char *reason = ERR_reason_error_string(ERR_get_error());
+ const char* reason = ERR_reason_error_string(ERR_get_error());
return std::string(reason ? reason : "");
}
@@ -70,137 +73,273 @@ bool CryptoManagerImpl::SSLContextImpl::IsInitCompleted() const {
return SSL_is_init_finished(connection_);
}
-SSLContext::HandshakeResult CryptoManagerImpl::SSLContextImpl::
-StartHandshake(const uint8_t** const out_data, size_t *out_data_size) {
+SSLContext::HandshakeResult CryptoManagerImpl::SSLContextImpl::StartHandshake(
+ const uint8_t** const out_data, size_t* out_data_size) {
is_handshake_pending_ = true;
return DoHandshakeStep(NULL, 0, out_data, out_data_size);
}
namespace {
- size_t aes128_gcm_sha256_max_block_size(size_t mtu) {
- if (mtu < 29)
- return 0;
- return mtu - 29;
- }
- size_t rc4_md5_max_block_size(size_t mtu) {
- if (mtu < 21)
- return 0;
- return mtu - 21;
- }
- size_t rc4_sha_max_block_size(size_t mtu) {
- if (mtu < 25)
- return 0;
- return mtu - 25;
- }
- size_t seed_sha_max_block_size(size_t mtu) {
- if (mtu < 53)
- return 0;
- return ((mtu - 37) & 0xfffffff0) - 5;
- }
- size_t aes128_sha256_max_block_size(size_t mtu) {
- if (mtu < 69)
- return 0;
- return ((mtu - 53) & 0xfffffff0) - 1;
- }
- size_t des_cbc3_sha_max_block_size(size_t mtu) {
- if (mtu < 37)
- return 0;
- return ((mtu - 29) & 0xfffffff8) - 5;
- }
+size_t aes128_gcm_sha256_max_block_size(size_t mtu) {
+ if (mtu < 29)
+ return 0;
+ return mtu - 29;
+}
+size_t rc4_md5_max_block_size(size_t mtu) {
+ if (mtu < 21)
+ return 0;
+ return mtu - 21;
+}
+size_t rc4_sha_max_block_size(size_t mtu) {
+ if (mtu < 25)
+ return 0;
+ return mtu - 25;
+}
+size_t seed_sha_max_block_size(size_t mtu) {
+ if (mtu < 53)
+ return 0;
+ return ((mtu - 37) & 0xfffffff0) - 5;
+}
+size_t aes128_sha256_max_block_size(size_t mtu) {
+ if (mtu < 69)
+ return 0;
+ return ((mtu - 53) & 0xfffffff0) - 1;
+}
+size_t des_cbc3_sha_max_block_size(size_t mtu) {
+ if (mtu < 37)
+ return 0;
+ return ((mtu - 29) & 0xfffffff8) - 5;
+}
} // namespace
std::map<std::string, CryptoManagerImpl::SSLContextImpl::BlockSizeGetter>
CryptoManagerImpl::SSLContextImpl::create_max_block_sizes() {
std::map<std::string, CryptoManagerImpl::SSLContextImpl::BlockSizeGetter> rc;
- rc.insert(std::make_pair("AES128-GCM-SHA256", aes128_gcm_sha256_max_block_size));
- rc.insert(std::make_pair("AES128-SHA256", aes128_sha256_max_block_size));
- rc.insert(std::make_pair("AES128-SHA", seed_sha_max_block_size));
- rc.insert(std::make_pair("AES256-GCM-SHA384", aes128_gcm_sha256_max_block_size));
- rc.insert(std::make_pair("AES256-SHA256", aes128_sha256_max_block_size));
- rc.insert(std::make_pair("AES256-SHA", seed_sha_max_block_size));
- rc.insert(std::make_pair("CAMELLIA128-SHA", seed_sha_max_block_size));
- rc.insert(std::make_pair("CAMELLIA256-SHA", seed_sha_max_block_size));
- rc.insert(std::make_pair("DES-CBC3-SHA", des_cbc3_sha_max_block_size));
- rc.insert(std::make_pair("DES-CBC-SHA", des_cbc3_sha_max_block_size));
- rc.insert(std::make_pair("RC4-MD5", rc4_md5_max_block_size));
- rc.insert(std::make_pair("RC4-SHA", rc4_sha_max_block_size));
- rc.insert(std::make_pair("SEED-SHA", seed_sha_max_block_size));
+ rc.insert(
+ std::make_pair("AES128-GCM-SHA256", aes128_gcm_sha256_max_block_size));
+ rc.insert(std::make_pair("AES128-SHA256", aes128_sha256_max_block_size));
+ rc.insert(std::make_pair("AES128-SHA", seed_sha_max_block_size));
+ rc.insert(
+ std::make_pair("AES256-GCM-SHA384", aes128_gcm_sha256_max_block_size));
+ rc.insert(std::make_pair("AES256-SHA256", aes128_sha256_max_block_size));
+ rc.insert(std::make_pair("AES256-SHA", seed_sha_max_block_size));
+ rc.insert(std::make_pair("CAMELLIA128-SHA", seed_sha_max_block_size));
+ rc.insert(std::make_pair("CAMELLIA256-SHA", seed_sha_max_block_size));
+ rc.insert(std::make_pair("DES-CBC3-SHA", des_cbc3_sha_max_block_size));
+ rc.insert(std::make_pair("DES-CBC-SHA", des_cbc3_sha_max_block_size));
+ rc.insert(std::make_pair("RC4-MD5", rc4_md5_max_block_size));
+ rc.insert(std::make_pair("RC4-SHA", rc4_sha_max_block_size));
+ rc.insert(std::make_pair("SEED-SHA", seed_sha_max_block_size));
return rc;
}
std::map<std::string, CryptoManagerImpl::SSLContextImpl::BlockSizeGetter>
-CryptoManagerImpl::SSLContextImpl::max_block_sizes =
- CryptoManagerImpl::SSLContextImpl::create_max_block_sizes();
+ CryptoManagerImpl::SSLContextImpl::max_block_sizes =
+ CryptoManagerImpl::SSLContextImpl::create_max_block_sizes();
+
+void CryptoManagerImpl::SSLContextImpl::PrintCertData(
+ X509* cert, const std::string& cert_owner) {
+ if (cert) {
+ X509_NAME* subj_name = X509_get_subject_name(cert);
+ char* subj = X509_NAME_oneline(subj_name, NULL, 0);
+ if (subj) {
+ std::replace(subj, subj + strlen(subj), '/', ' ');
+ LOG4CXX_DEBUG(logger_, cert_owner << " subject:" << subj);
+ OPENSSL_free(subj);
+ }
+ char* issuer = X509_NAME_oneline(X509_get_issuer_name(cert), NULL, 0);
+ if (issuer) {
+ std::replace(issuer, issuer + strlen(issuer), '/', ' ');
+ LOG4CXX_DEBUG(logger_, cert_owner << " issuer:" << issuer);
+ OPENSSL_free(issuer);
+ }
-SSLContext::HandshakeResult CryptoManagerImpl::SSLContextImpl::
-DoHandshakeStep(const uint8_t* const in_data, size_t in_data_size,
- const uint8_t** const out_data, size_t* out_data_size) {
- DCHECK(out_data);
- DCHECK(out_data_size);
- *out_data = NULL;
- *out_data_size = 0;
- // TODO(Ezamakhov): add test - hanshake fail -> restart StartHandshake
- sync_primitives::AutoLock locker(bio_locker);
- if (SSL_is_init_finished(connection_)) {
- is_handshake_pending_ = false;
- return SSLContext::Handshake_Result_Success;
+ ASN1_TIME* notBefore = X509_get_notBefore(cert);
+ ASN1_TIME* notAfter = X509_get_notAfter(cert);
+
+ if (notBefore) {
+ LOG4CXX_DEBUG(logger_, " Start date: " << (char*)notBefore->data);
+ }
+ if (notAfter) {
+ LOG4CXX_DEBUG(logger_, " End date: " << (char*)notAfter->data);
+ }
}
+}
+
+void CryptoManagerImpl::SSLContextImpl::PrintCertInfo() {
+ PrintCertData(SSL_get_certificate(connection_), "HU's");
+
+ STACK_OF(X509)* peer_certs = SSL_get_peer_cert_chain(connection_);
+ while (sk_X509_num(peer_certs) > 0) {
+ X509* cert = sk_X509_pop(peer_certs);
+ PrintCertData(cert, "SERVERS");
+ }
+}
+
+SSLContext::HandshakeResult
+CryptoManagerImpl::SSLContextImpl::CheckCertContext() {
+ X509* cert = SSL_get_peer_certificate(connection_);
+ if (!cert) {
+ // According to the openssl documentation the peer certificate
+ // might be ommitted for the SERVER but required for the cient.
+ return CLIENT == mode_ ? Handshake_Result_Fail : Handshake_Result_Success;
+ }
+
+ X509_NAME* subj_name = X509_get_subject_name(cert);
+
+ const std::string& cn = GetTextBy(subj_name, NID_commonName);
+ const std::string& sn = GetTextBy(subj_name, NID_serialNumber);
+
+ if (!(hsh_context_.expected_cn.CompareIgnoreCase(cn.c_str()))) {
+ LOG4CXX_ERROR(logger_,
+ "Trying to run handshake with wrong app name: "
+ << cn << ". Expected app name: "
+ << hsh_context_.expected_cn.AsMBString());
+ return Handshake_Result_AppNameMismatch;
+ }
+
+ if (!(hsh_context_.expected_sn.CompareIgnoreCase(sn.c_str()))) {
+ LOG4CXX_ERROR(logger_,
+ "Trying to run handshake with wrong app id: "
+ << sn << ". Expected app id: "
+ << hsh_context_.expected_sn.AsMBString());
+ return Handshake_Result_AppIDMismatch;
+ }
+ return Handshake_Result_Success;
+}
+
+bool CryptoManagerImpl::SSLContextImpl::ReadHandshakeData(
+ const uint8_t** const out_data, size_t* out_data_size) {
+ LOG4CXX_AUTO_TRACE(logger_);
+ const size_t pend = BIO_ctrl_pending(bioOut_);
+ LOG4CXX_DEBUG(logger_, "Available " << pend << " bytes for handshake");
+
+ if (pend > 0) {
+ LOG4CXX_DEBUG(logger_, "Reading handshake data");
+ EnsureBufferSizeEnough(pend);
+
+ const int read_count = BIO_read(bioOut_, buffer_, pend);
+ if (read_count == static_cast<int>(pend)) {
+ *out_data_size = read_count;
+ *out_data = buffer_;
+ } else {
+ LOG4CXX_WARN(logger_, "BIO read fail");
+ is_handshake_pending_ = false;
+ ResetConnection();
+ return false;
+ }
+ }
+
+ return true;
+}
+bool CryptoManagerImpl::SSLContextImpl::WriteHandshakeData(
+ const uint8_t* const in_data, size_t in_data_size) {
+ LOG4CXX_AUTO_TRACE(logger_);
if (in_data && in_data_size) {
const int ret = BIO_write(bioIn_, in_data, in_data_size);
if (ret <= 0) {
is_handshake_pending_ = false;
- SSL_clear(connection_);
- return SSLContext::Handshake_Result_AbnormalFail;
+ ResetConnection();
+ return Handshake_Result_AbnormalFail;
}
}
+ return true;
+}
+SSLContext::HandshakeResult
+CryptoManagerImpl::SSLContextImpl::PerformHandshake() {
const int handshake_result = SSL_do_handshake(connection_);
if (handshake_result == 1) {
+ const HandshakeResult result = CheckCertContext();
+ if (result != Handshake_Result_Success) {
+ ResetConnection();
+ is_handshake_pending_ = false;
+ return result;
+ }
+
+ LOG4CXX_DEBUG(logger_, "SSL handshake successfully finished");
// Handshake is successful
bioFilter_ = BIO_new(BIO_f_ssl());
BIO_set_ssl(bioFilter_, connection_, BIO_NOCLOSE);
- const SSL_CIPHER *cipher = SSL_get_current_cipher(connection_);
+ const SSL_CIPHER* cipher = SSL_get_current_cipher(connection_);
max_block_size_ = max_block_sizes[SSL_CIPHER_get_name(cipher)];
is_handshake_pending_ = false;
+
} else if (handshake_result == 0) {
SSL_clear(connection_);
is_handshake_pending_ = false;
- return SSLContext::Handshake_Result_Fail;
- } else if (SSL_get_error(connection_, handshake_result) != SSL_ERROR_WANT_READ) {
- SSL_clear(connection_);
- is_handshake_pending_ = false;
- return SSLContext::Handshake_Result_AbnormalFail;
+ return Handshake_Result_Fail;
+ } else {
+ const int error = SSL_get_error(connection_, handshake_result);
+ if (error != SSL_ERROR_WANT_READ) {
+ const long error = SSL_get_verify_result(connection_);
+ SetHandshakeError(error);
+ LOG4CXX_WARN(logger_,
+ "Handshake failed with error "
+ << " -> " << SSL_get_error(connection_, error) << " \""
+ << LastError() << '"');
+ ResetConnection();
+ is_handshake_pending_ = false;
+
+ // In case error happened but ssl verification shows OK
+ // method will return AbnormalFail.
+ if (X509_V_OK == error) {
+ return Handshake_Result_AbnormalFail;
+ }
+ return openssl_error_convert_to_internal(error);
+ }
}
+ return Handshake_Result_Success;
+}
- const size_t pend = BIO_ctrl_pending(bioOut_);
+SSLContext::HandshakeResult CryptoManagerImpl::SSLContextImpl::DoHandshakeStep(
+ const uint8_t* const in_data,
+ size_t in_data_size,
+ const uint8_t** const out_data,
+ size_t* out_data_size) {
+ LOG4CXX_AUTO_TRACE(logger_);
+ DCHECK(out_data);
+ DCHECK(out_data_size);
+ *out_data = NULL;
+ *out_data_size = 0;
- if (pend) {
- EnsureBufferSizeEnough(pend);
+ // TODO(Ezamakhov): add test - hanshake fail -> restart StartHandshake
+ {
+ sync_primitives::AutoLock locker(bio_locker);
- const int read_count = BIO_read(bioOut_, buffer_, pend);
- if (read_count == static_cast<int>(pend)) {
- *out_data_size = read_count;
- *out_data = buffer_;
- } else {
+ if (SSL_is_init_finished(connection_)) {
+ LOG4CXX_DEBUG(logger_, "SSL initilization is finished");
is_handshake_pending_ = false;
- SSL_clear(connection_);
- return SSLContext::Handshake_Result_AbnormalFail;
+ return Handshake_Result_Success;
}
}
- return SSLContext::Handshake_Result_Success;
-}
+ if (!WriteHandshakeData(in_data, in_data_size)) {
+ return Handshake_Result_AbnormalFail;
+ }
-bool CryptoManagerImpl::SSLContextImpl::Encrypt(
- const uint8_t * const in_data, size_t in_data_size,
- const uint8_t ** const out_data, size_t *out_data_size) {
+ PrintCertInfo();
+ const HandshakeResult res = PerformHandshake();
+ if (res != Handshake_Result_Success) {
+ return res;
+ }
+
+ if (!ReadHandshakeData(out_data, out_data_size)) {
+ return Handshake_Result_AbnormalFail;
+ }
+
+ return res;
+}
+
+bool CryptoManagerImpl::SSLContextImpl::Encrypt(const uint8_t* const in_data,
+ size_t in_data_size,
+ const uint8_t** const out_data,
+ size_t* out_data_size) {
sync_primitives::AutoLock locker(bio_locker);
- if (!SSL_is_init_finished(connection_) ||
- !in_data ||
- !in_data_size) {
+ if (!SSL_is_init_finished(connection_) || !in_data || !in_data_size) {
return false;
}
@@ -221,10 +360,10 @@ bool CryptoManagerImpl::SSLContextImpl::Encrypt(
return true;
}
-bool CryptoManagerImpl::SSLContextImpl::Decrypt(
- const uint8_t * const in_data, size_t in_data_size,
- const uint8_t ** const out_data, size_t *out_data_size) {
-
+bool CryptoManagerImpl::SSLContextImpl::Decrypt(const uint8_t* const in_data,
+ size_t in_data_size,
+ const uint8_t** const out_data,
+ size_t* out_data_size) {
sync_primitives::AutoLock locker(bio_locker);
if (!SSL_is_init_finished(connection_)) {
return false;
@@ -275,14 +414,94 @@ CryptoManagerImpl::SSLContextImpl::~SSLContextImpl() {
delete[] buffer_;
}
+void CryptoManagerImpl::SSLContextImpl::SetHandshakeError(const int error) {
+ const char* error_str = X509_verify_cert_error_string(error);
+ if (error_str) {
+ last_error_ = error_str;
+ } else {
+ // Error will be updated with the next LastError call
+ last_error_.clear();
+ }
+}
+
+void CryptoManagerImpl::SSLContextImpl::ResetConnection() {
+ LOG4CXX_AUTO_TRACE(logger_);
+ const int shutdown_result = SSL_shutdown(connection_);
+ if (shutdown_result != 1) {
+ const size_t pend = BIO_ctrl_pending(bioOut_);
+ LOG4CXX_DEBUG(logger_, "Available " << pend << " bytes for shutdown");
+ if (pend > 0) {
+ LOG4CXX_DEBUG(logger_, "Reading shutdown data");
+ EnsureBufferSizeEnough(pend);
+ BIO_read(bioOut_, buffer_, pend);
+ }
+ SSL_shutdown(connection_);
+ }
+ LOG4CXX_DEBUG(logger_, "SSL connection recreation");
+ SSL_CTX* ssl_context = connection_->ctx;
+ SSL_free(connection_);
+ connection_ = SSL_new(ssl_context);
+ if (mode_ == SERVER) {
+ SSL_set_accept_state(connection_);
+ } else {
+ SSL_set_connect_state(connection_);
+ }
+ bioIn_ = BIO_new(BIO_s_mem());
+ bioOut_ = BIO_new(BIO_s_mem());
+ SSL_set_bio(connection_, bioIn_, bioOut_);
+}
+
+void CryptoManagerImpl::SSLContextImpl::SetHandshakeContext(
+ const SSLContext::HandshakeContext& hsh_ctx) {
+ hsh_context_ = hsh_ctx;
+}
+
void CryptoManagerImpl::SSLContextImpl::EnsureBufferSizeEnough(size_t size) {
if (buffer_size_ < size) {
delete[] buffer_;
- buffer_ = new(std::nothrow) uint8_t[size];
+ buffer_ = new (std::nothrow) uint8_t[size];
if (buffer_) {
buffer_size_ = size;
}
}
}
+SSLContext::HandshakeResult
+CryptoManagerImpl::SSLContextImpl::openssl_error_convert_to_internal(
+ const long error) {
+ switch (error) {
+ case X509_V_ERR_CERT_HAS_EXPIRED:
+ return Handshake_Result_CertExpired;
+ case X509_V_ERR_CERT_NOT_YET_VALID:
+ return Handshake_Result_NotYetValid;
+ case X509_V_ERR_SUBJECT_ISSUER_MISMATCH:
+ case X509_V_ERR_CERT_SIGNATURE_FAILURE:
+ case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
+ case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
+ return Handshake_Result_CertNotSigned;
+ default:
+ return Handshake_Result_Fail;
+ }
+}
+
+std::string CryptoManagerImpl::SSLContextImpl::GetTextBy(X509_NAME* name,
+ int object) const {
+ const int req_len = X509_NAME_get_text_by_NID(name, object, NULL, 0);
+
+ if (-1 == req_len) {
+ LOG4CXX_WARN(logger_,
+ "Unable to obtain object: " << object << " from certificate");
+ return std::string();
+ }
+
+ std::vector<char> data;
+ data.resize(req_len + 1);
+ X509_NAME_get_text_by_NID(name, object, &data.front(), data.size());
+
+ std::string str(data.begin(), data.end() - 1);
+
+ std::transform(str.begin(), str.end(), str.begin(), ::tolower);
+ return str;
+}
+
} // namespace security_manager