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