From patchwork Mon Jan 18 23:49:10 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "brian m. carlson" X-Patchwork-Id: 12028435 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-18.8 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER, INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 46DFDC433E0 for ; Mon, 18 Jan 2021 23:51:22 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 0FA2922E00 for ; Mon, 18 Jan 2021 23:51:21 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2389097AbhARXvG (ORCPT ); Mon, 18 Jan 2021 18:51:06 -0500 Received: from injection.crustytoothpaste.net ([192.241.140.119]:55892 "EHLO injection.crustytoothpaste.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2387806AbhARXuv (ORCPT ); Mon, 18 Jan 2021 18:50:51 -0500 Received: from camp.crustytoothpaste.net (castro.crustytoothpaste.net [75.10.60.170]) (using TLSv1.2 with cipher ECDHE-RSA-CHACHA20-POLY1305 (256/256 bits)) (No client certificate requested) by injection.crustytoothpaste.net (Postfix) with ESMTPSA id 134AA60782; Mon, 18 Jan 2021 23:50:09 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=crustytoothpaste.net; s=default; t=1611013809; bh=L7ADkjDP1frigp6VTY1f3MKD0s5aKVlbrPm/qFiCz6U=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From:Reply-To: Subject:Date:To:CC:Resent-Date:Resent-From:Resent-To:Resent-Cc: In-Reply-To:References:Content-Type:Content-Disposition; b=g3qf4bDfCd4C3J/N9wYCSoU+ZclWejYPbcLLJbyn5pHOuQJgokSkKeIJ4ZSLPQuhk 3isE0ubCN1SCepni0xzTe8z3S7W+gkXSzLInJRFM1oLdnspVDBdEwC5pIKJ9HMb6yt ml3PtUmMYl3pot+tgp9DpQS+SzRHLfTQOLs3x+hc0ei+Q+Hnpuwv+yHXvLTs7KLvqA A6uvLOlTqQ4x1R0/TIc/Ub/OMg/eDdOhna6TMBfw430kj8zUWro/YmAFLSYRC0SenT Fe2He5Zy5wgtyP4fTHtTAZDg8aivL2YR6tIvT6P9T6Jwe8FCdTFXNbHR4bE2ddQrxR b8u+UjvxXbvMysob9mFA8hWmzpPkavgFo3LOgxYTzYHybGQg28UswTac3U1Le3gU5X AJ/m3mDQAHy44Coq72/T9HxzKHoyuOej9RdCuissf+F6YH/B4G96qfvnFQXFjaRjas y3ZQzQVU6gyCgESt1hyxHfCEgaZz1nxxTZErhMNBm5kkJKRtbCK From: "brian m. carlson" To: Cc: =?utf-8?q?SZEDER_G=C3=A1bor?= Subject: [PATCH v3 1/6] ref-filter: switch some uses of unsigned long to size_t Date: Mon, 18 Jan 2021 23:49:10 +0000 Message-Id: <20210118234915.2036197-2-sandals@crustytoothpaste.net> X-Mailer: git-send-email 2.30.0.284.gd98b1dd5eaa7 In-Reply-To: <20210118234915.2036197-1-sandals@crustytoothpaste.net> References: <20210111035840.2437737-1-sandals@crustytoothpaste.net> <20210118234915.2036197-1-sandals@crustytoothpaste.net> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org In the future, we'll want to pass some of the arguments of find_subpos to strbuf_detach, which takes a size_t. This is fine on systems where that's the same size as unsigned long, but that isn't the case on all systems. Moreover, size_t makes sense since it's not possible to use a buffer here that's larger than memory anyway. Let's switch each use to size_t for these lengths in grab_sub_body_contents and find_subpos. Signed-off-by: brian m. carlson --- ref-filter.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/ref-filter.c b/ref-filter.c index aa260bfd09..606f638ab1 100644 --- a/ref-filter.c +++ b/ref-filter.c @@ -1210,10 +1210,10 @@ static void grab_person(const char *who, struct atom_value *val, int deref, void } static void find_subpos(const char *buf, - const char **sub, unsigned long *sublen, - const char **body, unsigned long *bodylen, - unsigned long *nonsiglen, - const char **sig, unsigned long *siglen) + const char **sub, size_t *sublen, + const char **body, size_t *bodylen, + size_t *nonsiglen, + const char **sig, size_t *siglen) { const char *eol; /* skip past header until we hit empty line */ @@ -1285,7 +1285,7 @@ static void grab_sub_body_contents(struct atom_value *val, int deref, void *buf) { int i; const char *subpos = NULL, *bodypos = NULL, *sigpos = NULL; - unsigned long sublen = 0, bodylen = 0, nonsiglen = 0, siglen = 0; + size_t sublen = 0, bodylen = 0, nonsiglen = 0, siglen = 0; for (i = 0; i < used_atom_cnt; i++) { struct used_atom *atom = &used_atom[i]; From patchwork Mon Jan 18 23:49:11 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "brian m. carlson" X-Patchwork-Id: 12028437 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-18.8 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER, INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id EAF49C433DB for ; Mon, 18 Jan 2021 23:51:26 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id BC14E22E00 for ; Mon, 18 Jan 2021 23:51:26 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2389458AbhARXv0 (ORCPT ); Mon, 18 Jan 2021 18:51:26 -0500 Received: from injection.crustytoothpaste.net ([192.241.140.119]:55914 "EHLO injection.crustytoothpaste.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726044AbhARXvW (ORCPT ); Mon, 18 Jan 2021 18:51:22 -0500 Received: from camp.crustytoothpaste.net (castro.crustytoothpaste.net [75.10.60.170]) (using TLSv1.2 with cipher ECDHE-RSA-CHACHA20-POLY1305 (256/256 bits)) (No client certificate requested) by injection.crustytoothpaste.net (Postfix) with ESMTPSA id 7861560783; Mon, 18 Jan 2021 23:50:09 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=crustytoothpaste.net; s=default; t=1611013809; bh=uFaOdu8axthgOLwjB/5kF7RCAZQ2R6rKv7prmdn1Dno=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From:Reply-To: Subject:Date:To:CC:Resent-Date:Resent-From:Resent-To:Resent-Cc: In-Reply-To:References:Content-Type:Content-Disposition; b=m9auZvWsrg2IZLgsY0eDpEwVU2CqpVkPmU7OeaB2YKQX132e5aRZNy8OGsGcoQn6k 8u/kCoPaQ+DeaxUku8zMzXRfhsTykBCvX3gpyfrCHHcyDGRH+SepB/sz6xXWOt+yye cl5TJp0Mt7OlR7MdtpxU7HTQCskwAn5JiK8K6t15HUS+jKBhQCaP53HiBGEnY50op5 0YVclMqshMNY10/cTJF9AtJm3ZMNtOA3z9MiROqka6WR/LMYRumHsUOv7PGr5QDREv 4dI1wtp/dOv2BZIBCqmaYsBXGSbodBUQKWKkw5HRYoa0iBIrX+t81QlK9sSyF8FIMZ 5RLI2oFdRmt9cuHmasd9opkftrZ55pdFCDcz5JiRkPl2LueXZytTEUuidUhzcwx13S 0hpYlOjD8Y2fyOs2Xnnbq9kkOEZMqc0hJ8T0FQ9H8ZUU2QhnbYavJngJPc82cLeAGN CyB8MQB5ssF+YRYvzt6ah7fHvv+KNPVwXWnWj/pN1+o4td8sCUX From: "brian m. carlson" To: Cc: =?utf-8?q?SZEDER_G=C3=A1bor?= Subject: [PATCH v3 2/6] commit: ignore additional signatures when parsing signed commits Date: Mon, 18 Jan 2021 23:49:11 +0000 Message-Id: <20210118234915.2036197-3-sandals@crustytoothpaste.net> X-Mailer: git-send-email 2.30.0.284.gd98b1dd5eaa7 In-Reply-To: <20210118234915.2036197-1-sandals@crustytoothpaste.net> References: <20210111035840.2437737-1-sandals@crustytoothpaste.net> <20210118234915.2036197-1-sandals@crustytoothpaste.net> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org When we create a commit with multiple signatures, neither of these signatures includes the other. Consequently, when we produce the payload which has been signed so we can verify the commit, we must strip off any other signatures, or the payload will differ from what was signed. Do so, and in preparation for verifying with multiple algorithms, pass the algorithm we want to verify into parse_signed_commit. Signed-off-by: brian m. carlson --- commit.c | 54 +++++++++++++++++++++++++--------------- commit.h | 3 ++- log-tree.c | 2 +- t/t7510-signed-commit.sh | 43 +++++++++++++++++++++++++++++++- 4 files changed, 79 insertions(+), 23 deletions(-) diff --git a/commit.c b/commit.c index bab8d5ab07..1006c85ca8 100644 --- a/commit.c +++ b/commit.c @@ -1036,20 +1036,18 @@ static int do_sign_commit(struct strbuf *buf, const char *keyid) } 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 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 +1055,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,7 +1072,8 @@ 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; @@ -1082,23 +1087,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 +1117,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) @@ -1165,7 +1179,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); diff --git a/commit.h b/commit.h index f4e7b0158e..030aa65ab8 100644 --- a/commit.h +++ b/commit.h @@ -317,7 +317,8 @@ void set_merge_remote_desc(struct commit *commit, struct commit *get_merge_parent(const char *name); int parse_signed_commit(const struct commit *commit, - struct strbuf *message, struct strbuf *signature); + struct strbuf *message, struct strbuf *signature, + const struct git_hash_algo *algop); int remove_signature(struct strbuf *buf); /* diff --git a/log-tree.c b/log-tree.c index fd0dde97ec..7e0335e548 100644 --- a/log-tree.c +++ b/log-tree.c @@ -502,7 +502,7 @@ static void show_signature(struct rev_info *opt, struct commit *commit) struct signature_check sigc = { 0 }; int status; - if (parse_signed_commit(commit, &payload, &signature) <= 0) + if (parse_signed_commit(commit, &payload, &signature, the_hash_algo) <= 0) goto out; status = check_signature(payload.buf, payload.len, signature.buf, diff --git a/t/t7510-signed-commit.sh b/t/t7510-signed-commit.sh index 6baaa1ad91..d78319d5c8 100755 --- a/t/t7510-signed-commit.sh +++ b/t/t7510-signed-commit.sh @@ -172,7 +172,7 @@ test_expect_success GPG 'show signed commit with signature' ' git cat-file commit initial >cat && grep -v -e "gpg: " -e "Warning: " show >show.commit && grep -e "gpg: " -e "Warning: " show >show.gpg && - grep -v "^ " cat | grep -v "^$(test_oid header) " >cat.commit && + grep -v "^ " cat | grep -v "^gpgsig.* " >cat.commit && test_cmp show.commit commit && test_cmp show.gpg verify.2 && test_cmp cat.commit verify.1 @@ -334,4 +334,45 @@ test_expect_success GPG 'show double signature with custom format' ' test_cmp expect actual ' + +test_expect_success GPG 'verify-commit verifies multiply signed commits' ' + git init multiply-signed && + cd multiply-signed && + test_commit first && + echo 1 >second && + git add second && + tree=$(git write-tree) && + parent=$(git rev-parse HEAD^{commit}) && + git commit --gpg-sign -m second && + git cat-file commit HEAD && + # Avoid trailing whitespace. + sed -e "s/^Q//" -e "s/^Z/ /" >commit <<-EOF && + Qtree $tree + Qparent $parent + Qauthor A U Thor 1112912653 -0700 + Qcommitter C O Mitter 1112912653 -0700 + Qgpgsig -----BEGIN PGP SIGNATURE----- + QZ + Q iHQEABECADQWIQRz11h0S+chaY7FTocTtvUezd5DDQUCX/uBDRYcY29tbWl0dGVy + Q QGV4YW1wbGUuY29tAAoJEBO29R7N3kMNd+8AoK1I8mhLHviPH+q2I5fIVgPsEtYC + Q AKCTqBh+VabJceXcGIZuF0Ry+udbBQ== + Q =tQ0N + Q -----END PGP SIGNATURE----- + Qgpgsig-sha256 -----BEGIN PGP SIGNATURE----- + QZ + Q iHQEABECADQWIQRz11h0S+chaY7FTocTtvUezd5DDQUCX/uBIBYcY29tbWl0dGVy + Q QGV4YW1wbGUuY29tAAoJEBO29R7N3kMN/NEAn0XO9RYSBj2dFyozi0JKSbssYMtO + Q AJwKCQ1BQOtuwz//IjU8TiS+6S4iUw== + Q =pIwP + Q -----END PGP SIGNATURE----- + Q + Qsecond + EOF + head=$(git hash-object -t commit -w commit) && + git reset --hard $head && + git verify-commit $head 2>actual && + grep "Good signature from" actual && + ! grep "BAD signature from" actual +' + test_done From patchwork Mon Jan 18 23:49:12 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "brian m. carlson" X-Patchwork-Id: 12028441 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-18.8 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER, INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 9769EC433E6 for ; Mon, 18 Jan 2021 23:51:40 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 538D422E00 for ; Mon, 18 Jan 2021 23:51:40 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2389310AbhARXvj (ORCPT ); Mon, 18 Jan 2021 18:51:39 -0500 Received: from injection.crustytoothpaste.net ([192.241.140.119]:55916 "EHLO injection.crustytoothpaste.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2387806AbhARXvW (ORCPT ); Mon, 18 Jan 2021 18:51:22 -0500 Received: from camp.crustytoothpaste.net (castro.crustytoothpaste.net [75.10.60.170]) (using TLSv1.2 with cipher ECDHE-RSA-CHACHA20-POLY1305 (256/256 bits)) (No client certificate requested) by injection.crustytoothpaste.net (Postfix) with ESMTPSA id DBC2360784; Mon, 18 Jan 2021 23:50:09 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=crustytoothpaste.net; s=default; t=1611013810; bh=gZwjNjG0rrPzkbv2N7B6QULdmlWaROoNeaLgwPl2Bhs=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From:Reply-To: Subject:Date:To:CC:Resent-Date:Resent-From:Resent-To:Resent-Cc: In-Reply-To:References:Content-Type:Content-Disposition; b=FJSex/SOR0TU+urd/U/bllGiGvNJ1YKEay+KbJSqEHkwxD1IaJA6mkNQe0TxbByUs +YnUY4Q7Hbf+QhEJAAeVB9Jc0/j2qPfTYNckOi5eV3shDYkfBVSMujGRG7sqllakaP ltEAA8hBjaEvRYT8ojBkjwJEKoVW55jHe5lCEB/qxdqnc4GaG/y1wFoFKdlZUBDR5A 8UHiZVGcICPtcj1vSsTURLTL1hku7RVDPBrLBlV7HC5n71TVu1Hr3uJK2vXAZdsVvP Aboh+afWdiber2Q0uYoEQrW0rI1J/dRRl5MJGeScYgdG+MrzIQIFWwPq8QurAp9gaC B02R/Bjzsv6I+7Ei5iv/vmtgX6HYP8O2VYHVtj8qGLTlOwOxp2mTtoV4FSWCjHS52t WfL8BKz57CE9LAvtXDLe5iMxCF/TlbgTm0HTh1+TwN1BQoN/ir11r26tdiGQSJnJe6 6sHbJI9BwysjY2dD+fBZwu0g2I80UjKNYVz22bR15T/p/dvTk0i From: "brian m. carlson" To: Cc: =?utf-8?q?SZEDER_G=C3=A1bor?= Subject: [PATCH v3 3/6] gpg-interface: improve interface for parsing tags Date: Mon, 18 Jan 2021 23:49:12 +0000 Message-Id: <20210118234915.2036197-4-sandals@crustytoothpaste.net> X-Mailer: git-send-email 2.30.0.284.gd98b1dd5eaa7 In-Reply-To: <20210118234915.2036197-1-sandals@crustytoothpaste.net> References: <20210111035840.2437737-1-sandals@crustytoothpaste.net> <20210118234915.2036197-1-sandals@crustytoothpaste.net> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org 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 --- builtin/receive-pack.c | 4 ++-- builtin/tag.c | 16 ++++++++++++---- commit.c | 9 ++++++--- fmt-merge-msg.c | 29 ++++++++++++++++++----------- gpg-interface.c | 13 ++++++++++++- gpg-interface.h | 9 ++++++++- log-tree.c | 13 +++++++------ ref-filter.c | 18 ++++++++++++++---- tag.c | 15 ++++++++------- 9 files changed, 87 insertions(+), 39 deletions(-) diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c index d49d050e6e..b89ce31bf2 100644 --- a/builtin/receive-pack.c +++ b/builtin/receive-pack.c @@ -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); diff --git a/builtin/tag.c b/builtin/tag.c index ecf011776d..7162f4ccc5 100644 --- a/builtin/tag.c +++ b/builtin/tag.c @@ -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) diff --git a/commit.c b/commit.c index 1006c85ca8..ccb912b9b5 100644 --- 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: diff --git a/fmt-merge-msg.c b/fmt-merge-msg.c index 9a664a4a58..7fd99f0ac1 100644 --- a/fmt-merge-msg.c +++ b/fmt-merge-msg.c @@ -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'); diff --git a/gpg-interface.c b/gpg-interface.c index b499270836..c6274c14af 100644 --- a/gpg-interface.c +++ b/gpg-interface.c @@ -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); diff --git a/gpg-interface.h b/gpg-interface.h index f4e9b4f371..80567e4894 100644 --- a/gpg-interface.h +++ b/gpg-interface.h @@ -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 diff --git a/log-tree.c b/log-tree.c index 7e0335e548..b025c8da93 100644 --- a/log-tree.c +++ b/log-tree.c @@ -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; } diff --git a/ref-filter.c b/ref-filter.c index 606f638ab1..bba4877745 100644 --- a/ref-filter.c +++ b/ref-filter.c @@ -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,6 +1344,8 @@ 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 1ed2684e45..3e18a41841 100644 --- 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; } From patchwork Mon Jan 18 23:49:13 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "brian m. carlson" X-Patchwork-Id: 12028439 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-18.8 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER, INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id D4686C433DB for ; Mon, 18 Jan 2021 23:51:38 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id A5C9622E00 for ; Mon, 18 Jan 2021 23:51:38 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2390293AbhARXv3 (ORCPT ); Mon, 18 Jan 2021 18:51:29 -0500 Received: from injection.crustytoothpaste.net ([192.241.140.119]:55920 "EHLO injection.crustytoothpaste.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2389310AbhARXvW (ORCPT ); Mon, 18 Jan 2021 18:51:22 -0500 Received: from camp.crustytoothpaste.net (castro.crustytoothpaste.net [75.10.60.170]) (using TLSv1.2 with cipher ECDHE-RSA-CHACHA20-POLY1305 (256/256 bits)) (No client certificate requested) by injection.crustytoothpaste.net (Postfix) with ESMTPSA id 4A4086080E; Mon, 18 Jan 2021 23:50:10 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=crustytoothpaste.net; s=default; t=1611013810; bh=p2YFF5bzcl9Azh40Ne8B8/U2E5WlWLEohVXeK7uMOPQ=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From:Reply-To: Subject:Date:To:CC:Resent-Date:Resent-From:Resent-To:Resent-Cc: In-Reply-To:References:Content-Type:Content-Disposition; b=rzqaIaQI8iq6n9q23qOl1T8jzj3dvbR7wvngfs0bE/2Fv92t8wOokEJ4IIHs1wJvE jXeZ5l0+cNFJEX26amQeoMb7riwjoR68He3UogUBIEDzb4oBYUiREIQMDwZWY9eAgA 5rqxfp+nhq/Dn6mkHuUca1fxHET8eU2YZIejyScColx8Seqe2kuMLQpf+GHJgMCQP5 ze7GVLBg4aMwPyHKkw5H3Jp0m+YqLYhKkk9/z1CHoiWmzjt4m7HaCkS/X5zkGORmEr jWvwdc05YuLXcuWRXqsvYcopTfxazuChpwdBykDtCH5Y3Q+Dq9W5VGBTaCoYH/hDug YRHNZMl+/uSRksr3VFqUp6rJIvXQsczNeXKKrb3zUC5htxIcb9E7xfA9TB0keTT5Od OCB4bJjnLwcXuVgbzItGroCkWZ55WipBaxZRxjtRotaVOFiy+VgLn2XF2heMbSgJPr xyhg+x2rkXIrieZbaHaAwWZVf0aRqgtE5Z3gV2sB3J5J3YxRU0A From: "brian m. carlson" To: Cc: =?utf-8?q?SZEDER_G=C3=A1bor?= Subject: [PATCH v3 4/6] commit: allow parsing arbitrary buffers with headers Date: Mon, 18 Jan 2021 23:49:13 +0000 Message-Id: <20210118234915.2036197-5-sandals@crustytoothpaste.net> X-Mailer: git-send-email 2.30.0.284.gd98b1dd5eaa7 In-Reply-To: <20210118234915.2036197-1-sandals@crustytoothpaste.net> References: <20210111035840.2437737-1-sandals@crustytoothpaste.net> <20210118234915.2036197-1-sandals@crustytoothpaste.net> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org Currently only commits are signed with headers. However, in the future, we'll also sign tags with headers as well. Let's refactor out a function called parse_buffer_signed_by_header which does exactly that. In addition, since we'll want to sign things other than commits this way, let's call the function sign_with_header instead of do_sign_commit. Signed-off-by: brian m. carlson --- commit.c | 20 ++++++++++++++++---- commit.h | 9 +++++++++ 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/commit.c b/commit.c index ccb912b9b5..2c57b6ded9 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,13 +1035,26 @@ 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, const struct git_hash_algo *algop) { - unsigned long size; const char *buffer = get_commit_buffer(commit, &size); + 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)]; @@ -1078,7 +1091,6 @@ int parse_signed_commit(const struct commit *commit, } line = next; } - unuse_commit_buffer(commit, buffer); return saw_signature; } @@ -1532,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; } diff --git a/commit.h b/commit.h index 030aa65ab8..e2856ce8ef 100644 --- a/commit.h +++ b/commit.h @@ -360,4 +360,13 @@ int compare_commits_by_gen_then_commit_date(const void *a_, const void *b_, void LAST_ARG_MUST_BE_NULL int run_commit_hook(int editor_is_used, const char *index_file, const char *name, ...); +/* Sign a commit or tag buffer, storing the result in a header. */ +int sign_with_header(struct strbuf *buf, const char *keyid); +/* Parse the signature out of a header. */ +int parse_buffer_signed_by_header(const char *buffer, + unsigned long size, + struct strbuf *payload, + struct strbuf *signature, + const struct git_hash_algo *algop); + #endif /* COMMIT_H */ From patchwork Mon Jan 18 23:49:14 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "brian m. carlson" X-Patchwork-Id: 12028445 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-18.8 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER, INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id B6069C433E0 for ; Mon, 18 Jan 2021 23:52:41 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 7F1EE22E00 for ; Mon, 18 Jan 2021 23:52:41 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1733238AbhARXw0 (ORCPT ); Mon, 18 Jan 2021 18:52:26 -0500 Received: from injection.crustytoothpaste.net ([192.241.140.119]:55932 "EHLO injection.crustytoothpaste.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1733215AbhARXwD (ORCPT ); Mon, 18 Jan 2021 18:52:03 -0500 Received: from camp.crustytoothpaste.net (castro.crustytoothpaste.net [75.10.60.170]) (using TLSv1.2 with cipher ECDHE-RSA-CHACHA20-POLY1305 (256/256 bits)) (No client certificate requested) by injection.crustytoothpaste.net (Postfix) with ESMTPSA id AC7AA6081F; Mon, 18 Jan 2021 23:50:10 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=crustytoothpaste.net; s=default; t=1611013810; bh=eWe08JyPGPhuNkoBKNMgo54eo3iXKpY520PeCX/aVU8=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From:Reply-To: Subject:Date:To:CC:Resent-Date:Resent-From:Resent-To:Resent-Cc: In-Reply-To:References:Content-Type:Content-Disposition; b=mMNIvvE30bAX6WY+1aXY7fFkwlCH2qpEPePYG9z1NJ4N60/cwdWMGJR5AZ+tdzbla ic82IKqhtoqudk6xpC3vgbqUjedvF9BCIcO2/Z9V7UWGmZFkPX5tBYl+HNZrVnnGBi QnVN2xvMPE0VRJlVGCv1xp8/2w3r+TxL+5Kkq5otUuNBloqWVZrr2sQ9xdELjGduKo M/CJGIMb/QTDyU3IqjUaxxCIjpsGotvsCnMGVd4QiWupHgZkxJ/iNSb7bp7L4sxyYI KdNOEVUFzccJfnnugFfIG4wtfmn1l1VxynnMKxcsLcy8SmcTJQIqzqzpW/ylGvjKNR 9rBtyr3jG0P89nHmYK9Yt/q6ul6JkB1SQVszC0hfBZwllkQyUg2kgMftXxTNJDMhJa esYmuIdReyLHlMYhgFNbsLLmbjXVU/Y29Dc/sxXf84Eq26G1SZ6lz1wfV531X6UOLl 5GDbwmY9rs1VvPUzzrKCVVKCnS0HGEaoz/u+bZbCEbFtmuGihGL From: "brian m. carlson" To: Cc: =?utf-8?q?SZEDER_G=C3=A1bor?= Subject: [PATCH v3 5/6] ref-filter: hoist signature parsing Date: Mon, 18 Jan 2021 23:49:14 +0000 Message-Id: <20210118234915.2036197-6-sandals@crustytoothpaste.net> X-Mailer: git-send-email 2.30.0.284.gd98b1dd5eaa7 In-Reply-To: <20210118234915.2036197-1-sandals@crustytoothpaste.net> References: <20210111035840.2437737-1-sandals@crustytoothpaste.net> <20210118234915.2036197-1-sandals@crustytoothpaste.net> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org When we parse a signature in the ref-filter code, we continually increment the buffer pointer. Hoist the signature parsing above the blank line delimiting headers and body so we can find the signature when using a header to sign the buffer. Signed-off-by: brian m. carlson --- ref-filter.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/ref-filter.c b/ref-filter.c index bba4877745..e6c8106377 100644 --- a/ref-filter.c +++ b/ref-filter.c @@ -1221,6 +1221,8 @@ static void find_subpos(const char *buf, const char *end = buf + strlen(buf); const char *sigstart; + /* parse signature first; we might not even have a subject line */ + parse_signature(buf, end - buf, &payload, &signature); /* skip past header until we hit empty line */ while (*buf && *buf != '\n') { @@ -1232,9 +1234,6 @@ static void find_subpos(const char *buf, /* skip any empty lines */ while (*buf == '\n') buf++; - - /* parse signature first; we might not even have a subject line */ - parse_signature(buf, end - buf, &payload, &signature); *sig = strbuf_detach(&signature, siglen); sigstart = buf + parse_signed_buffer(buf, strlen(buf)); @@ -1330,7 +1329,7 @@ static void grab_sub_body_contents(struct atom_value *val, int deref, void *buf) v->s = xmemdupz(sigpos, siglen); else if (atom->u.contents.option == C_LINES) { struct strbuf s = STRBUF_INIT; - const char *contents_end = bodylen + bodypos - siglen; + const char *contents_end = bodypos + nonsiglen; /* Size is the length of the message after removing the signature */ append_lines(&s, subpos, contents_end - subpos, atom->u.contents.nlines); From patchwork Mon Jan 18 23:49:15 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "brian m. carlson" X-Patchwork-Id: 12028443 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-18.8 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER, INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 4EDF6C433E0 for ; Mon, 18 Jan 2021 23:52:25 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 0CD3B22E00 for ; Mon, 18 Jan 2021 23:52:25 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1733108AbhARXwL (ORCPT ); Mon, 18 Jan 2021 18:52:11 -0500 Received: from injection.crustytoothpaste.net ([192.241.140.119]:55930 "EHLO injection.crustytoothpaste.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2387806AbhARXwD (ORCPT ); Mon, 18 Jan 2021 18:52:03 -0500 Received: from camp.crustytoothpaste.net (castro.crustytoothpaste.net [75.10.60.170]) (using TLSv1.2 with cipher ECDHE-RSA-CHACHA20-POLY1305 (256/256 bits)) (No client certificate requested) by injection.crustytoothpaste.net (Postfix) with ESMTPSA id 218F460820; Mon, 18 Jan 2021 23:50:11 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=crustytoothpaste.net; s=default; t=1611013811; bh=iOk2zNQtGOchx4/xFaRbXMeuwZfTKEgGvqnvKg8PJc0=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From:Reply-To: Subject:Date:To:CC:Resent-Date:Resent-From:Resent-To:Resent-Cc: In-Reply-To:References:Content-Type:Content-Disposition; b=KhWx9rFrFSMOAVCV/+G8sIw20vBe64a40eFBsBE47jOuLQzYzr/z7iMnhRQxKLjDz fc6hFwZLnSdrO0uBNh4Rk7YqvI1ZbW7rzDjlxMoQdOGJ4lQxnqgu6ywGgbhAZoCdHj A3RhXSslbKR2ATgBWjjxIA7b9GQAbkkx5mRgD/fc7maMWtFXC3NoLKdjDUFs3IpuhI Msi9F5bUnieCW4fX9pvKrcRLdsc5nTmogEASaioSS4mMxabOjpKYP71b1ip0gdlQ5M xkBywqHRidaaoTq3BTyK6ZQSFe1QoO8NfCLTjgs6jILWljF9p9gTMPVWPOgqTI8+WJ xgvOcNp+VUJBeb7ZDF9GOSVFfSd5qB5Jc7PvGyn7DSIV+Ggpv1LygbiEvxfiP3Ed3/ fOhEdchxXAkl7YrmHm3N8I+xWtWUmVNYQQ+n8MfhLjPjVSQF1gwk92AJp2g9kKTpJZ Sm+V1w7m48HxqBEm8NOEJ98hP4MghJk6wEah+JyFS97X9UJcUFR From: "brian m. carlson" To: Cc: =?utf-8?q?SZEDER_G=C3=A1bor?= Subject: [PATCH v3 6/6] gpg-interface: remove other signature headers before verifying Date: Mon, 18 Jan 2021 23:49:15 +0000 Message-Id: <20210118234915.2036197-7-sandals@crustytoothpaste.net> X-Mailer: git-send-email 2.30.0.284.gd98b1dd5eaa7 In-Reply-To: <20210118234915.2036197-1-sandals@crustytoothpaste.net> References: <20210111035840.2437737-1-sandals@crustytoothpaste.net> <20210118234915.2036197-1-sandals@crustytoothpaste.net> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org When we have a multiply signed commit, we need to remove the signature in the header before verifying the object, since the trailing signature will not be over both pieces of data. Do so, and verify that we validate the signature appropriately. Signed-off-by: brian m. carlson --- gpg-interface.c | 2 ++ t/t7004-tag.sh | 25 +++++++++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/gpg-interface.c b/gpg-interface.c index c6274c14af..127aecfc2b 100644 --- a/gpg-interface.c +++ b/gpg-interface.c @@ -1,4 +1,5 @@ #include "cache.h" +#include "commit.h" #include "config.h" #include "run-command.h" #include "strbuf.h" @@ -366,6 +367,7 @@ int parse_signature(const char *buf, size_t size, struct strbuf *payload, struct size_t match = parse_signed_buffer(buf, size); if (match != size) { strbuf_add(payload, buf, match); + remove_signature(payload); strbuf_add(signature, buf + match, size - match); return 1; } diff --git a/t/t7004-tag.sh b/t/t7004-tag.sh index 05f411c821..6fb4e3cf11 100755 --- a/t/t7004-tag.sh +++ b/t/t7004-tag.sh @@ -17,6 +17,13 @@ tag_exists () { git show-ref --quiet --verify refs/tags/"$1" } +test_expect_success 'setup' ' + test_oid_cache <<-EOM + othersigheader sha1:gpgsig-sha256 + othersigheader sha256:gpgsig + EOM +' + test_expect_success 'listing all tags in an empty tree should succeed' ' git tag -l && git tag @@ -1371,6 +1378,24 @@ test_expect_success GPG \ 'test_config gpg.program echo && test_must_fail git tag -s -m tail tag-gpg-failure' +# try to produce invalid signature +test_expect_success GPG 'git verifies tag is valid with double signature' ' + git tag -s -m tail tag-gpg-double-sig && + git cat-file tag tag-gpg-double-sig >tag && + othersigheader=$(test_oid othersigheader) && + sed -ne "/^\$/q;p" tag >new-tag && + cat <<-EOM >>new-tag && + $othersigheader -----BEGIN PGP SIGNATURE----- + someinvaliddata + -----END PGP SIGNATURE----- + EOM + sed -e "1,/^tagger/d" tag >>new-tag && + new_tag=$(git hash-object -t tag -w new-tag) && + git update-ref refs/tags/tag-gpg-double-sig $new_tag && + git verify-tag tag-gpg-double-sig && + git fsck +' + # try to sign with bad user.signingkey test_expect_success GPGSM \ 'git tag -s fails if gpgsm is misconfigured (bad key)' \