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

Support multiple GPG keys #6

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

MarkKoz
Copy link

@MarkKoz MarkKoz commented Jan 27, 2022

This feature relies on getting a key ID from SETKEYINFO, so I assume it only works when --no-allow-external-cache is not set as a GPG agent option. This seems to be a reliable way to get a key ID except for this case. One aspect I am unsure of is what determines that format of the ID provided by the agent. The documentation states that it could be in 3 different forms. In practice, for me, it has used the n/key-grip format. To help the user figure out the exact value, a balloon notification with the key info string is shown if a matching entry cannot be found.

When the key info is available, the entry is looked up by comparing the username to the key info. Due to the nature of the key ID, it seems unlikely that there'll be a false positive match for some other unrelated entry. I figured allowing the title to be anything is nice for flexibility, but requiring "GPG" in the title too could be implemented if desired.

If for some reason the key info is cleared, the plugin instead looks up an entry by title using "GPG" as the search string. Then, it looks for the entry whose username is "default" (case-insensitive). An existing entry could be set as default by the user by using a password field reference for the default entry.

Some error handling has been added so that the GPG agent doesn't hang waiting for a response if the plugin is unable to find a suitable entry or crashes before the pin can be sent to the agent.

Comment on lines +63 to +64
var message = $"Unable to find entry with the search string {param.SearchString}.";
ShowBalloonNotification(message);
Copy link
Author

Choose a reason for hiding this comment

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

This message is unfortunately vague since it does not state which fields of the entry are being searched. Furthermore, the predicate can perform some arbitrary check; what it checks for cannot be inferred at this point. I think that for more specific messages, the error would have to be handled in all the higher-level wrappers like GetByUserName, but that might feel like duplicate code.

@djherbis
Copy link
Owner

Hey I'm still reviewing this! Was trying to fix my local build environment (Microsoft has gone and changed their docker images).

Once I've got it building, I'll test it out. Thanks!

@MarkKoz
Copy link
Author

MarkKoz commented Feb 1, 2022

Yeah I had the same problem. IIRC I did manage to change it to the right base image, but then it complained that it's not supported by my platform. This is probably because I needed to switch to Windows container mode, but that requires a system restart so bleh. I just opened Visual Studio and built it that way.

Also, I realised that I forgot to update the README with new usage instructions. I suppose I will wait for your review in case something needs to be changed before I update the instructions.

Copy link
Owner

@djherbis djherbis left a comment

Choose a reason for hiding this comment

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

I got my build working locally, the remote one is broken because of travis deciding to stop being nice to open source projects and force us to use their paid model. I'll move to github actions eventually.

I found this command:
gpg-connect-agent "keyinfo --list" /bye

Which prints out the keygrip, we should include that in the documentation updates.

{
PwEntry entry = string.IsNullOrWhiteSpace(keyInfo)
? db.GetByTitleAndUserName("GPG", "DEFAULT")
: db.GetByUserName(keyInfo);
Copy link
Owner

Choose a reason for hiding this comment

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

We may want to fallback to the 'default' entry to support existing use cases. I use a blank username for the 'default' entry personally.

Copy link
Owner

Choose a reason for hiding this comment

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

I think we need GetByUserName to require GPG as the Title still.

Main reason will be for security. Currently only the GPG key is being 'exposed' over the gpg pinentry agent. Technically any program on your system though can fake the pinentry protocol and ask for the password (we don't have a way to detect that it's a legit request).

Therefore we don't want arbitrary keys to be able to be requested.

Copy link
Author

Choose a reason for hiding this comment

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

@djherbis

We may want to fallback to the 'default' entry to support existing use cases.

Can you elaborate on what you mean? Are you referring to the previous behaviour that just gets the first "GPG"-named entry?

I think we need GetByUserName to require GPG as the Title still.

I agree. You made an excellent point. I never felt strongly about making the name flexible anyway.

try
{
IEnumerable<PwEntry> entries = GetAll(param);
PwEntry entry = predicate is null ? entries.First() : entries.First(predicate);
Copy link
Owner

Choose a reason for hiding this comment

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

FirstOrDefault() will let you handle the 'not found' case nicer than an exception.

Copy link
Author

Choose a reason for hiding this comment

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

Do you think it's significantly nicer to compare against null than to catch an exception? I am more in the habit of "easier to ask for forgiveness than for permission."

@MarkKoz
Copy link
Author

MarkKoz commented Feb 14, 2022

I'll move to github actions eventually.

Maybe if I have some time, I could help out with that as well. :)

Which prints out the keygrip, we should include that in the documentation updates.

I was using gpg --with-keygrip --list-secret-keys, which shows more info about keys (such as the descriptions), making it easier to find the right keygrip. This is what the documentation I linked to also suggests.

My concern with keygrips is specifically regarding the prefix. I haven't found a way to ask GPG for this prefix or any more documentation on what it means (I didn't look too hard). I'm not sure how to help users find this besides making them try to use the key and looking at the name in the error notification from KeePass.

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.

2 participants