Skip to content
This repository has been archived by the owner on Jan 13, 2025. It is now read-only.

Keypair: implement clone() #26248

Merged
merged 2 commits into from
Aug 6, 2022

Conversation

ckamm
Copy link
Contributor

@ckamm ckamm commented Jun 27, 2022

Problem

Keypair::clone() was not implemented upstream in ed25519-dalek to force everyone to think twice before creating another copy of a potentially sensitive private key in memory.

See dalek-cryptography/ed25519-dalek#76

However, there are now 9 instances of

  Keypair::from_bytes(&keypair.to_bytes())

in the solana codebase and it would be preferable to have a function.

In particular since this also comes up when writing programs and can cause users to either start messing with lifetimes or discover the from_bytes() workaround themselves.

Summary of Changes

Add clone() to Keypair.

This patch opts to not implement the Clone trait. This avoids automatic use in order to preserve some of the original "let developers think twice about this" intention.

@mergify mergify bot added the community Community contribution label Jun 27, 2022
@mergify mergify bot requested a review from a team June 27, 2022 15:01
@mvines
Copy link
Contributor

mvines commented Jun 27, 2022

I see the utility but am concerned about using .clone() since that makes it very easy to misuse. Some options:

  1. .clone_if_you_really_must_but_please_dont()
  2. Mark the .clone() as unsafe to make it painful to use

@ckamm
Copy link
Contributor Author

ckamm commented Jun 27, 2022

How about we put the clone() impl in a separate file and force use sdk::signer::keypair_clone_if_you_must before it becomes available? That would make using it in tests more straightforward and would still stick out a lot.

Alternatively there could be an UnimportantKeypair that implements clone() ;)

@ckamm ckamm force-pushed the ckamm/clonable-keypair branch from 5b578ff to 7aa8c84 Compare June 27, 2022 17:38
@mvines
Copy link
Contributor

mvines commented Jun 27, 2022

How about we put the clone() impl in a separate file and force use sdk::signer::keypair_clone_if_you_must before it becomes available? That would make using it in tests more straightforward and would still stick out a lot.

Yeah, something like that sgtm!

@ckamm ckamm force-pushed the ckamm/clonable-keypair branch from 7aa8c84 to 90fff18 Compare June 28, 2022 11:55
@ckamm
Copy link
Contributor Author

ckamm commented Jun 28, 2022

@mvines Updated so you need to explicitly use a separate KeypairInsecureClone trait to use the function.

Copy link
Contributor

@mvines mvines left a comment

Choose a reason for hiding this comment

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

lgtm once CI is green

@ckamm ckamm force-pushed the ckamm/clonable-keypair branch from 90fff18 to 23d9ca2 Compare June 29, 2022 05:01
@stale
Copy link

stale bot commented Jul 10, 2022

This pull request has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs.

@stale stale bot added the stale [bot only] Added to stale content; results in auto-close after a week. label Jul 10, 2022
@ckamm ckamm force-pushed the ckamm/clonable-keypair branch from 23d9ca2 to ab9562f Compare July 13, 2022 08:41
@stale stale bot removed the stale [bot only] Added to stale content; results in auto-close after a week. label Jul 13, 2022
@mvines
Copy link
Contributor

mvines commented Jul 13, 2022

Looks like a rebase is needed to resolve the cargo audit issue in CI

@ckamm ckamm force-pushed the ckamm/clonable-keypair branch from ab9562f to 315b53e Compare July 13, 2022 18:27
ckamm added 2 commits July 19, 2022 10:56
This was not implemented upstream in ed25519-dalek to force everyone to
think twice before creating another copy of a potentially sensitive
private key in memory.

See dalek-cryptography/ed25519-dalek#76

However, there are now 9 instances of
  Keypair::from_bytes(&keypair.to_bytes())
in the solana codebase and it would be preferable to have a function.

In particular since this also comes up when writing programs and can
cause users to either start messing with lifetimes or discover the
from_bytes() workaround themselves.

This patch opts to not implement the Clone trait. This avoids automatic
use in order to preserve some of the original "let developers think
twice about this" intention.
@ckamm ckamm force-pushed the ckamm/clonable-keypair branch from 315b53e to 7e2a5ab Compare July 19, 2022 08:57
@stale
Copy link

stale bot commented Jul 31, 2022

This pull request has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs.

@stale stale bot added the stale [bot only] Added to stale content; results in auto-close after a week. label Jul 31, 2022
@ckamm
Copy link
Contributor Author

ckamm commented Jul 31, 2022

@mvines Please merge if you think this makes sense to have.

@stale stale bot removed the stale [bot only] Added to stale content; results in auto-close after a week. label Jul 31, 2022
@CriesofCarrots CriesofCarrots merged commit cf58640 into solana-labs:master Aug 6, 2022
@CriesofCarrots
Copy link
Contributor

Thanks for the contribution!

apfitzge pushed a commit to apfitzge/agave that referenced this pull request Aug 9, 2022
* Keypair: implement clone()

This was not implemented upstream in ed25519-dalek to force everyone to
think twice before creating another copy of a potentially sensitive
private key in memory.

See dalek-cryptography/ed25519-dalek#76

However, there are now 9 instances of
  Keypair::from_bytes(&keypair.to_bytes())
in the solana codebase and it would be preferable to have a function.

In particular since this also comes up when writing programs and can
cause users to either start messing with lifetimes or discover the
from_bytes() workaround themselves.

This patch opts to not implement the Clone trait. This avoids automatic
use in order to preserve some of the original "let developers think
twice about this" intention.

* Use Keypair::clone
xiangzhu70 pushed a commit to xiangzhu70/solana that referenced this pull request Aug 17, 2022
* Keypair: implement clone()

This was not implemented upstream in ed25519-dalek to force everyone to
think twice before creating another copy of a potentially sensitive
private key in memory.

See dalek-cryptography/ed25519-dalek#76

However, there are now 9 instances of
  Keypair::from_bytes(&keypair.to_bytes())
in the solana codebase and it would be preferable to have a function.

In particular since this also comes up when writing programs and can
cause users to either start messing with lifetimes or discover the
from_bytes() workaround themselves.

This patch opts to not implement the Clone trait. This avoids automatic
use in order to preserve some of the original "let developers think
twice about this" intention.

* Use Keypair::clone
@behzadnouri
Copy link
Contributor

What is the benefit of using a trait here?
Why not just add an unsecure_clone or mock_clone method to Keypair?
We have been using mock_clone already elsewhere in the code:
https://github.com/solana-labs/solana/search?q=mock_clone

The KeypairInsecureClone trait has the downside that if the file is already importing this trait then later on someone can erroneously add another keypair.clone elsewhere unknowingly that this is not right but the code compiles fine and there is no indication that they should avoid this.
It also does not help that method is just called .clone.

@ckamm ckamm deleted the ckamm/clonable-keypair branch August 17, 2022 13:39
@ckamm
Copy link
Contributor Author

ckamm commented Aug 17, 2022

There's no advantage to the trait. The goal was to gate the function via the suspicious-looking use. Making each callsite stick out sounds better. I wasn't aware of mock_clone.

@behzadnouri
Copy link
Contributor

@ckamm Do you agree this is introducing this risk:

The KeypairInsecureClone trait has the downside that if the file is already importing this trait then later on someone can erroneously add another keypair.clone elsewhere unknowingly that this is not right but the code compiles fine and there is no indication that they should avoid this.

@ckamm
Copy link
Contributor Author

ckamm commented Aug 17, 2022

@ckamm Do you agree this is introducing this risk:

The KeypairInsecureClone trait has the downside that if the file is already importing this trait then later on someone can erroneously add another keypair.clone elsewhere unknowingly that this is not right but the code compiles fine and there is no indication that they should avoid this.

Yes. Marking at each callsite would avoid accidental bugs like this and stick out more while reviewing.

@t-nelson
Copy link
Contributor

wondering why the solution here was to implement Clone and not eliminate those unsafe instances by Arc wrapping them?

ckamm added a commit to ckamm/solana that referenced this pull request Aug 25, 2022
ckamm added a commit to ckamm/solana that referenced this pull request Aug 27, 2022
ckamm added a commit to ckamm/solana that referenced this pull request Sep 7, 2022
ckamm added a commit to ckamm/solana that referenced this pull request Sep 12, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
community Community contribution
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants