Open epaulson opened 9 years ago
It turns out that gpg can handle a key missing a self-signature at the command line, with the '--allow-non-selfsigned-uid' commandline option.
https://www.gnupg.org/gph/en/manual/r1424.html
zebra:test cpaulser$ gpg --no-default-keyring --allow-non-selfsigned-uid --keyring ./stock.gpg --import public-key-blob.withuid
gpg: keyring `./stock.gpg' created
gpg: key 28FD6F75: accepted non self-signed user ID "(camlistore)"
gpg: key 28FD6F75: public key "(camlistore)" imported
gpg: Total number processed: 1
gpg: imported: 1 (RSA: 1)
zebra:test cpaulser$ ls -l stock.gpg
-rw------- 1 cpaulser staff 286 Jun 23 15:17 stock.gpg
gpg still chokes on the default camlistore public key because there's no UID data embedded in the key. There is a '--local-user' commandline option that I thought might create a UID as part of the import, but I didn't have any luck with it.
zebra:test cpaulser$ rm stock.gpg
zebra:test cpaulser$ gpg --no-default-keyring --allow-non-selfsigned-uid --local-user camlistore@camlistore.com --keyring ./stock.gpg --import public-key-blob.stock
gpg: keyring `./stock.gpg' created
gpg: key 28FD6F75: no user ID
gpg: Total number processed: 1
zebra:test cpaulser$ ls -l stock.gpg
-rw------- 1 cpaulser staff 0 Jun 23 15:19 stock.gpg
zebra:test cpaulser$
The gpg manual says of --allow-non-selfsigned-uid: "You should really avoid using it, because OpenPGP has better mechanics to do separate signing and encryption keys." but I'm still searching for the right recipe to use the camlistore-generated public key with the gpg commandline tools.
@epaulson Hey! I'd like to get that fixed. I am working on a python implementation of some perkeep internals and this makes things way more complicated that they need to be.
The other challenging issue is that existing signed blobs reference the hash of the signing key - which is generated on startup from ~/.config/camlistore/identity-secring.gpg. With the changes above, the key will change, and existing deployments will have blobrefs to a blob that is no longer published.
I don't understand what you mean by that. Why would the blobref no longer be published? Isn't it stored permanently just like all other blobs?
Edit: ah, you probably refer to the signhandler endpoints where we wouldn't advertise our older key anymore?
This is a followup to the discussion here: https://groups.google.com/forum/#!topic/camlistore/Q5Ljhehrzg0
tl;dr: camlistore doesn't put enough info into the public key it serializes for a stock openpgp client to use it. Adding the extra bits changes the sha-1 of the blob, so an upgrade path needs to be considered for a fix.
Using this:
I am unable to import the public keys camlistore stores. With a fresh build and simply running bin/camlistored, I get a public key like so:
Using gpg to import it fails:
The trick seems to be to add in a UID and Self-signing packet. As-is now, when Camlistore serializes the public key, it only serializes the public key, and not any of the other entity metadata it extracts from identity-secring.gpg, ie in jsonsign/keys.go ArmoredPublicKey() it only does entity.PrivateKey.PublicKey.Serialize(wc). I think that should either be https://godoc.org/golang.org/x/crypto/openpgp#Entity.Serialize or at least follow its algorithm (though it might be way more than is really needed - but at the same time, if you're using an existing keypair, it'd be good to also publish any web of trust signatures).
This was the minimal diff I used, but Entity.Serialize is probably better:
If I leave off the ident.SelfSignature.Serialize bit, I get:
Adding in the SelfSignature succeeds:
If you simply serialize extra information, Camlistore panics on startup in pkg/schema/sign.go: it still only reads the public key packet from the blob in openArmoredPublicKeyFile, and as a sanity check computes the hash of what it read to be sure that the blob matches. Now that the blob has additional OpenPGP packets, the hash of the partial read camli does doesn't match the blob.
This turned out to be a pretty easy fix, because a TeeReader is used in pkg/shema/sign.go to copy bytes into the buffer to hash without ParseArmoredPublicKey in jsonsign having to know anything about it. There's also a great API in the crypto/openpgp package that let you read packets and just ignore what you're not interested in, so I slid that in, read and gave back the public key packet to the callers, and just did the extra reads in the background to make sure the hashes match without needing to change any callers. A real fix might want to make sure that all callers are aware that the hash of the key blobfile does not match the hash of the bytes openArmoredPublicKeyFile returns.
The other challenging issue is that existing signed blobs reference the hash of the signing key - which is generated on startup from ~/.config/camlistore/identity-secring.gpg. With the changes above, the key will change, and existing deployments will have blobrefs to a blob that is no longer published. If you decide to publish additional data in the public key, I imagine you'll want to publish the public key using both the old serialization scheme and a new one.