class PortStringificationTests(unittest.TestCase): if interfaces.IReactorTCP(reactor, None) is not None: def testTCP(self): p = reactor.listenTCP(0, protocol.ServerFactory()) portNo = p.getHost().port self.assertNotEqual(str(p).find(str(portNo)), -1, "%d not found in %s" % (portNo, p)) return p.stopListening() if interfaces.IReactorUDP(reactor, None) is not None: def testUDP(self): p = reactor.listenUDP(0, protocol.DatagramProtocol()) portNo = p.getHost().port self.assertNotEqual(str(p).find(str(portNo)), -1, "%d not found in %s" % (portNo, p)) return p.stopListening() if interfaces.IReactorSSL(reactor, None) is not None and ssl: def testSSL(self, ssl=ssl): pem = util.sibpath(__file__, 'server.pem') p = reactor.listenSSL(0, protocol.ServerFactory(), ssl.DefaultOpenSSLContextFactory(pem, pem)) portNo = p.getHost().port self.assertNotEqual(str(p).find(str(portNo)), -1, "%d not found in %s" % (portNo, p)) return p.stopListening() if _PY3: testSSL.skip = ("Re-enable once the Python 3 SSL port is done.")
class PortStringificationTests(TestCase): @skipIf(not interfaces.IReactorTCP(reactor, None), "IReactorTCP is needed") def testTCP(self): p = reactor.listenTCP(0, protocol.ServerFactory()) portNo = p.getHost().port self.assertNotEqual( str(p).find(str(portNo)), -1, "%d not found in %s" % (portNo, p) ) return p.stopListening() @skipIf(not interfaces.IReactorUDP(reactor, None), "IReactorUDP is needed") def testUDP(self): p = reactor.listenUDP(0, protocol.DatagramProtocol()) portNo = p.getHost().port self.assertNotEqual( str(p).find(str(portNo)), -1, "%d not found in %s" % (portNo, p) ) return p.stopListening() @skipIf(not interfaces.IReactorSSL(reactor, None), "IReactorSSL is needed") @skipIf(not ssl, "SSL support is missing") def testSSL(self, ssl=ssl): pem = util.sibpath(__file__, "server.pem") p = reactor.listenSSL( 0, protocol.ServerFactory(), ssl.DefaultOpenSSLContextFactory(pem, pem) ) portNo = p.getHost().port self.assertNotEqual( str(p).find(str(portNo)), -1, "%d not found in %s" % (portNo, p) ) return p.stopListening()
class SpammyTLSTests(TLSTests): """ Test TLS features with bytes sitting in the out buffer. """ if interfaces.IReactorSSL(reactor, None) is None: skip = "Reactor does not support SSL, cannot run SSL tests" fillBuffer = True
class StolenTCPTests(ProperlyCloseFilesMixin, TestCase): """ For SSL transports, test many of the same things which are tested for TCP transports. """ if interfaces.IReactorSSL(reactor, None) is None: skip = "Reactor does not support SSL, cannot run SSL tests" def createServer(self, address, portNumber, factory): """ Create an SSL server with a certificate using L{IReactorSSL.listenSSL}. """ cert = ssl.PrivateCertificate.loadPEM(FilePath(certPath).getContent()) contextFactory = cert.options() return reactor.listenSSL( portNumber, factory, contextFactory, interface=address) def connectClient(self, address, portNumber, clientCreator): """ Create an SSL client using L{IReactorSSL.connectSSL}. """ contextFactory = ssl.CertificateOptions() return clientCreator.connectSSL(address, portNumber, contextFactory) def getHandleExceptionType(self): """ Return L{OpenSSL.SSL.Error} as the expected error type which will be raised by a write to the L{OpenSSL.SSL.Connection} object after it has been closed. """ return SSL.Error def getHandleErrorCodeMatcher(self): """ Return a L{hamcrest.core.matcher.Matcher} for the argument L{OpenSSL.SSL.Error} will be constructed with for this case. This is basically just a random OpenSSL implementation detail. It would be better if this test worked in a way which did not require this. """ # We expect an error about how we tried to write to a shutdown # connection. This is terribly implementation-specific. return hamcrest.contains( hamcrest.contains( hamcrest.equal_to('SSL routines'), hamcrest.any_of( hamcrest.equal_to('SSL_write'), hamcrest.equal_to('ssl_write_internal'), ), hamcrest.equal_to('protocol is shutdown'), ), )
class DefaultOpenSSLContextFactoryTests(TestCase): """ Tests for L{ssl.DefaultOpenSSLContextFactory}. """ if interfaces.IReactorSSL(reactor, None) is None: skip = "Reactor does not support SSL, cannot run SSL tests" def setUp(self): # pyOpenSSL Context objects aren't introspectable enough. Pass in # an alternate context factory so we can inspect what is done to it. self.contextFactory = ssl.DefaultOpenSSLContextFactory( certPath, certPath, _contextFactory=FakeContext) self.context = self.contextFactory.getContext() def test_method(self): """ L{ssl.DefaultOpenSSLContextFactory.getContext} returns an SSL context which can use SSLv3 or TLSv1 but not SSLv2. """ # SSLv23_METHOD allows SSLv2, SSLv3, or TLSv1 self.assertEqual(self.context._method, SSL.SSLv23_METHOD) # And OP_NO_SSLv2 disables the SSLv2 support. self.assertEqual(self.context._options & SSL.OP_NO_SSLv2, SSL.OP_NO_SSLv2) # Make sure SSLv3 and TLSv1 aren't disabled though. self.assertFalse(self.context._options & SSL.OP_NO_SSLv3) self.assertFalse(self.context._options & SSL.OP_NO_TLSv1) def test_missingCertificateFile(self): """ Instantiating L{ssl.DefaultOpenSSLContextFactory} with a certificate filename which does not identify an existing file results in the initializer raising L{OpenSSL.SSL.Error}. """ self.assertRaises( SSL.Error, ssl.DefaultOpenSSLContextFactory, certPath, self.mktemp()) def test_missingPrivateKeyFile(self): """ Instantiating L{ssl.DefaultOpenSSLContextFactory} with a private key filename which does not identify an existing file results in the initializer raising L{OpenSSL.SSL.Error}. """ self.assertRaises( SSL.Error, ssl.DefaultOpenSSLContextFactory, self.mktemp(), certPath)
class BufferingTests(TestCase): if interfaces.IReactorSSL(reactor, None) is None: skip = "Reactor does not support SSL, cannot run SSL tests" serverProto = None clientProto = None def tearDown(self): if self.serverProto.transport is not None: self.serverProto.transport.loseConnection() if self.clientProto.transport is not None: self.clientProto.transport.loseConnection() return waitUntilAllDisconnected( reactor, [self.serverProto, self.clientProto]) def test_openSSLBuffering(self): serverProto = self.serverProto = SingleLineServerProtocol() clientProto = self.clientProto = RecordingClientProtocol() server = protocol.ServerFactory() client = self.client = protocol.ClientFactory() server.protocol = lambda: serverProto client.protocol = lambda: clientProto sCTX = ssl.DefaultOpenSSLContextFactory(certPath, certPath) cCTX = ssl.ClientContextFactory() port = reactor.listenSSL(0, server, sCTX, interface='127.0.0.1') self.addCleanup(port.stopListening) clientConnector = reactor.connectSSL('127.0.0.1', port.getHost().port, client, cCTX) self.addCleanup(clientConnector.disconnect) return clientProto.deferred.addCallback( self.assertEqual, b"+OK <some crap>\r\n")
class ClientContextFactoryTests(TestCase): """ Tests for L{ssl.ClientContextFactory}. """ if interfaces.IReactorSSL(reactor, None) is None: skip = "Reactor does not support SSL, cannot run SSL tests" def setUp(self): self.contextFactory = ssl.ClientContextFactory() self.contextFactory._contextFactory = FakeContext self.context = self.contextFactory.getContext() def test_method(self): """ L{ssl.ClientContextFactory.getContext} returns a context which can use SSLv3 or TLSv1 but not SSLv2. """ self.assertEqual(self.context._method, SSL.SSLv23_METHOD) self.assertEqual(self.context._options & SSL.OP_NO_SSLv2, SSL.OP_NO_SSLv2) self.assertFalse(self.context._options & SSL.OP_NO_SSLv3) self.assertFalse(self.context._options & SSL.OP_NO_TLSv1)
L{Agent._computeHostValue} returns a string giving just the host name passed to it. """ self.assertEquals( self.agent._computeHostValue('https', 'example.com', 443), 'example.com') def test_hostValueNonStandardHTTPS(self): """ When passed a scheme of C{'https'} and a port other than C{443}, L{Agent._computeHostValue} returns a string giving the host passed to it joined together with the port number by C{":"}. """ self.assertEquals( self.agent._computeHostValue('https', 'example.com', 54321), 'example.com:54321') if ssl is None or not hasattr(ssl, 'DefaultOpenSSLContextFactory'): for case in [ WebClientSSLTestCase, WebClientRedirectBetweenSSLandPlainText ]: case.skip = "OpenSSL not present" if not interfaces.IReactorSSL(reactor, None): for case in [ WebClientSSLTestCase, WebClientRedirectBetweenSSLandPlainText ]: case.skip = "Reactor doesn't support SSL"
class ConnectionLostTests(TestCase, ContextGeneratingMixin): """ SSL connection closing tests. """ if interfaces.IReactorSSL(reactor, None) is None: skip = "Reactor does not support SSL, cannot run SSL tests" def testImmediateDisconnect(self): org = "twisted.test.test_ssl" self.setupServerAndClient((org, org + ", client"), {}, (org, org + ", server"), {}) # Set up a server, connect to it with a client, which should work since our verifiers # allow anything, then disconnect. serverProtocolFactory = protocol.ServerFactory() serverProtocolFactory.protocol = protocol.Protocol self.serverPort = serverPort = reactor.listenSSL( 0, serverProtocolFactory, self.serverCtxFactory) clientProtocolFactory = protocol.ClientFactory() clientProtocolFactory.protocol = ImmediatelyDisconnectingProtocol clientProtocolFactory.connectionDisconnected = defer.Deferred() reactor.connectSSL( "127.0.0.1", serverPort.getHost().port, clientProtocolFactory, self.clientCtxFactory, ) return clientProtocolFactory.connectionDisconnected.addCallback( lambda ignoredResult: self.serverPort.stopListening()) def test_bothSidesLoseConnection(self): """ Both sides of SSL connection close connection; the connections should close cleanly, and only after the underlying TCP connection has disconnected. """ @implementer(interfaces.IHandshakeListener) class CloseAfterHandshake(protocol.Protocol): gotData = False def __init__(self): self.done = defer.Deferred() def handshakeCompleted(self): self.transport.loseConnection() def connectionLost(self, reason): self.done.errback(reason) del self.done org = "twisted.test.test_ssl" self.setupServerAndClient((org, org + ", client"), {}, (org, org + ", server"), {}) serverProtocol = CloseAfterHandshake() serverProtocolFactory = protocol.ServerFactory() serverProtocolFactory.protocol = lambda: serverProtocol serverPort = reactor.listenSSL(0, serverProtocolFactory, self.serverCtxFactory) self.addCleanup(serverPort.stopListening) clientProtocol = CloseAfterHandshake() clientProtocolFactory = protocol.ClientFactory() clientProtocolFactory.protocol = lambda: clientProtocol reactor.connectSSL( "127.0.0.1", serverPort.getHost().port, clientProtocolFactory, self.clientCtxFactory, ) def checkResult(failure): failure.trap(ConnectionDone) return defer.gatherResults([ clientProtocol.done.addErrback(checkResult), serverProtocol.done.addErrback(checkResult), ]) def testFailedVerify(self): org = "twisted.test.test_ssl" self.setupServerAndClient((org, org + ", client"), {}, (org, org + ", server"), {}) def verify(*a): return False self.clientCtxFactory.getContext().set_verify(SSL.VERIFY_PEER, verify) serverConnLost = defer.Deferred() serverProtocol = protocol.Protocol() serverProtocol.connectionLost = serverConnLost.callback serverProtocolFactory = protocol.ServerFactory() serverProtocolFactory.protocol = lambda: serverProtocol self.serverPort = serverPort = reactor.listenSSL( 0, serverProtocolFactory, self.serverCtxFactory) clientConnLost = defer.Deferred() clientProtocol = protocol.Protocol() clientProtocol.connectionLost = clientConnLost.callback clientProtocolFactory = protocol.ClientFactory() clientProtocolFactory.protocol = lambda: clientProtocol reactor.connectSSL( "127.0.0.1", serverPort.getHost().port, clientProtocolFactory, self.clientCtxFactory, ) dl = defer.DeferredList([serverConnLost, clientConnLost], consumeErrors=True) return dl.addCallback(self._cbLostConns) def _cbLostConns(self, results): (sSuccess, sResult), (cSuccess, cResult) = results self.assertFalse(sSuccess) self.assertFalse(cSuccess) acceptableErrors = [SSL.Error] # Rather than getting a verification failure on Windows, we are getting # a connection failure. Without something like sslverify proxying # in-between we can't fix up the platform's errors, so let's just # specifically say it is only OK in this one case to keep the tests # passing. Normally we'd like to be as strict as possible here, so # we're not going to allow this to report errors incorrectly on any # other platforms. if platform.isWindows(): from twisted.internet.error import ConnectionLost acceptableErrors.append(ConnectionLost) sResult.trap(*acceptableErrors) cResult.trap(*acceptableErrors) return self.serverPort.stopListening()
class TLSTests(TestCase): """ Tests for startTLS support. @ivar fillBuffer: forwarded to L{LineCollector.fillBuffer} @type fillBuffer: C{bool} """ if interfaces.IReactorSSL(reactor, None) is None: skip = "Reactor does not support SSL, cannot run SSL tests" fillBuffer = False clientProto = None serverProto = None def tearDown(self): if self.clientProto.transport is not None: self.clientProto.transport.loseConnection() if self.serverProto.transport is not None: self.serverProto.transport.loseConnection() def _runTest(self, clientProto, serverProto, clientIsServer=False): """ Helper method to run TLS tests. @param clientProto: protocol instance attached to the client connection. @param serverProto: protocol instance attached to the server connection. @param clientIsServer: flag indicated if client should initiate startTLS instead of server. @return: a L{defer.Deferred} that will fire when both connections are lost. """ self.clientProto = clientProto cf = self.clientFactory = protocol.ClientFactory() cf.protocol = lambda: clientProto if clientIsServer: cf.server = False else: cf.client = True self.serverProto = serverProto sf = self.serverFactory = protocol.ServerFactory() sf.protocol = lambda: serverProto if clientIsServer: sf.client = False else: sf.server = True port = reactor.listenTCP(0, sf, interface="127.0.0.1") self.addCleanup(port.stopListening) reactor.connectTCP("127.0.0.1", port.getHost().port, cf) return defer.gatherResults( [clientProto.deferred, serverProto.deferred]) def test_TLS(self): """ Test for server and client startTLS: client should received data both before and after the startTLS. """ def check(ignore): self.assertEqual( self.serverFactory.lines, UnintelligentProtocol.pretext + UnintelligentProtocol.posttext, ) d = self._runTest(UnintelligentProtocol(), LineCollector(True, self.fillBuffer)) return d.addCallback(check) def test_unTLS(self): """ Test for server startTLS not followed by a startTLS in client: the data received after server startTLS should be received as raw. """ def check(ignored): self.assertEqual(self.serverFactory.lines, UnintelligentProtocol.pretext) self.assertTrue(self.serverFactory.rawdata, "No encrypted bytes received") d = self._runTest(UnintelligentProtocol(), LineCollector(False, self.fillBuffer)) return d.addCallback(check) def test_backwardsTLS(self): """ Test startTLS first initiated by client. """ def check(ignored): self.assertEqual( self.clientFactory.lines, UnintelligentProtocol.pretext + UnintelligentProtocol.posttext, ) d = self._runTest(LineCollector(True, self.fillBuffer), UnintelligentProtocol(), True) return d.addCallback(check)
self.mktemp(), certPath) class ClientContextFactoryTests(unittest.TestCase): """ Tests for L{ssl.ClientContextFactory}. """ def setUp(self): self.contextFactory = ssl.ClientContextFactory() self.contextFactory._contextFactory = FakeContext self.context = self.contextFactory.getContext() def test_method(self): """ L{ssl.ClientContextFactory.getContext} returns a context which can use SSLv3 or TLSv1 but not SSLv2. """ self.assertEqual(self.context._method, SSL.SSLv23_METHOD) self.assertTrue(self.context._options & SSL.OP_NO_SSLv2) self.assertFalse(self.context._options & SSL.OP_NO_SSLv3) self.assertFalse(self.context._options & SSL.OP_NO_TLSv1) if interfaces.IReactorSSL(reactor, None) is None: for tCase in [ StolenTCPTests, TLSTests, SpammyTLSTests, BufferingTests, ConnectionLostTests, DefaultOpenSSLContextFactoryTests, ClientContextFactoryTests ]: tCase.skip = "Reactor does not support SSL, cannot run SSL tests"
def connectionMade(self): self.factory.input = [] self.output = self.output[:] for line in self.output.pop(0): self.sendLine(line) def lineReceived(self, line): self.factory.input.append(line) [self.sendLine(l) for l in self.output.pop(0)] if line == b"STLS": self.transport.startTLS(self.context) @skipIf(not ClientTLSContext, "OpenSSL not present") @skipIf(not interfaces.IReactorSSL(reactor, None), "OpenSSL not present") class POP3TLSTests(TestCase): """ Tests for POP3Client's support for TLS connections. """ def test_startTLS(self): """ POP3Client.startTLS starts a TLS session over its existing TCP connection. """ sf = TLSServerFactory() sf.protocol.output = [ [b"+OK"], # Server greeting [b"+OK", b"STLS", b"."], # CAPA response [b"+OK"], # STLS response [b"+OK", b"."], # Second CAPA response
class Constructors(unittest.TestCase): if interfaces.IReactorSSL(reactor, None) is None: skip = "Reactor does not support SSL, cannot run SSL tests" def test_peerFromNonSSLTransport(self): """ Verify that peerFromTransport raises an exception if the transport passed is not actually an SSL transport. """ x = self.assertRaises(CertificateError, sslverify.Certificate.peerFromTransport, _NotSSLTransport()) self.failUnless(str(x).startswith("non-TLS")) def test_peerFromBlankSSLTransport(self): """ Verify that peerFromTransport raises an exception if the transport passed is an SSL transport, but doesn't have a peer certificate. """ x = self.assertRaises(CertificateError, sslverify.Certificate.peerFromTransport, _MaybeSSLTransport()) self.failUnless(str(x).startswith("TLS")) def test_hostFromNonSSLTransport(self): """ Verify that hostFromTransport raises an exception if the transport passed is not actually an SSL transport. """ x = self.assertRaises(CertificateError, sslverify.Certificate.hostFromTransport, _NotSSLTransport()) self.failUnless(str(x).startswith("non-TLS")) def test_hostFromBlankSSLTransport(self): """ Verify that hostFromTransport raises an exception if the transport passed is an SSL transport, but doesn't have a host certificate. """ x = self.assertRaises(CertificateError, sslverify.Certificate.hostFromTransport, _MaybeSSLTransport()) self.failUnless(str(x).startswith("TLS")) def test_hostFromSSLTransport(self): """ Verify that hostFromTransport successfully creates the correct certificate if passed a valid SSL transport. """ self.assertEqual( sslverify.Certificate.hostFromTransport( _ActualSSLTransport()).serialNumber(), 12345) def test_peerFromSSLTransport(self): """ Verify that peerFromTransport successfully creates the correct certificate if passed a valid SSL transport. """ self.assertEqual( sslverify.Certificate.peerFromTransport( _ActualSSLTransport()).serialNumber(), 12346)
class OpenSSLOptions(unittest.TestCase): if interfaces.IReactorSSL(reactor, None) is None: skip = "Reactor does not support SSL, cannot run SSL tests" serverPort = clientConn = None onServerLost = onClientLost = None sKey = None sCert = None cKey = None cCert = None def setUp(self): """ Create class variables of client and server certificates. """ self.sKey, self.sCert = makeCertificate(O=b"Server Test Certificate", CN=b"server") self.cKey, self.cCert = makeCertificate(O=b"Client Test Certificate", CN=b"client") self.caCert1 = makeCertificate(O=b"CA Test Certificate 1", CN=b"ca1")[1] self.caCert2 = makeCertificate(O=b"CA Test Certificate", CN=b"ca2")[1] self.caCerts = [self.caCert1, self.caCert2] self.extraCertChain = self.caCerts def tearDown(self): if self.serverPort is not None: self.serverPort.stopListening() if self.clientConn is not None: self.clientConn.disconnect() L = [] if self.onServerLost is not None: L.append(self.onServerLost) if self.onClientLost is not None: L.append(self.onClientLost) return defer.DeferredList(L, consumeErrors=True) def loopback(self, serverCertOpts, clientCertOpts, onServerLost=None, onClientLost=None, onData=None): if onServerLost is None: self.onServerLost = onServerLost = defer.Deferred() if onClientLost is None: self.onClientLost = onClientLost = defer.Deferred() if onData is None: onData = defer.Deferred() serverFactory = protocol.ServerFactory() serverFactory.protocol = DataCallbackProtocol serverFactory.onLost = onServerLost serverFactory.onData = onData clientFactory = protocol.ClientFactory() clientFactory.protocol = WritingProtocol clientFactory.onLost = onClientLost self.serverPort = reactor.listenSSL(0, serverFactory, serverCertOpts) self.clientConn = reactor.connectSSL('127.0.0.1', self.serverPort.getHost().port, clientFactory, clientCertOpts) def test_constructorWithOnlyPrivateKey(self): """ C{privateKey} and C{certificate} make only sense if both are set. """ self.assertRaises(ValueError, sslverify.OpenSSLCertificateOptions, privateKey=self.sKey) def test_constructorWithOnlyCertificate(self): """ C{privateKey} and C{certificate} make only sense if both are set. """ self.assertRaises(ValueError, sslverify.OpenSSLCertificateOptions, certificate=self.sCert) def test_constructorWithCertificateAndPrivateKey(self): """ Specifying C{privateKey} and C{certificate} initializes correctly. """ opts = sslverify.OpenSSLCertificateOptions(privateKey=self.sKey, certificate=self.sCert) self.assertEqual(opts.privateKey, self.sKey) self.assertEqual(opts.certificate, self.sCert) self.assertEqual(opts.extraCertChain, []) def test_constructorDoesNotAllowVerifyWithoutCACerts(self): """ C{verify} must not be C{True} without specifying C{caCerts}. """ self.assertRaises(ValueError, sslverify.OpenSSLCertificateOptions, privateKey=self.sKey, certificate=self.sCert, verify=True) def test_constructorAllowsCACertsWithoutVerify(self): """ It's currently a NOP, but valid. """ opts = sslverify.OpenSSLCertificateOptions(privateKey=self.sKey, certificate=self.sCert, caCerts=self.caCerts) self.assertFalse(opts.verify) self.assertEqual(self.caCerts, opts.caCerts) def test_constructorWithVerifyAndCACerts(self): """ Specifying C{verify} and C{caCerts} initializes correctly. """ opts = sslverify.OpenSSLCertificateOptions(privateKey=self.sKey, certificate=self.sCert, verify=True, caCerts=self.caCerts) self.assertTrue(opts.verify) self.assertEqual(self.caCerts, opts.caCerts) def test_constructorSetsExtraChain(self): """ Setting C{extraCertChain} works if C{certificate} and C{privateKey} are set along with it. """ opts = sslverify.OpenSSLCertificateOptions( privateKey=self.sKey, certificate=self.sCert, extraCertChain=self.extraCertChain, ) self.assertEqual(self.extraCertChain, opts.extraCertChain) def test_constructorDoesNotAllowExtraChainWithoutPrivateKey(self): """ A C{extraCertChain} without C{privateKey} doesn't make sense and is thus rejected. """ self.assertRaises( ValueError, sslverify.OpenSSLCertificateOptions, certificate=self.sCert, extraCertChain=self.extraCertChain, ) def test_constructorDoesNotAllowExtraChainWithOutPrivateKey(self): """ A C{extraCertChain} without C{certificate} doesn't make sense and is thus rejected. """ self.assertRaises( ValueError, sslverify.OpenSSLCertificateOptions, privateKey=self.sKey, extraCertChain=self.extraCertChain, ) def test_extraChainFilesAreAddedIfSupplied(self): """ If C{extraCertChain} is set and all prerequisites are met, the specified chain certificates are added to C{Context}s that get created. """ opts = sslverify.OpenSSLCertificateOptions( privateKey=self.sKey, certificate=self.sCert, extraCertChain=self.extraCertChain, ) opts._contextFactory = FakeContext ctx = opts.getContext() self.assertEqual(self.sKey, ctx._privateKey) self.assertEqual(self.sCert, ctx._certificate) self.assertEqual(self.extraCertChain, ctx._extraCertChain) def test_extraChainDoesNotBreakPyOpenSSL(self): """ C{extraCertChain} doesn't break C{OpenSSL.SSL.Context} creation. """ opts = sslverify.OpenSSLCertificateOptions( privateKey=self.sKey, certificate=self.sCert, extraCertChain=self.extraCertChain, ) ctx = opts.getContext() self.assertIsInstance(ctx, SSL.Context) def test_abbreviatingDistinguishedNames(self): """ Check that abbreviations used in certificates correctly map to complete names. """ self.assertEqual( sslverify.DN(CN=b'a', OU=b'hello'), sslverify.DistinguishedName(commonName=b'a', organizationalUnitName=b'hello')) self.assertNotEquals( sslverify.DN(CN=b'a', OU=b'hello'), sslverify.DN(CN=b'a', OU=b'hello', emailAddress=b'xxx')) dn = sslverify.DN(CN=b'abcdefg') self.assertRaises(AttributeError, setattr, dn, 'Cn', b'x') self.assertEqual(dn.CN, dn.commonName) dn.CN = b'bcdefga' self.assertEqual(dn.CN, dn.commonName) def testInspectDistinguishedName(self): n = sslverify.DN(commonName=b'common name', organizationName=b'organization name', organizationalUnitName=b'organizational unit name', localityName=b'locality name', stateOrProvinceName=b'state or province name', countryName=b'country name', emailAddress=b'email address') s = n.inspect() for k in [ 'common name', 'organization name', 'organizational unit name', 'locality name', 'state or province name', 'country name', 'email address' ]: self.assertIn(k, s, "%r was not in inspect output." % (k, )) self.assertIn(k.title(), s, "%r was not in inspect output." % (k, )) def testInspectDistinguishedNameWithoutAllFields(self): n = sslverify.DN(localityName=b'locality name') s = n.inspect() for k in [ 'common name', 'organization name', 'organizational unit name', 'state or province name', 'country name', 'email address' ]: self.assertNotIn(k, s, "%r was in inspect output." % (k, )) self.assertNotIn(k.title(), s, "%r was in inspect output." % (k, )) self.assertIn('locality name', s) self.assertIn('Locality Name', s) def test_inspectCertificate(self): """ Test that the C{inspect} method of L{sslverify.Certificate} returns a human-readable string containing some basic information about the certificate. """ c = sslverify.Certificate.loadPEM(A_HOST_CERTIFICATE_PEM) self.assertEqual(c.inspect().split('\n'), [ "Certificate For Subject:", " Common Name: example.twistedmatrix.com", " Country Name: US", " Email Address: [email protected]", " Locality Name: Boston", " Organization Name: Twisted Matrix Labs", " Organizational Unit Name: Security", " State Or Province Name: Massachusetts", "", "Issuer:", " Common Name: example.twistedmatrix.com", " Country Name: US", " Email Address: [email protected]", " Locality Name: Boston", " Organization Name: Twisted Matrix Labs", " Organizational Unit Name: Security", " State Or Province Name: Massachusetts", "", "Serial Number: 12345", "Digest: C4:96:11:00:30:C3:EC:EE:A3:55:AA:ED:8C:84:85:18", "Public Key with Hash: ff33994c80812aa95a79cdb85362d054" ]) def test_certificateOptionsSerialization(self): """ Test that __setstate__(__getstate__()) round-trips properly. """ firstOpts = sslverify.OpenSSLCertificateOptions( privateKey=self.sKey, certificate=self.sCert, method=SSL.SSLv3_METHOD, verify=True, caCerts=[self.sCert], verifyDepth=2, requireCertificate=False, verifyOnce=False, enableSingleUseKeys=False, enableSessions=False, fixBrokenPeers=True, enableSessionTickets=True) context = firstOpts.getContext() self.assertIdentical(context, firstOpts._context) self.assertNotIdentical(context, None) state = firstOpts.__getstate__() self.assertNotIn("_context", state) opts = sslverify.OpenSSLCertificateOptions() opts.__setstate__(state) self.assertEqual(opts.privateKey, self.sKey) self.assertEqual(opts.certificate, self.sCert) self.assertEqual(opts.method, SSL.SSLv3_METHOD) self.assertEqual(opts.verify, True) self.assertEqual(opts.caCerts, [self.sCert]) self.assertEqual(opts.verifyDepth, 2) self.assertEqual(opts.requireCertificate, False) self.assertEqual(opts.verifyOnce, False) self.assertEqual(opts.enableSingleUseKeys, False) self.assertEqual(opts.enableSessions, False) self.assertEqual(opts.fixBrokenPeers, True) self.assertEqual(opts.enableSessionTickets, True) def test_certificateOptionsSessionTickets(self): """ Enabling session tickets should not set the OP_NO_TICKET option. """ opts = sslverify.OpenSSLCertificateOptions(enableSessionTickets=True) ctx = opts.getContext() self.assertEqual(0, ctx.set_options(0) & 0x00004000) def test_certificateOptionsSessionTicketsDisabled(self): """ Enabling session tickets should set the OP_NO_TICKET option. """ opts = sslverify.OpenSSLCertificateOptions(enableSessionTickets=False) ctx = opts.getContext() self.assertEqual(0x00004000, ctx.set_options(0) & 0x00004000) def test_allowedAnonymousClientConnection(self): """ Check that anonymous connections are allowed when certificates aren't required on the server. """ onData = defer.Deferred() self.loopback( sslverify.OpenSSLCertificateOptions(privateKey=self.sKey, certificate=self.sCert, requireCertificate=False), sslverify.OpenSSLCertificateOptions(requireCertificate=False), onData=onData) return onData.addCallback( lambda result: self.assertEqual(result, WritingProtocol.byte)) def test_refusedAnonymousClientConnection(self): """ Check that anonymous connections are refused when certificates are required on the server. """ onServerLost = defer.Deferred() onClientLost = defer.Deferred() self.loopback( sslverify.OpenSSLCertificateOptions(privateKey=self.sKey, certificate=self.sCert, verify=True, caCerts=[self.sCert], requireCertificate=True), sslverify.OpenSSLCertificateOptions(requireCertificate=False), onServerLost=onServerLost, onClientLost=onClientLost) d = defer.DeferredList([onClientLost, onServerLost], consumeErrors=True) def afterLost(result): ((cSuccess, cResult), (sSuccess, sResult)) = result self.failIf(cSuccess) self.failIf(sSuccess) # Win32 fails to report the SSL Error, and report a connection lost # instead: there is a race condition so that's not totally # surprising (see ticket #2877 in the tracker) self.assertIsInstance(cResult.value, (SSL.Error, ConnectionLost)) self.assertIsInstance(sResult.value, SSL.Error) return d.addCallback(afterLost) def test_failedCertificateVerification(self): """ Check that connecting with a certificate not accepted by the server CA fails. """ onServerLost = defer.Deferred() onClientLost = defer.Deferred() self.loopback( sslverify.OpenSSLCertificateOptions(privateKey=self.sKey, certificate=self.sCert, verify=False, requireCertificate=False), sslverify.OpenSSLCertificateOptions(verify=True, requireCertificate=False, caCerts=[self.cCert]), onServerLost=onServerLost, onClientLost=onClientLost) d = defer.DeferredList([onClientLost, onServerLost], consumeErrors=True) def afterLost(result): ((cSuccess, cResult), (sSuccess, sResult)) = result self.failIf(cSuccess) self.failIf(sSuccess) return d.addCallback(afterLost) def test_successfulCertificateVerification(self): """ Test a successful connection with client certificate validation on server side. """ onData = defer.Deferred() self.loopback( sslverify.OpenSSLCertificateOptions(privateKey=self.sKey, certificate=self.sCert, verify=False, requireCertificate=False), sslverify.OpenSSLCertificateOptions(verify=True, requireCertificate=True, caCerts=[self.sCert]), onData=onData) return onData.addCallback( lambda result: self.assertEqual(result, WritingProtocol.byte)) def test_successfulSymmetricSelfSignedCertificateVerification(self): """ Test a successful connection with validation on both server and client sides. """ onData = defer.Deferred() self.loopback( sslverify.OpenSSLCertificateOptions(privateKey=self.sKey, certificate=self.sCert, verify=True, requireCertificate=True, caCerts=[self.cCert]), sslverify.OpenSSLCertificateOptions(privateKey=self.cKey, certificate=self.cCert, verify=True, requireCertificate=True, caCerts=[self.sCert]), onData=onData) return onData.addCallback( lambda result: self.assertEqual(result, WritingProtocol.byte)) def test_verification(self): """ Check certificates verification building custom certificates data. """ clientDN = sslverify.DistinguishedName(commonName='client') clientKey = sslverify.KeyPair.generate() clientCertReq = clientKey.certificateRequest(clientDN) serverDN = sslverify.DistinguishedName(commonName='server') serverKey = sslverify.KeyPair.generate() serverCertReq = serverKey.certificateRequest(serverDN) clientSelfCertReq = clientKey.certificateRequest(clientDN) clientSelfCertData = clientKey.signCertificateRequest( clientDN, clientSelfCertReq, lambda dn: True, 132) clientSelfCert = clientKey.newCertificate(clientSelfCertData) serverSelfCertReq = serverKey.certificateRequest(serverDN) serverSelfCertData = serverKey.signCertificateRequest( serverDN, serverSelfCertReq, lambda dn: True, 516) serverSelfCert = serverKey.newCertificate(serverSelfCertData) clientCertData = serverKey.signCertificateRequest( serverDN, clientCertReq, lambda dn: True, 7) clientCert = clientKey.newCertificate(clientCertData) serverCertData = clientKey.signCertificateRequest( clientDN, serverCertReq, lambda dn: True, 42) serverCert = serverKey.newCertificate(serverCertData) onData = defer.Deferred() serverOpts = serverCert.options(serverSelfCert) clientOpts = clientCert.options(clientSelfCert) self.loopback(serverOpts, clientOpts, onData=onData) return onData.addCallback( lambda result: self.assertEqual(result, WritingProtocol.byte))