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 _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)
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)
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 _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)
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
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
# 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: