You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by ac...@apache.org on 2015/12/30 22:13:08 UTC
[20/50] [abbrv] qpid-proton git commit: PROTON-1074: C++ ssl_domain:
restore removed ref counting; add test
PROTON-1074: C++ ssl_domain: restore removed ref counting; add test
Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/d9c0ed5a
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/d9c0ed5a
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/d9c0ed5a
Branch: refs/heads/go1
Commit: d9c0ed5a4087b621af13c2f395afba91f2bd9063
Parents: 595a854
Author: Clifford Jansen <cl...@apache.org>
Authored: Fri Dec 11 09:25:46 2015 -0800
Committer: Clifford Jansen <cl...@apache.org>
Committed: Fri Dec 11 09:57:04 2015 -0800
----------------------------------------------------------------------
examples/cpp/example_test.py | 25 +++++++
examples/cpp/ssl.cpp | 17 ++++-
examples/cpp/ssl_client_cert.cpp | 86 +++++++++++++----------
proton-c/bindings/cpp/include/proton/ssl.hpp | 13 ++--
proton-c/bindings/cpp/src/ssl_domain.cpp | 72 +++++++++++++------
5 files changed, 149 insertions(+), 64 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d9c0ed5a/examples/cpp/example_test.py
----------------------------------------------------------------------
diff --git a/examples/cpp/example_test.py b/examples/cpp/example_test.py
index 2f8b08c..3ea0c28 100644
--- a/examples/cpp/example_test.py
+++ b/examples/cpp/example_test.py
@@ -25,6 +25,7 @@ from random import randrange
from subprocess import Popen, PIPE, STDOUT
from copy import copy
import platform
+from os.path import dirname as dirname
def cmdline(*args):
"""Adjust executable name args[0] for windows and/or valgrind"""
@@ -82,6 +83,11 @@ def pick_addr():
p = randrange(10000, 20000)
return "127.0.0.1:%s" % p
+def ssl_certs_dir():
+ """Absolute path to the test SSL certificates"""
+ pn_root = dirname(dirname(dirname(sys.argv[0])))
+ return os.path.join(pn_root, "examples/cpp/ssl_certs")
+
class Broker(object):
"""Run the test broker"""
@@ -237,5 +243,24 @@ Tock...
finally:
os.environ = env # Restore environment
+ def test_ssl(self):
+ # SSL without SASL
+ expect="""Outgoing client connection connected via SSL. Server certificate identity CN=test_server
+"Hello World!"
+"""
+ addr = "amqps://" + pick_addr() + "/examples"
+ ignore_first_line, ignore_nl, ssl_hw = execute("ssl", addr, ssl_certs_dir()).partition('\n')
+ self.assertEqual(expect, ssl_hw)
+
+ def test_ssl_client_cert(self):
+ # SSL with SASL EXTERNAL
+ expect="""Inbound client certificate identity CN=test_client
+Outgoing client connection connected via SSL. Server certificate identity CN=test_server
+"Hello World!"
+"""
+ addr = "amqps://" + pick_addr() + "/examples"
+ ignore_first_line, ignore_nl, ssl_hw = execute("ssl_client_cert", addr, ssl_certs_dir()).partition('\n')
+ self.assertEqual(expect, ssl_hw)
+
if __name__ == "__main__":
unittest.main()
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d9c0ed5a/examples/cpp/ssl.cpp
----------------------------------------------------------------------
diff --git a/examples/cpp/ssl.cpp b/examples/cpp/ssl.cpp
index 13ad76f..5e670c2 100644
--- a/examples/cpp/ssl.cpp
+++ b/examples/cpp/ssl.cpp
@@ -38,6 +38,7 @@ bool using_OpenSSL();
std::string platform_CA(const std::string &base_name);
ssl_certificate platform_certificate(const std::string &base_name, const std::string &passwd);
std::string cert_directory;
+std::string find_CN(const std::string &);
struct server_handler : public proton::messaging_handler {
@@ -83,8 +84,9 @@ class hello_world_direct : public proton::messaging_handler {
}
void on_connection_opened(proton::event &e) {
- std::cout << "Outgoing client connection connected via SSL. Server certificate has subject " <<
- e.connection().transport().ssl().remote_subject() << std::endl;
+ std::string subject = e.connection().transport().ssl().remote_subject();
+ std::cout << "Outgoing client connection connected via SSL. Server certificate identity " <<
+ find_CN(subject) << std::endl;
}
void on_sendable(proton::event &e) {
@@ -159,3 +161,14 @@ std::string platform_CA(const std::string &base_name) {
return cert_directory + base_name + "-certificate.p12";
}
}
+
+std::string find_CN(const std::string &subject) {
+ // The subject string is returned with different whitespace and component ordering between platforms.
+ // Here we just return the common name by searching for "CN=...." in the subject, knowing that
+ // the test certificates do not contain any escaped characters.
+ size_t pos = subject.find("CN=");
+ if (pos == std::string::npos) throw std::runtime_error("No common name in certificate subject");
+ std::string cn = subject.substr(pos);
+ pos = cn.find(',');
+ return pos == std::string::npos ? cn : cn.substr(0, pos);
+}
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d9c0ed5a/examples/cpp/ssl_client_cert.cpp
----------------------------------------------------------------------
diff --git a/examples/cpp/ssl_client_cert.cpp b/examples/cpp/ssl_client_cert.cpp
index 412162a..0be0c32 100644
--- a/examples/cpp/ssl_client_cert.cpp
+++ b/examples/cpp/ssl_client_cert.cpp
@@ -40,22 +40,24 @@ bool using_OpenSSL();
std::string platform_CA(const std::string &base_name);
ssl_certificate platform_certificate(const std::string &base_name, const std::string &passwd);
std::string cert_directory;
+std::string find_CN(const std::string &);
struct server_handler : public proton::messaging_handler {
proton::acceptor inbound_listener;
void on_connection_opened(proton::event &e) {
- std::cout << "Inbound server connection connected via SSL. Protocol: " <<
+ std::cout << "Inbound server connection connected via SSL. Protocol: " <<
e.connection().transport().ssl().protocol() << std::endl;
- if (e.connection().transport().sasl().outcome() == sasl::OK)
- std::cout << "Inbound client certificate subject is " <<
- e.connection().transport().ssl().remote_subject() << std::endl;
+ if (e.connection().transport().sasl().outcome() == sasl::OK) {
+ std::string subject = e.connection().transport().ssl().remote_subject();
+ std::cout << "Inbound client certificate identity " << find_CN(subject) << std::endl;
+ }
else {
std::cout << "Inbound client authentication failed" <<std::endl;
e.connection().close();
}
- inbound_listener.close();
+ inbound_listener.close();
}
void on_message(proton::event &e) {
@@ -75,18 +77,18 @@ class hello_world_direct : public proton::messaging_handler {
void on_start(proton::event &e) {
// Configure listener. Details vary by platform.
ssl_certificate server_cert = platform_certificate("tserver", "tserverpw");
- std::string client_CA = platform_CA("tclient");
+ std::string client_CA = platform_CA("tclient");
// Specify an SSL domain with CA's for client certificate verification.
server_domain sdomain(server_cert, client_CA);
connection_options server_opts;
server_opts.server_domain(sdomain).handler(&s_handler);
- server_opts.allowed_mechs("EXTERNAL");
+ server_opts.allowed_mechs("EXTERNAL");
e.container().server_connection_options(server_opts);
// Configure client.
- ssl_certificate client_cert = platform_certificate("tclient", "tclientpw");
- std::string server_CA = platform_CA("tserver");
- client_domain cdomain(client_cert, server_CA);
+ ssl_certificate client_cert = platform_certificate("tclient", "tclientpw");
+ std::string server_CA = platform_CA("tserver");
+ client_domain cdomain(client_cert, server_CA);
connection_options client_opts;
client_opts.client_domain(cdomain).allowed_mechs("EXTERNAL");
// Validate the server certificate against this name:
@@ -98,8 +100,9 @@ class hello_world_direct : public proton::messaging_handler {
}
void on_connection_opened(proton::event &e) {
- std::cout << "Outgoing client connection connected via SSL. Server certificate has subject " <<
- e.connection().transport().ssl().remote_subject() << std::endl;
+ std::string subject = e.connection().transport().ssl().remote_subject();
+ std::cout << "Outgoing client connection connected via SSL. Server certificate identity " <<
+ find_CN(subject) << std::endl;
}
void on_sendable(proton::event &e) {
@@ -110,7 +113,7 @@ class hello_world_direct : public proton::messaging_handler {
}
void on_accepted(proton::event &e) {
- // All done.
+ // All done.
e.connection().close();
}
};
@@ -118,16 +121,16 @@ class hello_world_direct : public proton::messaging_handler {
int main(int argc, char **argv) {
try {
// Pick an "unusual" port since we are going to be talking to ourselves, not a broker.
- // Note the use of "amqps" as the URL scheme to denote a TLS/SSL connection.
+ // Note the use of "amqps" as the URL scheme to denote a TLS/SSL connection.
std::string url = argc > 1 ? argv[1] : "amqps://127.0.0.1:8888/examples";
- // Location of certificates and private key information:
- if (argc > 2) {
- cert_directory = argv[2];
- size_t sz = cert_directory.size();
- if (sz && cert_directory[sz -1] != '/')
- cert_directory.append("/");
- }
- else cert_directory = "ssl_certs/";
+ // Location of certificates and private key information:
+ if (argc > 2) {
+ cert_directory = argv[2];
+ size_t sz = cert_directory.size();
+ if (sz && cert_directory[sz -1] != '/')
+ cert_directory.append("/");
+ }
+ else cert_directory = "ssl_certs/";
hello_world_direct hwd(url);
proton::container(hwd).run();
@@ -139,7 +142,7 @@ int main(int argc, char **argv) {
}
-bool using_OpenSSL() {
+bool using_OpenSSL() {
// Current defaults.
#if defined(WIN32)
return false;
@@ -150,27 +153,38 @@ bool using_OpenSSL() {
ssl_certificate platform_certificate(const std::string &base_name, const std::string &passwd) {
if (using_OpenSSL()) {
- // The first argument will be the name of the file containing the public certificate, the
- // second argument will be the name of the file containing the private key.
- return ssl_certificate(cert_directory + base_name + "-certificate.pem",
- cert_directory + base_name + "-private-key.pem", passwd);
+ // The first argument will be the name of the file containing the public certificate, the
+ // second argument will be the name of the file containing the private key.
+ return ssl_certificate(cert_directory + base_name + "-certificate.pem",
+ cert_directory + base_name + "-private-key.pem", passwd);
}
else {
- // Windows SChannel
- // The first argument will be the database or store that contains one or more complete certificates
- // (public and private data). The second will be an optional name of the certificate in the store
- // (not used in this example with one certificate per store).
- return ssl_certificate(cert_directory + base_name + "-full.p12", "", passwd);
+ // Windows SChannel
+ // The first argument will be the database or store that contains one or more complete certificates
+ // (public and private data). The second will be an optional name of the certificate in the store
+ // (not used in this example with one certificate per store).
+ return ssl_certificate(cert_directory + base_name + "-full.p12", "", passwd);
}
}
std::string platform_CA(const std::string &base_name) {
if (using_OpenSSL()) {
- // In this simple example with self-signed certificates, the peer's certificate is the CA database.
- return cert_directory + base_name + "-certificate.pem";
+ // In this simple example with self-signed certificates, the peer's certificate is the CA database.
+ return cert_directory + base_name + "-certificate.pem";
}
else {
- // Windows SChannel. Use a pkcs#12 file with just the peer's public certificate information.
- return cert_directory + base_name + "-certificate.p12";
+ // Windows SChannel. Use a pkcs#12 file with just the peer's public certificate information.
+ return cert_directory + base_name + "-certificate.p12";
}
}
+
+std::string find_CN(const std::string &subject) {
+ // The subject string is returned with different whitespace and component ordering between platforms.
+ // Here we just return the common name by searching for "CN=...." in the subject, knowing that
+ // the test certificates do not contain any escaped characters.
+ size_t pos = subject.find("CN=");
+ if (pos == std::string::npos) throw std::runtime_error("No common name in certificate subject");
+ std::string cn = subject.substr(pos);
+ pos = cn.find(',');
+ return pos == std::string::npos ? cn : cn.substr(0, pos);
+}
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d9c0ed5a/proton-c/bindings/cpp/include/proton/ssl.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/ssl.hpp b/proton-c/bindings/cpp/include/proton/ssl.hpp
index f1b5974..bb78ae3 100644
--- a/proton-c/bindings/cpp/include/proton/ssl.hpp
+++ b/proton-c/bindings/cpp/include/proton/ssl.hpp
@@ -71,18 +71,22 @@ class ssl_certificate {
friend class server_domain;
};
+
+class ssl_domain_impl;
+
// Base class for SSL configuration
class ssl_domain {
public:
+ PN_CPP_EXTERN ssl_domain(const ssl_domain&);
+ PN_CPP_EXTERN ssl_domain& operator=(const ssl_domain&);
~ssl_domain();
protected:
- ssl_domain();
- pn_ssl_domain_t *init(bool is_server);
+ ssl_domain(bool is_server);
pn_ssl_domain_t *pn_domain();
private:
- pn_ssl_domain_t *impl_;
+ ssl_domain_impl *impl_;
};
/** SSL/TLS configuration for inbound connections created from a listener */
@@ -122,9 +126,6 @@ class client_domain : private ssl_domain {
friend class connection_options;
};
-
-
-
}
#endif /*!PROTON_CPP_SSL_H*/
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d9c0ed5a/proton-c/bindings/cpp/src/ssl_domain.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/ssl_domain.cpp b/proton-c/bindings/cpp/src/ssl_domain.cpp
index 2631880..9062713 100644
--- a/proton-c/bindings/cpp/src/ssl_domain.cpp
+++ b/proton-c/bindings/cpp/src/ssl_domain.cpp
@@ -26,19 +26,50 @@
namespace proton {
-ssl_domain::ssl_domain() : impl_(0) {}
-
-// Create on demand
-pn_ssl_domain_t *ssl_domain::init(bool server_type) {
- if (impl_) return impl_;
- impl_ = pn_ssl_domain(server_type ? PN_SSL_MODE_SERVER : PN_SSL_MODE_CLIENT);
- if (!impl_) throw error(MSG("SSL/TLS unavailable"));
- return impl_;
+class ssl_domain_impl {
+ public:
+ ssl_domain_impl(bool is_server) : refcount_(1), server_type_(is_server), pn_domain_(0) {}
+ void incref() { refcount_++; }
+ void decref() {
+ if (--refcount_ == 0) {
+ if (pn_domain_) pn_ssl_domain_free(pn_domain_);
+ delete this;
+ }
+ }
+ pn_ssl_domain_t *pn_domain();
+ private:
+ int refcount_;
+ bool server_type_;
+ pn_ssl_domain_t *pn_domain_;
+ ssl_domain_impl(const ssl_domain_impl&);
+ ssl_domain_impl& operator=(const ssl_domain_impl&);
+};
+
+pn_ssl_domain_t *ssl_domain_impl::pn_domain() {
+ if (pn_domain_) return pn_domain_;
+ // Lazily create in case never actually used or configured.
+ pn_domain_ = pn_ssl_domain(server_type_ ? PN_SSL_MODE_SERVER : PN_SSL_MODE_CLIENT);
+ if (!pn_domain_) throw error(MSG("SSL/TLS unavailable"));
+ return pn_domain_;
}
-pn_ssl_domain_t *ssl_domain::pn_domain() { return impl_; }
+ssl_domain::ssl_domain(bool is_server) : impl_(new ssl_domain_impl(is_server)) {}
+
+ssl_domain::ssl_domain(const ssl_domain &x) {
+ impl_ = x.impl_;
+ impl_->incref();
+}
+ssl_domain& ssl_domain::operator=(const ssl_domain&x) {
+ if (this != &x) {
+ impl_ = x.impl_;
+ impl_->incref();
+ }
+ return *this;
+}
+ssl_domain::~ssl_domain() { impl_->decref(); }
+
+pn_ssl_domain_t *ssl_domain::pn_domain() { return impl_->pn_domain(); }
-ssl_domain::~ssl_domain() { if (impl_) pn_ssl_domain_free(impl_); }
namespace {
@@ -51,17 +82,17 @@ void set_cred(pn_ssl_domain_t *dom, const std::string &main, const std::string &
}
}
-server_domain::server_domain(ssl_certificate &cert) {
- set_cred(init(true), cert.certdb_main_, cert.certdb_extra_, cert.passwd_, cert.pw_set_);
+server_domain::server_domain(ssl_certificate &cert) : ssl_domain(true) {
+ set_cred(pn_domain(), cert.certdb_main_, cert.certdb_extra_, cert.passwd_, cert.pw_set_);
}
server_domain::server_domain(
ssl_certificate &cert,
const std::string &trust_db,
const std::string &advertise_db,
- ssl::verify_mode_t mode)
+ ssl::verify_mode_t mode) : ssl_domain(true)
{
- pn_ssl_domain_t* dom = init(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));
@@ -70,9 +101,10 @@ server_domain::server_domain(
throw error(MSG("SSL server configuration failure requiring client certificates using " << db));
}
-server_domain::server_domain() {}
+server_domain::server_domain() : ssl_domain(true) {}
server_domain::~server_domain() {}
+
namespace {
void client_setup(pn_ssl_domain_t *dom, const std::string &trust_db, ssl::verify_mode_t mode) {
if (pn_ssl_domain_set_trusted_ca_db(dom, trust_db.c_str()))
@@ -82,17 +114,17 @@ void client_setup(pn_ssl_domain_t *dom, const std::string &trust_db, ssl::verify
}
}
-client_domain::client_domain(const std::string &trust_db, ssl::verify_mode_t mode) {
- client_setup(init(false), trust_db, mode);
+client_domain::client_domain(const std::string &trust_db, ssl::verify_mode_t mode) : ssl_domain(false) {
+ client_setup(pn_domain(), trust_db, mode);
}
-client_domain::client_domain(ssl_certificate &cert, const std::string &trust_db, ssl::verify_mode_t mode) {
- pn_ssl_domain_t *dom = init(false);
+client_domain::client_domain(ssl_certificate &cert, const std::string &trust_db, ssl::verify_mode_t 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);
}
-client_domain::client_domain() {}
+client_domain::client_domain() : ssl_domain(false) {}
client_domain::~client_domain() {}
ssl_certificate::ssl_certificate(const std::string &main, const std::string &extra)
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org