{"thread":{"id":"11765","subject":"[RFC] Authenticate push via PGP signature, not SSH","startedAt":"2008-01-28T04:12:01Z","lastAt":"2008-01-31T09:25:27Z","messageCount":21,"participants":["Sam Vilain","Shawn O. Pearce","Pierre Habouzit","Jan Hudec","Johannes Sixt"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"66707","messageId":"479D5611.4010205@vilain.net","threadId":"11765","inReplyTo":null,"subject":"[RFC] Authenticate push via PGP signature, not SSH","fromName":"Sam Vilain","fromEmail":"sam@vilain.net","sentAt":"2008-01-28T04:12:01Z","receivedAt":"2008-01-28T04:12:01Z","isPatch":false,"sender":{"key":"sam@vilain.net","avatar":"https://gravatar.com/avatar/8fc840ca854dbf6f7065b4335e3b934951c1dca3b11db688e95e471901f8f4a8?d=mp&s=160"},"body":"I recently sent this to the gitorious list; I knocked up a working\nsystem for this, and it so far seems workable, and it is now topical.\n\nNote that the design used by the proof of concept would not be suitable\nfor the upcoming versions of git which do not allow pushing tags to\nbranch refs - they would require calling the tags something like\nrefs/tags/heads/master or some other suitable convention.  Probably not\neven using refs/tags etc, to avoid races.\n\nThe key idea is to reject pushes if the PGP signature cannot be verified.\n\nConnect to this data - http://www.rubin.ch/wotsap/ - and give everyone\nin the world with a working and well signed PGP key secure push access\nwithout them having to set anything up.  Of course, you would also want\nto layer on top of this rules that would force unknown contributors into\na \"mob\"-like namespace.\n\nWhen heads are pushed, the signed tags that are moved from refs/heads/\nfoo can be saved in an \"archive\" tag space, such as under refs/audit/\nKEYID/ - this will allow, in the case of a network of git servers, for\nservers to synchronise from each other, even when they\ndon't trust each other.\n\nThe update hook first verifies the signature, and rejects the signature\nif not accepted:\n\n------8<------\n#!/bin/sh\n#\n# An example hook script to require all pushes be signed\n#\n\nref=$1\nsha1_old=$2\nsha1_new=$3\n\nif [ -d \"$GIT_DIR/keyring\" ]; then\n        echo \"pgp-git: using repository keyring\" >&2\n        GNUPGHOME=$GIT_DIR/keyring\n        export GNUPGHOME\nelse\n        echo \"pgp-git: using default keyring\" >&2\nfi\n\nset -e\n\ncase $ref in\n        refs/tags/tmp/*)\n                echo \"E:Even TRYING that lark makes me ANGRY!\" >&2\n                exit 38\n                ;;\n\n        refs/heads/*|refs/tags/*)\n                audit=$(echo \"$ref\" | sed 's!refs/!refs/tags/tmp/!')\n                tagname=$(echo \"$audit\" | sed 's!refs/tags!!')\n                git update-ref -m \"update hook\" \\\n                        \"$audit\" $sha1_new\n                ;;\n\n        *)\n                echo \"E:WHOA!  Pushing to $ref?\" >&2\n                exit 1\n                ;;\nesac\n\ntrap \"git-tag -d $tagname\" ERR\ngit-tag -v \"$tagname\"\n------8<------\n\nAnd then, the post-update hook will move the tag into the designed place;\n\n------8<------\n#!/bin/sh\n#\n# An example hook script to prepare a packed repository for use over\n# dumb transports.\n#\n# To enable this hook, make this file executable by \"chmod +x post-update\".\n\nfor ref\ndo\n        case \"$ref\" in\n                refs/heads/*)\n                        type=$(git cat-file -t $ref)\n                        if [ $type = \"tag\" ]\n                        then\n                                echo \"pgp-git: removing dummy tag\" >&2\n                                git update-ref -m \"post-update hook -\nremove dummy tag\" \"$ref\" \"$ref^{commit}\"\n                        fi\n\n                        ;;\n                *);;\n        esac\ndone\n\ngit-update-server-info\n------8<------\n\nThis does force potential contributors to get PGP keys, and get them\nsigned - but that seems to me to be a reasonable barrier of entry and\nmay even help drive some PGP adoption.\n\nRemember this is a proof of concept, so let's discuss the design first\nand not worry too much about the glaring bugs yet.\n\nSam.\n"},{"id":"66719","messageId":"20080128081258.GE24004@spearce.org","threadId":"11765","inReplyTo":"479D5611.4010205@vilain.net","subject":"Re: [RFC] Authenticate push via PGP signature, not SSH","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2008-01-28T08:12:58Z","receivedAt":"2008-01-28T08:12:58Z","isPatch":false,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"Sam Vilain <sam@vilain.net> wrote:\n...\n> The key idea is to reject pushes if the PGP signature cannot be verified.\n...\n> When heads are pushed, the signed tags that are moved from refs/heads/\n> foo can be saved in an \"archive\" tag space, such as under refs/audit/\n> KEYID/ - this will allow, in the case of a network of git servers, for\n> servers to synchronise from each other, even when they\n> don't trust each other.\n\nThis is certainly interesting.  It would benefit from the recursive\nlocking scheme we were talking about for the update hook, which\nsomeone (Steven Grimm?) wanted so they could execute git-svn\ntransparently during push and have the update hook change the ref\ninstead of receive-pack.\n\nThe downside to this is you have to tag everything before you push\nit, so you need some sort of wrapper around git-push.  That isn't\nas hard as it sounds for the command line case, but it does make\nthings more difficult for a usage from say git-gui.  :)\n\nI was also thinking about using GPG to sign the command packets\nbeing sent between send-pack and receive-pack.  If the GPG signature\nfor that set of packets is good and a known key then the update is\nallowed to continue.  This avoids the mess of needing to run git-tag\nlocally before push, and of needing to \"unwrap\" the temporary tag\nin the receiving repository, but it adds yet another extension to\nthe send-pack/receive-pack protocol.\n \n> This does force potential contributors to get PGP keys, and get them\n> signed - but that seems to me to be a reasonable barrier of entry and\n> may even help drive some PGP adoption.\n\nIn many cases today such contributers would have been forced to get\nan SSH account on the server they want to push to.  Getting an SSH\naccount configured and a key installed may be more difficult than\ngenerating a PGP key pair and emailing in the public key.\n\nOf course the PGP based system is nicer in that the administrator\nmight get a public key that has been signed by others he trusts,\nand thus is more readily able to verify that the contributor is\nwho they think it is.\n\n\nTo be perfectly honest, in a wide open source community I think\nthe truely distributed nature of development like the linux kernel\nor git itself uses works very well.  Development schedules aren't\norganized into \"next 30 minutes\", \"next 4 hours\", and \"next week\".\n\nPeer review and community acceptance of changes is a very important\nconcept.  Blindly accepting changes into a tree because of a PGP\nsignature/SSL certificate/SSH key isn't really the norm, and is\nfar from the best solution.  We've all posted cr**p^Wless-than-\nthe-best-code to this list before, and yet many of us would have\n\"committer access\" to the git tree under a centralized model.\n\nI'm happy my changes aren't accepted just because I signed them.\nIts better that Linus/Nico/Dscho/Junio/you/et.al. have looked at\nthem and also felt they were worthwhile.\n\n\nBut in a smaller business type setting, where there's under 100\nemployees working, odds are you've already created the user account\non systems, and physically passed the initial password via a sticky\nnote after checking the person's government issued IDs.  In such a\nsetting having yet another authentication system (PGP keys) is just\nyet more work for the already over worked/under appreciated IT staff.\n\n-- \nShawn.\n"},{"id":"66722","messageId":"20080128084830.GB15935@artemis.madism.org","threadId":"11765","inReplyTo":"479D5611.4010205@vilain.net","subject":"Re: [RFC] Authenticate push via PGP signature, not SSH","fromName":"Pierre Habouzit","fromEmail":"madcoder@debian.org","sentAt":"2008-01-28T08:48:30Z","receivedAt":"2008-01-28T08:48:30Z","isPatch":false,"sender":{"key":"madcoder@debian.org","avatar":"https://avatars.githubusercontent.com/u/44708?v=4"},"body":"On Mon, Jan 28, 2008 at 06:12:34AM +0000, Sam Vilain wrote:\n> This does force potential contributors to get PGP keys, and get them\n> signed - but that seems to me to be a reasonable barrier of entry and\n> may even help drive some PGP adoption.\n> \n> Remember this is a proof of concept, so let's discuss the design first\n> and not worry too much about the glaring bugs yet.\n\n  FWIW I'm really interested into such a \"thing\", and that I'd like to\navoid giving unix (even with git-shell, not only because of security,\nbut because it pollutes the machine setup a lot) accounts to my git\nservers, though would like to let people help in my Debian packaging.\nFors us GPG isn't an issue, as every single DD or wannabe has a GPG key\n:)\n\n  Note though that the fact that you need to push a dummy tag is somehow\ndisgusting IMHO, it should at least be integrated into git-push so that\nthe user doesn't have to generate the dummy tag himself.\n\n-- \n·O·  Pierre Habouzit\n··O                                                madcoder@debian.org\nOOO                                                http://www.madism.org\n"},{"id":"66758","messageId":"20080128210640.GC5788@efreet.light.src","threadId":"11765","inReplyTo":"20080128081258.GE24004@spearce.org","subject":"Re: [RFC] Authenticate push via PGP signature, not SSH","fromName":"Jan Hudec","fromEmail":"bulb@ucw.cz","sentAt":"2008-01-28T21:06:40Z","receivedAt":"2008-01-28T21:06:40Z","isPatch":false,"sender":{"key":"bulb@ucw.cz","avatar":null},"body":"On Mon, Jan 28, 2008 at 03:12:58 -0500, Shawn O. Pearce wrote:\n> Sam Vilain <sam@vilain.net> wrote:\n> > This does force potential contributors to get PGP keys, and get them\n> > signed - but that seems to me to be a reasonable barrier of entry and\n> > may even help drive some PGP adoption.\n> \n> In many cases today such contributers would have been forced to get\n> an SSH account on the server they want to push to.  Getting an SSH\n> account configured and a key installed may be more difficult than\n> generating a PGP key pair and emailing in the public key.\n\nActually no. SSH key pair is good enough in current situation. In fact\nit might be *better* than SSH account, because with SSH account, the user\neither has or does not have write access, while with SSH key pair he is still\nsubject to limitations enforced by the receive-hook.\n\n> Of course the PGP based system is nicer in that the administrator\n> might get a public key that has been signed by others he trusts,\n> and thus is more readily able to verify that the contributor is\n> who they think it is.\n\nThat, however, is an advantage of PGP. Obviously, additional rules can still\nbe enforced by the receive-hook.\n\n-- \n\t\t\t\t\t\t Jan 'Bulb' Hudec <bulb@ucw.cz>\n"},{"id":"66761","messageId":"479E5021.7010404@vilain.net","threadId":"11765","inReplyTo":"20080128081258.GE24004@spearce.org","subject":"Re: [RFC] Authenticate push via PGP signature, not SSH","fromName":"Sam Vilain","fromEmail":"sam@vilain.net","sentAt":"2008-01-28T21:58:57Z","receivedAt":"2008-01-28T21:58:57Z","isPatch":false,"sender":{"key":"sam@vilain.net","avatar":"https://gravatar.com/avatar/8fc840ca854dbf6f7065b4335e3b934951c1dca3b11db688e95e471901f8f4a8?d=mp&s=160"},"body":"Shawn O. Pearce wrote:\n> To be perfectly honest, in a wide open source community I think\n> the truely distributed nature of development like the linux kernel\n> or git itself uses works very well.  Development schedules aren't\n> organized into \"next 30 minutes\", \"next 4 hours\", and \"next week\".\n> \n> Peer review and community acceptance of changes is a very important\n> concept.  Blindly accepting changes into a tree because of a PGP\n> signature/SSL certificate/SSH key isn't really the norm, and is\n> far from the best solution.  We've all posted cr**p^Wless-than-\n> the-best-code to this list before, and yet many of us would have\n> \"committer access\" to the git tree under a centralized model.\n>\n> I'm happy my changes aren't accepted just because I signed them.\n> Its better that Linus/Nico/Dscho/Junio/you/et.al. have looked at\n> them and also felt they were worthwhile.\n\nI agree wholeheartedly - hence my comment about \"mob\" branches.  What I\nwas implying is that you could model it conceptually off repo.or.cz.\n\nThat is, when you start a project, you \"own\" a namespace.  Everyone else\nhas to pick a fork name, and the first push they make to\n\"forks/forkname/*\" registers that fork name to that key.\n\nThis could support fully distributed access control over the namespaces.\n  What it means for access control to be distributed is that any node\ncan check the log of tags that granted permission to people, and\nassuming that they processed the same grants in the same order they will\narrive at the same access control result.\n\nTo describe this with an example, say Linus decides that Junio can push\nto any ref on the project, he can note in a tag;\n\n  \"From this release forward, Junio Hamano <KEYID> will be authorized to\n   push to any reference, and grant access to others under the reference\n   space 'refs/heads/topics/'\".\n\nOr, preferably something more automatically parsable.  Anyway, the\npresence of a signed document is a hint for the audit program to try to\nreach Junio's key from Linus' key (like this would:\nhttp://pgp.cs.uu.nl/mk_path.cgi?FROM=76E21CBB&TO=F3119B9A&PATHS=trust+paths)\nif it can, and then add the signing key to the ACL's PGP keyring.\n\nThe ACL state could be a branch in a funny refspace with a directory for\nthe keyring, and a place to keep copies of any tags it removed because\nthey were there just for the push.\n\nAnd yes, it would need a simple interface.\n\n> But in a smaller business type setting, where there's under 100\n> employees working, odds are you've already created the user account\n> on systems, and physically passed the initial password via a sticky\n> note after checking the person's government issued IDs.  In such a\n> setting having yet another authentication system (PGP keys) is just\n> yet more work for the already over worked/under appreciated IT staff.\n\nAgreed - again I'd personally consider allowing receive-pack with\nreflogs in those environments if setting up PGP or SSH keys was a hassle.\n\nSam.\n"},{"id":"66781","messageId":"20080129025743.GH24004@spearce.org","threadId":"11765","inReplyTo":"479E5021.7010404@vilain.net","subject":"Re: [RFC] Authenticate push via PGP signature, not SSH","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2008-01-29T02:57:43Z","receivedAt":"2008-01-29T02:57:43Z","isPatch":false,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"Sam Vilain <sam@vilain.net> wrote:\n> Shawn O. Pearce wrote:\n> > But in a smaller business type setting, where there's under 100\n> > employees working, odds are you've already created the user account\n> > on systems, and physically passed the initial password via a sticky\n> > note after checking the person's government issued IDs.  In such a\n> > setting having yet another authentication system (PGP keys) is just\n> > yet more work for the already over worked/under appreciated IT staff.\n> \n> Agreed - again I'd personally consider allowing receive-pack with\n> reflogs in those environments if setting up PGP or SSH keys was a hassle.\n\nYea, I already have reflogs enabled for all stored branches on the\ncentral server.  And since some branches have a no-delete policy\n(based upon the rules offered by contrib/hooks/update-paranoid) the\nreflogs are also effectively no-delete, even if the branch rewinds.\n\nI also never run `git reflog expire`.  I might in another year or\nso consider it, but most of my no-delete branches also don't rewind\nvery often (if ever) so there's very little disk to be gained by\nreflog expiry.\n\n-- \nShawn.\n"},{"id":"66803","messageId":"20080129041000.GK24004@spearce.org","threadId":"11765","inReplyTo":"479E5021.7010404@vilain.net","subject":"Re: [RFC] Authenticate push via PGP signature, not SSH","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2008-01-29T04:10:00Z","receivedAt":"2008-01-29T04:10:00Z","isPatch":false,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"Sam Vilain <sam@vilain.net> wrote:\n> This could support fully distributed access control over the namespaces.\n>   What it means for access control to be distributed is that any node\n> can check the log of tags that granted permission to people, and\n> assuming that they processed the same grants in the same order they will\n> arrive at the same access control result.\n> \n> To describe this with an example, say Linus decides that Junio can push\n> to any ref on the project, he can note in a tag;\n> \n>   \"From this release forward, Junio Hamano <KEYID> will be authorized to\n>    push to any reference, and grant access to others under the reference\n>    space 'refs/heads/topics/'\".\n> \n> The ACL state could be a branch in a funny refspace with a directory for\n> the keyring, and a place to keep copies of any tags it removed because\n> they were there just for the push.\n> \n> And yes, it would need a simple interface.\n\nAfter some thought today about your message above and Pierre's about\nthe Debian package maintainers have gotten me into thinking that\nwe really should just support PGP signature verification as part\nof send-pack/receive-pack, making it reasonably safe to expose an\nopen git-daemon over TCP/IP, complete with receive-pack enabled.\n\nMy attempt to use UNIX authentication over a domain socket was\nprobably stupid.  Good thing there are smarter people than I\non this list, and even better that they decided to join in the\nconversation.  :)\n\nHere's (I hope) a short outline of what I was thinking:\n\n* New protocol extension to send-pack/receive-pack pair:\n\n  If server wants to require (or optionally) accept a signed push\n  event it sends a new capability string when it advertises its\n  current known heads:\n\n    auth-1=[0-9a-f]{40}\n\n  The actual length and data value is mostly irrelevant to this\n  discussion, but the data is a nonce for this single connection\n  between send-pack and receive-pack.  It needs to come from a\n  reasonably good PRNG.\n\n  If send-pack then wants to upload one or more refs:\n\n  Send back the capability \"auth-1\" as part of the first ref\n  being pushed.  Note we skip the nonce in the capablity request.\n  Send all ref update commands using current protocol.\n\n  Generate a SHA-1 around the following:\n\n    <nonce><command>+<auth>\n\n    command  ::= <old_sha1> <new_sha1> <op> <ref> '\\0'\n    old_sha1 ::= 20 byte binary string\n    new_sha1 ::= 20 byte binary string\n    op       ::= ' ' | '+'\n    ref      ::= ref name\n\n  Send another pkt-line before the flush containing the user\n  identity and the PGP signature for the hash from the above:\n\n    <auth><pgp_sig>\n\n    auth    ::= 'auth' ' ' <name> ' ' '<' <email> '>' '\\n'\n    name    ::= like a commit author-name\n    email   ::= like a commit author-email\n    pgp_sig ::= armored signature from PGP\n\n  receive-pack expects this new auth pkt-line if the client asked\n  to enable the auth-1 capablity in the first command.\n\n  If receive-pack was configured (say by config receive.auth)\n  to require authentication then it closes the connection if the\n  client didn't request the capablity in the first command.\n\n  receive-pack can generate the same SHA-1 hash from the commands\n  it read from send-pack, and can verify the PGP signature on the\n  auth line.\n\n  This assures us the command stream wasn't modified, and likely\n  originated from the named identity.  The rest of the packfile\n  data is already well protected by its own SHA-1 footer and the\n  individual object SHA-1s, and the roots pointing into that DAG\n  (or sub-DAG) mentioned in the commands were verified by the PGP\n  signature of them.\n\n  Push isn't that common, but this extension format doesn't require\n  any additional round-trips between the two peers, so latency\n  doesn't change.  Which I guess is nice.\n\n  It also avoids the relatively ugly part of having a dummy tag\n  involved in the transfer and shoved into the ref namespace for\n  a short period of time.\n\n\n* receive-hook validations:\n\n  If we got an auth line above then we export the <name> and\n  <email> values into a pair of new environment variables:\n\n    GIT_PUSHER_NAME=<name>\n    GIT_PUSHER_EMAIL=<email>\n\n  thus exposing the who down to any hooks we might execute, in\n  particular the pre-receive and the update hooks, as tools like\n  contrib/hooks/update-paranoid and gitosis can then base their\n  per-ref access decisions off these.\n\n\n* PGP public key storage:\n\n  Use a \"hidden\" ref called \"refs/access-keys\" to store a commit.\n  The access control change log is a normal Git commit chain.\n\n  The tree under this commit stores a file per <email> string.\n  Public keys for auth line validation are located by <email>,\n  from the tip of this branch.\n\n  This branch could be a symlink to another repository (e.g.\n  a site-wide \"admin\" repository) and the ODB for that other\n  repository could be an alternate for this repository.\n\n\n* ref/access-keys security:\n\n  Probably an update or pre-receive hook could verify pushes\n  to this branch by something like this:\n\n    - If the only difference between $old_sha1 $new_sha1 is\n      a modification of $GIT_PUSHER_EMAIL then allow it\n      (user is replacing their own key);\n\n    - If the only difference between $old_sha1 $new_sha1 is\n      modifications of names other than $GIT_PUSHER_EMAIL but\n      the file content differences are only $GIT_PUSHER_EMAIL\n      signing those public keys then allow it (the user doing\n      the push is publishing some trust);\n\n    - If the difference between $old_sha1 $new_sha1 is new\n      keys added or existing keys removed then allow it only\n      if $GIT_PUSHER_EMAIL is also listed inside of the\n      \"admin/\" subtree and the new key is also signed by\n      $GIT_PUSHER_EMAIL's key.\n\n\nBut here's where things start to get funny.\n\nOn a site like repo.or.cz the idea of being able to create your\nown unique subnamespace by pushing your key at the server is\nsimple enough, and actually sorta cool.\n\nBut in my central repository layout at day-job I don't want people\nforking.  Instead I want them to stay within their pre-assigned\nnamespace of the single common repository.  So the access control\nrules being applied start to really head in lots of different\ndirections at this point.\n\n-- \nShawn.\n"},{"id":"66845","messageId":"20080129190845.GC30093@artemis.madism.org","threadId":"11765","inReplyTo":"20080129041000.GK24004@spearce.org","subject":"Re: [RFC] Authenticate push via PGP signature, not SSH","fromName":"Pierre Habouzit","fromEmail":"madcoder@debian.org","sentAt":"2008-01-29T19:08:45Z","receivedAt":"2008-01-29T19:08:45Z","isPatch":false,"sender":{"key":"madcoder@debian.org","avatar":"https://avatars.githubusercontent.com/u/44708?v=4"},"body":"On Tue, Jan 29, 2008 at 04:10:00AM +0000, Shawn O. Pearce wrote:\n> * PGP public key storage:\n> \n>   Use a \"hidden\" ref called \"refs/access-keys\" to store a commit.\n>   The access control change log is a normal Git commit chain.\n> \n>   The tree under this commit stores a file per <email> string.\n>   Public keys for auth line validation are located by <email>,\n>   from the tip of this branch.\n> \n>   This branch could be a symlink to another repository (e.g.\n>   a site-wide \"admin\" repository) and the ODB for that other\n>   repository could be an alternate for this repository.\n\n  This won't work well, because I don't think GnuPG is able to check\nsome signature against an armored GPG public Key (at least I didn't\nfound a way to do that). You have to create one pubring per submitter,\nwich is kind of a waste in fact, and the format is horribly binary.\n\n  I don't even know if you really need the versionning of this\npseudo-keyring, and if a .git/keyring.gpg isn't enough.\n\n  As a side note, you don't really need to use GIT_PUSH_*. It doesn't\nmake anything safer (as the UIDs of a given public key are public\ninformation anyways), you just want to know which key signed that data,\nand the signature holds that information. Hence if you still want to\nhave a flat-file based keyring (which I repeat I don't think gpg\nsupports directly -- and that's really a shame) you'd better index them\nper key fingerprint than by author name.\n\n  And then you just need to call gpg this way:\n\n$ gpg --keyring path/to/the/keyring.gpg --quiet --batch --status-fd 1 --verify some-file.tar.gz.gpg 2>|/dev/null\n[GNUPG:] SIG_ID dw0VliO0DFjOQA3HUSHijYekQYY 2008-01-29 1201633002\n[GNUPG:] GOODSIG BC6AFB5BA1EE761C Pierre Habouzit <pierre.habouzit@polytechnique.edu>\n[GNUPG:] VALIDSIG 72B4C59ADA78D70E055C129EBC6AFB5BA1EE761C 2008-01-29 1201633002 0 3 0 17 2 00 72B4C59ADA78D70E055C129EBC6AFB5BA1EE761C\n[GNUPG:] TRUST_ULTIMATE\n\n  And if the key is not in your keyring this looks like:\n$ GNUPGHOME=/tmp gpg --verify --status-fd 1 some-file.tar.gz.gpg 2>/dev/null\n[GNUPG:] ERRSIG BC6AFB5BA1EE761C 17 2 00 1201633002 9\n[GNUPG:] NO_PUBKEY BC6AFB5BA1EE761C\n                   ^^^^^^^^^^^^^^^^\n            that's the key id you look for.\n\n\n-- \n·O·  Pierre Habouzit\n··O                                                madcoder@debian.org\nOOO                                                http://www.madism.org\n"},{"id":"66878","messageId":"20080130042201.GO24004@spearce.org","threadId":"11765","inReplyTo":"20080129190845.GC30093@artemis.madism.org","subject":"Re: [RFC] Authenticate push via PGP signature, not SSH","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2008-01-30T04:22:01Z","receivedAt":"2008-01-30T04:22:01Z","isPatch":false,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"Pierre Habouzit <madcoder@debian.org> wrote:\n> On Tue, Jan 29, 2008 at 04:10:00AM +0000, Shawn O. Pearce wrote:\n> > * PGP public key storage:\n> > \n> >   Use a \"hidden\" ref called \"refs/access-keys\" to store a commit.\n> >   The access control change log is a normal Git commit chain.\n> \n>   This won't work well, because I don't think GnuPG is able to check\n> some signature against an armored GPG public Key (at least I didn't\n> found a way to do that). You have to create one pubring per submitter,\n> wich is kind of a waste in fact, and the format is horribly binary.\n\nGaaah.\n\nI hate tools that build their own little internal databases of\nobjects, and don't let you store their data in other random places,\nlike in any random file format you choose[*1*].  ;-)\n\nI just read the GnuPG manual and you are obviously correct.  The only\nway to get GnuPG to process a key is to load it onto a keyring.\nWe could extract the armored (or binary) public key and load it\nonto a temporary keyring created just for the purpose of verifying\nthis connection, but that's rather messy.\n \n>   I don't even know if you really need the versionning of this\n> pseudo-keyring, and if a .git/keyring.gpg isn't enough.\n\nWell, I don't know about that.\n\nPeople come and go on a project.  It would be nice if there was\na reasonably trusted store available as part of the project, that\none can verify using a current trusted project member's public key,\nand obtain prior project member's public keys out of.  But maybe the\nDebian folks just doesn't worry about this as it isn't a real issue.\n\nIn the case of access control however I need to have a full history\nof who had access, during what time periods.  If someone has their\naccess revoked, I need to know when it was revoked, and by whom.\nGit commit chains make for a nice log of such activity.  Obviously\naccess changes don't need to be reflected through a GnuPG keyring,\nand can be as simple as a text file listing the allowed users.\n\nBut as a remote administrator for my project (think repo.or.cz!)\nhow do I add new users to the keyring.gpg on the server?  Being\nable to use the existing send-pack/receive-pack infrastructure to\ntransport the new public key has nice advantages.  Web UIs are\ncool, but some of us are command line oriented animals.\n\n>   As a side note, you don't really need to use GIT_PUSH_*. It doesn't\n> make anything safer (as the UIDs of a given public key are public\n> information anyways), you just want to know which key signed that data,\n> and the signature holds that information. Hence if you still want to\n> have a flat-file based keyring (which I repeat I don't think gpg\n> supports directly -- and that's really a shame) you'd better index them\n> per key fingerprint than by author name.\n\nYea, I know, you haven't told me anything I didn't already know.\n\nHaving GIT_PUSHER_{NAME,EMAIL} makes it easier for a hook to\nobtain information about this person and use it in an automated\nemail message.  Think a post-receive hook that automatically sends\nout announcement emails.\n\nHaving G_P_{NAME,EMAIL} makes it easier for the branch reflogs on the\nserver to have names in them.  If you look at your local reflogs they\nare driven off GIT_COMMITTER_{NAME,EMAIL} and thus report something\nmeaningful about who did a change.  But when we are in receive-pack\nand we update a reflog we don't really have this information, do we?\n\nHaving G_P_{NAME,EMAIL} makes it easier to write a hook that looks\nup access control data and makes access control decisions based upon\nsymbols we like to refer to other water transport devices with.\nI'd much rather refer to you by your given name 'Pierre' than by\nyour GPG key id BC6AFB5BA1EE761C.  Especially if I have to list\nyou in an access control file with 50 other people that lists which\nbranches you are allowed to push changes into, and which ones you\nare restricted from.\n\nYes, I know the key ids are unique enough for our needs.  But dammit,\nthey just aren't friendly to work with when you are storing log\nrecords for later inspection, or maintaing an access list.\n\nThere is after all reason we have a \"tagger\" field with a human\nreadable name on it, rather than relying solely on the GPG key id\nof the signature.\n\n>   And then you just need to call gpg this way:\n> \n> $ gpg --keyring path/to/the/keyring.gpg --quiet --batch --status-fd 1 --verify some-file.tar.gz.gpg 2>|/dev/null\n> [GNUPG:] SIG_ID dw0VliO0DFjOQA3HUSHijYekQYY 2008-01-29 1201633002\n> [GNUPG:] GOODSIG BC6AFB5BA1EE761C Pierre Habouzit <pierre.habouzit@polytechnique.edu>\n> [GNUPG:] VALIDSIG 72B4C59ADA78D70E055C129EBC6AFB5BA1EE761C 2008-01-29 1201633002 0 3 0 17 2 00 72B4C59ADA78D70E055C129EBC6AFB5BA1EE761C\n> [GNUPG:] TRUST_ULTIMATE\n> \n>   And if the key is not in your keyring this looks like:\n> $ GNUPGHOME=/tmp gpg --verify --status-fd 1 some-file.tar.gz.gpg 2>/dev/null\n> [GNUPG:] ERRSIG BC6AFB5BA1EE761C 17 2 00 1201633002 9\n> [GNUPG:] NO_PUBKEY BC6AFB5BA1EE761C\n>                    ^^^^^^^^^^^^^^^^\n>             that's the key id you look for.\n\nUrgh.  So then we need to go and extract that key, load it onto a\ntemporary keyring, then reinvoke gpg with the temporary keyring,\njust to verify the short command input we received?  Ouch.\n\nOK, maybe I'm making it sound worse than it really will be.\n\nI'm currently finishing a side-band-64k protocol extension to the\nsend-pack/receive-pack pair.  My next task after I flush those\nRFC patches out to the list tonight will be to prototype at least\nsome of the auth1 extension I described.  I'll maybe try to keep\nit really simple initially, which means doing what you suggested\nabove and using a .git/keyring.gpg for the repository.  Its not\neasily remotely administered, but its only a damn proof of concept.\n\n\n\n*1* If you don't get this joke, well, uh, I can't help you.\n    Oh, ASCII formatted Git packfiles are on the way!  :)\n\n-- \nShawn.\n"},{"id":"66885","messageId":"47A01162.7070503@vilain.net","threadId":"11765","inReplyTo":"20080130042201.GO24004@spearce.org","subject":"Re: [RFC] Authenticate push via PGP signature, not SSH","fromName":"Sam Vilain","fromEmail":"sam@vilain.net","sentAt":"2008-01-30T05:55:46Z","receivedAt":"2008-01-30T05:55:46Z","isPatch":false,"sender":{"key":"sam@vilain.net","avatar":"https://gravatar.com/avatar/8fc840ca854dbf6f7065b4335e3b934951c1dca3b11db688e95e471901f8f4a8?d=mp&s=160"},"body":"Shawn O. Pearce wrote:\n> I just read the GnuPG manual and you are obviously correct.  The only\n> way to get GnuPG to process a key is to load it onto a keyring.\n> We could extract the armored (or binary) public key and load it\n> onto a temporary keyring created just for the purpose of verifying\n> this connection, but that's rather messy.\n\nIt should be fine just to throw the lot into a single keyring, and just\ncheck which key verified it after the fact and whether that key was allowed.\n\nThe Perl Crypt::OpenPGP module doesn't suffer from this problem (and is\nperformant), though it suffers from a dependency stack that will hurt\neveryone except Debian users ;-).\n\nI think this is a non-issue.\n\n>> $ gpg --keyring path/to/the/keyring.gpg --quiet --batch --status-fd 1 --verify some-file.tar.gz.gpg 2>|/dev/null\n>> [GNUPG:] SIG_ID dw0VliO0DFjOQA3HUSHijYekQYY 2008-01-29 1201633002\n>> [GNUPG:] GOODSIG BC6AFB5BA1EE761C Pierre Habouzit <pierre.habouzit@polytechnique.edu>\n>> [GNUPG:] VALIDSIG 72B4C59ADA78D70E055C129EBC6AFB5BA1EE761C 2008-01-29 1201633002 0 3 0 17 2 00 72B4C59ADA78D70E055C129EBC6AFB5BA1EE761C\n^^^ there GPG just told you which key was used.\n>> [GNUPG:] TRUST_ULTIMATE\n\nSam.\n"},{"id":"66886","messageId":"20080130061605.GQ24004@spearce.org","threadId":"11765","inReplyTo":"47A01162.7070503@vilain.net","subject":"Re: [RFC] Authenticate push via PGP signature, not SSH","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2008-01-30T06:16:05Z","receivedAt":"2008-01-30T06:16:05Z","isPatch":false,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"Sam Vilain <sam@vilain.net> wrote:\n> Shawn O. Pearce wrote:\n> > I just read the GnuPG manual and you are obviously correct.  The only\n> > way to get GnuPG to process a key is to load it onto a keyring.\n> > We could extract the armored (or binary) public key and load it\n> > onto a temporary keyring created just for the purpose of verifying\n> > this connection, but that's rather messy.\n> \n> It should be fine just to throw the lot into a single keyring, and just\n> check which key verified it after the fact and whether that key was allowed.\n> \n> The Perl Crypt::OpenPGP module doesn't suffer from this problem (and is\n> performant), though it suffers from a dependency stack that will hurt\n> everyone except Debian users ;-).\n\nHeh.  One of my Gentoo boxes seems to claim this would be an easier\nemerge than the Qt3 emerge that it keeps trying to do, and failing,\nfor the past week and a half.  But yea, I don't have half the stuff\nits asking for installed.\n \n> >> $ gpg --keyring path/to/the/keyring.gpg --quiet --batch --status-fd 1 --verify some-file.tar.gz.gpg 2>|/dev/null\n> >> [GNUPG:] SIG_ID dw0VliO0DFjOQA3HUSHijYekQYY 2008-01-29 1201633002\n> >> [GNUPG:] GOODSIG BC6AFB5BA1EE761C Pierre Habouzit <pierre.habouzit@polytechnique.edu>\n> >> [GNUPG:] VALIDSIG 72B4C59ADA78D70E055C129EBC6AFB5BA1EE761C 2008-01-29 1201633002 0 3 0 17 2 00 72B4C59ADA78D70E055C129EBC6AFB5BA1EE761C\n> ^^^ there GPG just told you which key was used.\n\nYup.  I think that's what we'll have to do.  But managing the keyring\nis (I think) something we need to solve.  It should be able to be\ndone remotely, assuming you have authority, and ideally through\nstandard Git channels.\n\nIf we're going to the trouble of effectively replacing SSH for\nauthenticated Git object push (at least for stuff that is open\nsource and thus doesn't require privacy during upload) we might\nas well make sure it can actually be managed too.\n\n-- \nShawn.\n"},{"id":"66895","messageId":"47A01963.1030703@vilain.net","threadId":"11765","inReplyTo":"20080129041000.GK24004@spearce.org","subject":"Re: [RFC] Authenticate push via PGP signature, not SSH","fromName":"Sam Vilain","fromEmail":"sam@vilain.net","sentAt":"2008-01-30T06:29:55Z","receivedAt":"2008-01-30T06:29:55Z","isPatch":false,"sender":{"key":"sam@vilain.net","avatar":"https://gravatar.com/avatar/8fc840ca854dbf6f7065b4335e3b934951c1dca3b11db688e95e471901f8f4a8?d=mp&s=160"},"body":"Shawn O. Pearce wrote:\n> * New protocol extension to send-pack/receive-pack pair:\n> \n>   If server wants to require (or optionally) accept a signed push\n>   event it sends a new capability string when it advertises its\n>   current known heads:\n> \n>     auth-1=[0-9a-f]{40}\n  [...]\n>     <auth><pgp_sig>\n> \n>     auth    ::= 'auth' ' ' <name> ' ' '<' <email> '>' '\\n'\n>     name    ::= like a commit author-name\n>     email   ::= like a commit author-email\n>     pgp_sig ::= armored signature from PGP\n> \n>   receive-pack expects this new auth pkt-line if the client asked\n>   to enable the auth-1 capablity in the first command.\n> \n>   If receive-pack was configured (say by config receive.auth)\n>   to require authentication then it closes the connection if the\n>   client didn't request the capablity in the first command.\n> \n>   receive-pack can generate the same SHA-1 hash from the commands\n>   it read from send-pack, and can verify the PGP signature on the\n>   auth line.\n> \n>   This assures us the command stream wasn't modified, and likely\n>   originated from the named identity.  The rest of the packfile\n>   data is already well protected by its own SHA-1 footer and the\n>   individual object SHA-1s, and the roots pointing into that DAG\n>   (or sub-DAG) mentioned in the commands were verified by the PGP\n>   signature of them.\n\nOk - but I think if the client is pushing a signed tag to the tagname\nlisted in the signed body of the tag, that no extra signature should be\nnecessary.  It's only commits that need the extra information.\n\nAnd remember, for global replication of the data between untrusted nodes\nto be possible, the signatures must be saved somewhere.  I have sketched\na simple design below.\n\n> * PGP public key storage:\n> \n>   Use a \"hidden\" ref called \"refs/access-keys\" to store a commit.\n>   The access control change log is a normal Git commit chain.\n> \n>   The tree under this commit stores a file per <email> string.\n>   Public keys for auth line validation are located by <email>,\n>   from the tip of this branch.\n> \n>   This branch could be a symlink to another repository (e.g.\n>   a site-wide \"admin\" repository) and the ODB for that other\n>   repository could be an alternate for this repository.\n> \n> \n> * ref/access-keys security:\n> \n>   Probably an update or pre-receive hook could verify pushes\n>   to this branch by something like this:\n> \n>     - If the only difference between $old_sha1 $new_sha1 is\n>       a modification of $GIT_PUSHER_EMAIL then allow it\n>       (user is replacing their own key);\n> \n>     - If the only difference between $old_sha1 $new_sha1 is\n>       modifications of names other than $GIT_PUSHER_EMAIL but\n>       the file content differences are only $GIT_PUSHER_EMAIL\n>       signing those public keys then allow it (the user doing\n>       the push is publishing some trust);\n> \n>     - If the difference between $old_sha1 $new_sha1 is new\n>       keys added or existing keys removed then allow it only\n>       if $GIT_PUSHER_EMAIL is also listed inside of the\n>       \"admin/\" subtree and the new key is also signed by\n>       $GIT_PUSHER_EMAIL's key.\n\nOk perhaps it is best to wrap all this up in a single state branch, that\nhas in it:\n\n   access-keys/\n     - tree with one key per e-mail address\n   access\n     - maps reference globs to e-mail addresses permitted to change\n       them - with a \"+\" if the address may rewind the ref\n   owners\n     - maps reference globs to e-mail addresses permitted to add entries\n       to the \"access\" map above\n   signatures/\n     - stores any detached signatures.  only the signatures verifying\n       updates since the last commit to the access meta-branch need to\n       be stored\n   packed-refs\n     - the new list of references (the refs/access commitid is naturally\n       absent or the same as the parent), or just the changed\n       references.\n\nYou don't necessarily need a new commit on this for every single push,\njust once \"every so often\", and perhaps for safety once for every change\nto the access file.\n\nThis branch should then be auditable; replicating tools can go and\nverify that there have been no unauthorized changes.\n\nForks don't necessarily need special treatment; they can exist under\nrefs/forks/foobar/ - similar to the refs/remotes/ namespace, and have\ntheir own independent ACL branches within.\n\nAllowing \"grant\" permissions to refspaces would need to be handled\nspecially; you can't simply grant access to change refs/access; the\nactual push to refs/access would need inspecting to see if the changed\n\"access\" file comes within the rights of the user that signed the update.\n\nI think this seems about right for a first cut.  Possibly bigger\nprojects like Debian would like to say that for certain ref spaces,\nmultiple signatures are required, so that no one PGP key retains\ncomplete control.  But I think these things are easily added as features\non top of this basic infrastructure.\n\nSound like something worth working towards?\nSam.\n"},{"id":"66904","messageId":"20080130074758.GT24004@spearce.org","threadId":"11765","inReplyTo":"47A01963.1030703@vilain.net","subject":"Re: [RFC] Authenticate push via PGP signature, not SSH","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2008-01-30T07:47:58Z","receivedAt":"2008-01-30T07:47:58Z","isPatch":false,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"Sam Vilain <sam@vilain.net> wrote:\n> Shawn O. Pearce wrote:\n> > * New protocol extension to send-pack/receive-pack pair:\n> > \n> >   If server wants to require (or optionally) accept a signed push\n> >   event it sends a new capability string when it advertises its\n> >   current known heads:\n> \n> Ok - but I think if the client is pushing a signed tag to the tagname\n> listed in the signed body of the tag, that no extra signature should be\n> necessary.  It's only commits that need the extra information.\n\nDoh.  Of course the standard signed tag case is easily verified,\nwithout the new authentication extension.  But adding it around\na signed tag push doesn't really hurt anything, except maybe the\nuser who entered her passphrase yet again.\n\nSigning a tag push is actually relevant in some cases.  For example\nwhen I mirror Junio's git.git tree into my local server at day-job.\nJunio signed the v1.5.4-rc5 tag.  I pushed it to the same location,\nand although we can validate Junio's signature, it may matter (to\npeople who have too much free time on their hands but I digress)\nwho at our organization put that v1.5.4-rc5 tag from Junio onto\nthat particular system, and when they did that.  Was it me?\nOr another co-worker?\n\n> And remember, for global replication of the data between untrusted nodes\n> to be possible, the signatures must be saved somewhere.  I have sketched\n> a simple design below.\n\nCrap.  You mentioned this in your initial email, and I forgot\nabout it when I posted the message you are responding to now.\nIts actually an interesting concept.  We can validate the entire\nchain of commits that led up to a signed tag, and we can validate\nthat signature on that tag.  So why shouldn't we also be able to\nvalidate the changes to refs in a distributed fashion?\n\nThis does complicate things considerably, as now we're talking\nabout the ref namespace no longer being this simple set of DAG\npointers, but itself becoming a DAG.  Someone please stop the\nmadness!  :-)\n\n> > * PGP public key storage:\n> > * ref/access-keys security:\n> \n> Ok perhaps it is best to wrap all this up in a single state branch, that\n> has in it:\n> \n>    access-keys/\n>      - tree with one key per e-mail address\n>    access\n>      - maps reference globs to e-mail addresses permitted to change\n>        them - with a \"+\" if the address may rewind the ref\n>    owners\n>      - maps reference globs to e-mail addresses permitted to add entries\n>        to the \"access\" map above\n\nThis part I get.  Using only globs is a tad limited in my mind.\nI actually abuse regexes on refs at day-job in a few places to get\nthe access list to work with just a handful of rules.\n\n>    signatures/\n>      - stores any detached signatures.  only the signatures verifying\n>        updates since the last commit to the access meta-branch need to\n>        be stored\n>    packed-refs\n>      - the new list of references (the refs/access commitid is naturally\n>        absent or the same as the parent), or just the changed\n>        references.\n\nThis I'm not so sure.  Are you suggesting that we save the detached\nsignature I described earlier that signed the push command set and\nstore it here, in this access state branch?  And that we also store\na copy of all refs (save this one) as a flat file?\n\nI guess the hidden part here is one can recover the command set used\nbetween any two pushes by diffing the packed-refs file and parsing\nthat diff to regenerate the command set.  Then you have to find some\ndetached signature that is associated with this set of commands and\nverify it.  Matching the signature back to its public key is easy.\nWhat isn't described here is the complexity of matching the detached\nsignature to a command set that was extracted from the diff of the\npacked-refs file.\n\nUrgh.\n\nI think this needs to be rethunk.  Its really freaking early morning\nhere, and I probably should be in bed, not solving security problems,\nbut this is starting to feel like we are trying to use the Titantic\nas a hammer to tighten a motherboard mounting screw.  Its a bit\nheavy, somewhat difficult to yield with one hand, and probably\nnot the best tool for the job.  But it moved that D@*! screw.\nAnd your desk, your floor, your office building, and the rest of\nthe city block while it was at it.\n \n> You don't necessarily need a new commit on this for every single push,\n> just once \"every so often\", and perhaps for safety once for every change\n> to the access file.\n\nActually I think you would need a new commit for each detached\nsignature you received.  Otherwise you may wind up with a set of\nrefs that you cannot explain how they happened, and the signatures\nyou do have don't sign those changes.\n\nNow maybe you have a \"mob\" branch that anyone can push to, without\nauthorization, in which case OK, I can see the not every push does\nan update to the access state branch case.  But I think that if we\nget a signature for a ref command set we'd need to save that, if\nwe are saving them at all.\n\n> This branch should then be auditable; replicating tools can go and\n> verify that there have been no unauthorized changes.\n> \n> Forks don't necessarily need special treatment; they can exist under\n> refs/forks/foobar/ - similar to the refs/remotes/ namespace, and have\n> their own independent ACL branches within.\n> \n> Allowing \"grant\" permissions to refspaces would need to be handled\n> specially; you can't simply grant access to change refs/access; the\n> actual push to refs/access would need inspecting to see if the changed\n> \"access\" file comes within the rights of the user that signed the update.\n\nRight.  Which gets interesting.  The paranoid update hook also does\nfile level ACLs by checking the output of `git diff-tree $old $new`,\nbut it really gets tripped up during merges.  It cannot tell that\nyou are just merging some other branch and haven't yourself made\nmodifications to the files.\n\n> I think this seems about right for a first cut.  Possibly bigger\n> projects like Debian would like to say that for certain ref spaces,\n> multiple signatures are required, so that no one PGP key retains\n> complete control.  But I think these things are easily added as features\n> on top of this basic infrastructure.\n\nWhere do we enqueue the partial pushes until final approval?\n\nI actually like this idea, of allowing voting for a refspace change,\nand having the refspace update only when sufficient authorization\nhas been received.  Possibly based upon pure number of users who\nauthorized the change, or based upon their PGP trust values in the\nserver's PGP trust database, or a combination of the two.\n\nAt day-job we use a code review system based upon Git where code\nreviewers push commit SHA-1s into special hidden namespaces:\n\n\trefs/approved/$ri/$branch\n\trefs/rejected/$ri/$branch\n\nThe $ri is the reviewer's private namespace (e.g. mine is sp,\nyours might have been sv) and $branch is the name of the branch\nhead, minus refs/heads.  A little Perl script reads the output of\n`git ls-remote` to count the number of approved and rejected refs\nfor a given branch, where the SHA-1 values are all identical.  If a\ndeveloper amends or pushes new commits onto an already approved\nbranch the approval is no longer counted, as the SHA-1s now differ.\n\nA simple GC script cleans up any stale approved and rejected refs,\nand gets run once a week alongside repack.\n\nReally simple Apache style change voting, in git.\n\nI bring this up now because our code review approvals are sort\nof along the lines you were just suggesting \"bigger projects like\nDebain\" might need to allow changes to say their stable security\nfix branch.  We're a lot smaller than Debian, but it would be nice\nif there is some sort of middle ground that would get both groups\nsome support within the core.\n\nEnterprises that have \"two person change\" rules may also like this\nsort of feature, as then the system automatically enforces the\nrule that at least two individuals must approve a change in status\nfor software.  Oh, my day-job is such a group, but since our tools\ndon't really verify squat we ignore that two man change thing.\n\nBut yes, this is really heavy-weight process wise, and we can't\nplease everyone and still have a really simple system that mere\nmortals can understand, so I'm probably off in la-la land at this\npoint in the discussion.\n \n> Sound like something worth working towards?\n\nWe're getting there.\n\n-- \nShawn.\n"},{"id":"66906","messageId":"47A02EA8.50507@viscovery.net","threadId":"11765","inReplyTo":"20080130042201.GO24004@spearce.org","subject":"Re: [RFC] Authenticate push via PGP signature, not SSH","fromName":"Johannes Sixt","fromEmail":"j.sixt@viscovery.net","sentAt":"2008-01-30T08:00:40Z","receivedAt":"2008-01-30T08:00:40Z","isPatch":false,"sender":{"key":"j6t@kdbg.org","avatar":"https://avatars.githubusercontent.com/u/14810926?v=4"},"body":"Shawn O. Pearce schrieb:\n> I'm currently finishing a side-band-64k protocol extension to the\n> send-pack/receive-pack pair.  My next task after I flush those\n> RFC patches out to the list tonight will be to prototype at least\n> some of the auth1 extension I described.\n\nI propose to make the syntax of the extension\n\nserver capability:  auth=<list of hash methods>:<challenge>\nclient response:    auth=<chosen hash method>\n\nwhere <challenge> is a random sequence of non-blank ASCII text, not\nnecessarily of a fixed length, but perhaps of a minimum length.\n\nThen we can extend the list of hash algorithms (that are used for\nauthentication purposes) if people think that SHA1 is not secure enough:\n\n    auth=SHA1,SHA256:random-stuff-goes-here\n\nI'm not a security expert, so take this with a grain of salt.\n\n-- Hannes\n"},{"id":"66910","messageId":"20080130083315.GB8698@artemis.madism.org","threadId":"11765","inReplyTo":"20080130042201.GO24004@spearce.org","subject":"Re: [RFC] Authenticate push via PGP signature, not SSH","fromName":"Pierre Habouzit","fromEmail":"madcoder@debian.org","sentAt":"2008-01-30T08:33:16Z","receivedAt":"2008-01-30T08:33:16Z","isPatch":false,"sender":{"key":"madcoder@debian.org","avatar":"https://avatars.githubusercontent.com/u/44708?v=4"},"body":"On Wed, Jan 30, 2008 at 04:22:01AM +0000, Shawn O. Pearce wrote:\n> Pierre Habouzit <madcoder@debian.org> wrote:\n> > On Tue, Jan 29, 2008 at 04:10:00AM +0000, Shawn O. Pearce wrote:\n> > > * PGP public key storage:\n> > > \n> > >   Use a \"hidden\" ref called \"refs/access-keys\" to store a commit.\n> > >   The access control change log is a normal Git commit chain.\n> > \n> >   This won't work well, because I don't think GnuPG is able to check\n> > some signature against an armored GPG public Key (at least I didn't\n> > found a way to do that). You have to create one pubring per submitter,\n> > wich is kind of a waste in fact, and the format is horribly binary.\n> \n> Gaaah.\n> \n> I hate tools that build their own little internal databases of\n> objects, and don't let you store their data in other random places,\n> like in any random file format you choose[*1*].  ;-)\n\n  [for the record I got the joke].\n\n> I just read the GnuPG manual and you are obviously correct.  The only\n> way to get GnuPG to process a key is to load it onto a keyring.\n> We could extract the armored (or binary) public key and load it\n> onto a temporary keyring created just for the purpose of verifying\n> this connection, but that's rather messy.\n\n  That was my point.\n\n> >   I don't even know if you really need the versionning of this\n> > pseudo-keyring, and if a .git/keyring.gpg isn't enough.\n> \n> Well, I don't know about that.\n> \n> People come and go on a project.  It would be nice if there was\n> a reasonably trusted store available as part of the project, that\n> one can verify using a current trusted project member's public key,\n> and obtain prior project member's public keys out of.  But maybe the\n> Debian folks just doesn't worry about this as it isn't a real issue.\n\n  It is, we have since recently the princple of \"Debian Maintainers\",\npeople that are only allowed to upload their own package, and the\nkeyring used for that purpose is versionned using a custom development\nof ours called jetring (by Joey Hess and al.), I suppose the sources are\nsomewhere around, and it has an internal ascii-armored database IIRC\n_and_ a gpg-usable keyring, I think. Or is able to generate the keyring\nat least.\n\n  But for the case I discussed, indeed, I'd use\n/usr/share/keyrings/debian-keyring.gpg anyways, and won't be the one\nupdating it. That's why your developpement should be able to allow\nchecking against another keyring. IOW I'm less and less sure that you\nwant to manage the keyring _necessarily_ inside the git tree, and that\nallowing any external way to manage a keyring (inside a git tree beeing\none of the options) is the most flexible way.\n\n> >   As a side note, you don't really need to use GIT_PUSH_*. It doesn't\n> > make anything safer (as the UIDs of a given public key are public\n> > information anyways), you just want to know which key signed that data,\n> > and the signature holds that information. Hence if you still want to\n> > have a flat-file based keyring (which I repeat I don't think gpg\n> > supports directly -- and that's really a shame) you'd better index them\n> > per key fingerprint than by author name.\n> \n> Yea, I know, you haven't told me anything I didn't already know.\n> \n> Having GIT_PUSHER_{NAME,EMAIL} makes it easier for a hook to\n> obtain information about this person and use it in an automated\n> email message.  Think a post-receive hook that automatically sends\n> out announcement emails.\n\n  okay, that makes sense. Sorry about the obvious parts, it sensed like\nyou didn't used gpg on a regular basis, hence wasn't sure of what you\nalready knew or not. I agree that for the sake of logging GIT_PUSHER_*\nare nice, since as you can see on the CLI examples I gave, gpg says that\nthe email associated to my key is pierre.habouzit@polytechnique.edu\nwhereas I ususally contribute to open source projects using\nmadcoder@debian.org ;)\n\n> Yes, I know the key ids are unique enough for our needs.  But dammit,\n> they just aren't friendly to work with when you are storing log\n> records for later inspection, or maintaing an access list.\n\n  Well, I know my gpg key ID, but I'm biased for sure ;)\n\n-- \n·O·  Pierre Habouzit\n··O                                                madcoder@debian.org\nOOO                                                http://www.madism.org\n"},{"id":"66911","messageId":"20080130083528.GC8698@artemis.madism.org","threadId":"11765","inReplyTo":"47A01162.7070503@vilain.net","subject":"Re: [RFC] Authenticate push via PGP signature, not SSH","fromName":"Pierre Habouzit","fromEmail":"madcoder@debian.org","sentAt":"2008-01-30T08:35:28Z","receivedAt":"2008-01-30T08:35:28Z","isPatch":false,"sender":{"key":"madcoder@debian.org","avatar":"https://avatars.githubusercontent.com/u/44708?v=4"},"body":"On Wed, Jan 30, 2008 at 08:50:33AM +0000, Sam Vilain wrote:\n> Shawn O. Pearce wrote:\n> > I just read the GnuPG manual and you are obviously correct.  The only\n> > way to get GnuPG to process a key is to load it onto a keyring.\n> > We could extract the armored (or binary) public key and load it\n> > onto a temporary keyring created just for the purpose of verifying\n> > this connection, but that's rather messy.\n> \n> It should be fine just to throw the lot into a single keyring, and just\n> check which key verified it after the fact and whether that key was allowed.\n> \n> The Perl Crypt::OpenPGP module doesn't suffer from this problem (and is\n> performant), though it suffers from a dependency stack that will hurt\n> everyone except Debian users ;-).\n\n  Actually, if it's engineered like libgpgme (gpg made easy) is, well,\nit basically wraps calls to gpg, a thing that we can do ourselves easily\nusually :)\n\n  And here is the tool I mentioned in my other mail and forgot to give\nan url to: http://kitenet.net/~joey/code/jetring/\n-- \n·O·  Pierre Habouzit\n··O                                                madcoder@debian.org\nOOO                                                http://www.madism.org\n"},{"id":"66921","messageId":"47A0DC98.9080406@vilain.net","threadId":"11765","inReplyTo":"20080130083528.GC8698@artemis.madism.org","subject":"Re: [RFC] Authenticate push via PGP signature, not SSH","fromName":"Sam Vilain","fromEmail":"sam@vilain.net","sentAt":"2008-01-30T20:22:48Z","receivedAt":"2008-01-30T20:22:48Z","isPatch":false,"sender":{"key":"sam@vilain.net","avatar":"https://gravatar.com/avatar/8fc840ca854dbf6f7065b4335e3b934951c1dca3b11db688e95e471901f8f4a8?d=mp&s=160"},"body":"Pierre Habouzit wrote:\n>> The Perl Crypt::OpenPGP module doesn't suffer from this problem (and is\n>> performant), though it suffers from a dependency stack that will hurt\n>> everyone except Debian users ;-).\n> \n>   Actually, if it's engineered like libgpgme (gpg made easy) is, well,\n> it basically wraps calls to gpg, a thing that we can do ourselves easily\n> usually :)\n\nIt's nothing like gpgme - it brings together all of the Perl modules\nthat together implement PGP completely.  It doesn't use gpg.\n\nSam.\n"},{"id":"66942","messageId":"47A121F2.4040400@vilain.net","threadId":"11765","inReplyTo":"20080130074758.GT24004@spearce.org","subject":"Re: [RFC] Authenticate push via PGP signature, not SSH","fromName":"Sam Vilain","fromEmail":"sam@vilain.net","sentAt":"2008-01-31T01:18:42Z","receivedAt":"2008-01-31T01:18:42Z","isPatch":false,"sender":{"key":"sam@vilain.net","avatar":"https://gravatar.com/avatar/8fc840ca854dbf6f7065b4335e3b934951c1dca3b11db688e95e471901f8f4a8?d=mp&s=160"},"body":"Shawn O. Pearce wrote:\n>> Ok - but I think if the client is pushing a signed tag to the tagname\n>> listed in the signed body of the tag, that no extra signature should be\n>> necessary.  It's only commits that need the extra information.\n> \n> Doh.  Of course the standard signed tag case is easily verified,\n> without the new authentication extension.  But adding it around\n> a signed tag push doesn't really hurt anything, except maybe the\n> user who entered her passphrase yet again.\n> \n> Signing a tag push is actually relevant in some cases.  For example\n> when I mirror Junio's git.git tree into my local server at day-job.\n> Junio signed the v1.5.4-rc5 tag.  I pushed it to the same location,\n> and although we can validate Junio's signature, it may matter (to\n> people who have too much free time on their hands but I digress)\n> who at our organization put that v1.5.4-rc5 tag from Junio onto\n> that particular system, and when they did that.  Was it me?\n> Or another co-worker?\n\nOk, well if people want to sign those pushes then let them - but\nallowing them to be pushed anonymously does have the nice side effect\nthat absolutely nothing needs to be done for the case of replicating\ntagged releases of an existing project.  ie, projects that are just\ntagging using existing tools and have no knowledge of this system.\n\n>> And remember, for global replication of the data between untrusted nodes\n>> to be possible, the signatures must be saved somewhere.  I have sketched\n>> a simple design below.\n> \n> Crap.  You mentioned this in your initial email, and I forgot\n> about it when I posted the message you are responding to now.\n> Its actually an interesting concept.  We can validate the entire\n> chain of commits that led up to a signed tag, and we can validate\n> that signature on that tag.  So why shouldn't we also be able to\n> validate the changes to refs in a distributed fashion?\n\nYes, you could be lazy about it and throw away signatures that were\nobsoleted.\n\n>>    access-keys/\n>>      - tree with one key per e-mail address\n>>    access\n>>      - maps reference globs to e-mail addresses permitted to change\n>>        them - with a \"+\" if the address may rewind the ref\n>>    owners\n>>      - maps reference globs to e-mail addresses permitted to add entries\n>>        to the \"access\" map above\n> \n> This part I get.  Using only globs is a tad limited in my mind.\n> I actually abuse regexes on refs at day-job in a few places to get\n> the access list to work with just a handful of rules.\n\nExtended POSIX or limited PCRE or something like that will do then.\n\n>>    signatures/\n>>      - stores any detached signatures.  only the signatures verifying\n>>        updates since the last commit to the access meta-branch need to\n>>        be stored\n>>    packed-refs\n>>      - the new list of references (the refs/access commitid is naturally\n>>        absent or the same as the parent), or just the changed\n>>        references.\n> \n> This I'm not so sure.  Are you suggesting that we save the detached\n> signature I described earlier that signed the push command set and\n> store it here, in this access state branch?  And that we also store\n> a copy of all refs (save this one) as a flat file?\n\nOn second thoughts, these are only of interest to the auditing and\nreplication side of things.\n\n> Someone please stop the madness!  :-)\n\nOk, I think I see the simple beginning path.  Let's go back to the tree\nstate idea and not worry about replication and auditing yet.  I think it\nshould fit in smoothly anyway with the above basics.\n\nThis means we can nail down the rules for validating a single push/ref\nchange.  Handling ACL changes is the second level once this first level\nworks.  It can be manual initially.\n\nYou bring up an idea I didn't think of, which is setting up ACLs for\npaths within a tree.  I guess quite a few people want that.\n\nHow about this syntax (and using globs for illustrative simplicity only):\n\n  refs/heads/*:path/* = any(email email email)\n\nAlso, I think that the point about the debian keyrings requires some\nconsideration.  Maybe groups;\n\n  access-keys/debian/\n\nThat way the debian/ access-keys sub-directory can be shared via\nalternates across a number of repositories on a shared system.  Instead\nof an email address, a group is listed.  But again I think should fall\ninto place later, once the basic idea is nailed down.\n\nSam.\n"},{"id":"66957","messageId":"20080131043056.GX24004@spearce.org","threadId":"11765","inReplyTo":"20080130083315.GB8698@artemis.madism.org","subject":"Re: [RFC] Authenticate push via PGP signature, not SSH","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2008-01-31T04:30:56Z","receivedAt":"2008-01-31T04:30:56Z","isPatch":false,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"Pierre Habouzit <madcoder@debian.org> wrote:\n> On Wed, Jan 30, 2008 at 04:22:01AM +0000, Shawn O. Pearce wrote:\n> > [...] But maybe the\n> > Debian folks just doesn't worry about this as it isn't a real issue.\n> \n>   It is, we have since recently the princple of \"Debian Maintainers\",\n> people that are only allowed to upload their own package, and the\n> keyring used for that purpose is versionned using a custom development\n> of ours called jetring (by Joey Hess and al.), I suppose the sources are\n> somewhere around, and it has an internal ascii-armored database IIRC\n> _and_ a gpg-usable keyring, I think. Or is able to generate the keyring\n> at least.\n\nI looked at jetring earlier today, after you posted the URL in\nyour other email.  Its an interesting tool for distributed keyring\nmanagement.  I can see why the Debian folks use it, but it does seem\na little awkward if one has to create those change files by hand.\n \n>   But for the case I discussed, indeed, I'd use\n> /usr/share/keyrings/debian-keyring.gpg anyways, and won't be the one\n> updating it. That's why your developpement should be able to allow\n> checking against another keyring. IOW I'm less and less sure that you\n> want to manage the keyring _necessarily_ inside the git tree, and that\n> allowing any external way to manage a keyring (inside a git tree beeing\n> one of the options) is the most flexible way.\n\nOf this you have convinced me.\n\nIf we get any sort of push authorization based upon PGP signatures\nimplemented we should be validating against a keyring that is\nconfigured by a receive.keyring configuration option, and that\ndefaults to $GIT_DIR/receive-keyring.gpg or something suitable.\nIf you want to point receive-pack at an existing keyring on your\nsystem, you can and should do so.\n \n> > Having GIT_PUSHER_{NAME,EMAIL} makes it easier for a hook to\n> > obtain information about this person and use it in an automated\n> > email message.  Think a post-receive hook that automatically sends\n> > out announcement emails.\n> \n>   okay, that makes sense. Sorry about the obvious parts, it sensed like\n> you didn't used gpg on a regular basis, hence wasn't sure of what you\n> already knew or not. I agree that for the sake of logging GIT_PUSHER_*\n> are nice, since as you can see on the CLI examples I gave, gpg says that\n> the email associated to my key is pierre.habouzit@polytechnique.edu\n> whereas I ususally contribute to open source projects using\n> madcoder@debian.org ;)\n\nA repository owner may require that to push your GIT_PUSHER_*\nvalues must match the data found in your PGP key on their keyring,\njust to keep their logs in a particular way.  Others may not care\nand would allow anything, so long as the signature was validated\nby a key on the keyring.  But I think that level of checking is\nsomething we leave up to the repository owner.\n\nWhich leads me to three variables:\n\n\tGIT_PUSHER_NAME\n\tGIT_PUSHER_EMAIL\n\tGIT_PUSHER_KEYID\n\nthe latter being important if you really wanted to enforce the\n$GIT_PUSHER_EMAIL matching the data within the public key used.\n\n-- \nShawn.\n"},{"id":"66959","messageId":"20080131054304.GY24004@spearce.org","threadId":"11765","inReplyTo":"47A02EA8.50507@viscovery.net","subject":"Re: [RFC] Authenticate push via PGP signature, not SSH","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2008-01-31T05:43:05Z","receivedAt":"2008-01-31T05:43:05Z","isPatch":false,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"Johannes Sixt <j.sixt@viscovery.net> wrote:\n> Shawn O. Pearce schrieb:\n> > I'm currently finishing a side-band-64k protocol extension to the\n> > send-pack/receive-pack pair.  My next task after I flush those\n> > RFC patches out to the list tonight will be to prototype at least\n> > some of the auth1 extension I described.\n> \n> I propose to make the syntax of the extension\n> \n> server capability:  auth=<list of hash methods>:<challenge>\n> client response:    auth=<chosen hash method>\n> \n> where <challenge> is a random sequence of non-blank ASCII text, not\n> necessarily of a fixed length, but perhaps of a minimum length.\n> \n> Then we can extend the list of hash algorithms (that are used for\n> authentication purposes) if people think that SHA1 is not secure enough:\n> \n>     auth=SHA1,SHA256:random-stuff-goes-here\n> \n> I'm not a security expert, so take this with a grain of salt.\n\nI'm not certain this is worth the extra complexity.\n\nOne reason I proposed \"auth-1\" as the extension name is so we could\nintroduce an \"auth-2\" and make changes in the future if we need to.\n\nBut I think there's little value in this authentication hash being\nanything other than SHA-1.  Remember that the data itself in the\npackfile following the authentication is only protected by SHA-1.\nIf SHA-1 is considered too weak to protect the ref update commands\nthen its likely also too weak to protect the file content following\nbehind those same commands.\n\nGetting stronger authentication here than SHA-1 would probably\nrequire changing the commit object name hash to something stronger\nthan SHA-1, and the tree object name hash, etc.  Remember that\nsigned tags are only using the SHA-1 of the commit and that's only\ngot the SHA-1 of the tree... ;-)\n\n-- \nShawn.\n"},{"id":"66967","messageId":"20080131092527.GC24403@artemis.madism.org","threadId":"11765","inReplyTo":"20080131043056.GX24004@spearce.org","subject":"Re: [RFC] Authenticate push via PGP signature, not SSH","fromName":"Pierre Habouzit","fromEmail":"madcoder@debian.org","sentAt":"2008-01-31T09:25:27Z","receivedAt":"2008-01-31T09:25:27Z","isPatch":false,"sender":{"key":"madcoder@debian.org","avatar":"https://avatars.githubusercontent.com/u/44708?v=4"},"body":"On Thu, Jan 31, 2008 at 04:30:56AM +0000, Shawn O. Pearce wrote:\n> Pierre Habouzit <madcoder@debian.org> wrote:\n> >   It is, we have since recently the princple of \"Debian Maintainers\",\n> > people that are only allowed to upload their own package, and the\n> > keyring used for that purpose is versionned using a custom development\n> > of ours called jetring (by Joey Hess and al.), I suppose the sources are\n> > somewhere around, and it has an internal ascii-armored database IIRC\n> > _and_ a gpg-usable keyring, I think. Or is able to generate the keyring\n> > at least.\n> \n> I looked at jetring earlier today, after you posted the URL in\n> your other email.  Its an interesting tool for distributed keyring\n> management.  I can see why the Debian folks use it, but it does seem\n> a little awkward if one has to create those change files by hand.\n\n  Well, *I* don't use it, it's just a fancy tool that replaces the fully\nmanual (sigh) Debian keyring management for the DM keyring, so that it\ncan be used by multiple people at the same time. I just pointed to it,\nas like you said, reinventing the wheel sucks. Though Joey will probably\nbe open to improvements if needed :)\n\n> >   But for the case I discussed, indeed, I'd use\n> > /usr/share/keyrings/debian-keyring.gpg anyways, and won't be the one\n> > updating it. That's why your developpement should be able to allow\n> > checking against another keyring. IOW I'm less and less sure that you\n> > want to manage the keyring _necessarily_ inside the git tree, and that\n> > allowing any external way to manage a keyring (inside a git tree beeing\n> > one of the options) is the most flexible way.\n> \n> Of this you have convinced me.\n> \n> If we get any sort of push authorization based upon PGP signatures\n> implemented we should be validating against a keyring that is\n> configured by a receive.keyring configuration option, and that\n> defaults to $GIT_DIR/receive-keyring.gpg or something suitable.\n> If you want to point receive-pack at an existing keyring on your\n> system, you can and should do so.\n\n  Full ACK. Another issue that I didn't saw in the first place, is that\nif you want to store your keyring in git itself, then it brings the\nissue that you would have to write ACLs to protect the branch where it's\nstored, whereas it's usually _way_ more easy to just decorrelate both.\nIOW it's weak wrt security.\n-- \n·O·  Pierre Habouzit\n··O                                                madcoder@debian.org\nOOO                                                http://www.madism.org\n"}]}