Author: kgiusti
Date: Thu Oct 11 18:43:40 2012
New Revision: 1397226
URL: http://svn.apache.org/viewvc?rev=1397226&view=rev
Log:
PROTON-64: separate certificate config and cipher settings.
Modified:
qpid/proton/trunk/proton-c/include/proton/ssl.h
qpid/proton/trunk/proton-c/src/ssl/openssl.c
qpid/proton/trunk/tests/proton_tests/ssl.py
Modified: qpid/proton/trunk/proton-c/include/proton/ssl.h
URL:
http://svn.apache.org/viewvc/qpid/proton/trunk/proton-c/include/proton/ssl.h?rev=1397226&r1=1397225&r2=1397226&view=diff
==============================================================================
--- qpid/proton/trunk/proton-c/include/proton/ssl.h (original)
+++ qpid/proton/trunk/proton-c/include/proton/ssl.h Thu Oct 11 18:43:40 2012
@@ -156,6 +156,12 @@ typedef enum {
* SSL servers do not attempt to verify their peers (PN_SSL_NO_VERIFY), and
SSL clients
* require the remote to provide a valid certificate (PN_SSL_VERIFY_PEER).
*
+ * @note In order to verify a peer, a trusted CA must be configured. See
+ * ::pn_ssl_set_trusted_ca_db().
+ *
+ * @note Servers must provide their own certificate when verifying a peer. See
+ * ::pn_ssl_set_credentials().
+ *
* @param[in] ssl the ssl client/server to configure.
* @param[in] mode the level of validation to apply to the peer's certificate.
* @param[in] trusted_CAs path to a database of trusted CAs that the server
will advertise
Modified: qpid/proton/trunk/proton-c/src/ssl/openssl.c
URL:
http://svn.apache.org/viewvc/qpid/proton/trunk/proton-c/src/ssl/openssl.c?rev=1397226&r1=1397225&r2=1397226&view=diff
==============================================================================
--- qpid/proton/trunk/proton-c/src/ssl/openssl.c (original)
+++ qpid/proton/trunk/proton-c/src/ssl/openssl.c Thu Oct 11 18:43:40 2012
@@ -87,7 +87,7 @@ struct pn_ssl_t {
// define two sets of allowable ciphers: those that require authentication,
and those
// that do not require authentication (anonymous). See ciphers(1).
#define CIPHERS_AUTHENTICATE "ALL:!aNULL:!eNULL:@STRENGTH"
-#define CIPHERS_ANONYMOUS "ALL:+aNULL:!eNULL:@STRENGTH"
+#define CIPHERS_ANONYMOUS "ALL:aNULL:!eNULL:@STRENGTH"
/* */
static int keyfile_pw_cb(char *buf, int size, int rwflag, void *userdata);
@@ -281,14 +281,6 @@ int pn_ssl_set_credentials( pn_ssl_t *ss
ssl->has_certificate = true;
- // Now that a certificate is configured, we can eliminate those ciphers that
do not
- // authenticate as they are vulnerable to Man in the Middle attacks.
- if (ssl->verify_mode == PN_SSL_ANONYMOUS_PEER) {
- if (pn_ssl_set_peer_authentication(ssl, PN_SSL_NO_VERIFY_PEER, NULL)) {
- return -2;
- }
- }
-
_log( ssl, "Configured local certificate file %s\n", certificate_file );
return 0;
}
@@ -362,6 +354,12 @@ int pn_ssl_set_peer_authentication(pn_ss
switch (mode) {
case PN_SSL_VERIFY_PEER:
+ if (!ssl->has_ca_db) {
+ _log_error("Error: cannot verify peer without a trusted CA configured.\n"
+ " Use pn_ssl_set_trusted_ca_db()\n");
+ return -1;
+ }
+
if (ssl->mode == PN_SSL_MODE_SERVER) {
// openssl requires that server connections supply a list of trusted CAs
which is
// sent to the client
@@ -369,6 +367,10 @@ int pn_ssl_set_peer_authentication(pn_ss
_log_error("Error: a list of trusted CAs must be provided.\n");
return -1;
}
+ if (!ssl->has_certificate) {
+ _log_error("Error: Server cannot verify peer without configuring a
certificate.\n"
+ " Use pn_ssl_set_credentials()\n");
+ }
ssl->trusted_CAs = pn_strdup( trusted_CAs );
STACK_OF(X509_NAME) *cert_names;
@@ -387,8 +389,7 @@ int pn_ssl_set_peer_authentication(pn_ss
SSL_CTX_set_verify_depth(ssl->ctx, 1);
#endif
- // Since we require the peer to authenticate, we should avoid anonymous
ciphers (KAG:
- // is this a reasonable approach?)
+ // Since we will exchange certificates, we must avoid anonymous ciphers.
if (!SSL_CTX_set_cipher_list( ssl->ctx, CIPHERS_AUTHENTICATE )) {
_log_ssl_error(ssl, "Failed to set cipher list to %s\n",
CIPHERS_AUTHENTICATE);
return -2;
@@ -397,6 +398,7 @@ int pn_ssl_set_peer_authentication(pn_ss
break;
case PN_SSL_NO_VERIFY_PEER:
+ // @todo - punt this setting?
SSL_CTX_set_verify( ssl->ctx, SSL_VERIFY_NONE, NULL );
// Still require authenticating ciphers, since they are stronger than
anonymous (KAG:
@@ -472,12 +474,6 @@ int pn_ssl_init(pn_ssl_t *ssl, pn_ssl_mo
_log_error("Unable to initialize SSL context: %s\n", strerror(errno));
return -1;
}
-
- // default: always verify the remote server, and only use ciphers that
authenticate.
- // This can be changed by pn_ssl_set_peer_authentication().
- if (pn_ssl_set_peer_authentication( ssl, PN_SSL_VERIFY_PEER, NULL)) {
- return -2;
- }
break;
case PN_SSL_MODE_SERVER:
@@ -488,13 +484,16 @@ int pn_ssl_init(pn_ssl_t *ssl, pn_ssl_mo
_log_error("Unable to initialize SSL context: %s\n", strerror(errno));
return -1;
}
-
- // default: no client authentication, allow ciphers that do not support
- // authentication (until a certificate is configured).
- if (pn_ssl_set_peer_authentication( ssl, PN_SSL_ANONYMOUS_PEER, NULL )) {
- return -2;
- }
break;
+
+ default:
+ _log_error("Invalid valid for pn_ssl_mode_t: %d\n", mode);
+ return -1;
+ }
+
+ // by default, allow anonymous ciphers so certificates are not required 'out
of the box'
+ if (pn_ssl_set_peer_authentication( ssl, PN_SSL_ANONYMOUS_PEER, NULL )) {
+ return -2;
}
DH *dh = get_dh2048();
Modified: qpid/proton/trunk/tests/proton_tests/ssl.py
URL:
http://svn.apache.org/viewvc/qpid/proton/trunk/tests/proton_tests/ssl.py?rev=1397226&r1=1397225&r2=1397226&view=diff
==============================================================================
--- qpid/proton/trunk/tests/proton_tests/ssl.py (original)
+++ qpid/proton/trunk/tests/proton_tests/ssl.py Thu Oct 11 18:43:40 2012
@@ -53,13 +53,49 @@ class SslTest(common.Test):
return os.path.join(os.path.dirname(__file__),
"ssl_db/%s" % file)
+ def test_defaults(self):
+ """ By default, both the server and the client support anonymous
+ ciphers.
+ """
+ client_conn = Connection()
+ self.t_client.bind(client_conn)
+ server_conn = Connection()
+ self.t_server.bind(server_conn)
+ client_conn.open()
+ server_conn.open()
+ self._pump()
+ client_conn.close()
+ server_conn.close()
+ self._pump()
+
+
+ def test_server_certificate(self):
+ """ Test that anonymous clients can still connect to a server that has
+ a certificate configured.
+ """
+ self.server.set_credentials(self._testpath("server-certificate.pem"),
+ self._testpath("server-private-key.pem"),
+ "server-password")
+ client_conn = Connection()
+ self.t_client.bind(client_conn)
+ server_conn = Connection()
+ self.t_server.bind(server_conn)
+ client_conn.open()
+ server_conn.open()
+ self._pump()
+ client_conn.close()
+ server_conn.close()
+ self._pump()
+
def test_server_authentication(self):
""" Simple SSL connection with authentication of the server
"""
self.server.set_credentials(self._testpath("server-certificate.pem"),
self._testpath("server-private-key.pem"),
"server-password")
+
self.client.set_trusted_ca_db(self._testpath("ca-certificate.pem"))
+ self.client.set_peer_authentication( SSL.VERIFY_PEER )
client_conn = Connection()
self.t_client.bind(client_conn)
@@ -72,11 +108,24 @@ class SslTest(common.Test):
server_conn.close()
self._pump()
- def test_server_anonymous(self):
- """ Simple SSL connection without configuring a server certificate, and
- configuring the client to accept an unverified peer.
+ def test_client_authentication(self):
+ """ Force the client to authenticate.
"""
+ # note: when requesting client auth, the server _must_ send its
+ # certificate, so make sure we configure one!
+ self.server.set_credentials(self._testpath("server-certificate.pem"),
+ self._testpath("server-private-key.pem"),
+ "server-password")
+ self.server.set_trusted_ca_db(self._testpath("ca-certificate.pem"))
+ self.server.set_peer_authentication( SSL.VERIFY_PEER,
+
self._testpath("ca-certificate.pem") )
+
+ # give the client a certificate, but let's not require server
authentication
+ self.client.set_credentials(self._testpath("client-certificate.pem"),
+ self._testpath("client-private-key.pem"),
+ "client-password")
self.client.set_peer_authentication( SSL.ANONYMOUS_PEER )
+
client_conn = Connection()
self.t_client.bind(client_conn)
server_conn = Connection()
@@ -88,17 +137,22 @@ class SslTest(common.Test):
server_conn.close()
self._pump()
- def test_client_authentication(self):
- """ @TODO: fix
+
+ def test_client_server_authentication(self):
+ """ Require both client and server to mutually identify themselves.
"""
self.server.set_credentials(self._testpath("server-certificate.pem"),
self._testpath("server-private-key.pem"),
"server-password")
self.server.set_trusted_ca_db(self._testpath("ca-certificate.pem"))
+ self.server.set_peer_authentication( SSL.VERIFY_PEER,
+
self._testpath("ca-certificate.pem") )
+
self.client.set_credentials(self._testpath("client-certificate.pem"),
self._testpath("client-private-key.pem"),
"client-password")
self.client.set_trusted_ca_db(self._testpath("ca-certificate.pem"))
+ self.client.set_peer_authentication( SSL.VERIFY_PEER )
client_conn = Connection()
self.t_client.bind(client_conn)
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]