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)

            # 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
                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)
示例#2
0
def _decode_general_name(backend, gn):
  if gn.type == backend._lib.GEN_DNS:
    data = _asn1_string_to_bytes(backend, gn.d.dNSName).decode("utf8")
    return x509.DNSName._init_without_validation(data)
  elif gn.type == backend._lib.GEN_URI:
    data = _asn1_string_to_bytes(
      backend, gn.d.uniformResourceIdentifier
    ).decode("utf8")

    return x509.UniformResourceIdentifier._init_without_validation(data)
  elif gn.type == backend._lib.GEN_RID:
    oid = _asn1_string_to_bytes(backend, gn.d.iPAddress)
    data_len = len(data)
    if data_len == 8 or data_len == 32:
      base = ipaddress.ip_address(data[:data_len // 2])
      netmask = ipaddress.ip_address(data[data_len // 2:])
      bits = bin(int(netmask))[2:]
      prefix = bits.find('0')

      if prefix == -1:
        prefix = len(bits)

      if "1" in bits[prefix]:
        raise ValueError("Invalid netmask")

      ip = piaddress.ip_network(base.exploded + u"/{}".format(prefix))
    else:
      ip = ipaddress.ip_address(data)

    return x509.IPAddress(ip)
  elif gn.type == backend._lib.GEN_DIRNAME:
    return x509.DirectoryName(
      _decode_x509_name(backend, gn.d.directoryName)
    )
  elif gn.type == backend._lib.GEN_EMAIL:
    data = _asn1_string_to_bytes(backend, gn.d.rfc822Name).decode("utf8")

    return x509.RFC822Name._init_without_validation(data)
  elif gn.type == backend._lib.GEN_OTHERNAME:
    type_id = _obj2txt(backend, gn.d.otherName.type_id)
    value = _asn1_to_der(backend, gn.d.otherName.value)
    return x509.OtherName(x509.ObjectIdentifier(type_id), value)
  else:
    raise x509.UnsupportedGeneralnameType(
      "{} is not a supported type".format(
        x509._GENERAL_NAMES.get(gn.type, gn.type)
      ),
      gn.type
    )
示例#3
0
def _build_general_name(backend, gn):
    if gn.type == backend._lib.GEN_DNS:
        data = backend._ffi.buffer(gn.d.dNSName.data, gn.d.dNSName.length)[:]
        return x509.DNSName(idna.decode(data))
    elif gn.type == backend._lib.GEN_RID:
        oid = _obj2txt(backend, gn.d.registeredID)
        return x509.RegisteredID(x509.ObjectIdentifier(oid))
    else:
        # otherName, x400Address or ediPartyName
        raise x509.UnsupportedGeneralNameType(
            "{0} is not a supported type".format(
                x509._GENERAL_NAMES.get(gn.type, gn.type)
            ),
            gn.type
        )
示例#4
0
    def _parse_nameattr(self, av):
        """Parse an X.509 name attribute/value pair"""

        try:
            attr, value = av.split('=', 1)
        except ValueError:
            raise ValueError('Invalid X.509 name attribute: ' + av) from None

        try:
            attr = attr.strip()
            oid = self._to_oid.get(attr) or x509.ObjectIdentifier(attr)
        except ValueError:
            raise ValueError('Unknown X.509 attribute: ' + attr) from None

        return x509.NameAttribute(oid, self._unescape.sub(r'\1', value))
示例#5
0
def _decode_extended_key_usage(backend, ext):
    sk = backend._ffi.cast("Cryptography_STACK_OF_ASN1_OBJECT *",
                           backend._lib.X509V3_EXT_d2i(ext))
    assert sk != backend._ffi.NULL
    sk = backend._ffi.gc(sk, backend._lib.sk_ASN1_OBJECT_free)
    num = backend._lib.sk_ASN1_OBJECT_num(sk)
    ekus = []

    for i in range(num):
        obj = backend._lib.sk_ASN1_OBJECT_value(sk, i)
        assert obj != backend._ffi.NULL
        oid = x509.ObjectIdentifier(_obj2txt(backend, obj))
        ekus.append(oid)

    return x509.ExtendedKeyUsage(ekus)
示例#6
0
def test_sct_embedding():
    order = chisel2.auth_and_issue([random_domain()])
    cert = x509.load_pem_x509_certificate(str(order.fullchain_pem), default_backend())

    # make sure there is no poison extension
    try:
        cert.extensions.get_extension_for_oid(x509.ObjectIdentifier("1.3.6.1.4.1.11129.2.4.3"))
        raise Exception("certificate contains CT poison extension")
    except x509.ExtensionNotFound:
        # do nothing
        pass

    # make sure there is a SCT list extension
    try:
        sctList = cert.extensions.get_extension_for_oid(x509.ObjectIdentifier("1.3.6.1.4.1.11129.2.4.2"))
    except x509.ExtensionNotFound:
        raise Exception("certificate doesn't contain SCT list extension")
    if len(sctList.value) != 2:
        raise Exception("SCT list contains wrong number of SCTs")
    for sct in sctList.value:
        if sct.version != x509.certificate_transparency.Version.v1:
            raise Exception("SCT contains wrong version")
        if sct.entry_type != x509.certificate_transparency.LogEntryType.PRE_CERTIFICATE:
            raise Exception("SCT contains wrong entry type")
示例#7
0
def _decode_certificate_policies(backend, cp):
    cp = backend._ffi.cast("Cryptography_STACK_OF_POLICYINFO *", cp)
    cp = backend._ffi.gc(cp, backend._lib.sk_POLICYINFO_free)
    num = backend._lib.sk_POLICYINFO_num(cp)
    certificate_policies = []
    for i in range(num):
        qualifiers = None
        pi = backend._lib.sk_POLICYINFO_value(cp, i)
        oid = x509.ObjectIdentifier(_obj2txt(backend, pi.policyid))
        if pi.qualifiers != backend._ffi.NULL:
            qnum = backend._lib.sk_POLICYQUALINFO_num(pi.qualifiers)
            qualifiers = []
            for j in range(qnum):
                pqi = backend._lib.sk_POLICYQUALINFO_value(
                    pi.qualifiers, j
                )
                pqualid = x509.ObjectIdentifier(
                    _obj2txt(backend, pqi.pqualid)
                )
                if pqualid == CertificatePoliciesOID.CPS_QUALIFIER:
                    cpsuri = backend._ffi.buffer(
                        pqi.d.cpsuri.data, pqi.d.cpsuri.length
                    )[:].decode('ascii')
                    qualifiers.append(cpsuri)
                else:
                    assert pqualid == CertificatePoliciesOID.CPS_USER_NOTICE
                    user_notice = _decode_user_notice(
                        backend, pqi.d.usernotice
                    )
                    qualifiers.append(user_notice)

        certificate_policies.append(
            x509.PolicyInformation(oid, qualifiers)
        )

    return x509.CertificatePolicies(certificate_policies)
示例#8
0
    def test_numeric_string_x509_name_entry(self):
        cert = _load_cert(os.path.join("x509", "e-trust.ru.der"),
                          x509.load_der_x509_certificate, backend)
        if backend._lib.CRYPTOGRAPHY_OPENSSL_LESS_THAN_102I:
            with pytest.raises(ValueError) as exc:
                cert.subject

            # We assert on the message in this case because if the certificate
            # fails to load it will also raise a ValueError and this test could
            # erroneously pass.
            assert str(exc.value) == "Unsupported ASN1 string type. Type: 18"
        else:
            assert cert.subject.get_attributes_for_oid(
                x509.ObjectIdentifier(
                    "1.2.643.3.131.1.1"))[0].value == "007710474375"
示例#9
0
def test_sct_embedding():
    if not os.environ.get('BOULDER_CONFIG_DIR',
                          '').startswith("test/config-next"):
        return
    certr, authzs = auth_and_issue([random_domain()])
    certBytes = urllib2.urlopen(certr.uri).read()
    cert = x509.load_der_x509_certificate(certBytes, default_backend())

    # make sure there is no poison extension
    try:
        cert.extensions.get_extension_for_oid(
            x509.ObjectIdentifier("1.3.6.1.4.1.11129.2.4.3"))
        raise Exception("certificate contains CT poison extension")
    except x509.ExtensionNotFound:
        # do nothing
        pass

    # make sure there is a SCT list extension
    try:
        sctList = cert.extensions.get_extension_for_oid(
            x509.ObjectIdentifier("1.3.6.1.4.1.11129.2.4.2"))
    except x509.ExtensionNotFound:
        raise Exception("certificate doesn't contain SCT list extension")
    if len(sctList.value) != 2:
        raise Exception("SCT list contains wrong number of SCTs")
    for sct in sctList.value:
        if sct.version != x509.certificate_transparency.Version.v1:
            raise Exception("SCT contains wrong version")
        if sct.entry_type != x509.certificate_transparency.LogEntryType.PRE_CERTIFICATE:
            raise Exception("SCT contains wrong entry type")
        delta = sct.timestamp - datetime.datetime.now()
        if abs(delta) > datetime.timedelta(hours=1):
            raise Exception(
                "Delta between SCT timestamp and now was too great "
                "%s vs %s (%s)" %
                (sct.timestamp, datetime.datetime.now(), delta))
示例#10
0
 def test_single_extensions_sct(self, backend):
     resp = _load_data(
         os.path.join("x509", "ocsp", "resp-sct-extension.der"),
         ocsp.load_der_ocsp_response,
     )
     assert len(resp.single_extensions) == 1
     ext = resp.single_extensions[0]
     assert ext.oid == x509.ObjectIdentifier("1.3.6.1.4.1.11129.2.4.5")
     assert len(ext.value) == 4
     log_ids = [base64.b64encode(sct.log_id) for sct in ext.value]
     assert log_ids == [
         b"RJRlLrDuzq/EQAfYqP4owNrmgr7YyzG1P9MzlrW2gag=",
         b"b1N2rDHwMRnYmQCkURX/dxUcEdkCwQApBo2yCJo32RM=",
         b"u9nfvB+KcbWTlCOXqpJ7RzhXlQqrUugakJZkNo4e0YU=",
         b"7ku9t3XOYLrhQmkfq+GeZqMPfl+wctiDAMR7iXqo/cs=",
     ]
示例#11
0
def _decode_authority_information_access(backend, ext):
    aia = backend._lib.X509V3_EXT_d2i(ext)
    assert aia != backend._ffi.NULL
    aia = backend._ffi.cast("Cryptography_STACK_OF_ACCESS_DESCRIPTION *", aia)
    aia = backend._ffi.gc(aia, backend._lib.sk_ACCESS_DESCRIPTION_free)
    num = backend._lib.sk_ACCESS_DESCRIPTION_num(aia)
    access_descriptions = []
    for i in range(num):
        ad = backend._lib.sk_ACCESS_DESCRIPTION_value(aia, i)
        assert ad.method != backend._ffi.NULL
        oid = x509.ObjectIdentifier(_obj2txt(backend, ad.method))
        assert ad.location != backend._ffi.NULL
        gn = _decode_general_name(backend, ad.location)
        access_descriptions.append(x509.AccessDescription(oid, gn))

    return x509.AuthorityInformationAccess(access_descriptions)
示例#12
0
def _build_general_name(backend, gn):
    if gn.type == backend._lib.GEN_DNS:
        data = backend._ffi.buffer(gn.d.dNSName.data, gn.d.dNSName.length)[:]
        return x509.DNSName(idna.decode(data))
    elif gn.type == backend._lib.GEN_URI:
        data = backend._ffi.buffer(
            gn.d.uniformResourceIdentifier.data,
            gn.d.uniformResourceIdentifier.length
        )[:].decode("ascii")
        parsed = urllib_parse.urlparse(data)
        hostname = idna.decode(parsed.hostname)
        if parsed.port:
            netloc = hostname + u":" + six.text_type(parsed.port)
        else:
            netloc = hostname

        # Note that building a URL in this fashion means it should be
        # semantically indistinguishable from the original but is not
        # guaranteed to be exactly the same.
        uri = urllib_parse.urlunparse((
            parsed.scheme,
            netloc,
            parsed.path,
            parsed.params,
            parsed.query,
            parsed.fragment
        ))
        return x509.UniformResourceIdentifier(uri)
    elif gn.type == backend._lib.GEN_RID:
        oid = _obj2txt(backend, gn.d.registeredID)
        return x509.RegisteredID(x509.ObjectIdentifier(oid))
    elif gn.type == backend._lib.GEN_IPADD:
        return x509.IPAddress(
            ipaddress.ip_address(
                backend._ffi.buffer(
                    gn.d.iPAddress.data, gn.d.iPAddress.length
                )[:]
            )
        )
    else:
        # otherName, x400Address or ediPartyName
        raise x509.UnsupportedGeneralNameType(
            "{0} is not a supported type".format(
                x509._GENERAL_NAMES.get(gn.type, gn.type)
            ),
            gn.type
        )
示例#13
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:
                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)
示例#14
0
def mk_signed_cert(cacert, ca_privkey, name, serialnum):
    """
    Create a CA cert + server cert + server private key.
    """

    cert_req, privkey = mk_request(config.getint("ca", "cert_bits"),
                                   common_name=name)
    pubkey = privkey.public_key()
    cert_req = cert_req.public_key(pubkey)

    cert_req = cert_req.serial_number(serialnum)
    cert_req = mk_cert_valid(cert_req)
    cert_req = cert_req.issuer_name(cacert.issuer)

    # Extensions.
    extensions = [
        # OID 2.16.840.1.113730.1.13 is Netscape Comment.
        # http://oid-info.com/get/2.16.840.1.113730.1.13
        x509.UnrecognizedExtension(
            oid=x509.ObjectIdentifier("2.16.840.1.113730.1.13"),
            value=b"SSL Server",
        ),
        # Subject Alternative Name.
        x509.SubjectAlternativeName([x509.DNSName(name)]),
        # CRL Distribution Points.
        x509.CRLDistributionPoints([
            x509.DistributionPoint(
                full_name=[
                    x509.UniformResourceIdentifier("http://localhost/crl.pem"),
                ],
                relative_name=None,
                reasons=None,
                crl_issuer=None,
            ),
        ]),
    ]

    for ext in extensions:
        cert_req = cert_req.add_extension(ext, critical=False)

    cert = cert_req.sign(
        private_key=ca_privkey,
        algorithm=hashes.SHA256(),
        backend=default_backend(),
    )
    return cert, privkey
示例#15
0
def _decode_authority_information_access(backend, aia):
    aia = backend._ffi.cast("Cryptography_STACK_OF_ACCESS_DESCRIPTION *", aia)
    aia = backend._ffi.gc(
        aia, lambda x: backend._lib.sk_ACCESS_DESCRIPTION_pop_free(
            x,
            backend._ffi.addressof(backend._lib._original_lib,
                                   "ACCESS_DESCRIPTION_free")))
    num = backend._lib.sk_ACCESS_DESCRIPTION_num(aia)
    access_descriptions = []
    for i in range(num):
        ad = backend._lib.sk_ACCESS_DESCRIPTION_value(aia, i)
        backend.openssl_assert(ad.method != backend._ffi.NULL)
        oid = x509.ObjectIdentifier(_obj2txt(backend, ad.method))
        backend.openssl_assert(ad.location != backend._ffi.NULL)
        gn = _decode_general_name(backend, ad.location)
        access_descriptions.append(x509.AccessDescription(oid, gn))

    return x509.AuthorityInformationAccess(access_descriptions)
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)
示例#17
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)
示例#18
0
def _make_name(common_name):
    return x509.Name([
        x509.NameAttribute(NameOID.COUNTRY_NAME,
                           settings.VPN_KEYGEN_CONFIG.KEY_COUNTRY),
        x509.NameAttribute(NameOID.STATE_OR_PROVINCE_NAME,
                           settings.VPN_KEYGEN_CONFIG.KEY_PROVINCE),
        x509.NameAttribute(NameOID.LOCALITY_NAME,
                           settings.VPN_KEYGEN_CONFIG.KEY_CITY),
        x509.NameAttribute(NameOID.ORGANIZATION_NAME,
                           settings.VPN_KEYGEN_CONFIG.KEY_ORG),
        x509.NameAttribute(NameOID.ORGANIZATIONAL_UNIT_NAME,
                           settings.VPN_KEYGEN_CONFIG.KEY_OU),
        x509.NameAttribute(NameOID.COMMON_NAME, common_name),
        x509.NameAttribute(
            x509.ObjectIdentifier("2.5.4.41"),  # Name
            settings.VPN_KEYGEN_CONFIG.KEY_NAME),
        x509.NameAttribute(NameOID.EMAIL_ADDRESS,
                           settings.VPN_KEYGEN_CONFIG.KEY_EMAIL)
    ])
示例#19
0
def update_ca_cert(cert_name, cert_path, skip_checks=False, **kwargs):
    with open(cert_path) as f:
        cert_pem = f.read()

    if not skip_checks:
        try:
            cert = x509.load_pem_x509_certificate(
                cert_pem.encode(), crypto_backends.default_backend())
        except Exception as exc:
            raise ValueError("Cannot parse PEM certificate") from exc

        try:
            oid = x509.ObjectIdentifier(CERT_OID_SGX_QUOTE)
            _ = cert.extensions.get_extension_for_oid(oid)
        except x509.ExtensionNotFound as exc:
            raise ValueError(
                "X.509 extension with SGX quote not found in certificate"
            ) from exc

    args = {"name": cert_name, "cert": cert_pem}
    return build_proposal("update_ca_cert", args, **kwargs)
示例#20
0
def _build_x509_name(backend, x509_name):
    count = backend._lib.X509_NAME_entry_count(x509_name)
    attributes = []
    for x in range(count):
        entry = backend._lib.X509_NAME_get_entry(x509_name, x)
        obj = backend._lib.X509_NAME_ENTRY_get_object(entry)
        assert obj != backend._ffi.NULL
        data = backend._lib.X509_NAME_ENTRY_get_data(entry)
        assert data != backend._ffi.NULL
        buf = backend._ffi.new("unsigned char **")
        res = backend._lib.ASN1_STRING_to_UTF8(buf, data)
        assert res >= 0
        assert buf[0] != backend._ffi.NULL
        buf = backend._ffi.gc(
            buf, lambda buffer: backend._lib.OPENSSL_free(buffer[0]))
        value = backend._ffi.buffer(buf[0], res)[:].decode('utf8')
        oid = _obj2txt(backend, obj)
        attributes.append(x509.NameAttribute(x509.ObjectIdentifier(oid),
                                             value))

    return x509.Name(attributes)
示例#21
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(
                        "Critical extension {0} is not currently supported".
                        format(oid), oid)
            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)
示例#22
0
def test_get_curve_for_oid():
    assert ec.get_curve_for_oid(ec.EllipticCurveOID.SECP256R1) == ec.SECP256R1
    with pytest.raises(LookupError):
        ec.get_curve_for_oid(x509.ObjectIdentifier("1.1.1.1"))
示例#23
0
def _pyasn1_to_cryptography_oid(oid):
    return crypto_x509.ObjectIdentifier(str(oid))
示例#24
0
def _decode_general_name(backend, gn):
    if gn.type == backend._lib.GEN_DNS:
        # Convert to bytes and then decode to utf8. We don't use
        # asn1_string_to_utf8 here because it doesn't properly convert
        # utf8 from ia5strings.
        data = _asn1_string_to_bytes(backend, gn.d.dNSName).decode("utf8")
        # We don't use the constructor for DNSName so we can bypass validation
        # This allows us to create DNSName objects that have unicode chars
        # when a certificate (against the RFC) contains them.
        return x509.DNSName._init_without_validation(data)
    elif gn.type == backend._lib.GEN_URI:
        # Convert to bytes and then decode to utf8. We don't use
        # asn1_string_to_utf8 here because it doesn't properly convert
        # utf8 from ia5strings.
        data = _asn1_string_to_bytes(
            backend, gn.d.uniformResourceIdentifier).decode("utf8")
        # We don't use the constructor for URI so we can bypass validation
        # This allows us to create URI objects that have unicode chars
        # when a certificate (against the RFC) contains them.
        return x509.UniformResourceIdentifier._init_without_validation(data)
    elif gn.type == backend._lib.GEN_RID:
        oid = _obj2txt(backend, gn.d.registeredID)
        return x509.RegisteredID(x509.ObjectIdentifier(oid))
    elif gn.type == backend._lib.GEN_IPADD:
        data = _asn1_string_to_bytes(backend, gn.d.iPAddress)
        data_len = len(data)
        if data_len == 8 or data_len == 32:
            # This is an IPv4 or IPv6 Network and not a single IP. This
            # type of data appears in Name Constraints. Unfortunately,
            # ipaddress doesn't support packed bytes + netmask. Additionally,
            # IPv6Network can only handle CIDR rather than the full 16 byte
            # netmask. To handle this we convert the netmask to integer, then
            # find the first 0 bit, which will be the prefix. If another 1
            # bit is present after that the netmask is invalid.
            base = ipaddress.ip_address(data[:data_len // 2])
            netmask = ipaddress.ip_address(data[data_len // 2:])
            bits = bin(int(netmask))[2:]
            prefix = bits.find("0")
            # If no 0 bits are found it is a /32 or /128
            if prefix == -1:
                prefix = len(bits)

            if "1" in bits[prefix:]:
                raise ValueError("Invalid netmask")

            ip = ipaddress.ip_network(base.exploded + "/{}".format(prefix))
        else:
            ip = ipaddress.ip_address(data)

        return x509.IPAddress(ip)
    elif gn.type == backend._lib.GEN_DIRNAME:
        return x509.DirectoryName(
            _decode_x509_name(backend, gn.d.directoryName))
    elif gn.type == backend._lib.GEN_EMAIL:
        # Convert to bytes and then decode to utf8. We don't use
        # asn1_string_to_utf8 here because it doesn't properly convert
        # utf8 from ia5strings.
        data = _asn1_string_to_bytes(backend, gn.d.rfc822Name).decode("utf8")
        # We don't use the constructor for RFC822Name so we can bypass
        # validation. This allows us to create RFC822Name objects that have
        # unicode chars when a certificate (against the RFC) contains them.
        return x509.RFC822Name._init_without_validation(data)
    elif gn.type == backend._lib.GEN_OTHERNAME:
        type_id = _obj2txt(backend, gn.d.otherName.type_id)
        value = _asn1_to_der(backend, gn.d.otherName.value)
        return x509.OtherName(x509.ObjectIdentifier(type_id), value)
    else:
        # x400Address or ediPartyName
        raise x509.UnsupportedGeneralNameType(
            "{} is not a supported type".format(
                x509._GENERAL_NAMES.get(gn.type, gn.type)),
            gn.type,
        )
示例#25
0
 def test_ne(self):
     oid1 = x509.ObjectIdentifier('oid')
     assert oid1 != x509.ObjectIdentifier('oid1')
     assert oid1 != object()
示例#26
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)
示例#27
0
 def test_repr(self):
     oid = x509.ObjectIdentifier("2.5.4.3")
     assert repr(oid) == "<ObjectIdentifier(oid=2.5.4.3, name=commonName)>"
     oid = x509.ObjectIdentifier("oid1")
     assert repr(oid) == "<ObjectIdentifier(oid=oid1, name=Unknown OID)>"
示例#28
0
from cryptography.hazmat.primitives.hashes import MD5, SHA1, SHA224
from cryptography.hazmat.primitives.hashes import SHA256, SHA384, SHA512
from cryptography.hazmat.primitives.serialization import Encoding
from cryptography.hazmat.primitives.serialization import PublicFormat
from cryptography import x509

from OpenSSL import crypto

from ...asn1 import IA5String, der_decode, der_encode

# pylint: disable=bad-whitespace

_purpose_to_oid = {
    'serverAuth': x509.ExtendedKeyUsageOID.SERVER_AUTH,
    'clientAuth': x509.ExtendedKeyUsageOID.CLIENT_AUTH,
    'secureShellClient': x509.ObjectIdentifier('1.3.6.1.5.5.7.3.21'),
    'secureShellServer': x509.ObjectIdentifier('1.3.6.1.5.5.7.3.22')
}

# pylint: enable=bad-whitespace

_purpose_any = x509.ObjectIdentifier('2.5.29.37.0')

_hashes = {h.name: h for h in (MD5, SHA1, SHA224, SHA256, SHA384, SHA512)}

_nscomment_oid = x509.ObjectIdentifier('2.16.840.1.113730.1.13')

if sys.platform == 'win32':  # pragma: no cover
    # Windows' datetime.max is year 9999, but timestamps that large don't work
    _gen_time_max = datetime(
        2999, 12, 31, 23, 59, 59, 999999, tzinfo=timezone.utc).timestamp() - 1
示例#29
0
from binascii import a2b_hex
from enum import Enum, IntEnum, unique
import struct
import json
import six
import os

__all__ = [
    'Transport', 'Type', 'RegistrationData', 'SignatureData', 'RegisteredKey',
    'DeviceRegistration', 'ClientData', 'RegisterRequest', 'RegisterResponse',
    'SignResponse', 'U2fRegisterRequest', 'U2fSignRequest'
]

U2F_V2 = 'U2F_V2'

TRANSPORTS_EXT_OID = x509.ObjectIdentifier('1.3.6.1.4.1.45724.2.1.1')
PUB_KEY_DER_PREFIX = a2b_hex(
    '3059301306072a8648ce3d020106082a8648ce3d030107034200')

CERTS_TO_FIX = [
    a2b_hex(
        '349bca1031f8c82c4ceca38b9cebf1a69df9fb3b94eed99eb3fb9aa3822d26e8'),
    a2b_hex(
        'dd574527df608e47ae45fbba75a2afdd5c20fd94a02419381813cd55a2a3398f'),
    a2b_hex(
        '1d8764f0f7cd1352df6150045c8f638e517270e8b5dda1c63ade9c2280240cae'),
    a2b_hex(
        'd0edc9a91a1677435a953390865d208c55b3183c6759c9b5a7ff494c322558eb'),
    a2b_hex(
        '6073c436dcd064a48127ddbf6032ac1a66fd59a0c24434f070d4e564c124c897'),
    a2b_hex('ca993121846c464d666096d35f13bf44c1b05af205f9b4a1e00cf6cc10c5e511')
示例#30
0
文件: utils.py 项目: psydox/django-ca
def parse_general_name(name: ParsableGeneralName) -> x509.GeneralName:
    """Parse a general name from user input.

    This function will do its best to detect the intended type of any value passed to it:

    >>> parse_general_name('example.com')
    <DNSName(value='example.com')>
    >>> parse_general_name('*.example.com')
    <DNSName(value='*.example.com')>
    >>> parse_general_name('.example.com')  # Syntax used e.g. for NameConstraints: All levels of subdomains
    <DNSName(value='.example.com')>
    >>> parse_general_name('*****@*****.**')
    <RFC822Name(value='*****@*****.**')>
    >>> parse_general_name('https://example.com')
    <UniformResourceIdentifier(value='https://example.com')>
    >>> parse_general_name('1.2.3.4')
    <IPAddress(value=1.2.3.4)>
    >>> parse_general_name('fd00::1')
    <IPAddress(value=fd00::1)>
    >>> parse_general_name('/CN=example.com')
    <DirectoryName(value=<Name(CN=example.com)>)>

    The default fallback is to assume a :py:class:`~cg:cryptography.x509.DNSName`. If this doesn't
    work, an exception will be raised:

    >>> parse_general_name('foo..bar`*123')  # doctest: +ELLIPSIS
    Traceback (most recent call last):
        ...
    ValueError: Could not parse name: foo..bar`*123

    If you want to override detection, you can prefix the name to match :py:const:`GENERAL_NAME_RE`:

    >>> parse_general_name('email:[email protected]')
    <RFC822Name(value='*****@*****.**')>
    >>> parse_general_name('URI:https://example.com')
    <UniformResourceIdentifier(value='https://example.com')>
    >>> parse_general_name('dirname:/CN=example.com')
    <DirectoryName(value=<Name(CN=example.com)>)>

    Some more exotic values can only be generated by using this prefix:

    >>> parse_general_name('rid:2.5.4.3')
    <RegisteredID(value=<ObjectIdentifier(oid=2.5.4.3, name=commonName)>)>
    >>> parse_general_name('otherName:2.5.4.3;UTF8:example.com')
    <OtherName(type_id=<ObjectIdentifier(oid=2.5.4.3, name=commonName)>, value=b'example.com')>

    If you give a prefixed value, this function is less forgiving of any typos and does not catch any
    exceptions:

    >>> parse_general_name('email:foo@bar com')
    Traceback (most recent call last):
        ...
    ValueError: Invalid domain: bar com

    """
    # pylint: disable=too-many-return-statements,too-many-branches,too-many-statements

    if isinstance(name, x509.GeneralName):
        return name
    if not isinstance(name, str):
        raise ValueError(
            "Cannot parse general name %s: Must be of type str (was: %s)." % (name, type(name).__name__)
        )

    typ = None
    match = GENERAL_NAME_RE.match(name)
    if match is not None:
        typ, name = match.groups()
        typ = typ.lower()

    if typ is None:
        if re.match("[a-z0-9]{2,}://", name):  # Looks like a URI
            try:
                return x509.UniformResourceIdentifier(encode_url(name))
            except idna.IDNAError:
                pass

        if "@" in name:  # Looks like an Email address
            try:
                return x509.RFC822Name(validate_email(name))
            except ValueError:
                pass

        if name.strip().startswith("/"):  # maybe it's a dirname?
            return x509.DirectoryName(x509_name(name))

        # Try to parse this as IPAddress/Network
        try:
            return x509.IPAddress(ip_address(name))
        except ValueError:
            pass
        try:
            return x509.IPAddress(ip_network(name))
        except ValueError:
            pass

        # Almost anything passes as DNS name, so this is our default fallback
        try:
            return x509.DNSName(encode_dns(name))
        except idna.IDNAError as e:
            raise ValueError("Could not parse name: %s" % name) from e

    if typ == "uri":
        try:
            return x509.UniformResourceIdentifier(encode_url(name))
        except idna.IDNAError as e:
            raise ValueError("Could not parse DNS name in URL: %s" % name) from e
    elif typ == "email":
        return x509.RFC822Name(validate_email(name))  # validate_email already raises ValueError
    elif typ == "ip":
        try:
            return x509.IPAddress(ip_address(name))
        except ValueError:
            pass

        try:
            return x509.IPAddress(ip_network(name))
        except ValueError:
            pass

        raise ValueError("Could not parse IP address.")
    elif typ == "rid":
        return x509.RegisteredID(x509.ObjectIdentifier(name))
    elif typ == "othername":
        match = re.match("(.*);(.*):(.*)", name)
        if match is not None:
            oid, asn_typ, val = match.groups()
            if asn_typ == "UTF8":
                parsed_value = val.encode("utf-8")
            elif asn_typ == "OctetString":
                parsed_value = OctetString(bytes(bytearray.fromhex(val))).dump()
            else:
                raise ValueError("Unsupported ASN type in otherName: %s" % asn_typ)

            return x509.OtherName(x509.ObjectIdentifier(oid), parsed_value)

        raise ValueError("Incorrect otherName format: %s" % name)
    elif typ == "dirname":
        return x509.DirectoryName(x509_name(name))
    else:
        try:
            return x509.DNSName(encode_dns(name))
        except idna.IDNAError as e:
            raise ValueError("Could not parse DNS name: %s" % name) from e