Commit d340e3c1 authored by Sam Rushing's avatar Sam Rushing

merge openssl branch

parents e4023e78 b4d13a0f
# -*- Mode: Python -*-
from server import server, tlslite_server, connection, http_request
from server import server, tlslite_server, openssl_server, connection, http_request
import handlers
import coro
from coro import read_stream
......
......@@ -458,11 +458,11 @@ class server:
Try up to <retries> time to bind to that address.
Raises an exception if the bind fails."""
self.sock = coro.tcp_sock()
self.addr = addr
self.sock = self.create_sock()
self.sock.set_reuse_addr()
done = 0
save_errno = 0
self.addr = addr
while not done:
for x in xrange (retries):
try:
......@@ -505,6 +505,14 @@ class server:
def accept (self):
return self.sock.accept()
def create_sock (self):
# the assumption here is that you would never run an HTTP server
# on a unix socket, if you need that then override this method.
if ':' in self.addr[0]:
return coro.tcp6_sock()
else:
return coro.tcp_sock()
def create_connection (self):
return connection (self)
......@@ -558,3 +566,20 @@ class tlslite_server (server):
open (self.key_path).read(),
private=True
)
class openssl_server (server):
def __init__ (self, ctx, verify=False):
self.ctx = ctx
# XXX do something with verify
self.verify = verify
server.__init__ (self)
def create_sock (self):
import coro.ssl
import socket
if ':' in self.addr[0]:
domain = socket.AF_INET6
else:
domain = socket.AF_INET
return coro.ssl.sock (self.ctx, domain=domain)
# -*- Mode: Python -*-
import coro
from coro.ssl import openssl
import socket
ssl_op_map = {
"sslv2":openssl.SSL_OP.NO_SSLv3|openssl.SSL_OP.NO_TLSv1,
"sslv3":openssl.SSL_OP.NO_SSLv2|openssl.SSL_OP.NO_TLSv1,
"tlsv1":openssl.SSL_OP.NO_SSLv2|openssl.SSL_OP.NO_SSLv3,
"sslv2sslv3":openssl.SSL_OP.NO_TLSv1,
"sslv3tlsv1":openssl.SSL_OP.NO_SSLv2,
"sslv2sslv3tlsv1":0
}
from openssl import x509, pkey, dh_param
def new_ctx (cert=None, chain=(), key=None, proto=None, ciphers=None, dhparam=None, next_protos=None):
ctx = openssl.ssl_ctx()
if cert:
ctx.use_cert (cert, chain)
if key:
ctx.use_key (key)
if proto:
ctx.set_options (ctx.get_options() | ssl_op_map[proto])
if ciphers:
ctx.set_ciphers (ciphers)
if dhparam:
ctx.set_tmp_dh (dhparam)
if next_protos:
ctx.set_next_protos (next_protos)
return ctx
class sock (coro.sock):
def __init__ (self, ctx, fd=-1, verify=False, domain=socket.AF_INET):
coro.sock.__init__ (self, fd=fd, domain=domain)
self.ctx = ctx
# Note: this uses SSLv23_method(), which allows it to accept V2 client hello
# (which are common), but still limit to V3 or TLS1 via the 'proto' arg.
self.ssl = self.ctx.ssl()
self.ssl.set_fd (self.fd)
if verify:
self.ssl.set_verify (openssl.SSL_VERIFY_PEER)
def __repr__ (self):
return '<openssl sock fd=%d ssl@%x @%x>' % (self.fd, id (self.ssl), id (self))
def _non_blocking_retry (self, fun, *args):
while 1:
try:
return fun (*args)
except openssl.WantRead:
self.wait_for_read()
except openssl.WantWrite:
self.wait_for_write()
def accept (self):
conn, addr = coro.sock.accept (self)
try:
# hand the fd off to a new ssl sock object...
new = self.__class__ (self.ctx, domain=conn.domain, fd=conn.fd)
# ...avoid having socket.pyx close the fd
conn.fd = -1
# using set_accept_state() makes NPN very difficult
#new.ssl.set_accept_state()
new.ssl_accept()
return new, addr
except:
conn.close()
raise
def set_accept_state (self):
return self.ssl.set_accept_state()
def set_connect_state (self):
return self.ssl.set_connect_state()
def ssl_accept (self):
self._non_blocking_retry (self.ssl.accept)
def connect (self, addr):
coro.sock.connect (self, addr)
# using set_connect_state makes NPN very difficult
#self.ssl.set_connect_state()
return self.ssl_connect()
def ssl_connect (self):
self._non_blocking_retry (self.ssl.connect)
def recv (self, block_size):
return self._non_blocking_retry (self.ssl.read, block_size)
read = recv
def read_exact (self, size):
left = size
r = []
while left:
block = self.recv (left)
if not block:
break
else:
r.append (block)
left -= len (block)
return ''.join (r)
def recvfrom (self, block_size, timeout=30):
raise SystemError, "recvfrom not supported for SSL sockets"
def send (self, data):
return self._non_blocking_retry (self.ssl.write, data)
write = send
# SSL_write() makes this guarantee.
sendall = send
def sendto (self, data, addr):
raise SystemError, "sendto not supported for SSL sockets"
def writev (self, list_of_data):
_sum = 0
for data in list_of_data:
_sum += self._non_blocking_retry (self.ssl.write, data)
return _sum
def shutdown (self, how=None):
return self._non_blocking_retry (self.ssl.shutdown)
def close (self):
try:
self.shutdown()
finally:
coro.sock.close (self)
def getCipher (self):
return self.ssl.get_cipher()
# The following are taken from #defines in /usr/include/openssl/*.h
_protocol_str_map = {
0x0002: 'SSLv2', # SSL2_VERSION
0x0300: 'SSLv3', # SSL3_VERSION
0x0301: 'TLSv1', # TLS1_VERSION
}
def getProtocol (self):
prot_id = self.ssl.get_protocol()
try:
return self._protocol_str_map[prot_id]
except KeyError:
return '(UNKNOWN:%x)' % (prot_id,)
This diff is collapsed.
This diff is collapsed.
# -*- Mode: Python -*-
import coro
from coro.ssl import openssl
import coro.ssl
import coro.backdoor
W = coro.write_stderr
ctx = openssl.ssl_ctx()
ctx.use_cert (openssl.x509 (open ('../../http/cert/server.crt').read()))
ctx.use_key (openssl.pkey (open ('../../http/cert/server.key').read(), '', True))
ctx.set_ciphers ('RC4-SHA:RC4-MD5:ALL')
#ctx.set_tmp_dh (openssl.dh_param (open ('../../http/cert/dh_param_1024.pem').read()))
#ctx.set_next_protos (['spdy/2', 'http/1.1'])
def session (conn, addr):
conn.ssl.set_fd (conn.fd)
try:
print 'conn=', conn, conn.__class__
while 1:
block = conn.recv (1000)
if not block:
break
else:
conn.send (block)
finally:
coro.sleep_relative (1000)
W ('why for I exit?\n')
all_conns = []
def serve (port=9000):
s = coro.ssl.sock (ctx)
s.bind (('0.0.0.0', port))
s.listen (50)
print 's=', s
while 1:
conn, addr = s.accept()
print 'conn, addr=', conn, addr
all_conns.append (conn)
coro.spawn (session, conn, addr)
if __name__ == '__main__':
coro.spawn (coro.backdoor.serve, unix_path='/tmp/xx.bd')
coro.spawn (serve)
coro.event_loop()
......@@ -54,9 +54,48 @@ compile_time_env = {
'CORO_DEBUG': False,
}
#--------------------------------------------------------------------------------
# OpenSSL support
#--------------------------------------------------------------------------------
import os
import sys
# If you need NPN support (for SPDY), you most likely will have to link against
# newer openssl than the one that came with your OS. (this is circa 2012).
# 1) change the value of ossl_base below.
# 2) change the value of either 'libraries' or 'extra_link_args' depending on
# your platform.
# For OS X: use 'manual static link'
# statically link is a bit tricky
# Note: be sure to remove coro/openssl.c if you change this, see NPN probe below.
ossl_base = '/Users/rushing/src/openssl-1.0.1c'
#ossl_base = '/usr/'
def O (path):
return os.path.join (ossl_base, path)
# cheap probe for npn support
USE_NPN = (open (O('include/openssl/ssl.h')).read().find ('next_protos') != -1)
OpenSSL_Extension = Extension (
'coro.ssl.openssl',
['coro/ssl/openssl.pyx'],
depends=['coro/ssl/openssl.pxi'],
# manual static link
extra_link_args = [ O('libcrypto.a'), O('libssl.a') ],
# link to an absolute location
#extra_link_args = [ '-L %s -lcrypto -lssl' % (ossl_base,) ]
# 'normal' link
#libraries = ['crypto', 'ssl'],
include_dirs = [ O('include') ],
cython_compile_time_env = {'NPN' : USE_NPN},
)
#--------------------------------------------------------------------------------
setup (
name='coro',
version='1.0.2-000',
version='1.0.3-000',
description='IronPort Coroutine/Threading Library',
author='Sam Rushing, Eric Huss, IronPort Engineering',
author_email='sam-coro@rushing.nightmare.com',
......@@ -119,13 +158,14 @@ setup (
os.path.join(include_dir, 'include'),
],
),
# the pre-computed openssl extension from above
OpenSSL_Extension,
],
packages=[
'coro', 'coro.clocks', 'coro.http', 'coro.dns',
'coro', 'coro.clocks', 'coro.http', 'coro.dns', 'coro.ssl',
'coro.emulation', 'coro.db', 'coro.asn1', 'coro.db.postgres'
],
package_dir = {
# '': 'coroutine',
'coro': 'coro',
'coro.clocks': 'coro/clocks',
'coro.dns': 'coro/dns',
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment