{"record":{"id":"21ebc00b10a404d1","repo":"passbolt/passbolt_api","slug":"can-not-verify-without-a-key-set-a-verification-key-first","errorCode":null,"errorMessage":"Can not verify without a key. Set a verification key first.","messagePattern":"Can not verify without a key\\. Set a verification key first\\.","errorType":"exception","errorClass":"Cake\\Core\\Exception\\CakeException","httpStatus":null,"severity":"error","filePath":"src/Utility/OpenPGP/Traits/OpenPGPCommonAssertsTrait.php","lineNumber":81,"sourceCode":"     * @return void\n     */\n    public function assertSignKey(): void\n    {\n        if (empty($this->_signKeyFingerprint)) {\n            throw new CakeException('Can not sign without a key. Set a sign key first.');\n        }\n    }\n\n    /**\n     * Assert the verification key is set\n     *\n     * @throws \\Cake\\Core\\Exception\\CakeException if not signature key is set\n     * @return void\n     */\n    public function assertVerifyKey(): void\n    {\n        if (empty($this->_verifyKeyFingerprint)) {\n            throw new CakeException('Can not verify without a key. Set a verification key first.');\n        }\n    }\n\n    /**\n     * Check if an encryption key is set\n     *\n     * @throws \\Cake\\Core\\Exception\\CakeException if no encryption key is set\n     * @return void\n     */\n    public function assertEncryptKey(): void\n    {\n        if (empty($this->_encryptKeyFingerprint)) {\n            throw new CakeException('Can not encrypt without a key. Set a public key first.');\n        }\n    }\n\n    /**\n     * Check if a decrypt key is set","sourceCodeStart":63,"sourceCodeEnd":99,"githubUrl":"https://github.com/passbolt/passbolt_api/blob/31c1bbc10f32808a607fa9bd81891e898779c0bc/src/Utility/OpenPGP/Traits/OpenPGPCommonAssertsTrait.php#L63-L99","documentation":"assertVerifyKey() is a precondition check for signature verification in OpenPGPCommonAssertsTrait. It throws a CakeException when _verifyKeyFingerprint is empty, since GnuPG needs to know which public key to verify a signature against.","triggerScenarios":"Calling verify() (or code that invokes assertVerifyKey) on an instance where setVerifyKey() was never called or was passed an empty value, leaving _verifyKeyFingerprint empty.","commonSituations":"Verifying incoming signed payloads (e.g. server-signed responses) without first setting the sender's public key fingerprint; test setups skipping key initialization; wiring a new verification path that bypasses the shared key-setup helper.","solutions":["Call setVerifyKey() with the sender's public key fingerprint before verifying.","Make sure the corresponding public key is also imported into the keyring.","Check the bootstrap/config path that should populate the verification key actually runs in this context."],"exampleFix":"// before\n$isValid = $gpg->verify($signedMessage); // throws: no verify key\n// after\n$gpg->setVerifyKey($senderFingerprint);\n$isValid = $gpg->verify($signedMessage);","handlingStrategy":"type-guard","validationCode":"if (empty($gpg->getVerifyKeyFingerprint())) {\n    $gpg->setVerifyKey($senderFingerprint);\n}","typeGuard":"function canVerify($gpg): bool {\n    return isset($gpg) && !empty($gpg->getVerifyKeyFingerprint());\n}","tryCatchPattern":"try {\n    $ok = $gpg->verify($message);\n} catch (\\Cake\\Core\\Exception\\CakeException $e) {\n    if (str_contains($e->getMessage(), 'verify without a key')) {\n        $gpg->setVerifyKey($senderFingerprint);\n        $ok = $gpg->verify($message);\n    } else { throw $e; }\n}","preventionTips":["Set verification keys in the same bootstrap that handles decryption/signing.","Keep sender fingerprints in configuration or the database, never hardcode in call sites.","Write an integration test that verifies a signed fixture in CI."],"tags":["openpgp","verification","missing-key"],"backgroundTag":"empty-required-field","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"}