Skip to content

Commit

Permalink
Merge pull request #2378 from reaperhulk/backport-death-to-asserts
Browse files Browse the repository at this point in the history
Backport final assert changes
  • Loading branch information
alex committed Sep 27, 2015
2 parents 476350e + 1a66a17 commit 1e5c2ef
Show file tree
Hide file tree
Showing 10 changed files with 68 additions and 96 deletions.
4 changes: 3 additions & 1 deletion src/cryptography/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,9 @@ class InvalidSignature(Exception):


class InternalError(Exception):
pass
def __init__(self, msg, err_code):
super(InternalError, self).__init__(msg)
self.err_code = err_code


class InvalidKey(Exception):
Expand Down
3 changes: 2 additions & 1 deletion src/cryptography/hazmat/backends/commoncrypto/backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,8 @@ def _check_cipher_response(self, response):
else:
raise InternalError(
"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):
Expand Down
51 changes: 5 additions & 46 deletions src/cryptography/hazmat/backends/openssl/backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,7 @@
import six

from cryptography import utils, x509
from cryptography.exceptions import (
InternalError, UnsupportedAlgorithm, _Reasons
)
from cryptography.exceptions import UnsupportedAlgorithm, _Reasons
from cryptography.hazmat.backends.interfaces import (
CMACBackend, CipherBackend, DERSerializationBackend, DSABackend,
EllipticCurveBackend, HMACBackend, HashBackend, PBKDF2HMACBackend,
Expand All @@ -41,7 +39,7 @@
_Certificate, _CertificateSigningRequest, _DISTPOINT_TYPE_FULLNAME,
_DISTPOINT_TYPE_RELATIVENAME
)
from cryptography.hazmat.bindings.openssl.binding import Binding
from cryptography.hazmat.bindings.openssl import binding
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import dsa, ec, rsa
from cryptography.hazmat.primitives.asymmetric.padding import (
Expand All @@ -57,14 +55,6 @@


_MemoryBIO = collections.namedtuple("_MemoryBIO", ["bio", "char_ptr"])
_OpenSSLError = collections.namedtuple("_OpenSSLError",
["code", "lib", "func", "reason"])


class UnhandledOpenSSLError(Exception):
def __init__(self, msg, errors):
super(UnhandledOpenSSLError, self).__init__(msg)
self.errors = errors


def _encode_asn1_int(backend, x):
Expand Down Expand Up @@ -523,7 +513,7 @@ class Backend(object):
name = "openssl"

def __init__(self):
self._binding = Binding()
self._binding = binding.Binding()
self._ffi = self._binding.ffi
self._lib = self._binding.lib

Expand All @@ -547,14 +537,7 @@ def __init__(self):
self.activate_osrandom_engine()

def openssl_assert(self, ok):
if not ok:
errors = self._consume_errors()
raise UnhandledOpenSSLError(
"Unknown OpenSSL error. Please file an issue at https://github"
".com/pyca/cryptography/issues with information on how to "
"reproduce this.",
errors
)
return binding._openssl_assert(self._lib, ok)

def activate_builtin_random(self):
# Obtain a new structural reference.
Expand Down Expand Up @@ -759,32 +742,8 @@ def derive_pbkdf2_hmac(self, algorithm, length, salt, iterations,

return self._ffi.buffer(buf)[:]

def _err_string(self, code):
err_buf = self._ffi.new("char[]", 256)
self._lib.ERR_error_string_n(code, err_buf, 256)
return self._ffi.string(err_buf, 256)[:]

def _consume_errors(self):
errors = []
while True:
code = self._lib.ERR_get_error()
if code == 0:
break

lib = self._lib.ERR_GET_LIB(code)
func = self._lib.ERR_GET_FUNC(code)
reason = self._lib.ERR_GET_REASON(code)

errors.append(_OpenSSLError(code, lib, func, reason))
return errors

def _unknown_error(self, error):
return InternalError(
"Unknown error code {0} from OpenSSL, "
"you should probably file a bug. {1}.".format(
error.code, self._err_string(error.code)
)
)
return binding._consume_errors(self._lib)

def _bn_to_int(self, bn):
assert bn != self._ffi.NULL
Expand Down
30 changes: 14 additions & 16 deletions src/cryptography/hazmat/backends/openssl/ciphers.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,23 +136,21 @@ def finalize(self):
if not errors and isinstance(self._mode, modes.GCM):
raise InvalidTag

assert errors

if errors[0][1:] == (
self._backend._lib.ERR_LIB_EVP,
self._backend._lib.EVP_F_EVP_ENCRYPTFINAL_EX,
self._backend._lib.EVP_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH
) or errors[0][1:] == (
self._backend._lib.ERR_LIB_EVP,
self._backend._lib.EVP_F_EVP_DECRYPTFINAL_EX,
self._backend._lib.EVP_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH
):
raise ValueError(
"The length of the provided data is not a multiple of "
"the block length."
self._backend.openssl_assert(
errors[0][1:] == (
self._backend._lib.ERR_LIB_EVP,
self._backend._lib.EVP_F_EVP_ENCRYPTFINAL_EX,
self._backend._lib.EVP_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH
) or errors[0][1:] == (
self._backend._lib.ERR_LIB_EVP,
self._backend._lib.EVP_F_EVP_DECRYPTFINAL_EX,
self._backend._lib.EVP_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH
)
else:
raise self._backend._unknown_error(errors[0])
)
raise ValueError(
"The length of the provided data is not a multiple of "
"the block length."
)

if (isinstance(self._mode, modes.GCM) and
self._operation == self._ENCRYPT):
Expand Down
2 changes: 1 addition & 1 deletion src/cryptography/hazmat/backends/openssl/dsa.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ def finalize(self):
0, data_to_sign, len(data_to_sign), sig_buf,
buflen, self._private_key._dsa_cdata)
self._backend.openssl_assert(res == 1)
assert buflen[0]
self._backend.openssl_assert(buflen[0])

return self._backend._ffi.buffer(sig_buf)[:buflen[0]]

Expand Down
2 changes: 1 addition & 1 deletion src/cryptography/hazmat/backends/openssl/hashes.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ def finalize(self):
outlen = self._backend._ffi.new("unsigned int *")
res = self._backend._lib.EVP_DigestFinal_ex(self._ctx, buf, outlen)
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)
self._backend.openssl_assert(res == 1)
return self._backend._ffi.buffer(buf)[:outlen[0]]
2 changes: 1 addition & 1 deletion src/cryptography/hazmat/backends/openssl/hmac.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ def finalize(self):
self._ctx, buf, outlen
)
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)
return self._backend._ffi.buffer(buf)[:outlen[0]]

Expand Down
3 changes: 0 additions & 3 deletions src/cryptography/hazmat/bindings/commoncrypto/binding.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,3 @@ class Binding(object):
"""
lib = lib
ffi = ffi

def __init__(self):
pass
46 changes: 39 additions & 7 deletions src/cryptography/hazmat/bindings/openssl/binding.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,46 @@

from __future__ import absolute_import, division, print_function

import collections
import os
import threading
import types

from cryptography.exceptions import InternalError
from cryptography.hazmat.bindings._openssl import ffi, lib
from cryptography.hazmat.bindings.openssl._conditional import CONDITIONAL_NAMES


_OpenSSLError = collections.namedtuple("_OpenSSLError",
["code", "lib", "func", "reason"])


def _consume_errors(lib):
errors = []
while True:
code = lib.ERR_get_error()
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)
Expand Down Expand Up @@ -64,27 +96,27 @@ def __init__(self):

@classmethod
def _register_osrandom_engine(cls):
assert cls.lib.ERR_peek_error() == 0
_openssl_assert(cls.lib, cls.lib.ERR_peek_error() == 0)
looked_up_engine = cls.lib.ENGINE_by_id(cls._osrandom_engine_id)
if looked_up_engine != ffi.NULL:
raise RuntimeError("osrandom engine already registered")

cls.lib.ERR_clear_error()

engine = cls.lib.ENGINE_new()
assert engine != cls.ffi.NULL
_openssl_assert(cls.lib, engine != cls.ffi.NULL)
try:
result = cls.lib.ENGINE_set_id(engine, cls._osrandom_engine_id)
assert result == 1
_openssl_assert(cls.lib, result == 1)
result = cls.lib.ENGINE_set_name(engine, cls._osrandom_engine_name)
assert result == 1
_openssl_assert(cls.lib, result == 1)
result = cls.lib.ENGINE_set_RAND(engine, cls._osrandom_method)
assert result == 1
_openssl_assert(cls.lib, result == 1)
result = cls.lib.ENGINE_add(engine)
assert result == 1
_openssl_assert(cls.lib, result == 1)
finally:
result = cls.lib.ENGINE_free(engine)
assert result == 1
_openssl_assert(cls.lib, result == 1)

@classmethod
def _ensure_ffi_initialized(cls):
Expand Down
21 changes: 2 additions & 19 deletions tests/hazmat/backends/test_openssl.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
from cryptography.exceptions import InternalError, _Reasons
from cryptography.hazmat.backends.interfaces import RSABackend
from cryptography.hazmat.backends.openssl.backend import (
Backend, UnhandledOpenSSLError, backend
Backend, backend
)
from cryptography.hazmat.backends.openssl.ec import _sn_to_elliptic_curve
from cryptography.hazmat.primitives import hashes, serialization
Expand Down Expand Up @@ -124,7 +124,7 @@ def test_nonexistent_cipher(self, mode):

def test_openssl_assert(self):
backend.openssl_assert(True)
with pytest.raises(UnhandledOpenSSLError):
with pytest.raises(InternalError):
backend.openssl_assert(False)

def test_consume_errors(self):
Expand All @@ -139,23 +139,6 @@ def test_consume_errors(self):
assert backend._lib.ERR_peek_error() == 0
assert len(errors) == 10

def test_openssl_error_string(self):
backend._lib.ERR_put_error(
backend._lib.ERR_LIB_EVP,
backend._lib.EVP_F_EVP_DECRYPTFINAL_EX,
0,
b"test_openssl.py",
-1
)

errors = backend._consume_errors()
exc = backend._unknown_error(errors[0])

assert (
"digital envelope routines:"
"EVP_DecryptFinal_ex:digital envelope routines" in str(exc)
)

def test_ssl_ciphers_registered(self):
meth = backend._lib.TLSv1_method()
ctx = backend._lib.SSL_CTX_new(meth)
Expand Down

0 comments on commit 1e5c2ef

Please sign in to comment.