diff --git a/wrapper/python/wolfssl/test/test_client.py b/wrapper/python/wolfssl/test/test_client.py new file mode 100644 index 000000000..f5e26061c --- /dev/null +++ b/wrapper/python/wolfssl/test/test_client.py @@ -0,0 +1,45 @@ +# test_client.py +# +# Copyright (C) 2006-2016 wolfSSL Inc. +# +# This file is part of wolfSSL. (formerly known as CyaSSL) +# +# wolfSSL is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# wolfSSL is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA +import unittest +import socket +import wolfssl +import ssl + +class SSLClientTest(unittest.TestCase): + ssl_provider = ssl + host = "www.google.com" + port = 443 + + def setUp(self): + self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + + def test_wrap_socket(self): + self.secure_sock = self.ssl_provider.wrap_socket( + self.sock, ssl_version=ssl.PROTOCOL_TLSv1_2) + self.secure_sock.connect((self.host, self.port)) + + self.secure_sock.send(b"GET / HTTP/1.1\n\n") + self.assertEquals(b"HTTP", self.secure_sock.recv(4)) + + self.secure_sock.close() + + +#class TestWolfSSL(SSLClientTest): +# ssl_provider = wolfssl diff --git a/wrapper/python/wolfssl/test/test_methods.py b/wrapper/python/wolfssl/test/test_methods.py new file mode 100644 index 000000000..7548ed6f6 --- /dev/null +++ b/wrapper/python/wolfssl/test/test_methods.py @@ -0,0 +1,71 @@ +# test_methods.py +# +# Copyright (C) 2006-2016 wolfSSL Inc. +# +# This file is part of wolfSSL. (formerly known as CyaSSL) +# +# wolfSSL is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# wolfSSL is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA +import unittest +from wolfssl._methods import * +from wolfssl._ffi import ffi as _ffi + + +class TestMethods(unittest.TestCase): + def test_SSLv3_raises(self): + self.assertRaises(ValueError, WolfSSLMethod, PROTOCOL_SSLv3, False) + self.assertRaises(ValueError, WolfSSLMethod, PROTOCOL_SSLv3, True) + + + def test_TLSv1_raises(self): + self.assertRaises(ValueError, WolfSSLMethod, PROTOCOL_TLSv1, False) + self.assertRaises(ValueError, WolfSSLMethod, PROTOCOL_TLSv1, True) + + + def test_TLSv1_1_raises(self): + self.assertRaises(ValueError, WolfSSLMethod, PROTOCOL_TLSv1_1, False) + self.assertRaises(ValueError, WolfSSLMethod, PROTOCOL_TLSv1_1, True) + + + def test_SSLv23_doesnt_raises(self): + client = WolfSSLMethod(PROTOCOL_SSLv23, False) + server = WolfSSLMethod(PROTOCOL_SSLv23, True) + + self.assertIsInstance(client, WolfSSLMethod) + self.assertIsInstance(server, WolfSSLMethod) + + self.assertNotEquals(client.native_object, _ffi.NULL) + self.assertNotEquals(server.native_object, _ffi.NULL) + + + def test_TLS_doesnt_raises(self): + client = WolfSSLMethod(PROTOCOL_TLS, False) + server = WolfSSLMethod(PROTOCOL_TLS, True) + + self.assertIsInstance(client, WolfSSLMethod) + self.assertIsInstance(server, WolfSSLMethod) + + self.assertNotEquals(client.native_object, _ffi.NULL) + self.assertNotEquals(server.native_object, _ffi.NULL) + + + def test_TLSv1_2_doesnt_raises(self): + client = WolfSSLMethod(PROTOCOL_TLSv1_2, False) + server = WolfSSLMethod(PROTOCOL_TLSv1_2, True) + + self.assertIsInstance(client, WolfSSLMethod) + self.assertIsInstance(server, WolfSSLMethod) + + self.assertNotEquals(client.native_object, _ffi.NULL) + self.assertNotEquals(server.native_object, _ffi.NULL) diff --git a/wrapper/python/wolfssl/wolfssl/_context.py b/wrapper/python/wolfssl/wolfssl/_context.py new file mode 100644 index 000000000..d7335d1a1 --- /dev/null +++ b/wrapper/python/wolfssl/wolfssl/_context.py @@ -0,0 +1,74 @@ +# _context.py +# +# Copyright (C) 2006-2016 wolfSSL Inc. +# +# This file is part of wolfSSL. (formerly known as CyaSSL) +# +# wolfSSL is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# wolfSSL is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA +try: + from wolfssl._ffi import ffi as _ffi + from wolfssl._ffi import lib as _lib +except ImportError: + pass + +from wolfssl._methods import WolfSSLMethod + +CERT_NONE = 0 +CERT_OPTIONAL = 1 +CERT_REQUIRED = 2 + +class SSLContext: + """An SSLContext holds various SSL-related configuration options and + data, such as certificates and possibly a private key.""" + + + def __init__(self, protocol, server_side=False): + method = WolfSSLMethod(protocol, server_side) + + self.protocol = protocol + self._side = server_side + self.native_object = _lib.wolfSSL_CTX_new(method.native_object) + + # wolfSSL_CTX_new() takes ownership of the method. + # the method is freed later inside wolfSSL_CTX_free() + # or if wolfSSL_CTX_new() failed to allocate the context object. + method.native_object = None + + if self.native_object == _ffi.NULL: + raise MemoryError("Unnable to allocate context object") + + + def __del__(self): + if self.native_object is not None: + _lib.wolfSSL_CTX_free(self.native_object) + + +# def wrap_socket(self, sock, server_side=False, +# do_handshake_on_connect=True, +# suppress_ragged_eofs=True, +# server_hostname=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) +# +# +# def load_cert_chain(self, certfile, keyfile=None, password=None): +# pass +# +# +# def load_verify_locations(self, cafile=None, capath=None, cadata=None): +# pass \ No newline at end of file diff --git a/wrapper/python/wolfssl/wolfssl/_memory.py b/wrapper/python/wolfssl/wolfssl/_memory.py new file mode 100644 index 000000000..809508a4f --- /dev/null +++ b/wrapper/python/wolfssl/wolfssl/_memory.py @@ -0,0 +1,29 @@ +# _memory.py +# +# Copyright (C) 2006-2016 wolfSSL Inc. +# +# This file is part of wolfSSL. (formerly known as CyaSSL) +# +# wolfSSL is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# wolfSSL is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA +try: + from wolfssl._ffi import ffi as _ffi + from wolfssl._ffi import lib as _lib +except ImportError: + pass + +_DYNAMIC_TYPE_METHOD = 11 + +def _native_free(native_object, dynamic_type): + _lib.wolfSSL_Free(native_object, _ffi.NULL, dynamic_type) \ No newline at end of file diff --git a/wrapper/python/wolfssl/wolfssl/_methods.py b/wrapper/python/wolfssl/wolfssl/_methods.py index 0b13bc2b7..c5d7901e6 100644 --- a/wrapper/python/wolfssl/wolfssl/_methods.py +++ b/wrapper/python/wolfssl/wolfssl/_methods.py @@ -17,31 +17,57 @@ # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA -from wolfssl._ffi import ffi as _ffi -from wolfssl._ffi import lib as _lib +try: + from wolfssl._ffi import ffi as _ffi + from wolfssl._ffi import lib as _lib +except ImportError: + pass + +from wolfssl._memory import ( + _native_free, _DYNAMIC_TYPE_METHOD +) + PROTOCOL_SSLv23 = 1 PROTOCOL_SSLv3 = 2 +PROTOCOL_TLS = 1 PROTOCOL_TLSv1 = 3 PROTOCOL_TLSv1_1 = 4 PROTOCOL_TLSv1_2 = 5 -_PROTOCOL_LIST = [PROTOCOL_SSLv23, PROTOCOL_SSLv3, PROTOCOL_TLSv1, - PROTOCOL_TLSv1_1, PROTOCOL_TLSv1_2] +_PROTOCOL_LIST = [PROTOCOL_SSLv23, PROTOCOL_SSLv3, PROTOCOL_TLS, + PROTOCOL_TLSv1, PROTOCOL_TLSv1_1, PROTOCOL_TLSv1_2] + class WolfSSLMethod: + def __init__(self, protocol, server_side): if protocol not in _PROTOCOL_LIST: raise ValueError("this protocol is not supported") + elif protocol is PROTOCOL_SSLv3: raise ValueError("this protocol is not supported") + elif protocol is PROTOCOL_TLSv1: raise ValueError("this protocol is not supported") + elif protocol is PROTOCOL_TLSv1_1: raise ValueError("this protocol is not supported") + elif protocol is PROTOCOL_TLSv1_2: - self._method = _lib.wolfTLSv1_2_server_method() if server_side else\ - _lib.wolfTLSv1_2_client_method() - elif protocol is PROTOCOL_SSLv23: - self._method = _lib.wolfSSLv23_server_method() if server_side else \ - _lib.wolfSSLv23_client_method() + self.native_object = \ + _lib.wolfTLSv1_2_server_method() if server_side else \ + _lib.wolfTLSv1_2_client_method() + + elif protocol in [PROTOCOL_SSLv23, PROTOCOL_TLS]: + self.native_object = \ + _lib.wolfSSLv23_server_method() if server_side else \ + _lib.wolfSSLv23_client_method() + + if self.native_object == _ffi.NULL: + raise MemoryError("Unnable to allocate method object") + + + def __del__(self): + if self.native_object is not None: + _native_free(self.native_object, _DYNAMIC_TYPE_METHOD) diff --git a/wrapper/python/wolfssl/wolfssl/build_ffi.py b/wrapper/python/wolfssl/wolfssl/build_ffi.py index ac18e0b0a..55cf3431f 100644 --- a/wrapper/python/wolfssl/wolfssl/build_ffi.py +++ b/wrapper/python/wolfssl/wolfssl/build_ffi.py @@ -27,6 +27,8 @@ ffi.set_source("wolfssl._ffi", """ #include #include + + void wolfSSL_Free(void *ptr, void* heap, int type); """, include_dirs=["/usr/local/include"], library_dirs=["/usr/local/lib"], @@ -38,13 +40,15 @@ ffi.cdef( typedef unsigned char byte; typedef unsigned int word32; - int wolfSSL_Init(void); - int wolfSSL_Cleanup(void); + void wolfSSL_Free(void *ptr, void* heap, int type); - void *wolfSSLv23_server_method(void); - void *wolfSSLv23_client_method(void); - void *wolfTLSv1_2_server_method(void); - void *wolfTLSv1_2_client_method(void); + void* wolfSSLv23_server_method(void); + void* wolfSSLv23_client_method(void); + void* wolfTLSv1_2_server_method(void); + void* wolfTLSv1_2_client_method(void); + + void* wolfSSL_CTX_new(void* method); + void wolfSSL_CTX_free(void* ctx); """ )