git.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [RFC] Authenticate push via PGP signature, not SSH
@ 2008-01-28  4:12 Sam Vilain
  2008-01-28  8:12 ` Shawn O. Pearce
  2008-01-28  8:48 ` Pierre Habouzit
  0 siblings, 2 replies; 21+ messages in thread
From: Sam Vilain @ 2008-01-28  4:12 UTC (permalink / raw)
  To: git

I recently sent this to the gitorious list; I knocked up a working
system for this, and it so far seems workable, and it is now topical.

Note that the design used by the proof of concept would not be suitable
for the upcoming versions of git which do not allow pushing tags to
branch refs - they would require calling the tags something like
refs/tags/heads/master or some other suitable convention.  Probably not
even using refs/tags etc, to avoid races.

The key idea is to reject pushes if the PGP signature cannot be verified.

Connect to this data - http://www.rubin.ch/wotsap/ - and give everyone
in the world with a working and well signed PGP key secure push access
without them having to set anything up.  Of course, you would also want
to layer on top of this rules that would force unknown contributors into
a "mob"-like namespace.

When heads are pushed, the signed tags that are moved from refs/heads/
foo can be saved in an "archive" tag space, such as under refs/audit/
KEYID/ - this will allow, in the case of a network of git servers, for
servers to synchronise from each other, even when they
don't trust each other.

The update hook first verifies the signature, and rejects the signature
if not accepted:

------8<------
#!/bin/sh
#
# An example hook script to require all pushes be signed
#

ref=$1
sha1_old=$2
sha1_new=$3

if [ -d "$GIT_DIR/keyring" ]; then
        echo "pgp-git: using repository keyring" >&2
        GNUPGHOME=$GIT_DIR/keyring
        export GNUPGHOME
else
        echo "pgp-git: using default keyring" >&2
fi

set -e

case $ref in
        refs/tags/tmp/*)
                echo "E:Even TRYING that lark makes me ANGRY!" >&2
                exit 38
                ;;

        refs/heads/*|refs/tags/*)
                audit=$(echo "$ref" | sed 's!refs/!refs/tags/tmp/!')
                tagname=$(echo "$audit" | sed 's!refs/tags!!')
                git update-ref -m "update hook" \
                        "$audit" $sha1_new
                ;;

        *)
                echo "E:WHOA!  Pushing to $ref?" >&2
                exit 1
                ;;
esac

trap "git-tag -d $tagname" ERR
git-tag -v "$tagname"
------8<------

And then, the post-update hook will move the tag into the designed place;

------8<------
#!/bin/sh
#
# An example hook script to prepare a packed repository for use over
# dumb transports.
#
# To enable this hook, make this file executable by "chmod +x post-update".

for ref
do
        case "$ref" in
                refs/heads/*)
                        type=$(git cat-file -t $ref)
                        if [ $type = "tag" ]
                        then
                                echo "pgp-git: removing dummy tag" >&2
                                git update-ref -m "post-update hook -
remove dummy tag" "$ref" "$ref^{commit}"
                        fi

                        ;;
                *);;
        esac
done

git-update-server-info
------8<------

This does force potential contributors to get PGP keys, and get them
signed - but that seems to me to be a reasonable barrier of entry and
may even help drive some PGP adoption.

Remember this is a proof of concept, so let's discuss the design first
and not worry too much about the glaring bugs yet.

Sam.

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [RFC] Authenticate push via PGP signature, not SSH
  2008-01-28  4:12 [RFC] Authenticate push via PGP signature, not SSH Sam Vilain
@ 2008-01-28  8:12 ` Shawn O. Pearce
  2008-01-28 21:06   ` Jan Hudec
  2008-01-28 21:58   ` Sam Vilain
  2008-01-28  8:48 ` Pierre Habouzit
  1 sibling, 2 replies; 21+ messages in thread
From: Shawn O. Pearce @ 2008-01-28  8:12 UTC (permalink / raw)
  To: Sam Vilain; +Cc: git

Sam Vilain <sam@vilain.net> wrote:
...
> The key idea is to reject pushes if the PGP signature cannot be verified.
...
> When heads are pushed, the signed tags that are moved from refs/heads/
> foo can be saved in an "archive" tag space, such as under refs/audit/
> KEYID/ - this will allow, in the case of a network of git servers, for
> servers to synchronise from each other, even when they
> don't trust each other.

This is certainly interesting.  It would benefit from the recursive
locking scheme we were talking about for the update hook, which
someone (Steven Grimm?) wanted so they could execute git-svn
transparently during push and have the update hook change the ref
instead of receive-pack.

The downside to this is you have to tag everything before you push
it, so you need some sort of wrapper around git-push.  That isn't
as hard as it sounds for the command line case, but it does make
things more difficult for a usage from say git-gui.  :)

I was also thinking about using GPG to sign the command packets
being sent between send-pack and receive-pack.  If the GPG signature
for that set of packets is good and a known key then the update is
allowed to continue.  This avoids the mess of needing to run git-tag
locally before push, and of needing to "unwrap" the temporary tag
in the receiving repository, but it adds yet another extension to
the send-pack/receive-pack protocol.
 
> This does force potential contributors to get PGP keys, and get them
> signed - but that seems to me to be a reasonable barrier of entry and
> may even help drive some PGP adoption.

In many cases today such contributers would have been forced to get
an SSH account on the server they want to push to.  Getting an SSH
account configured and a key installed may be more difficult than
generating a PGP key pair and emailing in the public key.

Of course the PGP based system is nicer in that the administrator
might get a public key that has been signed by others he trusts,
and thus is more readily able to verify that the contributor is
who they think it is.


To be perfectly honest, in a wide open source community I think
the truely distributed nature of development like the linux kernel
or git itself uses works very well.  Development schedules aren't
organized into "next 30 minutes", "next 4 hours", and "next week".

Peer review and community acceptance of changes is a very important
concept.  Blindly accepting changes into a tree because of a PGP
signature/SSL certificate/SSH key isn't really the norm, and is
far from the best solution.  We've all posted cr**p^Wless-than-
the-best-code to this list before, and yet many of us would have
"committer access" to the git tree under a centralized model.

I'm happy my changes aren't accepted just because I signed them.
Its better that Linus/Nico/Dscho/Junio/you/et.al. have looked at
them and also felt they were worthwhile.


But in a smaller business type setting, where there's under 100
employees working, odds are you've already created the user account
on systems, and physically passed the initial password via a sticky
note after checking the person's government issued IDs.  In such a
setting having yet another authentication system (PGP keys) is just
yet more work for the already over worked/under appreciated IT staff.

-- 
Shawn.

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [RFC] Authenticate push via PGP signature, not SSH
  2008-01-28  4:12 [RFC] Authenticate push via PGP signature, not SSH Sam Vilain
  2008-01-28  8:12 ` Shawn O. Pearce
@ 2008-01-28  8:48 ` Pierre Habouzit
  1 sibling, 0 replies; 21+ messages in thread
From: Pierre Habouzit @ 2008-01-28  8:48 UTC (permalink / raw)
  To: Sam Vilain; +Cc: git

[-- Attachment #1: Type: text/plain, Size: 1128 bytes --]

On Mon, Jan 28, 2008 at 06:12:34AM +0000, Sam Vilain wrote:
> This does force potential contributors to get PGP keys, and get them
> signed - but that seems to me to be a reasonable barrier of entry and
> may even help drive some PGP adoption.
> 
> Remember this is a proof of concept, so let's discuss the design first
> and not worry too much about the glaring bugs yet.

  FWIW I'm really interested into such a "thing", and that I'd like to
avoid giving unix (even with git-shell, not only because of security,
but because it pollutes the machine setup a lot) accounts to my git
servers, though would like to let people help in my Debian packaging.
Fors us GPG isn't an issue, as every single DD or wannabe has a GPG key
:)

  Note though that the fact that you need to push a dummy tag is somehow
disgusting IMHO, it should at least be integrated into git-push so that
the user doesn't have to generate the dummy tag himself.

-- 
·O·  Pierre Habouzit
··O                                                madcoder@debian.org
OOO                                                http://www.madism.org

[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [RFC] Authenticate push via PGP signature, not SSH
  2008-01-28  8:12 ` Shawn O. Pearce
@ 2008-01-28 21:06   ` Jan Hudec
  2008-01-28 21:58   ` Sam Vilain
  1 sibling, 0 replies; 21+ messages in thread
From: Jan Hudec @ 2008-01-28 21:06 UTC (permalink / raw)
  To: Shawn O. Pearce; +Cc: Sam Vilain, git

[-- Attachment #1: Type: text/plain, Size: 1243 bytes --]

On Mon, Jan 28, 2008 at 03:12:58 -0500, Shawn O. Pearce wrote:
> Sam Vilain <sam@vilain.net> wrote:
> > This does force potential contributors to get PGP keys, and get them
> > signed - but that seems to me to be a reasonable barrier of entry and
> > may even help drive some PGP adoption.
> 
> In many cases today such contributers would have been forced to get
> an SSH account on the server they want to push to.  Getting an SSH
> account configured and a key installed may be more difficult than
> generating a PGP key pair and emailing in the public key.

Actually no. SSH key pair is good enough in current situation. In fact
it might be *better* than SSH account, because with SSH account, the user
either has or does not have write access, while with SSH key pair he is still
subject to limitations enforced by the receive-hook.

> Of course the PGP based system is nicer in that the administrator
> might get a public key that has been signed by others he trusts,
> and thus is more readily able to verify that the contributor is
> who they think it is.

That, however, is an advantage of PGP. Obviously, additional rules can still
be enforced by the receive-hook.

-- 
						 Jan 'Bulb' Hudec <bulb@ucw.cz>

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [RFC] Authenticate push via PGP signature, not SSH
  2008-01-28  8:12 ` Shawn O. Pearce
  2008-01-28 21:06   ` Jan Hudec
@ 2008-01-28 21:58   ` Sam Vilain
  2008-01-29  2:57     ` Shawn O. Pearce
  2008-01-29  4:10     ` Shawn O. Pearce
  1 sibling, 2 replies; 21+ messages in thread
From: Sam Vilain @ 2008-01-28 21:58 UTC (permalink / raw)
  To: Shawn O. Pearce; +Cc: git

Shawn O. Pearce wrote:
> To be perfectly honest, in a wide open source community I think
> the truely distributed nature of development like the linux kernel
> or git itself uses works very well.  Development schedules aren't
> organized into "next 30 minutes", "next 4 hours", and "next week".
> 
> Peer review and community acceptance of changes is a very important
> concept.  Blindly accepting changes into a tree because of a PGP
> signature/SSL certificate/SSH key isn't really the norm, and is
> far from the best solution.  We've all posted cr**p^Wless-than-
> the-best-code to this list before, and yet many of us would have
> "committer access" to the git tree under a centralized model.
>
> I'm happy my changes aren't accepted just because I signed them.
> Its better that Linus/Nico/Dscho/Junio/you/et.al. have looked at
> them and also felt they were worthwhile.

I agree wholeheartedly - hence my comment about "mob" branches.  What I
was implying is that you could model it conceptually off repo.or.cz.

That is, when you start a project, you "own" a namespace.  Everyone else
has to pick a fork name, and the first push they make to
"forks/forkname/*" registers that fork name to that key.

This could support fully distributed access control over the namespaces.
  What it means for access control to be distributed is that any node
can check the log of tags that granted permission to people, and
assuming that they processed the same grants in the same order they will
arrive at the same access control result.

To describe this with an example, say Linus decides that Junio can push
to any ref on the project, he can note in a tag;

  "From this release forward, Junio Hamano <KEYID> will be authorized to
   push to any reference, and grant access to others under the reference
   space 'refs/heads/topics/'".

Or, preferably something more automatically parsable.  Anyway, the
presence of a signed document is a hint for the audit program to try to
reach Junio's key from Linus' key (like this would:
http://pgp.cs.uu.nl/mk_path.cgi?FROM=76E21CBB&TO=F3119B9A&PATHS=trust+paths)
if it can, and then add the signing key to the ACL's PGP keyring.

The ACL state could be a branch in a funny refspace with a directory for
the keyring, and a place to keep copies of any tags it removed because
they were there just for the push.

And yes, it would need a simple interface.

> But in a smaller business type setting, where there's under 100
> employees working, odds are you've already created the user account
> on systems, and physically passed the initial password via a sticky
> note after checking the person's government issued IDs.  In such a
> setting having yet another authentication system (PGP keys) is just
> yet more work for the already over worked/under appreciated IT staff.

Agreed - again I'd personally consider allowing receive-pack with
reflogs in those environments if setting up PGP or SSH keys was a hassle.

Sam.

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [RFC] Authenticate push via PGP signature, not SSH
  2008-01-28 21:58   ` Sam Vilain
@ 2008-01-29  2:57     ` Shawn O. Pearce
  2008-01-29  4:10     ` Shawn O. Pearce
  1 sibling, 0 replies; 21+ messages in thread
From: Shawn O. Pearce @ 2008-01-29  2:57 UTC (permalink / raw)
  To: Sam Vilain; +Cc: git

Sam Vilain <sam@vilain.net> wrote:
> Shawn O. Pearce wrote:
> > But in a smaller business type setting, where there's under 100
> > employees working, odds are you've already created the user account
> > on systems, and physically passed the initial password via a sticky
> > note after checking the person's government issued IDs.  In such a
> > setting having yet another authentication system (PGP keys) is just
> > yet more work for the already over worked/under appreciated IT staff.
> 
> Agreed - again I'd personally consider allowing receive-pack with
> reflogs in those environments if setting up PGP or SSH keys was a hassle.

Yea, I already have reflogs enabled for all stored branches on the
central server.  And since some branches have a no-delete policy
(based upon the rules offered by contrib/hooks/update-paranoid) the
reflogs are also effectively no-delete, even if the branch rewinds.

I also never run `git reflog expire`.  I might in another year or
so consider it, but most of my no-delete branches also don't rewind
very often (if ever) so there's very little disk to be gained by
reflog expiry.

-- 
Shawn.

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [RFC] Authenticate push via PGP signature, not SSH
  2008-01-28 21:58   ` Sam Vilain
  2008-01-29  2:57     ` Shawn O. Pearce
@ 2008-01-29  4:10     ` Shawn O. Pearce
  2008-01-29 19:08       ` Pierre Habouzit
  2008-01-30  6:29       ` Sam Vilain
  1 sibling, 2 replies; 21+ messages in thread
From: Shawn O. Pearce @ 2008-01-29  4:10 UTC (permalink / raw)
  To: Sam Vilain, Pierre Habouzit; +Cc: git

Sam Vilain <sam@vilain.net> wrote:
> This could support fully distributed access control over the namespaces.
>   What it means for access control to be distributed is that any node
> can check the log of tags that granted permission to people, and
> assuming that they processed the same grants in the same order they will
> arrive at the same access control result.
> 
> To describe this with an example, say Linus decides that Junio can push
> to any ref on the project, he can note in a tag;
> 
>   "From this release forward, Junio Hamano <KEYID> will be authorized to
>    push to any reference, and grant access to others under the reference
>    space 'refs/heads/topics/'".
> 
> The ACL state could be a branch in a funny refspace with a directory for
> the keyring, and a place to keep copies of any tags it removed because
> they were there just for the push.
> 
> And yes, it would need a simple interface.

After some thought today about your message above and Pierre's about
the Debian package maintainers have gotten me into thinking that
we really should just support PGP signature verification as part
of send-pack/receive-pack, making it reasonably safe to expose an
open git-daemon over TCP/IP, complete with receive-pack enabled.

My attempt to use UNIX authentication over a domain socket was
probably stupid.  Good thing there are smarter people than I
on this list, and even better that they decided to join in the
conversation.  :)

Here's (I hope) a short outline of what I was thinking:

* New protocol extension to send-pack/receive-pack pair:

  If server wants to require (or optionally) accept a signed push
  event it sends a new capability string when it advertises its
  current known heads:

    auth-1=[0-9a-f]{40}

  The actual length and data value is mostly irrelevant to this
  discussion, but the data is a nonce for this single connection
  between send-pack and receive-pack.  It needs to come from a
  reasonably good PRNG.

  If send-pack then wants to upload one or more refs:

  Send back the capability "auth-1" as part of the first ref
  being pushed.  Note we skip the nonce in the capablity request.
  Send all ref update commands using current protocol.

  Generate a SHA-1 around the following:

    <nonce><command>+<auth>

    command  ::= <old_sha1> <new_sha1> <op> <ref> '\0'
    old_sha1 ::= 20 byte binary string
    new_sha1 ::= 20 byte binary string
    op       ::= ' ' | '+'
    ref      ::= ref name

  Send another pkt-line before the flush containing the user
  identity and the PGP signature for the hash from the above:

    <auth><pgp_sig>

    auth    ::= 'auth' ' ' <name> ' ' '<' <email> '>' '\n'
    name    ::= like a commit author-name
    email   ::= like a commit author-email
    pgp_sig ::= armored signature from PGP

  receive-pack expects this new auth pkt-line if the client asked
  to enable the auth-1 capablity in the first command.

  If receive-pack was configured (say by config receive.auth)
  to require authentication then it closes the connection if the
  client didn't request the capablity in the first command.

  receive-pack can generate the same SHA-1 hash from the commands
  it read from send-pack, and can verify the PGP signature on the
  auth line.

  This assures us the command stream wasn't modified, and likely
  originated from the named identity.  The rest of the packfile
  data is already well protected by its own SHA-1 footer and the
  individual object SHA-1s, and the roots pointing into that DAG
  (or sub-DAG) mentioned in the commands were verified by the PGP
  signature of them.

  Push isn't that common, but this extension format doesn't require
  any additional round-trips between the two peers, so latency
  doesn't change.  Which I guess is nice.

  It also avoids the relatively ugly part of having a dummy tag
  involved in the transfer and shoved into the ref namespace for
  a short period of time.


* receive-hook validations:

  If we got an auth line above then we export the <name> and
  <email> values into a pair of new environment variables:

    GIT_PUSHER_NAME=<name>
    GIT_PUSHER_EMAIL=<email>

  thus exposing the who down to any hooks we might execute, in
  particular the pre-receive and the update hooks, as tools like
  contrib/hooks/update-paranoid and gitosis can then base their
  per-ref access decisions off these.


* 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.

  The tree under this commit stores a file per <email> string.
  Public keys for auth line validation are located by <email>,
  from the tip of this branch.

  This branch could be a symlink to another repository (e.g.
  a site-wide "admin" repository) and the ODB for that other
  repository could be an alternate for this repository.


* ref/access-keys security:

  Probably an update or pre-receive hook could verify pushes
  to this branch by something like this:

    - If the only difference between $old_sha1 $new_sha1 is
      a modification of $GIT_PUSHER_EMAIL then allow it
      (user is replacing their own key);

    - If the only difference between $old_sha1 $new_sha1 is
      modifications of names other than $GIT_PUSHER_EMAIL but
      the file content differences are only $GIT_PUSHER_EMAIL
      signing those public keys then allow it (the user doing
      the push is publishing some trust);

    - If the difference between $old_sha1 $new_sha1 is new
      keys added or existing keys removed then allow it only
      if $GIT_PUSHER_EMAIL is also listed inside of the
      "admin/" subtree and the new key is also signed by
      $GIT_PUSHER_EMAIL's key.


But here's where things start to get funny.

On a site like repo.or.cz the idea of being able to create your
own unique subnamespace by pushing your key at the server is
simple enough, and actually sorta cool.

But in my central repository layout at day-job I don't want people
forking.  Instead I want them to stay within their pre-assigned
namespace of the single common repository.  So the access control
rules being applied start to really head in lots of different
directions at this point.

-- 
Shawn.

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [RFC] Authenticate push via PGP signature, not SSH
  2008-01-29  4:10     ` Shawn O. Pearce
@ 2008-01-29 19:08       ` Pierre Habouzit
  2008-01-30  4:22         ` Shawn O. Pearce
  2008-01-30  6:29       ` Sam Vilain
  1 sibling, 1 reply; 21+ messages in thread
From: Pierre Habouzit @ 2008-01-29 19:08 UTC (permalink / raw)
  To: Shawn O. Pearce; +Cc: Sam Vilain, git

[-- Attachment #1: Type: text/plain, Size: 2438 bytes --]

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.
> 
>   The tree under this commit stores a file per <email> string.
>   Public keys for auth line validation are located by <email>,
>   from the tip of this branch.
> 
>   This branch could be a symlink to another repository (e.g.
>   a site-wide "admin" repository) and the ODB for that other
>   repository could be an alternate for this repository.

  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.

  I don't even know if you really need the versionning of this
pseudo-keyring, and if a .git/keyring.gpg isn't enough.

  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.

  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 <pierre.habouzit@polytechnique.edu>
[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.


-- 
·O·  Pierre Habouzit
··O                                                madcoder@debian.org
OOO                                                http://www.madism.org

[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [RFC] Authenticate push via PGP signature, not SSH
  2008-01-29 19:08       ` Pierre Habouzit
@ 2008-01-30  4:22         ` Shawn O. Pearce
  2008-01-30  5:55           ` Sam Vilain
                             ` (2 more replies)
  0 siblings, 3 replies; 21+ messages in thread
From: Shawn O. Pearce @ 2008-01-30  4:22 UTC (permalink / raw)
  To: Pierre Habouzit; +Cc: Sam Vilain, git

Pierre Habouzit <madcoder@debian.org> 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 <pierre.habouzit@polytechnique.edu>
> [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.

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [RFC] Authenticate push via PGP signature, not SSH
  2008-01-30  4:22         ` Shawn O. Pearce
@ 2008-01-30  5:55           ` Sam Vilain
  2008-01-30  6:16             ` Shawn O. Pearce
  2008-01-30  8:35             ` Pierre Habouzit
  2008-01-30  8:00           ` Johannes Sixt
  2008-01-30  8:33           ` Pierre Habouzit
  2 siblings, 2 replies; 21+ messages in thread
From: Sam Vilain @ 2008-01-30  5:55 UTC (permalink / raw)
  To: Shawn O. Pearce; +Cc: Pierre Habouzit, git

Shawn O. Pearce wrote:
> 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.

It should be fine just to throw the lot into a single keyring, and just
check which key verified it after the fact and whether that key was allowed.

The Perl Crypt::OpenPGP module doesn't suffer from this problem (and is
performant), though it suffers from a dependency stack that will hurt
everyone except Debian users ;-).

I think this is a non-issue.

>> $ 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 <pierre.habouzit@polytechnique.edu>
>> [GNUPG:] VALIDSIG 72B4C59ADA78D70E055C129EBC6AFB5BA1EE761C 2008-01-29 1201633002 0 3 0 17 2 00 72B4C59ADA78D70E055C129EBC6AFB5BA1EE761C
^^^ there GPG just told you which key was used.
>> [GNUPG:] TRUST_ULTIMATE

Sam.

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [RFC] Authenticate push via PGP signature, not SSH
  2008-01-30  5:55           ` Sam Vilain
@ 2008-01-30  6:16             ` Shawn O. Pearce
  2008-01-30  8:35             ` Pierre Habouzit
  1 sibling, 0 replies; 21+ messages in thread
From: Shawn O. Pearce @ 2008-01-30  6:16 UTC (permalink / raw)
  To: Sam Vilain; +Cc: Pierre Habouzit, git

Sam Vilain <sam@vilain.net> wrote:
> Shawn O. Pearce wrote:
> > 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.
> 
> It should be fine just to throw the lot into a single keyring, and just
> check which key verified it after the fact and whether that key was allowed.
> 
> The Perl Crypt::OpenPGP module doesn't suffer from this problem (and is
> performant), though it suffers from a dependency stack that will hurt
> everyone except Debian users ;-).

Heh.  One of my Gentoo boxes seems to claim this would be an easier
emerge than the Qt3 emerge that it keeps trying to do, and failing,
for the past week and a half.  But yea, I don't have half the stuff
its asking for installed.
 
> >> $ 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 <pierre.habouzit@polytechnique.edu>
> >> [GNUPG:] VALIDSIG 72B4C59ADA78D70E055C129EBC6AFB5BA1EE761C 2008-01-29 1201633002 0 3 0 17 2 00 72B4C59ADA78D70E055C129EBC6AFB5BA1EE761C
> ^^^ there GPG just told you which key was used.

Yup.  I think that's what we'll have to do.  But managing the keyring
is (I think) something we need to solve.  It should be able to be
done remotely, assuming you have authority, and ideally through
standard Git channels.

If we're going to the trouble of effectively replacing SSH for
authenticated Git object push (at least for stuff that is open
source and thus doesn't require privacy during upload) we might
as well make sure it can actually be managed too.

-- 
Shawn.

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [RFC] Authenticate push via PGP signature, not SSH
  2008-01-29  4:10     ` Shawn O. Pearce
  2008-01-29 19:08       ` Pierre Habouzit
@ 2008-01-30  6:29       ` Sam Vilain
  2008-01-30  7:47         ` Shawn O. Pearce
  1 sibling, 1 reply; 21+ messages in thread
From: Sam Vilain @ 2008-01-30  6:29 UTC (permalink / raw)
  To: Shawn O. Pearce; +Cc: Pierre Habouzit, git

Shawn O. Pearce wrote:
> * New protocol extension to send-pack/receive-pack pair:
> 
>   If server wants to require (or optionally) accept a signed push
>   event it sends a new capability string when it advertises its
>   current known heads:
> 
>     auth-1=[0-9a-f]{40}
  [...]
>     <auth><pgp_sig>
> 
>     auth    ::= 'auth' ' ' <name> ' ' '<' <email> '>' '\n'
>     name    ::= like a commit author-name
>     email   ::= like a commit author-email
>     pgp_sig ::= armored signature from PGP
> 
>   receive-pack expects this new auth pkt-line if the client asked
>   to enable the auth-1 capablity in the first command.
> 
>   If receive-pack was configured (say by config receive.auth)
>   to require authentication then it closes the connection if the
>   client didn't request the capablity in the first command.
> 
>   receive-pack can generate the same SHA-1 hash from the commands
>   it read from send-pack, and can verify the PGP signature on the
>   auth line.
> 
>   This assures us the command stream wasn't modified, and likely
>   originated from the named identity.  The rest of the packfile
>   data is already well protected by its own SHA-1 footer and the
>   individual object SHA-1s, and the roots pointing into that DAG
>   (or sub-DAG) mentioned in the commands were verified by the PGP
>   signature of them.

Ok - but I think if the client is pushing a signed tag to the tagname
listed in the signed body of the tag, that no extra signature should be
necessary.  It's only commits that need the extra information.

And remember, for global replication of the data between untrusted nodes
to be possible, the signatures must be saved somewhere.  I have sketched
a simple design below.

> * 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.
> 
>   The tree under this commit stores a file per <email> string.
>   Public keys for auth line validation are located by <email>,
>   from the tip of this branch.
> 
>   This branch could be a symlink to another repository (e.g.
>   a site-wide "admin" repository) and the ODB for that other
>   repository could be an alternate for this repository.
> 
> 
> * ref/access-keys security:
> 
>   Probably an update or pre-receive hook could verify pushes
>   to this branch by something like this:
> 
>     - If the only difference between $old_sha1 $new_sha1 is
>       a modification of $GIT_PUSHER_EMAIL then allow it
>       (user is replacing their own key);
> 
>     - If the only difference between $old_sha1 $new_sha1 is
>       modifications of names other than $GIT_PUSHER_EMAIL but
>       the file content differences are only $GIT_PUSHER_EMAIL
>       signing those public keys then allow it (the user doing
>       the push is publishing some trust);
> 
>     - If the difference between $old_sha1 $new_sha1 is new
>       keys added or existing keys removed then allow it only
>       if $GIT_PUSHER_EMAIL is also listed inside of the
>       "admin/" subtree and the new key is also signed by
>       $GIT_PUSHER_EMAIL's key.

Ok perhaps it is best to wrap all this up in a single state branch, that
has in it:

   access-keys/
     - tree with one key per e-mail address
   access
     - maps reference globs to e-mail addresses permitted to change
       them - with a "+" if the address may rewind the ref
   owners
     - maps reference globs to e-mail addresses permitted to add entries
       to the "access" map above
   signatures/
     - stores any detached signatures.  only the signatures verifying
       updates since the last commit to the access meta-branch need to
       be stored
   packed-refs
     - the new list of references (the refs/access commitid is naturally
       absent or the same as the parent), or just the changed
       references.

You don't necessarily need a new commit on this for every single push,
just once "every so often", and perhaps for safety once for every change
to the access file.

This branch should then be auditable; replicating tools can go and
verify that there have been no unauthorized changes.

Forks don't necessarily need special treatment; they can exist under
refs/forks/foobar/ - similar to the refs/remotes/ namespace, and have
their own independent ACL branches within.

Allowing "grant" permissions to refspaces would need to be handled
specially; you can't simply grant access to change refs/access; the
actual push to refs/access would need inspecting to see if the changed
"access" file comes within the rights of the user that signed the update.

I think this seems about right for a first cut.  Possibly bigger
projects like Debian would like to say that for certain ref spaces,
multiple signatures are required, so that no one PGP key retains
complete control.  But I think these things are easily added as features
on top of this basic infrastructure.

Sound like something worth working towards?
Sam.

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [RFC] Authenticate push via PGP signature, not SSH
  2008-01-30  6:29       ` Sam Vilain
@ 2008-01-30  7:47         ` Shawn O. Pearce
  2008-01-31  1:18           ` Sam Vilain
  0 siblings, 1 reply; 21+ messages in thread
From: Shawn O. Pearce @ 2008-01-30  7:47 UTC (permalink / raw)
  To: Sam Vilain; +Cc: Pierre Habouzit, git

Sam Vilain <sam@vilain.net> wrote:
> Shawn O. Pearce wrote:
> > * New protocol extension to send-pack/receive-pack pair:
> > 
> >   If server wants to require (or optionally) accept a signed push
> >   event it sends a new capability string when it advertises its
> >   current known heads:
> 
> Ok - but I think if the client is pushing a signed tag to the tagname
> listed in the signed body of the tag, that no extra signature should be
> necessary.  It's only commits that need the extra information.

Doh.  Of course the standard signed tag case is easily verified,
without the new authentication extension.  But adding it around
a signed tag push doesn't really hurt anything, except maybe the
user who entered her passphrase yet again.

Signing a tag push is actually relevant in some cases.  For example
when I mirror Junio's git.git tree into my local server at day-job.
Junio signed the v1.5.4-rc5 tag.  I pushed it to the same location,
and although we can validate Junio's signature, it may matter (to
people who have too much free time on their hands but I digress)
who at our organization put that v1.5.4-rc5 tag from Junio onto
that particular system, and when they did that.  Was it me?
Or another co-worker?

> And remember, for global replication of the data between untrusted nodes
> to be possible, the signatures must be saved somewhere.  I have sketched
> a simple design below.

Crap.  You mentioned this in your initial email, and I forgot
about it when I posted the message you are responding to now.
Its actually an interesting concept.  We can validate the entire
chain of commits that led up to a signed tag, and we can validate
that signature on that tag.  So why shouldn't we also be able to
validate the changes to refs in a distributed fashion?

This does complicate things considerably, as now we're talking
about the ref namespace no longer being this simple set of DAG
pointers, but itself becoming a DAG.  Someone please stop the
madness!  :-)

> > * PGP public key storage:
> > * ref/access-keys security:
> 
> Ok perhaps it is best to wrap all this up in a single state branch, that
> has in it:
> 
>    access-keys/
>      - tree with one key per e-mail address
>    access
>      - maps reference globs to e-mail addresses permitted to change
>        them - with a "+" if the address may rewind the ref
>    owners
>      - maps reference globs to e-mail addresses permitted to add entries
>        to the "access" map above

This part I get.  Using only globs is a tad limited in my mind.
I actually abuse regexes on refs at day-job in a few places to get
the access list to work with just a handful of rules.

>    signatures/
>      - stores any detached signatures.  only the signatures verifying
>        updates since the last commit to the access meta-branch need to
>        be stored
>    packed-refs
>      - the new list of references (the refs/access commitid is naturally
>        absent or the same as the parent), or just the changed
>        references.

This I'm not so sure.  Are you suggesting that we save the detached
signature I described earlier that signed the push command set and
store it here, in this access state branch?  And that we also store
a copy of all refs (save this one) as a flat file?

I guess the hidden part here is one can recover the command set used
between any two pushes by diffing the packed-refs file and parsing
that diff to regenerate the command set.  Then you have to find some
detached signature that is associated with this set of commands and
verify it.  Matching the signature back to its public key is easy.
What isn't described here is the complexity of matching the detached
signature to a command set that was extracted from the diff of the
packed-refs file.

Urgh.

I think this needs to be rethunk.  Its really freaking early morning
here, and I probably should be in bed, not solving security problems,
but this is starting to feel like we are trying to use the Titantic
as a hammer to tighten a motherboard mounting screw.  Its a bit
heavy, somewhat difficult to yield with one hand, and probably
not the best tool for the job.  But it moved that D@*! screw.
And your desk, your floor, your office building, and the rest of
the city block while it was at it.
 
> You don't necessarily need a new commit on this for every single push,
> just once "every so often", and perhaps for safety once for every change
> to the access file.

Actually I think you would need a new commit for each detached
signature you received.  Otherwise you may wind up with a set of
refs that you cannot explain how they happened, and the signatures
you do have don't sign those changes.

Now maybe you have a "mob" branch that anyone can push to, without
authorization, in which case OK, I can see the not every push does
an update to the access state branch case.  But I think that if we
get a signature for a ref command set we'd need to save that, if
we are saving them at all.

> This branch should then be auditable; replicating tools can go and
> verify that there have been no unauthorized changes.
> 
> Forks don't necessarily need special treatment; they can exist under
> refs/forks/foobar/ - similar to the refs/remotes/ namespace, and have
> their own independent ACL branches within.
> 
> Allowing "grant" permissions to refspaces would need to be handled
> specially; you can't simply grant access to change refs/access; the
> actual push to refs/access would need inspecting to see if the changed
> "access" file comes within the rights of the user that signed the update.

Right.  Which gets interesting.  The paranoid update hook also does
file level ACLs by checking the output of `git diff-tree $old $new`,
but it really gets tripped up during merges.  It cannot tell that
you are just merging some other branch and haven't yourself made
modifications to the files.

> I think this seems about right for a first cut.  Possibly bigger
> projects like Debian would like to say that for certain ref spaces,
> multiple signatures are required, so that no one PGP key retains
> complete control.  But I think these things are easily added as features
> on top of this basic infrastructure.

Where do we enqueue the partial pushes until final approval?

I actually like this idea, of allowing voting for a refspace change,
and having the refspace update only when sufficient authorization
has been received.  Possibly based upon pure number of users who
authorized the change, or based upon their PGP trust values in the
server's PGP trust database, or a combination of the two.

At day-job we use a code review system based upon Git where code
reviewers push commit SHA-1s into special hidden namespaces:

	refs/approved/$ri/$branch
	refs/rejected/$ri/$branch

The $ri is the reviewer's private namespace (e.g. mine is sp,
yours might have been sv) and $branch is the name of the branch
head, minus refs/heads.  A little Perl script reads the output of
`git ls-remote` to count the number of approved and rejected refs
for a given branch, where the SHA-1 values are all identical.  If a
developer amends or pushes new commits onto an already approved
branch the approval is no longer counted, as the SHA-1s now differ.

A simple GC script cleans up any stale approved and rejected refs,
and gets run once a week alongside repack.

Really simple Apache style change voting, in git.

I bring this up now because our code review approvals are sort
of along the lines you were just suggesting "bigger projects like
Debain" might need to allow changes to say their stable security
fix branch.  We're a lot smaller than Debian, but it would be nice
if there is some sort of middle ground that would get both groups
some support within the core.

Enterprises that have "two person change" rules may also like this
sort of feature, as then the system automatically enforces the
rule that at least two individuals must approve a change in status
for software.  Oh, my day-job is such a group, but since our tools
don't really verify squat we ignore that two man change thing.

But yes, this is really heavy-weight process wise, and we can't
please everyone and still have a really simple system that mere
mortals can understand, so I'm probably off in la-la land at this
point in the discussion.
 
> Sound like something worth working towards?

We're getting there.

-- 
Shawn.

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [RFC] Authenticate push via PGP signature, not SSH
  2008-01-30  4:22         ` Shawn O. Pearce
  2008-01-30  5:55           ` Sam Vilain
@ 2008-01-30  8:00           ` Johannes Sixt
  2008-01-31  5:43             ` Shawn O. Pearce
  2008-01-30  8:33           ` Pierre Habouzit
  2 siblings, 1 reply; 21+ messages in thread
From: Johannes Sixt @ 2008-01-30  8:00 UTC (permalink / raw)
  To: Shawn O. Pearce; +Cc: Pierre Habouzit, Sam Vilain, git

Shawn O. Pearce schrieb:
> 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 propose to make the syntax of the extension

server capability:  auth=<list of hash methods>:<challenge>
client response:    auth=<chosen hash method>

where <challenge> is a random sequence of non-blank ASCII text, not
necessarily of a fixed length, but perhaps of a minimum length.

Then we can extend the list of hash algorithms (that are used for
authentication purposes) if people think that SHA1 is not secure enough:

    auth=SHA1,SHA256:random-stuff-goes-here

I'm not a security expert, so take this with a grain of salt.

-- Hannes

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [RFC] Authenticate push via PGP signature, not SSH
  2008-01-30  4:22         ` Shawn O. Pearce
  2008-01-30  5:55           ` Sam Vilain
  2008-01-30  8:00           ` Johannes Sixt
@ 2008-01-30  8:33           ` Pierre Habouzit
  2008-01-31  4:30             ` Shawn O. Pearce
  2 siblings, 1 reply; 21+ messages in thread
From: Pierre Habouzit @ 2008-01-30  8:33 UTC (permalink / raw)
  To: Shawn O. Pearce; +Cc: Sam Vilain, git

[-- Attachment #1: Type: text/plain, Size: 4368 bytes --]

On Wed, Jan 30, 2008 at 04:22:01AM +0000, Shawn O. Pearce wrote:
> Pierre Habouzit <madcoder@debian.org> 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*].  ;-)

  [for the record I got the joke].

> 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.

  That was my point.

> >   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.

  It is, we have since recently the princple of "Debian Maintainers",
people that are only allowed to upload their own package, and the
keyring used for that purpose is versionned using a custom development
of ours called jetring (by Joey Hess and al.), I suppose the sources are
somewhere around, and it has an internal ascii-armored database IIRC
_and_ a gpg-usable keyring, I think. Or is able to generate the keyring
at least.

  But for the case I discussed, indeed, I'd use
/usr/share/keyrings/debian-keyring.gpg anyways, and won't be the one
updating it. That's why your developpement should be able to allow
checking against another keyring. IOW I'm less and less sure that you
want to manage the keyring _necessarily_ inside the git tree, and that
allowing any external way to manage a keyring (inside a git tree beeing
one of the options) is the most flexible way.

> >   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.

  okay, that makes sense. Sorry about the obvious parts, it sensed like
you didn't used gpg on a regular basis, hence wasn't sure of what you
already knew or not. I agree that for the sake of logging GIT_PUSHER_*
are nice, since as you can see on the CLI examples I gave, gpg says that
the email associated to my key is pierre.habouzit@polytechnique.edu
whereas I ususally contribute to open source projects using
madcoder@debian.org ;)

> 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.

  Well, I know my gpg key ID, but I'm biased for sure ;)

-- 
·O·  Pierre Habouzit
··O                                                madcoder@debian.org
OOO                                                http://www.madism.org

[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [RFC] Authenticate push via PGP signature, not SSH
  2008-01-30  5:55           ` Sam Vilain
  2008-01-30  6:16             ` Shawn O. Pearce
@ 2008-01-30  8:35             ` Pierre Habouzit
  2008-01-30 20:22               ` Sam Vilain
  1 sibling, 1 reply; 21+ messages in thread
From: Pierre Habouzit @ 2008-01-30  8:35 UTC (permalink / raw)
  To: Sam Vilain; +Cc: Shawn O. Pearce, git

[-- Attachment #1: Type: text/plain, Size: 1229 bytes --]

On Wed, Jan 30, 2008 at 08:50:33AM +0000, Sam Vilain wrote:
> Shawn O. Pearce wrote:
> > 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.
> 
> It should be fine just to throw the lot into a single keyring, and just
> check which key verified it after the fact and whether that key was allowed.
> 
> The Perl Crypt::OpenPGP module doesn't suffer from this problem (and is
> performant), though it suffers from a dependency stack that will hurt
> everyone except Debian users ;-).

  Actually, if it's engineered like libgpgme (gpg made easy) is, well,
it basically wraps calls to gpg, a thing that we can do ourselves easily
usually :)

  And here is the tool I mentioned in my other mail and forgot to give
an url to: http://kitenet.net/~joey/code/jetring/
-- 
·O·  Pierre Habouzit
··O                                                madcoder@debian.org
OOO                                                http://www.madism.org

[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [RFC] Authenticate push via PGP signature, not SSH
  2008-01-30  8:35             ` Pierre Habouzit
@ 2008-01-30 20:22               ` Sam Vilain
  0 siblings, 0 replies; 21+ messages in thread
From: Sam Vilain @ 2008-01-30 20:22 UTC (permalink / raw)
  To: Pierre Habouzit; +Cc: Shawn O. Pearce, git

Pierre Habouzit wrote:
>> The Perl Crypt::OpenPGP module doesn't suffer from this problem (and is
>> performant), though it suffers from a dependency stack that will hurt
>> everyone except Debian users ;-).
> 
>   Actually, if it's engineered like libgpgme (gpg made easy) is, well,
> it basically wraps calls to gpg, a thing that we can do ourselves easily
> usually :)

It's nothing like gpgme - it brings together all of the Perl modules
that together implement PGP completely.  It doesn't use gpg.

Sam.

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [RFC] Authenticate push via PGP signature, not SSH
  2008-01-30  7:47         ` Shawn O. Pearce
@ 2008-01-31  1:18           ` Sam Vilain
  0 siblings, 0 replies; 21+ messages in thread
From: Sam Vilain @ 2008-01-31  1:18 UTC (permalink / raw)
  To: Shawn O. Pearce; +Cc: Pierre Habouzit, git

Shawn O. Pearce wrote:
>> Ok - but I think if the client is pushing a signed tag to the tagname
>> listed in the signed body of the tag, that no extra signature should be
>> necessary.  It's only commits that need the extra information.
> 
> Doh.  Of course the standard signed tag case is easily verified,
> without the new authentication extension.  But adding it around
> a signed tag push doesn't really hurt anything, except maybe the
> user who entered her passphrase yet again.
> 
> Signing a tag push is actually relevant in some cases.  For example
> when I mirror Junio's git.git tree into my local server at day-job.
> Junio signed the v1.5.4-rc5 tag.  I pushed it to the same location,
> and although we can validate Junio's signature, it may matter (to
> people who have too much free time on their hands but I digress)
> who at our organization put that v1.5.4-rc5 tag from Junio onto
> that particular system, and when they did that.  Was it me?
> Or another co-worker?

Ok, well if people want to sign those pushes then let them - but
allowing them to be pushed anonymously does have the nice side effect
that absolutely nothing needs to be done for the case of replicating
tagged releases of an existing project.  ie, projects that are just
tagging using existing tools and have no knowledge of this system.

>> And remember, for global replication of the data between untrusted nodes
>> to be possible, the signatures must be saved somewhere.  I have sketched
>> a simple design below.
> 
> Crap.  You mentioned this in your initial email, and I forgot
> about it when I posted the message you are responding to now.
> Its actually an interesting concept.  We can validate the entire
> chain of commits that led up to a signed tag, and we can validate
> that signature on that tag.  So why shouldn't we also be able to
> validate the changes to refs in a distributed fashion?

Yes, you could be lazy about it and throw away signatures that were
obsoleted.

>>    access-keys/
>>      - tree with one key per e-mail address
>>    access
>>      - maps reference globs to e-mail addresses permitted to change
>>        them - with a "+" if the address may rewind the ref
>>    owners
>>      - maps reference globs to e-mail addresses permitted to add entries
>>        to the "access" map above
> 
> This part I get.  Using only globs is a tad limited in my mind.
> I actually abuse regexes on refs at day-job in a few places to get
> the access list to work with just a handful of rules.

Extended POSIX or limited PCRE or something like that will do then.

>>    signatures/
>>      - stores any detached signatures.  only the signatures verifying
>>        updates since the last commit to the access meta-branch need to
>>        be stored
>>    packed-refs
>>      - the new list of references (the refs/access commitid is naturally
>>        absent or the same as the parent), or just the changed
>>        references.
> 
> This I'm not so sure.  Are you suggesting that we save the detached
> signature I described earlier that signed the push command set and
> store it here, in this access state branch?  And that we also store
> a copy of all refs (save this one) as a flat file?

On second thoughts, these are only of interest to the auditing and
replication side of things.

> Someone please stop the madness!  :-)

Ok, I think I see the simple beginning path.  Let's go back to the tree
state idea and not worry about replication and auditing yet.  I think it
should fit in smoothly anyway with the above basics.

This means we can nail down the rules for validating a single push/ref
change.  Handling ACL changes is the second level once this first level
works.  It can be manual initially.

You bring up an idea I didn't think of, which is setting up ACLs for
paths within a tree.  I guess quite a few people want that.

How about this syntax (and using globs for illustrative simplicity only):

  refs/heads/*:path/* = any(email email email)

Also, I think that the point about the debian keyrings requires some
consideration.  Maybe groups;

  access-keys/debian/

That way the debian/ access-keys sub-directory can be shared via
alternates across a number of repositories on a shared system.  Instead
of an email address, a group is listed.  But again I think should fall
into place later, once the basic idea is nailed down.

Sam.

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [RFC] Authenticate push via PGP signature, not SSH
  2008-01-30  8:33           ` Pierre Habouzit
@ 2008-01-31  4:30             ` Shawn O. Pearce
  2008-01-31  9:25               ` Pierre Habouzit
  0 siblings, 1 reply; 21+ messages in thread
From: Shawn O. Pearce @ 2008-01-31  4:30 UTC (permalink / raw)
  To: Pierre Habouzit; +Cc: Sam Vilain, git

Pierre Habouzit <madcoder@debian.org> wrote:
> On Wed, Jan 30, 2008 at 04:22:01AM +0000, Shawn O. Pearce wrote:
> > [...] But maybe the
> > Debian folks just doesn't worry about this as it isn't a real issue.
> 
>   It is, we have since recently the princple of "Debian Maintainers",
> people that are only allowed to upload their own package, and the
> keyring used for that purpose is versionned using a custom development
> of ours called jetring (by Joey Hess and al.), I suppose the sources are
> somewhere around, and it has an internal ascii-armored database IIRC
> _and_ a gpg-usable keyring, I think. Or is able to generate the keyring
> at least.

I looked at jetring earlier today, after you posted the URL in
your other email.  Its an interesting tool for distributed keyring
management.  I can see why the Debian folks use it, but it does seem
a little awkward if one has to create those change files by hand.
 
>   But for the case I discussed, indeed, I'd use
> /usr/share/keyrings/debian-keyring.gpg anyways, and won't be the one
> updating it. That's why your developpement should be able to allow
> checking against another keyring. IOW I'm less and less sure that you
> want to manage the keyring _necessarily_ inside the git tree, and that
> allowing any external way to manage a keyring (inside a git tree beeing
> one of the options) is the most flexible way.

Of this you have convinced me.

If we get any sort of push authorization based upon PGP signatures
implemented we should be validating against a keyring that is
configured by a receive.keyring configuration option, and that
defaults to $GIT_DIR/receive-keyring.gpg or something suitable.
If you want to point receive-pack at an existing keyring on your
system, you can and should do so.
 
> > 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.
> 
>   okay, that makes sense. Sorry about the obvious parts, it sensed like
> you didn't used gpg on a regular basis, hence wasn't sure of what you
> already knew or not. I agree that for the sake of logging GIT_PUSHER_*
> are nice, since as you can see on the CLI examples I gave, gpg says that
> the email associated to my key is pierre.habouzit@polytechnique.edu
> whereas I ususally contribute to open source projects using
> madcoder@debian.org ;)

A repository owner may require that to push your GIT_PUSHER_*
values must match the data found in your PGP key on their keyring,
just to keep their logs in a particular way.  Others may not care
and would allow anything, so long as the signature was validated
by a key on the keyring.  But I think that level of checking is
something we leave up to the repository owner.

Which leads me to three variables:

	GIT_PUSHER_NAME
	GIT_PUSHER_EMAIL
	GIT_PUSHER_KEYID

the latter being important if you really wanted to enforce the
$GIT_PUSHER_EMAIL matching the data within the public key used.

-- 
Shawn.

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [RFC] Authenticate push via PGP signature, not SSH
  2008-01-30  8:00           ` Johannes Sixt
@ 2008-01-31  5:43             ` Shawn O. Pearce
  0 siblings, 0 replies; 21+ messages in thread
From: Shawn O. Pearce @ 2008-01-31  5:43 UTC (permalink / raw)
  To: Johannes Sixt; +Cc: Pierre Habouzit, Sam Vilain, git

Johannes Sixt <j.sixt@viscovery.net> wrote:
> Shawn O. Pearce schrieb:
> > 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 propose to make the syntax of the extension
> 
> server capability:  auth=<list of hash methods>:<challenge>
> client response:    auth=<chosen hash method>
> 
> where <challenge> is a random sequence of non-blank ASCII text, not
> necessarily of a fixed length, but perhaps of a minimum length.
> 
> Then we can extend the list of hash algorithms (that are used for
> authentication purposes) if people think that SHA1 is not secure enough:
> 
>     auth=SHA1,SHA256:random-stuff-goes-here
> 
> I'm not a security expert, so take this with a grain of salt.

I'm not certain this is worth the extra complexity.

One reason I proposed "auth-1" as the extension name is so we could
introduce an "auth-2" and make changes in the future if we need to.

But I think there's little value in this authentication hash being
anything other than SHA-1.  Remember that the data itself in the
packfile following the authentication is only protected by SHA-1.
If SHA-1 is considered too weak to protect the ref update commands
then its likely also too weak to protect the file content following
behind those same commands.

Getting stronger authentication here than SHA-1 would probably
require changing the commit object name hash to something stronger
than SHA-1, and the tree object name hash, etc.  Remember that
signed tags are only using the SHA-1 of the commit and that's only
got the SHA-1 of the tree... ;-)

-- 
Shawn.

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [RFC] Authenticate push via PGP signature, not SSH
  2008-01-31  4:30             ` Shawn O. Pearce
@ 2008-01-31  9:25               ` Pierre Habouzit
  0 siblings, 0 replies; 21+ messages in thread
From: Pierre Habouzit @ 2008-01-31  9:25 UTC (permalink / raw)
  To: Shawn O. Pearce; +Cc: Sam Vilain, git

[-- Attachment #1: Type: text/plain, Size: 2584 bytes --]

On Thu, Jan 31, 2008 at 04:30:56AM +0000, Shawn O. Pearce wrote:
> Pierre Habouzit <madcoder@debian.org> wrote:
> >   It is, we have since recently the princple of "Debian Maintainers",
> > people that are only allowed to upload their own package, and the
> > keyring used for that purpose is versionned using a custom development
> > of ours called jetring (by Joey Hess and al.), I suppose the sources are
> > somewhere around, and it has an internal ascii-armored database IIRC
> > _and_ a gpg-usable keyring, I think. Or is able to generate the keyring
> > at least.
> 
> I looked at jetring earlier today, after you posted the URL in
> your other email.  Its an interesting tool for distributed keyring
> management.  I can see why the Debian folks use it, but it does seem
> a little awkward if one has to create those change files by hand.

  Well, *I* don't use it, it's just a fancy tool that replaces the fully
manual (sigh) Debian keyring management for the DM keyring, so that it
can be used by multiple people at the same time. I just pointed to it,
as like you said, reinventing the wheel sucks. Though Joey will probably
be open to improvements if needed :)

> >   But for the case I discussed, indeed, I'd use
> > /usr/share/keyrings/debian-keyring.gpg anyways, and won't be the one
> > updating it. That's why your developpement should be able to allow
> > checking against another keyring. IOW I'm less and less sure that you
> > want to manage the keyring _necessarily_ inside the git tree, and that
> > allowing any external way to manage a keyring (inside a git tree beeing
> > one of the options) is the most flexible way.
> 
> Of this you have convinced me.
> 
> If we get any sort of push authorization based upon PGP signatures
> implemented we should be validating against a keyring that is
> configured by a receive.keyring configuration option, and that
> defaults to $GIT_DIR/receive-keyring.gpg or something suitable.
> If you want to point receive-pack at an existing keyring on your
> system, you can and should do so.

  Full ACK. Another issue that I didn't saw in the first place, is that
if you want to store your keyring in git itself, then it brings the
issue that you would have to write ACLs to protect the branch where it's
stored, whereas it's usually _way_ more easy to just decorrelate both.
IOW it's weak wrt security.
-- 
·O·  Pierre Habouzit
··O                                                madcoder@debian.org
OOO                                                http://www.madism.org

[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply	[flat|nested] 21+ messages in thread

end of thread, other threads:[~2008-01-31  9:26 UTC | newest]

Thread overview: 21+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-01-28  4:12 [RFC] Authenticate push via PGP signature, not SSH Sam Vilain
2008-01-28  8:12 ` Shawn O. Pearce
2008-01-28 21:06   ` Jan Hudec
2008-01-28 21:58   ` Sam Vilain
2008-01-29  2:57     ` Shawn O. Pearce
2008-01-29  4:10     ` Shawn O. Pearce
2008-01-29 19:08       ` Pierre Habouzit
2008-01-30  4:22         ` Shawn O. Pearce
2008-01-30  5:55           ` Sam Vilain
2008-01-30  6:16             ` Shawn O. Pearce
2008-01-30  8:35             ` Pierre Habouzit
2008-01-30 20:22               ` Sam Vilain
2008-01-30  8:00           ` Johannes Sixt
2008-01-31  5:43             ` Shawn O. Pearce
2008-01-30  8:33           ` Pierre Habouzit
2008-01-31  4:30             ` Shawn O. Pearce
2008-01-31  9:25               ` Pierre Habouzit
2008-01-30  6:29       ` Sam Vilain
2008-01-30  7:47         ` Shawn O. Pearce
2008-01-31  1:18           ` Sam Vilain
2008-01-28  8:48 ` Pierre Habouzit

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).