summaryrefslogtreecommitdiff
path: root/Lib/ssl.py
diff options
context:
space:
mode:
authorChristian Heimes <christian@python.org>2016-09-10 23:44:53 +0200
committerChristian Heimes <christian@python.org>2016-09-10 23:44:53 +0200
commit99a6570295de5684bfac767b4d35c72f8f36612d (patch)
treefa37c6d2134c3cd3bc107188ea3f611cfd1152ba /Lib/ssl.py
parentd04863771b0c5bedeb1e4afe05dcba3adcc0fb58 (diff)
downloadcpython-git-99a6570295de5684bfac767b4d35c72f8f36612d.tar.gz
Issue #19500: Add client-side SSL session resumption to the ssl module.
Diffstat (limited to 'Lib/ssl.py')
-rw-r--r--Lib/ssl.py65
1 files changed, 53 insertions, 12 deletions
diff --git a/Lib/ssl.py b/Lib/ssl.py
index f3da464986..df5e98efc7 100644
--- a/Lib/ssl.py
+++ b/Lib/ssl.py
@@ -99,7 +99,7 @@ from enum import Enum as _Enum, IntEnum as _IntEnum, IntFlag as _IntFlag
import _ssl # if we can't import it, let the error propagate
from _ssl import OPENSSL_VERSION_NUMBER, OPENSSL_VERSION_INFO, OPENSSL_VERSION
-from _ssl import _SSLContext, MemoryBIO
+from _ssl import _SSLContext, MemoryBIO, SSLSession
from _ssl import (
SSLError, SSLZeroReturnError, SSLWantReadError, SSLWantWriteError,
SSLSyscallError, SSLEOFError,
@@ -391,18 +391,18 @@ class SSLContext(_SSLContext):
def wrap_socket(self, sock, server_side=False,
do_handshake_on_connect=True,
suppress_ragged_eofs=True,
- server_hostname=None):
+ server_hostname=None, session=None):
return SSLSocket(sock=sock, server_side=server_side,
do_handshake_on_connect=do_handshake_on_connect,
suppress_ragged_eofs=suppress_ragged_eofs,
server_hostname=server_hostname,
- _context=self)
+ _context=self, _session=session)
def wrap_bio(self, incoming, outgoing, server_side=False,
- server_hostname=None):
+ server_hostname=None, session=None):
sslobj = self._wrap_bio(incoming, outgoing, server_side=server_side,
server_hostname=server_hostname)
- return SSLObject(sslobj)
+ return SSLObject(sslobj, session=session)
def set_npn_protocols(self, npn_protocols):
protos = bytearray()
@@ -572,10 +572,12 @@ class SSLObject:
* The ``do_handshake_on_connect`` and ``suppress_ragged_eofs`` machinery.
"""
- def __init__(self, sslobj, owner=None):
+ def __init__(self, sslobj, owner=None, session=None):
self._sslobj = sslobj
# Note: _sslobj takes a weak reference to owner
self._sslobj.owner = owner or self
+ if session is not None:
+ self._sslobj.session = session
@property
def context(self):
@@ -587,6 +589,20 @@ class SSLObject:
self._sslobj.context = ctx
@property
+ def session(self):
+ """The SSLSession for client socket."""
+ return self._sslobj.session
+
+ @session.setter
+ def session(self, session):
+ self._sslobj.session = session
+
+ @property
+ def session_reused(self):
+ """Was the client session reused during handshake"""
+ return self._sslobj.session_reused
+
+ @property
def server_side(self):
"""Whether this is a server-side socket."""
return self._sslobj.server_side
@@ -703,7 +719,7 @@ class SSLSocket(socket):
family=AF_INET, type=SOCK_STREAM, proto=0, fileno=None,
suppress_ragged_eofs=True, npn_protocols=None, ciphers=None,
server_hostname=None,
- _context=None):
+ _context=None, _session=None):
if _context:
self._context = _context
@@ -735,11 +751,16 @@ class SSLSocket(socket):
# mixed in.
if sock.getsockopt(SOL_SOCKET, SO_TYPE) != SOCK_STREAM:
raise NotImplementedError("only stream sockets are supported")
- if server_side and server_hostname:
- raise ValueError("server_hostname can only be specified "
- "in client mode")
+ if server_side:
+ if server_hostname:
+ raise ValueError("server_hostname can only be specified "
+ "in client mode")
+ if _session is not None:
+ raise ValueError("session can only be specified in "
+ "client mode")
if self._context.check_hostname and not server_hostname:
raise ValueError("check_hostname requires server_hostname")
+ self._session = _session
self.server_side = server_side
self.server_hostname = server_hostname
self.do_handshake_on_connect = do_handshake_on_connect
@@ -775,7 +796,8 @@ class SSLSocket(socket):
try:
sslobj = self._context._wrap_socket(self, server_side,
server_hostname)
- self._sslobj = SSLObject(sslobj, owner=self)
+ self._sslobj = SSLObject(sslobj, owner=self,
+ session=self._session)
if do_handshake_on_connect:
timeout = self.gettimeout()
if timeout == 0.0:
@@ -796,6 +818,24 @@ class SSLSocket(socket):
self._context = ctx
self._sslobj.context = ctx
+ @property
+ def session(self):
+ """The SSLSession for client socket."""
+ if self._sslobj is not None:
+ return self._sslobj.session
+
+ @session.setter
+ def session(self, session):
+ self._session = session
+ if self._sslobj is not None:
+ self._sslobj.session = session
+
+ @property
+ def session_reused(self):
+ """Was the client session reused during handshake"""
+ if self._sslobj is not None:
+ return self._sslobj.session_reused
+
def dup(self):
raise NotImplemented("Can't dup() %s instances" %
self.__class__.__name__)
@@ -1028,7 +1068,8 @@ class SSLSocket(socket):
if self._connected:
raise ValueError("attempt to connect already-connected SSLSocket!")
sslobj = self.context._wrap_socket(self, False, self.server_hostname)
- self._sslobj = SSLObject(sslobj, owner=self)
+ self._sslobj = SSLObject(sslobj, owner=self,
+ session=self._session)
try:
if connect_ex:
rc = socket.connect_ex(self, addr)