Merge pull request #2147 from reaperhulk/there-are-two-parts

parts can't be > 2, so let's not pretend it could be
diff --git a/.travis.yml b/.travis.yml
index 8ad514f..b8206e0 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -120,7 +120,7 @@
     - ./.travis/run.sh
 
 after_success:
-    - source ~/.venv/bin/activate && bash <(curl -s https://codecov.io/bash) -e TRAVIS_OS_NAME,TOXENV,OPENSSL
+    - ./.travis/upload_coverage.sh
 
 notifications:
     irc:
diff --git a/.travis/upload_coverage.sh b/.travis/upload_coverage.sh
new file mode 100755
index 0000000..554116f
--- /dev/null
+++ b/.travis/upload_coverage.sh
@@ -0,0 +1,10 @@
+#!/bin/bash
+
+set -e
+set -x
+
+NO_COVERAGE_TOXENVS=(pypy pypy3 pep8 py3pep8 docs)
+if ! [[ "${NO_COVERAGE_TOXENVS[*]}" =~ "${TOXENV}" ]]; then
+    source ~/.venv/bin/activate
+    bash <(curl -s https://codecov.io/bash) -e TRAVIS_OS_NAME,TOXENV,OPENSSL
+fi
diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index 475a2a3..85f8447 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -93,7 +93,7 @@
   Note that unsupported extensions with the critical flag raise
   :class:`~cryptography.x509.UnsupportedExtension` while unsupported extensions
   set to non-critical are silently ignored. Read the
-  :doc:`X.509 documentation</x509>` for more information.
+  :doc:`X.509 documentation</x509/index>` for more information.
 
 0.8.2 - 2015-04-10
 ~~~~~~~~~~~~~~~~~~
@@ -120,7 +120,7 @@
   from :mod:`~cryptography.hazmat.primitives.interfaces` to
   :mod:`~cryptography.hazmat.primitives.kdf`.
 * Added support for parsing X.509 names. See the
-  :doc:`X.509 documentation</x509>` for more information.
+  :doc:`X.509 documentation</x509/index>` for more information.
 * Added
   :func:`~cryptography.hazmat.primitives.serialization.load_der_private_key` to
   support loading of DER encoded private keys and
@@ -256,7 +256,7 @@
   support the loading of OpenSSH public keys (:rfc:`4253`). Only RSA and DSA
   keys are currently supported.
 * Added initial support for X.509 certificate parsing. See the
-  :doc:`X.509 documentation</x509>` for more information.
+  :doc:`X.509 documentation</x509/index>` for more information.
 
 0.6.1 - 2014-10-15
 ~~~~~~~~~~~~~~~~~~
diff --git a/docs/hazmat/primitives/asymmetric/serialization.rst b/docs/hazmat/primitives/asymmetric/serialization.rst
index 7839f34..8d51f0d 100644
--- a/docs/hazmat/primitives/asymmetric/serialization.rst
+++ b/docs/hazmat/primitives/asymmetric/serialization.rst
@@ -97,8 +97,8 @@
 .. note::
 
     A PEM block which starts with ``-----BEGIN CERTIFICATE-----`` is not a
-    public or private key, it's an :doc:`X.509 Certificate </x509>`. You can
-    load it using :func:`~cryptography.x509.load_pem_x509_certificate` and
+    public or private key, it's an :doc:`X.509 Certificate </x509/index>`. You
+    can load it using :func:`~cryptography.x509.load_pem_x509_certificate` and
     extract the public key with
     :meth:`Certificate.public_key <cryptography.x509.Certificate.public_key>`.
 
diff --git a/docs/index.rst b/docs/index.rst
index 35f80a2..5c26a75 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -63,7 +63,7 @@
     :maxdepth: 2
 
     fernet
-    x509
+    x509/index
     random-numbers
     exceptions
     faq
diff --git a/docs/x509/index.rst b/docs/x509/index.rst
new file mode 100644
index 0000000..c3fa1ed
--- /dev/null
+++ b/docs/x509/index.rst
@@ -0,0 +1,14 @@
+X.509
+=====
+
+X.509 is an ITU-T standard for a `public key infrastructure`_. X.509v3 is
+defined in :rfc:`5280` (which obsoletes :rfc:`2459` and :rfc:`3280`). X.509
+certificates are commonly used in protocols like `TLS`_.
+
+.. toctree::
+    :maxdepth: 2
+
+    reference
+
+.. _`public key infrastructure`: https://en.wikipedia.org/wiki/Public_key_infrastructure
+.. _`TLS`: https://en.wikipedia.org/wiki/Transport_Layer_Security
diff --git a/docs/x509.rst b/docs/x509/reference.rst
similarity index 98%
rename from docs/x509.rst
rename to docs/x509/reference.rst
index bcb6ee6..9179468 100644
--- a/docs/x509.rst
+++ b/docs/x509/reference.rst
@@ -1,5 +1,5 @@
-X.509
-=====
+X.509 Reference
+===============
 
 .. currentmodule:: cryptography.x509
 
@@ -86,10 +86,6 @@
     -----END CERTIFICATE-----
     """.strip()
 
-X.509 is an ITU-T standard for a `public key infrastructure`_. X.509v3 is
-defined in :rfc:`5280` (which obsoletes :rfc:`2459` and :rfc:`3280`). X.509
-certificates are commonly used in protocols like `TLS`_.
-
 Loading Certificates
 ~~~~~~~~~~~~~~~~~~~~
 
@@ -1582,7 +1578,5 @@
         types can be found in `RFC 5280 section 4.2.1.6`_.
 
 
-.. _`public key infrastructure`: https://en.wikipedia.org/wiki/Public_key_infrastructure
-.. _`TLS`: https://en.wikipedia.org/wiki/Transport_Layer_Security
 .. _`RFC 5280 section 4.2.1.1`: https://tools.ietf.org/html/rfc5280#section-4.2.1.1
 .. _`RFC 5280 section 4.2.1.6`: https://tools.ietf.org/html/rfc5280#section-4.2.1.6
diff --git a/src/cryptography/hazmat/bindings/openssl/binding.py b/src/cryptography/hazmat/bindings/openssl/binding.py
index b7178bb..86fac5c 100644
--- a/src/cryptography/hazmat/bindings/openssl/binding.py
+++ b/src/cryptography/hazmat/bindings/openssl/binding.py
@@ -72,9 +72,6 @@
 
     @classmethod
     def _ensure_ffi_initialized(cls):
-        if cls._lib_loaded:
-            return
-
         with cls._init_lock:
             if not cls._lib_loaded:
                 cls._lib_loaded = True
diff --git a/src/cryptography/hazmat/primitives/asymmetric/rsa.py b/src/cryptography/hazmat/primitives/asymmetric/rsa.py
index 89eac4d..41b0089 100644
--- a/src/cryptography/hazmat/primitives/asymmetric/rsa.py
+++ b/src/cryptography/hazmat/primitives/asymmetric/rsa.py
@@ -307,6 +307,17 @@
     def __ne__(self, other):
         return not self == other
 
+    def __hash__(self):
+        return hash((
+            self.p,
+            self.q,
+            self.d,
+            self.dmp1,
+            self.dmq1,
+            self.iqmp,
+            self.public_numbers,
+        ))
+
 
 class RSAPublicNumbers(object):
     def __init__(self, e, n):
@@ -336,3 +347,6 @@
 
     def __ne__(self, other):
         return not self == other
+
+    def __hash__(self):
+        return hash((self.e, self.n))
diff --git a/src/cryptography/x509.py b/src/cryptography/x509.py
index 33c6416..8bed79e 100644
--- a/src/cryptography/x509.py
+++ b/src/cryptography/x509.py
@@ -6,8 +6,11 @@
 
 import abc
 import ipaddress
+from email.utils import parseaddr
 from enum import Enum
 
+import idna
+
 import six
 
 from cryptography import utils
@@ -901,7 +904,23 @@
         if not isinstance(value, six.text_type):
             raise TypeError("value must be a unicode string")
 
+        name, address = parseaddr(value)
+        parts = address.split(u"@")
+        if name or not address:
+            # parseaddr has found a name (e.g. Name <email>) or the entire
+            # value is an empty string.
+            raise ValueError("Invalid rfc822name value")
+        elif len(parts) == 1:
+            # Single label email name. This is valid for local delivery.
+            # No IDNA encoding needed since there is no domain component.
+            encoded = address.encode("ascii")
+        else:
+            # A normal email of the form user@domain.com. Let's attempt to
+            # encode the domain component and reconstruct the address.
+            encoded = parts[0].encode("ascii") + b"@" + idna.encode(parts[1])
+
         self._value = value
+        self._encoded = encoded
 
     value = utils.read_only_property("_value")
 
diff --git a/tests/conftest.py b/tests/conftest.py
index 6599a64..bdd17fb 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -12,10 +12,10 @@
 
 
 def pytest_generate_tests(metafunc):
-    names = metafunc.config.getoption("--backend")
-    selected_backends = select_backends(names, _available_backends())
-
     if "backend" in metafunc.fixturenames:
+        names = metafunc.config.getoption("--backend")
+        selected_backends = select_backends(names, _available_backends())
+
         filtered_backends = []
         required = metafunc.function.requires_backend_interface
         required_interfaces = [
diff --git a/tests/hazmat/primitives/test_rsa.py b/tests/hazmat/primitives/test_rsa.py
index bfeab8d..0c5f704 100644
--- a/tests/hazmat/primitives/test_rsa.py
+++ b/tests/hazmat/primitives/test_rsa.py
@@ -1705,6 +1705,22 @@
         )
         assert num != object()
 
+    def test_public_numbers_hash(self):
+        pub1 = RSAPublicNumbers(3, 17)
+        pub2 = RSAPublicNumbers(3, 17)
+        pub3 = RSAPublicNumbers(7, 21)
+
+        assert hash(pub1) == hash(pub2)
+        assert hash(pub1) != hash(pub3)
+
+    def test_private_numbers_hash(self):
+        priv1 = RSAPrivateNumbers(1, 2, 3, 4, 5, 6, RSAPublicNumbers(1, 2))
+        priv2 = RSAPrivateNumbers(1, 2, 3, 4, 5, 6, RSAPublicNumbers(1, 2))
+        priv3 = RSAPrivateNumbers(1, 2, 3, 4, 5, 6, RSAPublicNumbers(1, 3))
+
+        assert hash(priv1) == hash(priv2)
+        assert hash(priv1) != hash(priv3)
+
 
 class TestRSAPrimeFactorRecovery(object):
     @pytest.mark.parametrize(
diff --git a/tests/test_x509_ext.py b/tests/test_x509_ext.py
index af0ffaf..84a4099 100644
--- a/tests/test_x509_ext.py
+++ b/tests/test_x509_ext.py
@@ -1087,6 +1087,24 @@
         assert gn != object()
 
 
+class TestRFC822Name(object):
+    def test_invalid_email(self):
+        with pytest.raises(ValueError):
+            x509.RFC822Name(u"Name <email>")
+
+        with pytest.raises(ValueError):
+            x509.RFC822Name(u"")
+
+    def test_single_label(self):
+        gn = x509.RFC822Name(u"administrator")
+        assert gn.value == u"administrator"
+
+    def test_idna(self):
+        gn = x509.RFC822Name(u"email@em\xe5\xefl.com")
+        assert gn.value == u"email@em\xe5\xefl.com"
+        assert gn._encoded == b"email@xn--eml-vla4c.com"
+
+
 class TestRegisteredID(object):
     def test_not_oid(self):
         with pytest.raises(TypeError):