merge/pull Check for untrusted good GPG signatures

When --verify-signatures is specified, abort the merge in case a good
GPG signature from an untrusted key is encountered.

Signed-off-by: Sebastian Götte <jaseg@physik-pool.tu-berlin.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
diff --git a/Documentation/merge-options.txt b/Documentation/merge-options.txt
index 31f1067..a0f022b 100644
--- a/Documentation/merge-options.txt
+++ b/Documentation/merge-options.txt
@@ -85,8 +85,8 @@
 
 --verify-signatures::
 --no-verify-signatures::
-	Verify that the commits being merged have good GPG signatures and abort the
-	merge in case they do not.
+	Verify that the commits being merged have good and trusted GPG signatures
+	and abort the merge in case they do not.
 
 --summary::
 --no-summary::
diff --git a/builtin/merge.c b/builtin/merge.c
index e57c42c..bac11d1 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -1248,6 +1248,9 @@
 			switch (signature_check.result) {
 			case 'G':
 				break;
+			case 'U':
+				die(_("Commit %s has an untrusted GPG signature, "
+				      "allegedly by %s."), hex, signature_check.signer);
 			case 'B':
 				die(_("Commit %s has a bad GPG signature "
 				      "allegedly by %s."), hex, signature_check.signer);
diff --git a/commit.c b/commit.c
index 94029c9..516a4ff 100644
--- a/commit.c
+++ b/commit.c
@@ -1047,6 +1047,8 @@
 } sigcheck_gpg_status[] = {
 	{ 'G', "\n[GNUPG:] GOODSIG " },
 	{ 'B', "\n[GNUPG:] BADSIG " },
+	{ 'U', "\n[GNUPG:] TRUST_NEVER" },
+	{ 'U', "\n[GNUPG:] TRUST_UNDEFINED" },
 };
 
 static void parse_gpg_output(struct signature_check *sigc)
@@ -1068,11 +1070,13 @@
 			found += strlen(sigcheck_gpg_status[i].check);
 		}
 		sigc->result = sigcheck_gpg_status[i].result;
-		sigc->key = xmemdupz(found, 16);
-		found += 17;
-		next = strchrnul(found, '\n');
-		sigc->signer = xmemdupz(found, next - found);
-		break;
+		/* The trust messages are not followed by key/signer information */
+		if (sigc->result != 'U') {
+			sigc->key = xmemdupz(found, 16);
+			found += 17;
+			next = strchrnul(found, '\n');
+			sigc->signer = xmemdupz(found, next - found);
+		}
 	}
 }
 
diff --git a/commit.h b/commit.h
index c24b844..87b4b6c 100644
--- a/commit.h
+++ b/commit.h
@@ -234,11 +234,11 @@
 			      const char *format_last);
 
 /*
- * Check the signature of the given commit. The result of the check is stored in
- * sig->result, 'G' for a good signature, 'B' for a bad signature and 'N'
- * for no signature at all.
- * This may allocate memory for sig->gpg_output, sig->gpg_status, sig->signer
- * and sig->key.
+ * Check the signature of the given commit. The result of the check is stored
+ * in sig->check_result, 'G' for a good signature, 'U' for a good signature
+ * from an untrusted signer, 'B' for a bad signature and 'N' for no signature
+ * at all.  This may allocate memory for sig->gpg_output, sig->gpg_status,
+ * sig->signer and sig->key.
  */
 extern void check_commit_signature(const struct commit* commit, struct signature_check *sigc);
 
diff --git a/gpg-interface.h b/gpg-interface.h
index 5884aa4..a85cb5b 100644
--- a/gpg-interface.h
+++ b/gpg-interface.h
@@ -6,6 +6,7 @@
 	char *gpg_status;
 	char result; /* 0 (not checked),
 		      * N (checked but no further result),
+		      * U (untrusted good),
 		      * G (good)
 		      * B (bad) */
 	char *signer;
diff --git a/t/lib-gpg/pubring.gpg b/t/lib-gpg/pubring.gpg
index 83855fa..1a3c2d4 100644
--- a/t/lib-gpg/pubring.gpg
+++ b/t/lib-gpg/pubring.gpg
Binary files differ
diff --git a/t/lib-gpg/random_seed b/t/lib-gpg/random_seed
index 8fed133..95d249f 100644
--- a/t/lib-gpg/random_seed
+++ b/t/lib-gpg/random_seed
Binary files differ
diff --git a/t/lib-gpg/secring.gpg b/t/lib-gpg/secring.gpg
index d831cd9..82dca8f 100644
--- a/t/lib-gpg/secring.gpg
+++ b/t/lib-gpg/secring.gpg
Binary files differ
diff --git a/t/lib-gpg/trustdb.gpg b/t/lib-gpg/trustdb.gpg
index abace96..4879ae9 100644
--- a/t/lib-gpg/trustdb.gpg
+++ b/t/lib-gpg/trustdb.gpg
Binary files differ
diff --git a/t/t7612-merge-verify-signatures.sh b/t/t7612-merge-verify-signatures.sh
index 6ccfbf3..21a0bf8 100755
--- a/t/t7612-merge-verify-signatures.sh
+++ b/t/t7612-merge-verify-signatures.sh
@@ -27,6 +27,10 @@
 	git hash-object -w -t commit forged >forged.commit &&
 	git checkout initial &&
 
+	git checkout -b side-untrusted &&
+	echo 3 >baz && git add baz &&
+	test_tick && git commit -SB7227189 -m "untrusted on side"
+
 	git checkout master
 '
 
@@ -40,6 +44,11 @@
 	test_i18ngrep "has a bad GPG signature" mergeerror
 '
 
+test_expect_success GPG 'merge commit with untrusted signature with verification' '
+	test_must_fail git merge --ff-only --verify-signatures side-untrusted 2>mergeerror &&
+	test_i18ngrep "has an untrusted GPG signature" mergeerror
+'
+
 test_expect_success GPG 'merge signed commit with verification' '
 	git merge --verbose --ff-only --verify-signatures side-signed >mergeoutput &&
 	test_i18ngrep "has a good GPG signature" mergeoutput