Modified: qpid/proton/trunk/proton-j/proton/src/main/java/org/apache/qpid/proton/engine/impl/ssl/SslImpl.java URL: http://svn.apache.org/viewvc/qpid/proton/trunk/proton-j/proton/src/main/java/org/apache/qpid/proton/engine/impl/ssl/SslImpl.java?rev=1423617&r1=1423616&r2=1423617&view=diff ============================================================================== --- qpid/proton/trunk/proton-j/proton/src/main/java/org/apache/qpid/proton/engine/impl/ssl/SslImpl.java (original) +++ qpid/proton/trunk/proton-j/proton/src/main/java/org/apache/qpid/proton/engine/impl/ssl/SslImpl.java Tue Dec 18 20:17:28 2012 @@ -21,99 +21,32 @@ package org.apache.qpid.proton.engine.impl.ssl; import org.apache.qpid.proton.engine.Ssl; +import org.apache.qpid.proton.engine.SslDomain; +import org.apache.qpid.proton.engine.SslPeerDetails; import org.apache.qpid.proton.engine.impl.TransportInput; import org.apache.qpid.proton.engine.impl.TransportOutput; import org.apache.qpid.proton.engine.impl.TransportWrapper; import org.apache.qpid.proton.engine.impl.PlainTransportWrapper; -/* - * Enables the JSSE system debugging system property: - * - * -Djavax.net.debug=all - */ public class SslImpl implements Ssl { - private Mode _mode; - private VerifyMode _verifyMode = VerifyMode.ANONYMOUS_PEER; - private String _certificateFile; - private String _privateKeyFile; - private String _privateKeyPassword; - private String _trustedCaDb; - private boolean _allowUnsecuredClient; - private SslTransportWrapper _unsecureClientAwareTransportWrapper; - @Override - public void init(Mode mode) - { - _mode = mode; - } - - @Override - public void setCredentials(String certificateFile, - String privateKeyFile, String privateKeyPassword) - { - _certificateFile = certificateFile; - _privateKeyFile = privateKeyFile; - _privateKeyPassword = privateKeyPassword; - } - - @Override - public void setTrustedCaDb(String certificateDb) - { - _trustedCaDb = certificateDb; - } - - @Override - public String getTrustedCaDb() - { - return _trustedCaDb; - } - - @Override - public void allowUnsecuredClient(boolean allowUnsecuredClient) - { - if (_mode == Mode.CLIENT) - { - throw new IllegalArgumentException("Only servers may allow unsecured clients"); - } - _allowUnsecuredClient = allowUnsecuredClient; - } - - @Override - public void setPeerAuthentication(VerifyMode verifyMode) - { - _verifyMode = verifyMode; - } - - @Override - public VerifyMode getPeerAuthentication() - { - return _verifyMode; - } - - @Override - public Mode getMode() - { - return _mode; - } - - @Override - public String getPrivateKeyFile() - { - return _privateKeyFile; - } + private final SslDomain _domain; + private final ProtonSslEngineProvider _protonSslEngineProvider; - @Override - public String getPrivateKeyPassword() - { - return _privateKeyPassword; - } + private final SslPeerDetails _peerDetails; - @Override - public String getCertificateFile() - { - return _certificateFile; + /** + * @param sslDomain must implement {@link ProtonSslEngineProvider}. This is not possible + * enforce at the API level because {@link ProtonSslEngineProvider} is not part of the + * public Proton API.</p> + */ + public SslImpl(SslDomain domain, SslPeerDetails peerDetails) + { + _domain = domain; + _protonSslEngineProvider = (ProtonSslEngineProvider)domain; + _peerDetails = peerDetails; } public TransportWrapper wrap(TransportInput inputProcessor, TransportOutput outputProcessor) @@ -206,8 +139,12 @@ public class SslImpl implements Ssl { if (_transportWrapper == null) { - SslTransportWrapper sslTransportWrapper = new SimpleSslTransportWrapper(SslImpl.this, _inputProcessor, _outputProcessor); - if (_allowUnsecuredClient) + SslTransportWrapper sslTransportWrapper = new SimpleSslTransportWrapper( + _protonSslEngineProvider.createSslEngine(_peerDetails), + _inputProcessor, + _outputProcessor); + + if (_domain.allowUnsecuredClient()) { TransportWrapper plainTransportWrapper = new PlainTransportWrapper(_outputProcessor, _inputProcessor); _transportWrapper = new SslHandshakeSniffingTransportWrapper(sslTransportWrapper, plainTransportWrapper);
Modified: qpid/proton/trunk/proton-j/proton/src/main/scripts/proton.py URL: http://svn.apache.org/viewvc/qpid/proton/trunk/proton-j/proton/src/main/scripts/proton.py?rev=1423617&r1=1423616&r2=1423617&view=diff ============================================================================== --- qpid/proton/trunk/proton-j/proton/src/main/scripts/proton.py (original) +++ qpid/proton/trunk/proton-j/proton/src/main/scripts/proton.py Tue Dec 18 20:17:28 2012 @@ -17,9 +17,11 @@ # from uuid import UUID -from org.apache.qpid.proton.engine import EndpointState, TransportException, Sasl, Ssl + +from org.apache.qpid.proton.engine import EndpointState, TransportException, Sasl, SslDomain from org.apache.qpid.proton.engine.impl import ConnectionImpl, SessionImpl, \ SenderImpl, ReceiverImpl, TransportImpl +from org.apache.qpid.proton.engine.impl.ssl import SslDomainImpl, SslPeerDetailsImpl from org.apache.qpid.proton.message import MessageFormat from org.apache.qpid.proton.message.impl import MessageImpl from org.apache.qpid.proton.messenger import AcceptMode, MessengerException, Status @@ -29,6 +31,8 @@ from org.apache.qpid.proton.amqp import from jarray import zeros from java.util import EnumSet, UUID as JUUID +LANGUAGE = "Java" + class Skipped(Exception): skipped = True @@ -827,30 +831,50 @@ class SSLException(Exception): class SSLUnavailable(SSLException): pass -class SSL(object): +class SSLDomain(object): - MODE_SERVER = Ssl.Mode.SERVER - MODE_CLIENT = Ssl.Mode.CLIENT - VERIFY_PEER = Ssl.VerifyMode.VERIFY_PEER - ANONYMOUS_PEER = Ssl.VerifyMode.ANONYMOUS_PEER + MODE_SERVER = SslDomain.Mode.SERVER + MODE_CLIENT = SslDomain.Mode.CLIENT + VERIFY_PEER = SslDomain.VerifyMode.VERIFY_PEER + ANONYMOUS_PEER = SslDomain.VerifyMode.ANONYMOUS_PEER VERIFY_PEER_NAME = None # TBD - def __init__(self,transport): - self._ssl = transport.impl.ssl() - - def init(self, mode): - self._ssl.init(mode) + def __init__(self, mode): + self._domain = SslDomainImpl() + self._domain.init(mode) - def set_credentials(self, cert_file,key_file,password): - self._ssl.setCredentials(cert_file,key_file,password) + def set_credentials(self, cert_file, key_file, password): + self._domain.setCredentials(cert_file, key_file, password) def set_trusted_ca_db(self, certificate_db): - self._ssl.setTrustedCaDb(certificate_db) + self._domain.setTrustedCaDb(certificate_db) def set_peer_authentication(self, verify_mode, trusted_CAs=None): - self._ssl.setPeerAuthentication(verify_mode) + self._domain.setPeerAuthentication(verify_mode) if trusted_CAs is not None: - self._ssl.setTrustedCaDb(trusted_CAs) + self._domain.setTrustedCaDb(trusted_CAs) + + def allow_unsecured_client(self, allow_unsecured = True): + self._domain.allowUnsecuredClient(allow_unsecured) + +class SSLSessionDetails(object): + + def __init__(self, session_id): + self._session_details = SslPeerDetailsImpl(session_id, 1) + +class SSL(object): + + def __init__(self, transport, domain, session_details=None): + + internal_session_details = None + if session_details: + internal_session_details = session_details._session_details + + self._ssl = transport.impl.ssl(domain._domain, internal_session_details) + self._session_details = session_details + + def get_session_details(self): + return self._session_details def cipher_name(self): return self._ssl.getCipherName() @@ -858,19 +882,41 @@ class SSL(object): def protocol_name(self): return self._ssl.getProtocolName() - def allow_unsecured_client(self): - self._ssl.allowUnsecuredClient(True) - def _set_peer_hostname(self, hostname): raise Skipped() def _get_peer_hostname(self): raise Skipped() peer_hostname = property(_get_peer_hostname, _set_peer_hostname) -__all__ = ["Messenger", "Message", "ProtonException", "MessengerException", - "MessageException", "Timeout", "Condition", "Data", "Endpoint", - "Connection", "Session", "Link", "Terminus", "Sender", "Receiver", - "Delivery", "Transport", "TransportException", "SASL", "SSL", - "SSLException", "SSLUnavailable", "PN_SESSION_WINDOW", "symbol", - "MANUAL", "PENDING", "ACCEPTED", "REJECTED"] - +__all__ = [ + "ACCEPTED", + "LANGUAGE", + "MANUAL", + "PENDING", + "REJECTED", + "PN_SESSION_WINDOW", + "Condition", + "Connection", + "Data", + "Delivery", + "Endpoint", + "Link", + "Message", + "MessageException", + "Messenger", + "MessengerException", + "ProtonException", + "Receiver", + "SASL", + "Sender", + "Session", + "SSL", + "SSLDomain", + "SSLException", + "SSLSessionDetails", + "SSLUnavailable", + "symbol", + "Terminus", + "Timeout", + "Transport", + "TransportException"] Modified: qpid/proton/trunk/proton-j/proton/src/test/java/org/apache/qpid/proton/engine/impl/ssl/CapitalisingDummySslEngine.java URL: http://svn.apache.org/viewvc/qpid/proton/trunk/proton-j/proton/src/test/java/org/apache/qpid/proton/engine/impl/ssl/CapitalisingDummySslEngine.java?rev=1423617&r1=1423616&r2=1423617&view=diff ============================================================================== --- qpid/proton/trunk/proton-j/proton/src/test/java/org/apache/qpid/proton/engine/impl/ssl/CapitalisingDummySslEngine.java (original) +++ qpid/proton/trunk/proton-j/proton/src/test/java/org/apache/qpid/proton/engine/impl/ssl/CapitalisingDummySslEngine.java Tue Dec 18 20:17:28 2012 @@ -26,11 +26,10 @@ import static org.junit.Assert.assertTru import java.nio.ByteBuffer; import javax.net.ssl.SSLEngineResult; -import javax.net.ssl.SSLException; import javax.net.ssl.SSLEngineResult.HandshakeStatus; import javax.net.ssl.SSLEngineResult.Status; +import javax.net.ssl.SSLException; -import org.apache.qpid.proton.engine.impl.ssl.SslEngineFacade; /** @@ -39,7 +38,7 @@ import org.apache.qpid.proton.engine.imp * * Using a true SSLEngine for this would be impractical. */ -public class CapitalisingDummySslEngine implements SslEngineFacade +public class CapitalisingDummySslEngine implements ProtonSslEngine { static final int SHORT_ENCODED_CHUNK_SIZE = 2; private static final int MAX_ENCODED_CHUNK_SIZE = 5; @@ -223,4 +222,10 @@ public class CapitalisingDummySslEngine assertTrue("Clear text character " + uncapitalisedChar + " must be lowercase", Character.isLowerCase(uncapitalisedChar)); assertEquals("Unexpected clear text pad", Character.toString(CLEARTEXT_PADDING), Character.toString(underscore)); } + + @Override + public boolean getUseClientMode() + { + return true; + } } Modified: qpid/proton/trunk/proton-j/proton/src/test/java/org/apache/qpid/proton/engine/impl/ssl/SimpleSslTransportWrapperTest.java URL: http://svn.apache.org/viewvc/qpid/proton/trunk/proton-j/proton/src/test/java/org/apache/qpid/proton/engine/impl/ssl/SimpleSslTransportWrapperTest.java?rev=1423617&r1=1423616&r2=1423617&view=diff ============================================================================== --- qpid/proton/trunk/proton-j/proton/src/test/java/org/apache/qpid/proton/engine/impl/ssl/SimpleSslTransportWrapperTest.java (original) +++ qpid/proton/trunk/proton-j/proton/src/test/java/org/apache/qpid/proton/engine/impl/ssl/SimpleSslTransportWrapperTest.java Tue Dec 18 20:17:28 2012 @@ -24,10 +24,7 @@ import static org.apache.qpid.proton.eng import static org.apache.qpid.proton.engine.impl.ssl.ByteTestHelper.createFilledBuffer; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; -import org.apache.qpid.proton.engine.Ssl; import org.junit.Before; import org.junit.Test; @@ -37,9 +34,6 @@ import org.junit.Test; */ public class SimpleSslTransportWrapperTest { - private Ssl _sslConfiguration = mock(Ssl.class); - private SslEngineFacadeFactory _dummySslEngineFacadeFactory = mock(SslEngineFacadeFactory.class); - private RememberingTransportInput _underlyingInput = new RememberingTransportInput(); private CannedTransportOutput _underlyingOutput = new CannedTransportOutput(); @@ -50,8 +44,7 @@ public class SimpleSslTransportWrapperTe @Before public void setUp() { - when(_dummySslEngineFacadeFactory.createSslEngineFacade(_sslConfiguration)).thenReturn(_dummySslEngine); - _transportWrapper = new SimpleSslTransportWrapper(_sslConfiguration, _underlyingInput, _underlyingOutput, _dummySslEngineFacadeFactory); + _transportWrapper = new SimpleSslTransportWrapper(_dummySslEngine, _underlyingInput, _underlyingOutput); } @Test Modified: qpid/proton/trunk/tests/proton_tests/ssl.py URL: http://svn.apache.org/viewvc/qpid/proton/trunk/tests/proton_tests/ssl.py?rev=1423617&r1=1423616&r2=1423617&view=diff ============================================================================== --- qpid/proton/trunk/tests/proton_tests/ssl.py (original) +++ qpid/proton/trunk/tests/proton_tests/ssl.py Tue Dec 18 20:17:28 2012 @@ -30,28 +30,39 @@ class SslTest(common.Test): def setup(self): try: - self.t_server = Transport() - self.server = SSL(self.t_server) - self.server.init(SSL.MODE_SERVER) - self.t_client = Transport() - self.client = SSL(self.t_client) - self.client.init(SSL.MODE_CLIENT) + self.server_domain = SSLDomain(SSLDomain.MODE_SERVER) + self.client_domain = SSLDomain(SSLDomain.MODE_CLIENT) except SSLUnavailable, e: raise Skipped(e) def teardown(self): - self.client = None - self.t_client = None - self.server = None - self.t_server = None + self.server_domain = None + self.client_domain = None - def _pump(self): + class SslTestConnection(object): + """ Represents a single SSL connection. + """ + def __init__(self, domain=None, session_details=None): + try: + self.ssl = None + self.domain = domain + self.transport = Transport() + self.connection = Connection() + self.transport.bind(self.connection) + if domain: + self.ssl = SSL( self.transport, self.domain, session_details ) + except SSLUnavailable, e: + raise Skipped(e) + + def _pump(self, ssl1, ssl2): + """ Allow two SslTestConnections to transfer data until done. + """ while True: - out_client = self.t_client.output(1024) - out_server = self.t_server.output(1024) - if out_client: self.t_server.input(out_client) - if out_server: self.t_client.input(out_server) - if not out_client and not out_server: break + out1 = ssl1.transport.output(1024) + out2 = ssl2.transport.output(1024) + if out1: ssl2.transport.input(out1) + if out2: ssl1.transport.input(out2) + if not out1 and not out2: break def _testpath(self, file): """ Set the full path to the certificate,keyfile, etc. for the test. @@ -59,242 +70,412 @@ class SslTest(common.Test): return os.path.join(os.path.dirname(__file__), "ssl_db/%s" % file) - def _do_handshake(self): + def _do_handshake(self, client, server): """ Attempt to connect client to server. Will throw a TransportException if the SSL handshake fails. """ - 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() - assert self.client.protocol_name() is not None - client_conn.close() - server_conn.close() - self._pump() - + client.connection.open() + server.connection.open() + self._pump(client, server) + assert client.ssl.protocol_name() is not None + client.connection.close() + server.connection.close() + self._pump(client, server) def test_defaults(self): """ By default, both the server and the client support anonymous ciphers - they should connect without need for a certificate. """ - client_conn = Connection() - self.t_client.bind(client_conn) - server_conn = Connection() - self.t_server.bind(server_conn) + server = SslTest.SslTestConnection( self.server_domain ) + client = SslTest.SslTestConnection( self.client_domain ) # check that no SSL connection exists - assert not self.server.cipher_name() - assert not self.client.protocol_name() + assert not server.ssl.cipher_name() + assert not client.ssl.protocol_name() - client_conn.open() - server_conn.open() - self._pump() + #client.transport.trace(Transport.TRACE_DRV) + #server.transport.trace(Transport.TRACE_DRV) + + client.connection.open() + server.connection.open() + self._pump( client, server ) # now SSL should be active - assert self.server.cipher_name() is not None - assert self.client.protocol_name() is not None + assert server.ssl.cipher_name() is not None + assert client.ssl.protocol_name() is not None - client_conn.close() - server_conn.close() - self._pump() + client.connection.close() + server.connection.close() + self._pump( client, server ) 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() - assert self.client.protocol_name() is not None - client_conn.close() - server_conn.close() - self._pump() + self.server_domain.set_credentials(self._testpath("server-certificate.pem"), + self._testpath("server-private-key.pem"), + "server-password") + server = SslTest.SslTestConnection( self.server_domain ) + client = SslTest.SslTestConnection( self.client_domain ) + + client.connection.open() + server.connection.open() + self._pump( client, server ) + assert client.ssl.protocol_name() is not None + client.connection.close() + server.connection.close() + self._pump( client, server ) 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) - server_conn = Connection() - self.t_server.bind(server_conn) - client_conn.open() - server_conn.open() - self._pump() - assert self.client.protocol_name() is not None - client_conn.close() - server_conn.close() - self._pump() + self.server_domain.set_credentials(self._testpath("server-certificate.pem"), + self._testpath("server-private-key.pem"), + "server-password") + + self.client_domain.set_trusted_ca_db(self._testpath("ca-certificate.pem")) + self.client_domain.set_peer_authentication( SSLDomain.VERIFY_PEER ) + + server = SslTest.SslTestConnection( self.server_domain ) + client = SslTest.SslTestConnection( self.client_domain ) + + client.connection.open() + server.connection.open() + self._pump( client, server ) + assert client.ssl.protocol_name() is not None + client.connection.close() + server.connection.close() + self._pump( client, server ) 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") ) + self.server_domain.set_credentials(self._testpath("server-certificate.pem"), + self._testpath("server-private-key.pem"), + "server-password") + self.server_domain.set_trusted_ca_db(self._testpath("ca-certificate.pem")) + self.server_domain.set_peer_authentication( SSLDomain.VERIFY_PEER, + self._testpath("ca-certificate.pem") ) + server = SslTest.SslTestConnection( self.server_domain ) # 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() - self.t_server.bind(server_conn) - client_conn.open() - server_conn.open() - self._pump() - assert self.client.protocol_name() is not None - client_conn.close() - server_conn.close() - self._pump() + self.client_domain.set_credentials(self._testpath("client-certificate.pem"), + self._testpath("client-private-key.pem"), + "client-password") + self.client_domain.set_peer_authentication( SSLDomain.ANONYMOUS_PEER ) + client = SslTest.SslTestConnection( self.client_domain ) + + client.connection.open() + server.connection.open() + self._pump( client, server ) + assert client.ssl.protocol_name() is not None + client.connection.close() + server.connection.close() + self._pump( client, server ) + + def test_client_authentication_fail_bad_cert(self): + """ Ensure that the server can detect a bad client certificate. + """ + # note: when requesting client auth, the server _must_ send its + # certificate, so make sure we configure one! + self.server_domain.set_credentials(self._testpath("server-certificate.pem"), + self._testpath("server-private-key.pem"), + "server-password") + self.server_domain.set_trusted_ca_db(self._testpath("ca-certificate.pem")) + self.server_domain.set_peer_authentication( SSLDomain.VERIFY_PEER, + self._testpath("ca-certificate.pem") ) + server = SslTest.SslTestConnection( self.server_domain ) + + self.client_domain.set_credentials(self._testpath("bad-server-certificate.pem"), + self._testpath("bad-server-private-key.pem"), + "server-password") + self.client_domain.set_peer_authentication( SSLDomain.ANONYMOUS_PEER ) + client = SslTest.SslTestConnection( self.client_domain ) + + client.connection.open() + server.connection.open() + try: + self._pump( client, server ) + assert False, "Server failed to reject bad certificate." + except TransportException, e: + pass + + def test_client_authentication_fail_no_cert(self): + """ Ensure that the server will fail a client that does not provide a + certificate. + """ + # note: when requesting client auth, the server _must_ send its + # certificate, so make sure we configure one! + self.server_domain.set_credentials(self._testpath("server-certificate.pem"), + self._testpath("server-private-key.pem"), + "server-password") + self.server_domain.set_trusted_ca_db(self._testpath("ca-certificate.pem")) + self.server_domain.set_peer_authentication( SSLDomain.VERIFY_PEER, + self._testpath("ca-certificate.pem") ) + server = SslTest.SslTestConnection( self.server_domain ) + self.client_domain.set_peer_authentication( SSLDomain.ANONYMOUS_PEER ) + client = SslTest.SslTestConnection( self.client_domain ) + + client.connection.open() + server.connection.open() + try: + self._pump( client, server ) + assert False, "Server failed to reject bad certificate." + except TransportException, e: + pass 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) - server_conn = Connection() - self.t_server.bind(server_conn) - client_conn.open() - server_conn.open() - self._pump() - assert self.client.protocol_name() is not None - client_conn.close() - server_conn.close() - self._pump() + self.server_domain.set_credentials(self._testpath("server-certificate.pem"), + self._testpath("server-private-key.pem"), + "server-password") + self.server_domain.set_trusted_ca_db(self._testpath("ca-certificate.pem")) + self.server_domain.set_peer_authentication( SSLDomain.VERIFY_PEER, + self._testpath("ca-certificate.pem") ) + + self.client_domain.set_credentials(self._testpath("client-certificate.pem"), + self._testpath("client-private-key.pem"), + "client-password") + self.client_domain.set_trusted_ca_db(self._testpath("ca-certificate.pem")) + self.client_domain.set_peer_authentication( SSLDomain.VERIFY_PEER ) + + server = SslTest.SslTestConnection( self.server_domain ) + client = SslTest.SslTestConnection( self.client_domain ) + + client.connection.open() + server.connection.open() + self._pump( client, server ) + assert client.ssl.protocol_name() is not None + client.connection.close() + server.connection.close() + self._pump( client, server ) def test_server_only_authentication(self): """ Client verifies server, but server does not verify client. """ - self.server.set_credentials(self._testpath("server-certificate.pem"), - self._testpath("server-private-key.pem"), - "server-password") - self.server.set_peer_authentication( SSL.ANONYMOUS_PEER ) - - 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) - server_conn = Connection() - self.t_server.bind(server_conn) - client_conn.open() - server_conn.open() - self._pump() - assert self.client.protocol_name() is not None - client_conn.close() - server_conn.close() - self._pump() + self.server_domain.set_credentials(self._testpath("server-certificate.pem"), + self._testpath("server-private-key.pem"), + "server-password") + self.server_domain.set_peer_authentication( SSLDomain.ANONYMOUS_PEER ) + + self.client_domain.set_credentials(self._testpath("client-certificate.pem"), + self._testpath("client-private-key.pem"), + "client-password") + self.client_domain.set_trusted_ca_db(self._testpath("ca-certificate.pem")) + self.client_domain.set_peer_authentication( SSLDomain.VERIFY_PEER ) + + server = SslTest.SslTestConnection( self.server_domain ) + client = SslTest.SslTestConnection( self.client_domain ) + + client.connection.open() + server.connection.open() + self._pump( client, server ) + assert client.ssl.protocol_name() is not None + client.connection.close() + server.connection.close() + self._pump( client, server ) def test_bad_server_certificate(self): """ A server with a self-signed certificate that is not trusted by the client. The client should reject the server. """ - self.server.set_credentials(self._testpath("bad-server-certificate.pem"), - self._testpath("bad-server-private-key.pem"), - "server-password") - self.server.set_peer_authentication( SSL.ANONYMOUS_PEER ) + self.server_domain.set_credentials(self._testpath("bad-server-certificate.pem"), + self._testpath("bad-server-private-key.pem"), + "server-password") + self.server_domain.set_peer_authentication( SSLDomain.ANONYMOUS_PEER ) - self.client.set_trusted_ca_db(self._testpath("ca-certificate.pem")) - self.client.set_peer_authentication( SSL.VERIFY_PEER ) + self.client_domain.set_trusted_ca_db(self._testpath("ca-certificate.pem")) + self.client_domain.set_peer_authentication( SSLDomain.VERIFY_PEER ) - client_conn = Connection() - self.t_client.bind(client_conn) - server_conn = Connection() - self.t_server.bind(server_conn) - client_conn.open() - server_conn.open() + server = SslTest.SslTestConnection( self.server_domain ) + client = SslTest.SslTestConnection( self.client_domain ) + + client.connection.open() + server.connection.open() try: - self._pump() + self._pump( client, server ) assert False, "Client failed to reject bad certificate." except TransportException, e: pass + del server + del client + + # now re-try with a client that does not require peer verification + self.client_domain.set_peer_authentication( SSLDomain.ANONYMOUS_PEER ) + + client = SslTest.SslTestConnection( self.client_domain ) + server = SslTest.SslTestConnection( self.server_domain ) + + client.connection.open() + server.connection.open() + self._pump( client, server ) + assert client.ssl.protocol_name() is not None + client.connection.close() + server.connection.close() + self._pump( client, server ) + def test_allow_unsecured_client(self): - """ Client is allows to connect unsecured to secured client + """ Server allows an unsecured client to connect if configured. """ - self.t_client = Transport() - - 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.server.allow_unsecured_client() - - 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() + self.server_domain.set_credentials(self._testpath("server-certificate.pem"), + self._testpath("server-private-key.pem"), + "server-password") + self.server_domain.set_trusted_ca_db(self._testpath("ca-certificate.pem")) + self.server_domain.set_peer_authentication( SSLDomain.VERIFY_PEER, + self._testpath("ca-certificate.pem") ) + # allow unsecured clients on this connection + self.server_domain.allow_unsecured_client() + server = SslTest.SslTestConnection( self.server_domain ) + + # non-ssl connection + client = SslTest.SslTestConnection() + + client.connection.open() + server.connection.open() + self._pump( client, server ) + assert server.ssl.protocol_name() is None + client.connection.close() + server.connection.close() + self._pump( client, server ) def test_disallow_unsecured_client(self): - """ Client is disallowed from connecting unsecured to secured client + """ Non-SSL Client is disallowed from connecting to server. """ - self.t_client = Transport() + self.server_domain.set_credentials(self._testpath("server-certificate.pem"), + self._testpath("server-private-key.pem"), + "server-password") + self.server_domain.set_trusted_ca_db(self._testpath("ca-certificate.pem")) + self.server_domain.set_peer_authentication( SSLDomain.ANONYMOUS_PEER ) + server = SslTest.SslTestConnection( self.server_domain ) - 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") ) - - client_conn = Connection() - self.t_client.bind(client_conn) - server_conn = Connection() - self.t_server.bind(server_conn) - client_conn.open() - server_conn.open() + # non-ssl connection + client = SslTest.SslTestConnection() + + client.connection.open() + server.connection.open() try: - self._pump() - assert False, "Expecting exception" + self._pump( client, server ) + assert False, "Server did not reject client as expected." except TransportException: - assert True + pass + + def test_session_resume(self): + """ Test resume of client session. + """ + self.server_domain.set_credentials(self._testpath("server-certificate.pem"), + self._testpath("server-private-key.pem"), + "server-password") + self.server_domain.set_peer_authentication( SSLDomain.ANONYMOUS_PEER ) + + self.client_domain.set_trusted_ca_db(self._testpath("ca-certificate.pem")) + self.client_domain.set_peer_authentication( SSLDomain.VERIFY_PEER ) + + # details will be used in initial and subsequent connections to allow session to be resumed + initial_session_details = SSLSessionDetails("my-session-id") + + server = SslTest.SslTestConnection( self.server_domain ) + client = SslTest.SslTestConnection( self.client_domain, initial_session_details ) + + # bring up the connection and store its state + client.connection.open() + server.connection.open() + self._pump( client, server ) + assert client.ssl.protocol_name() is not None + + # cleanly shutdown the connection + client.connection.close() + server.connection.close() + self._pump( client, server ) + + # destroy the existing clients + del client + del server + + # now create a new set of connections, use last session id + server = SslTest.SslTestConnection( self.server_domain ) + # provide the details of the last session, allowing it to be resumed + client = SslTest.SslTestConnection( self.client_domain, initial_session_details ) + + #client.transport.trace(Transport.TRACE_DRV) + #server.transport.trace(Transport.TRACE_DRV) + + client.connection.open() + server.connection.open() + self._pump( client, server ) + assert server.ssl.protocol_name() is not None + if(LANGUAGE=="C"): + assert client.ssl.resume_status() == SSL.RESUME_REUSED + else: + # Java gives no way to check whether a previous session has been resumed + pass + + client.connection.close() + server.connection.close() + self._pump( client, server ) + + # now try to resume using an unknown session-id, expect resume to fail + # and a new session is negotiated + + del client + del server + + server = SslTest.SslTestConnection( self.server_domain ) + client = SslTest.SslTestConnection( self.client_domain, SSLSessionDetails("some-other-session-id") ) + + client.connection.open() + server.connection.open() + self._pump( client, server ) + assert server.ssl.protocol_name() is not None + if(LANGUAGE=="C"): + assert client.ssl.resume_status() == SSL.RESUME_NEW + + client.connection.close() + server.connection.close() + self._pump( client, server ) + + def test_multiple_sessions(self): + """ Test multiple simultaineous active SSL sessions with bi-directional + certificate verification, shared across two domains. + """ + self.server_domain.set_credentials(self._testpath("server-certificate.pem"), + self._testpath("server-private-key.pem"), + "server-password") + self.server_domain.set_trusted_ca_db(self._testpath("ca-certificate.pem")) + self.server_domain.set_peer_authentication( SSLDomain.VERIFY_PEER, + self._testpath("ca-certificate.pem") ) + + self.client_domain.set_credentials(self._testpath("client-certificate.pem"), + self._testpath("client-private-key.pem"), + "client-password") + self.client_domain.set_trusted_ca_db(self._testpath("ca-certificate.pem")) + self.client_domain.set_peer_authentication( SSLDomain.VERIFY_PEER ) + + max_count = 100 + sessions = [(SslTest.SslTestConnection( self.server_domain ), + SslTest.SslTestConnection( self.client_domain )) for x in + range(max_count)] + for s in sessions: + s[0].connection.open() + self._pump( s[0], s[1] ) + + for s in sessions: + s[1].connection.open() + self._pump( s[1], s[0] ) + assert s[0].ssl.cipher_name() is not None + assert s[1].ssl.cipher_name() == s[0].ssl.cipher_name() + + for s in sessions: + s[1].connection.close() + self._pump( s[0], s[1] ) + + for s in sessions: + s[0].connection.close() + self._pump( s[1], s[0] ) def test_server_hostname_authentication(self): """ Test authentication of the names held in the server's certificate @@ -303,29 +484,41 @@ class SslTest(common.Test): # Check the CommonName matches (case insensitive). # Assumes certificate contains "CN=A1.Good.Server.domain.com" - 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_NAME ) - self.client.peer_hostname = "a1.good.server.domain.com" - assert self.client.peer_hostname == "a1.good.server.domain.com" - self._do_handshake() + self.server_domain.set_credentials(self._testpath("server-certificate.pem"), + self._testpath("server-private-key.pem"), + "server-password") + self.client_domain.set_trusted_ca_db(self._testpath("ca-certificate.pem")) + self.client_domain.set_peer_authentication( SSLDomain.VERIFY_PEER_NAME ) + + server = SslTest.SslTestConnection( self.server_domain ) + client = SslTest.SslTestConnection( self.client_domain ) + + client.ssl.peer_hostname = "a1.good.server.domain.com" + assert client.ssl.peer_hostname == "a1.good.server.domain.com" + self._do_handshake( client, server ) + del server + del client self.teardown() # Should fail on CN name mismatch: self.setup() - 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_NAME ) - self.client.peer_hostname = "A1.Good.Server.domain.comX" + self.server_domain.set_credentials(self._testpath("server-certificate.pem"), + self._testpath("server-private-key.pem"), + "server-password") + self.client_domain.set_trusted_ca_db(self._testpath("ca-certificate.pem")) + self.client_domain.set_peer_authentication( SSLDomain.VERIFY_PEER_NAME ) + + server = SslTest.SslTestConnection( self.server_domain ) + client = SslTest.SslTestConnection( self.client_domain ) + + client.ssl.peer_hostname = "A1.Good.Server.domain.comX" try: - self._do_handshake() + self._do_handshake( client, server ) assert False, "Expected connection to fail due to hostname mismatch" except TransportException: pass + del server + del client self.teardown() # Wildcarded Certificate @@ -337,73 +530,107 @@ class SslTest(common.Test): # Pass: match an alternate self.setup() - self.server.set_credentials(self._testpath("server-wc-certificate.pem"), - self._testpath("server-wc-private-key.pem"), - "server-password") - self.client.set_trusted_ca_db(self._testpath("ca-certificate.pem")) - self.client.set_peer_authentication( SSL.VERIFY_PEER_NAME ) - self.client.peer_hostname = "alternate.Name.one.com" - self._do_handshake() + self.server_domain.set_credentials(self._testpath("server-wc-certificate.pem"), + self._testpath("server-wc-private-key.pem"), + "server-password") + self.client_domain.set_trusted_ca_db(self._testpath("ca-certificate.pem")) + self.client_domain.set_peer_authentication( SSLDomain.VERIFY_PEER_NAME ) + + server = SslTest.SslTestConnection( self.server_domain ) + client = SslTest.SslTestConnection( self.client_domain ) + + client.ssl.peer_hostname = "alternate.Name.one.com" + self._do_handshake( client, server ) + del client + del server self.teardown() # Pass: match an alternate self.setup() - self.server.set_credentials(self._testpath("server-wc-certificate.pem"), + self.server_domain.set_credentials(self._testpath("server-wc-certificate.pem"), self._testpath("server-wc-private-key.pem"), "server-password") - self.client.set_trusted_ca_db(self._testpath("ca-certificate.pem")) - self.client.set_peer_authentication( SSL.VERIFY_PEER_NAME ) - self.client.peer_hostname = "ANOTHER.NAME.COM" - self._do_handshake() + self.client_domain.set_trusted_ca_db(self._testpath("ca-certificate.pem")) + self.client_domain.set_peer_authentication( SSLDomain.VERIFY_PEER_NAME ) + + server = SslTest.SslTestConnection( self.server_domain ) + client = SslTest.SslTestConnection( self.client_domain ) + + client.ssl.peer_hostname = "ANOTHER.NAME.COM" + self._do_handshake(client, server) + del client + del server self.teardown() # Pass: match the pattern self.setup() - self.server.set_credentials(self._testpath("server-wc-certificate.pem"), + self.server_domain.set_credentials(self._testpath("server-wc-certificate.pem"), self._testpath("server-wc-private-key.pem"), "server-password") - self.client.set_trusted_ca_db(self._testpath("ca-certificate.pem")) - self.client.set_peer_authentication( SSL.VERIFY_PEER_NAME ) - self.client.peer_hostname = "SOME.PREfix.domain.COM" - self._do_handshake() + self.client_domain.set_trusted_ca_db(self._testpath("ca-certificate.pem")) + self.client_domain.set_peer_authentication( SSLDomain.VERIFY_PEER_NAME ) + + server = SslTest.SslTestConnection( self.server_domain ) + client = SslTest.SslTestConnection( self.client_domain ) + + client.ssl.peer_hostname = "SOME.PREfix.domain.COM" + self._do_handshake( client, server ) + del client + del server self.teardown() # Pass: match the pattern self.setup() - self.server.set_credentials(self._testpath("server-wc-certificate.pem"), + self.server_domain.set_credentials(self._testpath("server-wc-certificate.pem"), self._testpath("server-wc-private-key.pem"), "server-password") - self.client.set_trusted_ca_db(self._testpath("ca-certificate.pem")) - self.client.set_peer_authentication( SSL.VERIFY_PEER_NAME ) - self.client.peer_hostname = "FOO.PREfixZZZ.domain.com" - self._do_handshake() + self.client_domain.set_trusted_ca_db(self._testpath("ca-certificate.pem")) + self.client_domain.set_peer_authentication( SSLDomain.VERIFY_PEER_NAME ) + + server = SslTest.SslTestConnection( self.server_domain ) + client = SslTest.SslTestConnection( self.client_domain ) + + client.ssl.peer_hostname = "FOO.PREfixZZZ.domain.com" + self._do_handshake( client, server ) + del client + del server self.teardown() # Fail: must match prefix on wildcard self.setup() - self.server.set_credentials(self._testpath("server-wc-certificate.pem"), + self.server_domain.set_credentials(self._testpath("server-wc-certificate.pem"), self._testpath("server-wc-private-key.pem"), "server-password") - self.client.set_trusted_ca_db(self._testpath("ca-certificate.pem")) - self.client.set_peer_authentication( SSL.VERIFY_PEER_NAME ) - self.client.peer_hostname = "FOO.PREfi.domain.com" + self.client_domain.set_trusted_ca_db(self._testpath("ca-certificate.pem")) + self.client_domain.set_peer_authentication( SSLDomain.VERIFY_PEER_NAME ) + + server = SslTest.SslTestConnection( self.server_domain ) + client = SslTest.SslTestConnection( self.client_domain ) + + client.ssl.peer_hostname = "FOO.PREfi.domain.com" try: - self._do_handshake() + self._do_handshake( client, server ) assert False, "Expected connection to fail due to hostname mismatch" except TransportException: pass + del server + del client self.teardown() # Fail: leading wildcards are not optional self.setup() - self.server.set_credentials(self._testpath("server-wc-certificate.pem"), + self.server_domain.set_credentials(self._testpath("server-wc-certificate.pem"), self._testpath("server-wc-private-key.pem"), "server-password") - self.client.set_trusted_ca_db(self._testpath("ca-certificate.pem")) - self.client.set_peer_authentication( SSL.VERIFY_PEER_NAME ) - self.client.peer_hostname = "PREfix.domain.COM" + self.client_domain.set_trusted_ca_db(self._testpath("ca-certificate.pem")) + self.client_domain.set_peer_authentication( SSLDomain.VERIFY_PEER_NAME ) + + server = SslTest.SslTestConnection( self.server_domain ) + client = SslTest.SslTestConnection( self.client_domain ) + + client.ssl.peer_hostname = "PREfix.domain.COM" try: - self._do_handshake() + self._do_handshake( client, server ) assert False, "Expected connection to fail due to hostname mismatch" except TransportException: pass --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
