788fbf
From fb637b7c58e42d7c99558276ffaabec1878bf97d Mon Sep 17 00:00:00 2001
788fbf
From: Christian Heimes <cheimes@redhat.com>
788fbf
Date: Mon, 29 May 2017 16:33:20 -0500
788fbf
Subject: [PATCH 4/4] Enlarge _oid2txt buffer to handle larger OIDs (#3612)
788fbf
788fbf
The OpenSSL manual recommends a buffer size of 80 for OBJ_oid2txt:
788fbf
https://www.openssl.org/docs/crypto/OBJ_nid2ln.html#return_values.
788fbf
But OIDs longer than this occur in real life (e.g. Active Directory
788fbf
makes some very long OIDs).  If the length of the stringified OID
788fbf
exceeds the buffer size, allocate a new buffer that is big enough to
788fbf
hold the stringified OID, and re-do the conversion into the new
788fbf
buffer.
788fbf
788fbf
NOTE: bigoid.pem has been moved to tests/.
788fbf
788fbf
Fixes RHBZ #1455755
788fbf
---
788fbf
 docs/development/test-vectors.rst                  |  3 ++
788fbf
 .../hazmat/backends/openssl/decode_asn1.py         | 14 ++++++++++
788fbf
 tests/bigoid.pem                                   | 32 ++++++++++++++++++++++
788fbf
 tests/test_x509_ext.py                             | 19 +++++++++++++
788fbf
 4 files changed, 68 insertions(+)
788fbf
 create mode 100644 tests/bigoid.pem
788fbf
788fbf
diff --git a/docs/development/test-vectors.rst b/docs/development/test-vectors.rst
788fbf
index fb72240d..bc72a470 100644
788fbf
--- a/docs/development/test-vectors.rst
788fbf
+++ b/docs/development/test-vectors.rst
788fbf
@@ -127,6 +127,9 @@ X.509
788fbf
 * ``alternate-rsa-sha1-oid.pem`` - A certificate from an
788fbf
   `unknown signature OID`_ Mozilla bug that uses an alternate signature OID for
788fbf
   RSA with SHA1.
788fbf
+* ``bigoid.pem`` - A certificate with a rather long OID in the
788fbf
+  Certificate Policies extension.  We need to make sure we can parse
788fbf
+  long OIDs.
788fbf
 
788fbf
 Custom X.509 Vectors
788fbf
 ~~~~~~~~~~~~~~~~~~~~
788fbf
diff --git a/src/cryptography/hazmat/backends/openssl/decode_asn1.py b/src/cryptography/hazmat/backends/openssl/decode_asn1.py
788fbf
index 2cbc349e..5a23da25 100644
788fbf
--- a/src/cryptography/hazmat/backends/openssl/decode_asn1.py
788fbf
+++ b/src/cryptography/hazmat/backends/openssl/decode_asn1.py
788fbf
@@ -24,9 +24,23 @@ from cryptography.x509.oid import (
788fbf
 def _obj2txt(backend, obj):
788fbf
     # Set to 80 on the recommendation of
788fbf
     # https://www.openssl.org/docs/crypto/OBJ_nid2ln.html#return_values
788fbf
+    #
788fbf
+    # But OIDs longer than this occur in real life (e.g. Active
788fbf
+    # Directory makes some very long OIDs).  So we need to detect
788fbf
+    # and properly handle the case where the default buffer is not
788fbf
+    # big enough.
788fbf
+    #
788fbf
     buf_len = 80
788fbf
     buf = backend._ffi.new("char[]", buf_len)
788fbf
+
788fbf
+    # 'res' is the number of bytes that *would* be written if the
788fbf
+    # buffer is large enough.  If 'res' > buf_len - 1, we need to
788fbf
+    # alloc a big-enough buffer and go again.
788fbf
     res = backend._lib.OBJ_obj2txt(buf, buf_len, obj, 1)
788fbf
+    if res > buf_len - 1:  # account for terminating null byte
788fbf
+        buf_len = res + 1
788fbf
+        buf = backend._ffi.new("char[]", buf_len)
788fbf
+        res = backend._lib.OBJ_obj2txt(buf, buf_len, obj, 1)
788fbf
     backend.openssl_assert(res > 0)
788fbf
     return backend._ffi.buffer(buf, res)[:].decode()
788fbf
 
788fbf
diff --git a/tests/bigoid.pem b/tests/bigoid.pem
788fbf
new file mode 100644
788fbf
index 00000000..7bf865bf
788fbf
--- /dev/null
788fbf
+++ b/tests/bigoid.pem
788fbf
@@ -0,0 +1,32 @@
788fbf
+-----BEGIN CERTIFICATE-----
788fbf
+MIIFiTCCBHGgAwIBAgITSAAAAAd1bEC5lsOdnQAAAAAABzANBgkqhkiG9w0BAQsF
788fbf
+ADBLMRUwEwYKCZImiZPyLGQBGRYFbG9jYWwxEjAQBgoJkiaJk/IsZAEZFgJhZDEe
788fbf
+MBwGA1UEAxMVYWQtV0lOLVBQSzAxNUY5TURRLUNBMB4XDTE3MDUyNTIzNDg0NVoX
788fbf
+DTE5MDUyNTIzNTg0NVowNDESMBAGA1UEChMJSVBBLkxPQ0FMMR4wHAYDVQQDExVD
788fbf
+ZXJ0aWZpY2F0ZSBBdXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
788fbf
+AoIBAQDyyuty6irlL89hdaSW0UyAGLsOOMgAuJwBAeuRUorR159rsSnUXLcTHIsm
788fbf
+EszKhwxp3NkkawRWx/s0UN1m2+RUwMl6gvlw+G80Mz0S77C77M+2lO8HRmZGm+Wu
788fbf
+zBNcc9SANHuDQ1NISfZgLiscMS0+l0T3g6/Iqtg1kPWrq/tMevfh6tJEIedSBGo4
788fbf
+3xKEMSDkrvaeTuSVrgn/QT0m+WNccZa0c7X35L/hgR22/l5sr057Ef8F9vL8zUH5
788fbf
+TttFBIuiWJo8A8XX9I1zYIFhWjW3OVDZPBUnhGHH6yNyXGxXMRfcrrc74eTw8ivC
788fbf
+080AQuRtgwvDErB/JPDJ5w5t/ielAgMBAAGjggJ7MIICdzA9BgkrBgEEAYI3FQcE
788fbf
+MDAuBiYrBgEEAYI3FQiEoqJGhYq1PoGllQqGi+F4nacAgRODs5gfgozzAAIBZAIB
788fbf
+BTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUnSrC
788fbf
+yW3CR0e3ilJdN6kL06P3KHMwHwYDVR0jBBgwFoAUj69xtyUNwp8on+NWO+HlxKyg
788fbf
+X7AwgdgGA1UdHwSB0DCBzTCByqCBx6CBxIaBwWxkYXA6Ly8vQ049YWQtV0lOLVBQ
788fbf
+SzAxNUY5TURRLUNBLENOPVdJTi1QUEswMTVGOU1EUSxDTj1DRFAsQ049UHVibGlj
788fbf
+JTIwS2V5JTIwU2VydmljZXMsQ049U2VydmljZXMsQ049Q29uZmlndXJhdGlvbixE
788fbf
+Qz1hZCxEQz1sb2NhbD9jZXJ0aWZpY2F0ZVJldm9jYXRpb25MaXN0P2Jhc2U/b2Jq
788fbf
+ZWN0Q2xhc3M9Y1JMRGlzdHJpYnV0aW9uUG9pbnQwgcQGCCsGAQUFBwEBBIG3MIG0
788fbf
+MIGxBggrBgEFBQcwAoaBpGxkYXA6Ly8vQ049YWQtV0lOLVBQSzAxNUY5TURRLUNB
788fbf
+LENOPUFJQSxDTj1QdWJsaWMlMjBLZXklMjBTZXJ2aWNlcyxDTj1TZXJ2aWNlcyxD
788fbf
+Tj1Db25maWd1cmF0aW9uLERDPWFkLERDPWxvY2FsP2NBQ2VydGlmaWNhdGU/YmFz
788fbf
+ZT9vYmplY3RDbGFzcz1jZXJ0aWZpY2F0aW9uQXV0aG9yaXR5MDMGA1UdIAQsMCow
788fbf
+KAYmKwYBBAGCNxUIhKKiRoWKtT6BpZUKhovheJ2nAIEThrXzUYabpA4wDQYJKoZI
788fbf
+hvcNAQELBQADggEBAIsFS+Qc/ufTrkuHbMmzksOpxq+OIi9rot8zy9/1Vmj6d+iP
788fbf
+kB+vQ1u4/IhdQArJFNhsBzWSY9Pi8ZclovpepFeEZfXPUenyeRCU43HdMXcHXnlP
788fbf
+YZfyLQWOugdo1WxK6S9qQSOSlC7BSGZWvKkiAPAwr4zNbbS+ROA2w0xaYMv0rr5W
788fbf
+A4UAyzZAdqaGRJBRvCZ/uFHM5wMw0LzNCL4CqKW9jfZX0Fc2tdGx8zbTYxIdgr2D
788fbf
+PL25as32r3S/m4uWqoQaK0lxK5Y97eusK2rrmidy32Jctzwl29UWq8kpjRAuD8iR
788fbf
+CSc7sKqOf+fn3+fKITR2/DcSVvb0SGCr5fVVnjQ=
788fbf
+-----END CERTIFICATE-----
788fbf
diff --git a/tests/test_x509_ext.py b/tests/test_x509_ext.py
788fbf
index 00cf0a6f..91df35db 100644
788fbf
--- a/tests/test_x509_ext.py
788fbf
+++ b/tests/test_x509_ext.py
788fbf
@@ -409,6 +409,7 @@ class TestPolicyInformation(object):
788fbf
         assert pi != object()
788fbf
 
788fbf
 
788fbf
+@pytest.mark.requires_backend_interface(interface=X509Backend)
788fbf
 class TestCertificatePolicies(object):
788fbf
     def test_invalid_policies(self):
788fbf
         pq = [u"string"]
788fbf
@@ -481,6 +482,24 @@ class TestCertificatePolicies(object):
788fbf
         assert cp[-1] == cp[4]
788fbf
         assert cp[2:6:2] == [cp[2], cp[4]]
788fbf
 
788fbf
+    def test_long_oid(self, backend):
788fbf
+        """
788fbf
+        Test that parsing a CertificatePolicies ext with
788fbf
+        a very long OID succeeds.
788fbf
+        """
788fbf
+        here = os.path.dirname(os.path.abspath(__file__))
788fbf
+        with open(os.path.join(here, "bigoid.pem"), 'rb') as f:
788fbf
+            cert = x509.load_pem_x509_certificate(f.read(), backend)
788fbf
+        ext = cert.extensions.get_extension_for_class(
788fbf
+            x509.CertificatePolicies)
788fbf
+
788fbf
+        oid = x509.ObjectIdentifier(
788fbf
+            "1.3.6.1.4.1.311.21.8.8950086.10656446.2706058"
788fbf
+            ".12775672.480128.147.13466065.13029902"
788fbf
+        )
788fbf
+
788fbf
+        assert ext.value[0].policy_identifier == oid
788fbf
+
788fbf
 
788fbf
 @pytest.mark.requires_backend_interface(interface=RSABackend)
788fbf
 @pytest.mark.requires_backend_interface(interface=X509Backend)
788fbf
-- 
788fbf
2.13.5
788fbf