basic support for parsing x509 requests
diff --git a/docs/hazmat/backends/interfaces.rst b/docs/hazmat/backends/interfaces.rst
index 1af8d8f..1f71f5d 100644
--- a/docs/hazmat/backends/interfaces.rst
+++ b/docs/hazmat/backends/interfaces.rst
@@ -509,3 +509,11 @@
         :param bytes data: DER formatted certificate data.
 
         :returns: An instance of :class:`~cryptography.x509.Certificate`.
+
+    .. method:: load_pem_x509_request(data)
+
+        .. versionadded:: 0.9
+
+        :param bytes data: PEM formatted certificate request data.
+
+        :returns: An instance of :class:`~cryptography.x509.Request`.
diff --git a/docs/x509.rst b/docs/x509.rst
index f17c3da..2ff1290 100644
--- a/docs/x509.rst
+++ b/docs/x509.rst
@@ -77,6 +77,58 @@
     >>> cert.serial
     2
 
+Loading Certificate Requests
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. function:: load_pem_x509_request(data, backend)
+
+    .. versionadded:: 0.9
+
+    Deserialize a certificate request from PEM encoded data. PEM requests are
+    base64 decoded and have delimiters that look like
+    ``-----BEGIN CERTIFICATE REQUEST-----``. This is also known as PKCS#10
+    format.
+
+    :param bytes data: The PEM encoded request data.
+
+    :param backend: A backend supporting the
+        :class:`~cryptography.hazmat.backends.interfaces.X509Backend`
+        interface.
+
+    :returns: An instance of :class:`~cryptography.x509.Request`.
+
+.. testsetup::
+
+    pem_req_data = b"""
+    -----BEGIN CERTIFICATE REQUEST-----
+    MIIC0zCCAbsCAQAwWTELMAkGA1UEBhMCVVMxETAPBgNVBAgMCElsbGlub2lzMRAw
+    DgYDVQQHDAdDaGljYWdvMREwDwYDVQQKDAhyNTA5IExMQzESMBAGA1UEAwwJaGVs
+    bG8uY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqhZx+Mo9VRd9
+    vsnWWa6NBCws21rZ0+1B/JGgB4hDsZS7iDE4Bj5z4idheFRtl8bBbdjPknq7BfoF
+    8v15Zq/Zv7i2xMSDL+LUrTBZezRd4bRTGqCm6YJ5EYkhqdcqeZleHCFImguHoq1J
+    Fh0+kObQrTHXw3ZP57a3o1IvyIUA3nNoCBL0QQhwBXaDXOojMKNR+bqB5ve8GS1y
+    Elr0AM/+cJsfaIahNQUgFKx3Eu3GeEOMKYOAG1lycgdQdmTUybLrT3U7vkClTseM
+    xHg1r5En7ALjONIhqRuq3rddYahrP8HXozb3zUy3cJ7P6IeaosuvNzvMXOX9P6HD
+    Ha9urDAJ1wIDAQABoDUwMwYJKoZIhvcNAQkOMSYwJDAiBgNVHREEGzAZggl3b3Js
+    ZC5jb22CDHdoYXRldmVyLmNvbTANBgkqhkiG9w0BAQUFAAOCAQEAS4Ro6h+z52SK
+    YSLCYARpnEu/rmh4jdqndt8naqcNb6uLx9mlKZ2W9on9XDjnSdQD9q+ZP5aZfESw
+    R0+rJhW9ZrNa/g1pt6M24ihclHYDAxYMWxT1z/TXXGM3TmZZ6gfYlNE1kkBuODHa
+    UYsR/1Ht1E1EsmmUimt2n+zQR2K8T9Coa+boaUW/GsTEuz1aaJAkj5ZvTDiIhRG4
+    AOCqFZOLAQmCCNgJnnspD9hDz/Ons085LF5wnYjN4/Nsk5tS6AGs3xjZ3jPoOGGn
+    82WQ9m4dBGoVDZXsobVTaN592JEYwN5iu72zRn7Einb4V4H5y3yD2dD4yWPlt4pk
+    5wFkeYsZEA==
+    -----END CERTIFICATE REQUEST-----
+    """.strip()
+
+.. doctest::
+
+    >>> from cryptography import x509
+    >>> from cryptography.hazmat.backends import default_backend
+    >>> from cryptography.hazmat.primitives import hashes
+    >>> request = x509.load_pem_x509_request(pem_req_data, default_backend())
+    >>> isinstance(request.signature_hash_algorithm, hashes.SHA1)
+    True
+
 X.509 Certificate Object
 ~~~~~~~~~~~~~~~~~~~~~~~~
 
@@ -211,6 +263,49 @@
             ...     print(ext)
             <Extension(oid=<ObjectIdentifier(oid=2.5.29.19, name=basicConstraints)>, critical=True, value=<BasicConstraints(ca=True, path_length=None)>)>
 
+X.509 Certificate Request Object
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. class:: Request
+
+    .. versionadded:: 0.9
+
+    .. method:: public_key()
+
+        :type:
+            :class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPublicKey` or
+            :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPublicKey` or
+            :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePublicKey`
+
+        The public key associated with the request.
+
+        .. doctest::
+
+            >>> from cryptography.hazmat.primitives.asymmetric import rsa
+            >>> public_key = request.public_key()
+            >>> isinstance(public_key, rsa.RSAPublicKey)
+            True
+
+    .. attribute:: subject
+
+        :type: :class:`Name`
+
+        The :class:`Name` of the subject.
+
+    .. attribute:: signature_hash_algorithm
+
+        :type: :class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm`
+
+        Returns the
+        :class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm` which
+        was used in signing this request.
+
+        .. doctest::
+
+            >>> from cryptography.hazmat.primitives import hashes
+            >>> isinstance(request.signature_hash_algorithm, hashes.SHA1)
+            True
+
 .. class:: Name
 
     .. versionadded:: 0.8
diff --git a/src/cryptography/hazmat/backends/interfaces.py b/src/cryptography/hazmat/backends/interfaces.py
index 7980890..44a3d81 100644
--- a/src/cryptography/hazmat/backends/interfaces.py
+++ b/src/cryptography/hazmat/backends/interfaces.py
@@ -261,3 +261,9 @@
         """
         Load an X.509 certificate from DER encoded data.
         """
+
+    @abc.abstractmethod
+    def load_pem_x509_request(self, data):
+        """
+        Load an X.509 request from PEM encoded data.
+        """
diff --git a/src/cryptography/hazmat/backends/multibackend.py b/src/cryptography/hazmat/backends/multibackend.py
index 6e378c1..b09484c 100644
--- a/src/cryptography/hazmat/backends/multibackend.py
+++ b/src/cryptography/hazmat/backends/multibackend.py
@@ -324,3 +324,14 @@
             "This backend does not support X.509.",
             _Reasons.UNSUPPORTED_X509
         )
+
+    def load_pem_x509_request(self, data):
+        for b in self._filtered_backends(
+            X509Backend
+        ):
+            return b.load_pem_x509_request(data)
+
+        raise UnsupportedAlgorithm(
+            "This backend does not support X.509.",
+            _Reasons.UNSUPPORTED_X509
+        )
diff --git a/src/cryptography/hazmat/backends/openssl/backend.py b/src/cryptography/hazmat/backends/openssl/backend.py
index 60aa453..5dfc31c 100644
--- a/src/cryptography/hazmat/backends/openssl/backend.py
+++ b/src/cryptography/hazmat/backends/openssl/backend.py
@@ -34,7 +34,7 @@
 from cryptography.hazmat.backends.openssl.rsa import (
     _RSAPrivateKey, _RSAPublicKey
 )
-from cryptography.hazmat.backends.openssl.x509 import _Certificate
+from cryptography.hazmat.backends.openssl.x509 import _Certificate, _Request
 from cryptography.hazmat.bindings.openssl.binding import Binding
 from cryptography.hazmat.primitives import hashes, serialization
 from cryptography.hazmat.primitives.asymmetric import dsa, ec, rsa
@@ -820,6 +820,18 @@
         x509 = self._ffi.gc(x509, self._lib.X509_free)
         return _Certificate(self, x509)
 
+    def load_pem_x509_request(self, data):
+        mem_bio = self._bytes_to_bio(data)
+        x509_req = self._lib.PEM_read_bio_X509_REQ(
+            mem_bio.bio, self._ffi.NULL, self._ffi.NULL, self._ffi.NULL
+        )
+        if x509_req == self._ffi.NULL:
+            self._consume_errors()
+            raise ValueError("Unable to load request")
+
+        x509_req = self._ffi.gc(x509_req, self._lib.X509_REQ_free)
+        return _Request(self, x509_req)
+
     def _load_key(self, openssl_read_func, convert_func, data, password):
         mem_bio = self._bytes_to_bio(data)
 
diff --git a/src/cryptography/hazmat/backends/openssl/x509.py b/src/cryptography/hazmat/backends/openssl/x509.py
index 1c9cf5c..fb76779 100644
--- a/src/cryptography/hazmat/backends/openssl/x509.py
+++ b/src/cryptography/hazmat/backends/openssl/x509.py
@@ -216,3 +216,32 @@
             path_length = self._backend._bn_to_int(bn)
 
         return x509.BasicConstraints(ca, path_length)
+
+
+@utils.register_interface(x509.Request)
+class _Request(object):
+    def __init__(self, backend, x509_req):
+        self._backend = backend
+        self._x509_req = x509_req
+
+    def public_key(self):
+        pkey = self._backend._lib.X509_REQ_get_pubkey(self._x509_req)
+        assert pkey != self._backend._ffi.NULL
+        pkey = self._backend._ffi.gc(pkey, self._backend._lib.EVP_PKEY_free)
+        return self._backend._evp_pkey_to_public_key(pkey)
+
+    @property
+    def subject(self):
+        subject = self._backend._lib.X509_REQ_get_subject_name(self._x509_req)
+        assert subject != self._backend._ffi.NULL
+        return _build_x509_name(self._backend, subject)
+
+    @property
+    def signature_hash_algorithm(self):
+        oid = _obj2txt(self._backend, self._x509_req.sig_alg.algorithm)
+        try:
+            return x509._SIG_OIDS_TO_HASH[oid]
+        except KeyError:
+            raise UnsupportedAlgorithm(
+                "Signature algorithm OID:{0} not recognized".format(oid)
+            )
diff --git a/src/cryptography/hazmat/bindings/openssl/x509.py b/src/cryptography/hazmat/bindings/openssl/x509.py
index 949a936..e867450 100644
--- a/src/cryptography/hazmat/bindings/openssl/x509.py
+++ b/src/cryptography/hazmat/bindings/openssl/x509.py
@@ -44,7 +44,10 @@
 
 typedef ... X509_EXTENSIONS;
 
-typedef ... X509_REQ;
+typedef struct {
+    X509_ALGOR *sig_alg;
+    ...;
+} X509_REQ;
 
 typedef struct {
     ASN1_INTEGER *serialNumber;
diff --git a/src/cryptography/x509.py b/src/cryptography/x509.py
index 864736e..7b61e81 100644
--- a/src/cryptography/x509.py
+++ b/src/cryptography/x509.py
@@ -60,6 +60,10 @@
     return backend.load_der_x509_certificate(data)
 
 
+def load_pem_x509_request(data, backend):
+    return backend.load_pem_x509_request(data)
+
+
 class InvalidVersion(Exception):
     def __init__(self, msg, parsed_version):
         super(InvalidVersion, self).__init__(msg)
@@ -336,3 +340,25 @@
         Returns a HashAlgorithm corresponding to the type of the digest signed
         in the certificate.
         """
+
+
+@six.add_metaclass(abc.ABCMeta)
+class Request(object):
+    @abc.abstractmethod
+    def public_key(self):
+        """
+        Returns the public key
+        """
+
+    @abc.abstractproperty
+    def subject(self):
+        """
+        Returns the subject name object.
+        """
+
+    @abc.abstractproperty
+    def signature_hash_algorithm(self):
+        """
+        Returns a HashAlgorithm corresponding to the type of the digest signed
+        in the certificate.
+        """
diff --git a/tests/hazmat/backends/test_multibackend.py b/tests/hazmat/backends/test_multibackend.py
index 5a8891c..8f833ad 100644
--- a/tests/hazmat/backends/test_multibackend.py
+++ b/tests/hazmat/backends/test_multibackend.py
@@ -197,6 +197,9 @@
     def load_der_x509_certificate(self, data):
         pass
 
+    def load_pem_x509_request(self, data):
+        pass
+
 
 class TestMultiBackend(object):
     def test_ciphers(self):
@@ -472,9 +475,12 @@
 
         backend.load_pem_x509_certificate(b"certdata")
         backend.load_der_x509_certificate(b"certdata")
+        backend.load_pem_x509_request(b"reqdata")
 
         backend = MultiBackend([])
         with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_X509):
             backend.load_pem_x509_certificate(b"certdata")
         with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_X509):
             backend.load_der_x509_certificate(b"certdata")
+        with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_X509):
+            backend.load_pem_x509_request(b"reqdata")
diff --git a/tests/test_x509.py b/tests/test_x509.py
index 2a47268..8f18888 100644
--- a/tests/test_x509.py
+++ b/tests/test_x509.py
@@ -340,6 +340,34 @@
         with pytest.raises(UnsupportedAlgorithm):
             cert.signature_hash_algorithm
 
+    def test_load_rsa_certificate_request(self, backend):
+        request = _load_cert(
+            os.path.join("x509", "requests", "rsa_sha1.pem"),
+            x509.load_pem_x509_request,
+            backend
+        )
+        assert isinstance(request.signature_hash_algorithm, hashes.SHA1)
+        public_key = request.public_key()
+        assert isinstance(public_key, rsa.RSAPublicKey)
+        subject = request.subject
+        assert isinstance(subject, x509.Name)
+        assert list(subject) == [
+            x509.NameAttribute(x509.OID_COUNTRY_NAME, 'US'),
+            x509.NameAttribute(x509.OID_STATE_OR_PROVINCE_NAME, 'Texas'),
+            x509.NameAttribute(x509.OID_LOCALITY_NAME, 'Austin'),
+            x509.NameAttribute(x509.OID_ORGANIZATION_NAME, 'PyCA'),
+            x509.NameAttribute(x509.OID_COMMON_NAME, 'cryptography.io'),
+        ]
+
+    def test_unsupported_signature_hash_algorithm_request(self, backend):
+        request = _load_cert(
+            os.path.join("x509", "requests", "rsa_md4.pem"),
+            x509.load_pem_x509_request,
+            backend
+        )
+        with pytest.raises(UnsupportedAlgorithm):
+            request.signature_hash_algorithm
+
 
 @pytest.mark.requires_backend_interface(interface=DSABackend)
 @pytest.mark.requires_backend_interface(interface=X509Backend)
@@ -392,6 +420,25 @@
                 "822ff5d234e073b901cf5941f58e1f538e71d40d", 16
             )
 
+    def test_load_dsa_request(self, backend):
+        request = _load_cert(
+            os.path.join("x509", "requests", "dsa_sha1.pem"),
+            x509.load_pem_x509_request,
+            backend
+        )
+        assert isinstance(request.signature_hash_algorithm, hashes.SHA1)
+        public_key = request.public_key()
+        assert isinstance(public_key, dsa.DSAPublicKey)
+        subject = request.subject
+        assert isinstance(subject, x509.Name)
+        assert list(subject) == [
+            x509.NameAttribute(x509.OID_COMMON_NAME, 'cryptography.io'),
+            x509.NameAttribute(x509.OID_ORGANIZATION_NAME, 'PyCA'),
+            x509.NameAttribute(x509.OID_COUNTRY_NAME, 'US'),
+            x509.NameAttribute(x509.OID_STATE_OR_PROVINCE_NAME, 'Texas'),
+            x509.NameAttribute(x509.OID_LOCALITY_NAME, 'Austin'),
+        ]
+
 
 @pytest.mark.requires_backend_interface(interface=EllipticCurveBackend)
 @pytest.mark.requires_backend_interface(interface=X509Backend)
@@ -428,6 +475,26 @@
         with pytest.raises(NotImplementedError):
             cert.public_key()
 
+    def test_load_ecdsa_certificate_request(self, backend):
+        _skip_curve_unsupported(backend, ec.SECP384R1())
+        request = _load_cert(
+            os.path.join("x509", "requests", "ec_sha256.pem"),
+            x509.load_pem_x509_request,
+            backend
+        )
+        assert isinstance(request.signature_hash_algorithm, hashes.SHA256)
+        public_key = request.public_key()
+        assert isinstance(public_key, ec.EllipticCurvePublicKey)
+        subject = request.subject
+        assert isinstance(subject, x509.Name)
+        assert list(subject) == [
+            x509.NameAttribute(x509.OID_COMMON_NAME, 'cryptography.io'),
+            x509.NameAttribute(x509.OID_ORGANIZATION_NAME, 'PyCA'),
+            x509.NameAttribute(x509.OID_COUNTRY_NAME, 'US'),
+            x509.NameAttribute(x509.OID_STATE_OR_PROVINCE_NAME, 'Texas'),
+            x509.NameAttribute(x509.OID_LOCALITY_NAME, 'Austin'),
+        ]
+
 
 class TestNameAttribute(object):
     def test_init_bad_oid(self):