passbolt/passbolt_api · critical · InternalErrorException

The OpenPGP server key defined in the config cannot be used…

Error message

The OpenPGP server key defined in the config cannot be used to decrypt. 

What it means

Thrown by setDecryptKeyWithServerKey when the GnuPG backend cannot set the configured server key as decryption key, even after importing the server key into the keyring. The underlying gnupg exception message is appended. Decryption of user-secret data (e.g. during recovery or resource sharing) fails until the server key is usable for decryption.

Solutions

  1. Check the appended exception message — 'bad passphrase' means fix passbolt.gpg.serverKey.passphrase in config; 'get key failed' means the key is missing from the keyring.
  2. Verify the fingerprint in config matches the key file: `gpg --show-keys /etc/passbolt/serverkey.asc` and compare with `passbolt.gpg.serverKey.fingerprint`.
  3. Import the private key as the web server user: `sudo -H -u www-data gpg --home <gnupghome> --import /etc/passbolt/serverkey_private.asc`.
  4. Fix keyring ownership/permissions: `chown -R www-data:www-data /var/lib/passbolt/.gnupg && chmod 700 /var/lib/passbolt/.gnupg`.
  5. Test decryption manually as the web user: `sudo -H -u www-data gpg --home <gnupghome> --list-secret-keys` to confirm the secret key is loadable with the passphrase.

Example fix

// before (config/app.php)
'passphrase' => 'old-passphrase',
// after
'passphrase' => getenv('PASSBOLT_GPG_SERVERKEY_PASSPHRASE'), // matches the key actually on disk
Defensive patterns

Strategy: try-catch

Validate before calling

$fp = Configure::read('passbolt.gpg.serverKey.fingerprint');
exec(sprintf('sudo -H -u www-data gpg --batch --list-secret-keys %s 2>/dev/null', escapeshellarg($fp)), $out, $code);
if ($code !== 0) {
    throw new Exception('Server SECRET key not importable/decryption will fail');
}
if (!is_string(Configure::read('passbolt.gpg.serverKey.passphrase'))) {
    throw new Exception('Server key passphrase config missing');
}

Type guard

function hasDecryptableServerKeyConfig(): bool
{
    $fp = Configure::read('passbolt.gpg.serverKey.fingerprint');
    $pp = Configure::read('passbolt.gpg.serverKey.passphrase');
    return is_string($fp) && PublicKeyValidationService::isValidFingerprint($fp) && is_string($pp);
}

Try / catch

try {
    $gpg = $this->setDecryptKeyWithServerKey($gpg);
} catch (InternalErrorException $e) {
    Log::error('Server key decrypt setup failed: ' . $e->getMessage());
    throw new InternalErrorException('Server cannot decrypt secrets; check server key/passphrase config.');
}

Prevention

When it happens

Trigger: Calling setDecryptKeyWithServerKey when: the private key is not present in the keyring and serverkey.asc import fails; the configured passphrase does not match the key; the fingerprint does not correspond to the imported key; keyring permission issues (GNUPGHOME not writable/readable by web user); gpg agent caching/passphrase issues.

Common situations: Wrong passbolt.gpg.serverKey.passphrase after the key was regenerated with a new passphrase; key replaced on disk but fingerprint config kept from the old key; www-data cannot read ~/.gnupg/private-keys-v1.d after restoring from backup with wrong ownership; running in a container where GNUPGHOME was not volume-persisted.

Understand the failure class

Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.

Related errors


AI-assisted analysis of passbolt/passbolt_api@31c1bbc10f (2026-09-17). Data as JSON: /api/errors/1bd6658160b61c32. Report an issue: GitHub.

Appendix: source

Thrown at src/Service/OpenPGP/OpenPGPCommonServerOperationsTrait.php:83

        // Check if config contains fingerprint
        $fingerprint = Configure::read('passbolt.gpg.serverKey.fingerprint');
        $this->assertServerFingerprint($fingerprint);

        // Check if config contains valid passphrase
        $passphrase = Configure::read('passbolt.gpg.serverKey.passphrase');
        $this->assertServerPassphrase($passphrase);

        // set the key to be used for decrypting
        try {
            $gpg->setDecryptKeyFromFingerprint($fingerprint, $passphrase);
        } catch (Exception $exception) {
            try {
                $gpg->importServerKeyInKeyring();
                $gpg->setDecryptKeyFromFingerprint($fingerprint, $passphrase);
            } catch (Exception $exception) {
                $msg = __('The OpenPGP server key defined in the config cannot be used to decrypt.') . ' ';
                $msg .= $exception->getMessage();
                throw new InternalErrorException($msg, 500, $exception);
            }
        }

        return $gpg;
    }

    /**
     * @param \App\Utility\OpenPGP\OpenPGPBackend $gpg for example OpenPGPBackendFactory::get()
     * @return \App\Utility\OpenPGP\OpenPGPBackend backend configured to use server key to verify
     * @throws \Cake\Http\Exception\InternalErrorException if the server key cannot be loaded
     */
    public function setVerifyKeyWithServerKey(OpenPGPBackend $gpg): OpenPGPBackend
    {
        // Check if config contains fingerprint
        $fingerprint = Configure::read('passbolt.gpg.serverKey.fingerprint');
        $this->assertServerFingerprint($fingerprint);

        // Check if config contains valid passphrase

View on GitHub (pinned to 31c1bbc10f)