update Linux_x86_64

This commit is contained in:
j 2015-11-04 12:58:41 +01:00
parent 93422b0274
commit e7ebbedd38
336 changed files with 34353 additions and 21020 deletions

1
.gitignore vendored
View file

@ -3,3 +3,4 @@
*.pyo *.pyo
*.pyd *.pyd
__pycache__ __pycache__
pip_cache

View file

@ -1,29 +1,39 @@
from sys import platform from sys import platform
from functools import wraps, partial from functools import wraps, partial
from itertools import count from itertools import count, chain
from weakref import WeakValueDictionary from weakref import WeakValueDictionary
from errno import errorcode from errno import errorcode
from six import text_type as _text_type from six import text_type as _text_type
from six import binary_type as _binary_type
from six import integer_types as integer_types from six import integer_types as integer_types
from six import int2byte, indexbytes
from OpenSSL._util import ( from OpenSSL._util import (
ffi as _ffi, ffi as _ffi,
lib as _lib, lib as _lib,
exception_from_error_queue as _exception_from_error_queue, exception_from_error_queue as _exception_from_error_queue,
native as _native) native as _native,
text_to_bytes_and_warn as _text_to_bytes_and_warn,
path_string as _path_string,
UNSPECIFIED as _UNSPECIFIED,
)
from OpenSSL.crypto import ( from OpenSSL.crypto import (
FILETYPE_PEM, _PassphraseHelper, PKey, X509Name, X509, X509Store) FILETYPE_PEM, _PassphraseHelper, PKey, X509Name, X509, X509Store)
_unspecified = object()
try: try:
_memoryview = memoryview _memoryview = memoryview
except NameError: except NameError:
class _memoryview(object): class _memoryview(object):
pass pass
try:
_buffer = buffer
except NameError:
class _buffer(object):
pass
OPENSSL_VERSION_NUMBER = _lib.OPENSSL_VERSION_NUMBER OPENSSL_VERSION_NUMBER = _lib.OPENSSL_VERSION_NUMBER
SSLEAY_VERSION = _lib.SSLEAY_VERSION SSLEAY_VERSION = _lib.SSLEAY_VERSION
SSLEAY_CFLAGS = _lib.SSLEAY_CFLAGS SSLEAY_CFLAGS = _lib.SSLEAY_CFLAGS
@ -81,7 +91,10 @@ except AttributeError:
OP_NO_QUERY_MTU = _lib.SSL_OP_NO_QUERY_MTU OP_NO_QUERY_MTU = _lib.SSL_OP_NO_QUERY_MTU
OP_COOKIE_EXCHANGE = _lib.SSL_OP_COOKIE_EXCHANGE OP_COOKIE_EXCHANGE = _lib.SSL_OP_COOKIE_EXCHANGE
OP_NO_TICKET = _lib.SSL_OP_NO_TICKET try:
OP_NO_TICKET = _lib.SSL_OP_NO_TICKET
except AttributeError:
pass
OP_ALL = _lib.SSL_OP_ALL OP_ALL = _lib.SSL_OP_ALL
@ -121,7 +134,6 @@ SSL_CB_CONNECT_EXIT = _lib.SSL_CB_CONNECT_EXIT
SSL_CB_HANDSHAKE_START = _lib.SSL_CB_HANDSHAKE_START SSL_CB_HANDSHAKE_START = _lib.SSL_CB_HANDSHAKE_START
SSL_CB_HANDSHAKE_DONE = _lib.SSL_CB_HANDSHAKE_DONE SSL_CB_HANDSHAKE_DONE = _lib.SSL_CB_HANDSHAKE_DONE
class Error(Exception): class Error(Exception):
""" """
An error occurred in an `OpenSSL.SSL` API. An error occurred in an `OpenSSL.SSL` API.
@ -156,11 +168,42 @@ class SysCallError(Error):
pass pass
class _CallbackExceptionHelper(object):
"""
A base class for wrapper classes that allow for intelligent exception
handling in OpenSSL callbacks.
class _VerifyHelper(object): :ivar list _problems: Any exceptions that occurred while executing in a
def __init__(self, connection, callback): context where they could not be raised in the normal way. Typically
this is because OpenSSL has called into some Python code and requires a
return value. The exceptions are saved to be raised later when it is
possible to do so.
"""
def __init__(self):
self._problems = [] self._problems = []
def raise_if_problem(self):
"""
Raise an exception from the OpenSSL error queue or that was previously
captured whe running a callback.
"""
if self._problems:
try:
_raise_current_error()
except Error:
pass
raise self._problems.pop(0)
class _VerifyHelper(_CallbackExceptionHelper):
"""
Wrap a callback such that it can be used as a certificate verification
callback.
"""
def __init__(self, callback):
_CallbackExceptionHelper.__init__(self)
@wraps(callback) @wraps(callback)
def wrapper(ok, store_ctx): def wrapper(ok, store_ctx):
cert = X509.__new__(X509) cert = X509.__new__(X509)
@ -168,6 +211,10 @@ class _VerifyHelper(object):
error_number = _lib.X509_STORE_CTX_get_error(store_ctx) error_number = _lib.X509_STORE_CTX_get_error(store_ctx)
error_depth = _lib.X509_STORE_CTX_get_error_depth(store_ctx) error_depth = _lib.X509_STORE_CTX_get_error_depth(store_ctx)
index = _lib.SSL_get_ex_data_X509_STORE_CTX_idx()
ssl = _lib.X509_STORE_CTX_get_ex_data(store_ctx, index)
connection = Connection._reverse_mapping[ssl]
try: try:
result = callback(connection, cert, error_number, error_depth, ok) result = callback(connection, cert, error_number, error_depth, ok)
except Exception as e: except Exception as e:
@ -184,14 +231,142 @@ class _VerifyHelper(object):
"int (*)(int, X509_STORE_CTX *)", wrapper) "int (*)(int, X509_STORE_CTX *)", wrapper)
def raise_if_problem(self): class _NpnAdvertiseHelper(_CallbackExceptionHelper):
if self._problems: """
try: Wrap a callback such that it can be used as an NPN advertisement callback.
_raise_current_error() """
except Error: def __init__(self, callback):
pass _CallbackExceptionHelper.__init__(self)
raise self._problems.pop(0)
@wraps(callback)
def wrapper(ssl, out, outlen, arg):
try:
conn = Connection._reverse_mapping[ssl]
protos = callback(conn)
# Join the protocols into a Python bytestring, length-prefixing
# each element.
protostr = b''.join(
chain.from_iterable((int2byte(len(p)), p) for p in protos)
)
# Save our callback arguments on the connection object. This is
# done to make sure that they don't get freed before OpenSSL
# uses them. Then, return them appropriately in the output
# parameters.
conn._npn_advertise_callback_args = [
_ffi.new("unsigned int *", len(protostr)),
_ffi.new("unsigned char[]", protostr),
]
outlen[0] = conn._npn_advertise_callback_args[0][0]
out[0] = conn._npn_advertise_callback_args[1]
return 0
except Exception as e:
self._problems.append(e)
return 2 # SSL_TLSEXT_ERR_ALERT_FATAL
self.callback = _ffi.callback(
"int (*)(SSL *, const unsigned char **, unsigned int *, void *)",
wrapper
)
class _NpnSelectHelper(_CallbackExceptionHelper):
"""
Wrap a callback such that it can be used as an NPN selection callback.
"""
def __init__(self, callback):
_CallbackExceptionHelper.__init__(self)
@wraps(callback)
def wrapper(ssl, out, outlen, in_, inlen, arg):
try:
conn = Connection._reverse_mapping[ssl]
# The string passed to us is actually made up of multiple
# length-prefixed bytestrings. We need to split that into a
# list.
instr = _ffi.buffer(in_, inlen)[:]
protolist = []
while instr:
l = indexbytes(instr, 0)
proto = instr[1:l+1]
protolist.append(proto)
instr = instr[l+1:]
# Call the callback
outstr = callback(conn, protolist)
# Save our callback arguments on the connection object. This is
# done to make sure that they don't get freed before OpenSSL
# uses them. Then, return them appropriately in the output
# parameters.
conn._npn_select_callback_args = [
_ffi.new("unsigned char *", len(outstr)),
_ffi.new("unsigned char[]", outstr),
]
outlen[0] = conn._npn_select_callback_args[0][0]
out[0] = conn._npn_select_callback_args[1]
return 0
except Exception as e:
self._problems.append(e)
return 2 # SSL_TLSEXT_ERR_ALERT_FATAL
self.callback = _ffi.callback(
"int (*)(SSL *, unsigned char **, unsigned char *, "
"const unsigned char *, unsigned int, void *)",
wrapper
)
class _ALPNSelectHelper(_CallbackExceptionHelper):
"""
Wrap a callback such that it can be used as an ALPN selection callback.
"""
def __init__(self, callback):
_CallbackExceptionHelper.__init__(self)
@wraps(callback)
def wrapper(ssl, out, outlen, in_, inlen, arg):
try:
conn = Connection._reverse_mapping[ssl]
# The string passed to us is made up of multiple
# length-prefixed bytestrings. We need to split that into a
# list.
instr = _ffi.buffer(in_, inlen)[:]
protolist = []
while instr:
encoded_len = indexbytes(instr, 0)
proto = instr[1:encoded_len + 1]
protolist.append(proto)
instr = instr[encoded_len + 1:]
# Call the callback
outstr = callback(conn, protolist)
if not isinstance(outstr, _binary_type):
raise TypeError("ALPN callback must return a bytestring.")
# Save our callback arguments on the connection object to make
# sure that they don't get freed before OpenSSL can use them.
# Then, return them in the appropriate output parameters.
conn._alpn_select_callback_args = [
_ffi.new("unsigned char *", len(outstr)),
_ffi.new("unsigned char[]", outstr),
]
outlen[0] = conn._alpn_select_callback_args[0][0]
out[0] = conn._alpn_select_callback_args[1]
return 0
except Exception as e:
self._problems.append(e)
return 2 # SSL_TLSEXT_ERR_ALERT_FATAL
self.callback = _ffi.callback(
"int (*)(SSL *, unsigned char **, unsigned char *, "
"const unsigned char *, unsigned int, void *)",
wrapper
)
def _asFileDescriptor(obj): def _asFileDescriptor(obj):
@ -223,6 +398,37 @@ def SSLeay_version(type):
return _ffi.string(_lib.SSLeay_version(type)) return _ffi.string(_lib.SSLeay_version(type))
def _requires_npn(func):
"""
Wraps any function that requires NPN support in OpenSSL, ensuring that
NotImplementedError is raised if NPN is not present.
"""
@wraps(func)
def wrapper(*args, **kwargs):
if not _lib.Cryptography_HAS_NEXTPROTONEG:
raise NotImplementedError("NPN not available.")
return func(*args, **kwargs)
return wrapper
def _requires_alpn(func):
"""
Wraps any function that requires ALPN support in OpenSSL, ensuring that
NotImplementedError is raised if ALPN support is not present.
"""
@wraps(func)
def wrapper(*args, **kwargs):
if not _lib.Cryptography_HAS_ALPN:
raise NotImplementedError("ALPN not available.")
return func(*args, **kwargs)
return wrapper
class Session(object): class Session(object):
pass pass
@ -235,6 +441,7 @@ class Context(object):
new SSL connections. new SSL connections.
""" """
_methods = { _methods = {
SSLv2_METHOD: "SSLv2_method",
SSLv3_METHOD: "SSLv3_method", SSLv3_METHOD: "SSLv3_method",
SSLv23_METHOD: "SSLv23_method", SSLv23_METHOD: "SSLv23_method",
TLSv1_METHOD: "TLSv1_method", TLSv1_METHOD: "TLSv1_method",
@ -280,6 +487,12 @@ class Context(object):
self._info_callback = None self._info_callback = None
self._tlsext_servername_callback = None self._tlsext_servername_callback = None
self._app_data = None self._app_data = None
self._npn_advertise_helper = None
self._npn_advertise_callback = None
self._npn_select_helper = None
self._npn_select_callback = None
self._alpn_select_helper = None
self._alpn_select_callback = None
# SSL_CTX_set_app_data(self->ctx, self); # SSL_CTX_set_app_data(self->ctx, self);
# SSL_CTX_set_mode(self->ctx, SSL_MODE_ENABLE_PARTIAL_WRITE | # SSL_CTX_set_mode(self->ctx, SSL_MODE_ENABLE_PARTIAL_WRITE |
@ -293,19 +506,22 @@ class Context(object):
Let SSL know where we can find trusted certificates for the certificate Let SSL know where we can find trusted certificates for the certificate
chain chain
:param cafile: In which file we can find the certificates :param cafile: In which file we can find the certificates (``bytes`` or
``unicode``).
:param capath: In which directory we can find the certificates :param capath: In which directory we can find the certificates
(``bytes`` or ``unicode``).
:return: None :return: None
""" """
if cafile is None: if cafile is None:
cafile = _ffi.NULL cafile = _ffi.NULL
elif not isinstance(cafile, bytes): else:
raise TypeError("cafile must be None or a byte string") cafile = _path_string(cafile)
if capath is None: if capath is None:
capath = _ffi.NULL capath = _ffi.NULL
elif not isinstance(capath, bytes): else:
raise TypeError("capath must be None or a byte string") capath = _path_string(capath)
load_result = _lib.SSL_CTX_load_verify_locations(self._context, cafile, capath) load_result = _lib.SSL_CTX_load_verify_locations(self._context, cafile, capath)
if not load_result: if not load_result:
@ -355,15 +571,12 @@ class Context(object):
""" """
Load a certificate chain from a file Load a certificate chain from a file
:param certfile: The name of the certificate chain file :param certfile: The name of the certificate chain file (``bytes`` or
``unicode``).
:return: None :return: None
""" """
if isinstance(certfile, _text_type): certfile = _path_string(certfile)
# Perhaps sys.getfilesystemencoding() could be better?
certfile = certfile.encode("utf-8")
if not isinstance(certfile, bytes):
raise TypeError("certfile must be bytes or unicode")
result = _lib.SSL_CTX_use_certificate_chain_file(self._context, certfile) result = _lib.SSL_CTX_use_certificate_chain_file(self._context, certfile)
if not result: if not result:
@ -374,15 +587,13 @@ class Context(object):
""" """
Load a certificate from a file Load a certificate from a file
:param certfile: The name of the certificate file :param certfile: The name of the certificate file (``bytes`` or
``unicode``).
:param filetype: (optional) The encoding of the file, default is PEM :param filetype: (optional) The encoding of the file, default is PEM
:return: None :return: None
""" """
if isinstance(certfile, _text_type): certfile = _path_string(certfile)
# Perhaps sys.getfilesystemencoding() could be better?
certfile = certfile.encode("utf-8")
if not isinstance(certfile, bytes):
raise TypeError("certfile must be bytes or unicode")
if not isinstance(filetype, integer_types): if not isinstance(filetype, integer_types):
raise TypeError("filetype must be an integer") raise TypeError("filetype must be an integer")
@ -432,22 +643,18 @@ class Context(object):
raise exception raise exception
def use_privatekey_file(self, keyfile, filetype=_unspecified): def use_privatekey_file(self, keyfile, filetype=_UNSPECIFIED):
""" """
Load a private key from a file Load a private key from a file
:param keyfile: The name of the key file :param keyfile: The name of the key file (``bytes`` or ``unicode``)
:param filetype: (optional) The encoding of the file, default is PEM :param filetype: (optional) The encoding of the file, default is PEM
:return: None :return: None
""" """
if isinstance(keyfile, _text_type): keyfile = _path_string(keyfile)
# Perhaps sys.getfilesystemencoding() could be better?
keyfile = keyfile.encode("utf-8")
if not isinstance(keyfile, bytes): if filetype is _UNSPECIFIED:
raise TypeError("keyfile must be a byte string")
if filetype is _unspecified:
filetype = FILETYPE_PEM filetype = FILETYPE_PEM
elif not isinstance(filetype, integer_types): elif not isinstance(filetype, integer_types):
raise TypeError("filetype must be an integer") raise TypeError("filetype must be an integer")
@ -479,6 +686,9 @@ class Context(object):
:return: None (raises an exception if something's wrong) :return: None (raises an exception if something's wrong)
""" """
if not _lib.SSL_CTX_check_private_key(self._context):
_raise_current_error()
def load_client_ca(self, cafile): def load_client_ca(self, cafile):
""" """
@ -538,7 +748,7 @@ class Context(object):
if not callable(callback): if not callable(callback):
raise TypeError("callback must be callable") raise TypeError("callback must be callable")
self._verify_helper = _VerifyHelper(self, callback) self._verify_helper = _VerifyHelper(callback)
self._verify_callback = self._verify_helper.callback self._verify_callback = self._verify_helper.callback
_lib.SSL_CTX_set_verify(self._context, mode, self._verify_callback) _lib.SSL_CTX_set_verify(self._context, mode, self._verify_callback)
@ -578,11 +788,12 @@ class Context(object):
""" """
Load parameters for Ephemeral Diffie-Hellman Load parameters for Ephemeral Diffie-Hellman
:param dhfile: The file to load EDH parameters from :param dhfile: The file to load EDH parameters from (``bytes`` or
``unicode``).
:return: None :return: None
""" """
if not isinstance(dhfile, bytes): dhfile = _path_string(dhfile)
raise TypeError("dhfile must be a byte string")
bio = _lib.BIO_new_file(dhfile, b"r") bio = _lib.BIO_new_file(dhfile, b"r")
if bio == _ffi.NULL: if bio == _ffi.NULL:
@ -594,6 +805,19 @@ class Context(object):
_lib.SSL_CTX_set_tmp_dh(self._context, dh) _lib.SSL_CTX_set_tmp_dh(self._context, dh)
def set_tmp_ecdh(self, curve):
"""
Select a curve to use for ECDHE key exchange.
:param curve: A curve object to use as returned by either
:py:meth:`OpenSSL.crypto.get_elliptic_curve` or
:py:meth:`OpenSSL.crypto.get_elliptic_curves`.
:return: None
"""
_lib.SSL_CTX_set_tmp_ecdh(self._context, curve._to_EC_KEY())
def set_cipher_list(self, cipher_list): def set_cipher_list(self, cipher_list):
""" """
Change the cipher list Change the cipher list
@ -783,6 +1007,79 @@ class Context(object):
_lib.SSL_CTX_set_tlsext_servername_callback( _lib.SSL_CTX_set_tlsext_servername_callback(
self._context, self._tlsext_servername_callback) self._context, self._tlsext_servername_callback)
@_requires_npn
def set_npn_advertise_callback(self, callback):
"""
Specify a callback function that will be called when offering `Next
Protocol Negotiation
<https://technotes.googlecode.com/git/nextprotoneg.html>`_ as a server.
:param callback: The callback function. It will be invoked with one
argument, the Connection instance. It should return a list of
bytestrings representing the advertised protocols, like
``[b'http/1.1', b'spdy/2']``.
"""
self._npn_advertise_helper = _NpnAdvertiseHelper(callback)
self._npn_advertise_callback = self._npn_advertise_helper.callback
_lib.SSL_CTX_set_next_protos_advertised_cb(
self._context, self._npn_advertise_callback, _ffi.NULL)
@_requires_npn
def set_npn_select_callback(self, callback):
"""
Specify a callback function that will be called when a server offers
Next Protocol Negotiation options.
:param callback: The callback function. It will be invoked with two
arguments: the Connection, and a list of offered protocols as
bytestrings, e.g. ``[b'http/1.1', b'spdy/2']``. It should return
one of those bytestrings, the chosen protocol.
"""
self._npn_select_helper = _NpnSelectHelper(callback)
self._npn_select_callback = self._npn_select_helper.callback
_lib.SSL_CTX_set_next_proto_select_cb(
self._context, self._npn_select_callback, _ffi.NULL)
@_requires_alpn
def set_alpn_protos(self, protos):
"""
Specify the clients ALPN protocol list.
These protocols are offered to the server during protocol negotiation.
:param protos: A list of the protocols to be offered to the server.
This list should be a Python list of bytestrings representing the
protocols to offer, e.g. ``[b'http/1.1', b'spdy/2']``.
"""
# Take the list of protocols and join them together, prefixing them
# with their lengths.
protostr = b''.join(
chain.from_iterable((int2byte(len(p)), p) for p in protos)
)
# Build a C string from the list. We don't need to save this off
# because OpenSSL immediately copies the data out.
input_str = _ffi.new("unsigned char[]", protostr)
input_str_len = _ffi.cast("unsigned", len(protostr))
_lib.SSL_CTX_set_alpn_protos(self._context, input_str, input_str_len)
@_requires_alpn
def set_alpn_select_callback(self, callback):
"""
Set the callback to handle ALPN protocol choice.
:param callback: The callback function. It will be invoked with two
arguments: the Connection, and a list of offered protocols as
bytestrings, e.g ``[b'http/1.1', b'spdy/2']``. It should return
one of those bytestrings, the chosen protocol.
"""
self._alpn_select_helper = _ALPNSelectHelper(callback)
self._alpn_select_callback = self._alpn_select_helper.callback
_lib.SSL_CTX_set_alpn_select_cb(
self._context, self._alpn_select_callback, _ffi.NULL)
ContextType = Context ContextType = Context
@ -807,6 +1104,19 @@ class Connection(object):
self._ssl = _ffi.gc(ssl, _lib.SSL_free) self._ssl = _ffi.gc(ssl, _lib.SSL_free)
self._context = context self._context = context
# References to strings used for Next Protocol Negotiation. OpenSSL's
# header files suggest that these might get copied at some point, but
# doesn't specify when, so we store them here to make sure they don't
# get freed before OpenSSL uses them.
self._npn_advertise_callback_args = None
self._npn_select_callback_args = None
# References to strings used for Application Layer Protocol
# Negotiation. These strings get copied at some point but it's well
# after the callback returns, so we have to hang them somewhere to
# avoid them getting freed.
self._alpn_select_callback_args = None
self._reverse_mapping[self._ssl] = self self._reverse_mapping[self._ssl] = self
if socket is None: if socket is None:
@ -841,6 +1151,12 @@ class Connection(object):
def _raise_ssl_error(self, ssl, result): def _raise_ssl_error(self, ssl, result):
if self._context._verify_helper is not None: if self._context._verify_helper is not None:
self._context._verify_helper.raise_if_problem() self._context._verify_helper.raise_if_problem()
if self._context._npn_advertise_helper is not None:
self._context._npn_advertise_helper.raise_if_problem()
if self._context._npn_select_helper is not None:
self._context._npn_select_helper.raise_if_problem()
if self._context._alpn_select_helper is not None:
self._context._alpn_select_helper.raise_if_problem()
error = _lib.SSL_get_error(ssl, result) error = _lib.SSL_get_error(ssl, result)
if error == _lib.SSL_ERROR_WANT_READ: if error == _lib.SSL_ERROR_WANT_READ:
@ -859,7 +1175,7 @@ class Connection(object):
errno = _ffi.getwinerror()[0] errno = _ffi.getwinerror()[0]
else: else:
errno = _ffi.errno errno = _ffi.errno
raise SysCallError(errno, errorcode[errno]) raise SysCallError(errno, errorcode.get(errno))
else: else:
raise SysCallError(-1, "Unexpected EOF") raise SysCallError(-1, "Unexpected EOF")
else: else:
@ -936,15 +1252,20 @@ class Connection(object):
WantWrite or WantX509Lookup exceptions on this, you have to call the WantWrite or WantX509Lookup exceptions on this, you have to call the
method again with the SAME buffer. method again with the SAME buffer.
:param buf: The string to send :param buf: The string, buffer or memoryview to send
:param flags: (optional) Included for compatibility with the socket :param flags: (optional) Included for compatibility with the socket
API, the value is ignored API, the value is ignored
:return: The number of bytes written :return: The number of bytes written
""" """
# Backward compatibility
buf = _text_to_bytes_and_warn("buf", buf)
if isinstance(buf, _memoryview): if isinstance(buf, _memoryview):
buf = buf.tobytes() buf = buf.tobytes()
if isinstance(buf, _buffer):
buf = str(buf)
if not isinstance(buf, bytes): if not isinstance(buf, bytes):
raise TypeError("data must be a byte string") raise TypeError("data must be a memoryview, buffer or byte string")
result = _lib.SSL_write(self._ssl, buf, len(buf)) result = _lib.SSL_write(self._ssl, buf, len(buf))
self._raise_ssl_error(self._ssl, result) self._raise_ssl_error(self._ssl, result)
@ -958,15 +1279,19 @@ class Connection(object):
all data is sent. If an error occurs, it's impossible to tell how much all data is sent. If an error occurs, it's impossible to tell how much
data has been sent. data has been sent.
:param buf: The string to send :param buf: The string, buffer or memoryview to send
:param flags: (optional) Included for compatibility with the socket :param flags: (optional) Included for compatibility with the socket
API, the value is ignored API, the value is ignored
:return: The number of bytes written :return: The number of bytes written
""" """
buf = _text_to_bytes_and_warn("buf", buf)
if isinstance(buf, _memoryview): if isinstance(buf, _memoryview):
buf = buf.tobytes() buf = buf.tobytes()
if isinstance(buf, _buffer):
buf = str(buf)
if not isinstance(buf, bytes): if not isinstance(buf, bytes):
raise TypeError("buf must be a byte string") raise TypeError("buf must be a memoryview, buffer or byte string")
left_to_send = len(buf) left_to_send = len(buf)
total_sent = 0 total_sent = 0
@ -997,6 +1322,45 @@ class Connection(object):
read = recv read = recv
def recv_into(self, buffer, nbytes=None, flags=None):
"""
Receive data on the connection and store the data into a buffer rather
than creating a new string.
:param buffer: The buffer to copy into.
:param nbytes: (optional) The maximum number of bytes to read into the
buffer. If not present, defaults to the size of the buffer. If
larger than the size of the buffer, is reduced to the size of the
buffer.
:param flags: (optional) Included for compatibility with the socket
API, the value is ignored.
:return: The number of bytes read into the buffer.
"""
if nbytes is None:
nbytes = len(buffer)
else:
nbytes = min(nbytes, len(buffer))
# We need to create a temporary buffer. This is annoying, it would be
# better if we could pass memoryviews straight into the SSL_read call,
# but right now we can't. Revisit this if CFFI gets that ability.
buf = _ffi.new("char[]", nbytes)
result = _lib.SSL_read(self._ssl, buf, nbytes)
self._raise_ssl_error(self._ssl, result)
# This strange line is all to avoid a memory copy. The buffer protocol
# should allow us to assign a CFFI buffer to the LHS of this line, but
# on CPython 3.3+ that segfaults. As a workaround, we can temporarily
# wrap it in a memoryview, except on Python 2.6 which doesn't have a
# memoryview type.
try:
buffer[:result] = memoryview(_ffi.buffer(buf, result))
except NameError:
buffer[:result] = _ffi.buffer(buf, result)
return result
def _handle_bio_errors(self, bio, result): def _handle_bio_errors(self, bio, result):
if _lib.BIO_should_retry(bio): if _lib.BIO_should_retry(bio):
if _lib.BIO_should_read(bio): if _lib.BIO_should_read(bio):
@ -1046,6 +1410,8 @@ class Connection(object):
:param buf: The string to put into the memory BIO. :param buf: The string to put into the memory BIO.
:return: The number of bytes written :return: The number of bytes written
""" """
buf = _text_to_bytes_and_warn("buf", buf)
if self._into_ssl is None: if self._into_ssl is None:
raise TypeError("Connection sock was not None") raise TypeError("Connection sock was not None")
@ -1153,8 +1519,7 @@ class Connection(object):
""" """
result = _lib.SSL_shutdown(self._ssl) result = _lib.SSL_shutdown(self._ssl)
if result < 0: if result < 0:
# TODO: This is untested. self._raise_ssl_error(self._ssl, result)
_raise_current_error()
elif result > 0: elif result > 0:
return True return True
else: else:
@ -1210,7 +1575,7 @@ class Connection(object):
The makefile() method is not implemented, since there is no dup semantics The makefile() method is not implemented, since there is no dup semantics
for SSL connections for SSL connections
:raise NotImplementedError :raise: NotImplementedError
""" """
raise NotImplementedError("Cannot make file object of OpenSSL.SSL.Connection") raise NotImplementedError("Cannot make file object of OpenSSL.SSL.Connection")
@ -1416,6 +1781,166 @@ class Connection(object):
if not result: if not result:
_raise_current_error() _raise_current_error()
def _get_finished_message(self, function):
"""
Helper to implement :py:meth:`get_finished` and
:py:meth:`get_peer_finished`.
:param function: Either :py:data:`SSL_get_finished`: or
:py:data:`SSL_get_peer_finished`.
:return: :py:data:`None` if the desired message has not yet been
received, otherwise the contents of the message.
:rtype: :py:class:`bytes` or :py:class:`NoneType`
"""
# The OpenSSL documentation says nothing about what might happen if the
# count argument given is zero. Specifically, it doesn't say whether
# the output buffer may be NULL in that case or not. Inspection of the
# implementation reveals that it calls memcpy() unconditionally.
# Section 7.1.4, paragraph 1 of the C standard suggests that
# memcpy(NULL, source, 0) is not guaranteed to produce defined (let
# alone desirable) behavior (though it probably does on just about
# every implementation...)
#
# Allocate a tiny buffer to pass in (instead of just passing NULL as
# one might expect) for the initial call so as to be safe against this
# potentially undefined behavior.
empty = _ffi.new("char[]", 0)
size = function(self._ssl, empty, 0)
if size == 0:
# No Finished message so far.
return None
buf = _ffi.new("char[]", size)
function(self._ssl, buf, size)
return _ffi.buffer(buf, size)[:]
def get_finished(self):
"""
Obtain the latest `handshake finished` message sent to the peer.
:return: The contents of the message or :py:obj:`None` if the TLS
handshake has not yet completed.
:rtype: :py:class:`bytes` or :py:class:`NoneType`
"""
return self._get_finished_message(_lib.SSL_get_finished)
def get_peer_finished(self):
"""
Obtain the latest `handshake finished` message received from the peer.
:return: The contents of the message or :py:obj:`None` if the TLS
handshake has not yet completed.
:rtype: :py:class:`bytes` or :py:class:`NoneType`
"""
return self._get_finished_message(_lib.SSL_get_peer_finished)
def get_cipher_name(self):
"""
Obtain the name of the currently used cipher.
:returns: The name of the currently used cipher or :py:obj:`None`
if no connection has been established.
:rtype: :py:class:`unicode` or :py:class:`NoneType`
"""
cipher = _lib.SSL_get_current_cipher(self._ssl)
if cipher == _ffi.NULL:
return None
else:
name = _ffi.string(_lib.SSL_CIPHER_get_name(cipher))
return name.decode("utf-8")
def get_cipher_bits(self):
"""
Obtain the number of secret bits of the currently used cipher.
:returns: The number of secret bits of the currently used cipher
or :py:obj:`None` if no connection has been established.
:rtype: :py:class:`int` or :py:class:`NoneType`
"""
cipher = _lib.SSL_get_current_cipher(self._ssl)
if cipher == _ffi.NULL:
return None
else:
return _lib.SSL_CIPHER_get_bits(cipher, _ffi.NULL)
def get_cipher_version(self):
"""
Obtain the protocol version of the currently used cipher.
:returns: The protocol name of the currently used cipher
or :py:obj:`None` if no connection has been established.
:rtype: :py:class:`unicode` or :py:class:`NoneType`
"""
cipher = _lib.SSL_get_current_cipher(self._ssl)
if cipher == _ffi.NULL:
return None
else:
version =_ffi.string(_lib.SSL_CIPHER_get_version(cipher))
return version.decode("utf-8")
@_requires_npn
def get_next_proto_negotiated(self):
"""
Get the protocol that was negotiated by NPN.
"""
data = _ffi.new("unsigned char **")
data_len = _ffi.new("unsigned int *")
_lib.SSL_get0_next_proto_negotiated(self._ssl, data, data_len)
return _ffi.buffer(data[0], data_len[0])[:]
@_requires_alpn
def set_alpn_protos(self, protos):
"""
Specify the client's ALPN protocol list.
These protocols are offered to the server during protocol negotiation.
:param protos: A list of the protocols to be offered to the server.
This list should be a Python list of bytestrings representing the
protocols to offer, e.g. ``[b'http/1.1', b'spdy/2']``.
"""
# Take the list of protocols and join them together, prefixing them
# with their lengths.
protostr = b''.join(
chain.from_iterable((int2byte(len(p)), p) for p in protos)
)
# Build a C string from the list. We don't need to save this off
# because OpenSSL immediately copies the data out.
input_str = _ffi.new("unsigned char[]", protostr)
input_str_len = _ffi.cast("unsigned", len(protostr))
_lib.SSL_set_alpn_protos(self._ssl, input_str, input_str_len)
def get_alpn_proto_negotiated(self):
"""
Get the protocol that was negotiated by ALPN.
"""
if not _lib.Cryptography_HAS_ALPN:
raise NotImplementedError("ALPN not available")
data = _ffi.new("unsigned char **")
data_len = _ffi.new("unsigned int *")
_lib.SSL_get0_alpn_selected(self._ssl, data, data_len)
if not data_len:
return b''
return _ffi.buffer(data[0], data_len[0])[:]
ConnectionType = Connection ConnectionType = Connection
# This is similar to the initialization calls at the end of OpenSSL/crypto.py # This is similar to the initialization calls at the end of OpenSSL/crypto.py

View file

@ -1,3 +1,6 @@
from warnings import warn
import sys
from six import PY3, binary_type, text_type from six import PY3, binary_type, text_type
from cryptography.hazmat.bindings.openssl.binding import Binding from cryptography.hazmat.bindings.openssl.binding import Binding
@ -5,11 +8,34 @@ binding = Binding()
ffi = binding.ffi ffi = binding.ffi
lib = binding.lib lib = binding.lib
def exception_from_error_queue(exceptionType):
def text(charp):
def text(charp):
"""
Get a native string type representing of the given CFFI ``char*`` object.
:param charp: A C-style string represented using CFFI.
:return: :class:`str`
"""
if not charp:
return ""
return native(ffi.string(charp)) return native(ffi.string(charp))
def exception_from_error_queue(exception_type):
"""
Convert an OpenSSL library failure into a Python exception.
When a call to the native OpenSSL library fails, this is usually signalled
by the return value, and an error code is stored in an error queue
associated with the current thread. The err library provides functions to
obtain these error codes and textual error messages.
"""
errors = [] errors = []
while True: while True:
error = lib.ERR_get_error() error = lib.ERR_get_error()
if error == 0: if error == 0:
@ -19,7 +45,7 @@ def exception_from_error_queue(exceptionType):
text(lib.ERR_func_error_string(error)), text(lib.ERR_func_error_string(error)),
text(lib.ERR_reason_error_string(error)))) text(lib.ERR_reason_error_string(error))))
raise exceptionType(errors) raise exception_type(errors)
@ -45,9 +71,57 @@ def native(s):
def path_string(s):
"""
Convert a Python string to a :py:class:`bytes` string identifying the same
path and which can be passed into an OpenSSL API accepting a filename.
:param s: An instance of :py:class:`bytes` or :py:class:`unicode`.
:return: An instance of :py:class:`bytes`.
"""
if isinstance(s, binary_type):
return s
elif isinstance(s, text_type):
return s.encode(sys.getfilesystemencoding())
else:
raise TypeError("Path must be represented as bytes or unicode string")
if PY3: if PY3:
def byte_string(s): def byte_string(s):
return s.encode("charmap") return s.encode("charmap")
else: else:
def byte_string(s): def byte_string(s):
return s return s
# A marker object to observe whether some optional arguments are passed any
# value or not.
UNSPECIFIED = object()
_TEXT_WARNING = (
text_type.__name__ + " for {0} is no longer accepted, use bytes"
)
def text_to_bytes_and_warn(label, obj):
"""
If ``obj`` is text, emit a warning that it should be bytes instead and try
to convert it to bytes automatically.
:param str label: The name of the parameter from which ``obj`` was taken
(so a developer can easily find the source of the problem and correct
it).
:return: If ``obj`` is the text string type, a ``bytes`` object giving the
UTF-8 encoding of that text is returned. Otherwise, ``obj`` itself is
returned.
"""
if isinstance(obj, text_type):
warn(
_TEXT_WARNING.format(label),
category=DeprecationWarning,
stacklevel=3
)
return obj.encode('utf-8')
return obj

View file

@ -2,17 +2,22 @@ from time import time
from base64 import b16encode from base64 import b16encode
from functools import partial from functools import partial
from operator import __eq__, __ne__, __lt__, __le__, __gt__, __ge__ from operator import __eq__, __ne__, __lt__, __le__, __gt__, __ge__
from warnings import warn as _warn
from six import ( from six import (
integer_types as _integer_types, integer_types as _integer_types,
text_type as _text_type) text_type as _text_type,
PY3 as _PY3)
from OpenSSL._util import ( from OpenSSL._util import (
ffi as _ffi, ffi as _ffi,
lib as _lib, lib as _lib,
exception_from_error_queue as _exception_from_error_queue, exception_from_error_queue as _exception_from_error_queue,
byte_string as _byte_string, byte_string as _byte_string,
native as _native) native as _native,
UNSPECIFIED as _UNSPECIFIED,
text_to_bytes_and_warn as _text_to_bytes_and_warn,
)
FILETYPE_PEM = _lib.SSL_FILETYPE_PEM FILETYPE_PEM = _lib.SSL_FILETYPE_PEM
FILETYPE_ASN1 = _lib.SSL_FILETYPE_ASN1 FILETYPE_ASN1 = _lib.SSL_FILETYPE_ASN1
@ -24,6 +29,7 @@ TYPE_RSA = _lib.EVP_PKEY_RSA
TYPE_DSA = _lib.EVP_PKEY_DSA TYPE_DSA = _lib.EVP_PKEY_DSA
class Error(Exception): class Error(Exception):
""" """
An error occurred in an `OpenSSL.crypto` API. An error occurred in an `OpenSSL.crypto` API.
@ -32,6 +38,8 @@ class Error(Exception):
_raise_current_error = partial(_exception_from_error_queue, Error) _raise_current_error = partial(_exception_from_error_queue, Error)
def _untested_error(where): def _untested_error(where):
""" """
An OpenSSL API failed somehow. Additionally, the failure which was An OpenSSL API failed somehow. Additionally, the failure which was
@ -263,6 +271,156 @@ PKeyType = PKey
class _EllipticCurve(object):
"""
A representation of a supported elliptic curve.
@cvar _curves: :py:obj:`None` until an attempt is made to load the curves.
Thereafter, a :py:type:`set` containing :py:type:`_EllipticCurve`
instances each of which represents one curve supported by the system.
@type _curves: :py:type:`NoneType` or :py:type:`set`
"""
_curves = None
if _PY3:
# This only necessary on Python 3. Morever, it is broken on Python 2.
def __ne__(self, other):
"""
Implement cooperation with the right-hand side argument of ``!=``.
Python 3 seems to have dropped this cooperation in this very narrow
circumstance.
"""
if isinstance(other, _EllipticCurve):
return super(_EllipticCurve, self).__ne__(other)
return NotImplemented
@classmethod
def _load_elliptic_curves(cls, lib):
"""
Get the curves supported by OpenSSL.
:param lib: The OpenSSL library binding object.
:return: A :py:type:`set` of ``cls`` instances giving the names of the
elliptic curves the underlying library supports.
"""
if lib.Cryptography_HAS_EC:
num_curves = lib.EC_get_builtin_curves(_ffi.NULL, 0)
builtin_curves = _ffi.new('EC_builtin_curve[]', num_curves)
# The return value on this call should be num_curves again. We could
# check it to make sure but if it *isn't* then.. what could we do?
# Abort the whole process, I suppose...? -exarkun
lib.EC_get_builtin_curves(builtin_curves, num_curves)
return set(
cls.from_nid(lib, c.nid)
for c in builtin_curves)
return set()
@classmethod
def _get_elliptic_curves(cls, lib):
"""
Get, cache, and return the curves supported by OpenSSL.
:param lib: The OpenSSL library binding object.
:return: A :py:type:`set` of ``cls`` instances giving the names of the
elliptic curves the underlying library supports.
"""
if cls._curves is None:
cls._curves = cls._load_elliptic_curves(lib)
return cls._curves
@classmethod
def from_nid(cls, lib, nid):
"""
Instantiate a new :py:class:`_EllipticCurve` associated with the given
OpenSSL NID.
:param lib: The OpenSSL library binding object.
:param nid: The OpenSSL NID the resulting curve object will represent.
This must be a curve NID (and not, for example, a hash NID) or
subsequent operations will fail in unpredictable ways.
:type nid: :py:class:`int`
:return: The curve object.
"""
return cls(lib, nid, _ffi.string(lib.OBJ_nid2sn(nid)).decode("ascii"))
def __init__(self, lib, nid, name):
"""
:param _lib: The :py:mod:`cryptography` binding instance used to
interface with OpenSSL.
:param _nid: The OpenSSL NID identifying the curve this object
represents.
:type _nid: :py:class:`int`
:param name: The OpenSSL short name identifying the curve this object
represents.
:type name: :py:class:`unicode`
"""
self._lib = lib
self._nid = nid
self.name = name
def __repr__(self):
return "<Curve %r>" % (self.name,)
def _to_EC_KEY(self):
"""
Create a new OpenSSL EC_KEY structure initialized to use this curve.
The structure is automatically garbage collected when the Python object
is garbage collected.
"""
key = self._lib.EC_KEY_new_by_curve_name(self._nid)
return _ffi.gc(key, _lib.EC_KEY_free)
def get_elliptic_curves():
"""
Return a set of objects representing the elliptic curves supported in the
OpenSSL build in use.
The curve objects have a :py:class:`unicode` ``name`` attribute by which
they identify themselves.
The curve objects are useful as values for the argument accepted by
:py:meth:`Context.set_tmp_ecdh` to specify which elliptical curve should be
used for ECDHE key exchange.
"""
return _EllipticCurve._get_elliptic_curves(_lib)
def get_elliptic_curve(name):
"""
Return a single curve object selected by name.
See :py:func:`get_elliptic_curves` for information about curve objects.
:param name: The OpenSSL short name identifying the curve object to
retrieve.
:type name: :py:class:`unicode`
If the named curve is not supported then :py:class:`ValueError` is raised.
"""
for curve in get_elliptic_curves():
if curve.name == name:
return curve
raise ValueError("unknown curve name", name)
class X509Name(object): class X509Name(object):
def __init__(self, name): def __init__(self, name):
""" """
@ -697,6 +855,21 @@ class X509Req(object):
_raise_current_error() _raise_current_error()
def get_extensions(self):
"""
Get extensions to the request.
:return: A :py:class:`list` of :py:class:`X509Extension` objects.
"""
exts = []
native_exts_obj = _lib.X509_REQ_get_extensions(self._req)
for i in range(_lib.sk_X509_EXTENSION_num(native_exts_obj)):
ext = X509Extension.__new__(X509Extension)
ext._extension = _lib.sk_X509_EXTENSION_value(native_exts_obj, i)
exts.append(ext)
return exts
def sign(self, pkey, digest): def sign(self, pkey, digest):
""" """
Sign the certificate request using the supplied key and digest Sign the certificate request using the supplied key and digest
@ -1190,6 +1363,125 @@ class X509Store(object):
X509StoreType = X509Store X509StoreType = X509Store
class X509StoreContextError(Exception):
"""
An error occurred while verifying a certificate using
`OpenSSL.X509StoreContext.verify_certificate`.
:ivar certificate: The certificate which caused verificate failure.
:type cert: :class:`X509`
"""
def __init__(self, message, certificate):
super(X509StoreContextError, self).__init__(message)
self.certificate = certificate
class X509StoreContext(object):
"""
An X.509 store context.
An :py:class:`X509StoreContext` is used to define some of the criteria for
certificate verification. The information encapsulated in this object
includes, but is not limited to, a set of trusted certificates,
verification parameters, and revoked certificates.
Of these, only the set of trusted certificates is currently exposed.
:ivar _store_ctx: The underlying X509_STORE_CTX structure used by this
instance. It is dynamically allocated and automatically garbage
collected.
:ivar _store: See the ``store`` ``__init__`` parameter.
:ivar _cert: See the ``certificate`` ``__init__`` parameter.
"""
def __init__(self, store, certificate):
"""
:param X509Store store: The certificates which will be trusted for the
purposes of any verifications.
:param X509 certificate: The certificate to be verified.
"""
store_ctx = _lib.X509_STORE_CTX_new()
self._store_ctx = _ffi.gc(store_ctx, _lib.X509_STORE_CTX_free)
self._store = store
self._cert = certificate
# Make the store context available for use after instantiating this
# class by initializing it now. Per testing, subsequent calls to
# :py:meth:`_init` have no adverse affect.
self._init()
def _init(self):
"""
Set up the store context for a subsequent verification operation.
"""
ret = _lib.X509_STORE_CTX_init(self._store_ctx, self._store._store, self._cert._x509, _ffi.NULL)
if ret <= 0:
_raise_current_error()
def _cleanup(self):
"""
Internally cleans up the store context.
The store context can then be reused with a new call to
:py:meth:`_init`.
"""
_lib.X509_STORE_CTX_cleanup(self._store_ctx)
def _exception_from_context(self):
"""
Convert an OpenSSL native context error failure into a Python
exception.
When a call to native OpenSSL X509_verify_cert fails, additonal information
about the failure can be obtained from the store context.
"""
errors = [
_lib.X509_STORE_CTX_get_error(self._store_ctx),
_lib.X509_STORE_CTX_get_error_depth(self._store_ctx),
_native(_ffi.string(_lib.X509_verify_cert_error_string(
_lib.X509_STORE_CTX_get_error(self._store_ctx)))),
]
# A context error should always be associated with a certificate, so we
# expect this call to never return :class:`None`.
_x509 = _lib.X509_STORE_CTX_get_current_cert(self._store_ctx)
_cert = _lib.X509_dup(_x509)
pycert = X509.__new__(X509)
pycert._x509 = _ffi.gc(_cert, _lib.X509_free)
return X509StoreContextError(errors, pycert)
def set_store(self, store):
"""
Set the context's trust store.
:param X509Store store: The certificates which will be trusted for the
purposes of any *future* verifications.
"""
self._store = store
def verify_certificate(self):
"""
Verify a certificate in a context.
:param store_ctx: The :py:class:`X509StoreContext` to verify.
:raises: Error
"""
# Always re-initialize the store context in case
# :py:meth:`verify_certificate` is called multiple times.
self._init()
ret = _lib.X509_verify_cert(self._store_ctx)
self._cleanup()
if ret <= 0:
raise self._exception_from_context()
def load_certificate(type, buffer): def load_certificate(type, buffer):
""" """
@ -1308,9 +1600,11 @@ def _X509_REVOKED_dup(original):
_raise_current_error() _raise_current_error()
if original.serialNumber != _ffi.NULL: if original.serialNumber != _ffi.NULL:
_lib.ASN1_INTEGER_free(copy.serialNumber)
copy.serialNumber = _lib.ASN1_INTEGER_dup(original.serialNumber) copy.serialNumber = _lib.ASN1_INTEGER_dup(original.serialNumber)
if original.revocationDate != _ffi.NULL: if original.revocationDate != _ffi.NULL:
_lib.ASN1_TIME_free(copy.revocationDate)
copy.revocationDate = _lib.M_ASN1_TIME_dup(original.revocationDate) copy.revocationDate = _lib.M_ASN1_TIME_dup(original.revocationDate)
if original.extensions != _ffi.NULL: if original.extensions != _ffi.NULL:
@ -1539,7 +1833,8 @@ class CRL(object):
_raise_current_error() _raise_current_error()
def export(self, cert, key, type=FILETYPE_PEM, days=100): def export(self, cert, key, type=FILETYPE_PEM, days=100,
digest=_UNSPECIFIED):
""" """
export a CRL as a string export a CRL as a string
@ -1549,12 +1844,15 @@ class CRL(object):
:param key: Used to sign CRL. :param key: Used to sign CRL.
:type key: :class:`PKey` :type key: :class:`PKey`
:param type: The export format, either :py:data:`FILETYPE_PEM`, :py:data:`FILETYPE_ASN1`, or :py:data:`FILETYPE_TEXT`. :param type: The export format, either :py:data:`FILETYPE_PEM`,
:py:data:`FILETYPE_ASN1`, or :py:data:`FILETYPE_TEXT`.
:param days: The number of days until the next update of this CRL. :param int days: The number of days until the next update of this CRL.
:type days: :py:data:`int`
:return: :py:data:`str` :param bytes digest: The name of the message digest to use (eg
``b"sha1"``).
:return: :py:data:`bytes`
""" """
if not isinstance(cert, X509): if not isinstance(cert, X509):
raise TypeError("cert must be an X509 instance") raise TypeError("cert must be an X509 instance")
@ -1563,6 +1861,19 @@ class CRL(object):
if not isinstance(type, int): if not isinstance(type, int):
raise TypeError("type must be an integer") raise TypeError("type must be an integer")
if digest is _UNSPECIFIED:
_warn(
"The default message digest (md5) is deprecated. "
"Pass the name of a message digest explicitly.",
category=DeprecationWarning,
stacklevel=2,
)
digest = b"md5"
digest_obj = _lib.EVP_get_digestbyname(digest)
if digest_obj == _ffi.NULL:
raise ValueError("No such digest method")
bio = _lib.BIO_new(_lib.BIO_s_mem()) bio = _lib.BIO_new(_lib.BIO_s_mem())
if bio == _ffi.NULL: if bio == _ffi.NULL:
# TODO: This is untested. # TODO: This is untested.
@ -1582,7 +1893,7 @@ class CRL(object):
_lib.X509_CRL_set_issuer_name(self._crl, _lib.X509_get_subject_name(cert._x509)) _lib.X509_CRL_set_issuer_name(self._crl, _lib.X509_get_subject_name(cert._x509))
sign_result = _lib.X509_CRL_sign(self._crl, key._pkey, _lib.EVP_md5()) sign_result = _lib.X509_CRL_sign(self._crl, key._pkey, digest_obj)
if not sign_result: if not sign_result:
_raise_current_error() _raise_current_error()
@ -1729,7 +2040,7 @@ class PKCS12(object):
def set_ca_certificates(self, cacerts): def set_ca_certificates(self, cacerts):
""" """
Replace or set the CA certificates withing the PKCS12 object. Replace or set the CA certificates within the PKCS12 object.
:param cacerts: The new CA certificates. :param cacerts: The new CA certificates.
:type cacerts: :py:data:`None` or an iterable of :py:class:`X509` :type cacerts: :py:data:`None` or an iterable of :py:class:`X509`
@ -1784,6 +2095,8 @@ class PKCS12(object):
:return: The string containing the PKCS12 :return: The string containing the PKCS12
""" """
passphrase = _text_to_bytes_and_warn("passphrase", passphrase)
if self._cacerts is None: if self._cacerts is None:
cacerts = _ffi.NULL cacerts = _ffi.NULL
else: else:
@ -2081,6 +2394,8 @@ def sign(pkey, data, digest):
:param digest: message digest to use :param digest: message digest to use
:return: signature :return: signature
""" """
data = _text_to_bytes_and_warn("data", data)
digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest)) digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
if digest_obj == _ffi.NULL: if digest_obj == _ffi.NULL:
raise ValueError("No such digest method") raise ValueError("No such digest method")
@ -2115,6 +2430,8 @@ def verify(cert, signature, data, digest):
:param digest: message digest to use :param digest: message digest to use
:return: None if the signature is correct, raise exception otherwise :return: None if the signature is correct, raise exception otherwise
""" """
data = _text_to_bytes_and_warn("data", data)
digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest)) digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))
if digest_obj == _ffi.NULL: if digest_obj == _ffi.NULL:
raise ValueError("No such digest method") raise ValueError("No such digest method")
@ -2136,7 +2453,6 @@ def verify(cert, signature, data, digest):
_raise_current_error() _raise_current_error()
def load_crl(type, buffer): def load_crl(type, buffer):
""" """
Load a certificate revocation list from a buffer Load a certificate revocation list from a buffer
@ -2183,7 +2499,7 @@ def load_pkcs7_data(type, buffer):
if type == FILETYPE_PEM: if type == FILETYPE_PEM:
pkcs7 = _lib.PEM_read_bio_PKCS7(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL) pkcs7 = _lib.PEM_read_bio_PKCS7(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL)
elif type == FILETYPE_ASN1: elif type == FILETYPE_ASN1:
pass pkcs7 = _lib.d2i_PKCS7_bio(bio, _ffi.NULL)
else: else:
# TODO: This is untested. # TODO: This is untested.
_raise_current_error() _raise_current_error()
@ -2198,7 +2514,7 @@ def load_pkcs7_data(type, buffer):
def load_pkcs12(buffer, passphrase): def load_pkcs12(buffer, passphrase=None):
""" """
Load a PKCS12 object from a buffer Load a PKCS12 object from a buffer
@ -2206,11 +2522,20 @@ def load_pkcs12(buffer, passphrase):
:param passphrase: (Optional) The password to decrypt the PKCS12 lump :param passphrase: (Optional) The password to decrypt the PKCS12 lump
:returns: The PKCS12 object :returns: The PKCS12 object
""" """
passphrase = _text_to_bytes_and_warn("passphrase", passphrase)
if isinstance(buffer, _text_type): if isinstance(buffer, _text_type):
buffer = buffer.encode("ascii") buffer = buffer.encode("ascii")
bio = _new_mem_buf(buffer) bio = _new_mem_buf(buffer)
# Use null passphrase if passphrase is None or empty string. With PKCS#12
# password based encryption no password and a zero length password are two
# different things, but OpenSSL implementation will try both to figure out
# which one works.
if not passphrase:
passphrase = _ffi.NULL
p12 = _lib.d2i_PKCS12_bio(bio, _ffi.NULL) p12 = _lib.d2i_PKCS12_bio(bio, _ffi.NULL)
if p12 == _ffi.NULL: if p12 == _ffi.NULL:
_raise_current_error() _raise_current_error()

View file

@ -11,7 +11,8 @@ from six import integer_types as _integer_types
from OpenSSL._util import ( from OpenSSL._util import (
ffi as _ffi, ffi as _ffi,
lib as _lib, lib as _lib,
exception_from_error_queue as _exception_from_error_queue) exception_from_error_queue as _exception_from_error_queue,
path_string as _path_string)
class Error(Exception): class Error(Exception):
@ -131,13 +132,13 @@ def load_file(filename, maxbytes=_unspecified):
""" """
Seed the PRNG with data from a file Seed the PRNG with data from a file
:param filename: The file to read data from :param filename: The file to read data from (``bytes`` or ``unicode``).
:param maxbytes: (optional) The number of bytes to read, default is :param maxbytes: (optional) The number of bytes to read, default is to read
to read the entire file the entire file
:return: The number of bytes read :return: The number of bytes read
""" """
if not isinstance(filename, _builtin_bytes): filename = _path_string(filename)
raise TypeError("filename must be a string")
if maxbytes is _unspecified: if maxbytes is _unspecified:
maxbytes = -1 maxbytes = -1
@ -152,12 +153,11 @@ def write_file(filename):
""" """
Save PRNG state to a file Save PRNG state to a file
:param filename: The file to write data to :param filename: The file to write data to (``bytes`` or ``unicode``).
:return: The number of bytes written :return: The number of bytes written
""" """
if not isinstance(filename, _builtin_bytes): filename = _path_string(filename)
raise TypeError("filename must be a string")
return _lib.RAND_write_file(filename) return _lib.RAND_write_file(filename)

View file

@ -6,16 +6,22 @@ Unit tests for :py:mod:`OpenSSL.crypto`.
""" """
from unittest import main from unittest import main
from warnings import catch_warnings, simplefilter
import os, re import base64
import os
import re
from subprocess import PIPE, Popen from subprocess import PIPE, Popen
from datetime import datetime, timedelta from datetime import datetime, timedelta
from six import binary_type from six import u, b, binary_type, PY3
from warnings import simplefilter
from warnings import catch_warnings
from OpenSSL.crypto import TYPE_RSA, TYPE_DSA, Error, PKey, PKeyType from OpenSSL.crypto import TYPE_RSA, TYPE_DSA, Error, PKey, PKeyType
from OpenSSL.crypto import X509, X509Type, X509Name, X509NameType from OpenSSL.crypto import X509, X509Type, X509Name, X509NameType
from OpenSSL.crypto import X509Store, X509StoreType, X509Req, X509ReqType from OpenSSL.crypto import X509Store, X509StoreType, X509StoreContext, X509StoreContextError
from OpenSSL.crypto import X509Req, X509ReqType
from OpenSSL.crypto import X509Extension, X509ExtensionType from OpenSSL.crypto import X509Extension, X509ExtensionType
from OpenSSL.crypto import load_certificate, load_privatekey from OpenSSL.crypto import load_certificate, load_privatekey
from OpenSSL.crypto import FILETYPE_PEM, FILETYPE_ASN1, FILETYPE_TEXT from OpenSSL.crypto import FILETYPE_PEM, FILETYPE_ASN1, FILETYPE_TEXT
@ -25,9 +31,12 @@ from OpenSSL.crypto import PKCS7Type, load_pkcs7_data
from OpenSSL.crypto import PKCS12, PKCS12Type, load_pkcs12 from OpenSSL.crypto import PKCS12, PKCS12Type, load_pkcs12
from OpenSSL.crypto import CRL, Revoked, load_crl from OpenSSL.crypto import CRL, Revoked, load_crl
from OpenSSL.crypto import NetscapeSPKI, NetscapeSPKIType from OpenSSL.crypto import NetscapeSPKI, NetscapeSPKIType
from OpenSSL.crypto import sign, verify from OpenSSL.crypto import (
from OpenSSL.test.util import TestCase, b sign, verify, get_elliptic_curve, get_elliptic_curves)
from OpenSSL._util import native from OpenSSL.test.util import (
EqualityTestsMixin, TestCase, WARNING_TYPE_EXPECTED
)
from OpenSSL._util import native, lib
def normalize_certificate_pem(pem): def normalize_certificate_pem(pem):
return dump_certificate(FILETYPE_PEM, load_certificate(FILETYPE_PEM, pem)) return dump_certificate(FILETYPE_PEM, load_certificate(FILETYPE_PEM, pem))
@ -80,6 +89,40 @@ cbvAhow217X9V0dVerEOKxnNYspXRrh36h7k4mQA+sDq
-----END RSA PRIVATE KEY----- -----END RSA PRIVATE KEY-----
""") """)
intermediate_cert_pem = b("""-----BEGIN CERTIFICATE-----
MIICVzCCAcCgAwIBAgIRAMPzhm6//0Y/g2pmnHR2C4cwDQYJKoZIhvcNAQENBQAw
WDELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAklMMRAwDgYDVQQHEwdDaGljYWdvMRAw
DgYDVQQKEwdUZXN0aW5nMRgwFgYDVQQDEw9UZXN0aW5nIFJvb3QgQ0EwHhcNMTQw
ODI4MDIwNDA4WhcNMjQwODI1MDIwNDA4WjBmMRUwEwYDVQQDEwxpbnRlcm1lZGlh
dGUxDDAKBgNVBAoTA29yZzERMA8GA1UECxMIb3JnLXVuaXQxCzAJBgNVBAYTAlVT
MQswCQYDVQQIEwJDQTESMBAGA1UEBxMJU2FuIERpZWdvMIGfMA0GCSqGSIb3DQEB
AQUAA4GNADCBiQKBgQDYcEQw5lfbEQRjr5Yy4yxAHGV0b9Al+Lmu7wLHMkZ/ZMmK
FGIbljbviiD1Nz97Oh2cpB91YwOXOTN2vXHq26S+A5xe8z/QJbBsyghMur88CjdT
21H2qwMa+r5dCQwEhuGIiZ3KbzB/n4DTMYI5zy4IYPv0pjxShZn4aZTCCK2IUwID
AQABoxMwETAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBDQUAA4GBAPIWSkLX
QRMApOjjyC+tMxumT5e2pMqChHmxobQK4NMdrf2VCx+cRT6EmY8sK3/Xl/X8UBQ+
9n5zXb1ZwhW/sTWgUvmOceJ4/XVs9FkdWOOn1J0XBch9ZIiFe/s5ASIgG7fUdcUF
9mAWS6FK2ca3xIh5kIupCXOFa0dPvlw/YUFT
-----END CERTIFICATE-----
""")
intermediate_key_pem = b("""-----BEGIN RSA PRIVATE KEY-----
MIICWwIBAAKBgQDYcEQw5lfbEQRjr5Yy4yxAHGV0b9Al+Lmu7wLHMkZ/ZMmKFGIb
ljbviiD1Nz97Oh2cpB91YwOXOTN2vXHq26S+A5xe8z/QJbBsyghMur88CjdT21H2
qwMa+r5dCQwEhuGIiZ3KbzB/n4DTMYI5zy4IYPv0pjxShZn4aZTCCK2IUwIDAQAB
AoGAfSZVV80pSeOKHTYfbGdNY/jHdU9eFUa/33YWriXU+77EhpIItJjkRRgivIfo
rhFJpBSGmDLblaqepm8emsXMeH4+2QzOYIf0QGGP6E6scjTt1PLqdqKfVJ1a2REN
147cujNcmFJb/5VQHHMpaPTgttEjlzuww4+BCDPsVRABWrkCQQD3loH36nLoQTtf
+kQq0T6Bs9/UWkTAGo0ND81ALj0F8Ie1oeZg6RNT96RxZ3aVuFTESTv6/TbjWywO
wdzlmV1vAkEA38rTJ6PTwaJlw5OttdDzAXGPB9tDmzh9oSi7cHwQQXizYd8MBYx4
sjHUKD3dCQnb1dxJFhd3BT5HsnkRMbVZXQJAbXduH17ZTzcIOXc9jHDXYiFVZV5D
52vV0WCbLzVCZc3jMrtSUKa8lPN5EWrdU3UchWybyG0MR5mX8S5lrF4SoQJAIyUD
DBKaSqpqONCUUx1BTFS9FYrFjzbL4+c1qHCTTPTblt8kUCrDOZjBrKAqeiTmNSum
/qUot9YUBF8m6BuGsQJATHHmdFy/fG1VLkyBp49CAa8tN3Z5r/CgTznI4DfMTf4C
NbRHn2UmYlwQBa+L5lg9phewNe8aEwpPyPLoV85U8Q==
-----END RSA PRIVATE KEY-----
""")
server_cert_pem = b("""-----BEGIN CERTIFICATE----- server_cert_pem = b("""-----BEGIN CERTIFICATE-----
MIICKDCCAZGgAwIBAgIJAJn/HpR21r/8MA0GCSqGSIb3DQEBBQUAMFgxCzAJBgNV MIICKDCCAZGgAwIBAgIJAJn/HpR21r/8MA0GCSqGSIb3DQEBBQUAMFgxCzAJBgNV
BAYTAlVTMQswCQYDVQQIEwJJTDEQMA4GA1UEBxMHQ2hpY2FnbzEQMA4GA1UEChMH BAYTAlVTMQswCQYDVQQIEwJJTDEQMA4GA1UEBxMHQ2hpY2FnbzEQMA4GA1UEChMH
@ -113,6 +156,40 @@ r50+LF74iLXFwqysVCebPKMOpDWp/qQ1BbJQIPs7/A==
-----END RSA PRIVATE KEY----- -----END RSA PRIVATE KEY-----
""")) """))
intermediate_server_cert_pem = b("""-----BEGIN CERTIFICATE-----
MIICWDCCAcGgAwIBAgIRAPQFY9jfskSihdiNSNdt6GswDQYJKoZIhvcNAQENBQAw
ZjEVMBMGA1UEAxMMaW50ZXJtZWRpYXRlMQwwCgYDVQQKEwNvcmcxETAPBgNVBAsT
CG9yZy11bml0MQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0ExEjAQBgNVBAcTCVNh
biBEaWVnbzAeFw0xNDA4MjgwMjEwNDhaFw0yNDA4MjUwMjEwNDhaMG4xHTAbBgNV
BAMTFGludGVybWVkaWF0ZS1zZXJ2aWNlMQwwCgYDVQQKEwNvcmcxETAPBgNVBAsT
CG9yZy11bml0MQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0ExEjAQBgNVBAcTCVNh
biBEaWVnbzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAqpJZygd+w1faLOr1
iOAmbBhx5SZWcTCZ/ZjHQTJM7GuPT624QkqsixFghRKdDROwpwnAP7gMRukLqiy4
+kRuGT5OfyGggL95i2xqA+zehjj08lSTlvGHpePJgCyTavIy5+Ljsj4DKnKyuhxm
biXTRrH83NDgixVkObTEmh/OVK0CAwEAATANBgkqhkiG9w0BAQ0FAAOBgQBa0Npw
UkzjaYEo1OUE1sTI6Mm4riTIHMak4/nswKh9hYup//WVOlr/RBSBtZ7Q/BwbjobN
3bfAtV7eSAqBsfxYXyof7G1ALANQERkq3+oyLP1iVt08W1WOUlIMPhdCF/QuCwy6
x9MJLhUCGLJPM+O2rAPWVD9wCmvq10ALsiH3yA==
-----END CERTIFICATE-----
""")
intermediate_server_key_pem = b("""-----BEGIN RSA PRIVATE KEY-----
MIICXAIBAAKBgQCqklnKB37DV9os6vWI4CZsGHHlJlZxMJn9mMdBMkzsa49PrbhC
SqyLEWCFEp0NE7CnCcA/uAxG6QuqLLj6RG4ZPk5/IaCAv3mLbGoD7N6GOPTyVJOW
8Yel48mALJNq8jLn4uOyPgMqcrK6HGZuJdNGsfzc0OCLFWQ5tMSaH85UrQIDAQAB
AoGAIQ594j5zna3/9WaPsTgnmhlesVctt4AAx/n827DA4ayyuHFlXUuVhtoWR5Pk
5ezj9mtYW8DyeCegABnsu2vZni/CdvU6uiS1Hv6qM1GyYDm9KWgovIP9rQCDSGaz
d57IWVGxx7ODFkm3gN5nxnSBOFVHytuW1J7FBRnEsehRroECQQDXHFOv82JuXDcz
z3+4c74IEURdOHcbycxlppmK9kFqm5lsUdydnnGW+mvwDk0APOB7Wg7vyFyr393e
dpmBDCzNAkEAyv6tVbTKUYhSjW+QhabJo896/EqQEYUmtMXxk4cQnKeR/Ao84Rkf
EqD5IykMUfUI0jJU4DGX+gWZ10a7kNbHYQJAVFCuHNFxS4Cpwo0aqtnzKoZaHY/8
X9ABZfafSHCtw3Op92M+7ikkrOELXdS9KdKyyqbKJAKNEHF3LbOfB44WIQJAA2N4
9UNNVUsXRbElEnYUS529CdUczo4QdVgQjkvk5RiPAUwSdBd9Q0xYnFOlFwEmIowg
ipWJWe0aAlP18ZcEQQJBAL+5lekZ/GUdQoZ4HAsN5a9syrzavJ9VvU1KOOPorPZK
nMRZbbQgP+aSB7yl6K0gaLaZ8XaK0pjxNBh6ASqg9f4=
-----END RSA PRIVATE KEY-----
""")
client_cert_pem = b("""-----BEGIN CERTIFICATE----- client_cert_pem = b("""-----BEGIN CERTIFICATE-----
MIICJjCCAY+gAwIBAgIJAKxpFI5lODkjMA0GCSqGSIb3DQEBBQUAMFgxCzAJBgNV MIICJjCCAY+gAwIBAgIJAKxpFI5lODkjMA0GCSqGSIb3DQEBBQUAMFgxCzAJBgNV
BAYTAlVTMQswCQYDVQQIEwJJTDEQMA4GA1UEBxMHQ2hpY2FnbzEQMA4GA1UEChMH BAYTAlVTMQswCQYDVQQIEwJJTDEQMA4GA1UEBxMHQ2hpY2FnbzEQMA4GA1UEChMH
@ -247,6 +324,27 @@ Ho4EzbYCOaEAMQA=
-----END PKCS7----- -----END PKCS7-----
""") """)
pkcs7DataASN1 = base64.b64decode(b"""
MIIDNwYJKoZIhvcNAQcCoIIDKDCCAyQCAQExADALBgkqhkiG9w0BBwGgggMKMIID
BjCCAm+gAwIBAgIBATANBgkqhkiG9w0BAQQFADB7MQswCQYDVQQGEwJTRzERMA8G
A1UEChMITTJDcnlwdG8xFDASBgNVBAsTC00yQ3J5cHRvIENBMSQwIgYDVQQDExtN
MkNyeXB0byBDZXJ0aWZpY2F0ZSBNYXN0ZXIxHTAbBgkqhkiG9w0BCQEWDm5ncHNA
cG9zdDEuY29tMB4XDTAwMDkxMDA5NTEzMFoXDTAyMDkxMDA5NTEzMFowUzELMAkG
A1UEBhMCU0cxETAPBgNVBAoTCE0yQ3J5cHRvMRIwEAYDVQQDEwlsb2NhbGhvc3Qx
HTAbBgkqhkiG9w0BCQEWDm5ncHNAcG9zdDEuY29tMFwwDQYJKoZIhvcNAQEBBQAD
SwAwSAJBAKy+e3dulvXzV7zoTZWc5TzgApr8DmeQHTYC8ydfzH7EECe4R1Xh5kwI
zOuuFfn178FBiS84gngaNcrFi0Z5fAkCAwEAAaOCAQQwggEAMAkGA1UdEwQCMAAw
LAYJYIZIAYb4QgENBB8WHU9wZW5TU0wgR2VuZXJhdGVkIENlcnRpZmljYXRlMB0G
A1UdDgQWBBTPhIKSvnsmYsBVNWjj0m3M2z0qVTCBpQYDVR0jBIGdMIGagBT7hyNp
65w6kxXlxb8pUU/+7Sg4AaF/pH0wezELMAkGA1UEBhMCU0cxETAPBgNVBAoTCE0y
Q3J5cHRvMRQwEgYDVQQLEwtNMkNyeXB0byBDQTEkMCIGA1UEAxMbTTJDcnlwdG8g
Q2VydGlmaWNhdGUgTWFzdGVyMR0wGwYJKoZIhvcNAQkBFg5uZ3BzQHBvc3QxLmNv
bYIBADANBgkqhkiG9w0BAQQFAAOBgQA7/CqT6PoHycTdhEStWNZde7M/2Yc6BoJu
VwnW8YxGO8Sn6UJ4FeffZNcYZddSDKosw8LtPOeWoK3JINjAk5jiPQ2cww++7QGG
/g5NDjxFZNDJP1dGiLAxPW6JXwov4v0FmdzfLOZ01jDcgQQZqEpYlgpuI5JEWUQ9
Ho4EzbYCOaEAMQA=
""")
crlData = b("""\ crlData = b("""\
-----BEGIN X509 CRL----- -----BEGIN X509 CRL-----
MIIBWzCBxTANBgkqhkiG9w0BAQQFADBYMQswCQYDVQQGEwJVUzELMAkGA1UECBMC MIIBWzCBxTANBgkqhkiG9w0BAQQFADBYMQswCQYDVQQGEwJVUzELMAkGA1UECBMC
@ -512,7 +610,7 @@ class X509ExtTests(TestCase):
def test_issuer(self): def test_issuer(self):
""" """
If an extension requires a issuer, the :py:data:`issuer` parameter to If an extension requires an issuer, the :py:data:`issuer` parameter to
:py:class:`X509Extension` provides its value. :py:class:`X509Extension` provides its value.
""" """
ext2 = X509Extension( ext2 = X509Extension(
@ -1108,7 +1206,32 @@ class X509ReqTests(TestCase, _PKeyInteractionTestsMixin):
request = X509Req() request = X509Req()
request.add_extensions([ request.add_extensions([
X509Extension(b('basicConstraints'), True, b('CA:false'))]) X509Extension(b('basicConstraints'), True, b('CA:false'))])
# XXX Add get_extensions so the rest of this unit test can be written. exts = request.get_extensions()
self.assertEqual(len(exts), 1)
self.assertEqual(exts[0].get_short_name(), b('basicConstraints'))
self.assertEqual(exts[0].get_critical(), 1)
self.assertEqual(exts[0].get_data(), b('0\x00'))
def test_get_extensions(self):
"""
:py:obj:`X509Req.get_extensions` returns a :py:obj:`list` of
extensions added to this X509 request.
"""
request = X509Req()
exts = request.get_extensions()
self.assertEqual(exts, [])
request.add_extensions([
X509Extension(b('basicConstraints'), True, b('CA:true')),
X509Extension(b('keyUsage'), False, b('digitalSignature'))])
exts = request.get_extensions()
self.assertEqual(len(exts), 2)
self.assertEqual(exts[0].get_short_name(), b('basicConstraints'))
self.assertEqual(exts[0].get_critical(), 1)
self.assertEqual(exts[0].get_data(), b('0\x03\x01\x01\xff'))
self.assertEqual(exts[1].get_short_name(), b('keyUsage'))
self.assertEqual(exts[1].get_critical(), 0)
self.assertEqual(exts[1].get_data(), b('\x03\x02\x07\x80'))
def test_add_extensions_wrong_args(self): def test_add_extensions_wrong_args(self):
@ -1163,7 +1286,7 @@ class X509ReqTests(TestCase, _PKeyInteractionTestsMixin):
def test_verify_success(self): def test_verify_success(self):
""" """
:py:obj:`X509Req.verify` returns :py:obj:`True` if called with a :py:obj:`X509Req.verify` returns :py:obj:`True` if called with a
:py:obj:`OpenSSL.crypto.PKey` which represents the public part ofthe key :py:obj:`OpenSSL.crypto.PKey` which represents the public part of the key
which signed the request. which signed the request.
""" """
request = X509Req() request = X509Req()
@ -1915,6 +2038,21 @@ class PKCS12Tests(TestCase):
self.assertEqual(recovered_cert[-len(ca):], ca) self.assertEqual(recovered_cert[-len(ca):], ca)
def verify_pkcs12_container(self, p12):
"""
Verify that the PKCS#12 container contains the correct client
certificate and private key.
:param p12: The PKCS12 instance to verify.
:type p12: :py:class:`PKCS12`
"""
cert_pem = dump_certificate(FILETYPE_PEM, p12.get_certificate())
key_pem = dump_privatekey(FILETYPE_PEM, p12.get_privatekey())
self.assertEqual(
(client_cert_pem, client_key_pem, None),
(cert_pem, key_pem, p12.get_ca_certificates()))
def test_load_pkcs12(self): def test_load_pkcs12(self):
""" """
A PKCS12 string generated using the openssl command line can be loaded A PKCS12 string generated using the openssl command line can be loaded
@ -1924,14 +2062,95 @@ class PKCS12Tests(TestCase):
pem = client_key_pem + client_cert_pem pem = client_key_pem + client_cert_pem
p12_str = _runopenssl( p12_str = _runopenssl(
pem, b"pkcs12", b"-export", b"-clcerts", b"-passout", b"pass:" + passwd) pem, b"pkcs12", b"-export", b"-clcerts", b"-passout", b"pass:" + passwd)
p12 = load_pkcs12(p12_str, passwd) p12 = load_pkcs12(p12_str, passphrase=passwd)
# verify self.verify_pkcs12_container(p12)
self.assertTrue(isinstance(p12, PKCS12))
cert_pem = dump_certificate(FILETYPE_PEM, p12.get_certificate())
self.assertEqual(cert_pem, client_cert_pem) def test_load_pkcs12_text_passphrase(self):
key_pem = dump_privatekey(FILETYPE_PEM, p12.get_privatekey()) """
self.assertEqual(key_pem, client_key_pem) A PKCS12 string generated using the openssl command line can be loaded
self.assertEqual(None, p12.get_ca_certificates()) with :py:obj:`load_pkcs12` and its components extracted and examined.
Using text as passphrase instead of bytes. DeprecationWarning expected.
"""
pem = client_key_pem + client_cert_pem
passwd = b"whatever"
p12_str = _runopenssl(pem, b"pkcs12", b"-export", b"-clcerts",
b"-passout", b"pass:" + passwd)
with catch_warnings(record=True) as w:
simplefilter("always")
p12 = load_pkcs12(p12_str, passphrase=b"whatever".decode("ascii"))
self.assertEqual(
"{0} for passphrase is no longer accepted, use bytes".format(
WARNING_TYPE_EXPECTED
),
str(w[-1].message)
)
self.assertIs(w[-1].category, DeprecationWarning)
self.verify_pkcs12_container(p12)
def test_load_pkcs12_no_passphrase(self):
"""
A PKCS12 string generated using openssl command line can be loaded with
:py:obj:`load_pkcs12` without a passphrase and its components extracted
and examined.
"""
pem = client_key_pem + client_cert_pem
p12_str = _runopenssl(
pem, b"pkcs12", b"-export", b"-clcerts", b"-passout", b"pass:")
p12 = load_pkcs12(p12_str)
self.verify_pkcs12_container(p12)
def _dump_and_load(self, dump_passphrase, load_passphrase):
"""
A helper method to dump and load a PKCS12 object.
"""
p12 = self.gen_pkcs12(client_cert_pem, client_key_pem)
dumped_p12 = p12.export(passphrase=dump_passphrase, iter=2, maciter=3)
return load_pkcs12(dumped_p12, passphrase=load_passphrase)
def test_load_pkcs12_null_passphrase_load_empty(self):
"""
A PKCS12 string can be dumped with a null passphrase, loaded with an
empty passphrase with :py:obj:`load_pkcs12`, and its components
extracted and examined.
"""
self.verify_pkcs12_container(
self._dump_and_load(dump_passphrase=None, load_passphrase=b''))
def test_load_pkcs12_null_passphrase_load_null(self):
"""
A PKCS12 string can be dumped with a null passphrase, loaded with a
null passphrase with :py:obj:`load_pkcs12`, and its components
extracted and examined.
"""
self.verify_pkcs12_container(
self._dump_and_load(dump_passphrase=None, load_passphrase=None))
def test_load_pkcs12_empty_passphrase_load_empty(self):
"""
A PKCS12 string can be dumped with an empty passphrase, loaded with an
empty passphrase with :py:obj:`load_pkcs12`, and its components
extracted and examined.
"""
self.verify_pkcs12_container(
self._dump_and_load(dump_passphrase=b'', load_passphrase=b''))
def test_load_pkcs12_empty_passphrase_load_null(self):
"""
A PKCS12 string can be dumped with an empty passphrase, loaded with a
null passphrase with :py:obj:`load_pkcs12`, and its components
extracted and examined.
"""
self.verify_pkcs12_container(
self._dump_and_load(dump_passphrase=b'', load_passphrase=None))
def test_load_pkcs12_garbage(self): def test_load_pkcs12_garbage(self):
@ -2073,6 +2292,26 @@ class PKCS12Tests(TestCase):
dumped_p12, key=server_key_pem, cert=server_cert_pem, passwd=b"") dumped_p12, key=server_key_pem, cert=server_cert_pem, passwd=b"")
def test_export_without_bytes(self):
"""
Test :py:obj:`PKCS12.export` with text not bytes as passphrase
"""
p12 = self.gen_pkcs12(server_cert_pem, server_key_pem, root_cert_pem)
with catch_warnings(record=True) as w:
simplefilter("always")
dumped_p12 = p12.export(passphrase=b"randomtext".decode("ascii"))
self.assertEqual(
"{0} for passphrase is no longer accepted, use bytes".format(
WARNING_TYPE_EXPECTED
),
str(w[-1].message)
)
self.assertIs(w[-1].category, DeprecationWarning)
self.check_recovery(
dumped_p12, key=server_key_pem, cert=server_cert_pem, passwd=b"randomtext")
def test_key_cert_mismatch(self): def test_key_cert_mismatch(self):
""" """
:py:obj:`PKCS12.export` raises an exception when a key and certificate :py:obj:`PKCS12.export` raises an exception when a key and certificate
@ -2463,7 +2702,7 @@ class FunctionTests(TestCase):
dump_privatekey, FILETYPE_PEM, key, GOOD_CIPHER, cb) dump_privatekey, FILETYPE_PEM, key, GOOD_CIPHER, cb)
def test_load_pkcs7_data(self): def test_load_pkcs7_data_pem(self):
""" """
:py:obj:`load_pkcs7_data` accepts a PKCS#7 string and returns an instance of :py:obj:`load_pkcs7_data` accepts a PKCS#7 string and returns an instance of
:py:obj:`PKCS7Type`. :py:obj:`PKCS7Type`.
@ -2472,6 +2711,15 @@ class FunctionTests(TestCase):
self.assertTrue(isinstance(pkcs7, PKCS7Type)) self.assertTrue(isinstance(pkcs7, PKCS7Type))
def test_load_pkcs7_data_asn1(self):
"""
:py:obj:`load_pkcs7_data` accepts a bytes containing ASN1 data
representing PKCS#7 and returns an instance of :py:obj`PKCS7Type`.
"""
pkcs7 = load_pkcs7_data(FILETYPE_ASN1, pkcs7DataASN1)
self.assertTrue(isinstance(pkcs7, PKCS7Type))
def test_load_pkcs7_data_invalid(self): def test_load_pkcs7_data_invalid(self):
""" """
If the data passed to :py:obj:`load_pkcs7_data` is invalid, If the data passed to :py:obj:`load_pkcs7_data` is invalid,
@ -2796,11 +3044,9 @@ class CRLTests(TestCase):
self.assertRaises(TypeError, CRL, None) self.assertRaises(TypeError, CRL, None)
def test_export(self): def _get_crl(self):
""" """
Use python to create a simple CRL with a revocation, and export Get a new ``CRL`` with a revocation.
the CRL in formats of PEM, DER and text. Those outputs are verified
with the openssl program.
""" """
crl = CRL() crl = CRL()
revoked = Revoked() revoked = Revoked()
@ -2809,26 +3055,110 @@ class CRLTests(TestCase):
revoked.set_serial(b('3ab')) revoked.set_serial(b('3ab'))
revoked.set_reason(b('sUpErSeDEd')) revoked.set_reason(b('sUpErSeDEd'))
crl.add_revoked(revoked) crl.add_revoked(revoked)
return crl
def test_export_pem(self):
"""
If not passed a format, ``CRL.export`` returns a "PEM" format string
representing a serial number, a revoked reason, and certificate issuer
information.
"""
crl = self._get_crl()
# PEM format # PEM format
dumped_crl = crl.export(self.cert, self.pkey, days=20) dumped_crl = crl.export(self.cert, self.pkey, days=20)
text = _runopenssl(dumped_crl, b"crl", b"-noout", b"-text") text = _runopenssl(dumped_crl, b"crl", b"-noout", b"-text")
# These magic values are based on the way the CRL above was constructed
# and with what certificate it was exported.
text.index(b('Serial Number: 03AB')) text.index(b('Serial Number: 03AB'))
text.index(b('Superseded')) text.index(b('Superseded'))
text.index(b('Issuer: /C=US/ST=IL/L=Chicago/O=Testing/CN=Testing Root CA')) text.index(
b('Issuer: /C=US/ST=IL/L=Chicago/O=Testing/CN=Testing Root CA')
)
def test_export_der(self):
"""
If passed ``FILETYPE_ASN1`` for the format, ``CRL.export`` returns a
"DER" format string representing a serial number, a revoked reason, and
certificate issuer information.
"""
crl = self._get_crl()
# DER format # DER format
dumped_crl = crl.export(self.cert, self.pkey, FILETYPE_ASN1) dumped_crl = crl.export(self.cert, self.pkey, FILETYPE_ASN1)
text = _runopenssl(dumped_crl, b"crl", b"-noout", b"-text", b"-inform", b"DER") text = _runopenssl(
dumped_crl, b"crl", b"-noout", b"-text", b"-inform", b"DER"
)
text.index(b('Serial Number: 03AB')) text.index(b('Serial Number: 03AB'))
text.index(b('Superseded')) text.index(b('Superseded'))
text.index(b('Issuer: /C=US/ST=IL/L=Chicago/O=Testing/CN=Testing Root CA')) text.index(
b('Issuer: /C=US/ST=IL/L=Chicago/O=Testing/CN=Testing Root CA')
)
def test_export_text(self):
"""
If passed ``FILETYPE_TEXT`` for the format, ``CRL.export`` returns a
text format string like the one produced by the openssl command line
tool.
"""
crl = self._get_crl()
dumped_crl = crl.export(self.cert, self.pkey, FILETYPE_ASN1)
text = _runopenssl(
dumped_crl, b"crl", b"-noout", b"-text", b"-inform", b"DER"
)
# text format # text format
dumped_text = crl.export(self.cert, self.pkey, type=FILETYPE_TEXT) dumped_text = crl.export(self.cert, self.pkey, type=FILETYPE_TEXT)
self.assertEqual(text, dumped_text) self.assertEqual(text, dumped_text)
def test_export_custom_digest(self):
"""
If passed the name of a digest function, ``CRL.export`` uses a
signature algorithm based on that digest function.
"""
crl = self._get_crl()
dumped_crl = crl.export(self.cert, self.pkey, digest=b"sha1")
text = _runopenssl(dumped_crl, b"crl", b"-noout", b"-text")
text.index(b('Signature Algorithm: sha1'))
def test_export_md5_digest(self):
"""
If passed md5 as the digest function, ``CRL.export`` uses md5 and does
not emit a deprecation warning.
"""
crl = self._get_crl()
with catch_warnings(record=True) as catcher:
simplefilter("always")
self.assertEqual(0, len(catcher))
dumped_crl = crl.export(self.cert, self.pkey, digest=b"md5")
text = _runopenssl(dumped_crl, b"crl", b"-noout", b"-text")
text.index(b('Signature Algorithm: md5'))
def test_export_default_digest(self):
"""
If not passed the name of a digest function, ``CRL.export`` uses a
signature algorithm based on MD5 and emits a deprecation warning.
"""
crl = self._get_crl()
with catch_warnings(record=True) as catcher:
simplefilter("always")
dumped_crl = crl.export(self.cert, self.pkey)
self.assertEqual(
"The default message digest (md5) is deprecated. "
"Pass the name of a message digest explicitly.",
str(catcher[0].message),
)
text = _runopenssl(dumped_crl, b"crl", b"-noout", b"-text")
text.index(b('Signature Algorithm: md5'))
def test_export_invalid(self): def test_export_invalid(self):
""" """
If :py:obj:`CRL.export` is used with an uninitialized :py:obj:`X509` If :py:obj:`CRL.export` is used with an uninitialized :py:obj:`X509`
@ -2859,7 +3189,7 @@ class CRLTests(TestCase):
crl = CRL() crl = CRL()
self.assertRaises(TypeError, crl.export) self.assertRaises(TypeError, crl.export)
self.assertRaises(TypeError, crl.export, self.cert) self.assertRaises(TypeError, crl.export, self.cert)
self.assertRaises(TypeError, crl.export, self.cert, self.pkey, FILETYPE_PEM, 10, "foo") self.assertRaises(TypeError, crl.export, self.cert, self.pkey, FILETYPE_PEM, 10, "md5", "foo")
self.assertRaises(TypeError, crl.export, None, self.pkey, FILETYPE_PEM, 10) self.assertRaises(TypeError, crl.export, None, self.pkey, FILETYPE_PEM, 10)
self.assertRaises(TypeError, crl.export, self.cert, None, FILETYPE_PEM, 10) self.assertRaises(TypeError, crl.export, self.cert, None, FILETYPE_PEM, 10)
@ -2877,6 +3207,19 @@ class CRLTests(TestCase):
self.assertRaises(ValueError, crl.export, self.cert, self.pkey, 100, 10) self.assertRaises(ValueError, crl.export, self.cert, self.pkey, 100, 10)
def test_export_unknown_digest(self):
"""
Calling :py:obj:`OpenSSL.CRL.export` with a unsupported digest results
in a :py:obj:`ValueError` being raised.
"""
crl = CRL()
self.assertRaises(
ValueError,
crl.export,
self.cert, self.pkey, FILETYPE_PEM, 10, b"strange-digest"
)
def test_get_revoked(self): def test_get_revoked(self):
""" """
Use python to create a simple CRL with two revocations. Use python to create a simple CRL with two revocations.
@ -2977,6 +3320,107 @@ class CRLTests(TestCase):
class X509StoreContextTests(TestCase):
"""
Tests for :py:obj:`OpenSSL.crypto.X509StoreContext`.
"""
root_cert = load_certificate(FILETYPE_PEM, root_cert_pem)
intermediate_cert = load_certificate(FILETYPE_PEM, intermediate_cert_pem)
intermediate_server_cert = load_certificate(FILETYPE_PEM, intermediate_server_cert_pem)
def test_valid(self):
"""
:py:obj:`verify_certificate` returns ``None`` when called with a certificate
and valid chain.
"""
store = X509Store()
store.add_cert(self.root_cert)
store.add_cert(self.intermediate_cert)
store_ctx = X509StoreContext(store, self.intermediate_server_cert)
self.assertEqual(store_ctx.verify_certificate(), None)
def test_reuse(self):
"""
:py:obj:`verify_certificate` can be called multiple times with the same
``X509StoreContext`` instance to produce the same result.
"""
store = X509Store()
store.add_cert(self.root_cert)
store.add_cert(self.intermediate_cert)
store_ctx = X509StoreContext(store, self.intermediate_server_cert)
self.assertEqual(store_ctx.verify_certificate(), None)
self.assertEqual(store_ctx.verify_certificate(), None)
def test_trusted_self_signed(self):
"""
:py:obj:`verify_certificate` returns ``None`` when called with a self-signed
certificate and itself in the chain.
"""
store = X509Store()
store.add_cert(self.root_cert)
store_ctx = X509StoreContext(store, self.root_cert)
self.assertEqual(store_ctx.verify_certificate(), None)
def test_untrusted_self_signed(self):
"""
:py:obj:`verify_certificate` raises error when a self-signed certificate is
verified without itself in the chain.
"""
store = X509Store()
store_ctx = X509StoreContext(store, self.root_cert)
e = self.assertRaises(X509StoreContextError, store_ctx.verify_certificate)
self.assertEqual(e.args[0][2], 'self signed certificate')
self.assertEqual(e.certificate.get_subject().CN, 'Testing Root CA')
def test_invalid_chain_no_root(self):
"""
:py:obj:`verify_certificate` raises error when a root certificate is missing
from the chain.
"""
store = X509Store()
store.add_cert(self.intermediate_cert)
store_ctx = X509StoreContext(store, self.intermediate_server_cert)
e = self.assertRaises(X509StoreContextError, store_ctx.verify_certificate)
self.assertEqual(e.args[0][2], 'unable to get issuer certificate')
self.assertEqual(e.certificate.get_subject().CN, 'intermediate')
def test_invalid_chain_no_intermediate(self):
"""
:py:obj:`verify_certificate` raises error when an intermediate certificate is
missing from the chain.
"""
store = X509Store()
store.add_cert(self.root_cert)
store_ctx = X509StoreContext(store, self.intermediate_server_cert)
e = self.assertRaises(X509StoreContextError, store_ctx.verify_certificate)
self.assertEqual(e.args[0][2], 'unable to get local issuer certificate')
self.assertEqual(e.certificate.get_subject().CN, 'intermediate-service')
def test_modification_pre_verify(self):
"""
:py:obj:`verify_certificate` can use a store context modified after
instantiation.
"""
store_bad = X509Store()
store_bad.add_cert(self.intermediate_cert)
store_good = X509Store()
store_good.add_cert(self.root_cert)
store_good.add_cert(self.intermediate_cert)
store_ctx = X509StoreContext(store_bad, self.intermediate_server_cert)
e = self.assertRaises(X509StoreContextError, store_ctx.verify_certificate)
self.assertEqual(e.args[0][2], 'unable to get issuer certificate')
self.assertEqual(e.certificate.get_subject().CN, 'intermediate')
store_ctx.set_store(store_good)
self.assertEqual(store_ctx.verify_certificate(), None)
class SignVerifyTests(TestCase): class SignVerifyTests(TestCase):
""" """
Tests for :py:obj:`OpenSSL.crypto.sign` and :py:obj:`OpenSSL.crypto.verify`. Tests for :py:obj:`OpenSSL.crypto.sign` and :py:obj:`OpenSSL.crypto.verify`.
@ -3022,6 +3466,47 @@ class SignVerifyTests(TestCase):
ValueError, verify, good_cert, sig, content, "strange-digest") ValueError, verify, good_cert, sig, content, "strange-digest")
def test_sign_verify_with_text(self):
"""
:py:obj:`sign` generates a cryptographic signature which :py:obj:`verify` can check.
Deprecation warnings raised because using text instead of bytes as content
"""
content = (
b"It was a bright cold day in April, and the clocks were striking "
b"thirteen. Winston Smith, his chin nuzzled into his breast in an "
b"effort to escape the vile wind, slipped quickly through the "
b"glass doors of Victory Mansions, though not quickly enough to "
b"prevent a swirl of gritty dust from entering along with him."
).decode("ascii")
priv_key = load_privatekey(FILETYPE_PEM, root_key_pem)
cert = load_certificate(FILETYPE_PEM, root_cert_pem)
for digest in ['md5', 'sha1']:
with catch_warnings(record=True) as w:
simplefilter("always")
sig = sign(priv_key, content, digest)
self.assertEqual(
"{0} for data is no longer accepted, use bytes".format(
WARNING_TYPE_EXPECTED
),
str(w[-1].message)
)
self.assertIs(w[-1].category, DeprecationWarning)
with catch_warnings(record=True) as w:
simplefilter("always")
verify(cert, sig, content, digest)
self.assertEqual(
"{0} for data is no longer accepted, use bytes".format(
WARNING_TYPE_EXPECTED
),
str(w[-1].message)
)
self.assertIs(w[-1].category, DeprecationWarning)
def test_sign_nulls(self): def test_sign_nulls(self):
""" """
:py:obj:`sign` produces a signature for a string with embedded nulls. :py:obj:`sign` produces a signature for a string with embedded nulls.
@ -3033,5 +3518,154 @@ class SignVerifyTests(TestCase):
verify(good_cert, sig, content, "sha1") verify(good_cert, sig, content, "sha1")
class EllipticCurveTests(TestCase):
"""
Tests for :py:class:`_EllipticCurve`, :py:obj:`get_elliptic_curve`, and
:py:obj:`get_elliptic_curves`.
"""
def test_set(self):
"""
:py:obj:`get_elliptic_curves` returns a :py:obj:`set`.
"""
self.assertIsInstance(get_elliptic_curves(), set)
def test_some_curves(self):
"""
If :py:mod:`cryptography` has elliptic curve support then the set
returned by :py:obj:`get_elliptic_curves` has some elliptic curves in
it.
There could be an OpenSSL that violates this assumption. If so, this
test will fail and we'll find out.
"""
curves = get_elliptic_curves()
if lib.Cryptography_HAS_EC:
self.assertTrue(curves)
else:
self.assertFalse(curves)
def test_a_curve(self):
"""
:py:obj:`get_elliptic_curve` can be used to retrieve a particular
supported curve.
"""
curves = get_elliptic_curves()
if curves:
curve = next(iter(curves))
self.assertEqual(curve.name, get_elliptic_curve(curve.name).name)
else:
self.assertRaises(ValueError, get_elliptic_curve, u("prime256v1"))
def test_not_a_curve(self):
"""
:py:obj:`get_elliptic_curve` raises :py:class:`ValueError` if called
with a name which does not identify a supported curve.
"""
self.assertRaises(
ValueError, get_elliptic_curve, u("this curve was just invented"))
def test_repr(self):
"""
The string representation of a curve object includes simply states the
object is a curve and what its name is.
"""
curves = get_elliptic_curves()
if curves:
curve = next(iter(curves))
self.assertEqual("<Curve %r>" % (curve.name,), repr(curve))
def test_to_EC_KEY(self):
"""
The curve object can export a version of itself as an EC_KEY* via the
private :py:meth:`_EllipticCurve._to_EC_KEY`.
"""
curves = get_elliptic_curves()
if curves:
curve = next(iter(curves))
# It's not easy to assert anything about this object. However, see
# leakcheck/crypto.py for a test that demonstrates it at least does
# not leak memory.
curve._to_EC_KEY()
class EllipticCurveFactory(object):
"""
A helper to get the names of two curves.
"""
def __init__(self):
curves = iter(get_elliptic_curves())
try:
self.curve_name = next(curves).name
self.another_curve_name = next(curves).name
except StopIteration:
self.curve_name = self.another_curve_name = None
class EllipticCurveEqualityTests(TestCase, EqualityTestsMixin):
"""
Tests :py:type:`_EllipticCurve`\ 's implementation of ``==`` and ``!=``.
"""
curve_factory = EllipticCurveFactory()
if curve_factory.curve_name is None:
skip = "There are no curves available there can be no curve objects."
def anInstance(self):
"""
Get the curve object for an arbitrary curve supported by the system.
"""
return get_elliptic_curve(self.curve_factory.curve_name)
def anotherInstance(self):
"""
Get the curve object for an arbitrary curve supported by the system -
but not the one returned by C{anInstance}.
"""
return get_elliptic_curve(self.curve_factory.another_curve_name)
class EllipticCurveHashTests(TestCase):
"""
Tests for :py:type:`_EllipticCurve`\ 's implementation of hashing (thus use
as an item in a :py:type:`dict` or :py:type:`set`).
"""
curve_factory = EllipticCurveFactory()
if curve_factory.curve_name is None:
skip = "There are no curves available there can be no curve objects."
def test_contains(self):
"""
The ``in`` operator reports that a :py:type:`set` containing a curve
does contain that curve.
"""
curve = get_elliptic_curve(self.curve_factory.curve_name)
curves = set([curve])
self.assertIn(curve, curves)
def test_does_not_contain(self):
"""
The ``in`` operator reports that a :py:type:`set` not containing a
curve does not contain that curve.
"""
curve = get_elliptic_curve(self.curve_factory.curve_name)
curves = set([get_elliptic_curve(self.curve_factory.another_curve_name)])
self.assertNotIn(curve, curves)
if __name__ == '__main__': if __name__ == '__main__':
main() main()

View file

@ -10,7 +10,7 @@ import os
import stat import stat
import sys import sys
from OpenSSL.test.util import TestCase, b from OpenSSL.test.util import NON_ASCII, TestCase, b
from OpenSSL import rand from OpenSSL import rand
@ -176,27 +176,47 @@ class RandTests(TestCase):
self.assertRaises(TypeError, rand.write_file, None) self.assertRaises(TypeError, rand.write_file, None)
self.assertRaises(TypeError, rand.write_file, "foo", None) self.assertRaises(TypeError, rand.write_file, "foo", None)
def _read_write_test(self, path):
"""
Verify that ``rand.write_file`` and ``rand.load_file`` can be used.
"""
# Create the file so cleanup is more straightforward
with open(path, "w"):
pass
def test_files(self):
"""
Test reading and writing of files via rand functions.
"""
# Write random bytes to a file
tmpfile = self.mktemp()
# Make sure it exists (so cleanup definitely succeeds)
fObj = open(tmpfile, 'w')
fObj.close()
try: try:
rand.write_file(tmpfile) # Write random bytes to a file
rand.write_file(path)
# Verify length of written file # Verify length of written file
size = os.stat(tmpfile)[stat.ST_SIZE] size = os.stat(path)[stat.ST_SIZE]
self.assertEqual(1024, size) self.assertEqual(1024, size)
# Read random bytes from file # Read random bytes from file
rand.load_file(tmpfile) rand.load_file(path)
rand.load_file(tmpfile, 4) # specify a length rand.load_file(path, 4) # specify a length
finally: finally:
# Cleanup # Cleanup
os.unlink(tmpfile) os.unlink(path)
def test_bytes_paths(self):
"""
Random data can be saved and loaded to files with paths specified as
bytes.
"""
path = self.mktemp()
path += NON_ASCII.encode(sys.getfilesystemencoding())
self._read_write_test(path)
def test_unicode_paths(self):
"""
Random data can be saved and loaded to files with paths specified as
unicode.
"""
path = self.mktemp().decode('utf-8') + NON_ASCII
self._read_write_test(path)
if __name__ == '__main__': if __name__ == '__main__':

View file

@ -0,0 +1,24 @@
# Copyright (C) Jean-Paul Calderone
# See LICENSE for details.
"""
Unit tests for :py:obj:`OpenSSL.tsafe`.
"""
from OpenSSL.SSL import TLSv1_METHOD, Context
from OpenSSL.tsafe import Connection
from OpenSSL.test.util import TestCase
class ConnectionTest(TestCase):
"""
Tests for :py:obj:`OpenSSL.tsafe.Connection`.
"""
def test_instantiation(self):
"""
:py:obj:`OpenSSL.tsafe.Connection` can be instantiated.
"""
# The following line should not throw an error. This isn't an ideal
# test. It would be great to refactor the other Connection tests so
# they could automatically be applied to this class too.
Connection(Context(TLSv1_METHOD), None)

View file

@ -0,0 +1,17 @@
from OpenSSL._util import exception_from_error_queue, lib
from OpenSSL.test.util import TestCase
class ErrorTests(TestCase):
"""
Tests for handling of certain OpenSSL error cases.
"""
def test_exception_from_error_queue_nonexistent_reason(self):
"""
:py:func:`exception_from_error_queue` raises ``ValueError`` when it
encounters an OpenSSL error code which does not have a reason string.
"""
lib.ERR_put_error(lib.ERR_LIB_EVP, 0, 1112, b"", 10)
exc = self.assertRaises(ValueError, exception_from_error_queue, ValueError)
self.assertEqual(exc.args[0][0][2], "")

View file

@ -14,6 +14,8 @@ from tempfile import mktemp
from unittest import TestCase from unittest import TestCase
import sys import sys
from six import PY3
from OpenSSL._util import exception_from_error_queue from OpenSSL._util import exception_from_error_queue
from OpenSSL.crypto import Error from OpenSSL.crypto import Error
@ -25,6 +27,11 @@ except Exception:
from OpenSSL._util import ffi, lib, byte_string as b from OpenSSL._util import ffi, lib, byte_string as b
# This is the UTF-8 encoding of the SNOWMAN unicode code point.
NON_ASCII = b("\xe2\x98\x83").decode("utf-8")
class TestCase(TestCase): class TestCase(TestCase):
""" """
:py:class:`TestCase` adds useful testing functionality beyond what is available :py:class:`TestCase` adds useful testing functionality beyond what is available
@ -210,7 +217,24 @@ class TestCase(TestCase):
return containee return containee
assertIn = failUnlessIn assertIn = failUnlessIn
def failUnlessIdentical(self, first, second, msg=None): def assertNotIn(self, containee, container, msg=None):
"""
Fail the test if C{containee} is found in C{container}.
@param containee: the value that should not be in C{container}
@param container: a sequence type, or in the case of a mapping type,
will follow semantics of 'if key in dict.keys()'
@param msg: if msg is None, then the failure message will be
'%r in %r' % (first, second)
"""
if containee in container:
raise self.failureException(msg or "%r in %r"
% (containee, container))
return containee
failIfIn = assertNotIn
def assertIs(self, first, second, msg=None):
""" """
Fail the test if :py:data:`first` is not :py:data:`second`. This is an Fail the test if :py:data:`first` is not :py:data:`second`. This is an
obect-identity-equality test, not an object equality obect-identity-equality test, not an object equality
@ -222,10 +246,10 @@ class TestCase(TestCase):
if first is not second: if first is not second:
raise self.failureException(msg or '%r is not %r' % (first, second)) raise self.failureException(msg or '%r is not %r' % (first, second))
return first return first
assertIdentical = failUnlessIdentical assertIdentical = failUnlessIdentical = assertIs
def failIfIdentical(self, first, second, msg=None): def assertIsNot(self, first, second, msg=None):
""" """
Fail the test if :py:data:`first` is :py:data:`second`. This is an Fail the test if :py:data:`first` is :py:data:`second`. This is an
obect-identity-equality test, not an object equality obect-identity-equality test, not an object equality
@ -237,7 +261,7 @@ class TestCase(TestCase):
if first is second: if first is second:
raise self.failureException(msg or '%r is %r' % (first, second)) raise self.failureException(msg or '%r is %r' % (first, second))
return first return first
assertNotIdentical = failIfIdentical assertNotIdentical = failIfIdentical = assertIsNot
def failUnlessRaises(self, exception, f, *args, **kwargs): def failUnlessRaises(self, exception, f, *args, **kwargs):
@ -300,3 +324,140 @@ class TestCase(TestCase):
self.assertTrue(isinstance(theType, type)) self.assertTrue(isinstance(theType, type))
instance = theType(*constructionArgs) instance = theType(*constructionArgs)
self.assertIdentical(type(instance), theType) self.assertIdentical(type(instance), theType)
class EqualityTestsMixin(object):
"""
A mixin defining tests for the standard implementation of C{==} and C{!=}.
"""
def anInstance(self):
"""
Return an instance of the class under test. Each call to this method
must return a different object. All objects returned must be equal to
each other.
"""
raise NotImplementedError()
def anotherInstance(self):
"""
Return an instance of the class under test. Each call to this method
must return a different object. The objects must not be equal to the
objects returned by C{anInstance}. They may or may not be equal to
each other (they will not be compared against each other).
"""
raise NotImplementedError()
def test_identicalEq(self):
"""
An object compares equal to itself using the C{==} operator.
"""
o = self.anInstance()
self.assertTrue(o == o)
def test_identicalNe(self):
"""
An object doesn't compare not equal to itself using the C{!=} operator.
"""
o = self.anInstance()
self.assertFalse(o != o)
def test_sameEq(self):
"""
Two objects that are equal to each other compare equal to each other
using the C{==} operator.
"""
a = self.anInstance()
b = self.anInstance()
self.assertTrue(a == b)
def test_sameNe(self):
"""
Two objects that are equal to each other do not compare not equal to
each other using the C{!=} operator.
"""
a = self.anInstance()
b = self.anInstance()
self.assertFalse(a != b)
def test_differentEq(self):
"""
Two objects that are not equal to each other do not compare equal to
each other using the C{==} operator.
"""
a = self.anInstance()
b = self.anotherInstance()
self.assertFalse(a == b)
def test_differentNe(self):
"""
Two objects that are not equal to each other compare not equal to each
other using the C{!=} operator.
"""
a = self.anInstance()
b = self.anotherInstance()
self.assertTrue(a != b)
def test_anotherTypeEq(self):
"""
The object does not compare equal to an object of an unrelated type
(which does not implement the comparison) using the C{==} operator.
"""
a = self.anInstance()
b = object()
self.assertFalse(a == b)
def test_anotherTypeNe(self):
"""
The object compares not equal to an object of an unrelated type (which
does not implement the comparison) using the C{!=} operator.
"""
a = self.anInstance()
b = object()
self.assertTrue(a != b)
def test_delegatedEq(self):
"""
The result of comparison using C{==} is delegated to the right-hand
operand if it is of an unrelated type.
"""
class Delegate(object):
def __eq__(self, other):
# Do something crazy and obvious.
return [self]
a = self.anInstance()
b = Delegate()
self.assertEqual(a == b, [b])
def test_delegateNe(self):
"""
The result of comparison using C{!=} is delegated to the right-hand
operand if it is of an unrelated type.
"""
class Delegate(object):
def __ne__(self, other):
# Do something crazy and obvious.
return [self]
a = self.anInstance()
b = Delegate()
self.assertEqual(a != b, [b])
# The type name expected in warnings about using the wrong string type.
if PY3:
WARNING_TYPE_EXPECTED = "str"
else:
WARNING_TYPE_EXPECTED = "unicode"

View file

@ -8,7 +8,7 @@ del threading
class Connection: class Connection:
def __init__(self, *args): def __init__(self, *args):
self._ssl_conn = apply(_ssl.Connection, args) self._ssl_conn = _ssl.Connection(*args)
self._lock = _RLock() self._lock = _RLock()
for f in ('get_context', 'pending', 'send', 'write', 'recv', 'read', for f in ('get_context', 'pending', 'send', 'write', 'recv', 'read',

View file

@ -6,4 +6,4 @@
pyOpenSSL - A simple wrapper around the OpenSSL library pyOpenSSL - A simple wrapper around the OpenSSL library
""" """
__version__ = '0.14' __version__ = '0.15.1'

View file

@ -1,361 +1,361 @@
../sqlalchemy/interfaces.py
../sqlalchemy/events.py
../sqlalchemy/types.py
../sqlalchemy/exc.py
../sqlalchemy/schema.py
../sqlalchemy/inspection.py
../sqlalchemy/__init__.py ../sqlalchemy/__init__.py
../sqlalchemy/events.py
../sqlalchemy/exc.py
../sqlalchemy/inspection.py
../sqlalchemy/interfaces.py
../sqlalchemy/log.py
../sqlalchemy/pool.py ../sqlalchemy/pool.py
../sqlalchemy/processors.py ../sqlalchemy/processors.py
../sqlalchemy/log.py ../sqlalchemy/schema.py
../sqlalchemy/types.py
../sqlalchemy/connectors/__init__.py
../sqlalchemy/connectors/mxodbc.py
../sqlalchemy/connectors/mysqldb.py
../sqlalchemy/connectors/pyodbc.py
../sqlalchemy/connectors/zxJDBC.py
../sqlalchemy/databases/__init__.py ../sqlalchemy/databases/__init__.py
../sqlalchemy/testing/engines.py ../sqlalchemy/dialects/__init__.py
../sqlalchemy/testing/schema.py ../sqlalchemy/dialects/postgres.py
../sqlalchemy/testing/pickleable.py ../sqlalchemy/dialects/drizzle/__init__.py
../sqlalchemy/testing/fixtures.py ../sqlalchemy/dialects/drizzle/base.py
../sqlalchemy/dialects/drizzle/mysqldb.py
../sqlalchemy/dialects/firebird/__init__.py
../sqlalchemy/dialects/firebird/base.py
../sqlalchemy/dialects/firebird/fdb.py
../sqlalchemy/dialects/firebird/kinterbasdb.py
../sqlalchemy/dialects/mssql/__init__.py
../sqlalchemy/dialects/mssql/adodbapi.py
../sqlalchemy/dialects/mssql/base.py
../sqlalchemy/dialects/mssql/information_schema.py
../sqlalchemy/dialects/mssql/mxodbc.py
../sqlalchemy/dialects/mssql/pymssql.py
../sqlalchemy/dialects/mssql/pyodbc.py
../sqlalchemy/dialects/mssql/zxjdbc.py
../sqlalchemy/dialects/mysql/__init__.py
../sqlalchemy/dialects/mysql/base.py
../sqlalchemy/dialects/mysql/cymysql.py
../sqlalchemy/dialects/mysql/gaerdbms.py
../sqlalchemy/dialects/mysql/mysqlconnector.py
../sqlalchemy/dialects/mysql/mysqldb.py
../sqlalchemy/dialects/mysql/oursql.py
../sqlalchemy/dialects/mysql/pymysql.py
../sqlalchemy/dialects/mysql/pyodbc.py
../sqlalchemy/dialects/mysql/zxjdbc.py
../sqlalchemy/dialects/oracle/__init__.py
../sqlalchemy/dialects/oracle/base.py
../sqlalchemy/dialects/oracle/cx_oracle.py
../sqlalchemy/dialects/oracle/zxjdbc.py
../sqlalchemy/dialects/postgresql/__init__.py
../sqlalchemy/dialects/postgresql/base.py
../sqlalchemy/dialects/postgresql/constraints.py
../sqlalchemy/dialects/postgresql/hstore.py
../sqlalchemy/dialects/postgresql/json.py
../sqlalchemy/dialects/postgresql/pg8000.py
../sqlalchemy/dialects/postgresql/psycopg2.py
../sqlalchemy/dialects/postgresql/pypostgresql.py
../sqlalchemy/dialects/postgresql/ranges.py
../sqlalchemy/dialects/postgresql/zxjdbc.py
../sqlalchemy/dialects/sqlite/__init__.py
../sqlalchemy/dialects/sqlite/base.py
../sqlalchemy/dialects/sqlite/pysqlite.py
../sqlalchemy/dialects/sybase/__init__.py
../sqlalchemy/dialects/sybase/base.py
../sqlalchemy/dialects/sybase/mxodbc.py
../sqlalchemy/dialects/sybase/pyodbc.py
../sqlalchemy/dialects/sybase/pysybase.py
../sqlalchemy/engine/__init__.py
../sqlalchemy/engine/base.py
../sqlalchemy/engine/default.py
../sqlalchemy/engine/interfaces.py
../sqlalchemy/engine/reflection.py
../sqlalchemy/engine/result.py
../sqlalchemy/engine/strategies.py
../sqlalchemy/engine/threadlocal.py
../sqlalchemy/engine/url.py
../sqlalchemy/engine/util.py
../sqlalchemy/event/__init__.py
../sqlalchemy/event/api.py
../sqlalchemy/event/attr.py
../sqlalchemy/event/base.py
../sqlalchemy/event/legacy.py
../sqlalchemy/event/registry.py
../sqlalchemy/ext/__init__.py
../sqlalchemy/ext/associationproxy.py
../sqlalchemy/ext/automap.py
../sqlalchemy/ext/compiler.py
../sqlalchemy/ext/horizontal_shard.py
../sqlalchemy/ext/hybrid.py
../sqlalchemy/ext/instrumentation.py
../sqlalchemy/ext/mutable.py
../sqlalchemy/ext/orderinglist.py
../sqlalchemy/ext/serializer.py
../sqlalchemy/ext/declarative/__init__.py
../sqlalchemy/ext/declarative/api.py
../sqlalchemy/ext/declarative/base.py
../sqlalchemy/ext/declarative/clsregistry.py
../sqlalchemy/orm/__init__.py
../sqlalchemy/orm/attributes.py
../sqlalchemy/orm/base.py
../sqlalchemy/orm/collections.py
../sqlalchemy/orm/dependency.py
../sqlalchemy/orm/deprecated_interfaces.py
../sqlalchemy/orm/descriptor_props.py
../sqlalchemy/orm/dynamic.py
../sqlalchemy/orm/evaluator.py
../sqlalchemy/orm/events.py
../sqlalchemy/orm/exc.py
../sqlalchemy/orm/identity.py
../sqlalchemy/orm/instrumentation.py
../sqlalchemy/orm/interfaces.py
../sqlalchemy/orm/loading.py
../sqlalchemy/orm/mapper.py
../sqlalchemy/orm/path_registry.py
../sqlalchemy/orm/persistence.py
../sqlalchemy/orm/properties.py
../sqlalchemy/orm/query.py
../sqlalchemy/orm/relationships.py
../sqlalchemy/orm/scoping.py
../sqlalchemy/orm/session.py
../sqlalchemy/orm/state.py
../sqlalchemy/orm/strategies.py
../sqlalchemy/orm/strategy_options.py
../sqlalchemy/orm/sync.py
../sqlalchemy/orm/unitofwork.py
../sqlalchemy/orm/util.py
../sqlalchemy/sql/__init__.py
../sqlalchemy/sql/annotation.py
../sqlalchemy/sql/base.py
../sqlalchemy/sql/compiler.py
../sqlalchemy/sql/ddl.py
../sqlalchemy/sql/default_comparator.py
../sqlalchemy/sql/dml.py
../sqlalchemy/sql/elements.py
../sqlalchemy/sql/expression.py
../sqlalchemy/sql/functions.py
../sqlalchemy/sql/naming.py
../sqlalchemy/sql/operators.py
../sqlalchemy/sql/schema.py
../sqlalchemy/sql/selectable.py
../sqlalchemy/sql/sqltypes.py
../sqlalchemy/sql/type_api.py
../sqlalchemy/sql/util.py
../sqlalchemy/sql/visitors.py
../sqlalchemy/testing/__init__.py ../sqlalchemy/testing/__init__.py
../sqlalchemy/testing/assertions.py
../sqlalchemy/testing/assertsql.py ../sqlalchemy/testing/assertsql.py
../sqlalchemy/testing/config.py ../sqlalchemy/testing/config.py
../sqlalchemy/testing/warnings.py
../sqlalchemy/testing/distutils_run.py ../sqlalchemy/testing/distutils_run.py
../sqlalchemy/testing/engines.py
../sqlalchemy/testing/entities.py
../sqlalchemy/testing/exclusions.py
../sqlalchemy/testing/fixtures.py
../sqlalchemy/testing/mock.py
../sqlalchemy/testing/pickleable.py
../sqlalchemy/testing/profiling.py
../sqlalchemy/testing/requirements.py ../sqlalchemy/testing/requirements.py
../sqlalchemy/testing/runner.py ../sqlalchemy/testing/runner.py
../sqlalchemy/testing/assertions.py ../sqlalchemy/testing/schema.py
../sqlalchemy/testing/profiling.py
../sqlalchemy/testing/mock.py
../sqlalchemy/testing/exclusions.py
../sqlalchemy/testing/util.py ../sqlalchemy/testing/util.py
../sqlalchemy/testing/entities.py ../sqlalchemy/testing/warnings.py
../sqlalchemy/testing/plugin/noseplugin.py
../sqlalchemy/testing/plugin/__init__.py ../sqlalchemy/testing/plugin/__init__.py
../sqlalchemy/testing/plugin/pytestplugin.py ../sqlalchemy/testing/plugin/noseplugin.py
../sqlalchemy/testing/plugin/plugin_base.py ../sqlalchemy/testing/plugin/plugin_base.py
../sqlalchemy/testing/suite/test_insert.py ../sqlalchemy/testing/plugin/pytestplugin.py
../sqlalchemy/testing/suite/test_results.py
../sqlalchemy/testing/suite/__init__.py ../sqlalchemy/testing/suite/__init__.py
../sqlalchemy/testing/suite/test_ddl.py
../sqlalchemy/testing/suite/test_insert.py
../sqlalchemy/testing/suite/test_reflection.py
../sqlalchemy/testing/suite/test_results.py
../sqlalchemy/testing/suite/test_select.py ../sqlalchemy/testing/suite/test_select.py
../sqlalchemy/testing/suite/test_sequence.py ../sqlalchemy/testing/suite/test_sequence.py
../sqlalchemy/testing/suite/test_types.py ../sqlalchemy/testing/suite/test_types.py
../sqlalchemy/testing/suite/test_update_delete.py ../sqlalchemy/testing/suite/test_update_delete.py
../sqlalchemy/testing/suite/test_reflection.py ../sqlalchemy/util/__init__.py
../sqlalchemy/testing/suite/test_ddl.py ../sqlalchemy/util/_collections.py
../sqlalchemy/orm/persistence.py ../sqlalchemy/util/compat.py
../sqlalchemy/orm/interfaces.py ../sqlalchemy/util/deprecations.py
../sqlalchemy/orm/events.py
../sqlalchemy/orm/path_registry.py
../sqlalchemy/orm/descriptor_props.py
../sqlalchemy/orm/identity.py
../sqlalchemy/orm/evaluator.py
../sqlalchemy/orm/exc.py
../sqlalchemy/orm/base.py
../sqlalchemy/orm/__init__.py
../sqlalchemy/orm/properties.py
../sqlalchemy/orm/relationships.py
../sqlalchemy/orm/collections.py
../sqlalchemy/orm/strategy_options.py
../sqlalchemy/orm/dynamic.py
../sqlalchemy/orm/attributes.py
../sqlalchemy/orm/mapper.py
../sqlalchemy/orm/state.py
../sqlalchemy/orm/sync.py
../sqlalchemy/orm/loading.py
../sqlalchemy/orm/strategies.py
../sqlalchemy/orm/unitofwork.py
../sqlalchemy/orm/query.py
../sqlalchemy/orm/instrumentation.py
../sqlalchemy/orm/session.py
../sqlalchemy/orm/deprecated_interfaces.py
../sqlalchemy/orm/scoping.py
../sqlalchemy/orm/dependency.py
../sqlalchemy/orm/util.py
../sqlalchemy/sql/default_comparator.py
../sqlalchemy/sql/sqltypes.py
../sqlalchemy/sql/functions.py
../sqlalchemy/sql/base.py
../sqlalchemy/sql/schema.py
../sqlalchemy/sql/__init__.py
../sqlalchemy/sql/ddl.py
../sqlalchemy/sql/elements.py
../sqlalchemy/sql/compiler.py
../sqlalchemy/sql/annotation.py
../sqlalchemy/sql/dml.py
../sqlalchemy/sql/expression.py
../sqlalchemy/sql/operators.py
../sqlalchemy/sql/selectable.py
../sqlalchemy/sql/visitors.py
../sqlalchemy/sql/type_api.py
../sqlalchemy/sql/naming.py
../sqlalchemy/sql/util.py
../sqlalchemy/ext/serializer.py
../sqlalchemy/ext/associationproxy.py
../sqlalchemy/ext/automap.py
../sqlalchemy/ext/__init__.py
../sqlalchemy/ext/hybrid.py
../sqlalchemy/ext/compiler.py
../sqlalchemy/ext/horizontal_shard.py
../sqlalchemy/ext/orderinglist.py
../sqlalchemy/ext/instrumentation.py
../sqlalchemy/ext/mutable.py
../sqlalchemy/ext/declarative/base.py
../sqlalchemy/ext/declarative/__init__.py
../sqlalchemy/ext/declarative/clsregistry.py
../sqlalchemy/ext/declarative/api.py
../sqlalchemy/util/langhelpers.py ../sqlalchemy/util/langhelpers.py
../sqlalchemy/util/queue.py ../sqlalchemy/util/queue.py
../sqlalchemy/util/compat.py
../sqlalchemy/util/__init__.py
../sqlalchemy/util/deprecations.py
../sqlalchemy/util/_collections.py
../sqlalchemy/util/topological.py ../sqlalchemy/util/topological.py
../sqlalchemy/connectors/mxodbc.py
../sqlalchemy/connectors/__init__.py
../sqlalchemy/connectors/pyodbc.py
../sqlalchemy/connectors/mysqldb.py
../sqlalchemy/connectors/zxJDBC.py
../sqlalchemy/dialects/postgres.py
../sqlalchemy/dialects/__init__.py
../sqlalchemy/dialects/mssql/adodbapi.py
../sqlalchemy/dialects/mssql/mxodbc.py
../sqlalchemy/dialects/mssql/base.py
../sqlalchemy/dialects/mssql/information_schema.py
../sqlalchemy/dialects/mssql/__init__.py
../sqlalchemy/dialects/mssql/pyodbc.py
../sqlalchemy/dialects/mssql/zxjdbc.py
../sqlalchemy/dialects/mssql/pymssql.py
../sqlalchemy/dialects/postgresql/pg8000.py
../sqlalchemy/dialects/postgresql/ranges.py
../sqlalchemy/dialects/postgresql/base.py
../sqlalchemy/dialects/postgresql/__init__.py
../sqlalchemy/dialects/postgresql/zxjdbc.py
../sqlalchemy/dialects/postgresql/json.py
../sqlalchemy/dialects/postgresql/pypostgresql.py
../sqlalchemy/dialects/postgresql/constraints.py
../sqlalchemy/dialects/postgresql/hstore.py
../sqlalchemy/dialects/postgresql/psycopg2.py
../sqlalchemy/dialects/sybase/mxodbc.py
../sqlalchemy/dialects/sybase/base.py
../sqlalchemy/dialects/sybase/__init__.py
../sqlalchemy/dialects/sybase/pyodbc.py
../sqlalchemy/dialects/sybase/pysybase.py
../sqlalchemy/dialects/drizzle/base.py
../sqlalchemy/dialects/drizzle/__init__.py
../sqlalchemy/dialects/drizzle/mysqldb.py
../sqlalchemy/dialects/mysql/mysqlconnector.py
../sqlalchemy/dialects/mysql/base.py
../sqlalchemy/dialects/mysql/__init__.py
../sqlalchemy/dialects/mysql/pyodbc.py
../sqlalchemy/dialects/mysql/zxjdbc.py
../sqlalchemy/dialects/mysql/oursql.py
../sqlalchemy/dialects/mysql/pymysql.py
../sqlalchemy/dialects/mysql/cymysql.py
../sqlalchemy/dialects/mysql/gaerdbms.py
../sqlalchemy/dialects/mysql/mysqldb.py
../sqlalchemy/dialects/sqlite/base.py
../sqlalchemy/dialects/sqlite/__init__.py
../sqlalchemy/dialects/sqlite/pysqlite.py
../sqlalchemy/dialects/firebird/base.py
../sqlalchemy/dialects/firebird/__init__.py
../sqlalchemy/dialects/firebird/fdb.py
../sqlalchemy/dialects/firebird/kinterbasdb.py
../sqlalchemy/dialects/oracle/base.py
../sqlalchemy/dialects/oracle/__init__.py
../sqlalchemy/dialects/oracle/zxjdbc.py
../sqlalchemy/dialects/oracle/cx_oracle.py
../sqlalchemy/engine/interfaces.py
../sqlalchemy/engine/result.py
../sqlalchemy/engine/base.py
../sqlalchemy/engine/url.py
../sqlalchemy/engine/threadlocal.py
../sqlalchemy/engine/__init__.py
../sqlalchemy/engine/default.py
../sqlalchemy/engine/strategies.py
../sqlalchemy/engine/reflection.py
../sqlalchemy/engine/util.py
../sqlalchemy/event/base.py
../sqlalchemy/event/__init__.py
../sqlalchemy/event/attr.py
../sqlalchemy/event/registry.py
../sqlalchemy/event/legacy.py
../sqlalchemy/event/api.py
../sqlalchemy/__pycache__/interfaces.cpython-34.pyc
../sqlalchemy/__pycache__/events.cpython-34.pyc
../sqlalchemy/__pycache__/types.cpython-34.pyc
../sqlalchemy/__pycache__/exc.cpython-34.pyc
../sqlalchemy/__pycache__/schema.cpython-34.pyc
../sqlalchemy/__pycache__/inspection.cpython-34.pyc
../sqlalchemy/__pycache__/__init__.cpython-34.pyc ../sqlalchemy/__pycache__/__init__.cpython-34.pyc
../sqlalchemy/__pycache__/events.cpython-34.pyc
../sqlalchemy/__pycache__/exc.cpython-34.pyc
../sqlalchemy/__pycache__/inspection.cpython-34.pyc
../sqlalchemy/__pycache__/interfaces.cpython-34.pyc
../sqlalchemy/__pycache__/log.cpython-34.pyc
../sqlalchemy/__pycache__/pool.cpython-34.pyc ../sqlalchemy/__pycache__/pool.cpython-34.pyc
../sqlalchemy/__pycache__/processors.cpython-34.pyc ../sqlalchemy/__pycache__/processors.cpython-34.pyc
../sqlalchemy/__pycache__/log.cpython-34.pyc ../sqlalchemy/__pycache__/schema.cpython-34.pyc
../sqlalchemy/__pycache__/types.cpython-34.pyc
../sqlalchemy/connectors/__pycache__/__init__.cpython-34.pyc
../sqlalchemy/connectors/__pycache__/mxodbc.cpython-34.pyc
../sqlalchemy/connectors/__pycache__/mysqldb.cpython-34.pyc
../sqlalchemy/connectors/__pycache__/pyodbc.cpython-34.pyc
../sqlalchemy/connectors/__pycache__/zxJDBC.cpython-34.pyc
../sqlalchemy/databases/__pycache__/__init__.cpython-34.pyc ../sqlalchemy/databases/__pycache__/__init__.cpython-34.pyc
../sqlalchemy/testing/__pycache__/engines.cpython-34.pyc ../sqlalchemy/dialects/__pycache__/__init__.cpython-34.pyc
../sqlalchemy/testing/__pycache__/schema.cpython-34.pyc ../sqlalchemy/dialects/__pycache__/postgres.cpython-34.pyc
../sqlalchemy/testing/__pycache__/pickleable.cpython-34.pyc ../sqlalchemy/dialects/drizzle/__pycache__/__init__.cpython-34.pyc
../sqlalchemy/testing/__pycache__/fixtures.cpython-34.pyc ../sqlalchemy/dialects/drizzle/__pycache__/base.cpython-34.pyc
../sqlalchemy/dialects/drizzle/__pycache__/mysqldb.cpython-34.pyc
../sqlalchemy/dialects/firebird/__pycache__/__init__.cpython-34.pyc
../sqlalchemy/dialects/firebird/__pycache__/base.cpython-34.pyc
../sqlalchemy/dialects/firebird/__pycache__/fdb.cpython-34.pyc
../sqlalchemy/dialects/firebird/__pycache__/kinterbasdb.cpython-34.pyc
../sqlalchemy/dialects/mssql/__pycache__/__init__.cpython-34.pyc
../sqlalchemy/dialects/mssql/__pycache__/adodbapi.cpython-34.pyc
../sqlalchemy/dialects/mssql/__pycache__/base.cpython-34.pyc
../sqlalchemy/dialects/mssql/__pycache__/information_schema.cpython-34.pyc
../sqlalchemy/dialects/mssql/__pycache__/mxodbc.cpython-34.pyc
../sqlalchemy/dialects/mssql/__pycache__/pymssql.cpython-34.pyc
../sqlalchemy/dialects/mssql/__pycache__/pyodbc.cpython-34.pyc
../sqlalchemy/dialects/mssql/__pycache__/zxjdbc.cpython-34.pyc
../sqlalchemy/dialects/mysql/__pycache__/__init__.cpython-34.pyc
../sqlalchemy/dialects/mysql/__pycache__/base.cpython-34.pyc
../sqlalchemy/dialects/mysql/__pycache__/cymysql.cpython-34.pyc
../sqlalchemy/dialects/mysql/__pycache__/gaerdbms.cpython-34.pyc
../sqlalchemy/dialects/mysql/__pycache__/mysqlconnector.cpython-34.pyc
../sqlalchemy/dialects/mysql/__pycache__/mysqldb.cpython-34.pyc
../sqlalchemy/dialects/mysql/__pycache__/oursql.cpython-34.pyc
../sqlalchemy/dialects/mysql/__pycache__/pymysql.cpython-34.pyc
../sqlalchemy/dialects/mysql/__pycache__/pyodbc.cpython-34.pyc
../sqlalchemy/dialects/mysql/__pycache__/zxjdbc.cpython-34.pyc
../sqlalchemy/dialects/oracle/__pycache__/__init__.cpython-34.pyc
../sqlalchemy/dialects/oracle/__pycache__/base.cpython-34.pyc
../sqlalchemy/dialects/oracle/__pycache__/cx_oracle.cpython-34.pyc
../sqlalchemy/dialects/oracle/__pycache__/zxjdbc.cpython-34.pyc
../sqlalchemy/dialects/postgresql/__pycache__/__init__.cpython-34.pyc
../sqlalchemy/dialects/postgresql/__pycache__/base.cpython-34.pyc
../sqlalchemy/dialects/postgresql/__pycache__/constraints.cpython-34.pyc
../sqlalchemy/dialects/postgresql/__pycache__/hstore.cpython-34.pyc
../sqlalchemy/dialects/postgresql/__pycache__/json.cpython-34.pyc
../sqlalchemy/dialects/postgresql/__pycache__/pg8000.cpython-34.pyc
../sqlalchemy/dialects/postgresql/__pycache__/psycopg2.cpython-34.pyc
../sqlalchemy/dialects/postgresql/__pycache__/pypostgresql.cpython-34.pyc
../sqlalchemy/dialects/postgresql/__pycache__/ranges.cpython-34.pyc
../sqlalchemy/dialects/postgresql/__pycache__/zxjdbc.cpython-34.pyc
../sqlalchemy/dialects/sqlite/__pycache__/__init__.cpython-34.pyc
../sqlalchemy/dialects/sqlite/__pycache__/base.cpython-34.pyc
../sqlalchemy/dialects/sqlite/__pycache__/pysqlite.cpython-34.pyc
../sqlalchemy/dialects/sybase/__pycache__/__init__.cpython-34.pyc
../sqlalchemy/dialects/sybase/__pycache__/base.cpython-34.pyc
../sqlalchemy/dialects/sybase/__pycache__/mxodbc.cpython-34.pyc
../sqlalchemy/dialects/sybase/__pycache__/pyodbc.cpython-34.pyc
../sqlalchemy/dialects/sybase/__pycache__/pysybase.cpython-34.pyc
../sqlalchemy/engine/__pycache__/__init__.cpython-34.pyc
../sqlalchemy/engine/__pycache__/base.cpython-34.pyc
../sqlalchemy/engine/__pycache__/default.cpython-34.pyc
../sqlalchemy/engine/__pycache__/interfaces.cpython-34.pyc
../sqlalchemy/engine/__pycache__/reflection.cpython-34.pyc
../sqlalchemy/engine/__pycache__/result.cpython-34.pyc
../sqlalchemy/engine/__pycache__/strategies.cpython-34.pyc
../sqlalchemy/engine/__pycache__/threadlocal.cpython-34.pyc
../sqlalchemy/engine/__pycache__/url.cpython-34.pyc
../sqlalchemy/engine/__pycache__/util.cpython-34.pyc
../sqlalchemy/event/__pycache__/__init__.cpython-34.pyc
../sqlalchemy/event/__pycache__/api.cpython-34.pyc
../sqlalchemy/event/__pycache__/attr.cpython-34.pyc
../sqlalchemy/event/__pycache__/base.cpython-34.pyc
../sqlalchemy/event/__pycache__/legacy.cpython-34.pyc
../sqlalchemy/event/__pycache__/registry.cpython-34.pyc
../sqlalchemy/ext/__pycache__/__init__.cpython-34.pyc
../sqlalchemy/ext/__pycache__/associationproxy.cpython-34.pyc
../sqlalchemy/ext/__pycache__/automap.cpython-34.pyc
../sqlalchemy/ext/__pycache__/compiler.cpython-34.pyc
../sqlalchemy/ext/__pycache__/horizontal_shard.cpython-34.pyc
../sqlalchemy/ext/__pycache__/hybrid.cpython-34.pyc
../sqlalchemy/ext/__pycache__/instrumentation.cpython-34.pyc
../sqlalchemy/ext/__pycache__/mutable.cpython-34.pyc
../sqlalchemy/ext/__pycache__/orderinglist.cpython-34.pyc
../sqlalchemy/ext/__pycache__/serializer.cpython-34.pyc
../sqlalchemy/ext/declarative/__pycache__/__init__.cpython-34.pyc
../sqlalchemy/ext/declarative/__pycache__/api.cpython-34.pyc
../sqlalchemy/ext/declarative/__pycache__/base.cpython-34.pyc
../sqlalchemy/ext/declarative/__pycache__/clsregistry.cpython-34.pyc
../sqlalchemy/orm/__pycache__/__init__.cpython-34.pyc
../sqlalchemy/orm/__pycache__/attributes.cpython-34.pyc
../sqlalchemy/orm/__pycache__/base.cpython-34.pyc
../sqlalchemy/orm/__pycache__/collections.cpython-34.pyc
../sqlalchemy/orm/__pycache__/dependency.cpython-34.pyc
../sqlalchemy/orm/__pycache__/deprecated_interfaces.cpython-34.pyc
../sqlalchemy/orm/__pycache__/descriptor_props.cpython-34.pyc
../sqlalchemy/orm/__pycache__/dynamic.cpython-34.pyc
../sqlalchemy/orm/__pycache__/evaluator.cpython-34.pyc
../sqlalchemy/orm/__pycache__/events.cpython-34.pyc
../sqlalchemy/orm/__pycache__/exc.cpython-34.pyc
../sqlalchemy/orm/__pycache__/identity.cpython-34.pyc
../sqlalchemy/orm/__pycache__/instrumentation.cpython-34.pyc
../sqlalchemy/orm/__pycache__/interfaces.cpython-34.pyc
../sqlalchemy/orm/__pycache__/loading.cpython-34.pyc
../sqlalchemy/orm/__pycache__/mapper.cpython-34.pyc
../sqlalchemy/orm/__pycache__/path_registry.cpython-34.pyc
../sqlalchemy/orm/__pycache__/persistence.cpython-34.pyc
../sqlalchemy/orm/__pycache__/properties.cpython-34.pyc
../sqlalchemy/orm/__pycache__/query.cpython-34.pyc
../sqlalchemy/orm/__pycache__/relationships.cpython-34.pyc
../sqlalchemy/orm/__pycache__/scoping.cpython-34.pyc
../sqlalchemy/orm/__pycache__/session.cpython-34.pyc
../sqlalchemy/orm/__pycache__/state.cpython-34.pyc
../sqlalchemy/orm/__pycache__/strategies.cpython-34.pyc
../sqlalchemy/orm/__pycache__/strategy_options.cpython-34.pyc
../sqlalchemy/orm/__pycache__/sync.cpython-34.pyc
../sqlalchemy/orm/__pycache__/unitofwork.cpython-34.pyc
../sqlalchemy/orm/__pycache__/util.cpython-34.pyc
../sqlalchemy/sql/__pycache__/__init__.cpython-34.pyc
../sqlalchemy/sql/__pycache__/annotation.cpython-34.pyc
../sqlalchemy/sql/__pycache__/base.cpython-34.pyc
../sqlalchemy/sql/__pycache__/compiler.cpython-34.pyc
../sqlalchemy/sql/__pycache__/ddl.cpython-34.pyc
../sqlalchemy/sql/__pycache__/default_comparator.cpython-34.pyc
../sqlalchemy/sql/__pycache__/dml.cpython-34.pyc
../sqlalchemy/sql/__pycache__/elements.cpython-34.pyc
../sqlalchemy/sql/__pycache__/expression.cpython-34.pyc
../sqlalchemy/sql/__pycache__/functions.cpython-34.pyc
../sqlalchemy/sql/__pycache__/naming.cpython-34.pyc
../sqlalchemy/sql/__pycache__/operators.cpython-34.pyc
../sqlalchemy/sql/__pycache__/schema.cpython-34.pyc
../sqlalchemy/sql/__pycache__/selectable.cpython-34.pyc
../sqlalchemy/sql/__pycache__/sqltypes.cpython-34.pyc
../sqlalchemy/sql/__pycache__/type_api.cpython-34.pyc
../sqlalchemy/sql/__pycache__/util.cpython-34.pyc
../sqlalchemy/sql/__pycache__/visitors.cpython-34.pyc
../sqlalchemy/testing/__pycache__/__init__.cpython-34.pyc ../sqlalchemy/testing/__pycache__/__init__.cpython-34.pyc
../sqlalchemy/testing/__pycache__/assertions.cpython-34.pyc
../sqlalchemy/testing/__pycache__/assertsql.cpython-34.pyc ../sqlalchemy/testing/__pycache__/assertsql.cpython-34.pyc
../sqlalchemy/testing/__pycache__/config.cpython-34.pyc ../sqlalchemy/testing/__pycache__/config.cpython-34.pyc
../sqlalchemy/testing/__pycache__/warnings.cpython-34.pyc
../sqlalchemy/testing/__pycache__/distutils_run.cpython-34.pyc ../sqlalchemy/testing/__pycache__/distutils_run.cpython-34.pyc
../sqlalchemy/testing/__pycache__/engines.cpython-34.pyc
../sqlalchemy/testing/__pycache__/entities.cpython-34.pyc
../sqlalchemy/testing/__pycache__/exclusions.cpython-34.pyc
../sqlalchemy/testing/__pycache__/fixtures.cpython-34.pyc
../sqlalchemy/testing/__pycache__/mock.cpython-34.pyc
../sqlalchemy/testing/__pycache__/pickleable.cpython-34.pyc
../sqlalchemy/testing/__pycache__/profiling.cpython-34.pyc
../sqlalchemy/testing/__pycache__/requirements.cpython-34.pyc ../sqlalchemy/testing/__pycache__/requirements.cpython-34.pyc
../sqlalchemy/testing/__pycache__/runner.cpython-34.pyc ../sqlalchemy/testing/__pycache__/runner.cpython-34.pyc
../sqlalchemy/testing/__pycache__/assertions.cpython-34.pyc ../sqlalchemy/testing/__pycache__/schema.cpython-34.pyc
../sqlalchemy/testing/__pycache__/profiling.cpython-34.pyc
../sqlalchemy/testing/__pycache__/mock.cpython-34.pyc
../sqlalchemy/testing/__pycache__/exclusions.cpython-34.pyc
../sqlalchemy/testing/__pycache__/util.cpython-34.pyc ../sqlalchemy/testing/__pycache__/util.cpython-34.pyc
../sqlalchemy/testing/__pycache__/entities.cpython-34.pyc ../sqlalchemy/testing/__pycache__/warnings.cpython-34.pyc
../sqlalchemy/testing/plugin/__pycache__/noseplugin.cpython-34.pyc
../sqlalchemy/testing/plugin/__pycache__/__init__.cpython-34.pyc ../sqlalchemy/testing/plugin/__pycache__/__init__.cpython-34.pyc
../sqlalchemy/testing/plugin/__pycache__/pytestplugin.cpython-34.pyc ../sqlalchemy/testing/plugin/__pycache__/noseplugin.cpython-34.pyc
../sqlalchemy/testing/plugin/__pycache__/plugin_base.cpython-34.pyc ../sqlalchemy/testing/plugin/__pycache__/plugin_base.cpython-34.pyc
../sqlalchemy/testing/suite/__pycache__/test_insert.cpython-34.pyc ../sqlalchemy/testing/plugin/__pycache__/pytestplugin.cpython-34.pyc
../sqlalchemy/testing/suite/__pycache__/test_results.cpython-34.pyc
../sqlalchemy/testing/suite/__pycache__/__init__.cpython-34.pyc ../sqlalchemy/testing/suite/__pycache__/__init__.cpython-34.pyc
../sqlalchemy/testing/suite/__pycache__/test_ddl.cpython-34.pyc
../sqlalchemy/testing/suite/__pycache__/test_insert.cpython-34.pyc
../sqlalchemy/testing/suite/__pycache__/test_reflection.cpython-34.pyc
../sqlalchemy/testing/suite/__pycache__/test_results.cpython-34.pyc
../sqlalchemy/testing/suite/__pycache__/test_select.cpython-34.pyc ../sqlalchemy/testing/suite/__pycache__/test_select.cpython-34.pyc
../sqlalchemy/testing/suite/__pycache__/test_sequence.cpython-34.pyc ../sqlalchemy/testing/suite/__pycache__/test_sequence.cpython-34.pyc
../sqlalchemy/testing/suite/__pycache__/test_types.cpython-34.pyc ../sqlalchemy/testing/suite/__pycache__/test_types.cpython-34.pyc
../sqlalchemy/testing/suite/__pycache__/test_update_delete.cpython-34.pyc ../sqlalchemy/testing/suite/__pycache__/test_update_delete.cpython-34.pyc
../sqlalchemy/testing/suite/__pycache__/test_reflection.cpython-34.pyc ../sqlalchemy/util/__pycache__/__init__.cpython-34.pyc
../sqlalchemy/testing/suite/__pycache__/test_ddl.cpython-34.pyc ../sqlalchemy/util/__pycache__/_collections.cpython-34.pyc
../sqlalchemy/orm/__pycache__/persistence.cpython-34.pyc ../sqlalchemy/util/__pycache__/compat.cpython-34.pyc
../sqlalchemy/orm/__pycache__/interfaces.cpython-34.pyc ../sqlalchemy/util/__pycache__/deprecations.cpython-34.pyc
../sqlalchemy/orm/__pycache__/events.cpython-34.pyc
../sqlalchemy/orm/__pycache__/path_registry.cpython-34.pyc
../sqlalchemy/orm/__pycache__/descriptor_props.cpython-34.pyc
../sqlalchemy/orm/__pycache__/identity.cpython-34.pyc
../sqlalchemy/orm/__pycache__/evaluator.cpython-34.pyc
../sqlalchemy/orm/__pycache__/exc.cpython-34.pyc
../sqlalchemy/orm/__pycache__/base.cpython-34.pyc
../sqlalchemy/orm/__pycache__/__init__.cpython-34.pyc
../sqlalchemy/orm/__pycache__/properties.cpython-34.pyc
../sqlalchemy/orm/__pycache__/relationships.cpython-34.pyc
../sqlalchemy/orm/__pycache__/collections.cpython-34.pyc
../sqlalchemy/orm/__pycache__/strategy_options.cpython-34.pyc
../sqlalchemy/orm/__pycache__/dynamic.cpython-34.pyc
../sqlalchemy/orm/__pycache__/attributes.cpython-34.pyc
../sqlalchemy/orm/__pycache__/mapper.cpython-34.pyc
../sqlalchemy/orm/__pycache__/state.cpython-34.pyc
../sqlalchemy/orm/__pycache__/sync.cpython-34.pyc
../sqlalchemy/orm/__pycache__/loading.cpython-34.pyc
../sqlalchemy/orm/__pycache__/strategies.cpython-34.pyc
../sqlalchemy/orm/__pycache__/unitofwork.cpython-34.pyc
../sqlalchemy/orm/__pycache__/query.cpython-34.pyc
../sqlalchemy/orm/__pycache__/instrumentation.cpython-34.pyc
../sqlalchemy/orm/__pycache__/session.cpython-34.pyc
../sqlalchemy/orm/__pycache__/deprecated_interfaces.cpython-34.pyc
../sqlalchemy/orm/__pycache__/scoping.cpython-34.pyc
../sqlalchemy/orm/__pycache__/dependency.cpython-34.pyc
../sqlalchemy/orm/__pycache__/util.cpython-34.pyc
../sqlalchemy/sql/__pycache__/default_comparator.cpython-34.pyc
../sqlalchemy/sql/__pycache__/sqltypes.cpython-34.pyc
../sqlalchemy/sql/__pycache__/functions.cpython-34.pyc
../sqlalchemy/sql/__pycache__/base.cpython-34.pyc
../sqlalchemy/sql/__pycache__/schema.cpython-34.pyc
../sqlalchemy/sql/__pycache__/__init__.cpython-34.pyc
../sqlalchemy/sql/__pycache__/ddl.cpython-34.pyc
../sqlalchemy/sql/__pycache__/elements.cpython-34.pyc
../sqlalchemy/sql/__pycache__/compiler.cpython-34.pyc
../sqlalchemy/sql/__pycache__/annotation.cpython-34.pyc
../sqlalchemy/sql/__pycache__/dml.cpython-34.pyc
../sqlalchemy/sql/__pycache__/expression.cpython-34.pyc
../sqlalchemy/sql/__pycache__/operators.cpython-34.pyc
../sqlalchemy/sql/__pycache__/selectable.cpython-34.pyc
../sqlalchemy/sql/__pycache__/visitors.cpython-34.pyc
../sqlalchemy/sql/__pycache__/type_api.cpython-34.pyc
../sqlalchemy/sql/__pycache__/naming.cpython-34.pyc
../sqlalchemy/sql/__pycache__/util.cpython-34.pyc
../sqlalchemy/ext/__pycache__/serializer.cpython-34.pyc
../sqlalchemy/ext/__pycache__/associationproxy.cpython-34.pyc
../sqlalchemy/ext/__pycache__/automap.cpython-34.pyc
../sqlalchemy/ext/__pycache__/__init__.cpython-34.pyc
../sqlalchemy/ext/__pycache__/hybrid.cpython-34.pyc
../sqlalchemy/ext/__pycache__/compiler.cpython-34.pyc
../sqlalchemy/ext/__pycache__/horizontal_shard.cpython-34.pyc
../sqlalchemy/ext/__pycache__/orderinglist.cpython-34.pyc
../sqlalchemy/ext/__pycache__/instrumentation.cpython-34.pyc
../sqlalchemy/ext/__pycache__/mutable.cpython-34.pyc
../sqlalchemy/ext/declarative/__pycache__/base.cpython-34.pyc
../sqlalchemy/ext/declarative/__pycache__/__init__.cpython-34.pyc
../sqlalchemy/ext/declarative/__pycache__/clsregistry.cpython-34.pyc
../sqlalchemy/ext/declarative/__pycache__/api.cpython-34.pyc
../sqlalchemy/util/__pycache__/langhelpers.cpython-34.pyc ../sqlalchemy/util/__pycache__/langhelpers.cpython-34.pyc
../sqlalchemy/util/__pycache__/queue.cpython-34.pyc ../sqlalchemy/util/__pycache__/queue.cpython-34.pyc
../sqlalchemy/util/__pycache__/compat.cpython-34.pyc
../sqlalchemy/util/__pycache__/__init__.cpython-34.pyc
../sqlalchemy/util/__pycache__/deprecations.cpython-34.pyc
../sqlalchemy/util/__pycache__/_collections.cpython-34.pyc
../sqlalchemy/util/__pycache__/topological.cpython-34.pyc ../sqlalchemy/util/__pycache__/topological.cpython-34.pyc
../sqlalchemy/connectors/__pycache__/mxodbc.cpython-34.pyc
../sqlalchemy/connectors/__pycache__/__init__.cpython-34.pyc
../sqlalchemy/connectors/__pycache__/pyodbc.cpython-34.pyc
../sqlalchemy/connectors/__pycache__/mysqldb.cpython-34.pyc
../sqlalchemy/connectors/__pycache__/zxJDBC.cpython-34.pyc
../sqlalchemy/dialects/__pycache__/postgres.cpython-34.pyc
../sqlalchemy/dialects/__pycache__/__init__.cpython-34.pyc
../sqlalchemy/dialects/mssql/__pycache__/adodbapi.cpython-34.pyc
../sqlalchemy/dialects/mssql/__pycache__/mxodbc.cpython-34.pyc
../sqlalchemy/dialects/mssql/__pycache__/base.cpython-34.pyc
../sqlalchemy/dialects/mssql/__pycache__/information_schema.cpython-34.pyc
../sqlalchemy/dialects/mssql/__pycache__/__init__.cpython-34.pyc
../sqlalchemy/dialects/mssql/__pycache__/pyodbc.cpython-34.pyc
../sqlalchemy/dialects/mssql/__pycache__/zxjdbc.cpython-34.pyc
../sqlalchemy/dialects/mssql/__pycache__/pymssql.cpython-34.pyc
../sqlalchemy/dialects/postgresql/__pycache__/pg8000.cpython-34.pyc
../sqlalchemy/dialects/postgresql/__pycache__/ranges.cpython-34.pyc
../sqlalchemy/dialects/postgresql/__pycache__/base.cpython-34.pyc
../sqlalchemy/dialects/postgresql/__pycache__/__init__.cpython-34.pyc
../sqlalchemy/dialects/postgresql/__pycache__/zxjdbc.cpython-34.pyc
../sqlalchemy/dialects/postgresql/__pycache__/json.cpython-34.pyc
../sqlalchemy/dialects/postgresql/__pycache__/pypostgresql.cpython-34.pyc
../sqlalchemy/dialects/postgresql/__pycache__/constraints.cpython-34.pyc
../sqlalchemy/dialects/postgresql/__pycache__/hstore.cpython-34.pyc
../sqlalchemy/dialects/postgresql/__pycache__/psycopg2.cpython-34.pyc
../sqlalchemy/dialects/sybase/__pycache__/mxodbc.cpython-34.pyc
../sqlalchemy/dialects/sybase/__pycache__/base.cpython-34.pyc
../sqlalchemy/dialects/sybase/__pycache__/__init__.cpython-34.pyc
../sqlalchemy/dialects/sybase/__pycache__/pyodbc.cpython-34.pyc
../sqlalchemy/dialects/sybase/__pycache__/pysybase.cpython-34.pyc
../sqlalchemy/dialects/drizzle/__pycache__/base.cpython-34.pyc
../sqlalchemy/dialects/drizzle/__pycache__/__init__.cpython-34.pyc
../sqlalchemy/dialects/drizzle/__pycache__/mysqldb.cpython-34.pyc
../sqlalchemy/dialects/mysql/__pycache__/mysqlconnector.cpython-34.pyc
../sqlalchemy/dialects/mysql/__pycache__/base.cpython-34.pyc
../sqlalchemy/dialects/mysql/__pycache__/__init__.cpython-34.pyc
../sqlalchemy/dialects/mysql/__pycache__/pyodbc.cpython-34.pyc
../sqlalchemy/dialects/mysql/__pycache__/zxjdbc.cpython-34.pyc
../sqlalchemy/dialects/mysql/__pycache__/oursql.cpython-34.pyc
../sqlalchemy/dialects/mysql/__pycache__/pymysql.cpython-34.pyc
../sqlalchemy/dialects/mysql/__pycache__/cymysql.cpython-34.pyc
../sqlalchemy/dialects/mysql/__pycache__/gaerdbms.cpython-34.pyc
../sqlalchemy/dialects/mysql/__pycache__/mysqldb.cpython-34.pyc
../sqlalchemy/dialects/sqlite/__pycache__/base.cpython-34.pyc
../sqlalchemy/dialects/sqlite/__pycache__/__init__.cpython-34.pyc
../sqlalchemy/dialects/sqlite/__pycache__/pysqlite.cpython-34.pyc
../sqlalchemy/dialects/firebird/__pycache__/base.cpython-34.pyc
../sqlalchemy/dialects/firebird/__pycache__/__init__.cpython-34.pyc
../sqlalchemy/dialects/firebird/__pycache__/fdb.cpython-34.pyc
../sqlalchemy/dialects/firebird/__pycache__/kinterbasdb.cpython-34.pyc
../sqlalchemy/dialects/oracle/__pycache__/base.cpython-34.pyc
../sqlalchemy/dialects/oracle/__pycache__/__init__.cpython-34.pyc
../sqlalchemy/dialects/oracle/__pycache__/zxjdbc.cpython-34.pyc
../sqlalchemy/dialects/oracle/__pycache__/cx_oracle.cpython-34.pyc
../sqlalchemy/engine/__pycache__/interfaces.cpython-34.pyc
../sqlalchemy/engine/__pycache__/result.cpython-34.pyc
../sqlalchemy/engine/__pycache__/base.cpython-34.pyc
../sqlalchemy/engine/__pycache__/url.cpython-34.pyc
../sqlalchemy/engine/__pycache__/threadlocal.cpython-34.pyc
../sqlalchemy/engine/__pycache__/__init__.cpython-34.pyc
../sqlalchemy/engine/__pycache__/default.cpython-34.pyc
../sqlalchemy/engine/__pycache__/strategies.cpython-34.pyc
../sqlalchemy/engine/__pycache__/reflection.cpython-34.pyc
../sqlalchemy/engine/__pycache__/util.cpython-34.pyc
../sqlalchemy/event/__pycache__/base.cpython-34.pyc
../sqlalchemy/event/__pycache__/__init__.cpython-34.pyc
../sqlalchemy/event/__pycache__/attr.cpython-34.pyc
../sqlalchemy/event/__pycache__/registry.cpython-34.pyc
../sqlalchemy/event/__pycache__/legacy.cpython-34.pyc
../sqlalchemy/event/__pycache__/api.cpython-34.pyc
../sqlalchemy/cprocessors.cpython-34m.so ../sqlalchemy/cprocessors.cpython-34m.so
../sqlalchemy/cresultproxy.cpython-34m.so ../sqlalchemy/cresultproxy.cpython-34m.so
../sqlalchemy/cutils.cpython-34m.so ../sqlalchemy/cutils.cpython-34m.so

View file

@ -1,104 +0,0 @@
LICENSE
MANIFEST.in
setup.cfg
setup.py
setup_base.py
c/_cffi_backend.c
c/file_emulator.h
c/malloc_closure.h
c/minibuffer.h
c/misc_thread.h
c/misc_win32.h
c/test_c.py
c/wchar_helper.h
c/libffi_msvc/ffi.c
c/libffi_msvc/ffi.h
c/libffi_msvc/ffi_common.h
c/libffi_msvc/fficonfig.h
c/libffi_msvc/ffitarget.h
c/libffi_msvc/prep_cif.c
c/libffi_msvc/types.c
c/libffi_msvc/win32.c
c/libffi_msvc/win64.asm
c/libffi_msvc/win64.obj
cffi/__init__.py
cffi/api.py
cffi/backend_ctypes.py
cffi/commontypes.py
cffi/cparser.py
cffi/ffiplatform.py
cffi/gc_weakref.py
cffi/lock.py
cffi/model.py
cffi/vengine_cpy.py
cffi/vengine_gen.py
cffi/verifier.py
cffi.egg-info/PKG-INFO
cffi.egg-info/SOURCES.txt
cffi.egg-info/dependency_links.txt
cffi.egg-info/not-zip-safe
cffi.egg-info/requires.txt
cffi.egg-info/top_level.txt
demo/_curses.py
demo/api.py
demo/bsdopendirtype.py
demo/btrfs-snap.py
demo/cffi-cocoa.py
demo/fastcsv.py
demo/gmp.py
demo/pwuid.py
demo/py.cleanup
demo/pyobj.py
demo/readdir.py
demo/readdir2.py
demo/readdir_ctypes.py
demo/setup.py
demo/winclipboard.py
demo/xclient.py
doc/Makefile
doc/design.rst
doc/make.bat
doc/source/conf.py
doc/source/index.rst
testing/__init__.py
testing/backend_tests.py
testing/callback_in_thread.py
testing/support.py
testing/test_cdata.py
testing/test_ctypes.py
testing/test_ffi_backend.py
testing/test_function.py
testing/test_model.py
testing/test_ownlib.py
testing/test_parsing.py
testing/test_platform.py
testing/test_unicode_literals.py
testing/test_verify.py
testing/test_verify2.py
testing/test_version.py
testing/test_vgen.py
testing/test_vgen2.py
testing/test_zdistutils.py
testing/test_zintegration.py
testing/udir.py
testing/snippets/distutils_module/setup.py
testing/snippets/distutils_module/snip_basic_verify.py
testing/snippets/distutils_module/build/lib.linux-x86_64-2.7/snip_basic_verify.py
testing/snippets/distutils_package_1/setup.py
testing/snippets/distutils_package_1/build/lib.linux-x86_64-2.7/snip_basic_verify1/__init__.py
testing/snippets/distutils_package_1/snip_basic_verify1/__init__.py
testing/snippets/distutils_package_2/setup.py
testing/snippets/distutils_package_2/build/lib.linux-x86_64-2.7/snip_basic_verify2/__init__.py
testing/snippets/distutils_package_2/snip_basic_verify2/__init__.py
testing/snippets/infrastructure/setup.py
testing/snippets/infrastructure/build/lib.linux-x86_64-2.7/snip_infrastructure/__init__.py
testing/snippets/infrastructure/snip_infrastructure/__init__.py
testing/snippets/setuptools_module/setup.py
testing/snippets/setuptools_module/snip_setuptools_verify.py
testing/snippets/setuptools_module/build/lib.linux-x86_64-2.7/snip_setuptools_verify.py
testing/snippets/setuptools_package_1/setup.py
testing/snippets/setuptools_package_1/build/lib.linux-x86_64-2.7/snip_setuptools_verify1/__init__.py
testing/snippets/setuptools_package_1/snip_setuptools_verify1/__init__.py
testing/snippets/setuptools_package_2/setup.py
testing/snippets/setuptools_package_2/build/lib.linux-x86_64-2.7/snip_setuptools_verify2/__init__.py
testing/snippets/setuptools_package_2/snip_setuptools_verify2/__init__.py

View file

@ -1,6 +1,6 @@
Metadata-Version: 1.1 Metadata-Version: 1.1
Name: cffi Name: cffi
Version: 0.8.6 Version: 1.3.0
Summary: Foreign Function Interface for Python calling C code. Summary: Foreign Function Interface for Python calling C code.
Home-page: http://cffi.readthedocs.org Home-page: http://cffi.readthedocs.org
Author: Armin Rigo, Maciej Fijalkowski Author: Armin Rigo, Maciej Fijalkowski
@ -26,3 +26,6 @@ Classifier: Programming Language :: Python :: 2.7
Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.2 Classifier: Programming Language :: Python :: 3.2
Classifier: Programming Language :: Python :: 3.3 Classifier: Programming Language :: Python :: 3.3
Classifier: Programming Language :: Python :: 3.4
Classifier: Programming Language :: Python :: Implementation :: CPython
Classifier: Programming Language :: Python :: Implementation :: PyPy

View file

@ -0,0 +1,145 @@
AUTHORS
LICENSE
MANIFEST.in
setup.cfg
setup.py
setup_base.py
c/_cffi_backend.c
c/cdlopen.c
c/cffi1_module.c
c/cglob.c
c/ffi_obj.c
c/file_emulator.h
c/lib_obj.c
c/malloc_closure.h
c/minibuffer.h
c/misc_thread.h
c/misc_win32.h
c/parse_c_type.c
c/realize_c_type.c
c/test_c.py
c/wchar_helper.h
c/libffi_msvc/ffi.c
c/libffi_msvc/ffi.h
c/libffi_msvc/ffi_common.h
c/libffi_msvc/fficonfig.h
c/libffi_msvc/ffitarget.h
c/libffi_msvc/prep_cif.c
c/libffi_msvc/types.c
c/libffi_msvc/win32.c
c/libffi_msvc/win64.asm
c/libffi_msvc/win64.obj
cffi/__init__.py
cffi/_cffi_include.h
cffi/api.py
cffi/backend_ctypes.py
cffi/cffi_opcode.py
cffi/commontypes.py
cffi/cparser.py
cffi/ffiplatform.py
cffi/gc_weakref.py
cffi/lock.py
cffi/model.py
cffi/parse_c_type.h
cffi/recompiler.py
cffi/setuptools_ext.py
cffi/vengine_cpy.py
cffi/vengine_gen.py
cffi/verifier.py
cffi.egg-info/PKG-INFO
cffi.egg-info/SOURCES.txt
cffi.egg-info/dependency_links.txt
cffi.egg-info/entry_points.txt
cffi.egg-info/not-zip-safe
cffi.egg-info/requires.txt
cffi.egg-info/top_level.txt
demo/_curses.py
demo/_curses_build.py
demo/_curses_setup.py
demo/api.py
demo/bsdopendirtype.py
demo/bsdopendirtype_build.py
demo/bsdopendirtype_setup.py
demo/btrfs-snap.py
demo/cffi-cocoa.py
demo/fastcsv.py
demo/gmp.py
demo/manual.c
demo/manual2.py
demo/pwuid.py
demo/py.cleanup
demo/pyobj.py
demo/readdir.py
demo/readdir2.py
demo/readdir2_build.py
demo/readdir2_setup.py
demo/readdir_build.py
demo/readdir_ctypes.py
demo/readdir_setup.py
demo/recopendirtype.py
demo/recopendirtype_build.py
demo/setup.py
demo/setup_manual.py
demo/winclipboard.py
demo/xclient.py
doc/Makefile
doc/make.bat
doc/misc/design.rst
doc/misc/grant-cffi-1.0.rst
doc/misc/parse_c_type.rst
doc/source/cdef.rst
doc/source/conf.py
doc/source/index.rst
doc/source/installation.rst
doc/source/overview.rst
doc/source/using.rst
doc/source/whatsnew.rst
testing/__init__.py
testing/support.py
testing/udir.py
testing/cffi0/__init__.py
testing/cffi0/backend_tests.py
testing/cffi0/callback_in_thread.py
testing/cffi0/test_cdata.py
testing/cffi0/test_ctypes.py
testing/cffi0/test_ffi_backend.py
testing/cffi0/test_function.py
testing/cffi0/test_model.py
testing/cffi0/test_ownlib.py
testing/cffi0/test_parsing.py
testing/cffi0/test_platform.py
testing/cffi0/test_unicode_literals.py
testing/cffi0/test_verify.py
testing/cffi0/test_verify2.py
testing/cffi0/test_version.py
testing/cffi0/test_vgen.py
testing/cffi0/test_vgen2.py
testing/cffi0/test_zdistutils.py
testing/cffi0/test_zintegration.py
testing/cffi0/snippets/distutils_module/setup.py
testing/cffi0/snippets/distutils_module/snip_basic_verify.py
testing/cffi0/snippets/distutils_package_1/setup.py
testing/cffi0/snippets/distutils_package_1/snip_basic_verify1/__init__.py
testing/cffi0/snippets/distutils_package_2/setup.py
testing/cffi0/snippets/distutils_package_2/snip_basic_verify2/__init__.py
testing/cffi0/snippets/infrastructure/setup.py
testing/cffi0/snippets/infrastructure/snip_infrastructure/__init__.py
testing/cffi0/snippets/setuptools_module/setup.py
testing/cffi0/snippets/setuptools_module/snip_setuptools_verify.py
testing/cffi0/snippets/setuptools_package_1/setup.py
testing/cffi0/snippets/setuptools_package_1/snip_setuptools_verify1/__init__.py
testing/cffi0/snippets/setuptools_package_2/setup.py
testing/cffi0/snippets/setuptools_package_2/snip_setuptools_verify2/__init__.py
testing/cffi1/__init__.py
testing/cffi1/test_cffi_binary.py
testing/cffi1/test_dlopen.py
testing/cffi1/test_dlopen_unicode_literals.py
testing/cffi1/test_ffi_obj.py
testing/cffi1/test_new_ffi_1.py
testing/cffi1/test_parse_c_type.py
testing/cffi1/test_re_python.py
testing/cffi1/test_realize_c_type.py
testing/cffi1/test_recompiler.py
testing/cffi1/test_unicode_literals.py
testing/cffi1/test_verify1.py
testing/cffi1/test_zdist.py

View file

@ -0,0 +1,3 @@
[distutils.setup_keywords]
cffi_modules = cffi.setuptools_ext:cffi_modules

View file

@ -1,32 +1,41 @@
../cffi/lock.py
../cffi/backend_ctypes.py
../cffi/__init__.py
../cffi/ffiplatform.py
../cffi/vengine_gen.py
../cffi/commontypes.py
../cffi/vengine_cpy.py
../cffi/api.py
../cffi/gc_weakref.py ../cffi/gc_weakref.py
../cffi/recompiler.py
../cffi/verifier.py ../cffi/verifier.py
../cffi/backend_ctypes.py
../cffi/api.py
../cffi/ffiplatform.py
../cffi/cparser.py ../cffi/cparser.py
../cffi/vengine_cpy.py
../cffi/lock.py
../cffi/cffi_opcode.py
../cffi/setuptools_ext.py
../cffi/vengine_gen.py
../cffi/model.py ../cffi/model.py
../cffi/__pycache__/lock.cpython-34.pyc ../cffi/__init__.py
../cffi/__pycache__/backend_ctypes.cpython-34.pyc ../cffi/commontypes.py
../cffi/__pycache__/__init__.cpython-34.pyc ../cffi/_cffi_include.h
../cffi/__pycache__/ffiplatform.cpython-34.pyc ../cffi/parse_c_type.h
../cffi/__pycache__/vengine_gen.cpython-34.pyc
../cffi/__pycache__/commontypes.cpython-34.pyc
../cffi/__pycache__/vengine_cpy.cpython-34.pyc
../cffi/__pycache__/api.cpython-34.pyc
../cffi/__pycache__/gc_weakref.cpython-34.pyc ../cffi/__pycache__/gc_weakref.cpython-34.pyc
../cffi/__pycache__/recompiler.cpython-34.pyc
../cffi/__pycache__/verifier.cpython-34.pyc ../cffi/__pycache__/verifier.cpython-34.pyc
../cffi/__pycache__/backend_ctypes.cpython-34.pyc
../cffi/__pycache__/api.cpython-34.pyc
../cffi/__pycache__/ffiplatform.cpython-34.pyc
../cffi/__pycache__/cparser.cpython-34.pyc ../cffi/__pycache__/cparser.cpython-34.pyc
../cffi/__pycache__/vengine_cpy.cpython-34.pyc
../cffi/__pycache__/lock.cpython-34.pyc
../cffi/__pycache__/cffi_opcode.cpython-34.pyc
../cffi/__pycache__/setuptools_ext.cpython-34.pyc
../cffi/__pycache__/vengine_gen.cpython-34.pyc
../cffi/__pycache__/model.cpython-34.pyc ../cffi/__pycache__/model.cpython-34.pyc
../cffi/__pycache__/__init__.cpython-34.pyc
../cffi/__pycache__/commontypes.cpython-34.pyc
../_cffi_backend.cpython-34m.so ../_cffi_backend.cpython-34m.so
./ ./
dependency_links.txt
PKG-INFO PKG-INFO
SOURCES.txt SOURCES.txt
entry_points.txt
not-zip-safe not-zip-safe
top_level.txt dependency_links.txt
requires.txt requires.txt
top_level.txt

View file

@ -4,5 +4,10 @@ __all__ = ['FFI', 'VerificationError', 'VerificationMissing', 'CDefError',
from .api import FFI, CDefError, FFIError from .api import FFI, CDefError, FFIError
from .ffiplatform import VerificationError, VerificationMissing from .ffiplatform import VerificationError, VerificationMissing
__version__ = "0.8.6" __version__ = "1.3.0"
__version_info__ = (0, 8, 6) __version_info__ = (1, 3, 0)
# The verifier module file names are based on the CRC32 of a string that
# contains the following version number. It may be older than __version__
# if nothing is clearly incompatible.
__version_verifier_modules__ = "0.8.6"

View file

@ -0,0 +1,229 @@
#define _CFFI_
#include <Python.h>
#ifdef __cplusplus
extern "C" {
#endif
#include <stddef.h>
#include "parse_c_type.h"
/* this block of #ifs should be kept exactly identical between
c/_cffi_backend.c, cffi/vengine_cpy.py, cffi/vengine_gen.py
and cffi/_cffi_include.h */
#if defined(_MSC_VER)
# include <malloc.h> /* for alloca() */
# if _MSC_VER < 1600 /* MSVC < 2010 */
typedef __int8 int8_t;
typedef __int16 int16_t;
typedef __int32 int32_t;
typedef __int64 int64_t;
typedef unsigned __int8 uint8_t;
typedef unsigned __int16 uint16_t;
typedef unsigned __int32 uint32_t;
typedef unsigned __int64 uint64_t;
typedef __int8 int_least8_t;
typedef __int16 int_least16_t;
typedef __int32 int_least32_t;
typedef __int64 int_least64_t;
typedef unsigned __int8 uint_least8_t;
typedef unsigned __int16 uint_least16_t;
typedef unsigned __int32 uint_least32_t;
typedef unsigned __int64 uint_least64_t;
typedef __int8 int_fast8_t;
typedef __int16 int_fast16_t;
typedef __int32 int_fast32_t;
typedef __int64 int_fast64_t;
typedef unsigned __int8 uint_fast8_t;
typedef unsigned __int16 uint_fast16_t;
typedef unsigned __int32 uint_fast32_t;
typedef unsigned __int64 uint_fast64_t;
typedef __int64 intmax_t;
typedef unsigned __int64 uintmax_t;
# else
# include <stdint.h>
# endif
# if _MSC_VER < 1800 /* MSVC < 2013 */
typedef unsigned char _Bool;
# endif
#else
# include <stdint.h>
# if (defined (__SVR4) && defined (__sun)) || defined(_AIX) || defined(__hpux)
# include <alloca.h>
# endif
#endif
#ifdef __GNUC__
# define _CFFI_UNUSED_FN __attribute__((unused))
#else
# define _CFFI_UNUSED_FN /* nothing */
#endif
/********** CPython-specific section **********/
#ifndef PYPY_VERSION
#if PY_MAJOR_VERSION >= 3
# define PyInt_FromLong PyLong_FromLong
#endif
#define _cffi_from_c_double PyFloat_FromDouble
#define _cffi_from_c_float PyFloat_FromDouble
#define _cffi_from_c_long PyInt_FromLong
#define _cffi_from_c_ulong PyLong_FromUnsignedLong
#define _cffi_from_c_longlong PyLong_FromLongLong
#define _cffi_from_c_ulonglong PyLong_FromUnsignedLongLong
#define _cffi_to_c_double PyFloat_AsDouble
#define _cffi_to_c_float PyFloat_AsDouble
#define _cffi_from_c_int(x, type) \
(((type)-1) > 0 ? /* unsigned */ \
(sizeof(type) < sizeof(long) ? \
PyInt_FromLong((long)x) : \
sizeof(type) == sizeof(long) ? \
PyLong_FromUnsignedLong((unsigned long)x) : \
PyLong_FromUnsignedLongLong((unsigned long long)x)) : \
(sizeof(type) <= sizeof(long) ? \
PyInt_FromLong((long)x) : \
PyLong_FromLongLong((long long)x)))
#define _cffi_to_c_int(o, type) \
((type)( \
sizeof(type) == 1 ? (((type)-1) > 0 ? (type)_cffi_to_c_u8(o) \
: (type)_cffi_to_c_i8(o)) : \
sizeof(type) == 2 ? (((type)-1) > 0 ? (type)_cffi_to_c_u16(o) \
: (type)_cffi_to_c_i16(o)) : \
sizeof(type) == 4 ? (((type)-1) > 0 ? (type)_cffi_to_c_u32(o) \
: (type)_cffi_to_c_i32(o)) : \
sizeof(type) == 8 ? (((type)-1) > 0 ? (type)_cffi_to_c_u64(o) \
: (type)_cffi_to_c_i64(o)) : \
(Py_FatalError("unsupported size for type " #type), (type)0)))
#define _cffi_to_c_i8 \
((int(*)(PyObject *))_cffi_exports[1])
#define _cffi_to_c_u8 \
((int(*)(PyObject *))_cffi_exports[2])
#define _cffi_to_c_i16 \
((int(*)(PyObject *))_cffi_exports[3])
#define _cffi_to_c_u16 \
((int(*)(PyObject *))_cffi_exports[4])
#define _cffi_to_c_i32 \
((int(*)(PyObject *))_cffi_exports[5])
#define _cffi_to_c_u32 \
((unsigned int(*)(PyObject *))_cffi_exports[6])
#define _cffi_to_c_i64 \
((long long(*)(PyObject *))_cffi_exports[7])
#define _cffi_to_c_u64 \
((unsigned long long(*)(PyObject *))_cffi_exports[8])
#define _cffi_to_c_char \
((int(*)(PyObject *))_cffi_exports[9])
#define _cffi_from_c_pointer \
((PyObject *(*)(char *, CTypeDescrObject *))_cffi_exports[10])
#define _cffi_to_c_pointer \
((char *(*)(PyObject *, CTypeDescrObject *))_cffi_exports[11])
#define _cffi_get_struct_layout \
not used any more
#define _cffi_restore_errno \
((void(*)(void))_cffi_exports[13])
#define _cffi_save_errno \
((void(*)(void))_cffi_exports[14])
#define _cffi_from_c_char \
((PyObject *(*)(char))_cffi_exports[15])
#define _cffi_from_c_deref \
((PyObject *(*)(char *, CTypeDescrObject *))_cffi_exports[16])
#define _cffi_to_c \
((int(*)(char *, CTypeDescrObject *, PyObject *))_cffi_exports[17])
#define _cffi_from_c_struct \
((PyObject *(*)(char *, CTypeDescrObject *))_cffi_exports[18])
#define _cffi_to_c_wchar_t \
((wchar_t(*)(PyObject *))_cffi_exports[19])
#define _cffi_from_c_wchar_t \
((PyObject *(*)(wchar_t))_cffi_exports[20])
#define _cffi_to_c_long_double \
((long double(*)(PyObject *))_cffi_exports[21])
#define _cffi_to_c__Bool \
((_Bool(*)(PyObject *))_cffi_exports[22])
#define _cffi_prepare_pointer_call_argument \
((Py_ssize_t(*)(CTypeDescrObject *, PyObject *, char **))_cffi_exports[23])
#define _cffi_convert_array_from_object \
((int(*)(char *, CTypeDescrObject *, PyObject *))_cffi_exports[24])
#define _CFFI_NUM_EXPORTS 25
typedef struct _ctypedescr CTypeDescrObject;
static void *_cffi_exports[_CFFI_NUM_EXPORTS];
#define _cffi_type(index) ( \
assert((((uintptr_t)_cffi_types[index]) & 1) == 0), \
(CTypeDescrObject *)_cffi_types[index])
static PyObject *_cffi_init(const char *module_name, Py_ssize_t version,
const struct _cffi_type_context_s *ctx)
{
PyObject *module, *o_arg, *new_module;
void *raw[] = {
(void *)module_name,
(void *)version,
(void *)_cffi_exports,
(void *)ctx,
};
module = PyImport_ImportModule("_cffi_backend");
if (module == NULL)
goto failure;
o_arg = PyLong_FromVoidPtr((void *)raw);
if (o_arg == NULL)
goto failure;
new_module = PyObject_CallMethod(
module, (char *)"_init_cffi_1_0_external_module", (char *)"O", o_arg);
Py_DECREF(o_arg);
Py_DECREF(module);
return new_module;
failure:
Py_XDECREF(module);
return NULL;
}
_CFFI_UNUSED_FN
static PyObject **_cffi_unpack_args(PyObject *args_tuple, Py_ssize_t expected,
const char *fnname)
{
if (PyTuple_GET_SIZE(args_tuple) != expected) {
PyErr_Format(PyExc_TypeError,
"%.150s() takes exactly %zd arguments (%zd given)",
fnname, expected, PyTuple_GET_SIZE(args_tuple));
return NULL;
}
return &PyTuple_GET_ITEM(args_tuple, 0); /* pointer to the first item,
the others follow */
}
#endif
/********** end CPython-specific section **********/
#define _cffi_array_len(array) (sizeof(array) / sizeof((array)[0]))
#define _cffi_prim_int(size, sign) \
((size) == 1 ? ((sign) ? _CFFI_PRIM_INT8 : _CFFI_PRIM_UINT8) : \
(size) == 2 ? ((sign) ? _CFFI_PRIM_INT16 : _CFFI_PRIM_UINT16) : \
(size) == 4 ? ((sign) ? _CFFI_PRIM_INT32 : _CFFI_PRIM_UINT32) : \
(size) == 8 ? ((sign) ? _CFFI_PRIM_INT64 : _CFFI_PRIM_UINT64) : \
_CFFI__UNKNOWN_PRIM)
#define _cffi_prim_float(size) \
((size) == sizeof(float) ? _CFFI_PRIM_FLOAT : \
(size) == sizeof(double) ? _CFFI_PRIM_DOUBLE : \
(size) == sizeof(long double) ? _CFFI__UNKNOWN_LONG_DOUBLE : \
_CFFI__UNKNOWN_FLOAT_PRIM)
#define _cffi_check_int(got, got_nonpos, expected) \
((got_nonpos) == (expected <= 0) && \
(got) == (unsigned long long)expected)
#ifdef __cplusplus
}
#endif

View file

@ -55,7 +55,8 @@ class FFI(object):
# _cffi_backend.so compiled. # _cffi_backend.so compiled.
import _cffi_backend as backend import _cffi_backend as backend
from . import __version__ from . import __version__
assert backend.__version__ == __version__ assert backend.__version__ == __version__, \
"version mismatch, %s != %s" % (backend.__version__, __version__)
# (If you insist you can also try to pass the option # (If you insist you can also try to pass the option
# 'backend=backend_ctypes.CTypesBackend()', but don't # 'backend=backend_ctypes.CTypesBackend()', but don't
# rely on it! It's probably not going to work well.) # rely on it! It's probably not going to work well.)
@ -69,6 +70,8 @@ class FFI(object):
self._function_caches = [] self._function_caches = []
self._libraries = [] self._libraries = []
self._cdefsources = [] self._cdefsources = []
self._included_ffis = []
self._windows_unicode = None
if hasattr(backend, 'set_ffi'): if hasattr(backend, 'set_ffi'):
backend.set_ffi(self) backend.set_ffi(self)
for name in backend.__dict__: for name in backend.__dict__:
@ -77,6 +80,7 @@ class FFI(object):
# #
with self._lock: with self._lock:
self.BVoidP = self._get_cached_btype(model.voidp_type) self.BVoidP = self._get_cached_btype(model.voidp_type)
self.BCharA = self._get_cached_btype(model.char_array_type)
if isinstance(backend, types.ModuleType): if isinstance(backend, types.ModuleType):
# _cffi_backend: attach these constants to the class # _cffi_backend: attach these constants to the class
if not hasattr(FFI, 'NULL'): if not hasattr(FFI, 'NULL'):
@ -105,6 +109,11 @@ class FFI(object):
if override: if override:
for cache in self._function_caches: for cache in self._function_caches:
cache.clear() cache.clear()
finishlist = self._parser._recomplete
if finishlist:
self._parser._recomplete = []
for tp in finishlist:
tp.finish_backend_type(self, finishlist)
def dlopen(self, name, flags=0): def dlopen(self, name, flags=0):
"""Load and return a dynamic library identified by 'name'. """Load and return a dynamic library identified by 'name'.
@ -189,13 +198,16 @@ class FFI(object):
cdecl = self._typeof(cdecl) cdecl = self._typeof(cdecl)
return self._backend.alignof(cdecl) return self._backend.alignof(cdecl)
def offsetof(self, cdecl, fieldname): def offsetof(self, cdecl, *fields_or_indexes):
"""Return the offset of the named field inside the given """Return the offset of the named field inside the given
structure, which must be given as a C type name. structure or array, which must be given as a C type name.
You can give several field names in case of nested structures.
You can also give numeric values which correspond to array
items, in case of an array type.
""" """
if isinstance(cdecl, basestring): if isinstance(cdecl, basestring):
cdecl = self._typeof(cdecl) cdecl = self._typeof(cdecl)
return self._backend.typeoffsetof(cdecl, fieldname)[1] return self._typeoffsetof(cdecl, *fields_or_indexes)[1]
def new(self, cdecl, init=None): def new(self, cdecl, init=None):
"""Allocate an instance according to the specified C type and """Allocate an instance according to the specified C type and
@ -224,6 +236,30 @@ class FFI(object):
cdecl = self._typeof(cdecl) cdecl = self._typeof(cdecl)
return self._backend.newp(cdecl, init) return self._backend.newp(cdecl, init)
def new_allocator(self, alloc=None, free=None,
should_clear_after_alloc=True):
"""Return a new allocator, i.e. a function that behaves like ffi.new()
but uses the provided low-level 'alloc' and 'free' functions.
'alloc' is called with the size as argument. If it returns NULL, a
MemoryError is raised. 'free' is called with the result of 'alloc'
as argument. Both can be either Python function or directly C
functions. If 'free' is None, then no free function is called.
If both 'alloc' and 'free' are None, the default is used.
If 'should_clear_after_alloc' is set to False, then the memory
returned by 'alloc' is assumed to be already cleared (or you are
fine with garbage); otherwise CFFI will clear it.
"""
compiled_ffi = self._backend.FFI()
allocator = compiled_ffi.new_allocator(alloc, free,
should_clear_after_alloc)
def allocate(cdecl, init=None):
if isinstance(cdecl, basestring):
cdecl = self._typeof(cdecl)
return allocator(cdecl, init)
return allocate
def cast(self, cdecl, source): def cast(self, cdecl, source):
"""Similar to a C cast: returns an instance of the named C """Similar to a C cast: returns an instance of the named C
type initialized with the given 'source'. The source is type initialized with the given 'source'. The source is
@ -264,7 +300,33 @@ class FFI(object):
""" """
return self._backend.buffer(cdata, size) return self._backend.buffer(cdata, size)
def callback(self, cdecl, python_callable=None, error=None): def from_buffer(self, python_buffer):
"""Return a <cdata 'char[]'> that points to the data of the
given Python object, which must support the buffer interface.
Note that this is not meant to be used on the built-in types str,
unicode, or bytearray (you can build 'char[]' arrays explicitly)
but only on objects containing large quantities of raw data
in some other format, like 'array.array' or numpy arrays.
"""
return self._backend.from_buffer(self.BCharA, python_buffer)
def memmove(self, dest, src, n):
"""ffi.memmove(dest, src, n) copies n bytes of memory from src to dest.
Like the C function memmove(), the memory areas may overlap;
apart from that it behaves like the C function memcpy().
'src' can be any cdata ptr or array, or any Python buffer object.
'dest' can be any cdata ptr or array, or a writable Python buffer
object. The size to copy, 'n', is always measured in bytes.
Unlike other methods, this one supports all Python buffer including
byte strings and bytearrays---but it still does not support
non-contiguous buffers.
"""
return self._backend.memmove(dest, src, n)
def callback(self, cdecl, python_callable=None, error=None, onerror=None):
"""Return a callback object or a decorator making such a """Return a callback object or a decorator making such a
callback object. 'cdecl' must name a C function pointer type. callback object. 'cdecl' must name a C function pointer type.
The callback invokes the specified 'python_callable' (which may The callback invokes the specified 'python_callable' (which may
@ -276,7 +338,8 @@ class FFI(object):
if not callable(python_callable): if not callable(python_callable):
raise TypeError("the 'python_callable' argument " raise TypeError("the 'python_callable' argument "
"is not callable") "is not callable")
return self._backend.callback(cdecl, python_callable, error) return self._backend.callback(cdecl, python_callable,
error, onerror)
if isinstance(cdecl, basestring): if isinstance(cdecl, basestring):
cdecl = self._typeof(cdecl, consider_function_as_funcptr=True) cdecl = self._typeof(cdecl, consider_function_as_funcptr=True)
if python_callable is None: if python_callable is None:
@ -305,6 +368,13 @@ class FFI(object):
data. Later, when this new cdata object is garbage-collected, data. Later, when this new cdata object is garbage-collected,
'destructor(old_cdata_object)' will be called. 'destructor(old_cdata_object)' will be called.
""" """
try:
gcp = self._backend.gcp
except AttributeError:
pass
else:
return gcp(cdata, destructor)
#
with self._lock: with self._lock:
try: try:
gc_weakrefs = self.gc_weakrefs gc_weakrefs = self.gc_weakrefs
@ -335,9 +405,23 @@ class FFI(object):
which requires binary compatibility in the signatures. which requires binary compatibility in the signatures.
""" """
from .verifier import Verifier, _caller_dir_pycache from .verifier import Verifier, _caller_dir_pycache
#
# If set_unicode(True) was called, insert the UNICODE and
# _UNICODE macro declarations
if self._windows_unicode:
self._apply_windows_unicode(kwargs)
#
# Set the tmpdir here, and not in Verifier.__init__: it picks
# up the caller's directory, which we want to be the caller of
# ffi.verify(), as opposed to the caller of Veritier().
tmpdir = tmpdir or _caller_dir_pycache() tmpdir = tmpdir or _caller_dir_pycache()
#
# Make a Verifier() and use it to load the library.
self.verifier = Verifier(self, source, tmpdir, **kwargs) self.verifier = Verifier(self, source, tmpdir, **kwargs)
lib = self.verifier.load_library() lib = self.verifier.load_library()
#
# Save the loaded library for keep-alive purposes, even
# if the caller doesn't keep it alive itself (it should).
self._libraries.append(lib) self._libraries.append(lib)
return lib return lib
@ -356,15 +440,29 @@ class FFI(object):
with self._lock: with self._lock:
return model.pointer_cache(self, ctype) return model.pointer_cache(self, ctype)
def addressof(self, cdata, field=None): def addressof(self, cdata, *fields_or_indexes):
"""Return the address of a <cdata 'struct-or-union'>. """Return the address of a <cdata 'struct-or-union'>.
If 'field' is specified, return the address of this field. If 'fields_or_indexes' are given, returns the address of that
field or array item in the structure or array, recursively in
case of nested structures.
""" """
ctype = self._backend.typeof(cdata) ctype = self._backend.typeof(cdata)
ctype, offset = self._backend.typeoffsetof(ctype, field) if fields_or_indexes:
ctype, offset = self._typeoffsetof(ctype, *fields_or_indexes)
else:
if ctype.kind == "pointer":
raise TypeError("addressof(pointer)")
offset = 0
ctypeptr = self._pointer_to(ctype) ctypeptr = self._pointer_to(ctype)
return self._backend.rawaddressof(ctypeptr, cdata, offset) return self._backend.rawaddressof(ctypeptr, cdata, offset)
def _typeoffsetof(self, ctype, field_or_index, *fields_or_indexes):
ctype, offset = self._backend.typeoffsetof(ctype, field_or_index)
for field1 in fields_or_indexes:
ctype, offset1 = self._backend.typeoffsetof(ctype, field1, 1)
offset += offset1
return ctype, offset
def include(self, ffi_to_include): def include(self, ffi_to_include):
"""Includes the typedefs, structs, unions and enums defined """Includes the typedefs, structs, unions and enums defined
in another FFI instance. Usage is similar to a #include in C, in another FFI instance. Usage is similar to a #include in C,
@ -374,12 +472,19 @@ class FFI(object):
variables, which must anyway be accessed directly from the variables, which must anyway be accessed directly from the
lib object returned by the original FFI instance. lib object returned by the original FFI instance.
""" """
if not isinstance(ffi_to_include, FFI):
raise TypeError("ffi.include() expects an argument that is also of"
" type cffi.FFI, not %r" % (
type(ffi_to_include).__name__,))
if ffi_to_include is self:
raise ValueError("self.include(self)")
with ffi_to_include._lock: with ffi_to_include._lock:
with self._lock: with self._lock:
self._parser.include(ffi_to_include._parser) self._parser.include(ffi_to_include._parser)
self._cdefsources.append('[') self._cdefsources.append('[')
self._cdefsources.extend(ffi_to_include._cdefsources) self._cdefsources.extend(ffi_to_include._cdefsources)
self._cdefsources.append(']') self._cdefsources.append(']')
self._included_ffis.append(ffi_to_include)
def new_handle(self, x): def new_handle(self, x):
return self._backend.newp_handle(self.BVoidP, x) return self._backend.newp_handle(self.BVoidP, x)
@ -387,6 +492,112 @@ class FFI(object):
def from_handle(self, x): def from_handle(self, x):
return self._backend.from_handle(x) return self._backend.from_handle(x)
def set_unicode(self, enabled_flag):
"""Windows: if 'enabled_flag' is True, enable the UNICODE and
_UNICODE defines in C, and declare the types like TCHAR and LPTCSTR
to be (pointers to) wchar_t. If 'enabled_flag' is False,
declare these types to be (pointers to) plain 8-bit characters.
This is mostly for backward compatibility; you usually want True.
"""
if self._windows_unicode is not None:
raise ValueError("set_unicode() can only be called once")
enabled_flag = bool(enabled_flag)
if enabled_flag:
self.cdef("typedef wchar_t TBYTE;"
"typedef wchar_t TCHAR;"
"typedef const wchar_t *LPCTSTR;"
"typedef const wchar_t *PCTSTR;"
"typedef wchar_t *LPTSTR;"
"typedef wchar_t *PTSTR;"
"typedef TBYTE *PTBYTE;"
"typedef TCHAR *PTCHAR;")
else:
self.cdef("typedef char TBYTE;"
"typedef char TCHAR;"
"typedef const char *LPCTSTR;"
"typedef const char *PCTSTR;"
"typedef char *LPTSTR;"
"typedef char *PTSTR;"
"typedef TBYTE *PTBYTE;"
"typedef TCHAR *PTCHAR;")
self._windows_unicode = enabled_flag
def _apply_windows_unicode(self, kwds):
defmacros = kwds.get('define_macros', ())
if not isinstance(defmacros, (list, tuple)):
raise TypeError("'define_macros' must be a list or tuple")
defmacros = list(defmacros) + [('UNICODE', '1'),
('_UNICODE', '1')]
kwds['define_macros'] = defmacros
def set_source(self, module_name, source, source_extension='.c', **kwds):
if hasattr(self, '_assigned_source'):
raise ValueError("set_source() cannot be called several times "
"per ffi object")
if not isinstance(module_name, basestring):
raise TypeError("'module_name' must be a string")
self._assigned_source = (str(module_name), source,
source_extension, kwds)
def distutils_extension(self, tmpdir='build', verbose=True):
from distutils.dir_util import mkpath
from .recompiler import recompile
#
if not hasattr(self, '_assigned_source'):
if hasattr(self, 'verifier'): # fallback, 'tmpdir' ignored
return self.verifier.get_extension()
raise ValueError("set_source() must be called before"
" distutils_extension()")
module_name, source, source_extension, kwds = self._assigned_source
if source is None:
raise TypeError("distutils_extension() is only for C extension "
"modules, not for dlopen()-style pure Python "
"modules")
mkpath(tmpdir)
ext, updated = recompile(self, module_name,
source, tmpdir=tmpdir, extradir=tmpdir,
source_extension=source_extension,
call_c_compiler=False, **kwds)
if verbose:
if updated:
sys.stderr.write("regenerated: %r\n" % (ext.sources[0],))
else:
sys.stderr.write("not modified: %r\n" % (ext.sources[0],))
return ext
def emit_c_code(self, filename):
from .recompiler import recompile
#
if not hasattr(self, '_assigned_source'):
raise ValueError("set_source() must be called before emit_c_code()")
module_name, source, source_extension, kwds = self._assigned_source
if source is None:
raise TypeError("emit_c_code() is only for C extension modules, "
"not for dlopen()-style pure Python modules")
recompile(self, module_name, source,
c_file=filename, call_c_compiler=False, **kwds)
def emit_python_code(self, filename):
from .recompiler import recompile
#
if not hasattr(self, '_assigned_source'):
raise ValueError("set_source() must be called before emit_c_code()")
module_name, source, source_extension, kwds = self._assigned_source
if source is not None:
raise TypeError("emit_python_code() is only for dlopen()-style "
"pure Python modules, not for C extension modules")
recompile(self, module_name, source,
c_file=filename, call_c_compiler=False, **kwds)
def compile(self, tmpdir='.'):
from .recompiler import recompile
#
if not hasattr(self, '_assigned_source'):
raise ValueError("set_source() must be called before compile()")
module_name, source, source_extension, kwds = self._assigned_source
return recompile(self, module_name, source, tmpdir=tmpdir,
source_extension=source_extension, **kwds)
def _load_backend_lib(backend, name, flags): def _load_backend_lib(backend, name, flags):
if name is None: if name is None:
@ -414,7 +625,7 @@ def _make_ffi_library(ffi, libname, flags):
def make_accessor_locked(name): def make_accessor_locked(name):
key = 'function ' + name key = 'function ' + name
if key in ffi._parser._declarations: if key in ffi._parser._declarations:
tp = ffi._parser._declarations[key] tp, _ = ffi._parser._declarations[key]
BType = ffi._get_cached_btype(tp) BType = ffi._get_cached_btype(tp)
try: try:
value = backendlib.load_function(BType, name) value = backendlib.load_function(BType, name)
@ -425,7 +636,7 @@ def _make_ffi_library(ffi, libname, flags):
# #
key = 'variable ' + name key = 'variable ' + name
if key in ffi._parser._declarations: if key in ffi._parser._declarations:
tp = ffi._parser._declarations[key] tp, _ = ffi._parser._declarations[key]
BType = ffi._get_cached_btype(tp) BType = ffi._get_cached_btype(tp)
read_variable = backendlib.read_variable read_variable = backendlib.read_variable
write_variable = backendlib.write_variable write_variable = backendlib.write_variable
@ -436,12 +647,23 @@ def _make_ffi_library(ffi, libname, flags):
# #
if not copied_enums: if not copied_enums:
from . import model from . import model
for key, tp in ffi._parser._declarations.items(): error = None
for key, (tp, _) in ffi._parser._declarations.items():
if not isinstance(tp, model.EnumType): if not isinstance(tp, model.EnumType):
continue continue
try:
tp.check_not_partial()
except Exception as e:
error = e
continue
for enumname, enumval in zip(tp.enumerators, tp.enumvalues): for enumname, enumval in zip(tp.enumerators, tp.enumvalues):
if enumname not in library.__dict__: if enumname not in library.__dict__:
library.__dict__[enumname] = enumval library.__dict__[enumname] = enumval
if error is not None:
if name in library.__dict__:
return # ignore error, about a different enum
raise error
for key, val in ffi._parser._int_constants.items(): for key, val in ffi._parser._int_constants.items():
if key not in library.__dict__: if key not in library.__dict__:
library.__dict__[key] = val library.__dict__[key] = val
@ -450,6 +672,11 @@ def _make_ffi_library(ffi, libname, flags):
if name in library.__dict__: if name in library.__dict__:
return return
# #
key = 'constant ' + name
if key in ffi._parser._declarations:
raise NotImplementedError("fetching a non-integer constant "
"after dlopen()")
#
raise AttributeError(name) raise AttributeError(name)
# #
def make_accessor(name): def make_accessor(name):

View file

@ -2,11 +2,10 @@ import ctypes, ctypes.util, operator, sys
from . import model from . import model
if sys.version_info < (3,): if sys.version_info < (3,):
integer_types = (int, long)
bytechr = chr bytechr = chr
else: else:
unicode = str unicode = str
integer_types = int long = int
xrange = range xrange = range
bytechr = lambda num: bytes([num]) bytechr = lambda num: bytes([num])
@ -169,6 +168,7 @@ class CTypesGenericArray(CTypesData):
class CTypesGenericPtr(CTypesData): class CTypesGenericPtr(CTypesData):
__slots__ = ['_address', '_as_ctype_ptr'] __slots__ = ['_address', '_as_ctype_ptr']
_automatic_casts = False _automatic_casts = False
kind = "pointer"
@classmethod @classmethod
def _newp(cls, init): def _newp(cls, init):
@ -180,7 +180,7 @@ class CTypesGenericPtr(CTypesData):
address = 0 address = 0
elif isinstance(source, CTypesData): elif isinstance(source, CTypesData):
address = source._cast_to_integer() address = source._cast_to_integer()
elif isinstance(source, integer_types): elif isinstance(source, (int, long)):
address = source address = source
else: else:
raise TypeError("bad type for cast to %r: %r" % raise TypeError("bad type for cast to %r: %r" %
@ -357,7 +357,7 @@ class CTypesBackend(object):
is_signed = (ctype(-1).value == -1) is_signed = (ctype(-1).value == -1)
# #
def _cast_source_to_int(source): def _cast_source_to_int(source):
if isinstance(source, (integer_types, float)): if isinstance(source, (int, long, float)):
source = int(source) source = int(source)
elif isinstance(source, CTypesData): elif isinstance(source, CTypesData):
source = source._cast_to_integer() source = source._cast_to_integer()
@ -370,10 +370,12 @@ class CTypesBackend(object):
(CTypesPrimitive, type(source).__name__)) (CTypesPrimitive, type(source).__name__))
return source return source
# #
kind1 = kind
class CTypesPrimitive(CTypesGenericPrimitive): class CTypesPrimitive(CTypesGenericPrimitive):
__slots__ = ['_value'] __slots__ = ['_value']
_ctype = ctype _ctype = ctype
_reftypename = '%s &' % name _reftypename = '%s &' % name
kind = kind1
def __init__(self, value): def __init__(self, value):
self._value = value self._value = value
@ -396,7 +398,7 @@ class CTypesBackend(object):
if kind == 'bool': if kind == 'bool':
@classmethod @classmethod
def _cast_from(cls, source): def _cast_from(cls, source):
if not isinstance(source, (integer_types, float)): if not isinstance(source, (int, long, float)):
source = _cast_source_to_int(source) source = _cast_source_to_int(source)
return cls(bool(source)) return cls(bool(source))
def __int__(self): def __int__(self):
@ -435,7 +437,7 @@ class CTypesBackend(object):
if kind == 'int' or kind == 'byte' or kind == 'bool': if kind == 'int' or kind == 'byte' or kind == 'bool':
@staticmethod @staticmethod
def _to_ctypes(x): def _to_ctypes(x):
if not isinstance(x, integer_types): if not isinstance(x, (int, long)):
if isinstance(x, CTypesData): if isinstance(x, CTypesData):
x = int(x) x = int(x)
else: else:
@ -462,7 +464,7 @@ class CTypesBackend(object):
if kind == 'float': if kind == 'float':
@staticmethod @staticmethod
def _to_ctypes(x): def _to_ctypes(x):
if not isinstance(x, (integer_types, float, CTypesData)): if not isinstance(x, (int, long, float, CTypesData)):
raise TypeError("float expected, got %s" % raise TypeError("float expected, got %s" %
type(x).__name__) type(x).__name__)
return ctype(x).value return ctype(x).value
@ -526,14 +528,14 @@ class CTypesBackend(object):
self._own = True self._own = True
def __add__(self, other): def __add__(self, other):
if isinstance(other, integer_types): if isinstance(other, (int, long)):
return self._new_pointer_at(self._address + return self._new_pointer_at(self._address +
other * self._bitem_size) other * self._bitem_size)
else: else:
return NotImplemented return NotImplemented
def __sub__(self, other): def __sub__(self, other):
if isinstance(other, integer_types): if isinstance(other, (int, long)):
return self._new_pointer_at(self._address - return self._new_pointer_at(self._address -
other * self._bitem_size) other * self._bitem_size)
elif type(self) is type(other): elif type(self) is type(other):
@ -608,7 +610,7 @@ class CTypesBackend(object):
def __init__(self, init): def __init__(self, init):
if length is None: if length is None:
if isinstance(init, integer_types): if isinstance(init, (int, long)):
len1 = init len1 = init
init = None init = None
elif kind == 'char' and isinstance(init, bytes): elif kind == 'char' and isinstance(init, bytes):
@ -683,7 +685,7 @@ class CTypesBackend(object):
return CTypesPtr._arg_to_ctypes(value) return CTypesPtr._arg_to_ctypes(value)
def __add__(self, other): def __add__(self, other):
if isinstance(other, integer_types): if isinstance(other, (int, long)):
return CTypesPtr._new_pointer_at( return CTypesPtr._new_pointer_at(
ctypes.addressof(self._blob) + ctypes.addressof(self._blob) +
other * ctypes.sizeof(BItem._ctype)) other * ctypes.sizeof(BItem._ctype))
@ -703,12 +705,13 @@ class CTypesBackend(object):
class struct_or_union(base_ctypes_class): class struct_or_union(base_ctypes_class):
pass pass
struct_or_union.__name__ = '%s_%s' % (kind, name) struct_or_union.__name__ = '%s_%s' % (kind, name)
kind1 = kind
# #
class CTypesStructOrUnion(CTypesBaseStructOrUnion): class CTypesStructOrUnion(CTypesBaseStructOrUnion):
__slots__ = ['_blob'] __slots__ = ['_blob']
_ctype = struct_or_union _ctype = struct_or_union
_reftypename = '%s &' % (name,) _reftypename = '%s &' % (name,)
_kind = kind _kind = kind = kind1
# #
CTypesStructOrUnion._fix_class() CTypesStructOrUnion._fix_class()
return CTypesStructOrUnion return CTypesStructOrUnion
@ -986,7 +989,8 @@ class CTypesBackend(object):
def cast(self, BType, source): def cast(self, BType, source):
return BType._cast_from(source) return BType._cast_from(source)
def callback(self, BType, source, error): def callback(self, BType, source, error, onerror):
assert onerror is None # XXX not implemented
return BType(source, error) return BType(source, error)
typeof = type typeof = type
@ -994,27 +998,42 @@ class CTypesBackend(object):
def getcname(self, BType, replace_with): def getcname(self, BType, replace_with):
return BType._get_c_name(replace_with) return BType._get_c_name(replace_with)
def typeoffsetof(self, BType, fieldname): def typeoffsetof(self, BType, fieldname, num=0):
if fieldname is not None and issubclass(BType, CTypesGenericPtr): if isinstance(fieldname, str):
if num == 0 and issubclass(BType, CTypesGenericPtr):
BType = BType._BItem BType = BType._BItem
if not issubclass(BType, CTypesBaseStructOrUnion): if not issubclass(BType, CTypesBaseStructOrUnion):
raise TypeError("expected a struct or union ctype") raise TypeError("expected a struct or union ctype")
if fieldname is None:
return (BType, 0)
else:
BField = BType._bfield_types[fieldname] BField = BType._bfield_types[fieldname]
if BField is Ellipsis: if BField is Ellipsis:
raise TypeError("not supported for bitfields") raise TypeError("not supported for bitfields")
return (BField, BType._offsetof(fieldname)) return (BField, BType._offsetof(fieldname))
elif isinstance(fieldname, (int, long)):
if issubclass(BType, CTypesGenericArray):
BType = BType._CTPtr
if not issubclass(BType, CTypesGenericPtr):
raise TypeError("expected an array or ptr ctype")
BItem = BType._BItem
offset = BItem._get_size() * fieldname
if offset > sys.maxsize:
raise OverflowError
return (BItem, offset)
else:
raise TypeError(type(fieldname))
def rawaddressof(self, BTypePtr, cdata, offset): def rawaddressof(self, BTypePtr, cdata, offset=None):
if isinstance(cdata, CTypesBaseStructOrUnion): if isinstance(cdata, CTypesBaseStructOrUnion):
ptr = ctypes.pointer(type(cdata)._to_ctypes(cdata)) ptr = ctypes.pointer(type(cdata)._to_ctypes(cdata))
elif isinstance(cdata, CTypesGenericPtr): elif isinstance(cdata, CTypesGenericPtr):
if offset is None or not issubclass(type(cdata)._BItem,
CTypesBaseStructOrUnion):
raise TypeError("unexpected cdata type")
ptr = type(cdata)._to_ctypes(cdata)
elif isinstance(cdata, CTypesGenericArray):
ptr = type(cdata)._to_ctypes(cdata) ptr = type(cdata)._to_ctypes(cdata)
else: else:
raise TypeError("expected a <cdata 'struct-or-union'>") raise TypeError("expected a <cdata 'struct-or-union'>")
if offset != 0: if offset:
ptr = ctypes.cast( ptr = ctypes.cast(
ctypes.c_void_p( ctypes.c_void_p(
ctypes.cast(ptr, ctypes.c_void_p).value + offset), ctypes.cast(ptr, ctypes.c_void_p).value + offset),

View file

@ -0,0 +1,176 @@
class CffiOp(object):
def __init__(self, op, arg):
self.op = op
self.arg = arg
def as_c_expr(self):
if self.op is None:
assert isinstance(self.arg, str)
return '(_cffi_opcode_t)(%s)' % (self.arg,)
classname = CLASS_NAME[self.op]
return '_CFFI_OP(_CFFI_OP_%s, %s)' % (classname, self.arg)
def as_python_bytes(self):
if self.op is None and self.arg.isdigit():
value = int(self.arg) # non-negative: '-' not in self.arg
if value >= 2**31:
raise OverflowError("cannot emit %r: limited to 2**31-1"
% (self.arg,))
return format_four_bytes(value)
if isinstance(self.arg, str):
from .ffiplatform import VerificationError
raise VerificationError("cannot emit to Python: %r" % (self.arg,))
return format_four_bytes((self.arg << 8) | self.op)
def __str__(self):
classname = CLASS_NAME.get(self.op, self.op)
return '(%s %s)' % (classname, self.arg)
def format_four_bytes(num):
return '\\x%02X\\x%02X\\x%02X\\x%02X' % (
(num >> 24) & 0xFF,
(num >> 16) & 0xFF,
(num >> 8) & 0xFF,
(num ) & 0xFF)
OP_PRIMITIVE = 1
OP_POINTER = 3
OP_ARRAY = 5
OP_OPEN_ARRAY = 7
OP_STRUCT_UNION = 9
OP_ENUM = 11
OP_FUNCTION = 13
OP_FUNCTION_END = 15
OP_NOOP = 17
OP_BITFIELD = 19
OP_TYPENAME = 21
OP_CPYTHON_BLTN_V = 23 # varargs
OP_CPYTHON_BLTN_N = 25 # noargs
OP_CPYTHON_BLTN_O = 27 # O (i.e. a single arg)
OP_CONSTANT = 29
OP_CONSTANT_INT = 31
OP_GLOBAL_VAR = 33
OP_DLOPEN_FUNC = 35
OP_DLOPEN_CONST = 37
OP_GLOBAL_VAR_F = 39
PRIM_VOID = 0
PRIM_BOOL = 1
PRIM_CHAR = 2
PRIM_SCHAR = 3
PRIM_UCHAR = 4
PRIM_SHORT = 5
PRIM_USHORT = 6
PRIM_INT = 7
PRIM_UINT = 8
PRIM_LONG = 9
PRIM_ULONG = 10
PRIM_LONGLONG = 11
PRIM_ULONGLONG = 12
PRIM_FLOAT = 13
PRIM_DOUBLE = 14
PRIM_LONGDOUBLE = 15
PRIM_WCHAR = 16
PRIM_INT8 = 17
PRIM_UINT8 = 18
PRIM_INT16 = 19
PRIM_UINT16 = 20
PRIM_INT32 = 21
PRIM_UINT32 = 22
PRIM_INT64 = 23
PRIM_UINT64 = 24
PRIM_INTPTR = 25
PRIM_UINTPTR = 26
PRIM_PTRDIFF = 27
PRIM_SIZE = 28
PRIM_SSIZE = 29
PRIM_INT_LEAST8 = 30
PRIM_UINT_LEAST8 = 31
PRIM_INT_LEAST16 = 32
PRIM_UINT_LEAST16 = 33
PRIM_INT_LEAST32 = 34
PRIM_UINT_LEAST32 = 35
PRIM_INT_LEAST64 = 36
PRIM_UINT_LEAST64 = 37
PRIM_INT_FAST8 = 38
PRIM_UINT_FAST8 = 39
PRIM_INT_FAST16 = 40
PRIM_UINT_FAST16 = 41
PRIM_INT_FAST32 = 42
PRIM_UINT_FAST32 = 43
PRIM_INT_FAST64 = 44
PRIM_UINT_FAST64 = 45
PRIM_INTMAX = 46
PRIM_UINTMAX = 47
_NUM_PRIM = 48
_UNKNOWN_PRIM = -1
_UNKNOWN_FLOAT_PRIM = -2
_UNKNOWN_LONG_DOUBLE = -3
PRIMITIVE_TO_INDEX = {
'char': PRIM_CHAR,
'short': PRIM_SHORT,
'int': PRIM_INT,
'long': PRIM_LONG,
'long long': PRIM_LONGLONG,
'signed char': PRIM_SCHAR,
'unsigned char': PRIM_UCHAR,
'unsigned short': PRIM_USHORT,
'unsigned int': PRIM_UINT,
'unsigned long': PRIM_ULONG,
'unsigned long long': PRIM_ULONGLONG,
'float': PRIM_FLOAT,
'double': PRIM_DOUBLE,
'long double': PRIM_LONGDOUBLE,
'_Bool': PRIM_BOOL,
'wchar_t': PRIM_WCHAR,
'int8_t': PRIM_INT8,
'uint8_t': PRIM_UINT8,
'int16_t': PRIM_INT16,
'uint16_t': PRIM_UINT16,
'int32_t': PRIM_INT32,
'uint32_t': PRIM_UINT32,
'int64_t': PRIM_INT64,
'uint64_t': PRIM_UINT64,
'intptr_t': PRIM_INTPTR,
'uintptr_t': PRIM_UINTPTR,
'ptrdiff_t': PRIM_PTRDIFF,
'size_t': PRIM_SIZE,
'ssize_t': PRIM_SSIZE,
'int_least8_t': PRIM_INT_LEAST8,
'uint_least8_t': PRIM_UINT_LEAST8,
'int_least16_t': PRIM_INT_LEAST16,
'uint_least16_t': PRIM_UINT_LEAST16,
'int_least32_t': PRIM_INT_LEAST32,
'uint_least32_t': PRIM_UINT_LEAST32,
'int_least64_t': PRIM_INT_LEAST64,
'uint_least64_t': PRIM_UINT_LEAST64,
'int_fast8_t': PRIM_INT_FAST8,
'uint_fast8_t': PRIM_UINT_FAST8,
'int_fast16_t': PRIM_INT_FAST16,
'uint_fast16_t': PRIM_UINT_FAST16,
'int_fast32_t': PRIM_INT_FAST32,
'uint_fast32_t': PRIM_UINT_FAST32,
'int_fast64_t': PRIM_INT_FAST64,
'uint_fast64_t': PRIM_UINT_FAST64,
'intmax_t': PRIM_INTMAX,
'uintmax_t': PRIM_UINTMAX,
}
F_UNION = 0x01
F_CHECK_FIELDS = 0x02
F_PACKED = 0x04
F_EXTERNAL = 0x08
F_OPAQUE = 0x10
G_FLAGS = dict([('_CFFI_' + _key, globals()[_key])
for _key in ['F_UNION', 'F_CHECK_FIELDS', 'F_PACKED',
'F_EXTERNAL', 'F_OPAQUE']])
CLASS_NAME = {}
for _name, _value in list(globals().items()):
if _name.startswith('OP_') and isinstance(_value, int):
CLASS_NAME[_value] = _name[3:]

View file

@ -29,6 +29,9 @@ def resolve_common_type(commontype):
result = model.PointerType(resolve_common_type(result[:-2])) result = model.PointerType(resolve_common_type(result[:-2]))
elif result in model.PrimitiveType.ALL_PRIMITIVE_TYPES: elif result in model.PrimitiveType.ALL_PRIMITIVE_TYPES:
result = model.PrimitiveType(result) result = model.PrimitiveType(result)
elif result == 'set-unicode-needed':
raise api.FFIError("The Windows type %r is only available after "
"you call ffi.set_unicode()" % (commontype,))
else: else:
if commontype == result: if commontype == result:
raise api.FFIError("Unsupported type: %r. Please file a bug " raise api.FFIError("Unsupported type: %r. Please file a bug "
@ -86,8 +89,6 @@ def win_common_types(maxsize):
"ULONGLONG": "unsigned long long", "ULONGLONG": "unsigned long long",
"WCHAR": "wchar_t", "WCHAR": "wchar_t",
"SHORT": "short", "SHORT": "short",
"TBYTE": "WCHAR",
"TCHAR": "WCHAR",
"UCHAR": "unsigned char", "UCHAR": "unsigned char",
"UINT": "unsigned int", "UINT": "unsigned int",
"UINT8": "unsigned char", "UINT8": "unsigned char",
@ -157,14 +158,12 @@ def win_common_types(maxsize):
"LPCVOID": model.const_voidp_type, "LPCVOID": model.const_voidp_type,
"LPCWSTR": "const WCHAR *", "LPCWSTR": "const WCHAR *",
"LPCTSTR": "LPCWSTR",
"LPDWORD": "DWORD *", "LPDWORD": "DWORD *",
"LPHANDLE": "HANDLE *", "LPHANDLE": "HANDLE *",
"LPINT": "int *", "LPINT": "int *",
"LPLONG": "long *", "LPLONG": "long *",
"LPSTR": "CHAR *", "LPSTR": "CHAR *",
"LPWSTR": "WCHAR *", "LPWSTR": "WCHAR *",
"LPTSTR": "LPWSTR",
"LPVOID": model.voidp_type, "LPVOID": model.voidp_type,
"LPWORD": "WORD *", "LPWORD": "WORD *",
"LRESULT": "LONG_PTR", "LRESULT": "LONG_PTR",
@ -173,7 +172,6 @@ def win_common_types(maxsize):
"PBYTE": "BYTE *", "PBYTE": "BYTE *",
"PCHAR": "CHAR *", "PCHAR": "CHAR *",
"PCSTR": "const CHAR *", "PCSTR": "const CHAR *",
"PCTSTR": "LPCWSTR",
"PCWSTR": "const WCHAR *", "PCWSTR": "const WCHAR *",
"PDWORD": "DWORD *", "PDWORD": "DWORD *",
"PDWORDLONG": "DWORDLONG *", "PDWORDLONG": "DWORDLONG *",
@ -200,9 +198,6 @@ def win_common_types(maxsize):
"PSIZE_T": "SIZE_T *", "PSIZE_T": "SIZE_T *",
"PSSIZE_T": "SSIZE_T *", "PSSIZE_T": "SSIZE_T *",
"PSTR": "CHAR *", "PSTR": "CHAR *",
"PTBYTE": "TBYTE *",
"PTCHAR": "TCHAR *",
"PTSTR": "LPWSTR",
"PUCHAR": "UCHAR *", "PUCHAR": "UCHAR *",
"PUHALF_PTR": "UHALF_PTR *", "PUHALF_PTR": "UHALF_PTR *",
"PUINT": "UINT *", "PUINT": "UINT *",
@ -240,6 +235,15 @@ def win_common_types(maxsize):
"USN": "LONGLONG", "USN": "LONGLONG",
"VOID": model.void_type, "VOID": model.void_type,
"WPARAM": "UINT_PTR", "WPARAM": "UINT_PTR",
"TBYTE": "set-unicode-needed",
"TCHAR": "set-unicode-needed",
"LPCTSTR": "set-unicode-needed",
"PCTSTR": "set-unicode-needed",
"LPTSTR": "set-unicode-needed",
"PTSTR": "set-unicode-needed",
"PTBYTE": "set-unicode-needed",
"PTCHAR": "set-unicode-needed",
}) })
return result return result

View file

@ -1,4 +1,3 @@
from . import api, model from . import api, model
from .commontypes import COMMON_TYPES, resolve_common_type from .commontypes import COMMON_TYPES, resolve_common_type
try: try:
@ -16,15 +15,20 @@ try:
except ImportError: except ImportError:
lock = None lock = None
_r_comment = re.compile(r"/\*.*?\*/|//.*?$", re.DOTALL | re.MULTILINE) _r_comment = re.compile(r"/\*.*?\*/|//([^\n\\]|\\.)*?$",
_r_define = re.compile(r"^\s*#\s*define\s+([A-Za-z_][A-Za-z_0-9]*)\s+(.*?)$", re.DOTALL | re.MULTILINE)
re.MULTILINE) _r_define = re.compile(r"^\s*#\s*define\s+([A-Za-z_][A-Za-z_0-9]*)"
r"\b((?:[^\n\\]|\\.)*?)$",
re.DOTALL | re.MULTILINE)
_r_partial_enum = re.compile(r"=\s*\.\.\.\s*[,}]|\.\.\.\s*\}") _r_partial_enum = re.compile(r"=\s*\.\.\.\s*[,}]|\.\.\.\s*\}")
_r_enum_dotdotdot = re.compile(r"__dotdotdot\d+__$") _r_enum_dotdotdot = re.compile(r"__dotdotdot\d+__$")
_r_partial_array = re.compile(r"\[\s*\.\.\.\s*\]") _r_partial_array = re.compile(r"\[\s*\.\.\.\s*\]")
_r_words = re.compile(r"\w+|\S") _r_words = re.compile(r"\w+|\S")
_parser_cache = None _parser_cache = None
_r_int_literal = re.compile(r"^0?x?[0-9a-f]+u?l?$", re.IGNORECASE) _r_int_literal = re.compile(r"-?0?x?[0-9a-f]+[lu]*$", re.IGNORECASE)
_r_stdcall1 = re.compile(r"\b(__stdcall|WINAPI)\b")
_r_stdcall2 = re.compile(r"[(]\s*(__stdcall|WINAPI)\b")
_r_cdecl = re.compile(r"\b__cdecl\b")
def _get_parser(): def _get_parser():
global _parser_cache global _parser_cache
@ -40,8 +44,17 @@ def _preprocess(csource):
macros = {} macros = {}
for match in _r_define.finditer(csource): for match in _r_define.finditer(csource):
macroname, macrovalue = match.groups() macroname, macrovalue = match.groups()
macrovalue = macrovalue.replace('\\\n', '').strip()
macros[macroname] = macrovalue macros[macroname] = macrovalue
csource = _r_define.sub('', csource) csource = _r_define.sub('', csource)
# BIG HACK: replace WINAPI or __stdcall with "volatile const".
# It doesn't make sense for the return type of a function to be
# "volatile volatile const", so we abuse it to detect __stdcall...
# Hack number 2 is that "int(volatile *fptr)();" is not valid C
# syntax, so we place the "volatile" before the opening parenthesis.
csource = _r_stdcall2.sub(' volatile volatile const(', csource)
csource = _r_stdcall1.sub(' volatile volatile const ', csource)
csource = _r_cdecl.sub(' ', csource)
# Replace "[...]" with "[__dotdotdotarray__]" # Replace "[...]" with "[__dotdotdotarray__]"
csource = _r_partial_array.sub('[__dotdotdotarray__]', csource) csource = _r_partial_array.sub('[__dotdotdotarray__]', csource)
# Replace "...}" with "__dotdotdotNUM__}". This construction should # Replace "...}" with "__dotdotdotNUM__}". This construction should
@ -73,9 +86,13 @@ def _common_type_names(csource):
# but should be fine for all the common types. # but should be fine for all the common types.
look_for_words = set(COMMON_TYPES) look_for_words = set(COMMON_TYPES)
look_for_words.add(';') look_for_words.add(';')
look_for_words.add(',')
look_for_words.add('(')
look_for_words.add(')')
look_for_words.add('typedef') look_for_words.add('typedef')
words_used = set() words_used = set()
is_typedef = False is_typedef = False
paren = 0
previous_word = '' previous_word = ''
for word in _r_words.findall(csource): for word in _r_words.findall(csource):
if word in look_for_words: if word in look_for_words:
@ -86,6 +103,15 @@ def _common_type_names(csource):
is_typedef = False is_typedef = False
elif word == 'typedef': elif word == 'typedef':
is_typedef = True is_typedef = True
paren = 0
elif word == '(':
paren += 1
elif word == ')':
paren -= 1
elif word == ',':
if is_typedef and paren == 0:
words_used.discard(previous_word)
look_for_words.discard(previous_word)
else: # word in COMMON_TYPES else: # word in COMMON_TYPES
words_used.add(word) words_used.add(word)
previous_word = word previous_word = word
@ -96,11 +122,14 @@ class Parser(object):
def __init__(self): def __init__(self):
self._declarations = {} self._declarations = {}
self._included_declarations = set()
self._anonymous_counter = 0 self._anonymous_counter = 0
self._structnode2type = weakref.WeakKeyDictionary() self._structnode2type = weakref.WeakKeyDictionary()
self._override = False self._override = False
self._packed = False self._packed = False
self._int_constants = {} self._int_constants = {}
self._recomplete = []
self._uses_new_feature = None
def _parse(self, csource): def _parse(self, csource):
csource, macros = _preprocess(csource) csource, macros = _preprocess(csource)
@ -187,9 +216,10 @@ class Parser(object):
if not decl.name: if not decl.name:
raise api.CDefError("typedef does not declare any name", raise api.CDefError("typedef does not declare any name",
decl) decl)
quals = 0
if (isinstance(decl.type.type, pycparser.c_ast.IdentifierType) if (isinstance(decl.type.type, pycparser.c_ast.IdentifierType)
and decl.type.type.names == ['__dotdotdot__']): and decl.type.type.names[-1] == '__dotdotdot__'):
realtype = model.unknown_type(decl.name) realtype = self._get_unknown_type(decl)
elif (isinstance(decl.type, pycparser.c_ast.PtrDecl) and elif (isinstance(decl.type, pycparser.c_ast.PtrDecl) and
isinstance(decl.type.type, pycparser.c_ast.TypeDecl) and isinstance(decl.type.type, pycparser.c_ast.TypeDecl) and
isinstance(decl.type.type.type, isinstance(decl.type.type.type,
@ -197,8 +227,9 @@ class Parser(object):
decl.type.type.type.names == ['__dotdotdot__']): decl.type.type.type.names == ['__dotdotdot__']):
realtype = model.unknown_ptr_type(decl.name) realtype = model.unknown_ptr_type(decl.name)
else: else:
realtype = self._get_type(decl.type, name=decl.name) realtype, quals = self._get_type_and_quals(
self._declare('typedef ' + decl.name, realtype) decl.type, name=decl.name)
self._declare('typedef ' + decl.name, realtype, quals=quals)
else: else:
raise api.CDefError("unrecognized construct", decl) raise api.CDefError("unrecognized construct", decl)
except api.FFIError as e: except api.FFIError as e:
@ -209,60 +240,84 @@ class Parser(object):
def _add_constants(self, key, val): def _add_constants(self, key, val):
if key in self._int_constants: if key in self._int_constants:
if self._int_constants[key] == val:
return # ignore identical double declarations
raise api.FFIError( raise api.FFIError(
"multiple declarations of constant: %s" % (key,)) "multiple declarations of constant: %s" % (key,))
self._int_constants[key] = val self._int_constants[key] = val
def _add_integer_constant(self, name, int_str):
int_str = int_str.lower().rstrip("ul")
neg = int_str.startswith('-')
if neg:
int_str = int_str[1:]
# "010" is not valid oct in py3
if (int_str.startswith("0") and int_str != '0'
and not int_str.startswith("0x")):
int_str = "0o" + int_str[1:]
pyvalue = int(int_str, 0)
if neg:
pyvalue = -pyvalue
self._add_constants(name, pyvalue)
self._declare('macro ' + name, pyvalue)
def _process_macros(self, macros): def _process_macros(self, macros):
for key, value in macros.items(): for key, value in macros.items():
value = value.strip() value = value.strip()
match = _r_int_literal.search(value) if _r_int_literal.match(value):
if match is not None: self._add_integer_constant(key, value)
int_str = match.group(0).lower().rstrip("ul")
# "010" is not valid oct in py3
if (int_str.startswith("0") and
int_str != "0" and
not int_str.startswith("0x")):
int_str = "0o" + int_str[1:]
pyvalue = int(int_str, 0)
self._add_constants(key, pyvalue)
elif value == '...': elif value == '...':
self._declare('macro ' + key, value) self._declare('macro ' + key, value)
else: else:
raise api.CDefError('only supports the syntax "#define ' raise api.CDefError(
'%s ..." (literally) or "#define ' 'only supports one of the following syntax:\n'
'%s 0x1FF" for now' % (key, key)) ' #define %s ... (literally dot-dot-dot)\n'
' #define %s NUMBER (with NUMBER an integer'
' constant, decimal/hex/octal)\n'
'got:\n'
' #define %s %s'
% (key, key, key, value))
def _parse_decl(self, decl): def _parse_decl(self, decl):
node = decl.type node = decl.type
if isinstance(node, pycparser.c_ast.FuncDecl): if isinstance(node, pycparser.c_ast.FuncDecl):
tp = self._get_type(node, name=decl.name) tp, quals = self._get_type_and_quals(node, name=decl.name)
assert isinstance(tp, model.RawFunctionType) assert isinstance(tp, model.RawFunctionType)
tp = self._get_type_pointer(tp) tp = self._get_type_pointer(tp, quals)
self._declare('function ' + decl.name, tp) self._declare('function ' + decl.name, tp)
else: else:
if isinstance(node, pycparser.c_ast.Struct): if isinstance(node, pycparser.c_ast.Struct):
# XXX do we need self._declare in any of those?
if node.decls is not None:
self._get_struct_union_enum_type('struct', node) self._get_struct_union_enum_type('struct', node)
elif isinstance(node, pycparser.c_ast.Union): elif isinstance(node, pycparser.c_ast.Union):
if node.decls is not None:
self._get_struct_union_enum_type('union', node) self._get_struct_union_enum_type('union', node)
elif isinstance(node, pycparser.c_ast.Enum): elif isinstance(node, pycparser.c_ast.Enum):
if node.values is not None:
self._get_struct_union_enum_type('enum', node) self._get_struct_union_enum_type('enum', node)
elif not decl.name: elif not decl.name:
raise api.CDefError("construct does not declare any variable", raise api.CDefError("construct does not declare any variable",
decl) decl)
# #
if decl.name: if decl.name:
tp = self._get_type(node, partial_length_ok=True) tp, quals = self._get_type_and_quals(node,
if self._is_constant_globalvar(node): partial_length_ok=True)
self._declare('constant ' + decl.name, tp) if tp.is_raw_function:
tp = self._get_type_pointer(tp, quals)
self._declare('function ' + decl.name, tp)
elif (tp.is_integer_type() and
hasattr(decl, 'init') and
hasattr(decl.init, 'value') and
_r_int_literal.match(decl.init.value)):
self._add_integer_constant(decl.name, decl.init.value)
elif (tp.is_integer_type() and
isinstance(decl.init, pycparser.c_ast.UnaryOp) and
decl.init.op == '-' and
hasattr(decl.init.expr, 'value') and
_r_int_literal.match(decl.init.expr.value)):
self._add_integer_constant(decl.name,
'-' + decl.init.expr.value)
elif (quals & model.Q_CONST) and not tp.is_array_type:
self._declare('constant ' + decl.name, tp, quals=quals)
else: else:
self._declare('variable ' + decl.name, tp) self._declare('variable ' + decl.name, tp, quals=quals)
def parse_type(self, cdecl): def parse_type(self, cdecl):
ast, macros = self._parse('void __dummy(\n%s\n);' % cdecl)[:2] ast, macros = self._parse('void __dummy(\n%s\n);' % cdecl)[:2]
@ -270,34 +325,51 @@ class Parser(object):
exprnode = ast.ext[-1].type.args.params[0] exprnode = ast.ext[-1].type.args.params[0]
if isinstance(exprnode, pycparser.c_ast.ID): if isinstance(exprnode, pycparser.c_ast.ID):
raise api.CDefError("unknown identifier '%s'" % (exprnode.name,)) raise api.CDefError("unknown identifier '%s'" % (exprnode.name,))
return self._get_type(exprnode.type) tp, quals = self._get_type_and_quals(exprnode.type)
return tp
def _declare(self, name, obj): def _declare(self, name, obj, included=False, quals=0):
if name in self._declarations: if name in self._declarations:
if self._declarations[name] is obj: prevobj, prevquals = self._declarations[name]
if prevobj is obj and prevquals == quals:
return return
if not self._override: if not self._override:
raise api.FFIError( raise api.FFIError(
"multiple declarations of %s (for interactive usage, " "multiple declarations of %s (for interactive usage, "
"try cdef(xx, override=True))" % (name,)) "try cdef(xx, override=True))" % (name,))
assert '__dotdotdot__' not in name.split() assert '__dotdotdot__' not in name.split()
self._declarations[name] = obj self._declarations[name] = (obj, quals)
if included:
self._included_declarations.add(obj)
def _get_type_pointer(self, type, const=False): def _extract_quals(self, type):
quals = 0
if isinstance(type, (pycparser.c_ast.TypeDecl,
pycparser.c_ast.PtrDecl)):
if 'const' in type.quals:
quals |= model.Q_CONST
if 'restrict' in type.quals:
quals |= model.Q_RESTRICT
return quals
def _get_type_pointer(self, type, quals, declname=None):
if isinstance(type, model.RawFunctionType): if isinstance(type, model.RawFunctionType):
return type.as_function_pointer() return type.as_function_pointer()
if const: if (isinstance(type, model.StructOrUnionOrEnum) and
return model.ConstPointerType(type) type.name.startswith('$') and type.name[1:].isdigit() and
return model.PointerType(type) type.forcename is None and declname is not None):
return model.NamedPointerType(type, declname, quals)
return model.PointerType(type, quals)
def _get_type(self, typenode, name=None, partial_length_ok=False): def _get_type_and_quals(self, typenode, name=None, partial_length_ok=False):
# first, dereference typedefs, if we have it already parsed, we're good # first, dereference typedefs, if we have it already parsed, we're good
if (isinstance(typenode, pycparser.c_ast.TypeDecl) and if (isinstance(typenode, pycparser.c_ast.TypeDecl) and
isinstance(typenode.type, pycparser.c_ast.IdentifierType) and isinstance(typenode.type, pycparser.c_ast.IdentifierType) and
len(typenode.type.names) == 1 and len(typenode.type.names) == 1 and
('typedef ' + typenode.type.names[0]) in self._declarations): ('typedef ' + typenode.type.names[0]) in self._declarations):
type = self._declarations['typedef ' + typenode.type.names[0]] tp, quals = self._declarations['typedef ' + typenode.type.names[0]]
return type quals |= self._extract_quals(typenode)
return tp, quals
# #
if isinstance(typenode, pycparser.c_ast.ArrayDecl): if isinstance(typenode, pycparser.c_ast.ArrayDecl):
# array type # array type
@ -306,15 +378,19 @@ class Parser(object):
else: else:
length = self._parse_constant( length = self._parse_constant(
typenode.dim, partial_length_ok=partial_length_ok) typenode.dim, partial_length_ok=partial_length_ok)
return model.ArrayType(self._get_type(typenode.type), length) tp, quals = self._get_type_and_quals(typenode.type,
partial_length_ok=partial_length_ok)
return model.ArrayType(tp, length), quals
# #
if isinstance(typenode, pycparser.c_ast.PtrDecl): if isinstance(typenode, pycparser.c_ast.PtrDecl):
# pointer type # pointer type
const = (isinstance(typenode.type, pycparser.c_ast.TypeDecl) itemtype, itemquals = self._get_type_and_quals(typenode.type)
and 'const' in typenode.type.quals) tp = self._get_type_pointer(itemtype, itemquals, declname=name)
return self._get_type_pointer(self._get_type(typenode.type), const) quals = self._extract_quals(typenode)
return tp, quals
# #
if isinstance(typenode, pycparser.c_ast.TypeDecl): if isinstance(typenode, pycparser.c_ast.TypeDecl):
quals = self._extract_quals(typenode)
type = typenode.type type = typenode.type
if isinstance(type, pycparser.c_ast.IdentifierType): if isinstance(type, pycparser.c_ast.IdentifierType):
# assume a primitive type. get it from .names, but reduce # assume a primitive type. get it from .names, but reduce
@ -342,35 +418,38 @@ class Parser(object):
names = newnames + names names = newnames + names
ident = ' '.join(names) ident = ' '.join(names)
if ident == 'void': if ident == 'void':
return model.void_type return model.void_type, quals
if ident == '__dotdotdot__': if ident == '__dotdotdot__':
raise api.FFIError(':%d: bad usage of "..."' % raise api.FFIError(':%d: bad usage of "..."' %
typenode.coord.line) typenode.coord.line)
return resolve_common_type(ident) return resolve_common_type(ident), quals
# #
if isinstance(type, pycparser.c_ast.Struct): if isinstance(type, pycparser.c_ast.Struct):
# 'struct foobar' # 'struct foobar'
return self._get_struct_union_enum_type('struct', type, name) tp = self._get_struct_union_enum_type('struct', type, name)
return tp, quals
# #
if isinstance(type, pycparser.c_ast.Union): if isinstance(type, pycparser.c_ast.Union):
# 'union foobar' # 'union foobar'
return self._get_struct_union_enum_type('union', type, name) tp = self._get_struct_union_enum_type('union', type, name)
return tp, quals
# #
if isinstance(type, pycparser.c_ast.Enum): if isinstance(type, pycparser.c_ast.Enum):
# 'enum foobar' # 'enum foobar'
return self._get_struct_union_enum_type('enum', type, name) tp = self._get_struct_union_enum_type('enum', type, name)
return tp, quals
# #
if isinstance(typenode, pycparser.c_ast.FuncDecl): if isinstance(typenode, pycparser.c_ast.FuncDecl):
# a function type # a function type
return self._parse_function_type(typenode, name) return self._parse_function_type(typenode, name), 0
# #
# nested anonymous structs or unions end up here # nested anonymous structs or unions end up here
if isinstance(typenode, pycparser.c_ast.Struct): if isinstance(typenode, pycparser.c_ast.Struct):
return self._get_struct_union_enum_type('struct', typenode, name, return self._get_struct_union_enum_type('struct', typenode, name,
nested=True) nested=True), 0
if isinstance(typenode, pycparser.c_ast.Union): if isinstance(typenode, pycparser.c_ast.Union):
return self._get_struct_union_enum_type('union', typenode, name, return self._get_struct_union_enum_type('union', typenode, name,
nested=True) nested=True), 0
# #
raise api.FFIError(":%d: bad or unsupported type declaration" % raise api.FFIError(":%d: bad or unsupported type declaration" %
typenode.coord.line) typenode.coord.line)
@ -389,31 +468,28 @@ class Parser(object):
raise api.CDefError( raise api.CDefError(
"%s: a function with only '(...)' as argument" "%s: a function with only '(...)' as argument"
" is not correct C" % (funcname or 'in expression')) " is not correct C" % (funcname or 'in expression'))
elif (len(params) == 1 and args = [self._as_func_arg(*self._get_type_and_quals(argdeclnode.type))
isinstance(params[0].type, pycparser.c_ast.TypeDecl) and
isinstance(params[0].type.type, pycparser.c_ast.IdentifierType)
and list(params[0].type.type.names) == ['void']):
del params[0]
args = [self._as_func_arg(self._get_type(argdeclnode.type))
for argdeclnode in params] for argdeclnode in params]
result = self._get_type(typenode.type) if not ellipsis and args == [model.void_type]:
return model.RawFunctionType(tuple(args), result, ellipsis) args = []
result, quals = self._get_type_and_quals(typenode.type)
# the 'quals' on the result type are ignored. HACK: we absure them
# to detect __stdcall functions: we textually replace "__stdcall"
# with "volatile volatile const" above.
abi = None
if hasattr(typenode.type, 'quals'): # else, probable syntax error anyway
if typenode.type.quals[-3:] == ['volatile', 'volatile', 'const']:
abi = '__stdcall'
return model.RawFunctionType(tuple(args), result, ellipsis, abi)
def _as_func_arg(self, type): def _as_func_arg(self, type, quals):
if isinstance(type, model.ArrayType): if isinstance(type, model.ArrayType):
return model.PointerType(type.item) return model.PointerType(type.item, quals)
elif isinstance(type, model.RawFunctionType): elif isinstance(type, model.RawFunctionType):
return type.as_function_pointer() return type.as_function_pointer()
else: else:
return type return type
def _is_constant_globalvar(self, typenode):
if isinstance(typenode, pycparser.c_ast.PtrDecl):
return 'const' in typenode.quals
if isinstance(typenode, pycparser.c_ast.TypeDecl):
return 'const' in typenode.quals
return False
def _get_struct_union_enum_type(self, kind, type, name=None, nested=False): def _get_struct_union_enum_type(self, kind, type, name=None, nested=False):
# First, a level of caching on the exact 'type' node of the AST. # First, a level of caching on the exact 'type' node of the AST.
# This is obscure, but needed because pycparser "unrolls" declarations # This is obscure, but needed because pycparser "unrolls" declarations
@ -452,7 +528,7 @@ class Parser(object):
else: else:
explicit_name = name explicit_name = name
key = '%s %s' % (kind, name) key = '%s %s' % (kind, name)
tp = self._declarations.get(key, None) tp, _ = self._declarations.get(key, (None, None))
# #
if tp is None: if tp is None:
if kind == 'struct': if kind == 'struct':
@ -460,6 +536,8 @@ class Parser(object):
elif kind == 'union': elif kind == 'union':
tp = model.UnionType(explicit_name, None, None, None) tp = model.UnionType(explicit_name, None, None, None)
elif kind == 'enum': elif kind == 'enum':
if explicit_name == '__dotdotdot__':
raise CDefError("Enums cannot be declared with ...")
tp = self._build_enum_type(explicit_name, type.values) tp = self._build_enum_type(explicit_name, type.values)
else: else:
raise AssertionError("kind = %r" % (kind,)) raise AssertionError("kind = %r" % (kind,))
@ -492,6 +570,7 @@ class Parser(object):
fldnames = [] fldnames = []
fldtypes = [] fldtypes = []
fldbitsize = [] fldbitsize = []
fldquals = []
for decl in type.decls: for decl in type.decls:
if (isinstance(decl.type, pycparser.c_ast.IdentifierType) and if (isinstance(decl.type, pycparser.c_ast.IdentifierType) and
''.join(decl.type.names) == '__dotdotdot__'): ''.join(decl.type.names) == '__dotdotdot__'):
@ -505,7 +584,8 @@ class Parser(object):
else: else:
bitsize = self._parse_constant(decl.bitsize) bitsize = self._parse_constant(decl.bitsize)
self._partial_length = False self._partial_length = False
type = self._get_type(decl.type, partial_length_ok=True) type, fqual = self._get_type_and_quals(decl.type,
partial_length_ok=True)
if self._partial_length: if self._partial_length:
self._make_partial(tp, nested) self._make_partial(tp, nested)
if isinstance(type, model.StructType) and type.partial: if isinstance(type, model.StructType) and type.partial:
@ -513,14 +593,19 @@ class Parser(object):
fldnames.append(decl.name or '') fldnames.append(decl.name or '')
fldtypes.append(type) fldtypes.append(type)
fldbitsize.append(bitsize) fldbitsize.append(bitsize)
fldquals.append(fqual)
tp.fldnames = tuple(fldnames) tp.fldnames = tuple(fldnames)
tp.fldtypes = tuple(fldtypes) tp.fldtypes = tuple(fldtypes)
tp.fldbitsize = tuple(fldbitsize) tp.fldbitsize = tuple(fldbitsize)
tp.fldquals = tuple(fldquals)
if fldbitsize != [-1] * len(fldbitsize): if fldbitsize != [-1] * len(fldbitsize):
if isinstance(tp, model.StructType) and tp.partial: if isinstance(tp, model.StructType) and tp.partial:
raise NotImplementedError("%s: using both bitfields and '...;'" raise NotImplementedError("%s: using both bitfields and '...;'"
% (tp,)) % (tp,))
tp.packed = self._packed tp.packed = self._packed
if tp.completed: # must be re-completed: it is not opaque any more
tp.completed = 0
self._recomplete.append(tp)
return tp return tp
def _make_partial(self, tp, nested): def _make_partial(self, tp, nested):
@ -532,9 +617,24 @@ class Parser(object):
def _parse_constant(self, exprnode, partial_length_ok=False): def _parse_constant(self, exprnode, partial_length_ok=False):
# for now, limited to expressions that are an immediate number # for now, limited to expressions that are an immediate number
# or negative number # or positive/negative number
if isinstance(exprnode, pycparser.c_ast.Constant): if isinstance(exprnode, pycparser.c_ast.Constant):
return int(exprnode.value, 0) s = exprnode.value
if s.startswith('0'):
if s.startswith('0x') or s.startswith('0X'):
return int(s, 16)
return int(s, 8)
elif '1' <= s[0] <= '9':
return int(s, 10)
elif s[0] == "'" and s[-1] == "'" and (
len(s) == 3 or (len(s) == 4 and s[1] == "\\")):
return ord(s[-2])
else:
raise api.CDefError("invalid constant %r" % (s,))
#
if (isinstance(exprnode, pycparser.c_ast.UnaryOp) and
exprnode.op == '+'):
return self._parse_constant(exprnode.expr)
# #
if (isinstance(exprnode, pycparser.c_ast.UnaryOp) and if (isinstance(exprnode, pycparser.c_ast.UnaryOp) and
exprnode.op == '-'): exprnode.op == '-'):
@ -555,19 +655,21 @@ class Parser(object):
def _build_enum_type(self, explicit_name, decls): def _build_enum_type(self, explicit_name, decls):
if decls is not None: if decls is not None:
enumerators1 = [enum.name for enum in decls.enumerators] partial = False
enumerators = [s for s in enumerators1 enumerators = []
if not _r_enum_dotdotdot.match(s)]
partial = len(enumerators) < len(enumerators1)
enumerators = tuple(enumerators)
enumvalues = [] enumvalues = []
nextenumvalue = 0 nextenumvalue = 0
for enum in decls.enumerators[:len(enumerators)]: for enum in decls.enumerators:
if _r_enum_dotdotdot.match(enum.name):
partial = True
continue
if enum.value is not None: if enum.value is not None:
nextenumvalue = self._parse_constant(enum.value) nextenumvalue = self._parse_constant(enum.value)
enumerators.append(enum.name)
enumvalues.append(nextenumvalue) enumvalues.append(nextenumvalue)
self._add_constants(enum.name, nextenumvalue) self._add_constants(enum.name, nextenumvalue)
nextenumvalue += 1 nextenumvalue += 1
enumerators = tuple(enumerators)
enumvalues = tuple(enumvalues) enumvalues = tuple(enumvalues)
tp = model.EnumType(explicit_name, enumerators, enumvalues) tp = model.EnumType(explicit_name, enumerators, enumvalues)
tp.partial = partial tp.partial = partial
@ -576,9 +678,35 @@ class Parser(object):
return tp return tp
def include(self, other): def include(self, other):
for name, tp in other._declarations.items(): for name, (tp, quals) in other._declarations.items():
if name.startswith('anonymous $enum_$'):
continue # fix for test_anonymous_enum_include
kind = name.split(' ', 1)[0] kind = name.split(' ', 1)[0]
if kind in ('typedef', 'struct', 'union', 'enum'): if kind in ('struct', 'union', 'enum', 'anonymous', 'typedef'):
self._declare(name, tp) self._declare(name, tp, included=True, quals=quals)
for k, v in other._int_constants.items(): for k, v in other._int_constants.items():
self._add_constants(k, v) self._add_constants(k, v)
def _get_unknown_type(self, decl):
typenames = decl.type.type.names
assert typenames[-1] == '__dotdotdot__'
if len(typenames) == 1:
return model.unknown_type(decl.name)
if (typenames[:-1] == ['float'] or
typenames[:-1] == ['double']):
# not for 'long double' so far
result = model.UnknownFloatType(decl.name)
else:
for t in typenames[:-1]:
if t not in ['int', 'short', 'long', 'signed',
'unsigned', 'char']:
raise api.FFIError(':%d: bad usage of "..."' %
decl.coord.line)
result = model.UnknownIntegerType(decl.name)
if self._uses_new_feature is None:
self._uses_new_feature = "'typedef %s... %s'" % (
' '.join(typenames[:-1]), decl.name)
return result

View file

@ -1,4 +1,4 @@
import os import sys, os
class VerificationError(Exception): class VerificationError(Exception):
@ -11,6 +11,9 @@ class VerificationMissing(Exception):
""" """
LIST_OF_FILE_NAMES = ['sources', 'include_dirs', 'library_dirs',
'extra_objects', 'depends']
def get_extension(srcfilename, modname, sources=(), **kwds): def get_extension(srcfilename, modname, sources=(), **kwds):
from distutils.core import Extension from distutils.core import Extension
allsources = [srcfilename] allsources = [srcfilename]

View file

@ -2,18 +2,21 @@ from weakref import ref
class GcWeakrefs(object): class GcWeakrefs(object):
# code copied and adapted from WeakKeyDictionary.
def __init__(self, ffi): def __init__(self, ffi):
self.ffi = ffi self.ffi = ffi
self.data = data = {} self.data = {}
def remove(k):
destructor, cdata = data.pop(k)
destructor(cdata)
self.remove = remove
def build(self, cdata, destructor): def build(self, cdata, destructor):
# make a new cdata of the same type as the original one # make a new cdata of the same type as the original one
new_cdata = self.ffi.cast(self.ffi._backend.typeof(cdata), cdata) new_cdata = self.ffi.cast(self.ffi._backend.typeof(cdata), cdata)
self.data[ref(new_cdata, self.remove)] = destructor, cdata #
def remove(key):
# careful, this function is not protected by any lock
old_key = self.data.pop(index)
assert old_key is key
destructor(cdata)
#
key = ref(new_cdata, remove)
index = object()
self.data[index] = key
return new_cdata return new_cdata

View file

@ -1,14 +1,29 @@
import types import types, sys
import weakref import weakref
from .lock import allocate_lock from .lock import allocate_lock
# type qualifiers
Q_CONST = 0x01
Q_RESTRICT = 0x02
def qualify(quals, replace_with):
if quals & Q_CONST:
replace_with = ' const ' + replace_with.lstrip()
if quals & Q_RESTRICT:
# It seems that __restrict is supported by gcc and msvc.
# If you hit some different compiler, add a #define in
# _cffi_include.h for it (and in its copies, documented there)
replace_with = ' __restrict ' + replace_with.lstrip()
return replace_with
class BaseTypeByIdentity(object): class BaseTypeByIdentity(object):
is_array_type = False is_array_type = False
is_raw_function = False is_raw_function = False
def get_c_name(self, replace_with='', context='a C file'): def get_c_name(self, replace_with='', context='a C file', quals=0):
result = self.c_name_with_marker result = self.c_name_with_marker
assert result.count('&') == 1 assert result.count('&') == 1
# some logic duplication with ffi.getctype()... :-( # some logic duplication with ffi.getctype()... :-(
@ -18,6 +33,7 @@ class BaseTypeByIdentity(object):
replace_with = '(%s)' % replace_with replace_with = '(%s)' % replace_with
elif not replace_with[0] in '[(': elif not replace_with[0] in '[(':
replace_with = ' ' + replace_with replace_with = ' ' + replace_with
replace_with = qualify(quals, replace_with)
result = result.replace('&', replace_with) result = result.replace('&', replace_with)
if '$' in result: if '$' in result:
from .ffiplatform import VerificationError from .ffiplatform import VerificationError
@ -32,6 +48,9 @@ class BaseTypeByIdentity(object):
def has_c_name(self): def has_c_name(self):
return '$' not in self._get_c_name() return '$' not in self._get_c_name()
def is_integer_type(self):
return False
def get_cached_btype(self, ffi, finishlist, can_delay=False): def get_cached_btype(self, ffi, finishlist, can_delay=False):
try: try:
BType = ffi._cached_btypes[self] BType = ffi._cached_btypes[self]
@ -73,7 +92,11 @@ class VoidType(BaseType):
void_type = VoidType() void_type = VoidType()
class PrimitiveType(BaseType): class BasePrimitiveType(BaseType):
pass
class PrimitiveType(BasePrimitiveType):
_attrs_ = ('name',) _attrs_ = ('name',)
ALL_PRIMITIVE_TYPES = { ALL_PRIMITIVE_TYPES = {
@ -102,8 +125,26 @@ class PrimitiveType(BaseType):
'uint32_t': 'i', 'uint32_t': 'i',
'int64_t': 'i', 'int64_t': 'i',
'uint64_t': 'i', 'uint64_t': 'i',
'int_least8_t': 'i',
'uint_least8_t': 'i',
'int_least16_t': 'i',
'uint_least16_t': 'i',
'int_least32_t': 'i',
'uint_least32_t': 'i',
'int_least64_t': 'i',
'uint_least64_t': 'i',
'int_fast8_t': 'i',
'uint_fast8_t': 'i',
'int_fast16_t': 'i',
'uint_fast16_t': 'i',
'int_fast32_t': 'i',
'uint_fast32_t': 'i',
'int_fast64_t': 'i',
'uint_fast64_t': 'i',
'intptr_t': 'i', 'intptr_t': 'i',
'uintptr_t': 'i', 'uintptr_t': 'i',
'intmax_t': 'i',
'uintmax_t': 'i',
'ptrdiff_t': 'i', 'ptrdiff_t': 'i',
'size_t': 'i', 'size_t': 'i',
'ssize_t': 'i', 'ssize_t': 'i',
@ -125,19 +166,48 @@ class PrimitiveType(BaseType):
return global_cache(self, ffi, 'new_primitive_type', self.name) return global_cache(self, ffi, 'new_primitive_type', self.name)
class BaseFunctionType(BaseType): class UnknownIntegerType(BasePrimitiveType):
_attrs_ = ('args', 'result', 'ellipsis') _attrs_ = ('name',)
def __init__(self, args, result, ellipsis): def __init__(self, name):
self.name = name
self.c_name_with_marker = name + '&'
def is_integer_type(self):
return True
def build_backend_type(self, ffi, finishlist):
raise NotImplementedError("integer type '%s' can only be used after "
"compilation" % self.name)
class UnknownFloatType(BasePrimitiveType):
_attrs_ = ('name', )
def __init__(self, name):
self.name = name
self.c_name_with_marker = name + '&'
def build_backend_type(self, ffi, finishlist):
raise NotImplementedError("float type '%s' can only be used after "
"compilation" % self.name)
class BaseFunctionType(BaseType):
_attrs_ = ('args', 'result', 'ellipsis', 'abi')
def __init__(self, args, result, ellipsis, abi=None):
self.args = args self.args = args
self.result = result self.result = result
self.ellipsis = ellipsis self.ellipsis = ellipsis
self.abi = abi
# #
reprargs = [arg._get_c_name() for arg in self.args] reprargs = [arg._get_c_name() for arg in self.args]
if self.ellipsis: if self.ellipsis:
reprargs.append('...') reprargs.append('...')
reprargs = reprargs or ['void'] reprargs = reprargs or ['void']
replace_with = self._base_pattern % (', '.join(reprargs),) replace_with = self._base_pattern % (', '.join(reprargs),)
if abi is not None:
replace_with = replace_with[:1] + abi + ' ' + replace_with[1:]
self.c_name_with_marker = ( self.c_name_with_marker = (
self.result.c_name_with_marker.replace('&', replace_with)) self.result.c_name_with_marker.replace('&', replace_with))
@ -155,7 +225,7 @@ class RawFunctionType(BaseFunctionType):
"type, not a pointer-to-function type" % (self,)) "type, not a pointer-to-function type" % (self,))
def as_function_pointer(self): def as_function_pointer(self):
return FunctionPtrType(self.args, self.result, self.ellipsis) return FunctionPtrType(self.args, self.result, self.ellipsis, self.abi)
class FunctionPtrType(BaseFunctionType): class FunctionPtrType(BaseFunctionType):
@ -166,21 +236,29 @@ class FunctionPtrType(BaseFunctionType):
args = [] args = []
for tp in self.args: for tp in self.args:
args.append(tp.get_cached_btype(ffi, finishlist)) args.append(tp.get_cached_btype(ffi, finishlist))
abi_args = ()
if self.abi == "__stdcall":
if not self.ellipsis: # __stdcall ignored for variadic funcs
try:
abi_args = (ffi._backend.FFI_STDCALL,)
except AttributeError:
pass
return global_cache(self, ffi, 'new_function_type', return global_cache(self, ffi, 'new_function_type',
tuple(args), result, self.ellipsis) tuple(args), result, self.ellipsis, *abi_args)
def as_raw_function(self):
return RawFunctionType(self.args, self.result, self.ellipsis, self.abi)
class PointerType(BaseType): class PointerType(BaseType):
_attrs_ = ('totype',) _attrs_ = ('totype', 'quals')
_base_pattern = " *&"
_base_pattern_array = "(*&)"
def __init__(self, totype): def __init__(self, totype, quals=0):
self.totype = totype self.totype = totype
self.quals = quals
extra = qualify(quals, " *&")
if totype.is_array_type: if totype.is_array_type:
extra = self._base_pattern_array extra = "(%s)" % (extra.lstrip(),)
else:
extra = self._base_pattern
self.c_name_with_marker = totype.c_name_with_marker.replace('&', extra) self.c_name_with_marker = totype.c_name_with_marker.replace('&', extra)
def build_backend_type(self, ffi, finishlist): def build_backend_type(self, ffi, finishlist):
@ -189,10 +267,8 @@ class PointerType(BaseType):
voidp_type = PointerType(void_type) voidp_type = PointerType(void_type)
def ConstPointerType(totype):
class ConstPointerType(PointerType): return PointerType(totype, Q_CONST)
_base_pattern = " const *&"
_base_pattern_array = "(const *&)"
const_voidp_type = ConstPointerType(void_type) const_voidp_type = ConstPointerType(void_type)
@ -200,8 +276,8 @@ const_voidp_type = ConstPointerType(void_type)
class NamedPointerType(PointerType): class NamedPointerType(PointerType):
_attrs_ = ('totype', 'name') _attrs_ = ('totype', 'name')
def __init__(self, totype, name): def __init__(self, totype, name, quals=0):
PointerType.__init__(self, totype) PointerType.__init__(self, totype, quals)
self.name = name self.name = name
self.c_name_with_marker = name + '&' self.c_name_with_marker = name + '&'
@ -219,7 +295,7 @@ class ArrayType(BaseType):
elif length == '...': elif length == '...':
brackets = '&[/*...*/]' brackets = '&[/*...*/]'
else: else:
brackets = '&[%d]' % length brackets = '&[%s]' % length
self.c_name_with_marker = ( self.c_name_with_marker = (
self.item.c_name_with_marker.replace('&', brackets)) self.item.c_name_with_marker.replace('&', brackets))
@ -235,6 +311,8 @@ class ArrayType(BaseType):
BPtrItem = PointerType(self.item).get_cached_btype(ffi, finishlist) BPtrItem = PointerType(self.item).get_cached_btype(ffi, finishlist)
return global_cache(self, ffi, 'new_array_type', BPtrItem, self.length) return global_cache(self, ffi, 'new_array_type', BPtrItem, self.length)
char_array_type = ArrayType(PrimitiveType('char'), None)
class StructOrUnionOrEnum(BaseTypeByIdentity): class StructOrUnionOrEnum(BaseTypeByIdentity):
_attrs_ = ('name',) _attrs_ = ('name',)
@ -255,26 +333,38 @@ class StructOrUnionOrEnum(BaseTypeByIdentity):
class StructOrUnion(StructOrUnionOrEnum): class StructOrUnion(StructOrUnionOrEnum):
fixedlayout = None fixedlayout = None
completed = False completed = 0
partial = False partial = False
packed = False packed = False
def __init__(self, name, fldnames, fldtypes, fldbitsize): def __init__(self, name, fldnames, fldtypes, fldbitsize, fldquals=None):
self.name = name self.name = name
self.fldnames = fldnames self.fldnames = fldnames
self.fldtypes = fldtypes self.fldtypes = fldtypes
self.fldbitsize = fldbitsize self.fldbitsize = fldbitsize
self.fldquals = fldquals
self.build_c_name_with_marker() self.build_c_name_with_marker()
def has_anonymous_struct_fields(self):
if self.fldtypes is None:
return False
for name, type in zip(self.fldnames, self.fldtypes):
if name == '' and isinstance(type, StructOrUnion):
return True
return False
def enumfields(self): def enumfields(self):
for name, type, bitsize in zip(self.fldnames, self.fldtypes, fldquals = self.fldquals
self.fldbitsize): if fldquals is None:
fldquals = (0,) * len(self.fldnames)
for name, type, bitsize, quals in zip(self.fldnames, self.fldtypes,
self.fldbitsize, fldquals):
if name == '' and isinstance(type, StructOrUnion): if name == '' and isinstance(type, StructOrUnion):
# nested anonymous struct/union # nested anonymous struct/union
for result in type.enumfields(): for result in type.enumfields():
yield result yield result
else: else:
yield (name, type, bitsize) yield (name, type, bitsize, quals)
def force_flatten(self): def force_flatten(self):
# force the struct or union to have a declaration that lists # force the struct or union to have a declaration that lists
@ -283,13 +373,16 @@ class StructOrUnion(StructOrUnionOrEnum):
names = [] names = []
types = [] types = []
bitsizes = [] bitsizes = []
for name, type, bitsize in self.enumfields(): fldquals = []
for name, type, bitsize, quals in self.enumfields():
names.append(name) names.append(name)
types.append(type) types.append(type)
bitsizes.append(bitsize) bitsizes.append(bitsize)
fldquals.append(quals)
self.fldnames = tuple(names) self.fldnames = tuple(names)
self.fldtypes = tuple(types) self.fldtypes = tuple(types)
self.fldbitsize = tuple(bitsizes) self.fldbitsize = tuple(bitsizes)
self.fldquals = tuple(fldquals)
def get_cached_btype(self, ffi, finishlist, can_delay=False): def get_cached_btype(self, ffi, finishlist, can_delay=False):
BType = StructOrUnionOrEnum.get_cached_btype(self, ffi, finishlist, BType = StructOrUnionOrEnum.get_cached_btype(self, ffi, finishlist,
@ -305,12 +398,13 @@ class StructOrUnion(StructOrUnionOrEnum):
"for '%s'" % (self.name,)) "for '%s'" % (self.name,))
return return
BType = ffi._cached_btypes[self] BType = ffi._cached_btypes[self]
if self.fldtypes is None:
return # not completing it: it's an opaque struct
# #
self.completed = 1 self.completed = 1
# #
if self.fixedlayout is None: if self.fldtypes is None:
pass # not completing it: it's an opaque struct
#
elif self.fixedlayout is None:
fldtypes = [tp.get_cached_btype(ffi, finishlist) fldtypes = [tp.get_cached_btype(ffi, finishlist)
for tp in self.fldtypes] for tp in self.fldtypes]
lst = list(zip(self.fldnames, fldtypes, self.fldbitsize)) lst = list(zip(self.fldnames, fldtypes, self.fldbitsize))
@ -449,11 +543,12 @@ def unknown_type(name, structname=None):
structname = '$%s' % name structname = '$%s' % name
tp = StructType(structname, None, None, None) tp = StructType(structname, None, None, None)
tp.force_the_name(name) tp.force_the_name(name)
tp.origin = "unknown_type"
return tp return tp
def unknown_ptr_type(name, structname=None): def unknown_ptr_type(name, structname=None):
if structname is None: if structname is None:
structname = '*$%s' % name structname = '$$%s' % name
tp = StructType(structname, None, None, None) tp = StructType(structname, None, None, None)
return NamedPointerType(tp, name) return NamedPointerType(tp, name)
@ -478,7 +573,7 @@ def global_cache(srctype, ffi, funcname, *args, **kwds):
try: try:
res = getattr(ffi._backend, funcname)(*args) res = getattr(ffi._backend, funcname)(*args)
except NotImplementedError as e: except NotImplementedError as e:
raise NotImplementedError("%r: %s" % (srctype, e)) raise NotImplementedError("%s: %r: %s" % (funcname, srctype, e))
# note that setdefault() on WeakValueDictionary is not atomic # note that setdefault() on WeakValueDictionary is not atomic
# and contains a rare bug (http://bugs.python.org/issue19542); # and contains a rare bug (http://bugs.python.org/issue19542);
# we have to use a lock and do it ourselves # we have to use a lock and do it ourselves

View file

@ -0,0 +1,167 @@
/* See doc/misc/parse_c_type.rst in the source of CFFI for more information */
typedef void *_cffi_opcode_t;
#define _CFFI_OP(opcode, arg) (_cffi_opcode_t)(opcode | (((uintptr_t)(arg)) << 8))
#define _CFFI_GETOP(cffi_opcode) ((unsigned char)(uintptr_t)cffi_opcode)
#define _CFFI_GETARG(cffi_opcode) (((intptr_t)cffi_opcode) >> 8)
#define _CFFI_OP_PRIMITIVE 1
#define _CFFI_OP_POINTER 3
#define _CFFI_OP_ARRAY 5
#define _CFFI_OP_OPEN_ARRAY 7
#define _CFFI_OP_STRUCT_UNION 9
#define _CFFI_OP_ENUM 11
#define _CFFI_OP_FUNCTION 13
#define _CFFI_OP_FUNCTION_END 15
#define _CFFI_OP_NOOP 17
#define _CFFI_OP_BITFIELD 19
#define _CFFI_OP_TYPENAME 21
#define _CFFI_OP_CPYTHON_BLTN_V 23 // varargs
#define _CFFI_OP_CPYTHON_BLTN_N 25 // noargs
#define _CFFI_OP_CPYTHON_BLTN_O 27 // O (i.e. a single arg)
#define _CFFI_OP_CONSTANT 29
#define _CFFI_OP_CONSTANT_INT 31
#define _CFFI_OP_GLOBAL_VAR 33
#define _CFFI_OP_DLOPEN_FUNC 35
#define _CFFI_OP_DLOPEN_CONST 37
#define _CFFI_OP_GLOBAL_VAR_F 39
#define _CFFI_PRIM_VOID 0
#define _CFFI_PRIM_BOOL 1
#define _CFFI_PRIM_CHAR 2
#define _CFFI_PRIM_SCHAR 3
#define _CFFI_PRIM_UCHAR 4
#define _CFFI_PRIM_SHORT 5
#define _CFFI_PRIM_USHORT 6
#define _CFFI_PRIM_INT 7
#define _CFFI_PRIM_UINT 8
#define _CFFI_PRIM_LONG 9
#define _CFFI_PRIM_ULONG 10
#define _CFFI_PRIM_LONGLONG 11
#define _CFFI_PRIM_ULONGLONG 12
#define _CFFI_PRIM_FLOAT 13
#define _CFFI_PRIM_DOUBLE 14
#define _CFFI_PRIM_LONGDOUBLE 15
#define _CFFI_PRIM_WCHAR 16
#define _CFFI_PRIM_INT8 17
#define _CFFI_PRIM_UINT8 18
#define _CFFI_PRIM_INT16 19
#define _CFFI_PRIM_UINT16 20
#define _CFFI_PRIM_INT32 21
#define _CFFI_PRIM_UINT32 22
#define _CFFI_PRIM_INT64 23
#define _CFFI_PRIM_UINT64 24
#define _CFFI_PRIM_INTPTR 25
#define _CFFI_PRIM_UINTPTR 26
#define _CFFI_PRIM_PTRDIFF 27
#define _CFFI_PRIM_SIZE 28
#define _CFFI_PRIM_SSIZE 29
#define _CFFI_PRIM_INT_LEAST8 30
#define _CFFI_PRIM_UINT_LEAST8 31
#define _CFFI_PRIM_INT_LEAST16 32
#define _CFFI_PRIM_UINT_LEAST16 33
#define _CFFI_PRIM_INT_LEAST32 34
#define _CFFI_PRIM_UINT_LEAST32 35
#define _CFFI_PRIM_INT_LEAST64 36
#define _CFFI_PRIM_UINT_LEAST64 37
#define _CFFI_PRIM_INT_FAST8 38
#define _CFFI_PRIM_UINT_FAST8 39
#define _CFFI_PRIM_INT_FAST16 40
#define _CFFI_PRIM_UINT_FAST16 41
#define _CFFI_PRIM_INT_FAST32 42
#define _CFFI_PRIM_UINT_FAST32 43
#define _CFFI_PRIM_INT_FAST64 44
#define _CFFI_PRIM_UINT_FAST64 45
#define _CFFI_PRIM_INTMAX 46
#define _CFFI_PRIM_UINTMAX 47
#define _CFFI__NUM_PRIM 48
#define _CFFI__UNKNOWN_PRIM (-1)
#define _CFFI__UNKNOWN_FLOAT_PRIM (-2)
#define _CFFI__UNKNOWN_LONG_DOUBLE (-3)
struct _cffi_global_s {
const char *name;
void *address;
_cffi_opcode_t type_op;
void *size_or_direct_fn; // OP_GLOBAL_VAR: size, or 0 if unknown
// OP_CPYTHON_BLTN_*: addr of direct function
};
struct _cffi_getconst_s {
unsigned long long value;
const struct _cffi_type_context_s *ctx;
int gindex;
};
struct _cffi_struct_union_s {
const char *name;
int type_index; // -> _cffi_types, on a OP_STRUCT_UNION
int flags; // _CFFI_F_* flags below
size_t size;
int alignment;
int first_field_index; // -> _cffi_fields array
int num_fields;
};
#define _CFFI_F_UNION 0x01 // is a union, not a struct
#define _CFFI_F_CHECK_FIELDS 0x02 // complain if fields are not in the
// "standard layout" or if some are missing
#define _CFFI_F_PACKED 0x04 // for CHECK_FIELDS, assume a packed struct
#define _CFFI_F_EXTERNAL 0x08 // in some other ffi.include()
#define _CFFI_F_OPAQUE 0x10 // opaque
struct _cffi_field_s {
const char *name;
size_t field_offset;
size_t field_size;
_cffi_opcode_t field_type_op;
};
struct _cffi_enum_s {
const char *name;
int type_index; // -> _cffi_types, on a OP_ENUM
int type_prim; // _CFFI_PRIM_xxx
const char *enumerators; // comma-delimited string
};
struct _cffi_typename_s {
const char *name;
int type_index; /* if opaque, points to a possibly artificial
OP_STRUCT which is itself opaque */
};
struct _cffi_type_context_s {
_cffi_opcode_t *types;
const struct _cffi_global_s *globals;
const struct _cffi_field_s *fields;
const struct _cffi_struct_union_s *struct_unions;
const struct _cffi_enum_s *enums;
const struct _cffi_typename_s *typenames;
int num_globals;
int num_struct_unions;
int num_enums;
int num_typenames;
const char *const *includes;
int num_types;
int flags; /* future extension */
};
struct _cffi_parse_info_s {
const struct _cffi_type_context_s *ctx;
_cffi_opcode_t *output;
unsigned int output_size;
size_t error_location;
const char *error_message;
};
#ifdef _CFFI_INTERNAL
static int parse_c_type(struct _cffi_parse_info_s *info, const char *input);
static int search_in_globals(const struct _cffi_type_context_s *ctx,
const char *search, size_t search_len);
static int search_in_struct_unions(const struct _cffi_type_context_s *ctx,
const char *search, size_t search_len);
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,161 @@
import os
try:
basestring
except NameError:
# Python 3.x
basestring = str
def error(msg):
from distutils.errors import DistutilsSetupError
raise DistutilsSetupError(msg)
def execfile(filename, glob):
# We use execfile() (here rewritten for Python 3) instead of
# __import__() to load the build script. The problem with
# a normal import is that in some packages, the intermediate
# __init__.py files may already try to import the file that
# we are generating.
with open(filename) as f:
src = f.read()
src += '\n' # Python 2.6 compatibility
code = compile(src, filename, 'exec')
exec(code, glob, glob)
def add_cffi_module(dist, mod_spec):
from cffi.api import FFI
if not isinstance(mod_spec, basestring):
error("argument to 'cffi_modules=...' must be a str or a list of str,"
" not %r" % (type(mod_spec).__name__,))
mod_spec = str(mod_spec)
try:
build_file_name, ffi_var_name = mod_spec.split(':')
except ValueError:
error("%r must be of the form 'path/build.py:ffi_variable'" %
(mod_spec,))
if not os.path.exists(build_file_name):
ext = ''
rewritten = build_file_name.replace('.', '/') + '.py'
if os.path.exists(rewritten):
ext = ' (rewrite cffi_modules to [%r])' % (
rewritten + ':' + ffi_var_name,)
error("%r does not name an existing file%s" % (build_file_name, ext))
mod_vars = {'__name__': '__cffi__', '__file__': build_file_name}
execfile(build_file_name, mod_vars)
try:
ffi = mod_vars[ffi_var_name]
except KeyError:
error("%r: object %r not found in module" % (mod_spec,
ffi_var_name))
if not isinstance(ffi, FFI):
ffi = ffi() # maybe it's a function instead of directly an ffi
if not isinstance(ffi, FFI):
error("%r is not an FFI instance (got %r)" % (mod_spec,
type(ffi).__name__))
if not hasattr(ffi, '_assigned_source'):
error("%r: the set_source() method was not called" % (mod_spec,))
module_name, source, source_extension, kwds = ffi._assigned_source
if ffi._windows_unicode:
kwds = kwds.copy()
ffi._apply_windows_unicode(kwds)
if source is None:
_add_py_module(dist, ffi, module_name)
else:
_add_c_module(dist, ffi, module_name, source, source_extension, kwds)
def _add_c_module(dist, ffi, module_name, source, source_extension, kwds):
from distutils.core import Extension
from distutils.command.build_ext import build_ext
from distutils.dir_util import mkpath
from distutils import log
from cffi import recompiler
allsources = ['$PLACEHOLDER']
allsources.extend(kwds.pop('sources', []))
ext = Extension(name=module_name, sources=allsources, **kwds)
def make_mod(tmpdir, pre_run=None):
c_file = os.path.join(tmpdir, module_name + source_extension)
log.info("generating cffi module %r" % c_file)
mkpath(tmpdir)
# a setuptools-only, API-only hook: called with the "ext" and "ffi"
# arguments just before we turn the ffi into C code. To use it,
# subclass the 'distutils.command.build_ext.build_ext' class and
# add a method 'def pre_run(self, ext, ffi)'.
if pre_run is not None:
pre_run(ext, ffi)
updated = recompiler.make_c_source(ffi, module_name, source, c_file)
if not updated:
log.info("already up-to-date")
return c_file
if dist.ext_modules is None:
dist.ext_modules = []
dist.ext_modules.append(ext)
base_class = dist.cmdclass.get('build_ext', build_ext)
class build_ext_make_mod(base_class):
def run(self):
if ext.sources[0] == '$PLACEHOLDER':
pre_run = getattr(self, 'pre_run', None)
ext.sources[0] = make_mod(self.build_temp, pre_run)
base_class.run(self)
dist.cmdclass['build_ext'] = build_ext_make_mod
# NB. multiple runs here will create multiple 'build_ext_make_mod'
# classes. Even in this case the 'build_ext' command should be
# run once; but just in case, the logic above does nothing if
# called again.
def _add_py_module(dist, ffi, module_name):
from distutils.dir_util import mkpath
from distutils.command.build_py import build_py
from distutils.command.build_ext import build_ext
from distutils import log
from cffi import recompiler
def generate_mod(py_file):
log.info("generating cffi module %r" % py_file)
mkpath(os.path.dirname(py_file))
updated = recompiler.make_py_source(ffi, module_name, py_file)
if not updated:
log.info("already up-to-date")
base_class = dist.cmdclass.get('build_py', build_py)
class build_py_make_mod(base_class):
def run(self):
base_class.run(self)
module_path = module_name.split('.')
module_path[-1] += '.py'
generate_mod(os.path.join(self.build_lib, *module_path))
dist.cmdclass['build_py'] = build_py_make_mod
# the following is only for "build_ext -i"
base_class_2 = dist.cmdclass.get('build_ext', build_ext)
class build_ext_make_mod(base_class_2):
def run(self):
base_class_2.run(self)
if self.inplace:
# from get_ext_fullpath() in distutils/command/build_ext.py
module_path = module_name.split('.')
package = '.'.join(module_path[:-1])
build_py = self.get_finalized_command('build_py')
package_dir = build_py.get_package_dir(package)
file_name = module_path[-1] + '.py'
generate_mod(os.path.join(package_dir, file_name))
dist.cmdclass['build_ext'] = build_ext_make_mod
def cffi_modules(dist, attr, value):
assert attr == 'cffi_modules'
if isinstance(value, basestring):
value = [value]
for cffi_module in value:
add_cffi_module(dist, cffi_module)

View file

@ -65,7 +65,7 @@ class VCPythonEngine(object):
# The following two 'chained_list_constants' items contains # The following two 'chained_list_constants' items contains
# the head of these two chained lists, as a string that gives the # the head of these two chained lists, as a string that gives the
# call to do, if any. # call to do, if any.
self._chained_list_constants = ['0', '0'] self._chained_list_constants = ['((void)lib,0)', '((void)lib,0)']
# #
prnt = self._prnt prnt = self._prnt
# first paste some standard set of lines that are mostly '#define' # first paste some standard set of lines that are mostly '#define'
@ -138,15 +138,26 @@ class VCPythonEngine(object):
prnt() prnt()
prnt('#endif') prnt('#endif')
def load_library(self): def load_library(self, flags=None):
# XXX review all usages of 'self' here! # XXX review all usages of 'self' here!
# import it as a new extension module # import it as a new extension module
imp.acquire_lock()
try: try:
if hasattr(sys, "getdlopenflags"):
previous_flags = sys.getdlopenflags()
try:
if hasattr(sys, "setdlopenflags") and flags is not None:
sys.setdlopenflags(flags)
module = imp.load_dynamic(self.verifier.get_module_name(), module = imp.load_dynamic(self.verifier.get_module_name(),
self.verifier.modulefilename) self.verifier.modulefilename)
except ImportError as e: except ImportError as e:
error = "importing %r: %s" % (self.verifier.modulefilename, e) error = "importing %r: %s" % (self.verifier.modulefilename, e)
raise ffiplatform.VerificationError(error) raise ffiplatform.VerificationError(error)
finally:
if hasattr(sys, "setdlopenflags"):
sys.setdlopenflags(previous_flags)
finally:
imp.release_lock()
# #
# call loading_cpy_struct() to get the struct layout inferred by # call loading_cpy_struct() to get the struct layout inferred by
# the C compiler # the C compiler
@ -186,7 +197,10 @@ class VCPythonEngine(object):
return library return library
def _get_declarations(self): def _get_declarations(self):
return sorted(self.ffi._parser._declarations.items()) lst = [(key, tp) for (key, (tp, qual)) in
self.ffi._parser._declarations.items()]
lst.sort()
return lst
def _generate(self, step_name): def _generate(self, step_name):
for name, tp in self._get_declarations(): for name, tp in self._get_declarations():
@ -228,7 +242,8 @@ class VCPythonEngine(object):
converter = '_cffi_to_c_int' converter = '_cffi_to_c_int'
extraarg = ', %s' % tp.name extraarg = ', %s' % tp.name
else: else:
converter = '_cffi_to_c_%s' % (tp.name.replace(' ', '_'),) converter = '(%s)_cffi_to_c_%s' % (tp.get_c_name(''),
tp.name.replace(' ', '_'))
errvalue = '-1' errvalue = '-1'
# #
elif isinstance(tp, model.PointerType): elif isinstance(tp, model.PointerType):
@ -267,8 +282,8 @@ class VCPythonEngine(object):
self._prnt(' if (datasize != 0) {') self._prnt(' if (datasize != 0) {')
self._prnt(' if (datasize < 0)') self._prnt(' if (datasize < 0)')
self._prnt(' %s;' % errcode) self._prnt(' %s;' % errcode)
self._prnt(' %s = alloca(datasize);' % (tovar,)) self._prnt(' %s = alloca((size_t)datasize);' % (tovar,))
self._prnt(' memset((void *)%s, 0, datasize);' % (tovar,)) self._prnt(' memset((void *)%s, 0, (size_t)datasize);' % (tovar,))
self._prnt(' if (_cffi_convert_array_from_object(' self._prnt(' if (_cffi_convert_array_from_object('
'(char *)%s, _cffi_type(%d), %s) < 0)' % ( '(char *)%s, _cffi_type(%d), %s) < 0)' % (
tovar, self._gettypenum(tp), fromvar)) tovar, self._gettypenum(tp), fromvar))
@ -336,7 +351,7 @@ class VCPythonEngine(object):
prnt = self._prnt prnt = self._prnt
numargs = len(tp.args) numargs = len(tp.args)
if numargs == 0: if numargs == 0:
argname = 'no_arg' argname = 'noarg'
elif numargs == 1: elif numargs == 1:
argname = 'arg0' argname = 'arg0'
else: else:
@ -386,6 +401,9 @@ class VCPythonEngine(object):
prnt(' Py_END_ALLOW_THREADS') prnt(' Py_END_ALLOW_THREADS')
prnt() prnt()
# #
prnt(' (void)self; /* unused */')
if numargs == 0:
prnt(' (void)noarg; /* unused */')
if result_code: if result_code:
prnt(' return %s;' % prnt(' return %s;' %
self._convert_expr_from_c(tp.result, 'result', 'result type')) self._convert_expr_from_c(tp.result, 'result', 'result type'))
@ -452,7 +470,8 @@ class VCPythonEngine(object):
prnt('static void %s(%s *p)' % (checkfuncname, cname)) prnt('static void %s(%s *p)' % (checkfuncname, cname))
prnt('{') prnt('{')
prnt(' /* only to generate compile-time warnings or errors */') prnt(' /* only to generate compile-time warnings or errors */')
for fname, ftype, fbitsize in tp.enumfields(): prnt(' (void)p;')
for fname, ftype, fbitsize, fqual in tp.enumfields():
if (isinstance(ftype, model.PrimitiveType) if (isinstance(ftype, model.PrimitiveType)
and ftype.is_integer_type()) or fbitsize >= 0: and ftype.is_integer_type()) or fbitsize >= 0:
# accept all integers, but complain on float or double # accept all integers, but complain on float or double
@ -461,7 +480,8 @@ class VCPythonEngine(object):
# only accept exactly the type declared. # only accept exactly the type declared.
try: try:
prnt(' { %s = &p->%s; (void)tmp; }' % ( prnt(' { %s = &p->%s; (void)tmp; }' % (
ftype.get_c_name('*tmp', 'field %r'%fname), fname)) ftype.get_c_name('*tmp', 'field %r'%fname, quals=fqual),
fname))
except ffiplatform.VerificationError as e: except ffiplatform.VerificationError as e:
prnt(' /* %s */' % str(e)) # cannot verify it, ignore prnt(' /* %s */' % str(e)) # cannot verify it, ignore
prnt('}') prnt('}')
@ -472,7 +492,7 @@ class VCPythonEngine(object):
prnt(' static Py_ssize_t nums[] = {') prnt(' static Py_ssize_t nums[] = {')
prnt(' sizeof(%s),' % cname) prnt(' sizeof(%s),' % cname)
prnt(' offsetof(struct _cffi_aligncheck, y),') prnt(' offsetof(struct _cffi_aligncheck, y),')
for fname, ftype, fbitsize in tp.enumfields(): for fname, ftype, fbitsize, fqual in tp.enumfields():
if fbitsize >= 0: if fbitsize >= 0:
continue # xxx ignore fbitsize for now continue # xxx ignore fbitsize for now
prnt(' offsetof(%s, %s),' % (cname, fname)) prnt(' offsetof(%s, %s),' % (cname, fname))
@ -482,6 +502,8 @@ class VCPythonEngine(object):
prnt(' sizeof(((%s *)0)->%s),' % (cname, fname)) prnt(' sizeof(((%s *)0)->%s),' % (cname, fname))
prnt(' -1') prnt(' -1')
prnt(' };') prnt(' };')
prnt(' (void)self; /* unused */')
prnt(' (void)noarg; /* unused */')
prnt(' return _cffi_get_struct_layout(nums);') prnt(' return _cffi_get_struct_layout(nums);')
prnt(' /* the next line is not executed, but compiled */') prnt(' /* the next line is not executed, but compiled */')
prnt(' %s(0);' % (checkfuncname,)) prnt(' %s(0);' % (checkfuncname,))
@ -534,7 +556,7 @@ class VCPythonEngine(object):
check(layout[0], ffi.sizeof(BStruct), "wrong total size") check(layout[0], ffi.sizeof(BStruct), "wrong total size")
check(layout[1], ffi.alignof(BStruct), "wrong total alignment") check(layout[1], ffi.alignof(BStruct), "wrong total alignment")
i = 2 i = 2
for fname, ftype, fbitsize in tp.enumfields(): for fname, ftype, fbitsize, fqual in tp.enumfields():
if fbitsize >= 0: if fbitsize >= 0:
continue # xxx ignore fbitsize for now continue # xxx ignore fbitsize for now
check(layout[i], ffi.offsetof(BStruct, fname), check(layout[i], ffi.offsetof(BStruct, fname),
@ -578,7 +600,8 @@ class VCPythonEngine(object):
# constants, likely declared with '#define' # constants, likely declared with '#define'
def _generate_cpy_const(self, is_int, name, tp=None, category='const', def _generate_cpy_const(self, is_int, name, tp=None, category='const',
vartp=None, delayed=True, size_too=False): vartp=None, delayed=True, size_too=False,
check_value=None):
prnt = self._prnt prnt = self._prnt
funcname = '_cffi_%s_%s' % (category, name) funcname = '_cffi_%s_%s' % (category, name)
prnt('static int %s(PyObject *lib)' % funcname) prnt('static int %s(PyObject *lib)' % funcname)
@ -590,6 +613,9 @@ class VCPythonEngine(object):
else: else:
assert category == 'const' assert category == 'const'
# #
if check_value is not None:
self._check_int_constant_value(name, check_value)
#
if not is_int: if not is_int:
if category == 'var': if category == 'var':
realexpr = '&' + name realexpr = '&' + name
@ -637,6 +663,27 @@ class VCPythonEngine(object):
# ---------- # ----------
# enums # enums
def _check_int_constant_value(self, name, value, err_prefix=''):
prnt = self._prnt
if value <= 0:
prnt(' if ((%s) > 0 || (long)(%s) != %dL) {' % (
name, name, value))
else:
prnt(' if ((%s) <= 0 || (unsigned long)(%s) != %dUL) {' % (
name, name, value))
prnt(' char buf[64];')
prnt(' if ((%s) <= 0)' % name)
prnt(' snprintf(buf, 63, "%%ld", (long)(%s));' % name)
prnt(' else')
prnt(' snprintf(buf, 63, "%%lu", (unsigned long)(%s));' %
name)
prnt(' PyErr_Format(_cffi_VerificationError,')
prnt(' "%s%s has the real value %s, not %s",')
prnt(' "%s", "%s", buf, "%d");' % (
err_prefix, name, value))
prnt(' return -1;')
prnt(' }')
def _enum_funcname(self, prefix, name): def _enum_funcname(self, prefix, name):
# "$enum_$1" => "___D_enum____D_1" # "$enum_$1" => "___D_enum____D_1"
name = name.replace('$', '___D_') name = name.replace('$', '___D_')
@ -653,25 +700,8 @@ class VCPythonEngine(object):
prnt('static int %s(PyObject *lib)' % funcname) prnt('static int %s(PyObject *lib)' % funcname)
prnt('{') prnt('{')
for enumerator, enumvalue in zip(tp.enumerators, tp.enumvalues): for enumerator, enumvalue in zip(tp.enumerators, tp.enumvalues):
if enumvalue < 0: self._check_int_constant_value(enumerator, enumvalue,
prnt(' if ((%s) >= 0 || (long)(%s) != %dL) {' % ( "enum %s: " % name)
enumerator, enumerator, enumvalue))
else:
prnt(' if ((%s) < 0 || (unsigned long)(%s) != %dUL) {' % (
enumerator, enumerator, enumvalue))
prnt(' char buf[64];')
prnt(' if ((%s) < 0)' % enumerator)
prnt(' snprintf(buf, 63, "%%ld", (long)(%s));' % enumerator)
prnt(' else')
prnt(' snprintf(buf, 63, "%%lu", (unsigned long)(%s));' %
enumerator)
prnt(' PyErr_Format(_cffi_VerificationError,')
prnt(' "enum %s: %s has the real value %s, '
'not %s",')
prnt(' "%s", "%s", buf, "%d");' % (
name, enumerator, enumvalue))
prnt(' return -1;')
prnt(' }')
prnt(' return %s;' % self._chained_list_constants[True]) prnt(' return %s;' % self._chained_list_constants[True])
self._chained_list_constants[True] = funcname + '(lib)' self._chained_list_constants[True] = funcname + '(lib)'
prnt('}') prnt('}')
@ -695,8 +725,11 @@ class VCPythonEngine(object):
# macros: for now only for integers # macros: for now only for integers
def _generate_cpy_macro_decl(self, tp, name): def _generate_cpy_macro_decl(self, tp, name):
assert tp == '...' if tp == '...':
self._generate_cpy_const(True, name) check_value = None
else:
check_value = tp # an integer
self._generate_cpy_const(True, name, check_value=check_value)
_generate_cpy_macro_collecttype = _generate_nothing _generate_cpy_macro_collecttype = _generate_nothing
_generate_cpy_macro_method = _generate_nothing _generate_cpy_macro_method = _generate_nothing
@ -783,6 +816,24 @@ cffimod_header = r'''
typedef unsigned __int16 uint16_t; typedef unsigned __int16 uint16_t;
typedef unsigned __int32 uint32_t; typedef unsigned __int32 uint32_t;
typedef unsigned __int64 uint64_t; typedef unsigned __int64 uint64_t;
typedef __int8 int_least8_t;
typedef __int16 int_least16_t;
typedef __int32 int_least32_t;
typedef __int64 int_least64_t;
typedef unsigned __int8 uint_least8_t;
typedef unsigned __int16 uint_least16_t;
typedef unsigned __int32 uint_least32_t;
typedef unsigned __int64 uint_least64_t;
typedef __int8 int_fast8_t;
typedef __int16 int_fast16_t;
typedef __int32 int_fast32_t;
typedef __int64 int_fast64_t;
typedef unsigned __int8 uint_fast8_t;
typedef unsigned __int16 uint_fast16_t;
typedef unsigned __int32 uint_fast32_t;
typedef unsigned __int64 uint_fast64_t;
typedef __int64 intmax_t;
typedef unsigned __int64 uintmax_t;
# else # else
# include <stdint.h> # include <stdint.h>
# endif # endif
@ -829,14 +880,18 @@ cffimod_header = r'''
#define _cffi_from_c_int(x, type) \ #define _cffi_from_c_int(x, type) \
(((type)-1) > 0 ? /* unsigned */ \ (((type)-1) > 0 ? /* unsigned */ \
(sizeof(type) < sizeof(long) ? PyInt_FromLong(x) : \ (sizeof(type) < sizeof(long) ? \
sizeof(type) == sizeof(long) ? PyLong_FromUnsignedLong(x) : \ PyInt_FromLong((long)x) : \
PyLong_FromUnsignedLongLong(x)) \ sizeof(type) == sizeof(long) ? \
: (sizeof(type) <= sizeof(long) ? PyInt_FromLong(x) : \ PyLong_FromUnsignedLong((unsigned long)x) : \
PyLong_FromLongLong(x))) PyLong_FromUnsignedLongLong((unsigned long long)x)) : \
(sizeof(type) <= sizeof(long) ? \
PyInt_FromLong((long)x) : \
PyLong_FromLongLong((long long)x)))
#define _cffi_to_c_int(o, type) \ #define _cffi_to_c_int(o, type) \
(sizeof(type) == 1 ? (((type)-1) > 0 ? (type)_cffi_to_c_u8(o) \ ((type)( \
sizeof(type) == 1 ? (((type)-1) > 0 ? (type)_cffi_to_c_u8(o) \
: (type)_cffi_to_c_i8(o)) : \ : (type)_cffi_to_c_i8(o)) : \
sizeof(type) == 2 ? (((type)-1) > 0 ? (type)_cffi_to_c_u16(o) \ sizeof(type) == 2 ? (((type)-1) > 0 ? (type)_cffi_to_c_u16(o) \
: (type)_cffi_to_c_i16(o)) : \ : (type)_cffi_to_c_i16(o)) : \
@ -844,7 +899,7 @@ cffimod_header = r'''
: (type)_cffi_to_c_i32(o)) : \ : (type)_cffi_to_c_i32(o)) : \
sizeof(type) == 8 ? (((type)-1) > 0 ? (type)_cffi_to_c_u64(o) \ sizeof(type) == 8 ? (((type)-1) > 0 ? (type)_cffi_to_c_u64(o) \
: (type)_cffi_to_c_i64(o)) : \ : (type)_cffi_to_c_i64(o)) : \
(Py_FatalError("unsupported size for type " #type), 0)) (Py_FatalError("unsupported size for type " #type), (type)0)))
#define _cffi_to_c_i8 \ #define _cffi_to_c_i8 \
((int(*)(PyObject *))_cffi_exports[1]) ((int(*)(PyObject *))_cffi_exports[1])
@ -907,6 +962,7 @@ static PyObject *_cffi_setup(PyObject *self, PyObject *args)
{ {
PyObject *library; PyObject *library;
int was_alive = (_cffi_types != NULL); int was_alive = (_cffi_types != NULL);
(void)self; /* unused */
if (!PyArg_ParseTuple(args, "OOO", &_cffi_types, &_cffi_VerificationError, if (!PyArg_ParseTuple(args, "OOO", &_cffi_types, &_cffi_VerificationError,
&library)) &library))
return NULL; return NULL;

View file

@ -58,12 +58,12 @@ class VGenericEngine(object):
modname = self.verifier.get_module_name() modname = self.verifier.get_module_name()
prnt("void %s%s(void) { }\n" % (prefix, modname)) prnt("void %s%s(void) { }\n" % (prefix, modname))
def load_library(self): def load_library(self, flags=0):
# import it with the CFFI backend # import it with the CFFI backend
backend = self.ffi._backend backend = self.ffi._backend
# needs to make a path that contains '/', on Posix # needs to make a path that contains '/', on Posix
filename = os.path.join(os.curdir, self.verifier.modulefilename) filename = os.path.join(os.curdir, self.verifier.modulefilename)
module = backend.load_library(filename) module = backend.load_library(filename, flags)
# #
# call loading_gen_struct() to get the struct layout inferred by # call loading_gen_struct() to get the struct layout inferred by
# the C compiler # the C compiler
@ -87,7 +87,10 @@ class VGenericEngine(object):
return library return library
def _get_declarations(self): def _get_declarations(self):
return sorted(self.ffi._parser._declarations.items()) lst = [(key, tp) for (key, (tp, qual)) in
self.ffi._parser._declarations.items()]
lst.sort()
return lst
def _generate(self, step_name): def _generate(self, step_name):
for name, tp in self._get_declarations(): for name, tp in self._get_declarations():
@ -149,15 +152,25 @@ class VGenericEngine(object):
context = 'argument of %s' % name context = 'argument of %s' % name
arglist = [type.get_c_name(' %s' % arg, context) arglist = [type.get_c_name(' %s' % arg, context)
for type, arg in zip(tp.args, argnames)] for type, arg in zip(tp.args, argnames)]
tpresult = tp.result
if isinstance(tpresult, model.StructOrUnion):
arglist.insert(0, tpresult.get_c_name(' *r', context))
tpresult = model.void_type
arglist = ', '.join(arglist) or 'void' arglist = ', '.join(arglist) or 'void'
wrappername = '_cffi_f_%s' % name wrappername = '_cffi_f_%s' % name
self.export_symbols.append(wrappername) self.export_symbols.append(wrappername)
funcdecl = ' %s(%s)' % (wrappername, arglist) if tp.abi:
abi = tp.abi + ' '
else:
abi = ''
funcdecl = ' %s%s(%s)' % (abi, wrappername, arglist)
context = 'result of %s' % name context = 'result of %s' % name
prnt(tp.result.get_c_name(funcdecl, context)) prnt(tpresult.get_c_name(funcdecl, context))
prnt('{') prnt('{')
# #
if not isinstance(tp.result, model.VoidType): if isinstance(tp.result, model.StructOrUnion):
result_code = '*r = '
elif not isinstance(tp.result, model.VoidType):
result_code = 'return ' result_code = 'return '
else: else:
result_code = '' result_code = ''
@ -174,15 +187,26 @@ class VGenericEngine(object):
else: else:
indirections = [] indirections = []
base_tp = tp base_tp = tp
if any(isinstance(typ, model.StructOrUnion) for typ in tp.args): if (any(isinstance(typ, model.StructOrUnion) for typ in tp.args)
or isinstance(tp.result, model.StructOrUnion)):
indirect_args = [] indirect_args = []
for i, typ in enumerate(tp.args): for i, typ in enumerate(tp.args):
if isinstance(typ, model.StructOrUnion): if isinstance(typ, model.StructOrUnion):
typ = model.PointerType(typ) typ = model.PointerType(typ)
indirections.append((i, typ)) indirections.append((i, typ))
indirect_args.append(typ) indirect_args.append(typ)
indirect_result = tp.result
if isinstance(indirect_result, model.StructOrUnion):
if indirect_result.fldtypes is None:
raise TypeError("'%s' is used as result type, "
"but is opaque" % (
indirect_result._get_c_name(),))
indirect_result = model.PointerType(indirect_result)
indirect_args.insert(0, indirect_result)
indirections.insert(0, ("result", indirect_result))
indirect_result = model.void_type
tp = model.FunctionPtrType(tuple(indirect_args), tp = model.FunctionPtrType(tuple(indirect_args),
tp.result, tp.ellipsis) indirect_result, tp.ellipsis)
BFunc = self.ffi._get_cached_btype(tp) BFunc = self.ffi._get_cached_btype(tp)
wrappername = '_cffi_f_%s' % name wrappername = '_cffi_f_%s' % name
newfunction = module.load_function(BFunc, wrappername) newfunction = module.load_function(BFunc, wrappername)
@ -195,6 +219,13 @@ class VGenericEngine(object):
def _make_struct_wrapper(self, oldfunc, i, tp, base_tp): def _make_struct_wrapper(self, oldfunc, i, tp, base_tp):
backend = self.ffi._backend backend = self.ffi._backend
BType = self.ffi._get_cached_btype(tp) BType = self.ffi._get_cached_btype(tp)
if i == "result":
ffi = self.ffi
def newfunc(*args):
res = ffi.new(BType)
oldfunc(res, *args)
return res[0]
else:
def newfunc(*args): def newfunc(*args):
args = args[:i] + (backend.newp(BType, args[i]),) + args[i+1:] args = args[:i] + (backend.newp(BType, args[i]),) + args[i+1:]
return oldfunc(*args) return oldfunc(*args)
@ -235,7 +266,8 @@ class VGenericEngine(object):
prnt('static void %s(%s *p)' % (checkfuncname, cname)) prnt('static void %s(%s *p)' % (checkfuncname, cname))
prnt('{') prnt('{')
prnt(' /* only to generate compile-time warnings or errors */') prnt(' /* only to generate compile-time warnings or errors */')
for fname, ftype, fbitsize in tp.enumfields(): prnt(' (void)p;')
for fname, ftype, fbitsize, fqual in tp.enumfields():
if (isinstance(ftype, model.PrimitiveType) if (isinstance(ftype, model.PrimitiveType)
and ftype.is_integer_type()) or fbitsize >= 0: and ftype.is_integer_type()) or fbitsize >= 0:
# accept all integers, but complain on float or double # accept all integers, but complain on float or double
@ -244,7 +276,8 @@ class VGenericEngine(object):
# only accept exactly the type declared. # only accept exactly the type declared.
try: try:
prnt(' { %s = &p->%s; (void)tmp; }' % ( prnt(' { %s = &p->%s; (void)tmp; }' % (
ftype.get_c_name('*tmp', 'field %r'%fname), fname)) ftype.get_c_name('*tmp', 'field %r'%fname, quals=fqual),
fname))
except ffiplatform.VerificationError as e: except ffiplatform.VerificationError as e:
prnt(' /* %s */' % str(e)) # cannot verify it, ignore prnt(' /* %s */' % str(e)) # cannot verify it, ignore
prnt('}') prnt('}')
@ -255,7 +288,7 @@ class VGenericEngine(object):
prnt(' static intptr_t nums[] = {') prnt(' static intptr_t nums[] = {')
prnt(' sizeof(%s),' % cname) prnt(' sizeof(%s),' % cname)
prnt(' offsetof(struct _cffi_aligncheck, y),') prnt(' offsetof(struct _cffi_aligncheck, y),')
for fname, ftype, fbitsize in tp.enumfields(): for fname, ftype, fbitsize, fqual in tp.enumfields():
if fbitsize >= 0: if fbitsize >= 0:
continue # xxx ignore fbitsize for now continue # xxx ignore fbitsize for now
prnt(' offsetof(%s, %s),' % (cname, fname)) prnt(' offsetof(%s, %s),' % (cname, fname))
@ -317,7 +350,7 @@ class VGenericEngine(object):
check(layout[0], ffi.sizeof(BStruct), "wrong total size") check(layout[0], ffi.sizeof(BStruct), "wrong total size")
check(layout[1], ffi.alignof(BStruct), "wrong total alignment") check(layout[1], ffi.alignof(BStruct), "wrong total alignment")
i = 2 i = 2
for fname, ftype, fbitsize in tp.enumfields(): for fname, ftype, fbitsize, fqual in tp.enumfields():
if fbitsize >= 0: if fbitsize >= 0:
continue # xxx ignore fbitsize for now continue # xxx ignore fbitsize for now
check(layout[i], ffi.offsetof(BStruct, fname), check(layout[i], ffi.offsetof(BStruct, fname),
@ -354,11 +387,20 @@ class VGenericEngine(object):
# ---------- # ----------
# constants, likely declared with '#define' # constants, likely declared with '#define'
def _generate_gen_const(self, is_int, name, tp=None, category='const'): def _generate_gen_const(self, is_int, name, tp=None, category='const',
check_value=None):
prnt = self._prnt prnt = self._prnt
funcname = '_cffi_%s_%s' % (category, name) funcname = '_cffi_%s_%s' % (category, name)
self.export_symbols.append(funcname) self.export_symbols.append(funcname)
if is_int: if check_value is not None:
assert is_int
assert category == 'const'
prnt('int %s(char *out_error)' % funcname)
prnt('{')
self._check_int_constant_value(name, check_value)
prnt(' return 0;')
prnt('}')
elif is_int:
assert category == 'const' assert category == 'const'
prnt('int %s(long long *out_value)' % funcname) prnt('int %s(long long *out_value)' % funcname)
prnt('{') prnt('{')
@ -367,12 +409,17 @@ class VGenericEngine(object):
prnt('}') prnt('}')
else: else:
assert tp is not None assert tp is not None
prnt(tp.get_c_name(' %s(void)' % funcname, name),) assert check_value is None
prnt('{')
if category == 'var': if category == 'var':
ampersand = '&' ampersand = '&'
else: else:
ampersand = '' ampersand = ''
extra = ''
if category == 'const' and isinstance(tp, model.StructOrUnion):
extra = 'const *'
ampersand = '&'
prnt(tp.get_c_name(' %s%s(void)' % (extra, funcname), name))
prnt('{')
prnt(' return (%s%s);' % (ampersand, name)) prnt(' return (%s%s);' % (ampersand, name))
prnt('}') prnt('}')
prnt() prnt()
@ -383,9 +430,13 @@ class VGenericEngine(object):
_loading_gen_constant = _loaded_noop _loading_gen_constant = _loaded_noop
def _load_constant(self, is_int, tp, name, module): def _load_constant(self, is_int, tp, name, module, check_value=None):
funcname = '_cffi_const_%s' % name funcname = '_cffi_const_%s' % name
if is_int: if check_value is not None:
assert is_int
self._load_known_int_constant(module, funcname)
value = check_value
elif is_int:
BType = self.ffi._typeof_locked("long long*")[0] BType = self.ffi._typeof_locked("long long*")[0]
BFunc = self.ffi._typeof_locked("int(*)(long long*)")[0] BFunc = self.ffi._typeof_locked("int(*)(long long*)")[0]
function = module.load_function(BFunc, funcname) function = module.load_function(BFunc, funcname)
@ -396,9 +447,15 @@ class VGenericEngine(object):
BLongLong = self.ffi._typeof_locked("long long")[0] BLongLong = self.ffi._typeof_locked("long long")[0]
value += (1 << (8*self.ffi.sizeof(BLongLong))) value += (1 << (8*self.ffi.sizeof(BLongLong)))
else: else:
BFunc = self.ffi._typeof_locked(tp.get_c_name('(*)(void)', name))[0] assert check_value is None
fntypeextra = '(*)(void)'
if isinstance(tp, model.StructOrUnion):
fntypeextra = '*' + fntypeextra
BFunc = self.ffi._typeof_locked(tp.get_c_name(fntypeextra, name))[0]
function = module.load_function(BFunc, funcname) function = module.load_function(BFunc, funcname)
value = function() value = function()
if isinstance(tp, model.StructOrUnion):
value = value[0]
return value return value
def _loaded_gen_constant(self, tp, name, module, library): def _loaded_gen_constant(self, tp, name, module, library):
@ -410,6 +467,36 @@ class VGenericEngine(object):
# ---------- # ----------
# enums # enums
def _check_int_constant_value(self, name, value):
prnt = self._prnt
if value <= 0:
prnt(' if ((%s) > 0 || (long)(%s) != %dL) {' % (
name, name, value))
else:
prnt(' if ((%s) <= 0 || (unsigned long)(%s) != %dUL) {' % (
name, name, value))
prnt(' char buf[64];')
prnt(' if ((%s) <= 0)' % name)
prnt(' sprintf(buf, "%%ld", (long)(%s));' % name)
prnt(' else')
prnt(' sprintf(buf, "%%lu", (unsigned long)(%s));' %
name)
prnt(' sprintf(out_error, "%s has the real value %s, not %s",')
prnt(' "%s", buf, "%d");' % (name[:100], value))
prnt(' return -1;')
prnt(' }')
def _load_known_int_constant(self, module, funcname):
BType = self.ffi._typeof_locked("char[]")[0]
BFunc = self.ffi._typeof_locked("int(*)(char*)")[0]
function = module.load_function(BFunc, funcname)
p = self.ffi.new(BType, 256)
if function(p) < 0:
error = self.ffi.string(p)
if sys.version_info >= (3,):
error = str(error, 'utf-8')
raise ffiplatform.VerificationError(error)
def _enum_funcname(self, prefix, name): def _enum_funcname(self, prefix, name):
# "$enum_$1" => "___D_enum____D_1" # "$enum_$1" => "___D_enum____D_1"
name = name.replace('$', '___D_') name = name.replace('$', '___D_')
@ -427,24 +514,7 @@ class VGenericEngine(object):
prnt('int %s(char *out_error)' % funcname) prnt('int %s(char *out_error)' % funcname)
prnt('{') prnt('{')
for enumerator, enumvalue in zip(tp.enumerators, tp.enumvalues): for enumerator, enumvalue in zip(tp.enumerators, tp.enumvalues):
if enumvalue < 0: self._check_int_constant_value(enumerator, enumvalue)
prnt(' if ((%s) >= 0 || (long)(%s) != %dL) {' % (
enumerator, enumerator, enumvalue))
else:
prnt(' if ((%s) < 0 || (unsigned long)(%s) != %dUL) {' % (
enumerator, enumerator, enumvalue))
prnt(' char buf[64];')
prnt(' if ((%s) < 0)' % enumerator)
prnt(' sprintf(buf, "%%ld", (long)(%s));' % enumerator)
prnt(' else')
prnt(' sprintf(buf, "%%lu", (unsigned long)(%s));' %
enumerator)
prnt(' sprintf(out_error,'
' "%s has the real value %s, not %s",')
prnt(' "%s", buf, "%d");' % (
enumerator[:100], enumvalue))
prnt(' return -1;')
prnt(' }')
prnt(' return 0;') prnt(' return 0;')
prnt('}') prnt('}')
prnt() prnt()
@ -456,16 +526,8 @@ class VGenericEngine(object):
tp.enumvalues = tuple(enumvalues) tp.enumvalues = tuple(enumvalues)
tp.partial_resolved = True tp.partial_resolved = True
else: else:
BType = self.ffi._typeof_locked("char[]")[0]
BFunc = self.ffi._typeof_locked("int(*)(char*)")[0]
funcname = self._enum_funcname(prefix, name) funcname = self._enum_funcname(prefix, name)
function = module.load_function(BFunc, funcname) self._load_known_int_constant(module, funcname)
p = self.ffi.new(BType, 256)
if function(p) < 0:
error = self.ffi.string(p)
if sys.version_info >= (3,):
error = str(error, 'utf-8')
raise ffiplatform.VerificationError(error)
def _loaded_gen_enum(self, tp, name, module, library): def _loaded_gen_enum(self, tp, name, module, library):
for enumerator, enumvalue in zip(tp.enumerators, tp.enumvalues): for enumerator, enumvalue in zip(tp.enumerators, tp.enumvalues):
@ -476,13 +538,21 @@ class VGenericEngine(object):
# macros: for now only for integers # macros: for now only for integers
def _generate_gen_macro_decl(self, tp, name): def _generate_gen_macro_decl(self, tp, name):
assert tp == '...' if tp == '...':
self._generate_gen_const(True, name) check_value = None
else:
check_value = tp # an integer
self._generate_gen_const(True, name, check_value=check_value)
_loading_gen_macro = _loaded_noop _loading_gen_macro = _loaded_noop
def _loaded_gen_macro(self, tp, name, module, library): def _loaded_gen_macro(self, tp, name, module, library):
value = self._load_constant(True, tp, name, module) if tp == '...':
check_value = None
else:
check_value = tp # an integer
value = self._load_constant(True, tp, name, module,
check_value=check_value)
setattr(library, name, value) setattr(library, name, value)
type(library)._cffi_dir.append(name) type(library)._cffi_dir.append(name)
@ -565,6 +635,24 @@ cffimod_header = r'''
typedef unsigned __int16 uint16_t; typedef unsigned __int16 uint16_t;
typedef unsigned __int32 uint32_t; typedef unsigned __int32 uint32_t;
typedef unsigned __int64 uint64_t; typedef unsigned __int64 uint64_t;
typedef __int8 int_least8_t;
typedef __int16 int_least16_t;
typedef __int32 int_least32_t;
typedef __int64 int_least64_t;
typedef unsigned __int8 uint_least8_t;
typedef unsigned __int16 uint_least16_t;
typedef unsigned __int32 uint_least32_t;
typedef unsigned __int64 uint_least64_t;
typedef __int8 int_fast8_t;
typedef __int16 int_fast16_t;
typedef __int32 int_fast32_t;
typedef __int64 int_fast64_t;
typedef unsigned __int8 uint_fast8_t;
typedef unsigned __int16 uint_fast16_t;
typedef unsigned __int32 uint_fast32_t;
typedef unsigned __int64 uint_fast64_t;
typedef __int64 intmax_t;
typedef unsigned __int64 uintmax_t;
# else # else
# include <stdint.h> # include <stdint.h>
# endif # endif

View file

@ -1,12 +1,47 @@
import sys, os, binascii, imp, shutil import sys, os, binascii, shutil, io
from . import __version__ from . import __version_verifier_modules__
from . import ffiplatform from . import ffiplatform
if sys.version_info >= (3, 3):
import importlib.machinery
def _extension_suffixes():
return importlib.machinery.EXTENSION_SUFFIXES[:]
else:
import imp
def _extension_suffixes():
return [suffix for suffix, _, type in imp.get_suffixes()
if type == imp.C_EXTENSION]
if sys.version_info >= (3,):
NativeIO = io.StringIO
else:
class NativeIO(io.BytesIO):
def write(self, s):
if isinstance(s, unicode):
s = s.encode('ascii')
super(NativeIO, self).write(s)
def _hack_at_distutils():
# Windows-only workaround for some configurations: see
# https://bugs.python.org/issue23246 (Python 2.7 with
# a specific MS compiler suite download)
if sys.platform == "win32":
try:
import setuptools # for side-effects, patches distutils
except ImportError:
pass
class Verifier(object): class Verifier(object):
def __init__(self, ffi, preamble, tmpdir=None, modulename=None, def __init__(self, ffi, preamble, tmpdir=None, modulename=None,
ext_package=None, tag='', force_generic_engine=False, **kwds): ext_package=None, tag='', force_generic_engine=False,
source_extension='.c', flags=None, relative_to=None, **kwds):
if ffi._parser._uses_new_feature:
raise ffiplatform.VerificationError(
"feature not supported with ffi.verify(), but only "
"with ffi.set_source(): %s" % (ffi._parser._uses_new_feature,))
self.ffi = ffi self.ffi = ffi
self.preamble = preamble self.preamble = preamble
if not modulename: if not modulename:
@ -14,14 +49,15 @@ class Verifier(object):
vengine_class = _locate_engine_class(ffi, force_generic_engine) vengine_class = _locate_engine_class(ffi, force_generic_engine)
self._vengine = vengine_class(self) self._vengine = vengine_class(self)
self._vengine.patch_extension_kwds(kwds) self._vengine.patch_extension_kwds(kwds)
self.kwds = kwds self.flags = flags
self.kwds = self.make_relative_to(kwds, relative_to)
# #
if modulename: if modulename:
if tag: if tag:
raise TypeError("can't specify both 'modulename' and 'tag'") raise TypeError("can't specify both 'modulename' and 'tag'")
else: else:
key = '\x00'.join([sys.version[:3], __version__, preamble, key = '\x00'.join([sys.version[:3], __version_verifier_modules__,
flattened_kwds] + preamble, flattened_kwds] +
ffi._cdefsources) ffi._cdefsources)
if sys.version_info >= (3,): if sys.version_info >= (3,):
key = key.encode('utf-8') key = key.encode('utf-8')
@ -33,7 +69,7 @@ class Verifier(object):
k1, k2) k1, k2)
suffix = _get_so_suffixes()[0] suffix = _get_so_suffixes()[0]
self.tmpdir = tmpdir or _caller_dir_pycache() self.tmpdir = tmpdir or _caller_dir_pycache()
self.sourcefilename = os.path.join(self.tmpdir, modulename + '.c') self.sourcefilename = os.path.join(self.tmpdir, modulename + source_extension)
self.modulefilename = os.path.join(self.tmpdir, modulename + suffix) self.modulefilename = os.path.join(self.tmpdir, modulename + suffix)
self.ext_package = ext_package self.ext_package = ext_package
self._has_source = False self._has_source = False
@ -86,6 +122,7 @@ class Verifier(object):
return basename return basename
def get_extension(self): def get_extension(self):
_hack_at_distutils() # backward compatibility hack
if not self._has_source: if not self._has_source:
with self.ffi._lock: with self.ffi._lock:
if not self._has_source: if not self._has_source:
@ -97,6 +134,20 @@ class Verifier(object):
def generates_python_module(self): def generates_python_module(self):
return self._vengine._gen_python_module return self._vengine._gen_python_module
def make_relative_to(self, kwds, relative_to):
if relative_to and os.path.dirname(relative_to):
dirname = os.path.dirname(relative_to)
kwds = kwds.copy()
for key in ffiplatform.LIST_OF_FILE_NAMES:
if key in kwds:
lst = kwds[key]
if not isinstance(lst, (list, tuple)):
raise TypeError("keyword '%s' should be a list or tuple"
% (key,))
lst = [os.path.join(dirname, fn) for fn in lst]
kwds[key] = lst
return kwds
# ---------- # ----------
def _locate_module(self): def _locate_module(self):
@ -118,19 +169,36 @@ class Verifier(object):
self._vengine.collect_types() self._vengine.collect_types()
self._has_module = True self._has_module = True
def _write_source(self, file=None): def _write_source_to(self, file):
must_close = (file is None)
if must_close:
_ensure_dir(self.sourcefilename)
file = open(self.sourcefilename, 'w')
self._vengine._f = file self._vengine._f = file
try: try:
self._vengine.write_source_to_f() self._vengine.write_source_to_f()
finally: finally:
del self._vengine._f del self._vengine._f
if must_close:
file.close() def _write_source(self, file=None):
if must_close: if file is not None:
self._write_source_to(file)
else:
# Write our source file to an in memory file.
f = NativeIO()
self._write_source_to(f)
source_data = f.getvalue()
# Determine if this matches the current file
if os.path.exists(self.sourcefilename):
with open(self.sourcefilename, "r") as fp:
needs_written = not (fp.read() == source_data)
else:
needs_written = True
# Actually write the file out if it doesn't match
if needs_written:
_ensure_dir(self.sourcefilename)
with open(self.sourcefilename, "w") as fp:
fp.write(source_data)
# Set this flag
self._has_source = True self._has_source = True
def _compile_module(self): def _compile_module(self):
@ -148,6 +216,9 @@ class Verifier(object):
def _load_library(self): def _load_library(self):
assert self._has_module assert self._has_module
if self.flags is not None:
return self._vengine.load_library(self.flags)
else:
return self._vengine.load_library() return self._vengine.load_library()
# ____________________________________________________________ # ____________________________________________________________
@ -181,6 +252,9 @@ _TMPDIR = None
def _caller_dir_pycache(): def _caller_dir_pycache():
if _TMPDIR: if _TMPDIR:
return _TMPDIR return _TMPDIR
result = os.environ.get('CFFI_TMPDIR')
if result:
return result
filename = sys._getframe(2).f_code.co_filename filename = sys._getframe(2).f_code.co_filename
return os.path.abspath(os.path.join(os.path.dirname(filename), return os.path.abspath(os.path.join(os.path.dirname(filename),
'__pycache__')) '__pycache__'))
@ -222,11 +296,7 @@ def cleanup_tmpdir(tmpdir=None, keep_so=False):
pass pass
def _get_so_suffixes(): def _get_so_suffixes():
suffixes = [] suffixes = _extension_suffixes()
for suffix, mode, type in imp.get_suffixes():
if type == imp.C_EXTENSION:
suffixes.append(suffix)
if not suffixes: if not suffixes:
# bah, no C_EXTENSION available. Occurs on pypy without cpyext # bah, no C_EXTENSION available. Occurs on pypy without cpyext
if sys.platform == 'win32': if sys.platform == 'win32':

View file

@ -1,217 +0,0 @@
AUTHORS.rst
CHANGELOG.rst
CONTRIBUTING.rst
LICENSE
MANIFEST.in
README.rst
setup.cfg
setup.py
cryptography/__about__.py
cryptography/__init__.py
cryptography/exceptions.py
cryptography/fernet.py
cryptography/utils.py
cryptography.egg-info/PKG-INFO
cryptography.egg-info/SOURCES.txt
cryptography.egg-info/dependency_links.txt
cryptography.egg-info/entry_points.txt
cryptography.egg-info/not-zip-safe
cryptography.egg-info/requires.txt
cryptography.egg-info/top_level.txt
cryptography/hazmat/__init__.py
cryptography/hazmat/backends/__init__.py
cryptography/hazmat/backends/interfaces.py
cryptography/hazmat/backends/multibackend.py
cryptography/hazmat/backends/commoncrypto/__init__.py
cryptography/hazmat/backends/commoncrypto/backend.py
cryptography/hazmat/backends/commoncrypto/ciphers.py
cryptography/hazmat/backends/commoncrypto/hashes.py
cryptography/hazmat/backends/commoncrypto/hmac.py
cryptography/hazmat/backends/openssl/__init__.py
cryptography/hazmat/backends/openssl/backend.py
cryptography/hazmat/backends/openssl/ciphers.py
cryptography/hazmat/backends/openssl/cmac.py
cryptography/hazmat/backends/openssl/dsa.py
cryptography/hazmat/backends/openssl/ec.py
cryptography/hazmat/backends/openssl/hashes.py
cryptography/hazmat/backends/openssl/hmac.py
cryptography/hazmat/backends/openssl/rsa.py
cryptography/hazmat/bindings/__init__.py
cryptography/hazmat/bindings/utils.py
cryptography/hazmat/bindings/__pycache__/_Cryptography_cffi_3e31f141x4000d087.c
cryptography/hazmat/bindings/commoncrypto/__init__.py
cryptography/hazmat/bindings/commoncrypto/binding.py
cryptography/hazmat/bindings/commoncrypto/cf.py
cryptography/hazmat/bindings/commoncrypto/common_cryptor.py
cryptography/hazmat/bindings/commoncrypto/common_digest.py
cryptography/hazmat/bindings/commoncrypto/common_hmac.py
cryptography/hazmat/bindings/commoncrypto/common_key_derivation.py
cryptography/hazmat/bindings/commoncrypto/secimport.py
cryptography/hazmat/bindings/commoncrypto/secitem.py
cryptography/hazmat/bindings/commoncrypto/seckey.py
cryptography/hazmat/bindings/commoncrypto/seckeychain.py
cryptography/hazmat/bindings/commoncrypto/sectransform.py
cryptography/hazmat/bindings/openssl/__init__.py
cryptography/hazmat/bindings/openssl/aes.py
cryptography/hazmat/bindings/openssl/asn1.py
cryptography/hazmat/bindings/openssl/bignum.py
cryptography/hazmat/bindings/openssl/binding.py
cryptography/hazmat/bindings/openssl/bio.py
cryptography/hazmat/bindings/openssl/cmac.py
cryptography/hazmat/bindings/openssl/cms.py
cryptography/hazmat/bindings/openssl/conf.py
cryptography/hazmat/bindings/openssl/crypto.py
cryptography/hazmat/bindings/openssl/dh.py
cryptography/hazmat/bindings/openssl/dsa.py
cryptography/hazmat/bindings/openssl/ec.py
cryptography/hazmat/bindings/openssl/ecdh.py
cryptography/hazmat/bindings/openssl/ecdsa.py
cryptography/hazmat/bindings/openssl/engine.py
cryptography/hazmat/bindings/openssl/err.py
cryptography/hazmat/bindings/openssl/evp.py
cryptography/hazmat/bindings/openssl/hmac.py
cryptography/hazmat/bindings/openssl/nid.py
cryptography/hazmat/bindings/openssl/objects.py
cryptography/hazmat/bindings/openssl/opensslv.py
cryptography/hazmat/bindings/openssl/osrandom_engine.py
cryptography/hazmat/bindings/openssl/pem.py
cryptography/hazmat/bindings/openssl/pkcs12.py
cryptography/hazmat/bindings/openssl/pkcs7.py
cryptography/hazmat/bindings/openssl/rand.py
cryptography/hazmat/bindings/openssl/rsa.py
cryptography/hazmat/bindings/openssl/ssl.py
cryptography/hazmat/bindings/openssl/x509.py
cryptography/hazmat/bindings/openssl/x509_vfy.py
cryptography/hazmat/bindings/openssl/x509name.py
cryptography/hazmat/bindings/openssl/x509v3.py
cryptography/hazmat/primitives/__init__.py
cryptography/hazmat/primitives/cmac.py
cryptography/hazmat/primitives/constant_time.py
cryptography/hazmat/primitives/hashes.py
cryptography/hazmat/primitives/hmac.py
cryptography/hazmat/primitives/interfaces.py
cryptography/hazmat/primitives/padding.py
cryptography/hazmat/primitives/serialization.py
cryptography/hazmat/primitives/__pycache__/_Cryptography_cffi_7ab3712bx4f158fee.c
cryptography/hazmat/primitives/__pycache__/_Cryptography_cffi_dd416c1exc1767c5a.c
cryptography/hazmat/primitives/asymmetric/__init__.py
cryptography/hazmat/primitives/asymmetric/dsa.py
cryptography/hazmat/primitives/asymmetric/ec.py
cryptography/hazmat/primitives/asymmetric/padding.py
cryptography/hazmat/primitives/asymmetric/rsa.py
cryptography/hazmat/primitives/ciphers/__init__.py
cryptography/hazmat/primitives/ciphers/algorithms.py
cryptography/hazmat/primitives/ciphers/base.py
cryptography/hazmat/primitives/ciphers/modes.py
cryptography/hazmat/primitives/kdf/__init__.py
cryptography/hazmat/primitives/kdf/hkdf.py
cryptography/hazmat/primitives/kdf/pbkdf2.py
cryptography/hazmat/primitives/src/constant_time.c
cryptography/hazmat/primitives/src/constant_time.h
cryptography/hazmat/primitives/twofactor/__init__.py
cryptography/hazmat/primitives/twofactor/hotp.py
cryptography/hazmat/primitives/twofactor/totp.py
docs/Makefile
docs/api-stability.rst
docs/changelog.rst
docs/community.rst
docs/conf.py
docs/cryptography-docs.py
docs/doing-a-release.rst
docs/exceptions.rst
docs/faq.rst
docs/fernet.rst
docs/glossary.rst
docs/index.rst
docs/installation.rst
docs/limitations.rst
docs/make.bat
docs/random-numbers.rst
docs/security.rst
docs/spelling_wordlist.txt
docs/_static/.keep
docs/development/c-bindings.rst
docs/development/getting-started.rst
docs/development/index.rst
docs/development/reviewing-patches.rst
docs/development/submitting-patches.rst
docs/development/test-vectors.rst
docs/development/custom-vectors/cast5.rst
docs/development/custom-vectors/idea.rst
docs/development/custom-vectors/seed.rst
docs/development/custom-vectors/cast5/generate_cast5.py
docs/development/custom-vectors/cast5/verify_cast5.go
docs/development/custom-vectors/idea/generate_idea.py
docs/development/custom-vectors/idea/verify_idea.py
docs/development/custom-vectors/seed/generate_seed.py
docs/development/custom-vectors/seed/verify_seed.py
docs/hazmat/backends/commoncrypto.rst
docs/hazmat/backends/index.rst
docs/hazmat/backends/interfaces.rst
docs/hazmat/backends/multibackend.rst
docs/hazmat/backends/openssl.rst
docs/hazmat/bindings/commoncrypto.rst
docs/hazmat/bindings/index.rst
docs/hazmat/bindings/openssl.rst
docs/hazmat/primitives/constant-time.rst
docs/hazmat/primitives/cryptographic-hashes.rst
docs/hazmat/primitives/index.rst
docs/hazmat/primitives/interfaces.rst
docs/hazmat/primitives/key-derivation-functions.rst
docs/hazmat/primitives/padding.rst
docs/hazmat/primitives/symmetric-encryption.rst
docs/hazmat/primitives/twofactor.rst
docs/hazmat/primitives/asymmetric/dsa.rst
docs/hazmat/primitives/asymmetric/ec.rst
docs/hazmat/primitives/asymmetric/index.rst
docs/hazmat/primitives/asymmetric/padding.rst
docs/hazmat/primitives/asymmetric/rsa.rst
docs/hazmat/primitives/asymmetric/serialization.rst
docs/hazmat/primitives/mac/cmac.rst
docs/hazmat/primitives/mac/hmac.rst
docs/hazmat/primitives/mac/index.rst
tests/__init__.py
tests/conftest.py
tests/test_fernet.py
tests/test_utils.py
tests/utils.py
tests/hazmat/__init__.py
tests/hazmat/backends/__init__.py
tests/hazmat/backends/test_commoncrypto.py
tests/hazmat/backends/test_multibackend.py
tests/hazmat/backends/test_openssl.py
tests/hazmat/bindings/test_commoncrypto.py
tests/hazmat/bindings/test_openssl.py
tests/hazmat/bindings/test_utils.py
tests/hazmat/primitives/__init__.py
tests/hazmat/primitives/fixtures_dsa.py
tests/hazmat/primitives/fixtures_rsa.py
tests/hazmat/primitives/test_3des.py
tests/hazmat/primitives/test_aes.py
tests/hazmat/primitives/test_arc4.py
tests/hazmat/primitives/test_block.py
tests/hazmat/primitives/test_blowfish.py
tests/hazmat/primitives/test_camellia.py
tests/hazmat/primitives/test_cast5.py
tests/hazmat/primitives/test_ciphers.py
tests/hazmat/primitives/test_cmac.py
tests/hazmat/primitives/test_constant_time.py
tests/hazmat/primitives/test_dsa.py
tests/hazmat/primitives/test_ec.py
tests/hazmat/primitives/test_hash_vectors.py
tests/hazmat/primitives/test_hashes.py
tests/hazmat/primitives/test_hkdf.py
tests/hazmat/primitives/test_hkdf_vectors.py
tests/hazmat/primitives/test_hmac.py
tests/hazmat/primitives/test_hmac_vectors.py
tests/hazmat/primitives/test_idea.py
tests/hazmat/primitives/test_padding.py
tests/hazmat/primitives/test_pbkdf2hmac.py
tests/hazmat/primitives/test_pbkdf2hmac_vectors.py
tests/hazmat/primitives/test_rsa.py
tests/hazmat/primitives/test_seed.py
tests/hazmat/primitives/test_serialization.py
tests/hazmat/primitives/utils.py
tests/hazmat/primitives/twofactor/__init__.py
tests/hazmat/primitives/twofactor/test_hotp.py
tests/hazmat/primitives/twofactor/test_totp.py

View file

@ -1,3 +0,0 @@
cffi>=0.8
six>=1.4.1
setuptools

View file

@ -1,4 +0,0 @@
cryptography
_Cryptography_cffi_7ab3712bx4f158fee
_Cryptography_cffi_3e31f141x4000d087
_Cryptography_cffi_dd416c1exc1767c5a

View file

@ -1,15 +1,15 @@
Metadata-Version: 1.1 Metadata-Version: 1.1
Name: cryptography Name: cryptography
Version: 0.6 Version: 1.1
Summary: cryptography is a package which provides cryptographic recipes and primitives to Python developers. Summary: cryptography is a package which provides cryptographic recipes and primitives to Python developers.
Home-page: https://github.com/pyca/cryptography Home-page: https://github.com/pyca/cryptography
Author: The cryptography developers Author: The cryptography developers
Author-email: cryptography-dev@python.org Author-email: cryptography-dev@python.org
License: Apache License, Version 2.0 License: BSD or Apache License, Version 2.0
Description: Cryptography Description: Cryptography
============ ============
.. image:: https://pypip.in/version/cryptography/badge.svg .. image:: https://img.shields.io/pypi/v/cryptography.svg
:target: https://pypi.python.org/pypi/cryptography/ :target: https://pypi.python.org/pypi/cryptography/
:alt: Latest Version :alt: Latest Version
@ -20,13 +20,13 @@ Description: Cryptography
.. image:: https://travis-ci.org/pyca/cryptography.svg?branch=master .. image:: https://travis-ci.org/pyca/cryptography.svg?branch=master
:target: https://travis-ci.org/pyca/cryptography :target: https://travis-ci.org/pyca/cryptography
.. image:: https://coveralls.io/repos/pyca/cryptography/badge.png?branch=master .. image:: https://codecov.io/github/pyca/cryptography/coverage.svg?branch=master
:target: https://coveralls.io/r/pyca/cryptography?branch=master :target: https://codecov.io/github/pyca/cryptography?branch=master
``cryptography`` is a package which provides cryptographic recipes and ``cryptography`` is a package which provides cryptographic recipes and
primitives to Python developers. Our goal is for it to be your "cryptographic primitives to Python developers. Our goal is for it to be your "cryptographic
standard library". It supports Python 2.6-2.7, Python 3.2+, and PyPy. standard library". It supports Python 2.6-2.7, Python 3.3+, and PyPy 2.6+.
``cryptography`` includes both high level recipes, and low level interfaces to ``cryptography`` includes both high level recipes, and low level interfaces to
common cryptographic algorithms such as symmetric ciphers, message digests and common cryptographic algorithms such as symmetric ciphers, message digests and
@ -65,6 +65,7 @@ Description: Cryptography
Platform: UNKNOWN Platform: UNKNOWN
Classifier: Intended Audience :: Developers Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: Apache Software License Classifier: License :: OSI Approved :: Apache Software License
Classifier: License :: OSI Approved :: BSD License
Classifier: Natural Language :: English Classifier: Natural Language :: English
Classifier: Operating System :: MacOS :: MacOS X Classifier: Operating System :: MacOS :: MacOS X
Classifier: Operating System :: POSIX Classifier: Operating System :: POSIX
@ -76,9 +77,9 @@ Classifier: Programming Language :: Python :: 2
Classifier: Programming Language :: Python :: 2.6 Classifier: Programming Language :: Python :: 2.6
Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 2.7
Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.2
Classifier: Programming Language :: Python :: 3.3 Classifier: Programming Language :: Python :: 3.3
Classifier: Programming Language :: Python :: 3.4 Classifier: Programming Language :: Python :: 3.4
Classifier: Programming Language :: Python :: 3.5
Classifier: Programming Language :: Python :: Implementation :: CPython Classifier: Programming Language :: Python :: Implementation :: CPython
Classifier: Programming Language :: Python :: Implementation :: PyPy Classifier: Programming Language :: Python :: Implementation :: PyPy
Classifier: Topic :: Security :: Cryptography Classifier: Topic :: Security :: Cryptography

View file

@ -0,0 +1,260 @@
AUTHORS.rst
CHANGELOG.rst
CONTRIBUTING.rst
LICENSE
LICENSE.APACHE
LICENSE.BSD
MANIFEST.in
README.rst
setup.cfg
setup.py
docs/Makefile
docs/api-stability.rst
docs/changelog.rst
docs/community.rst
docs/conf.py
docs/cryptography-docs.py
docs/doing-a-release.rst
docs/exceptions.rst
docs/faq.rst
docs/fernet.rst
docs/glossary.rst
docs/index.rst
docs/installation.rst
docs/limitations.rst
docs/make.bat
docs/random-numbers.rst
docs/security.rst
docs/spelling_wordlist.txt
docs/_static/.keep
docs/development/c-bindings.rst
docs/development/getting-started.rst
docs/development/index.rst
docs/development/reviewing-patches.rst
docs/development/submitting-patches.rst
docs/development/test-vectors.rst
docs/development/custom-vectors/cast5.rst
docs/development/custom-vectors/idea.rst
docs/development/custom-vectors/secp256k1.rst
docs/development/custom-vectors/seed.rst
docs/development/custom-vectors/cast5/generate_cast5.py
docs/development/custom-vectors/cast5/verify_cast5.go
docs/development/custom-vectors/idea/generate_idea.py
docs/development/custom-vectors/idea/verify_idea.py
docs/development/custom-vectors/secp256k1/generate_secp256k1.py
docs/development/custom-vectors/secp256k1/verify_secp256k1.py
docs/development/custom-vectors/seed/generate_seed.py
docs/development/custom-vectors/seed/verify_seed.py
docs/hazmat/backends/commoncrypto.rst
docs/hazmat/backends/index.rst
docs/hazmat/backends/interfaces.rst
docs/hazmat/backends/multibackend.rst
docs/hazmat/backends/openssl.rst
docs/hazmat/bindings/commoncrypto.rst
docs/hazmat/bindings/index.rst
docs/hazmat/bindings/openssl.rst
docs/hazmat/primitives/constant-time.rst
docs/hazmat/primitives/cryptographic-hashes.rst
docs/hazmat/primitives/index.rst
docs/hazmat/primitives/interfaces.rst
docs/hazmat/primitives/key-derivation-functions.rst
docs/hazmat/primitives/keywrap.rst
docs/hazmat/primitives/padding.rst
docs/hazmat/primitives/symmetric-encryption.rst
docs/hazmat/primitives/twofactor.rst
docs/hazmat/primitives/asymmetric/dh.rst
docs/hazmat/primitives/asymmetric/dsa.rst
docs/hazmat/primitives/asymmetric/ec.rst
docs/hazmat/primitives/asymmetric/index.rst
docs/hazmat/primitives/asymmetric/interfaces.rst
docs/hazmat/primitives/asymmetric/rsa.rst
docs/hazmat/primitives/asymmetric/serialization.rst
docs/hazmat/primitives/asymmetric/utils.rst
docs/hazmat/primitives/mac/cmac.rst
docs/hazmat/primitives/mac/hmac.rst
docs/hazmat/primitives/mac/index.rst
docs/x509/index.rst
docs/x509/reference.rst
docs/x509/tutorial.rst
src/_cffi_src/__init__.py
src/_cffi_src/build_commoncrypto.py
src/_cffi_src/build_constant_time.py
src/_cffi_src/build_openssl.py
src/_cffi_src/build_padding.py
src/_cffi_src/utils.py
src/_cffi_src/commoncrypto/__init__.py
src/_cffi_src/commoncrypto/cf.py
src/_cffi_src/commoncrypto/common_cryptor.py
src/_cffi_src/commoncrypto/common_digest.py
src/_cffi_src/commoncrypto/common_hmac.py
src/_cffi_src/commoncrypto/common_key_derivation.py
src/_cffi_src/commoncrypto/common_symmetric_key_wrap.py
src/_cffi_src/commoncrypto/secimport.py
src/_cffi_src/commoncrypto/secitem.py
src/_cffi_src/commoncrypto/seckey.py
src/_cffi_src/commoncrypto/seckeychain.py
src/_cffi_src/commoncrypto/sectransform.py
src/_cffi_src/hazmat_src/constant_time.c
src/_cffi_src/hazmat_src/constant_time.h
src/_cffi_src/hazmat_src/padding.c
src/_cffi_src/hazmat_src/padding.h
src/_cffi_src/openssl/__init__.py
src/_cffi_src/openssl/aes.py
src/_cffi_src/openssl/asn1.py
src/_cffi_src/openssl/bignum.py
src/_cffi_src/openssl/bio.py
src/_cffi_src/openssl/cmac.py
src/_cffi_src/openssl/cms.py
src/_cffi_src/openssl/conf.py
src/_cffi_src/openssl/crypto.py
src/_cffi_src/openssl/dh.py
src/_cffi_src/openssl/dsa.py
src/_cffi_src/openssl/ec.py
src/_cffi_src/openssl/ecdh.py
src/_cffi_src/openssl/ecdsa.py
src/_cffi_src/openssl/engine.py
src/_cffi_src/openssl/err.py
src/_cffi_src/openssl/evp.py
src/_cffi_src/openssl/hmac.py
src/_cffi_src/openssl/nid.py
src/_cffi_src/openssl/objects.py
src/_cffi_src/openssl/opensslv.py
src/_cffi_src/openssl/pem.py
src/_cffi_src/openssl/pkcs12.py
src/_cffi_src/openssl/pkcs7.py
src/_cffi_src/openssl/rand.py
src/_cffi_src/openssl/rsa.py
src/_cffi_src/openssl/ssl.py
src/_cffi_src/openssl/x509.py
src/_cffi_src/openssl/x509_vfy.py
src/_cffi_src/openssl/x509name.py
src/_cffi_src/openssl/x509v3.py
src/cryptography/__about__.py
src/cryptography/__init__.py
src/cryptography/exceptions.py
src/cryptography/fernet.py
src/cryptography/utils.py
src/cryptography.egg-info/PKG-INFO
src/cryptography.egg-info/SOURCES.txt
src/cryptography.egg-info/dependency_links.txt
src/cryptography.egg-info/entry_points.txt
src/cryptography.egg-info/not-zip-safe
src/cryptography.egg-info/requires.txt
src/cryptography.egg-info/top_level.txt
src/cryptography/hazmat/__init__.py
src/cryptography/hazmat/backends/__init__.py
src/cryptography/hazmat/backends/interfaces.py
src/cryptography/hazmat/backends/multibackend.py
src/cryptography/hazmat/backends/commoncrypto/__init__.py
src/cryptography/hazmat/backends/commoncrypto/backend.py
src/cryptography/hazmat/backends/commoncrypto/ciphers.py
src/cryptography/hazmat/backends/commoncrypto/hashes.py
src/cryptography/hazmat/backends/commoncrypto/hmac.py
src/cryptography/hazmat/backends/openssl/__init__.py
src/cryptography/hazmat/backends/openssl/backend.py
src/cryptography/hazmat/backends/openssl/ciphers.py
src/cryptography/hazmat/backends/openssl/cmac.py
src/cryptography/hazmat/backends/openssl/dsa.py
src/cryptography/hazmat/backends/openssl/ec.py
src/cryptography/hazmat/backends/openssl/hashes.py
src/cryptography/hazmat/backends/openssl/hmac.py
src/cryptography/hazmat/backends/openssl/rsa.py
src/cryptography/hazmat/backends/openssl/utils.py
src/cryptography/hazmat/backends/openssl/x509.py
src/cryptography/hazmat/bindings/__init__.py
src/cryptography/hazmat/bindings/commoncrypto/__init__.py
src/cryptography/hazmat/bindings/commoncrypto/binding.py
src/cryptography/hazmat/bindings/openssl/__init__.py
src/cryptography/hazmat/bindings/openssl/_conditional.py
src/cryptography/hazmat/bindings/openssl/binding.py
src/cryptography/hazmat/primitives/__init__.py
src/cryptography/hazmat/primitives/cmac.py
src/cryptography/hazmat/primitives/constant_time.py
src/cryptography/hazmat/primitives/hashes.py
src/cryptography/hazmat/primitives/hmac.py
src/cryptography/hazmat/primitives/keywrap.py
src/cryptography/hazmat/primitives/padding.py
src/cryptography/hazmat/primitives/serialization.py
src/cryptography/hazmat/primitives/asymmetric/__init__.py
src/cryptography/hazmat/primitives/asymmetric/dh.py
src/cryptography/hazmat/primitives/asymmetric/dsa.py
src/cryptography/hazmat/primitives/asymmetric/ec.py
src/cryptography/hazmat/primitives/asymmetric/padding.py
src/cryptography/hazmat/primitives/asymmetric/rsa.py
src/cryptography/hazmat/primitives/asymmetric/utils.py
src/cryptography/hazmat/primitives/ciphers/__init__.py
src/cryptography/hazmat/primitives/ciphers/algorithms.py
src/cryptography/hazmat/primitives/ciphers/base.py
src/cryptography/hazmat/primitives/ciphers/modes.py
src/cryptography/hazmat/primitives/interfaces/__init__.py
src/cryptography/hazmat/primitives/kdf/__init__.py
src/cryptography/hazmat/primitives/kdf/concatkdf.py
src/cryptography/hazmat/primitives/kdf/hkdf.py
src/cryptography/hazmat/primitives/kdf/pbkdf2.py
src/cryptography/hazmat/primitives/kdf/x963kdf.py
src/cryptography/hazmat/primitives/twofactor/__init__.py
src/cryptography/hazmat/primitives/twofactor/hotp.py
src/cryptography/hazmat/primitives/twofactor/totp.py
src/cryptography/hazmat/primitives/twofactor/utils.py
src/cryptography/x509/__init__.py
src/cryptography/x509/base.py
src/cryptography/x509/extensions.py
src/cryptography/x509/general_name.py
src/cryptography/x509/name.py
src/cryptography/x509/oid.py
tests/__init__.py
tests/conftest.py
tests/test_fernet.py
tests/test_interfaces.py
tests/test_utils.py
tests/test_warnings.py
tests/test_x509.py
tests/test_x509_ext.py
tests/utils.py
tests/hazmat/__init__.py
tests/hazmat/backends/__init__.py
tests/hazmat/backends/test_commoncrypto.py
tests/hazmat/backends/test_multibackend.py
tests/hazmat/backends/test_openssl.py
tests/hazmat/bindings/test_commoncrypto.py
tests/hazmat/bindings/test_openssl.py
tests/hazmat/primitives/__init__.py
tests/hazmat/primitives/fixtures_dsa.py
tests/hazmat/primitives/fixtures_rsa.py
tests/hazmat/primitives/test_3des.py
tests/hazmat/primitives/test_aes.py
tests/hazmat/primitives/test_arc4.py
tests/hazmat/primitives/test_asym_utils.py
tests/hazmat/primitives/test_block.py
tests/hazmat/primitives/test_blowfish.py
tests/hazmat/primitives/test_camellia.py
tests/hazmat/primitives/test_cast5.py
tests/hazmat/primitives/test_ciphers.py
tests/hazmat/primitives/test_cmac.py
tests/hazmat/primitives/test_concatkdf.py
tests/hazmat/primitives/test_constant_time.py
tests/hazmat/primitives/test_dh.py
tests/hazmat/primitives/test_dsa.py
tests/hazmat/primitives/test_ec.py
tests/hazmat/primitives/test_hash_vectors.py
tests/hazmat/primitives/test_hashes.py
tests/hazmat/primitives/test_hkdf.py
tests/hazmat/primitives/test_hkdf_vectors.py
tests/hazmat/primitives/test_hmac.py
tests/hazmat/primitives/test_hmac_vectors.py
tests/hazmat/primitives/test_idea.py
tests/hazmat/primitives/test_keywrap.py
tests/hazmat/primitives/test_padding.py
tests/hazmat/primitives/test_pbkdf2hmac.py
tests/hazmat/primitives/test_pbkdf2hmac_vectors.py
tests/hazmat/primitives/test_rsa.py
tests/hazmat/primitives/test_seed.py
tests/hazmat/primitives/test_serialization.py
tests/hazmat/primitives/test_x963_vectors.py
tests/hazmat/primitives/test_x963kdf.py
tests/hazmat/primitives/utils.py
tests/hazmat/primitives/twofactor/__init__.py
tests/hazmat/primitives/twofactor/test_hotp.py
tests/hazmat/primitives/twofactor/test_totp.py
tests/hypothesis/__init__.py
tests/hypothesis/test_fernet.py

View file

@ -1,202 +1,143 @@
../cryptography/utils.py
../cryptography/__about__.py ../cryptography/__about__.py
../cryptography/__init__.py ../cryptography/__init__.py
../cryptography/exceptions.py ../cryptography/exceptions.py
../cryptography/fernet.py ../cryptography/fernet.py
../cryptography/utils.py
../cryptography/hazmat/__init__.py ../cryptography/hazmat/__init__.py
../cryptography/hazmat/bindings/utils.py ../cryptography/x509/__init__.py
../cryptography/hazmat/bindings/__init__.py ../cryptography/x509/base.py
../cryptography/hazmat/primitives/interfaces.py ../cryptography/x509/extensions.py
../cryptography/hazmat/primitives/constant_time.py ../cryptography/x509/general_name.py
../cryptography/hazmat/primitives/__init__.py ../cryptography/x509/name.py
../cryptography/hazmat/primitives/hashes.py ../cryptography/x509/oid.py
../cryptography/hazmat/primitives/hmac.py ../cryptography/hazmat/backends/__init__.py
../cryptography/hazmat/primitives/padding.py
../cryptography/hazmat/primitives/serialization.py
../cryptography/hazmat/primitives/cmac.py
../cryptography/hazmat/backends/interfaces.py ../cryptography/hazmat/backends/interfaces.py
../cryptography/hazmat/backends/multibackend.py ../cryptography/hazmat/backends/multibackend.py
../cryptography/hazmat/backends/__init__.py ../cryptography/hazmat/bindings/__init__.py
../cryptography/hazmat/bindings/commoncrypto/secimport.py ../cryptography/hazmat/primitives/__init__.py
../cryptography/hazmat/bindings/commoncrypto/common_cryptor.py ../cryptography/hazmat/primitives/cmac.py
../cryptography/hazmat/bindings/commoncrypto/seckeychain.py ../cryptography/hazmat/primitives/constant_time.py
../cryptography/hazmat/bindings/commoncrypto/common_hmac.py ../cryptography/hazmat/primitives/hashes.py
../cryptography/hazmat/bindings/commoncrypto/__init__.py ../cryptography/hazmat/primitives/hmac.py
../cryptography/hazmat/bindings/commoncrypto/common_key_derivation.py ../cryptography/hazmat/primitives/keywrap.py
../cryptography/hazmat/bindings/commoncrypto/sectransform.py ../cryptography/hazmat/primitives/padding.py
../cryptography/hazmat/bindings/commoncrypto/binding.py ../cryptography/hazmat/primitives/serialization.py
../cryptography/hazmat/bindings/commoncrypto/common_digest.py
../cryptography/hazmat/bindings/commoncrypto/seckey.py
../cryptography/hazmat/bindings/commoncrypto/secitem.py
../cryptography/hazmat/bindings/commoncrypto/cf.py
../cryptography/hazmat/bindings/openssl/opensslv.py
../cryptography/hazmat/bindings/openssl/ec.py
../cryptography/hazmat/bindings/openssl/x509_vfy.py
../cryptography/hazmat/bindings/openssl/aes.py
../cryptography/hazmat/bindings/openssl/asn1.py
../cryptography/hazmat/bindings/openssl/objects.py
../cryptography/hazmat/bindings/openssl/dsa.py
../cryptography/hazmat/bindings/openssl/x509name.py
../cryptography/hazmat/bindings/openssl/osrandom_engine.py
../cryptography/hazmat/bindings/openssl/rand.py
../cryptography/hazmat/bindings/openssl/cms.py
../cryptography/hazmat/bindings/openssl/engine.py
../cryptography/hazmat/bindings/openssl/__init__.py
../cryptography/hazmat/bindings/openssl/ssl.py
../cryptography/hazmat/bindings/openssl/nid.py
../cryptography/hazmat/bindings/openssl/x509v3.py
../cryptography/hazmat/bindings/openssl/err.py
../cryptography/hazmat/bindings/openssl/bio.py
../cryptography/hazmat/bindings/openssl/ecdsa.py
../cryptography/hazmat/bindings/openssl/pkcs7.py
../cryptography/hazmat/bindings/openssl/bignum.py
../cryptography/hazmat/bindings/openssl/binding.py
../cryptography/hazmat/bindings/openssl/pem.py
../cryptography/hazmat/bindings/openssl/rsa.py
../cryptography/hazmat/bindings/openssl/hmac.py
../cryptography/hazmat/bindings/openssl/conf.py
../cryptography/hazmat/bindings/openssl/dh.py
../cryptography/hazmat/bindings/openssl/x509.py
../cryptography/hazmat/bindings/openssl/ecdh.py
../cryptography/hazmat/bindings/openssl/evp.py
../cryptography/hazmat/bindings/openssl/cmac.py
../cryptography/hazmat/bindings/openssl/crypto.py
../cryptography/hazmat/bindings/openssl/pkcs12.py
../cryptography/hazmat/primitives/kdf/__init__.py
../cryptography/hazmat/primitives/kdf/hkdf.py
../cryptography/hazmat/primitives/kdf/pbkdf2.py
../cryptography/hazmat/primitives/asymmetric/ec.py
../cryptography/hazmat/primitives/asymmetric/dsa.py
../cryptography/hazmat/primitives/asymmetric/__init__.py
../cryptography/hazmat/primitives/asymmetric/rsa.py
../cryptography/hazmat/primitives/asymmetric/padding.py
../cryptography/hazmat/primitives/ciphers/base.py
../cryptography/hazmat/primitives/ciphers/__init__.py
../cryptography/hazmat/primitives/ciphers/modes.py
../cryptography/hazmat/primitives/ciphers/algorithms.py
../cryptography/hazmat/primitives/twofactor/__init__.py
../cryptography/hazmat/primitives/twofactor/totp.py
../cryptography/hazmat/primitives/twofactor/hotp.py
../cryptography/hazmat/backends/commoncrypto/backend.py
../cryptography/hazmat/backends/commoncrypto/__init__.py ../cryptography/hazmat/backends/commoncrypto/__init__.py
../cryptography/hazmat/backends/commoncrypto/backend.py
../cryptography/hazmat/backends/commoncrypto/ciphers.py
../cryptography/hazmat/backends/commoncrypto/hashes.py ../cryptography/hazmat/backends/commoncrypto/hashes.py
../cryptography/hazmat/backends/commoncrypto/hmac.py ../cryptography/hazmat/backends/commoncrypto/hmac.py
../cryptography/hazmat/backends/commoncrypto/ciphers.py
../cryptography/hazmat/backends/openssl/ec.py
../cryptography/hazmat/backends/openssl/dsa.py
../cryptography/hazmat/backends/openssl/backend.py
../cryptography/hazmat/backends/openssl/__init__.py ../cryptography/hazmat/backends/openssl/__init__.py
../cryptography/hazmat/backends/openssl/hashes.py ../cryptography/hazmat/backends/openssl/backend.py
../cryptography/hazmat/backends/openssl/rsa.py
../cryptography/hazmat/backends/openssl/hmac.py
../cryptography/hazmat/backends/openssl/cmac.py
../cryptography/hazmat/backends/openssl/ciphers.py ../cryptography/hazmat/backends/openssl/ciphers.py
../cryptography/hazmat/bindings/__pycache__/_Cryptography_cffi_3e31f141x4000d087.c ../cryptography/hazmat/backends/openssl/cmac.py
../cryptography/hazmat/primitives/__pycache__/_Cryptography_cffi_7ab3712bx4f158fee.c ../cryptography/hazmat/backends/openssl/dsa.py
../cryptography/hazmat/primitives/__pycache__/_Cryptography_cffi_dd416c1exc1767c5a.c ../cryptography/hazmat/backends/openssl/ec.py
../cryptography/hazmat/primitives/src/constant_time.c ../cryptography/hazmat/backends/openssl/hashes.py
../cryptography/hazmat/primitives/src/constant_time.h ../cryptography/hazmat/backends/openssl/hmac.py
../cryptography/__pycache__/utils.cpython-34.pyc ../cryptography/hazmat/backends/openssl/rsa.py
../cryptography/hazmat/backends/openssl/utils.py
../cryptography/hazmat/backends/openssl/x509.py
../cryptography/hazmat/bindings/commoncrypto/__init__.py
../cryptography/hazmat/bindings/commoncrypto/binding.py
../cryptography/hazmat/bindings/openssl/__init__.py
../cryptography/hazmat/bindings/openssl/_conditional.py
../cryptography/hazmat/bindings/openssl/binding.py
../cryptography/hazmat/primitives/asymmetric/__init__.py
../cryptography/hazmat/primitives/asymmetric/dh.py
../cryptography/hazmat/primitives/asymmetric/dsa.py
../cryptography/hazmat/primitives/asymmetric/ec.py
../cryptography/hazmat/primitives/asymmetric/padding.py
../cryptography/hazmat/primitives/asymmetric/rsa.py
../cryptography/hazmat/primitives/asymmetric/utils.py
../cryptography/hazmat/primitives/ciphers/__init__.py
../cryptography/hazmat/primitives/ciphers/algorithms.py
../cryptography/hazmat/primitives/ciphers/base.py
../cryptography/hazmat/primitives/ciphers/modes.py
../cryptography/hazmat/primitives/interfaces/__init__.py
../cryptography/hazmat/primitives/kdf/__init__.py
../cryptography/hazmat/primitives/kdf/concatkdf.py
../cryptography/hazmat/primitives/kdf/hkdf.py
../cryptography/hazmat/primitives/kdf/pbkdf2.py
../cryptography/hazmat/primitives/kdf/x963kdf.py
../cryptography/hazmat/primitives/twofactor/__init__.py
../cryptography/hazmat/primitives/twofactor/hotp.py
../cryptography/hazmat/primitives/twofactor/totp.py
../cryptography/hazmat/primitives/twofactor/utils.py
../cryptography/__pycache__/__about__.cpython-34.pyc ../cryptography/__pycache__/__about__.cpython-34.pyc
../cryptography/__pycache__/__init__.cpython-34.pyc ../cryptography/__pycache__/__init__.cpython-34.pyc
../cryptography/__pycache__/exceptions.cpython-34.pyc ../cryptography/__pycache__/exceptions.cpython-34.pyc
../cryptography/__pycache__/fernet.cpython-34.pyc ../cryptography/__pycache__/fernet.cpython-34.pyc
../cryptography/__pycache__/utils.cpython-34.pyc
../cryptography/hazmat/__pycache__/__init__.cpython-34.pyc ../cryptography/hazmat/__pycache__/__init__.cpython-34.pyc
../cryptography/hazmat/bindings/__pycache__/utils.cpython-34.pyc ../cryptography/x509/__pycache__/__init__.cpython-34.pyc
../cryptography/hazmat/bindings/__pycache__/__init__.cpython-34.pyc ../cryptography/x509/__pycache__/base.cpython-34.pyc
../cryptography/hazmat/primitives/__pycache__/interfaces.cpython-34.pyc ../cryptography/x509/__pycache__/extensions.cpython-34.pyc
../cryptography/hazmat/primitives/__pycache__/constant_time.cpython-34.pyc ../cryptography/x509/__pycache__/general_name.cpython-34.pyc
../cryptography/hazmat/primitives/__pycache__/__init__.cpython-34.pyc ../cryptography/x509/__pycache__/name.cpython-34.pyc
../cryptography/hazmat/primitives/__pycache__/hashes.cpython-34.pyc ../cryptography/x509/__pycache__/oid.cpython-34.pyc
../cryptography/hazmat/primitives/__pycache__/hmac.cpython-34.pyc ../cryptography/hazmat/backends/__pycache__/__init__.cpython-34.pyc
../cryptography/hazmat/primitives/__pycache__/padding.cpython-34.pyc
../cryptography/hazmat/primitives/__pycache__/serialization.cpython-34.pyc
../cryptography/hazmat/primitives/__pycache__/cmac.cpython-34.pyc
../cryptography/hazmat/backends/__pycache__/interfaces.cpython-34.pyc ../cryptography/hazmat/backends/__pycache__/interfaces.cpython-34.pyc
../cryptography/hazmat/backends/__pycache__/multibackend.cpython-34.pyc ../cryptography/hazmat/backends/__pycache__/multibackend.cpython-34.pyc
../cryptography/hazmat/backends/__pycache__/__init__.cpython-34.pyc ../cryptography/hazmat/bindings/__pycache__/__init__.cpython-34.pyc
../cryptography/hazmat/bindings/commoncrypto/__pycache__/secimport.cpython-34.pyc ../cryptography/hazmat/primitives/__pycache__/__init__.cpython-34.pyc
../cryptography/hazmat/bindings/commoncrypto/__pycache__/common_cryptor.cpython-34.pyc ../cryptography/hazmat/primitives/__pycache__/cmac.cpython-34.pyc
../cryptography/hazmat/bindings/commoncrypto/__pycache__/seckeychain.cpython-34.pyc ../cryptography/hazmat/primitives/__pycache__/constant_time.cpython-34.pyc
../cryptography/hazmat/bindings/commoncrypto/__pycache__/common_hmac.cpython-34.pyc ../cryptography/hazmat/primitives/__pycache__/hashes.cpython-34.pyc
../cryptography/hazmat/bindings/commoncrypto/__pycache__/__init__.cpython-34.pyc ../cryptography/hazmat/primitives/__pycache__/hmac.cpython-34.pyc
../cryptography/hazmat/bindings/commoncrypto/__pycache__/common_key_derivation.cpython-34.pyc ../cryptography/hazmat/primitives/__pycache__/keywrap.cpython-34.pyc
../cryptography/hazmat/bindings/commoncrypto/__pycache__/sectransform.cpython-34.pyc ../cryptography/hazmat/primitives/__pycache__/padding.cpython-34.pyc
../cryptography/hazmat/bindings/commoncrypto/__pycache__/binding.cpython-34.pyc ../cryptography/hazmat/primitives/__pycache__/serialization.cpython-34.pyc
../cryptography/hazmat/bindings/commoncrypto/__pycache__/common_digest.cpython-34.pyc
../cryptography/hazmat/bindings/commoncrypto/__pycache__/seckey.cpython-34.pyc
../cryptography/hazmat/bindings/commoncrypto/__pycache__/secitem.cpython-34.pyc
../cryptography/hazmat/bindings/commoncrypto/__pycache__/cf.cpython-34.pyc
../cryptography/hazmat/bindings/openssl/__pycache__/opensslv.cpython-34.pyc
../cryptography/hazmat/bindings/openssl/__pycache__/ec.cpython-34.pyc
../cryptography/hazmat/bindings/openssl/__pycache__/x509_vfy.cpython-34.pyc
../cryptography/hazmat/bindings/openssl/__pycache__/aes.cpython-34.pyc
../cryptography/hazmat/bindings/openssl/__pycache__/asn1.cpython-34.pyc
../cryptography/hazmat/bindings/openssl/__pycache__/objects.cpython-34.pyc
../cryptography/hazmat/bindings/openssl/__pycache__/dsa.cpython-34.pyc
../cryptography/hazmat/bindings/openssl/__pycache__/x509name.cpython-34.pyc
../cryptography/hazmat/bindings/openssl/__pycache__/osrandom_engine.cpython-34.pyc
../cryptography/hazmat/bindings/openssl/__pycache__/rand.cpython-34.pyc
../cryptography/hazmat/bindings/openssl/__pycache__/cms.cpython-34.pyc
../cryptography/hazmat/bindings/openssl/__pycache__/engine.cpython-34.pyc
../cryptography/hazmat/bindings/openssl/__pycache__/__init__.cpython-34.pyc
../cryptography/hazmat/bindings/openssl/__pycache__/ssl.cpython-34.pyc
../cryptography/hazmat/bindings/openssl/__pycache__/nid.cpython-34.pyc
../cryptography/hazmat/bindings/openssl/__pycache__/x509v3.cpython-34.pyc
../cryptography/hazmat/bindings/openssl/__pycache__/err.cpython-34.pyc
../cryptography/hazmat/bindings/openssl/__pycache__/bio.cpython-34.pyc
../cryptography/hazmat/bindings/openssl/__pycache__/ecdsa.cpython-34.pyc
../cryptography/hazmat/bindings/openssl/__pycache__/pkcs7.cpython-34.pyc
../cryptography/hazmat/bindings/openssl/__pycache__/bignum.cpython-34.pyc
../cryptography/hazmat/bindings/openssl/__pycache__/binding.cpython-34.pyc
../cryptography/hazmat/bindings/openssl/__pycache__/pem.cpython-34.pyc
../cryptography/hazmat/bindings/openssl/__pycache__/rsa.cpython-34.pyc
../cryptography/hazmat/bindings/openssl/__pycache__/hmac.cpython-34.pyc
../cryptography/hazmat/bindings/openssl/__pycache__/conf.cpython-34.pyc
../cryptography/hazmat/bindings/openssl/__pycache__/dh.cpython-34.pyc
../cryptography/hazmat/bindings/openssl/__pycache__/x509.cpython-34.pyc
../cryptography/hazmat/bindings/openssl/__pycache__/ecdh.cpython-34.pyc
../cryptography/hazmat/bindings/openssl/__pycache__/evp.cpython-34.pyc
../cryptography/hazmat/bindings/openssl/__pycache__/cmac.cpython-34.pyc
../cryptography/hazmat/bindings/openssl/__pycache__/crypto.cpython-34.pyc
../cryptography/hazmat/bindings/openssl/__pycache__/pkcs12.cpython-34.pyc
../cryptography/hazmat/primitives/kdf/__pycache__/__init__.cpython-34.pyc
../cryptography/hazmat/primitives/kdf/__pycache__/hkdf.cpython-34.pyc
../cryptography/hazmat/primitives/kdf/__pycache__/pbkdf2.cpython-34.pyc
../cryptography/hazmat/primitives/asymmetric/__pycache__/ec.cpython-34.pyc
../cryptography/hazmat/primitives/asymmetric/__pycache__/dsa.cpython-34.pyc
../cryptography/hazmat/primitives/asymmetric/__pycache__/__init__.cpython-34.pyc
../cryptography/hazmat/primitives/asymmetric/__pycache__/rsa.cpython-34.pyc
../cryptography/hazmat/primitives/asymmetric/__pycache__/padding.cpython-34.pyc
../cryptography/hazmat/primitives/ciphers/__pycache__/base.cpython-34.pyc
../cryptography/hazmat/primitives/ciphers/__pycache__/__init__.cpython-34.pyc
../cryptography/hazmat/primitives/ciphers/__pycache__/modes.cpython-34.pyc
../cryptography/hazmat/primitives/ciphers/__pycache__/algorithms.cpython-34.pyc
../cryptography/hazmat/primitives/twofactor/__pycache__/__init__.cpython-34.pyc
../cryptography/hazmat/primitives/twofactor/__pycache__/totp.cpython-34.pyc
../cryptography/hazmat/primitives/twofactor/__pycache__/hotp.cpython-34.pyc
../cryptography/hazmat/backends/commoncrypto/__pycache__/backend.cpython-34.pyc
../cryptography/hazmat/backends/commoncrypto/__pycache__/__init__.cpython-34.pyc ../cryptography/hazmat/backends/commoncrypto/__pycache__/__init__.cpython-34.pyc
../cryptography/hazmat/backends/commoncrypto/__pycache__/backend.cpython-34.pyc
../cryptography/hazmat/backends/commoncrypto/__pycache__/ciphers.cpython-34.pyc
../cryptography/hazmat/backends/commoncrypto/__pycache__/hashes.cpython-34.pyc ../cryptography/hazmat/backends/commoncrypto/__pycache__/hashes.cpython-34.pyc
../cryptography/hazmat/backends/commoncrypto/__pycache__/hmac.cpython-34.pyc ../cryptography/hazmat/backends/commoncrypto/__pycache__/hmac.cpython-34.pyc
../cryptography/hazmat/backends/commoncrypto/__pycache__/ciphers.cpython-34.pyc
../cryptography/hazmat/backends/openssl/__pycache__/ec.cpython-34.pyc
../cryptography/hazmat/backends/openssl/__pycache__/dsa.cpython-34.pyc
../cryptography/hazmat/backends/openssl/__pycache__/backend.cpython-34.pyc
../cryptography/hazmat/backends/openssl/__pycache__/__init__.cpython-34.pyc ../cryptography/hazmat/backends/openssl/__pycache__/__init__.cpython-34.pyc
../cryptography/hazmat/backends/openssl/__pycache__/hashes.cpython-34.pyc ../cryptography/hazmat/backends/openssl/__pycache__/backend.cpython-34.pyc
../cryptography/hazmat/backends/openssl/__pycache__/rsa.cpython-34.pyc
../cryptography/hazmat/backends/openssl/__pycache__/hmac.cpython-34.pyc
../cryptography/hazmat/backends/openssl/__pycache__/cmac.cpython-34.pyc
../cryptography/hazmat/backends/openssl/__pycache__/ciphers.cpython-34.pyc ../cryptography/hazmat/backends/openssl/__pycache__/ciphers.cpython-34.pyc
../cryptography/_Cryptography_cffi_3e31f141x4000d087.cpython-34m.so ../cryptography/hazmat/backends/openssl/__pycache__/cmac.cpython-34.pyc
../cryptography/_Cryptography_cffi_7ab3712bx4f158fee.cpython-34m.so ../cryptography/hazmat/backends/openssl/__pycache__/dsa.cpython-34.pyc
../cryptography/_Cryptography_cffi_dd416c1exc1767c5a.cpython-34m.so ../cryptography/hazmat/backends/openssl/__pycache__/ec.cpython-34.pyc
../cryptography/hazmat/backends/openssl/__pycache__/hashes.cpython-34.pyc
../cryptography/hazmat/backends/openssl/__pycache__/hmac.cpython-34.pyc
../cryptography/hazmat/backends/openssl/__pycache__/rsa.cpython-34.pyc
../cryptography/hazmat/backends/openssl/__pycache__/utils.cpython-34.pyc
../cryptography/hazmat/backends/openssl/__pycache__/x509.cpython-34.pyc
../cryptography/hazmat/bindings/commoncrypto/__pycache__/__init__.cpython-34.pyc
../cryptography/hazmat/bindings/commoncrypto/__pycache__/binding.cpython-34.pyc
../cryptography/hazmat/bindings/openssl/__pycache__/__init__.cpython-34.pyc
../cryptography/hazmat/bindings/openssl/__pycache__/_conditional.cpython-34.pyc
../cryptography/hazmat/bindings/openssl/__pycache__/binding.cpython-34.pyc
../cryptography/hazmat/primitives/asymmetric/__pycache__/__init__.cpython-34.pyc
../cryptography/hazmat/primitives/asymmetric/__pycache__/dh.cpython-34.pyc
../cryptography/hazmat/primitives/asymmetric/__pycache__/dsa.cpython-34.pyc
../cryptography/hazmat/primitives/asymmetric/__pycache__/ec.cpython-34.pyc
../cryptography/hazmat/primitives/asymmetric/__pycache__/padding.cpython-34.pyc
../cryptography/hazmat/primitives/asymmetric/__pycache__/rsa.cpython-34.pyc
../cryptography/hazmat/primitives/asymmetric/__pycache__/utils.cpython-34.pyc
../cryptography/hazmat/primitives/ciphers/__pycache__/__init__.cpython-34.pyc
../cryptography/hazmat/primitives/ciphers/__pycache__/algorithms.cpython-34.pyc
../cryptography/hazmat/primitives/ciphers/__pycache__/base.cpython-34.pyc
../cryptography/hazmat/primitives/ciphers/__pycache__/modes.cpython-34.pyc
../cryptography/hazmat/primitives/interfaces/__pycache__/__init__.cpython-34.pyc
../cryptography/hazmat/primitives/kdf/__pycache__/__init__.cpython-34.pyc
../cryptography/hazmat/primitives/kdf/__pycache__/concatkdf.cpython-34.pyc
../cryptography/hazmat/primitives/kdf/__pycache__/hkdf.cpython-34.pyc
../cryptography/hazmat/primitives/kdf/__pycache__/pbkdf2.cpython-34.pyc
../cryptography/hazmat/primitives/kdf/__pycache__/x963kdf.cpython-34.pyc
../cryptography/hazmat/primitives/twofactor/__pycache__/__init__.cpython-34.pyc
../cryptography/hazmat/primitives/twofactor/__pycache__/hotp.cpython-34.pyc
../cryptography/hazmat/primitives/twofactor/__pycache__/totp.cpython-34.pyc
../cryptography/hazmat/primitives/twofactor/__pycache__/utils.cpython-34.pyc
../cryptography/hazmat/bindings/_openssl.cpython-34m.so
../cryptography/hazmat/bindings/_constant_time.cpython-34m.so
../cryptography/hazmat/bindings/_padding.cpython-34m.so
./ ./
dependency_links.txt dependency_links.txt
entry_points.txt entry_points.txt
PKG-INFO
SOURCES.txt
not-zip-safe not-zip-safe
top_level.txt PKG-INFO
requires.txt requires.txt
SOURCES.txt
top_level.txt

View file

@ -0,0 +1,5 @@
idna>=2.0
pyasn1>=0.1.8
six>=1.4.1
setuptools
cffi>=1.1.0

View file

@ -0,0 +1,4 @@
_constant_time
_openssl
_padding
cryptography

View file

@ -1,15 +1,7 @@
# Licensed under the Apache License, Version 2.0 (the "License"); # This file is dual licensed under the terms of the Apache License, Version
# you may not use this file except in compliance with the License. # 2.0, and the BSD License. See the LICENSE file in the root of this repository
# You may obtain a copy of the License at # for complete details.
#
# 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 from __future__ import absolute_import, division, print_function
__all__ = [ __all__ = [
@ -22,10 +14,10 @@ __summary__ = ("cryptography is a package which provides cryptographic recipes"
" and primitives to Python developers.") " and primitives to Python developers.")
__uri__ = "https://github.com/pyca/cryptography" __uri__ = "https://github.com/pyca/cryptography"
__version__ = "0.6" __version__ = "1.1"
__author__ = "The cryptography developers" __author__ = "The cryptography developers"
__email__ = "cryptography-dev@python.org" __email__ = "cryptography-dev@python.org"
__license__ = "Apache License, Version 2.0" __license__ = "BSD or Apache License, Version 2.0"
__copyright__ = "Copyright 2013-2014 {0}".format(__author__) __copyright__ = "Copyright 2013-2015 {0}".format(__author__)

View file

@ -1,18 +1,12 @@
# Licensed under the Apache License, Version 2.0 (the "License"); # This file is dual licensed under the terms of the Apache License, Version
# you may not use this file except in compliance with the License. # 2.0, and the BSD License. See the LICENSE file in the root of this repository
# You may obtain a copy of the License at # for complete details.
#
# 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 from __future__ import absolute_import, division, print_function
import sys
import warnings
from cryptography.__about__ import ( from cryptography.__about__ import (
__author__, __copyright__, __email__, __license__, __summary__, __title__, __author__, __copyright__, __email__, __license__, __summary__, __title__,
__uri__, __version__ __uri__, __version__
@ -23,3 +17,10 @@ __all__ = [
"__title__", "__summary__", "__uri__", "__version__", "__author__", "__title__", "__summary__", "__uri__", "__version__", "__author__",
"__email__", "__license__", "__copyright__", "__email__", "__license__", "__copyright__",
] ]
if sys.version_info[:2] == (2, 6):
warnings.warn(
"Python 2.6 is no longer supported by the Python core team, please "
"upgrade your Python.",
DeprecationWarning
)

View file

@ -1,28 +1,26 @@
# Licensed under the Apache License, Version 2.0 (the "License"); # This file is dual licensed under the terms of the Apache License, Version
# you may not use this file except in compliance with the License. # 2.0, and the BSD License. See the LICENSE file in the root of this repository
# You may obtain a copy of the License at # for complete details.
#
# 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 from __future__ import absolute_import, division, print_function
from enum import Enum
class _Reasons(object): from cryptography import utils
BACKEND_MISSING_INTERFACE = object() from cryptography.hazmat.primitives import twofactor
UNSUPPORTED_HASH = object()
UNSUPPORTED_CIPHER = object()
UNSUPPORTED_PADDING = object() class _Reasons(Enum):
UNSUPPORTED_MGF = object() BACKEND_MISSING_INTERFACE = 0
UNSUPPORTED_PUBLIC_KEY_ALGORITHM = object() UNSUPPORTED_HASH = 1
UNSUPPORTED_ELLIPTIC_CURVE = object() UNSUPPORTED_CIPHER = 2
UNSUPPORTED_SERIALIZATION = object() UNSUPPORTED_PADDING = 3
UNSUPPORTED_MGF = 4
UNSUPPORTED_PUBLIC_KEY_ALGORITHM = 5
UNSUPPORTED_ELLIPTIC_CURVE = 6
UNSUPPORTED_SERIALIZATION = 7
UNSUPPORTED_X509 = 8
UNSUPPORTED_EXCHANGE_ALGORITHM = 9
class UnsupportedAlgorithm(Exception): class UnsupportedAlgorithm(Exception):
@ -52,12 +50,21 @@ class InvalidSignature(Exception):
class InternalError(Exception): class InternalError(Exception):
pass def __init__(self, msg, err_code):
super(InternalError, self).__init__(msg)
self.err_code = err_code
class InvalidKey(Exception): class InvalidKey(Exception):
pass pass
class InvalidToken(Exception): InvalidToken = utils.deprecated(
pass twofactor.InvalidToken,
__name__,
(
"The InvalidToken exception has moved to the "
"cryptography.hazmat.primitives.twofactor module"
),
utils.DeprecatedIn09
)

View file

@ -1,15 +1,6 @@
# Licensed under the Apache License, Version 2.0 (the "License"); # This file is dual licensed under the terms of the Apache License, Version
# you may not use this file except in compliance with the License. # 2.0, and the BSD License. See the LICENSE file in the root of this repository
# You may obtain a copy of the License at # for complete details.
#
# 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 from __future__ import absolute_import, division, print_function
@ -90,7 +81,7 @@ class Fernet(object):
except (TypeError, binascii.Error): except (TypeError, binascii.Error):
raise InvalidToken raise InvalidToken
if six.indexbytes(data, 0) != 0x80: if not data or six.indexbytes(data, 0) != 0x80:
raise InvalidToken raise InvalidToken
try: try:
@ -127,3 +118,24 @@ class Fernet(object):
except ValueError: except ValueError:
raise InvalidToken raise InvalidToken
return unpadded return unpadded
class MultiFernet(object):
def __init__(self, fernets):
fernets = list(fernets)
if not fernets:
raise ValueError(
"MultiFernet requires at least one Fernet instance"
)
self._fernets = fernets
def encrypt(self, msg):
return self._fernets[0].encrypt(msg)
def decrypt(self, msg, ttl=None):
for f in self._fernets:
try:
return f.decrypt(msg, ttl)
except InvalidToken:
pass
raise InvalidToken

View file

@ -1,14 +1,5 @@
# Licensed under the Apache License, Version 2.0 (the "License"); # This file is dual licensed under the terms of the Apache License, Version
# you may not use this file except in compliance with the License. # 2.0, and the BSD License. See the LICENSE file in the root of this repository
# You may obtain a copy of the License at # for complete details.
#
# 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 from __future__ import absolute_import, division, print_function

View file

@ -1,15 +1,6 @@
# Licensed under the Apache License, Version 2.0 (the "License"); # This file is dual licensed under the terms of the Apache License, Version
# you may not use this file except in compliance with the License. # 2.0, and the BSD License. See the LICENSE file in the root of this repository
# You may obtain a copy of the License at # for complete details.
#
# 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 from __future__ import absolute_import, division, print_function
@ -26,8 +17,13 @@ def _available_backends():
if _available_backends_list is None: if _available_backends_list is None:
_available_backends_list = [ _available_backends_list = [
backend.load(require=False) # setuptools 11.3 deprecated support for the require parameter to
for backend in pkg_resources.iter_entry_points( # load(), and introduced the new resolve() method instead.
# This can be removed if/when we can assume setuptools>=11.3. At
# some point we may wish to add a warning, to push people along,
# but at present this would result in too many warnings.
ep.resolve() if hasattr(ep, "resolve") else ep.load(require=False)
for ep in pkg_resources.iter_entry_points(
"cryptography.backends" "cryptography.backends"
) )
] ]

View file

@ -1,15 +1,6 @@
# Licensed under the Apache License, Version 2.0 (the "License"); # This file is dual licensed under the terms of the Apache License, Version
# you may not use this file except in compliance with the License. # 2.0, and the BSD License. See the LICENSE file in the root of this repository
# You may obtain a copy of the License at # for complete details.
#
# 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 from __future__ import absolute_import, division, print_function

View file

@ -1,15 +1,6 @@
# Licensed under the Apache License, Version 2.0 (the "License"); # This file is dual licensed under the terms of the Apache License, Version
# you may not use this file except in compliance with the License. # 2.0, and the BSD License. See the LICENSE file in the root of this repository
# You may obtain a copy of the License at # for complete details.
#
# 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 from __future__ import absolute_import, division, print_function
@ -236,7 +227,8 @@ class Backend(object):
else: else:
raise InternalError( raise InternalError(
"The backend returned an unknown error, consider filing a bug." "The backend returned an unknown error, consider filing a bug."
" Code: {0}.".format(response) " Code: {0}.".format(response),
response
) )
def _release_cipher_ctx(self, ctx): def _release_cipher_ctx(self, ctx):

View file

@ -1,15 +1,6 @@
# Licensed under the Apache License, Version 2.0 (the "License"); # This file is dual licensed under the terms of the Apache License, Version
# you may not use this file except in compliance with the License. # 2.0, and the BSD License. See the LICENSE file in the root of this repository
# You may obtain a copy of the License at # for complete details.
#
# 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 from __future__ import absolute_import, division, print_function
@ -17,13 +8,14 @@ from cryptography import utils
from cryptography.exceptions import ( from cryptography.exceptions import (
InvalidTag, UnsupportedAlgorithm, _Reasons InvalidTag, UnsupportedAlgorithm, _Reasons
) )
from cryptography.hazmat.primitives import constant_time, interfaces from cryptography.hazmat.primitives import ciphers, constant_time
from cryptography.hazmat.primitives.ciphers import modes
from cryptography.hazmat.primitives.ciphers.modes import ( from cryptography.hazmat.primitives.ciphers.modes import (
CFB, CFB8, CTR, OFB CFB, CFB8, CTR, OFB
) )
@utils.register_interface(interfaces.CipherContext) @utils.register_interface(ciphers.CipherContext)
class _CipherContext(object): class _CipherContext(object):
def __init__(self, backend, cipher, mode, operation): def __init__(self, backend, cipher, mode, operation):
self._backend = backend self._backend = backend
@ -40,7 +32,7 @@ class _CipherContext(object):
# treat RC4 and other stream cipher block sizes). # treat RC4 and other stream cipher block sizes).
# This bug has been filed as rdar://15589470 # This bug has been filed as rdar://15589470
self._bytes_processed = 0 self._bytes_processed = 0
if (isinstance(cipher, interfaces.BlockCipherAlgorithm) and not if (isinstance(cipher, ciphers.BlockCipherAlgorithm) and not
isinstance(mode, (OFB, CFB, CFB8, CTR))): isinstance(mode, (OFB, CFB, CFB8, CTR))):
self._byte_block_size = cipher.block_size // 8 self._byte_block_size = cipher.block_size // 8
else: else:
@ -60,9 +52,9 @@ class _CipherContext(object):
ctx = self._backend._ffi.new("CCCryptorRef *") ctx = self._backend._ffi.new("CCCryptorRef *")
ctx = self._backend._ffi.gc(ctx, self._backend._release_cipher_ctx) ctx = self._backend._ffi.gc(ctx, self._backend._release_cipher_ctx)
if isinstance(mode, interfaces.ModeWithInitializationVector): if isinstance(mode, modes.ModeWithInitializationVector):
iv_nonce = mode.initialization_vector iv_nonce = mode.initialization_vector
elif isinstance(mode, interfaces.ModeWithNonce): elif isinstance(mode, modes.ModeWithNonce):
iv_nonce = mode.nonce iv_nonce = mode.nonce
else: else:
iv_nonce = self._backend._ffi.NULL iv_nonce = self._backend._ffi.NULL
@ -110,8 +102,8 @@ class _CipherContext(object):
return self._backend._ffi.buffer(buf)[:outlen[0]] return self._backend._ffi.buffer(buf)[:outlen[0]]
@utils.register_interface(interfaces.AEADCipherContext) @utils.register_interface(ciphers.AEADCipherContext)
@utils.register_interface(interfaces.AEADEncryptionContext) @utils.register_interface(ciphers.AEADEncryptionContext)
class _GCMCipherContext(object): class _GCMCipherContext(object):
def __init__(self, backend, cipher, mode, operation): def __init__(self, backend, cipher, mode, operation):
self._backend = backend self._backend = backend
@ -198,6 +190,4 @@ class _GCMCipherContext(object):
) )
self._backend._check_cipher_response(res) self._backend._check_cipher_response(res)
@property tag = utils.read_only_property("_tag")
def tag(self):
return self._tag

View file

@ -1,27 +1,18 @@
# Licensed under the Apache License, Version 2.0 (the "License"); # This file is dual licensed under the terms of the Apache License, Version
# you may not use this file except in compliance with the License. # 2.0, and the BSD License. See the LICENSE file in the root of this repository
# You may obtain a copy of the License at # for complete details.
#
# 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 from __future__ import absolute_import, division, print_function
from cryptography import utils from cryptography import utils
from cryptography.exceptions import UnsupportedAlgorithm, _Reasons from cryptography.exceptions import UnsupportedAlgorithm, _Reasons
from cryptography.hazmat.primitives import interfaces from cryptography.hazmat.primitives import hashes
@utils.register_interface(interfaces.HashContext) @utils.register_interface(hashes.HashContext)
class _HashContext(object): class _HashContext(object):
def __init__(self, backend, algorithm, ctx=None): def __init__(self, backend, algorithm, ctx=None):
self.algorithm = algorithm self._algorithm = algorithm
self._backend = backend self._backend = backend
if ctx is None: if ctx is None:
@ -39,6 +30,8 @@ class _HashContext(object):
self._ctx = ctx self._ctx = ctx
algorithm = utils.read_only_property("_algorithm")
def copy(self): def copy(self):
methods = self._backend._hash_mapping[self.algorithm.name] methods = self._backend._hash_mapping[self.algorithm.name]
new_ctx = self._backend._ffi.new(methods.ctx) new_ctx = self._backend._ffi.new(methods.ctx)

View file

@ -1,27 +1,21 @@
# Licensed under the Apache License, Version 2.0 (the "License"); # This file is dual licensed under the terms of the Apache License, Version
# you may not use this file except in compliance with the License. # 2.0, and the BSD License. See the LICENSE file in the root of this repository
# You may obtain a copy of the License at # for complete details.
#
# 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 from __future__ import absolute_import, division, print_function
from cryptography import utils from cryptography import utils
from cryptography.exceptions import UnsupportedAlgorithm, _Reasons from cryptography.exceptions import (
from cryptography.hazmat.primitives import interfaces InvalidSignature, UnsupportedAlgorithm, _Reasons
)
from cryptography.hazmat.primitives import constant_time, hashes, interfaces
@utils.register_interface(interfaces.HashContext) @utils.register_interface(interfaces.MACContext)
@utils.register_interface(hashes.HashContext)
class _HMACContext(object): class _HMACContext(object):
def __init__(self, backend, key, algorithm, ctx=None): def __init__(self, backend, key, algorithm, ctx=None):
self.algorithm = algorithm self._algorithm = algorithm
self._backend = backend self._backend = backend
if ctx is None: if ctx is None:
ctx = self._backend._ffi.new("CCHmacContext *") ctx = self._backend._ffi.new("CCHmacContext *")
@ -39,6 +33,8 @@ class _HMACContext(object):
self._ctx = ctx self._ctx = ctx
self._key = key self._key = key
algorithm = utils.read_only_property("_algorithm")
def copy(self): def copy(self):
copied_ctx = self._backend._ffi.new("CCHmacContext *") copied_ctx = self._backend._ffi.new("CCHmacContext *")
# CommonCrypto has no APIs for copying HMACs, so we have to copy the # CommonCrypto has no APIs for copying HMACs, so we have to copy the
@ -56,3 +52,8 @@ class _HMACContext(object):
self.algorithm.digest_size) self.algorithm.digest_size)
self._backend._lib.CCHmacFinal(self._ctx, buf) self._backend._lib.CCHmacFinal(self._ctx, buf)
return self._backend._ffi.buffer(buf)[:] return self._backend._ffi.buffer(buf)[:]
def verify(self, signature):
digest = self.finalize()
if not constant_time.bytes_eq(digest, signature):
raise InvalidSignature("Signature did not match digest.")

View file

@ -1,15 +1,6 @@
# Licensed under the Apache License, Version 2.0 (the "License"); # This file is dual licensed under the terms of the Apache License, Version
# you may not use this file except in compliance with the License. # 2.0, and the BSD License. See the LICENSE file in the root of this repository
# You may obtain a copy of the License at # for complete details.
#
# 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 from __future__ import absolute_import, division, print_function
@ -66,7 +57,7 @@ class HMACBackend(object):
@abc.abstractmethod @abc.abstractmethod
def create_hmac_ctx(self, key, algorithm): def create_hmac_ctx(self, key, algorithm):
""" """
Create a HashContext for calculating a message authentication code. Create a MACContext for calculating a message authentication code.
""" """
@ -81,7 +72,7 @@ class CMACBackend(object):
@abc.abstractmethod @abc.abstractmethod
def create_cmac_ctx(self, algorithm): def create_cmac_ctx(self, algorithm):
""" """
Create a CMACContext for calculating a message authentication code. Create a MACContext for calculating a message authentication code.
""" """
@ -111,39 +102,6 @@ class RSABackend(object):
of key_size bits. of key_size bits.
""" """
@abc.abstractmethod
def create_rsa_signature_ctx(self, private_key, padding, algorithm):
"""
Returns an object conforming to the AsymmetricSignatureContext
interface.
"""
@abc.abstractmethod
def create_rsa_verification_ctx(self, public_key, signature, padding,
algorithm):
"""
Returns an object conforming to the AsymmetricVerificationContext
interface.
"""
@abc.abstractmethod
def mgf1_hash_supported(self, algorithm):
"""
Return True if the hash algorithm is supported for MGF1 in PSS.
"""
@abc.abstractmethod
def decrypt_rsa(self, private_key, ciphertext, padding):
"""
Returns decrypted bytes.
"""
@abc.abstractmethod
def encrypt_rsa(self, public_key, plaintext, padding):
"""
Returns encrypted bytes.
"""
@abc.abstractmethod @abc.abstractmethod
def rsa_padding_supported(self, padding): def rsa_padding_supported(self, padding):
""" """
@ -191,20 +149,6 @@ class DSABackend(object):
Generate a DSAPrivateKey instance using key size only. Generate a DSAPrivateKey instance using key size only.
""" """
@abc.abstractmethod
def create_dsa_signature_ctx(self, private_key, algorithm):
"""
Returns an object conforming to the AsymmetricSignatureContext
interface.
"""
@abc.abstractmethod
def create_dsa_verification_ctx(self, public_key, signature, algorithm):
"""
Returns an object conforming to the AsymmetricVerificationContext
interface.
"""
@abc.abstractmethod @abc.abstractmethod
def dsa_hash_supported(self, algorithm): def dsa_hash_supported(self, algorithm):
""" """
@ -268,7 +212,13 @@ class EllipticCurveBackend(object):
@abc.abstractmethod @abc.abstractmethod
def load_elliptic_curve_private_numbers(self, numbers): def load_elliptic_curve_private_numbers(self, numbers):
""" """
Return an EllipticCurvePublicKey provider using the given numbers. Return an EllipticCurvePrivateKey provider using the given numbers.
"""
@abc.abstractmethod
def elliptic_curve_exchange_algorithm_supported(self, algorithm, curve):
"""
Returns whether the exchange algorithm is supported by this backend.
""" """
@ -289,20 +239,107 @@ class PEMSerializationBackend(object):
@six.add_metaclass(abc.ABCMeta) @six.add_metaclass(abc.ABCMeta)
class TraditionalOpenSSLSerializationBackend(object): class DERSerializationBackend(object):
@abc.abstractmethod @abc.abstractmethod
def load_traditional_openssl_pem_private_key(self, data, password): def load_der_private_key(self, data, password):
""" """
Load a private key from PEM encoded data, using password if the data Loads a private key from DER encoded data. Uses the provided password
is encrypted. if the data is encrypted.
"""
@abc.abstractmethod
def load_der_public_key(self, data):
"""
Loads a public key from DER encoded data.
""" """
@six.add_metaclass(abc.ABCMeta) @six.add_metaclass(abc.ABCMeta)
class PKCS8SerializationBackend(object): class X509Backend(object):
@abc.abstractmethod @abc.abstractmethod
def load_pkcs8_pem_private_key(self, data, password): def load_pem_x509_certificate(self, data):
""" """
Load a private key from PKCS8 encoded data, using password if the data Load an X.509 certificate from PEM encoded data.
is encrypted. """
@abc.abstractmethod
def load_der_x509_certificate(self, data):
"""
Load an X.509 certificate from DER encoded data.
"""
@abc.abstractmethod
def load_der_x509_csr(self, data):
"""
Load an X.509 CSR from DER encoded data.
"""
@abc.abstractmethod
def load_pem_x509_csr(self, data):
"""
Load an X.509 CSR from PEM encoded data.
"""
@abc.abstractmethod
def create_x509_csr(self, builder, private_key, algorithm):
"""
Create and sign an X.509 CSR from a CSR builder object.
"""
@abc.abstractmethod
def create_x509_certificate(self, builder, private_key, algorithm):
"""
Create and sign an X.509 certificate from a CertificateBuilder object.
"""
@six.add_metaclass(abc.ABCMeta)
class DHBackend(object):
@abc.abstractmethod
def generate_dh_parameters(self, key_size):
"""
Generate a DHParameters instance with a modulus of key_size bits.
"""
@abc.abstractmethod
def generate_dh_private_key(self, parameters):
"""
Generate a DHPrivateKey instance with parameters as a DHParameters
object.
"""
@abc.abstractmethod
def generate_dh_private_key_and_parameters(self, key_size):
"""
Generate a DHPrivateKey instance using key size only.
"""
@abc.abstractmethod
def load_dh_private_numbers(self, numbers):
"""
Returns a DHPrivateKey provider.
"""
@abc.abstractmethod
def load_dh_public_numbers(self, numbers):
"""
Returns a DHPublicKey provider.
"""
@abc.abstractmethod
def load_dh_parameter_numbers(self, numbers):
"""
Returns a DHParameters provider.
"""
@abc.abstractmethod
def dh_exchange_algorithm_supported(self, exchange_algorithm):
"""
Returns whether the exchange algorithm is supported by this backend.
"""
@abc.abstractmethod
def dh_parameters_supported(self, p, g):
"""
Returns whether the backend supports DH with these parameter values.
""" """

View file

@ -1,41 +1,29 @@
# Licensed under the Apache License, Version 2.0 (the "License"); # This file is dual licensed under the terms of the Apache License, Version
# you may not use this file except in compliance with the License. # 2.0, and the BSD License. See the LICENSE file in the root of this repository
# You may obtain a copy of the License at # for complete details.
#
# 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 from __future__ import absolute_import, division, print_function
import warnings
from cryptography import utils from cryptography import utils
from cryptography.exceptions import UnsupportedAlgorithm, _Reasons from cryptography.exceptions import UnsupportedAlgorithm, _Reasons
from cryptography.hazmat.backends.interfaces import ( from cryptography.hazmat.backends.interfaces import (
CMACBackend, CipherBackend, DSABackend, EllipticCurveBackend, HMACBackend, CMACBackend, CipherBackend, DERSerializationBackend, DSABackend,
HashBackend, PBKDF2HMACBackend, PEMSerializationBackend, EllipticCurveBackend, HMACBackend, HashBackend, PBKDF2HMACBackend,
PKCS8SerializationBackend, RSABackend, PEMSerializationBackend, RSABackend, X509Backend
TraditionalOpenSSLSerializationBackend
) )
@utils.register_interface(CMACBackend) @utils.register_interface(CMACBackend)
@utils.register_interface(CipherBackend) @utils.register_interface(CipherBackend)
@utils.register_interface(DERSerializationBackend)
@utils.register_interface(HashBackend) @utils.register_interface(HashBackend)
@utils.register_interface(HMACBackend) @utils.register_interface(HMACBackend)
@utils.register_interface(PBKDF2HMACBackend) @utils.register_interface(PBKDF2HMACBackend)
@utils.register_interface(PKCS8SerializationBackend)
@utils.register_interface(RSABackend) @utils.register_interface(RSABackend)
@utils.register_interface(TraditionalOpenSSLSerializationBackend)
@utils.register_interface(DSABackend) @utils.register_interface(DSABackend)
@utils.register_interface(EllipticCurveBackend) @utils.register_interface(EllipticCurveBackend)
@utils.register_interface(PEMSerializationBackend) @utils.register_interface(PEMSerializationBackend)
@utils.register_interface(X509Backend)
class MultiBackend(object): class MultiBackend(object):
name = "multibackend" name = "multibackend"
@ -47,33 +35,33 @@ class MultiBackend(object):
if isinstance(b, interface): if isinstance(b, interface):
yield b yield b
def cipher_supported(self, algorithm, mode): def cipher_supported(self, cipher, mode):
return any( return any(
b.cipher_supported(algorithm, mode) b.cipher_supported(cipher, mode)
for b in self._filtered_backends(CipherBackend) for b in self._filtered_backends(CipherBackend)
) )
def create_symmetric_encryption_ctx(self, algorithm, mode): def create_symmetric_encryption_ctx(self, cipher, mode):
for b in self._filtered_backends(CipherBackend): for b in self._filtered_backends(CipherBackend):
try: try:
return b.create_symmetric_encryption_ctx(algorithm, mode) return b.create_symmetric_encryption_ctx(cipher, mode)
except UnsupportedAlgorithm: except UnsupportedAlgorithm:
pass pass
raise UnsupportedAlgorithm( raise UnsupportedAlgorithm(
"cipher {0} in {1} mode is not supported by this backend.".format( "cipher {0} in {1} mode is not supported by this backend.".format(
algorithm.name, mode.name if mode else mode), cipher.name, mode.name if mode else mode),
_Reasons.UNSUPPORTED_CIPHER _Reasons.UNSUPPORTED_CIPHER
) )
def create_symmetric_decryption_ctx(self, algorithm, mode): def create_symmetric_decryption_ctx(self, cipher, mode):
for b in self._filtered_backends(CipherBackend): for b in self._filtered_backends(CipherBackend):
try: try:
return b.create_symmetric_decryption_ctx(algorithm, mode) return b.create_symmetric_decryption_ctx(cipher, mode)
except UnsupportedAlgorithm: except UnsupportedAlgorithm:
pass pass
raise UnsupportedAlgorithm( raise UnsupportedAlgorithm(
"cipher {0} in {1} mode is not supported by this backend.".format( "cipher {0} in {1} mode is not supported by this backend.".format(
algorithm.name, mode.name if mode else mode), cipher.name, mode.name if mode else mode),
_Reasons.UNSUPPORTED_CIPHER _Reasons.UNSUPPORTED_CIPHER
) )
@ -148,38 +136,6 @@ class MultiBackend(object):
raise UnsupportedAlgorithm("RSA is not supported by the backend.", raise UnsupportedAlgorithm("RSA is not supported by the backend.",
_Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM) _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM)
def create_rsa_signature_ctx(self, private_key, padding, algorithm):
for b in self._filtered_backends(RSABackend):
return b.create_rsa_signature_ctx(private_key, padding, algorithm)
raise UnsupportedAlgorithm("RSA is not supported by the backend.",
_Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM)
def create_rsa_verification_ctx(self, public_key, signature, padding,
algorithm):
for b in self._filtered_backends(RSABackend):
return b.create_rsa_verification_ctx(public_key, signature,
padding, algorithm)
raise UnsupportedAlgorithm("RSA is not supported by the backend.",
_Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM)
def mgf1_hash_supported(self, algorithm):
for b in self._filtered_backends(RSABackend):
return b.mgf1_hash_supported(algorithm)
raise UnsupportedAlgorithm("RSA is not supported by the backend.",
_Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM)
def decrypt_rsa(self, private_key, ciphertext, padding):
for b in self._filtered_backends(RSABackend):
return b.decrypt_rsa(private_key, ciphertext, padding)
raise UnsupportedAlgorithm("RSA is not supported by the backend.",
_Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM)
def encrypt_rsa(self, public_key, plaintext, padding):
for b in self._filtered_backends(RSABackend):
return b.encrypt_rsa(public_key, plaintext, padding)
raise UnsupportedAlgorithm("RSA is not supported by the backend.",
_Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM)
def rsa_padding_supported(self, padding): def rsa_padding_supported(self, padding):
for b in self._filtered_backends(RSABackend): for b in self._filtered_backends(RSABackend):
return b.rsa_padding_supported(padding) return b.rsa_padding_supported(padding)
@ -218,19 +174,6 @@ class MultiBackend(object):
raise UnsupportedAlgorithm("DSA is not supported by the backend.", raise UnsupportedAlgorithm("DSA is not supported by the backend.",
_Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM) _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM)
def create_dsa_verification_ctx(self, public_key, signature, algorithm):
for b in self._filtered_backends(DSABackend):
return b.create_dsa_verification_ctx(public_key, signature,
algorithm)
raise UnsupportedAlgorithm("DSA is not supported by the backend.",
_Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM)
def create_dsa_signature_ctx(self, private_key, algorithm):
for b in self._filtered_backends(DSABackend):
return b.create_dsa_signature_ctx(private_key, algorithm)
raise UnsupportedAlgorithm("DSA is not supported by the backend.",
_Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM)
def dsa_hash_supported(self, algorithm): def dsa_hash_supported(self, algorithm):
for b in self._filtered_backends(DSABackend): for b in self._filtered_backends(DSABackend):
return b.dsa_hash_supported(algorithm) return b.dsa_hash_supported(algorithm)
@ -255,6 +198,12 @@ class MultiBackend(object):
raise UnsupportedAlgorithm("DSA is not supported by the backend.", raise UnsupportedAlgorithm("DSA is not supported by the backend.",
_Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM) _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM)
def load_dsa_parameter_numbers(self, numbers):
for b in self._filtered_backends(DSABackend):
return b.load_dsa_parameter_numbers(numbers)
raise UnsupportedAlgorithm("DSA is not supported by the backend.",
_Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM)
def cmac_algorithm_supported(self, algorithm): def cmac_algorithm_supported(self, algorithm):
return any( return any(
b.cmac_algorithm_supported(algorithm) b.cmac_algorithm_supported(algorithm)
@ -298,24 +247,6 @@ class MultiBackend(object):
_Reasons.UNSUPPORTED_ELLIPTIC_CURVE _Reasons.UNSUPPORTED_ELLIPTIC_CURVE
) )
def elliptic_curve_private_key_from_numbers(self, numbers):
warnings.warn(
"elliptic_curve_private_key_from_numbers is deprecated and will "
"be removed in a future version.",
utils.DeprecatedIn06,
stacklevel=2
)
for b in self._filtered_backends(EllipticCurveBackend):
try:
return b.elliptic_curve_private_key_from_numbers(numbers)
except UnsupportedAlgorithm:
continue
raise UnsupportedAlgorithm(
"This backend does not support this elliptic curve.",
_Reasons.UNSUPPORTED_ELLIPTIC_CURVE
)
def load_elliptic_curve_private_numbers(self, numbers): def load_elliptic_curve_private_numbers(self, numbers):
for b in self._filtered_backends(EllipticCurveBackend): for b in self._filtered_backends(EllipticCurveBackend):
try: try:
@ -328,24 +259,6 @@ class MultiBackend(object):
_Reasons.UNSUPPORTED_ELLIPTIC_CURVE _Reasons.UNSUPPORTED_ELLIPTIC_CURVE
) )
def elliptic_curve_public_key_from_numbers(self, numbers):
warnings.warn(
"elliptic_curve_public_key_from_numbers is deprecated and will "
"be removed in a future version.",
utils.DeprecatedIn06,
stacklevel=2
)
for b in self._filtered_backends(EllipticCurveBackend):
try:
return b.elliptic_curve_public_key_from_numbers(numbers)
except UnsupportedAlgorithm:
continue
raise UnsupportedAlgorithm(
"This backend does not support this elliptic curve.",
_Reasons.UNSUPPORTED_ELLIPTIC_CURVE
)
def load_elliptic_curve_public_numbers(self, numbers): def load_elliptic_curve_public_numbers(self, numbers):
for b in self._filtered_backends(EllipticCurveBackend): for b in self._filtered_backends(EllipticCurveBackend):
try: try:
@ -358,6 +271,12 @@ class MultiBackend(object):
_Reasons.UNSUPPORTED_ELLIPTIC_CURVE _Reasons.UNSUPPORTED_ELLIPTIC_CURVE
) )
def elliptic_curve_exchange_algorithm_supported(self, algorithm, curve):
return any(
b.elliptic_curve_exchange_algorithm_supported(algorithm, curve)
for b in self._filtered_backends(EllipticCurveBackend)
)
def load_pem_private_key(self, data, password): def load_pem_private_key(self, data, password):
for b in self._filtered_backends(PEMSerializationBackend): for b in self._filtered_backends(PEMSerializationBackend):
return b.load_pem_private_key(data, password) return b.load_pem_private_key(data, password)
@ -376,22 +295,92 @@ class MultiBackend(object):
_Reasons.UNSUPPORTED_SERIALIZATION _Reasons.UNSUPPORTED_SERIALIZATION
) )
def load_pkcs8_pem_private_key(self, data, password): def load_der_private_key(self, data, password):
for b in self._filtered_backends(PKCS8SerializationBackend): for b in self._filtered_backends(DERSerializationBackend):
return b.load_pkcs8_pem_private_key(data, password) return b.load_der_private_key(data, password)
raise UnsupportedAlgorithm( raise UnsupportedAlgorithm(
"This backend does not support this key serialization.", "This backend does not support this key serialization.",
_Reasons.UNSUPPORTED_SERIALIZATION _Reasons.UNSUPPORTED_SERIALIZATION
) )
def load_traditional_openssl_pem_private_key(self, data, password): def load_der_public_key(self, data):
for b in self._filtered_backends( for b in self._filtered_backends(DERSerializationBackend):
TraditionalOpenSSLSerializationBackend return b.load_der_public_key(data)
):
return b.load_traditional_openssl_pem_private_key(data, password)
raise UnsupportedAlgorithm( raise UnsupportedAlgorithm(
"This backend does not support this key serialization.", "This backend does not support this key serialization.",
_Reasons.UNSUPPORTED_SERIALIZATION _Reasons.UNSUPPORTED_SERIALIZATION
) )
def load_pem_x509_certificate(self, data):
for b in self._filtered_backends(X509Backend):
return b.load_pem_x509_certificate(data)
raise UnsupportedAlgorithm(
"This backend does not support X.509.",
_Reasons.UNSUPPORTED_X509
)
def load_der_x509_certificate(self, data):
for b in self._filtered_backends(X509Backend):
return b.load_der_x509_certificate(data)
raise UnsupportedAlgorithm(
"This backend does not support X.509.",
_Reasons.UNSUPPORTED_X509
)
def load_pem_x509_crl(self, data):
for b in self._filtered_backends(X509Backend):
return b.load_pem_x509_crl(data)
raise UnsupportedAlgorithm(
"This backend does not support X.509.",
_Reasons.UNSUPPORTED_X509
)
def load_der_x509_crl(self, data):
for b in self._filtered_backends(X509Backend):
return b.load_der_x509_crl(data)
raise UnsupportedAlgorithm(
"This backend does not support X.509.",
_Reasons.UNSUPPORTED_X509
)
def load_der_x509_csr(self, data):
for b in self._filtered_backends(X509Backend):
return b.load_der_x509_csr(data)
raise UnsupportedAlgorithm(
"This backend does not support X.509.",
_Reasons.UNSUPPORTED_X509
)
def load_pem_x509_csr(self, data):
for b in self._filtered_backends(X509Backend):
return b.load_pem_x509_csr(data)
raise UnsupportedAlgorithm(
"This backend does not support X.509.",
_Reasons.UNSUPPORTED_X509
)
def create_x509_csr(self, builder, private_key, algorithm):
for b in self._filtered_backends(X509Backend):
return b.create_x509_csr(builder, private_key, algorithm)
raise UnsupportedAlgorithm(
"This backend does not support X.509.",
_Reasons.UNSUPPORTED_X509
)
def create_x509_certificate(self, builder, private_key, algorithm):
for b in self._filtered_backends(X509Backend):
return b.create_x509_certificate(builder, private_key, algorithm)
raise UnsupportedAlgorithm(
"This backend does not support X.509.",
_Reasons.UNSUPPORTED_X509
)

View file

@ -1,15 +1,6 @@
# Licensed under the Apache License, Version 2.0 (the "License"); # This file is dual licensed under the terms of the Apache License, Version
# you may not use this file except in compliance with the License. # 2.0, and the BSD License. See the LICENSE file in the root of this repository
# You may obtain a copy of the License at # for complete details.
#
# 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 from __future__ import absolute_import, division, print_function

View file

@ -1,27 +1,18 @@
# Licensed under the Apache License, Version 2.0 (the "License"); # This file is dual licensed under the terms of the Apache License, Version
# you may not use this file except in compliance with the License. # 2.0, and the BSD License. See the LICENSE file in the root of this repository
# You may obtain a copy of the License at # for complete details.
#
# 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 from __future__ import absolute_import, division, print_function
from cryptography import utils from cryptography import utils
from cryptography.exceptions import InvalidTag, UnsupportedAlgorithm, _Reasons from cryptography.exceptions import InvalidTag, UnsupportedAlgorithm, _Reasons
from cryptography.hazmat.primitives import interfaces from cryptography.hazmat.primitives import ciphers
from cryptography.hazmat.primitives.ciphers.modes import GCM from cryptography.hazmat.primitives.ciphers import modes
@utils.register_interface(interfaces.CipherContext) @utils.register_interface(ciphers.CipherContext)
@utils.register_interface(interfaces.AEADCipherContext) @utils.register_interface(ciphers.AEADCipherContext)
@utils.register_interface(interfaces.AEADEncryptionContext) @utils.register_interface(ciphers.AEADEncryptionContext)
class _CipherContext(object): class _CipherContext(object):
_ENCRYPT = 1 _ENCRYPT = 1
_DECRYPT = 0 _DECRYPT = 0
@ -33,7 +24,7 @@ class _CipherContext(object):
self._operation = operation self._operation = operation
self._tag = None self._tag = None
if isinstance(self._cipher, interfaces.BlockCipherAlgorithm): if isinstance(self._cipher, ciphers.BlockCipherAlgorithm):
self._block_size = self._cipher.block_size self._block_size = self._cipher.block_size
else: else:
self._block_size = 1 self._block_size = 1
@ -63,9 +54,9 @@ class _CipherContext(object):
_Reasons.UNSUPPORTED_CIPHER _Reasons.UNSUPPORTED_CIPHER
) )
if isinstance(mode, interfaces.ModeWithInitializationVector): if isinstance(mode, modes.ModeWithInitializationVector):
iv_nonce = mode.initialization_vector iv_nonce = mode.initialization_vector
elif isinstance(mode, interfaces.ModeWithNonce): elif isinstance(mode, modes.ModeWithNonce):
iv_nonce = mode.nonce iv_nonce = mode.nonce
else: else:
iv_nonce = self._backend._ffi.NULL iv_nonce = self._backend._ffi.NULL
@ -75,24 +66,24 @@ class _CipherContext(object):
self._backend._ffi.NULL, self._backend._ffi.NULL,
self._backend._ffi.NULL, self._backend._ffi.NULL,
operation) operation)
assert res != 0 self._backend.openssl_assert(res != 0)
# set the key length to handle variable key ciphers # set the key length to handle variable key ciphers
res = self._backend._lib.EVP_CIPHER_CTX_set_key_length( res = self._backend._lib.EVP_CIPHER_CTX_set_key_length(
ctx, len(cipher.key) ctx, len(cipher.key)
) )
assert res != 0 self._backend.openssl_assert(res != 0)
if isinstance(mode, GCM): if isinstance(mode, modes.GCM):
res = self._backend._lib.EVP_CIPHER_CTX_ctrl( res = self._backend._lib.EVP_CIPHER_CTX_ctrl(
ctx, self._backend._lib.EVP_CTRL_GCM_SET_IVLEN, ctx, self._backend._lib.EVP_CTRL_GCM_SET_IVLEN,
len(iv_nonce), self._backend._ffi.NULL len(iv_nonce), self._backend._ffi.NULL
) )
assert res != 0 self._backend.openssl_assert(res != 0)
if operation == self._DECRYPT: if operation == self._DECRYPT:
res = self._backend._lib.EVP_CIPHER_CTX_ctrl( res = self._backend._lib.EVP_CIPHER_CTX_ctrl(
ctx, self._backend._lib.EVP_CTRL_GCM_SET_TAG, ctx, self._backend._lib.EVP_CTRL_GCM_SET_TAG,
len(mode.tag), mode.tag len(mode.tag), mode.tag
) )
assert res != 0 self._backend.openssl_assert(res != 0)
# pass key/iv # pass key/iv
res = self._backend._lib.EVP_CipherInit_ex( res = self._backend._lib.EVP_CipherInit_ex(
@ -103,7 +94,7 @@ class _CipherContext(object):
iv_nonce, iv_nonce,
operation operation
) )
assert res != 0 self._backend.openssl_assert(res != 0)
# We purposely disable padding here as it's handled higher up in the # We purposely disable padding here as it's handled higher up in the
# API. # API.
self._backend._lib.EVP_CIPHER_CTX_set_padding(ctx, 0) self._backend._lib.EVP_CIPHER_CTX_set_padding(ctx, 0)
@ -116,7 +107,7 @@ class _CipherContext(object):
# should be taken only when length is zero and mode is not GCM because # should be taken only when length is zero and mode is not GCM because
# AES GCM can return improper tag values if you don't call update # AES GCM can return improper tag values if you don't call update
# with empty plaintext when authenticating AAD for ...reasons. # with empty plaintext when authenticating AAD for ...reasons.
if len(data) == 0 and not isinstance(self._mode, GCM): if len(data) == 0 and not isinstance(self._mode, modes.GCM):
return b"" return b""
buf = self._backend._ffi.new("unsigned char[]", buf = self._backend._ffi.new("unsigned char[]",
@ -124,7 +115,7 @@ class _CipherContext(object):
outlen = self._backend._ffi.new("int *") outlen = self._backend._ffi.new("int *")
res = self._backend._lib.EVP_CipherUpdate(self._ctx, buf, outlen, data, res = self._backend._lib.EVP_CipherUpdate(self._ctx, buf, outlen, data,
len(data)) len(data))
assert res != 0 self._backend.openssl_assert(res != 0)
return self._backend._ffi.buffer(buf)[:outlen[0]] return self._backend._ffi.buffer(buf)[:outlen[0]]
def finalize(self): def finalize(self):
@ -133,7 +124,7 @@ class _CipherContext(object):
# even if you are only using authenticate_additional_data or the # even if you are only using authenticate_additional_data or the
# GCM tag will be wrong. An (empty) call to update resolves this # GCM tag will be wrong. An (empty) call to update resolves this
# and is harmless for all other versions of OpenSSL. # and is harmless for all other versions of OpenSSL.
if isinstance(self._mode, GCM): if isinstance(self._mode, modes.GCM):
self.update(b"") self.update(b"")
buf = self._backend._ffi.new("unsigned char[]", self._block_size) buf = self._backend._ffi.new("unsigned char[]", self._block_size)
@ -142,12 +133,11 @@ class _CipherContext(object):
if res == 0: if res == 0:
errors = self._backend._consume_errors() errors = self._backend._consume_errors()
if not errors and isinstance(self._mode, GCM): if not errors and isinstance(self._mode, modes.GCM):
raise InvalidTag raise InvalidTag
assert errors self._backend.openssl_assert(
errors[0][1:] == (
if errors[0][1:] == (
self._backend._lib.ERR_LIB_EVP, self._backend._lib.ERR_LIB_EVP,
self._backend._lib.EVP_F_EVP_ENCRYPTFINAL_EX, self._backend._lib.EVP_F_EVP_ENCRYPTFINAL_EX,
self._backend._lib.EVP_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH self._backend._lib.EVP_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH
@ -155,15 +145,14 @@ class _CipherContext(object):
self._backend._lib.ERR_LIB_EVP, self._backend._lib.ERR_LIB_EVP,
self._backend._lib.EVP_F_EVP_DECRYPTFINAL_EX, self._backend._lib.EVP_F_EVP_DECRYPTFINAL_EX,
self._backend._lib.EVP_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH self._backend._lib.EVP_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH
): )
)
raise ValueError( raise ValueError(
"The length of the provided data is not a multiple of " "The length of the provided data is not a multiple of "
"the block length." "the block length."
) )
else:
raise self._backend._unknown_error(errors[0])
if (isinstance(self._mode, GCM) and if (isinstance(self._mode, modes.GCM) and
self._operation == self._ENCRYPT): self._operation == self._ENCRYPT):
block_byte_size = self._block_size // 8 block_byte_size = self._block_size // 8
tag_buf = self._backend._ffi.new( tag_buf = self._backend._ffi.new(
@ -173,11 +162,11 @@ class _CipherContext(object):
self._ctx, self._backend._lib.EVP_CTRL_GCM_GET_TAG, self._ctx, self._backend._lib.EVP_CTRL_GCM_GET_TAG,
block_byte_size, tag_buf block_byte_size, tag_buf
) )
assert res != 0 self._backend.openssl_assert(res != 0)
self._tag = self._backend._ffi.buffer(tag_buf)[:] self._tag = self._backend._ffi.buffer(tag_buf)[:]
res = self._backend._lib.EVP_CIPHER_CTX_cleanup(self._ctx) res = self._backend._lib.EVP_CIPHER_CTX_cleanup(self._ctx)
assert res == 1 self._backend.openssl_assert(res == 1)
return self._backend._ffi.buffer(buf)[:outlen[0]] return self._backend._ffi.buffer(buf)[:outlen[0]]
def authenticate_additional_data(self, data): def authenticate_additional_data(self, data):
@ -185,14 +174,12 @@ class _CipherContext(object):
res = self._backend._lib.EVP_CipherUpdate( res = self._backend._lib.EVP_CipherUpdate(
self._ctx, self._backend._ffi.NULL, outlen, data, len(data) self._ctx, self._backend._ffi.NULL, outlen, data, len(data)
) )
assert res != 0 self._backend.openssl_assert(res != 0)
@property tag = utils.read_only_property("_tag")
def tag(self):
return self._tag
@utils.register_interface(interfaces.CipherContext) @utils.register_interface(ciphers.CipherContext)
class _AESCTRCipherContext(object): class _AESCTRCipherContext(object):
""" """
This is needed to provide support for AES CTR mode in OpenSSL 0.9.8. It can This is needed to provide support for AES CTR mode in OpenSSL 0.9.8. It can
@ -202,11 +189,10 @@ class _AESCTRCipherContext(object):
self._backend = backend self._backend = backend
self._key = self._backend._ffi.new("AES_KEY *") self._key = self._backend._ffi.new("AES_KEY *")
assert self._key != self._backend._ffi.NULL
res = self._backend._lib.AES_set_encrypt_key( res = self._backend._lib.AES_set_encrypt_key(
cipher.key, len(cipher.key) * 8, self._key cipher.key, len(cipher.key) * 8, self._key
) )
assert res == 0 self._backend.openssl_assert(res == 0)
self._ecount = self._backend._ffi.new("char[]", 16) self._ecount = self._backend._ffi.new("char[]", 16)
self._nonce = self._backend._ffi.new("char[16]", mode.nonce) self._nonce = self._backend._ffi.new("char[16]", mode.nonce)
self._num = self._backend._ffi.new("unsigned int *", 0) self._num = self._backend._ffi.new("unsigned int *", 0)

View file

@ -1,26 +1,19 @@
# Licensed under the Apache License, Version 2.0 (the "License"); # This file is dual licensed under the terms of the Apache License, Version
# you may not use this file except in compliance with the License. # 2.0, and the BSD License. See the LICENSE file in the root of this repository
# You may obtain a copy of the License at # for complete details.
#
# 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 from __future__ import absolute_import, division, print_function
from cryptography import utils from cryptography import utils
from cryptography.exceptions import UnsupportedAlgorithm, _Reasons from cryptography.exceptions import (
from cryptography.hazmat.primitives import interfaces InvalidSignature, UnsupportedAlgorithm, _Reasons
)
from cryptography.hazmat.primitives import constant_time, interfaces
from cryptography.hazmat.primitives.ciphers.modes import CBC from cryptography.hazmat.primitives.ciphers.modes import CBC
@utils.register_interface(interfaces.CMACContext) @utils.register_interface(interfaces.MACContext)
class _CMACContext(object): class _CMACContext(object):
def __init__(self, backend, algorithm, ctx=None): def __init__(self, backend, algorithm, ctx=None):
if not backend.cmac_algorithm_supported(algorithm): if not backend.cmac_algorithm_supported(algorithm):
@ -40,7 +33,7 @@ class _CMACContext(object):
ctx = self._backend._lib.CMAC_CTX_new() ctx = self._backend._lib.CMAC_CTX_new()
assert ctx != self._backend._ffi.NULL self._backend.openssl_assert(ctx != self._backend._ffi.NULL)
ctx = self._backend._ffi.gc(ctx, self._backend._lib.CMAC_CTX_free) ctx = self._backend._ffi.gc(ctx, self._backend._lib.CMAC_CTX_free)
self._backend._lib.CMAC_Init( self._backend._lib.CMAC_Init(
@ -50,9 +43,11 @@ class _CMACContext(object):
self._ctx = ctx self._ctx = ctx
algorithm = utils.read_only_property("_algorithm")
def update(self, data): def update(self, data):
res = self._backend._lib.CMAC_Update(self._ctx, data, len(data)) res = self._backend._lib.CMAC_Update(self._ctx, data, len(data))
assert res == 1 self._backend.openssl_assert(res == 1)
def finalize(self): def finalize(self):
buf = self._backend._ffi.new("unsigned char[]", self._output_length) buf = self._backend._ffi.new("unsigned char[]", self._output_length)
@ -60,7 +55,7 @@ class _CMACContext(object):
res = self._backend._lib.CMAC_Final( res = self._backend._lib.CMAC_Final(
self._ctx, buf, length self._ctx, buf, length
) )
assert res == 1 self._backend.openssl_assert(res == 1)
self._ctx = None self._ctx = None
@ -74,7 +69,12 @@ class _CMACContext(object):
res = self._backend._lib.CMAC_CTX_copy( res = self._backend._lib.CMAC_CTX_copy(
copied_ctx, self._ctx copied_ctx, self._ctx
) )
assert res == 1 self._backend.openssl_assert(res == 1)
return _CMACContext( return _CMACContext(
self._backend, self._algorithm, ctx=copied_ctx self._backend, self._algorithm, ctx=copied_ctx
) )
def verify(self, signature):
digest = self.finalize()
if not constant_time.bytes_eq(digest, signature):
raise InvalidSignature("Signature did not match digest.")

View file

@ -1,28 +1,32 @@
# Licensed under the Apache License, Version 2.0 (the "License"); # This file is dual licensed under the terms of the Apache License, Version
# you may not use this file except in compliance with the License. # 2.0, and the BSD License. See the LICENSE file in the root of this repository
# You may obtain a copy of the License at # for complete details.
#
# 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 from __future__ import absolute_import, division, print_function
from cryptography import utils from cryptography import utils
from cryptography.exceptions import InvalidSignature from cryptography.exceptions import InvalidSignature
from cryptography.hazmat.primitives import hashes, interfaces from cryptography.hazmat.backends.openssl.utils import _truncate_digest
from cryptography.hazmat.primitives.asymmetric import dsa from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.interfaces import ( from cryptography.hazmat.primitives.asymmetric import (
DSAParametersWithNumbers, DSAPrivateKeyWithNumbers, DSAPublicKeyWithNumbers AsymmetricSignatureContext, AsymmetricVerificationContext, dsa
) )
@utils.register_interface(interfaces.AsymmetricVerificationContext) def _truncate_digest_for_dsa(dsa_cdata, digest, backend):
"""
This function truncates digests that are longer than a given DS
key's length so they can be signed. OpenSSL does this for us in
1.0.0c+ and it isn't needed in 0.9.8, but that leaves us with three
releases (1.0.0, 1.0.0a, and 1.0.0b) where this is a problem. This
truncation is not required in 0.9.8 because DSA is limited to SHA-1.
"""
order_bits = backend._lib.BN_num_bits(dsa_cdata.q)
return _truncate_digest(digest, order_bits)
@utils.register_interface(AsymmetricVerificationContext)
class _DSAVerificationContext(object): class _DSAVerificationContext(object):
def __init__(self, backend, public_key, signature, algorithm): def __init__(self, backend, public_key, signature, algorithm):
self._backend = backend self._backend = backend
@ -36,11 +40,12 @@ class _DSAVerificationContext(object):
self._hash_ctx.update(data) self._hash_ctx.update(data)
def verify(self): def verify(self):
self._dsa_cdata = self._backend._ffi.gc(self._public_key._dsa_cdata,
self._backend._lib.DSA_free)
data_to_verify = self._hash_ctx.finalize() data_to_verify = self._hash_ctx.finalize()
data_to_verify = _truncate_digest_for_dsa(
self._public_key._dsa_cdata, data_to_verify, self._backend
)
# The first parameter passed to DSA_verify is unused by OpenSSL but # The first parameter passed to DSA_verify is unused by OpenSSL but
# must be an integer. # must be an integer.
res = self._backend._lib.DSA_verify( res = self._backend._lib.DSA_verify(
@ -48,15 +53,11 @@ class _DSAVerificationContext(object):
len(self._signature), self._public_key._dsa_cdata) len(self._signature), self._public_key._dsa_cdata)
if res != 1: if res != 1:
errors = self._backend._consume_errors() self._backend._consume_errors()
assert errors
if res == -1:
assert errors[0].lib == self._backend._lib.ERR_LIB_ASN1
raise InvalidSignature raise InvalidSignature
@utils.register_interface(interfaces.AsymmetricSignatureContext) @utils.register_interface(AsymmetricSignatureContext)
class _DSASignatureContext(object): class _DSASignatureContext(object):
def __init__(self, backend, private_key, algorithm): def __init__(self, backend, private_key, algorithm):
self._backend = backend self._backend = backend
@ -69,6 +70,9 @@ class _DSASignatureContext(object):
def finalize(self): def finalize(self):
data_to_sign = self._hash_ctx.finalize() data_to_sign = self._hash_ctx.finalize()
data_to_sign = _truncate_digest_for_dsa(
self._private_key._dsa_cdata, data_to_sign, self._backend
)
sig_buf_len = self._backend._lib.DSA_size(self._private_key._dsa_cdata) sig_buf_len = self._backend._lib.DSA_size(self._private_key._dsa_cdata)
sig_buf = self._backend._ffi.new("unsigned char[]", sig_buf_len) sig_buf = self._backend._ffi.new("unsigned char[]", sig_buf_len)
buflen = self._backend._ffi.new("unsigned int *") buflen = self._backend._ffi.new("unsigned int *")
@ -78,13 +82,13 @@ class _DSASignatureContext(object):
res = self._backend._lib.DSA_sign( res = self._backend._lib.DSA_sign(
0, data_to_sign, len(data_to_sign), sig_buf, 0, data_to_sign, len(data_to_sign), sig_buf,
buflen, self._private_key._dsa_cdata) buflen, self._private_key._dsa_cdata)
assert res == 1 self._backend.openssl_assert(res == 1)
assert buflen[0] self._backend.openssl_assert(buflen[0])
return self._backend._ffi.buffer(sig_buf)[:buflen[0]] return self._backend._ffi.buffer(sig_buf)[:buflen[0]]
@utils.register_interface(DSAParametersWithNumbers) @utils.register_interface(dsa.DSAParametersWithNumbers)
class _DSAParameters(object): class _DSAParameters(object):
def __init__(self, backend, dsa_cdata): def __init__(self, backend, dsa_cdata):
self._backend = backend self._backend = backend
@ -101,19 +105,18 @@ class _DSAParameters(object):
return self._backend.generate_dsa_private_key(self) return self._backend.generate_dsa_private_key(self)
@utils.register_interface(DSAPrivateKeyWithNumbers) @utils.register_interface(dsa.DSAPrivateKeyWithSerialization)
class _DSAPrivateKey(object): class _DSAPrivateKey(object):
def __init__(self, backend, dsa_cdata): def __init__(self, backend, dsa_cdata, evp_pkey):
self._backend = backend self._backend = backend
self._dsa_cdata = dsa_cdata self._dsa_cdata = dsa_cdata
self._evp_pkey = evp_pkey
self._key_size = self._backend._lib.BN_num_bits(self._dsa_cdata.p) self._key_size = self._backend._lib.BN_num_bits(self._dsa_cdata.p)
@property key_size = utils.read_only_property("_key_size")
def key_size(self):
return self._key_size
def signer(self, algorithm): def signer(self, signature_algorithm):
return _DSASignatureContext(self._backend, self, algorithm) return _DSASignatureContext(self._backend, self, signature_algorithm)
def private_numbers(self): def private_numbers(self):
return dsa.DSAPrivateNumbers( return dsa.DSAPrivateNumbers(
@ -130,7 +133,7 @@ class _DSAPrivateKey(object):
def public_key(self): def public_key(self):
dsa_cdata = self._backend._lib.DSA_new() dsa_cdata = self._backend._lib.DSA_new()
assert dsa_cdata != self._backend._ffi.NULL self._backend.openssl_assert(dsa_cdata != self._backend._ffi.NULL)
dsa_cdata = self._backend._ffi.gc( dsa_cdata = self._backend._ffi.gc(
dsa_cdata, self._backend._lib.DSA_free dsa_cdata, self._backend._lib.DSA_free
) )
@ -138,11 +141,12 @@ class _DSAPrivateKey(object):
dsa_cdata.q = self._backend._lib.BN_dup(self._dsa_cdata.q) dsa_cdata.q = self._backend._lib.BN_dup(self._dsa_cdata.q)
dsa_cdata.g = self._backend._lib.BN_dup(self._dsa_cdata.g) dsa_cdata.g = self._backend._lib.BN_dup(self._dsa_cdata.g)
dsa_cdata.pub_key = self._backend._lib.BN_dup(self._dsa_cdata.pub_key) dsa_cdata.pub_key = self._backend._lib.BN_dup(self._dsa_cdata.pub_key)
return _DSAPublicKey(self._backend, dsa_cdata) evp_pkey = self._backend._dsa_cdata_to_evp_pkey(dsa_cdata)
return _DSAPublicKey(self._backend, dsa_cdata, evp_pkey)
def parameters(self): def parameters(self):
dsa_cdata = self._backend._lib.DSA_new() dsa_cdata = self._backend._lib.DSA_new()
assert dsa_cdata != self._backend._ffi.NULL self._backend.openssl_assert(dsa_cdata != self._backend._ffi.NULL)
dsa_cdata = self._backend._ffi.gc( dsa_cdata = self._backend._ffi.gc(
dsa_cdata, self._backend._lib.DSA_free dsa_cdata, self._backend._lib.DSA_free
) )
@ -151,21 +155,32 @@ class _DSAPrivateKey(object):
dsa_cdata.g = self._backend._lib.BN_dup(self._dsa_cdata.g) dsa_cdata.g = self._backend._lib.BN_dup(self._dsa_cdata.g)
return _DSAParameters(self._backend, dsa_cdata) return _DSAParameters(self._backend, dsa_cdata)
def private_bytes(self, encoding, format, encryption_algorithm):
return self._backend._private_key_bytes(
encoding,
format,
encryption_algorithm,
self._evp_pkey,
self._dsa_cdata
)
@utils.register_interface(DSAPublicKeyWithNumbers)
@utils.register_interface(dsa.DSAPublicKeyWithSerialization)
class _DSAPublicKey(object): class _DSAPublicKey(object):
def __init__(self, backend, dsa_cdata): def __init__(self, backend, dsa_cdata, evp_pkey):
self._backend = backend self._backend = backend
self._dsa_cdata = dsa_cdata self._dsa_cdata = dsa_cdata
self._evp_pkey = evp_pkey
self._key_size = self._backend._lib.BN_num_bits(self._dsa_cdata.p) self._key_size = self._backend._lib.BN_num_bits(self._dsa_cdata.p)
@property key_size = utils.read_only_property("_key_size")
def key_size(self):
return self._key_size def verifier(self, signature, signature_algorithm):
if not isinstance(signature, bytes):
raise TypeError("signature must be bytes.")
def verifier(self, signature, algorithm):
return _DSAVerificationContext( return _DSAVerificationContext(
self._backend, self, signature, algorithm self._backend, self, signature, signature_algorithm
) )
def public_numbers(self): def public_numbers(self):
@ -180,7 +195,7 @@ class _DSAPublicKey(object):
def parameters(self): def parameters(self):
dsa_cdata = self._backend._lib.DSA_new() dsa_cdata = self._backend._lib.DSA_new()
assert dsa_cdata != self._backend._ffi.NULL self._backend.openssl_assert(dsa_cdata != self._backend._ffi.NULL)
dsa_cdata = self._backend._ffi.gc( dsa_cdata = self._backend._ffi.gc(
dsa_cdata, self._backend._lib.DSA_free dsa_cdata, self._backend._lib.DSA_free
) )
@ -188,3 +203,16 @@ class _DSAPublicKey(object):
dsa_cdata.q = self._backend._lib.BN_dup(self._dsa_cdata.q) dsa_cdata.q = self._backend._lib.BN_dup(self._dsa_cdata.q)
dsa_cdata.g = self._backend._lib.BN_dup(self._dsa_cdata.g) dsa_cdata.g = self._backend._lib.BN_dup(self._dsa_cdata.g)
return _DSAParameters(self._backend, dsa_cdata) return _DSAParameters(self._backend, dsa_cdata)
def public_bytes(self, encoding, format):
if format is serialization.PublicFormat.PKCS1:
raise ValueError(
"DSA public keys do not support PKCS1 serialization"
)
return self._backend._public_key_bytes(
encoding,
format,
self._evp_pkey,
None
)

View file

@ -1,26 +1,18 @@
# Licensed under the Apache License, Version 2.0 (the "License"); # This file is dual licensed under the terms of the Apache License, Version
# you may not use this file except in compliance with the License. # 2.0, and the BSD License. See the LICENSE file in the root of this repository
# You may obtain a copy of the License at # for complete details.
#
# 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 from __future__ import absolute_import, division, print_function
import six
from cryptography import utils from cryptography import utils
from cryptography.exceptions import ( from cryptography.exceptions import (
InvalidSignature, UnsupportedAlgorithm, _Reasons InvalidSignature, UnsupportedAlgorithm, _Reasons
) )
from cryptography.hazmat.primitives import hashes, interfaces from cryptography.hazmat.backends.openssl.utils import _truncate_digest
from cryptography.hazmat.primitives.asymmetric import ec from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import (
AsymmetricSignatureContext, AsymmetricVerificationContext, ec
)
def _truncate_digest_for_ecdsa(ec_key_cdata, digest, backend): def _truncate_digest_for_ecdsa(ec_key_cdata, digest, backend):
@ -34,49 +26,52 @@ def _truncate_digest_for_ecdsa(ec_key_cdata, digest, backend):
_lib = backend._lib _lib = backend._lib
_ffi = backend._ffi _ffi = backend._ffi
digest_len = len(digest)
group = _lib.EC_KEY_get0_group(ec_key_cdata) group = _lib.EC_KEY_get0_group(ec_key_cdata)
with backend._tmp_bn_ctx() as bn_ctx: with backend._tmp_bn_ctx() as bn_ctx:
order = _lib.BN_CTX_get(bn_ctx) order = _lib.BN_CTX_get(bn_ctx)
assert order != _ffi.NULL backend.openssl_assert(order != _ffi.NULL)
res = _lib.EC_GROUP_get_order(group, order, bn_ctx) res = _lib.EC_GROUP_get_order(group, order, bn_ctx)
assert res == 1 backend.openssl_assert(res == 1)
order_bits = _lib.BN_num_bits(order) order_bits = _lib.BN_num_bits(order)
if 8 * digest_len > order_bits: return _truncate_digest(digest, order_bits)
digest_len = (order_bits + 7) // 8
digest = digest[:digest_len]
if 8 * digest_len > order_bits:
rshift = 8 - (order_bits & 0x7)
assert rshift > 0 and rshift < 8
mask = 0xFF >> rshift << rshift
# Set the bottom rshift bits to 0
digest = digest[:-1] + six.int2byte(six.indexbytes(digest, -1) & mask)
return digest
def _ec_key_curve_sn(backend, ec_key): def _ec_key_curve_sn(backend, ec_key):
group = backend._lib.EC_KEY_get0_group(ec_key) group = backend._lib.EC_KEY_get0_group(ec_key)
assert group != backend._ffi.NULL backend.openssl_assert(group != backend._ffi.NULL)
nid = backend._lib.EC_GROUP_get_curve_name(group) nid = backend._lib.EC_GROUP_get_curve_name(group)
assert nid != backend._lib.NID_undef # The following check is to find EC keys with unnamed curves and raise
# an error for now.
if nid == backend._lib.NID_undef:
raise NotImplementedError(
"ECDSA certificates with unnamed curves are unsupported "
"at this time"
)
curve_name = backend._lib.OBJ_nid2sn(nid) curve_name = backend._lib.OBJ_nid2sn(nid)
assert curve_name != backend._ffi.NULL backend.openssl_assert(curve_name != backend._ffi.NULL)
sn = backend._ffi.string(curve_name).decode('ascii') sn = backend._ffi.string(curve_name).decode('ascii')
return sn return sn
def _mark_asn1_named_ec_curve(backend, ec_cdata):
"""
Set the named curve flag on the EC_KEY. This causes OpenSSL to
serialize EC keys along with their curve OID which makes
deserialization easier.
"""
backend._lib.EC_KEY_set_asn1_flag(
ec_cdata, backend._lib.OPENSSL_EC_NAMED_CURVE
)
def _sn_to_elliptic_curve(backend, sn): def _sn_to_elliptic_curve(backend, sn):
try: try:
return ec._CURVE_TYPES[sn]() return ec._CURVE_TYPES[sn]()
@ -87,7 +82,7 @@ def _sn_to_elliptic_curve(backend, sn):
) )
@utils.register_interface(interfaces.AsymmetricSignatureContext) @utils.register_interface(AsymmetricSignatureContext)
class _ECDSASignatureContext(object): class _ECDSASignatureContext(object):
def __init__(self, backend, private_key, algorithm): def __init__(self, backend, private_key, algorithm):
self._backend = backend self._backend = backend
@ -105,7 +100,7 @@ class _ECDSASignatureContext(object):
digest = _truncate_digest_for_ecdsa(ec_key, digest, self._backend) digest = _truncate_digest_for_ecdsa(ec_key, digest, self._backend)
max_size = self._backend._lib.ECDSA_size(ec_key) max_size = self._backend._lib.ECDSA_size(ec_key)
assert max_size > 0 self._backend.openssl_assert(max_size > 0)
sigbuf = self._backend._ffi.new("char[]", max_size) sigbuf = self._backend._ffi.new("char[]", max_size)
siglen_ptr = self._backend._ffi.new("unsigned int[]", 1) siglen_ptr = self._backend._ffi.new("unsigned int[]", 1)
@ -117,11 +112,11 @@ class _ECDSASignatureContext(object):
siglen_ptr, siglen_ptr,
ec_key ec_key
) )
assert res == 1 self._backend.openssl_assert(res == 1)
return self._backend._ffi.buffer(sigbuf)[:siglen_ptr[0]] return self._backend._ffi.buffer(sigbuf)[:siglen_ptr[0]]
@utils.register_interface(interfaces.AsymmetricVerificationContext) @utils.register_interface(AsymmetricVerificationContext)
class _ECDSAVerificationContext(object): class _ECDSAVerificationContext(object):
def __init__(self, backend, public_key, signature, algorithm): def __init__(self, backend, public_key, signature, algorithm):
self._backend = backend self._backend = backend
@ -153,18 +148,18 @@ class _ECDSAVerificationContext(object):
return True return True
@utils.register_interface(interfaces.EllipticCurvePrivateKeyWithNumbers) @utils.register_interface(ec.EllipticCurvePrivateKeyWithSerialization)
class _EllipticCurvePrivateKey(object): class _EllipticCurvePrivateKey(object):
def __init__(self, backend, ec_key_cdata): def __init__(self, backend, ec_key_cdata, evp_pkey):
self._backend = backend self._backend = backend
_mark_asn1_named_ec_curve(backend, ec_key_cdata)
self._ec_key = ec_key_cdata self._ec_key = ec_key_cdata
self._evp_pkey = evp_pkey
sn = _ec_key_curve_sn(backend, ec_key_cdata) sn = _ec_key_curve_sn(backend, ec_key_cdata)
self._curve = _sn_to_elliptic_curve(backend, sn) self._curve = _sn_to_elliptic_curve(backend, sn)
@property curve = utils.read_only_property("_curve")
def curve(self):
return self._curve
def signer(self, signature_algorithm): def signer(self, signature_algorithm):
if isinstance(signature_algorithm, ec.ECDSA): if isinstance(signature_algorithm, ec.ECDSA):
@ -176,27 +171,52 @@ class _EllipticCurvePrivateKey(object):
"Unsupported elliptic curve signature algorithm.", "Unsupported elliptic curve signature algorithm.",
_Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM) _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM)
def exchange(self, algorithm, peer_public_key):
if not (
self._backend.elliptic_curve_exchange_algorithm_supported(
algorithm, self.curve
)
):
raise UnsupportedAlgorithm(
"This backend does not support the ECDH algorithm.",
_Reasons.UNSUPPORTED_EXCHANGE_ALGORITHM
)
group = self._backend._lib.EC_KEY_get0_group(self._ec_key)
z_len = (self._backend._lib.EC_GROUP_get_degree(group) + 7) // 8
self._backend.openssl_assert(z_len > 0)
z_buf = self._backend._ffi.new("uint8_t[]", z_len)
peer_key = self._backend._lib.EC_KEY_get0_public_key(
peer_public_key._ec_key
)
r = self._backend._lib.ECDH_compute_key(
z_buf, z_len, peer_key, self._ec_key, self._backend._ffi.NULL
)
self._backend.openssl_assert(r > 0)
return self._backend._ffi.buffer(z_buf)[:z_len]
def public_key(self): def public_key(self):
group = self._backend._lib.EC_KEY_get0_group(self._ec_key) group = self._backend._lib.EC_KEY_get0_group(self._ec_key)
assert group != self._backend._ffi.NULL self._backend.openssl_assert(group != self._backend._ffi.NULL)
curve_nid = self._backend._lib.EC_GROUP_get_curve_name(group) curve_nid = self._backend._lib.EC_GROUP_get_curve_name(group)
public_ec_key = self._backend._lib.EC_KEY_new_by_curve_name(curve_nid) public_ec_key = self._backend._lib.EC_KEY_new_by_curve_name(curve_nid)
assert public_ec_key != self._backend._ffi.NULL self._backend.openssl_assert(public_ec_key != self._backend._ffi.NULL)
public_ec_key = self._backend._ffi.gc( public_ec_key = self._backend._ffi.gc(
public_ec_key, self._backend._lib.EC_KEY_free public_ec_key, self._backend._lib.EC_KEY_free
) )
point = self._backend._lib.EC_KEY_get0_public_key(self._ec_key) point = self._backend._lib.EC_KEY_get0_public_key(self._ec_key)
assert point != self._backend._ffi.NULL self._backend.openssl_assert(point != self._backend._ffi.NULL)
res = self._backend._lib.EC_KEY_set_public_key(public_ec_key, point) res = self._backend._lib.EC_KEY_set_public_key(public_ec_key, point)
assert res == 1 self._backend.openssl_assert(res == 1)
return _EllipticCurvePublicKey( evp_pkey = self._backend._ec_cdata_to_evp_pkey(public_ec_key)
self._backend, public_ec_key
) return _EllipticCurvePublicKey(self._backend, public_ec_key, evp_pkey)
def private_numbers(self): def private_numbers(self):
bn = self._backend._lib.EC_KEY_get0_private_key(self._ec_key) bn = self._backend._lib.EC_KEY_get0_private_key(self._ec_key)
@ -206,21 +226,33 @@ class _EllipticCurvePrivateKey(object):
public_numbers=self.public_key().public_numbers() public_numbers=self.public_key().public_numbers()
) )
def private_bytes(self, encoding, format, encryption_algorithm):
return self._backend._private_key_bytes(
encoding,
format,
encryption_algorithm,
self._evp_pkey,
self._ec_key
)
@utils.register_interface(interfaces.EllipticCurvePublicKeyWithNumbers)
@utils.register_interface(ec.EllipticCurvePublicKeyWithSerialization)
class _EllipticCurvePublicKey(object): class _EllipticCurvePublicKey(object):
def __init__(self, backend, ec_key_cdata): def __init__(self, backend, ec_key_cdata, evp_pkey):
self._backend = backend self._backend = backend
_mark_asn1_named_ec_curve(backend, ec_key_cdata)
self._ec_key = ec_key_cdata self._ec_key = ec_key_cdata
self._evp_pkey = evp_pkey
sn = _ec_key_curve_sn(backend, ec_key_cdata) sn = _ec_key_curve_sn(backend, ec_key_cdata)
self._curve = _sn_to_elliptic_curve(backend, sn) self._curve = _sn_to_elliptic_curve(backend, sn)
@property curve = utils.read_only_property("_curve")
def curve(self):
return self._curve
def verifier(self, signature, signature_algorithm): def verifier(self, signature, signature_algorithm):
if not isinstance(signature, bytes):
raise TypeError("signature must be bytes.")
if isinstance(signature_algorithm, ec.ECDSA): if isinstance(signature_algorithm, ec.ECDSA):
return _ECDSAVerificationContext( return _ECDSAVerificationContext(
self._backend, self, signature, signature_algorithm.algorithm self._backend, self, signature, signature_algorithm.algorithm
@ -235,14 +267,14 @@ class _EllipticCurvePublicKey(object):
self._backend._ec_key_determine_group_get_set_funcs(self._ec_key) self._backend._ec_key_determine_group_get_set_funcs(self._ec_key)
) )
point = self._backend._lib.EC_KEY_get0_public_key(self._ec_key) point = self._backend._lib.EC_KEY_get0_public_key(self._ec_key)
assert point != self._backend._ffi.NULL self._backend.openssl_assert(point != self._backend._ffi.NULL)
with self._backend._tmp_bn_ctx() as bn_ctx: with self._backend._tmp_bn_ctx() as bn_ctx:
bn_x = self._backend._lib.BN_CTX_get(bn_ctx) bn_x = self._backend._lib.BN_CTX_get(bn_ctx)
bn_y = self._backend._lib.BN_CTX_get(bn_ctx) bn_y = self._backend._lib.BN_CTX_get(bn_ctx)
res = get_func(group, point, bn_x, bn_y, bn_ctx) res = get_func(group, point, bn_x, bn_y, bn_ctx)
assert res == 1 self._backend.openssl_assert(res == 1)
x = self._backend._bn_to_int(bn_x) x = self._backend._bn_to_int(bn_x)
y = self._backend._bn_to_int(bn_y) y = self._backend._bn_to_int(bn_y)
@ -252,3 +284,16 @@ class _EllipticCurvePublicKey(object):
y=y, y=y,
curve=self._curve curve=self._curve
) )
def public_bytes(self, encoding, format):
if format is serialization.PublicFormat.PKCS1:
raise ValueError(
"EC public keys do not support PKCS1 serialization"
)
return self._backend._public_key_bytes(
encoding,
format,
self._evp_pkey,
None
)

View file

@ -1,28 +1,19 @@
# Licensed under the Apache License, Version 2.0 (the "License"); # This file is dual licensed under the terms of the Apache License, Version
# you may not use this file except in compliance with the License. # 2.0, and the BSD License. See the LICENSE file in the root of this repository
# You may obtain a copy of the License at # for complete details.
#
# 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 from __future__ import absolute_import, division, print_function
from cryptography import utils from cryptography import utils
from cryptography.exceptions import UnsupportedAlgorithm, _Reasons from cryptography.exceptions import UnsupportedAlgorithm, _Reasons
from cryptography.hazmat.primitives import interfaces from cryptography.hazmat.primitives import hashes
@utils.register_interface(interfaces.HashContext) @utils.register_interface(hashes.HashContext)
class _HashContext(object): class _HashContext(object):
def __init__(self, backend, algorithm, ctx=None): def __init__(self, backend, algorithm, ctx=None):
self.algorithm = algorithm self._algorithm = algorithm
self._backend = backend self._backend = backend
@ -40,30 +31,32 @@ class _HashContext(object):
) )
res = self._backend._lib.EVP_DigestInit_ex(ctx, evp_md, res = self._backend._lib.EVP_DigestInit_ex(ctx, evp_md,
self._backend._ffi.NULL) self._backend._ffi.NULL)
assert res != 0 self._backend.openssl_assert(res != 0)
self._ctx = ctx self._ctx = ctx
algorithm = utils.read_only_property("_algorithm")
def copy(self): def copy(self):
copied_ctx = self._backend._lib.EVP_MD_CTX_create() copied_ctx = self._backend._lib.EVP_MD_CTX_create()
copied_ctx = self._backend._ffi.gc( copied_ctx = self._backend._ffi.gc(
copied_ctx, self._backend._lib.EVP_MD_CTX_destroy copied_ctx, self._backend._lib.EVP_MD_CTX_destroy
) )
res = self._backend._lib.EVP_MD_CTX_copy_ex(copied_ctx, self._ctx) res = self._backend._lib.EVP_MD_CTX_copy_ex(copied_ctx, self._ctx)
assert res != 0 self._backend.openssl_assert(res != 0)
return _HashContext(self._backend, self.algorithm, ctx=copied_ctx) return _HashContext(self._backend, self.algorithm, ctx=copied_ctx)
def update(self, data): def update(self, data):
res = self._backend._lib.EVP_DigestUpdate(self._ctx, data, len(data)) res = self._backend._lib.EVP_DigestUpdate(self._ctx, data, len(data))
assert res != 0 self._backend.openssl_assert(res != 0)
def finalize(self): def finalize(self):
buf = self._backend._ffi.new("unsigned char[]", buf = self._backend._ffi.new("unsigned char[]",
self._backend._lib.EVP_MAX_MD_SIZE) self._backend._lib.EVP_MAX_MD_SIZE)
outlen = self._backend._ffi.new("unsigned int *") outlen = self._backend._ffi.new("unsigned int *")
res = self._backend._lib.EVP_DigestFinal_ex(self._ctx, buf, outlen) res = self._backend._lib.EVP_DigestFinal_ex(self._ctx, buf, outlen)
assert res != 0 self._backend.openssl_assert(res != 0)
assert outlen[0] == self.algorithm.digest_size self._backend.openssl_assert(outlen[0] == self.algorithm.digest_size)
res = self._backend._lib.EVP_MD_CTX_cleanup(self._ctx) res = self._backend._lib.EVP_MD_CTX_cleanup(self._ctx)
assert res == 1 self._backend.openssl_assert(res == 1)
return self._backend._ffi.buffer(buf)[:outlen[0]] return self._backend._ffi.buffer(buf)[:outlen[0]]

View file

@ -1,28 +1,22 @@
# Licensed under the Apache License, Version 2.0 (the "License"); # This file is dual licensed under the terms of the Apache License, Version
# you may not use this file except in compliance with the License. # 2.0, and the BSD License. See the LICENSE file in the root of this repository
# You may obtain a copy of the License at # for complete details.
#
# 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 from __future__ import absolute_import, division, print_function
from cryptography import utils from cryptography import utils
from cryptography.exceptions import UnsupportedAlgorithm, _Reasons from cryptography.exceptions import (
from cryptography.hazmat.primitives import interfaces InvalidSignature, UnsupportedAlgorithm, _Reasons
)
from cryptography.hazmat.primitives import constant_time, hashes, interfaces
@utils.register_interface(interfaces.HashContext) @utils.register_interface(interfaces.MACContext)
@utils.register_interface(hashes.HashContext)
class _HMACContext(object): class _HMACContext(object):
def __init__(self, backend, key, algorithm, ctx=None): def __init__(self, backend, key, algorithm, ctx=None):
self.algorithm = algorithm self._algorithm = algorithm
self._backend = backend self._backend = backend
if ctx is None: if ctx is None:
@ -42,11 +36,13 @@ class _HMACContext(object):
res = self._backend._lib.Cryptography_HMAC_Init_ex( res = self._backend._lib.Cryptography_HMAC_Init_ex(
ctx, key, len(key), evp_md, self._backend._ffi.NULL ctx, key, len(key), evp_md, self._backend._ffi.NULL
) )
assert res != 0 self._backend.openssl_assert(res != 0)
self._ctx = ctx self._ctx = ctx
self._key = key self._key = key
algorithm = utils.read_only_property("_algorithm")
def copy(self): def copy(self):
copied_ctx = self._backend._ffi.new("HMAC_CTX *") copied_ctx = self._backend._ffi.new("HMAC_CTX *")
self._backend._lib.HMAC_CTX_init(copied_ctx) self._backend._lib.HMAC_CTX_init(copied_ctx)
@ -56,7 +52,7 @@ class _HMACContext(object):
res = self._backend._lib.Cryptography_HMAC_CTX_copy( res = self._backend._lib.Cryptography_HMAC_CTX_copy(
copied_ctx, self._ctx copied_ctx, self._ctx
) )
assert res != 0 self._backend.openssl_assert(res != 0)
return _HMACContext( return _HMACContext(
self._backend, self._key, self.algorithm, ctx=copied_ctx self._backend, self._key, self.algorithm, ctx=copied_ctx
) )
@ -65,7 +61,7 @@ class _HMACContext(object):
res = self._backend._lib.Cryptography_HMAC_Update( res = self._backend._lib.Cryptography_HMAC_Update(
self._ctx, data, len(data) self._ctx, data, len(data)
) )
assert res != 0 self._backend.openssl_assert(res != 0)
def finalize(self): def finalize(self):
buf = self._backend._ffi.new("unsigned char[]", buf = self._backend._ffi.new("unsigned char[]",
@ -74,7 +70,12 @@ class _HMACContext(object):
res = self._backend._lib.Cryptography_HMAC_Final( res = self._backend._lib.Cryptography_HMAC_Final(
self._ctx, buf, outlen self._ctx, buf, outlen
) )
assert res != 0 self._backend.openssl_assert(res != 0)
assert outlen[0] == self.algorithm.digest_size self._backend.openssl_assert(outlen[0] == self.algorithm.digest_size)
self._backend._lib.HMAC_CTX_cleanup(self._ctx) self._backend._lib.HMAC_CTX_cleanup(self._ctx)
return self._backend._ffi.buffer(buf)[:outlen[0]] return self._backend._ffi.buffer(buf)[:outlen[0]]
def verify(self, signature):
digest = self.finalize()
if not constant_time.bytes_eq(digest, signature):
raise InvalidSignature("Signature did not match digest.")

View file

@ -1,15 +1,6 @@
# Licensed under the Apache License, Version 2.0 (the "License"); # This file is dual licensed under the terms of the Apache License, Version
# you may not use this file except in compliance with the License. # 2.0, and the BSD License. See the LICENSE file in the root of this repository
# You may obtain a copy of the License at # for complete details.
#
# 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 from __future__ import absolute_import, division, print_function
@ -19,13 +10,15 @@ from cryptography import utils
from cryptography.exceptions import ( from cryptography.exceptions import (
AlreadyFinalized, InvalidSignature, UnsupportedAlgorithm, _Reasons AlreadyFinalized, InvalidSignature, UnsupportedAlgorithm, _Reasons
) )
from cryptography.hazmat.primitives import hashes, interfaces from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import rsa from cryptography.hazmat.primitives.asymmetric import (
from cryptography.hazmat.primitives.asymmetric.padding import ( AsymmetricSignatureContext, AsymmetricVerificationContext, rsa
MGF1, OAEP, PKCS1v15, PSS
) )
from cryptography.hazmat.primitives.interfaces import ( from cryptography.hazmat.primitives.asymmetric.padding import (
RSAPrivateKeyWithNumbers, RSAPublicKeyWithNumbers AsymmetricPadding, MGF1, OAEP, PKCS1v15, PSS
)
from cryptography.hazmat.primitives.asymmetric.rsa import (
RSAPrivateKeyWithSerialization, RSAPublicKeyWithSerialization
) )
@ -43,7 +36,7 @@ def _get_rsa_pss_salt_length(pss, key_size, digest_size):
def _enc_dec_rsa(backend, key, data, padding): def _enc_dec_rsa(backend, key, data, padding):
if not isinstance(padding, interfaces.AsymmetricPadding): if not isinstance(padding, AsymmetricPadding):
raise TypeError("Padding must be an instance of AsymmetricPadding.") raise TypeError("Padding must be an instance of AsymmetricPadding.")
if isinstance(padding, PKCS1v15): if isinstance(padding, PKCS1v15):
@ -96,15 +89,15 @@ def _enc_dec_rsa_pkey_ctx(backend, key, data, padding_enum):
pkey_ctx = backend._lib.EVP_PKEY_CTX_new( pkey_ctx = backend._lib.EVP_PKEY_CTX_new(
key._evp_pkey, backend._ffi.NULL key._evp_pkey, backend._ffi.NULL
) )
assert pkey_ctx != backend._ffi.NULL backend.openssl_assert(pkey_ctx != backend._ffi.NULL)
pkey_ctx = backend._ffi.gc(pkey_ctx, backend._lib.EVP_PKEY_CTX_free) pkey_ctx = backend._ffi.gc(pkey_ctx, backend._lib.EVP_PKEY_CTX_free)
res = init(pkey_ctx) res = init(pkey_ctx)
assert res == 1 backend.openssl_assert(res == 1)
res = backend._lib.EVP_PKEY_CTX_set_rsa_padding( res = backend._lib.EVP_PKEY_CTX_set_rsa_padding(
pkey_ctx, padding_enum) pkey_ctx, padding_enum)
assert res > 0 backend.openssl_assert(res > 0)
buf_size = backend._lib.EVP_PKEY_size(key._evp_pkey) buf_size = backend._lib.EVP_PKEY_size(key._evp_pkey)
assert buf_size > 0 backend.openssl_assert(buf_size > 0)
outlen = backend._ffi.new("size_t *", buf_size) outlen = backend._ffi.new("size_t *", buf_size)
buf = backend._ffi.new("char[]", buf_size) buf = backend._ffi.new("char[]", buf_size)
res = crypt(pkey_ctx, buf, outlen, data, len(data)) res = crypt(pkey_ctx, buf, outlen, data, len(data))
@ -121,7 +114,7 @@ def _enc_dec_rsa_098(backend, key, data, padding_enum):
crypt = backend._lib.RSA_private_decrypt crypt = backend._lib.RSA_private_decrypt
key_size = backend._lib.RSA_size(key._rsa_cdata) key_size = backend._lib.RSA_size(key._rsa_cdata)
assert key_size > 0 backend.openssl_assert(key_size > 0)
buf = backend._ffi.new("unsigned char[]", key_size) buf = backend._ffi.new("unsigned char[]", key_size)
res = crypt(len(data), data, buf, key._rsa_cdata, padding_enum) res = crypt(len(data), data, buf, key._rsa_cdata, padding_enum)
if res < 0: if res < 0:
@ -142,26 +135,30 @@ def _handle_rsa_enc_dec_error(backend, key):
"larger key size." "larger key size."
) )
else: else:
assert ( decoding_errors = [
errors[0].reason == backend._lib.RSA_R_BLOCK_TYPE_IS_NOT_01 or backend._lib.RSA_R_BLOCK_TYPE_IS_NOT_01,
errors[0].reason == backend._lib.RSA_R_BLOCK_TYPE_IS_NOT_02 backend._lib.RSA_R_BLOCK_TYPE_IS_NOT_02,
) ]
if backend._lib.Cryptography_HAS_RSA_R_PKCS_DECODING_ERROR:
decoding_errors.append(backend._lib.RSA_R_PKCS_DECODING_ERROR)
assert errors[0].reason in decoding_errors
raise ValueError("Decryption failed.") raise ValueError("Decryption failed.")
@utils.register_interface(interfaces.AsymmetricSignatureContext) @utils.register_interface(AsymmetricSignatureContext)
class _RSASignatureContext(object): class _RSASignatureContext(object):
def __init__(self, backend, private_key, padding, algorithm): def __init__(self, backend, private_key, padding, algorithm):
self._backend = backend self._backend = backend
self._private_key = private_key self._private_key = private_key
if not isinstance(padding, interfaces.AsymmetricPadding): if not isinstance(padding, AsymmetricPadding):
raise TypeError( raise TypeError("Expected provider of AsymmetricPadding.")
"Expected provider of interfaces.AsymmetricPadding.")
self._pkey_size = self._backend._lib.EVP_PKEY_size( self._pkey_size = self._backend._lib.EVP_PKEY_size(
self._private_key._evp_pkey self._private_key._evp_pkey
) )
self._backend.openssl_assert(self._pkey_size > 0)
if isinstance(padding, PKCS1v15): if isinstance(padding, PKCS1v15):
if self._backend._lib.Cryptography_HAS_PKEY_CTX: if self._backend._lib.Cryptography_HAS_PKEY_CTX:
@ -178,7 +175,6 @@ class _RSASignatureContext(object):
# Size of key in bytes - 2 is the maximum # Size of key in bytes - 2 is the maximum
# PSS signature length (salt length is checked later) # PSS signature length (salt length is checked later)
assert self._pkey_size > 0
if self._pkey_size - algorithm.digest_size - 2 < 0: if self._pkey_size - algorithm.digest_size - 2 < 0:
raise ValueError("Digest too large for key size. Use a larger " raise ValueError("Digest too large for key size. Use a larger "
"key.") "key.")
@ -211,7 +207,7 @@ class _RSASignatureContext(object):
def finalize(self): def finalize(self):
evp_md = self._backend._lib.EVP_get_digestbyname( evp_md = self._backend._lib.EVP_get_digestbyname(
self._algorithm.name.encode("ascii")) self._algorithm.name.encode("ascii"))
assert evp_md != self._backend._ffi.NULL self._backend.openssl_assert(evp_md != self._backend._ffi.NULL)
return self._finalize_method(evp_md) return self._finalize_method(evp_md)
@ -219,18 +215,18 @@ class _RSASignatureContext(object):
pkey_ctx = self._backend._lib.EVP_PKEY_CTX_new( pkey_ctx = self._backend._lib.EVP_PKEY_CTX_new(
self._private_key._evp_pkey, self._backend._ffi.NULL self._private_key._evp_pkey, self._backend._ffi.NULL
) )
assert pkey_ctx != self._backend._ffi.NULL self._backend.openssl_assert(pkey_ctx != self._backend._ffi.NULL)
pkey_ctx = self._backend._ffi.gc(pkey_ctx, pkey_ctx = self._backend._ffi.gc(pkey_ctx,
self._backend._lib.EVP_PKEY_CTX_free) self._backend._lib.EVP_PKEY_CTX_free)
res = self._backend._lib.EVP_PKEY_sign_init(pkey_ctx) res = self._backend._lib.EVP_PKEY_sign_init(pkey_ctx)
assert res == 1 self._backend.openssl_assert(res == 1)
res = self._backend._lib.EVP_PKEY_CTX_set_signature_md( res = self._backend._lib.EVP_PKEY_CTX_set_signature_md(
pkey_ctx, evp_md) pkey_ctx, evp_md)
assert res > 0 self._backend.openssl_assert(res > 0)
res = self._backend._lib.EVP_PKEY_CTX_set_rsa_padding( res = self._backend._lib.EVP_PKEY_CTX_set_rsa_padding(
pkey_ctx, self._padding_enum) pkey_ctx, self._padding_enum)
assert res > 0 self._backend.openssl_assert(res > 0)
if isinstance(self._padding, PSS): if isinstance(self._padding, PSS):
res = self._backend._lib.EVP_PKEY_CTX_set_rsa_pss_saltlen( res = self._backend._lib.EVP_PKEY_CTX_set_rsa_pss_saltlen(
pkey_ctx, pkey_ctx,
@ -240,17 +236,19 @@ class _RSASignatureContext(object):
self._hash_ctx.algorithm.digest_size self._hash_ctx.algorithm.digest_size
) )
) )
assert res > 0 self._backend.openssl_assert(res > 0)
if self._backend._lib.Cryptography_HAS_MGF1_MD: if self._backend._lib.Cryptography_HAS_MGF1_MD:
# MGF1 MD is configurable in OpenSSL 1.0.1+ # MGF1 MD is configurable in OpenSSL 1.0.1+
mgf1_md = self._backend._lib.EVP_get_digestbyname( mgf1_md = self._backend._lib.EVP_get_digestbyname(
self._padding._mgf._algorithm.name.encode("ascii")) self._padding._mgf._algorithm.name.encode("ascii"))
assert mgf1_md != self._backend._ffi.NULL self._backend.openssl_assert(
mgf1_md != self._backend._ffi.NULL
)
res = self._backend._lib.EVP_PKEY_CTX_set_rsa_mgf1_md( res = self._backend._lib.EVP_PKEY_CTX_set_rsa_mgf1_md(
pkey_ctx, mgf1_md pkey_ctx, mgf1_md
) )
assert res > 0 self._backend.openssl_assert(res > 0)
data_to_sign = self._hash_ctx.finalize() data_to_sign = self._hash_ctx.finalize()
buflen = self._backend._ffi.new("size_t *") buflen = self._backend._ffi.new("size_t *")
res = self._backend._lib.EVP_PKEY_sign( res = self._backend._lib.EVP_PKEY_sign(
@ -260,7 +258,7 @@ class _RSASignatureContext(object):
data_to_sign, data_to_sign,
len(data_to_sign) len(data_to_sign)
) )
assert res == 1 self._backend.openssl_assert(res == 1)
buf = self._backend._ffi.new("unsigned char[]", buflen[0]) buf = self._backend._ffi.new("unsigned char[]", buflen[0])
res = self._backend._lib.EVP_PKEY_sign( res = self._backend._lib.EVP_PKEY_sign(
pkey_ctx, buf, buflen, data_to_sign, len(data_to_sign)) pkey_ctx, buf, buflen, data_to_sign, len(data_to_sign))
@ -272,8 +270,9 @@ class _RSASignatureContext(object):
self._backend._lib.RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE): self._backend._lib.RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE):
reason = ("Salt length too long for key size. Try using " reason = ("Salt length too long for key size. Try using "
"MAX_LENGTH instead.") "MAX_LENGTH instead.")
elif (errors[0].reason == else:
self._backend._lib.RSA_R_DIGEST_TOO_BIG_FOR_RSA_KEY): assert (errors[0].reason ==
self._backend._lib.RSA_R_DIGEST_TOO_BIG_FOR_RSA_KEY)
reason = "Digest too large for key size. Use a larger key." reason = "Digest too large for key size. Use a larger key."
assert reason is not None assert reason is not None
raise ValueError(reason) raise ValueError(reason)
@ -333,24 +332,24 @@ class _RSASignatureContext(object):
self._private_key._rsa_cdata, self._private_key._rsa_cdata,
self._backend._lib.RSA_NO_PADDING self._backend._lib.RSA_NO_PADDING
) )
assert sig_len != -1 self._backend.openssl_assert(sig_len != -1)
return self._backend._ffi.buffer(sig_buf)[:sig_len] return self._backend._ffi.buffer(sig_buf)[:sig_len]
@utils.register_interface(interfaces.AsymmetricVerificationContext) @utils.register_interface(AsymmetricVerificationContext)
class _RSAVerificationContext(object): class _RSAVerificationContext(object):
def __init__(self, backend, public_key, signature, padding, algorithm): def __init__(self, backend, public_key, signature, padding, algorithm):
self._backend = backend self._backend = backend
self._public_key = public_key self._public_key = public_key
self._signature = signature self._signature = signature
if not isinstance(padding, interfaces.AsymmetricPadding): if not isinstance(padding, AsymmetricPadding):
raise TypeError( raise TypeError("Expected provider of AsymmetricPadding.")
"Expected provider of interfaces.AsymmetricPadding.")
self._pkey_size = self._backend._lib.EVP_PKEY_size( self._pkey_size = self._backend._lib.EVP_PKEY_size(
self._public_key._evp_pkey self._public_key._evp_pkey
) )
self._backend.openssl_assert(self._pkey_size > 0)
if isinstance(padding, PKCS1v15): if isinstance(padding, PKCS1v15):
if self._backend._lib.Cryptography_HAS_PKEY_CTX: if self._backend._lib.Cryptography_HAS_PKEY_CTX:
@ -367,7 +366,6 @@ class _RSAVerificationContext(object):
# Size of key in bytes - 2 is the maximum # Size of key in bytes - 2 is the maximum
# PSS signature length (salt length is checked later) # PSS signature length (salt length is checked later)
assert self._pkey_size > 0
if self._pkey_size - algorithm.digest_size - 2 < 0: if self._pkey_size - algorithm.digest_size - 2 < 0:
raise ValueError( raise ValueError(
"Digest too large for key size. Check that you have the " "Digest too large for key size. Check that you have the "
@ -402,7 +400,7 @@ class _RSAVerificationContext(object):
def verify(self): def verify(self):
evp_md = self._backend._lib.EVP_get_digestbyname( evp_md = self._backend._lib.EVP_get_digestbyname(
self._algorithm.name.encode("ascii")) self._algorithm.name.encode("ascii"))
assert evp_md != self._backend._ffi.NULL self._backend.openssl_assert(evp_md != self._backend._ffi.NULL)
self._verify_method(evp_md) self._verify_method(evp_md)
@ -410,18 +408,18 @@ class _RSAVerificationContext(object):
pkey_ctx = self._backend._lib.EVP_PKEY_CTX_new( pkey_ctx = self._backend._lib.EVP_PKEY_CTX_new(
self._public_key._evp_pkey, self._backend._ffi.NULL self._public_key._evp_pkey, self._backend._ffi.NULL
) )
assert pkey_ctx != self._backend._ffi.NULL self._backend.openssl_assert(pkey_ctx != self._backend._ffi.NULL)
pkey_ctx = self._backend._ffi.gc(pkey_ctx, pkey_ctx = self._backend._ffi.gc(pkey_ctx,
self._backend._lib.EVP_PKEY_CTX_free) self._backend._lib.EVP_PKEY_CTX_free)
res = self._backend._lib.EVP_PKEY_verify_init(pkey_ctx) res = self._backend._lib.EVP_PKEY_verify_init(pkey_ctx)
assert res == 1 self._backend.openssl_assert(res == 1)
res = self._backend._lib.EVP_PKEY_CTX_set_signature_md( res = self._backend._lib.EVP_PKEY_CTX_set_signature_md(
pkey_ctx, evp_md) pkey_ctx, evp_md)
assert res > 0 self._backend.openssl_assert(res > 0)
res = self._backend._lib.EVP_PKEY_CTX_set_rsa_padding( res = self._backend._lib.EVP_PKEY_CTX_set_rsa_padding(
pkey_ctx, self._padding_enum) pkey_ctx, self._padding_enum)
assert res > 0 self._backend.openssl_assert(res > 0)
if isinstance(self._padding, PSS): if isinstance(self._padding, PSS):
res = self._backend._lib.EVP_PKEY_CTX_set_rsa_pss_saltlen( res = self._backend._lib.EVP_PKEY_CTX_set_rsa_pss_saltlen(
pkey_ctx, pkey_ctx,
@ -431,16 +429,18 @@ class _RSAVerificationContext(object):
self._hash_ctx.algorithm.digest_size self._hash_ctx.algorithm.digest_size
) )
) )
assert res > 0 self._backend.openssl_assert(res > 0)
if self._backend._lib.Cryptography_HAS_MGF1_MD: if self._backend._lib.Cryptography_HAS_MGF1_MD:
# MGF1 MD is configurable in OpenSSL 1.0.1+ # MGF1 MD is configurable in OpenSSL 1.0.1+
mgf1_md = self._backend._lib.EVP_get_digestbyname( mgf1_md = self._backend._lib.EVP_get_digestbyname(
self._padding._mgf._algorithm.name.encode("ascii")) self._padding._mgf._algorithm.name.encode("ascii"))
assert mgf1_md != self._backend._ffi.NULL self._backend.openssl_assert(
mgf1_md != self._backend._ffi.NULL
)
res = self._backend._lib.EVP_PKEY_CTX_set_rsa_mgf1_md( res = self._backend._lib.EVP_PKEY_CTX_set_rsa_mgf1_md(
pkey_ctx, mgf1_md pkey_ctx, mgf1_md
) )
assert res > 0 self._backend.openssl_assert(res > 0)
data_to_verify = self._hash_ctx.finalize() data_to_verify = self._hash_ctx.finalize()
res = self._backend._lib.EVP_PKEY_verify( res = self._backend._lib.EVP_PKEY_verify(
@ -453,7 +453,7 @@ class _RSAVerificationContext(object):
# The previous call can return negative numbers in the event of an # The previous call can return negative numbers in the event of an
# error. This is not a signature failure but we need to fail if it # error. This is not a signature failure but we need to fail if it
# occurs. # occurs.
assert res >= 0 self._backend.openssl_assert(res >= 0)
if res == 0: if res == 0:
errors = self._backend._consume_errors() errors = self._backend._consume_errors()
assert errors assert errors
@ -473,7 +473,7 @@ class _RSAVerificationContext(object):
# The previous call can return negative numbers in the event of an # The previous call can return negative numbers in the event of an
# error. This is not a signature failure but we need to fail if it # error. This is not a signature failure but we need to fail if it
# occurs. # occurs.
assert res >= 0 self._backend.openssl_assert(res >= 0)
if res == 0: if res == 0:
errors = self._backend._consume_errors() errors = self._backend._consume_errors()
assert errors assert errors
@ -511,26 +511,16 @@ class _RSAVerificationContext(object):
raise InvalidSignature raise InvalidSignature
@utils.register_interface(RSAPrivateKeyWithNumbers) @utils.register_interface(RSAPrivateKeyWithSerialization)
class _RSAPrivateKey(object): class _RSAPrivateKey(object):
def __init__(self, backend, rsa_cdata): def __init__(self, backend, rsa_cdata, evp_pkey):
self._backend = backend self._backend = backend
self._rsa_cdata = rsa_cdata self._rsa_cdata = rsa_cdata
evp_pkey = self._backend._lib.EVP_PKEY_new()
assert evp_pkey != self._backend._ffi.NULL
evp_pkey = self._backend._ffi.gc(
evp_pkey, self._backend._lib.EVP_PKEY_free
)
res = self._backend._lib.EVP_PKEY_set1_RSA(evp_pkey, rsa_cdata)
assert res == 1
self._evp_pkey = evp_pkey self._evp_pkey = evp_pkey
self._key_size = self._backend._lib.BN_num_bits(self._rsa_cdata.n) self._key_size = self._backend._lib.BN_num_bits(self._rsa_cdata.n)
@property key_size = utils.read_only_property("_key_size")
def key_size(self):
return self._key_size
def signer(self, padding, algorithm): def signer(self, padding, algorithm):
return _RSASignatureContext(self._backend, self, padding, algorithm) return _RSASignatureContext(self._backend, self, padding, algorithm)
@ -544,13 +534,14 @@ class _RSAPrivateKey(object):
def public_key(self): def public_key(self):
ctx = self._backend._lib.RSA_new() ctx = self._backend._lib.RSA_new()
assert ctx != self._backend._ffi.NULL self._backend.openssl_assert(ctx != self._backend._ffi.NULL)
ctx = self._backend._ffi.gc(ctx, self._backend._lib.RSA_free) ctx = self._backend._ffi.gc(ctx, self._backend._lib.RSA_free)
ctx.e = self._backend._lib.BN_dup(self._rsa_cdata.e) ctx.e = self._backend._lib.BN_dup(self._rsa_cdata.e)
ctx.n = self._backend._lib.BN_dup(self._rsa_cdata.n) ctx.n = self._backend._lib.BN_dup(self._rsa_cdata.n)
res = self._backend._lib.RSA_blinding_on(ctx, self._backend._ffi.NULL) res = self._backend._lib.RSA_blinding_on(ctx, self._backend._ffi.NULL)
assert res == 1 self._backend.openssl_assert(res == 1)
return _RSAPublicKey(self._backend, ctx) evp_pkey = self._backend._rsa_cdata_to_evp_pkey(ctx)
return _RSAPublicKey(self._backend, ctx, evp_pkey)
def private_numbers(self): def private_numbers(self):
return rsa.RSAPrivateNumbers( return rsa.RSAPrivateNumbers(
@ -566,29 +557,31 @@ class _RSAPrivateKey(object):
) )
) )
def private_bytes(self, encoding, format, encryption_algorithm):
return self._backend._private_key_bytes(
encoding,
format,
encryption_algorithm,
self._evp_pkey,
self._rsa_cdata
)
@utils.register_interface(RSAPublicKeyWithNumbers)
@utils.register_interface(RSAPublicKeyWithSerialization)
class _RSAPublicKey(object): class _RSAPublicKey(object):
def __init__(self, backend, rsa_cdata): def __init__(self, backend, rsa_cdata, evp_pkey):
self._backend = backend self._backend = backend
self._rsa_cdata = rsa_cdata self._rsa_cdata = rsa_cdata
evp_pkey = self._backend._lib.EVP_PKEY_new()
assert evp_pkey != self._backend._ffi.NULL
evp_pkey = self._backend._ffi.gc(
evp_pkey, self._backend._lib.EVP_PKEY_free
)
res = self._backend._lib.EVP_PKEY_set1_RSA(evp_pkey, rsa_cdata)
assert res == 1
self._evp_pkey = evp_pkey self._evp_pkey = evp_pkey
self._key_size = self._backend._lib.BN_num_bits(self._rsa_cdata.n) self._key_size = self._backend._lib.BN_num_bits(self._rsa_cdata.n)
@property key_size = utils.read_only_property("_key_size")
def key_size(self):
return self._key_size
def verifier(self, signature, padding, algorithm): def verifier(self, signature, padding, algorithm):
if not isinstance(signature, bytes):
raise TypeError("signature must be bytes.")
return _RSAVerificationContext( return _RSAVerificationContext(
self._backend, self, signature, padding, algorithm self._backend, self, signature, padding, algorithm
) )
@ -601,3 +594,11 @@ class _RSAPublicKey(object):
e=self._backend._bn_to_int(self._rsa_cdata.e), e=self._backend._bn_to_int(self._rsa_cdata.e),
n=self._backend._bn_to_int(self._rsa_cdata.n), n=self._backend._bn_to_int(self._rsa_cdata.n),
) )
def public_bytes(self, encoding, format):
return self._backend._public_key_bytes(
encoding,
format,
self._evp_pkey,
self._rsa_cdata
)

View file

@ -0,0 +1,26 @@
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
import six
def _truncate_digest(digest, order_bits):
digest_len = len(digest)
if 8 * digest_len > order_bits:
digest_len = (order_bits + 7) // 8
digest = digest[:digest_len]
if 8 * digest_len > order_bits:
rshift = 8 - (order_bits & 0x7)
assert 0 < rshift < 8
mask = 0xFF >> rshift << rshift
# Set the bottom rshift bits to 0
digest = digest[:-1] + six.int2byte(six.indexbytes(digest, -1) & mask)
return digest

View file

@ -0,0 +1,940 @@
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
import datetime
import ipaddress
from email.utils import parseaddr
import idna
import six
from six.moves import urllib_parse
from cryptography import utils, x509
from cryptography.exceptions import UnsupportedAlgorithm
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.x509.oid import (
CRLExtensionOID, CertificatePoliciesOID, ExtensionOID
)
def _obj2txt(backend, obj):
# Set to 80 on the recommendation of
# https://www.openssl.org/docs/crypto/OBJ_nid2ln.html#return_values
buf_len = 80
buf = backend._ffi.new("char[]", buf_len)
res = backend._lib.OBJ_obj2txt(buf, buf_len, obj, 1)
backend.openssl_assert(res > 0)
return backend._ffi.buffer(buf, res)[:].decode()
def _decode_x509_name_entry(backend, x509_name_entry):
obj = backend._lib.X509_NAME_ENTRY_get_object(x509_name_entry)
backend.openssl_assert(obj != backend._ffi.NULL)
data = backend._lib.X509_NAME_ENTRY_get_data(x509_name_entry)
backend.openssl_assert(data != backend._ffi.NULL)
value = backend._asn1_string_to_utf8(data)
oid = _obj2txt(backend, obj)
return x509.NameAttribute(x509.ObjectIdentifier(oid), value)
def _decode_x509_name(backend, x509_name):
count = backend._lib.X509_NAME_entry_count(x509_name)
attributes = []
for x in range(count):
entry = backend._lib.X509_NAME_get_entry(x509_name, x)
attributes.append(_decode_x509_name_entry(backend, entry))
return x509.Name(attributes)
def _decode_general_names(backend, gns):
num = backend._lib.sk_GENERAL_NAME_num(gns)
names = []
for i in range(num):
gn = backend._lib.sk_GENERAL_NAME_value(gns, i)
backend.openssl_assert(gn != backend._ffi.NULL)
names.append(_decode_general_name(backend, gn))
return names
def _decode_general_name(backend, gn):
if gn.type == backend._lib.GEN_DNS:
data = backend._asn1_string_to_bytes(gn.d.dNSName)
if not data:
decoded = u""
elif data.startswith(b"*."):
# This is a wildcard name. We need to remove the leading wildcard,
# IDNA decode, then re-add the wildcard. Wildcard characters should
# always be left-most (RFC 2595 section 2.4).
decoded = u"*." + idna.decode(data[2:])
else:
# Not a wildcard, decode away. If the string has a * in it anywhere
# invalid this will raise an InvalidCodePoint
decoded = idna.decode(data)
if data.startswith(b"."):
# idna strips leading periods. Name constraints can have that
# so we need to re-add it. Sigh.
decoded = u"." + decoded
return x509.DNSName(decoded)
elif gn.type == backend._lib.GEN_URI:
data = backend._asn1_string_to_ascii(gn.d.uniformResourceIdentifier)
parsed = urllib_parse.urlparse(data)
if parsed.hostname:
hostname = idna.decode(parsed.hostname)
else:
hostname = ""
if parsed.port:
netloc = hostname + u":" + six.text_type(parsed.port)
else:
netloc = hostname
# Note that building a URL in this fashion means it should be
# semantically indistinguishable from the original but is not
# guaranteed to be exactly the same.
uri = urllib_parse.urlunparse((
parsed.scheme,
netloc,
parsed.path,
parsed.params,
parsed.query,
parsed.fragment
))
return x509.UniformResourceIdentifier(uri)
elif gn.type == backend._lib.GEN_RID:
oid = _obj2txt(backend, gn.d.registeredID)
return x509.RegisteredID(x509.ObjectIdentifier(oid))
elif gn.type == backend._lib.GEN_IPADD:
data = backend._asn1_string_to_bytes(gn.d.iPAddress)
data_len = len(data)
if data_len == 8 or data_len == 32:
# This is an IPv4 or IPv6 Network and not a single IP. This
# type of data appears in Name Constraints. Unfortunately,
# ipaddress doesn't support packed bytes + netmask. Additionally,
# IPv6Network can only handle CIDR rather than the full 16 byte
# netmask. To handle this we convert the netmask to integer, then
# find the first 0 bit, which will be the prefix. If another 1
# bit is present after that the netmask is invalid.
base = ipaddress.ip_address(data[:data_len // 2])
netmask = ipaddress.ip_address(data[data_len // 2:])
bits = bin(int(netmask))[2:]
prefix = bits.find('0')
# If no 0 bits are found it is a /32 or /128
if prefix == -1:
prefix = len(bits)
if "1" in bits[prefix:]:
raise ValueError("Invalid netmask")
ip = ipaddress.ip_network(base.exploded + u"/{0}".format(prefix))
else:
ip = ipaddress.ip_address(data)
return x509.IPAddress(ip)
elif gn.type == backend._lib.GEN_DIRNAME:
return x509.DirectoryName(
_decode_x509_name(backend, gn.d.directoryName)
)
elif gn.type == backend._lib.GEN_EMAIL:
data = backend._asn1_string_to_ascii(gn.d.rfc822Name)
name, address = parseaddr(data)
parts = address.split(u"@")
if name or not address:
# parseaddr has found a name (e.g. Name <email>) or the entire
# value is an empty string.
raise ValueError("Invalid rfc822name value")
elif len(parts) == 1:
# Single label email name. This is valid for local delivery. No
# IDNA decoding can be done since there is no domain component.
return x509.RFC822Name(address)
else:
# A normal email of the form user@domain.com. Let's attempt to
# decode the domain component and return the entire address.
return x509.RFC822Name(
parts[0] + u"@" + idna.decode(parts[1])
)
elif gn.type == backend._lib.GEN_OTHERNAME:
type_id = _obj2txt(backend, gn.d.otherName.type_id)
value = backend._asn1_to_der(gn.d.otherName.value)
return x509.OtherName(x509.ObjectIdentifier(type_id), value)
else:
# x400Address or ediPartyName
raise x509.UnsupportedGeneralNameType(
"{0} is not a supported type".format(
x509._GENERAL_NAMES.get(gn.type, gn.type)
),
gn.type
)
def _decode_ocsp_no_check(backend, ext):
return x509.OCSPNoCheck()
class _X509ExtensionParser(object):
def __init__(self, ext_count, get_ext, handlers, unsupported_exts=None):
self.ext_count = ext_count
self.get_ext = get_ext
self.handlers = handlers
self.unsupported_exts = unsupported_exts
def parse(self, backend, x509_obj):
extensions = []
seen_oids = set()
for i in range(self.ext_count(backend, x509_obj)):
ext = self.get_ext(backend, x509_obj, i)
backend.openssl_assert(ext != backend._ffi.NULL)
crit = backend._lib.X509_EXTENSION_get_critical(ext)
critical = crit == 1
oid = x509.ObjectIdentifier(_obj2txt(backend, ext.object))
if oid in seen_oids:
raise x509.DuplicateExtension(
"Duplicate {0} extension found".format(oid), oid
)
try:
handler = self.handlers[oid]
except KeyError:
if critical:
raise x509.UnsupportedExtension(
"Critical extension {0} is not currently supported"
.format(oid), oid
)
else:
# For extensions which are not supported by OpenSSL we pass the
# extension object directly to the parsing routine so it can
# be decoded manually.
if self.unsupported_exts and oid in self.unsupported_exts:
ext_data = ext
else:
ext_data = backend._lib.X509V3_EXT_d2i(ext)
if ext_data == backend._ffi.NULL:
backend._consume_errors()
raise ValueError(
"The {0} extension is invalid and can't be "
"parsed".format(oid)
)
value = handler(backend, ext_data)
extensions.append(x509.Extension(oid, critical, value))
seen_oids.add(oid)
return x509.Extensions(extensions)
@utils.register_interface(x509.Certificate)
class _Certificate(object):
def __init__(self, backend, x509):
self._backend = backend
self._x509 = x509
def __repr__(self):
return "<Certificate(subject={0}, ...)>".format(self.subject)
def __eq__(self, other):
if not isinstance(other, x509.Certificate):
return NotImplemented
res = self._backend._lib.X509_cmp(self._x509, other._x509)
return res == 0
def __ne__(self, other):
return not self == other
def __hash__(self):
return hash(self.public_bytes(serialization.Encoding.DER))
def fingerprint(self, algorithm):
h = hashes.Hash(algorithm, self._backend)
h.update(self.public_bytes(serialization.Encoding.DER))
return h.finalize()
@property
def version(self):
version = self._backend._lib.X509_get_version(self._x509)
if version == 0:
return x509.Version.v1
elif version == 2:
return x509.Version.v3
else:
raise x509.InvalidVersion(
"{0} is not a valid X509 version".format(version), version
)
@property
def serial(self):
asn1_int = self._backend._lib.X509_get_serialNumber(self._x509)
self._backend.openssl_assert(asn1_int != self._backend._ffi.NULL)
return self._backend._asn1_integer_to_int(asn1_int)
def public_key(self):
pkey = self._backend._lib.X509_get_pubkey(self._x509)
if pkey == self._backend._ffi.NULL:
# Remove errors from the stack.
self._backend._consume_errors()
raise ValueError("Certificate public key is of an unknown type")
pkey = self._backend._ffi.gc(pkey, self._backend._lib.EVP_PKEY_free)
return self._backend._evp_pkey_to_public_key(pkey)
@property
def not_valid_before(self):
asn1_time = self._backend._lib.X509_get_notBefore(self._x509)
return self._backend._parse_asn1_time(asn1_time)
@property
def not_valid_after(self):
asn1_time = self._backend._lib.X509_get_notAfter(self._x509)
return self._backend._parse_asn1_time(asn1_time)
@property
def issuer(self):
issuer = self._backend._lib.X509_get_issuer_name(self._x509)
self._backend.openssl_assert(issuer != self._backend._ffi.NULL)
return _decode_x509_name(self._backend, issuer)
@property
def subject(self):
subject = self._backend._lib.X509_get_subject_name(self._x509)
self._backend.openssl_assert(subject != self._backend._ffi.NULL)
return _decode_x509_name(self._backend, subject)
@property
def signature_hash_algorithm(self):
oid = _obj2txt(self._backend, self._x509.sig_alg.algorithm)
try:
return x509._SIG_OIDS_TO_HASH[oid]
except KeyError:
raise UnsupportedAlgorithm(
"Signature algorithm OID:{0} not recognized".format(oid)
)
@property
def extensions(self):
return _CERTIFICATE_EXTENSION_PARSER.parse(self._backend, self._x509)
def public_bytes(self, encoding):
bio = self._backend._create_mem_bio()
if encoding is serialization.Encoding.PEM:
res = self._backend._lib.PEM_write_bio_X509(bio, self._x509)
elif encoding is serialization.Encoding.DER:
res = self._backend._lib.i2d_X509_bio(bio, self._x509)
else:
raise TypeError("encoding must be an item from the Encoding enum")
self._backend.openssl_assert(res == 1)
return self._backend._read_mem_bio(bio)
def _decode_certificate_policies(backend, cp):
cp = backend._ffi.cast("Cryptography_STACK_OF_POLICYINFO *", cp)
cp = backend._ffi.gc(cp, backend._lib.sk_POLICYINFO_free)
num = backend._lib.sk_POLICYINFO_num(cp)
certificate_policies = []
for i in range(num):
qualifiers = None
pi = backend._lib.sk_POLICYINFO_value(cp, i)
oid = x509.ObjectIdentifier(_obj2txt(backend, pi.policyid))
if pi.qualifiers != backend._ffi.NULL:
qnum = backend._lib.sk_POLICYQUALINFO_num(pi.qualifiers)
qualifiers = []
for j in range(qnum):
pqi = backend._lib.sk_POLICYQUALINFO_value(
pi.qualifiers, j
)
pqualid = x509.ObjectIdentifier(
_obj2txt(backend, pqi.pqualid)
)
if pqualid == CertificatePoliciesOID.CPS_QUALIFIER:
cpsuri = backend._ffi.buffer(
pqi.d.cpsuri.data, pqi.d.cpsuri.length
)[:].decode('ascii')
qualifiers.append(cpsuri)
else:
assert pqualid == CertificatePoliciesOID.CPS_USER_NOTICE
user_notice = _decode_user_notice(
backend, pqi.d.usernotice
)
qualifiers.append(user_notice)
certificate_policies.append(
x509.PolicyInformation(oid, qualifiers)
)
return x509.CertificatePolicies(certificate_policies)
def _decode_user_notice(backend, un):
explicit_text = None
notice_reference = None
if un.exptext != backend._ffi.NULL:
explicit_text = backend._asn1_string_to_utf8(un.exptext)
if un.noticeref != backend._ffi.NULL:
organization = backend._asn1_string_to_utf8(un.noticeref.organization)
num = backend._lib.sk_ASN1_INTEGER_num(
un.noticeref.noticenos
)
notice_numbers = []
for i in range(num):
asn1_int = backend._lib.sk_ASN1_INTEGER_value(
un.noticeref.noticenos, i
)
notice_num = backend._asn1_integer_to_int(asn1_int)
notice_numbers.append(notice_num)
notice_reference = x509.NoticeReference(
organization, notice_numbers
)
return x509.UserNotice(notice_reference, explicit_text)
def _decode_basic_constraints(backend, bc_st):
basic_constraints = backend._ffi.cast("BASIC_CONSTRAINTS *", bc_st)
basic_constraints = backend._ffi.gc(
basic_constraints, backend._lib.BASIC_CONSTRAINTS_free
)
# The byte representation of an ASN.1 boolean true is \xff. OpenSSL
# chooses to just map this to its ordinal value, so true is 255 and
# false is 0.
ca = basic_constraints.ca == 255
if basic_constraints.pathlen == backend._ffi.NULL:
path_length = None
else:
path_length = backend._asn1_integer_to_int(basic_constraints.pathlen)
return x509.BasicConstraints(ca, path_length)
def _decode_subject_key_identifier(backend, asn1_string):
asn1_string = backend._ffi.cast("ASN1_OCTET_STRING *", asn1_string)
asn1_string = backend._ffi.gc(
asn1_string, backend._lib.ASN1_OCTET_STRING_free
)
return x509.SubjectKeyIdentifier(
backend._ffi.buffer(asn1_string.data, asn1_string.length)[:]
)
def _decode_authority_key_identifier(backend, akid):
akid = backend._ffi.cast("AUTHORITY_KEYID *", akid)
akid = backend._ffi.gc(akid, backend._lib.AUTHORITY_KEYID_free)
key_identifier = None
authority_cert_issuer = None
authority_cert_serial_number = None
if akid.keyid != backend._ffi.NULL:
key_identifier = backend._ffi.buffer(
akid.keyid.data, akid.keyid.length
)[:]
if akid.issuer != backend._ffi.NULL:
authority_cert_issuer = _decode_general_names(
backend, akid.issuer
)
if akid.serial != backend._ffi.NULL:
authority_cert_serial_number = backend._asn1_integer_to_int(
akid.serial
)
return x509.AuthorityKeyIdentifier(
key_identifier, authority_cert_issuer, authority_cert_serial_number
)
def _decode_authority_information_access(backend, aia):
aia = backend._ffi.cast("Cryptography_STACK_OF_ACCESS_DESCRIPTION *", aia)
aia = backend._ffi.gc(aia, backend._lib.sk_ACCESS_DESCRIPTION_free)
num = backend._lib.sk_ACCESS_DESCRIPTION_num(aia)
access_descriptions = []
for i in range(num):
ad = backend._lib.sk_ACCESS_DESCRIPTION_value(aia, i)
backend.openssl_assert(ad.method != backend._ffi.NULL)
oid = x509.ObjectIdentifier(_obj2txt(backend, ad.method))
backend.openssl_assert(ad.location != backend._ffi.NULL)
gn = _decode_general_name(backend, ad.location)
access_descriptions.append(x509.AccessDescription(oid, gn))
return x509.AuthorityInformationAccess(access_descriptions)
def _decode_key_usage(backend, bit_string):
bit_string = backend._ffi.cast("ASN1_BIT_STRING *", bit_string)
bit_string = backend._ffi.gc(bit_string, backend._lib.ASN1_BIT_STRING_free)
get_bit = backend._lib.ASN1_BIT_STRING_get_bit
digital_signature = get_bit(bit_string, 0) == 1
content_commitment = get_bit(bit_string, 1) == 1
key_encipherment = get_bit(bit_string, 2) == 1
data_encipherment = get_bit(bit_string, 3) == 1
key_agreement = get_bit(bit_string, 4) == 1
key_cert_sign = get_bit(bit_string, 5) == 1
crl_sign = get_bit(bit_string, 6) == 1
encipher_only = get_bit(bit_string, 7) == 1
decipher_only = get_bit(bit_string, 8) == 1
return x509.KeyUsage(
digital_signature,
content_commitment,
key_encipherment,
data_encipherment,
key_agreement,
key_cert_sign,
crl_sign,
encipher_only,
decipher_only
)
def _decode_general_names_extension(backend, gns):
gns = backend._ffi.cast("GENERAL_NAMES *", gns)
gns = backend._ffi.gc(gns, backend._lib.GENERAL_NAMES_free)
general_names = _decode_general_names(backend, gns)
return general_names
def _decode_subject_alt_name(backend, ext):
return x509.SubjectAlternativeName(
_decode_general_names_extension(backend, ext)
)
def _decode_issuer_alt_name(backend, ext):
return x509.IssuerAlternativeName(
_decode_general_names_extension(backend, ext)
)
def _decode_name_constraints(backend, nc):
nc = backend._ffi.cast("NAME_CONSTRAINTS *", nc)
nc = backend._ffi.gc(nc, backend._lib.NAME_CONSTRAINTS_free)
permitted = _decode_general_subtrees(backend, nc.permittedSubtrees)
excluded = _decode_general_subtrees(backend, nc.excludedSubtrees)
return x509.NameConstraints(
permitted_subtrees=permitted, excluded_subtrees=excluded
)
def _decode_general_subtrees(backend, stack_subtrees):
if stack_subtrees == backend._ffi.NULL:
return None
num = backend._lib.sk_GENERAL_SUBTREE_num(stack_subtrees)
subtrees = []
for i in range(num):
obj = backend._lib.sk_GENERAL_SUBTREE_value(stack_subtrees, i)
backend.openssl_assert(obj != backend._ffi.NULL)
name = _decode_general_name(backend, obj.base)
subtrees.append(name)
return subtrees
def _decode_extended_key_usage(backend, sk):
sk = backend._ffi.cast("Cryptography_STACK_OF_ASN1_OBJECT *", sk)
sk = backend._ffi.gc(sk, backend._lib.sk_ASN1_OBJECT_free)
num = backend._lib.sk_ASN1_OBJECT_num(sk)
ekus = []
for i in range(num):
obj = backend._lib.sk_ASN1_OBJECT_value(sk, i)
backend.openssl_assert(obj != backend._ffi.NULL)
oid = x509.ObjectIdentifier(_obj2txt(backend, obj))
ekus.append(oid)
return x509.ExtendedKeyUsage(ekus)
_DISTPOINT_TYPE_FULLNAME = 0
_DISTPOINT_TYPE_RELATIVENAME = 1
def _decode_crl_distribution_points(backend, cdps):
cdps = backend._ffi.cast("Cryptography_STACK_OF_DIST_POINT *", cdps)
cdps = backend._ffi.gc(cdps, backend._lib.sk_DIST_POINT_free)
num = backend._lib.sk_DIST_POINT_num(cdps)
dist_points = []
for i in range(num):
full_name = None
relative_name = None
crl_issuer = None
reasons = None
cdp = backend._lib.sk_DIST_POINT_value(cdps, i)
if cdp.reasons != backend._ffi.NULL:
# We will check each bit from RFC 5280
# ReasonFlags ::= BIT STRING {
# unused (0),
# keyCompromise (1),
# cACompromise (2),
# affiliationChanged (3),
# superseded (4),
# cessationOfOperation (5),
# certificateHold (6),
# privilegeWithdrawn (7),
# aACompromise (8) }
reasons = []
get_bit = backend._lib.ASN1_BIT_STRING_get_bit
if get_bit(cdp.reasons, 1):
reasons.append(x509.ReasonFlags.key_compromise)
if get_bit(cdp.reasons, 2):
reasons.append(x509.ReasonFlags.ca_compromise)
if get_bit(cdp.reasons, 3):
reasons.append(x509.ReasonFlags.affiliation_changed)
if get_bit(cdp.reasons, 4):
reasons.append(x509.ReasonFlags.superseded)
if get_bit(cdp.reasons, 5):
reasons.append(x509.ReasonFlags.cessation_of_operation)
if get_bit(cdp.reasons, 6):
reasons.append(x509.ReasonFlags.certificate_hold)
if get_bit(cdp.reasons, 7):
reasons.append(x509.ReasonFlags.privilege_withdrawn)
if get_bit(cdp.reasons, 8):
reasons.append(x509.ReasonFlags.aa_compromise)
reasons = frozenset(reasons)
if cdp.CRLissuer != backend._ffi.NULL:
crl_issuer = _decode_general_names(backend, cdp.CRLissuer)
# Certificates may have a crl_issuer/reasons and no distribution
# point so make sure it's not null.
if cdp.distpoint != backend._ffi.NULL:
# Type 0 is fullName, there is no #define for it in the code.
if cdp.distpoint.type == _DISTPOINT_TYPE_FULLNAME:
full_name = _decode_general_names(
backend, cdp.distpoint.name.fullname
)
# OpenSSL code doesn't test for a specific type for
# relativename, everything that isn't fullname is considered
# relativename.
else:
rns = cdp.distpoint.name.relativename
rnum = backend._lib.sk_X509_NAME_ENTRY_num(rns)
attributes = []
for i in range(rnum):
rn = backend._lib.sk_X509_NAME_ENTRY_value(
rns, i
)
backend.openssl_assert(rn != backend._ffi.NULL)
attributes.append(
_decode_x509_name_entry(backend, rn)
)
relative_name = x509.Name(attributes)
dist_points.append(
x509.DistributionPoint(
full_name, relative_name, reasons, crl_issuer
)
)
return x509.CRLDistributionPoints(dist_points)
def _decode_inhibit_any_policy(backend, asn1_int):
asn1_int = backend._ffi.cast("ASN1_INTEGER *", asn1_int)
asn1_int = backend._ffi.gc(asn1_int, backend._lib.ASN1_INTEGER_free)
skip_certs = backend._asn1_integer_to_int(asn1_int)
return x509.InhibitAnyPolicy(skip_certs)
_CRL_REASON_CODE_TO_ENUM = {
0: x509.ReasonFlags.unspecified,
1: x509.ReasonFlags.key_compromise,
2: x509.ReasonFlags.ca_compromise,
3: x509.ReasonFlags.affiliation_changed,
4: x509.ReasonFlags.superseded,
5: x509.ReasonFlags.cessation_of_operation,
6: x509.ReasonFlags.certificate_hold,
8: x509.ReasonFlags.remove_from_crl,
9: x509.ReasonFlags.privilege_withdrawn,
10: x509.ReasonFlags.aa_compromise,
}
def _decode_crl_reason(backend, enum):
enum = backend._ffi.cast("ASN1_ENUMERATED *", enum)
enum = backend._ffi.gc(enum, backend._lib.ASN1_ENUMERATED_free)
code = backend._lib.ASN1_ENUMERATED_get(enum)
try:
return _CRL_REASON_CODE_TO_ENUM[code]
except KeyError:
raise ValueError("Unsupported reason code: {0}".format(code))
def _decode_invalidity_date(backend, inv_date):
generalized_time = backend._ffi.cast(
"ASN1_GENERALIZEDTIME *", inv_date
)
generalized_time = backend._ffi.gc(
generalized_time, backend._lib.ASN1_GENERALIZEDTIME_free
)
time = backend._ffi.string(
backend._lib.ASN1_STRING_data(
backend._ffi.cast("ASN1_STRING *", generalized_time)
)
).decode("ascii")
return datetime.datetime.strptime(time, "%Y%m%d%H%M%SZ")
def _decode_cert_issuer(backend, ext):
"""
This handler decodes the CertificateIssuer entry extension directly
from the X509_EXTENSION object. This is necessary because this entry
extension is not directly supported by OpenSSL 0.9.8.
"""
data_ptr_ptr = backend._ffi.new("const unsigned char **")
data_ptr_ptr[0] = ext.value.data
gns = backend._lib.d2i_GENERAL_NAMES(
backend._ffi.NULL, data_ptr_ptr, ext.value.length
)
# Check the result of d2i_GENERAL_NAMES() is valid. Usually this is covered
# in _X509ExtensionParser but since we are responsible for decoding this
# entry extension ourselves, we have to this here.
if gns == backend._ffi.NULL:
backend._consume_errors()
raise ValueError(
"The {0} extension is corrupted and can't be parsed".format(
CRLExtensionOID.CERTIFICATE_ISSUER))
gns = backend._ffi.gc(gns, backend._lib.GENERAL_NAMES_free)
return x509.GeneralNames(_decode_general_names(backend, gns))
@utils.register_interface(x509.RevokedCertificate)
class _RevokedCertificate(object):
def __init__(self, backend, x509_revoked):
self._backend = backend
self._x509_revoked = x509_revoked
@property
def serial_number(self):
asn1_int = self._x509_revoked.serialNumber
self._backend.openssl_assert(asn1_int != self._backend._ffi.NULL)
return self._backend._asn1_integer_to_int(asn1_int)
@property
def revocation_date(self):
return self._backend._parse_asn1_time(
self._x509_revoked.revocationDate)
@property
def extensions(self):
return _REVOKED_CERTIFICATE_EXTENSION_PARSER.parse(
self._backend, self._x509_revoked
)
@utils.register_interface(x509.CertificateRevocationList)
class _CertificateRevocationList(object):
def __init__(self, backend, x509_crl):
self._backend = backend
self._x509_crl = x509_crl
def __eq__(self, other):
if not isinstance(other, x509.CertificateRevocationList):
return NotImplemented
res = self._backend._lib.X509_CRL_cmp(self._x509_crl, other._x509_crl)
return res == 0
def __ne__(self, other):
return not self == other
def fingerprint(self, algorithm):
h = hashes.Hash(algorithm, self._backend)
bio = self._backend._create_mem_bio()
res = self._backend._lib.i2d_X509_CRL_bio(
bio, self._x509_crl
)
self._backend.openssl_assert(res == 1)
der = self._backend._read_mem_bio(bio)
h.update(der)
return h.finalize()
@property
def signature_hash_algorithm(self):
oid = _obj2txt(self._backend, self._x509_crl.sig_alg.algorithm)
try:
return x509._SIG_OIDS_TO_HASH[oid]
except KeyError:
raise UnsupportedAlgorithm(
"Signature algorithm OID:{0} not recognized".format(oid)
)
@property
def issuer(self):
issuer = self._backend._lib.X509_CRL_get_issuer(self._x509_crl)
self._backend.openssl_assert(issuer != self._backend._ffi.NULL)
return _decode_x509_name(self._backend, issuer)
@property
def next_update(self):
nu = self._backend._lib.X509_CRL_get_nextUpdate(self._x509_crl)
self._backend.openssl_assert(nu != self._backend._ffi.NULL)
return self._backend._parse_asn1_time(nu)
@property
def last_update(self):
lu = self._backend._lib.X509_CRL_get_lastUpdate(self._x509_crl)
self._backend.openssl_assert(lu != self._backend._ffi.NULL)
return self._backend._parse_asn1_time(lu)
def _revoked_certificates(self):
revoked = self._backend._lib.X509_CRL_get_REVOKED(self._x509_crl)
self._backend.openssl_assert(revoked != self._backend._ffi.NULL)
num = self._backend._lib.sk_X509_REVOKED_num(revoked)
revoked_list = []
for i in range(num):
r = self._backend._lib.sk_X509_REVOKED_value(revoked, i)
self._backend.openssl_assert(r != self._backend._ffi.NULL)
revoked_list.append(_RevokedCertificate(self._backend, r))
return revoked_list
def __iter__(self):
return iter(self._revoked_certificates())
def __getitem__(self, idx):
return self._revoked_certificates()[idx]
def __len__(self):
return len(self._revoked_certificates())
@property
def extensions(self):
raise NotImplementedError()
@utils.register_interface(x509.CertificateSigningRequest)
class _CertificateSigningRequest(object):
def __init__(self, backend, x509_req):
self._backend = backend
self._x509_req = x509_req
def __eq__(self, other):
if not isinstance(other, _CertificateSigningRequest):
return NotImplemented
self_bytes = self.public_bytes(serialization.Encoding.DER)
other_bytes = other.public_bytes(serialization.Encoding.DER)
return self_bytes == other_bytes
def __ne__(self, other):
return not self == other
def __hash__(self):
return hash(self.public_bytes(serialization.Encoding.DER))
def public_key(self):
pkey = self._backend._lib.X509_REQ_get_pubkey(self._x509_req)
self._backend.openssl_assert(pkey != self._backend._ffi.NULL)
pkey = self._backend._ffi.gc(pkey, self._backend._lib.EVP_PKEY_free)
return self._backend._evp_pkey_to_public_key(pkey)
@property
def subject(self):
subject = self._backend._lib.X509_REQ_get_subject_name(self._x509_req)
self._backend.openssl_assert(subject != self._backend._ffi.NULL)
return _decode_x509_name(self._backend, subject)
@property
def signature_hash_algorithm(self):
oid = _obj2txt(self._backend, self._x509_req.sig_alg.algorithm)
try:
return x509._SIG_OIDS_TO_HASH[oid]
except KeyError:
raise UnsupportedAlgorithm(
"Signature algorithm OID:{0} not recognized".format(oid)
)
@property
def extensions(self):
x509_exts = self._backend._lib.X509_REQ_get_extensions(self._x509_req)
return _CSR_EXTENSION_PARSER.parse(self._backend, x509_exts)
def public_bytes(self, encoding):
bio = self._backend._create_mem_bio()
if encoding is serialization.Encoding.PEM:
res = self._backend._lib.PEM_write_bio_X509_REQ(
bio, self._x509_req
)
elif encoding is serialization.Encoding.DER:
res = self._backend._lib.i2d_X509_REQ_bio(bio, self._x509_req)
else:
raise TypeError("encoding must be an item from the Encoding enum")
self._backend.openssl_assert(res == 1)
return self._backend._read_mem_bio(bio)
_EXTENSION_HANDLERS = {
ExtensionOID.BASIC_CONSTRAINTS: _decode_basic_constraints,
ExtensionOID.SUBJECT_KEY_IDENTIFIER: _decode_subject_key_identifier,
ExtensionOID.KEY_USAGE: _decode_key_usage,
ExtensionOID.SUBJECT_ALTERNATIVE_NAME: _decode_subject_alt_name,
ExtensionOID.EXTENDED_KEY_USAGE: _decode_extended_key_usage,
ExtensionOID.AUTHORITY_KEY_IDENTIFIER: _decode_authority_key_identifier,
ExtensionOID.AUTHORITY_INFORMATION_ACCESS: (
_decode_authority_information_access
),
ExtensionOID.CERTIFICATE_POLICIES: _decode_certificate_policies,
ExtensionOID.CRL_DISTRIBUTION_POINTS: _decode_crl_distribution_points,
ExtensionOID.OCSP_NO_CHECK: _decode_ocsp_no_check,
ExtensionOID.INHIBIT_ANY_POLICY: _decode_inhibit_any_policy,
ExtensionOID.ISSUER_ALTERNATIVE_NAME: _decode_issuer_alt_name,
ExtensionOID.NAME_CONSTRAINTS: _decode_name_constraints,
}
_REVOKED_EXTENSION_HANDLERS = {
CRLExtensionOID.CRL_REASON: _decode_crl_reason,
CRLExtensionOID.INVALIDITY_DATE: _decode_invalidity_date,
CRLExtensionOID.CERTIFICATE_ISSUER: _decode_cert_issuer,
}
_REVOKED_UNSUPPORTED_EXTENSIONS = set([
CRLExtensionOID.CERTIFICATE_ISSUER,
])
_CERTIFICATE_EXTENSION_PARSER = _X509ExtensionParser(
ext_count=lambda backend, x: backend._lib.X509_get_ext_count(x),
get_ext=lambda backend, x, i: backend._lib.X509_get_ext(x, i),
handlers=_EXTENSION_HANDLERS
)
_CSR_EXTENSION_PARSER = _X509ExtensionParser(
ext_count=lambda backend, x: backend._lib.sk_X509_EXTENSION_num(x),
get_ext=lambda backend, x, i: backend._lib.sk_X509_EXTENSION_value(x, i),
handlers=_EXTENSION_HANDLERS
)
_REVOKED_CERTIFICATE_EXTENSION_PARSER = _X509ExtensionParser(
ext_count=lambda backend, x: backend._lib.X509_REVOKED_get_ext_count(x),
get_ext=lambda backend, x, i: backend._lib.X509_REVOKED_get_ext(x, i),
handlers=_REVOKED_EXTENSION_HANDLERS,
unsupported_exts=_REVOKED_UNSUPPORTED_EXTENSIONS
)

View file

@ -1,14 +1,5 @@
# Licensed under the Apache License, Version 2.0 (the "License"); # This file is dual licensed under the terms of the Apache License, Version
# you may not use this file except in compliance with the License. # 2.0, and the BSD License. See the LICENSE file in the root of this repository
# You may obtain a copy of the License at # for complete details.
#
# 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 from __future__ import absolute_import, division, print_function

View file

@ -1,14 +1,5 @@
# Licensed under the Apache License, Version 2.0 (the "License"); # This file is dual licensed under the terms of the Apache License, Version
# you may not use this file except in compliance with the License. # 2.0, and the BSD License. See the LICENSE file in the root of this repository
# You may obtain a copy of the License at # for complete details.
#
# 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 from __future__ import absolute_import, division, print_function

View file

@ -1,54 +1,15 @@
# Licensed under the Apache License, Version 2.0 (the "License"); # This file is dual licensed under the terms of the Apache License, Version
# you may not use this file except in compliance with the License. # 2.0, and the BSD License. See the LICENSE file in the root of this repository
# You may obtain a copy of the License at # for complete details.
#
# 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 from __future__ import absolute_import, division, print_function
from cryptography.hazmat.bindings.utils import build_ffi from cryptography.hazmat.bindings._commoncrypto import ffi, lib
class Binding(object): class Binding(object):
""" """
CommonCrypto API wrapper. CommonCrypto API wrapper.
""" """
_module_prefix = "cryptography.hazmat.bindings.commoncrypto." lib = lib
_modules = [ ffi = ffi
"cf",
"common_digest",
"common_hmac",
"common_key_derivation",
"common_cryptor",
"secimport",
"secitem",
"seckey",
"seckeychain",
"sectransform",
]
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
cls.ffi, cls.lib = build_ffi(
module_prefix=cls._module_prefix,
modules=cls._modules,
extra_link_args=[
"-framework", "Security", "-framework", "CoreFoundation"
]
)

View file

@ -1,114 +0,0 @@
# 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
INCLUDES = """
#include <CoreFoundation/CoreFoundation.h>
"""
TYPES = """
typedef bool Boolean;
typedef signed long OSStatus;
typedef unsigned char UInt8;
typedef uint32_t UInt32;
typedef const void * CFAllocatorRef;
const CFAllocatorRef kCFAllocatorDefault;
typedef const void * CFDataRef;
typedef signed long long CFIndex;
typedef ... *CFStringRef;
typedef ... *CFArrayRef;
typedef ... *CFBooleanRef;
typedef ... *CFErrorRef;
typedef ... *CFNumberRef;
typedef ... *CFTypeRef;
typedef ... *CFDictionaryRef;
typedef ... *CFMutableDictionaryRef;
typedef struct {
...;
} CFDictionaryKeyCallBacks;
typedef struct {
...;
} CFDictionaryValueCallBacks;
typedef struct {
...;
} CFRange;
typedef UInt32 CFStringEncoding;
enum {
kCFStringEncodingASCII = 0x0600
};
enum {
kCFNumberSInt8Type = 1,
kCFNumberSInt16Type = 2,
kCFNumberSInt32Type = 3,
kCFNumberSInt64Type = 4,
kCFNumberFloat32Type = 5,
kCFNumberFloat64Type = 6,
kCFNumberCharType = 7,
kCFNumberShortType = 8,
kCFNumberIntType = 9,
kCFNumberLongType = 10,
kCFNumberLongLongType = 11,
kCFNumberFloatType = 12,
kCFNumberDoubleType = 13,
kCFNumberCFIndexType = 14,
kCFNumberNSIntegerType = 15,
kCFNumberCGFloatType = 16,
kCFNumberMaxType = 16
};
typedef int CFNumberType;
const CFDictionaryKeyCallBacks kCFTypeDictionaryKeyCallBacks;
const CFDictionaryValueCallBacks kCFTypeDictionaryValueCallBacks;
const CFBooleanRef kCFBooleanTrue;
const CFBooleanRef kCFBooleanFalse;
"""
FUNCTIONS = """
CFDataRef CFDataCreate(CFAllocatorRef, const UInt8 *, CFIndex);
CFStringRef CFStringCreateWithCString(CFAllocatorRef, const char *,
CFStringEncoding);
CFDictionaryRef CFDictionaryCreate(CFAllocatorRef, const void **,
const void **, CFIndex,
const CFDictionaryKeyCallBacks *,
const CFDictionaryValueCallBacks *);
CFMutableDictionaryRef CFDictionaryCreateMutable(
CFAllocatorRef,
CFIndex,
const CFDictionaryKeyCallBacks *,
const CFDictionaryValueCallBacks *
);
void CFDictionarySetValue(CFMutableDictionaryRef, const void *, const void *);
CFIndex CFArrayGetCount(CFArrayRef);
const void *CFArrayGetValueAtIndex(CFArrayRef, CFIndex);
CFIndex CFDataGetLength(CFDataRef);
void CFDataGetBytes(CFDataRef, CFRange, UInt8 *);
CFRange CFRangeMake(CFIndex, CFIndex);
void CFShow(CFTypeRef);
Boolean CFBooleanGetValue(CFBooleanRef);
CFNumberRef CFNumberCreate(CFAllocatorRef, CFNumberType, const void *);
void CFRelease(CFTypeRef);
CFTypeRef CFRetain(CFTypeRef);
"""
MACROS = """
"""
CUSTOMIZATIONS = """
"""
CONDITIONAL_NAMES = {}

View file

@ -1,110 +0,0 @@
# 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
INCLUDES = """
#include <CommonCrypto/CommonCryptor.h>
"""
TYPES = """
enum {
kCCAlgorithmAES128 = 0,
kCCAlgorithmDES,
kCCAlgorithm3DES,
kCCAlgorithmCAST,
kCCAlgorithmRC4,
kCCAlgorithmRC2,
kCCAlgorithmBlowfish
};
typedef uint32_t CCAlgorithm;
enum {
kCCSuccess = 0,
kCCParamError = -4300,
kCCBufferTooSmall = -4301,
kCCMemoryFailure = -4302,
kCCAlignmentError = -4303,
kCCDecodeError = -4304,
kCCUnimplemented = -4305
};
typedef int32_t CCCryptorStatus;
typedef uint32_t CCOptions;
enum {
kCCEncrypt = 0,
kCCDecrypt,
};
typedef uint32_t CCOperation;
typedef ... *CCCryptorRef;
enum {
kCCModeOptionCTR_LE = 0x0001,
kCCModeOptionCTR_BE = 0x0002
};
typedef uint32_t CCModeOptions;
enum {
kCCModeECB = 1,
kCCModeCBC = 2,
kCCModeCFB = 3,
kCCModeCTR = 4,
kCCModeF8 = 5,
kCCModeLRW = 6,
kCCModeOFB = 7,
kCCModeXTS = 8,
kCCModeRC4 = 9,
kCCModeCFB8 = 10,
kCCModeGCM = 11
};
typedef uint32_t CCMode;
enum {
ccNoPadding = 0,
ccPKCS7Padding = 1,
};
typedef uint32_t CCPadding;
"""
FUNCTIONS = """
CCCryptorStatus CCCryptorCreateWithMode(CCOperation, CCMode, CCAlgorithm,
CCPadding, const void *, const void *,
size_t, const void *, size_t, int,
CCModeOptions, CCCryptorRef *);
CCCryptorStatus CCCryptorCreate(CCOperation, CCAlgorithm, CCOptions,
const void *, size_t, const void *,
CCCryptorRef *);
CCCryptorStatus CCCryptorUpdate(CCCryptorRef, const void *, size_t, void *,
size_t, size_t *);
CCCryptorStatus CCCryptorFinal(CCCryptorRef, void *, size_t, size_t *);
CCCryptorStatus CCCryptorRelease(CCCryptorRef);
CCCryptorStatus CCCryptorGCMAddIV(CCCryptorRef, const void *, size_t);
CCCryptorStatus CCCryptorGCMAddAAD(CCCryptorRef, const void *, size_t);
CCCryptorStatus CCCryptorGCMEncrypt(CCCryptorRef, const void *, size_t,
void *);
CCCryptorStatus CCCryptorGCMDecrypt(CCCryptorRef, const void *, size_t,
void *);
CCCryptorStatus CCCryptorGCMFinal(CCCryptorRef, const void *, size_t *);
CCCryptorStatus CCCryptorGCMReset(CCCryptorRef);
"""
MACROS = """
"""
CUSTOMIZATIONS = """
/* Not defined in the public header */
enum {
kCCModeGCM = 11
};
"""
CONDITIONAL_NAMES = {}

View file

@ -1,69 +0,0 @@
# 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
INCLUDES = """
#include <CommonCrypto/CommonDigest.h>
"""
TYPES = """
typedef uint32_t CC_LONG;
typedef uint64_t CC_LONG64;
typedef struct CC_MD5state_st {
...;
} CC_MD5_CTX;
typedef struct CC_SHA1state_st {
...;
} CC_SHA1_CTX;
typedef struct CC_SHA256state_st {
...;
} CC_SHA256_CTX;
typedef struct CC_SHA512state_st {
...;
} CC_SHA512_CTX;
"""
FUNCTIONS = """
int CC_MD5_Init(CC_MD5_CTX *);
int CC_MD5_Update(CC_MD5_CTX *, const void *, CC_LONG);
int CC_MD5_Final(unsigned char *, CC_MD5_CTX *);
int CC_SHA1_Init(CC_SHA1_CTX *);
int CC_SHA1_Update(CC_SHA1_CTX *, const void *, CC_LONG);
int CC_SHA1_Final(unsigned char *, CC_SHA1_CTX *);
int CC_SHA224_Init(CC_SHA256_CTX *);
int CC_SHA224_Update(CC_SHA256_CTX *, const void *, CC_LONG);
int CC_SHA224_Final(unsigned char *, CC_SHA256_CTX *);
int CC_SHA256_Init(CC_SHA256_CTX *);
int CC_SHA256_Update(CC_SHA256_CTX *, const void *, CC_LONG);
int CC_SHA256_Final(unsigned char *, CC_SHA256_CTX *);
int CC_SHA384_Init(CC_SHA512_CTX *);
int CC_SHA384_Update(CC_SHA512_CTX *, const void *, CC_LONG);
int CC_SHA384_Final(unsigned char *, CC_SHA512_CTX *);
int CC_SHA512_Init(CC_SHA512_CTX *);
int CC_SHA512_Update(CC_SHA512_CTX *, const void *, CC_LONG);
int CC_SHA512_Final(unsigned char *, CC_SHA512_CTX *);
"""
MACROS = """
"""
CUSTOMIZATIONS = """
"""
CONDITIONAL_NAMES = {}

View file

@ -1,48 +0,0 @@
# 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
INCLUDES = """
#include <CommonCrypto/CommonHMAC.h>
"""
TYPES = """
typedef struct {
...;
} CCHmacContext;
enum {
kCCHmacAlgSHA1,
kCCHmacAlgMD5,
kCCHmacAlgSHA256,
kCCHmacAlgSHA384,
kCCHmacAlgSHA512,
kCCHmacAlgSHA224
};
typedef uint32_t CCHmacAlgorithm;
"""
FUNCTIONS = """
void CCHmacInit(CCHmacContext *, CCHmacAlgorithm, const void *, size_t);
void CCHmacUpdate(CCHmacContext *, const void *, size_t);
void CCHmacFinal(CCHmacContext *, void *);
"""
MACROS = """
"""
CUSTOMIZATIONS = """
"""
CONDITIONAL_NAMES = {}

View file

@ -1,50 +0,0 @@
# 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
INCLUDES = """
#include <CommonCrypto/CommonKeyDerivation.h>
"""
TYPES = """
enum {
kCCPBKDF2 = 2,
};
typedef uint32_t CCPBKDFAlgorithm;
enum {
kCCPRFHmacAlgSHA1 = 1,
kCCPRFHmacAlgSHA224 = 2,
kCCPRFHmacAlgSHA256 = 3,
kCCPRFHmacAlgSHA384 = 4,
kCCPRFHmacAlgSHA512 = 5,
};
typedef uint32_t CCPseudoRandomAlgorithm;
typedef unsigned int uint;
"""
FUNCTIONS = """
int CCKeyDerivationPBKDF(CCPBKDFAlgorithm, const char *, size_t,
const uint8_t *, size_t, CCPseudoRandomAlgorithm,
uint, uint8_t *, size_t);
uint CCCalibratePBKDF(CCPBKDFAlgorithm, size_t, size_t,
CCPseudoRandomAlgorithm, size_t, uint32_t);
"""
MACROS = """
"""
CUSTOMIZATIONS = """
"""
CONDITIONAL_NAMES = {}

View file

@ -1,95 +0,0 @@
# 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
INCLUDES = """
#include <Security/SecImportExport.h>
"""
TYPES = """
typedef ... *SecAccessRef;
CFStringRef kSecImportExportPassphrase;
CFStringRef kSecImportExportKeychain;
CFStringRef kSecImportExportAccess;
typedef uint32_t SecExternalItemType;
enum {
kSecItemTypeUnknown,
kSecItemTypePrivateKey,
kSecItemTypePublicKey,
kSecItemTypeSessionKey,
kSecItemTypeCertificate,
kSecItemTypeAggregate
};
typedef uint32_t SecExternalFormat;
enum {
kSecFormatUnknown = 0,
kSecFormatOpenSSL,
kSecFormatSSH,
kSecFormatBSAFE,
kSecFormatRawKey,
kSecFormatWrappedPKCS8,
kSecFormatWrappedOpenSSL,
kSecFormatWrappedSSH,
kSecFormatWrappedLSH,
kSecFormatX509Cert,
kSecFormatPEMSequence,
kSecFormatPKCS7,
kSecFormatPKCS12,
kSecFormatNetscapeCertSequence,
kSecFormatSSHv2
};
typedef uint32_t SecItemImportExportFlags;
enum {
kSecKeyImportOnlyOne = 0x00000001,
kSecKeySecurePassphrase = 0x00000002,
kSecKeyNoAccessControl = 0x00000004
};
typedef uint32_t SecKeyImportExportFlags;
typedef struct {
/* for import and export */
uint32_t version;
SecKeyImportExportFlags flags;
CFTypeRef passphrase;
CFStringRef alertTitle;
CFStringRef alertPrompt;
/* for import only */
SecAccessRef accessRef;
CFArrayRef keyUsage;
CFArrayRef keyAttributes;
} SecItemImportExportKeyParameters;
"""
FUNCTIONS = """
OSStatus SecItemImport(CFDataRef, CFStringRef, SecExternalFormat *,
SecExternalItemType *, SecItemImportExportFlags,
const SecItemImportExportKeyParameters *,
SecKeychainRef, CFArrayRef *);
OSStatus SecPKCS12Import(CFDataRef, CFDictionaryRef, CFArrayRef *);
"""
MACROS = """
"""
CUSTOMIZATIONS = """
"""
CONDITIONAL_NAMES = {}

View file

@ -1,38 +0,0 @@
# 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
INCLUDES = """
#include <Security/SecItem.h>
"""
TYPES = """
const CFTypeRef kSecAttrKeyType;
const CFTypeRef kSecAttrKeySizeInBits;
const CFTypeRef kSecAttrIsPermanent;
const CFTypeRef kSecAttrKeyTypeRSA;
const CFTypeRef kSecAttrKeyTypeDSA;
const CFTypeRef kSecUseKeychain;
"""
FUNCTIONS = """
"""
MACROS = """
"""
CUSTOMIZATIONS = """
"""
CONDITIONAL_NAMES = {}

View file

@ -1,35 +0,0 @@
# 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
INCLUDES = """
#include <Security/SecKey.h>
"""
TYPES = """
typedef ... *SecKeyRef;
"""
FUNCTIONS = """
OSStatus SecKeyGeneratePair(CFDictionaryRef, SecKeyRef *, SecKeyRef *);
size_t SecKeyGetBlockSize(SecKeyRef);
"""
MACROS = """
"""
CUSTOMIZATIONS = """
"""
CONDITIONAL_NAMES = {}

View file

@ -1,36 +0,0 @@
# 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
INCLUDES = """
#include <Security/SecKeychain.h>
"""
TYPES = """
typedef ... *SecKeychainRef;
"""
FUNCTIONS = """
OSStatus SecKeychainCreate(const char *, UInt32, const void *, Boolean,
SecAccessRef, SecKeychainRef *);
OSStatus SecKeychainDelete(SecKeychainRef);
"""
MACROS = """
"""
CUSTOMIZATIONS = """
"""
CONDITIONAL_NAMES = {}

View file

@ -1,79 +0,0 @@
# 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
INCLUDES = """
#include <Security/SecDigestTransform.h>
#include <Security/SecSignVerifyTransform.h>
#include <Security/SecEncryptTransform.h>
"""
TYPES = """
typedef ... *SecTransformRef;
CFStringRef kSecImportExportPassphrase;
CFStringRef kSecImportExportKeychain;
CFStringRef kSecImportExportAccess;
CFStringRef kSecEncryptionMode;
CFStringRef kSecEncryptKey;
CFStringRef kSecIVKey;
CFStringRef kSecModeCBCKey;
CFStringRef kSecModeCFBKey;
CFStringRef kSecModeECBKey;
CFStringRef kSecModeNoneKey;
CFStringRef kSecModeOFBKey;
CFStringRef kSecOAEPEncodingParametersAttributeName;
CFStringRef kSecPaddingKey;
CFStringRef kSecPaddingNoneKey;
CFStringRef kSecPaddingOAEPKey;
CFStringRef kSecPaddingPKCS1Key;
CFStringRef kSecPaddingPKCS5Key;
CFStringRef kSecPaddingPKCS7Key;
const CFStringRef kSecTransformInputAttributeName;
const CFStringRef kSecTransformOutputAttributeName;
const CFStringRef kSecTransformDebugAttributeName;
const CFStringRef kSecTransformTransformName;
const CFStringRef kSecTransformAbortAttributeName;
CFStringRef kSecInputIsAttributeName;
CFStringRef kSecInputIsPlainText;
CFStringRef kSecInputIsDigest;
CFStringRef kSecInputIsRaw;
const CFStringRef kSecDigestTypeAttribute;
const CFStringRef kSecDigestLengthAttribute;
const CFStringRef kSecDigestMD5;
const CFStringRef kSecDigestSHA1;
const CFStringRef kSecDigestSHA2;
"""
FUNCTIONS = """
Boolean SecTransformSetAttribute(SecTransformRef, CFStringRef, CFTypeRef,
CFErrorRef *);
SecTransformRef SecDecryptTransformCreate(SecKeyRef, CFErrorRef *);
SecTransformRef SecEncryptTransformCreate(SecKeyRef, CFErrorRef *);
SecTransformRef SecVerifyTransformCreate(SecKeyRef, CFDataRef, CFErrorRef *);
SecTransformRef SecSignTransformCreate(SecKeyRef, CFErrorRef *) ;
CFTypeRef SecTransformExecute(SecTransformRef, CFErrorRef *);
"""
MACROS = """
"""
CUSTOMIZATIONS = """
"""
CONDITIONAL_NAMES = {}

View file

@ -1,14 +1,5 @@
# Licensed under the Apache License, Version 2.0 (the "License"); # This file is dual licensed under the terms of the Apache License, Version
# you may not use this file except in compliance with the License. # 2.0, and the BSD License. See the LICENSE file in the root of this repository
# You may obtain a copy of the License at # for complete details.
#
# 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 from __future__ import absolute_import, division, print_function

View file

@ -0,0 +1,418 @@
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
# This is a temporary copy of all the CONDITIONAL_NAMES from _cffi_src so
# we can loop over them and delete them at runtime. It will be removed when
# cffi supports #if in cdef
CONDITIONAL_NAMES = {
"Cryptography_HAS_AES_WRAP": [
"AES_wrap_key",
"AES_unwrap_key",
],
"Cryptography_HAS_CMAC": [
"CMAC_CTX_new",
"CMAC_Init",
"CMAC_Update",
"CMAC_Final",
"CMAC_CTX_copy",
"CMAC_CTX_free",
],
"Cryptography_HAS_CMS": [
"BIO_new_CMS",
"i2d_CMS_bio_stream",
"PEM_write_bio_CMS_stream",
"CMS_final",
"CMS_sign",
"CMS_verify",
"CMS_encrypt",
"CMS_decrypt",
"CMS_add1_signer",
"CMS_TEXT",
"CMS_NOCERTS",
"CMS_NO_CONTENT_VERIFY",
"CMS_NO_ATTR_VERIFY",
"CMS_NOSIGS",
"CMS_NOINTERN",
"CMS_NO_SIGNER_CERT_VERIFY",
"CMS_NOVERIFY",
"CMS_DETACHED",
"CMS_BINARY",
"CMS_NOATTR",
"CMS_NOSMIMECAP",
"CMS_NOOLDMIMETYPE",
"CMS_CRLFEOL",
"CMS_STREAM",
"CMS_NOCRL",
"CMS_PARTIAL",
"CMS_REUSE_DIGEST",
"CMS_USE_KEYID",
"CMS_DEBUG_DECRYPT",
],
"Cryptography_HAS_EC": [
"OPENSSL_EC_NAMED_CURVE",
"EC_GROUP_new",
"EC_GROUP_free",
"EC_GROUP_clear_free",
"EC_GROUP_new_curve_GFp",
"EC_GROUP_new_by_curve_name",
"EC_GROUP_set_curve_GFp",
"EC_GROUP_get_curve_GFp",
"EC_GROUP_method_of",
"EC_GROUP_get0_generator",
"EC_GROUP_get_curve_name",
"EC_GROUP_get_degree",
"EC_GROUP_set_asn1_flag",
"EC_GROUP_set_point_conversion_form",
"EC_KEY_new",
"EC_KEY_free",
"EC_get_builtin_curves",
"EC_KEY_new_by_curve_name",
"EC_KEY_copy",
"EC_KEY_dup",
"EC_KEY_up_ref",
"EC_KEY_set_group",
"EC_KEY_get0_private_key",
"EC_KEY_set_private_key",
"EC_KEY_set_public_key",
"EC_KEY_get_enc_flags",
"EC_KEY_set_enc_flags",
"EC_KEY_set_conv_form",
"EC_KEY_get_key_method_data",
"EC_KEY_insert_key_method_data",
"EC_KEY_set_asn1_flag",
"EC_KEY_precompute_mult",
"EC_KEY_generate_key",
"EC_KEY_check_key",
"EC_POINT_new",
"EC_POINT_free",
"EC_POINT_clear_free",
"EC_POINT_copy",
"EC_POINT_dup",
"EC_POINT_method_of",
"EC_POINT_set_to_infinity",
"EC_POINT_set_Jprojective_coordinates_GFp",
"EC_POINT_get_Jprojective_coordinates_GFp",
"EC_POINT_set_affine_coordinates_GFp",
"EC_POINT_get_affine_coordinates_GFp",
"EC_POINT_set_compressed_coordinates_GFp",
"EC_POINT_point2oct",
"EC_POINT_oct2point",
"EC_POINT_point2bn",
"EC_POINT_bn2point",
"EC_POINT_point2hex",
"EC_POINT_hex2point",
"EC_POINT_add",
"EC_POINT_dbl",
"EC_POINT_invert",
"EC_POINT_is_at_infinity",
"EC_POINT_is_on_curve",
"EC_POINT_cmp",
"EC_POINT_make_affine",
"EC_POINTs_make_affine",
"EC_POINTs_mul",
"EC_POINT_mul",
"EC_GROUP_precompute_mult",
"EC_GROUP_have_precompute_mult",
"EC_GFp_simple_method",
"EC_GFp_mont_method",
"EC_GFp_nist_method",
"EC_METHOD_get_field_type",
"EVP_PKEY_assign_EC_KEY",
"EVP_PKEY_get1_EC_KEY",
"EVP_PKEY_set1_EC_KEY",
"PEM_write_bio_ECPrivateKey",
"i2d_EC_PUBKEY",
"d2i_EC_PUBKEY",
"d2i_EC_PUBKEY_bio",
"i2d_EC_PUBKEY_bio",
"d2i_ECPrivateKey",
"d2i_ECPrivateKey_bio",
"i2d_ECPrivateKey",
"i2d_ECPrivateKey_bio",
"i2o_ECPublicKey",
"o2i_ECPublicKey",
"SSL_CTX_set_tmp_ecdh",
],
"Cryptography_HAS_EC_1_0_1": [
"EC_KEY_get_flags",
"EC_KEY_set_flags",
"EC_KEY_clear_flags",
"EC_KEY_set_public_key_affine_coordinates",
],
"Cryptography_HAS_EC_NISTP_64_GCC_128": [
"EC_GFp_nistp224_method",
"EC_GFp_nistp256_method",
"EC_GFp_nistp521_method",
],
"Cryptography_HAS_EC2M": [
"EC_GF2m_simple_method",
"EC_POINT_set_affine_coordinates_GF2m",
"EC_POINT_get_affine_coordinates_GF2m",
"EC_POINT_set_compressed_coordinates_GF2m",
"EC_GROUP_set_curve_GF2m",
"EC_GROUP_get_curve_GF2m",
"EC_GROUP_new_curve_GF2m",
],
"Cryptography_HAS_EC_1_0_2": [
"EC_curve_nid2nist",
],
"Cryptography_HAS_ECDH": [
"ECDH_compute_key",
"ECDH_get_ex_new_index",
"ECDH_set_ex_data",
"ECDH_get_ex_data",
],
"Cryptography_HAS_ECDSA": [
"ECDSA_SIG_new",
"ECDSA_SIG_free",
"i2d_ECDSA_SIG",
"d2i_ECDSA_SIG",
"ECDSA_do_sign",
"ECDSA_do_sign_ex",
"ECDSA_do_verify",
"ECDSA_sign_setup",
"ECDSA_sign",
"ECDSA_sign_ex",
"ECDSA_verify",
"ECDSA_size",
"ECDSA_OpenSSL",
"ECDSA_set_default_method",
"ECDSA_get_default_method",
"ECDSA_set_method",
"ECDSA_get_ex_new_index",
"ECDSA_set_ex_data",
"ECDSA_get_ex_data",
],
"Cryptography_HAS_ENGINE_CRYPTODEV": [
"ENGINE_load_cryptodev"
],
"Cryptography_HAS_REMOVE_THREAD_STATE": [
"ERR_remove_thread_state"
],
"Cryptography_HAS_098H_ERROR_CODES": [
"ASN1_F_B64_READ_ASN1",
"ASN1_F_B64_WRITE_ASN1",
"ASN1_F_SMIME_READ_ASN1",
"ASN1_F_SMIME_TEXT",
"ASN1_R_NO_CONTENT_TYPE",
"ASN1_R_NO_MULTIPART_BODY_FAILURE",
"ASN1_R_NO_MULTIPART_BOUNDARY",
],
"Cryptography_HAS_098C_CAMELLIA_CODES": [
"EVP_F_CAMELLIA_INIT_KEY",
"EVP_R_CAMELLIA_KEY_SETUP_FAILED"
],
"Cryptography_HAS_EC_CODES": [
"EC_R_UNKNOWN_GROUP",
"EC_F_EC_GROUP_NEW_BY_CURVE_NAME"
],
"Cryptography_HAS_RSA_R_PKCS_DECODING_ERROR": [
"RSA_R_PKCS_DECODING_ERROR"
],
"Cryptography_HAS_GCM": [
"EVP_CTRL_GCM_GET_TAG",
"EVP_CTRL_GCM_SET_TAG",
"EVP_CTRL_GCM_SET_IVLEN",
],
"Cryptography_HAS_PBKDF2_HMAC": [
"PKCS5_PBKDF2_HMAC"
],
"Cryptography_HAS_PKEY_CTX": [
"EVP_PKEY_CTX_new",
"EVP_PKEY_CTX_new_id",
"EVP_PKEY_CTX_dup",
"EVP_PKEY_CTX_free",
"EVP_PKEY_sign",
"EVP_PKEY_sign_init",
"EVP_PKEY_verify",
"EVP_PKEY_verify_init",
"Cryptography_EVP_PKEY_encrypt",
"EVP_PKEY_encrypt_init",
"Cryptography_EVP_PKEY_decrypt",
"EVP_PKEY_decrypt_init",
"EVP_PKEY_CTX_set_signature_md",
"EVP_PKEY_id",
"EVP_PKEY_CTX_set_rsa_padding",
"EVP_PKEY_CTX_set_rsa_pss_saltlen",
],
"Cryptography_HAS_ECDSA_SHA2_NIDS": [
"NID_ecdsa_with_SHA224",
"NID_ecdsa_with_SHA256",
"NID_ecdsa_with_SHA384",
"NID_ecdsa_with_SHA512",
],
"Cryptography_HAS_EGD": [
"RAND_egd",
"RAND_egd_bytes",
"RAND_query_egd_bytes",
],
"Cryptography_HAS_PSS_PADDING": [
"RSA_PKCS1_PSS_PADDING",
],
"Cryptography_HAS_MGF1_MD": [
"EVP_PKEY_CTX_set_rsa_mgf1_md",
],
"Cryptography_HAS_TLSv1_1": [
"SSL_OP_NO_TLSv1_1",
"TLSv1_1_method",
"TLSv1_1_server_method",
"TLSv1_1_client_method",
],
"Cryptography_HAS_TLSv1_2": [
"SSL_OP_NO_TLSv1_2",
"TLSv1_2_method",
"TLSv1_2_server_method",
"TLSv1_2_client_method",
],
"Cryptography_HAS_SSL2": [
"SSLv2_method",
"SSLv2_client_method",
"SSLv2_server_method",
],
"Cryptography_HAS_SSL3_METHOD": [
"SSLv3_method",
"SSLv3_client_method",
"SSLv3_server_method",
],
"Cryptography_HAS_TLSEXT_HOSTNAME": [
"SSL_set_tlsext_host_name",
"SSL_get_servername",
"SSL_CTX_set_tlsext_servername_callback",
],
"Cryptography_HAS_TLSEXT_STATUS_REQ_CB": [
"SSL_CTX_set_tlsext_status_cb",
"SSL_CTX_set_tlsext_status_arg"
],
"Cryptography_HAS_STATUS_REQ_OCSP_RESP": [
"SSL_set_tlsext_status_ocsp_resp",
"SSL_get_tlsext_status_ocsp_resp",
],
"Cryptography_HAS_TLSEXT_STATUS_REQ_TYPE": [
"SSL_set_tlsext_status_type",
],
"Cryptography_HAS_RELEASE_BUFFERS": [
"SSL_MODE_RELEASE_BUFFERS",
],
"Cryptography_HAS_OP_NO_COMPRESSION": [
"SSL_OP_NO_COMPRESSION",
],
"Cryptography_HAS_SSL_OP_MSIE_SSLV2_RSA_PADDING": [
"SSL_OP_MSIE_SSLV2_RSA_PADDING",
],
"Cryptography_HAS_SSL_OP_NO_TICKET": [
"SSL_OP_NO_TICKET",
],
"Cryptography_HAS_SSL_SET_SSL_CTX": [
"SSL_set_SSL_CTX",
"TLSEXT_NAMETYPE_host_name",
],
"Cryptography_HAS_NETBSD_D1_METH": [
"DTLSv1_method",
],
"Cryptography_HAS_NEXTPROTONEG": [
"SSL_CTX_set_next_protos_advertised_cb",
"SSL_CTX_set_next_proto_select_cb",
"SSL_select_next_proto",
"SSL_get0_next_proto_negotiated",
],
"Cryptography_HAS_SECURE_RENEGOTIATION": [
"SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION",
"SSL_OP_LEGACY_SERVER_CONNECT",
"SSL_get_secure_renegotiation_support",
],
"Cryptography_HAS_ALPN": [
"SSL_CTX_set_alpn_protos",
"SSL_set_alpn_protos",
"SSL_CTX_set_alpn_select_cb",
"SSL_get0_alpn_selected",
],
"Cryptography_HAS_COMPRESSION": [
"SSL_get_current_compression",
"SSL_get_current_expansion",
"SSL_COMP_get_name",
],
"Cryptography_HAS_GET_SERVER_TMP_KEY": [
"SSL_get_server_tmp_key",
],
"Cryptography_HAS_SSL_CTX_SET_CLIENT_CERT_ENGINE": [
"SSL_CTX_set_client_cert_engine",
],
"Cryptography_HAS_102_VERIFICATION_ERROR_CODES": [
'X509_V_ERR_SUITE_B_INVALID_VERSION',
'X509_V_ERR_SUITE_B_INVALID_ALGORITHM',
'X509_V_ERR_SUITE_B_INVALID_CURVE',
'X509_V_ERR_SUITE_B_INVALID_SIGNATURE_ALGORITHM',
'X509_V_ERR_SUITE_B_LOS_NOT_ALLOWED',
'X509_V_ERR_SUITE_B_CANNOT_SIGN_P_384_WITH_P_256',
'X509_V_ERR_HOSTNAME_MISMATCH',
'X509_V_ERR_EMAIL_MISMATCH',
'X509_V_ERR_IP_ADDRESS_MISMATCH'
],
"Cryptography_HAS_102_VERIFICATION_PARAMS": [
"X509_V_FLAG_SUITEB_128_LOS_ONLY",
"X509_V_FLAG_SUITEB_192_LOS",
"X509_V_FLAG_SUITEB_128_LOS",
"X509_VERIFY_PARAM_set1_host",
"X509_VERIFY_PARAM_set1_email",
"X509_VERIFY_PARAM_set1_ip",
"X509_VERIFY_PARAM_set1_ip_asc",
"X509_VERIFY_PARAM_set_hostflags",
],
"Cryptography_HAS_X509_V_FLAG_TRUSTED_FIRST": [
"X509_V_FLAG_TRUSTED_FIRST",
],
"Cryptography_HAS_X509_V_FLAG_PARTIAL_CHAIN": [
"X509_V_FLAG_PARTIAL_CHAIN",
],
"Cryptography_HAS_100_VERIFICATION_ERROR_CODES": [
'X509_V_ERR_DIFFERENT_CRL_SCOPE',
'X509_V_ERR_UNSUPPORTED_EXTENSION_FEATURE',
'X509_V_ERR_UNNESTED_RESOURCE',
'X509_V_ERR_PERMITTED_VIOLATION',
'X509_V_ERR_EXCLUDED_VIOLATION',
'X509_V_ERR_SUBTREE_MINMAX',
'X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE',
'X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX',
'X509_V_ERR_UNSUPPORTED_NAME_SYNTAX',
'X509_V_ERR_CRL_PATH_VALIDATION_ERROR',
],
"Cryptography_HAS_100_VERIFICATION_PARAMS": [
"Cryptography_HAS_100_VERIFICATION_PARAMS",
"X509_V_FLAG_EXTENDED_CRL_SUPPORT",
"X509_V_FLAG_USE_DELTAS",
],
"Cryptography_HAS_X509_V_FLAG_CHECK_SS_SIGNATURE": [
"X509_V_FLAG_CHECK_SS_SIGNATURE",
],
"Cryptography_HAS_SET_CERT_CB": [
"SSL_CTX_set_cert_cb",
"SSL_set_cert_cb",
],
}

View file

@ -1,70 +0,0 @@
# 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
INCLUDES = """
#include <openssl/aes.h>
"""
TYPES = """
static const int Cryptography_HAS_AES_WRAP;
struct aes_key_st {
...;
};
typedef struct aes_key_st AES_KEY;
"""
FUNCTIONS = """
int AES_set_encrypt_key(const unsigned char *, const int, AES_KEY *);
int AES_set_decrypt_key(const unsigned char *, const int, AES_KEY *);
"""
MACROS = """
/* these can be moved back to FUNCTIONS once we drop support for 0.9.8h.
This should be when we drop RHEL/CentOS 5, which is on 0.9.8e. */
int AES_wrap_key(AES_KEY *, const unsigned char *, unsigned char *,
const unsigned char *, unsigned int);
int AES_unwrap_key(AES_KEY *, const unsigned char *, unsigned char *,
const unsigned char *, unsigned int);
/* The ctr128_encrypt function is only useful in 0.9.8. You should use EVP for
this in 1.0.0+. It is defined in macros because the function signature
changed after 0.9.8 */
void AES_ctr128_encrypt(const unsigned char *, unsigned char *,
const size_t, const AES_KEY *,
unsigned char[], unsigned char[], unsigned int *);
"""
CUSTOMIZATIONS = """
/* OpenSSL 0.9.8h+ */
#if OPENSSL_VERSION_NUMBER >= 0x0090808fL
static const long Cryptography_HAS_AES_WRAP = 1;
#else
static const long Cryptography_HAS_AES_WRAP = 0;
int (*AES_wrap_key)(AES_KEY *, const unsigned char *, unsigned char *,
const unsigned char *, unsigned int) = NULL;
int (*AES_unwrap_key)(AES_KEY *, const unsigned char *, unsigned char *,
const unsigned char *, unsigned int) = NULL;
#endif
"""
CONDITIONAL_NAMES = {
"Cryptography_HAS_AES_WRAP": [
"AES_wrap_key",
"AES_unwrap_key",
],
}

View file

@ -1,152 +0,0 @@
# 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
INCLUDES = """
#include <openssl/asn1.h>
"""
TYPES = """
/*
* TODO: This typedef is wrong.
*
* This is due to limitations of cffi.
* See https://bitbucket.org/cffi/cffi/issue/69
*
* For another possible work-around (not used here because it involves more
* complicated use of the cffi API which falls outside the general pattern used
* by this package), see
* http://paste.pound-python.org/show/iJcTUMkKeBeS6yXpZWUU/
*
* The work-around used here is to just be sure to declare a type that is at
* least as large as the real type. Maciej explains:
*
* <fijal> I think you want to declare your value too large (e.g. long)
* <fijal> that way you'll never pass garbage
*/
typedef intptr_t time_t;
typedef int ASN1_BOOLEAN;
typedef ... ASN1_INTEGER;
struct asn1_string_st {
int length;
int type;
unsigned char *data;
long flags;
};
typedef struct asn1_string_st ASN1_OCTET_STRING;
typedef struct asn1_string_st ASN1_IA5STRING;
typedef ... ASN1_OBJECT;
typedef ... ASN1_STRING;
typedef ... ASN1_TYPE;
typedef ... ASN1_GENERALIZEDTIME;
typedef ... ASN1_ENUMERATED;
typedef ... ASN1_ITEM;
typedef ... ASN1_VALUE;
typedef struct {
...;
} ASN1_TIME;
typedef ... ASN1_ITEM_EXP;
typedef ... ASN1_UTCTIME;
static const int V_ASN1_GENERALIZEDTIME;
static const int MBSTRING_UTF8;
"""
FUNCTIONS = """
ASN1_OBJECT *ASN1_OBJECT_new(void);
void ASN1_OBJECT_free(ASN1_OBJECT *);
/* ASN1 OBJECT IDENTIFIER */
ASN1_OBJECT *d2i_ASN1_OBJECT(ASN1_OBJECT **, const unsigned char **, long);
int i2d_ASN1_OBJECT(ASN1_OBJECT *, unsigned char **);
/* ASN1 STRING */
ASN1_STRING *ASN1_STRING_new(void);
ASN1_STRING *ASN1_STRING_type_new(int);
void ASN1_STRING_free(ASN1_STRING *);
unsigned char *ASN1_STRING_data(ASN1_STRING *);
int ASN1_STRING_set(ASN1_STRING *, const void *, int);
int ASN1_STRING_type(ASN1_STRING *);
int ASN1_STRING_to_UTF8(unsigned char **, ASN1_STRING *);
/* ASN1 OCTET STRING */
ASN1_OCTET_STRING *ASN1_OCTET_STRING_new(void);
void ASN1_OCTET_STRING_free(ASN1_OCTET_STRING *);
int ASN1_OCTET_STRING_set(ASN1_OCTET_STRING *, const unsigned char *, int);
/* ASN1 INTEGER */
ASN1_INTEGER *ASN1_INTEGER_new(void);
void ASN1_INTEGER_free(ASN1_INTEGER *);
int ASN1_INTEGER_set(ASN1_INTEGER *, long);
int i2a_ASN1_INTEGER(BIO *, ASN1_INTEGER *);
/* ASN1 TIME */
ASN1_TIME *ASN1_TIME_new(void);
void ASN1_TIME_free(ASN1_TIME *);
ASN1_GENERALIZEDTIME *ASN1_TIME_to_generalizedtime(ASN1_TIME *,
ASN1_GENERALIZEDTIME **);
/* ASN1 UTCTIME */
int ASN1_UTCTIME_cmp_time_t(const ASN1_UTCTIME *, time_t);
/* ASN1 GENERALIZEDTIME */
int ASN1_GENERALIZEDTIME_set_string(ASN1_GENERALIZEDTIME *, const char *);
void ASN1_GENERALIZEDTIME_free(ASN1_GENERALIZEDTIME *);
/* ASN1 ENUMERATED */
ASN1_ENUMERATED *ASN1_ENUMERATED_new(void);
void ASN1_ENUMERATED_free(ASN1_ENUMERATED *);
int ASN1_ENUMERATED_set(ASN1_ENUMERATED *, long);
ASN1_VALUE *ASN1_item_d2i(ASN1_VALUE **, const unsigned char **, long,
const ASN1_ITEM *);
"""
MACROS = """
ASN1_TIME *M_ASN1_TIME_dup(void *);
const ASN1_ITEM *ASN1_ITEM_ptr(ASN1_ITEM_EXP *);
/* These aren't macros these arguments are all const X on openssl > 1.0.x */
int ASN1_STRING_length(ASN1_STRING *);
ASN1_STRING *ASN1_STRING_dup(ASN1_STRING *);
int ASN1_STRING_cmp(ASN1_STRING *, ASN1_STRING *);
ASN1_OCTET_STRING *ASN1_OCTET_STRING_dup(ASN1_OCTET_STRING *);
int ASN1_OCTET_STRING_cmp(ASN1_OCTET_STRING *, ASN1_OCTET_STRING *);
ASN1_INTEGER *ASN1_INTEGER_dup(ASN1_INTEGER *);
int ASN1_INTEGER_cmp(ASN1_INTEGER *, ASN1_INTEGER *);
long ASN1_INTEGER_get(ASN1_INTEGER *);
BIGNUM *ASN1_INTEGER_to_BN(ASN1_INTEGER *, BIGNUM *);
ASN1_INTEGER *BN_to_ASN1_INTEGER(BIGNUM *, ASN1_INTEGER *);
/* These isn't a macro the arg is const on openssl 1.0.2+ */
int ASN1_GENERALIZEDTIME_check(ASN1_GENERALIZEDTIME *);
/* Not a macro, const on openssl 1.0 */
int ASN1_STRING_set_default_mask_asc(char *);
"""
CUSTOMIZATIONS = """
"""
CONDITIONAL_NAMES = {}

View file

@ -1,114 +0,0 @@
# 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
INCLUDES = """
#include <openssl/bn.h>
"""
TYPES = """
typedef ... BN_CTX;
typedef ... BIGNUM;
/*
* TODO: This typedef is wrong.
*
* This is due to limitations of cffi.
* See https://bitbucket.org/cffi/cffi/issue/69
*
* For another possible work-around (not used here because it involves more
* complicated use of the cffi API which falls outside the general pattern used
* by this package), see
* http://paste.pound-python.org/show/iJcTUMkKeBeS6yXpZWUU/
*
* The work-around used here is to just be sure to declare a type that is at
* least as large as the real type. Maciej explains:
*
* <fijal> I think you want to declare your value too large (e.g. long)
* <fijal> that way you'll never pass garbage
*/
typedef uintptr_t BN_ULONG;
"""
FUNCTIONS = """
BIGNUM *BN_new(void);
void BN_free(BIGNUM *);
BN_CTX *BN_CTX_new(void);
void BN_CTX_free(BN_CTX *);
void BN_CTX_start(BN_CTX *);
BIGNUM *BN_CTX_get(BN_CTX *);
void BN_CTX_end(BN_CTX *);
BIGNUM *BN_copy(BIGNUM *, const BIGNUM *);
BIGNUM *BN_dup(const BIGNUM *);
int BN_set_word(BIGNUM *, BN_ULONG);
BN_ULONG BN_get_word(const BIGNUM *);
const BIGNUM *BN_value_one(void);
char *BN_bn2hex(const BIGNUM *);
int BN_hex2bn(BIGNUM **, const char *);
int BN_dec2bn(BIGNUM **, const char *);
int BN_bn2bin(const BIGNUM *, unsigned char *);
BIGNUM *BN_bin2bn(const unsigned char *, int, BIGNUM *);
int BN_num_bits(const BIGNUM *);
int BN_cmp(const BIGNUM *, const BIGNUM *);
int BN_add(BIGNUM *, const BIGNUM *, const BIGNUM *);
int BN_sub(BIGNUM *, const BIGNUM *, const BIGNUM *);
int BN_mul(BIGNUM *, const BIGNUM *, const BIGNUM *, BN_CTX *);
int BN_sqr(BIGNUM *, const BIGNUM *, BN_CTX *);
int BN_div(BIGNUM *, BIGNUM *, const BIGNUM *, const BIGNUM *, BN_CTX *);
int BN_nnmod(BIGNUM *, const BIGNUM *, const BIGNUM *, BN_CTX *);
int BN_mod_add(BIGNUM *, const BIGNUM *, const BIGNUM *, const BIGNUM *,
BN_CTX *);
int BN_mod_sub(BIGNUM *, const BIGNUM *, const BIGNUM *, const BIGNUM *,
BN_CTX *);
int BN_mod_mul(BIGNUM *, const BIGNUM *, const BIGNUM *, const BIGNUM *,
BN_CTX *);
int BN_mod_sqr(BIGNUM *, const BIGNUM *, const BIGNUM *, BN_CTX *);
int BN_exp(BIGNUM *, const BIGNUM *, const BIGNUM *, BN_CTX *);
int BN_mod_exp(BIGNUM *, const BIGNUM *, const BIGNUM *, const BIGNUM *,
BN_CTX *);
int BN_gcd(BIGNUM *, const BIGNUM *, const BIGNUM *, BN_CTX *);
BIGNUM *BN_mod_inverse(BIGNUM *, const BIGNUM *, const BIGNUM *, BN_CTX *);
int BN_set_bit(BIGNUM *, int);
int BN_clear_bit(BIGNUM *, int);
int BN_is_bit_set(const BIGNUM *, int);
int BN_mask_bits(BIGNUM *, int);
"""
MACROS = """
int BN_zero(BIGNUM *);
int BN_one(BIGNUM *);
int BN_mod(BIGNUM *, const BIGNUM *, const BIGNUM *, BN_CTX *);
int BN_lshift(BIGNUM *, const BIGNUM *, int);
int BN_lshift1(BIGNUM *, BIGNUM *);
int BN_rshift(BIGNUM *, BIGNUM *, int);
int BN_rshift1(BIGNUM *, BIGNUM *);
"""
CUSTOMIZATIONS = """
"""
CONDITIONAL_NAMES = {}

View file

@ -1,119 +1,137 @@
# Licensed under the Apache License, Version 2.0 (the "License"); # This file is dual licensed under the terms of the Apache License, Version
# you may not use this file except in compliance with the License. # 2.0, and the BSD License. See the LICENSE file in the root of this repository
# You may obtain a copy of the License at # for complete details.
#
# 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 from __future__ import absolute_import, division, print_function
import collections
import os import os
import sys
import threading import threading
import types
from cryptography.hazmat.bindings.utils import build_ffi from cryptography.exceptions import InternalError
from cryptography.hazmat.bindings._openssl import ffi, lib
from cryptography.hazmat.bindings.openssl._conditional import CONDITIONAL_NAMES
_OSX_PRE_INCLUDE = """ _OpenSSLError = collections.namedtuple("_OpenSSLError",
#ifdef __APPLE__ ["code", "lib", "func", "reason"])
#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__ def _consume_errors(lib):
#undef DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER errors = []
#define DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER \ while True:
__ORIG_DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER code = lib.ERR_get_error()
#endif if code == 0:
""" break
err_lib = lib.ERR_GET_LIB(code)
err_func = lib.ERR_GET_FUNC(code)
err_reason = lib.ERR_GET_REASON(code)
errors.append(_OpenSSLError(code, err_lib, err_func, err_reason))
return errors
def _openssl_assert(lib, ok):
if not ok:
errors = _consume_errors(lib)
raise InternalError(
"Unknown OpenSSL error. Please file an issue at https://github.com"
"/pyca/cryptography/issues with information on how to reproduce "
"this.",
errors
)
@ffi.callback("int (*)(unsigned char *, int)", error=-1)
def _osrandom_rand_bytes(buf, size):
signed = ffi.cast("char *", buf)
result = os.urandom(size)
signed[0:size] = result
return 1
@ffi.callback("int (*)(void)")
def _osrandom_rand_status():
return 1
def build_conditional_library(lib, conditional_names):
conditional_lib = types.ModuleType("lib")
excluded_names = set()
for condition, names in conditional_names.items():
if not getattr(lib, condition):
excluded_names |= set(names)
for attr in dir(lib):
if attr not in excluded_names:
setattr(conditional_lib, attr, getattr(lib, attr))
return conditional_lib
class Binding(object): class Binding(object):
""" """
OpenSSL API wrapper. OpenSSL API wrapper.
""" """
_module_prefix = "cryptography.hazmat.bindings.openssl." lib = None
_modules = [ ffi = ffi
"aes", _lib_loaded = False
"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 _locks = None
_lock_cb_handle = None _lock_cb_handle = None
_init_lock = threading.Lock()
_lock_init_lock = threading.Lock() _lock_init_lock = threading.Lock()
ffi = None _osrandom_engine_id = ffi.new("const char[]", b"osrandom")
lib = None _osrandom_engine_name = ffi.new("const char[]", b"osrandom_engine")
_osrandom_method = ffi.new(
"RAND_METHOD *",
dict(bytes=_osrandom_rand_bytes, pseudorand=_osrandom_rand_bytes,
status=_osrandom_rand_status)
)
def __init__(self): def __init__(self):
self._ensure_ffi_initialized() self._ensure_ffi_initialized()
@classmethod @classmethod
def _ensure_ffi_initialized(cls): def _register_osrandom_engine(cls):
if cls.ffi is not None and cls.lib is not None: _openssl_assert(cls.lib, cls.lib.ERR_peek_error() == 0)
return
# OpenSSL goes by a different library name on different operating engine = cls.lib.ENGINE_new()
# systems. _openssl_assert(cls.lib, engine != cls.ffi.NULL)
if sys.platform != "win32": try:
# In some circumstances, the order in which these libs are result = cls.lib.ENGINE_set_id(engine, cls._osrandom_engine_id)
# specified on the linker command-line is significant; _openssl_assert(cls.lib, result == 1)
# libssl must come before libcrypto result = cls.lib.ENGINE_set_name(engine, cls._osrandom_engine_name)
# (http://marc.info/?l=openssl-users&m=135361825921871) _openssl_assert(cls.lib, result == 1)
libraries = ["ssl", "crypto"] result = cls.lib.ENGINE_set_RAND(engine, cls._osrandom_method)
else: # pragma: no cover _openssl_assert(cls.lib, result == 1)
link_type = os.environ.get("PYCA_WINDOWS_LINK_TYPE", "static") result = cls.lib.ENGINE_add(engine)
libraries = _get_windows_libraries(link_type) if result != 1:
errors = _consume_errors(cls.lib)
cls.ffi, cls.lib = build_ffi( _openssl_assert(
module_prefix=cls._module_prefix, cls.lib,
modules=cls._modules, errors[0].reason == cls.lib.ENGINE_R_CONFLICTING_ENGINE_ID
pre_include=_OSX_PRE_INCLUDE,
post_include=_OSX_POST_INCLUDE,
libraries=libraries,
) )
res = cls.lib.Cryptography_add_osrandom_engine()
assert res != 0 finally:
result = cls.lib.ENGINE_free(engine)
_openssl_assert(cls.lib, result == 1)
@classmethod
def _ensure_ffi_initialized(cls):
with cls._init_lock:
if not cls._lib_loaded:
cls.lib = build_conditional_library(lib, CONDITIONAL_NAMES)
cls._lib_loaded = True
# initialize the SSL library
cls.lib.SSL_library_init()
# adds all ciphers/digests for EVP
cls.lib.OpenSSL_add_all_algorithms()
# loads error strings for libcrypto and libssl functions
cls.lib.SSL_load_error_strings()
cls._register_osrandom_engine()
@classmethod @classmethod
def init_static_locks(cls): def init_static_locks(cls):
@ -156,13 +174,9 @@ class Binding(object):
) )
def _get_windows_libraries(link_type): # OpenSSL is not thread safe until the locks are initialized. We call this
if link_type == "dynamic": # method in module scope so that it executes with the import lock. On
return ["libeay32", "ssleay32", "advapi32"] # Pythons < 3.4 this import lock is a global lock, which can prevent a race
elif link_type == "static" or link_type == "": # condition registering the OpenSSL locks. On Python 3.4+ the import lock
return ["libeay32mt", "ssleay32mt", "advapi32", # is per module so this approach will not work.
"crypt32", "gdi32", "user32", "ws2_32"] Binding.init_static_locks()
else:
raise ValueError(
"PYCA_WINDOWS_LINK_TYPE must be 'static' or 'dynamic'"
)

Some files were not shown because too many files have changed in this diff Show more