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)
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])
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
def _string_from_asn1(asn1): data = lib.ASN1_STRING_data(asn1) length = lib.ASN1_STRING_length(asn1) return _str_with_len(ffi.cast("char*", data), length)
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