Merge pull request #683 from moisesguimaraes/wolfssl-py

wolfssl python wrapper
This commit is contained in:
Chris Conlon 2017-07-19 09:22:02 -07:00 committed by GitHub
commit 667b8431cc
38 changed files with 2610 additions and 12 deletions

23
certs/external/ca-digicert-ev.pem vendored Normal file
View 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-----

View File

@ -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

View File

@ -13,3 +13,6 @@ dist/
.tox/
# Sphinx documentation
docs/_build/
# Virtual env
.env

View File

@ -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")

View 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
View 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/

View 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

View File

@ -0,0 +1,23 @@
Licensing
=========
wolfSSLs 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.

View File

@ -0,0 +1,2 @@
include LICENSING.rst
recursive-include certs *.pem

View 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

View 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
View 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

View 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."

View 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:

View 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'

View 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()

View File

@ -0,0 +1,8 @@
.. toctree::
:maxdepth: 2
installation
usage
api
examples
licensing

View File

@ -0,0 +1 @@
.. include:: ../README.rst

View File

@ -0,0 +1 @@
.. include:: ../LICENSING.rst

View File

@ -0,0 +1,2 @@
Sphinx
sphinx_rtd_theme

View 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()

View 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()

View 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()

View 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

View File

@ -0,0 +1,3 @@
pytest
cffi
tox

87
wrapper/python/wolfssl/setup.py Executable file
View 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)

View 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())

View 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 servers 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.
Heres 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)

View 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)

View 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)

View 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)

View 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

View 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")

View 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)

View 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"

View 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)

View 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

View 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}