Compare commits

..

No commits in common. "master" and "v5.6.6-stable" have entirely different histories.

30 changed files with 215 additions and 1359 deletions

View File

@ -1,34 +1,3 @@
wolfSSL-py Release 5.9.2 (Jul 15, 2026)
============================================
* Fix SSLSocket.write() corrupting bytes-like data such as bytearray/memoryview
* Return None instead of raising from getpeercert() when the peer sends no certificate
* Require verify_mode=CERT_REQUIRED when enabling check_hostname
* Map non-blocking WANT_READ/WANT_WRITE to SSLWantReadError/SSLWantWriteError
* FFI and build fixes
* Fenrir fixes
* Update wolfSSL to version 5.9.2
wolfSSL-py Release 5.8.4 (Dec 29, 2025)
============================================
* Fix an issue which allowed a client without a cert to connect despite setting verify_mode to CERT_REQUIRED (CVE-2025-15346):
A vulnerability in the handling of verify_mode = CERT_REQUIRED in the wolfssl Python package (wolfssl-py) causes client certificate requirements to not be fully enforced. Because the WOLFSSL_VERIFY_FAIL_IF_NO_PEER_CERT flag was not included, the behavior effectively matched CERT_OPTIONAL: a peer certificate was verified if presented, but connections were incorrectly authenticated when no client certificate was provided. This results in improper authentication, allowing attackers to bypass mutual TLS (mTLS) client authentication by omitting a client certificate during the TLS handshake.
Thanks to Matan Radomski from Microsoft for the report.
* Update wolfSSL to version 5.8.4
wolfSSL-py Release 5.8.2 (Jul 24, 2025)
============================================
* Update wolfSSL to version 5.8.2
wolfSSL-py Release 5.7.4 (Nov 13, 2024)
============================================
* Update wolfSSL to version 5.7.4
wolfSSL-py Release 5.7.2 (Sep 6, 2024)
============================================
* SSLSocket: support version() version
* support disabling secure renegotiation
* Update wolfSSL to version 5.7.2
wolfSSL-py Release 5.6.6 (Jan 23, 2024)
============================================
* Fix segfault issue with TLS v1.3

View File

@ -9,9 +9,9 @@ Open Source
~~~~~~~~~~~
wolfCrypt and wolfSSL software are free software downloads and may be modified
to the needs of the user as long as the user adheres to version three of the GPL
License. The GPLv3 license can be found on the `gnu.org website
<https://www.gnu.org/licenses/gpl-3.0.html>`_.
to the needs of the user as long as the user adheres to version two of the GPL
License. The GPLv2 license can be found on the `gnu.org website
<http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>`_.
Commercial Licensing
~~~~~~~~~~~~~~~~~~~~

View File

@ -82,7 +82,12 @@ servedocs: docs ## compile the docs watching for changes
watchmedo shell-command -p '*.rst' -c '$(MAKE) -C docs html' -R -D .
dist: clean ## builds source and wheel package
python setup.py sdist bdist_wheel
python setup.py sdist
./make/osx/build_wheels.sh
./make/manylinux1/build_wheels.sh
ls -l dist
release: ## package and upload a release

View File

@ -66,17 +66,6 @@ wolfSSL library. For example:
# Uses custom install location
$ USE_LOCAL_WOLFSSL=/tmp/install pip install .
Disabling secure renegotiation
------------------------------
When building wolfssl-py from source secure renegotiation is enabled by
default. To disable secure renegotiation set the environment variable
WOLFSSLPY_DISABLE_SCR during the build process. For example:
.. code-block:: bash
$ WOLFSSLPY_DISABLE_SCR=1 pip install .
Testing
=======

View File

@ -1,42 +1,41 @@
Certificate Revocation List (CRL):
Version 2 (0x1)
Signature Algorithm: sha256WithRSAEncryption
Issuer: C=US, ST=Montana, L=Bozeman, O=Sawtooth, OU=Consulting, CN=www.wolfssl.com, emailAddress=info@wolfssl.com
Last Update: Nov 13 20:41:50 2025 GMT
Next Update: Aug 9 20:41:50 2028 GMT
Issuer: C = US, ST = Montana, L = Bozeman, O = Sawtooth, OU = Consulting, CN = www.wolfssl.com, emailAddress = info@wolfssl.com
Last Update: Feb 15 12:50:27 2022 GMT
Next Update: Nov 11 12:50:27 2024 GMT
CRL extensions:
X509v3 CRL Number:
2
Revoked Certificates:
Serial Number: 02
Revocation Date: Nov 13 20:41:50 2025 GMT
Revocation Date: Feb 15 12:50:27 2022 GMT
Signature Algorithm: sha256WithRSAEncryption
Signature Value:
b7:0d:1c:78:99:1c:e8:0b:d9:33:a2:95:01:ad:cf:35:e9:86:
28:7f:49:6b:93:76:c1:70:08:61:aa:77:57:34:af:45:82:78:
5d:3b:7b:67:ca:b4:fb:d1:68:13:be:34:94:84:2d:65:ad:97:
52:69:1d:67:ea:8e:a7:ff:21:0f:21:6c:8c:75:7f:c7:50:c5:
6b:a5:fd:cd:3f:91:64:7b:5e:0f:4a:9c:c8:cd:39:a0:30:ad:
80:27:50:e0:a7:bf:19:68:cf:6b:26:75:51:14:77:5a:62:6d:
bc:66:1a:90:f7:00:09:34:c7:d0:9d:81:f3:b5:9f:90:40:02:
8d:3f:68:7f:0d:1d:c5:00:32:e5:cf:42:35:1c:b6:eb:02:a8:
d7:2a:a7:f3:f1:10:e2:d5:9e:41:de:2f:78:7d:7f:ad:68:06:
a0:6d:40:96:dd:35:59:4d:a0:d3:bd:2e:ba:b6:75:f8:1c:43:
b9:c0:b7:75:c4:38:59:46:00:71:ab:5a:df:f5:62:e9:ac:2b:
76:11:4f:1b:42:2c:dd:b2:38:6e:57:cf:c5:75:67:4c:3e:27:
bb:4c:d5:09:2c:4a:13:3d:8b:9c:89:76:b7:bd:73:1b:64:50:
ea:d5:13:0e:51:48:d8:43:08:93:00:85:8f:2f:08:ad:0d:aa:
d6:6c:f8:3d
43:e6:3b:30:0e:32:53:32:a4:08:3c:e5:d5:2e:f1:ce:e9:95:
ff:ba:d6:fe:2e:59:80:f8:0a:2f:cf:1e:e0:37:fe:ca:cc:33:
66:8b:ed:65:50:7d:44:92:d3:5c:52:9a:95:a5:9d:a5:4e:77:
8b:b4:7f:59:c8:7a:e0:eb:34:32:ae:a1:03:99:d2:3c:c0:f4:
7e:1c:87:4c:6c:5a:ba:0a:95:e8:a1:44:01:7b:8f:3e:a4:e3:
e8:1e:07:19:f0:09:7a:85:8f:f3:82:62:f8:1e:08:51:a3:60:
30:5b:06:c8:a2:b3:ff:aa:28:66:ad:fe:4b:81:49:30:ef:5f:
5d:ac:d9:ad:17:9f:2a:b6:22:d6:35:cc:9f:d9:11:26:dd:7a:
06:35:d0:d5:c7:41:6c:52:97:8c:aa:82:5a:e5:a8:58:d4:b7:
2b:31:84:34:15:bd:08:e4:9e:71:9e:c5:40:f8:02:a3:a0:1e:
4f:98:72:2b:eb:9e:8a:4e:01:83:88:e5:cb:6e:3b:52:e3:a9:
34:a1:7c:e4:79:2c:d1:e0:0b:74:22:ba:6d:cb:c3:a1:56:f9:
c9:f4:20:bf:00:49:df:6b:59:49:18:c7:75:27:8e:a1:5a:a6:
ff:f2:be:34:4a:c9:6d:6e:24:a3:1f:15:7e:34:90:b6:81:bf:
15:80:c3:ac
-----BEGIN X509 CRL-----
MIICBDCB7QIBATANBgkqhkiG9w0BAQsFADCBlDELMAkGA1UEBhMCVVMxEDAOBgNV
BAgMB01vbnRhbmExEDAOBgNVBAcMB0JvemVtYW4xETAPBgNVBAoMCFNhd3Rvb3Ro
MRMwEQYDVQQLDApDb25zdWx0aW5nMRgwFgYDVQQDDA93d3cud29sZnNzbC5jb20x
HzAdBgkqhkiG9w0BCQEWEGluZm9Ad29sZnNzbC5jb20XDTI1MTExMzIwNDE1MFoX
DTI4MDgwOTIwNDE1MFowFDASAgECFw0yNTExMTMyMDQxNTBaoA4wDDAKBgNVHRQE
AwIBAjANBgkqhkiG9w0BAQsFAAOCAQEAtw0ceJkc6AvZM6KVAa3PNemGKH9Ja5N2
wXAIYap3VzSvRYJ4XTt7Z8q0+9FoE740lIQtZa2XUmkdZ+qOp/8hDyFsjHV/x1DF
a6X9zT+RZHteD0qcyM05oDCtgCdQ4Ke/GWjPayZ1URR3WmJtvGYakPcACTTH0J2B
87WfkEACjT9ofw0dxQAy5c9CNRy26wKo1yqn8/EQ4tWeQd4veH1/rWgGoG1Alt01
WU2g070uurZ1+BxDucC3dcQ4WUYAcata3/Vi6awrdhFPG0Is3bI4blfPxXVnTD4n
u0zVCSxKEz2LnIl2t71zG2RQ6tUTDlFI2EMIkwCFjy8IrQ2q1mz4PQ==
HzAdBgkqhkiG9w0BCQEWEGluZm9Ad29sZnNzbC5jb20XDTIyMDIxNTEyNTAyN1oX
DTI0MTExMTEyNTAyN1owFDASAgECFw0yMjAyMTUxMjUwMjdaoA4wDDAKBgNVHRQE
AwIBAjANBgkqhkiG9w0BAQsFAAOCAQEAQ+Y7MA4yUzKkCDzl1S7xzumV/7rW/i5Z
gPgKL88e4Df+yswzZovtZVB9RJLTXFKalaWdpU53i7R/Wch64Os0Mq6hA5nSPMD0
fhyHTGxaugqV6KFEAXuPPqTj6B4HGfAJeoWP84Ji+B4IUaNgMFsGyKKz/6ooZq3+
S4FJMO9fXazZrRefKrYi1jXMn9kRJt16BjXQ1cdBbFKXjKqCWuWoWNS3KzGENBW9
COSecZ7FQPgCo6AeT5hyK+ueik4Bg4jly247UuOpNKF85Hks0eALdCK6bcvDoVb5
yfQgvwBJ32tZSRjHdSeOoVqm//K+NErJbW4kox8VfjSQtoG/FYDDrA==
-----END X509 CRL-----

View File

@ -1,12 +1,12 @@
# Makefile for Sphinx documentation
#
# Copyright (C) 2006-2026 wolfSSL Inc.
# Copyright (C) 2006-2020 wolfSSL Inc.
#
# This file is part of wolfSSL.
# 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 3 of the License, or
# 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,
@ -16,7 +16,7 @@
#
# 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-1335, USA
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
# You can set these variables from the command line.
SPHINXOPTS =

View File

@ -52,7 +52,7 @@ master_doc = 'index'
# General information about the project.
project = u'wolfssl Python'
copyright = u'2006-2026, wolfSSL Inc. All rights reserved'
copyright = u'2019, wolfSSL Inc. All rights reserved'
author = u'wolfSSL'
# The version info for the project you're documenting, acts as replacement for

View File

@ -4,13 +4,13 @@
#
# client.py
#
# Copyright (C) 2006-2026 wolfSSL Inc.
# Copyright (C) 2006-2020 wolfSSL Inc.
#
# This file is part of wolfSSL.
# 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 3 of the License, or
# 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,
@ -20,7 +20,7 @@
#
# 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-1335, USA
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
# pylint: disable=missing-docstring, invalid-name, import-error
@ -89,12 +89,6 @@ def build_arg_parser():
help="Disable client cert check"
)
parser.add_argument(
"-n", action="store_true",
help="Disable server hostname check "
"(IP literal hosts are never hostname-checked)"
)
parser.add_argument(
"-g", action="store_true",
help="Send server HTTP GET"
@ -131,61 +125,11 @@ def get_DTLSmethod(index):
wolfssl.PROTOCOL_DTLSv1_3
)[index]
def is_ip_literal(host):
# AI_NUMERICHOST never resolves, it only parses. Unlike
# socket.inet_pton() it is available on every supported platform.
try:
socket.getaddrinfo(host, None, 0, 0, 0, socket.AI_NUMERICHOST)
return True
except socket.error:
return False
def configure_verification(context, args):
"""
Configure peer certificate and hostname verification on the context
according to the parsed arguments. Returns the server_hostname to pass
to wrap_socket() (None when no hostname check should be performed).
When certificate verification is enabled (the default), hostname
verification is enabled too so that a CA-trusted certificate issued for
a different host is rejected. Pass -n to opt out explicitly (e.g. when
using test certificates).
IP literal hosts are not hostname-checked: wolfSSL_check_domain_name()
only matches DNS names (iPAddress SANs are skipped on this path), and
RFC 6066 forbids IP literals in SNI. Certificate verification against
the CA still applies. Connect by DNS name to also verify the hostname.
"""
if args.d:
context.verify_mode = wolfssl.CERT_NONE
context.check_hostname = False
return None
context.verify_mode = wolfssl.CERT_REQUIRED
context.load_verify_locations(args.A)
if args.n:
context.check_hostname = False
return None
if is_ip_literal(args.h):
print("Note: skipping hostname check for IP literal '{}'. "
"Connect by DNS name to enable it.".format(args.h))
context.check_hostname = False
return None
context.check_hostname = True
return args.h
def main():
args = build_arg_parser().parse_args()
# DTLS connection over UDP
if args.u:
if args.v > 2:
args.v = 1
bind_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, 0)
context = wolfssl.SSLContext(get_DTLSmethod(args.v))
# SSL/TLS connection over TCP
@ -194,22 +138,21 @@ def main():
context = wolfssl.SSLContext(get_SSLmethod(args.v))
# enable debug, if native wolfSSL has been compiled with '--enable-debug'
try:
wolfssl.WolfSSL.enable_debug()
except RuntimeError:
pass
wolfssl.WolfSSL.enable_debug()
context.load_cert_chain(args.c, args.k)
server_hostname = configure_verification(context, args)
if args.d:
context.verify_mode = wolfssl.CERT_NONE
else:
context.verify_mode = wolfssl.CERT_REQUIRED
context.load_verify_locations(args.A)
if args.l:
context.set_ciphers(args.l)
secure_socket = None
try:
secure_socket = context.wrap_socket(
bind_socket, server_hostname=server_hostname)
secure_socket = context.wrap_socket(bind_socket)
if not args.C:
secure_socket.enable_crl(1)
@ -228,8 +171,7 @@ def main():
print()
finally:
if secure_socket:
secure_socket.close()
secure_socket.close()
if __name__ == '__main__':

View File

@ -4,13 +4,13 @@
#
# server.py
#
# Copyright (C) 2006-2026 wolfSSL Inc.
# Copyright (C) 2006-2020 wolfSSL Inc.
#
# This file is part of wolfSSL.
# 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 3 of the License, or
# 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,
@ -20,7 +20,7 @@
#
# 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-1335, USA
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
# pylint: disable=missing-docstring, invalid-name, import-error
@ -115,30 +115,16 @@ def get_DTLSmethod(index):
)[index]
# Large enough to peek a DTLS ClientHello source address.
PEEK_BUFSIZE = 1500
def peek_peer_address(sock):
"""
Return the source address of the next pending datagram without removing
it from the socket queue. MSG_PEEK leaves the datagram (the DTLS
ClientHello) intact so wolfSSL_accept() can consume it during the
handshake.
"""
_, from_addr = sock.recvfrom(PEEK_BUFSIZE, socket.MSG_PEEK)
return from_addr
def main():
args = build_arg_parser().parse_args()
# DTLS connection over UDP
if args.u:
# Set DTLSv1.2 as default if unspecified
if args.v > 2:
# Set DTLSv1.2 as default if unspecified
if args.v == 5:
args.v = 1
bind_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, 0)
bind_socket.bind(("" if args.b else "localhost", args.p))
data, from_addr = bind_socket.recvfrom(1)
context = wolfssl.SSLContext(get_DTLSmethod(args.v), server_side=True)
# SSL/TLS connection over TCP
else:
@ -150,10 +136,7 @@ def main():
print("Server listening on port", bind_socket.getsockname()[1])
# enable debug, if native wolfSSL has been compiled with '--enable-debug'
try:
wolfssl.WolfSSL.enable_debug()
except RuntimeError:
pass
wolfssl.WolfSSL.enable_debug()
context.load_cert_chain(args.c, args.k)
@ -170,9 +153,6 @@ def main():
try:
secure_socket = None
if args.u:
# Peek the client's address for this connection without
# consuming the ClientHello datagram needed by the handshake.
from_addr = peek_peer_address(bind_socket)
secure_socket = context.wrap_socket(bind_socket)
else:
new_socket, from_addr = bind_socket.accept()
@ -190,11 +170,7 @@ def main():
finally:
if secure_socket:
secure_socket.shutdown(socket.SHUT_RDWR)
# Don't close for DTLS - secure_socket wraps the
# shared bind_socket which is needed for
# subsequent connections
if not args.u:
secure_socket.close()
secure_socket.close()
if not args.i:
break

@ -1 +1 @@
Subproject commit ac01707f552c611fbd135cc723b2682b3e7f80f2
Subproject commit 979707380c677dfa65e3ba48f19e149773a4a32d

View File

@ -1,13 +1,13 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Copyright (C) 2006-2026 wolfSSL Inc.
# Copyright (C) 2006-2020 wolfSSL Inc.
#
# This file is part of wolfSSL.
# 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 3 of the License, or
# 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,
@ -17,7 +17,7 @@
#
# 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-1335, USA
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
# pylint: disable=wrong-import-position
@ -59,7 +59,7 @@ setup(
author="wolfSSL Inc.",
author_email="info@wolfssl.com",
url="https://github.com/wolfssl/wolfssl-py",
license="GPLv3 or Commercial License",
license="GPLv2 or Commercial License",
packages=["wolfssl"],
@ -68,7 +68,7 @@ setup(
keywords="wolfssl, wolfcrypt, security, cryptography",
classifiers=[
u"License :: OSI Approved :: GNU General Public License v3 (GPLv3)",
u"License :: OSI Approved :: GNU General Public License v2 (GPLv2)",
u"License :: Other/Proprietary License",
u"Operating System :: OS Independent",
u"Programming Language :: Python :: 2.7",

View File

@ -2,13 +2,13 @@
#
# conftest.py
#
# Copyright (C) 2006-2026 wolfSSL Inc.
# Copyright (C) 2006-2020 wolfSSL Inc.
#
# This file is part of wolfSSL.
# 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 3 of the License, or
# 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,
@ -18,7 +18,7 @@
#
# 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-1335, USA
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
# pylint: disable=missing-docstring, redefined-outer-name
@ -27,7 +27,6 @@ import ssl
import pytest
import wolfssl
from wolfssl._ffi import lib as _lib
from wolfssltestserver import wolfSSLTestServer
@pytest.fixture
def tcp_socket():
@ -62,15 +61,3 @@ def ssl_context(ssl_provider, request):
return ssl_provider.SSLContext(ssl_provider.PROTOCOL_TLSv1_3)
if request.param == "SSLv23":
return ssl_provider.SSLContext(ssl_provider.PROTOCOL_SSLv23)
port = 1110
@pytest.fixture
def ssl_server():
from threading import Thread
global port
port += 1
with wolfSSLTestServer(('localhost', port)) as server:
t = Thread(target=server.handle_request)
t.daemon = True
t.start()
yield server

View File

@ -2,13 +2,13 @@
#
# test_client.py
#
# Copyright (C) 2006-2026 wolfSSL Inc.
# Copyright (C) 2006-2020 wolfSSL Inc.
#
# This file is part of wolfSSL.
# 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 3 of the License, or
# 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,
@ -18,15 +18,12 @@
#
# 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-1335, USA
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
# pylint: disable=missing-docstring, invalid-name, import-error
# pylint: disable=redefined-outer-name
import pytest
import wolfssl
from wolfssltestserver import wolfSSLTestServer
from threading import Thread
HOST = "www.python.org"
PORT = 443
@ -73,123 +70,3 @@ def test_secure_connection(secure_socket):
secure_socket.write(b"GET / HTTP/1.1\n\n")
assert secure_socket.read(4) == b"HTTP"
@pytest.mark.parametrize("ssl_version",
[pytest.param((wolfssl.PROTOCOL_TLSv1_1, "TLSv1.1"), id="TLSv1.1"),
pytest.param((wolfssl.PROTOCOL_TLSv1_2, "TLSv1.2"), id="TLSv1.2"),
pytest.param((wolfssl.PROTOCOL_TLSv1_3, "TLSv1.3"), id="TLSv1.3")])
def test_get_version(ssl_server, ssl_version, tcp_socket):
protocol = ssl_version[0]
protocol_name = ssl_version[1]
try:
ssl_context = wolfssl.SSLContext(protocol)
except ValueError:
pytest.skip("Protocol {} not supported".format(protocol_name))
return
secure_socket = ssl_context.wrap_socket(tcp_socket)
secure_socket.connect(('127.0.0.1', ssl_server.port))
assert secure_socket.version() == protocol_name
secure_socket.write(b'hello wolfssl')
secure_socket.read(1024)
def test_close_after_connected(ssl_server, tcp_socket):
ctx = wolfssl.SSLContext(wolfssl.PROTOCOL_TLSv1_2)
sock = ctx.wrap_socket(tcp_socket)
sock.connect(('127.0.0.1', ssl_server.port))
sock.write(b'hello wolfssl')
sock.read(1024)
sock.close()
def test_recv_into_nbytes_zero(ssl_server, tcp_socket):
ctx = wolfssl.SSLContext(wolfssl.PROTOCOL_TLSv1_2)
sock = ctx.wrap_socket(tcp_socket)
sock.connect(('127.0.0.1', ssl_server.port))
sock.write(b'hello wolfssl')
buf = bytearray(1024)
n = sock.recv_into(buf, 0)
assert n > 0
sock.close()
def test_unwrap_returns_socket(ssl_server, tcp_socket):
import socket as _socket
ctx = wolfssl.SSLContext(wolfssl.PROTOCOL_TLSv1_2)
sock = ctx.wrap_socket(tcp_socket)
sock.connect(('127.0.0.1', ssl_server.port))
sock.write(b'hello wolfssl')
sock.read(1024)
raw = sock.unwrap()
assert isinstance(raw, _socket.socket)
raw.close()
def test_sendall_large_buffer(ssl_server, tcp_socket):
ctx = wolfssl.SSLContext(wolfssl.PROTOCOL_TLSv1_2)
sock = ctx.wrap_socket(tcp_socket)
sock.connect(('127.0.0.1', ssl_server.port))
sock.sendall(b'x' * 8192)
sock.read(1024)
sock.close()
def test_client_cert_verification_failure():
"""
Test that a connection fails when the server requires client certificates
but the server's CA (globalsign) does not verify the client's certificate.
"""
import socket
import time
# Create a server with CERT_REQUIRED and globalsign CA
# This server will require client certificates but won't accept
# certificates signed by a different CA
port = 11111
with wolfSSLTestServer(
('localhost', port),
version=wolfssl.PROTOCOL_TLS,
verify=wolfssl.CERT_REQUIRED
) as server:
server_thread = Thread(target=server.handle_request)
server_thread.daemon = True
server_thread.start()
# Give the server a moment to start
time.sleep(0.1)
# Create a client socket
client_tcp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# Create a client context
client_ctx = wolfssl.SSLContext(wolfssl.PROTOCOL_TLS)
# Wrap the socket with the client context
# Set do_handshake_on_connect=False so we can explicitly call do_handshake()
# and catch the error
client_socket = client_ctx.wrap_socket(
client_tcp_socket,
do_handshake_on_connect=False
)
# Connect the TCP socket first
client_socket.connect(('127.0.0.1', port))
# Attempt handshake - this should fail because the client does not
# send a cert/key.
with pytest.raises(wolfssl.SSLError) as exc_info:
client_socket.do_handshake()
# Handshake appeared to succeed, try to read/write to trigger the error
# The server should reject the connection due to certificate verification failure
client_socket.write(b'hello')
client_socket.read(1024)
# Clean up (errors during close are expected if connection failed)
try:
client_socket.close()
except Exception:
pass
try:
client_tcp_socket.close()
except Exception:
pass

View File

@ -1,171 +0,0 @@
# -*- coding: utf-8 -*-
#
# test_client_example.py
#
# Copyright (C) 2006-2026 wolfSSL Inc.
#
# This file is part of wolfSSL.
#
# 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 3 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-1335, USA
# pylint: disable=missing-docstring, invalid-name, import-error
import os
import socket
import subprocess
import sys
import threading
import wolfssl
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "examples"))
import client as client_example # noqa: E402
def _args(argv):
return client_example.build_arg_parser().parse_args(argv)
def _ctx():
return wolfssl.SSLContext(wolfssl.PROTOCOL_TLSv1_2)
def test_verification_enables_hostname_check_by_default():
"""
F-5621: with cert verification on (the default), the client must also
verify the peer's hostname and pass server_hostname to wrap_socket.
"""
args = _args(["-h", "example.com"])
ctx = _ctx()
server_hostname = client_example.configure_verification(ctx, args)
assert ctx.verify_mode == wolfssl.CERT_REQUIRED
assert ctx.check_hostname is True
assert server_hostname == "example.com"
def test_disable_cert_check_skips_hostname():
args = _args(["-d"])
ctx = _ctx()
# Simulate a reused context that previously had hostname checking on:
# -d must clear it, not leave it dangling against CERT_NONE.
ctx.verify_mode = wolfssl.CERT_REQUIRED
ctx.check_hostname = True
server_hostname = client_example.configure_verification(ctx, args)
assert ctx.verify_mode == wolfssl.CERT_NONE
assert ctx.check_hostname is False
assert server_hostname is None
def test_hostname_check_can_be_opted_out():
"""An explicit opt-out is provided for test certificates."""
args = _args(["-n"])
ctx = _ctx()
# Reused context with hostname checking previously enabled: -n must
# actively turn it back off.
ctx.verify_mode = wolfssl.CERT_REQUIRED
ctx.check_hostname = True
server_hostname = client_example.configure_verification(ctx, args)
assert ctx.verify_mode == wolfssl.CERT_REQUIRED
assert ctx.check_hostname is False
assert server_hostname is None
def test_ip_literal_host_skips_hostname_check():
"""
The default host (127.0.0.1) is an IP literal. wolfSSL's
check_domain_name() never matches iPAddress SANs, so the example must
not hostname-check IP literals; certificate verification stays on.
"""
args = _args([])
ctx = _ctx()
ctx.verify_mode = wolfssl.CERT_REQUIRED
ctx.check_hostname = True
server_hostname = client_example.configure_verification(ctx, args)
assert args.h == "127.0.0.1"
assert ctx.verify_mode == wolfssl.CERT_REQUIRED
assert ctx.check_hostname is False
assert server_hostname is None
def test_ipv6_literal_host_skips_hostname_check():
args = _args(["-h", "::1"])
ctx = _ctx()
server_hostname = client_example.configure_verification(ctx, args)
assert ctx.verify_mode == wolfssl.CERT_REQUIRED
assert ctx.check_hostname is False
assert server_hostname is None
def _free_port():
sock = socket.socket()
sock.bind(("localhost", 0))
port = sock.getsockname()[1]
sock.close()
return port
def test_default_invocation_end_to_end():
"""
`python client.py` with the default host must complete a connection to
`python server.py` using the bundled certificates: verification is on
by default and the IP literal host must not trip the hostname check.
"""
root = os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))
port = _free_port()
# The examples must import the same wolfssl as this test process, even
# when the package is not installed (source-tree runs).
env = dict(os.environ)
pkg_root = os.path.dirname(os.path.dirname(os.path.abspath(
wolfssl.__file__)))
env["PYTHONPATH"] = os.pathsep.join(
[pkg_root] + ([env["PYTHONPATH"]] if env.get("PYTHONPATH") else []))
server = subprocess.Popen(
[sys.executable, "-u", os.path.join("examples", "server.py"),
"-p", str(port)],
cwd=root, env=env, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
try:
line = server.stdout.readline().decode()
assert "Server listening" in line, line
client = subprocess.Popen(
[sys.executable, "-u", os.path.join("examples", "client.py"),
"-p", str(port)],
cwd=root, env=env, stdout=subprocess.PIPE,
stderr=subprocess.STDOUT)
# Watchdog instead of communicate(timeout=...), which is 3.3+.
watchdog = threading.Timer(60, client.kill)
watchdog.start()
try:
out, _ = client.communicate()
finally:
watchdog.cancel()
assert client.returncode == 0, out.decode()
assert b"I hear you fa shizzle" in out
finally:
server.kill()
server.wait()

View File

@ -2,13 +2,13 @@
#
# test_context.py
#
# Copyright (C) 2006-2026 wolfSSL Inc.
# Copyright (C) 2006-2020 wolfSSL Inc.
#
# This file is part of wolfSSL.
# 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 3 of the License, or
# 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,
@ -18,7 +18,7 @@
#
# 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-1335, USA
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
# pylint: disable=missing-docstring, invalid-name, import-error
# pylint: disable=redefined-outer-name
@ -39,9 +39,6 @@ def test_verify_mode(ssl_provider, ssl_context):
assert ssl_context.verify_mode == ssl_provider.CERT_NONE
ssl_context.verify_mode = ssl_provider.CERT_OPTIONAL
assert ssl_context.verify_mode == ssl_provider.CERT_OPTIONAL
ssl_context.verify_mode = ssl_provider.CERT_REQUIRED
assert ssl_context.verify_mode == ssl_provider.CERT_REQUIRED
@ -74,35 +71,3 @@ def test_load_verify_locations_with_cafile(ssl_context):
def test_load_verify_locations_with_cadata(ssl_context):
ssl_context.load_verify_locations(cadata=_CADATA)
def test_check_hostname_requires_cert_required(ssl_provider, ssl_context):
with pytest.raises(ValueError):
ssl_context.check_hostname = True
ssl_context.verify_mode = ssl_provider.CERT_REQUIRED
ssl_context.check_hostname = True
assert ssl_context.check_hostname is True
def test_wrap_socket_server_side_mismatch(ssl_context, tcp_socket):
with pytest.raises(ValueError):
ssl_context.wrap_socket(tcp_socket, server_side=True)
def test_close_without_handshake(ssl_context, tcp_socket):
sock = ssl_context.wrap_socket(tcp_socket)
sock.close()
def test_close_releases_native_object(ssl_context, tcp_socket):
sock = ssl_context.wrap_socket(tcp_socket)
sock.close()
sock.close()
def test_operations_after_close_raise(ssl_context, tcp_socket):
sock = ssl_context.wrap_socket(tcp_socket)
sock.close()
with pytest.raises(ValueError):
sock.read()

View File

@ -1,105 +0,0 @@
# -*- coding: utf-8 -*-
#
# test_dtls_handshake_once.py
#
# Copyright (C) 2006-2026 wolfSSL Inc.
#
# This file is part of wolfSSL.
#
# 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 3 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-1335, USA
# pylint: disable=missing-docstring, invalid-name, import-error
# pylint: disable=protected-access
"""
F-4136: for DTLS, write()/read()/recv_into() used to call do_handshake() on
every single call. Once the handshake has completed, re-running it is wasteful
and, on a non-blocking socket, wolfSSL_accept/connect can raise
SSLWantReadError and abort an otherwise valid I/O. The handshake must only be
driven until it completes.
"""
from types import SimpleNamespace
import pytest
import wolfssl
class _OkLib:
"""_lib stub whose I/O calls always succeed."""
def wolfSSL_write(self, ssl, data, length):
return length
def wolfSSL_read(self, ssl, data, length):
return length
def wolfSSL_get_error(self, ssl, ret): # pragma: no cover
return 0
def _make_dtls_socket(handshake_complete):
sock = wolfssl.SSLSocket.__new__(wolfssl.SSLSocket)
sock.native_object = object()
sock._connected = True
sock._server_side = True
sock._context = SimpleNamespace(protocol=wolfssl.PROTOCOL_DTLSv1_2)
sock._handshake_complete = handshake_complete
sock._release_native_object = lambda: None
return sock
@pytest.fixture
def spy_handshake(monkeypatch):
monkeypatch.setattr(wolfssl, "_lib", _OkLib())
calls = []
def _record(sock):
calls.append(True)
sock._handshake_complete = True
return calls, _record
@pytest.mark.parametrize("op", ["write", "read", "recv_into"])
def test_dtls_io_does_not_redrive_completed_handshake(spy_handshake, op):
calls, record = spy_handshake
sock = _make_dtls_socket(handshake_complete=True)
sock.do_handshake = lambda block=False: record(sock)
if op == "write":
sock.write(b"payload")
elif op == "read":
sock.read(8)
else:
sock.recv_into(bytearray(8))
assert calls == [], "do_handshake() must not run once the handshake is done"
@pytest.mark.parametrize("op", ["write", "read", "recv_into"])
def test_dtls_io_drives_handshake_until_complete(spy_handshake, op):
calls, record = spy_handshake
sock = _make_dtls_socket(handshake_complete=False)
sock.do_handshake = lambda block=False: record(sock)
if op == "write":
sock.write(b"payload")
elif op == "read":
sock.read(8)
else:
sock.recv_into(bytearray(8))
assert calls == [True], "first DTLS I/O must drive the handshake once"

View File

@ -1,73 +0,0 @@
# -*- coding: utf-8 -*-
#
# test_dtls_server_example.py
#
# Copyright (C) 2006-2026 wolfSSL Inc.
#
# This file is part of wolfSSL.
#
# 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 3 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-1335, USA
# pylint: disable=missing-docstring, invalid-name, import-error
import os
import sys
import socket
import pytest
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "examples"))
import server as server_example # noqa: E402
@pytest.fixture
def udp_pair():
srv = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
srv.bind(("localhost", 0))
cli = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
try:
yield srv, cli, srv.getsockname()
finally:
srv.close()
cli.close()
def test_peek_peer_address_returns_source(udp_pair):
srv, cli, srv_addr = udp_pair
cli.bind(("localhost", 0))
cli.sendto(b"clienthello-payload", srv_addr)
addr = server_example.peek_peer_address(srv)
assert addr == cli.getsockname()
def test_peek_peer_address_does_not_consume_datagram(udp_pair):
"""
Regression test for F-3481: peeking the client's address before the
DTLS handshake must leave the ClientHello datagram intact. The previous
example used recvfrom(1), which consumed the datagram and discarded
everything past the first byte, breaking the handshake.
"""
srv, cli, srv_addr = udp_pair
payload = b"X" * 256 # stand-in for a DTLS ClientHello record
cli.sendto(payload, srv_addr)
server_example.peek_peer_address(srv)
# The datagram must still be fully available for wolfSSL_accept().
srv.settimeout(2)
data, _ = srv.recvfrom(4096)
assert data == payload

View File

@ -1,131 +0,0 @@
# -*- coding: utf-8 -*-
#
# test_getpeercert.py
#
# Copyright (C) 2006-2026 wolfSSL Inc.
#
# This file is part of wolfSSL.
#
# 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 3 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-1335, USA
# pylint: disable=missing-docstring, invalid-name, import-error
# pylint: disable=protected-access
import socket
from contextlib import contextmanager
from threading import Thread
import pytest
import wolfssl
@contextmanager
def _client_server_session():
"""
Establish a real TLS connection to a local server that does NOT request a
client certificate. Yields (client_socket, server_result); server_result
is populated (after the block exits) with the server's view of the peer:
{"x509", "cert"} on success or {"error"} if a call raised.
"""
result = {}
server_ctx = wolfssl.SSLContext(wolfssl.PROTOCOL_TLS, server_side=True)
server_ctx.verify_mode = wolfssl.CERT_NONE
server_ctx.load_cert_chain("certs/server-cert.pem", "certs/server-key.pem")
listener = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
listener.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
listener.bind(("localhost", 0))
listener.listen(1)
port = listener.getsockname()[1]
def serve():
conn, _ = listener.accept()
ssock = server_ctx.wrap_socket(conn, server_side=True)
try:
ssock.read(1024)
# Client sent no certificate: these must not raise.
result["x509"] = ssock.get_peer_x509()
result["cert"] = ssock.getpeercert()
ssock.write(b"ok")
except Exception as exc: # pylint: disable=broad-except
result["error"] = exc
finally:
ssock.close()
server_thread = Thread(target=serve, daemon=True)
server_thread.start()
client_ctx = wolfssl.SSLContext(wolfssl.PROTOCOL_TLS)
client_ctx.verify_mode = wolfssl.CERT_NONE
client = client_ctx.wrap_socket(
socket.socket(socket.AF_INET, socket.SOCK_STREAM))
client.connect(("localhost", port))
client.write(b"hi")
try:
yield client, result
finally:
try:
client.read(1024)
except Exception: # pylint: disable=broad-except
pass
client.close()
server_thread.join(timeout=10)
listener.close()
def test_getpeercert_returns_none_without_peer_cert():
"""
F-5623: on a valid TLS connection where the peer presented no
certificate (here, a server that does not request a client cert),
getpeercert()/get_peer_x509() must return None instead of raising.
"""
with _client_server_session() as (client, result):
# The peer (server) always presents a certificate.
server_cert = client.getpeercert()
assert "error" not in result, "getpeercert raised: %r" % result.get("error")
assert result["x509"] is None
assert result["cert"] is None
# Positive path: the server's certificate is still returned to the client.
assert server_cert is not None
def test_wolfsslx509_accepts_session_for_backward_compat():
"""
WolfSSLX509 historically accepted a WOLFSSL* session and fetched the peer
certificate itself. That constructor form must keep working alongside the
new WOLFSSL_X509* form used by get_peer_x509().
"""
with _client_server_session() as (client, _result):
from_session = wolfssl.WolfSSLX509(client.native_object)
from_helper = client.get_peer_x509()
# Both forms resolve to the same server certificate.
assert from_session.get_subject_cn() != ""
assert from_session.get_subject_cn() == from_helper.get_subject_cn()
def test_wolfsslx509_rejects_unexpected_types():
"""
WolfSSLX509 discriminates WOLFSSL* from WOLFSSL_X509* by cffi type.
Anything else must raise TypeError instead of being treated as a
certificate pointer.
"""
with pytest.raises(TypeError):
wolfssl.WolfSSLX509(object())
with pytest.raises(TypeError):
wolfssl.WolfSSLX509(wolfssl._ffi.new("int *"))

View File

@ -1,119 +0,0 @@
# -*- coding: utf-8 -*-
#
# test_io_error_mapping.py
#
# Copyright (C) 2006-2026 wolfSSL Inc.
#
# This file is part of wolfSSL.
#
# 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 3 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-1335, USA
# pylint: disable=missing-docstring, invalid-name, import-error
# pylint: disable=protected-access
"""
These tests exercise the error-code-to-exception mapping in SSLSocket's
read/write/recv_into. wolfSSL_write can return WANT_READ and wolfSSL_read can
return WANT_WRITE during a renegotiation; non-blocking callers rely on these
being surfaced as SSLWantReadError / SSLWantWriteError (matching the stdlib
ssl module) rather than a generic SSLError.
The renegotiation conditions are awkward to force over a real socket, so the
native wolfSSL_read/wolfSSL_write/wolfSSL_get_error functions are stubbed to
return the relevant codes and the Python-level mapping is verified directly.
"""
from types import SimpleNamespace
import pytest
import wolfssl
class _FakeLib:
"""Stand-in for wolfssl._lib that forces a given I/O return / error."""
def __init__(self, io_ret, err):
self._io_ret = io_ret
self._err = err
def wolfSSL_write(self, ssl, data, length):
return self._io_ret
def wolfSSL_read(self, ssl, data, length):
return self._io_ret
def wolfSSL_get_error(self, ssl, ret):
return self._err
def _make_socket():
"""A minimal, non-DTLS SSLSocket that skips __init__/native setup."""
sock = wolfssl.SSLSocket.__new__(wolfssl.SSLSocket)
sock.native_object = object() # non-NULL so _check_closed passes
sock._connected = True # so _check_connected is a no-op
sock._context = SimpleNamespace(protocol=wolfssl.PROTOCOL_TLS)
# The dummy native_object isn't a real cdata pointer, so make __del__
# a no-op to avoid wolfSSL_free() choking on it during GC.
sock._release_native_object = lambda: None
return sock
def _patch_lib(monkeypatch, io_ret, err):
monkeypatch.setattr(wolfssl, "_lib", _FakeLib(io_ret, err))
def test_write_want_read_raises_wantread(monkeypatch):
"""F-3905: wolfSSL_write returning WANT_READ -> SSLWantReadError."""
_patch_lib(monkeypatch, -1, wolfssl._SSL_ERROR_WANT_READ)
sock = _make_socket()
with pytest.raises(wolfssl.SSLWantReadError):
sock.write(b"data")
def test_write_want_write_still_raises_wantwrite(monkeypatch):
_patch_lib(monkeypatch, -1, wolfssl._SSL_ERROR_WANT_WRITE)
sock = _make_socket()
with pytest.raises(wolfssl.SSLWantWriteError):
sock.write(b"data")
def test_read_want_write_raises_wantwrite(monkeypatch):
"""F-3906: wolfSSL_read returning WANT_WRITE -> SSLWantWriteError."""
_patch_lib(monkeypatch, -1, wolfssl._SSL_ERROR_WANT_WRITE)
sock = _make_socket()
with pytest.raises(wolfssl.SSLWantWriteError):
sock.read(16)
def test_read_want_read_still_raises_wantread(monkeypatch):
_patch_lib(monkeypatch, -1, wolfssl._SSL_ERROR_WANT_READ)
sock = _make_socket()
with pytest.raises(wolfssl.SSLWantReadError):
sock.read(16)
def test_recv_into_want_write_raises_wantwrite(monkeypatch):
"""F-3907: wolfSSL_read in recv_into returning WANT_WRITE."""
_patch_lib(monkeypatch, -1, wolfssl._SSL_ERROR_WANT_WRITE)
sock = _make_socket()
with pytest.raises(wolfssl.SSLWantWriteError):
sock.recv_into(bytearray(16))
def test_recv_into_want_read_still_raises_wantread(monkeypatch):
_patch_lib(monkeypatch, -1, wolfssl._SSL_ERROR_WANT_READ)
sock = _make_socket()
with pytest.raises(wolfssl.SSLWantReadError):
sock.recv_into(bytearray(16))

View File

@ -2,13 +2,13 @@
#
# test_methods.py
#
# Copyright (C) 2006-2026 wolfSSL Inc.
# Copyright (C) 2006-2020 wolfSSL Inc.
#
# This file is part of wolfSSL.
# 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 3 of the License, or
# 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,
@ -18,7 +18,7 @@
#
# 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-1335, USA
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
# pylint: disable=missing-docstring, redefined-outer-name, import-error

View File

@ -1,85 +0,0 @@
# -*- coding: utf-8 -*-
#
# test_write_bytes.py
#
# Copyright (C) 2006-2026 wolfSSL Inc.
#
# This file is part of wolfSSL.
#
# 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 3 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-1335, USA
# pylint: disable=missing-docstring, invalid-name, import-error
# pylint: disable=protected-access
"""
F-5622: SSLSocket.write() ran data through t2b(), which str()-encodes anything
that is not already bytes. Valid bytes-like inputs (bytearray, memoryview)
were therefore serialized as their Python repr ("bytearray(b'...')",
"<memory at 0x...>") instead of their actual contents.
"""
from types import SimpleNamespace
import wolfssl
class _CaptureLib:
def __init__(self):
self.written = None
def wolfSSL_write(self, ssl, data, length):
self.written = bytes(data[:length])
return length
def wolfSSL_get_error(self, ssl, ret): # pragma: no cover
return 0
def _make_socket(monkeypatch):
lib = _CaptureLib()
monkeypatch.setattr(wolfssl, "_lib", lib)
sock = wolfssl.SSLSocket.__new__(wolfssl.SSLSocket)
sock.native_object = object()
sock._connected = True
sock._context = SimpleNamespace(protocol=wolfssl.PROTOCOL_TLS)
sock._release_native_object = lambda: None
return sock, lib
def test_write_bytes_unchanged(monkeypatch):
sock, lib = _make_socket(monkeypatch)
sock.write(b"hello")
assert lib.written == b"hello"
def test_write_bytearray_sends_contents(monkeypatch):
sock, lib = _make_socket(monkeypatch)
sock.write(bytearray(b"hello"))
assert lib.written == b"hello"
def test_write_memoryview_sends_contents(monkeypatch):
sock, lib = _make_socket(monkeypatch)
sock.write(memoryview(b"hello"))
assert lib.written == b"hello"
def test_write_str_is_utf8_encoded(monkeypatch):
# Backward compatibility: str is UTF-8 encoded (historical t2b()
# behavior), not rejected. The \u00e9 escape keeps the source 7-bit
# ASCII while still exercising a multi-byte UTF-8 encoding.
sock, lib = _make_socket(monkeypatch)
sock.write("h\u00e9llo")
assert lib.written == "h\u00e9llo".encode("utf-8")

View File

@ -1,25 +0,0 @@
from wolfssl import SSLContext, PROTOCOL_TLS, CERT_NONE
from socketserver import TCPServer, BaseRequestHandler
ca_path = './certs/client-cert.pem'
cert_path = './certs/server-cert.pem'
key_path = './certs/server-key.pem'
class wolfSSLTestServer(TCPServer):
class wolfSSLRequestHandler(BaseRequestHandler):
def handle(self):
ssl_socket = self.server.ctx.wrap_socket(self.request, server_side=True)
ssl_socket.recv(1024)
ssl_socket.sendall(b'I hear you fa shizzle!')
ctx = None
def __init__(self, address, version=PROTOCOL_TLS, ca=ca_path, cert=cert_path, key=key_path, verify=CERT_NONE):
TCPServer.__init__(self, address, self.wolfSSLRequestHandler, bind_and_activate=False)
self.allow_reuse_address = self.allow_reuse_port = True
self.ctx = SSLContext(version, server_side=True)
self.ctx.verify_mode = verify
self.ctx.load_verify_locations(ca)
self.ctx.load_cert_chain(cert, key)
self.port = address[1]
self.version = version
self.server_bind()
self.server_activate()

View File

@ -2,13 +2,13 @@
#
# __about__.py
#
# Copyright (C) 2006-2026 wolfSSL Inc.
# Copyright (C) 2006-2022 wolfSSL Inc.
#
# This file is part of wolfSSL.
# 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 3 of the License, or
# 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,
@ -18,7 +18,7 @@
#
# 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-1335, USA
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
from wolfssl._version import __version__, __wolfssl_version__
@ -29,8 +29,8 @@ __uri__ = "https://github.com/wolfssl/wolfssl-py"
__author__ = "wolfSSL Inc."
__email__ = "info@wolfssl.com"
__license__ = "GPLv3 or Commercial License"
__copyright__ = "Copyright (C) 2006-2026 wolfSSL Inc"
__license__ = "GPLv2 or Commercial License"
__copyright__ = "Copyright (C) 2006-2022 wolfSSL Inc"
__all__ = [
"__title__", "__summary__", "__uri__", "__version__",

View File

@ -2,13 +2,13 @@
#
# __init__.py
#
# Copyright (C) 2006-2026 wolfSSL Inc.
# Copyright (C) 2006-2022 wolfSSL Inc.
#
# This file is part of wolfSSL.
# 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 3 of the License, or
# 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,
@ -18,7 +18,7 @@
#
# 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-1335, USA
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
# pylint: disable=too-many-instance-attributes, too-many-arguments
# pylint: disable=too-many-arguments, too-many-branches, too-many-locals
@ -38,10 +38,8 @@ from wolfssl.__about__ import * # noqa: F401, F403
try:
from wolfssl._ffi import ffi as _ffi
from wolfssl._ffi import lib as _lib
except ImportError as e:
from wolfssl.utils import _FFIPlaceholder
_ffi = _FFIPlaceholder(e)
_lib = _FFIPlaceholder(e)
except ImportError:
pass
from wolfssl.utils import t2b
@ -57,15 +55,10 @@ from wolfssl._methods import ( # noqa: F401
PROTOCOL_DTLSv1_3, WolfSSLMethod as _WolfSSLMethod
)
_SSL_VERIFY_NONE = 0
_SSL_VERIFY_PEER = 1
_SSL_VERIFY_FAIL_IF_NO_PEER_CERT = 2
CERT_NONE = 0
CERT_REQUIRED = 1
CERT_NONE = _SSL_VERIFY_NONE
CERT_OPTIONAL = _SSL_VERIFY_PEER
CERT_REQUIRED = (_SSL_VERIFY_PEER | _SSL_VERIFY_FAIL_IF_NO_PEER_CERT)
_VERIFY_MODE_LIST = [CERT_NONE, CERT_OPTIONAL, CERT_REQUIRED]
_VERIFY_MODE_LIST = [CERT_NONE, CERT_REQUIRED]
_SSL_SUCCESS = 1
_SSL_FILETYPE_PEM = 1
@ -81,9 +74,7 @@ class WolfSSL(object):
@classmethod
def enable_debug(self):
if _lib.wolfSSL_Debugging_ON() != _SSL_SUCCESS:
raise RuntimeError(
"wolfSSL debugging not available")
_lib.wolfSSL_Debugging_ON()
@classmethod
def disable_debug(self):
@ -97,32 +88,11 @@ class WolfSSLX509(object):
"""
def __init__(self, session):
# `session` kept as the original public parameter name. Accept a
# WOLFSSL* session (fetch the peer cert here) or an already-obtained
# WOLFSSL_X509* (used by SSLSocket.get_peer_x509()).
# Compare cffi type objects, not type name strings: typeof()
# results are interned per FFI instance, so this is exact and
# does not depend on how cffi renders the name.
ctype = _ffi.typeof(session)
if ctype is _ffi.typeof("WOLFSSL *"):
x509 = _lib.wolfSSL_get_peer_certificate(session)
elif ctype is _ffi.typeof("WOLFSSL_X509 *"):
x509 = session
else:
raise TypeError("session must be a WOLFSSL* or a WOLFSSL_X509*, "
"got %s" % ctype)
self.native_object = x509
self.native_object = _lib.wolfSSL_get_peer_certificate(session)
if self.native_object == _ffi.NULL:
raise SSLError("Unable to get internal WOLFSSL_X509 from wolfSSL")
def __del__(self):
if getattr(self, 'native_object', None) is not None \
and self.native_object != _ffi.NULL:
_lib.wolfSSL_X509_free(self.native_object)
self.native_object = _ffi.NULL
def get_subject_cn(self):
cnPtr = _lib.wolfSSL_X509_get_subjectCN(self.native_object)
if cnPtr == _ffi.NULL:
@ -160,7 +130,9 @@ class WolfSSLX509(object):
if derPtr == _ffi.NULL:
return None
return _ffi.buffer(derPtr, outSz[0])[:]
derBytes = _ffi.buffer(derPtr, outSz[0])
return derBytes
class SSLContext(object):
"""
@ -169,9 +141,7 @@ class SSLContext(object):
"""
def __init__(self, protocol, server_side=None):
if _lib.wolfSSL_Init() != _SSL_SUCCESS:
raise RuntimeError(
"wolfSSL library initialization failed")
_lib.wolfSSL_Init()
method = _WolfSSLMethod(protocol, server_side)
self.protocol = protocol
@ -194,9 +164,8 @@ class SSLContext(object):
self.verify_mode = CERT_NONE
def __del__(self):
if getattr(self, 'native_object', None) is not None and self.native_object != _ffi.NULL:
if getattr(self, 'native_object', _ffi.NULL) != _ffi.NULL:
_lib.wolfSSL_CTX_free(self.native_object)
self.native_object = _ffi.NULL
@property
def verify_mode(self):
@ -232,11 +201,8 @@ class SSLContext(object):
@check_hostname.setter
def check_hostname(self, value):
if value is not True and value is not False:
raise ValueError("check_hostname must be either "
"True or False")
if value and self._verify_mode != CERT_REQUIRED:
raise ValueError("check_hostname needs verify_mode "
"set to CERT_REQUIRED")
raise ValueError("check_hostname must be either True or False")
self._check_hostname = value
def get_options(self):
@ -272,9 +238,6 @@ class SSLContext(object):
"between init and wrap_socket()")
if self._server_side is None:
if server_side:
raise ValueError("SSLContext server_side value not consistent "
"between init and wrap_socket()")
self._server_side = server_side
if server_side is None and self._server_side is not None:
@ -373,10 +336,9 @@ class SSLContext(object):
raise SSLError("Unable to load verify locations. E(%d)" % ret)
if cadata is not None:
cadata_bytes = t2b(cadata)
ret = _lib.wolfSSL_CTX_load_verify_buffer(
self.native_object, cadata_bytes,
len(cadata_bytes), _SSL_FILETYPE_PEM)
self.native_object, t2b(cadata),
len(cadata), _SSL_FILETYPE_PEM)
if ret != _SSL_SUCCESS:
raise SSLError("Unable to load verify locations. E(%d)" % ret)
@ -475,9 +437,6 @@ class SSLSocket(object):
self._closed = False
self._connected = connected
# Tracks whether the (DTLS) handshake has completed so I/O methods
# don't re-drive it on every call.
self._handshake_complete = False
# create the SSL object
self.native_object = _lib.wolfSSL_new(self.context.native_object)
@ -494,14 +453,8 @@ class SSLSocket(object):
if self._context.check_hostname:
sni = _ffi.new("char[]", server_hostname.encode("utf-8"))
ret = _lib.wolfSSL_check_domain_name(self.native_object,
sni)
if ret != _SSL_SUCCESS:
self._release_native_object()
raise SSLError(
"Unable to set domain name "
"check for hostname "
"verification")
_lib.wolfSSL_check_domain_name(self.native_object,
sni)
if connected:
try:
@ -516,12 +469,11 @@ class SSLSocket(object):
self._release_native_object()
def _release_native_object(self):
if getattr(self, 'native_object', None) is not None and self.native_object != _ffi.NULL:
if getattr(self, 'native_object', _ffi.NULL) != _ffi.NULL:
_lib.wolfSSL_free(self.native_object)
self.native_object = _ffi.NULL
def pending(self):
self._check_closed("pending")
return _lib.wolfSSL_pending(self.native_object)
@property
@ -592,35 +544,16 @@ class SSLSocket(object):
Returns number of bytes of DATA actually transmitted.
"""
self._check_closed("write")
# Check connected if not DTLS
# Check connected if not DTLS
if self._context.protocol < PROTOCOL_DTLSv1:
self._check_connected()
# Drive the DTLS handshake only until it has completed.
elif not self._handshake_complete:
# Complete handshake if DTLS connection
else:
self.do_handshake()
# Send bytes-like objects verbatim; fall back to t2b() for other
# types (e.g. str) to preserve backward compatibility.
if not isinstance(data, bytes):
try:
data = bytes(memoryview(data))
except TypeError:
data = t2b(data)
data = t2b(data)
ret = _lib.wolfSSL_write(
self.native_object, data, len(data))
if ret <= 0:
err = _lib.wolfSSL_get_error(
self.native_object, 0)
if err == _SSL_ERROR_WANT_WRITE:
raise SSLWantWriteError()
elif err == _SSL_ERROR_WANT_READ:
# wolfSSL_write can require a read first (e.g. renegotiation).
raise SSLWantReadError()
else:
raise SSLError(
"wolfSSL_write error (%d)" % err)
return ret
return _lib.wolfSSL_write(self.native_object, data, len(data))
def send(self, data, flags=0):
if flags != 0:
@ -639,6 +572,14 @@ class SSLSocket(object):
while sent < length:
ret = self.write(data[sent:])
if (ret <= 0):
#expect to receive 0 when peer is reset or closed
err = _lib.wolfSSL_get_error(self.native_object, 0)
if err == _SSL_ERROR_WANT_WRITE:
raise SSLWantWriteError()
else:
raise SSLError("wolfSSL_write error (%d)" % err)
sent += ret
return None
@ -667,8 +608,8 @@ class SSLSocket(object):
# Check connected if not DTLS
if self._context.protocol < PROTOCOL_DTLSv1:
self._check_connected()
# Drive the DTLS handshake only until it has completed.
elif not self._handshake_complete:
# Complete handshake if DTLS connection
else:
self.do_handshake()
if buffer is not None:
@ -682,9 +623,6 @@ class SSLSocket(object):
err = _lib.wolfSSL_get_error(self.native_object, 0)
if err == _SSL_ERROR_WANT_READ:
raise SSLWantReadError()
elif err == _SSL_ERROR_WANT_WRITE:
# wolfSSL_read can require a write first (e.g. renegotiation).
raise SSLWantWriteError()
else:
raise SSLError("wolfSSL_read error (%d)" % err)
@ -705,14 +643,11 @@ class SSLSocket(object):
self._check_closed("read")
if self._context.protocol < PROTOCOL_DTLSv1:
self._check_connected()
# Drive the DTLS handshake only until it has completed.
elif not self._handshake_complete:
self.do_handshake()
if buffer is None:
raise ValueError("buffer cannot be None")
if nbytes is None or nbytes == 0:
if nbytes is None:
nbytes = len(buffer)
else:
nbytes = min(len(buffer), nbytes)
@ -727,9 +662,6 @@ class SSLSocket(object):
err = _lib.wolfSSL_get_error(self.native_object, 0)
if err == _SSL_ERROR_WANT_READ:
raise SSLWantReadError()
elif err == _SSL_ERROR_WANT_WRITE:
# wolfSSL_read can require a write first (e.g. renegotiation).
raise SSLWantWriteError()
else:
raise SSLError("wolfSSL_read error (%d)" % err)
@ -756,9 +688,7 @@ class SSLSocket(object):
def shutdown(self, how):
if self.native_object != _ffi.NULL:
ret = _lib.wolfSSL_shutdown(self.native_object)
if ret == 0:
_lib.wolfSSL_shutdown(self.native_object)
_lib.wolfSSL_shutdown(self.native_object)
self._release_native_object()
if self._context.protocol < PROTOCOL_DTLSv1:
self._sock.shutdown(how)
@ -769,15 +699,10 @@ class SSLSocket(object):
Returns the wrapped OS socket.
"""
if self.native_object != _ffi.NULL:
if self._connected:
# Single-step shutdown is intentional; any
# bidirectional close_notify exchange is the
# caller's responsibility on the raw socket.
_lib.wolfSSL_shutdown(self.native_object)
self._release_native_object()
_lib.wolfSSL_set_fd(self.native_object, -1)
sock = socket(family=self._sock.family,
type=self._sock.type,
sock_type=self._sock.type,
proto=self._sock.proto,
fileno=self._sock.fileno())
@ -787,19 +712,14 @@ class SSLSocket(object):
return sock
def add_peer(self, addr):
peerAddr = _lib.wolfSSL_dtls_create_peer(addr[1], t2b(addr[0]))
if peerAddr == _ffi.NULL:
raise SSLError("Failed to create peer")
try:
ret = _lib.wolfSSL_dtls_set_peer(
self.native_object, peerAddr,
_SOCKADDR_SZ)
peerAddr = _lib.wolfSSL_dtls_create_peer(addr[1],t2b(addr[0]))
if peerAddr == _ffi.NULL:
raise SSLError("Failed to create peer")
ret = _lib.wolfSSL_dtls_set_peer(self.native_object, peerAddr,
_SOCKADDR_SZ)
if ret != _SSL_SUCCESS:
raise SSLError(
"Unable to set dtls peer."
" E(%d)" % ret)
finally:
_lib.wolfSSL_dtls_free_peer(peerAddr)
raise SSLError("Unable to set dtls peer. E(%d)" % ret)
_lib.wolfSSL_dtls_free_peer(peerAddr)
def do_handshake(self, block=False): # pylint: disable=unused-argument
"""
@ -838,7 +758,7 @@ class SSLSocket(object):
if alertRet == _SSL_SUCCESS:
alertHistory = alertHistoryPtr[0]
code = alertHistory.last_rx.code
alertDesc = _lib.wolfSSL_alert_desc_string_long(code)
alertDesc = _lib.wolfSSL_alert_type_string_long(code)
if alertDesc != _ffi.NULL:
alertStr = _ffi.string(alertDesc).decode("ascii")
else:
@ -851,9 +771,6 @@ class SSLSocket(object):
raise SSLError("do_handshake failed with error %d: %s" %
(err, eStr))
# Reached only on success (every failure path above raises).
self._handshake_complete = True
def _real_connect(self, addr, connect_ex):
if self._server_side:
raise ValueError("can't connect in server-side mode")
@ -864,16 +781,18 @@ class SSLSocket(object):
raise ValueError("attempt to connect already-connected SSLSocket!")
err = 0
ret = _SSL_SUCCESS
if self._context.protocol >= PROTOCOL_DTLSv1:
self.add_peer(addr)
self.add_peer(addr)
else:
if connect_ex:
err = self._sock.connect_ex(addr)
else:
err = 0
self._sock.connect(addr)
if err == 0:
if err == 0 and ret == _SSL_SUCCESS:
self._connected = True
if self.do_handshake_on_connect:
self.do_handshake()
@ -914,17 +833,13 @@ class SSLSocket(object):
def get_peer_x509(self):
"""
Returns a WolfSSLX509 object representing the peer's certificate,
or None if the peer did not present one (or there is no session).
Returns WolfSSLX509 object representing the peer's certificate,
after making a successful SSL/TLS connection.
"""
if self.native_object == _ffi.NULL:
return None
return _ffi.NULL
x509 = _lib.wolfSSL_get_peer_certificate(self.native_object)
if x509 == _ffi.NULL:
return None
return WolfSSLX509(x509)
return WolfSSLX509(self.native_object)
def getpeercert(self, binary_form=False):
"""
@ -935,33 +850,18 @@ class SSLSocket(object):
x509 = self.get_peer_x509()
if not x509:
return None
return x509
if binary_form:
return x509.get_der()
return {'subject': ((('commonName', x509.get_subject_cn()),),),
'subjectAltName': x509.get_altnames() }
def version(self):
"""
Returns the version of the protocol used in the connection.
"""
self._check_closed("version")
return _ffi.string(
_lib.wolfSSL_get_version(
self.native_object)).decode("ascii")
# The following functions expose functionality of the underlying
# Socket object. These are also exposed through Python's ssl module
# API and are provided here for compatibility.
def close(self):
if self.native_object != _ffi.NULL:
if self._connected:
# Single-step shutdown is intentional here; the
# socket is about to be closed so a bidirectional
# close_notify exchange is not required.
_lib.wolfSSL_shutdown(self.native_object)
self._release_native_object()
self._sock.close()
def fileno(self):
@ -1091,16 +991,12 @@ class WolfsslPwd_cb(object):
def _get_passwd(self, passwd, sz, rw, userdata):
try:
result = self._passwd_wrapper(sz, rw, userdata)
except Exception:
raise ValueError(
"Problem getting password from callback")
if not isinstance(result, bytes):
raise ValueError(
"Password callback must return bytes")
if len(result) > sz:
raise ValueError(
"Problem with password returned"
" being long")
for i in range(len(result)):
passwd[i] = result[i:i + 1]
return len(result)
if not isinstance(result, bytes):
raise ValueError("Problem, expected String, not bytes")
if len(result) > sz:
raise ValueError("Problem with password returned being long")
for i in range(len(result)):
passwd[i] = result[i:i + 1]
return len(result)
except Exception as e:
raise ValueError("Problem getting password from callback")

View File

@ -2,13 +2,13 @@
#
# build_ffi.py
#
# Copyright (C) 2006-2026 wolfSSL Inc.
# Copyright (C) 2006-2022 wolfSSL Inc.
#
# This file is part of wolfSSL.
# 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 3 of the License, or
# 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,
@ -18,7 +18,7 @@
#
# 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-1335, USA
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
# pylint: disable=missing-docstring, invalid-name
@ -35,6 +35,9 @@ import sys
from ctypes import cdll
from collections import namedtuple
libwolfssl_path = ""
def local_path(path):
""" Return path relative to the root of this project
"""
@ -69,14 +72,11 @@ def wolfssl_lib_path():
def call(cmd):
print("Calling: '{}' from working directory {}".format(
cmd, os.getcwd()))
print("Calling: '{}' from working directory {}".format(cmd, os.getcwd()))
old_env = os.environ["PATH"]
os.environ["PATH"] = "{}:{}".format(
WOLFSSL_SRC_PATH, old_env)
subprocess.check_call(
shlex.split(cmd), env=os.environ)
os.environ["PATH"] = "{}:{}".format(WOLFSSL_SRC_PATH, old_env)
subprocess.check_call(cmd, shell=True, env=os.environ)
os.environ["PATH"] = old_env
@ -142,8 +142,6 @@ def make_flags(prefix, debug):
"""
flags = []
cflags = []
# defaults to None (that eval to False)
disable_scr = os.getenv("WOLFSSLPY_DISABLE_SCR")
if get_platform() in ["linux-x86_64", "linux-i686"]:
cflags.append("-fpic")
@ -173,8 +171,7 @@ def make_flags(prefix, debug):
cflags.append("-DKEEP_PEER_CERT")
# for pyOpenSSL
if not disable_scr:
flags.append("--enable-secure-renegotiation")
flags.append("--enable-secure-renegotiation")
flags.append("--enable-opensslall")
cflags.append("-DFP_MAX_BITS=8192")
cflags.append("-DHAVE_EX_DATA")
@ -223,13 +220,8 @@ def build_wolfssl(ref, debug=False):
def make_optional_func_list(libwolfssl_path, funcs):
defined = []
sys.stderr.write("\nlibwolfssl Path: %s\n" % libwolfssl_path)
if not libwolfssl_path or not os.path.exists(libwolfssl_path):
sys.stderr.write("WARNING: libwolfssl not found, skipping optional "
"function detection\n")
return []
if libwolfssl_path.endswith(".so") or libwolfssl_path.endswith(".dylib"):
if libwolfssl_path.endswith(".so"):
libwolfssl = cdll.LoadLibrary(libwolfssl_path)
defined = []
for func in funcs:
@ -249,13 +241,16 @@ def make_optional_func_list(libwolfssl_path, funcs):
return defined
def get_libwolfssl_path():
lib_dir = wolfssl_lib_path()
for ext in (".so", ".dylib", ".a"):
path = os.path.join(lib_dir, "libwolfssl" + ext)
if os.path.exists(path):
return path
return None
def get_libwolfssl():
libwolfssl_path = os.path.join(wolfssl_lib_path(), "libwolfssl.a")
if not os.path.exists(libwolfssl_path):
libwolfssl_path = os.path.join(wolfssl_lib_path(), "libwolfssl.so")
if not os.path.exists(libwolfssl_path):
return 0
else:
return 1
else:
return 1
def generate_libwolfssl():
@ -284,7 +279,6 @@ if local_wolfssl:
raise RuntimeError("wolfSSL needs to be compiled with "
"--enable-opensslextra")
featureDetection = 1
libwolfssl_path = get_libwolfssl_path()
sys.stderr.write("\nDEBUG: Found <wolfssl/options.h>, attempting native "
"feature detection\n")
@ -293,10 +287,9 @@ else:
featureDetection = 0
sys.stderr.write("\nDEBUG: Skipping native feature detection, build not "
"using USE_LOCAL_WOLFSSL\n")
libwolfssl_path = get_libwolfssl_path()
if libwolfssl_path is None:
if get_libwolfssl() == 0:
generate_libwolfssl()
libwolfssl_path = get_libwolfssl_path()
get_libwolfssl()
# default values
OLDTLS_ENABLED = 0
@ -332,23 +325,13 @@ ffi_source = source + openssl.source
ffi = FFI()
if libwolfssl_path and libwolfssl_path.endswith(".a"):
# Static linking: pass the .a file directly via extra_objects
ffi.set_source(
"wolfssl._ffi",
ffi_source,
include_dirs=[wolfssl_inc_path()],
extra_objects=[libwolfssl_path],
)
else:
# Dynamic linking: use library_dirs + libraries
ffi.set_source(
"wolfssl._ffi",
ffi_source,
include_dirs=[wolfssl_inc_path()],
library_dirs=[wolfssl_lib_path()],
libraries=["wolfssl"],
)
ffi.set_source(
"wolfssl._ffi",
ffi_source,
include_dirs=[wolfssl_inc_path()],
library_dirs=[wolfssl_lib_path()],
libraries=["wolfssl"],
)
cdef = """
/*
@ -405,7 +388,7 @@ cdef = """
/*
* Debugging
*/
int wolfSSL_Debugging_ON(void);
void wolfSSL_Debugging_ON();
void wolfSSL_Debugging_OFF();
/*
@ -474,7 +457,7 @@ cdef += """
/*
* SSL/TLS Session functions
*/
int wolfSSL_Init(void);
void wolfSSL_Init();
WOLFSSL* wolfSSL_new(WOLFSSL_CTX*);
void wolfSSL_free(WOLFSSL*);
@ -502,7 +485,6 @@ cdef += """
void* wolfSSL_dtls_create_peer(int, char*);
int wolfSSL_dtls_free_peer(void*);
int wolfSSL_dtls_set_peer(WOLFSSL*, void*, unsigned int);
const char* wolfSSL_get_version(const WOLFSSL*);
/*
* WOLFSSL_X509 functions

View File

@ -2,13 +2,13 @@
#
# _methods.py
#
# Copyright (C) 2006-2026 wolfSSL Inc.
# Copyright (C) 2006-2022 wolfSSL Inc.
#
# This file is part of wolfSSL.
# 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 3 of the License, or
# 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,
@ -18,17 +18,15 @@
#
# 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-1335, USA
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
# pylint: disable=missing-docstring, invalid-name
try:
from wolfssl._ffi import lib as _lib
from wolfssl._ffi import ffi as _ffi
except ImportError as e:
from wolfssl.utils import _FFIPlaceholder
_ffi = _FFIPlaceholder(e)
_lib = _FFIPlaceholder(e)
except ImportError:
pass
PROTOCOL_SSLv23 = 1
@ -113,5 +111,5 @@ class WolfSSLMethod(object): # pylint: disable=too-few-public-methods
raise MemoryError("Cannot allocate method object")
def __del__(self):
if getattr(self, 'native_object', None) is not None and self.native_object != _ffi.NULL:
if getattr(self, 'native_object', _ffi.NULL) != _ffi.NULL:
_native_free(self.native_object, _DYNAMIC_TYPE_METHOD)

View File

@ -2,13 +2,13 @@
#
# _openssl.py
#
# Copyright (C) 2006-2026 wolfSSL Inc.
# Copyright (C) 2006-2022 wolfSSL Inc.
#
# This file is part of wolfSSL.
# 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 3 of the License, or
# 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,
@ -18,10 +18,9 @@
#
# 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-1335, USA
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
# pylint: disable=missing-docstring, invalid-name
import os
source = """
#include <wolfssl/options.h>
@ -249,6 +248,7 @@ def construct_cdef(optional_funcs, OLDTLS_ENABLED):
X509* SSL_get_peer_certificate(SSL*);
const char* SSL_alert_type_string_long(int);
const char* SSL_alert_desc_string_long(int);
int SSL_renegotiate(SSL*);
void SSL_get0_next_proto_negotiated(const SSL*,
const unsigned char**, unsigned*);
const char* SSL_get_servername(SSL*, unsigned char);
@ -306,13 +306,6 @@ def construct_cdef(optional_funcs, OLDTLS_ENABLED):
int OBJ_txt2nid(const char*);
"""
# defaults to None (that eval to False)
disable_scr = os.getenv("WOLFSSLPY_DISABLE_SCR")
if not disable_scr:
cdef += """
int SSL_renegotiate(SSL*);
"""
for func in optional_funcs:
cdef += "{};".format(func.ossl_sig)

View File

@ -1,6 +1,6 @@
# When bumping the C library version, reset the POST count to 0
__wolfssl_version__ = "v5.9.2-stable"
__wolfssl_version__ = "v5.6.6-stable"
# We're using implicit post releases [PEP 440] to bump package version
# while maintaining the C library version intact for better reference.
@ -8,4 +8,4 @@ __wolfssl_version__ = "v5.9.2-stable"
#
# MAJOR.MINOR.BUILD-POST
__version__ = "5.9.2-0"
__version__ = "5.6.6-0"

View File

@ -2,13 +2,13 @@
#
# exceptions.py
#
# Copyright (C) 2006-2026 wolfSSL Inc.
# Copyright (C) 2006-2022 wolfSSL Inc.
#
# This file is part of wolfSSL.
# 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 3 of the License, or
# 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,
@ -18,7 +18,7 @@
#
# 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-1335, USA
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
# pylint: disable=missing-docstring

View File

@ -2,13 +2,13 @@
#
# utils.py
#
# Copyright (C) 2006-2026 wolfSSL Inc.
# Copyright (C) 2006-2022 wolfSSL Inc.
#
# This file is part of wolfSSL.
# 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 3 of the License, or
# 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,
@ -18,7 +18,7 @@
#
# 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-1335, USA
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
# pylint: disable=missing-docstring, unused-import, undefined-variable
@ -30,19 +30,6 @@ _TEXT_TYPE = str if _PY3 else unicode # noqa: F821
_BINARY_TYPE = bytes if _PY3 else str
class _FFIPlaceholder:
def __init__(self, cause=None):
object.__setattr__(self, '_cause', cause)
def __getattr__(self, name):
raise ImportError(
"wolfssl._ffi is not available. The CFFI bindings have not been "
"compiled. If you installed wolfssl via pip, the build may have "
"failed silently. Try reinstalling with: "
"pip install --no-binary wolfssl wolfssl"
) from self._cause
def t2b(string):
"""
Converts text to binary.