passbolt/passbolt_api · critical · Cake\Http\Exception\InternalErrorException
There is an issue with the OpenPGP server key. The…
Error message
There is an issue with the OpenPGP server key. The fingerprint does not match the one associated with the key on file.
What it means
The key file was read and parsed as an armored private key and imported into the keyring, but isKeyInKeyring($fingerprint) then fails: the fingerprint configured in config does not match the fingerprint of the key actually on file. importServerKeyInKeyring treats this as a fatal server-key mismatch.
Solutions
- Get the true fingerprint: `gpg --show-keys <serverkey_private.asc>` (or `gpg --fingerprint <keyid>`) and set passbolt.gpg.serverKey.fingerprint to exactly that 40-hex-char value.
- If the key was rotated, update the fingerprint in config (or PASSBOLT_GPG_SERVER_KEY_FINGERPRINT env var) to the new key's fingerprint.
- Run `passbolt healthcheck` to validate the server key fingerprint/file pairing after fixing config.
- Ensure the same key file and fingerprint pair is deployed to all app servers behind the load balancer.
Example fix
// before (config/passbolt.php) 'serverKey' => ['fingerprint' => '0FC5F0D5B7A4B7F5...', // old fingerprint // after gpg --show-keys serverkey_private.asc # read actual fingerprint 'serverKey' => ['fingerprint' => '<actual-40-char-fingerprint>'],
Defensive patterns
Strategy: validation
Validate before calling
$fp = strtoupper(str_replace(' ', '', (string)Configure::read('passbolt.gpg.serverKey.fingerprint')));
$fileFp = trim(shell_exec('gpg --show-keys ' . escapeshellarg($keyPath) . ' 2>/dev/null | awk \'{print $1}\' | head -1') ?? '');
if (strlen($fp) !== 40 || $fp !== $fileFp) {
throw new \RuntimeException('Configured fingerprint does not match key file fingerprint.');
} Try / catch
try {
$backend->importServerKeyInKeyring($fingerprint, $keyPath);
} catch (\Cake\Http\Exception\InternalErrorException $e) {
if (str_contains($e->getMessage(), 'fingerprint does not match')) {
// recompute fingerprint from file and update config
}
throw $e;
} Prevention
- Generate the fingerprint config value from the key file itself, never by hand.
- After key rotation, update fingerprint and file together in one change.
- Run `passbolt healthcheck` after any server-key change; it checks the pairing.
When it happens
Trigger: importServerKeyInKeyring() imports the private key from file, then isKeyInKeyring($fingerprint) returns false because passbolt.gpg.serverKey.fingerprint differs from the key in the file (typo, stale fingerprint after key rotation, uppercase/lowercase or space formatting handled but wrong value).
Common situations: Server key was regenerated but config still holds the old fingerprint; fingerprint copied with/without spaces inconsistently between config sources (env var vs passbolt.php); multiple environments sharing one key file with different fingerprints.
Understand the failure class
Background: Checksum mismatch errors: "checksum verification failed", "digest mismatch", "expected vs actual checksum" — what they mean and how to fix them — this error's family across 41 libraries.
Related errors
- The OpenPGP server key defined in the config cannot be used…
- The OpenPGP server key defined in the config is not found…
- The OpenPGP server key defined in the config cannot be…
- The OpenPGP server key defined in the config cannot be used…
- The OpenPGP server key defined in the config cannot be used…
AI-assisted analysis of passbolt/passbolt_api@31c1bbc10f (2026-09-17).
Data as JSON: /api/errors/1a2fbfa41feb81f7.
Report an issue: GitHub.
Appendix: source
Thrown at src/Utility/OpenPGP/OpenPGPBackend.php:113
$msg = __('The OpenPGP server key defined in the config is not found in the file system.');
throw new InternalErrorException($msg);
}
$privateKey = file_get_contents($keyFilePath);
if ($privateKey === false) {
$msg = __('The OpenPGP server key defined in the config cannot be opened.');
throw new InternalErrorException($msg);
}
if (!$this->isParsableArmoredPrivateKey($privateKey)) {
$msg = __('The OpenPGP server key defined on file is not a valid private key.');
throw new InternalErrorException($msg);
}
// try to import it
$this->importKeyIntoKeyring($privateKey);
if (!$this->isKeyInKeyring($fingerprint)) {
$msg = __('There is an issue with the OpenPGP server key.') . ' ';
$msg .= __('The fingerprint does not match the one associated with the key on file.');
throw new InternalErrorException($msg);
}
}
/**
* Check if a message is valid.
*
* To do this, we try to unarmor the message. If the operation is successful, then we consider that
* the message is a valid one.
*
* @param string $armored ASCII armored message data
* @return bool true if valid, false otherwise
*/
public function isValidMessage(string $armored): bool
{
try {
$this->assertGpgMarker($armored, self::MESSAGE_MARKER);
} catch (CakeException $e) {
return false;View on GitHub (pinned to 31c1bbc10f)