Merge pull request #51 from pyca/sholsapp-master

Introduce `X509Req.get_extensions`
diff --git a/ChangeLog b/ChangeLog
index 95cf45b..873c1c4 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+2014-03-02  Stephen Holsapple  <sholsapp@gmail.com>
+
+	* OpenSSL/crypto.py: Add ``get_extensions`` method to ``X509Req``.
+
 2014-01-09  Jean-Paul Calderone  <exarkun@twistedmatrix.com>
 
 	* OpenSSL: Port to the cffi-based OpenSSL bindings provided by
diff --git a/OpenSSL/crypto.py b/OpenSSL/crypto.py
index d0026bd..ed0b629 100644
--- a/OpenSSL/crypto.py
+++ b/OpenSSL/crypto.py
@@ -697,6 +697,21 @@
             _raise_current_error()
 
 
+    def get_extensions(self):
+        """
+        Get extensions to the request.
+
+        :return: A :py:class:`list` of :py:class:`X509Extension` objects.
+        """
+        exts = []
+        native_exts_obj = _lib.X509_REQ_get_extensions(self._req)
+        for i in range(_lib.sk_X509_EXTENSION_num(native_exts_obj)):
+            ext = X509Extension.__new__(X509Extension)
+            ext._extension = _lib.sk_X509_EXTENSION_value(native_exts_obj, i)
+            exts.append(ext)
+        return exts
+
+
     def sign(self, pkey, digest):
         """
         Sign the certificate request using the supplied key and digest
diff --git a/OpenSSL/test/test_crypto.py b/OpenSSL/test/test_crypto.py
index 4e42f70..a3685a9 100644
--- a/OpenSSL/test/test_crypto.py
+++ b/OpenSSL/test/test_crypto.py
@@ -1108,7 +1108,32 @@
         request = X509Req()
         request.add_extensions([
                 X509Extension(b('basicConstraints'), True, b('CA:false'))])
-        # XXX Add get_extensions so the rest of this unit test can be written.
+        exts = request.get_extensions()
+        self.assertEqual(len(exts), 1)
+        self.assertEqual(exts[0].get_short_name(), b('basicConstraints'))
+        self.assertEqual(exts[0].get_critical(), 1)
+        self.assertEqual(exts[0].get_data(), b('0\x00'))
+
+
+    def test_get_extensions(self):
+        """
+        :py:obj:`X509Req.get_extensions` returns a :py:obj:`list` of
+        extensions added to this X509 request.
+        """
+        request = X509Req()
+        exts = request.get_extensions()
+        self.assertEqual(exts, [])
+        request.add_extensions([
+                X509Extension(b('basicConstraints'), True, b('CA:true')),
+                X509Extension(b('keyUsage'), False, b('digitalSignature'))])
+        exts = request.get_extensions()
+        self.assertEqual(len(exts), 2)
+        self.assertEqual(exts[0].get_short_name(), b('basicConstraints'))
+        self.assertEqual(exts[0].get_critical(), 1)
+        self.assertEqual(exts[0].get_data(), b('0\x03\x01\x01\xff'))
+        self.assertEqual(exts[1].get_short_name(), b('keyUsage'))
+        self.assertEqual(exts[1].get_critical(), 0)
+        self.assertEqual(exts[1].get_data(), b('\x03\x02\x07\x80'))
 
 
     def test_add_extensions_wrong_args(self):
diff --git a/doc/api/crypto.rst b/doc/api/crypto.rst
index 7c77b03..ee93cfb 100644
--- a/doc/api/crypto.rst
+++ b/doc/api/crypto.rst
@@ -485,6 +485,13 @@
     Get the version (RFC 2459, 4.1.2.1) of the certificate request.
 
 
+.. py:method:: X509Req.get_extensions()
+
+    Get extensions to the request.
+
+    .. versionadded:: 0.15
+
+
 .. _openssl-x509store:
 
 X509Store objects