upspin / upspin

Upspin: A framework for naming everyone's everything.
https://upspin.io
Apache License 2.0
6.27k stars 302 forks source link

keyserver: Mechanism for resetting a lost key #614

Open i4ki opened 5 years ago

i4ki commented 5 years ago

Related to #429

I lost the keys for both my personal and professional email. I experimented Upspin very earlier. I understand the security concerned but as we use email as username and use it to verify the user identity, why we cannot use it also to reset the keys? Obviously, everything encrypted by the old key will be lost but the point here is recovering the username ownership.

Someone with future access to your email can’t masquerade as you in Upspin

The statement above is strong in terms of security but the implications go against the idea of Upspin being a technology aiming personal users, families or group of friends.

A token sent to user's email address could be used by the keyserver to verify the identity again.

n2vi commented 5 years ago

I'm strongly convinced that temporary access to email should not be enough to reset the key. People do have their email accounts hacked, and that already leads to too much collateral damage.

What I have agreed to, but haven't implemented yet, is a periodic flag day in which unused upspin accounts, after a public notice period, are allowed to reset their keys using the proof of continued email access. That gives everyone involved a bit more chance to contain the damage.

oec commented 6 months ago

I think we need to define what exactly is meant by unused upspin accounts. Probably the most sensible place to decide is on the keyserver, where we could apply the following criteria:

  1. Hostnames for dir- and storage-servers are probed regularly for existence (DNS, Dial), say, once per month. After n failures, the account is flagged as unused. (Successful checks reset the failure counter to zero)

  2. Each user-entry maintains a last-accessed timestamp, i.e. when was the last time somebody asked for the keys for that name. Entries with timestamps older than, say, m years, are flagged as unused.

One could also consider criteria on dir- and storage-servers, but those are under the control of the users and should be handled by them.

n2vi commented 6 months ago

For criterion 1, you'll find my own accounts are currently inactive. I'm in the process of moving to a non-cloud-hosted server, but as a low priority project behind getting upspinfs working on more operating systems than today. I do still have all my buckets saved and might revive the cloud server if I wanted to check something out.

A possible disadvantage of criterion 2 is that a prankster could just ask for all the keys once a year and no account would ever become inactive.

It would be good to add an "inactive account notification" process as well, sending an email to the address on record at least a few weeks before taking any action on it.

For someone in my situation (no active servers but I still possess the secrets corresponding to the registered public key) it should be possible to have a registered-key-signed no-op sent to the keyserver to reset the "inactive" clock. I'm not sure we want to require that of all users, but we should allow power users to keep their accounts alive that way. Include simple instructions for doing so in the "inactive account notification" email.

Allow power users to designate themselves as such and opt out of the "inactive / recovery" process altogether, at the risk of course that they are forever frozen out of their accounts if they lose their secrets.

oec commented 6 months ago

I think the situation you describe sounds like a perfect use case for criterion 1 for the average user: There are unreachable hostnames in the keyserver, belonging to an user. After N failed attempts (for configurable N and frequency), the keyserver sends out an email to the user with a link to a keep-alive URL, pointing at the keyserver, to basically reset the counter of failed attempts.

Assuming that we keep criterion 1, how would a REST-API for keep-alive messages, signed by the private key of a user, interact with the situation described by criterion 1? I.e.: the keyserver receives keep-alive messages, but the corresponding hostnames of dir- and storage-servers are never accessible? Does the keep-alive message overrule the failed attempts counter? (I remember vaguely that you could register an user with email only, without dir- and storage-server. That might be such a case where the keep-alive message should allow to overwrite criterion 1).

I agree that criterion 2 might in practice actually never be triggered.

n2vi commented 6 months ago

Yes, you can register a user with email only; no servers. That's a common sequence during setup.

You already know why we disallowed email-reset, but just as an aside for the design record...

Well-run email systems have an absolute policy --- no exceptions --- that email addresses are never reused. If someone deletes their account or is frozen out of it for whatever reason, for security reasons that email address becomes permanently inaccessible.

Nevertheless, we designed upspin to not count on this property because a) not all email systems are well-run, and b) even such systems may not be invulnerable to account hijacking. Gmail accounts protected with U2F Security Keys are the only large example I've heard of that claim zero account hijacks over an extended period, but even there I'm not certain that some future Google won't change the rules out of a desire to help users and fall into the trap.

On Sat, Mar 2, 2024 at 2:22 PM Özgür Kesim @.***> wrote:

I think the situation you describe sounds like a perfect use case for criterion 1 for the average user: There are unreachable hostnames in the keyserver, belonging to an user. After N failed attempts (for configurable N and frequency), the keyserver sends out an email to the user with a link to a keep-alive URL, pointing at the keyserver, to basically reset the counter of failed attempts.

Assuming that we keep criterion 1, how would a REST-API for keep-alive messages, signed by the private key of a user, interact with the situation described by criterion 1? I.e.: the keyserver receives keep-alive messages, but the corresponding hostnames of dir- and storage-servers are never accessible? Does the keep-alive message overrule the failed attempts counter? (I remember vaguely that you could register an user with email only, without dir- and storage-server. That might be such a case where the keep-alive message should allow to overwrite criterion 1).

I agree that criteria 2 might in practice actually never be triggered.

— Reply to this email directly, view it on GitHub https://github.com/upspin/upspin/issues/614#issuecomment-1974924339, or unsubscribe https://github.com/notifications/unsubscribe-auth/ACADPOQ67T3PAKIIMA5PKPDYWJGLLAVCNFSM4GRSXWZ2U5DIOJSWCZC7NNSXTN2JONZXKZKDN5WW2ZLOOQ5TCOJXGQ4TENBTGM4Q . You are receiving this because you were assigned.Message ID: @.***>

oec commented 6 months ago

I do not propose to change the public key to an address or associated hosts in the key server by a link in an email, only to keep the entry marked "alive". Even if somebody had hijacked the email address, it won't be able to change the contents in the entry without the private key.

But, of course, in the email, instead of just providing a simple link, we could ask the user to use the upsin tool to generate the keep-alive message, signed by the corresponding private key and sent to the key-server via REST-API. (Also providing the opportunity to update the host records).

This would combine both use-cases: a) "power users" who send such keep-alive messages regularly and automatically and b) sending users emails when their hosts became unavailable for quite some (configurable) time.

oec commented 6 months ago

... to finish to the train of thought and provide a more complete proposal:

WDYT?

n2vi commented 6 months ago

Imagine that years ago I was at a family reunion and set up an upspin directory where we could collect family stories and photos. One of my distant cousins gets excited and sets up his own account, but eventually passes away. His personal servers get turned off. His obscure email vendor deletes his account and gives the address to someone else, who happens to create an upspin account themselves. (Yes, this is ludicrously hypothetical, just a concrete illustration of the abstract principle. Bear with me.)

Now I add a new family story to my directory after it has been quiet for years. My upspin client automatically encrypts the file using the latest keys of the addresses in my family Group. A stranger now can read the file!

It is arguably ok if I'm warned that there is a new key in use and asked for permission to proceed. But how is that discovered? I'm not even on the same machine as years ago at the family reunion. By spotting a discrepancy with the keys used in existing old files in the directory? No, that would would "warn" me even if I'd already been warned long ago for the same key in some other directory. So I guess upspin needs a new master file in my root directory, only visible to me and updated each time a new key is encountered. That's hard to justify just for account recovery, but could be useful to update in the background all relevant direntries whenever one of my friends re-keys.

On Sun, Mar 3, 2024 at 12:30 AM Özgür Kesim @.***> wrote:

... to finish to the train of thought and provide a more complete proposal:

-

A new REST-API on the key-server accepts signed (by the private key of an user) keep-alive messages from users to mark their entry as alive and used. In particular, for a valid request, any failure counters for the corresponding user are set to zero, see below.

The keyserver probes hostnames for dir- and storage-servers of users regularly for existence (DNS, Dial), with frequency f. After N failures (that is: after period N/f), the account is flagged as unused. (Successful probes reset the failure counter to zero, as do properly signed keep-alive messages via the new REST-API on the keyserver, see above).

The key-server sends emails to all users with unused accounts, asking them to use the upspin tool (newest version) to generate a keep-alive message, signed by their private key and sent to the key-server via REST-API. (Also providing the opportunity to update the host records).

If the user sends a signed keep-alive message, the account is marked as active again, potentially with updated host entries.

If no steps are taken by the user within a grace period P and the email hasn't been sent out more then M times, sent the email again.

After a period of M*P without receiving a signed keep-alive message from the user, the corresponding entries in the key-server are put into quarantine for a period Q and the keys are not served anymore by the key-server. However, within that period Q, the account can not be registered as new.

Yet, within period Q, a user can still re-active their own quarantined entry via a keep-alive message generated by the upspin tool and signed by their private key.

Otherwise, after period Q, the name and its corresponding entries are deleted from the keyserver completely. The name can be registered again, with new key material (by however owns that email address at that moment).

WDYT?

— Reply to this email directly, view it on GitHub https://github.com/upspin/upspin/issues/614#issuecomment-1975085850, or unsubscribe https://github.com/notifications/unsubscribe-auth/ACADPOWOPP7O6PGFJKKY3Z3YWLNSBAVCNFSM4GRSXWZ2U5DIOJSWCZC7NNSXTN2JONZXKZKDN5WW2ZLOOQ5TCOJXGUYDQNJYGUYA . You are receiving this because you were assigned.Message ID: @.***>

oec commented 6 months ago

I share your concern. And as I said in a different thread: Why should anybody trust the contents of the keyserver?

If I understand your suggestion correctly, upspin should maintain a file (keylist) with (name, pubkey)-pairs in a user's (upspin-)root directory and notify the user on changes of those keys, f. e. during file creation. I like that idea and suggest to add pinning: When a public key of a user is prior knowledge (f.e. retrieved via a trusted channel), even before the initial lookup of a user's key and hosts on the keyserver is executed, one could pin the public key in that keylist.

Changing a public key in that keylist will require the same choreography as with changed entries in Access files, though.

n2vi commented 6 months ago

sounds good to me

On Sun, Mar 3, 2024, 15:38 Özgür Kesim @.***> wrote:

I share your concern. And as I said in a different thread: Why should anybody trust the contents of the keyserver?

If I understand your suggestion correctly, upspin should maintain a file (keylist) with (name, pubkey)-pairs in a user's (upspin-)root directory and notify the user on changes of those keys, f. e. during file creation. I like that idea and suggest to add pinning: When a public key of a user is prior knowledge (f.e. retrieved via a trusted channel), even before the initial lookup of a user's key and hosts on the keyserver is executed, one could pin the public key in that keylist.

Changing a public key in that keylist will require the same choreography as with changed entries in Access files, though.

— Reply to this email directly, view it on GitHub https://github.com/upspin/upspin/issues/614#issuecomment-1975399496, or unsubscribe https://github.com/notifications/unsubscribe-auth/ACADPOWMX52X3DLRSE2YD7TYWOX63AVCNFSM4GRSXWZ2U5DIOJSWCZC7NNSXTN2JONZXKZKDN5WW2ZLOOQ5TCOJXGUZTSOJUHE3A . You are receiving this because you were assigned.Message ID: @.***>

n2vi commented 5 months ago

Thinking about this some more, I believe we should drop keyserver entirely and just go with a local cache of keys, much like .ssh/known_hosts. Concretely, here's the proposal:

Alongside the familiar $HOME/upspin/config will be a new file $HOME/upspin/known that lists usernames, servers, and public keys like this:

@.*** upspin.n2vi.net

p256

37328296944195073094147476081262281031954017557547476862287757547130566283616

63228633909623339196586434006117109419848109010997955593880491707935365466815

@.*** upspin.codeblau.de

p256

90688434547434670258814756206511756771655112727882642215530754582156744348646

40622479448254714088287737020424038500256267376277348918107227383407159551381

The first time I run the updated upspin command, it will automatically create this file, populating names from whatever top-level directories are in my upspinfs mount and in my Access files and taking information from the old keyserver. From then on, the file is used for all my upspin activity. It is updated by cut-and-paste manual editing, based on text emailed to me or that I observe on web pages or whatever other channel I trust.

As a means of watching for pranksters, I will publish my upspin/known file to my upspin tree as @.***/Pub/known and will set up a watcher for similar files in my peers' directories. Any anomalies will raise an alert that I'll investigate directly.

When someday I change my key with upspin rotate, I'll email the new key to my peers and offer hints on how they should paste it into their upspin/known file and how they should upspin share to update existing direntries to use the new key. In practice, key changes are rare, though I anticipate a burst next year when standardized PQC encryption arrives.

Thoughts, anyone? If it seems agreeable, I'll file a github/upspin issue.

oec commented 5 months ago

Thus spake Eric Grosse @.***):

Thinking about this some more, I believe we should drop keyserver entirely and just go with a local cache of keys, much like .ssh/known_hosts. Concretely, here's the proposal:

Alongside the familiar $HOME/upspin/config will be a new file $HOME/upspin/known that lists usernames, servers, and public keys like this:

@.*** upspin.n2vi.net

p256

37328296944195073094147476081262281031954017557547476862287757547130566283616

63228633909623339196586434006117109419848109010997955593880491707935365466815

@.*** upspin.codeblau.de

p256

90688434547434670258814756206511756771655112727882642215530754582156744348646

40622479448254714088287737020424038500256267376277348918107227383407159551381

I suggest to use a more succinct encoding, that "fits" on a single line:

***@***.*** hostname p256 <base64 encoded pub.X:pubY>

That makes it easier to grep for entries, and copy them around.

The first time I run the updated upspin command, it will automatically create this file, populating names from whatever top-level directories are in my upspinfs mount and in my Access files and taking information from the old keyserver. From then on, the file is used for all my upspin activity. It is updated by cut-and-paste manual editing, based on text emailed to me or that I observe on web pages or whatever other channel I trust.

As a means of watching for pranksters, I will publish my upspin/known file to my upspin tree as @.***/Pub/known and will set up a watcher for similar files in my peers' directories. Any anomalies will raise an alert that I'll investigate directly.

The @.***/Pub/known file would need to be readonly, for this to work. Do we leave this up to the owner to make sure he/she doesn't accidentally make the file writable by others?

When someday I change my key with upspin rotate, I'll email the new key to my peers and offer hints on how they should paste it into their upspin/known file and how they should upspin share to update existing direntries to use the new key. In practice, key changes are rare, though I anticipate a burst next year when standardized PQC encryption arrives.

Thoughts, anyone? If it seems agreeable, I'll file a github/upspin issue.

I like the idea of having a local, manually curated "known" file very much. Also, the prospect of removing the keyserver entirely and therefore simplify the design is quite nice, and also from robustness and attack surface perspectives.

For convenience, we could add key management to the upspin command (like add, rm, bulkimport), which would handle duplicate entries etc.

Cheers, Özgür

n2vi commented 5 months ago

I suggest to use a more succinct encoding, that "fits" on a single line:

***@***.*** hostname p256 <base64 encoded pub.X:pubY>

That makes it easier to grep for entries, and copy them around.

My example came from the upspin.pubkey file (or, equivalently, keyserver log) for ease of manually comparing. Anyway, we can expect longer keys coming soon for the hybrid Kyber768 ed25519 KEM that will likely need to become the new default, so there is not much hope of keeping pubkeys to a single line of text.

As a means of watching for pranksters, I will publish my upspin/known file

to my upspin tree as @.***/Pub/known and will set up a watcher for

similar files in my peers' directories. Any anomalies will raise an alert that I'll investigate directly.

The @.***/Pub/known file would need to be readonly, for this to work. Do we leave this up to the owner to make sure he/she doesn't accidentally make the file writable by others?

Yes, by "publish" I meant use the integrity-only packing method "eeintegrity" that leaves the file signed by me but readable by anyone, and the directory's Access file would restrict the Pub directory to write permission only for me. This is uncommon enough that I ought to do a separate doc about it when the time comes.

Note that even if someone overwrote the copy in Pub, that wouldn't change the master local version used by upspin software. But it likely would lead to one of those alerts I mention!

Also left unsaid was that I have the opportunity to prune out some of the entries before publishing, if I wish to hide some of my peers. I don't consider that a comprehensive privacy plan, but it may help in special circumstances.

Apologies for all the *** in the examples. It wasn't that way when I mailed to the group, only after the reflector, but such is the way of half-measures from well-meaning privacy folks. I'm pretty sure that publishing all email addresses in keyserver log has not yet led to disaster.

oec commented 5 months ago

Thus spake Eric Grosse @.***):

My example came from the upspin.pubkey file (or, equivalently, keyserver log) for ease of manually comparing. Anyway, we can expect longer keys coming soon for the hybrid Kyber768 ed25519 KEM that will likely need to become the new default, so there is not much hope of keeping pubkeys to a single line of text.

I guess we cross that bridge when we get there. Until then, a succinct, single-line entry seems to me the preferable.

to my upspin tree as @.***/Pub/known and will set up a watcher for similar files in my peers' directories. Any anomalies will raise an alert that I'll investigate directly.

The @.***/Pub/known file would need to be readonly, for this to work. Do we leave this up to the owner to make sure he/she doesn't accidentally make the file writable by others?

Yes, by "publish" I meant use the integrity-only packing method "eeintegrity" that leaves the file signed by me but readable by anyone, and the directory's Access file would restrict the Pub directory to write permission only for me. This is uncommon enough that I ought to do a separate doc about it when the time comes.

OK, that makes sense then.

Also left unsaid was that I have the opportunity to prune out some of the entries before publishing, if I wish to hide some of my peers. I don't consider that a comprehensive privacy plan, but it may help in special circumstances.

As a first step, to remove the requirement of a keyserver from the design entirely, a pruned known file seems to be sufficient to me.

In the long run, however, we might find a proper solution for a privacy preserving way to publish or query the known-file, that guarantees that we do not disclose user names.

Cheers, Özgür

n2vi commented 5 months ago

I'm not strongly committed to any particular pubkey format. If whoever implements this change wants single-line, ok by me. I hope they'll change keygen to match, so we only have one format.

Also, in addition to normal unit tests let's test the new code with some ordinary, non-expert users to confirm they can add, change, email/Signal, and delete keys.

n2vi commented 5 months ago

Among the peers that I need to notify when I change my key is every upspinserver that I use. It would be unworkable if that meant manual action by a human administrator so we will have to provide a signed key update command in the server.

Sending the update command needs access to old and new keys, potentially with robust queuing at the client for servers that are temporarily down, not to mention somehow maintaining a complete list of all servers I use.

Your DNS SRV keyserver record idea is sounding appealing in comparison!

n2vi commented 5 months ago

If by convention my upspinserver publishes its upspin/known file, and if the server is at upspin.{mydomain} then could we remove the need for keyservers entirely?

But that only works for email addresses on custom domains like eric@n2vi.com not like grosse@gmail.com. A look at key.upspin.io/log shows a third of upspin names are on gmail.com. I wish I'd thought of this earlier, or that our original plan of leveraging a common certificate transparency site had come to pass.

oec commented 5 months ago

Thus spake Eric Grosse @.***):

Among the peers that I need to notify when I change my key is every upspinserver that I use. It would be unworkable if that meant manual action by a human administrator so we will have to provide a signed key update command in the server.

Sending the update command needs access to old and new keys, potentially with robust queuing at the client for servers that are temporarily down, not to mention somehow maintaining a complete list of all servers I use.

Your DNS SRV keyserver record idea is sounding appealing in comparison!

[...]

If by convention my upspinserver publishes its upspin/known file, and if the server is at upspin.{mydomain} then could we remove the need for keyservers entirely?

But that only works for email addresses on custom domains like @. not like @. A look at key.upspin.io/log shows a third of upspin names are on gmail.com. I wish I'd thought of this earlier, or that our original plan of leveraging a common certificate transparency site had come to pass.

So, to summarize:

1a) For user-names in user-controlled domains, discovery of upspin support and servicing hosts can be done via DNS.

1b) For user-names in non-user-controlled domains, discovery of upspin support and servicing hosts requires a service under a known domain, such as upspin.io.

2) A user's keyring of known (user name, public key)-pairs is published under a fixed location in the user's namespace (no need for a dedicated keyserver).

3) The content of that known-file is at the owner's discretion, privacy of the content is not enforced.

So, some form of keyserver would be needed to provide support for 1b), at least for some period of time.

But, (to throw an idea to explore the design space, bear with me here), maybe this is a good opportunity and use case to use the GNU Name System? https://www.rfc-editor.org/rfc/rfc9498.html

"The GNU Name System is our contribution towards a decentralized and censorship-resistant domain name resolution system that provides a privacy-enhancing alternative to the Domain Name System (DNS)."

Basically, this would allow all users (including of type 1b) to become of type 1a - everybody gets its own zone to serve, in a privacy-preserving manner, with the zone and its entries cryptographically protected.

In practice, I could either give you my @., public key) for normal DNS-lookups, or the @., public key, zone public key) for the lookups within GNS. The later would allow any user with adresses under gmail.com et al. to setup their own GNS-zone with all required entries.

This would also provide a path of slow transition from the exisiting model to a fully decentralized model of operation.

WDYT?

Cheers, Özgür

oec commented 5 months ago

... to add to the train of thought: GNS could actually serve all the upspin-metadata per individual: A user's zone would provide the SRV- and A-records for the upspin-servers and could also serve the public keys of users itself, if wanted.

[update]

Alas, I just learned that adding GNS-support to upspin as a client in pure go would require implementing the underlying distributed hash table technology that GNS is build on top of. Sounds like similar in complexity as upspin itself, so rather not an option.

n2vi commented 5 months ago

I defer to Dave Presotto on DNS.