Opened 2 years ago

Closed 2 years ago

#5684 defect closed wontfix (wontfix)

OpenSSL.SSL.Connection object has no getpeername attribute

Reported by: nathanm Owned by: nathanm
Priority: normal Milestone:
Component: core Keywords: SSL Connection
Cc: Branch:
Author: Launchpad Bug:

Description

When reactor.connectSSL is used to create an SSL connection, the OpenSSL.SSL.Connection object has no getpeername attribute.

The following code sample can be used to reproduce the problem (change the connectSSL arguments to a valid IP and port where a secure server is accepting connections).

from OpenSSL import SSL
from twisted.internet import reactor, ssl
from twisted.internet.protocol import ClientFactory
from twisted.protocols.basic import LineReceiver

class MyContextFactory(ssl.ClientContextFactory):

    def _verify(self, connection, x509, errnum, errdepth, ok):
        peername = connection.getpeername()
        print "connected to", peername
        return ok

    def getContext(self):
        ctx = ssl.ClientContextFactory.getContext(self)
        ctx.set_verify(SSL.VERIFY_PEER, self._verify)
        return ctx

class MyClient(LineReceiver):
    def connectionMade(self):
        return

    def lineReceived(self):
        return

class MyClientFactory(ClientFactory):
    protocol = MyClient

    def clientConnectionFailed(self, connector, reason):
        reactor.stop()

    def clientConnectionLost(self, connector, reason):
        reactor.stop()

if __name__ == "__main__":
    reactor.connectSSL('10.1.2.3', 12345, MyClientFactory(), MyContextFactory())
    reactor.run()

This produces an exception:

exceptions.AttributeError: 'NoneType' object has no attribute 'getpeername'

Yet this works...

from OpenSSL import SSL
import socket

context = SSL.Context(SSL.TLSv1_METHOD)
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
connection = SSL.Connection(context, s)
connection.connect(('10.1.2.3', 12345))
print "connected to", connection.getpeername()

Change History (6)

comment:1 Changed 2 years ago by exarkun

  • Owner set to nathanm

I fail to reproduce this problem. Changing the host/port to www.google.com/443, I get this output:

connected to ('173.194.75.104', 443)

comment:2 Changed 2 years ago by nathanm

Using www.google.com/443 I still get the error. I'm running the latest Twisted 12.0.0 code from the svn repo. My pyOpenSSL version is 0.11. You're testing the first code sample, and not the second, correct?

comment:3 Changed 2 years ago by nathanm

I get the same result with pyOpenSSL version 0.13.

comment:4 Changed 2 years ago by exarkun

The difference is whether the Twisted memory bio-based transport implementation is in use or not.

Newer versions of Twisted don't let OpenSSL do networking. A consequence is that there is no Connection instance to pass to the verify callback (note that the object passed for the first argument is None, not a Connection object that is missing getpeername).

comment:5 Changed 2 years ago by nathanm

When memory BIO is in use, is there any way to ascertain peer name in the verify method?

comment:6 Changed 2 years ago by glyph

  • Resolution set to wontfix
  • Status changed from new to closed

You can use the self.transport.getPeer() method, since the "transport" attribute of Protocol is documented to be an ITransport, and an ITransport does not necessarily have a "socket" attribute.

This method has always worked, and is really how you ought to have been doing it all along.

I'm closing this as "wontfix" rather than "invalid", because in some cases this might be a valid observation about compatibility being broken - you didn't have to type "._" to get to it, which in many cases makes it fair game. However, in the case of an attribute with a documented interface, you really can't depend on more attributes than what the interface documentation says, if you want your code to keep working with new implementations of that interface, which the new BIO-based implementation is.

Note: See TracTickets for help on using tickets.