]> git.ipfire.org Git - thirdparty/git.git/commitdiff
gpg-interface: improve interface for parsing tags
authorbrian m. carlson <sandals@crustytoothpaste.net>
Thu, 11 Feb 2021 02:08:03 +0000 (02:08 +0000)
committerJunio C Hamano <gitster@pobox.com>
Thu, 11 Feb 2021 07:35:42 +0000 (23:35 -0800)
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>
builtin/receive-pack.c
builtin/tag.c
commit.c
fmt-merge-msg.c
gpg-interface.c
gpg-interface.h
log-tree.c
ref-filter.c
tag.c

index d49d050e6e57c0dd8f795a36d6f1a64aa7c8ddee..b89ce31bf23104da3343c3b49c46b597bc117f66 100644 (file)
@@ -764,7 +764,7 @@ static void prepare_push_cert_sha1(struct child_process *proc)
 
                memset(&sigcheck, '\0', sizeof(sigcheck));
 
-               bogs = parse_signature(push_cert.buf, push_cert.len);
+               bogs = parse_signed_buffer(push_cert.buf, push_cert.len);
                check_signature(push_cert.buf, bogs, push_cert.buf + bogs,
                                push_cert.len - bogs, &sigcheck);
 
@@ -2050,7 +2050,7 @@ static void queue_commands_from_cert(struct command **tail,
                die("malformed push certificate %.*s", 100, push_cert->buf);
        else
                boc += 2;
-       eoc = push_cert->buf + parse_signature(push_cert->buf, push_cert->len);
+       eoc = push_cert->buf + parse_signed_buffer(push_cert->buf, push_cert->len);
 
        while (boc < eoc) {
                const char *eol = memchr(boc, '\n', eoc - boc);
index ecf011776dc057421ce4862fa894cb48525b2035..7162f4ccc587162325795f899bc3e5982a0b5918 100644 (file)
@@ -174,11 +174,17 @@ static void write_tag_body(int fd, const struct object_id *oid)
 {
        unsigned long size;
        enum object_type type;
-       char *buf, *sp;
+       char *buf, *sp, *orig;
+       struct strbuf payload = STRBUF_INIT;
+       struct strbuf signature = STRBUF_INIT;
 
-       buf = read_object_file(oid, &type, &size);
+       orig = buf = read_object_file(oid, &type, &size);
        if (!buf)
                return;
+       if (parse_signature(buf, size, &payload, &signature)) {
+               buf = payload.buf;
+               size = payload.len;
+       }
        /* skip header */
        sp = strstr(buf, "\n\n");
 
@@ -187,9 +193,11 @@ static void write_tag_body(int fd, const struct object_id *oid)
                return;
        }
        sp += 2; /* skip the 2 LFs */
-       write_or_die(fd, sp, parse_signature(sp, buf + size - sp));
+       write_or_die(fd, sp, buf + size - sp);
 
-       free(buf);
+       free(orig);
+       strbuf_release(&payload);
+       strbuf_release(&signature);
 }
 
 static int build_tag_object(struct strbuf *buf, int sign, struct object_id *result)
index d2908cbbb090cbf66e647079d5ca18d62cc77cc0..d9ccbae51963f88edab5cb933341b62239893877 100644 (file)
--- a/commit.c
+++ b/commit.c
@@ -1136,8 +1136,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)
@@ -1145,8 +1147,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
@@ -1165,6 +1166,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:
index 9a664a4a5832daba2a69e1d91d996eddb1f8bb56..7fd99f0ac19fd8747cc142e991bde4e713740db9 100644 (file)
@@ -509,22 +509,28 @@ static void fmt_merge_msg_sigs(struct strbuf *out)
        for (i = 0; i < origins.nr; i++) {
                struct object_id *oid = origins.items[i].util;
                enum object_type type;
-               unsigned long size, len;
+               unsigned long size;
                char *buf = read_object_file(oid, &type, &size);
+               char *origbuf = buf;
+               unsigned long len = size;
                struct signature_check sigc = { NULL };
-               struct strbuf sig = STRBUF_INIT;
+               struct strbuf payload = STRBUF_INIT, sig = STRBUF_INIT;
 
                if (!buf || type != OBJ_TAG)
                        goto next;
-               len = parse_signature(buf, size);
 
-               if (size == len)
-                       ; /* merely annotated */
-               else if (check_signature(buf, len, buf + len, size - len, &sigc) &&
-                       !sigc.gpg_output)
-                       strbuf_addstr(&sig, "gpg verification failed.\n");
-               else
-                       strbuf_addstr(&sig, sigc.gpg_output);
+               if (!parse_signature(buf, size, &payload, &sig))
+                       ;/* merely annotated */
+               else {
+                       buf = payload.buf;
+                       len = payload.len;
+                       if (check_signature(payload.buf, payload.len, sig.buf,
+                                        sig.len, &sigc) &&
+                               !sigc.gpg_output)
+                               strbuf_addstr(&sig, "gpg verification failed.\n");
+                       else
+                               strbuf_addstr(&sig, sigc.gpg_output);
+               }
                signature_check_clear(&sigc);
 
                if (!tag_number++) {
@@ -547,9 +553,10 @@ static void fmt_merge_msg_sigs(struct strbuf *out)
                                        strlen(origins.items[i].string));
                        fmt_tag_signature(&tagbuf, &sig, buf, len);
                }
+               strbuf_release(&payload);
                strbuf_release(&sig);
        next:
-               free(buf);
+               free(origbuf);
        }
        if (tagbuf.len) {
                strbuf_addch(out, '\n');
index b49927083661c8ca695112b8432691f17ed6d835..c6274c14af435b593ba928f9ca7b8bbec96bc28e 100644 (file)
@@ -345,7 +345,7 @@ void print_signature_buffer(const struct signature_check *sigc, unsigned flags)
                fputs(output, stderr);
 }
 
-size_t parse_signature(const char *buf, size_t size)
+size_t parse_signed_buffer(const char *buf, size_t size)
 {
        size_t len = 0;
        size_t match = size;
@@ -361,6 +361,17 @@ size_t parse_signature(const char *buf, size_t size)
        return match;
 }
 
+int parse_signature(const char *buf, size_t size, struct strbuf *payload, struct strbuf *signature)
+{
+       size_t match = parse_signed_buffer(buf, size);
+       if (match != size) {
+               strbuf_add(payload, buf, match);
+               strbuf_add(signature, buf + match, size - match);
+               return 1;
+       }
+       return 0;
+}
+
 void set_signing_key(const char *key)
 {
        free(configured_signing_key);
index f4e9b4f3715a0b0d4be3ef526388bf6b87b56fda..80567e4894868d5d7a192cab0afb9ca9c09cb70d 100644 (file)
@@ -37,13 +37,20 @@ struct signature_check {
 
 void signature_check_clear(struct signature_check *sigc);
 
+/*
+ * Look at a GPG signed tag object.  If such a signature exists, store it in
+ * signature and the signed content in payload.  Return 1 if a signature was
+ * found, and 0 otherwise.
+ */
+int parse_signature(const char *buf, size_t size, struct strbuf *payload, struct strbuf *signature);
+
 /*
  * Look at GPG signed content (e.g. a signed tag object), whose
  * payload is followed by a detached signature on it.  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, size_t size);
+size_t parse_signed_buffer(const char *buf, size_t size);
 
 /*
  * Create a detached signature for the contents of "buffer" and append
index 7e0335e548a014f3463dffff3a63a7c5d4210b2b..b025c8da93d1d19469d0d8b20dab0b93bd6fc51b 100644 (file)
@@ -548,7 +548,8 @@ static int show_one_mergetag(struct commit *commit,
        struct strbuf verify_message;
        struct signature_check sigc = { 0 };
        int status, nth;
-       size_t payload_size;
+       struct strbuf payload = STRBUF_INIT;
+       struct strbuf signature = STRBUF_INIT;
 
        hash_object_file(the_hash_algo, extra->value, extra->len,
                         type_name(OBJ_TAG), &oid);
@@ -571,13 +572,11 @@ static int show_one_mergetag(struct commit *commit,
                strbuf_addf(&verify_message,
                            "parent #%d, tagged '%s'\n", nth + 1, tag->tag);
 
-       payload_size = parse_signature(extra->value, extra->len);
        status = -1;
-       if (extra->len > payload_size) {
+       if (parse_signature(extra->value, extra->len, &payload, &signature)) {
                /* could have a good signature */
-               status = check_signature(extra->value, payload_size,
-                                        extra->value + payload_size,
-                                        extra->len - payload_size, &sigc);
+               status = check_signature(payload.buf, payload.len,
+                                        signature.buf, signature.len, &sigc);
                if (sigc.gpg_output)
                        strbuf_addstr(&verify_message, sigc.gpg_output);
                else
@@ -588,6 +587,8 @@ static int show_one_mergetag(struct commit *commit,
 
        show_sig_lines(opt, status, verify_message.buf);
        strbuf_release(&verify_message);
+       strbuf_release(&payload);
+       strbuf_release(&signature);
        return 0;
 }
 
index 606f638ab1962cdd3630dc8899b283a0d0141a8d..a4c68cf451b0867cc535cf0cc017bda6d14e5200 100644 (file)
@@ -1215,7 +1215,13 @@ static void find_subpos(const char *buf,
                        size_t *nonsiglen,
                        const char **sig, size_t *siglen)
 {
+       struct strbuf payload = STRBUF_INIT;
+       struct strbuf signature = STRBUF_INIT;
        const char *eol;
+       const char *end = buf + strlen(buf);
+       const char *sigstart;
+
+
        /* skip past header until we hit empty line */
        while (*buf && *buf != '\n') {
                eol = strchrnul(buf, '\n');
@@ -1228,14 +1234,15 @@ static void find_subpos(const char *buf,
                buf++;
 
        /* parse signature first; we might not even have a subject line */
-       *sig = buf + parse_signature(buf, strlen(buf));
-       *siglen = strlen(*sig);
+       parse_signature(buf, end - buf, &payload, &signature);
+       *sig = strbuf_detach(&signature, siglen);
+       sigstart = buf + parse_signed_buffer(buf, strlen(buf));
 
        /* subject is first non-empty line */
        *sub = buf;
        /* subject goes to first empty line before signature begins */
        if ((eol = strstr(*sub, "\n\n"))) {
-               eol = eol < *sig ? eol : *sig;
+               eol = eol < sigstart ? eol : sigstart;
        /* check if message uses CRLF */
        } else if (! (eol = strstr(*sub, "\r\n\r\n"))) {
                /* treat whole message as subject */
@@ -1253,7 +1260,7 @@ static void find_subpos(const char *buf,
                buf++;
        *body = buf;
        *bodylen = strlen(buf);
-       *nonsiglen = *sig - buf;
+       *nonsiglen = sigstart - buf;
 }
 
 /*
@@ -1291,6 +1298,7 @@ static void grab_sub_body_contents(struct atom_value *val, int deref, void *buf)
                struct used_atom *atom = &used_atom[i];
                const char *name = atom->name;
                struct atom_value *v = &val[i];
+
                if (!!deref != (*name == '*'))
                        continue;
                if (deref)
@@ -1336,7 +1344,9 @@ static void grab_sub_body_contents(struct atom_value *val, int deref, void *buf)
                        v->s = strbuf_detach(&s, NULL);
                } else if (atom->u.contents.option == C_BARE)
                        v->s = xstrdup(subpos);
+
        }
+       free((void *)sigpos);
 }
 
 /*
diff --git a/tag.c b/tag.c
index 1ed2684e45bd50d051ade60cc6b66c8c44fbed59..3e18a41841485e8138d7ccaf36e24cc99e5d81cd 100644 (file)
--- a/tag.c
+++ b/tag.c
@@ -13,26 +13,27 @@ const char *tag_type = "tag";
 static int run_gpg_verify(const char *buf, unsigned long size, unsigned flags)
 {
        struct signature_check sigc;
-       size_t payload_size;
+       struct strbuf payload = STRBUF_INIT;
+       struct strbuf signature = STRBUF_INIT;
        int ret;
 
        memset(&sigc, 0, sizeof(sigc));
 
-       payload_size = parse_signature(buf, size);
-
-       if (size == payload_size) {
+       if (!parse_signature(buf, size, &payload, &signature)) {
                if (flags & GPG_VERIFY_VERBOSE)
-                       write_in_full(1, buf, payload_size);
+                       write_in_full(1, buf, size);
                return error("no signature found");
        }
 
-       ret = check_signature(buf, payload_size, buf + payload_size,
-                               size - payload_size, &sigc);
+       ret = check_signature(payload.buf, payload.len, signature.buf,
+                               signature.len, &sigc);
 
        if (!(flags & GPG_VERIFY_OMIT_STATUS))
                print_signature_buffer(&sigc, flags);
 
        signature_check_clear(&sigc);
+       strbuf_release(&payload);
+       strbuf_release(&signature);
        return ret;
 }