Skip to content

Commit 6c49aca

Browse files
committed
better integration and error handling. added tests
1 parent 0188cb8 commit 6c49aca

File tree

2 files changed

+93
-25
lines changed

2 files changed

+93
-25
lines changed

src/OpenSSL/SSL.py

Lines changed: 26 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -823,38 +823,41 @@ class Session:
823823
.. versionadded:: 0.14
824824
"""
825825

826-
_session: Any
826+
_session: Any = None
827827

828+
def __init__(self, data: Optional[bytes] = None) -> None:
829+
if data is None:
830+
return
831+
832+
p = _ffi.new("unsigned char[]", data)
833+
pp = _ffi.new("unsigned char **")
834+
pp[0] = p
835+
length = _ffi.cast("long", len(data))
828836

829-
def d2i_SSL_SESSION(data: bytes) -> Session:
830-
p = _ffi.new("unsigned char[]", data)
831-
pp = _ffi.new("unsigned char **")
832-
pp[0] = p
833-
length = _ffi.cast("long", len(data))
837+
session = _lib.d2i_SSL_SESSION(_ffi.NULL, pp, length)
838+
if session == _ffi.NULL:
839+
_raise_current_error()
834840

835-
session = _lib.d2i_SSL_SESSION(_ffi.NULL, pp, length)
836-
if session == _ffi.NULL:
837-
raise RuntimeError("d2i_SSL_SESSION failed")
841+
self._session = _ffi.gc(session, _lib.SSL_SESSION_free)
838842

839-
pysession = Session.__new__(Session)
840-
pysession._session = _ffi.gc(session, _lib.SSL_SESSION_free)
841-
return pysession
843+
def i2d(self) -> bytes:
844+
if self._session is None:
845+
raise ValueError("Not a valid session")
842846

843-
def i2d_SSL_SESSION(session: Session) -> bytes:
847+
length = _lib.i2d_SSL_SESSION(self._session, _ffi.NULL)
848+
if length == 0:
849+
raise ValueError("Not a valid session")
844850

845-
length = _lib.i2d_SSL_SESSION(session._session, _ffi.NULL)
846-
if length == 0:
847-
raise RuntimeError("i2d_SSL_SESSION failed to get length")
851+
pp = _ffi.new("unsigned char **")
852+
p = _ffi.new("unsigned char[]", length)
853+
pp[0] = p
848854

849-
pp = _ffi.new("unsigned char **")
850-
p = _ffi.new("unsigned char[]", length)
851-
pp[0] = p
855+
length = _lib.i2d_SSL_SESSION(self._session, pp)
856+
if length == 0:
857+
raise ValueError("Not a valid session")
852858

853-
length = _lib.i2d_SSL_SESSION(session._session, pp)
854-
if length == 0:
855-
raise RuntimeError("i2d_SSL_SESSION failed to produce DER")
859+
return _ffi.buffer(p, length)[:]
856860

857-
return _ffi.buffer(p, length)[:]
858861

859862
class Context:
860863
"""

tests/test_ssl.py

Lines changed: 67 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -299,17 +299,21 @@ def _create_certificate_chain():
299299
return [(cakey, cacert), (ikey, icert), (skey, scert)]
300300

301301

302-
def loopback_client_factory(socket, version=SSLv23_METHOD):
302+
def loopback_client_factory(socket, version=SSLv23_METHOD, session_data=None):
303303
client = Connection(Context(version), socket)
304+
if session_data is not None:
305+
client.set_session(Session(session_data))
304306
client.set_connect_state()
305307
return client
306308

307309

308-
def loopback_server_factory(socket, version=SSLv23_METHOD):
310+
def loopback_server_factory(socket, version=SSLv23_METHOD, session_data=None):
309311
ctx = Context(version)
310312
ctx.use_privatekey(load_privatekey(FILETYPE_PEM, server_key_pem))
311313
ctx.use_certificate(load_certificate(FILETYPE_PEM, server_cert_pem))
312314
server = Connection(ctx, socket)
315+
if session_data is not None:
316+
server.set_session(Session(session_data))
313317
server.set_accept_state()
314318
return server
315319

@@ -2154,6 +2158,67 @@ def test_construction(self):
21542158
new_session = Session()
21552159
assert isinstance(new_session, Session)
21562160

2161+
def test_d2i_fail(self):
2162+
with pytest.raises(Error) as e:
2163+
Session(b"abc" * 1000)
2164+
2165+
assert e.value.args[0][0] in [
2166+
# TODO
2167+
# 1.1.x
2168+
# (
2169+
# "SSL routines",
2170+
# "SSL_CTX_set_session_id_context",
2171+
# "ssl session id context too long",
2172+
# ),
2173+
# 3.0.x
2174+
(
2175+
"asn1 encoding routines",
2176+
"",
2177+
"wrong tag",
2178+
),
2179+
]
2180+
2181+
assert e.value.args[0][1] in [
2182+
# TODO
2183+
# 1.1.x
2184+
# (
2185+
# "SSL routines",
2186+
# "SSL_CTX_set_session_id_context",
2187+
# "ssl session id context too long",
2188+
# ),
2189+
# 3.0.x
2190+
(
2191+
"asn1 encoding routines",
2192+
"",
2193+
"nested asn1 error",
2194+
),
2195+
]
2196+
2197+
def test_session_success(self):
2198+
session_id = (
2199+
b"\x51\x6d\x1d\x18\xc3\xb5\x86\x81\xc6\x79\x89\x2c\x89\x3e\x56\x33"
2200+
b"\xa7\x9c\xcd\x9b\x87\xbb\xb3\xdc\xf6\x76\x70\xf9\xc0\xdd\xf4\xef"
2201+
)
2202+
2203+
session_data = (
2204+
b"\x30\x71\x02\x01\x01\x02\x02\x03\x03\x04\x02\xc0\x30\x04\x20" +
2205+
session_id +
2206+
b"\x04\x30\x0f\xb2\x51\xe3\x15\x60\x2d\xef\x6e\x6d\xd2\x94\x2d\xe5" +
2207+
b"\x37\x96\x72\xfa\xce\xb0\x39\xcc\x8d\xdf\xab\x32\xcc\x75\x0c\x66" +
2208+
b"\xf9\xfd\xef\xbc\xc6\x2a\x8f\x9c\x35\x16\xfd\x4d\x38\xd9\xf9\xeb" +
2209+
b"\x1d\xe4\xa1\x06\x02\x04\x66\xec\x4c\x2d\xa2\x04\x02\x02\x02\x58" +
2210+
b"\xa4\x02\x04\x00"
2211+
)
2212+
serverSocket, clientSocket = socket_pair()
2213+
2214+
client = loopback_client_factory(clientSocket, session_data=session_data)
2215+
server = loopback_server_factory(serverSocket, session_data=session_data)
2216+
2217+
handshake(client, server)
2218+
2219+
client.send(b"hello world")
2220+
assert b"hello world" == server.recv(len(b"hello world"))
2221+
21572222

21582223
@pytest.fixture(params=["context", "connection"])
21592224
def ctx_or_conn(request) -> Union[Context, Connection]:

0 commit comments

Comments
 (0)