static int bin_pe_init_security(RBinPEObj *pe) {
	if (!pe || !pe->nt_headers) {
		return false;
	}
	if (pe->nt_headers->optional_header.NumberOfRvaAndSizes < 5) {
		return false;
	}
	PE_(image_data_directory) *data_dir_security = &pe->data_directory[PE_IMAGE_DIRECTORY_ENTRY_SECURITY];
	PE_DWord paddr = data_dir_security->VirtualAddress;
	ut32 size = data_dir_security->Size;
	if (size < 8 || paddr > pe->size || paddr + size > pe->size) {
		pe_printf ("Invalid certificate table");
		return false;
	}

	Pe_image_security_directory *security_directory = R_NEW0 (Pe_image_security_directory);
	if (!security_directory) {
		return false;
	}
	pe->security_directory = security_directory;

	PE_DWord offset = paddr;
	while (offset < paddr + size) {
		Pe_certificate **tmp = (Pe_certificate **)realloc (security_directory->certificates, (security_directory->length + 1) * sizeof (Pe_certificate *));
		if (!tmp) {
			return false;
		}
		security_directory->certificates = tmp;
		Pe_certificate *cert = R_NEW0 (Pe_certificate);
		if (!cert) {
			return false;
		}
		cert->dwLength = r_buf_read_le32_at (pe->b, offset);
		cert->dwLength += (8 - (cert->dwLength & 7)) & 7; // align32
		if (offset + cert->dwLength > paddr + size) {
			pe_printf ("Invalid certificate entry");
			R_FREE (cert);
			return false;
		}
		cert->wRevision = r_buf_read_le16_at (pe->b, offset + 4);
		cert->wCertificateType = r_buf_read_le16_at (pe->b, offset + 6);
		if (cert->dwLength < 6) {
			eprintf ("Cert.dwLength must be > 6\n");
			R_FREE (cert);
			return false;
		}
		if (!(cert->bCertificate = malloc (cert->dwLength - 6))) {
			R_FREE (cert);
			return false;
		}
		r_buf_read_at (pe->b, offset + 8, cert->bCertificate, cert->dwLength - 6);

		if (!pe->cms && cert->wCertificateType == PE_WIN_CERT_TYPE_PKCS_SIGNED_DATA) {
			pe->cms = r_pkcs7_parse_cms (cert->bCertificate, cert->dwLength - 6);
			if (pe->cms) {
				pe->spcinfo = r_pkcs7_parse_spcinfo (pe->cms);
			}
		}

		security_directory->certificates[security_directory->length] = cert;
		security_directory->length++;
		offset += cert->dwLength;
	}

	if (pe->cms && pe->spcinfo) {
		const char *actual_authentihash = PE_(bin_pe_compute_authentihash) (pe);
		const char *claimed_authentihash = PE_(bin_pe_get_claimed_authentihash) (pe);
		if (actual_authentihash && claimed_authentihash) {
			pe->is_authhash_valid = !strcmp (actual_authentihash, claimed_authentihash);
		} else {
			pe->is_authhash_valid = false;
		}
		if (actual_authentihash) {
			free ((void *)actual_authentihash);
		}
		free ((void *)claimed_authentihash);
	}
	pe->is_signed = pe->cms != NULL;
	return true;
}
static int bin_pe_init_security(RBinPEObj *pe) {
	if (!pe || !pe->nt_headers) {
		return false;
	}
	if (pe->nt_headers->optional_header.NumberOfRvaAndSizes < 5) {
		return false;
	}
	PE_(image_data_directory) *data_dir_security = &pe->data_directory[PE_IMAGE_DIRECTORY_ENTRY_SECURITY];
	PE_DWord paddr = data_dir_security->VirtualAddress;
	ut32 size = data_dir_security->Size;
	if (size < 8 || paddr > pe->size || paddr + size > pe->size) {
		pe_printf ("Invalid certificate table");
		return false;
	}

	Pe_image_security_directory *security_directory = R_NEW0 (Pe_image_security_directory);
	if (!security_directory) {
		return false;
	}
	pe->security_directory = security_directory;

	PE_DWord offset = paddr;
	while (offset < paddr + size) {
		Pe_certificate **tmp = (Pe_certificate **)realloc (security_directory->certificates, (security_directory->length + 1) * sizeof (Pe_certificate *));
		if (!tmp) {
			return false;
		}
		security_directory->certificates = tmp;
		Pe_certificate *cert = R_NEW0 (Pe_certificate);
		if (!cert) {
			return false;
		}
		cert->dwLength = r_buf_read_le32_at (pe->b, offset);
		cert->dwLength += (8 - (cert->dwLength & 7)) & 7;  
		if (offset + cert->dwLength > paddr + size) {
			pe_printf ("Invalid certificate entry");
			R_FREE (cert);
			return false;
		}
		cert->wRevision = r_buf_read_le16_at (pe->b, offset + 4);
		cert->wCertificateType = r_buf_read_le16_at (pe->b, offset + 6);
		if (cert->dwLength < 6) {
			eprintf ("Cert.dwLength must be > 6\n");
			R_FREE (cert);
			return false;
		}
		if (!(cert->bCertificate = malloc (cert->dwLength - 6))) {
			R_FREE (cert);
			return false;
		}
		r_buf_read_at (pe->b, offset + 8, cert->bCertificate, cert->dwLength - 6);

		if (!pe->cms && cert->wCertificateType == PE_WIN_CERT_TYPE_PKCS_SIGNED_DATA) {
			pe->cms = r_pkcs7_parse_cms (cert->bCertificate, cert->dwLength - 6);
			if (pe->cms) {
				pe->spcinfo = r_pkcs7_parse_spcinfo (pe->cms);
			}
		}

		security_directory->certificates[security_directory->length] = cert;
		security_directory->length++;
		offset += cert->dwLength;
	}

	if (pe->cms && pe->spcinfo) {
		const char *actual_authentihash = PE_(bin_pe_compute_authentihash) (pe);
		const char *claimed_authentihash = PE_(bin_pe_get_claimed_authentihash) (pe);
		if (actual_authentihash && claimed_authentihash) {
			pe->is_authhash_valid = !strcmp (actual_authentihash, claimed_authentihash);
		} else {
			pe->is_authhash_valid = false;
		}
		if (actual_authentihash) {
			free ((void *)actual_authentihash);
		}
		free ((void *)claimed_authentihash);
	}
	pe->is_signed = pe->cms != NULL;
	return true;
}