Subject: Re: [RFC] Authenticate push via PGP signature, not SSH

From: "Shawn O. Pearce" <[email-masked]>
Date: Tue, 29 Jan 2008 23:22:01 -0500

Pierre Habouzit <[email-masked]> wrote:
> On Tue, Jan 29, 2008 at 04:10:00AM +0000, Shawn O. Pearce wrote:
> > * PGP public key storage:
> > 
> >   Use a "hidden" ref called "refs/access-keys" to store a commit.
> >   The access control change log is a normal Git commit chain.
> 
>   This won't work well, because I don't think GnuPG is able to check
> some signature against an armored GPG public Key (at least I didn't
> found a way to do that). You have to create one pubring per submitter,
> wich is kind of a waste in fact, and the format is horribly binary.

Gaaah.

I hate tools that build their own little internal databases of
objects, and don't let you store their data in other random places,
like in any random file format you choose[*1*].  ;-)

I just read the GnuPG manual and you are obviously correct.  The only
way to get GnuPG to process a key is to load it onto a keyring.
We could extract the armored (or binary) public key and load it
onto a temporary keyring created just for the purpose of verifying
this connection, but that's rather messy.
 
>   I don't even know if you really need the versionning of this
> pseudo-keyring, and if a .git/keyring.gpg isn't enough.

Well, I don't know about that.

People come and go on a project.  It would be nice if there was
a reasonably trusted store available as part of the project, that
one can verify using a current trusted project member's public key,
and obtain prior project member's public keys out of.  But maybe the
Debian folks just doesn't worry about this as it isn't a real issue.

In the case of access control however I need to have a full history
of who had access, during what time periods.  If someone has their
access revoked, I need to know when it was revoked, and by whom.
Git commit chains make for a nice log of such activity.  Obviously
access changes don't need to be reflected through a GnuPG keyring,
and can be as simple as a text file listing the allowed users.

But as a remote administrator for my project (think repo.or.cz!)
how do I add new users to the keyring.gpg on the server?  Being
able to use the existing send-pack/receive-pack infrastructure to
transport the new public key has nice advantages.  Web UIs are
cool, but some of us are command line oriented animals.

>   As a side note, you don't really need to use GIT_PUSH_*. It doesn't
> make anything safer (as the UIDs of a given public key are public
> information anyways), you just want to know which key signed that data,
> and the signature holds that information. Hence if you still want to
> have a flat-file based keyring (which I repeat I don't think gpg
> supports directly -- and that's really a shame) you'd better index them
> per key fingerprint than by author name.

Yea, I know, you haven't told me anything I didn't already know.

Having GIT_PUSHER_{NAME,EMAIL} makes it easier for a hook to
obtain information about this person and use it in an automated
email message.  Think a post-receive hook that automatically sends
out announcement emails.

Having G_P_{NAME,EMAIL} makes it easier for the branch reflogs on the
server to have names in them.  If you look at your local reflogs they
are driven off GIT_COMMITTER_{NAME,EMAIL} and thus report something
meaningful about who did a change.  But when we are in receive-pack
and we update a reflog we don't really have this information, do we?

Having G_P_{NAME,EMAIL} makes it easier to write a hook that looks
up access control data and makes access control decisions based upon
symbols we like to refer to other water transport devices with.
I'd much rather refer to you by your given name 'Pierre' than by
your GPG key id BC6AFB5BA1EE761C.  Especially if I have to list
you in an access control file with 50 other people that lists which
branches you are allowed to push changes into, and which ones you
are restricted from.

Yes, I know the key ids are unique enough for our needs.  But dammit,
they just aren't friendly to work with when you are storing log
records for later inspection, or maintaing an access list.

There is after all reason we have a "tagger" field with a human
readable name on it, rather than relying solely on the GPG key id
of the signature.

>   And then you just need to call gpg this way:
> 
> $ gpg --keyring path/to/the/keyring.gpg --quiet --batch --status-fd 1 --verify some-file.tar.gz.gpg 2>|/dev/null
> [GNUPG:] SIG_ID dw0VliO0DFjOQA3HUSHijYekQYY 2008-01-29 1201633002
> [GNUPG:] GOODSIG BC6AFB5BA1EE761C Pierre Habouzit <[email-masked]>
> [GNUPG:] VALIDSIG 72B4C59ADA78D70E055C129EBC6AFB5BA1EE761C 2008-01-29 1201633002 0 3 0 17 2 00 72B4C59ADA78D70E055C129EBC6AFB5BA1EE761C
> [GNUPG:] TRUST_ULTIMATE
> 
>   And if the key is not in your keyring this looks like:
> $ GNUPGHOME=/tmp gpg --verify --status-fd 1 some-file.tar.gz.gpg 2>/dev/null
> [GNUPG:] ERRSIG BC6AFB5BA1EE761C 17 2 00 1201633002 9
> [GNUPG:] NO_PUBKEY BC6AFB5BA1EE761C
>                    ^^^^^^^^^^^^^^^^
>             that's the key id you look for.

Urgh.  So then we need to go and extract that key, load it onto a
temporary keyring, then reinvoke gpg with the temporary keyring,
just to verify the short command input we received?  Ouch.

OK, maybe I'm making it sound worse than it really will be.

I'm currently finishing a side-band-64k protocol extension to the
send-pack/receive-pack pair.  My next task after I flush those
RFC patches out to the list tonight will be to prototype at least
some of the auth1 extension I described.  I'll maybe try to keep
it really simple initially, which means doing what you suggested
above and using a .git/keyring.gpg for the repository.  Its not
easily remotely administered, but its only a damn proof of concept.

*1* If you don't get this joke, well, uh, I can't help you.
    Oh, ASCII formatted Git packfiles are on the way!  :)

-- 
Shawn.