Example #1
0
retvalue signature_check(const struct signature_requirement *requirements, const char *releasegpg, const char *releasename, const char *releasedata, size_t releaselen) {
	gpg_error_t err;
	int gpgfd;
	gpgme_data_t dh, dh_gpg;

	assert (requirements != NULL);

	if (FAILEDTOALLOC(releasedata) || FAILEDTOALLOC(releasegpg))
		return RET_ERROR_OOM;

	assert (context != NULL);

	/* Read the file and its signature into memory: */
	gpgfd = open(releasegpg, O_RDONLY|O_NOCTTY);
	if (gpgfd < 0) {
		int e = errno;
		fprintf(stderr, "Error opening '%s': %s\n",
				releasegpg, strerror(e));
		return RET_ERRNO(e);
	}
	err = gpgme_data_new_from_fd(&dh_gpg, gpgfd);
	if (err != 0) {
		(void)close(gpgfd);
		fprintf(stderr, "Error reading '%s':\n", releasegpg);
		return gpgerror(err);
	}
	err = gpgme_data_new_from_mem(&dh, releasedata, releaselen, 0);
	if (err != 0) {
		gpgme_data_release(dh_gpg);
		return gpgerror(err);
	}

	/* Verify the signature */

	err = gpgme_op_verify(context, dh_gpg, dh, NULL);
	gpgme_data_release(dh_gpg);
	gpgme_data_release(dh);
	close(gpgfd);
	if (err != 0) {
		fprintf(stderr, "Error verifying '%s':\n", releasegpg);
		return gpgerror(err);
	}

	return verify_signature(requirements, releasegpg, releasename);
}
Example #2
0
retvalue signature_init(bool allowpassphrase){
#ifdef HAVE_LIBGPGME
	gpg_error_t err;

	if (context != NULL)
		return RET_NOTHING;
	gpgme_check_version(NULL);
	err = gpgme_engine_check_version(GPGME_PROTOCOL_OpenPGP);
	if (err != 0)
		return gpgerror(err);
	err = gpgme_new(&context);
	if (err != 0)
		return gpgerror(err);
	err = gpgme_set_protocol(context, GPGME_PROTOCOL_OpenPGP);
	if (err != 0)
		return gpgerror(err);
	if (allowpassphrase)
		gpgme_set_passphrase_cb(context, signature_getpassphrase,
				NULL);
	gpgme_set_armor(context, 1);
#endif /* HAVE_LIBGPGME */
	return RET_OK;
}
Example #3
0
retvalue signature_check(const struct signature_requirement *requirements, const char *releasegpg, const char *release) {
	gpg_error_t err;
	int fd, gpgfd;
	gpgme_data_t dh, dh_gpg;
	gpgme_verify_result_t result;
	int i;
	const struct signature_requirement *req;

	assert (requirements != NULL);

	if (FAILEDTOALLOC(release) || FAILEDTOALLOC(releasegpg))
		return RET_ERROR_OOM;

	assert (context != NULL);

	/* Read the file and its signature into memory: */
	gpgfd = open(releasegpg, O_RDONLY|O_NOCTTY);
	if (gpgfd < 0) {
		int e = errno;
		fprintf(stderr, "Error opening '%s': %s\n",
				releasegpg, strerror(e));
		return RET_ERRNO(e);
	}
	fd = open(release, O_RDONLY|O_NOCTTY);
	if (fd < 0) {
		int e = errno;
		(void)close(gpgfd);
		fprintf(stderr, "Error opening '%s': %s\n",
			       release, strerror(e));
		return RET_ERRNO(e);
	}
	err = gpgme_data_new_from_fd(&dh_gpg, gpgfd);
	if (err != 0) {
		(void)close(gpgfd); (void)close(fd);
		fprintf(stderr, "Error reading '%s':\n", releasegpg);
		return gpgerror(err);
	}
	err = gpgme_data_new_from_fd(&dh, fd);
	if (err != 0) {
		gpgme_data_release(dh_gpg);
		(void)close(gpgfd); (void)close(fd);
		fprintf(stderr, "Error reading '%s':\n", release);
		return gpgerror(err);
	}

	/* Verify the signature */

	err = gpgme_op_verify(context, dh_gpg, dh, NULL);
	gpgme_data_release(dh_gpg);
	gpgme_data_release(dh);
	close(gpgfd); close(fd);
	if (err != 0) {
		fprintf(stderr, "Error verifying '%s':\n", releasegpg);
		return gpgerror(err);
	}

	result = gpgme_op_verify_result(context);
	if (result == NULL) {
		fprintf(stderr,
"Internal error communicating with libgpgme: no result record!\n\n");
		return RET_ERROR_GPGME;
	}

	for (req = requirements ; req != NULL ; req = req->next) {
		bool fullfilled = false;

		/* check first for good signatures, and then for good enough
		   signatures, to not pester the user with warnings of one
		   of the alternate keys, if the last one is good enough */

		for (i = 0 ; (size_t)i < req->num_keys ; i++) {

			if (key_good(&req->keys[i], result->signatures)) {
				fullfilled = true;
				break;
			}
		}
		for (i = 0 ; !fullfilled && (size_t)i < req->num_keys ; i++) {

			if (key_good_enough(&req->keys[i], result->signatures,
						releasegpg, release)) {
				fullfilled = true;
				break;
			}
		}
		if (!fullfilled) {
			fprintf(stderr,
"ERROR: Condition '%s' not fullfilled for '%s'.\n",
					req->condition, releasegpg);
			print_signatures(stderr, result->signatures,
					releasegpg);
			return RET_ERROR_BADSIG;
		}
		if (verbose > 10) {
			fprintf(stdout, "Condition '%s' fullfilled for '%s'.\n",
					req->condition, releasegpg);
		}
	}
	if (verbose > 20)
		print_signatures(stdout, result->signatures, releasegpg);
	return RET_OK;
}
Example #4
0
retvalue signature_check_inline(const struct signature_requirement *requirements, const char *filename, char **chunk_p) {
	gpg_error_t err;
	gpgme_data_t dh, dh_gpg;
	int fd;

	fd = open(filename, O_RDONLY|O_NOCTTY);
	if (fd < 0) {
		int e = errno;
		fprintf(stderr, "Error opening '%s': %s\n",
				filename, strerror(e));
		return RET_ERRNO(e);
	}
	err = gpgme_data_new_from_fd(&dh_gpg, fd);
	if (err != 0) {
		(void)close(fd);
		return gpgerror(err);
	}

	err = gpgme_data_new(&dh);
	if (err != 0) {
		(void)close(fd);
		gpgme_data_release(dh_gpg);
		return gpgerror(err);
	}
	err = gpgme_op_verify(context, dh_gpg, NULL, dh);
	(void)close(fd);
	if (gpg_err_code(err) == GPG_ERR_NO_DATA) {
		char *chunk; const char *n;
		size_t len;
		retvalue r;

		gpgme_data_release(dh);
		gpgme_data_release(dh_gpg);

		r = readtextfile(filename, filename, &chunk, &len);
		assert (r != RET_NOTHING);
		if (RET_WAS_ERROR(r))
			return r;

		assert (chunk[len] == '\0');
		len = chunk_extract(chunk, chunk, len, false, &n);
		if (chunk[0] == '-' || *n != '\0') {
			fprintf(stderr,
"Cannot parse '%s': found no signature but does not looks safe to be assumed unsigned, either.\n",
				filename);
			free(chunk);
			return RET_ERROR;
		}
		if (requirements != NULL) {
			free(chunk);
			return RET_ERROR_BADSIG;
		}
		fprintf(stderr,
"WARNING: No signature found in %s, assuming it is unsigned!\n",
				filename);
		assert (chunk[len] == '\0');
		*chunk_p = realloc(chunk, len+1);
		if (FAILEDTOALLOC(*chunk_p))
			*chunk_p = chunk;
		return RET_OK;
	} else {
		char *plain_data, *chunk;
		const char *n;
		size_t plain_len, len;
		retvalue r;

		if (err != 0) {
			gpgme_data_release(dh_gpg);
			gpgme_data_release(dh);
			return gpgerror(err);
		}
		gpgme_data_release(dh_gpg);
		plain_data = gpgme_data_release_and_get_mem(dh, &plain_len);
		if (plain_data == NULL) {
			fprintf(stderr,
"Error: libgpgme failed to extract the plain data out of\n"
"'%s'.\n"
"While it did so in a way indicating running out of memory, experience says\n"
"this also happens when gpg returns a error code it does not understand.\n"
"To check this please try running gpg --verify '%s' manually.\n"
"Continuing extracting it ignoring all signatures...",
					filename, filename);
			return RET_ERROR;
		}
		chunk = malloc(plain_len+1);
		if (FAILEDTOALLOC(chunk))
			return RET_ERROR_OOM;
		len = chunk_extract(chunk, plain_data, plain_len, false, &n);
#ifdef HAVE_GPGPME_FREE
		gpgme_free(plain_data);
#else
		free(plain_data);
#endif
		assert (len <= plain_len);
		if (plain_len != (size_t)(n - plain_data)) {
			fprintf(stderr,
"Cannot parse '%s': extraced signed data looks malformed.\n",
				filename);
			r = RET_ERROR;
		} else
			r = verify_signature(requirements, filename, NULL);
		if (RET_IS_OK(r)) {
			*chunk_p = realloc(chunk, len+1);
			if (FAILEDTOALLOC(*chunk_p))
				*chunk_p = chunk;
		} else
			free(chunk);
		return r;
	}
}
Example #5
0
static retvalue extract_signed_data(const char *buffer, size_t bufferlen, const char *filenametoshow, char **chunkread, /*@null@*/ /*@out@*/struct signatures **signatures_p, bool *brokensignature) {
	char *chunk;
	gpg_error_t err;
	gpgme_data_t dh, dh_gpg;
	size_t plain_len;
	char *plain_data;
	retvalue r;
	struct signatures *signatures = NULL;
	bool foundbroken = false;

	r = signature_init(false);
	if (RET_WAS_ERROR(r))
		return r;

	err = gpgme_data_new_from_mem(&dh_gpg, buffer, bufferlen, 0);
	if (err != 0)
		return gpgerror(err);

	err = gpgme_data_new(&dh);
	if (err != 0) {
		gpgme_data_release(dh_gpg);
		return gpgerror(err);
	}
	err = gpgme_op_verify(context, dh_gpg, NULL, dh);
	if (gpg_err_code(err) == GPG_ERR_NO_DATA) {
		if (verbose > 5)
			fprintf(stderr,
"Data seems not to be signed trying to use directly....\n");
		gpgme_data_release(dh);
		gpgme_data_release(dh_gpg);
		return RET_NOTHING;
	} else {
		if (err != 0) {
			gpgme_data_release(dh_gpg);
			gpgme_data_release(dh);
			return gpgerror(err);
		}
		if (signatures_p != NULL || brokensignature != NULL) {
			r = checksigs(filenametoshow,
				(signatures_p!=NULL)?&signatures:NULL,
				(brokensignature!=NULL)?&foundbroken:NULL);
			if (RET_WAS_ERROR(r)) {
				gpgme_data_release(dh_gpg);
				gpgme_data_release(dh);
				return r;
			}
		}
		gpgme_data_release(dh_gpg);
		plain_data = gpgme_data_release_and_get_mem(dh, &plain_len);
		if (plain_data == NULL) {
			fprintf(stderr,
"(not yet fatal) ERROR: libgpgme failed to extract the plain data out of\n"
"'%s'.\n"
"While it did so in a way indicating running out of memory, experience says\n"
"this also happens when gpg returns a error code it does not understand.\n"
"To check this please try running gpg --verify '%s' manually.\n"
"Continuing extracting it ignoring all signatures...",
					filenametoshow, filenametoshow);
			signatures_free(signatures);
			return RET_NOTHING;
		}
		if (signatures != NULL) {
			r = check_primary_keys(signatures);
			if (RET_WAS_ERROR(r)) {
				signatures_free(signatures);
				return r;
			}
		}
	}

	if (FAILEDTOALLOC(plain_data))
		r = RET_ERROR_OOM;
	else {
		size_t len;
		const char *afterchanges;

		chunk = malloc(plain_len + 1);
		len = chunk_extract(chunk, plain_data, plain_len, false,
				&afterchanges);
		if (len == 0) {
			fprintf(stderr,
"Could only find spaces within '%s'!\n",
					filenametoshow);
			free(chunk);
			r = RET_ERROR;
		} else if (afterchanges != plain_data + plain_len) {
			if (*afterchanges == '\0')
				fprintf(stderr,
"Unexpected \\0 character within '%s'!\n",
					filenametoshow);
			else
				fprintf(stderr,
"Unexpected data after ending empty line in '%s'!\n",
					filenametoshow);
			free(chunk);
			r = RET_ERROR;
		} else
			*chunkread = chunk;
	}
#ifdef HAVE_GPGPME_FREE
	gpgme_free(plain_data);
#else
	free(plain_data);
#endif
	if (RET_IS_OK(r)) {
		if (signatures_p != NULL)
			*signatures_p = signatures;
		if (brokensignature != NULL)
			*brokensignature = foundbroken;
	} else {
		signatures_free(signatures);
	}
	return r;
}