remote-helpers that use the `import` capability, as they are
already trusted to run their own code.
---signed-tags=(verbatim|warn-verbatim|warn-strip|strip|abort)::
- Specify how to handle signed tags. Behaves in the same way
- as the same option in linkgit:git-fast-export[1], except that
- default is 'verbatim' (instead of 'abort').
-
---signed-commits=(verbatim|warn-verbatim|warn-strip|strip|abort)::
- Specify how to handle signed commits. Behaves in the same way
- as the same option in linkgit:git-fast-export[1], except that
- default is 'verbatim' (instead of 'abort').
+`--signed-tags=(verbatim|warn-verbatim|warn-strip|strip|abort)`::
+ Specify how to handle signed tags. Behaves in the same way as
+ the `--signed-commits=<mode>` below, except that the
+ `strip-if-invalid` mode is not yet supported. Like for signed
+ commits, the default mode is `verbatim`.
+
+`--signed-commits=<mode>`::
+ Specify how to handle signed commits. The following <mode>s
+ are supported:
++
+* `verbatim`, which is the default, will silently import commit
+ signatures.
+* `warn-verbatim` will import them, but will display a warning.
+* `abort` will make this program die when encountering a signed
+ commit.
+* `strip` will silently make the commits unsigned.
+* `warn-strip` will make them unsigned, but will display a warning.
+* `strip-if-invalid` will check signatures and, if they are invalid,
+ will strip them and display a warning.
Options for Frontends
~~~~~~~~~~~~~~~~~~~~~
(int)(committer_end - committer), committer);
if (signatures.nr) {
switch (signed_commit_mode) {
- case SIGN_ABORT:
- die("encountered signed commit %s; use "
- "--signed-commits=<mode> to handle it",
- oid_to_hex(&commit->object.oid));
+
+ /* Exporting modes */
case SIGN_WARN_VERBATIM:
- warning("exporting %"PRIuMAX" signature(s) for commit %s",
+ warning(_("exporting %"PRIuMAX" signature(s) for commit %s"),
(uintmax_t)signatures.nr, oid_to_hex(&commit->object.oid));
/* fallthru */
case SIGN_VERBATIM:
print_signature(item->string, item->util);
}
break;
+
+ /* Stripping modes */
case SIGN_WARN_STRIP:
- warning("stripping signature(s) from commit %s",
+ warning(_("stripping signature(s) from commit %s"),
oid_to_hex(&commit->object.oid));
/* fallthru */
case SIGN_STRIP:
break;
+
+ /* Aborting modes */
+ case SIGN_ABORT:
+ die(_("encountered signed commit %s; use "
+ "--signed-commits=<mode> to handle it"),
+ oid_to_hex(&commit->object.oid));
+ case SIGN_STRIP_IF_INVALID:
+ die(_("'strip-if-invalid' is not a valid mode for "
+ "git fast-export with --signed-commits=<mode>"));
+ default:
+ BUG("invalid signed_commit_mode value %d", signed_commit_mode);
}
string_list_clear(&signatures, 0);
}
size_t sig_offset = parse_signed_buffer(message, message_size);
if (sig_offset < message_size)
switch (signed_tag_mode) {
- case SIGN_ABORT:
- die("encountered signed tag %s; use "
- "--signed-tags=<mode> to handle it",
- oid_to_hex(&tag->object.oid));
+
+ /* Exporting modes */
case SIGN_WARN_VERBATIM:
- warning("exporting signed tag %s",
+ warning(_("exporting signed tag %s"),
oid_to_hex(&tag->object.oid));
/* fallthru */
case SIGN_VERBATIM:
break;
+
+ /* Stripping modes */
case SIGN_WARN_STRIP:
- warning("stripping signature from tag %s",
+ warning(_("stripping signature from tag %s"),
oid_to_hex(&tag->object.oid));
/* fallthru */
case SIGN_STRIP:
message_size = sig_offset;
break;
+
+ /* Aborting modes */
+ case SIGN_ABORT:
+ die(_("encountered signed tag %s; use "
+ "--signed-tags=<mode> to handle it"),
+ oid_to_hex(&tag->object.oid));
+ case SIGN_STRIP_IF_INVALID:
+ die(_("'strip-if-invalid' is not a valid mode for "
+ "git fast-export with --signed-tags=<mode>"));
+ default:
+ BUG("invalid signed_commit_mode value %d", signed_commit_mode);
}
}
{
struct string_list siglines = STRING_LIST_INIT_NODUP;
- if (!sig->hash_algo)
+ if (!sig || !sig->hash_algo)
return;
strbuf_addstr(commit_data, header);
strbuf_addbuf(new_data, msg);
}
+static void handle_strip_if_invalid(struct strbuf *new_data,
+ struct signature_data *sig_sha1,
+ struct signature_data *sig_sha256,
+ struct strbuf *msg)
+{
+ struct strbuf tmp_buf = STRBUF_INIT;
+ struct signature_check signature_check = { 0 };
+ int ret;
+
+ /* Check signature in a temporary commit buffer */
+ strbuf_addbuf(&tmp_buf, new_data);
+ finalize_commit_buffer(&tmp_buf, sig_sha1, sig_sha256, msg);
+ ret = verify_commit_buffer(tmp_buf.buf, tmp_buf.len, &signature_check);
+
+ if (ret) {
+ const char *signer = signature_check.signer ?
+ signature_check.signer : _("unknown");
+ const char *subject;
+ int subject_len = find_commit_subject(msg->buf, &subject);
+
+ if (subject_len > 100)
+ warning(_("stripping invalid signature for commit '%.100s...'\n"
+ " allegedly by %s"), subject, signer);
+ else if (subject_len > 0)
+ warning(_("stripping invalid signature for commit '%.*s'\n"
+ " allegedly by %s"), subject_len, subject, signer);
+ else
+ warning(_("stripping invalid signature for commit\n"
+ " allegedly by %s"), signer);
+
+ finalize_commit_buffer(new_data, NULL, NULL, msg);
+ } else {
+ strbuf_swap(new_data, &tmp_buf);
+ }
+
+ signature_check_clear(&signature_check);
+ strbuf_release(&tmp_buf);
+}
+
static void parse_new_commit(const char *arg)
{
static struct strbuf msg = STRBUF_INIT;
warning(_("importing a commit signature verbatim"));
/* fallthru */
case SIGN_VERBATIM:
+ case SIGN_STRIP_IF_INVALID:
import_one_signature(&sig_sha1, &sig_sha256, v);
break;
"encoding %s\n",
encoding);
- finalize_commit_buffer(&new_data, &sig_sha1, &sig_sha256, &msg);
+ if (signed_commit_mode == SIGN_STRIP_IF_INVALID &&
+ (sig_sha1.hash_algo || sig_sha256.hash_algo))
+ handle_strip_if_invalid(&new_data, &sig_sha1, &sig_sha256, &msg);
+ else
+ finalize_commit_buffer(&new_data, &sig_sha1, &sig_sha256, &msg);
free(author);
free(committer);
switch (signed_tag_mode) {
/* First, modes that don't change anything */
- case SIGN_ABORT:
- die(_("encountered signed tag; use "
- "--signed-tags=<mode> to handle it"));
case SIGN_WARN_VERBATIM:
warning(_("importing a tag signature verbatim for tag '%s'"), name);
/* fallthru */
strbuf_setlen(msg, sig_offset);
break;
- /* Third, BUG */
+ /* Third, aborting modes */
+ case SIGN_ABORT:
+ die(_("encountered signed tag; use "
+ "--signed-tags=<mode> to handle it"));
+ case SIGN_STRIP_IF_INVALID:
+ die(_("'strip-if-invalid' is not a valid mode for "
+ "git fast-import with --signed-tags=<mode>"));
default:
BUG("invalid signed_tag_mode value %d from tag '%s'",
signed_tag_mode, name);
*mode = SIGN_WARN_STRIP;
else if (!strcmp(arg, "strip"))
*mode = SIGN_STRIP;
+ else if (!strcmp(arg, "strip-if-invalid"))
+ *mode = SIGN_STRIP_IF_INVALID;
else
return -1;
return 0;
SIGN_VERBATIM,
SIGN_WARN_STRIP,
SIGN_STRIP,
+ SIGN_STRIP_IF_INVALID,
};
/*
echo B >explicit-sha256/B &&
git -C explicit-sha256 add B &&
test_tick &&
- git -C explicit-sha256 commit -S -m "signed" B &&
+ git -C explicit-sha256 commit -S -m "signed commit" B &&
SHA256_B=$(git -C explicit-sha256 rev-parse dual-signed) &&
# Create the corresponding SHA-1 commit
test_line_count = 2 out
'
+test_expect_success GPG 'import commit with no signature with --signed-commits=strip-if-invalid' '
+ git fast-export main >output &&
+ git -C new fast-import --quiet --signed-commits=strip-if-invalid <output >log 2>&1 &&
+ test_must_be_empty log
+'
+
+test_expect_success GPG 'keep valid OpenPGP signature with --signed-commits=strip-if-invalid' '
+ rm -rf new &&
+ git init new &&
+
+ git fast-export --signed-commits=verbatim openpgp-signing >output &&
+ git -C new fast-import --quiet --signed-commits=strip-if-invalid <output >log 2>&1 &&
+ IMPORTED=$(git -C new rev-parse --verify refs/heads/openpgp-signing) &&
+ test $OPENPGP_SIGNING = $IMPORTED &&
+ git -C new cat-file commit "$IMPORTED" >actual &&
+ test_grep -E "^gpgsig(-sha256)? " actual &&
+ test_must_be_empty log
+'
+
+test_expect_success GPG 'strip signature invalidated by message change with --signed-commits=strip-if-invalid' '
+ rm -rf new &&
+ git init new &&
+
+ git fast-export --signed-commits=verbatim openpgp-signing >output &&
+
+ # Change the commit message, which invalidates the signature.
+ # The commit message length should not change though, otherwise the
+ # corresponding `data <length>` command would have to be changed too.
+ sed "s/OpenPGP signed commit/OpenPGP forged commit/" output >modified &&
+
+ git -C new fast-import --quiet --signed-commits=strip-if-invalid <modified >log 2>&1 &&
+
+ IMPORTED=$(git -C new rev-parse --verify refs/heads/openpgp-signing) &&
+ test $OPENPGP_SIGNING != $IMPORTED &&
+ git -C new cat-file commit "$IMPORTED" >actual &&
+ test_grep ! -E "^gpgsig" actual &&
+ test_grep "stripping invalid signature" log
+'
+
+test_expect_success GPG 'keep valid dual OpenPGP signatures with --signed-commits=strip-if-invalid' '
+ rm -rf new &&
+ git init new &&
+
+ git -C explicit-sha256 fast-export --signed-commits=verbatim dual-signed >output &&
+ git -C new fast-import --quiet --signed-commits=strip-if-invalid <output >log 2>&1 &&
+
+ git -C new cat-file commit refs/heads/dual-signed >actual &&
+ test_grep -E "^gpgsig " actual &&
+ test_grep -E "^gpgsig-sha256 " actual &&
+ test_must_be_empty log &&
+
+ IMPORTED=$(git -C new rev-parse refs/heads/dual-signed) &&
+ if test "$GIT_DEFAULT_HASH" = "sha1"
+ then
+ test $SHA1_B = $IMPORTED
+ else
+ test $SHA256_B = $IMPORTED
+ fi
+'
+
+test_expect_success GPG 'strip both invalid dual OpenPGP signatures with --signed-commits=strip-if-invalid' '
+ rm -rf new &&
+ git init new &&
+
+ git -C explicit-sha256 fast-export --signed-commits=verbatim dual-signed >output &&
+
+ # Change the commit message, which invalidates the signature.
+ # The commit message length should not change though, otherwise the
+ # corresponding `data <length>` command would have to be changed too.
+ sed "s/signed commit/forged commit/" output >modified &&
+
+ git -C new fast-import --quiet --signed-commits=strip-if-invalid <modified >log 2>&1 &&
+
+ git -C new cat-file commit refs/heads/dual-signed >actual &&
+ test_grep ! -E "^gpgsig " actual &&
+ test_grep ! -E "^gpgsig-sha256 " actual &&
+
+ IMPORTED=$(git -C new rev-parse refs/heads/dual-signed) &&
+ if test "$GIT_DEFAULT_HASH" = "sha1"
+ then
+ test $SHA1_B != $IMPORTED
+ else
+ test $SHA256_B != $IMPORTED
+ fi &&
+
+ test_grep "stripping invalid signature" log
+'
+
+test_expect_success GPGSM 'keep valid X.509 signature with --signed-commits=strip-if-invalid' '
+ rm -rf new &&
+ git init new &&
+
+ git fast-export --signed-commits=verbatim x509-signing >output &&
+ git -C new fast-import --quiet --signed-commits=strip-if-invalid <output >log 2>&1 &&
+ IMPORTED=$(git -C new rev-parse --verify refs/heads/x509-signing) &&
+ test $X509_SIGNING = $IMPORTED &&
+ git -C new cat-file commit "$IMPORTED" >actual &&
+ test_grep -E "^gpgsig(-sha256)? " actual &&
+ test_must_be_empty log
+'
+
+test_expect_success GPGSSH 'keep valid SSH signature with --signed-commits=strip-if-invalid' '
+ rm -rf new &&
+ git init new &&
+
+ test_config -C new gpg.ssh.allowedSignersFile "${GPGSSH_ALLOWED_SIGNERS}" &&
+
+ git fast-export --signed-commits=verbatim ssh-signing >output &&
+ git -C new fast-import --quiet --signed-commits=strip-if-invalid <output >log 2>&1 &&
+ IMPORTED=$(git -C new rev-parse --verify refs/heads/ssh-signing) &&
+ test $SSH_SIGNING = $IMPORTED &&
+ git -C new cat-file commit "$IMPORTED" >actual &&
+ test_grep -E "^gpgsig(-sha256)? " actual &&
+ test_must_be_empty log
+'
+
test_done