[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