aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Kehrer <paul.l.kehrer@gmail.com>2017-05-25 23:05:00 -0500
committerAlex Gaynor <alex.gaynor@gmail.com>2017-05-26 00:05:00 -0400
commitd36bef0b744d79b209b13f87fb9c943e4091a2c5 (patch)
treeab33864d222f62b8c38511315e753063016c3153
parent349923379f1c1baf51ff1709abaa19559a59ad69 (diff)
downloadcryptography-d36bef0b744d79b209b13f87fb9c943e4091a2c5.tar.gz
cryptography-d36bef0b744d79b209b13f87fb9c943e4091a2c5.tar.bz2
cryptography-d36bef0b744d79b209b13f87fb9c943e4091a2c5.zip
fix libressl error/refactor some error handling (#3609)
* add libre so I can see the error * add the libre error needed and refactor error handling a bit We were historically matching on lib + func + reason, but func is somewhat unstable so now we match on lib + reason only. Of course, in this case libressl changed both lib and reason so it wouldn't have mattered. All error handling from the error queue in openssl is an illusion * fix a typo, probably an unneeded branch * review feedback * refactor tests to support libressl insert additional rant about libre here, although admittedly these tests were assuming stability where openssl itself guarantees none * better assert, fix flake8
-rw-r--r--Jenkinsfile5
-rw-r--r--src/cryptography/hazmat/backends/openssl/backend.py63
-rw-r--r--src/cryptography/hazmat/backends/openssl/ciphers.py6
-rw-r--r--src/cryptography/hazmat/backends/openssl/dh.py10
-rw-r--r--src/cryptography/hazmat/bindings/openssl/binding.py19
-rw-r--r--tests/hazmat/backends/test_openssl.py5
-rw-r--r--tests/hazmat/bindings/test_openssl.py18
7 files changed, 67 insertions, 59 deletions
diff --git a/Jenkinsfile b/Jenkinsfile
index 6cdf1623..a45d0b41 100644
--- a/Jenkinsfile
+++ b/Jenkinsfile
@@ -55,6 +55,11 @@ def configs = [
],
[
label: 'docker',
+ imageName: 'pyca/cryptography-runner-jessie-libressl:2.5.4',
+ toxenvs: ['py27'],
+ ],
+ [
+ label: 'docker',
imageName: 'pyca/cryptography-runner-ubuntu-xenial',
toxenvs: ['py27', 'py35'],
],
diff --git a/src/cryptography/hazmat/backends/openssl/backend.py b/src/cryptography/hazmat/backends/openssl/backend.py
index a259d668..9900d053 100644
--- a/src/cryptography/hazmat/backends/openssl/backend.py
+++ b/src/cryptography/hazmat/backends/openssl/backend.py
@@ -710,10 +710,13 @@ class Backend(object):
)
if res == 0:
errors = self._consume_errors()
- self.openssl_assert(errors[0][1] == self._lib.ERR_LIB_RSA)
self.openssl_assert(
- errors[0][3] == self._lib.RSA_R_DIGEST_TOO_BIG_FOR_RSA_KEY
+ errors[0]._lib_reason_match(
+ self._lib.ERR_LIB_RSA,
+ self._lib.RSA_R_DIGEST_TOO_BIG_FOR_RSA_KEY
+ )
)
+
raise ValueError("Digest too big for RSA key")
return _CertificateSigningRequest(self, x509_req)
@@ -792,9 +795,11 @@ class Backend(object):
)
if res == 0:
errors = self._consume_errors()
- self.openssl_assert(errors[0][1] == self._lib.ERR_LIB_RSA)
self.openssl_assert(
- errors[0][3] == self._lib.RSA_R_DIGEST_TOO_BIG_FOR_RSA_KEY
+ errors[0]._lib_reason_match(
+ self._lib.ERR_LIB_RSA,
+ self._lib.RSA_R_DIGEST_TOO_BIG_FOR_RSA_KEY
+ )
)
raise ValueError("Digest too big for RSA key")
@@ -802,9 +807,11 @@ class Backend(object):
def _raise_time_set_error(self):
errors = self._consume_errors()
- self.openssl_assert(errors[0][1] == self._lib.ERR_LIB_ASN1)
self.openssl_assert(
- errors[0][3] == self._lib.ASN1_R_ERROR_GETTING_TIME
+ errors[0]._lib_reason_match(
+ self._lib.ERR_LIB_ASN1,
+ self._lib.ASN1_R_ERROR_GETTING_TIME
+ )
)
raise ValueError(
"Invalid time. This error can occur if you set a time too far in "
@@ -879,9 +886,11 @@ class Backend(object):
)
if res == 0:
errors = self._consume_errors()
- self.openssl_assert(errors[0][1] == self._lib.ERR_LIB_RSA)
self.openssl_assert(
- errors[0][3] == self._lib.RSA_R_DIGEST_TOO_BIG_FOR_RSA_KEY
+ errors[0]._lib_reason_match(
+ self._lib.ERR_LIB_RSA,
+ self._lib.RSA_R_DIGEST_TOO_BIG_FOR_RSA_KEY
+ )
)
raise ValueError("Digest too big for RSA key")
@@ -1173,31 +1182,21 @@ class Backend(object):
if not errors:
raise ValueError("Could not deserialize key data.")
- elif errors[0][1:] in (
- (
- self._lib.ERR_LIB_EVP,
- self._lib.EVP_F_EVP_DECRYPTFINAL_EX,
- self._lib.EVP_R_BAD_DECRYPT
- ),
- (
+ elif (
+ errors[0]._lib_reason_match(
+ self._lib.ERR_LIB_EVP, self._lib.EVP_R_BAD_DECRYPT
+ ) or errors[0]._lib_reason_match(
self._lib.ERR_LIB_PKCS12,
- self._lib.PKCS12_F_PKCS12_PBE_CRYPT,
- self._lib.PKCS12_R_PKCS12_CIPHERFINAL_ERROR,
+ self._lib.PKCS12_R_PKCS12_CIPHERFINAL_ERROR
)
):
raise ValueError("Bad decrypt. Incorrect password?")
- elif errors[0][1:] in (
- (
- self._lib.ERR_LIB_PEM,
- self._lib.PEM_F_PEM_GET_EVP_CIPHER_INFO,
- self._lib.PEM_R_UNSUPPORTED_ENCRYPTION
- ),
-
- (
- self._lib.ERR_LIB_EVP,
- self._lib.EVP_F_EVP_PBE_CIPHERINIT,
- self._lib.EVP_R_UNKNOWN_PBE_ALGORITHM
+ elif (
+ errors[0]._lib_reason_match(
+ self._lib.ERR_LIB_EVP, self._lib.EVP_R_UNKNOWN_PBE_ALGORITHM
+ ) or errors[0]._lib_reason_match(
+ self._lib.ERR_LIB_PEM, self._lib.PEM_R_UNSUPPORTED_ENCRYPTION
)
):
raise UnsupportedAlgorithm(
@@ -1206,9 +1205,8 @@ class Backend(object):
)
elif any(
- error[1:] == (
+ error._lib_reason_match(
self._lib.ERR_LIB_EVP,
- self._lib.EVP_F_EVP_PKCS82PKEY,
self._lib.EVP_R_UNSUPPORTED_PRIVATE_KEY_ALGORITHM
)
for error in errors
@@ -1216,7 +1214,7 @@ class Backend(object):
raise ValueError("Unsupported public key algorithm.")
else:
- assert errors[0][1] in (
+ assert errors[0].lib in (
self._lib.ERR_LIB_EVP,
self._lib.ERR_LIB_PEM,
self._lib.ERR_LIB_ASN1,
@@ -1235,9 +1233,8 @@ class Backend(object):
errors = self._consume_errors()
self.openssl_assert(
curve_nid == self._lib.NID_undef or
- errors[0][1:] == (
+ errors[0]._lib_reason_match(
self._lib.ERR_LIB_EC,
- self._lib.EC_F_EC_GROUP_NEW_BY_CURVE_NAME,
self._lib.EC_R_UNKNOWN_GROUP
)
)
diff --git a/src/cryptography/hazmat/backends/openssl/ciphers.py b/src/cryptography/hazmat/backends/openssl/ciphers.py
index 13c9fa52..4ca2fee6 100644
--- a/src/cryptography/hazmat/backends/openssl/ciphers.py
+++ b/src/cryptography/hazmat/backends/openssl/ciphers.py
@@ -160,13 +160,11 @@ class _CipherContext(object):
raise InvalidTag
self._backend.openssl_assert(
- errors[0][1:] == (
+ errors[0]._lib_reason_match(
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:] == (
+ ) or errors[0]._lib_reason_match(
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
)
)
diff --git a/src/cryptography/hazmat/backends/openssl/dh.py b/src/cryptography/hazmat/backends/openssl/dh.py
index 88c876fc..456e9bea 100644
--- a/src/cryptography/hazmat/backends/openssl/dh.py
+++ b/src/cryptography/hazmat/backends/openssl/dh.py
@@ -63,11 +63,11 @@ class _DHParameters(object):
def _handle_dh_compute_key_error(errors, backend):
lib = backend._lib
- backend.openssl_assert(errors[0][1:] == (
- lib.ERR_LIB_DH,
- lib.DH_F_COMPUTE_KEY,
- lib.DH_R_INVALID_PUBKEY
- ))
+ backend.openssl_assert(
+ errors[0]._lib_reason_match(
+ lib.ERR_LIB_DH, lib.DH_R_INVALID_PUBKEY
+ )
+ )
raise ValueError("Public key value is invalid for this exchange.")
diff --git a/src/cryptography/hazmat/bindings/openssl/binding.py b/src/cryptography/hazmat/bindings/openssl/binding.py
index 6b3d50c4..d00fc794 100644
--- a/src/cryptography/hazmat/bindings/openssl/binding.py
+++ b/src/cryptography/hazmat/bindings/openssl/binding.py
@@ -8,17 +8,32 @@ import collections
import threading
import types
+from cryptography import utils
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"])
_OpenSSLErrorWithText = collections.namedtuple(
"_OpenSSLErrorWithText", ["code", "lib", "func", "reason", "reason_text"]
)
+class _OpenSSLError(object):
+ def __init__(self, code, lib, func, reason):
+ self._code = code
+ self._lib = lib
+ self._func = func
+ self._reason = reason
+
+ def _lib_reason_match(self, lib, reason):
+ return lib == self.lib and reason == self.reason
+
+ code = utils.read_only_property("_code")
+ lib = utils.read_only_property("_lib")
+ func = utils.read_only_property("_func")
+ reason = utils.read_only_property("_reason")
+
+
def _consume_errors(lib):
errors = []
while True:
diff --git a/tests/hazmat/backends/test_openssl.py b/tests/hazmat/backends/test_openssl.py
index 20c073a4..e857ff61 100644
--- a/tests/hazmat/backends/test_openssl.py
+++ b/tests/hazmat/backends/test_openssl.py
@@ -127,10 +127,7 @@ class TestOpenSSL(object):
def test_error_strings_loaded(self):
# returns a value in a static buffer
err = backend._lib.ERR_error_string(101183626, backend._ffi.NULL)
- assert backend._ffi.string(err) == (
- b"error:0607F08A:digital envelope routines:EVP_EncryptFinal_ex:"
- b"data not multiple of block length"
- )
+ assert b"data not multiple of block length" in backend._ffi.string(err)
def test_unknown_error_in_cipher_finalize(self):
cipher = Cipher(AES(b"\0" * 16), CBC(b"\0" * 16), backend=backend)
diff --git a/tests/hazmat/bindings/test_openssl.py b/tests/hazmat/bindings/test_openssl.py
index 9b0da67c..488f64e1 100644
--- a/tests/hazmat/bindings/test_openssl.py
+++ b/tests/hazmat/bindings/test_openssl.py
@@ -8,7 +8,7 @@ import pytest
from cryptography.exceptions import InternalError
from cryptography.hazmat.bindings.openssl.binding import (
- Binding, _OpenSSLErrorWithText, _consume_errors, _openssl_assert
+ Binding, _consume_errors, _openssl_assert
)
@@ -94,16 +94,12 @@ class TestOpenSSL(object):
with pytest.raises(InternalError) as exc_info:
_openssl_assert(b.lib, False)
- assert exc_info.value.err_code == [_OpenSSLErrorWithText(
- code=101183626,
- lib=b.lib.ERR_LIB_EVP,
- func=b.lib.EVP_F_EVP_ENCRYPTFINAL_EX,
- reason=b.lib.EVP_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH,
- reason_text=(
- b'error:0607F08A:digital envelope routines:EVP_EncryptFinal_'
- b'ex:data not multiple of block length'
- )
- )]
+ error = exc_info.value.err_code[0]
+ assert error.code == 101183626
+ assert error.lib == b.lib.ERR_LIB_EVP
+ assert error.func == b.lib.EVP_F_EVP_ENCRYPTFINAL_EX
+ assert error.reason == b.lib.EVP_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH
+ assert b"data not multiple of block length" in error.reason_text
def test_check_startup_errors_are_allowed(self):
b = Binding()