| /* |
| * |
| * 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 "proton/ssl.hpp" |
| #include "proton/error.hpp" |
| #include "msg.hpp" |
| |
| #include <proton/ssl.h> |
| |
| namespace proton { |
| |
| /// TODO: This whole class isn't really needed as pn_ssl_domain_t is already refcounted, with shared ownership for all pn_ssl_t objects |
| /// that hold one |
| /// cjansen: but note it is not a PN_CLASS object and two pn_ssl_domain_free() from the app will cause a free while still in use. |
| class ssl_domain_impl { |
| public: |
| ssl_domain_impl(bool is_server) : refcount_(1), pn_domain_(pn_ssl_domain(is_server ? PN_SSL_MODE_SERVER : PN_SSL_MODE_CLIENT)) { |
| if (!pn_domain_) throw error(MSG("SSL/TLS unavailable")); |
| } |
| ~ssl_domain_impl() { pn_ssl_domain_free(pn_domain_); } |
| void incref() { refcount_++; } |
| void decref() { |
| if (--refcount_ == 0) { |
| delete this; |
| } |
| } |
| pn_ssl_domain_t *pn_domain() { return pn_domain_; } |
| private: |
| int refcount_; |
| pn_ssl_domain_t *pn_domain_; |
| ssl_domain_impl(const ssl_domain_impl&); |
| ssl_domain_impl& operator=(const ssl_domain_impl&); |
| }; |
| |
| namespace internal { |
| ssl_domain::ssl_domain(bool is_server) : impl_(0), server_type_(is_server) {} |
| |
| ssl_domain::ssl_domain(const ssl_domain &x) : impl_(x.impl_), server_type_(x.server_type_) { |
| if (impl_) impl_->incref(); |
| } |
| |
| ssl_domain& internal::ssl_domain::operator=(const ssl_domain&x) { |
| if (&x == this) return *this; |
| if (impl_) impl_->decref(); |
| impl_ = x.impl_; |
| server_type_ = x.server_type_; |
| if (impl_) impl_->incref(); |
| return *this; |
| } |
| |
| ssl_domain::~ssl_domain() { if (impl_) impl_->decref(); } |
| |
| pn_ssl_domain_t *ssl_domain::pn_domain() { |
| if (!impl_) |
| // Lazily create in case never actually used or configured. |
| // The pn_ssl_domain_t is a heavy object. |
| impl_ = new ssl_domain_impl(server_type_); |
| return impl_->pn_domain(); |
| } |
| |
| } // namespace internal |
| |
| namespace { |
| |
| void 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 error(MSG("SSL certificate initialization failure for " << main << ":" << |
| (cred2 ? cred2 : "NULL") << ":" << (pw ? pw : "NULL"))); |
| } |
| } |
| |
| ssl_server_options::ssl_server_options(ssl_certificate &cert) : internal::ssl_domain(true) { |
| set_cred(pn_domain(), cert.certdb_main_, cert.certdb_extra_, cert.passwd_, cert.pw_set_); |
| } |
| |
| ssl_server_options::ssl_server_options( |
| ssl_certificate &cert, |
| const std::string &trust_db, |
| const std::string &advertise_db, |
| enum ssl::verify_mode mode) : internal::ssl_domain(true) |
| { |
| pn_ssl_domain_t* dom = pn_domain(); |
| set_cred(dom, cert.certdb_main_, cert.certdb_extra_, cert.passwd_, cert.pw_set_); |
| if (pn_ssl_domain_set_trusted_ca_db(dom, trust_db.c_str())) |
| throw error(MSG("SSL trust store initialization failure for " << trust_db)); |
| 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() : ssl_domain(true) {} |
| |
| namespace { |
| void client_setup(pn_ssl_domain_t *dom, const std::string &trust_db, enum ssl::verify_mode mode) { |
| if (pn_ssl_domain_set_trusted_ca_db(dom, trust_db.c_str())) |
| throw error(MSG("SSL trust store initialization failure for " << trust_db)); |
| if (pn_ssl_domain_set_peer_authentication(dom, pn_ssl_verify_mode_t(mode), NULL)) |
| throw error(MSG("SSL client verify mode failure")); |
| } |
| } |
| |
| ssl_client_options::ssl_client_options(const std::string &trust_db, enum ssl::verify_mode mode) : ssl_domain(false) { |
| client_setup(pn_domain(), trust_db, mode); |
| } |
| |
| ssl_client_options::ssl_client_options(ssl_certificate &cert, const std::string &trust_db, enum ssl::verify_mode mode) : ssl_domain(false) { |
| pn_ssl_domain_t *dom = pn_domain(); |
| set_cred(dom, cert.certdb_main_, cert.certdb_extra_, cert.passwd_, cert.pw_set_); |
| client_setup(dom, trust_db, mode); |
| } |
| |
| ssl_client_options::ssl_client_options() : ssl_domain(false) {} |
| |
| 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 |