{"record":{"id":"896edee1835986ab","repo":"passbolt/passbolt_api","slug":"the-openpgp-server-key-defined-in-the-config-cannot-be-used-896ede","errorCode":null,"errorMessage":"The OpenPGP server key defined in the config cannot be used to sign. ","messagePattern":"The OpenPGP server key defined in the config cannot be used to sign\\. ","errorType":"http","errorClass":"InternalErrorException","httpStatus":500,"severity":"critical","filePath":"src/Service/OpenPGP/OpenPGPCommonServerOperationsTrait.php","lineNumber":147,"sourceCode":"        // Check if config contains fingerprint\n        $fingerprint = Configure::read('passbolt.gpg.serverKey.fingerprint');\n        $this->assertServerFingerprint($fingerprint);\n\n        // Check if config contains valid passphrase\n        $passphrase = Configure::read('passbolt.gpg.serverKey.passphrase');\n        $this->assertServerPassphrase($passphrase);\n\n        // Set sign key as the one from the server\n        try {\n            $gpg->setSignKeyFromFingerprint($fingerprint, $passphrase);\n        } catch (Exception $exception) {\n            try {\n                $gpg->importServerKeyInKeyring();\n                $gpg->setSignKeyFromFingerprint($fingerprint, $passphrase);\n            } catch (Exception $exception) {\n                $msg = __('The OpenPGP server key defined in the config cannot be used to sign.') . ' ';\n                $msg .= $exception->getMessage();\n                throw new InternalErrorException($msg, 500, $exception);\n            }\n        }\n\n        return $gpg;\n    }\n\n    /**\n     * @param mixed $fingerprint fingerprint\n     * @return void\n     * @throws \\Cake\\Http\\Exception\\InternalErrorException if the server key fingerprint cannot be loaded\n     */\n    private function assertServerFingerprint(mixed $fingerprint): void\n    {\n        if (!is_string($fingerprint) || !PublicKeyValidationService::isValidFingerprint($fingerprint)) {\n            $msg = __('The config for the server private key fingerprint is not available or incomplete.');\n            throw new InternalErrorException($msg);\n        }\n    }","sourceCodeStart":129,"sourceCodeEnd":165,"githubUrl":"https://github.com/passbolt/passbolt_api/blob/31c1bbc10f32808a607fa9bd81891e898779c0bc/src/Service/OpenPGP/OpenPGPCommonServerOperationsTrait.php#L129-L165","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Read the appended exception message: 'bad passphrase' → correct passbolt.gpg.serverKey.passphrase; 'get key failed' → the secret key is not in the keyring.","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.","Verify the fingerprint config matches the secret key and that the key has signing capability (`gpg --edit-key <fp>` then `showpref`/usage flags).","Fix ownership/permissions of GNUPGHOME so the web server user can read the private key material.","Restart gpg-agent / clear stale agent state if passphrase prompt loops occur: `gpgconf --kill gpg-agent` as the web user."],"exampleFix":"// before\n$ gpg --import /etc/passbolt/serverkey.asc // public key only\n// after\n$ sudo -H -u www-data gpg --home /var/lib/passbolt/.gnupg --import /etc/passbolt/serverkey_private.asc","handlingStrategy":"try-catch","validationCode":"$fp = Configure::read('passbolt.gpg.serverKey.fingerprint');\nexec(sprintf('sudo -H -u www-data gpg --batch --pinentry-mode loopback --list-secret-keys %s 2>/dev/null', escapeshellarg($fp)), $out, $code);\nif ($code !== 0) {\n    throw new Exception('Server secret key unavailable for signing');\n}\nif (!is_string(Configure::read('passbolt.gpg.serverKey.passphrase'))) {\n    throw new Exception('Passphrase config must be a string');\n}","typeGuard":"function isStringOrThrow(mixed $v, string $name): string\n{\n    if (!is_string($v)) {\n        throw new InvalidArgumentException(\"{$name} must be a string\");\n    }\n    return $v;\n}","tryCatchPattern":"try {\n    $gpg = $this->setSignKeyWithServerKey($gpg);\n} catch (InternalErrorException $e) {\n    Log::error('Sign key setup failed: ' . $e->getMessage());\n    throw new InternalErrorException('Server cannot sign payloads; verify server key and passphrase.');\n}","preventionTips":["Verify a secret key with signing capability exists: gpg --list-secret-keys as the web user.","Keep passphrase in sync with the key; update config on every key rotation.","Ensure gpg-agent loopback pinentry is available in headless environments.","Check GNUPGHOME permissions after restores; gpg agent caches can hold stale passphrase state.","Generate keys with both sign and encrypt capabilities."],"tags":["openpgp","gnupg","server-key","signing","passphrase"],"backgroundTag":"invalid-config-value","analyzedSha":"31c1bbc10f32808a607fa9bd81891e898779c0bc","analyzedAt":"2026-09-17T00:04:38.960Z","contentChangedAt":"2026-09-17T00:04:38.960Z","schemaVersion":2},"datasetVersion":"2026-09-21T04:17:39.646Z"}