{"record":{"id":"b2656128ba67c4de","repo":"passbolt/passbolt_api","slug":"a-valid-openpgp-key-must-be-provided","errorCode":null,"errorMessage":"A valid OpenPGP key must be provided.","messagePattern":"A valid OpenPGP key must be provided\\.","errorType":"validation","errorClass":"App\\Error\\Exception\\CustomValidationException","httpStatus":400,"severity":"error","filePath":"src/Model/Table/GpgkeysTable.php","lineNumber":281,"sourceCode":"\n    /**\n     * Build a Gpgkey entity from the armored key\n     *\n     * @param string $armoredKey ascii armored key\n     * @param string $userId uuid of the user using the key\n     * @throws \\InvalidArgumentException if the user is not valid\n     * @throws \\App\\Error\\Exception\\ValidationException if the key info can not be parsed\n     * @return \\App\\Model\\Entity\\Gpgkey\n     */\n    public function buildEntityFromArmoredKey(string $armoredKey, string $userId): Gpgkey\n    {\n        if (!Validation::uuid($userId)) {\n            throw new InvalidArgumentException('The user identifier should be a valid UUID.');\n        }\n        try {\n            $info = PublicKeyValidationService::getPublicKeyInfo($armoredKey);\n        } catch (Exception $e) {\n            throw new CustomValidationException(__('A valid OpenPGP key must be provided.'), [\n                'armored_key' => [\n                    'isParsable' => __('The OpenPGP armored key could not be parsed.'),\n                ],\n            ]);\n        }\n\n        $data = [\n            'user_id' => $userId,\n            'fingerprint' => $info['fingerprint'],\n            'bits' => $info['bits'],\n            'type' => $info['type'],\n            'key_id' => $info['key_id'],\n            'uid' => $info['uid'],\n            'armored_key' => $armoredKey,\n            'deleted' => false,\n            'key_created' => new DateTime($info['key_created']),\n            'expires' => null,\n        ];","sourceCodeStart":263,"sourceCodeEnd":299,"githubUrl":"https://github.com/passbolt/passbolt_api/blob/31c1bbc10f32808a607fa9bd81891e898779c0bc/src/Model/Table/GpgkeysTable.php#L263-L299","documentation":"GpgkeysTable::buildEntityFromArmoredKey() parses the armored key with PublicKeyValidationService::getPublicKeyInfo(). Any parsing exception is converted to a CustomValidationException stating a valid OpenPGP key must be provided, with an armored_key.isParsable error detail.","triggerScenarios":"Calling buildEntityFromArmoredKey() with a string that is not a parseable armored OpenPGP key — wrong armor format, truncated key, non-key data, or corrupt ASCII armor.","commonSituations":"Users pasting SSH keys or certificates instead of PGP keys, copy/paste losing the BEGIN/END armor lines, keys generated by incompatible tooling, or wrong encoding.","solutions":["Validate the armored key client-side/server-side with PublicKeyValidationService::getPublicKeyInfo() before calling buildEntityFromArmoredKey().","Ensure the key includes full ASCII armor headers ('-----BEGIN PGP PUBLIC KEY BLOCK-----').","Re-export the key with gpg --armor --export <fingerprint>.","Catch the CustomValidationException and return the field error to the user."],"exampleFix":"// before\n$gpgkey = $this->Gpgkeys->buildEntityFromArmoredKey($data['armored_key'], $userId); // throws\n// after\ntry { PublicKeyValidationService::getPublicKeyInfo($data['armored_key']); }\ncatch (Exception $e) { throw new BadRequestException('Please provide a valid OpenPGP public key.'); }\n$gpgkey = $this->Gpgkeys->buildEntityFromArmoredKey($data['armored_key'], $userId);","handlingStrategy":"validation","validationCode":"use App\\Service\\OpenPGP\\PublicKeyValidationService;\ntry {\n  $info = PublicKeyValidationService::getPublicKeyInfo($armoredKey);\n} catch (Exception $e) {\n  throw new BadRequestException('Provide a valid OpenPGP armored public key.');\n}","typeGuard":"function looksLikeArmoredKey(?string $key): bool {\n  return is_string($key)\n    && str_contains($key, '-----BEGIN PGP PUBLIC KEY BLOCK-----')\n    && str_contains($key, '-----END PGP PUBLIC KEY BLOCK-----');\n}","tryCatchPattern":"try { $entity = $gpgkeysTable->buildEntityFromArmoredKey($armoredKey, $userId); }\ncatch (CustomValidationException $e) {\n  return $this->response->withStatus(400)->withStringBody(json_encode($e->getErrors()));\n}","preventionTips":["Verify armor BEGIN/END lines survive copy/paste (whitespace trimming).","Accept only PGP public key blocks, not SSH keys or certificates.","Pre-validate keys with PublicKeyValidationService before persistence.","Provide clear UI feedback pointing users to gpg --armor --export."],"tags":["openpgp","validation","gpg","invalid-input"],"backgroundTag":"invalid-argument-format","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"}