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 sign. 

What it means

Thrown by setSignKeyWithServerKey when the GnuPG backend cannot set the configured server key as signing key (with passphrase), even after importing it into the keyring. Signing of server responses/JWT-related payloads fails. The wrapped gnupg exception message is appended to the 500 response.

Solutions

  1. Read the appended exception message: 'bad passphrase' → correct passbolt.gpg.serverKey.passphrase; 'get key failed' → the secret key is not in the keyring.
  2. Confirm the secret (private) key is imported: `sudo -H -u www-data gpg --home <gnupghome> --list-secret-keys`; if missing, import the private key file, not just the public one.
  3. Verify the fingerprint config matches the secret key and that the key has signing capability (`gpg --edit-key <fp>` then `showpref`/usage flags).
  4. Fix ownership/permissions of GNUPGHOME so the web server user can read the private key material.
  5. Restart gpg-agent / clear stale agent state if passphrase prompt loops occur: `gpgconf --kill gpg-agent` as the web user.

Example fix

// before
$ gpg --import /etc/passbolt/serverkey.asc // public key only
// after
$ sudo -H -u www-data gpg --home /var/lib/passbolt/.gnupg --import /etc/passbolt/serverkey_private.asc
Defensive patterns

Strategy: try-catch

Validate before calling

$fp = Configure::read('passbolt.gpg.serverKey.fingerprint');
exec(sprintf('sudo -H -u www-data gpg --batch --pinentry-mode loopback --list-secret-keys %s 2>/dev/null', escapeshellarg($fp)), $out, $code);
if ($code !== 0) {
    throw new Exception('Server secret key unavailable for signing');
}
if (!is_string(Configure::read('passbolt.gpg.serverKey.passphrase'))) {
    throw new Exception('Passphrase config must be a string');
}

Type guard

function isStringOrThrow(mixed $v, string $name): string
{
    if (!is_string($v)) {
        throw new InvalidArgumentException("{$name} must be a string");
    }
    return $v;
}

Try / catch

try {
    $gpg = $this->setSignKeyWithServerKey($gpg);
} catch (InternalErrorException $e) {
    Log::error('Sign key setup failed: ' . $e->getMessage());
    throw new InternalErrorException('Server cannot sign payloads; verify server key and passphrase.');
}

Prevention

When it happens

Trigger: Calling setSignKeyWithServerKey when: the secret key is absent from the keyring and import fails; the passphrase is wrong so gnupg cannot unlock the secret key; the key lacks signing capability (usage flag S); keyring/GNUPGHOME permission problems; fingerprint in config does not match the secret key.

Common situations: Key regenerated with a different passphrase than configured; only the public key (serverkey.asc) present while signing needs the private key; www-data cannot read private-keys-v1.d after backup restore; gpg-agent socket/permission issues in containers.

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/896edee1835986ab. Report an issue: GitHub.

Appendix: source

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

        // 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 sign key as the one from the server
        try {
            $gpg->setSignKeyFromFingerprint($fingerprint, $passphrase);
        } catch (Exception $exception) {
            try {
                $gpg->importServerKeyInKeyring();
                $gpg->setSignKeyFromFingerprint($fingerprint, $passphrase);
            } catch (Exception $exception) {
                $msg = __('The OpenPGP server key defined in the config cannot be used to sign.') . ' ';
                $msg .= $exception->getMessage();
                throw new InternalErrorException($msg, 500, $exception);
            }
        }

        return $gpg;
    }

    /**
     * @param mixed $fingerprint fingerprint
     * @return void
     * @throws \Cake\Http\Exception\InternalErrorException if the server key fingerprint cannot be loaded
     */
    private function assertServerFingerprint(mixed $fingerprint): void
    {
        if (!is_string($fingerprint) || !PublicKeyValidationService::isValidFingerprint($fingerprint)) {
            $msg = __('The config for the server private key fingerprint is not available or incomplete.');
            throw new InternalErrorException($msg);
        }
    }

View on GitHub (pinned to 31c1bbc10f)