threads / patch / 9162

patchMake verify-tag a builtin.

Subject: [PATCH] Make verify-tag a builtin.

## tl;dr

6 messages between Jul 23, 2007 and Jul 23, 2007. Diffs are folded; open one to read it.

replies: 5people: 2as markdown or json

Carlos Rica· Jul 23, 2007, 00:20 UTC · lore
This replaces "git-verify-tag.sh" with "builtin-verify-tag.c".

Signal SIGPIPE is ignored because the program sometimes was stopped because that signal when writing the input for gpg.

Signed-off-by: Carlos Rica <jasampler@gmail.com>
---
   Comments are welcomed.
 Makefile                                           |    3 +-
 builtin-verify-tag.c                               |  113 ++++++++++++++++++++
 builtin.h                                          |    1 +
 .../examples/git-verify-tag.sh                     |    0
 git.c                                              |    1 +
 5 files changed, 117 insertions(+), 1 deletions(-)
 create mode 100644 builtin-verify-tag.c
 rename git-verify-tag.sh => contrib/examples/git-verify-tag.sh (100%)
Show changes to 5 files +117 −1

Makefile, builtin-verify-tag.c, builtin.h, git-verify-tag.sh, git.c

diff --git a/Makefile b/Makefile
index 73b487f..c6ed79f 100644
--- a/Makefile
+++ b/Makefile
@@ -206,7 +206,7 @@ SCRIPT_SH = \
 	git-pull.sh git-rebase.sh git-rebase--interactive.sh \
 	git-repack.sh git-request-pull.sh git-reset.sh \
 	git-sh-setup.sh \
-	git-tag.sh git-verify-tag.sh \
+	git-tag.sh \
 	git-am.sh \
 	git-merge.sh git-merge-stupid.sh git-merge-octopus.sh \
 	git-merge-resolve.sh git-merge-ours.sh \
@@ -367,6 +367,7 @@ BUILTIN_OBJS = \
 	builtin-update-ref.o \
 	builtin-upload-archive.o \
 	builtin-verify-pack.o \
+	builtin-verify-tag.o \
 	builtin-write-tree.o \
 	builtin-show-ref.o \
 	builtin-pack-refs.o
diff --git a/builtin-verify-tag.c b/builtin-verify-tag.c
new file mode 100644
index 0000000..586f28a
--- /dev/null
+++ b/builtin-verify-tag.c
@@ -0,0 +1,113 @@
+/*
+ * Builtin "git verify-tag"
+ *
+ * Copyright (c) 2007 Carlos Rica <jasampler@gmail.com>
+ *
+ * Based on git-verify-tag.sh
+ */
+#include "cache.h"
+#include "builtin.h"
+#include "tag.h"
+#include "run-command.h"
+#include <signal.h>
+
+static const char builtin_verify_tag_usage[] =
+		"git-verify-tag [-v|--verbose] <tag>...";
+
+#define PGP_SIGNATURE "-----BEGIN PGP SIGNATURE-----"
+
+static int run_gpg_verify(const char *buf, unsigned long size, int verbose)
+{
+	struct child_process gpg;
+	const char *args_gpg[] = {"gpg", "--verify", "FILE", "-", NULL};
+	char *path, *eol;
+	size_t len;
+	int fd, ret;
+
+	path = xstrdup(git_path("VTAG_TMP"));
+	fd = open(path, O_CREAT | O_TRUNC | O_WRONLY, 0600);
+	if (fd < 0)
+		return error("could not create temporary file '%s': %s",
+						path, strerror(errno));
+	if (write_in_full(fd, buf, size) < 0)
+		return error("failed writing temporary file '%s': %s",
+						path, strerror(errno));
+	close(fd);
+
+	/* find the length without signature */
+	len = 0;
+	while (len < size && prefixcmp(buf + len, PGP_SIGNATURE "\n")) {
+		eol = memchr(buf + len, '\n', size - len);
+		len += eol ? eol - (buf + len) + 1 : size - len;
+	}
+	if (verbose)
+		write_in_full(1, buf, len);
+
+	memset(&gpg, 0, sizeof(gpg));
+	gpg.argv = args_gpg;
+	gpg.in = -1;
+	gpg.out = 1;
+	args_gpg[2] = path;
+	if (start_command(&gpg))
+		return error("could not run gpg.");
+
+	write_in_full(gpg.in, buf, len);
+	close(gpg.in);
+	gpg.close_in = 0;
+	ret = finish_command(&gpg);
+
+	remove(path);
+	free(path);
+
+	return ret;
+}
+
+static int verify_tag(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("tag '%s' not found.", name);
+
+	type = sha1_object_info(sha1, NULL);
+	if (type <= OBJ_NONE)
+		return error("%s: bad object type.", name);
+	if (type != OBJ_TAG)
+		return error("%s: cannot verify a non-tag object of type %s.",
+				name, typename(type));
+
+	buf = read_sha1_file(sha1, &type, &size);
+	if (!buf)
+		return error("%s: unable to read file.", name);
+
+	ret = run_gpg_verify(buf, size, verbose);
+
+	free(buf);
+	return ret;
+}
+
+int cmd_verify_tag(int argc, const char **argv, const char *prefix)
+{
+	int i, verbose = 0, had_error = 0;
+
+	git_config(git_default_config);
+
+	if (argc == 1)
+		usage(builtin_verify_tag_usage);
+
+	i = 1;
+	if (!strcmp(argv[i], "-v") || !strcmp(argv[i], "--verbose")) {
+		verbose = 1;
+		i++;
+	}
+
+	signal(SIGPIPE, SIG_IGN);
+	while (i < argc)
+		if (verify_tag(argv[i++], verbose))
+			had_error = 1;
+	return had_error;
+}
diff --git a/builtin.h b/builtin.h
index 4cc228d..cb860a0 100644
--- a/builtin.h
+++ b/builtin.h
@@ -76,6 +76,7 @@ extern int cmd_update_index(int argc, const char **argv, const char *prefix);
 extern int cmd_update_ref(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_tar(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_whatchanged(int argc, const char **argv, const char *prefix);
 extern int cmd_write_tree(int argc, const char **argv, const char *prefix);
diff --git a/git-verify-tag.sh b/contrib/examples/git-verify-tag.sh
similarity index 100%
rename from git-verify-tag.sh
rename to contrib/examples/git-verify-tag.sh
diff --git a/git.c b/git.c
index a647f9c..1dfe120 100644
--- a/git.c
+++ b/git.c
@@ -368,6 +368,7 @@ static void handle_internal_command(int argc, const char **argv)
 		{ "update-index", cmd_update_index, RUN_SETUP },
 		{ "update-ref", cmd_update_ref, RUN_SETUP },
 		{ "upload-archive", cmd_upload_archive },
+		{ "verify-tag", cmd_verify_tag, RUN_SETUP },
 		{ "version", cmd_version },
 		{ "whatchanged", cmd_whatchanged, RUN_SETUP | USE_PAGER },
 		{ "write-tree", cmd_write_tree, RUN_SETUP },
-- 
1.5.0
Johannes Schindelin· Jul 23, 2007, 00:52 UTC · re: Carlos Rica · lore

Re: [PATCH] Make verify-tag a builtin.

Hi,
On Mon, 23 Jul 2007, Carlos Rica wrote:
Show 17 quoted lines
> +static int run_gpg_verify(const char *buf, unsigned long size, int verbose)
> +{
> +	struct child_process gpg;
> +	const char *args_gpg[] = {"gpg", "--verify", "FILE", "-", NULL};
> +	char *path, *eol;
> +	size_t len;
> +	int fd, ret;
> +
> +	path = xstrdup(git_path("VTAG_TMP"));
> +	fd = open(path, O_CREAT | O_TRUNC | O_WRONLY, 0600);
> +	if (fd < 0)
> +		return error("could not create temporary file '%s': %s",
> +						path, strerror(errno));
> +	if (write_in_full(fd, buf, size) < 0)
> +		return error("failed writing temporary file '%s': %s",
> +						path, strerror(errno));
> +	close(fd);

I just tested something like "gpg --verify - - < <filename>" and it worked...

Show 6 quoted lines
> +	/* find the length without signature */
> +	len = 0;
> +	while (len < size && prefixcmp(buf + len, PGP_SIGNATURE "\n")) {
> +		eol = memchr(buf + len, '\n', size - len);
> +		len += eol ? eol - (buf + len) + 1 : size - len;
> +	}
How about this instead:
	const char *sig = strstr(buf, "\n" PGP_SIGNATURE "\n"));
	if (!sig)
		sig = buf + len;
Hmm?

But of course only if gpg does not grok "git cat-file tag <signed-tag> | gpg --verify - -".

> +	remove(path);

I think we use unlink() consistently, since we are sure it is no directory.

Show 5 quoted lines
> +	if (type <= OBJ_NONE)
> +		return error("%s: bad object type.", name);
> +	if (type != OBJ_TAG)
> +		return error("%s: cannot verify a non-tag object of type %s.",
> +				name, typename(type));
These two can be unified into one, right?
Show 10 quoted lines
> +int cmd_verify_tag(int argc, const char **argv, const char *prefix)
> +{
> +	int i, verbose = 0, had_error = 0;
> +
> +	git_config(git_default_config);
> +
> +	if (argc == 1)
> +		usage(builtin_verify_tag_usage);
> +
> +	i = 1;
You can initialise i above.
Show 8 quoted lines
> +	if (!strcmp(argv[i], "-v") || !strcmp(argv[i], "--verbose")) {
> +		verbose = 1;
> +		i++;
> +	}
> +
> +	signal(SIGPIPE, SIG_IGN);
> +	while (i < argc)
> +		if (verify_tag(argv[i++], verbose))

Heh. I thought that you only made this a separate function to help building it into builtin-tag...

That was quick!

Ciao, Dscho

Carlos Rica· Jul 23, 2007, 21:21 UTC · re: Johannes Schindelin · lore

Re: [PATCH] Make verify-tag a builtin.

2007/7/23, Johannes Schindelin <Johannes.Schindelin@gmx.de>:
Show 21 quoted lines
> On Mon, 23 Jul 2007, Carlos Rica wrote:
> > +static int run_gpg_verify(const char *buf, unsigned long size, int verbose)
> > +{
> > +     struct child_process gpg;
> > +     const char *args_gpg[] = {"gpg", "--verify", "FILE", "-", NULL};
> > +     char *path, *eol;
> > +     size_t len;
> > +     int fd, ret;
> > +
> > +     path = xstrdup(git_path("VTAG_TMP"));
> > +     fd = open(path, O_CREAT | O_TRUNC | O_WRONLY, 0600);
> > +     if (fd < 0)
> > +             return error("could not create temporary file '%s': %s",
> > +                                             path, strerror(errno));
> > +     if (write_in_full(fd, buf, size) < 0)
> > +             return error("failed writing temporary file '%s': %s",
> > +                                             path, strerror(errno));
> > +     close(fd);
>
> I just tested something like "gpg --verify - - < <filename>" and it
> worked...

I couldn't verify tags using "gpg --verify - - <file" as you pointed in your response.

In my tests, it only allowed me to run:
"gpg --verify file.asc" or
"gpg --verify <file.asc" or
 "gpg --verify - <file.asc"
when file.asc was generated using the command "gpg --clearsign file",
in which it inserts a header:
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
<empty-line>
I even tested to insert the header myself after creating a signed file
as git does:
   cp file otherfile
   gpg -bsa otherfile
   ...
   cat otherfile.asc >>otherfile
   ( echo -e "-----BEGIN PGP SIGNED MESSAGE-----\nHash: SHA1\n" ; cat
otherfile ) \
     | gpg --verify
Note that sending them to "diff file.asc -" also shows different signatures,
but anyway it also says "gpg: BAD signature from ...", the same message as in:
   gpg --verify - - <otherfile
and different from the "gpg: Good signature from ..." when I run:
  gpg --verify file.asc
Johannes Schindelin· Jul 23, 2007, 21:48 UTC · re: Carlos Rica · lore

Re: [PATCH] Make verify-tag a builtin.

Hi,
On Mon, 23 Jul 2007, Carlos Rica wrote:
Show 26 quoted lines
> 2007/7/23, Johannes Schindelin <Johannes.Schindelin@gmx.de>:
> > On Mon, 23 Jul 2007, Carlos Rica wrote:
> > > +static int run_gpg_verify(const char *buf, unsigned long size, int
> > verbose)
> > > +{
> > > +     struct child_process gpg;
> > > +     const char *args_gpg[] = {"gpg", "--verify", "FILE", "-", NULL};
> > > +     char *path, *eol;
> > > +     size_t len;
> > > +     int fd, ret;
> > > +
> > > +     path = xstrdup(git_path("VTAG_TMP"));
> > > +     fd = open(path, O_CREAT | O_TRUNC | O_WRONLY, 0600);
> > > +     if (fd < 0)
> > > +             return error("could not create temporary file '%s': %s",
> > > +                                             path, strerror(errno));
> > > +     if (write_in_full(fd, buf, size) < 0)
> > > +             return error("failed writing temporary file '%s': %s",
> > > +                                             path, strerror(errno));
> > > +     close(fd);
> > 
> > I just tested something like "gpg --verify - - < <filename>" and it
> > worked...
> 
> I couldn't verify tags using "gpg --verify  -  -  <file" as you
> pointed in your response.

As discussed on IRC, my test did not use a detached signature, while tags _do_ use a detached signature.

Oh, well. I retract my suggestion. But I slightly disagree that having to write a temporary file is good for security, as the gpg man page suggests:

--verify [[sigfile]  [signed-files]]
         [...] To read the signed stuff from stdin, use - as the second 
	filename.  For security reasons a detached signature cannot read 
	the signed material from stdin without denoting it in the above 
	way.
So we have to live, or die, with the temporary file.

Just one request: please use lock_file, to prevent multiple instances from getting confused... Even if that cannot be 100% secure: if you write to the file, and only then start gpg, there is still the odd chance for an attacker. Even if you created the file with 0600 (very wise, BTW).

Ciao, Dscho

Carlos Rica· Jul 23, 2007, 22:31 UTC · re: Johannes Schindelin · lore

Re: [PATCH] Make verify-tag a builtin.

2007/7/23, Johannes Schindelin <Johannes.Schindelin@gmx.de>:
> Just one request: please use lock_file, to prevent multiple instances from
> getting confused...  Even if that cannot be 100% secure: if you write to
> the file, and only then start gpg, there is still the odd chance for an
> attacker.  Even if you created the file with 0600 (very wise, BTW).

Why not using also a random name for the temporary file? Something like "VTAG_TMP30946".

Johannes Schindelin· Jul 23, 2007, 22:32 UTC · re: Carlos Rica · lore

Re: [PATCH] Make verify-tag a builtin.

Hi,
On Tue, 24 Jul 2007, Carlos Rica wrote:
Show 8 quoted lines
> 2007/7/23, Johannes Schindelin <Johannes.Schindelin@gmx.de>:
> > Just one request: please use lock_file, to prevent multiple instances from
> > getting confused...  Even if that cannot be 100% secure: if you write to
> > the file, and only then start gpg, there is still the odd chance for an
> > attacker.  Even if you created the file with 0600 (very wise, BTW).
> 
> Why not using also a random name for the temporary file?
> Something like "VTAG_TMP30946".
Yes, makes sense.  One call to mkstemp() away.

Ciao, Dscho

← back to recent threads