Skip to content

Commit

Permalink
Split OpenSSL binding
Browse files Browse the repository at this point in the history
  • Loading branch information
public committed Jan 1, 2014
1 parent c9add40 commit 82c8cc1
Show file tree
Hide file tree
Showing 31 changed files with 233 additions and 144 deletions.
137 changes: 8 additions & 129 deletions cryptography/hazmat/backends/openssl/backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,6 @@
from __future__ import absolute_import, division, print_function

import itertools
import sys

import cffi

from cryptography import utils
from cryptography.exceptions import UnsupportedAlgorithm, InvalidTag
Expand All @@ -30,146 +27,28 @@
from cryptography.hazmat.primitives.ciphers.modes import (
CBC, CTR, ECB, OFB, CFB, GCM,
)

_OSX_PRE_INCLUDE = """
#ifdef __APPLE__
#include <AvailabilityMacros.h>
#define __ORIG_DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER \
DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER
#undef DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER
#define DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER
#endif
"""

_OSX_POST_INCLUDE = """
#ifdef __APPLE__
#undef DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER
#define DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER \
__ORIG_DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER
#endif
"""
from cryptography.hazmat.bindings.openssl.binding import Binding


@utils.register_interface(CipherBackend)
@utils.register_interface(HashBackend)
@utils.register_interface(HMACBackend)
class Backend(object):
"""
OpenSSL API wrapper.
Modules listed in the ``_modules`` listed should have the following
attributes:
* ``INCLUDES``: A string containg C includes.
* ``TYPES``: A string containing C declarations for types.
* ``FUNCTIONS``: A string containing C declarations for functions.
* ``MACROS``: A string containing C declarations for any macros.
* ``CUSTOMIZATIONS``: A string containing arbitrary top-level C code, this
can be used to do things like test for a define and provide an
alternate implementation based on that.
* ``CONDITIONAL_NAMES``: A dict mapping strings of condition names from the
library to a list of names which will not be present without the
condition.
OpenSSL API binding interfaces.
"""
_module_prefix = "cryptography.hazmat.backends.openssl."
_modules = [
"asn1",
"bignum",
"bio",
"conf",
"crypto",
"dh",
"dsa",
"engine",
"err",
"evp",
"hmac",
"nid",
"objects",
"opensslv",
"pem",
"pkcs7",
"pkcs12",
"rand",
"rsa",
"ssl",
"x509",
"x509name",
"x509v3",
]

ffi = None
lib = None

def __init__(self):
self._ensure_ffi_initialized()
self._binding = Binding()
self.ffi = self._binding.ffi
self.lib = self._binding.lib

self.lib.OpenSSL_add_all_algorithms()
self.lib.SSL_load_error_strings()

self._cipher_registry = {}
self._register_default_ciphers()

@classmethod
def _ensure_ffi_initialized(cls):
if cls.ffi is not None and cls.lib is not None:
return

ffi = cffi.FFI()
includes = []
functions = []
macros = []
customizations = []
for name in cls._modules:
module_name = cls._module_prefix + name
__import__(module_name)
module = sys.modules[module_name]

ffi.cdef(module.TYPES)

macros.append(module.MACROS)
functions.append(module.FUNCTIONS)
includes.append(module.INCLUDES)
customizations.append(module.CUSTOMIZATIONS)

# loop over the functions & macros after declaring all the types
# so we can set interdependent types in different files and still
# have them all defined before we parse the funcs & macros
for func in functions:
ffi.cdef(func)
for macro in macros:
ffi.cdef(macro)

# We include functions here so that if we got any of their definitions
# wrong, the underlying C compiler will explode. In C you are allowed
# to re-declare a function if it has the same signature. That is:
# int foo(int);
# int foo(int);
# is legal, but the following will fail to compile:
# int foo(int);
# int foo(short);

lib = ffi.verify(
source="\n".join(
[_OSX_PRE_INCLUDE] +
includes +
[_OSX_POST_INCLUDE] +
functions +
customizations
),
libraries=["crypto", "ssl"],
)

for name in cls._modules:
module_name = cls._module_prefix + name
module = sys.modules[module_name]
for condition, names in module.CONDITIONAL_NAMES.items():
if not getattr(lib, condition):
for name in names:
delattr(lib, name)

cls.ffi = ffi
cls.lib = lib
cls.lib.OpenSSL_add_all_algorithms()
cls.lib.SSL_load_error_strings()

def openssl_version_text(self):
"""
Friendly string name of linked OpenSSL.
Expand Down
12 changes: 12 additions & 0 deletions cryptography/hazmat/bindings/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
# implied.
# See the License for the specific language governing permissions and
# limitations under the License.
12 changes: 12 additions & 0 deletions cryptography/hazmat/bindings/openssl/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
# implied.
# See the License for the specific language governing permissions and
# limitations under the License.
149 changes: 149 additions & 0 deletions cryptography/hazmat/bindings/openssl/binding.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
# implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from __future__ import absolute_import, division, print_function

import sys

import cffi

_OSX_PRE_INCLUDE = """
#ifdef __APPLE__
#include <AvailabilityMacros.h>
#define __ORIG_DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER \
DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER
#undef DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER
#define DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER
#endif
"""

_OSX_POST_INCLUDE = """
#ifdef __APPLE__
#undef DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER
#define DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER \
__ORIG_DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER
#endif
"""


class Binding(object):
"""
OpenSSL API wrapper.
Modules listed in the ``_modules`` listed should have the following
attributes:
* ``INCLUDES``: A string containg C includes.
* ``TYPES``: A string containing C declarations for types.
* ``FUNCTIONS``: A string containing C declarations for functions.
* ``MACROS``: A string containing C declarations for any macros.
* ``CUSTOMIZATIONS``: A string containing arbitrary top-level C code, this
can be used to do things like test for a define and provide an
alternate implementation based on that.
* ``CONDITIONAL_NAMES``: A dict mapping strings of condition names from the
library to a list of names which will not be present without the
condition.
"""
_module_prefix = "cryptography.hazmat.bindings.openssl."
_modules = [
"asn1",
"bignum",
"bio",
"conf",
"crypto",
"dh",
"dsa",
"engine",
"err",
"evp",
"hmac",
"nid",
"objects",
"opensslv",
"pem",
"pkcs7",
"pkcs12",
"rand",
"rsa",
"ssl",
"x509",
"x509name",
"x509v3",
]

ffi = None
lib = None

def __init__(self):
self._ensure_ffi_initialized()

@classmethod
def _ensure_ffi_initialized(cls):
if cls.ffi is not None and cls.lib is not None:
return

ffi = cffi.FFI()
includes = []
functions = []
macros = []
customizations = []
for name in cls._modules:
module_name = cls._module_prefix + name
__import__(module_name)
module = sys.modules[module_name]

ffi.cdef(module.TYPES)

macros.append(module.MACROS)
functions.append(module.FUNCTIONS)
includes.append(module.INCLUDES)
customizations.append(module.CUSTOMIZATIONS)

# loop over the functions & macros after declaring all the types
# so we can set interdependent types in different files and still
# have them all defined before we parse the funcs & macros
for func in functions:
ffi.cdef(func)
for macro in macros:
ffi.cdef(macro)

# We include functions here so that if we got any of their definitions
# wrong, the underlying C compiler will explode. In C you are allowed
# to re-declare a function if it has the same signature. That is:
# int foo(int);
# int foo(int);
# is legal, but the following will fail to compile:
# int foo(int);
# int foo(short);

lib = ffi.verify(
source="\n".join(
[_OSX_PRE_INCLUDE] +
includes +
[_OSX_POST_INCLUDE] +
functions +
customizations
),
libraries=["crypto", "ssl"],
)

for name in cls._modules:
module_name = cls._module_prefix + name
module = sys.modules[module_name]
for condition, names in module.CONDITIONAL_NAMES.items():
if not getattr(lib, condition):
for name in names:
delattr(lib, name)

cls.ffi = ffi
cls.lib = lib
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
17 changes: 2 additions & 15 deletions docs/hazmat/backends/openssl.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,11 @@
OpenSSL Backend
===============

These are `CFFI`_ bindings to the `OpenSSL`_ C library.
The `OpenSSL`_ C library.

.. data:: cryptography.hazmat.backends.openssl.backend

This is the exposed API for the OpenSSL bindings. It has two public
attributes:

.. attribute:: ffi

This is a :class:`cffi.FFI` instance. It can be used to allocate and
otherwise manipulate OpenSSL structures.

.. attribute:: lib

This is a ``cffi`` library. It can be used to call OpenSSL functions,
and access constants.

This is the exposed API for the OpenSSL backend. It has no public attributes.

Using your own OpenSSL on Linux
-------------------------------
Expand Down Expand Up @@ -48,5 +36,4 @@ You'll also need to generate your own ``openssl.ld`` file. For example::
You should replace the version string on the first line as appropriate for your
build.

.. _`CFFI`: https://cffi.readthedocs.org/
.. _`OpenSSL`: https://www.openssl.org/

0 comments on commit 82c8cc1

Please sign in to comment.