Merge pull request #1152 from public/fedora20-ec-fix
Fix EC issue on Fedora 20
diff --git a/cryptography/hazmat/backends/openssl/backend.py b/cryptography/hazmat/backends/openssl/backend.py
index 53d92be..2a7e3cc 100644
--- a/cryptography/hazmat/backends/openssl/backend.py
+++ b/cryptography/hazmat/backends/openssl/backend.py
@@ -930,8 +930,28 @@
if self._lib.Cryptography_HAS_EC != 1:
return False
- curves = self._supported_curves()
- return curve.name.encode("ascii") in curves
+ try:
+ curve_nid = self._elliptic_curve_to_nid(curve)
+ except UnsupportedAlgorithm:
+ curve_nid = self._lib.NID_undef
+
+ ctx = self._lib.EC_GROUP_new_by_curve_name(curve_nid)
+
+ if ctx == self._ffi.NULL:
+ errors = self._consume_errors()
+ assert (
+ curve_nid == self._lib.NID_undef or
+ errors[0][1:] == (
+ self._lib.ERR_LIB_EC,
+ self._lib.EC_F_EC_GROUP_NEW_BY_CURVE_NAME,
+ self._lib.EC_R_UNKNOWN_GROUP
+ )
+ )
+ return False
+ else:
+ assert curve_nid != self._lib.NID_undef
+ self._lib.EC_GROUP_free(ctx)
+ return True
def elliptic_curve_signature_algorithm_supported(
self, signature_algorithm, curve
@@ -952,30 +972,6 @@
return self.elliptic_curve_supported(curve)
- def _supported_curves(self):
- if self._lib.Cryptography_HAS_EC != 1:
- return []
-
- num_curves = self._lib.EC_get_builtin_curves(self._ffi.NULL, 0)
- curve_array = self._ffi.new("EC_builtin_curve[]", num_curves)
- num_curves_assigned = self._lib.EC_get_builtin_curves(
- curve_array, num_curves)
- assert num_curves == num_curves_assigned
-
- curves = [
- self._ffi.string(self._lib.OBJ_nid2sn(curve.nid)).decode()
- for curve in curve_array
- ]
-
- curve_aliases = {
- "prime192v1": "secp192r1",
- "prime256v1": "secp256r1"
- }
- return [
- curve_aliases.get(curve, curve)
- for curve in curves
- ]
-
def _create_ecdsa_signature_ctx(self, private_key, ecdsa):
return _ECDSASignatureContext(self, private_key, ecdsa.algorithm)
@@ -2014,7 +2010,7 @@
mask = 0xFF >> rshift << rshift
# Set the bottom rshift bits to 0
- digest = digest[:-1] + six.int2byte(six.byte2int(digest[-1]) & mask)
+ digest = digest[:-1] + six.int2byte(six.indexbytes(digest, -1) & mask)
return digest
diff --git a/cryptography/hazmat/bindings/openssl/err.py b/cryptography/hazmat/bindings/openssl/err.py
index 9c9b45c..232060a 100644
--- a/cryptography/hazmat/bindings/openssl/err.py
+++ b/cryptography/hazmat/bindings/openssl/err.py
@@ -21,6 +21,7 @@
static const int Cryptography_HAS_REMOVE_THREAD_STATE;
static const int Cryptography_HAS_098H_ERROR_CODES;
static const int Cryptography_HAS_098C_CAMELLIA_CODES;
+static const int Cryptography_HAS_EC_CODES;
struct ERR_string_data_st {
unsigned long error;
@@ -29,6 +30,7 @@
typedef struct ERR_string_data_st ERR_STRING_DATA;
static const int ERR_LIB_EVP;
+static const int ERR_LIB_EC;
static const int ERR_LIB_PEM;
static const int ERR_LIB_ASN1;
static const int ERR_LIB_RSA;
@@ -172,6 +174,10 @@
static const int EVP_R_WRONG_FINAL_BLOCK_LENGTH;
static const int EVP_R_WRONG_PUBLIC_KEY_TYPE;
+static const int EC_F_EC_GROUP_NEW_BY_CURVE_NAME;
+
+static const int EC_R_UNKNOWN_GROUP;
+
static const int PEM_F_D2I_PKCS8PRIVATEKEY_BIO;
static const int PEM_F_D2I_PKCS8PRIVATEKEY_FP;
static const int PEM_F_DO_PK8PKEY;
@@ -306,6 +312,15 @@
static const int EVP_F_CAMELLIA_INIT_KEY = 0;
static const int EVP_R_CAMELLIA_KEY_SETUP_FAILED = 0;
#endif
+
+// OpenSSL without EC. e.g. RHEL
+#ifndef OPENSSL_NO_EC
+static const long Cryptography_HAS_EC_CODES = 1;
+#else
+static const long Cryptography_HAS_EC_CODES = 0;
+static const int EC_R_UNKNOWN_GROUP = 0;
+static const int EC_F_EC_GROUP_NEW_BY_CURVE_NAME = 0;
+#endif
"""
CONDITIONAL_NAMES = {
@@ -324,5 +339,9 @@
"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"
]
}
diff --git a/tests/hazmat/backends/test_openssl.py b/tests/hazmat/backends/test_openssl.py
index 0dd9169..bd99c8f 100644
--- a/tests/hazmat/backends/test_openssl.py
+++ b/tests/hazmat/backends/test_openssl.py
@@ -487,11 +487,6 @@
None, None
) is False
- def test_supported_curves(self, monkeypatch):
- monkeypatch.setattr(backend._lib, "Cryptography_HAS_EC", 0)
-
- assert backend._supported_curves() == []
-
class TestDeprecatedRSABackendMethods(object):
def test_create_rsa_signature_ctx(self):
diff --git a/tests/hazmat/primitives/test_ec.py b/tests/hazmat/primitives/test_ec.py
index 1879f4f..2690e79 100644
--- a/tests/hazmat/primitives/test_ec.py
+++ b/tests/hazmat/primitives/test_ec.py
@@ -70,6 +70,15 @@
)
+def _skip_curve_unsupported(backend, curve):
+ if not backend.elliptic_curve_supported(curve):
+ pytest.skip(
+ "Curve {0} is not supported by this backend {1}".format(
+ curve.name, backend
+ )
+ )
+
+
@utils.register_interface(interfaces.EllipticCurve)
class DummyCurve(object):
name = "dummy-curve"
@@ -81,6 +90,12 @@
pass
+@pytest.mark.elliptic
+def test_skip_curve_unsupported(backend):
+ with pytest.raises(pytest.skip.Exception):
+ _skip_curve_unsupported(backend, DummyCurve())
+
+
def test_ec_numbers():
numbers = ec.EllipticCurvePrivateNumbers(
1,
@@ -176,12 +191,7 @@
"curve", _CURVE_TYPES.values()
)
def test_generate_vector_curves(self, backend, curve):
- if not backend.elliptic_curve_supported(curve()):
- pytest.skip(
- "Curve {0} is not supported by this backend {1}".format(
- curve().name, backend
- )
- )
+ _skip_curve_unsupported(backend, curve())
key = ec.generate_private_key(curve(), backend)
assert key
@@ -205,12 +215,7 @@
) is False
def test_unknown_signature_algoritm(self, backend):
- if not backend.elliptic_curve_supported(ec.SECP192R1()):
- pytest.skip(
- "Curve secp192r1 is not supported by this backend {0}".format(
- backend
- )
- )
+ _skip_curve_unsupported(backend, ec.SECP192R1())
key = ec.generate_private_key(ec.SECP192R1(), backend)