Пример #1
0
 def pbkdf2_hmac(hash_name, password, salt, iterations, dklen=None):
     if not isinstance(hash_name, str):
         raise TypeError("expected 'str' for name, but got %s" % type(hash_name))
     c_name = _str_to_ffi_buffer(hash_name)
     digest = lib.EVP_get_digestbyname(c_name)
     if digest == ffi.NULL:
         raise ValueError("unsupported hash type")
     if dklen is None:
         dklen = lib.EVP_MD_size(digest)
     if dklen < 1:
         raise ValueError("key length must be greater than 0.")
     if dklen >= sys.maxsize:
         raise OverflowError("key length is too great.")
     if iterations < 1:
         raise ValueError("iteration value must be greater than 0.")
     if iterations >= sys.maxsize:
         raise OverflowError("iteration value is too great.")
     buf = ffi.new("unsigned char[]", dklen)
     c_password = ffi.from_buffer(bytes(password))
     c_salt = ffi.from_buffer(bytes(salt))
     r = lib.PKCS5_PBKDF2_HMAC(c_password, len(c_password),
             ffi.cast("unsigned char*",c_salt), len(c_salt),
             iterations, digest, dklen, buf)
     if r == 0:
         raise ValueError
     return _bytes_with_len(buf, dklen)
Пример #2
0
def _bio_get_str(biobuf):
    bio_buf = ffi.new("char[]", 2048)
    length = lib.BIO_gets(biobuf, bio_buf, len(bio_buf) - 1)
    if length < 0:
        if biobuf: lib.BIO_free(biobuf)
        raise ssl_error(None)
    return _str_with_len(bio_buf, length)
Пример #3
0
def _create_tuple_for_attribute(name, value):
    buf = ffi.new("char[]", X509_NAME_MAXLEN)
    length = lib.OBJ_obj2txt(buf, X509_NAME_MAXLEN, name, 0)
    if length < 0:
        raise ssl_error(None)
    name = _str_with_len(buf, length)

    buf_ptr = ffi.new("unsigned char**")
    length = lib.ASN1_STRING_to_UTF8(buf_ptr, value)
    if length < 0:
        raise ssl_error(None)
    try:
        value = _str_with_len(buf_ptr[0], length)
    finally:
        lib.OPENSSL_free(buf_ptr[0])
    return (name, value)
Пример #4
0
def _certificate_to_der(certificate):
    buf_ptr = ffi.new("unsigned char**")
    buf_ptr[0] = ffi.NULL
    length = lib.i2d_X509(certificate, buf_ptr)
    if length < 0:
        raise ssl_error(None)
    try:
        return _bytes_with_len(ffi.cast("char*", buf_ptr[0]), length)
    finally:
        lib.OPENSSL_free(buf_ptr[0])
Пример #5
0
def parseKeyUsage(pCertCtx, flags):
    pSize = ffi.new("DWORD *")
    if not lib.CertGetEnhancedKeyUsage(pCertCtx, flags, ffi.NULL, pSize):
        error_with_message = ffi.getwinerror()
        if error_with_message[0] == lib.CRYPT_E_NOT_FOUND:
            return True
        raise WindowsError(*error_with_message)

    pUsageMem = ffi.new("char[]", pSize[0])
    pUsage = ffi.cast("PCERT_ENHKEY_USAGE", pUsageMem)
    if not lib.CertGetEnhancedKeyUsage(pCertCtx, flags, pUsage, pSize):
        error_with_message = ffi.getwinerror()
        if error_with_message[0] == lib.CRYPT_E_NOT_FOUND:
            return True
        raise WindowsError(*error_with_message)

    retval = set()
    for i in range(pUsage.cUsageIdentifier):
        if pUsage.rgpszUsageIdentifier[i]:
            oid = ffi.string(pUsage.rgpszUsageIdentifier[i]).decode('ascii')
            retval.add(oid)
    return retval
Пример #6
0
 def _digest(self):
     ctx = lib.Cryptography_EVP_MD_CTX_new()
     if ctx == ffi.NULL:
         raise MemoryError
     try:
         with self.lock:
             if not lib.EVP_MD_CTX_copy_ex(ctx, self.ctx):
                 raise ValueError
         digest_size = self.digest_size
         buf = ffi.new("unsigned char[]", digest_size)
         lib.EVP_DigestFinal_ex(ctx, buf, ffi.NULL)
         return _bytes_with_len(buf, digest_size)
     finally:
         lib.Cryptography_EVP_MD_CTX_free(ctx)
Пример #7
0
def _get_peer_alt_names(certificate):
    # this code follows the procedure outlined in
    # OpenSSL's crypto/x509v3/v3_prn.c:X509v3_EXT_print()
    # function to extract the STACK_OF(GENERAL_NAME),
    # then iterates through the stack to add the
    # names.
    peer_alt_names = []

    if certificate == ffi.NULL:
        return None

    # get a memory buffer
    biobuf = lib.BIO_new(lib.BIO_s_mem())

    i = -1
    while True:
        i = lib.X509_get_ext_by_NID(certificate, lib.NID_subject_alt_name, i)
        if i < 0:
            break

        # now decode the altName
        ext = lib.X509_get_ext(certificate, i)
        method = lib.X509V3_EXT_get(ext)
        if method is ffi.NULL:
            raise ssl_error("No method for internalizing subjectAltName!")

        ext_data = lib.X509_EXTENSION_get_data(ext)
        ext_data_len = ext_data.length
        ext_data_value = ffi.new("unsigned char**", ffi.NULL)
        ext_data_value[0] = ext_data.data

        if method.it != ffi.NULL:
            names = lib.ASN1_item_d2i(ffi.NULL, ext_data_value, ext_data_len,
                                      lib.ASN1_ITEM_ptr(method.it))
        else:
            names = method.d2i(ffi.NULL, ext_data_value, ext_data_len)

        names = ffi.cast("GENERAL_NAMES*", names)
        count = lib.sk_GENERAL_NAME_num(names)
        for j in range(count):
            # get a rendering of each name in the set of names
            name = lib.sk_GENERAL_NAME_value(names, j)
            _type = name.type
            if _type == lib.GEN_DIRNAME:
                # we special-case DirName as a tuple of
                # tuples of attributes
                v = _create_tuple_for_X509_NAME(name.d.dirn)
                peer_alt_names.append(("DirName", v))
            # GENERAL_NAME_print() doesn't handle NULL bytes in ASN1_string
            # correctly, CVE-2013-4238
            elif _type == lib.GEN_EMAIL:
                v = _string_from_asn1(name.d.rfc822Name)
                peer_alt_names.append(("email", v))
            elif _type == lib.GEN_DNS:
                v = _string_from_asn1(name.d.dNSName)
                peer_alt_names.append(("DNS", v))
            elif _type == lib.GEN_URI:
                v = _string_from_asn1(name.d.uniformResourceIdentifier)
                peer_alt_names.append(("URI", v))
            elif _type == lib.GEN_RID:
                v = "Registered ID"
                buf = ffi.new("char[2048]")

                length = lib.OBJ_obj2txt(buf, 2047, name.d.rid, 0)
                if length < 0:
                    # TODO _setSSLError(NULL, 0, __FILE__, __LINE__);
                    raise NotImplementedError
                elif length >= 2048:
                    v = "<INVALID>"
                else:
                    v = _str_with_len(buf, length)
                peer_alt_names.append(("Registered ID", v))
            else:
                # for everything else, we use the OpenSSL print form
                if _type not in (lib.GEN_OTHERNAME, lib.GEN_X400, \
                                 lib.GEN_EDIPARTY, lib.GEN_IPADD, lib.GEN_RID):
                    warnings.warn("Unknown general type %d" % _type,
                                  RuntimeWarning)
                    continue
                lib.BIO_reset(biobuf)
                lib.GENERAL_NAME_print(biobuf, name)
                v = _bio_get_str(biobuf)
                idx = v.find(":")
                if idx == -1:
                    raise ValueError("Invalid value %s", v)
                peer_alt_names.append((v[:idx], v[idx + 1:]))

        free_func_addr = ffi.addressof(lib, "GENERAL_NAME_free")
        lib.sk_GENERAL_NAME_pop_free(names, free_func_addr)
    lib.BIO_free(biobuf)
    if peer_alt_names is not None:
        return tuple(peer_alt_names)
    return peer_alt_names
Пример #8
0
def _decode_certificate(certificate):
    retval = {}

    peer = _create_tuple_for_X509_NAME(lib.X509_get_subject_name(certificate))
    if not peer:
        return None
    retval["subject"] = peer

    issuer = _create_tuple_for_X509_NAME(lib.X509_get_issuer_name(certificate))
    if not issuer:
        return None
    retval["issuer"] = issuer

    version = lib.X509_get_version(certificate) + 1
    if version == 0:
        return None
    retval["version"] = version

    try:
        biobuf = lib.BIO_new(lib.BIO_s_mem())

        lib.BIO_reset(biobuf)
        serialNumber = lib.X509_get_serialNumber(certificate)
        # should not exceed 20 octets, 160 bits, so buf is big enough
        lib.i2a_ASN1_INTEGER(biobuf, serialNumber)
        buf = ffi.new("char[]", 2048)
        length = lib.BIO_gets(biobuf, buf, len(buf) - 1)
        if length < 0:
            raise ssl_error(None)
        retval["serialNumber"] = _str_with_len(buf, length)

        lib.BIO_reset(biobuf)
        notBefore = lib.X509_get_notBefore(certificate)
        lib.ASN1_TIME_print(biobuf, notBefore)
        length = lib.BIO_gets(biobuf, buf,
                              len(buf) - 1)
        if length < 0:
            raise ssl_error(None)
        retval["notBefore"] = _str_with_len(buf, length)

        lib.BIO_reset(biobuf)
        notAfter = lib.X509_get_notAfter(certificate)
        lib.ASN1_TIME_print(biobuf, notAfter)
        length = lib.BIO_gets(biobuf, buf,
                              len(buf) - 1)
        if length < 0:
            raise ssl_error(None)
        retval["notAfter"] = _str_with_len(buf, length)

        # Now look for subjectAltName
        peer_alt_names = _get_peer_alt_names(certificate)
        if peer_alt_names is None:
            return None
        if len(peer_alt_names) > 0:
            retval["subjectAltName"] = peer_alt_names

        # Authority Information Access: OCSP URIs
        obj = _get_aia_uri(certificate, lib.NID_ad_OCSP)
        if obj:
            retval["OCSP"] = obj

        obj = _get_aia_uri(certificate, lib.NID_ad_ca_issuers)
        if obj:
            retval["caIssuers"] = obj

        # CDP (CRL distribution points)
        obj = _get_crl_dp(certificate)
        if obj:
            retval["crlDistributionPoints"] = obj
    finally:
        lib.BIO_free(biobuf)

    return retval
Пример #9
0
        # now add this attribute to the current RDN
        name = lib.X509_NAME_ENTRY_get_object(entry)
        value = lib.X509_NAME_ENTRY_get_data(entry)
        attr = _create_tuple_for_attribute(name, value)
        if attr == ffi.NULL:
            raise NotImplementedError
        rdn.append(attr)

    # now, there's typically a dangling RDN
    if rdn and len(rdn) > 0:
        dn.append(tuple(rdn))

    return tuple(dn)


STATIC_BIO_BUF = ffi.new("char[]", 2048)


def _bio_get_str(biobuf):
    length = lib.BIO_gets(biobuf, STATIC_BIO_BUF, len(STATIC_BIO_BUF) - 1)
    if length < 0:
        if biobuf: lib.BIO_free(biobuf)
        raise ssl_error(None)
    return _str_with_len(STATIC_BIO_BUF, length)


def _decode_certificate(certificate):
    retval = {}

    peer = _create_tuple_for_X509_NAME(lib.X509_get_subject_name(certificate))
    if not peer: