{"record":{"id":"e590a8a5d8e43d78","repo":"passbolt/passbolt_api","slug":"could-not-import-the-user-openpgp-key-e590a8","errorCode":null,"errorMessage":"Could not import the user OpenPGP key.","messagePattern":"Could not import the user OpenPGP key\\.","errorType":"http","errorClass":"InternalErrorException","httpStatus":500,"severity":"error","filePath":"src/Service/OpenPGP/OpenPGPCommonUserOperationsTrait.php","lineNumber":57,"sourceCode":"        try {\n            $this->assertUserKey($userKey);\n        } catch (Exception $exception) {\n            $msg = __('Could not validate user data.');\n            throw new InternalErrorException($msg, 500, $exception);\n        }\n        try {\n            $gpg->setEncryptKeyFromFingerprint($userKey->fingerprint);\n        } catch (Exception $exception) {\n            // Try to import the key in keyring again\n            try {\n                $gpg->importKeyIntoKeyring($userKey->armored_key);\n                $gpg->setEncryptKeyFromFingerprint($userKey->fingerprint);\n            } catch (Exception $exception) {\n                if (Configure::read('debug')) {\n                    Log::error(json_encode($userKey));\n                }\n                $msg = __('Could not import the user OpenPGP key.');\n                throw new InternalErrorException($msg, 500, $exception);\n            }\n        }\n\n        return $gpg;\n    }\n\n    /**\n     * Get the OpenPGP Backend ready to verify with user key\n     *\n     * @param \\App\\Utility\\OpenPGP\\OpenPGPBackend $gpg for example OpenPGPBackendFactory::get()\n     * @param \\App\\Model\\Entity\\Gpgkey $userKey entity\n     * @return \\App\\Utility\\OpenPGP\\OpenPGPBackend backend configured to use user key to verify\n     * @throws \\Cake\\Http\\Exception\\InternalErrorException if the user key cannot be loaded\n     */\n    protected function setVerifyKeyWithUserKey(OpenPGPBackend $gpg, Gpgkey $userKey): OpenPGPBackend\n    {\n        // Set encryption key as the one from the user\n        try {","sourceCodeStart":39,"sourceCodeEnd":75,"githubUrl":"https://github.com/passbolt/passbolt_api/blob/31c1bbc10f32808a607fa9bd81891e898779c0bc/src/Service/OpenPGP/OpenPGPCommonUserOperationsTrait.php#L39-L75","documentation":"setEncryptKeyWithUserKey() first tries setEncryptKeyFromFingerprint($userKey->fingerprint); if the key is not in the GnuPG keyring it retries by importing armored_key via importKeyIntoKeyring() and setting the key again. If that fallback also throws, the InternalErrorException 'Could not import the user OpenPGP key.' (HTTP 500) is raised. The key data itself passed validation, but the GPG keyring refuses to store or use it.","triggerScenarios":"Calling setEncryptKeyWithUserKey() when the user's public key is absent from the server keyring AND the re-import of $userKey->armored_key fails (malformed armor despite passing validation, expired/revoked key rejected by gnupg, keyring permission or gnupg homedir issues, key already present with different fingerprint data).","commonSituations":"GnuPG homedir (e.g. /home/www-data/.gnupg) owned by wrong user or wrong permissions after server migration; different gnupg version on new server rejecting old key packets; keyring wiped/rebuilt (keyring dir deleted); armored key stored with broken line endings after a database import/export; corrupted key from third-party import scripts.","solutions":["Check the chained exception message in the log/debug output — it contains the underlying gnupg error explaining why the import or key selection failed.","Verify the web-server user's GnuPG keyring permissions and GNUPGHOME directory (ownership, 700, readable keyring files) and re-run the operation.","Manually test importing the armored key with gpg --import to see gnupg's own error for that key.","Have the user re-generate or re-upload their key if the stored key is rejected by the installed gnupg version (e.g. keys using deprecated algorithms).","If keyring corruption is suspected, rebuild the keyring (delete/recreate the gnupg homedir for the web user) and let passbolt re-import keys on demand."],"exampleFix":"// before: relying on keyring having the key\n$gpg->setEncryptKeyFromFingerprint($userKey->fingerprint);\n// after: pre-check key presence and surface the gnupg error clearly\ntry {\n    $gpg->setEncryptKeyFromFingerprint($userKey->fingerprint);\n} catch (Exception $e) {\n    $imported = $gpg->importKeyIntoKeyring($userKey->armored_key);\n    if (!$imported) {\n        throw new InternalErrorException(\n            __('The user key could not be imported into the keyring: {0}', $e->getMessage())\n        );\n    }\n    $gpg->setEncryptKeyFromFingerprint($userKey->fingerprint);\n}","handlingStrategy":"try-catch","validationCode":"use App\\Service\\OpenPGP\\PublicKeyValidationService;\n\nif (!PublicKeyValidationService::parseAndValidatePublicKey($userKey->armored_key)) {\n    throw new BadRequestException('User armored key is not a valid public key.');\n}\nif (!is_dir(getenv('GNUPGHOME') ?: sys_get_temp_dir())) {\n    throw new RuntimeException('GnuPG homedir is not available.');\n}","typeGuard":"function isNonEmptyString(mixed $value): bool\n{\n    return is_string($value) && $value !== '';\n}\n\n// use: isNonEmptyString($userKey->armored_key) && isNonEmptyString($userKey->fingerprint)","tryCatchPattern":"try {\n    $gpg = $this->setEncryptKeyWithUserKey($gpg, $userKey);\n} catch (InternalErrorException $e) {\n    $reason = $e->getPrevious()?->getMessage() ?? 'unknown gnupg error';\n    // e.g. keyring permission problem vs bad key data\n    $this->log(__('Keyring import failed for {0}: {1}', $userKey->fingerprint, $reason));\n    throw new InternalErrorException(\n        __('The user key could not be imported. Check the server GPG keyring: {0}', $reason)\n    );\n}","preventionTips":["Preserve the web-server user's .gnupg directory (correct ownership/permissions, 700) across deployments and migrations.","Keep gnupg versions consistent between environments; test key imports after OS upgrades.","Log the chained previous exception (enable debug or wrap the call) so gnupg's real error is visible.","Validate armored keys with PublicKeyValidationService before storing them.","Have a recovery path to let users re-upload keys that gnupg rejects (expired keys, deprecated algorithms)."],"tags":["openpgp","gpg","keyring","import","user-key"],"backgroundTag":"internal-invariant-violation","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"}