summaryrefslogtreecommitdiff
path: root/src/components/security_manager
diff options
context:
space:
mode:
authorAlexandr Galiuzov <agaliuzov@luxoft.com>2015-08-03 14:21:46 +0300
committerAleksandr Galiuzov <AGaliuzov@luxoft.com>2015-10-02 01:38:07 +0300
commit158aa1da4f33fd17466e72a384bb22e710180cb2 (patch)
treef7ddc8bef538c80866f7ae5308cf31c5a1b3aa96 /src/components/security_manager
parentf27ec44eb97ebb562c21629dcbd46ff8d9823871 (diff)
downloadsdl_core-158aa1da4f33fd17466e72a384bb22e710180cb2.tar.gz
Implement getting certificate from policy table
The commit contains changes which allows to obtain certificate for SSL from policy table. The certificate stored as base64 encoded PKCS12. The main flow as follows: User start SDL: lify_cycle asks about certificate from policy pass it to crypto manager which is creates SSL context with this data. Policy updated certidficate: Crypto manager has been notified over OnCertificateUpdated callback and reset new certificate and private key into SSL context. Test was changed as well. Now our tests are using encoded pkcs12 as well. Implements: APPLINK-12186 Closes-Issue: APPLINK-12187
Diffstat (limited to 'src/components/security_manager')
-rw-r--r--src/components/security_manager/include/security_manager/crypto_manager_impl.h29
-rw-r--r--src/components/security_manager/src/crypto_manager_impl.cc209
2 files changed, 183 insertions, 55 deletions
diff --git a/src/components/security_manager/include/security_manager/crypto_manager_impl.h b/src/components/security_manager/include/security_manager/crypto_manager_impl.h
index 43bb63ef67..6641050d40 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
@@ -87,21 +87,28 @@ class CryptoManagerImpl : public CryptoManager {
public:
CryptoManagerImpl();
- virtual bool Init(Mode mode,
- Protocol protocol,
- const std::string &cert_filename,
- const std::string &key_filename,
- const std::string &ciphers_list,
- bool verify_peer);
- virtual void Finish();
- virtual SSLContext *CreateSSLContext();
- virtual void ReleaseSSLContext(SSLContext *context);
- virtual std::string LastError() const;
+ ~CryptoManagerImpl();
+
+ bool Init(Mode mode,
+ Protocol protocol,
+ const std::string &cert_data,
+ const std::string &ciphers_list,
+ const bool verify_peer,
+ const std::string &ca_certificate_file) OVERRIDE;
+ bool OnCertificateUpdated(const std::string &data) OVERRIDE;
+ SSLContext *CreateSSLContext() OVERRIDE;
+ void ReleaseSSLContext(SSLContext *context) OVERRIDE;
+ std::string LastError() const OVERRIDE;
+
+private:
+ bool set_certificate(const std::string &cert_data);
- private:
SSL_CTX *context_;
Mode mode_;
static uint32_t instance_count_;
+ static sync_primitives::Lock instance_lock_;
+ std::string certificate_data_;
+ bool verify_peer_;
DISALLOW_COPY_AND_ASSIGN(CryptoManagerImpl);
};
} // 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 69121a7b19..6a38b76b63 100644
--- a/src/components/security_manager/src/crypto_manager_impl.cc
+++ b/src/components/security_manager/src/crypto_manager_impl.cc
@@ -31,12 +31,21 @@
*/
#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 "security_manager/security_manager.h"
+
#include "utils/logger.h"
#include "utils/atomic.h"
+#include "utils/macro.h"
+#include "utils/scope_guard.h"
#define TLS1_1_MINIMAL_VERSION 0x1000103fL
#define CONST_SSL_METHOD_MINIMAL_VERSION 0x00909000L
@@ -46,25 +55,75 @@ namespace security_manager {
CREATE_LOGGERPTR_GLOBAL(logger_, "CryptoManagerImpl")
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;
+ }
+
+ void free_ctx(SSL_CTX** ctx) {
+ if (ctx) {
+ SSL_CTX_free(*ctx);
+ *ctx = NULL;
+ }
+ }
}
-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) {
+CryptoManagerImpl::CryptoManagerImpl()
+ : context_(NULL),
+ mode_(CLIENT),
+ verify_peer_(false) {
+ 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();
}
+}
+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(Mode mode, Protocol protocol,
+ const std::string &cert_data,
+ const std::string &ciphers_list,
+ const bool verify_peer,
+ const std::string &ca_certificate_file) {
+ LOG4CXX_AUTO_TRACE(logger_);
mode_ = mode;
+ verify_peer_ = verify_peer;
+ certificate_data_ = cert_data;
+ LOG4CXX_DEBUG(logger_, (mode_ == SERVER ? "Server" : "Client") << " mode");
+ LOG4CXX_DEBUG(logger_, "Peer verification " << (verify_peer_? "enabled" : "disabled"));
+ LOG4CXX_DEBUG(logger_, "CA certificate file is \"" << ca_certificate_file << '"');
+
const bool is_server = (mode == SERVER);
#if OPENSSL_VERSION_NUMBER < CONST_SSL_METHOD_MINIMAL_VERSION
SSL_METHOD *method;
@@ -112,36 +171,18 @@ bool CryptoManagerImpl::Init(Mode mode,
LOG4CXX_ERROR(logger_, "Unknown protocol: " << protocol);
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");
- } 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);
- 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;
- }
- }
+ set_certificate(cert_data);
if (ciphers_list.empty()) {
LOG4CXX_WARN(logger_, "Empty ciphers list");
@@ -153,21 +194,41 @@ bool CryptoManagerImpl::Init(Mode mode,
}
}
- // 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);
+ if (ca_certificate_file.empty()) {
+ LOG4CXX_WARN(logger_, "Setting up empty CA certificate location");
+ }
+ LOG4CXX_DEBUG(logger_, "Setting up CA certificate location");
+ const int result = SSL_CTX_load_verify_locations(context_,
+ NULL,
+ ca_certificate_file.c_str());
+ if (!result) {
+ const unsigned long error = ERR_get_error();
+ UNUSED(error);
+ LOG4CXX_WARN(
+ logger_,
+ "Wrong certificate file '" << ca_certificate_file
+ << "', err 0x" << std::hex << error
+ << " \"" << ERR_reason_error_string(error) << '"');
+ }
+
+ guard.Dismiss();
+ const int verify_mode = 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() {
@@ -199,4 +260,64 @@ std::string CryptoManagerImpl::LastError() const {
return std::string(reason ? reason : "");
}
+
+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;
+ }
+
+ 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;
+}
+
} // namespace security_manager