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

Unsafe prompts #1126

Merged
merged 16 commits into from
Jul 24, 2020
Merged

Unsafe prompts #1126

merged 16 commits into from
Jul 24, 2020

Conversation

matejcik
Copy link
Contributor

partial fix for #1064

adds a setting called "unsafe prompts", available via trezorctl. When enabled, Keychain will not raise hard errors on non-conforming paths.

This necessitated (yet another) refactor of the Keychain, in which I took the time to also make a cleaner split on files.

The current Keychain implementation has a default curve set -- which is necessary, as previously we would take curve info from the namespace, and now we are being asked to derive paths that do not belong to a namespace.
The other option would have been to specify curve at every call to derive(), but that just seems spammy. We might come back to it in time though.

This way using "slip21" curve is not possible, so I had to introduce a separate derive_slip21() method and a corresponding slip21_namespaces argument. I don't particularly like this, but it seems best of bad options. If this grows cumbersome in the future, we could add a special keychain.slip21 accessor (and keychain.bip32 or keychain[curve_name] or something).


in addition, I removed the load_settings godfunction, in favor of individual setters.

@matejcik
Copy link
Contributor Author

@andrewkozlik this is hitting you because you're a code owner of storage, but I'd appreciate a review of the Keychain design

fwiw we might add you as a code owner of apps.bitcoin now, right?

Copy link
Contributor

@tsusanka tsusanka left a comment

Choose a reason for hiding this comment

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

Partial review: except core/src/apps/common/keychain.py, I will try to review that soon:tm:.

core/src/apps/debug/load_device.py Show resolved Hide resolved
core/src/apps/management/apply_settings.py Outdated Show resolved Hide resolved
core/src/apps/management/apply_settings.py Show resolved Hide resolved
core/src/storage/device.py Show resolved Hide resolved
core/src/storage/device.py Show resolved Hide resolved
core/src/storage/device.py Outdated Show resolved Hide resolved
@@ -132,6 +132,20 @@ def homescreen(client, filename):
return device.apply_settings(client, homescreen=img)


@cli.command()
@click.argument("allow", type=click.Choice(("on", "off")))
Copy link
Contributor

Choose a reason for hiding this comment

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

Here we use "on/off" and for passphrase for example we use trezorctl set passphrase enabled. We should unify those IMHO. Also "on" might be the default value? Maybe let's create a separate issue for that?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

#1130
I am not sure what to do here. I chose "on/off" instead of "enabled/disabled" because of a vague feeling that "set unsafe-prompts disabled" sounds like the less secure setting. But that's not very strong argument. Do you think we should change it to enabled/disabled?

Copy link
Contributor

Choose a reason for hiding this comment

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

I like on/off. I wouldn't mind having also "trezorctl set passphrase on". Anyway, since we are not sure I suggest to leave this as is and deal with it in #1130.

Copy link
Contributor

Choose a reason for hiding this comment

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

I chose "on/off" instead of "enabled/disabled" because of a vague feeling that "set unsafe-prompts disabled" sounds like the less secure setting.

I don't think on/off vs. enabled/disabled makes a difference in this respect. If a configuration sounds less secure it's more likely because of the name of the setting.

This is a power-user feature. With unsafe prompts enabled, Trezor will ask the user
to confirm possibly dangerous actions instead of rejecting them outright.
Use with caution.
"""
Copy link
Contributor

Choose a reason for hiding this comment

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

I suggest we display this description to the user in CLI. Also with a Continue? [y/N] to make this a bit more scarier :).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I considered that, but OTOH the scary warning is already displayed on the Trezor screen?

Copy link
Contributor

@tsusanka tsusanka Jul 23, 2020

Choose a reason for hiding this comment

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

Still - we can be more descriptive here. Exactly as you are in the comment.

Copy link
Contributor

@tsusanka tsusanka left a comment

Choose a reason for hiding this comment

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

keychain.py LGTM!

core/src/apps/common/keychain.py Outdated Show resolved Hide resolved
@tsusanka
Copy link
Contributor

Also let's add this to CHANGELOG.

self.curve = curve
self.namespaces = namespaces
self.slip21_namespaces = slip21_namespaces
self.restrict = restrict
Copy link
Contributor

Choose a reason for hiding this comment

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

I am not sure how much sense it makes to set restrict per Keychain instance, because right now it's considered a global setting. On the other hand I would like to see the Keychain class moving in a direction, where it will just be holding the derived nodes that it was authorized to hold, i.e. it shouldn't keep a copy of the seed at all.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Re restrict, it's reasonable that the Keychain would look at the setting directly; I'm honestly not sure why I did it this way originally. I'll remove it.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@matejcik
Copy link
Contributor Author

#1126 (comment) -> moving discussion to top level so that it doesn't get lost in a review comment:

Re the other idea, that's intriguiging, but I'm not sure if it makes sense implementation-wise.
For one, the requirement "allow namespace override" means that we would need special behavior for always keeping the seed anyway?
For two, that would mean that we would need to derive and store all the prefixes, which could often take more time than the requested derivation itself (e.g., consider a GetAddress call)

Perhaps something like keychain.narrow() could request that explicitly with no option of going back? To be used where applicable.

@andrewkozlik
Copy link
Contributor

Perhaps something like keychain.narrow() could request that explicitly with no option of going back? To be used where applicable.

Yeah, I am thinking something like that. Instead of the seed you'd be keeping the root node or one or more subnodes if you know beforehand that that's all you will be needing. Typically the Authorization objects would be doing that. BTW I am not suggesting we delve into this here, that's a separate issue, but it influences the way we think about the restrict parameter.

@matejcik
Copy link
Contributor Author

Added commits that allow Casa/Greenaddress namespaces without prompts. @tsusanka please take a look.

@matejcik matejcik requested a review from tsusanka July 24, 2020 11:33
Copy link
Contributor

@tsusanka tsusanka left a comment

Choose a reason for hiding this comment

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

Looks good. I am not sure whether it makes sense to limit paths for sign_message since there is a "coin prefix". We also added a check lately not to sign an empty prefix.

@tsusanka tsusanka added this to the 2020-08 milestone Jul 24, 2020
@matejcik
Copy link
Contributor Author

wrt naming:

in a meeting we decided to call the setting Safety checks, with possible levels being strict (default) and prompt (configurable by trezorctl). In the future we might add more granularity, e.g., to turn off prevtx streaming.

We decided to keep the naming as-is for this PR and for release. (This shouldn't even affect Connect, seeing as they won't be using this field at all.)

If we come up with something good, we can reword the dialogs relatively safely after the freeze.

For the next milestone (and for upcoming trezorlib release), I'm creating a separate issue for internal rewording.

Copy link
Contributor

@andrewkozlik andrewkozlik left a comment

Choose a reason for hiding this comment

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

Keychain LGTM, one nitpick.

raise FORBIDDEN_KEY_PATH

def _derive_with_cache(
self, prefix_len: int, path: paths.PathType, new_root: Callable[[], NodeType],
Copy link
Contributor

Choose a reason for hiding this comment

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

The name prefix_len doesn't tell me what the parameter is doing. How about calling it max_cache_depth? But the function is private so no big deal.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

i'm leaving that to #1135

@matejcik matejcik force-pushed the matejcik/unsafe-prompts-keychain-only branch from 39765eb to f80a0f9 Compare July 24, 2020 14:04
matejcik added 7 commits July 24, 2020 16:06
also make a cleaner distinction between keychain, seed, path

This enables using `unsafe_prompts`, because with the original code, if
there was no namespace match, we wouldn't know which curve to use.

For ease of implementation, we use a LRU cache for derived keys,
instead of the original design "one cache entry per namespace".

SLIP21 is now treated completely separately, via `slip21_namespaces` and
`derive_slip21` method.
If more slip21-like things come in the future, we can instead hang them
on the keychain: put a per-curve Keychain object accessible by
`keychain[curve_name].derive()`, and the majority usecase will just pass
around `keychain[curve_name]` instead of having to specify the curve in
every `derive()` call.

Or alternately we'll just specify the curve in every `derive()` call,
whichever seems more appropriate.
@matejcik matejcik force-pushed the matejcik/unsafe-prompts-keychain-only branch from f80a0f9 to 0ca9a54 Compare July 24, 2020 14:09
@matejcik matejcik force-pushed the matejcik/unsafe-prompts-keychain-only branch from 0ca9a54 to dde1945 Compare July 24, 2020 14:10
@matejcik
Copy link
Contributor Author

@tsusanka a quick review of dde1945 if you could?

@matejcik matejcik requested a review from tsusanka July 24, 2020 14:11
@tsusanka
Copy link
Contributor

👍 one comment. I have probably not done it via the review functionality, sorry.

@matejcik matejcik merged commit fdcb64a into master Jul 24, 2020
@matejcik matejcik deleted the matejcik/unsafe-prompts-keychain-only branch July 24, 2020 14:38
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.

4 participants