summaryrefslogtreecommitdiff
path: root/commit.c
diff options
context:
space:
mode:
authorJunio C Hamano <gitster@pobox.com>2021-02-23 00:12:42 (GMT)
committerJunio C Hamano <gitster@pobox.com>2021-02-23 00:12:42 (GMT)
commit15af6e6fee54632358798bef548d89dd3764805d (patch)
treef4464996780c0c94bd0901bab9e161b9679fe05f /commit.c
parentb9554c03a0a8147109608b94feb32837a6e6a145 (diff)
parent9b27b49240f6bf760ff58d917491bec0981aaf9f (diff)
downloadgit-15af6e6fee54632358798bef548d89dd3764805d.zip
git-15af6e6fee54632358798bef548d89dd3764805d.tar.gz
git-15af6e6fee54632358798bef548d89dd3764805d.tar.bz2
Merge branch 'bc/signed-objects-with-both-hashes'
Signed commits and tags now allow verification of objects, whose two object names (one in SHA-1, the other in SHA-256) are both signed. * bc/signed-objects-with-both-hashes: gpg-interface: remove other signature headers before verifying ref-filter: hoist signature parsing commit: allow parsing arbitrary buffers with headers gpg-interface: improve interface for parsing tags commit: ignore additional signatures when parsing signed commits ref-filter: switch some uses of unsigned long to size_t
Diffstat (limited to 'commit.c')
-rw-r--r--commit.c83
1 files changed, 56 insertions, 27 deletions
diff --git a/commit.c b/commit.c
index 4694c4c..6ccd774 100644
--- a/commit.c
+++ b/commit.c
@@ -995,7 +995,7 @@ static const char *gpg_sig_headers[] = {
"gpgsig-sha256",
};
-static int do_sign_commit(struct strbuf *buf, const char *keyid)
+int sign_with_header(struct strbuf *buf, const char *keyid)
{
struct strbuf sig = STRBUF_INIT;
int inspos, copypos;
@@ -1035,21 +1035,32 @@ static int do_sign_commit(struct strbuf *buf, const char *keyid)
return 0;
}
+
+
int parse_signed_commit(const struct commit *commit,
- struct strbuf *payload, struct strbuf *signature)
+ struct strbuf *payload, struct strbuf *signature,
+ const struct git_hash_algo *algop)
{
-
unsigned long size;
const char *buffer = get_commit_buffer(commit, &size);
- int in_signature, saw_signature = -1;
- const char *line, *tail;
- const char *gpg_sig_header = gpg_sig_headers[hash_algo_by_ptr(the_hash_algo)];
- int gpg_sig_header_len = strlen(gpg_sig_header);
+ int ret = parse_buffer_signed_by_header(buffer, size, payload, signature, algop);
+
+ unuse_commit_buffer(commit, buffer);
+ return ret;
+}
+
+int parse_buffer_signed_by_header(const char *buffer,
+ unsigned long size,
+ struct strbuf *payload,
+ struct strbuf *signature,
+ const struct git_hash_algo *algop)
+{
+ int in_signature = 0, saw_signature = 0, other_signature = 0;
+ const char *line, *tail, *p;
+ const char *gpg_sig_header = gpg_sig_headers[hash_algo_by_ptr(algop)];
line = buffer;
tail = buffer + size;
- in_signature = 0;
- saw_signature = 0;
while (line < tail) {
const char *sig = NULL;
const char *next = memchr(line, '\n', tail - line);
@@ -1057,9 +1068,15 @@ int parse_signed_commit(const struct commit *commit,
next = next ? next + 1 : tail;
if (in_signature && line[0] == ' ')
sig = line + 1;
- else if (starts_with(line, gpg_sig_header) &&
- line[gpg_sig_header_len] == ' ')
- sig = line + gpg_sig_header_len + 1;
+ else if (skip_prefix(line, gpg_sig_header, &p) &&
+ *p == ' ') {
+ sig = line + strlen(gpg_sig_header) + 1;
+ other_signature = 0;
+ }
+ else if (starts_with(line, "gpgsig"))
+ other_signature = 1;
+ else if (other_signature && line[0] != ' ')
+ other_signature = 0;
if (sig) {
strbuf_add(signature, sig, next - sig);
saw_signature = 1;
@@ -1068,12 +1085,12 @@ int parse_signed_commit(const struct commit *commit,
if (*line == '\n')
/* dump the whole remainder of the buffer */
next = tail;
- strbuf_add(payload, line, next - line);
+ if (!other_signature)
+ strbuf_add(payload, line, next - line);
in_signature = 0;
}
line = next;
}
- unuse_commit_buffer(commit, buffer);
return saw_signature;
}
@@ -1082,23 +1099,29 @@ int remove_signature(struct strbuf *buf)
const char *line = buf->buf;
const char *tail = buf->buf + buf->len;
int in_signature = 0;
- const char *sig_start = NULL;
- const char *sig_end = NULL;
+ struct sigbuf {
+ const char *start;
+ const char *end;
+ } sigs[2], *sigp = &sigs[0];
+ int i;
+ const char *orig_buf = buf->buf;
+
+ memset(sigs, 0, sizeof(sigs));
while (line < tail) {
const char *next = memchr(line, '\n', tail - line);
next = next ? next + 1 : tail;
if (in_signature && line[0] == ' ')
- sig_end = next;
+ sigp->end = next;
else if (starts_with(line, "gpgsig")) {
int i;
for (i = 1; i < GIT_HASH_NALGOS; i++) {
const char *p;
if (skip_prefix(line, gpg_sig_headers[i], &p) &&
*p == ' ') {
- sig_start = line;
- sig_end = next;
+ sigp->start = line;
+ sigp->end = next;
in_signature = 1;
}
}
@@ -1106,15 +1129,18 @@ int remove_signature(struct strbuf *buf)
if (*line == '\n')
/* dump the whole remainder of the buffer */
next = tail;
+ if (in_signature && sigp - sigs != ARRAY_SIZE(sigs))
+ sigp++;
in_signature = 0;
}
line = next;
}
- if (sig_start)
- strbuf_remove(buf, sig_start - buf->buf, sig_end - sig_start);
+ for (i = ARRAY_SIZE(sigs) - 1; i >= 0; i--)
+ if (sigs[i].start)
+ strbuf_remove(buf, sigs[i].start - orig_buf, sigs[i].end - sigs[i].start);
- return sig_start != NULL;
+ return sigs[0].start != NULL;
}
static void handle_signed_tag(struct commit *parent, struct commit_extra_header ***tail)
@@ -1122,8 +1148,10 @@ static void handle_signed_tag(struct commit *parent, struct commit_extra_header
struct merge_remote_desc *desc;
struct commit_extra_header *mergetag;
char *buf;
- unsigned long size, len;
+ unsigned long size;
enum object_type type;
+ struct strbuf payload = STRBUF_INIT;
+ struct strbuf signature = STRBUF_INIT;
desc = merge_remote_util(parent);
if (!desc || !desc->obj)
@@ -1131,8 +1159,7 @@ static void handle_signed_tag(struct commit *parent, struct commit_extra_header
buf = read_object_file(&desc->obj->oid, &type, &size);
if (!buf || type != OBJ_TAG)
goto free_return;
- len = parse_signature(buf, size);
- if (size == len)
+ if (!parse_signature(buf, size, &payload, &signature))
goto free_return;
/*
* We could verify this signature and either omit the tag when
@@ -1151,6 +1178,8 @@ static void handle_signed_tag(struct commit *parent, struct commit_extra_header
**tail = mergetag;
*tail = &mergetag->next;
+ strbuf_release(&payload);
+ strbuf_release(&signature);
return;
free_return:
@@ -1165,7 +1194,7 @@ int check_commit_signature(const struct commit *commit, struct signature_check *
sigc->result = 'N';
- if (parse_signed_commit(commit, &payload, &signature) <= 0)
+ if (parse_signed_commit(commit, &payload, &signature, the_hash_algo) <= 0)
goto out;
ret = check_signature(payload.buf, payload.len, signature.buf,
signature.len, sigc);
@@ -1515,7 +1544,7 @@ int commit_tree_extended(const char *msg, size_t msg_len,
if (encoding_is_utf8 && !verify_utf8(&buffer))
fprintf(stderr, _(commit_utf8_warn));
- if (sign_commit && do_sign_commit(&buffer, sign_commit)) {
+ if (sign_commit && sign_with_header(&buffer, sign_commit)) {
result = -1;
goto out;
}