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]

Reply via email to