cpp/src/ssl_options.cpp (154 lines of code) (raw):

/* * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * */ #include "ssl_options_impl.hpp" // https://stackoverflow.com/questions/31657499/how-to-detect-stdlib-libc-in-the-preprocessor #include <ciso646> #include "proton/ssl.hpp" #include "proton/error.hpp" #include "msg.hpp" #include <proton/ssl.h> namespace { void inline set_cred(pn_ssl_domain_t *dom, const std::string &main, const std::string &extra, const std::string &pass, bool pwset) { const char *cred2 = extra.empty() ? NULL : extra.c_str(); const char *pw = pwset ? pass.c_str() : NULL; if (pn_ssl_domain_set_credentials(dom, main.c_str(), cred2, pw)) throw proton::error(MSG("SSL certificate initialization failure for " << main << ":" << (cred2 ? cred2 : "NULL") << ":" << (pw ? pw : "NULL"))); } void inline set_trusted_ca_db(pn_ssl_domain_t *dom, const std::string &trust_db) { if (pn_ssl_domain_set_trusted_ca_db(dom, trust_db.c_str())) throw proton::error(MSG("SSL trust store initialization failure for " << trust_db)); } void inline set_client_verify_mode(pn_ssl_domain_t *dom, enum proton::ssl::verify_mode mode) { if (pn_ssl_domain_set_peer_authentication(dom, pn_ssl_verify_mode_t(mode), NULL)) throw proton::error(MSG("SSL client verify mode failure")); } } namespace proton { ssl_options_impl::ssl_options_impl(bool is_server) : pn_domain_(pn_ssl_domain(is_server ? PN_SSL_MODE_SERVER : PN_SSL_MODE_CLIENT)), refcount_(1) { if (!pn_domain_) throw proton::error(MSG("SSL/TLS unavailable")); } ssl_options_impl::~ssl_options_impl() { pn_ssl_domain_free(pn_domain_); } ssl_server_options& ssl_server_options::operator=(const ssl_server_options& x) { if (&x!=this) { if (impl_) impl_->decref(); impl_ = x.impl_; if (impl_) impl_->incref(); } return *this; } ssl_server_options::ssl_server_options(const ssl_server_options& x): impl_(x.impl_) { if (impl_) impl_->incref(); } ssl_server_options::~ssl_server_options() { if (impl_) impl_->decref(); } ssl_server_options::ssl_server_options(const ssl_certificate &cert) : impl_(new impl) { set_cred(impl_->pn_domain(), cert.certdb_main_, cert.certdb_extra_, cert.passwd_, cert.pw_set_); } ssl_server_options::ssl_server_options( const ssl_certificate &cert, const std::string &trust_db, const std::string &advertise_db, enum ssl::verify_mode mode) : impl_(new impl) { pn_ssl_domain_t* dom = impl_->pn_domain(); set_cred(dom, cert.certdb_main_, cert.certdb_extra_, cert.passwd_, cert.pw_set_); set_trusted_ca_db(dom, trust_db.c_str()); const std::string &db = advertise_db.empty() ? trust_db : advertise_db; if (pn_ssl_domain_set_peer_authentication(dom, pn_ssl_verify_mode_t(mode), db.c_str())) throw error(MSG("SSL server configuration failure requiring client certificates using " << db)); } ssl_server_options::ssl_server_options() : impl_(0) {} ssl_client_options::ssl_client_options(const ssl_client_options& x): impl_(x.impl_) { if (impl_) impl_->incref(); } ssl_client_options& ssl_client_options::operator=(const ssl_client_options& x) { if (&x!=this) { if (impl_) impl_->decref(); impl_ = x.impl_; if (impl_) impl_->incref(); } return *this; } ssl_client_options::~ssl_client_options() { if (impl_) impl_->decref(); } ssl_client_options::ssl_client_options() : impl_(0) {} ssl_client_options::ssl_client_options(enum ssl::verify_mode mode) : impl_(new impl) { pn_ssl_domain_t* dom = impl_->pn_domain(); set_client_verify_mode(dom, mode); } ssl_client_options::ssl_client_options(const std::string &trust_db, enum ssl::verify_mode mode) : impl_(new impl) { pn_ssl_domain_t* dom = impl_->pn_domain(); set_trusted_ca_db(dom, trust_db); set_client_verify_mode(dom, mode); } ssl_client_options::ssl_client_options(const ssl_certificate &cert, enum ssl::verify_mode mode) : impl_(new impl) { pn_ssl_domain_t* dom = impl_->pn_domain(); set_cred(dom, cert.certdb_main_, cert.certdb_extra_, cert.passwd_, cert.pw_set_); set_client_verify_mode(dom, mode); } ssl_client_options::ssl_client_options(const ssl_certificate &cert, const std::string &trust_db, enum ssl::verify_mode mode) : impl_(new impl) { pn_ssl_domain_t* dom = impl_->pn_domain(); set_cred(dom, cert.certdb_main_, cert.certdb_extra_, cert.passwd_, cert.pw_set_); set_trusted_ca_db(dom, trust_db); set_client_verify_mode(dom, mode); } ssl_certificate::ssl_certificate(const std::string &main) : certdb_main_(main), pw_set_(false) {} ssl_certificate::ssl_certificate(const std::string &main, const std::string &extra) : certdb_main_(main), certdb_extra_(extra), pw_set_(false) {} ssl_certificate::ssl_certificate(const std::string &main, const std::string &extra, const std::string &pw) : certdb_main_(main), certdb_extra_(extra), passwd_(pw), pw_set_(true) {} } // namespace // Hack alert - don't do this at home - just design better initially! // For backwards ABI compatibility we need to define some symbols: // // Don't do this with libc++ or with Visual Studio #if !defined(_LIBCPP_VERSION) && !defined(_MSC_VER) // // These are a bit easier as the entire class has been removed so we can just define the class here // They do rely on the impl_ member being effectively the same type and structure location from // The previous parent type ssl_domain to ssl_server_options/ssl_client_options. // // PN_CPP_EXTERN proton::internal::ssl_domain::ssl_domain(const ssl_domain&); // PN_CPP_EXTERN proton::internal::ssl_domain::ssl_domain& operator=(const ssl_domain&); // PN_CPP_EXTERN proton::internal::ssl_domain::~ssl_domain(); // namespace proton { namespace internal { class ssl_domain { PN_CPP_EXTERN ssl_domain(const ssl_domain&); PN_CPP_EXTERN ssl_domain& operator=(const ssl_domain&); PN_CPP_EXTERN ~ssl_domain(); ssl_options_impl* impl_; }; ssl_domain::ssl_domain(const ssl_domain& x): impl_(x.impl_) { if (impl_) impl_->incref(); } ssl_domain& ssl_domain::operator=(const ssl_domain& x) { if (&x != this) { if (impl_) impl_->decref(); impl_ = x.impl_; if (impl_) impl_->incref(); } return *this; } ssl_domain::~ssl_domain() { if (impl_) impl_->decref(); } }} // These are a bit harder because they can't be publicly in the classes anymore so just use alias definitions // but that needs the mangled symbol names unfortunately. // // PN_CPP_EXTERN proton::ssl_server_options::ssl_server_options(ssl_certificate &cert); // PN_CPP_EXTERN proton::ssl_server_options::ssl_server_options(ssl_certificate &cert, const std::string &trust_db, // const std::string &advertise_db = std::string(), // enum ssl::verify_mode mode = ssl::VERIFY_PEER); // PN_CPP_EXTERN proton::ssl_client_options::ssl_client_options(ssl_certificate&, const std::string &trust_db, // enum ssl::verify_mode = ssl::VERIFY_PEER_NAME); extern "C" { #pragma GCC diagnostic ignored "-Wpragmas" #pragma GCC diagnostic ignored "-Wunknown-warning-option" #pragma GCC diagnostic ignored "-Wattribute-alias" // 2 variants of each constructor (base & complete) PN_CPP_EXTERN void _ZN6proton18ssl_server_optionsC1ERNS_15ssl_certificateE() __attribute__((alias("_ZN6proton18ssl_server_optionsC1ERKNS_15ssl_certificateE"))); PN_CPP_EXTERN void _ZN6proton18ssl_server_optionsC2ERNS_15ssl_certificateE() __attribute__((alias("_ZN6proton18ssl_server_optionsC2ERKNS_15ssl_certificateE"))); #if defined(_GLIBCXX_USE_CXX11_ABI) && _GLIBCXX_USE_CXX11_ABI>0 // Post gcc 5.1 "C++11" ABI PN_CPP_EXTERN void _ZN6proton18ssl_server_optionsC1ERNS_15ssl_certificateERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESA_NS_3ssl11verify_modeE() __attribute__((alias("_ZN6proton18ssl_server_optionsC1ERKNS_15ssl_certificateERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESB_NS_3ssl11verify_modeE"))); PN_CPP_EXTERN void _ZN6proton18ssl_server_optionsC2ERNS_15ssl_certificateERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESA_NS_3ssl11verify_modeE() __attribute__((alias("_ZN6proton18ssl_server_optionsC2ERKNS_15ssl_certificateERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESB_NS_3ssl11verify_modeE"))); PN_CPP_EXTERN void _ZN6proton18ssl_client_optionsC1ERNS_15ssl_certificateERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEENS_3ssl11verify_modeE() __attribute__((alias("_ZN6proton18ssl_client_optionsC1ERKNS_15ssl_certificateERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEENS_3ssl11verify_modeE"))); PN_CPP_EXTERN void _ZN6proton18ssl_client_optionsC2ERNS_15ssl_certificateERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEENS_3ssl11verify_modeE() __attribute__((alias("_ZN6proton18ssl_client_optionsC2ERKNS_15ssl_certificateERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEENS_3ssl11verify_modeE"))); #else // Pre gcc 5.1 ABI PN_CPP_EXTERN void _ZN6proton18ssl_server_optionsC1ERNS_15ssl_certificateERKSsS4_NS_3ssl11verify_modeE() __attribute__((alias("_ZN6proton18ssl_server_optionsC1ERKNS_15ssl_certificateERKSsS5_NS_3ssl11verify_modeE"))); PN_CPP_EXTERN void _ZN6proton18ssl_server_optionsC2ERNS_15ssl_certificateERKSsS4_NS_3ssl11verify_modeE() __attribute__((alias("_ZN6proton18ssl_server_optionsC2ERKNS_15ssl_certificateERKSsS5_NS_3ssl11verify_modeE"))); PN_CPP_EXTERN void _ZN6proton18ssl_client_optionsC1ERNS_15ssl_certificateERKSsNS_3ssl11verify_modeE() __attribute__((alias("_ZN6proton18ssl_client_optionsC1ERKNS_15ssl_certificateERKSsNS_3ssl11verify_modeE"))); PN_CPP_EXTERN void _ZN6proton18ssl_client_optionsC2ERNS_15ssl_certificateERKSsNS_3ssl11verify_modeE() __attribute__((alias("_ZN6proton18ssl_client_optionsC2ERKNS_15ssl_certificateERKSsNS_3ssl11verify_modeE"))); #endif } #endif