Re: git-tag bug? confusing git fast-export with double tag objects

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Andreas Ericsson <ae@xxxxxx> writes:

> You re-create all your tag refs with same-name tags that point to the
> old tags.
> Joe Dev fetches from you, but your tags do not get stored as refs.
> Joe Dev publishes a repo somewhere with a bunch of topic-branches and
> requests you merge from those repositories.
> You fetch from Joe.
>
> Now we have two opposite problems.
> If tags aren't updated when Joe Dev fetches from you, his refs will
> not match yours when you fetch from him, and anyone cloning from him
> even after the re-sign will never get the new tags at all.
> If tag refs *do* get updated when fetching from a repo when we already
> have another tag ref with the same name, you fetching from Joe Dev
> could undo all your re-created tags and make the new tag-objects
> garbage-collectable. This assumes Joe Dev published his repo before
> fetching your new tags though.
>
> Perhaps I'm missing something....

No, you did not miss anything.  It illustrates the problem space very
well.

There are two "names" to a tag.  The name of a tag is recorded in the
object itself, in its "tag" header.

        $ git cat-file tag v1.6.3
        object f01f1099f40f24fe6f7802185340a6fa3a3d4f35
        type commit
        tag v1.6.3
        tagger Junio C Hamano <gitster@xxxxxxxxx> 1241659007 -0700

        GIT 1.6.3
        -----BEGIN PGP SIGNATURE-----
        Version: GnuPG v1.4.9 (GNU/Linux)
        ...

Anybody can forge, even down to the trailing signature part with a
compromised key, such a tag object that claims to be "tag v1.6.3" and
point anything with it.

But the "name" you usually access a tag object with is not this one.
Instead, you use the name of the ref in refs/tags hierarchy.  These two
names are supposed to match by convention, and I think recent fsck even
checks it.

Unlike the name recorded in tag objects, you can have only one v1.6.3 in
your ref namespace.  And the way git protects users from maliciously made
tags has been by not re-fetching what already exist unless explicitly
asked.  The consequence of this is that you somehow obtained a forged or
vulnerable one first, you will not get corrected ones automatically.

But that is a feature in the current set-up.

If the key that signs release tags were compromised and the tags got
re-signed with a new key (whether I re-tag by pointing at the commit
objects, or pointing at the old-genuine tag objects), that fact needs to
be advertised ("Sorry, but I had to re-tag; if you have old tags, please
re-fetch"), and the user who is currently protected by this "no automatic
re-fetching" mechanism has to somehow assert that "Sorry" is really from
me, and allow git to re-fetch.

The workflow for a such case would be:

 (0) I notice the signing key was somehow compromised; roll a new key,
     re-sign the tags, and send out a "I had to re-tag, and here is a list
     of the old and new tag object names you can use to verify" message;

 (1) You read such a message,  You do "git for-each-ref refs/tags" to see
     the object names to check with my message, and realize that you have
     stale tags.  So does Joe Dev but he may be slower to react;

 (2) You fetch (or ls-remote) from Joe Dev which is your preferrerd mirror
     of my tree and notice he hasn't updated, and let him know.  In the
     meantime you fetch "git fetch --tags" from me, and verify the result
     against my message.

 (3) Joe Dev would do the same.

That's largely manual, cumbersome, and makes everybody involved painfully
aware of what is going on, which may be an advantage over silently
updating with a new tag without telling anybody.

But you can improve the situation without losing security by doing
something like this.

 * Introduce a concept of "trusted signing keys" (similar to the way
   distros sign their binary packages), whose fingerprints are probably
   stored in .git/config of the receiving repositories;

 * Upon 'git tag -v <name>', verify that the signature was made with one
   of the trusted signing keys;

 * Inside 'git fetch':

   - before starting to fetch, see if there are signed tags that exist
     locally but not signed with any of the trusted keys;

   - for the signed tags we find in the above step, if the remote end has
     different tag object at the same refname, ask for them;

   - perform the main 'git fetch' transfer and store things according to
     the refspec as usual (but do not store the tags re-fetched only
     because of the new logic yet);

   - for the tags re-fetched with the new logic, see if they are signed by
     trusted keys, and if so replace the stale tags with them.

The step (0) to issue a "Sorry but I had to re-tag" message with "here is
the fingerprint of new signing key" is still necessary, and you need to
react to it by replacing the old trusted signing key with the fingerprint
of the new key, but after that everything can be made automatic.
--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Kernel Development]     [Gcc Help]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [V4L]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Fedora Users]