Merge pull request #683 from moisesguimaraes/wolfssl-py
wolfssl python wrapper
This commit is contained in:
commit
667b8431cc
23
certs/external/ca-digicert-ev.pem
vendored
Normal file
23
certs/external/ca-digicert-ev.pem
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBs
|
||||
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
|
||||
d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j
|
||||
ZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAwMFoXDTMxMTExMDAwMDAwMFowbDEL
|
||||
MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3
|
||||
LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFuY2Ug
|
||||
RVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm
|
||||
+9S75S0tMqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTW
|
||||
PNt0OKRKzE0lgvdKpVMSOO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEM
|
||||
xChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFB
|
||||
Ik5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQNAQTXKFx01p8VdteZOE3
|
||||
hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUeh10aUAsg
|
||||
EsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQF
|
||||
MAMBAf8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaA
|
||||
FLE+w2kD+L9HAdSYJhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3Nec
|
||||
nzyIZgYIVyHbIUf4KmeqvxgydkAQV8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6z
|
||||
eM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFpmyPInngiK3BD41VHMWEZ71jF
|
||||
hS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkKmNEVX58Svnw2
|
||||
Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe
|
||||
vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep
|
||||
+OkuE6N36B9K
|
||||
-----END CERTIFICATE-----
|
@ -3,6 +3,7 @@
|
||||
# All paths should be given relative to the root
|
||||
|
||||
include wrapper/python/wolfcrypt/include.am
|
||||
include wrapper/python/wolfssl/include.am
|
||||
|
||||
# wolfSSL CSharp wrapper files
|
||||
EXTRA_DIST+= wrapper/CSharp/wolfSSL-DTLS-PSK-Server/App.config
|
||||
|
3
wrapper/python/wolfcrypt/.gitignore
vendored
3
wrapper/python/wolfcrypt/.gitignore
vendored
@ -13,3 +13,6 @@ dist/
|
||||
.tox/
|
||||
# Sphinx documentation
|
||||
docs/_build/
|
||||
|
||||
# Virtual env
|
||||
.env
|
||||
|
@ -17,22 +17,20 @@
|
||||
# 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
|
||||
|
||||
# pylint: disable=unused-import, undefined-variable
|
||||
|
||||
import sys
|
||||
from binascii import hexlify as b2h, unhexlify as h2b
|
||||
|
||||
_PY3 = sys.version_info[0] == 3
|
||||
_TEXT_TYPE = str if _PY3 else unicode
|
||||
_BINARY_TYPE = bytes if _PY3 else str
|
||||
|
||||
if sys.version_info[0] == 3:
|
||||
_text_type = str
|
||||
_binary_type = bytes
|
||||
else:
|
||||
_text_type = unicode
|
||||
_binary_type = str
|
||||
|
||||
|
||||
def t2b(s):
|
||||
def t2b(string):
|
||||
"""
|
||||
Converts text to bynary.
|
||||
"""
|
||||
if isinstance(s, _binary_type):
|
||||
return s
|
||||
return _text_type(s).encode("utf-8")
|
||||
if isinstance(string, _BINARY_TYPE):
|
||||
return string
|
||||
return _TEXT_TYPE(string).encode("utf-8")
|
||||
|
38
wrapper/python/wolfssl/.centos-provisioner.sh
Normal file
38
wrapper/python/wolfssl/.centos-provisioner.sh
Normal file
@ -0,0 +1,38 @@
|
||||
[ "$(whoami)" != "root" ] && echo "Sorry, you are not root." && exit 1
|
||||
|
||||
rpm -ivh http://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm
|
||||
|
||||
yum install -y \
|
||||
git autoconf libtool libffi-devel python-devel python34-devel python2-pip
|
||||
|
||||
pip install -U pip setuptools
|
||||
|
||||
git clone --depth 1 https://github.com/wolfssl/wolfssl.git
|
||||
[ $? -ne 0 ] && echo "\n\nCouldn't download wolfssl.\n\n" && exit 1
|
||||
|
||||
pushd wolfssl
|
||||
|
||||
./autogen.sh
|
||||
./configure
|
||||
make
|
||||
make install
|
||||
echo /usr/local/lib > wolfssl.conf
|
||||
mv wolfssl.conf /etc/ld.so.conf
|
||||
ldconfig
|
||||
|
||||
popd
|
||||
|
||||
rm -rf wolfssl
|
||||
|
||||
pushd /vagrant
|
||||
|
||||
pip install -r requirements-testing.txt
|
||||
|
||||
make clean
|
||||
|
||||
tox -epy27,py34 -- -v
|
||||
|
||||
popd
|
||||
|
||||
# pip install wolfssl
|
||||
# [ $? -ne 0 ] && echo "\n\nCouldn't install wolfssl.\n\n" && exit 1
|
21
wrapper/python/wolfssl/.gitignore
vendored
Normal file
21
wrapper/python/wolfssl/.gitignore
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
# Byte-compiled / optimized / DLL files
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
|
||||
# Distribution
|
||||
build/
|
||||
dist/
|
||||
.eggs/
|
||||
*.egg-info/
|
||||
|
||||
# Unit test
|
||||
.tox/
|
||||
htmlcov/
|
||||
.coverage
|
||||
|
||||
# Sphinx documentation
|
||||
docs/_build/
|
||||
|
||||
# Certificates
|
||||
certs/
|
36
wrapper/python/wolfssl/.ubuntu-provisioner.sh
Normal file
36
wrapper/python/wolfssl/.ubuntu-provisioner.sh
Normal file
@ -0,0 +1,36 @@
|
||||
[ "$(whoami)" != "root" ] && echo "Sorry, you are not root." && exit 1
|
||||
|
||||
apt-get update
|
||||
|
||||
apt-get install -y \
|
||||
git autoconf libtool python-dev python3-dev python-pip libffi-dev
|
||||
|
||||
pip install -U pip setuptools
|
||||
|
||||
git clone --depth 1 https://github.com/wolfssl/wolfssl.git
|
||||
[ $? -ne 0 ] && echo "\n\nCouldn't download wolfssl.\n\n" && exit 1
|
||||
|
||||
pushd wolfssl
|
||||
|
||||
./autogen.sh
|
||||
./configure
|
||||
make
|
||||
make install
|
||||
ldconfig
|
||||
|
||||
popd
|
||||
|
||||
rm -rf wolfssl
|
||||
|
||||
pushd /vagrant
|
||||
|
||||
pip install -r requirements-testing.txt
|
||||
|
||||
make clean
|
||||
|
||||
tox -epy27,py34 -- -v
|
||||
|
||||
popd
|
||||
|
||||
# pip install wolfssl
|
||||
# [ $? -ne 0 ] && echo -e "\n\nCouldn't install wolfssl.\n\n" && exit 1
|
23
wrapper/python/wolfssl/LICENSING.rst
Normal file
23
wrapper/python/wolfssl/LICENSING.rst
Normal file
@ -0,0 +1,23 @@
|
||||
Licensing
|
||||
=========
|
||||
|
||||
wolfSSL’s software is available under two distinct licensing models:
|
||||
open source and standard commercial licensing. Please see the relevant
|
||||
section below for information on each type of license.
|
||||
|
||||
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 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
|
||||
--------------------
|
||||
|
||||
Businesses and enterprises who wish to incorporate wolfSSL products into
|
||||
proprietary appliances or other commercial software products for
|
||||
re-distribution must license commercial versions. Licenses are generally
|
||||
issued for one product and include unlimited royalty-free distribution.
|
||||
Custom licensing terms are also available at licensing@wolfssl.com.
|
2
wrapper/python/wolfssl/MANIFEST.in
Normal file
2
wrapper/python/wolfssl/MANIFEST.in
Normal file
@ -0,0 +1,2 @@
|
||||
include LICENSING.rst
|
||||
recursive-include certs *.pem
|
58
wrapper/python/wolfssl/Makefile
Normal file
58
wrapper/python/wolfssl/Makefile
Normal file
@ -0,0 +1,58 @@
|
||||
# Makefile
|
||||
#
|
||||
# Copyright (C) 2006-2017 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
|
||||
|
||||
.PHONY : all clean clean-test clean-build clean-pyc install test check upload
|
||||
|
||||
# builds the module
|
||||
all :
|
||||
python ./setup.py build
|
||||
|
||||
#builds and installs the module
|
||||
install : all
|
||||
python ./setup.py install
|
||||
|
||||
## removes all build, test, coverage and Python artifacts
|
||||
clean : clean-test clean-build clean-pyc
|
||||
|
||||
## removes test and coverage artifacts
|
||||
clean-test :
|
||||
rm -rf .coverage .tox/ htmlcov/
|
||||
|
||||
## removes build artifacts
|
||||
clean-build :
|
||||
rm -rf build/ dist/ .eggs/
|
||||
find . -name '*.egg-info' -exec rm -rf {} +
|
||||
find . -name '*.egg' -exec rm -v {} +
|
||||
|
||||
## removes Python file artifacts
|
||||
clean-pyc :
|
||||
find src test -name '__pycache__' -exec rm -rf {} +
|
||||
find src test -name '*.pyc' -exec rm -f {} +
|
||||
find src test -name '*.pyo' -exec rm -f {} +
|
||||
|
||||
# runs unit tests
|
||||
check : test
|
||||
|
||||
test : clean-pyc
|
||||
tox
|
||||
|
||||
# publishes module at pypi
|
||||
upload : test
|
||||
python ./setup.py sdist upload
|
96
wrapper/python/wolfssl/README.rst
Normal file
96
wrapper/python/wolfssl/README.rst
Normal file
@ -0,0 +1,96 @@
|
||||
Welcome
|
||||
=======
|
||||
|
||||
``wolfssl Python`` is a Python module that encapsulates ``wolfssl C``, a `lightweight C-language-based SSL/TLS library <https://wolfssl.com/wolfSSL/Products-wolfssl.html>`_ targeted for embedded, RTOS, or
|
||||
resource-constrained environments primarily because of its small size, speed,
|
||||
and portability.
|
||||
|
||||
Installation
|
||||
============
|
||||
|
||||
In order to use ``wolfssl Python``, you'll also need to install ``wolfssl C``.
|
||||
|
||||
Mac OSX
|
||||
-------
|
||||
|
||||
Installing from ``homebrew`` and ``pip`` package managers:
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
# wolfssl C installation
|
||||
brew install wolfssl
|
||||
|
||||
# wolfssl Python installation
|
||||
sudo -H pip install wolfssl
|
||||
|
||||
Installing from ``source code``:
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
# wolfssl C installation
|
||||
git clone https://github.com/wolfssl/wolfssl.git
|
||||
cd wolfssl/
|
||||
./autogen.sh
|
||||
./configure --enable-sha512
|
||||
make
|
||||
sudo make install
|
||||
|
||||
# wolfssl Python installation
|
||||
cd wrapper/python/wolfssl
|
||||
sudo make install
|
||||
|
||||
|
||||
Linux
|
||||
-----
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
# dependencies installation
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y git autoconf libtool
|
||||
sudo apt-get install -y python-dev python3-dev python-pip libffi-dev
|
||||
|
||||
# wolfssl C installation
|
||||
git clone https://github.com/wolfssl/wolfssl.git
|
||||
cd wolfssl/
|
||||
./autogen.sh
|
||||
./configure --enable-sha512
|
||||
make
|
||||
sudo make install
|
||||
|
||||
sudo ldconfig
|
||||
|
||||
# wolfssl Python installation
|
||||
sudo -H pip install wolfssl
|
||||
|
||||
|
||||
Testing
|
||||
=======
|
||||
|
||||
To run the tox tests in the source code, you'll need ``tox`` and a few other
|
||||
requirements. The source code relies at **WOLFSSL_DIR/wrapper/python/wolfssl**
|
||||
where **WOLFSSL_DIR** is the path of ``wolfssl C``'s source code.
|
||||
|
||||
1. Make sure that the testing requirements are installed:
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
sudo -H pip install -r requirements-testing.txt
|
||||
|
||||
|
||||
2. Run ``make check``:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ make check
|
||||
...
|
||||
_________________________________ summary _________________________________
|
||||
py27: commands succeeded
|
||||
SKIPPED: py34: InterpreterNotFound: python3.4
|
||||
py35: commands succeeded
|
||||
py36: commands succeeded
|
||||
congratulations :)
|
||||
|
||||
Note: the test is performed using multiple versions of python. If you are
|
||||
missing a version the test will be skipped with an **InterpreterNotFound
|
||||
error**.
|
17
wrapper/python/wolfssl/Vagrantfile
vendored
Normal file
17
wrapper/python/wolfssl/Vagrantfile
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
# -*- mode: ruby -*-
|
||||
# vi: set ft=ruby :
|
||||
VAGRANTFILE_API_VERSION = "2"
|
||||
|
||||
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
|
||||
|
||||
config.vm.define "default" do |default|
|
||||
default.vm.box = "ubuntu/trusty64"
|
||||
default.vm.provision "shell", path: ".ubuntu-provisioner.sh"
|
||||
end
|
||||
|
||||
config.vm.define "centos", autostart: false do |centos|
|
||||
centos.vm.box = "moisesguimaraes/centos72-64"
|
||||
centos.vm.provision "shell", path: ".centos-provisioner.sh"
|
||||
end
|
||||
|
||||
end
|
59
wrapper/python/wolfssl/docs/Makefile
Normal file
59
wrapper/python/wolfssl/docs/Makefile
Normal file
@ -0,0 +1,59 @@
|
||||
# Makefile
|
||||
#
|
||||
# Copyright (C) 2006-2017 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
|
||||
|
||||
.PHONY : all clean html pdf man
|
||||
|
||||
# You can set these variables from the command line.
|
||||
SPHINXOPTS =
|
||||
SPHINXBUILD = sphinx-build
|
||||
PAPER = a4
|
||||
BUILDDIR = _build
|
||||
|
||||
# Internal variables.
|
||||
PAPEROPT_a4 = -D latex_paper_size=a4
|
||||
PAPEROPT_letter = -D latex_paper_size=letter
|
||||
ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
|
||||
|
||||
all:
|
||||
@echo "Please use \`make <target>' where <target> is one of"
|
||||
@echo " html to make a single large HTML file"
|
||||
@echo " pdf to make LaTeX files and run them through pdflatex"
|
||||
@echo " man to make manual pages"
|
||||
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
|
||||
@echo " coverage to run coverage check of the documentation (if enabled)"
|
||||
|
||||
clean:
|
||||
rm -rf $(BUILDDIR)/*
|
||||
|
||||
html:
|
||||
$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
|
||||
@echo
|
||||
@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
|
||||
|
||||
pdf:
|
||||
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
|
||||
@echo "Running LaTeX files through pdflatex..."
|
||||
$(MAKE) -C $(BUILDDIR)/latex all-pdf
|
||||
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
|
||||
|
||||
man:
|
||||
$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
|
||||
@echo
|
||||
@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
|
21
wrapper/python/wolfssl/docs/api.rst
Normal file
21
wrapper/python/wolfssl/docs/api.rst
Normal file
@ -0,0 +1,21 @@
|
||||
API Documentation
|
||||
=================
|
||||
|
||||
.. module:: wolfssl
|
||||
|
||||
wrap_socket
|
||||
-----------
|
||||
|
||||
.. autofunction:: wrap_socket
|
||||
|
||||
SSL/TLS Context
|
||||
---------------
|
||||
|
||||
.. autoclass:: SSLContext
|
||||
:members:
|
||||
|
||||
SSL/TLS Socket
|
||||
--------------
|
||||
|
||||
.. autoclass:: SSLSocket
|
||||
:members:
|
300
wrapper/python/wolfssl/docs/conf.py
Normal file
300
wrapper/python/wolfssl/docs/conf.py
Normal file
@ -0,0 +1,300 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# wolfcrypt documentation build configuration file, created by
|
||||
# sphinx-quickstart on Fri Apr 29 16:47:53 2016.
|
||||
#
|
||||
# This file is execfile()d with the current directory set to its
|
||||
# containing dir.
|
||||
#
|
||||
# Note that not all possible configuration values are present in this
|
||||
# autogenerated file.
|
||||
#
|
||||
# All configuration values have a default; values that are commented out
|
||||
# serve to show the default.
|
||||
|
||||
# pylint: disable=invalid-name, redefined-builtin, exec-used
|
||||
|
||||
import os
|
||||
import sphinx_rtd_theme
|
||||
|
||||
# If extensions (or modules to document with autodoc) are in another directory,
|
||||
# add these directories to sys.path here. If the directory is relative to the
|
||||
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||
#sys.path.insert(0, os.path.abspath('.'))
|
||||
|
||||
# -- General configuration ------------------------------------------------
|
||||
|
||||
# If your documentation needs a minimal Sphinx version, state it here.
|
||||
#needs_sphinx = '1.0'
|
||||
|
||||
# Add any Sphinx extension module names here, as strings. They can be
|
||||
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
||||
# ones.
|
||||
extensions = [
|
||||
'sphinx.ext.autodoc',
|
||||
'sphinx.ext.doctest',
|
||||
'sphinx.ext.coverage',
|
||||
'sphinx.ext.viewcode',
|
||||
'sphinx.ext.githubpages',
|
||||
]
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
templates_path = ['_templates']
|
||||
|
||||
# The suffix(es) of source filenames.
|
||||
# You can specify multiple suffix as a list of string:
|
||||
# source_suffix = ['.rst', '.md']
|
||||
source_suffix = '.rst'
|
||||
|
||||
# The encoding of source files.
|
||||
#source_encoding = 'utf-8-sig'
|
||||
|
||||
# The master toctree document.
|
||||
master_doc = 'index'
|
||||
|
||||
# General information about the project.
|
||||
project = u'wolfssl Python'
|
||||
copyright = u'2017, wolfSSL Inc. All rights reserved'
|
||||
author = u'wolfSSL'
|
||||
|
||||
# The version info for the project you're documenting, acts as replacement for
|
||||
# |version| and |release|, also used in various other places throughout the
|
||||
# built documents.
|
||||
#
|
||||
|
||||
base_dir = os.path.join(os.path.dirname(__file__), os.pardir, "src")
|
||||
about = {}
|
||||
with open(os.path.join(base_dir, "wolfssl", "__about__.py")) as f:
|
||||
exec(f.read(), about)
|
||||
|
||||
version = release = about["__version__"]
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
#
|
||||
# This is also used if you do content translation via gettext catalogs.
|
||||
# Usually you set "language" from the command line for these cases.
|
||||
language = None
|
||||
|
||||
# There are two options for replacing |today|: either, you set today to some
|
||||
# non-false value, then it is used:
|
||||
#today = ''
|
||||
# Else, today_fmt is used as the format for a strftime call.
|
||||
#today_fmt = '%B %d, %Y'
|
||||
|
||||
# List of patterns, relative to source directory, that match files and
|
||||
# directories to ignore when looking for source files.
|
||||
# This patterns also effect to html_static_path and html_extra_path
|
||||
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
|
||||
|
||||
# The reST default role (used for this markup: `text`) to use for all
|
||||
# documents.
|
||||
#default_role = None
|
||||
|
||||
# If true, '()' will be appended to :func: etc. cross-reference text.
|
||||
#add_function_parentheses = True
|
||||
|
||||
# If true, the current module name will be prepended to all description
|
||||
# unit titles (such as .. function::).
|
||||
#add_module_names = True
|
||||
|
||||
# If true, sectionauthor and moduleauthor directives will be shown in the
|
||||
# output. They are ignored by default.
|
||||
#show_authors = False
|
||||
|
||||
# The name of the Pygments (syntax highlighting) style to use.
|
||||
pygments_style = 'sphinx'
|
||||
|
||||
# A list of ignored prefixes for module index sorting.
|
||||
#modindex_common_prefix = []
|
||||
|
||||
# If true, keep warnings as "system message" paragraphs in the built documents.
|
||||
#keep_warnings = False
|
||||
|
||||
# If true, `todo` and `todoList` produce output, else they produce nothing.
|
||||
todo_include_todos = False
|
||||
|
||||
|
||||
# -- Options for HTML output ----------------------------------------------
|
||||
|
||||
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||
# a list of builtin themes.
|
||||
html_theme = 'sphinx_rtd_theme'
|
||||
|
||||
# Theme options are theme-specific and customize the look and feel of a theme
|
||||
# further. For a list of options available for each theme, see the
|
||||
# documentation.
|
||||
#html_theme_options = {}
|
||||
|
||||
# Add any paths that contain custom themes here, relative to this directory.
|
||||
html_theme_path = [sphinx_rtd_theme.get_html_theme_path()]
|
||||
|
||||
# The name for this set of Sphinx documents.
|
||||
# "<project> v<release> documentation" by default.
|
||||
#html_title = u'%s v%s' % (project, release)
|
||||
|
||||
# A shorter title for the navigation bar. Default is the same as html_title.
|
||||
#html_short_title = None
|
||||
|
||||
# The name of an image file (relative to this directory) to place at the top
|
||||
# of the sidebar.
|
||||
#html_logo = None
|
||||
|
||||
# The name of an image file (relative to this directory) to use as a favicon of
|
||||
# the docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
|
||||
# pixels large.
|
||||
#html_favicon = None
|
||||
|
||||
# Add any paths that contain custom static files (such as style sheets) here,
|
||||
# relative to this directory. They are copied after the builtin static files,
|
||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||
html_static_path = ['_static']
|
||||
|
||||
# Add any extra paths that contain custom files (such as robots.txt or
|
||||
# .htaccess) here, relative to this directory. These files are copied
|
||||
# directly to the root of the documentation.
|
||||
#html_extra_path = []
|
||||
|
||||
# If not None, a 'Last updated on:' timestamp is inserted at every page
|
||||
# bottom, using the given strftime format.
|
||||
# The empty string is equivalent to '%b %d, %Y'.
|
||||
#html_last_updated_fmt = None
|
||||
|
||||
# If true, SmartyPants will be used to convert quotes and dashes to
|
||||
# typographically correct entities.
|
||||
#html_use_smartypants = True
|
||||
|
||||
# Custom sidebar templates, maps document names to template names.
|
||||
#html_sidebars = {}
|
||||
|
||||
# Additional templates that should be rendered to pages, maps page names to
|
||||
# template names.
|
||||
#html_additional_pages = {}
|
||||
|
||||
# If false, no module index is generated.
|
||||
#html_domain_indices = True
|
||||
|
||||
# If false, no index is generated.
|
||||
#html_use_index = True
|
||||
|
||||
# If true, the index is split into individual pages for each letter.
|
||||
#html_split_index = False
|
||||
|
||||
# If true, links to the reST sources are added to the pages.
|
||||
#html_show_sourcelink = True
|
||||
|
||||
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
|
||||
#html_show_sphinx = True
|
||||
|
||||
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
|
||||
#html_show_copyright = True
|
||||
|
||||
# If true, an OpenSearch description file will be output, and all pages will
|
||||
# contain a <link> tag referring to it. The value of this option must be the
|
||||
# base URL from which the finished HTML is served.
|
||||
#html_use_opensearch = ''
|
||||
|
||||
# This is the file name suffix for HTML files (e.g. ".xhtml").
|
||||
#html_file_suffix = None
|
||||
|
||||
# Language to be used for generating the HTML full-text search index.
|
||||
# Sphinx supports the following languages:
|
||||
# 'da', 'de', 'en', 'es', 'fi', 'fr', 'hu', 'it', 'ja'
|
||||
# 'nl', 'no', 'pt', 'ro', 'ru', 'sv', 'tr', 'zh'
|
||||
#html_search_language = 'en'
|
||||
|
||||
# A dictionary with options for the search language support, empty by default.
|
||||
# 'ja' uses this config value.
|
||||
# 'zh' user can custom change `jieba` dictionary path.
|
||||
#html_search_options = {'type': 'default'}
|
||||
|
||||
# The name of a javascript file (relative to the configuration directory) that
|
||||
# implements a search results scorer. If empty, the default will be used.
|
||||
#html_search_scorer = 'scorer.js'
|
||||
|
||||
# Output file base name for HTML help builder.
|
||||
htmlhelp_basename = 'wolfssl-pydoc'
|
||||
|
||||
# -- Options for LaTeX output ---------------------------------------------
|
||||
|
||||
latex_elements = {
|
||||
# The paper size ('letterpaper' or 'a4paper').
|
||||
#'papersize': 'letterpaper',
|
||||
|
||||
# The font size ('10pt', '11pt' or '12pt').
|
||||
#'pointsize': '10pt',
|
||||
|
||||
# Additional stuff for the LaTeX preamble.
|
||||
#'preamble': '',
|
||||
|
||||
# Latex figure (float) alignment
|
||||
#'figure_align': 'htbp',
|
||||
}
|
||||
|
||||
# Grouping the document tree into LaTeX files. List of tuples
|
||||
# (source start file, target name, title,
|
||||
# author, documentclass [howto, manual, or own class]).
|
||||
latex_documents = [
|
||||
(master_doc, 'wolfssl.tex', u'wolfssl Python Documentation',
|
||||
u'wolfSSL', 'manual'),
|
||||
]
|
||||
|
||||
# The name of an image file (relative to this directory) to place at the top of
|
||||
# the title page.
|
||||
#latex_logo = None
|
||||
|
||||
# For "manual" documents, if this is true, then toplevel headings are parts,
|
||||
# not chapters.
|
||||
#latex_use_parts = False
|
||||
|
||||
# If true, show page references after internal links.
|
||||
#latex_show_pagerefs = False
|
||||
|
||||
# If true, show URL addresses after external links.
|
||||
#latex_show_urls = False
|
||||
|
||||
# Documents to append as an appendix to all manuals.
|
||||
#latex_appendices = []
|
||||
|
||||
# If false, no module index is generated.
|
||||
#latex_domain_indices = True
|
||||
|
||||
|
||||
# -- Options for manual page output ---------------------------------------
|
||||
|
||||
# One entry per manual page. List of tuples
|
||||
# (source start file, name, description, authors, manual section).
|
||||
man_pages = [
|
||||
(master_doc, 'wolfssl', u'wolfssl Python Documentation',
|
||||
[author], 1)
|
||||
]
|
||||
|
||||
# If true, show URL addresses after external links.
|
||||
#man_show_urls = False
|
||||
|
||||
|
||||
# -- Options for Texinfo output -------------------------------------------
|
||||
|
||||
# Grouping the document tree into Texinfo files. List of tuples
|
||||
# (source start file, target name, title, author,
|
||||
# dir menu entry, description, category)
|
||||
texinfo_documents = [
|
||||
(master_doc, 'wolfssl', u'wolfssl Python Documentation',
|
||||
author, 'wolfssl', 'One line description of project.',
|
||||
'Miscellaneous'),
|
||||
]
|
||||
|
||||
# Documents to append as an appendix to all manuals.
|
||||
#texinfo_appendices = []
|
||||
|
||||
# If false, no module index is generated.
|
||||
#texinfo_domain_indices = True
|
||||
|
||||
# How to display URL addresses: 'footnote', 'no', or 'inline'.
|
||||
#texinfo_show_urls = 'footnote'
|
||||
|
||||
# If true, do not generate a @detailmenu in the "Top" node's menu.
|
||||
#texinfo_no_detailmenu = False
|
||||
|
||||
# Preserves the order of the members, doesn't sorts them alphabetically.
|
||||
autodoc_member_order = 'bysource'
|
95
wrapper/python/wolfssl/docs/examples.rst
Normal file
95
wrapper/python/wolfssl/docs/examples.rst
Normal file
@ -0,0 +1,95 @@
|
||||
Client and Server Examples
|
||||
==========================
|
||||
|
||||
SSL/TLS Client Example
|
||||
----------------------
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import socket
|
||||
import wolfssl
|
||||
|
||||
CA_DATA = \
|
||||
"""
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBs
|
||||
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
|
||||
d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j
|
||||
ZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAwMFoXDTMxMTExMDAwMDAwMFowbDEL
|
||||
MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3
|
||||
LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFuY2Ug
|
||||
RVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm
|
||||
+9S75S0tMqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTW
|
||||
PNt0OKRKzE0lgvdKpVMSOO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEM
|
||||
xChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFB
|
||||
Ik5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQNAQTXKFx01p8VdteZOE3
|
||||
hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUeh10aUAsg
|
||||
EsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQF
|
||||
MAMBAf8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaA
|
||||
FLE+w2kD+L9HAdSYJhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3Nec
|
||||
nzyIZgYIVyHbIUf4KmeqvxgydkAQV8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6z
|
||||
eM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFpmyPInngiK3BD41VHMWEZ71jF
|
||||
hS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkKmNEVX58Svnw2
|
||||
Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe
|
||||
vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep
|
||||
+OkuE6N36B9K
|
||||
-----END CERTIFICATE-----
|
||||
"""
|
||||
|
||||
bind_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
|
||||
|
||||
context = wolfssl.SSLContext(wolfssl.PROTOCOL_TLSv1_2)
|
||||
|
||||
context.verify_mode = wolfssl.CERT_REQUIRED
|
||||
context.load_verify_locations(cadata=CA_DATA)
|
||||
|
||||
secure_socket = context.wrap_socket(bind_socket)
|
||||
|
||||
secure_socket.connect(("www.python.org", 443))
|
||||
|
||||
secure_socket.write(b"GET / HTTP/1.1\n\n")
|
||||
|
||||
print(secure_socket.read())
|
||||
|
||||
secure_socket.close()
|
||||
|
||||
|
||||
SSL/TLS Server Example
|
||||
----------------------
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import socket
|
||||
import wolfssl
|
||||
|
||||
bind_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
|
||||
|
||||
bind_socket.bind(("", 4433))
|
||||
bind_socket.listen(5)
|
||||
|
||||
context = wolfssl.SSLContext(wolfssl.PROTOCOL_TLSv1_2, server_side=True)
|
||||
|
||||
context.load_cert_chain("certs/server-cert.pem", "certs/server-key.pem")
|
||||
|
||||
while True:
|
||||
try:
|
||||
secure_socket = None
|
||||
|
||||
new_socket, from_addr = bind_socket.accept()
|
||||
|
||||
secure_socket = context.wrap_socket(new_socket)
|
||||
|
||||
print("Connection received from", from_addr)
|
||||
|
||||
print("\n", secure_socket.read(), "\n")
|
||||
secure_socket.write(b"I hear you fa shizzle!")
|
||||
|
||||
except KeyboardInterrupt:
|
||||
print()
|
||||
break
|
||||
|
||||
finally:
|
||||
if secure_socket:
|
||||
secure_socket.close()
|
||||
|
||||
bind_socket.close()
|
8
wrapper/python/wolfssl/docs/index.rst
Normal file
8
wrapper/python/wolfssl/docs/index.rst
Normal file
@ -0,0 +1,8 @@
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
installation
|
||||
usage
|
||||
api
|
||||
examples
|
||||
licensing
|
1
wrapper/python/wolfssl/docs/installation.rst
Normal file
1
wrapper/python/wolfssl/docs/installation.rst
Normal file
@ -0,0 +1 @@
|
||||
.. include:: ../README.rst
|
1
wrapper/python/wolfssl/docs/licensing.rst
Normal file
1
wrapper/python/wolfssl/docs/licensing.rst
Normal file
@ -0,0 +1 @@
|
||||
.. include:: ../LICENSING.rst
|
2
wrapper/python/wolfssl/docs/requirements.txt
Normal file
2
wrapper/python/wolfssl/docs/requirements.txt
Normal file
@ -0,0 +1,2 @@
|
||||
Sphinx
|
||||
sphinx_rtd_theme
|
87
wrapper/python/wolfssl/docs/usage.rst
Normal file
87
wrapper/python/wolfssl/docs/usage.rst
Normal file
@ -0,0 +1,87 @@
|
||||
Basic Usage
|
||||
===========
|
||||
|
||||
The SSL/TLS protocol works securing an underlying TCP connection, this module
|
||||
adds the secure layer around the Python standard library
|
||||
`socket <https://docs.python.org/3.6/library/socket.html>`_ module.
|
||||
|
||||
There are three different paths to secure a socket in this module:
|
||||
|
||||
* Using the top level function wolfssl.wrap_socket();
|
||||
* Using the method wrap_socket() from a SSLContext instance;
|
||||
* Creating an SSLSocket object from the scratch.
|
||||
|
||||
Note 1:
|
||||
It is possible to use the same SSLContext for multiple SSLSockets to save
|
||||
time and resources.
|
||||
|
||||
Note 2:
|
||||
Each path provides its own options for fine-tuning the securint parameters.
|
||||
Check them out in the API documentation.
|
||||
|
||||
|
||||
Using the top level function wolfssl.wrap_socket()
|
||||
--------------------------------------------------
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> import socket
|
||||
>>> import wolfssl
|
||||
>>>
|
||||
>>> sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
|
||||
>>>
|
||||
>>> secure_socket = wolfssl.wrap_socket(sock)
|
||||
>>>
|
||||
>>> secure_socket.connect(("www.python.org", 443))
|
||||
>>>
|
||||
>>> secure_socket.write(b"GET / HTTP/1.1\n\n")
|
||||
>>>
|
||||
>>> print(secure_socket.read())
|
||||
b'HTTP/1.1 500 Domain Not Found\r\nServer: Varnish\r\nRetry-After: 0\r\ncontent-type: text/html\r\nCache-Control: private, no-cache\r\nconnection: keep-alive\r\nContent-Length: 179\r\nAccept-Ranges: bytes\r\nDate: Sun, 05 Feb 2017 21:26:48 GMT\r\nVia: 1.1 varnish\r\nConnection: keep-alive\r\n\r\n\n<html>\n<head>\n<title>Fastly error: unknown domain </title>\n</head>\n<body>\nFastly error: unknown domain: . Please check that this domain has been added to a service.</body></html>'
|
||||
>>>
|
||||
>>> secure_socket.close()
|
||||
|
||||
|
||||
Using the method wrap_socket() from a SSLContext instance
|
||||
---------------------------------------------------------
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> import socket
|
||||
>>> import wolfssl
|
||||
>>>
|
||||
>>> sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
|
||||
>>>
|
||||
>>> context = wolfssl.SSLContext(wolfssl.PROTOCOL_TLSv1_2)
|
||||
>>>
|
||||
>>> secure_socket = context.wrap_socket(sock)
|
||||
>>>
|
||||
>>> secure_socket.connect(("www.python.org", 443))
|
||||
>>>
|
||||
>>> secure_socket.write(b"GET / HTTP/1.1\n\n")
|
||||
>>>
|
||||
>>> print(secure_socket.read())
|
||||
b'HTTP/1.1 500 Domain Not Found\r\nServer: Varnish\r\nRetry-After: 0\r\ncontent-type: text/html\r\nCache-Control: private, no-cache\r\nconnection: keep-alive\r\nContent-Length: 179\r\nAccept-Ranges: bytes\r\nDate: Sun, 05 Feb 2017 21:26:48 GMT\r\nVia: 1.1 varnish\r\nConnection: keep-alive\r\n\r\n\n<html>\n<head>\n<title>Fastly error: unknown domain </title>\n</head>\n<body>\nFastly error: unknown domain: . Please check that this domain has been added to a service.</body></html>'
|
||||
>>>
|
||||
>>> secure_socket.close()
|
||||
|
||||
Creating an SSLSocket object from the scratch
|
||||
---------------------------------------------
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> import socket
|
||||
>>> import wolfssl
|
||||
>>>
|
||||
>>> sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
|
||||
>>>
|
||||
>>> secure_socket = wolfssl.SSLSocket(sock)
|
||||
>>>
|
||||
>>> secure_socket.connect(("www.python.org", 443))
|
||||
>>>
|
||||
>>> secure_socket.write(b"GET / HTTP/1.1\n\n")
|
||||
>>>
|
||||
>>> print(secure_socket.read())
|
||||
b'HTTP/1.1 500 Domain Not Found\r\nServer: Varnish\r\nRetry-After: 0\r\ncontent-type: text/html\r\nCache-Control: private, no-cache\r\nconnection: keep-alive\r\nContent-Length: 179\r\nAccept-Ranges: bytes\r\nDate: Sun, 05 Feb 2017 21:26:48 GMT\r\nVia: 1.1 varnish\r\nConnection: keep-alive\r\n\r\n\n<html>\n<head>\n<title>Fastly error: unknown domain </title>\n</head>\n<body>\nFastly error: unknown domain: . Please check that this domain has been added to a service.</body></html>'
|
||||
>>>
|
||||
>>> secure_socket.close()
|
140
wrapper/python/wolfssl/examples/client.py
Executable file
140
wrapper/python/wolfssl/examples/client.py
Executable file
@ -0,0 +1,140 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# client.py
|
||||
#
|
||||
# Copyright (C) 2006-2017 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
|
||||
|
||||
# pylint: disable=missing-docstring, invalid-name, import-error
|
||||
|
||||
import sys
|
||||
import socket
|
||||
import argparse
|
||||
|
||||
try:
|
||||
import wolfssl
|
||||
except ImportError:
|
||||
print("You must run 'python setup.py install' to use the examples")
|
||||
sys.exit()
|
||||
|
||||
def build_arg_parser():
|
||||
parser = argparse.ArgumentParser(add_help=False)
|
||||
|
||||
parser.add_argument(
|
||||
"-?", "--help", action="help",
|
||||
help="show this help message and exit"
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"-h", metavar="host", default="127.0.0.1",
|
||||
help="Host to connect to, default 127.0.0.1"
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"-p", metavar="port", type=int, default=11111,
|
||||
help="Port to connect on, not 0, default 11111"
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"-v", metavar="version", type=int, choices=[0, 1, 2, 3], default=3,
|
||||
help="SSL version [0-3], SSLv3(0) - TLS1.2(3)), default 3"
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"-l", metavar="ciphers", type=str, default="",
|
||||
help="Cipher suite list (: delimited)"
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"-c", metavar="certificate", default="./certs/client-cert.pem",
|
||||
help="Certificate file, default ./certs/client-cert.pem"
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"-k", metavar="key", default="./certs/client-key.pem",
|
||||
help="Key file, default ./certs/client-key.pem"
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"-A", metavar="ca_file", default="./certs/ca-cert.pem",
|
||||
help="Certificate Authority file, default ./certs/ca-cert.pem"
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"-d", action="store_true",
|
||||
help="Disable client cert check"
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"-g", action="store_true",
|
||||
help="Send server HTTP GET"
|
||||
)
|
||||
|
||||
return parser
|
||||
|
||||
|
||||
def get_method(index):
|
||||
return (
|
||||
wolfssl.PROTOCOL_SSLv3,
|
||||
wolfssl.PROTOCOL_TLSv1,
|
||||
wolfssl.PROTOCOL_TLSv1_1,
|
||||
wolfssl.PROTOCOL_TLSv1_2
|
||||
)[index]
|
||||
|
||||
|
||||
def main():
|
||||
args = build_arg_parser().parse_args()
|
||||
|
||||
bind_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
|
||||
|
||||
context = wolfssl.SSLContext(get_method(args.v))
|
||||
|
||||
context.load_cert_chain(args.c, args.k)
|
||||
|
||||
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)
|
||||
|
||||
try:
|
||||
secure_socket = context.wrap_socket(bind_socket)
|
||||
|
||||
secure_socket.connect((args.h, args.p))
|
||||
|
||||
if args.g:
|
||||
secure_socket.write(b"GET / HTTP/1.1\n\n")
|
||||
else:
|
||||
secure_socket.write(b"hello wolfssl")
|
||||
|
||||
print("\n", secure_socket.read(), "\n")
|
||||
|
||||
except KeyboardInterrupt:
|
||||
print()
|
||||
|
||||
finally:
|
||||
secure_socket.close()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
152
wrapper/python/wolfssl/examples/server.py
Executable file
152
wrapper/python/wolfssl/examples/server.py
Executable file
@ -0,0 +1,152 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# server.py
|
||||
#
|
||||
# Copyright (C) 2006-2017 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
|
||||
|
||||
# pylint: disable=missing-docstring, invalid-name, import-error
|
||||
|
||||
import sys
|
||||
import socket
|
||||
import argparse
|
||||
|
||||
try:
|
||||
import wolfssl
|
||||
except ImportError:
|
||||
print("You must run 'python setup.py install' to use the examples")
|
||||
sys.exit()
|
||||
|
||||
def build_arg_parser():
|
||||
parser = argparse.ArgumentParser(add_help=False)
|
||||
|
||||
parser.add_argument(
|
||||
"-?", "--help", action="help",
|
||||
help="show this help message and exit"
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"-p", metavar="port", type=int, default=11111,
|
||||
help="Port to listen on, not 0, default 11111"
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"-v", metavar="version", type=int, choices=[0, 1, 2, 3], default=3,
|
||||
help="SSL version [0-3], SSLv3(0) - TLS1.2(3)), default 3"
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"-l", metavar="ciphers", type=str, default="",
|
||||
help="Cipher suite list (: delimited)"
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"-c", metavar="certificate", default="./certs/server-cert.pem",
|
||||
help="Certificate file, default ./certs/server-cert.pem"
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"-k", metavar="key", default="./certs/server-key.pem",
|
||||
help="Key file, default ./certs/server-key.pem"
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"-A", metavar="ca_file", default="./certs/client-cert.pem",
|
||||
help="Certificate Authority file, default ./certs/client-cert.pem"
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"-d", action="store_true",
|
||||
help="Disable client cert check"
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"-b", action="store_true",
|
||||
help="Bind to any interface instead of localhost only"
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"-i", action="store_true",
|
||||
help="Loop indefinitely (allow repeated connections)"
|
||||
)
|
||||
|
||||
return parser
|
||||
|
||||
|
||||
def get_method(index):
|
||||
return (
|
||||
wolfssl.PROTOCOL_SSLv3,
|
||||
wolfssl.PROTOCOL_TLSv1,
|
||||
wolfssl.PROTOCOL_TLSv1_1,
|
||||
wolfssl.PROTOCOL_TLSv1_2
|
||||
)[index]
|
||||
|
||||
|
||||
def main():
|
||||
args = build_arg_parser().parse_args()
|
||||
|
||||
bind_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
|
||||
bind_socket.bind(("" if args.b else "localhost", args.p))
|
||||
bind_socket.listen(5)
|
||||
|
||||
print("Server listening on port", bind_socket.getsockname()[1])
|
||||
|
||||
context = wolfssl.SSLContext(get_method(args.v), server_side=True)
|
||||
|
||||
context.load_cert_chain(args.c, args.k)
|
||||
|
||||
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)
|
||||
|
||||
while True:
|
||||
try:
|
||||
secure_socket = None
|
||||
|
||||
new_socket, from_addr = bind_socket.accept()
|
||||
|
||||
secure_socket = context.wrap_socket(new_socket)
|
||||
|
||||
print("Connection received from", from_addr)
|
||||
|
||||
print("\n", secure_socket.read(), "\n")
|
||||
secure_socket.write(b"I hear you fa shizzle!")
|
||||
|
||||
except KeyboardInterrupt:
|
||||
print()
|
||||
break
|
||||
|
||||
finally:
|
||||
if secure_socket:
|
||||
secure_socket.close()
|
||||
|
||||
if not args.i:
|
||||
break
|
||||
|
||||
bind_socket.close()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
38
wrapper/python/wolfssl/include.am
Normal file
38
wrapper/python/wolfssl/include.am
Normal file
@ -0,0 +1,38 @@
|
||||
# vim:ft=automake
|
||||
# included from Top Level Makefile.am
|
||||
# All paths should be given relative to the root
|
||||
|
||||
EXTRA_DIST+= wrapper/python/wolfssl/.gitignore
|
||||
EXTRA_DIST+= wrapper/python/wolfssl/docs/api.rst
|
||||
EXTRA_DIST+= wrapper/python/wolfssl/docs/conf.py
|
||||
EXTRA_DIST+= wrapper/python/wolfssl/docs/examples.rst
|
||||
EXTRA_DIST+= wrapper/python/wolfssl/docs/index.rst
|
||||
EXTRA_DIST+= wrapper/python/wolfssl/docs/installation.rst
|
||||
EXTRA_DIST+= wrapper/python/wolfssl/docs/Makefile
|
||||
EXTRA_DIST+= wrapper/python/wolfssl/docs/licensing.rst
|
||||
EXTRA_DIST+= wrapper/python/wolfssl/docs/requirements.txt
|
||||
EXTRA_DIST+= wrapper/python/wolfssl/docs/usage.rst
|
||||
EXTRA_DIST+= wrapper/python/wolfssl/examples/client.py
|
||||
EXTRA_DIST+= wrapper/python/wolfssl/examples/server.py
|
||||
EXTRA_DIST+= wrapper/python/wolfssl/test/conftest.py
|
||||
EXTRA_DIST+= wrapper/python/wolfssl/test/test_client.py
|
||||
EXTRA_DIST+= wrapper/python/wolfssl/test/test_context.py
|
||||
EXTRA_DIST+= wrapper/python/wolfssl/test/test_methods.py
|
||||
EXTRA_DIST+= wrapper/python/wolfssl/src/wolfssl/__about__.py
|
||||
EXTRA_DIST+= wrapper/python/wolfssl/src/wolfssl/__init__.py
|
||||
EXTRA_DIST+= wrapper/python/wolfssl/src/wolfssl/build_ffi.py
|
||||
EXTRA_DIST+= wrapper/python/wolfssl/src/wolfssl/_memory.py
|
||||
EXTRA_DIST+= wrapper/python/wolfssl/src/wolfssl/_methods.py
|
||||
EXTRA_DIST+= wrapper/python/wolfssl/src/wolfssl/exceptions.py
|
||||
EXTRA_DIST+= wrapper/python/wolfssl/src/wolfssl/utils.py
|
||||
EXTRA_DIST+= wrapper/python/wolfssl/LICENSING.rst
|
||||
EXTRA_DIST+= wrapper/python/wolfssl/Makefile
|
||||
EXTRA_DIST+= wrapper/python/wolfssl/MANIFEST.in
|
||||
EXTRA_DIST+= wrapper/python/wolfssl/README.rst
|
||||
EXTRA_DIST+= wrapper/python/wolfssl/requirements-testing.txt
|
||||
EXTRA_DIST+= wrapper/python/wolfssl/setup.py
|
||||
EXTRA_DIST+= wrapper/python/wolfssl/tox.ini
|
||||
EXTRA_DIST+= wrapper/python/wolfssl/Vagrantfile
|
||||
EXTRA_DIST+= wrapper/python/wolfssl/.centos-provisioner.sh
|
||||
EXTRA_DIST+= wrapper/python/wolfssl/.ubuntu-provisioner.sh
|
||||
|
3
wrapper/python/wolfssl/requirements-testing.txt
Normal file
3
wrapper/python/wolfssl/requirements-testing.txt
Normal file
@ -0,0 +1,3 @@
|
||||
pytest
|
||||
cffi
|
||||
tox
|
87
wrapper/python/wolfssl/setup.py
Executable file
87
wrapper/python/wolfssl/setup.py
Executable file
@ -0,0 +1,87 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# setup.py
|
||||
#
|
||||
# Copyright (C) 2006-2017 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
|
||||
|
||||
# Python 2.7 Standard Library
|
||||
|
||||
# pylint: disable=import-error, wrong-import-position
|
||||
|
||||
from __future__ import absolute_import
|
||||
import os
|
||||
import sys
|
||||
import shutil
|
||||
from setuptools import setup, find_packages
|
||||
|
||||
sys.path.insert(0, 'src')
|
||||
from wolfssl.__about__ import METADATA
|
||||
|
||||
os.chdir(os.path.dirname(sys.argv[0]) or ".")
|
||||
|
||||
LONG_DESCRIPTION = open("README.rst", "rt").read().replace(
|
||||
".. include:: LICENSING.rst\n",
|
||||
open("LICENSING.rst", "rt").read()
|
||||
)
|
||||
|
||||
INFO = dict(
|
||||
metadata={k[2:-2]: METADATA[k] for k in METADATA},
|
||||
contents={
|
||||
"long_description" : LONG_DESCRIPTION,
|
||||
"package_data" : {"": ["*.txt"]},
|
||||
"packages" : find_packages("src"),
|
||||
"package_dir" : {"": "src"},
|
||||
"cffi_modules" : ["./src/wolfssl/build_ffi.py:ffi"],
|
||||
},
|
||||
requirements={
|
||||
"setup_requires" : ["cffi>=1.6.0"],
|
||||
"install_requires" : ["cffi>=1.6.0"],
|
||||
},
|
||||
scripts={},
|
||||
plugins={},
|
||||
tests={},
|
||||
)
|
||||
|
||||
|
||||
def update_certs():
|
||||
c_certs_dir = "../../../certs"
|
||||
py_certs_dir = "certs"
|
||||
certs = [
|
||||
"ca-cert.pem",
|
||||
"client-cert.pem",
|
||||
"client-key.pem",
|
||||
"server-cert.pem",
|
||||
"server-key.pem",
|
||||
"external/ca-digicert-ev.pem"
|
||||
]
|
||||
|
||||
if os.path.isdir(c_certs_dir):
|
||||
if not os.path.isdir(py_certs_dir):
|
||||
os.makedirs(py_certs_dir)
|
||||
|
||||
for cert in certs:
|
||||
shutil.copy(os.path.join(c_certs_dir, cert), py_certs_dir)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
update_certs()
|
||||
|
||||
KWARGS = {k:v for dct in INFO.values() for (k, v) in dct.items()}
|
||||
setup(**KWARGS)
|
49
wrapper/python/wolfssl/src/wolfssl/__about__.py
Normal file
49
wrapper/python/wolfssl/src/wolfssl/__about__.py
Normal file
@ -0,0 +1,49 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# __about__.py
|
||||
#
|
||||
# Copyright (C) 2006-2017 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
|
||||
|
||||
# pylint: disable=missing-docstring
|
||||
|
||||
METADATA = dict(
|
||||
__name__="wolfssl",
|
||||
__version__="0.1.0",
|
||||
__license__="GPLv2 or Commercial License",
|
||||
__author__="wolfSSL Inc.",
|
||||
__author_email__="info@wolfssl.com",
|
||||
__url__="https://wolfssl.github.io/wolfssl-py",
|
||||
__description__= \
|
||||
u"A Python module that encapsulates wolfSSL's C SSL/TLS library.",
|
||||
__keywords__="security, cryptography, ssl, embedded, embedded ssl",
|
||||
__classifiers__=[
|
||||
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",
|
||||
u"Programming Language :: Python :: 3.5",
|
||||
u"Topic :: Security",
|
||||
u"Topic :: Security :: Cryptography",
|
||||
u"Topic :: Software Development"
|
||||
]
|
||||
)
|
||||
|
||||
globals().update(METADATA)
|
||||
|
||||
__all__ = list(METADATA.keys())
|
677
wrapper/python/wolfssl/src/wolfssl/__init__.py
Normal file
677
wrapper/python/wolfssl/src/wolfssl/__init__.py
Normal file
@ -0,0 +1,677 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# __init__.py
|
||||
#
|
||||
# Copyright (C) 2006-2017 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 sys
|
||||
import errno
|
||||
from socket import (
|
||||
socket, AF_INET, SOCK_STREAM, SOL_SOCKET, SO_TYPE, error as socket_error
|
||||
)
|
||||
|
||||
try:
|
||||
from wolfssl._ffi import ffi as _ffi
|
||||
from wolfssl._ffi import lib as _lib
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
from wolfssl.utils import t2b
|
||||
|
||||
from wolfssl.exceptions import (
|
||||
CertificateError, SSLError, SSLEOFError, SSLSyscallError,
|
||||
SSLWantReadError, SSLWantWriteError, SSLZeroReturnError
|
||||
)
|
||||
|
||||
from wolfssl._methods import (
|
||||
PROTOCOL_SSLv23, PROTOCOL_SSLv3, PROTOCOL_TLSv1,
|
||||
PROTOCOL_TLSv1_1, PROTOCOL_TLSv1_2, PROTOCOL_TLS,
|
||||
WolfSSLMethod as _WolfSSLMethod
|
||||
)
|
||||
|
||||
from wolfssl.__about__ import (
|
||||
__all__, METADATA
|
||||
)
|
||||
|
||||
globals().update(METADATA)
|
||||
|
||||
CERT_NONE = 0
|
||||
CERT_REQUIRED = 1
|
||||
|
||||
_VERIFY_MODE_LIST = [CERT_NONE, CERT_REQUIRED]
|
||||
|
||||
_SSL_SUCCESS = 1
|
||||
_SSL_FILETYPE_PEM = 1
|
||||
_SSL_ERROR_WANT_READ = 2
|
||||
|
||||
_WOLFSSL_ECC_SECP160K1 = 15
|
||||
_WOLFSSL_ECC_SECP160R1 = 16
|
||||
_WOLFSSL_ECC_SECP160R2 = 17
|
||||
_WOLFSSL_ECC_SECP192K1 = 18
|
||||
_WOLFSSL_ECC_SECP192R1 = 19
|
||||
_WOLFSSL_ECC_SECP224K1 = 20
|
||||
_WOLFSSL_ECC_SECP224R1 = 21
|
||||
_WOLFSSL_ECC_SECP256K1 = 22
|
||||
_WOLFSSL_ECC_SECP256R1 = 23
|
||||
_WOLFSSL_ECC_SECP384R1 = 24
|
||||
_WOLFSSL_ECC_SECP521R1 = 25
|
||||
_WOLFSSL_ECC_BRAINPOOLP256R1 = 26
|
||||
_WOLFSSL_ECC_BRAINPOOLP384R1 = 27
|
||||
_WOLFSSL_ECC_BRAINPOOLP512R1 = 28
|
||||
|
||||
_SUPPORTED_CURVES = [
|
||||
_WOLFSSL_ECC_SECP160K1, _WOLFSSL_ECC_SECP160R1, _WOLFSSL_ECC_SECP160R2,
|
||||
_WOLFSSL_ECC_SECP192K1, _WOLFSSL_ECC_SECP192R1, _WOLFSSL_ECC_SECP224K1,
|
||||
_WOLFSSL_ECC_SECP224R1, _WOLFSSL_ECC_SECP256K1, _WOLFSSL_ECC_SECP256R1,
|
||||
_WOLFSSL_ECC_SECP384R1, _WOLFSSL_ECC_SECP521R1,
|
||||
_WOLFSSL_ECC_BRAINPOOLP256R1, _WOLFSSL_ECC_BRAINPOOLP384R1,
|
||||
_WOLFSSL_ECC_BRAINPOOLP512R1
|
||||
]
|
||||
|
||||
_PY3 = sys.version_info[0] == 3
|
||||
|
||||
class SSLContext(object):
|
||||
"""
|
||||
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._verify_mode = None
|
||||
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 = _ffi.NULL
|
||||
|
||||
if self.native_object == _ffi.NULL:
|
||||
raise MemoryError("Unnable to allocate context object")
|
||||
|
||||
# verify_mode initialization needs a valid native_object.
|
||||
self.verify_mode = CERT_NONE
|
||||
|
||||
if not server_side:
|
||||
for curve in _SUPPORTED_CURVES:
|
||||
ret = _lib.wolfSSL_CTX_UseSupportedCurve(self.native_object,
|
||||
curve)
|
||||
if ret != _SSL_SUCCESS:
|
||||
raise SSLError("unnable to set curve (%d)" % curve)
|
||||
|
||||
|
||||
def __del__(self):
|
||||
if getattr(self, 'native_object', _ffi.NULL) != _ffi.NULL:
|
||||
_lib.wolfSSL_CTX_free(self.native_object)
|
||||
|
||||
|
||||
@property
|
||||
def verify_mode(self):
|
||||
"""
|
||||
Whether to try to verify other peers’ certificates and how to behave
|
||||
if verification fails. This attribute must be one of CERT_NONE,
|
||||
CERT_OPTIONAL or CERT_REQUIRED.
|
||||
"""
|
||||
return self._verify_mode
|
||||
|
||||
|
||||
@verify_mode.setter
|
||||
def verify_mode(self, value):
|
||||
if value not in _VERIFY_MODE_LIST:
|
||||
raise ValueError("verify_mode must be one of CERT_NONE, "
|
||||
"CERT_OPTIONAL or CERT_REQUIRED")
|
||||
|
||||
if value != self._verify_mode:
|
||||
self._verify_mode = value
|
||||
_lib.wolfSSL_CTX_set_verify(self.native_object,
|
||||
self._verify_mode,
|
||||
_ffi.NULL)
|
||||
|
||||
|
||||
def wrap_socket(self, sock, server_side=False,
|
||||
do_handshake_on_connect=True,
|
||||
suppress_ragged_eofs=True):
|
||||
"""
|
||||
Wrap an existing Python socket sock and return an SSLSocket object.
|
||||
sock must be a SOCK_STREAM socket; other socket types are unsupported.
|
||||
|
||||
The returned SSL socket is tied to the context, its settings and
|
||||
certificates. The parameters server_side, do_handshake_on_connect and
|
||||
suppress_ragged_eofs have the same meaning as in the top-level
|
||||
wrap_socket() function.
|
||||
"""
|
||||
return SSLSocket(sock=sock, server_side=server_side,
|
||||
do_handshake_on_connect=do_handshake_on_connect,
|
||||
suppress_ragged_eofs=suppress_ragged_eofs,
|
||||
_context=self)
|
||||
|
||||
|
||||
def set_ciphers(self, ciphers):
|
||||
"""
|
||||
Set the available ciphers for sockets created with this context. It
|
||||
should be a string in the wolfSSL cipher list format. If no cipher can
|
||||
be selected (because compile-time options or other configuration forbids
|
||||
use of all the specified ciphers), an SSLError will be raised.
|
||||
"""
|
||||
ret = _lib.wolfSSL_CTX_set_cipher_list(self.native_object, t2b(ciphers))
|
||||
|
||||
if ret != _SSL_SUCCESS:
|
||||
raise SSLError("Unnable to set cipher list")
|
||||
|
||||
|
||||
def load_cert_chain(self, certfile, keyfile=None, password=None):
|
||||
"""
|
||||
Load a private key and the corresponding certificate. The certfile
|
||||
string must be the path to a single file in PEM format containing
|
||||
the certificate as well as any number of CA certificates needed to
|
||||
establish the certificate's authenticity.
|
||||
|
||||
The keyfile string, if present, must point to a file containing the
|
||||
private key in.
|
||||
|
||||
The password parameter is not supported yet.
|
||||
"""
|
||||
|
||||
if password is not None:
|
||||
raise NotImplementedError("password callback support not "
|
||||
"implemented yet")
|
||||
|
||||
if certfile is not None:
|
||||
ret = _lib.wolfSSL_CTX_use_certificate_chain_file(
|
||||
self.native_object, t2b(certfile))
|
||||
if ret != _SSL_SUCCESS:
|
||||
raise SSLError("Unnable to load certificate chain. Err %d"% ret)
|
||||
else:
|
||||
raise TypeError("certfile should be a valid filesystem path")
|
||||
|
||||
if keyfile is not None:
|
||||
ret = _lib.wolfSSL_CTX_use_PrivateKey_file(
|
||||
self.native_object, t2b(keyfile), _SSL_FILETYPE_PEM)
|
||||
if ret != _SSL_SUCCESS:
|
||||
raise SSLError("Unnable to load private key. Err %d" % ret)
|
||||
|
||||
|
||||
def load_verify_locations(self, cafile=None, capath=None, cadata=None):
|
||||
"""
|
||||
Load a set of "certification authority" (CA) certificates used to
|
||||
validate other peers' certificates when verify_mode is other than
|
||||
CERT_NONE. At least one of cafile or capath must be specified.
|
||||
|
||||
The cafile string, if present, is the path to a file of concatenated
|
||||
CA certificates in PEM format.
|
||||
|
||||
The capath string, if present, is the path to a directory containing
|
||||
several CA certificates in PEM format.
|
||||
"""
|
||||
|
||||
if cafile is None and capath is None and cadata is None:
|
||||
raise TypeError("cafile, capath and cadata cannot be all omitted")
|
||||
|
||||
if cafile is not None or capath is not None:
|
||||
ret = _lib.wolfSSL_CTX_load_verify_locations(
|
||||
self.native_object,
|
||||
t2b(cafile) if cafile else _ffi.NULL,
|
||||
t2b(capath) if capath else _ffi.NULL)
|
||||
|
||||
if ret != _SSL_SUCCESS:
|
||||
raise SSLError("Unnable to load verify locations. Err %d" % ret)
|
||||
|
||||
if cadata is not None:
|
||||
ret = _lib.wolfSSL_CTX_load_verify_buffer(
|
||||
self.native_object, t2b(cadata), len(cadata), _SSL_FILETYPE_PEM)
|
||||
|
||||
if ret != _SSL_SUCCESS:
|
||||
raise SSLError("Unnable to load verify locations. Err %d" % ret)
|
||||
|
||||
|
||||
class SSLSocket(socket):
|
||||
"""
|
||||
This class implements a subtype of socket.socket that wraps the
|
||||
underlying OS socket in an SSL/TLS connection, providing secure
|
||||
read and write methods over that channel.
|
||||
"""
|
||||
|
||||
def __init__(self, sock=None, keyfile=None, certfile=None,
|
||||
server_side=False, cert_reqs=CERT_NONE,
|
||||
ssl_version=PROTOCOL_TLS, ca_certs=None,
|
||||
do_handshake_on_connect=True, family=AF_INET,
|
||||
sock_type=SOCK_STREAM, proto=0, fileno=None,
|
||||
suppress_ragged_eofs=True, ciphers=None,
|
||||
_context=None):
|
||||
|
||||
# set options
|
||||
self.do_handshake_on_connect = do_handshake_on_connect
|
||||
self.suppress_ragged_eofs = suppress_ragged_eofs
|
||||
self.server_side = server_side
|
||||
|
||||
# set context
|
||||
if _context:
|
||||
self._context = _context
|
||||
else:
|
||||
if server_side and not certfile:
|
||||
raise ValueError("certfile must be specified for server-side "
|
||||
"operations")
|
||||
|
||||
if keyfile and not certfile:
|
||||
raise ValueError("certfile must be specified")
|
||||
|
||||
if certfile and not keyfile:
|
||||
keyfile = certfile
|
||||
|
||||
self._context = SSLContext(ssl_version, server_side)
|
||||
self._context.verify_mode = cert_reqs
|
||||
if ca_certs:
|
||||
self._context.load_verify_locations(ca_certs)
|
||||
if certfile:
|
||||
self._context.load_cert_chain(certfile, keyfile)
|
||||
if ciphers:
|
||||
self._context.set_ciphers(ciphers)
|
||||
|
||||
self.keyfile = keyfile
|
||||
self.certfile = certfile
|
||||
self.cert_reqs = cert_reqs
|
||||
self.ssl_version = ssl_version
|
||||
self.ca_certs = ca_certs
|
||||
self.ciphers = ciphers
|
||||
|
||||
# preparing socket
|
||||
if sock is not None:
|
||||
# Can't use sock.type as other flags (such as SOCK_NONBLOCK) get
|
||||
# mixed in.
|
||||
if sock.getsockopt(SOL_SOCKET, SO_TYPE) != SOCK_STREAM:
|
||||
raise NotImplementedError("only stream sockets are supported")
|
||||
|
||||
if _PY3:
|
||||
socket.__init__(self,
|
||||
family=sock.family,
|
||||
type=sock.type,
|
||||
proto=sock.proto,
|
||||
fileno=sock.fileno())
|
||||
else:
|
||||
socket.__init__(self, _sock=sock._sock)
|
||||
|
||||
self.settimeout(sock.gettimeout())
|
||||
|
||||
if _PY3:
|
||||
sock.detach()
|
||||
|
||||
elif fileno is not None:
|
||||
socket.__init__(self, fileno=fileno)
|
||||
|
||||
else:
|
||||
socket.__init__(self, family=family, type=sock_type,
|
||||
proto=proto)
|
||||
|
||||
# see if we are connected
|
||||
try:
|
||||
self.getpeername()
|
||||
except socket_error as exception:
|
||||
if exception.errno != errno.ENOTCONN:
|
||||
raise
|
||||
connected = False
|
||||
else:
|
||||
connected = True
|
||||
|
||||
self._closed = False
|
||||
self._connected = connected
|
||||
|
||||
# create the SSL object
|
||||
self.native_object = _lib.wolfSSL_new(self.context.native_object)
|
||||
if self.native_object == _ffi.NULL:
|
||||
raise MemoryError("Unnable to allocate ssl object")
|
||||
|
||||
ret = _lib.wolfSSL_set_fd(self.native_object, self.fileno())
|
||||
if ret != _SSL_SUCCESS:
|
||||
self._release_native_object()
|
||||
raise ValueError("Unnable to set fd to ssl object")
|
||||
|
||||
if connected:
|
||||
try:
|
||||
if do_handshake_on_connect:
|
||||
self.do_handshake()
|
||||
except:
|
||||
self._release_native_object()
|
||||
self.close()
|
||||
raise
|
||||
|
||||
|
||||
def __del__(self):
|
||||
self._release_native_object()
|
||||
|
||||
|
||||
def _release_native_object(self):
|
||||
if getattr(self, 'native_object', _ffi.NULL) != _ffi.NULL:
|
||||
_lib.wolfSSL_CTX_free(self.native_object)
|
||||
self.native_object = _ffi.NULL
|
||||
|
||||
|
||||
@property
|
||||
def context(self):
|
||||
"""
|
||||
Returns the context used by this object.
|
||||
"""
|
||||
return self._context
|
||||
|
||||
|
||||
def dup(self):
|
||||
raise NotImplementedError("Can't dup() %s instances" %
|
||||
self.__class__.__name__)
|
||||
|
||||
|
||||
def _check_closed(self, call=None):
|
||||
if self.native_object == _ffi.NULL:
|
||||
raise ValueError("%s on closed or unwrapped secure channel" % call)
|
||||
|
||||
def _check_connected(self):
|
||||
if not self._connected:
|
||||
# getpeername() will raise ENOTCONN if the socket is really
|
||||
# not connected; note that we can be connected even without
|
||||
# _connected being set, e.g. if connect() first returned
|
||||
# EAGAIN.
|
||||
self.getpeername()
|
||||
|
||||
|
||||
def write(self, data):
|
||||
"""
|
||||
Write DATA to the underlying secure channel.
|
||||
Returns number of bytes of DATA actually transmitted.
|
||||
"""
|
||||
self._check_closed("write")
|
||||
self._check_connected()
|
||||
|
||||
data = t2b(data)
|
||||
|
||||
return _lib.wolfSSL_write(self.native_object, data, len(data))
|
||||
|
||||
|
||||
def send(self, data, flags=0):
|
||||
if flags != 0:
|
||||
raise NotImplementedError("non-zero flags not allowed in calls to "
|
||||
"send() on %s" % self.__class__)
|
||||
|
||||
return self.write(data)
|
||||
|
||||
|
||||
def sendall(self, data, flags=0):
|
||||
if flags != 0:
|
||||
raise NotImplementedError("non-zero flags not allowed in calls to "
|
||||
"sendall() on %s" % self.__class__)
|
||||
|
||||
length = len(data)
|
||||
sent = 0
|
||||
|
||||
while sent < length:
|
||||
sent += self.write(data[sent:])
|
||||
|
||||
return sent
|
||||
|
||||
|
||||
def sendto(self, data, flags_or_addr, addr=None):
|
||||
# Ensure programs don't send unencrypted data trying to use this method
|
||||
raise NotImplementedError("sendto not allowed on instances "
|
||||
"of %s" % self.__class__)
|
||||
|
||||
|
||||
def sendmsg(self, *args, **kwargs):
|
||||
# Ensure programs don't send unencrypted data trying to use this method
|
||||
raise NotImplementedError("sendmsg not allowed on instances "
|
||||
"of %s" % self.__class__)
|
||||
|
||||
|
||||
def sendfile(self, file, offset=0, count=None):
|
||||
# Ensure programs don't send unencrypted files trying to use this method
|
||||
raise NotImplementedError("sendfile not allowed on instances "
|
||||
"of %s" % self.__class__)
|
||||
|
||||
|
||||
def read(self, length=1024, buffer=None):
|
||||
"""
|
||||
Read up to LENGTH bytes and return them.
|
||||
Return zero-length string on EOF.
|
||||
"""
|
||||
self._check_closed("read")
|
||||
self._check_connected()
|
||||
|
||||
if buffer is not None:
|
||||
raise ValueError("buffer not allowed in calls to "
|
||||
"read() on %s" % self.__class__)
|
||||
|
||||
data = _ffi.new('byte[%d]' % length)
|
||||
length = _lib.wolfSSL_read(self.native_object, data, length)
|
||||
|
||||
if length < 0:
|
||||
err = _lib.wolfSSL_get_error(self.native_object, 0)
|
||||
if err == _SSL_ERROR_WANT_READ:
|
||||
raise SSLWantReadError()
|
||||
else:
|
||||
raise SSLError("wolfSSL_read error (%d)" % err)
|
||||
|
||||
return _ffi.buffer(data, length)[:] if length > 0 else b''
|
||||
|
||||
|
||||
def recv(self, length=1024, flags=0):
|
||||
if flags != 0:
|
||||
raise NotImplementedError("non-zero flags not allowed in calls to "
|
||||
"recv() on %s" % self.__class__)
|
||||
|
||||
return self.read(self, length)
|
||||
|
||||
|
||||
def recv_into(self, buffer, nbytes=None, flags=0):
|
||||
raise NotImplementedError("recv_into not allowed on instances "
|
||||
"of %s" % self.__class__)
|
||||
|
||||
|
||||
def recvfrom(self, length=1024, flags=0):
|
||||
# Ensure programs don't receive encrypted data trying to use this method
|
||||
raise NotImplementedError("recvfrom not allowed on instances "
|
||||
"of %s" % self.__class__)
|
||||
|
||||
|
||||
def recvfrom_into(self, buffer, nbytes=None, flags=0):
|
||||
# Ensure programs don't receive encrypted data trying to use this method
|
||||
raise NotImplementedError("recvfrom_into not allowed on instances "
|
||||
"of %s" % self.__class__)
|
||||
|
||||
|
||||
def recvmsg(self, *args, **kwargs):
|
||||
raise NotImplementedError("recvmsg not allowed on instances of %s" %
|
||||
self.__class__)
|
||||
|
||||
|
||||
def recvmsg_into(self, *args, **kwargs):
|
||||
raise NotImplementedError("recvmsg_into not allowed on instances of "
|
||||
"%s" % self.__class__)
|
||||
|
||||
|
||||
def shutdown(self, how):
|
||||
if self.native_object != _ffi.NULL:
|
||||
_lib.wolfSSL_shutdown(self.native_object)
|
||||
self._release_native_object()
|
||||
socket.shutdown(self, how)
|
||||
|
||||
|
||||
def unwrap(self):
|
||||
"""
|
||||
Unwraps the underlying OS socket from the SSL/TLS connection.
|
||||
Returns the wrapped OS socket.
|
||||
"""
|
||||
if self.native_object != _ffi.NULL:
|
||||
_lib.wolfSSL_set_fd(self.native_object, -1)
|
||||
|
||||
sock = socket(family=self.family,
|
||||
sock_type=self.type,
|
||||
proto=self.proto,
|
||||
fileno=self.fileno())
|
||||
sock.settimeout(self.gettimeout())
|
||||
self.detach()
|
||||
|
||||
return sock
|
||||
|
||||
|
||||
def do_handshake(self, block=False):
|
||||
"""
|
||||
Perform a TLS/SSL handshake.
|
||||
"""
|
||||
self._check_closed("do_handshake")
|
||||
self._check_connected()
|
||||
|
||||
ret = _lib.wolfSSL_negotiate(self.native_object)
|
||||
if ret != _SSL_SUCCESS:
|
||||
raise SSLError("do_handshake failed with error %d" % ret)
|
||||
|
||||
|
||||
def _real_connect(self, addr, connect_ex):
|
||||
if self.server_side:
|
||||
raise ValueError("can't connect in server-side mode")
|
||||
|
||||
# Here we assume that the socket is client-side, and not
|
||||
# connected at the time of the call. We connect it, then wrap it.
|
||||
if self._connected:
|
||||
raise ValueError("attempt to connect already-connected SSLSocket!")
|
||||
|
||||
if connect_ex:
|
||||
err = socket.connect_ex(self, addr)
|
||||
else:
|
||||
err = 0
|
||||
socket.connect(self, addr)
|
||||
|
||||
if err == 0:
|
||||
self._connected = True
|
||||
if self.do_handshake_on_connect:
|
||||
self.do_handshake()
|
||||
|
||||
return err
|
||||
|
||||
|
||||
def connect(self, addr):
|
||||
"""
|
||||
Connects to remote ADDR, and then wraps the connection in a secure
|
||||
channel.
|
||||
"""
|
||||
self._real_connect(addr, False)
|
||||
|
||||
|
||||
def connect_ex(self, addr):
|
||||
"""
|
||||
Connects to remote ADDR, and then wraps the connection in a secure
|
||||
channel.
|
||||
"""
|
||||
return self._real_connect(addr, True)
|
||||
|
||||
|
||||
def accept(self):
|
||||
"""
|
||||
Accepts a new connection from a remote client, and returns a tuple
|
||||
containing that new connection wrapped with a server-side secure
|
||||
channel, and the address of the remote client.
|
||||
"""
|
||||
if not self.server_side:
|
||||
raise ValueError("can't accept in client-side mode")
|
||||
|
||||
newsock, addr = socket.accept(self)
|
||||
newsock = self.context.wrap_socket(
|
||||
newsock,
|
||||
do_handshake_on_connect=self.do_handshake_on_connect,
|
||||
suppress_ragged_eofs=self.suppress_ragged_eofs,
|
||||
server_side=True)
|
||||
|
||||
return newsock, addr
|
||||
|
||||
|
||||
def wrap_socket(sock, keyfile=None, certfile=None, server_side=False,
|
||||
cert_reqs=CERT_NONE, ssl_version=PROTOCOL_TLS, ca_certs=None,
|
||||
do_handshake_on_connect=True, suppress_ragged_eofs=True,
|
||||
ciphers=None):
|
||||
"""
|
||||
Takes an instance sock of socket.socket, and returns an instance of
|
||||
wolfssl.SSLSocket, wraping the underlying socket in an SSL context.
|
||||
|
||||
The sock parameter must be a SOCK_STREAM socket; other socket types are
|
||||
unsupported.
|
||||
|
||||
The keyfile and certfile parameters specify optional files whith proper
|
||||
key and the certificates used to identify the local side of the connection.
|
||||
|
||||
The parameter server_side is a boolean which identifies whether server-side
|
||||
or client-side behavior is desired from this socket.
|
||||
|
||||
The parameter cert_reqs specifies whether a certificate is required from the
|
||||
other side of the connection, and whether it will be validated if provided.
|
||||
It must be one of the three values:
|
||||
|
||||
* CERT_NONE (certificates ignored)
|
||||
* CERT_OPTIONAL (not required, but validated if provided)
|
||||
* CERT_REQUIRED (required and validated)
|
||||
|
||||
If the value of this parameter is not CERT_NONE, then the ca_certs parameter
|
||||
must point to a file of CA certificates.
|
||||
|
||||
The ca_certs file contains a set of concatenated “certification authority”
|
||||
certificates, which are used to validate certificates passed from the other
|
||||
end of the connection.
|
||||
|
||||
The parameter ssl_version specifies which version of the SSL protocol to
|
||||
use. Typically, the server chooses a particular protocol version, and the
|
||||
client must adapt to the server’s choice. Most of the versions are not
|
||||
interoperable with the other versions. If not specified, the default is
|
||||
PROTOCOL_TLS; it provides the most compatibility with other versions.
|
||||
|
||||
Here’s a table showing which versions in a client (down the side) can
|
||||
connect to which versions in a server (along the top):
|
||||
|
||||
+------------------+-------+-----+-------+---------+---------+
|
||||
| client \\ server | SSLv3 | TLS | TLSv1 | TLSv1.1 | TLSv1.2 |
|
||||
+------------------+-------+-----+-------+---------+---------+
|
||||
| SSLv3 | yes | yes | no | no | no |
|
||||
+------------------+-------+-----+-------+---------+---------+
|
||||
| TLS (SSLv23) | yes | yes | yes | yes | yes |
|
||||
+------------------+-------+-----+-------+---------+---------+
|
||||
| TLSv1 | no | yes | yes | no | no |
|
||||
+------------------+-------+-----+-------+---------+---------+
|
||||
| TLSv1.1 | no | yes | no | yes | no |
|
||||
+------------------+-------+-----+-------+---------+---------+
|
||||
| TLSv1.2 | no | yes | no | no | yes |
|
||||
+------------------+-------+-----+-------+---------+---------+
|
||||
|
||||
Note:
|
||||
Which connections succeed will vary depending on the versions of the ssl
|
||||
providers on both sides of the communication.
|
||||
|
||||
The ciphers parameter sets the available ciphers for this SSL object. It
|
||||
should be a string in the wolfSSL cipher list format.
|
||||
|
||||
The parameter do_handshake_on_connect specifies whether to do the SSL
|
||||
handshake automatically after doing a socket.connect(), or whether the
|
||||
application program will call it explicitly, by invoking the
|
||||
SSLSocket.do_handshake() method. Calling SSLSocket.do_handshake() explicitly
|
||||
gives the program control over the blocking behavior of the socket I/O
|
||||
involved in the handshake.
|
||||
|
||||
The parameter suppress_ragged_eofs is not supported yet.
|
||||
"""
|
||||
return SSLSocket(sock=sock, keyfile=keyfile, certfile=certfile,
|
||||
server_side=server_side, cert_reqs=cert_reqs,
|
||||
ssl_version=ssl_version, ca_certs=ca_certs,
|
||||
do_handshake_on_connect=do_handshake_on_connect,
|
||||
suppress_ragged_eofs=suppress_ragged_eofs,
|
||||
ciphers=ciphers)
|
34
wrapper/python/wolfssl/src/wolfssl/_memory.py
Normal file
34
wrapper/python/wolfssl/src/wolfssl/_memory.py
Normal file
@ -0,0 +1,34 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# _memory.py
|
||||
#
|
||||
# Copyright (C) 2006-2017 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
|
||||
|
||||
# pylint: disable=missing-docstring
|
||||
|
||||
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)
|
82
wrapper/python/wolfssl/src/wolfssl/_methods.py
Normal file
82
wrapper/python/wolfssl/src/wolfssl/_methods.py
Normal file
@ -0,0 +1,82 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# _methods.py
|
||||
#
|
||||
# Copyright (C) 2006-2017 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
|
||||
|
||||
# pylint: disable=missing-docstring, invalid-name
|
||||
|
||||
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_TLS,
|
||||
PROTOCOL_TLSv1, PROTOCOL_TLSv1_1, PROTOCOL_TLSv1_2]
|
||||
|
||||
|
||||
class WolfSSLMethod(object):
|
||||
"""
|
||||
An SSLMethod holds SSL-related configuration options such as
|
||||
protocol version and communication side.
|
||||
"""
|
||||
|
||||
def __init__(self, protocol, server_side):
|
||||
if protocol not in _PROTOCOL_LIST:
|
||||
raise ValueError("this protocol is not supported")
|
||||
|
||||
elif protocol == PROTOCOL_SSLv3:
|
||||
raise ValueError("this protocol is not supported")
|
||||
|
||||
elif protocol == PROTOCOL_TLSv1:
|
||||
raise ValueError("this protocol is not supported")
|
||||
|
||||
elif protocol == PROTOCOL_TLSv1_1:
|
||||
raise ValueError("this protocol is not supported")
|
||||
|
||||
elif protocol == PROTOCOL_TLSv1_2:
|
||||
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 getattr(self, 'native_object', _ffi.NULL) != _ffi.NULL:
|
||||
_native_free(self.native_object, _DYNAMIC_TYPE_METHOD)
|
79
wrapper/python/wolfssl/src/wolfssl/build_ffi.py
Normal file
79
wrapper/python/wolfssl/src/wolfssl/build_ffi.py
Normal file
@ -0,0 +1,79 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# build_ffi.py
|
||||
#
|
||||
# Copyright (C) 2006-2017 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
|
||||
|
||||
# pylint: disable=missing-docstring, invalid-name
|
||||
|
||||
from cffi import FFI
|
||||
|
||||
ffi = FFI()
|
||||
|
||||
ffi.set_source(
|
||||
"wolfssl._ffi",
|
||||
"""
|
||||
#include <wolfssl/options.h>
|
||||
#include <wolfssl/ssl.h>
|
||||
|
||||
void wolfSSL_Free(void *ptr, void* heap, int type);
|
||||
""",
|
||||
include_dirs=["/usr/local/include"],
|
||||
library_dirs=["/usr/local/lib"],
|
||||
libraries=["wolfssl"],
|
||||
)
|
||||
|
||||
ffi.cdef(
|
||||
"""
|
||||
typedef unsigned char byte;
|
||||
typedef unsigned int word32;
|
||||
|
||||
void wolfSSL_Free(void*, void*, int);
|
||||
|
||||
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*);
|
||||
void wolfSSL_CTX_free(void*);
|
||||
|
||||
void wolfSSL_CTX_set_verify(void*, int, void*);
|
||||
int wolfSSL_CTX_set_cipher_list(void*, const char*);
|
||||
int wolfSSL_CTX_use_PrivateKey_file(void*, const char*, int);
|
||||
int wolfSSL_CTX_load_verify_locations(void*, const char*, const char*);
|
||||
int wolfSSL_CTX_load_verify_buffer(void*, const unsigned char*, long, int);
|
||||
int wolfSSL_CTX_use_certificate_chain_file(void*, const char *);
|
||||
int wolfSSL_CTX_UseSupportedCurve(void*, short);
|
||||
|
||||
|
||||
void* wolfSSL_new(void*);
|
||||
void wolfSSL_free(void*);
|
||||
|
||||
int wolfSSL_set_fd(void*, int);
|
||||
int wolfSSL_get_error(void*, int);
|
||||
int wolfSSL_negotiate(void*);
|
||||
int wolfSSL_write(void*, const void*, int);
|
||||
int wolfSSL_read(void*, void*, int);
|
||||
int wolfSSL_shutdown(void*);
|
||||
"""
|
||||
)
|
||||
|
||||
if __name__ == "__main__":
|
||||
ffi.compile(verbose=1)
|
88
wrapper/python/wolfssl/src/wolfssl/exceptions.py
Normal file
88
wrapper/python/wolfssl/src/wolfssl/exceptions.py
Normal file
@ -0,0 +1,88 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# exceptions.py
|
||||
#
|
||||
# Copyright (C) 2006-2017 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
|
||||
|
||||
# pylint: disable=missing-docstring
|
||||
|
||||
from socket import error as socket_error
|
||||
|
||||
|
||||
class SSLError(socket_error):
|
||||
"""
|
||||
Raised to signal an error from the wolfSSL's SSL/TLS library. This signifies
|
||||
some problem in the higher-level encryption and authentication layer that's
|
||||
superimposed on the underlying network connection. This error is a subtype
|
||||
of socket.error, which in turn is a subtype of IOError. The error code and
|
||||
message of SSLError instances are provided by the wolfSSL library.
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
class SSLZeroReturnError(SSLError):
|
||||
"""
|
||||
A subclass of SSLError raised when trying to read or write and the SSL
|
||||
connection has been closed cleanly. Note that this doesn't mean that the
|
||||
underlying transport (read TCP) has been closed.
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
class SSLWantReadError(SSLError):
|
||||
"""
|
||||
A subclass of SSLError raised by a non-blocking SSL socket when trying to
|
||||
read or write data, but more data needs to be received on the underlying TCP
|
||||
transport before the request can be fulfilled.
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
class SSLWantWriteError(SSLError):
|
||||
"""
|
||||
A subclass of SSLError raised by a non-blocking SSL socket when trying to
|
||||
read or write data, but more data needs to be sent on the underlying TCP
|
||||
transport before the request can be fulfilled.
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
class SSLSyscallError(SSLError):
|
||||
"""
|
||||
A subclass of SSLError raised when a system error was encountered while
|
||||
trying to fulfill an operation on a SSL socket. Unfortunately, there is no
|
||||
easy way to inspect the original errno number.
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
class SSLEOFError(SSLError):
|
||||
"""
|
||||
A subclass of SSLError raised when the SSL connection has been terminated
|
||||
abruptly. Generally, you shouldn't try to reuse the underlying transport
|
||||
when this error is encountered.
|
||||
"""
|
||||
pass
|
||||
|
||||
class CertificateError(ValueError):
|
||||
"""
|
||||
Raised to signal an error with a certificate (such as mismatching hostname).
|
||||
Certificate errors detected by wolfSSL, though, raise an SSLError.
|
||||
"""
|
||||
pass
|
38
wrapper/python/wolfssl/src/wolfssl/utils.py
Normal file
38
wrapper/python/wolfssl/src/wolfssl/utils.py
Normal file
@ -0,0 +1,38 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# utils.py
|
||||
#
|
||||
# Copyright (C) 2006-2017 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
|
||||
|
||||
# pylint: disable=missing-docstring, unused-import, undefined-variable
|
||||
|
||||
import sys
|
||||
from binascii import hexlify as b2h, unhexlify as h2b
|
||||
|
||||
_PY3 = sys.version_info[0] == 3
|
||||
_TEXT_TYPE = str if _PY3 else unicode
|
||||
_BINARY_TYPE = bytes if _PY3 else str
|
||||
|
||||
def t2b(string):
|
||||
"""
|
||||
Converts text to bynary.
|
||||
"""
|
||||
if isinstance(string, _BINARY_TYPE):
|
||||
return string
|
||||
return _TEXT_TYPE(string).encode("utf-8")
|
46
wrapper/python/wolfssl/test/conftest.py
Normal file
46
wrapper/python/wolfssl/test/conftest.py
Normal file
@ -0,0 +1,46 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# conftest.py
|
||||
#
|
||||
# Copyright (C) 2006-2017 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
|
||||
|
||||
# pylint: disable=missing-docstring, redefined-outer-name
|
||||
|
||||
import sys
|
||||
import ssl
|
||||
import wolfssl
|
||||
import pytest
|
||||
|
||||
@pytest.fixture
|
||||
def tcp_socket():
|
||||
import socket
|
||||
from contextlib import closing
|
||||
|
||||
with closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as sock:
|
||||
yield sock
|
||||
|
||||
@pytest.fixture(
|
||||
params=[ssl, wolfssl] if sys.version_info.major == 3 else [wolfssl],
|
||||
ids=["ssl", "wolfssl"] if sys.version_info.major == 3 else ["wolfssl"])
|
||||
def ssl_provider(request):
|
||||
return request.param
|
||||
|
||||
@pytest.fixture
|
||||
def ssl_context(ssl_provider):
|
||||
return ssl_provider.SSLContext(ssl_provider.PROTOCOL_SSLv23)
|
65
wrapper/python/wolfssl/test/test_client.py
Normal file
65
wrapper/python/wolfssl/test/test_client.py
Normal file
@ -0,0 +1,65 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# test_client.py
|
||||
#
|
||||
# Copyright (C) 2006-2017 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
|
||||
|
||||
# pylint: disable=missing-docstring, invalid-name, import-error
|
||||
# pylint: disable=redefined-outer-name
|
||||
|
||||
import pytest
|
||||
|
||||
HOST = "www.python.org"
|
||||
PORT = 443
|
||||
CA_CERTS = "certs/ca-digicert-ev.pem"
|
||||
|
||||
@pytest.fixture(
|
||||
params=["wrap_socket", "wrap_socket_with_ca",
|
||||
"wrap_socket_from_context", "ssl_socket"])
|
||||
def secure_socket(request, ssl_provider, tcp_socket):
|
||||
sock = None
|
||||
|
||||
if request.param == "wrap_socket":
|
||||
sock = ssl_provider.wrap_socket(tcp_socket)
|
||||
|
||||
elif request.param == "wrap_socket_with_ca":
|
||||
sock = ssl_provider.wrap_socket(
|
||||
tcp_socket, cert_reqs=ssl_provider.CERT_REQUIRED, ca_certs=CA_CERTS)
|
||||
|
||||
elif request.param == "wrap_socket_from_context":
|
||||
ctx = ssl_provider.SSLContext(ssl_provider.PROTOCOL_TLSv1_2)
|
||||
|
||||
ctx.verify_mode = ssl_provider.CERT_REQUIRED
|
||||
ctx.load_verify_locations(CA_CERTS)
|
||||
|
||||
sock = ctx.wrap_socket(tcp_socket)
|
||||
|
||||
elif request.param == "ssl_socket":
|
||||
sock = ssl_provider.SSLSocket(
|
||||
tcp_socket, cert_reqs=ssl_provider.CERT_REQUIRED, ca_certs=CA_CERTS)
|
||||
|
||||
if sock:
|
||||
yield sock
|
||||
sock.close()
|
||||
|
||||
def test_secure_connection(secure_socket):
|
||||
secure_socket.connect((HOST, PORT))
|
||||
|
||||
secure_socket.write(b"GET / HTTP/1.1\n\n")
|
||||
assert secure_socket.read(4) == b"HTTP"
|
65
wrapper/python/wolfssl/test/test_context.py
Normal file
65
wrapper/python/wolfssl/test/test_context.py
Normal file
@ -0,0 +1,65 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# test_context.py
|
||||
#
|
||||
# Copyright (C) 2006-2017 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
|
||||
|
||||
# pylint: disable=missing-docstring, invalid-name, import-error
|
||||
# pylint: disable=redefined-outer-name
|
||||
|
||||
import pytest
|
||||
|
||||
with open("certs/ca-cert.pem") as ca:
|
||||
_CADATA = ca.read()
|
||||
|
||||
def test_context_creation(ssl_context):
|
||||
assert ssl_context != None
|
||||
|
||||
def test_verify_mode(ssl_provider, ssl_context):
|
||||
with pytest.raises(ValueError):
|
||||
ssl_context.verify_mode = -1
|
||||
|
||||
assert ssl_context.verify_mode == ssl_provider.CERT_NONE
|
||||
|
||||
ssl_context.verify_mode = ssl_provider.CERT_REQUIRED
|
||||
assert ssl_context.verify_mode == ssl_provider.CERT_REQUIRED
|
||||
|
||||
def test_set_ciphers(ssl_context):
|
||||
ssl_context.set_ciphers("DHE-RSA-AES256-SHA256")
|
||||
|
||||
with pytest.raises(Exception):
|
||||
ssl_context.set_ciphers("foo")
|
||||
|
||||
def test_load_cert_chain_raises(ssl_context):
|
||||
with pytest.raises(TypeError):
|
||||
ssl_context.load_cert_chain(None)
|
||||
|
||||
def test_load_cert_chain(ssl_context):
|
||||
ssl_context.load_cert_chain("certs/client-cert.pem",
|
||||
"certs/client-key.pem")
|
||||
|
||||
def test_load_verify_locations_raises(ssl_context):
|
||||
with pytest.raises(TypeError):
|
||||
ssl_context.load_verify_locations(None)
|
||||
|
||||
def test_load_verify_locations_with_cafile(ssl_context):
|
||||
ssl_context.load_verify_locations(cafile="certs/ca-cert.pem")
|
||||
|
||||
def test_load_verify_locations_with_cadata(ssl_provider, ssl_context):
|
||||
ssl_context.load_verify_locations(cadata=_CADATA)
|
58
wrapper/python/wolfssl/test/test_methods.py
Normal file
58
wrapper/python/wolfssl/test/test_methods.py
Normal file
@ -0,0 +1,58 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# test_methods.py
|
||||
#
|
||||
# Copyright (C) 2006-2017 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
|
||||
|
||||
# pylint: disable=missing-docstring, redefined-outer-name, import-error
|
||||
|
||||
import pytest
|
||||
from wolfssl._methods import (WolfSSLMethod, PROTOCOL_SSLv3, PROTOCOL_SSLv23,
|
||||
PROTOCOL_TLS, PROTOCOL_TLSv1, PROTOCOL_TLSv1_1,
|
||||
PROTOCOL_TLSv1_2)
|
||||
from wolfssl._ffi import ffi as _ffi
|
||||
|
||||
@pytest.fixture(
|
||||
params=[-1, PROTOCOL_SSLv3, PROTOCOL_TLSv1, PROTOCOL_TLSv1_1],
|
||||
ids=["invalid", "SSLv3", "TLSv1", "TLSv1_1"])
|
||||
def unsupported_method(request):
|
||||
yield request.param
|
||||
|
||||
@pytest.fixture(
|
||||
params=[PROTOCOL_SSLv23, PROTOCOL_TLS, PROTOCOL_TLSv1_2],
|
||||
ids=["SSLv23", "TLS", "TLSv1_2"])
|
||||
def supported_method(request):
|
||||
yield request.param
|
||||
|
||||
|
||||
def test_unsupported_method(unsupported_method):
|
||||
with pytest.raises(ValueError):
|
||||
WolfSSLMethod(unsupported_method, False)
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
WolfSSLMethod(unsupported_method, True)
|
||||
|
||||
def test_supported_method(supported_method):
|
||||
client = WolfSSLMethod(supported_method, False)
|
||||
server = WolfSSLMethod(supported_method, True)
|
||||
|
||||
assert isinstance(client, WolfSSLMethod)
|
||||
assert isinstance(server, WolfSSLMethod)
|
||||
assert client.native_object != _ffi.NULL
|
||||
assert server.native_object != _ffi.NULL
|
7
wrapper/python/wolfssl/tox.ini
Normal file
7
wrapper/python/wolfssl/tox.ini
Normal file
@ -0,0 +1,7 @@
|
||||
[tox]
|
||||
envlist=py27,py34,py35,py36
|
||||
skip_missing_interpreters=true
|
||||
|
||||
[testenv]
|
||||
deps=-rrequirements-testing.txt
|
||||
commands=py.test test/ {posargs}
|
Loading…
x
Reference in New Issue
Block a user