mirror of
git://git.gnupg.org/gnupg.git
synced 2024-12-22 10:19:57 +01:00
g10: Be more careful when checking cross signatures.
* g10/tofu.c (cross_sigs): When checking cross signatures, only consider the signatures on the specified user id. * tests/openpgp/tofu.scm: Add test for the above. * tests/openpgp/tofu/cross-sigs/ 1938C3A0E4674B6C217AC0B987DB2814EC38277E-1.gpg: New file. * tests/openpgp/tofu/cross-sigs/ 1938C3A0E4674B6C217AC0B987DB2814EC38277E-1.txt: New file. * tests/openpgp/tofu/cross-sigs/ 1938C3A0E4674B6C217AC0B987DB2814EC38277E-2.gpg: New file. * tests/openpgp/tofu/cross-sigs/ 1938C3A0E4674B6C217AC0B987DB2814EC38277E-2.txt: New file. * tests/openpgp/tofu/cross-sigs/ 1938C3A0E4674B6C217AC0B987DB2814EC38277E-3.txt: New file. * tests/openpgp/tofu/cross-sigs/ 1938C3A0E4674B6C217AC0B987DB2814EC38277E-secret.gpg: New file. * tests/openpgp/tofu/cross-sigs/ DC463A16E42F03240D76E8BA8B48C6BD871C2247-1.gpg: New file. * tests/openpgp/tofu/cross-sigs/ DC463A16E42F03240D76E8BA8B48C6BD871C2247-1.txt: New file. * tests/openpgp/tofu/cross-sigs/ DC463A16E42F03240D76E8BA8B48C6BD871C2247-2.gpg: New file. * tests/openpgp/tofu/cross-sigs/ DC463A16E42F03240D76E8BA8B48C6BD871C2247-2.txt: New file. * tests/openpgp/tofu/cross-sigs/ DC463A16E42F03240D76E8BA8B48C6BD871C2247-3.gpg: New file. * tests/openpgp/tofu/cross-sigs/ DC463A16E42F03240D76E8BA8B48C6BD871C2247-3.txt: New file. * tests/openpgp/tofu/cross-sigs/ DC463A16E42F03240D76E8BA8B48C6BD871C2247-4.gpg: New file. * tests/openpgp/tofu/cross-sigs/ DC463A16E42F03240D76E8BA8B48C6BD871C2247-secret.gpg: New file. * tests/openpgp/tofu/cross-sigs/README: New file. -- Signed-off-by: Neal H. Walfield
This commit is contained in:
parent
e09166c772
commit
4c0389f8eb
28
g10/tofu.c
28
g10/tofu.c
@ -1211,7 +1211,7 @@ format_conflict_msg_part1 (int policy, strlist_t conflict_set,
|
||||
|
||||
/* Return 1 if A signed B and B signed A. */
|
||||
static int
|
||||
cross_sigs (kbnode_t a, kbnode_t b)
|
||||
cross_sigs (const char *email, kbnode_t a, kbnode_t b)
|
||||
{
|
||||
int i;
|
||||
|
||||
@ -1240,12 +1240,36 @@ cross_sigs (kbnode_t a, kbnode_t b)
|
||||
u32 *signer_kid = pk_main_keyid (signer_pk);
|
||||
kbnode_t n;
|
||||
|
||||
int saw_email = 0;
|
||||
|
||||
/* Iterate over SIGNEE's keyblock and see if there is a valid
|
||||
signature from SIGNER. */
|
||||
for (n = signee; n; n = n->next)
|
||||
{
|
||||
PKT_signature *sig;
|
||||
|
||||
if (n->pkt->pkttype == PKT_USER_ID)
|
||||
{
|
||||
if (saw_email)
|
||||
/* We're done: we've processed all signatures on the
|
||||
user id. */
|
||||
break;
|
||||
else
|
||||
{
|
||||
/* See if this is the matching user id. */
|
||||
PKT_user_id *user_id = n->pkt->pkt.user_id;
|
||||
char *email2 = email_from_user_id (user_id->name);
|
||||
|
||||
if (strcmp (email, email2) == 0)
|
||||
saw_email = 1;
|
||||
|
||||
xfree (email2);
|
||||
}
|
||||
}
|
||||
|
||||
if (! saw_email)
|
||||
continue;
|
||||
|
||||
if (n->pkt->pkttype != PKT_SIGNATURE)
|
||||
continue;
|
||||
|
||||
@ -1974,7 +1998,7 @@ build_conflict_set (tofu_dbs_t dbs, const char *fingerprint, const char *email)
|
||||
|
||||
for (j = i + 1; j < conflict_set_count; j ++)
|
||||
/* Be careful: we might not have a key block for a key. */
|
||||
if (kb_all[i] && kb_all[j] && cross_sigs (kb_all[i], kb_all[j]))
|
||||
if (kb_all[i] && kb_all[j] && cross_sigs (email, kb_all[i], kb_all[j]))
|
||||
die[j] = 1;
|
||||
}
|
||||
|
||||
|
@ -159,3 +159,76 @@
|
||||
(checkpolicy "BC15C85A" "ask")
|
||||
(checkpolicy "2183839A" "bad")
|
||||
(checkpolicy "EE37CF96" "ask")
|
||||
|
||||
|
||||
|
||||
;; Check that we detect the following attack:
|
||||
;;
|
||||
;; Alice and Bob each have a key and cross sign them. Bob then adds a
|
||||
;; new user id, "Alice". TOFU should now detect a conflict, because
|
||||
;; Alice only signed Bob's "Bob" user id.
|
||||
|
||||
(display "Checking cross sigs...\n")
|
||||
(define GPG `(,(tool 'gpg) --no-permission-warning
|
||||
--faked-system-time=1476304861))
|
||||
|
||||
;; Carefully remove the TOFU db.
|
||||
(catch '() (unlink (string-append GNUPGHOME "/tofu.db")))
|
||||
|
||||
(define DIR "tofu/cross-sigs")
|
||||
;; The test keys.
|
||||
(define KEYA "1938C3A0E4674B6C217AC0B987DB2814EC38277E")
|
||||
(define KEYB "DC463A16E42F03240D76E8BA8B48C6BD871C2247")
|
||||
|
||||
(define (verify-messages)
|
||||
(for-each
|
||||
(lambda (key)
|
||||
(for-each
|
||||
(lambda (i)
|
||||
(let ((fn (in-srcdir DIR (string-append key "-" i ".txt"))))
|
||||
(call-check `(,@GPG --trust-model=tofu --verify ,fn))))
|
||||
(list "1" "2")))
|
||||
(list KEYA KEYB)))
|
||||
|
||||
;; Import the public keys.
|
||||
(display " > Two keys. ")
|
||||
(call-check `(,@GPG --import ,(in-srcdir DIR (string-append KEYA "-1.gpg"))))
|
||||
(call-check `(,@GPG --import ,(in-srcdir DIR (string-append KEYB "-1.gpg"))))
|
||||
;; Make sure the tofu engine registers the keys.
|
||||
(verify-messages)
|
||||
(display "<\n")
|
||||
|
||||
;; Since their is no conflict, the policy should be auto.
|
||||
(checkpolicy KEYA "auto")
|
||||
(checkpolicy KEYB "auto")
|
||||
|
||||
;; Import the cross sigs.
|
||||
(display " > Adding cross signatures. ")
|
||||
(call-check `(,@GPG --import ,(in-srcdir DIR (string-append KEYA "-2.gpg"))))
|
||||
(call-check `(,@GPG --import ,(in-srcdir DIR (string-append KEYB "-2.gpg"))))
|
||||
(verify-messages)
|
||||
(display "<\n")
|
||||
|
||||
;; There is still no conflict, so the policy shouldn't have changed.
|
||||
(checkpolicy KEYA "auto")
|
||||
(checkpolicy KEYB "auto")
|
||||
|
||||
;; Import the conflicting user id.
|
||||
(display " > Adding conflicting user id. ")
|
||||
(call-check `(,@GPG --import ,(in-srcdir DIR (string-append KEYB "-3.gpg"))))
|
||||
(call-check `(,@GPG --trust-model=tofu
|
||||
--verify ,(in-srcdir DIR (string-append KEYB "-1.txt"))))
|
||||
(verify-messages)
|
||||
(display "<\n")
|
||||
|
||||
(checkpolicy KEYA "ask")
|
||||
(checkpolicy KEYB "ask")
|
||||
|
||||
;; Import Alice's signature on the conflicting user id.
|
||||
(display " > Adding cross signature on user id. ")
|
||||
(call-check `(,@GPG --import ,(in-srcdir DIR (string-append KEYB "-4.gpg"))))
|
||||
(verify-messages)
|
||||
(display "<\n")
|
||||
|
||||
(checkpolicy KEYA "auto")
|
||||
(checkpolicy KEYB "auto")
|
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
79
tests/openpgp/tofu/cross-sigs/README
Normal file
79
tests/openpgp/tofu/cross-sigs/README
Normal file
@ -0,0 +1,79 @@
|
||||
# How I generate the keys and messages to verify:
|
||||
|
||||
# Generate and export two non-conflicting keys.
|
||||
gpg --quick-gen-key 'Spy Cow <spy@cow.com>'
|
||||
gpg --quick-gen-key 'Spy R. Cow <spy@cow.de>'
|
||||
|
||||
KEYIDA=1938C3A0E4674B6C217AC0B987DB2814EC38277E
|
||||
KEYIDB=DC463A16E42F03240D76E8BA8B48C6BD871C2247
|
||||
|
||||
for KEYID in $KEYIDA $KEYIDB
|
||||
do
|
||||
gpg --export $KEYID > tofu-$KEYID.gpg
|
||||
gpg --export-secret-keys $KEYID > tofu-$KEYID-secret.gpg
|
||||
done
|
||||
|
||||
# Sign some data.
|
||||
echo foo | gpg --default-key $KEYIDA -s > tofu-$KEYIDA-1.txt
|
||||
echo foo | gpg --default-key $KEYIDB -s > tofu-$KEYIDB-1.txt
|
||||
|
||||
# Again, but with an issuer.
|
||||
echo foo | gpg --default-key "<spy@cow.com>" -s > tofu-$KEYIDA-2.txt
|
||||
echo foo | gpg --default-key "<spy@cow.de>" -s > tofu-$KEYIDB-2.txt
|
||||
|
||||
# Have A sign B and vice versa.
|
||||
gpg --default-key $KEYIDA --quick-sign $KEYIDB
|
||||
gpg --default-key $KEYIDB --quick-sign $KEYIDA
|
||||
|
||||
gpg --export $KEYIDA > tofu-$KEYIDA-2.gpg
|
||||
gpg --export $KEYIDB > tofu-$KEYIDB-2.gpg
|
||||
|
||||
# Cause A and B to conflict.
|
||||
gpg --quick-adduid $KEYIDB 'Spy R. Cow <spy@cow.com>'
|
||||
gpg --export $KEYIDB > tofu-$KEYIDB-3.gpg
|
||||
|
||||
echo foo | gpg --default-key "<spy@cow.com>" -s > tofu-$KEYIDA-3.txt
|
||||
echo foo | gpg --default-key "<spy@cow.com>" -s > tofu-$KEYIDB-3.txt
|
||||
|
||||
# Have A sign B's conflicting user id.
|
||||
gpg --default-key $KEYIDA --quick-sign $KEYIDB
|
||||
gpg --export $KEYIDB > tofu-$KEYIDB-4.gpg
|
||||
|
||||
exit 0
|
||||
|
||||
# In a new directory (so the keys are not ultimately trusted).
|
||||
|
||||
D=~/neal/work/gpg/test
|
||||
echo 'trust-model tofu+pgp' > gpg.conf
|
||||
gpg --import $D/tofu-$KEYIDA.gpg
|
||||
gpg --import $D/tofu-$KEYIDB.gpg
|
||||
gpg -k
|
||||
|
||||
gpg --verify $D/tofu-$KEYIDA-1.txt
|
||||
gpg --verify $D/tofu-$KEYIDB-1.txt
|
||||
# With an issuer.
|
||||
gpg --verify $D/tofu-$KEYIDA-2.txt
|
||||
gpg --verify $D/tofu-$KEYIDB-2.txt
|
||||
|
||||
# Import the cross signatures.
|
||||
gpg --import $D/tofu-$KEYIDA-2.gpg
|
||||
gpg --import $D/tofu-$KEYIDB-2.gpg
|
||||
gpg -k
|
||||
|
||||
gpg --verify $D/tofu-$KEYIDA-1.txt
|
||||
gpg --verify $D/tofu-$KEYIDB-1.txt
|
||||
# With an issuer.
|
||||
gpg --verify $D/tofu-$KEYIDA-2.txt
|
||||
gpg --verify $D/tofu-$KEYIDB-2.txt
|
||||
|
||||
|
||||
gpg --status-fd=1 --batch --verify $D/tofu-$KEYIDA-3.txt | grep TRUST_UNDEFINED
|
||||
gpg --status-fd=1 --batch --verify $D/tofu-$KEYIDB-3.txt | grep TRUST_UNDEFINED
|
||||
|
||||
# Import the conflicting user id.
|
||||
gpg --import $D/tofu-$KEYIDB-3.gpg
|
||||
gpg -k
|
||||
|
||||
# Import the cross signature, which should remove the conflict.
|
||||
gpg --import $D/tofu-$KEYIDB-4.gpg
|
||||
gpg -k
|
Loading…
x
Reference in New Issue
Block a user