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