Exemple #1
0
    def parse(self, backend, x509_obj):
        extensions = []
        seen_oids = set()
        for i in range(self.ext_count(backend, x509_obj)):
            ext = self.get_ext(backend, x509_obj, i)
            backend.openssl_assert(ext != backend._ffi.NULL)
            crit = backend._lib.X509_EXTENSION_get_critical(ext)
            critical = crit == 1
            oid = x509.ObjectIdentifier(_obj2txt(backend, ext.object))
            if oid in seen_oids:
                raise x509.DuplicateExtension(
                    "Duplicate {0} extension found".format(oid), oid
                )
            try:
                handler = self.handlers[oid]
            except KeyError:
                if critical:
                    raise x509.UnsupportedExtension(
                        "{0} is not currently supported".format(oid), oid
                    )
            else:
                d2i = backend._lib.X509V3_EXT_d2i(ext)
                if d2i == backend._ffi.NULL:
                    backend._consume_errors()
                    raise ValueError(
                        "The {0} extension is invalid and can't be "
                        "parsed".format(oid)
                    )

                value = handler(backend, d2i)
                extensions.append(x509.Extension(oid, critical, value))

            seen_oids.add(oid)

        return x509.Extensions(extensions)
Exemple #2
0
    def parse(self, backend, x509_obj):
        extensions = []
        seen_oids = set()
        for i in range(self.ext_count(backend, x509_obj)):
            ext = self.get_ext(backend, x509_obj, i)
            assert ext != backend._ffi.NULL
            crit = backend._lib.X509_EXTENSION_get_critical(ext)
            critical = crit == 1
            oid = x509.ObjectIdentifier(_obj2txt(backend, ext.object))
            if oid in seen_oids:
                raise x509.DuplicateExtension(
                    "Duplicate {0} extension found".format(oid), oid
                )
            try:
                handler = self.handlers[oid]
            except KeyError:
                if critical:
                    raise x509.UnsupportedExtension(
                        "{0} is not currently supported".format(oid), oid
                    )
            else:
                value = handler(backend, ext)
                extensions.append(x509.Extension(oid, critical, value))

            seen_oids.add(oid)

        return x509.Extensions(extensions)
Exemple #3
0
    def extensions(self):
        extensions = []
        seen_oids = set()
        extcount = self._backend._lib.X509_get_ext_count(self._x509)
        for i in range(0, extcount):
            ext = self._backend._lib.X509_get_ext(self._x509, i)
            assert ext != self._backend._ffi.NULL
            crit = self._backend._lib.X509_EXTENSION_get_critical(ext)
            critical = crit == 1
            oid = x509.ObjectIdentifier(_obj2txt(self._backend, ext.object))
            if oid in seen_oids:
                raise x509.DuplicateExtension(
                    "Duplicate {0} extension found".format(oid), oid)
            elif oid == x509.OID_BASIC_CONSTRAINTS:
                value = self._build_basic_constraints(ext)
            elif oid == x509.OID_SUBJECT_KEY_IDENTIFIER:
                value = self._build_subject_key_identifier(ext)
            elif oid == x509.OID_KEY_USAGE:
                value = self._build_key_usage(ext)
            elif critical:
                raise x509.UnsupportedExtension(
                    "{0} is not currently supported".format(oid), oid)
            else:
                # Unsupported non-critical extension, silently skipping for now
                seen_oids.add(oid)
                continue

            seen_oids.add(oid)
            extensions.append(x509.Extension(oid, critical, value))

        return x509.Extensions(extensions)
Exemple #4
0
    def extensions(self):
        extensions = []
        seen_oids = set()
        extcount = self._backend._lib.X509_get_ext_count(self._x509)
        for i in range(0, extcount):
            ext = self._backend._lib.X509_get_ext(self._x509, i)
            assert ext != self._backend._ffi.NULL
            crit = self._backend._lib.X509_EXTENSION_get_critical(ext)
            critical = crit == 1
            oid = x509.ObjectIdentifier(_obj2txt(self._backend, ext.object))
            if oid in seen_oids:
                raise x509.DuplicateExtension(
                    "Duplicate {0} extension found".format(oid), oid)
            elif oid == x509.OID_BASIC_CONSTRAINTS:
                value = self._build_basic_constraints(ext)
            elif oid == x509.OID_KEY_USAGE and critical:
                # TODO: remove this obviously.
                warnings.warn(
                    "Extension support is not fully implemented. A key usage "
                    "extension with the critical flag was seen and IGNORED.")
                seen_oids.add(oid)
                continue
            elif critical:
                raise x509.UnsupportedExtension(
                    "{0} is not currently supported".format(oid), oid)
            else:
                # Unsupported non-critical extension, silently skipping for now
                seen_oids.add(oid)
                continue

            seen_oids.add(oid)
            extensions.append(x509.Extension(oid, critical, value))

        return x509.Extensions(extensions)
    def parse(self, x509_obj):
        extensions: typing.List[x509.Extension[x509.ExtensionType]] = []
        seen_oids = set()
        for i in range(self.ext_count(x509_obj)):
            ext = self.get_ext(x509_obj, i)
            self._backend.openssl_assert(ext != self._backend._ffi.NULL)
            crit = self._backend._lib.X509_EXTENSION_get_critical(ext)
            critical = crit == 1
            oid = x509.ObjectIdentifier(
                _obj2txt(
                    self._backend,
                    self._backend._lib.X509_EXTENSION_get_object(ext),
                ))
            if oid in seen_oids:
                raise x509.DuplicateExtension(
                    "Duplicate {} extension found".format(oid), oid)

            # Try to parse this with the rust callback first
            oid_ptr = self._backend._lib.X509_EXTENSION_get_object(ext)
            oid_der_bytes = self._backend._ffi.buffer(
                self._backend._lib.Cryptography_OBJ_get0_data(oid_ptr),
                self._backend._lib.Cryptography_OBJ_length(oid_ptr),
            )[:]
            data = self._backend._lib.X509_EXTENSION_get_data(ext)
            data_bytes = _asn1_string_to_bytes(self._backend, data)
            ext_obj = self.rust_callback(oid_der_bytes, data_bytes)
            if ext_obj is None:
                ext_obj = x509.UnrecognizedExtension(oid, data_bytes)

            extensions.append(x509.Extension(oid, critical, ext_obj))
            seen_oids.add(oid)

        return x509.Extensions(extensions)
Exemple #6
0
def _create_extensions(extensions):
    if extensions is None:
        return x509.Extensions([])

    if not isinstance(extensions, dict):
        raise ValueError(
            f"Extensions must be a dictionary, but is: {extensions!r}")

    result = []

    for name, value in extensions.items():
        if not name in _EXTENSIONS:
            raise KeyError(f"Unsupported extension: {name}")

        result.append(_EXTENSIONS[name].build(value))

    return x509.Extensions(result)
Exemple #7
0
    def parse(self, backend, x509_obj):
        extensions = []
        seen_oids = set()
        for i in range(self.ext_count(backend, x509_obj)):
            ext = self.get_ext(backend, x509_obj, i)
            backend.openssl_assert(ext != backend._ffi.NULL)
            crit = backend._lib.X509_EXTENSION_get_critical(ext)
            critical = crit == 1
            oid = x509.ObjectIdentifier(
                _obj2txt(backend, backend._lib.X509_EXTENSION_get_object(ext)))
            if oid in seen_oids:
                raise x509.DuplicateExtension(
                    "Duplicate {} extension found".format(oid), oid)

            # These OIDs are only supported in OpenSSL 1.1.0+ but we want
            # to support them in all versions of OpenSSL so we decode them
            # ourselves.
            if oid == ExtensionOID.TLS_FEATURE:
                data = backend._lib.X509_EXTENSION_get_data(ext)
                parsed = _Integers.load(_asn1_string_to_bytes(backend, data))
                value = x509.TLSFeature(
                    [_TLS_FEATURE_TYPE_TO_ENUM[x.native] for x in parsed])
                extensions.append(x509.Extension(oid, critical, value))
                seen_oids.add(oid)
                continue
            elif oid == ExtensionOID.PRECERT_POISON:
                data = backend._lib.X509_EXTENSION_get_data(ext)
                parsed = asn1crypto.core.Null.load(
                    _asn1_string_to_bytes(backend, data))
                assert parsed == asn1crypto.core.Null()
                extensions.append(
                    x509.Extension(oid, critical, x509.PrecertPoison()))
                seen_oids.add(oid)
                continue

            try:
                handler = self.handlers[oid]
            except KeyError:
                # Dump the DER payload into an UnrecognizedExtension object
                data = backend._lib.X509_EXTENSION_get_data(ext)
                backend.openssl_assert(data != backend._ffi.NULL)
                der = backend._ffi.buffer(data.data, data.length)[:]
                unrecognized = x509.UnrecognizedExtension(oid, der)
                extensions.append(x509.Extension(oid, critical, unrecognized))
            else:
                ext_data = backend._lib.X509V3_EXT_d2i(ext)
                if ext_data == backend._ffi.NULL:
                    backend._consume_errors()
                    raise ValueError(
                        "The {} extension is invalid and can't be "
                        "parsed".format(oid))

                value = handler(backend, ext_data)
                extensions.append(x509.Extension(oid, critical, value))

            seen_oids.add(oid)

        return x509.Extensions(extensions)
Exemple #8
0
    def parse(self, backend, x509_obj):
        extensions = []
        seen_oids = set()
        for i in range(self.ext_count(backend, x509_obj)):
            ext = self.get_ext(backend, x509_obj, i)
            backend.openssl_assert(ext != backend._ffi.NULL)
            crit = backend._lib.X509_EXTENSION_get_critical(ext)
            critical = crit == 1
            oid = x509.ObjectIdentifier(
                _obj2txt(backend, backend._lib.X509_EXTENSION_get_object(ext))
            )
            if oid in seen_oids:
                raise x509.DuplicateExtension(
                    "Duplicate {0} extension found".format(oid), oid
                )
            try:
                handler = self.handlers[oid]
            except KeyError:
                if critical:
                    raise x509.UnsupportedExtension(
                        "Critical extension {0} is not currently supported"
                        .format(oid), oid
                    )
                else:
                    # Dump the DER payload into an UnrecognizedExtension object
                    data = backend._lib.X509_EXTENSION_get_data(ext)
                    backend.openssl_assert(data != backend._ffi.NULL)
                    der = backend._ffi.buffer(data.data, data.length)[:]
                    unrecognized = x509.UnrecognizedExtension(oid, der)
                    extensions.append(
                        x509.Extension(oid, critical, unrecognized)
                    )
            else:
                # For extensions which are not supported by OpenSSL we pass the
                # extension object directly to the parsing routine so it can
                # be decoded manually.
                if self.unsupported_exts and oid in self.unsupported_exts:
                    ext_data = ext
                else:
                    ext_data = backend._lib.X509V3_EXT_d2i(ext)
                    if ext_data == backend._ffi.NULL:
                        backend._consume_errors()
                        raise ValueError(
                            "The {0} extension is invalid and can't be "
                            "parsed".format(oid)
                        )

                value = handler(backend, ext_data)
                extensions.append(x509.Extension(oid, critical, value))

            seen_oids.add(oid)

        return x509.Extensions(extensions)
Exemple #9
0
def test_create_csr(mods, tmpdir):
    path = os.path.join(tmpdir, "example.csr")

    ret = mods["pki.create_csr"](
        path,
        key="test/fixtures/example-ec.key",
        subject={
            "commonName": "localhost",
            "countryName": "DE"
        },
        extensions={
            "subjectAltName": "DNS:localhost,IP:127.0.0.1"
        },
    )

    assert os.path.exists(path)
    assert ret == {
        "extensions": {
            "subjectAltName": ["DNS:localhost", "IP:127.0.0.1"]
        },
        "public_key": _EXAMPLE_PUBKEY,
        "subject": {
            "commonName": "localhost",
            "countryName": "DE"
        },
    }

    with open(path, "rb") as f:
        csr = x509.load_pem_x509_csr(f.read(), default_backend())

    assert isinstance(csr, x509.CertificateSigningRequest)
    assert csr.subject == x509.Name([
        x509.NameAttribute(x509.NameOID.COMMON_NAME, "localhost"),
        x509.NameAttribute(x509.NameOID.COUNTRY_NAME, "DE"),
    ])

    assert repr(csr.extensions) == repr(
        x509.Extensions([
            x509.Extension(
                x509.ExtensionOID.SUBJECT_ALTERNATIVE_NAME,
                False,
                x509.SubjectAlternativeName([
                    x509.DNSName("localhost"),
                    x509.IPAddress(ipaddress.ip_address("127.0.0.1")),
                ]),
            )
        ]))
def _xep_patched_parse(self, backend, x509_obj):
    extensions = []
    seen_oids = set()
    for i in range(self.ext_count(backend, x509_obj)):
        ext = self.get_ext(backend, x509_obj, i)
        backend.openssl_assert(ext != backend._ffi.NULL)
        crit = backend._lib.X509_EXTENSION_get_critical(ext)
        critical = crit == 1
        oid = x509.ObjectIdentifier(
            _obj2txt(backend, backend._lib.X509_EXTENSION_get_object(ext)))

        # This OID is only supported in OpenSSL 1.1.0+ but we want
        # to support it in all versions of OpenSSL so we decode it
        # ourselves.
        if oid == ExtensionOID.TLS_FEATURE:
            data = backend._lib.X509_EXTENSION_get_data(ext)
            parsed = _Integers.load(_asn1_string_to_bytes(backend, data))
            value = x509.TLSFeature(
                [_TLS_FEATURE_TYPE_TO_ENUM[x.native] for x in parsed])
            extensions.append(x509.Extension(oid, critical, value))
            seen_oids.add(oid)
            continue

        try:
            handler = self.handlers[oid]
        except KeyError:
            # Dump the DER payload into an UnrecognizedExtension object
            der = dump_der(ext, backend)
            unrecognized = x509.UnrecognizedExtension(oid, der)
            extensions.append(x509.Extension(oid, critical, unrecognized))
        else:
            ext_data = backend._lib.X509V3_EXT_d2i(ext)
            if ext_data == backend._ffi.NULL:
                backend._consume_errors()
                der = dump_der(ext, backend)
                unrecognized = x509.UnrecognizedExtension(oid, der)
                extensions.append(x509.Extension(oid, critical, unrecognized))
            else:
                value = handler(backend, ext_data)
                extensions.append(x509.Extension(oid, critical, value))

        seen_oids.add(oid)

    return x509.Extensions(extensions)
Exemple #11
0
    def extensions(self):
        extensions = []
        seen_oids = set()
        extcount = self._backend._lib.X509_get_ext_count(self._x509)
        for i in range(0, extcount):
            ext = self._backend._lib.X509_get_ext(self._x509, i)
            assert ext != self._backend._ffi.NULL
            crit = self._backend._lib.X509_EXTENSION_get_critical(ext)
            critical = crit == 1
            oid = x509.ObjectIdentifier(_obj2txt(self._backend, ext.object))
            if oid in seen_oids:
                raise x509.DuplicateExtension(
                    "Duplicate {0} extension found".format(oid), oid)
            elif oid == x509.OID_BASIC_CONSTRAINTS:
                value = self._build_basic_constraints(ext)
            elif oid == x509.OID_SUBJECT_KEY_IDENTIFIER:
                value = self._build_subject_key_identifier(ext)
            elif oid == x509.OID_KEY_USAGE:
                value = self._build_key_usage(ext)
            elif oid == x509.OID_SUBJECT_ALTERNATIVE_NAME:
                value = self._build_subject_alt_name(ext)
            elif oid == x509.OID_EXTENDED_KEY_USAGE:
                value = self._build_extended_key_usage(ext)
            elif oid == x509.OID_AUTHORITY_KEY_IDENTIFIER:
                value = self._build_authority_key_identifier(ext)
            elif oid == x509.OID_AUTHORITY_INFORMATION_ACCESS:
                value = self._build_authority_information_access(ext)
            elif oid == x509.OID_CERTIFICATE_POLICIES:
                value = self._build_certificate_policies(ext)
            elif oid == x509.OID_CRL_DISTRIBUTION_POINTS:
                value = self._build_crl_distribution_points(ext)
            elif critical:
                raise x509.UnsupportedExtension(
                    "{0} is not currently supported".format(oid), oid)
            else:
                # Unsupported non-critical extension, silently skipping for now
                seen_oids.add(oid)
                continue

            seen_oids.add(oid)
            extensions.append(x509.Extension(oid, critical, value))

        return x509.Extensions(extensions)
Exemple #12
0
def test_create_csr_domains(mods):
    ret = mods["pki.create_csr"](
        text=True,
        key="test/fixtures/example-ec.key",
        domains=["example.org", "example.com"],
    )

    csr = x509.load_pem_x509_csr(ret.encode(), default_backend())

    assert isinstance(csr, x509.CertificateSigningRequest)
    assert csr.subject == x509.Name(
        [x509.NameAttribute(x509.NameOID.COMMON_NAME, "example.org")])

    assert repr(csr.extensions) == repr(
        x509.Extensions([
            x509.Extension(
                x509.ExtensionOID.SUBJECT_ALTERNATIVE_NAME,
                False,
                x509.SubjectAlternativeName(
                    [x509.DNSName("example.org"),
                     x509.DNSName("example.com")]),
            )
        ]))
    def parse(self, backend, x509_obj):
        extensions = []
        seen_oids = set()
        for i in range(self.ext_count(backend, x509_obj)):
            ext = self.get_ext(backend, x509_obj, i)
            backend.openssl_assert(ext != backend._ffi.NULL)
            crit = backend._lib.X509_EXTENSION_get_critical(ext)
            critical = crit == 1
            oid = x509.ObjectIdentifier(
                _obj2txt(backend, backend._lib.X509_EXTENSION_get_object(ext)))
            if oid in seen_oids:
                raise x509.DuplicateExtension(
                    "Duplicate {0} extension found".format(oid), oid)
            try:
                handler = self.handlers[oid]
            except KeyError:
                # Dump the DER payload into an UnrecognizedExtension object
                data = backend._lib.X509_EXTENSION_get_data(ext)
                backend.openssl_assert(data != backend._ffi.NULL)
                der = backend._ffi.buffer(data.data, data.length)[:]
                unrecognized = x509.UnrecognizedExtension(oid, der)
                extensions.append(x509.Extension(oid, critical, unrecognized))
            else:
                ext_data = backend._lib.X509V3_EXT_d2i(ext)
                if ext_data == backend._ffi.NULL:
                    backend._consume_errors()
                    raise ValueError(
                        "The {0} extension is invalid and can't be "
                        "parsed".format(oid))

                value = handler(backend, ext_data)
                extensions.append(x509.Extension(oid, critical, value))

            seen_oids.add(oid)

        return x509.Extensions(extensions)
Exemple #14
0
    def parse(self, x509_obj):
        extensions = []
        seen_oids = set()
        for i in range(self.ext_count(x509_obj)):
            ext = self.get_ext(x509_obj, i)
            self._backend.openssl_assert(ext != self._backend._ffi.NULL)
            crit = self._backend._lib.X509_EXTENSION_get_critical(ext)
            critical = crit == 1
            oid = x509.ObjectIdentifier(
                _obj2txt(self._backend,
                         self._backend._lib.X509_EXTENSION_get_object(ext)))
            if oid in seen_oids:
                raise x509.DuplicateExtension(
                    "Duplicate {} extension found".format(oid), oid)

            # These OIDs are only supported in OpenSSL 1.1.0+ but we want
            # to support them in all versions of OpenSSL so we decode them
            # ourselves.
            if oid == ExtensionOID.TLS_FEATURE:
                # The extension contents are a SEQUENCE OF INTEGERs.
                data = self._backend._lib.X509_EXTENSION_get_data(ext)
                data_bytes = _asn1_string_to_bytes(self._backend, data)
                features = DERReader(data_bytes).read_single_element(SEQUENCE)
                parsed = []
                while not features.is_empty():
                    parsed.append(features.read_element(INTEGER).as_integer())
                # Map the features to their enum value.
                value = x509.TLSFeature(
                    [_TLS_FEATURE_TYPE_TO_ENUM[x] for x in parsed])
                extensions.append(x509.Extension(oid, critical, value))
                seen_oids.add(oid)
                continue
            elif oid == ExtensionOID.PRECERT_POISON:
                data = self._backend._lib.X509_EXTENSION_get_data(ext)
                # The contents of the extension must be an ASN.1 NULL.
                reader = DERReader(_asn1_string_to_bytes(self._backend, data))
                reader.read_single_element(NULL).check_empty()
                extensions.append(
                    x509.Extension(oid, critical, x509.PrecertPoison()))
                seen_oids.add(oid)
                continue

            try:
                handler = self.handlers[oid]
            except KeyError:
                # Dump the DER payload into an UnrecognizedExtension object
                data = self._backend._lib.X509_EXTENSION_get_data(ext)
                self._backend.openssl_assert(data != self._backend._ffi.NULL)
                der = self._backend._ffi.buffer(data.data, data.length)[:]
                unrecognized = x509.UnrecognizedExtension(oid, der)
                extensions.append(x509.Extension(oid, critical, unrecognized))
            else:
                ext_data = self._backend._lib.X509V3_EXT_d2i(ext)
                if ext_data == self._backend._ffi.NULL:
                    self._backend._consume_errors()
                    raise ValueError(
                        "The {} extension is invalid and can't be "
                        "parsed".format(oid))

                value = handler(self._backend, ext_data)
                extensions.append(x509.Extension(oid, critical, value))

            seen_oids.add(oid)

        return x509.Extensions(extensions)
Exemple #15
0
    def parse(self, x509_obj):
        extensions: typing.List[x509.Extension[x509.ExtensionType]] = []
        seen_oids = set()
        for i in range(self.ext_count(x509_obj)):
            ext = self.get_ext(x509_obj, i)
            self._backend.openssl_assert(ext != self._backend._ffi.NULL)
            crit = self._backend._lib.X509_EXTENSION_get_critical(ext)
            critical = crit == 1
            oid = x509.ObjectIdentifier(
                _obj2txt(
                    self._backend,
                    self._backend._lib.X509_EXTENSION_get_object(ext),
                ))
            if oid in seen_oids:
                raise x509.DuplicateExtension(
                    "Duplicate {} extension found".format(oid), oid)

            if self.rust_callback is not None:
                oid_ptr = self._backend._lib.X509_EXTENSION_get_object(ext)
                oid_der_bytes = self._backend._ffi.buffer(
                    self._backend._lib.Cryptography_OBJ_get0_data(oid_ptr),
                    self._backend._lib.Cryptography_OBJ_length(oid_ptr),
                )[:]
                data = self._backend._lib.X509_EXTENSION_get_data(ext)
                data_bytes = _asn1_string_to_bytes(self._backend, data)
                ext = self.rust_callback(oid_der_bytes, data_bytes)
                extensions.append(x509.Extension(oid, critical, ext))
                seen_oids.add(oid)
                continue

            # These OIDs are only supported in OpenSSL 1.1.0+ but we want
            # to support them in all versions of OpenSSL so we decode them
            # ourselves.
            if oid == ExtensionOID.TLS_FEATURE:
                # The extension contents are a SEQUENCE OF INTEGERs.
                data = self._backend._lib.X509_EXTENSION_get_data(ext)
                data_bytes = _asn1_string_to_bytes(self._backend, data)
                tls_feature = asn1.parse_tls_feature(data_bytes)

                extensions.append(x509.Extension(oid, critical, tls_feature))
                seen_oids.add(oid)
                continue
            elif oid == ExtensionOID.PRECERT_POISON:
                data = self._backend._lib.X509_EXTENSION_get_data(ext)
                data_bytes = _asn1_string_to_bytes(self._backend, data)
                precert_poison = asn1.parse_precert_poison(data_bytes)

                extensions.append(x509.Extension(oid, critical,
                                                 precert_poison))
                seen_oids.add(oid)
                continue

            try:
                handler = self.handlers[oid]
            except KeyError:
                # Dump the DER payload into an UnrecognizedExtension object
                data = self._backend._lib.X509_EXTENSION_get_data(ext)
                self._backend.openssl_assert(data != self._backend._ffi.NULL)
                der = self._backend._ffi.buffer(data.data, data.length)[:]
                unrecognized = x509.UnrecognizedExtension(oid, der)
                extensions.append(x509.Extension(oid, critical, unrecognized))
            else:
                ext_data = self._backend._lib.X509V3_EXT_d2i(ext)
                if ext_data == self._backend._ffi.NULL:
                    self._backend._consume_errors()
                    raise ValueError(
                        "The {} extension is invalid and can't be "
                        "parsed".format(oid))

                value = handler(self._backend, ext_data)
                extensions.append(x509.Extension(oid, critical, value))

            seen_oids.add(oid)

        return x509.Extensions(extensions)
Exemple #16
0
  def parse(self, backend, x509_obj):
    extensions = []
    seen_oids = set()
    for i in range(self.ext_count(backend, x509_obj)):
      ext = self.get_ext(backend, x509_obj, i)
      backend.openssl_assert(ext != backend._ffi.NULL)
      crit = backend._lib.X509_EXTENSION_get_critical(ext)
      critical = crit == 1
      oid = x509.ObjectIdentifier(
        _obj2txt(backend, backend._lib.X509_EXTENSION_get_object(ext))        
      )
      if oid in seen_oids:
        raise x509.DuplicateExtension(
          "Duplicate {} extension found".format(oid), oid        
        )

      if oid == ExtensionOID.TLS_FEATURE:
        data = backend._lib.X509_EXTENSION_get_data(ext)
        data_bytes = _asn1_string_to_bytes(backend, data)
        features = DERReader(data_bytes).read_single_element(SEQUENCE)
        parsed = []
        while not features.is_empty():
          parsed.append(features.read_element(INTEGER).as_integer())

        value = x509.TLSFeature(
          [_TLS_FEATURE_TYPE_TO_ENUM[x] for x in parsed]        
        )
        extensions.append(x509.Extension(oid, critical, value))
        seen_oids.add(oid)
        continue
      elif oid == ExtensionOID.PRECERT_POSION:
        data = backend._lib.X509_EXTENSION_get_data(ext)
        reader = DERReader(_asn1_string_to_bytes(backend, data))
        reader.read_single_element(NULL).check_empty()
        extensions.append(x509.Extension(
          oid, critical, x509.PrecertPoison()    
        ))
        seen_oids.add(oid)
        continue
      elif oid == ExtensionOID.PRECERT_POISON:
        data = backend._lib.X509_EXTENSION_get_data(ext)
        reader = DERReader(_asn1_string_to_bytes(backend, data))
        reader.read_single_element(NULL).check_empty()
        extensions.append(x509.Extension(
          oid, critical, x509.PrecertPoison()    
        ))
        seen_oids.add(oid)
        continue

      try:
        handler = self.handlers[oid]
      except KeyError:
        data = backend._lib.X509_EXTENSION_get_data(ext)
        backend.openssl_assert(data != backend._ffi.NULL)
        der = backend._ffi.buffer(data.data, data.length)[:]
        unrecognized = x509.UnrecognizedExtension(oid, der)
        extensions.append(
          x509.Extension(oid, critical, unrecognized)        
        )
      else:
        ext_data = backend._lib.X509V3_EXT_d2i(ext)
        if ext_data == backend._ffi.NULL:
          backend._consume_errors()
          raise ValueError(
            "The {} extension is invalid and can't be "
            "parsed".format(oid)
          )

        value = handler(backend, ext_data)
        extensions.append(x509.Extension(oid, critical, value))

      seen_oids.add(oid)

    return x509.Extensions(extenions)