keybase / keybase-issues

A single repo for managing publicly recognized issues with the keybase client, installer, and website.
900 stars 37 forks source link

Proof documentation needs work #742

Open timbray opened 10 years ago

timbray commented 10 years ago

I’m starting to work on verifying proofs for OpenKeychain and it seems pretty straightforward, except for the construction of the payload-to-be-signed. Just for a random example I’m looking at https://keybase.io/linuxwolf/sigs/GxNlVwMadNRIHa3hthcNvFo0GwgvN4eMnuWK and the signed payload is { "body": { "key": { "fingerprint": "31d7588dec90690d6bcc98e0ecf4724e109e05bb", "host": "keybase.io", "key_id": "ECF4724E109E05BB", "uid": "2299a80ced34e930a2f780f0b545a000", "username": "linuxwolf" }, "service": { "name": "twitter", "username": "linuxwolf" }, "type": "web_service_binding", "version": 1 }, "ctime": 1396037812, "expire_in": 157680000, "prev": "d101ca6baf3844841d02e76270ac2b67d88349677141beb577c2875c4f5780c8", "seqno": 9, "tag": "signature" } I can see where many of these data fields come from, some seem arbitrary/hardwired like "type" and "version" and "tag". I don’t see where “prev” and “seqno” come from.

I think if I can construct this JSON, I can replicate the proof in an android app quite straightforwardly. Happy to RTFM, if there is one. Happy to use someone else’s code if it’ been written.

maxtaco commented 10 years ago

prev and seqno you can get with the sig/next_seqno endpoint.

I'll update the docs for sig/post to point there.

Also, if you run the client with --debug, you'll get a fair amount of useful data dumped on you. Or, running the Chrome network inspector helps, too, since the Web client uses a lot of the same calls.

maxtaco commented 10 years ago

(Updated)

timbray commented 10 years ago

Oh wait.... of course that only works for checking my own proofs. Clearly I’m missing something obvious here. Back to the drawing board, don’t mind me.

timbray commented 10 years ago

OK, pardon me for being a moron... to check the proof, all I need is to fetch the signed statement, verify it with the person's public key, and check that it matches the tweet. So where do I get the signed statement? I could scrape it out of the HTML at, say, for example, https://keybase.io/timbray/sigs/uvc8wZIXtZztvzXRbax9WoJXSW-iP7Xo2Fh4 but perhaps it has its own address?

maxtaco commented 10 years ago

Let's use the example of timbray's client trying to verify linuxwolf's twitter proof. I think the steps are:

  1. Fetch his proofs from the keybase server with the sig/get endpoint (sorry, it's not documented yet).
  2. Scan through the list to find the most recent, non-revoked twitter proof (seqno=9 is the right one).
  3. Verify the sig with linuxwolf's public key
  4. Take the SHA256 of the body of the signature (after base64-decoding).
  5. Check that it matches with the tweeted sig, available as api_url in the JSON dictionary you found in step 2.
timbray commented 10 years ago

Aha! sig/get is what I want. Thanks! I notice that in the output from user/lookup there’s a sig_id, and a proof_id. Will start poking at sig/get with curl, unless you have any hints :)

timbray commented 10 years ago

never mind, I followed your link, now I should be good

maxtaco commented 10 years ago

Looks like you can give it either uid= or sig_id=. If you provide uid= you can also provide low= to only show sigs starting at a given point in the chain.

maxtaco commented 10 years ago

Yeah, it might be worthwhile to fetch the whole sequence, so you can look for subsequent revocations. That's what our client is doing

timbray commented 10 years ago

Hm... this actually raises a mildly interesting question. All I currently keep around on the client side is the keybase username. So the options are:

  1. Start keeping the keybase uid in my database and go straight to sig/get?uid=, or...
  2. Do a user/lookup to get the uid, then do the sig/get?uid= and scan through looking for revocations, or...
  3. Do a a user/lookup to get the sig_id of the proof I’m checking then do sig/get?sig_id= and assume that I don’t have to worry about revocation because proofs returned by user/lookup are current, or...
  4. If sig/get supported username= I could do #2 with one less round-trip.

But I think I probably have to do a user/lookup anyhow because I think the UX is something like a button labeled “Trust this key?” which displays the current proofs and buttons to perform checks.

maxtaco commented 10 years ago

If you're willing to trust the server to reconcile the proofs against the revocations, you can go with option 3. If you want to catch the server cheating, the client needs to hold onto signature history in a persistent DB (otherwise the server could rollback the user's signature chain), which can also keep the userid/username mapping. So it's a question of how sophisticated you think the client should be, and how much server cheating it can detect. (Going offline for a few hours, cheers).

timbray commented 10 years ago

OK, I think I got it. I can check an individual proof from the user structure and indeed, it proves that some key was also some Twitter/github/whatever ID at that timestamp, but it might have been revoked. A few remarks in the docs about how you’d properly use the sig chain to verify integrity, and what the minimum state a client needs to preserve, might be useful; I’ll see if I can figure it out.

maxtaco commented 10 years ago

Exactly.

BTW, there's a second way for users to revoke a proof, which is simply to delete the Tweet/Gist/DNS-TXT-Entry/WebPage. So there's a case to be made that you're not trusting the server much at all, since it will get caught cheating if it publishes a link to a 404'ed proof.

Also, tangentially related, we published a doc on server security last week that explains how to check sitewide state against rollbacks.

timbray commented 10 years ago

Well, except for the failure mode is that someone hacks my Twitter account and maybe one or two of my other proofs and I have trouble recovering them (I don’t think this scenario is that implausible) but fortunately I preserved my keybase account so I can get in and revoke those proofs. Because whether you want it to be or not, trust transitive; people are going to start trusting my github handle is me because they trust my keybase ID.

Anyhow, I think the notion of being able to use Keybase without having to trust Keybase is very powerful, although maybe underappreciated at the moment. So I’ll try to do this that way.