gpg-interface: improve interface for parsing tags
We have a function which parses a buffer with a signature at the end, parse_signature, and this function is used for signed tags. However, we'll need to store values for multiple algorithms, and we'll do this by using a header for the non-default algorithm. Adjust the parse_signature interface to store the parsed data in two strbufs and turn the existing function into parse_signed_buffer. The latter is still used in places where we know we always have a signed buffer, such as push certs. Adjust all the callers to deal with this new interface. Signed-off-by: brian m. carlson <sandals@crustytoothpaste.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
brian m. carlson committed
Feb 11, 2021 at 02:08 UTC
482c119186987110bfccf705a5ac75d399b08766
9 files changed
+87
-39
builtin/receive-pack.c
+2
-2
@@ -764,7 +764,7 @@ static void prepare_push_cert_sha1(struct child_process *proc)
764
765
memset(&sigcheck, '\0', sizeof(sigcheck));
766
767
- bogs = parse_signature(push_cert.buf, push_cert.len);
767
+ bogs = parse_signed_buffer(push_cert.buf, push_cert.len);
768
check_signature(push_cert.buf, bogs, push_cert.buf + bogs,
769
push_cert.len - bogs, &sigcheck);
770
@@ -2050,7 +2050,7 @@ static void queue_commands_from_cert(struct command **tail,
2050
die("malformed push certificate %.*s", 100, push_cert->buf);
2051
else
2052
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);
2054
2055
while (boc < eoc) {
2056
const char *eol = memchr(boc, '\n', eoc - boc);
builtin/tag.c
+12
-4
@@ -174,11 +174,17 @@ static void write_tag_body(int fd, const struct object_id *oid)
174
{
175
unsigned long size;
176
enum object_type type;
177
- char *buf, *sp;
177
+ char *buf, *sp, *orig;
178
+ struct strbuf payload = STRBUF_INIT;
179
+ struct strbuf signature = STRBUF_INIT;
180
179
- buf = read_object_file(oid, &type, &size);
181
+ orig = buf = read_object_file(oid, &type, &size);
182
if (!buf)
183
return;
184
+ if (parse_signature(buf, size, &payload, &signature)) {
185
+ buf = payload.buf;
186
+ size = payload.len;
187
+ }
188
/* skip header */
189
sp = strstr(buf, "\n\n");
190
@@ -187,9 +193,11 @@ static void write_tag_body(int fd, const struct object_id *oid)
193
return;
194
}
195
sp += 2; /* skip the 2 LFs */
190
- write_or_die(fd, sp, parse_signature(sp, buf + size - sp));
196
+ write_or_die(fd, sp, buf + size - sp);
197
192
- free(buf);
198
+ free(orig);
199
+ strbuf_release(&payload);
200
+ strbuf_release(&signature);
201
}
202
203
static int build_tag_object(struct strbuf *buf, int sign, struct object_id *result)
commit.c
+6
-3
@@ -1136,8 +1136,10 @@ static void handle_signed_tag(struct commit *parent, struct commit_extra_header
1136
struct merge_remote_desc *desc;
1137
struct commit_extra_header *mergetag;
1138
char *buf;
1139
- unsigned long size, len;
1139
+ unsigned long size;
1140
enum object_type type;
1141
+ struct strbuf payload = STRBUF_INIT;
1142
+ struct strbuf signature = STRBUF_INIT;
1143
1144
desc = merge_remote_util(parent);
1145
if (!desc || !desc->obj)
@@ -1145,8 +1147,7 @@ static void handle_signed_tag(struct commit *parent, struct commit_extra_header
1147
buf = read_object_file(&desc->obj->oid, &type, &size);
1148
if (!buf || type != OBJ_TAG)
1149
goto free_return;
1148
- len = parse_signature(buf, size);
1149
- if (size == len)
1150
+ if (!parse_signature(buf, size, &payload, &signature))
1151
goto free_return;
1152
/*
1153
* We could verify this signature and either omit the tag when
@@ -1165,6 +1166,8 @@ static void handle_signed_tag(struct commit *parent, struct commit_extra_header
1166
1167
**tail = mergetag;
1168
*tail = &mergetag->next;
1169
+ strbuf_release(&payload);
1170
+ strbuf_release(&signature);
1171
return;
1172
1173
free_return:
fmt-merge-msg.c
+18
-11
@@ -509,22 +509,28 @@ static void fmt_merge_msg_sigs(struct strbuf *out)
509
for (i = 0; i < origins.nr; i++) {
510
struct object_id *oid = origins.items[i].util;
511
enum object_type type;
512
- unsigned long size, len;
512
+ unsigned long size;
513
char *buf = read_object_file(oid, &type, &size);
514
+ char *origbuf = buf;
515
+ unsigned long len = size;
516
struct signature_check sigc = { NULL };
515
- struct strbuf sig = STRBUF_INIT;
517
+ struct strbuf payload = STRBUF_INIT, sig = STRBUF_INIT;
518
519
if (!buf || type != OBJ_TAG)
520
goto next;
519
- len = parse_signature(buf, size);
521
521
- if (size == len)
522
- ; /* merely annotated */
523
- else if (check_signature(buf, len, buf + len, size - len, &sigc) &&
524
- !sigc.gpg_output)
525
- strbuf_addstr(&sig, "gpg verification failed.\n");
526
- else
527
- strbuf_addstr(&sig, sigc.gpg_output);
522
+ if (!parse_signature(buf, size, &payload, &sig))
523
+ ;/* merely annotated */
524
+ else {
525
+ buf = payload.buf;
526
+ len = payload.len;
527
+ if (check_signature(payload.buf, payload.len, sig.buf,
528
+ sig.len, &sigc) &&
529
+ !sigc.gpg_output)
530
+ strbuf_addstr(&sig, "gpg verification failed.\n");
531
+ else
532
+ strbuf_addstr(&sig, sigc.gpg_output);
533
+ }
534
signature_check_clear(&sigc);
535
536
if (!tag_number++) {
@@ -547,9 +553,10 @@ static void fmt_merge_msg_sigs(struct strbuf *out)
553
strlen(origins.items[i].string));
554
fmt_tag_signature(&tagbuf, &sig, buf, len);
555
}
556
+ strbuf_release(&payload);
557
strbuf_release(&sig);
558
next:
552
- free(buf);
559
+ free(origbuf);
560
}
561
if (tagbuf.len) {
562
strbuf_addch(out, '\n');
gpg-interface.c
+12
-1
@@ -345,7 +345,7 @@ void print_signature_buffer(const struct signature_check *sigc, unsigned flags)
345
fputs(output, stderr);
346
}
347
348
-size_t parse_signature(const char *buf, size_t size)
348
+size_t parse_signed_buffer(const char *buf, size_t size)
349
{
350
size_t len = 0;
351
size_t match = size;
@@ -361,6 +361,17 @@ size_t parse_signature(const char *buf, size_t size)
361
return match;
362
}
363
364
+int parse_signature(const char *buf, size_t size, struct strbuf *payload, struct strbuf *signature)
365
+{
366
+ size_t match = parse_signed_buffer(buf, size);
367
+ if (match != size) {
368
+ strbuf_add(payload, buf, match);
369
+ strbuf_add(signature, buf + match, size - match);
370
+ return 1;
371
+ }
372
+ return 0;
373
+}
374
+
375
void set_signing_key(const char *key)
376
{
377
free(configured_signing_key);
gpg-interface.h
+8
-1
@@ -37,13 +37,20 @@ struct signature_check {
37
38
void signature_check_clear(struct signature_check *sigc);
39
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
+
47
/*
48
* Look at GPG signed content (e.g. a signed tag object), whose
49
* payload is followed by a detached signature on it. Return the
50
* offset where the embedded detached signature begins, or the end of
51
* the data when there is no such signature.
52
*/
46
-size_t parse_signature(const char *buf, size_t size);
53
+size_t parse_signed_buffer(const char *buf, size_t size);
54
55
/*
56
* Create a detached signature for the contents of "buffer" and append
log-tree.c
+7
-6
@@ -548,7 +548,8 @@ static int show_one_mergetag(struct commit *commit,
548
struct strbuf verify_message;
549
struct signature_check sigc = { 0 };
550
int status, nth;
551
- size_t payload_size;
551
+ struct strbuf payload = STRBUF_INIT;
552
+ struct strbuf signature = STRBUF_INIT;
553
554
hash_object_file(the_hash_algo, extra->value, extra->len,
555
type_name(OBJ_TAG), &oid);
@@ -571,13 +572,11 @@ static int show_one_mergetag(struct commit *commit,
572
strbuf_addf(&verify_message,
573
"parent #%d, tagged '%s'\n", nth + 1, tag->tag);
574
574
- payload_size = parse_signature(extra->value, extra->len);
575
status = -1;
576
- if (extra->len > payload_size) {
576
+ if (parse_signature(extra->value, extra->len, &payload, &signature)) {
577
/* could have a good signature */
578
- status = check_signature(extra->value, payload_size,
579
- extra->value + payload_size,
580
- extra->len - payload_size, &sigc);
578
+ status = check_signature(payload.buf, payload.len,
579
+ signature.buf, signature.len, &sigc);
580
if (sigc.gpg_output)
581
strbuf_addstr(&verify_message, sigc.gpg_output);
582
else
@@ -588,6 +587,8 @@ static int show_one_mergetag(struct commit *commit,
587
588
show_sig_lines(opt, status, verify_message.buf);
589
strbuf_release(&verify_message);
590
+ strbuf_release(&payload);
591
+ strbuf_release(&signature);
592
return 0;
593
}
594
ref-filter.c
+14
-4
@@ -1215,7 +1215,13 @@ static void find_subpos(const char *buf,
1215
size_t *nonsiglen,
1216
const char **sig, size_t *siglen)
1217
{
1218
+ struct strbuf payload = STRBUF_INIT;
1219
+ struct strbuf signature = STRBUF_INIT;
1220
const char *eol;
1221
+ const char *end = buf + strlen(buf);
1222
+ const char *sigstart;
1223
+
1224
+
1225
/* skip past header until we hit empty line */
1226
while (*buf && *buf != '\n') {
1227
eol = strchrnul(buf, '\n');
@@ -1228,14 +1234,15 @@ static void find_subpos(const char *buf,
1234
buf++;
1235
1236
/* parse signature first; we might not even have a subject line */
1231
- *sig = buf + parse_signature(buf, strlen(buf));
1232
- *siglen = strlen(*sig);
1237
+ parse_signature(buf, end - buf, &payload, &signature);
1238
+ *sig = strbuf_detach(&signature, siglen);
1239
+ sigstart = buf + parse_signed_buffer(buf, strlen(buf));
1240
1241
/* subject is first non-empty line */
1242
*sub = buf;
1243
/* subject goes to first empty line before signature begins */
1244
if ((eol = strstr(*sub, "\n\n"))) {
1238
- eol = eol < *sig ? eol : *sig;
1245
+ eol = eol < sigstart ? eol : sigstart;
1246
/* check if message uses CRLF */
1247
} else if (! (eol = strstr(*sub, "\r\n\r\n"))) {
1248
/* treat whole message as subject */
@@ -1253,7 +1260,7 @@ static void find_subpos(const char *buf,
1260
buf++;
1261
*body = buf;
1262
*bodylen = strlen(buf);
1256
- *nonsiglen = *sig - buf;
1263
+ *nonsiglen = sigstart - buf;
1264
}
1265
1266
/*
@@ -1291,6 +1298,7 @@ static void grab_sub_body_contents(struct atom_value *val, int deref, void *buf)
1298
struct used_atom *atom = &used_atom[i];
1299
const char *name = atom->name;
1300
struct atom_value *v = &val[i];
1301
+
1302
if (!!deref != (*name == '*'))
1303
continue;
1304
if (deref)
@@ -1336,7 +1344,9 @@ static void grab_sub_body_contents(struct atom_value *val, int deref, void *buf)
1344
v->s = strbuf_detach(&s, NULL);
1345
} else if (atom->u.contents.option == C_BARE)
1346
v->s = xstrdup(subpos);
1347
+
1348
}
1349
+ free((void *)sigpos);
1350
}
1351
1352
/*
tag.c
+8
-7
@@ -13,26 +13,27 @@ const char *tag_type = "tag";
13
static int run_gpg_verify(const char *buf, unsigned long size, unsigned flags)
14
{
15
struct signature_check sigc;
16
- size_t payload_size;
16
+ struct strbuf payload = STRBUF_INIT;
17
+ struct strbuf signature = STRBUF_INIT;
18
int ret;
19
20
memset(&sigc, 0, sizeof(sigc));
21
21
- payload_size = parse_signature(buf, size);
22
-
23
- if (size == payload_size) {
22
+ if (!parse_signature(buf, size, &payload, &signature)) {
23
if (flags & GPG_VERIFY_VERBOSE)
25
- write_in_full(1, buf, payload_size);
24
+ write_in_full(1, buf, size);
25
return error("no signature found");
26
}
27
29
- ret = check_signature(buf, payload_size, buf + payload_size,
30
- size - payload_size, &sigc);
28
+ ret = check_signature(payload.buf, payload.len, signature.buf,
29
+ signature.len, &sigc);
30
31
if (!(flags & GPG_VERIFY_OMIT_STATUS))
32
print_signature_buffer(&sigc, flags);
33
34
signature_check_clear(&sigc);
35
+ strbuf_release(&payload);
36
+ strbuf_release(&signature);
37
return ret;
38
}
39