verify-commit: scriptable commit signature verification
Commit signatures can be verified using "git show -s --show-signature" or the "%G?" pretty format and parsing the output, which is well suited for user inspection, but not for scripting. Provide a command "verify-commit" which is analogous to "verify-tag": It returns 0 for good signatures and non-zero otherwise, has the gpg output on stderr and (optionally) the commit object on stdout, sans the signature, just like "verify-tag" does. Signed-off-by: Michael J Gruber <git@drmicha.warpmail.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>maint
							parent
							
								
									71c214c840
								
							
						
					
					
						commit
						d07b00b7f3
					
				|  | @ -0,0 +1,28 @@ | ||||||
|  | git-verify-commit(1) | ||||||
|  | ==================== | ||||||
|  |  | ||||||
|  | NAME | ||||||
|  | ---- | ||||||
|  | git-verify-commit - Check the GPG signature of commits | ||||||
|  |  | ||||||
|  | SYNOPSIS | ||||||
|  | -------- | ||||||
|  | [verse] | ||||||
|  | 'git verify-commit' <commit>... | ||||||
|  |  | ||||||
|  | DESCRIPTION | ||||||
|  | ----------- | ||||||
|  | Validates the gpg signature created by 'git commit -S'. | ||||||
|  |  | ||||||
|  | OPTIONS | ||||||
|  | ------- | ||||||
|  | -v:: | ||||||
|  | --verbose:: | ||||||
|  | 	Print the contents of the commit object before validating it. | ||||||
|  |  | ||||||
|  | <commit>...:: | ||||||
|  | 	SHA-1 identifiers of Git commit objects. | ||||||
|  |  | ||||||
|  | GIT | ||||||
|  | --- | ||||||
|  | Part of the linkgit:git[1] suite | ||||||
							
								
								
									
										1
									
								
								Makefile
								
								
								
								
							
							
						
						
									
										1
									
								
								Makefile
								
								
								
								
							|  | @ -999,6 +999,7 @@ BUILTIN_OBJS += builtin/update-ref.o | ||||||
| BUILTIN_OBJS += builtin/update-server-info.o | BUILTIN_OBJS += builtin/update-server-info.o | ||||||
| BUILTIN_OBJS += builtin/upload-archive.o | BUILTIN_OBJS += builtin/upload-archive.o | ||||||
| BUILTIN_OBJS += builtin/var.o | BUILTIN_OBJS += builtin/var.o | ||||||
|  | BUILTIN_OBJS += builtin/verify-commit.o | ||||||
| BUILTIN_OBJS += builtin/verify-pack.o | BUILTIN_OBJS += builtin/verify-pack.o | ||||||
| BUILTIN_OBJS += builtin/verify-tag.o | BUILTIN_OBJS += builtin/verify-tag.o | ||||||
| BUILTIN_OBJS += builtin/write-tree.o | BUILTIN_OBJS += builtin/write-tree.o | ||||||
|  |  | ||||||
|  | @ -128,6 +128,7 @@ extern int cmd_update_server_info(int argc, const char **argv, const char *prefi | ||||||
| extern int cmd_upload_archive(int argc, const char **argv, const char *prefix); | extern int cmd_upload_archive(int argc, const char **argv, const char *prefix); | ||||||
| extern int cmd_upload_archive_writer(int argc, const char **argv, const char *prefix); | extern int cmd_upload_archive_writer(int argc, const char **argv, const char *prefix); | ||||||
| extern int cmd_var(int argc, const char **argv, const char *prefix); | extern int cmd_var(int argc, const char **argv, const char *prefix); | ||||||
|  | extern int cmd_verify_commit(int argc, const char **argv, const char *prefix); | ||||||
| extern int cmd_verify_tag(int argc, const char **argv, const char *prefix); | extern int cmd_verify_tag(int argc, const char **argv, const char *prefix); | ||||||
| extern int cmd_version(int argc, const char **argv, const char *prefix); | extern int cmd_version(int argc, const char **argv, const char *prefix); | ||||||
| extern int cmd_whatchanged(int argc, const char **argv, const char *prefix); | extern int cmd_whatchanged(int argc, const char **argv, const char *prefix); | ||||||
|  |  | ||||||
|  | @ -0,0 +1,93 @@ | ||||||
|  | /* | ||||||
|  |  * Builtin "git commit-commit" | ||||||
|  |  * | ||||||
|  |  * Copyright (c) 2014 Michael J Gruber <git@drmicha.warpmail.net> | ||||||
|  |  * | ||||||
|  |  * Based on git-verify-tag | ||||||
|  |  */ | ||||||
|  | #include "cache.h" | ||||||
|  | #include "builtin.h" | ||||||
|  | #include "commit.h" | ||||||
|  | #include "run-command.h" | ||||||
|  | #include <signal.h> | ||||||
|  | #include "parse-options.h" | ||||||
|  | #include "gpg-interface.h" | ||||||
|  |  | ||||||
|  | static const char * const verify_commit_usage[] = { | ||||||
|  | 		N_("git verify-commit [-v|--verbose] <commit>..."), | ||||||
|  | 		NULL | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | static int run_gpg_verify(const unsigned char *sha1, const char *buf, unsigned long size, int verbose) | ||||||
|  | { | ||||||
|  | 	struct signature_check signature_check; | ||||||
|  |  | ||||||
|  | 	memset(&signature_check, 0, sizeof(signature_check)); | ||||||
|  |  | ||||||
|  | 	check_commit_signature(lookup_commit(sha1), &signature_check); | ||||||
|  |  | ||||||
|  | 	if (verbose && signature_check.payload) | ||||||
|  | 		fputs(signature_check.payload, stdout); | ||||||
|  |  | ||||||
|  | 	if (signature_check.gpg_output) | ||||||
|  | 		fputs(signature_check.gpg_output, stderr); | ||||||
|  |  | ||||||
|  | 	signature_check_clear(&signature_check); | ||||||
|  | 	return signature_check.result != 'G'; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static int verify_commit(const char *name, int verbose) | ||||||
|  | { | ||||||
|  | 	enum object_type type; | ||||||
|  | 	unsigned char sha1[20]; | ||||||
|  | 	char *buf; | ||||||
|  | 	unsigned long size; | ||||||
|  | 	int ret; | ||||||
|  |  | ||||||
|  | 	if (get_sha1(name, sha1)) | ||||||
|  | 		return error("commit '%s' not found.", name); | ||||||
|  |  | ||||||
|  | 	buf = read_sha1_file(sha1, &type, &size); | ||||||
|  | 	if (!buf) | ||||||
|  | 		return error("%s: unable to read file.", name); | ||||||
|  | 	if (type != OBJ_COMMIT) | ||||||
|  | 		return error("%s: cannot verify a non-commit object of type %s.", | ||||||
|  | 				name, typename(type)); | ||||||
|  |  | ||||||
|  | 	ret = run_gpg_verify(sha1, buf, size, verbose); | ||||||
|  |  | ||||||
|  | 	free(buf); | ||||||
|  | 	return ret; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static int git_verify_commit_config(const char *var, const char *value, void *cb) | ||||||
|  | { | ||||||
|  | 	int status = git_gpg_config(var, value, cb); | ||||||
|  | 	if (status) | ||||||
|  | 		return status; | ||||||
|  | 	return git_default_config(var, value, cb); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int cmd_verify_commit(int argc, const char **argv, const char *prefix) | ||||||
|  | { | ||||||
|  | 	int i = 1, verbose = 0, had_error = 0; | ||||||
|  | 	const struct option verify_commit_options[] = { | ||||||
|  | 		OPT__VERBOSE(&verbose, N_("print commit contents")), | ||||||
|  | 		OPT_END() | ||||||
|  | 	}; | ||||||
|  |  | ||||||
|  | 	git_config(git_verify_commit_config, NULL); | ||||||
|  |  | ||||||
|  | 	argc = parse_options(argc, argv, prefix, verify_commit_options, | ||||||
|  | 			     verify_commit_usage, PARSE_OPT_KEEP_ARGV0); | ||||||
|  | 	if (argc <= i) | ||||||
|  | 		usage_with_options(verify_commit_usage, verify_commit_options); | ||||||
|  |  | ||||||
|  | 	/* sometimes the program was terminated because this signal | ||||||
|  | 	 * was received in the process of writing the gpg input: */ | ||||||
|  | 	signal(SIGPIPE, SIG_IGN); | ||||||
|  | 	while (i < argc) | ||||||
|  | 		if (verify_commit(argv[i++], verbose)) | ||||||
|  | 			had_error = 1; | ||||||
|  | 	return had_error; | ||||||
|  | } | ||||||
|  | @ -132,6 +132,7 @@ git-update-server-info                  synchingrepositories | ||||||
| git-upload-archive                      synchelpers | git-upload-archive                      synchelpers | ||||||
| git-upload-pack                         synchelpers | git-upload-pack                         synchelpers | ||||||
| git-var                                 plumbinginterrogators | git-var                                 plumbinginterrogators | ||||||
|  | git-verify-commit                       ancillaryinterrogators | ||||||
| git-verify-pack                         plumbinginterrogators | git-verify-pack                         plumbinginterrogators | ||||||
| git-verify-tag                          ancillaryinterrogators | git-verify-tag                          ancillaryinterrogators | ||||||
| gitweb                                  ancillaryinterrogators | gitweb                                  ancillaryinterrogators | ||||||
|  |  | ||||||
							
								
								
									
										1
									
								
								git.c
								
								
								
								
							
							
						
						
									
										1
									
								
								git.c
								
								
								
								
							|  | @ -441,6 +441,7 @@ static struct cmd_struct commands[] = { | ||||||
| 	{ "upload-archive", cmd_upload_archive }, | 	{ "upload-archive", cmd_upload_archive }, | ||||||
| 	{ "upload-archive--writer", cmd_upload_archive_writer }, | 	{ "upload-archive--writer", cmd_upload_archive_writer }, | ||||||
| 	{ "var", cmd_var, RUN_SETUP_GENTLY }, | 	{ "var", cmd_var, RUN_SETUP_GENTLY }, | ||||||
|  | 	{ "verify-commit", cmd_verify_commit, RUN_SETUP }, | ||||||
| 	{ "verify-pack", cmd_verify_pack }, | 	{ "verify-pack", cmd_verify_pack }, | ||||||
| 	{ "verify-tag", cmd_verify_tag, RUN_SETUP }, | 	{ "verify-tag", cmd_verify_tag, RUN_SETUP }, | ||||||
| 	{ "version", cmd_version }, | 	{ "version", cmd_version }, | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue
	
	 Michael J Gruber
						Michael J Gruber