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)