blob: ff9039cfad210c875f1250da0f553432e7ecfb7e [file] [log] [blame]
# 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 os
import sys
import threading
from cryptography.hazmat.bindings.utils import (
build_ffi_for_binding, load_library_for_binding,
)
_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
"""
def _get_libraries(platform):
# OpenSSL goes by a different library name on different operating systems.
if platform != "win32":
# In some circumstances, the order in which these libs are
# specified on the linker command-line is significant;
# libssl must come before libcrypto
# (http://marc.info/?l=openssl-users&m=135361825921871)
return ["ssl", "crypto"]
else:
link_type = os.environ.get("PYCA_WINDOWS_LINK_TYPE", "static")
return _get_windows_libraries(link_type)
def _get_windows_libraries(link_type):
if link_type == "dynamic":
return ["libeay32", "ssleay32", "advapi32"]
elif link_type == "static" or link_type == "":
return ["libeay32mt", "ssleay32mt", "advapi32",
"crypt32", "gdi32", "user32", "ws2_32"]
else:
raise ValueError(
"PYCA_WINDOWS_LINK_TYPE must be 'static' or 'dynamic'"
)
class Binding(object):
"""
OpenSSL API wrapper.
"""
_module_prefix = "cryptography.hazmat.bindings.openssl."
_modules = [
"aes",
"asn1",
"bignum",
"bio",
"cmac",
"cms",
"conf",
"crypto",
"dh",
"dsa",
"ec",
"ecdh",
"ecdsa",
"engine",
"err",
"evp",
"hmac",
"nid",
"objects",
"opensslv",
"osrandom_engine",
"pem",
"pkcs7",
"pkcs12",
"rand",
"rsa",
"ssl",
"x509",
"x509name",
"x509v3",
"x509_vfy"
]
_locks = None
_lock_cb_handle = None
_lock_init_lock = threading.Lock()
ffi = build_ffi_for_binding(
module_prefix=_module_prefix,
modules=_modules,
pre_include=_OSX_PRE_INCLUDE,
post_include=_OSX_POST_INCLUDE,
libraries=_get_libraries(sys.platform)
)
lib = None
def __init__(self):
self._ensure_ffi_initialized()
@classmethod
def _ensure_ffi_initialized(cls):
if cls.lib is not None:
return
cls.lib = load_library_for_binding(
cls.ffi,
cls._module_prefix,
cls._modules,
)
res = cls.lib.Cryptography_add_osrandom_engine()
assert res != 0
@classmethod
def init_static_locks(cls):
with cls._lock_init_lock:
cls._ensure_ffi_initialized()
if not cls._lock_cb_handle:
cls._lock_cb_handle = cls.ffi.callback(
"void(int, int, const char *, int)",
cls._lock_cb
)
# Use Python's implementation if available, importing _ssl triggers
# the setup for this.
__import__("_ssl")
if cls.lib.CRYPTO_get_locking_callback() != cls.ffi.NULL:
return
# If nothing else has setup a locking callback already, we set up
# our own
num_locks = cls.lib.CRYPTO_num_locks()
cls._locks = [threading.Lock() for n in range(num_locks)]
cls.lib.CRYPTO_set_locking_callback(cls._lock_cb_handle)
@classmethod
def _lock_cb(cls, mode, n, file, line):
lock = cls._locks[n]
if mode & cls.lib.CRYPTO_LOCK:
lock.acquire()
elif mode & cls.lib.CRYPTO_UNLOCK:
lock.release()
else:
raise RuntimeError(
"Unknown lock mode {0}: lock={1}, file={2}, line={3}.".format(
mode, n, file, line
)
)