Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NIP-22 Key Migration #1056

Draft
wants to merge 15 commits into
base: master
Choose a base branch
from

Conversation

vitorpamplona
Copy link
Collaborator

@vitorpamplona vitorpamplona commented Feb 16, 2024

This is a key migration procedure that simply formalizes how we migrate keys today: via waiting for confirmations by friends of the key.

There is no automated migration procedure, no proofs of control, and no forced key derivation paths.

The goal is to offer a way to migrate current keys to new key schemes so that we can introduce the idea of key derivation to most users today. I strongly believe that many potential identity management proposals are held back by their need to make it work with current keys. This establishes something everyone can implement that can get us out of this hole we put ourselves into.

Read here

@vitorpamplona vitorpamplona marked this pull request as draft February 16, 2024 16:17
Copy link
Member

@staab staab left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't answer some important questions:

  • What if the key has been lost, not leaked, and they can't publish the event?
  • How are "close acquaintances" identified? This isn't a straightforward web of trust problem, because you might not follow anyone who follows the original pubkey.

I'm all in favor of social key rotation but a lot more details need to be filled out before it becomes possible.

@vitorpamplona
Copy link
Collaborator Author

vitorpamplona commented Feb 16, 2024

What if the key has been lost, not leaked, and they can't publish the event?

Lost keys get lost forever. This is not a key recovery protocol. It's just for migrations.

How are "close acquaintances" identified?

Web of Trust

you might not follow anyone who follows the original pubkey.

You will have to wait until somebody you follow makes the change or you might need to get more information from outside of Nostr.

Again, this is nothing different than what users already do today. Clients don't actually need to do anything automatically. They just need to present information and wait for the user to have the confidence to migrate.

@basantagoswami
Copy link
Contributor

Need to extend the NIP by adding the following things:

  • An event for the list of people that the pubkey owner considers to be trustworthy (maybe open timestamped)
  • An event for ACK/NACKing the kind: 18 events

Leaving these things up for interpretations will lead to incompatibility

@vitorpamplona
Copy link
Collaborator Author

vitorpamplona commented Feb 17, 2024

An event for the list of people that the pubkey owner considers to be trustworthy (maybe open timestamped)

It doesn't work. This just opens another attack vector where the person that steals the key recommends the wrong keys.

Ack/Nack

Acks and Nacks are not needed. Just track the contact list instead.

Leaving these things up for interpretations will lead to incompatibility

There are no ways to be incompatible in this NIP. Clients can recommend different actions and review systems and that's all good. No matter what happens, everybody else can see the final changes in contact lists.

@melvincarvalho

This comment was marked as spam.

@vitorpamplona
Copy link
Collaborator Author

The presence of one or more kind:18s, no matter who writes it, declares the key to be out of use, unreliable, unsafe and potentially stolen: No event, past and future, from this key can be trusted anymore.

Sounds dangerous. One bad click and you lose your identity forever. Leave your phone on a table, and you risk losing everything.

Yep, clients need to put some warnings. But this is the same case for any migration scheme. Once you start there is no way back.

@gzuuus
Copy link
Contributor

gzuuus commented Feb 17, 2024

I actually like the passive approach you show, so that clients are not forced to take actions on behalf of their users, just warnings and options in the ux.
The approach is actually the same as I proposed in #1032, the main difference is the kind:1776 instead of kind:18 and that you need to complement this event with a proof that gives veracity to the rotation event.
In #1032 there are two possibilities, as I have respected all of pablo's previous work, but basically the proofs you can provide are a proof of the event published by the master key, where the user publishes kind:1776 with his master key, and the same kind:1776 with the subkey, but this time adding the id of the event using an e tag pointing to the event published by the master key. In the case of pablo's rotation, open timestamps are used in these events, and you get proof of who published first.
From my point of view I like your proposal, but I think it is simplistic when dealing with a critical event like key rotation, I think for the protocol to be more robust clients and users need to have proofs that are easily verifiable and difficult to crack, then they can make the best decision with the minimum of headache.

@vitorpamplona
Copy link
Collaborator Author

The approach is actually the same as I proposed in #1032, the main difference is the kind:1776 instead of kind:18 and that you need to complement this event with a proof that gives veracity to the rotation event.

Yep. My issue with any proof is that they quickly become attack vectors. If we had provable derived keys for everyone in Nostr from the beginning, that would have worked better. But we don't. Assigning a master key to today's keys is dangerous because anyone can write messages in the past and even hide them until the attack is ready. Trusting the proof becomes a problem.

So, I think we need an intermediary key migration procedure where we can move users to key schemes that might offer additional proof (master key) options. This PR is that intermediary option. :)

@gzuuus
Copy link
Contributor

gzuuus commented Feb 17, 2024

I understand, but I think that with your approach the process of verifying whether a rotation event is valid or not becomes difficult to distinguish, and therefore less reliable and expensive. It is true that relying on proofs is something that can introduce some attack vectors, but the absence of them I think makes the process expensive in terms of ability to distinguish whether a rotation event is trusworthiness or not.
In #1032 I introduced the concept of social proof, which from my point of view is interesting in terms of the reliability it offers, it defines a list of keys that can cast a vote reacting to the rotation event, the verdict of these keys is considered trusted because it uses web of trust and the social graph of each one. If an attacker publishes a rotation event that requires social proof and designates random keys it can be easily identified as untrusted. The only thing that may be problematic with this is that first time users do not have a web of trust, but I think it is not problematic since a rotation event is expected to be infrequent, and not at the beginning.

@vitorpamplona
Copy link
Collaborator Author

vitorpamplona commented Feb 17, 2024

Sure, but the social proof defined in #1032 only works if the key has a master key pair, which Simple Keys / current keys don't and if somebody has access to them today can easily create one.

I am a firm believer that most keys in Nostr have leaked already. My own key is probably out there somewhere. Attackers are just waiting for #1032 to become a reality and start creating those secure checkpoints and master keys before users even take notice.

@gzuuus
Copy link
Contributor

gzuuus commented Feb 17, 2024

Sure, but the social proof defined in #1032 only works if the key has a master key pair, which Simple Keys / current keys don't

Why? as long as the user has web of trust and a recognizable social graph anyone can use this proof.
In any case, how do you imagine we can make the process of validating a valid key rotation more affordable, and reliable?

@vitorpamplona
Copy link
Collaborator Author

vitorpamplona commented Feb 17, 2024

Why? as long as the user has web of trust and a recognizable social graph anyone can use this proof.

If you rely on Web of Trust, then you don't need proofs. It's about trust on top of everything else. Sure, proofs are a datapoint in the process, but because the proofs themselves can be faked (that's why you need the web of trust on #1032 ), the proofs can't be used to make any trust assessment. In fact, they can be used to diminish the need for a web of trust assessment. They serve as a mere conversation starter, which is the same kind:18 does in this PR. The proofs are just confusing everyone.

Let's say an attacker has my key right now. The attacker creates an open timestamped kind:1775 event before I do. Then the attacker creates its own kind:1776 pointing to a key only he controls. But it does that without broadcasting to the network. At the same time, the attacker starts to create a story (a set of nostr events) that will be sent to my friends in Nostr in an opportune time. They are all going to be timestamped, but sent later. Remember the attacker has full access to my keys and can create any event, in the past and present, and send these events only to that single person in ways that I wouldn't even notice.

For instance, the attacker can easily create DMs from me telling each of my closest friends that I will be rotating to a new key, wait the 60 day period, and then send them all. Then send one today referencing those DMs saying that it's all good: "I am just doing what I told I would be doing 60 days ago. I am sure you were too busy to see these messages, but here is a reminder". Then add a couple more public events discussing the same transition that ONLY those target friends will see and you have a convincing story that my friend doesn't need to call me to check. The automatic migration then goes through and suddenly the Web of Trust get tricked into accepting the attacker and people start following the new key.

All of that can happen in this PR as well. But here, the attacker can't use Nostr identity management proofs to decrease the need for the social verification off-nostr.

@vitorpamplona
Copy link
Collaborator Author

Hopefully, with this PR focusing on Web of Trust, we can get to a point where new key-controlling schemes can do these migrations without any web of trust component. Those are the proofs that make sense to have.

@arthurfranca
Copy link
Contributor

Liked this part "Clients SHOULD use Generic Repost (kind:16) with a stringified version of the kind:18 to warn followers and guarantee its retention in as many relays as possible." What I don't like is that kind 18 is already used here xD~ though I could change it.

If I see someone I follow and trust holding the kind:18 copy with an interface saying: "Hey, Bob says it's changing his profile to Bob X and your friend Joe confirms it is true. Do you want to follow the new profile?", I would click "Yes" button.

The kind:18 alone can't be trusted.

@vitorpamplona
Copy link
Collaborator Author

The kind:18 alone can't be trusted.

Obviously. Maybe I need to make this more clear in the text. It only works because somebody is validating it outside of Nostr.

@arthurfranca
Copy link
Contributor

Yeah I guess it is obvious I was just saying what I understood Hhehe
The thing that upon seeing a kind:18, the client can check client user's follow list to see if some of their follows have already followed the new profile could also show a message like the one on my above comment.

Easy to implement. On the other hand #1032 is soooooooo big of a read with like 4 new kinds and 2 time windows =0

@arthurfranca
Copy link
Contributor

@vitorpamplona If I got it right, you are recommending clients to actively look for:

  1. kind:18s from client user's follows, then each time one is found, look for kind:3s from follows with a matching p tag to see if someone the client's user knows has followed the new pubkey OR;
  2. kind:16s (reposts) with #k=["18"] from client user's follows. A repost is already a recommendation from a follow, so no need to check kind:3s

Maybe it is better to recommend just one flow and 2) feels simpler.

For that, reposts could be an automatic client action after following anyone that signals on kind:0 metadata which one was their previous pubkey.

For example, if there is a previous_pubkey field on the metadata of someone I've just followed, my client will look for the previous pubkey's kind:18 and if it finds one it will repost it.

Then my follows would receive the repost.


I mean, the process could start from the new account. The user would just paste the old privkey > then client would publish the kind:18 to the new account's relays (old account's relay list can't be trusted) > then client would set new account's previous_pubkey to the old privkey.

It would be great if #539 was a thing so that the kind:18 couldn't be deleted by the author just by using it instead of having to say that "Supporting Relays [...] MUST reject Event Deletion requests of kind:18s."

@vitorpamplona
Copy link
Collaborator Author

vitorpamplona commented Feb 17, 2024

On the other hand #1032 is soooooooo big of a read with like 4 new kinds and 2 time windows =0

That's what's good about this. Having to wait 60 days from seen (which means clients MUST have a local DB) is a unique ask.

If I got it right, you are recommending clients to actively look for:

I think the flow will depend on the client. I suspect most clients can easily add a kind:18 filter to their usual (let's download my follow list posts subscription). Amethyst downloads kind:16 for all follows all the time, so that can bring kind:18s as well. From there, Amethyst will open a screen to warn the user and start downloading the follow's contact lists and if a follow already made the change, show it to the user. If there are multiple kind:18s, we will show which follow went for which pubkey.

A repost is already a recommendation from a follow, so no need to check kind:3s

Not really. The repost just warns followers. It shouldn't mean that the person has decided if it is valid or not. The truth can only come from contact lists.

then client would publish the kind:18 to the new account's relays (old account's relay list can't be trusted)

Good point, the client should post everywhere, just like NIP-65 changes.

It would be great if #539 was a thing so that the kind:18 couldn't be deleted by the author just by using it instead of having to say that "Supporting Relays [...] MUST reject Event Deletion requests of kind:18s."

Agree.

Adds clarification that this requires web of trust validation
Adds k-tag to generic reposts
Adds optional behavior to client.
@gzuuus
Copy link
Contributor

gzuuus commented Feb 18, 2024

Easy to implement. On the other hand #1032 is soooooooo big of a read with like 4 new kinds and 2 time windows =0

I really agree, my intention was to respect the previous work of the previous most accepted pr to introduce secure identities, and master/subkey roles. But different points of how to deal with key rotation seems complicated and inconvenient to me (I guess that's why it has never been implemented properly). However I like this proposal because of the simplicity and it can make #1032 smaller, and focus only on secure identity management. For me the fundamental idea behind #1032 is to have an identity based on a subkey, and master key as a source of truth, which is mostly used to make relevant public announcements about a subkey, and can be stored cold.

Talking about the kinds used I only introduced kind:1775 to create secure checkpoints, the others I reused and expanded a bit to fit the use case.
The 30 day time window is recommended only if it is necessary to migrate to a fresh master pair, and acts as this proposal mentions (just look at the reactions emitted by the designated users), it is a recommended time to take a vote on the trustworthiness of a new identity in a 'serious' way.

@gzuuus
Copy link
Contributor

gzuuus commented Feb 18, 2024

@vitorpamplona What about the possibility of adding an tag "e" in the event to point to the key rotation event issued by a master keypair? Simply adding this optional tag would make this proposal compatible with my secure identity model.

In my proposal if a subkey of a secure identity is compromised the master keypair does a subkey rotation announcement event, and the subkey should do the same, but also point to the masterkey pair event.

@vitorpamplona
Copy link
Collaborator Author

@vitorpamplona What about the possibility of adding an tag "e" in the event to point to the key rotation event issued by a master keypair? Simply adding this optional tag would make this proposal compatible with my secure identity model.

In my proposal if a subkey of a secure identity is compromised the master keypair does a subkey rotation announcement event, and the subkey should do the same, but also point to the masterkey pair event.

I think we can add those when master key pairs become available. I am not convinced a master key pair rotation should reuse kind18s. They could have their own method to avoid the Web of Trust recommendation here.

@gzuuus
Copy link
Contributor

gzuuus commented Feb 18, 2024

Yes, absolutely, the master key rotation comes with a revocation certificate and a checkpoint. I've also been thinking about simplifying #1032 by using the scheme you suggest here, as it's arguably a drop-in replacement for the kind:1776 events, simplifying the process and not requiring time windows.

I've also been thinking that it would be interesting to be able to signal a trust level on a user's new keys, for example when a user issues their kind:16 in response to a key rotation event, or when the user adds the new key to their kind3. Maybe the gpg trust levels could work here:

  • Ultimate: Used for your own keys. Any message signed with that key will be trusted.
  • Full: Used for keys you trust to sign other keys.
  • Marginal: Makes a key show as valid if it has been signed by at least three keys which you set to 'Marginal' trust-level.
  • Unknown: The default state, meaning no ownertrust has been set yet.
  • Undefined: Has the same meaning as 'Unknown' but differs, since it has actually been set by the user.
  • Never: The key is not trusted, and you actively state to never trust the key in question

@vitorpamplona
Copy link
Collaborator Author

and not requiring time windows

That alone is a huge simplification to me.

Maybe the gpg trust levels could work here..

Those trust levels make sense. But should that be in the NIP or a client's feature? I tend to minimize the specs and let relays/clients figure out the best way to implement each NIP. I think we could have a client offering such levels and if they become a common way to represent it, then they can turn that part into a NIP (or extend this NIP).

@arthurfranca
Copy link
Contributor

@vitorpamplona Saw your answer but have you considered the previous_pubkey part?

It would be added to any new account's kind:0 that wants to point to a previous account.

Upon an user following the new account with such metadata field, even if they didn't know the old one, their supporting client would then fetch on the new account's write relays the kind:18 event signed by the previous account and choose to repost it.

This way the reposting mechanism would keep working far in the future each time someone follows the new account. Even if the kind:18 event is very old, it would still be reposted. Well, atleast while the kind:18 is kept by the write relays.

[...] their supporting client would then fetch on the new account's write relays the kind:18 event signed by the previous account [...] Well, atleast while the kind:18 is kept by the write relays

Hmm, maybe better if instead the client fetchs the kind:16 signed by the new account. It would be easier to keep this event fresh on relays by republishing a new one from time to time.

@vitorpamplona
Copy link
Collaborator Author

About the previous_pubkey, I am not sure if it's needed. Clients can search for kind:18s that p-tag the follow's key and repost it. Adding it to the metadata seems redundant.

But maybe there is a reason for the new key to sign where it came from.

@arthurfranca
Copy link
Contributor

Clients can search for kind:18s that p-tag the follow's key

Oh sorry you're right, although there can be many fake kind:18s p-tagging the key just to mess things.

Talking about another detail, after some time it may be a problem relying on an event signed by an abandoned account cause its client won't keep publishing the same kind:18 with an updated created_at and relays tend to delete old events.

Yeah, previous_pubkey isn't needed. The new account could publish the kind:16 with #k=["18"]. Its own client can look for the repost existence, cache the embedded kind:18 and keep refreshing the repost on relays. Other people clients could then rely on it to publish its own reposts after following the new account.

Just ideas, don't know.

@melvincarvalho

This comment was marked as spam.

@vitorpamplona
Copy link
Collaborator Author

I am not sure what's hard about it and why it needs to be mandatory. People already switch keys today in the same way with kind 1 posts and friends retweeting or replying to the post. It's the same thing, but now the client can help users navigate it.

They can keep doing the kind 1 texts to migrate as well. The existence of this NIP doesn't forbid people to migrate in the manual way.

@mikedilger
Copy link
Contributor

Since this is just for migrations, and not for recovery from a lost key, I think the interpretation of a kind-18 is far too strong:

... declares the key to be out of use, unreliable, unsafe, and potentially stolen: No event, past and future, from this key can be trusted anymore.

I would like to put out a new key with a kind-18, but I don't want people thinking my old key is not me anymore. I will have to post under both keys for some time as the community learns my new key.

@vitorpamplona
Copy link
Collaborator Author

vitorpamplona commented Feb 24, 2024

The reason for coupling migration with the deprecation of the current key is the uncertainty surrounding whether kind:18 was created by the rightful owner. Key migration schemes are an easy attack vector and can be exploited to seize control of a victim's keys and impersonate them to their contacts. Consequently, until the receiving user can verify that kind:18 was indeed intended by the owner, they cannot trust any messages originating from that key. DMs from both old and new keys attempting to convince the recipient of kind:18's authenticity cannot be trusted. The NIP is intentionally crafted to regard any instance of kind:18 as a potential attack on the owner rather than viewing such attacks as rare occurrences.

Remember, kind:18s might be selectively broadcasted to non-savvy users around the owner in order to get some initial buy-in and signal the trust in the migration to only then target everybody else. If selective broadcasting happens, Clients should scream this event out of their devices to let everyone know that something is up. If we allow users to assume good intentions in these migrations, we might be harming them instead.

I couldn't square those forms of attacks in this WoT-based migration scheme without coupling migration and deprecation of the key. But I am open to ideas.

@vitorpamplona
Copy link
Collaborator Author

vitorpamplona commented Feb 24, 2024

A different way to put this:

  • If you trust kind:18s, you don't need WebOfTrust confirmations.
  • If you don't trust kind:18s, you are also not trusting the key and all past and future events (at least temporarily).

@mikedilger
Copy link
Contributor

If I were an attacker and I had your old key, I wouldn't put out a kind-18. I would just use your old key directly. Therefore because this is possible, every message by everybody at all times must not be trusted???

@vitorpamplona
Copy link
Collaborator Author

If I were an attacker and I had your old key, I wouldn't put out a kind-18

You would if you could lock me out of my own account and fully control the conversations with my friends.

Therefore because this is possible, every message by everybody at all times must not be trusted???

No. I think kind:18 just requires more scrutiny than the other messages because if it succeeds it can block the owner from accessing the new key.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants