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
This commit is contained in:
85
commit.c
85
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)
|
||||
{
|
||||
|
||||
|
||||
int parse_signed_commit(const struct commit *commit,
|
||||
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;
|
||||
}
|
||||
|
Reference in New Issue
Block a user