Skip to content

handle malformed PGP keys without crashing (fix #715) - #726

Merged
mssun merged 1 commit into
masterfrom
claude/issue-715-4eb2d0
Aug 2, 2026
Merged

handle malformed PGP keys without crashing (fix #715)#726
mssun merged 1 commit into
masterfrom
claude/issue-715-4eb2d0

Conversation

@mssun

@mssun mssun commented Aug 2, 2026

Copy link
Copy Markdown
Owner

Fixes #715.

Root cause

ObjectivePGP.readKeys(from:) raises an Objective-C exception (NSInvalidArgumentException: -[NSPlaceholderMutableString initWithString:]: nil argument) when it is given an armored block with headers but no body. Swift cannot catch an NSException, so the process aborts.

PGPAgent.initKeys() falls back to ObjectivePGP whenever GopenPGP rejects a key, and the settings screen requests the short key ID in viewDidLoad just to render the detail label. With such a key stored, opening the settings screen was an immediate crash. The keys live in the keychain and therefore survive uninstalling the app, which is why reinstalling did not help.

Of eight malformed key variants tested against PGPAgent, only the empty armor block crashed; garbage base64, truncated keys, dropped characters and plain text already produced proper errors.

A second problem prevented recovery: the "Remove PGP Keys" action was only offered when Defaults.pgpKeySource != nil. That default lives in the user defaults and is wiped by an uninstall, so after reinstalling the option was hidden while the broken key was still present.

Changes

  • New ObjectiveCExceptionCatcher in passKit which runs a block inside @try/@catch and converts an NSException into an NSError.
  • ObjectivePGPInterface routes key reading, decryption and encryption through it and reports AppError.keyImport, .decryption and .encryption instead of terminating. The user now sees "Cannot import the key.".
  • The removal of PGP keys is offered whenever keys are stored in the keychain, and it also clears the stored passphrases.
  • Regression tests for an empty armored key and a truncated key.

Testing

  • bundle exec fastlane test equivalent run locally: 145 tests, 0 failures. The new testEmptyArmoredKey fails without the fix.
  • Manually in the simulator: importing the malformed key shows an error alert instead of aborting; after uninstalling and reinstalling, the settings screen opens normally, offers "Remove PGP Keys" and removing them clears the stale keychain entries.

🤖 Generated with Claude Code

ObjectivePGP raises an Objective-C exception when reading an armored block
without a body. Swift cannot catch it, so the app terminated as soon as a key
ID was requested, e.g. when opening the settings screen. As the keys live in the
keychain, they survive reinstalling the app and the crash persisted.

Route the calls into ObjectivePGP through an Objective-C exception catcher which
turns exceptions into regular errors. Additionally, offer the removal of PGP
keys whenever keys are stored, not only when a key source is set. The key source
is gone after a reinstall while the keys are not, which left no way to get rid
of unusable keys.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@mssun
mssun merged commit cb836aa into master Aug 2, 2026
2 checks passed
@mssun
mssun deleted the claude/issue-715-4eb2d0 branch August 2, 2026 16:33
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.

Crash when accessing GPG Key Settings after entering an invalid/corrupted GPG key

1 participant