mirror of
https://github.com/git/git.git
synced 2026-03-16 19:50:09 +01:00
Merge branch 'jc/signed-commit' into next
* jc/signed-commit: Revert the previous "signed commit" attempt
This commit is contained in:
2
Makefile
2
Makefile
@@ -529,7 +529,6 @@ LIB_H += fmt-merge-msg.h
|
||||
LIB_H += fsck.h
|
||||
LIB_H += gettext.h
|
||||
LIB_H += git-compat-util.h
|
||||
LIB_H += gpg-interface.h
|
||||
LIB_H += graph.h
|
||||
LIB_H += grep.h
|
||||
LIB_H += hash.h
|
||||
@@ -623,7 +622,6 @@ LIB_OBJS += entry.o
|
||||
LIB_OBJS += environment.o
|
||||
LIB_OBJS += exec_cmd.o
|
||||
LIB_OBJS += fsck.o
|
||||
LIB_OBJS += gpg-interface.o
|
||||
LIB_OBJS += graph.o
|
||||
LIB_OBJS += grep.o
|
||||
LIB_OBJS += hash.o
|
||||
|
||||
@@ -8,9 +8,8 @@
|
||||
#include "tree.h"
|
||||
#include "builtin.h"
|
||||
#include "utf8.h"
|
||||
#include "gpg-interface.h"
|
||||
|
||||
static const char commit_tree_usage[] = "git commit-tree [-S<signer>] <sha1> [(-p <sha1>)...] < changelog";
|
||||
static const char commit_tree_usage[] = "git commit-tree <sha1> [(-p <sha1>)...] < changelog";
|
||||
|
||||
static void new_parent(struct commit *parent, struct commit_list **parents_p)
|
||||
{
|
||||
@@ -26,14 +25,6 @@ static void new_parent(struct commit *parent, struct commit_list **parents_p)
|
||||
commit_list_insert(parent, parents_p);
|
||||
}
|
||||
|
||||
static int commit_tree_config(const char *var, const char *value, void *cb)
|
||||
{
|
||||
int status = git_gpg_config(var, value, NULL);
|
||||
if (status)
|
||||
return status;
|
||||
return git_default_config(var, value, cb);
|
||||
}
|
||||
|
||||
int cmd_commit_tree(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
int i;
|
||||
@@ -41,19 +32,11 @@ int cmd_commit_tree(int argc, const char **argv, const char *prefix)
|
||||
unsigned char tree_sha1[20];
|
||||
unsigned char commit_sha1[20];
|
||||
struct strbuf buffer = STRBUF_INIT;
|
||||
const char *sign_commit = NULL;
|
||||
|
||||
git_config(commit_tree_config, NULL);
|
||||
git_config(git_default_config, NULL);
|
||||
|
||||
if (argc < 2 || !strcmp(argv[1], "-h"))
|
||||
usage(commit_tree_usage);
|
||||
|
||||
if (!memcmp(argv[1], "-S", 2)) {
|
||||
sign_commit = argv[1] + 2;
|
||||
argv++;
|
||||
argc--;
|
||||
}
|
||||
|
||||
if (get_sha1(argv[1], tree_sha1))
|
||||
die("Not a valid object name %s", argv[1]);
|
||||
|
||||
@@ -73,8 +56,7 @@ int cmd_commit_tree(int argc, const char **argv, const char *prefix)
|
||||
if (strbuf_read(&buffer, 0, 0) < 0)
|
||||
die_errno("git commit-tree: failed to read");
|
||||
|
||||
if (commit_tree(buffer.buf, tree_sha1, parents, commit_sha1,
|
||||
NULL, sign_commit)) {
|
||||
if (commit_tree(buffer.buf, tree_sha1, parents, commit_sha1, NULL)) {
|
||||
strbuf_release(&buffer);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -26,7 +26,6 @@
|
||||
#include "unpack-trees.h"
|
||||
#include "quote.h"
|
||||
#include "submodule.h"
|
||||
#include "gpg-interface.h"
|
||||
|
||||
static const char * const builtin_commit_usage[] = {
|
||||
"git commit [options] [--] <filepattern>...",
|
||||
@@ -86,8 +85,6 @@ static int all, edit_flag, also, interactive, patch_interactive, only, amend, si
|
||||
static int quiet, verbose, no_verify, allow_empty, dry_run, renew_authorship;
|
||||
static int no_post_rewrite, allow_empty_message;
|
||||
static char *untracked_files_arg, *force_date, *ignore_submodule_arg;
|
||||
static char *sign_commit;
|
||||
|
||||
/*
|
||||
* The default commit message cleanup mode will remove the lines
|
||||
* beginning with # (shell comments) and leading and trailing
|
||||
@@ -147,8 +144,6 @@ static struct option builtin_commit_options[] = {
|
||||
OPT_BOOLEAN('e', "edit", &edit_flag, "force edit of commit"),
|
||||
OPT_STRING(0, "cleanup", &cleanup_arg, "default", "how to strip spaces and #comments from message"),
|
||||
OPT_BOOLEAN(0, "status", &include_status, "include status in commit message template"),
|
||||
{ OPTION_STRING, 'S', "gpg-sign", &sign_commit, "key id",
|
||||
"GPG sign commit", PARSE_OPT_OPTARG, NULL, (intptr_t) "" },
|
||||
/* end commit message options */
|
||||
|
||||
OPT_GROUP("Commit contents options"),
|
||||
@@ -1329,7 +1324,6 @@ static void print_summary(const char *prefix, const unsigned char *sha1,
|
||||
static int git_commit_config(const char *k, const char *v, void *cb)
|
||||
{
|
||||
struct wt_status *s = cb;
|
||||
int status;
|
||||
|
||||
if (!strcmp(k, "commit.template"))
|
||||
return git_config_pathname(&template_file, k, v);
|
||||
@@ -1337,9 +1331,7 @@ static int git_commit_config(const char *k, const char *v, void *cb)
|
||||
include_status = git_config_bool(k, v);
|
||||
return 0;
|
||||
}
|
||||
status = git_gpg_config(k, v, NULL);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
return git_status_config(k, v, s);
|
||||
}
|
||||
|
||||
@@ -1492,7 +1484,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
|
||||
}
|
||||
|
||||
if (commit_tree(sb.buf, active_cache_tree->sha1, parents, sha1,
|
||||
author_ident.buf, sign_commit)) {
|
||||
author_ident.buf)) {
|
||||
rollback_index_files();
|
||||
die(_("failed to write commit object"));
|
||||
}
|
||||
|
||||
@@ -27,7 +27,6 @@
|
||||
#include "resolve-undo.h"
|
||||
#include "remote.h"
|
||||
#include "fmt-merge-msg.h"
|
||||
#include "gpg-interface.h"
|
||||
|
||||
#define DEFAULT_TWOHEAD (1<<0)
|
||||
#define DEFAULT_OCTOPUS (1<<1)
|
||||
@@ -64,7 +63,6 @@ static int allow_rerere_auto;
|
||||
static int abort_current_merge;
|
||||
static int show_progress = -1;
|
||||
static int default_to_upstream;
|
||||
static const char *sign_commit;
|
||||
|
||||
static struct strategy all_strategy[] = {
|
||||
{ "recursive", DEFAULT_TWOHEAD | NO_TRIVIAL },
|
||||
@@ -210,8 +208,6 @@ static struct option builtin_merge_options[] = {
|
||||
OPT_BOOLEAN(0, "abort", &abort_current_merge,
|
||||
"abort the current in-progress merge"),
|
||||
OPT_SET_INT(0, "progress", &show_progress, "force progress reporting", 1),
|
||||
{ OPTION_STRING, 'S', "gpg-sign", &sign_commit, "key id",
|
||||
"GPG sign commit", PARSE_OPT_OPTARG, NULL, (intptr_t) "" },
|
||||
OPT_END()
|
||||
};
|
||||
|
||||
@@ -574,11 +570,7 @@ static int git_merge_config(const char *k, const char *v, void *cb)
|
||||
default_to_upstream = git_config_bool(k, v);
|
||||
return 0;
|
||||
}
|
||||
|
||||
status = fmt_merge_msg_config(k, v, cb);
|
||||
if (status)
|
||||
return status;
|
||||
status = git_gpg_config(k, v, NULL);
|
||||
if (status)
|
||||
return status;
|
||||
return git_diff_ui_config(k, v, cb);
|
||||
@@ -913,8 +905,7 @@ static int merge_trivial(struct commit *head)
|
||||
parent->next->item = remoteheads->item;
|
||||
parent->next->next = NULL;
|
||||
prepare_to_commit();
|
||||
commit_tree(merge_msg.buf, result_tree, parent, result_commit, NULL,
|
||||
sign_commit);
|
||||
commit_tree(merge_msg.buf, result_tree, parent, result_commit, NULL);
|
||||
finish(head, result_commit, "In-index merge");
|
||||
drop_save();
|
||||
return 0;
|
||||
@@ -945,8 +936,7 @@ static int finish_automerge(struct commit *head,
|
||||
strbuf_addch(&merge_msg, '\n');
|
||||
prepare_to_commit();
|
||||
free_commit_list(remoteheads);
|
||||
commit_tree(merge_msg.buf, result_tree, parents, result_commit,
|
||||
NULL, sign_commit);
|
||||
commit_tree(merge_msg.buf, result_tree, parents, result_commit, NULL);
|
||||
strbuf_addf(&buf, "Merge made by the '%s' strategy.", wt_strategy);
|
||||
finish(head, result_commit, buf.buf);
|
||||
strbuf_release(&buf);
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
#include "parse-options.h"
|
||||
#include "diff.h"
|
||||
#include "revision.h"
|
||||
#include "gpg-interface.h"
|
||||
|
||||
static const char * const git_tag_usage[] = {
|
||||
"git tag [-a|-s|-u <key-id>] [-f] [-m <msg>|-F <file>] <tagname> [<head>]",
|
||||
@@ -24,6 +23,8 @@ static const char * const git_tag_usage[] = {
|
||||
NULL
|
||||
};
|
||||
|
||||
static char signingkey[1000];
|
||||
|
||||
struct tag_filter {
|
||||
const char **patterns;
|
||||
int lines;
|
||||
@@ -207,7 +208,60 @@ static int verify_tag(const char *name, const char *ref,
|
||||
|
||||
static int do_sign(struct strbuf *buffer)
|
||||
{
|
||||
return sign_buffer(buffer, buffer, get_signing_key());
|
||||
struct child_process gpg;
|
||||
const char *args[4];
|
||||
char *bracket;
|
||||
int len;
|
||||
int i, j;
|
||||
|
||||
if (!*signingkey) {
|
||||
if (strlcpy(signingkey, git_committer_info(IDENT_ERROR_ON_NO_NAME),
|
||||
sizeof(signingkey)) > sizeof(signingkey) - 1)
|
||||
return error(_("committer info too long."));
|
||||
bracket = strchr(signingkey, '>');
|
||||
if (bracket)
|
||||
bracket[1] = '\0';
|
||||
}
|
||||
|
||||
/* When the username signingkey is bad, program could be terminated
|
||||
* because gpg exits without reading and then write gets SIGPIPE. */
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
|
||||
memset(&gpg, 0, sizeof(gpg));
|
||||
gpg.argv = args;
|
||||
gpg.in = -1;
|
||||
gpg.out = -1;
|
||||
args[0] = "gpg";
|
||||
args[1] = "-bsau";
|
||||
args[2] = signingkey;
|
||||
args[3] = NULL;
|
||||
|
||||
if (start_command(&gpg))
|
||||
return error(_("could not run gpg."));
|
||||
|
||||
if (write_in_full(gpg.in, buffer->buf, buffer->len) != buffer->len) {
|
||||
close(gpg.in);
|
||||
close(gpg.out);
|
||||
finish_command(&gpg);
|
||||
return error(_("gpg did not accept the tag data"));
|
||||
}
|
||||
close(gpg.in);
|
||||
len = strbuf_read(buffer, gpg.out, 1024);
|
||||
close(gpg.out);
|
||||
|
||||
if (finish_command(&gpg) || !len || len < 0)
|
||||
return error(_("gpg failed to sign the tag"));
|
||||
|
||||
/* Strip CR from the line endings, in case we are on Windows. */
|
||||
for (i = j = 0; i < buffer->len; i++)
|
||||
if (buffer->buf[i] != '\r') {
|
||||
if (i != j)
|
||||
buffer->buf[j] = buffer->buf[i];
|
||||
j++;
|
||||
}
|
||||
strbuf_setlen(buffer, j);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char tag_template[] =
|
||||
@@ -216,11 +270,21 @@ static const char tag_template[] =
|
||||
"# Write a tag message\n"
|
||||
"#\n");
|
||||
|
||||
static void set_signingkey(const char *value)
|
||||
{
|
||||
if (strlcpy(signingkey, value, sizeof(signingkey)) >= sizeof(signingkey))
|
||||
die(_("signing key value too long (%.10s...)"), value);
|
||||
}
|
||||
|
||||
static int git_tag_config(const char *var, const char *value, void *cb)
|
||||
{
|
||||
int status = git_gpg_config(var, value, cb);
|
||||
if (status)
|
||||
return status;
|
||||
if (!strcmp(var, "user.signingkey")) {
|
||||
if (!value)
|
||||
return config_error_nonbool(var);
|
||||
set_signingkey(value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return git_default_config(var, value, cb);
|
||||
}
|
||||
|
||||
@@ -399,7 +463,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
|
||||
|
||||
if (keyid) {
|
||||
sign = 1;
|
||||
set_signing_key(keyid);
|
||||
set_signingkey(keyid);
|
||||
}
|
||||
if (sign)
|
||||
annotate = 1;
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
#include "run-command.h"
|
||||
#include <signal.h>
|
||||
#include "parse-options.h"
|
||||
#include "gpg-interface.h"
|
||||
|
||||
static const char * const verify_tag_usage[] = {
|
||||
"git verify-tag [-v|--verbose] <tag>...",
|
||||
@@ -20,16 +19,42 @@ static const char * const verify_tag_usage[] = {
|
||||
|
||||
static int run_gpg_verify(const char *buf, unsigned long size, int verbose)
|
||||
{
|
||||
int len;
|
||||
struct child_process gpg;
|
||||
const char *args_gpg[] = {"gpg", "--verify", "FILE", "-", NULL};
|
||||
char path[PATH_MAX];
|
||||
size_t len;
|
||||
int fd, ret;
|
||||
|
||||
fd = git_mkstemp(path, PATH_MAX, ".git_vtag_tmpXXXXXX");
|
||||
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 = parse_signature(buf, size);
|
||||
if (verbose)
|
||||
write_in_full(1, buf, len);
|
||||
|
||||
if (size == len)
|
||||
return error("no signature found");
|
||||
memset(&gpg, 0, sizeof(gpg));
|
||||
gpg.argv = args_gpg;
|
||||
gpg.in = -1;
|
||||
args_gpg[2] = path;
|
||||
if (start_command(&gpg)) {
|
||||
unlink(path);
|
||||
return error("could not run gpg.");
|
||||
}
|
||||
|
||||
return verify_signed_buffer(buf, len, buf + len, size - len, NULL);
|
||||
write_in_full(gpg.in, buf, len);
|
||||
close(gpg.in);
|
||||
ret = finish_command(&gpg);
|
||||
|
||||
unlink_or_warn(path);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int verify_tag(const char *name, int verbose)
|
||||
|
||||
77
commit.c
77
commit.c
@@ -6,7 +6,6 @@
|
||||
#include "diff.h"
|
||||
#include "revision.h"
|
||||
#include "notes.h"
|
||||
#include "gpg-interface.h"
|
||||
|
||||
int save_commit_buffer = 1;
|
||||
|
||||
@@ -841,77 +840,6 @@ struct commit_list *reduce_heads(struct commit_list *heads)
|
||||
return result;
|
||||
}
|
||||
|
||||
static const char gpg_sig_header[] = "gpgsig ";
|
||||
static const int gpg_sig_header_len = sizeof(gpg_sig_header) - 1;
|
||||
|
||||
static int do_sign_commit(struct strbuf *buf, const char *keyid)
|
||||
{
|
||||
struct strbuf sig = STRBUF_INIT;
|
||||
int inspos, copypos;
|
||||
|
||||
/* find the end of the header */
|
||||
inspos = strstr(buf->buf, "\n\n") - buf->buf + 1;
|
||||
|
||||
if (!keyid || !*keyid)
|
||||
keyid = get_signing_key();
|
||||
if (sign_buffer(buf, &sig, keyid)) {
|
||||
strbuf_release(&sig);
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (copypos = 0; sig.buf[copypos]; ) {
|
||||
const char *bol = sig.buf + copypos;
|
||||
const char *eol = strchrnul(bol, '\n');
|
||||
int len = (eol - bol) + !!*eol;
|
||||
|
||||
strbuf_insert(buf, inspos, gpg_sig_header, gpg_sig_header_len);
|
||||
inspos += gpg_sig_header_len;
|
||||
strbuf_insert(buf, inspos, bol, len);
|
||||
inspos += len;
|
||||
copypos += len;
|
||||
}
|
||||
strbuf_release(&sig);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int parse_signed_commit(const unsigned char *sha1,
|
||||
struct strbuf *payload, struct strbuf *signature)
|
||||
{
|
||||
unsigned long size;
|
||||
enum object_type type;
|
||||
char *buffer = read_sha1_file(sha1, &type, &size);
|
||||
int saw_signature = -1;
|
||||
char *line, *tail;
|
||||
|
||||
if (!buffer || type != OBJ_COMMIT)
|
||||
goto cleanup;
|
||||
|
||||
line = buffer;
|
||||
tail = buffer + size;
|
||||
saw_signature = 0;
|
||||
while (line < tail) {
|
||||
char *next = memchr(line, '\n', tail - line);
|
||||
if (!next)
|
||||
next = tail;
|
||||
else
|
||||
next++;
|
||||
if (!prefixcmp(line, gpg_sig_header)) {
|
||||
const char *sig = line + gpg_sig_header_len;
|
||||
strbuf_add(signature, sig, next - sig);
|
||||
saw_signature = 1;
|
||||
} else {
|
||||
if (*line == '\n')
|
||||
/* dump the whole remainder of the buffer */
|
||||
next = tail;
|
||||
strbuf_add(payload, line, next - line);
|
||||
}
|
||||
line = next;
|
||||
}
|
||||
cleanup:
|
||||
free(buffer);
|
||||
return saw_signature;
|
||||
}
|
||||
|
||||
static const char commit_utf8_warn[] =
|
||||
"Warning: commit message does not conform to UTF-8.\n"
|
||||
"You may want to amend it after fixing the message, or set the config\n"
|
||||
@@ -919,7 +847,7 @@ static const char commit_utf8_warn[] =
|
||||
|
||||
int commit_tree(const char *msg, unsigned char *tree,
|
||||
struct commit_list *parents, unsigned char *ret,
|
||||
const char *author, const char *sign_commit)
|
||||
const char *author)
|
||||
{
|
||||
int result;
|
||||
int encoding_is_utf8;
|
||||
@@ -962,9 +890,6 @@ int commit_tree(const char *msg, unsigned char *tree,
|
||||
if (encoding_is_utf8 && !is_utf8(buffer.buf))
|
||||
fprintf(stderr, commit_utf8_warn);
|
||||
|
||||
if (sign_commit && do_sign_commit(&buffer, sign_commit))
|
||||
return -1;
|
||||
|
||||
result = write_sha1_file(buffer.buf, buffer.len, commit_type, ret);
|
||||
strbuf_release(&buffer);
|
||||
return result;
|
||||
|
||||
5
commit.h
5
commit.h
@@ -183,9 +183,6 @@ struct commit_list *reduce_heads(struct commit_list *heads);
|
||||
|
||||
extern int commit_tree(const char *msg, unsigned char *tree,
|
||||
struct commit_list *parents, unsigned char *ret,
|
||||
const char *author, const char *sign_commit);
|
||||
|
||||
extern int parse_signed_commit(const unsigned char *sha1,
|
||||
struct strbuf *message, struct strbuf *signature);
|
||||
const char *author);
|
||||
|
||||
#endif /* COMMIT_H */
|
||||
|
||||
138
gpg-interface.c
138
gpg-interface.c
@@ -1,138 +0,0 @@
|
||||
#include "cache.h"
|
||||
#include "run-command.h"
|
||||
#include "strbuf.h"
|
||||
#include "gpg-interface.h"
|
||||
#include "sigchain.h"
|
||||
|
||||
static char *configured_signing_key;
|
||||
|
||||
void set_signing_key(const char *key)
|
||||
{
|
||||
free(configured_signing_key);
|
||||
configured_signing_key = xstrdup(key);
|
||||
}
|
||||
|
||||
int git_gpg_config(const char *var, const char *value, void *cb)
|
||||
{
|
||||
if (!strcmp(var, "user.signingkey")) {
|
||||
if (!value)
|
||||
return config_error_nonbool(var);
|
||||
set_signing_key(value);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char *get_signing_key(void)
|
||||
{
|
||||
if (configured_signing_key)
|
||||
return configured_signing_key;
|
||||
return git_committer_info(IDENT_ERROR_ON_NO_NAME|IDENT_NO_DATE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a detached signature for the contents of "buffer" and append
|
||||
* it after "signature"; "buffer" and "signature" can be the same
|
||||
* strbuf instance, which would cause the detached signature appended
|
||||
* at the end.
|
||||
*/
|
||||
int sign_buffer(struct strbuf *buffer, struct strbuf *signature, const char *signing_key)
|
||||
{
|
||||
struct child_process gpg;
|
||||
const char *args[4];
|
||||
ssize_t len;
|
||||
size_t i, j, bottom;
|
||||
|
||||
memset(&gpg, 0, sizeof(gpg));
|
||||
gpg.argv = args;
|
||||
gpg.in = -1;
|
||||
gpg.out = -1;
|
||||
args[0] = "gpg";
|
||||
args[1] = "-bsau";
|
||||
args[2] = signing_key;
|
||||
args[3] = NULL;
|
||||
|
||||
if (start_command(&gpg))
|
||||
return error(_("could not run gpg."));
|
||||
|
||||
/*
|
||||
* When the username signingkey is bad, program could be terminated
|
||||
* because gpg exits without reading and then write gets SIGPIPE.
|
||||
*/
|
||||
sigchain_push(SIGPIPE, SIG_IGN);
|
||||
|
||||
if (write_in_full(gpg.in, buffer->buf, buffer->len) != buffer->len) {
|
||||
close(gpg.in);
|
||||
close(gpg.out);
|
||||
finish_command(&gpg);
|
||||
return error(_("gpg did not accept the data"));
|
||||
}
|
||||
close(gpg.in);
|
||||
|
||||
bottom = signature->len;
|
||||
len = strbuf_read(signature, gpg.out, 1024);
|
||||
close(gpg.out);
|
||||
|
||||
sigchain_pop(SIGPIPE);
|
||||
|
||||
if (finish_command(&gpg) || !len || len < 0)
|
||||
return error(_("gpg failed to sign the data"));
|
||||
|
||||
/* Strip CR from the line endings, in case we are on Windows. */
|
||||
for (i = j = bottom; i < signature->len; i++)
|
||||
if (signature->buf[i] != '\r') {
|
||||
if (i != j)
|
||||
signature->buf[j] = signature->buf[i];
|
||||
j++;
|
||||
}
|
||||
strbuf_setlen(signature, j);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Run "gpg" to see if the payload matches the detached signature.
|
||||
* gpg_output_to tells where the output from "gpg" should go:
|
||||
* < 0: /dev/null
|
||||
* = 0: standard error of the calling process
|
||||
* > 0: the specified file descriptor
|
||||
*/
|
||||
int verify_signed_buffer(const char *payload, size_t payload_size,
|
||||
const char *signature, size_t signature_size,
|
||||
struct strbuf *gpg_output)
|
||||
{
|
||||
struct child_process gpg;
|
||||
const char *args_gpg[] = {"gpg", "--verify", "FILE", "-", NULL};
|
||||
char path[PATH_MAX];
|
||||
int fd, ret;
|
||||
|
||||
fd = git_mkstemp(path, PATH_MAX, ".git_vtag_tmpXXXXXX");
|
||||
if (fd < 0)
|
||||
return error("could not create temporary file '%s': %s",
|
||||
path, strerror(errno));
|
||||
if (write_in_full(fd, signature, signature_size) < 0)
|
||||
return error("failed writing detached signature to '%s': %s",
|
||||
path, strerror(errno));
|
||||
close(fd);
|
||||
|
||||
memset(&gpg, 0, sizeof(gpg));
|
||||
gpg.argv = args_gpg;
|
||||
gpg.in = -1;
|
||||
if (gpg_output)
|
||||
gpg.err = -1;
|
||||
args_gpg[2] = path;
|
||||
if (start_command(&gpg)) {
|
||||
unlink(path);
|
||||
return error("could not run gpg.");
|
||||
}
|
||||
|
||||
write_in_full(gpg.in, payload, payload_size);
|
||||
close(gpg.in);
|
||||
|
||||
if (gpg_output)
|
||||
strbuf_read(gpg_output, gpg.err, 0);
|
||||
ret = finish_command(&gpg);
|
||||
|
||||
unlink_or_warn(path);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
#ifndef GPG_INTERFACE_H
|
||||
#define GPG_INTERFACE_H
|
||||
|
||||
extern int sign_buffer(struct strbuf *buffer, struct strbuf *signature, const char *signing_key);
|
||||
extern int verify_signed_buffer(const char *payload, size_t payload_size, const char *signature, size_t signature_size, struct strbuf *gpg_output);
|
||||
extern int git_gpg_config(const char *, const char *, void *);
|
||||
extern void set_signing_key(const char *);
|
||||
extern const char *get_signing_key(void);
|
||||
|
||||
#endif
|
||||
39
log-tree.c
39
log-tree.c
@@ -8,7 +8,6 @@
|
||||
#include "refs.h"
|
||||
#include "string-list.h"
|
||||
#include "color.h"
|
||||
#include "gpg-interface.h"
|
||||
|
||||
struct decoration name_decoration = { "object names" };
|
||||
|
||||
@@ -404,41 +403,6 @@ void log_write_email_headers(struct rev_info *opt, struct commit *commit,
|
||||
*extra_headers_p = extra_headers;
|
||||
}
|
||||
|
||||
static void show_signature(struct rev_info *opt, struct commit *commit)
|
||||
{
|
||||
struct strbuf payload = STRBUF_INIT;
|
||||
struct strbuf signature = STRBUF_INIT;
|
||||
struct strbuf gpg_output = STRBUF_INIT;
|
||||
int status;
|
||||
const char *color, *reset, *bol, *eol;
|
||||
|
||||
if (parse_signed_commit(commit->object.sha1, &payload, &signature) <= 0)
|
||||
goto out;
|
||||
|
||||
status = verify_signed_buffer(payload.buf, payload.len,
|
||||
signature.buf, signature.len,
|
||||
&gpg_output);
|
||||
if (status && !gpg_output.len)
|
||||
strbuf_addstr(&gpg_output, "No signature\n");
|
||||
|
||||
color = diff_get_color_opt(&opt->diffopt,
|
||||
status ? DIFF_WHITESPACE : DIFF_FRAGINFO);
|
||||
reset = diff_get_color_opt(&opt->diffopt, DIFF_RESET);
|
||||
|
||||
bol = gpg_output.buf;
|
||||
while (*bol) {
|
||||
eol = strchrnul(bol, '\n');
|
||||
printf("%s%.*s%s%s", color, (int)(eol - bol), bol, reset,
|
||||
*eol ? "\n" : "");
|
||||
bol = (*eol) ? (eol + 1) : eol;
|
||||
}
|
||||
|
||||
out:
|
||||
strbuf_release(&gpg_output);
|
||||
strbuf_release(&payload);
|
||||
strbuf_release(&signature);
|
||||
}
|
||||
|
||||
void show_log(struct rev_info *opt)
|
||||
{
|
||||
struct strbuf msgbuf = STRBUF_INIT;
|
||||
@@ -550,9 +514,6 @@ void show_log(struct rev_info *opt)
|
||||
}
|
||||
}
|
||||
|
||||
if (opt->show_signature)
|
||||
show_signature(opt, commit);
|
||||
|
||||
if (!commit->buffer)
|
||||
return;
|
||||
|
||||
|
||||
@@ -56,7 +56,7 @@ int notes_cache_write(struct notes_cache *c)
|
||||
|
||||
if (write_notes_tree(&c->tree, tree_sha1))
|
||||
return -1;
|
||||
if (commit_tree(c->validity, tree_sha1, NULL, commit_sha1, NULL, NULL) < 0)
|
||||
if (commit_tree(c->validity, tree_sha1, NULL, commit_sha1, NULL) < 0)
|
||||
return -1;
|
||||
if (update_ref("update notes cache", c->tree.ref, commit_sha1, NULL,
|
||||
0, QUIET_ON_ERR) < 0)
|
||||
|
||||
@@ -546,7 +546,7 @@ void create_notes_commit(struct notes_tree *t, struct commit_list *parents,
|
||||
/* else: t->ref points to nothing, assume root/orphan commit */
|
||||
}
|
||||
|
||||
if (commit_tree(msg, tree_sha1, parents, result_sha1, NULL, NULL))
|
||||
if (commit_tree(msg, tree_sha1, parents, result_sha1, NULL))
|
||||
die("Failed to commit notes tree to database");
|
||||
}
|
||||
|
||||
|
||||
86
pretty.c
86
pretty.c
@@ -9,7 +9,6 @@
|
||||
#include "notes.h"
|
||||
#include "color.h"
|
||||
#include "reflog-walk.h"
|
||||
#include "gpg-interface.h"
|
||||
|
||||
static char *user_format;
|
||||
static struct cmt_fmt_map {
|
||||
@@ -641,12 +640,6 @@ struct format_commit_context {
|
||||
const struct pretty_print_context *pretty_ctx;
|
||||
unsigned commit_header_parsed:1;
|
||||
unsigned commit_message_parsed:1;
|
||||
unsigned commit_signature_parsed:1;
|
||||
struct {
|
||||
char *gpg_output;
|
||||
char good_bad;
|
||||
char *signer;
|
||||
} signature;
|
||||
char *message;
|
||||
size_t width, indent1, indent2;
|
||||
|
||||
@@ -829,59 +822,6 @@ static void rewrap_message_tail(struct strbuf *sb,
|
||||
c->indent2 = new_indent2;
|
||||
}
|
||||
|
||||
static struct {
|
||||
char result;
|
||||
const char *check;
|
||||
} signature_check[] = {
|
||||
{ 'G', ": Good signature from " },
|
||||
{ 'B', ": BAD signature from " },
|
||||
};
|
||||
|
||||
static void parse_signature_lines(struct format_commit_context *ctx)
|
||||
{
|
||||
const char *buf = ctx->signature.gpg_output;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(signature_check); i++) {
|
||||
const char *found = strstr(buf, signature_check[i].check);
|
||||
const char *next;
|
||||
if (!found)
|
||||
continue;
|
||||
ctx->signature.good_bad = signature_check[i].result;
|
||||
found += strlen(signature_check[i].check);
|
||||
next = strchrnul(found, '\n');
|
||||
ctx->signature.signer = xmemdupz(found, next - found);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void parse_commit_signature(struct format_commit_context *ctx)
|
||||
{
|
||||
struct strbuf payload = STRBUF_INIT;
|
||||
struct strbuf signature = STRBUF_INIT;
|
||||
struct strbuf gpg_output = STRBUF_INIT;
|
||||
int status;
|
||||
|
||||
ctx->commit_signature_parsed = 1;
|
||||
|
||||
if (parse_signed_commit(ctx->commit->object.sha1,
|
||||
&payload, &signature) <= 0)
|
||||
goto out;
|
||||
status = verify_signed_buffer(payload.buf, payload.len,
|
||||
signature.buf, signature.len,
|
||||
&gpg_output);
|
||||
if (status && !gpg_output.len)
|
||||
goto out;
|
||||
ctx->signature.gpg_output = strbuf_detach(&gpg_output, NULL);
|
||||
parse_signature_lines(ctx);
|
||||
|
||||
out:
|
||||
strbuf_release(&gpg_output);
|
||||
strbuf_release(&payload);
|
||||
strbuf_release(&signature);
|
||||
}
|
||||
|
||||
|
||||
static size_t format_commit_one(struct strbuf *sb, const char *placeholder,
|
||||
void *context)
|
||||
{
|
||||
@@ -1034,30 +974,6 @@ static size_t format_commit_one(struct strbuf *sb, const char *placeholder,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (placeholder[0] == 'G') {
|
||||
if (!c->commit_signature_parsed)
|
||||
parse_commit_signature(c);
|
||||
switch (placeholder[1]) {
|
||||
case 'G':
|
||||
if (c->signature.gpg_output)
|
||||
strbuf_addstr(sb, c->signature.gpg_output);
|
||||
break;
|
||||
case '?':
|
||||
switch (c->signature.good_bad) {
|
||||
case 'G':
|
||||
case 'B':
|
||||
strbuf_addch(sb, c->signature.good_bad);
|
||||
}
|
||||
break;
|
||||
case 'S':
|
||||
if (c->signature.signer)
|
||||
strbuf_addstr(sb, c->signature.signer);
|
||||
break;
|
||||
}
|
||||
return 2;
|
||||
}
|
||||
|
||||
|
||||
/* For the rest we have to parse the commit header. */
|
||||
if (!c->commit_header_parsed)
|
||||
parse_commit_header(c);
|
||||
@@ -1200,8 +1116,6 @@ void format_commit_message(const struct commit *commit,
|
||||
|
||||
if (context.message != commit->buffer)
|
||||
free(context.message);
|
||||
free(context.signature.gpg_output);
|
||||
free(context.signature.signer);
|
||||
}
|
||||
|
||||
static void pp_header(const struct pretty_print_context *pp,
|
||||
|
||||
@@ -1469,8 +1469,6 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg
|
||||
revs->show_notes = 1;
|
||||
revs->show_notes_given = 1;
|
||||
revs->notes_opt.use_default_notes = 1;
|
||||
} else if (!strcmp(arg, "--show-signature")) {
|
||||
revs->show_signature = 1;
|
||||
} else if (!prefixcmp(arg, "--show-notes=") ||
|
||||
!prefixcmp(arg, "--notes=")) {
|
||||
struct strbuf buf = STRBUF_INIT;
|
||||
|
||||
@@ -110,7 +110,6 @@ struct rev_info {
|
||||
show_merge:1,
|
||||
show_notes:1,
|
||||
show_notes_given:1,
|
||||
show_signature:1,
|
||||
pretty_given:1,
|
||||
abbrev_commit:1,
|
||||
abbrev_commit_given:1,
|
||||
|
||||
@@ -1,71 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
test_description='signed commit tests'
|
||||
. ./test-lib.sh
|
||||
. "$TEST_DIRECTORY/lib-gpg.sh"
|
||||
|
||||
test_expect_success GPG 'create signed commits' '
|
||||
echo 1 >file && git add file &&
|
||||
test_tick && git commit -S -m initial &&
|
||||
git tag initial &&
|
||||
git branch side &&
|
||||
|
||||
echo 2 >file && test_tick && git commit -a -S -m second &&
|
||||
git tag second &&
|
||||
|
||||
git checkout side &&
|
||||
echo 3 >elif && git add elif &&
|
||||
test_tick && git commit -m "third on side" &&
|
||||
|
||||
git checkout master &&
|
||||
test_tick && git merge -S side &&
|
||||
git tag merge &&
|
||||
|
||||
echo 4 >file && test_tick && git commit -a -m "fourth unsigned" &&
|
||||
git tag fourth-unsigned &&
|
||||
|
||||
test_tick && git commit --amend -S -m "fourth signed"
|
||||
'
|
||||
|
||||
test_expect_success GPG 'show signatures' '
|
||||
(
|
||||
for commit in initial second merge master
|
||||
do
|
||||
git show --pretty=short --show-signature $commit >actual &&
|
||||
grep "Good signature from" actual || exit 1
|
||||
! grep "BAD signature from" actual || exit 1
|
||||
echo $commit OK
|
||||
done
|
||||
) &&
|
||||
(
|
||||
for commit in merge^2 fourth-unsigned
|
||||
do
|
||||
git show --pretty=short --show-signature $commit >actual &&
|
||||
grep "Good signature from" actual && exit 1
|
||||
! grep "BAD signature from" actual || exit 1
|
||||
echo $commit OK
|
||||
done
|
||||
)
|
||||
'
|
||||
|
||||
test_expect_success GPG 'detect fudged signature' '
|
||||
git cat-file commit master >raw &&
|
||||
|
||||
sed -e "s/fourth signed/4th forged/" raw >forged1 &&
|
||||
git hash-object -w -t commit forged1 >forged1.commit &&
|
||||
git show --pretty=short --show-signature $(cat forged1.commit) >actual1 &&
|
||||
grep "BAD signature from" actual1 &&
|
||||
! grep "Good signature from" actual1
|
||||
'
|
||||
|
||||
test_expect_success GPG 'detect fudged signature with NUL' '
|
||||
git cat-file commit master >raw &&
|
||||
cat raw >forged2 &&
|
||||
echo Qwik | tr "Q" "\000" >>forged2 &&
|
||||
git hash-object -w -t commit forged2 >forged2.commit &&
|
||||
git show --pretty=short --show-signature $(cat forged2.commit) >actual2 &&
|
||||
grep "BAD signature from" actual2 &&
|
||||
! grep "Good signature from" actual2
|
||||
'
|
||||
|
||||
test_done
|
||||
5
tag.c
5
tag.c
@@ -139,11 +139,6 @@ int parse_tag(struct tag *item)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Look at a signed tag object, and return the offset where
|
||||
* the embedded detached signature begins, or the end of the
|
||||
* data when there is no such signature.
|
||||
*/
|
||||
size_t parse_signature(const char *buf, unsigned long size)
|
||||
{
|
||||
char *eol;
|
||||
|
||||
Reference in New Issue
Block a user