Merge pull request #492 from public/py-thread-safe

Python implementation of OpenSSL locking callback
diff --git a/cryptography/exceptions.py b/cryptography/exceptions.py
index 44363c2..2654b45 100644
--- a/cryptography/exceptions.py
+++ b/cryptography/exceptions.py
@@ -34,3 +34,7 @@
 
 class InvalidSignature(Exception):
     pass
+
+
+class InternalError(Exception):
+    pass
diff --git a/cryptography/hazmat/backends/commoncrypto/backend.py b/cryptography/hazmat/backends/commoncrypto/backend.py
index 7193f1d..4e70cab 100644
--- a/cryptography/hazmat/backends/commoncrypto/backend.py
+++ b/cryptography/hazmat/backends/commoncrypto/backend.py
@@ -16,7 +16,9 @@
 from collections import namedtuple
 
 from cryptography import utils
-from cryptography.exceptions import UnsupportedAlgorithm, InvalidTag
+from cryptography.exceptions import (
+    UnsupportedAlgorithm, InvalidTag, InternalError
+)
 from cryptography.hazmat.backends.interfaces import (
     HashBackend, HMACBackend, CipherBackend
 )
@@ -197,8 +199,9 @@
                 "the block length"
             )
         else:
-            raise SystemError(
-                "The backend returned an error. Code: {0}".format(response)
+            raise InternalError(
+                "The backend returned an unknown error, consider filing a bug."
+                " Code: {0}.".format(response)
             )
 
 
diff --git a/cryptography/hazmat/backends/openssl/backend.py b/cryptography/hazmat/backends/openssl/backend.py
index 504ad55..d8d4669 100644
--- a/cryptography/hazmat/backends/openssl/backend.py
+++ b/cryptography/hazmat/backends/openssl/backend.py
@@ -16,7 +16,9 @@
 import itertools
 
 from cryptography import utils
-from cryptography.exceptions import UnsupportedAlgorithm, InvalidTag
+from cryptography.exceptions import (
+    UnsupportedAlgorithm, InvalidTag, InternalError
+)
 from cryptography.hazmat.backends.interfaces import (
     CipherBackend, HashBackend, HMACBackend
 )
@@ -156,7 +158,7 @@
                         "the block length"
                     )
 
-        raise SystemError(
+        raise InternalError(
             "Unknown error code from OpenSSL, you should probably file a bug."
         )
 
diff --git a/docs/hazmat/backends/openssl.rst b/docs/hazmat/backends/openssl.rst
index a1f2d28..926ec7d 100644
--- a/docs/hazmat/backends/openssl.rst
+++ b/docs/hazmat/backends/openssl.rst
@@ -26,9 +26,11 @@
 even when multiple versions of the library are linked into the same program. If
 you are using your distribution's source packages these will probably be
 patched in for you already, otherwise you'll need to use options something like
-this when configuring OpenSSL::
+this when configuring OpenSSL:
 
-    ./config -Wl,--version-script=openssl.ld -Wl,-Bsymbolic-functions -fPIC shared
+.. code-block:: console
+
+    $ ./config -Wl,--version-script=openssl.ld -Wl,-Bsymbolic-functions -fPIC shared
 
 You'll also need to generate your own ``openssl.ld`` file. For example::
 
@@ -40,4 +42,23 @@
 You should replace the version string on the first line as appropriate for your
 build.
 
+Using your own OpenSSL on OS X
+------------------------------
+
+To link cryptography against a custom version of OpenSSL you'll need to set
+``ARCHFLAGS``, ``LDFLAGS``, and ``CFLAGS``. OpenSSL can be installed via
+`Homebrew`_:
+
+.. code-block:: console
+
+    $ brew install openssl
+
+Then install cryptography linking against the brewed version:
+
+.. code-block:: console
+
+    $ env ARCHFLAGS="-arch x86_64" LDFLAGS="-L/usr/local/opt/openssl/lib" CFLAGS="-I/usr/local/opt/openssl/include" pip install cryptography
+
+
 .. _`OpenSSL`: https://www.openssl.org/
+.. _`Homebrew`: http://brew.sh
diff --git a/tests/hazmat/backends/test_commoncrypto.py b/tests/hazmat/backends/test_commoncrypto.py
index cfa332d..7cc0f72 100644
--- a/tests/hazmat/backends/test_commoncrypto.py
+++ b/tests/hazmat/backends/test_commoncrypto.py
@@ -14,7 +14,7 @@
 import pytest
 
 from cryptography import utils
-from cryptography.exceptions import UnsupportedAlgorithm
+from cryptography.exceptions import UnsupportedAlgorithm, InternalError
 from cryptography.hazmat.bindings.commoncrypto.binding import Binding
 from cryptography.hazmat.primitives import interfaces
 from cryptography.hazmat.primitives.ciphers.algorithms import AES
@@ -49,10 +49,10 @@
         with pytest.raises(ValueError):
             backend._check_response(backend._lib.kCCAlignmentError)
 
-        with pytest.raises(SystemError):
+        with pytest.raises(InternalError):
             backend._check_response(backend._lib.kCCMemoryFailure)
 
-        with pytest.raises(SystemError):
+        with pytest.raises(InternalError):
             backend._check_response(backend._lib.kCCDecodeError)
 
     def test_nonexistent_aead_cipher(self):
diff --git a/tests/hazmat/backends/test_openssl.py b/tests/hazmat/backends/test_openssl.py
index 2a32992..f01c3f6 100644
--- a/tests/hazmat/backends/test_openssl.py
+++ b/tests/hazmat/backends/test_openssl.py
@@ -14,7 +14,7 @@
 import pytest
 
 from cryptography import utils
-from cryptography.exceptions import UnsupportedAlgorithm
+from cryptography.exceptions import UnsupportedAlgorithm, InternalError
 from cryptography.hazmat.backends import default_backend
 from cryptography.hazmat.backends.openssl.backend import backend, Backend
 from cryptography.hazmat.primitives import interfaces
@@ -76,20 +76,20 @@
             cipher.encryptor()
 
     def test_handle_unknown_error(self):
-        with pytest.raises(SystemError):
+        with pytest.raises(InternalError):
             backend._handle_error_code(0, 0, 0)
 
-        with pytest.raises(SystemError):
+        with pytest.raises(InternalError):
             backend._handle_error_code(backend._lib.ERR_LIB_EVP, 0, 0)
 
-        with pytest.raises(SystemError):
+        with pytest.raises(InternalError):
             backend._handle_error_code(
                 backend._lib.ERR_LIB_EVP,
                 backend._lib.EVP_F_EVP_ENCRYPTFINAL_EX,
                 0
             )
 
-        with pytest.raises(SystemError):
+        with pytest.raises(InternalError):
             backend._handle_error_code(
                 backend._lib.ERR_LIB_EVP,
                 backend._lib.EVP_F_EVP_DECRYPTFINAL_EX,