[Twisted-Python] Authenticated SSL

Clark C. Evans cce at clarkevans.com
Thu May 22 10:58:25 MDT 2003


Err, no, this would only verify the cert and doesn't work with xmlrpc.
Sorry.  -- Clark

On Thu, May 22, 2003 at 04:56:46PM +0000, Clark C. Evans wrote:
| On Wed, May 21, 2003 at 11:25:10AM -0400, Itamar Shtull-Trauring wrote:
| | On Wed, 21 May 2003 23:06:13 +0800
| | Wari Wahab <wari at home.wari.org> wrote:
| | 
| | > Hi there, following the echoserver-ssl.py example, I was able to get
| | > up to speed and basically running my xmlrpc server on SSL. As usual, 
| | > twisted makes it easy. Now my problem becomes this: I need to verify 
| | > that the certificate on the other side (The client) is signed by me
| | > (or a known CA). How would one go about such task?
| | 
| | 1. Read pyOpenSSL documentation. (http://pyopenssl.sf.net)
| | 
| | 2. Implement a context factory that does the appropriate setup, based on
| | docs in (1). (twisted.internet.ssl has some sample context factories).
| 
| 3. Apply this (very old) patch and use twisted.client.getSecurePage
| 
| *evil grins*
| 
| Clark

| 39c39
| < from OpenSSL import SSL
| ---
| > from OpenSSL import SSL, crypto
| 57a58,60
| > def dumpCertificate(cert, filetype = crypto.FILETYPE_PEM ):
| >     ''' a helper to dump an incoming cert as a PEM '''
| >     return crypto.dump_certificate(filetype, cert)
| 62,63c65,67
| <                  sslmethod=SSL.SSLv23_METHOD):
| <         self.privateKeyFileName = privateKeyFileName
| ---
| >                  sslmethod=SSL.SSLv23_METHOD, verifyCallback = None):
| >         self.verifyCallback      = (verifyCallback, )      
| >         self.privateKeyFileName  = privateKeyFileName
| 67a72,77
| >                         
| >     def verifyCertificate(self, conn, cert, errno, depth, retcode):
| >         cb = self.verifyCallback[0]
| >         if cb: return cb(cert)
| >         return 1
| > 
| 71a82,83
| >         if self.verifyCallback[0]:
| >             ctx.set_verify(SSL.VERIFY_PEER, self.verifyCertificate) 

| --- client.py.orig	Tue Mar 25 18:10:28 2003
| +++ client.py	Tue Mar 25 18:55:08 2003
| @@ -63,7 +63,8 @@
|          l = self.headers.get('location')
|          if not l:
|              self.handleStatusDefault()
| -        host, port, url = _parse(l[0])
| +        https, host, port, url = _parse(l[0])
| +        assert not https, "https redirects not implemented yet"
|          self.factory.host, self.factory.url = host, url
|          reactor.connectTCP(host, port, self.factory)
|          self.quietLoss = 1
| @@ -105,7 +106,9 @@
|  
|      protocol = HTTPPageGetter
|  
| -    def __init__(self, host, url, method='GET', postdata=None, headers=None, agent="Twisted PageGetter"):
| +    def __init__(self, host, url, method='GET', postdata=None, 
| +                 headers=None, agent=None):
| +        if agent is None: agent = "Twisted PageGetter"
|          if headers is not None:
|              self.headers = headers
|          if postdata is not None:
| @@ -141,8 +144,10 @@
|      protocol = HTTPPageDownloader
|      value = None
|  
| -    def __init__(self, host, url, fileName, method='GET', postdata=None, headers=None, agent="Twisted client"):
| -        HTTPClientFactory.__init__(self, host, url, method=method, postdata=postdata, headers=headers, agent=agent)
| +    def __init__(self, host, url, fileName, method='GET', postdata=None, 
| +                 headers=None, agent = None):
| +        HTTPClientFactory.__init__(self, host, url, method, 
| +                                   postdata, headers, agent)
|          self.fileName = fileName
|          self.deferred = defer.Deferred()
|          self.waiting = 1
| @@ -166,26 +171,59 @@
|  def _parse(url):
|      parsed = urlparse.urlparse(url)
|      url = urlparse.urlunparse(('','')+parsed[2:])
| -    host, port = parsed[1], 80
| +    host = parsed[1]
| +    if 'https' == parsed[0]:
| +        https, port = 1, 443
| +    else:
| +        https, port = 0, 80
|      if ':' in host:
|          host, port = host.split(':')
|          port = int(port)
| -    return host, port, url
| +    return https, host, port, url
|  
| -def getPage(url, *args, **kwargs):
| +def getPage(url, method='GET', postdata=None, headers=None, agent = None):
|      '''download a web page
|  
|      Download a page. Return a deferred, which will
|      callback with a page or errback with a description
|      of the error.
|      '''
| -    host, port, url = _parse(url)
| -    factory = HTTPClientFactory(host, url, *args, **kwargs)
| +    https, host, port, path = _parse(url)
| +    if https: return getSecurePage(url, method, postdata, headers, agent)
| +    factory = HTTPClientFactory(host, path, method, postdata, headers, agent)
|      reactor.connectTCP(host, port, factory)
|      return factory.deferred
|  
| +try:
| +    from twisted.internet import ssl
| +    def getSecurePage(url, method='GET', postdata=None, headers=None, 
| +                      agent = None,
| +                      privateKeyFileName = None, certificateFileName = None,
| +                      sslmethod=ssl.SSL.SSLv23_METHOD, verifyCallback = None, 
| +                      serverCertificateFileName = None):
| +        """ download a secure page """
| +        https, host, port, path = _parse(url)
| +        if serverCertificateFileName:
| +            cert = file(serverCertificateFileName).read()
| +            verifyCallback = lambda rhs: ssl.dumpCertificate(cert) == rhs
| +        if verifyCallback or certificateFileName or privateKeyFileName:
| +            context = ssl.DefaultOpenSSLContextFactory(
| +                          privateKeyFileName, certificateFileName,
| +                          sslmethod, verifyCallback)
| +            context.isClient = 1
| +        else:
| +            context = ssl.ClientContextFactory()
| +        factory = HTTPClientFactory(host, path, method, postdata, headers)
| +        reactor.connectSSL(host, port, factory, context)
| +        return factory.deferred
| +except:
| +    def getSecurePage(*args,**kwargs):
| +        raise Exception("ssl not available")
| +
|  def downloadPage(url, file, *args, **kwargs):
| -    host, port, url = _parse(url)
| -    factory = HTTPDownloader(host, url, file, *args, **kwargs)
| +    https, host, port, path = _parse(url)
| +    assert not https, "https is not yet implemented here"
| +    factory = HTTPDownloader(host, path, file, *args, **kwargs)
|      reactor.connectTCP(host, port, factory)
|      return factory.deferred
| +





More information about the Twisted-Python mailing list