Example #1
0
ssize_t calculate_signature_space(pesign_context *ctx)
{
	int rc;

	SECItem sig = { 0, };

	rc = generate_spc_signed_data(&sig, &ctx->cms_ctx);
	if (rc < 0) {
err:
		fprintf(stderr, "Could not generate signature.\n");
		exit(1);
	}

	data_directory *dd = NULL;
	rc = pe_getdatadir(ctx->outpe, &dd);
	if (rc < 0)
		goto err;

	ssize_t ret = sig.len + dd->certs.size + sizeof(win_certificate) -
						available_cert_space(ctx);

	//free(sig.data);

	return ret;
}
Example #2
0
int
cert_iter_init(cert_iter *iter, Pe *pe)
{
	iter->pe = pe;
	iter->n = 0;
	iter->certs = 0;
	iter->size = -1;

	data_directory *dd;

	int rc = pe_getdatadir(pe, &dd);
	if (rc < 0)
		return -1;

	void *map;
	size_t map_size;

	map = pe_rawfile(pe, &map_size);
	if (!map)
		return -1;

	iter->certs = map + dd->certs.virtual_address;
	if (dd->certs.virtual_address) {
		iter->size = dd->certs.size;
	}

	return rc;
}
Example #3
0
int
pe_populatecert(Pe *pe, void *cert, size_t size)
{
	int rc;
	data_directory *dd = NULL;
	rc = pe_getdatadir(pe, &dd);
	if (rc < 0)
		return rc;

	if (size != dd->certs.size)
		return -1;

	void *mem = compute_mem_addr(pe, dd->certs.virtual_address);
	if (!mem)
		return -1;

	memcpy(mem, cert, size);

	uint64_t max_size = pe->maximum_size;
	uint32_t new_space;
	uint32_t page_size = sysconf(_SC_PAGESIZE);

	pe_extend_file(pe, 0, &new_space, page_size);
	uint64_t new_max_size = pe->maximum_size;
	mem = compute_mem_addr(pe, 0);
	msync(mem, new_max_size, MS_SYNC);
	new_max_size -= max_size;
	pe_shorten_file(pe, new_max_size);

	return 0;
}
Example #4
0
ssize_t
available_cert_space(pesign_context *ctx)
{
	cert_iter iter;
	int rc = cert_iter_init(&iter, ctx->outpe);
	if (rc < 0)
		return -1;

	data_directory *dd;

	rc = pe_getdatadir(ctx->outpe, &dd);
	if (rc < 0)
		return -1;

	ssize_t totalsize = dd->certs.size;
	ssize_t foundsize = 0;

	void *data;
	ssize_t datalen;

	while (1) {
		rc = next_cert(&iter, &data, &datalen);
		if (rc <= 0)
			break;
		foundsize += datalen;
	}

	return totalsize - foundsize;
}
Example #5
0
int
pe_alloccert(Pe *pe, size_t size)
{
	int rc;
	data_directory *dd = NULL;

	pe_clearcert(pe);

	uint32_t new_space = 0;
	rc = pe_extend_file(pe, size, &new_space, 8);
	if (rc < 0)
		return rc;

	rc = pe_getdatadir(pe, &dd);
	if (rc < 0)
		return rc;

	void *addr = compute_mem_addr(pe, new_space);
	/* We leave the whole list empty until finalize...*/
	memset(addr, '\0', size);

	dd->certs.virtual_address = compute_file_addr(pe, addr);
	dd->certs.size += size;

	return 0;
}
Example #6
0
off_t
__pe_updatemmap(Pe *pe, size_t shnum __attribute__((__unused__)))
{
	/* This needs to write back the whole file:
	 * 1) mz/pe/pe-o headers
	 * 2) section headers and sections
	 * 3) data directory table and data directories
	 *
	 * We also need to check if the signature is valid and if not,
	 * make sure it's not in the data directory.
	 */

	struct mz_hdr *mzhdr = pe->state.pe.mzhdr;
	struct pe_hdr *pehdr = pe->state.pe.pehdr;

	if (pe->flags & PE_F_DIRTY) {
		off_t offset = 0;
		memcpy(pe->map_address + offset, mzhdr, sizeof(*mzhdr));

		offset += le32_to_cpu(mzhdr->peaddr);
		memcpy(pe->map_address + offset, pehdr, sizeof(*pehdr));
	}

	/* it's not dirty any more, so clear the flag. */
	pe->flags &= ~PE_F_DIRTY;

	/* flush back to disk */
	char *msync_start = ((char *) pe->map_address
		+ (~(sysconf(_SC_PAGESIZE) -1 )));

	data_directory *dd = NULL;
	int rc = pe_getdatadir(pe, &dd);
	if (rc < 0) {
		/* XXX set an error here */
		return -1;
	}

	char *msync_end = (char *)dd + sizeof(*dd);
	msync(msync_start, msync_end - msync_start, MS_SYNC);

	#warning this is not done yet.
	//struct section_header *sh = __get_last_section(pe);

	size_t dd_size = sizeof (*dd) / sizeof (dd->exports);
	data_dirent *dde = &dd->exports;
	for (unsigned int i = 0; i < dd_size; i++, dde++) {
		if (dde->size != 0) {
			char *addr = compute_mem_addr(pe, dde->virtual_address);
			msync(addr, dde->size, MS_SYNC);
		}
	}

	return 0;
}
Example #7
0
int
pe_clearcert(Pe *pe)
{
	int rc;
	data_directory *dd = NULL;

	rc = pe_getdatadir(pe, &dd);
	if (rc < 0)
		return rc;

	if (dd->certs.virtual_address != 0) {
		pe_freespace(pe, dd->certs.virtual_address, dd->certs.size);
		memset(&dd->certs, '\0', sizeof (dd->certs));
	}

	return 0;
}
Example #8
0
int
pe_populatecert(Pe *pe, void *cert, size_t size)
{
	int rc;
	data_directory *dd = NULL;
	rc = pe_getdatadir(pe, &dd);
	if (rc < 0)
		return rc;

	if (size != dd->certs.size)
		return -1;

	void *addr = compute_mem_addr(pe, dd->certs.virtual_address);
	if (!addr)
		return -1;

	memcpy(addr, cert, size);
	msync(addr, size, MS_SYNC);

	return 0;
}
Example #9
0
int
generate_digest(pesign_context *ctx, Pe *pe)
{
	void *hash_base;
	size_t hash_size;
	struct pe32_opt_hdr *pe32opthdr = NULL;
	struct pe32plus_opt_hdr *pe64opthdr = NULL;
	PK11Context *pk11ctx;
	unsigned long hashed_bytes = 0;
	int rc = -1;

	if (!pe) {
		fprintf(stderr, "pesign: no output pe ready\n");
		exit(1);
	}

	struct pe_hdr pehdr;
	if (pe_getpehdr(pe, &pehdr) == NULL) {
		fprintf(stderr, "pesign: invalid output file header\n");
		exit(1);
	}

	void *map = NULL;
	size_t map_size = 0;

	/* 1. Load the image header into memory - should be done
	 * 2. Initialize SHA hash context. */
	map = pe_rawfile(pe, &map_size);
	if (!map) {
		fprintf(stderr, "pesign: could not get raw output file address\n");
		exit(1);
	}

	pk11ctx = PK11_CreateDigestContext(ctx->cms_ctx.digest_oid_tag);
	if (!pk11ctx) {
		fprintf(stderr, "pesign: could not initialize digest\n");
		exit(1);
	}
	PK11_DigestBegin(pk11ctx);

	/* 3. Calculate the distance from the base of the image header to the
	 * image checksum.
	 * 4. Hash the image header from start to the beginning of the
	 * checksum. */
	hash_base = map;
	switch (pe_kind(pe)) {
	case PE_K_PE_EXE: {
		void *opthdr = pe_getopthdr(pe);
		pe32opthdr = opthdr;
		hash_size = (uintptr_t)&pe32opthdr->csum - (uintptr_t)hash_base;
		break;
	}
	case PE_K_PE64_EXE: {
		void *opthdr = pe_getopthdr(pe);
		pe64opthdr = opthdr;
		hash_size = (uintptr_t)&pe64opthdr->csum - (uintptr_t)hash_base;
		break;
	}
	default:
		goto error;
	}
	PK11_DigestOp(pk11ctx, hash_base, hash_size);

	/* 5. Skip over the image checksum
	 * 6. Get the address of the beginning of the cert dir entry
	 * 7. Hash from the end of the csum to the start of the cert dirent. */
	hash_base += hash_size;
	hash_base += pe32opthdr ? sizeof(pe32opthdr->csum)
				: sizeof(pe64opthdr->csum);
	data_directory *dd;

	rc = pe_getdatadir(pe, &dd);
	if (rc < 0 || !dd)
		goto error;

	hash_size = (uintptr_t)&dd->certs - (uintptr_t)hash_base;
	PK11_DigestOp(pk11ctx, hash_base, hash_size);

	/* 8. Skip over the crt dir
	 * 9. Hash everything up to the end of the image header. */
	hash_base = &dd->base_relocations;
	hash_size = (pe32opthdr ? pe32opthdr->header_size
				: pe64opthdr->header_size) -
		((uintptr_t)&dd->base_relocations - (uintptr_t)map);
	PK11_DigestOp(pk11ctx, hash_base, hash_size);

	/* 10. Set SUM_OF_BYTES_HASHED to the size of the header. */
	hashed_bytes = pe32opthdr ? pe32opthdr->header_size
				: pe64opthdr->header_size;

	struct section_header *shdrs = calloc(pehdr.sections, sizeof (*shdrs));
	if (!shdrs)
		goto error;
	Pe_Scn *scn = NULL;
	for (int i = 0; i < pehdr.sections; i++) {
		scn = pe_nextscn(pe, scn);
		if (scn == NULL)
			break;
		pe_getshdr(scn, &shdrs[i]);
	}
	sort_shdrs(shdrs, pehdr.sections - 1);

	for (int i = 0; i < pehdr.sections; i++) {
		hash_base = (void *)((uintptr_t)map + shdrs[i].data_addr);
		hash_size = shdrs[i].raw_data_size;
		PK11_DigestOp(pk11ctx, hash_base, hash_size);

		hashed_bytes += hash_size;
	}

	if (map_size > hashed_bytes) {
		hash_base = (void *)((uintptr_t)map + hashed_bytes);
		hash_size = map_size - dd->certs.size - hashed_bytes;
		PK11_DigestOp(pk11ctx, hash_base, hash_size);
	}

	SECItem *digest = PORT_ArenaZAlloc(ctx->cms_ctx.arena,
					sizeof (SECItem));
	if (!digest)
		goto error_shdrs;

	digest->type = siBuffer;
	digest->data = PORT_ArenaZAlloc(ctx->cms_ctx.arena,
						ctx->cms_ctx.digest_size);
	digest->len = ctx->cms_ctx.digest_size;
	if (!digest->data)
		goto error_digest;

	PK11_DigestFinal(pk11ctx, digest->data, &digest->len,
						ctx->cms_ctx.digest_size);
	ctx->cms_ctx.pe_digest = digest;

	if (shdrs)
		free(shdrs);
	PK11_DestroyContext(pk11ctx, PR_TRUE);

	return 0;

error_digest:
	PORT_Free(digest->data);
error_shdrs:
	if (shdrs)
		free(shdrs);
error:
	PK11_DestroyContext(pk11ctx, PR_TRUE);
	fprintf(stderr, "pesign: could not digest file.\n");
	exit(1);
}