Skip to content

Commit 15af6e6

Browse files
committed
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
2 parents b9554c0 + 9b27b49 commit 15af6e6

File tree

12 files changed

+225
-74
lines changed

12 files changed

+225
-74
lines changed

builtin/receive-pack.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -764,7 +764,7 @@ static void prepare_push_cert_sha1(struct child_process *proc)
764764

765765
memset(&sigcheck, '\0', sizeof(sigcheck));
766766

767-
bogs = parse_signature(push_cert.buf, push_cert.len);
767+
bogs = parse_signed_buffer(push_cert.buf, push_cert.len);
768768
check_signature(push_cert.buf, bogs, push_cert.buf + bogs,
769769
push_cert.len - bogs, &sigcheck);
770770

@@ -2050,7 +2050,7 @@ static void queue_commands_from_cert(struct command **tail,
20502050
die("malformed push certificate %.*s", 100, push_cert->buf);
20512051
else
20522052
boc += 2;
2053-
eoc = push_cert->buf + parse_signature(push_cert->buf, push_cert->len);
2053+
eoc = push_cert->buf + parse_signed_buffer(push_cert->buf, push_cert->len);
20542054

20552055
while (boc < eoc) {
20562056
const char *eol = memchr(boc, '\n', eoc - boc);

builtin/tag.c

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -198,11 +198,17 @@ static void write_tag_body(int fd, const struct object_id *oid)
198198
{
199199
unsigned long size;
200200
enum object_type type;
201-
char *buf, *sp;
201+
char *buf, *sp, *orig;
202+
struct strbuf payload = STRBUF_INIT;
203+
struct strbuf signature = STRBUF_INIT;
202204

203-
buf = read_object_file(oid, &type, &size);
205+
orig = buf = read_object_file(oid, &type, &size);
204206
if (!buf)
205207
return;
208+
if (parse_signature(buf, size, &payload, &signature)) {
209+
buf = payload.buf;
210+
size = payload.len;
211+
}
206212
/* skip header */
207213
sp = strstr(buf, "\n\n");
208214

@@ -211,9 +217,11 @@ static void write_tag_body(int fd, const struct object_id *oid)
211217
return;
212218
}
213219
sp += 2; /* skip the 2 LFs */
214-
write_or_die(fd, sp, parse_signature(sp, buf + size - sp));
220+
write_or_die(fd, sp, buf + size - sp);
215221

216-
free(buf);
222+
free(orig);
223+
strbuf_release(&payload);
224+
strbuf_release(&signature);
217225
}
218226

219227
static int build_tag_object(struct strbuf *buf, int sign, struct object_id *result)

commit.c

Lines changed: 56 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -995,7 +995,7 @@ static const char *gpg_sig_headers[] = {
995995
"gpgsig-sha256",
996996
};
997997

998-
static int do_sign_commit(struct strbuf *buf, const char *keyid)
998+
int sign_with_header(struct strbuf *buf, const char *keyid)
999999
{
10001000
struct strbuf sig = STRBUF_INIT;
10011001
int inspos, copypos;
@@ -1035,31 +1035,48 @@ static int do_sign_commit(struct strbuf *buf, const char *keyid)
10351035
return 0;
10361036
}
10371037

1038+
1039+
10381040
int parse_signed_commit(const struct commit *commit,
1039-
struct strbuf *payload, struct strbuf *signature)
1041+
struct strbuf *payload, struct strbuf *signature,
1042+
const struct git_hash_algo *algop)
10401043
{
1041-
10421044
unsigned long size;
10431045
const char *buffer = get_commit_buffer(commit, &size);
1044-
int in_signature, saw_signature = -1;
1045-
const char *line, *tail;
1046-
const char *gpg_sig_header = gpg_sig_headers[hash_algo_by_ptr(the_hash_algo)];
1047-
int gpg_sig_header_len = strlen(gpg_sig_header);
1046+
int ret = parse_buffer_signed_by_header(buffer, size, payload, signature, algop);
1047+
1048+
unuse_commit_buffer(commit, buffer);
1049+
return ret;
1050+
}
1051+
1052+
int parse_buffer_signed_by_header(const char *buffer,
1053+
unsigned long size,
1054+
struct strbuf *payload,
1055+
struct strbuf *signature,
1056+
const struct git_hash_algo *algop)
1057+
{
1058+
int in_signature = 0, saw_signature = 0, other_signature = 0;
1059+
const char *line, *tail, *p;
1060+
const char *gpg_sig_header = gpg_sig_headers[hash_algo_by_ptr(algop)];
10481061

10491062
line = buffer;
10501063
tail = buffer + size;
1051-
in_signature = 0;
1052-
saw_signature = 0;
10531064
while (line < tail) {
10541065
const char *sig = NULL;
10551066
const char *next = memchr(line, '\n', tail - line);
10561067

10571068
next = next ? next + 1 : tail;
10581069
if (in_signature && line[0] == ' ')
10591070
sig = line + 1;
1060-
else if (starts_with(line, gpg_sig_header) &&
1061-
line[gpg_sig_header_len] == ' ')
1062-
sig = line + gpg_sig_header_len + 1;
1071+
else if (skip_prefix(line, gpg_sig_header, &p) &&
1072+
*p == ' ') {
1073+
sig = line + strlen(gpg_sig_header) + 1;
1074+
other_signature = 0;
1075+
}
1076+
else if (starts_with(line, "gpgsig"))
1077+
other_signature = 1;
1078+
else if (other_signature && line[0] != ' ')
1079+
other_signature = 0;
10631080
if (sig) {
10641081
strbuf_add(signature, sig, next - sig);
10651082
saw_signature = 1;
@@ -1068,12 +1085,12 @@ int parse_signed_commit(const struct commit *commit,
10681085
if (*line == '\n')
10691086
/* dump the whole remainder of the buffer */
10701087
next = tail;
1071-
strbuf_add(payload, line, next - line);
1088+
if (!other_signature)
1089+
strbuf_add(payload, line, next - line);
10721090
in_signature = 0;
10731091
}
10741092
line = next;
10751093
}
1076-
unuse_commit_buffer(commit, buffer);
10771094
return saw_signature;
10781095
}
10791096

@@ -1082,57 +1099,67 @@ int remove_signature(struct strbuf *buf)
10821099
const char *line = buf->buf;
10831100
const char *tail = buf->buf + buf->len;
10841101
int in_signature = 0;
1085-
const char *sig_start = NULL;
1086-
const char *sig_end = NULL;
1102+
struct sigbuf {
1103+
const char *start;
1104+
const char *end;
1105+
} sigs[2], *sigp = &sigs[0];
1106+
int i;
1107+
const char *orig_buf = buf->buf;
1108+
1109+
memset(sigs, 0, sizeof(sigs));
10871110

10881111
while (line < tail) {
10891112
const char *next = memchr(line, '\n', tail - line);
10901113
next = next ? next + 1 : tail;
10911114

10921115
if (in_signature && line[0] == ' ')
1093-
sig_end = next;
1116+
sigp->end = next;
10941117
else if (starts_with(line, "gpgsig")) {
10951118
int i;
10961119
for (i = 1; i < GIT_HASH_NALGOS; i++) {
10971120
const char *p;
10981121
if (skip_prefix(line, gpg_sig_headers[i], &p) &&
10991122
*p == ' ') {
1100-
sig_start = line;
1101-
sig_end = next;
1123+
sigp->start = line;
1124+
sigp->end = next;
11021125
in_signature = 1;
11031126
}
11041127
}
11051128
} else {
11061129
if (*line == '\n')
11071130
/* dump the whole remainder of the buffer */
11081131
next = tail;
1132+
if (in_signature && sigp - sigs != ARRAY_SIZE(sigs))
1133+
sigp++;
11091134
in_signature = 0;
11101135
}
11111136
line = next;
11121137
}
11131138

1114-
if (sig_start)
1115-
strbuf_remove(buf, sig_start - buf->buf, sig_end - sig_start);
1139+
for (i = ARRAY_SIZE(sigs) - 1; i >= 0; i--)
1140+
if (sigs[i].start)
1141+
strbuf_remove(buf, sigs[i].start - orig_buf, sigs[i].end - sigs[i].start);
11161142

1117-
return sig_start != NULL;
1143+
return sigs[0].start != NULL;
11181144
}
11191145

11201146
static void handle_signed_tag(struct commit *parent, struct commit_extra_header ***tail)
11211147
{
11221148
struct merge_remote_desc *desc;
11231149
struct commit_extra_header *mergetag;
11241150
char *buf;
1125-
unsigned long size, len;
1151+
unsigned long size;
11261152
enum object_type type;
1153+
struct strbuf payload = STRBUF_INIT;
1154+
struct strbuf signature = STRBUF_INIT;
11271155

11281156
desc = merge_remote_util(parent);
11291157
if (!desc || !desc->obj)
11301158
return;
11311159
buf = read_object_file(&desc->obj->oid, &type, &size);
11321160
if (!buf || type != OBJ_TAG)
11331161
goto free_return;
1134-
len = parse_signature(buf, size);
1135-
if (size == len)
1162+
if (!parse_signature(buf, size, &payload, &signature))
11361163
goto free_return;
11371164
/*
11381165
* 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
11511178

11521179
**tail = mergetag;
11531180
*tail = &mergetag->next;
1181+
strbuf_release(&payload);
1182+
strbuf_release(&signature);
11541183
return;
11551184

11561185
free_return:
@@ -1165,7 +1194,7 @@ int check_commit_signature(const struct commit *commit, struct signature_check *
11651194

11661195
sigc->result = 'N';
11671196

1168-
if (parse_signed_commit(commit, &payload, &signature) <= 0)
1197+
if (parse_signed_commit(commit, &payload, &signature, the_hash_algo) <= 0)
11691198
goto out;
11701199
ret = check_signature(payload.buf, payload.len, signature.buf,
11711200
signature.len, sigc);
@@ -1515,7 +1544,7 @@ int commit_tree_extended(const char *msg, size_t msg_len,
15151544
if (encoding_is_utf8 && !verify_utf8(&buffer))
15161545
fprintf(stderr, _(commit_utf8_warn));
15171546

1518-
if (sign_commit && do_sign_commit(&buffer, sign_commit)) {
1547+
if (sign_commit && sign_with_header(&buffer, sign_commit)) {
15191548
result = -1;
15201549
goto out;
15211550
}

commit.h

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -319,7 +319,8 @@ void set_merge_remote_desc(struct commit *commit,
319319
struct commit *get_merge_parent(const char *name);
320320

321321
int parse_signed_commit(const struct commit *commit,
322-
struct strbuf *message, struct strbuf *signature);
322+
struct strbuf *message, struct strbuf *signature,
323+
const struct git_hash_algo *algop);
323324
int remove_signature(struct strbuf *buf);
324325

325326
/*
@@ -361,4 +362,13 @@ int compare_commits_by_gen_then_commit_date(const void *a_, const void *b_, void
361362
LAST_ARG_MUST_BE_NULL
362363
int run_commit_hook(int editor_is_used, const char *index_file, const char *name, ...);
363364

365+
/* Sign a commit or tag buffer, storing the result in a header. */
366+
int sign_with_header(struct strbuf *buf, const char *keyid);
367+
/* Parse the signature out of a header. */
368+
int parse_buffer_signed_by_header(const char *buffer,
369+
unsigned long size,
370+
struct strbuf *payload,
371+
struct strbuf *signature,
372+
const struct git_hash_algo *algop);
373+
364374
#endif /* COMMIT_H */

fmt-merge-msg.c

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -510,22 +510,28 @@ static void fmt_merge_msg_sigs(struct strbuf *out)
510510
for (i = 0; i < origins.nr; i++) {
511511
struct object_id *oid = origins.items[i].util;
512512
enum object_type type;
513-
unsigned long size, len;
513+
unsigned long size;
514514
char *buf = read_object_file(oid, &type, &size);
515+
char *origbuf = buf;
516+
unsigned long len = size;
515517
struct signature_check sigc = { NULL };
516-
struct strbuf sig = STRBUF_INIT;
518+
struct strbuf payload = STRBUF_INIT, sig = STRBUF_INIT;
517519

518520
if (!buf || type != OBJ_TAG)
519521
goto next;
520-
len = parse_signature(buf, size);
521522

522-
if (size == len)
523-
; /* merely annotated */
524-
else if (check_signature(buf, len, buf + len, size - len, &sigc) &&
525-
!sigc.gpg_output)
526-
strbuf_addstr(&sig, "gpg verification failed.\n");
527-
else
528-
strbuf_addstr(&sig, sigc.gpg_output);
523+
if (!parse_signature(buf, size, &payload, &sig))
524+
;/* merely annotated */
525+
else {
526+
buf = payload.buf;
527+
len = payload.len;
528+
if (check_signature(payload.buf, payload.len, sig.buf,
529+
sig.len, &sigc) &&
530+
!sigc.gpg_output)
531+
strbuf_addstr(&sig, "gpg verification failed.\n");
532+
else
533+
strbuf_addstr(&sig, sigc.gpg_output);
534+
}
529535
signature_check_clear(&sigc);
530536

531537
if (!tag_number++) {
@@ -548,9 +554,10 @@ static void fmt_merge_msg_sigs(struct strbuf *out)
548554
strlen(origins.items[i].string));
549555
fmt_tag_signature(&tagbuf, &sig, buf, len);
550556
}
557+
strbuf_release(&payload);
551558
strbuf_release(&sig);
552559
next:
553-
free(buf);
560+
free(origbuf);
554561
}
555562
if (tagbuf.len) {
556563
strbuf_addch(out, '\n');

gpg-interface.c

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#include "cache.h"
2+
#include "commit.h"
23
#include "config.h"
34
#include "run-command.h"
45
#include "strbuf.h"
@@ -345,7 +346,7 @@ void print_signature_buffer(const struct signature_check *sigc, unsigned flags)
345346
fputs(output, stderr);
346347
}
347348

348-
size_t parse_signature(const char *buf, size_t size)
349+
size_t parse_signed_buffer(const char *buf, size_t size)
349350
{
350351
size_t len = 0;
351352
size_t match = size;
@@ -361,6 +362,18 @@ size_t parse_signature(const char *buf, size_t size)
361362
return match;
362363
}
363364

365+
int parse_signature(const char *buf, size_t size, struct strbuf *payload, struct strbuf *signature)
366+
{
367+
size_t match = parse_signed_buffer(buf, size);
368+
if (match != size) {
369+
strbuf_add(payload, buf, match);
370+
remove_signature(payload);
371+
strbuf_add(signature, buf + match, size - match);
372+
return 1;
373+
}
374+
return 0;
375+
}
376+
364377
void set_signing_key(const char *key)
365378
{
366379
free(configured_signing_key);

gpg-interface.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,13 +37,20 @@ struct signature_check {
3737

3838
void signature_check_clear(struct signature_check *sigc);
3939

40+
/*
41+
* Look at a GPG signed tag object. If such a signature exists, store it in
42+
* signature and the signed content in payload. Return 1 if a signature was
43+
* found, and 0 otherwise.
44+
*/
45+
int parse_signature(const char *buf, size_t size, struct strbuf *payload, struct strbuf *signature);
46+
4047
/*
4148
* Look at GPG signed content (e.g. a signed tag object), whose
4249
* payload is followed by a detached signature on it. Return the
4350
* offset where the embedded detached signature begins, or the end of
4451
* the data when there is no such signature.
4552
*/
46-
size_t parse_signature(const char *buf, size_t size);
53+
size_t parse_signed_buffer(const char *buf, size_t size);
4754

4855
/*
4956
* Create a detached signature for the contents of "buffer" and append

0 commit comments

Comments
 (0)