blob: db27f64f0782eef415dfcd83c166afbe439c2b60 [file] [log] [blame]
/*
*
* 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 {
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"));
}
void incref() { refcount_++; }
void decref() {
if (--refcount_ == 0) {
pn_ssl_domain_free(pn_domain_);
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_;
if (impl_) impl_->incref();
}
ssl_domain& internal::ssl_domain::operator=(const ssl_domain&x) {
if (impl_) impl_->decref();
impl_ = x.impl_;
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