{"record":{"id":"6c57a564e3acaa52","repo":"passbolt/passbolt_api","slug":"the-openpgp-key-can-not-be-used-to-encrypt","errorCode":null,"errorMessage":"The OpenPGP key can not be used to encrypt.","messagePattern":"The OpenPGP key can not be used to encrypt\\.","errorType":"validation","errorClass":"CustomValidationException","httpStatus":400,"severity":"error","filePath":"plugins/PassboltEe/AccountRecovery/src/Service/AccountRecoveryOrganizationPolicies/AbstractAccountRecoveryOrganizationPolicySetService.php","lineNumber":271,"sourceCode":"    public function buildPublicKeyEntityFromDataOrFail(UserAccessControl $uac): AccountRecoveryOrganizationPublicKey\n    {\n        try {\n            $data = $this->getData('account_recovery_organization_public_key');\n            $entity = $this->AccountRecoveryOrganizationPublicKeys->buildAndValidateEntity($uac, $data);\n\n            // Check key can be parsed\n            PublicKeyValidationService::parseAndValidatePublicKey(\n                $entity->armored_key,\n                PublicKeyValidationService::getStrictRules()\n            );\n\n            // Prevent key reuse\n            $this->assertPublicKeyModelRules($entity);\n\n            // Make sure key can be used to encrypt - ref. PBL-07-002\n            if (!PublicKeyCanEncryptCheckService::check($entity->armored_key, $entity->fingerprint)) {\n                $msg = __('The OpenPGP key can not be used to encrypt.');\n                throw new CustomValidationException($msg, ['armored_key' => ['canEncrypt' => $msg]]);\n            }\n        } catch (ValidationException | CustomValidationException $exception) {\n            throw new CustomValidationException(__('Could not validate policy data.'), [\n                'account_recovery_organization_public_key' => $exception->getErrors(),\n            ]);\n        } catch (Exception $exception) {\n            throw new CustomValidationException(__('Could not validate policy data.'), [\n                'account_recovery_organization_public_key' => [\n                    'armored_key' => [\n                        'invalidArmoredKey' => $exception->getMessage(),\n                    ],\n                ],\n            ]);\n        }\n\n        return $entity;\n    }\n","sourceCodeStart":253,"sourceCodeEnd":289,"githubUrl":"https://github.com/passbolt/passbolt_api/blob/31c1bbc10f32808a607fa9bd81891e898779c0bc/plugins/PassboltEe/AccountRecovery/src/Service/AccountRecoveryOrganizationPolicies/AbstractAccountRecoveryOrganizationPolicySetService.php#L253-L289","documentation":"Thrown in buildPublicKeyEntityFromDataOrFail when the submitted OpenPGP public key passes armor parsing but PublicKeyCanEncryptCheckService determines it cannot actually be used for encryption (e.g. key usage flags or algorithm/capability problems). It is immediately re-wrapped as 'Could not validate policy data.' with a canEncrypt error on armored_key.","triggerScenarios":"Enabling or setting account recovery organization policy (POST /account-recovery/organization-policies) with an organization public key that is valid armor but not encryption-capable — e.g. a sign-only key, a revoked key, or a key with unsuitable cipher support.","commonSituations":"Admin uploads a dedicated signing key instead of an encryption key; key generated with usage restrictions; old GnuPG key formats; key whose subkeys lack encryption capability while the primary key is sign-only.","solutions":["Generate a fresh RSA (or other supported) key pair usable for encryption, e.g. `gpg --quick-generate-key \"passbolt recovery\" rsa3072 encr`","Export and submit the public key in ASCII armor via armored_key with the matching fingerprint","Check that the key is not revoked or expired before upload","Look at the wrapped 'Could not validate policy data.' errors for the canEncrypt entry confirming the diagnosis"],"exampleFix":"// before\ngpg --quick-generate-key \"recovery\" rsa3072 sign  // sign-only\n// after\ngpg --quick-generate-key \"recovery\" rsa3072 encr  // encryption-capable","handlingStrategy":"validation","validationCode":"// Pre-check the key is encryption-capable before upload\nimport { readKey } from 'openpgp';\nconst key = await readKey({ armoredKey: armored_key });\nconst canEncrypt = await key.getEncryptionKey();\nif (!canEncrypt) throw new Error('Key cannot encrypt');","typeGuard":"function isEncryptCapableKeyPacket(key) {\n  return key && typeof key.getEncryptionKey === 'function' && !key.isRevoked();\n}","tryCatchPattern":"try {\n  await api.setOrganizationPolicy({policy, armored_key, fingerprint});\n} catch (e) {\n  if (e.body?.errors?.account_recovery_organization_public_key?.armored_key?.canEncrypt) {\n    // regenerate an encryption-capable key and retry\n  }\n}","preventionTips":["Generate organization keys explicitly with encryption usage (e.g. `gpg --quick-generate-key name rsa3072 encr`)","Never reuse a signing-only key for the recovery organization key","Check key is not expired/revoked before uploading"],"tags":["openpgp","account-recovery","validation","encryption"],"backgroundTag":"invalid-argument-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"}