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

Runtime check for persistent storage? #147

Closed
benwr opened this issue Oct 6, 2023 · 11 comments · Fixed by #150
Closed

Runtime check for persistent storage? #147

benwr opened this issue Oct 6, 2023 · 11 comments · Fixed by #150
Assignees

Comments

@benwr
Copy link

benwr commented Oct 6, 2023

After reading through #123, my understanding is that the keyutils backend (as well as the mock backend) doesn't persist its stored items to disk.

In my application, there's an encrypted database that's created on first run. My goal is to make it as hard as possible for unauthorized code to read from that database. But it's not acceptable from a UI perspective to have the user memorize or store the encryption key. So I randomly generate a key, store that key in the keyring, and rely on the OS to gatekeep access to it. Thus, the user is prompted when access to the database is required, but (at least on MacOS, which is the platform I'm most familiar with here) that prompt is for their OS password, which is much better UI-wise. (there's some additional hardening, aiming to ensure that the key and the db contents can't be read by a different process). The upshot here is that the user doesn't know the encryption key, and so the keyring needs to persist it.

One of the most useful parts of this crate is that it lets me abstract over the underlying OS capabilities, and I don't have to sprinkle cfg()s everywhere. Since, in some configurations, the default keyring doesn't persist its storage (mock and keyutils), it would be great if there was a simple way to check if the default credential store does or does not have this capability.

@brotskydotcom
Copy link
Collaborator

I agree this is a critical difference between keystores, @benwr, so thanks for this suggestion. To be clear: you are asking for an API-level way for the client to understand the persistence of the keystore, yes? As opposed to just clearer documentation on this point?

@benwr
Copy link
Author

benwr commented Oct 8, 2023

Yes; imo it would be really useful to have a way to check this property from code. Personally I think it would be nicest if it were a runtime check (maybe even one that can be implemented for custom keystores, though the obvious way to do that would be a breaking change), but a compile-time check would also be acceptable.

@brotskydotcom
Copy link
Collaborator

Sorry it's taken me so long to answer. I think probably the easiest way to do this would be to add some sort of characteristics API to the underlying keystores and then plumb that up as an extra cross-platform call. As long as it's an additive API it would just be a minor-version bump that was compatible with existing client code.

Do you have in mind anything other than persistence across reboots that you would want to know?

brotskydotcom added a commit to brotskydotcom/keyring-rs that referenced this issue Nov 26, 2023
brotskydotcom added a commit to brotskydotcom/keyring-rs that referenced this issue Nov 26, 2023
@brotskydotcom brotskydotcom self-assigned this Nov 26, 2023
@brotskydotcom
Copy link
Collaborator

@benwr Please take a look at #150 and see if it gives you want you need. You can do, for example:

if matches!(default::default_credential_builder().persistence(), crate::credential::CredentialPersistence::UntilDelete) {
    println!("The default credential builder persists credentials on disk!")
} else {
    println!("The default credential builder doesn't persist credentials on disk!")
}

@benwr
Copy link
Author

benwr commented Dec 3, 2023

@brotskydotcom Yeah, looks great!

@brotskydotcom
Copy link
Collaborator

OK, great, thanks, I'll release the fix.

@John-Nagle
Copy link

Oh, good, there's a way I can tell this. Thanks.

@ReactorScram
Copy link
Contributor

I can't figure out where it's exposed in the public API

@brotskydotcom
Copy link
Collaborator

Hi @ReactorScram, it's in the public, cross-platform CredentialBuilderApi, in particular the persistence method. So first get your hands on an instance of the CredentialBuilder trait, and then call persistence on that instance.

Assuming you are using the default credential builder, here's an example of how to access it:

if matches!(default::default_credential_builder().persistence(), crate::credential::CredentialPersistence::UntilDelete) {
    println!("The default credential builder persists credentials on disk!")
} else {
    println!("The default credential builder doesn't persist credentials on disk!")
}

Note that Entry structures don't expose the credential builder that constructed them, so you can't get persistence information from an entry. You have to know which credential builder you are using to get the information.

Hope this helps!

@ReactorScram
Copy link
Contributor

I did see default in lib.rs but it's not exposed as public. In my app I ended up writing Linux-specific and Windows-specific functions to check persistence of secret-service and the Windows equivalent. It feels like I did it wrong but I can't figure out any way to get the default builder using the public interfaces?

@brotskydotcom
Copy link
Collaborator

Great point! Not sure why this changed between v2 and v3, or whether v2 had this problem, but in any event I think it's a bug (see #197) and I will fix it right away! Thanks for bringing this to my attention!

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

Successfully merging a pull request may close this issue.

4 participants