passbolt/passbolt_api · error · SubscriptionSignatureException

The subscription key cannot be verified.

Error message

The subscription key cannot be verified.

What it means

_verifySignature() throws SubscriptionSignatureException when the OpenPGP verification of the subscription payload fails: the GnuPG/OpenPGP backend (import of the vendor public key succeeded, key fingerprint set) could not verify the signature over the armored message. The underlying GPG backend message is appended to the exception text.

Solutions

  1. Read the appended GPG message in the exception/log to see the concrete verification failure.
  2. Do not alter the key: submit the exact base64 string from passbolt — any edit invalidates the signature.
  3. Fix keyring health for the web user: `sudo chown -R www-data:www-data /var/lib/passbolt/.gnupg` and ensure the gnupg PHP extension works.
  4. Confirm the key matches your edition/version and request a re-issued key from passbolt if verification still fails.

Example fix

// before: edited key payload
$key = str_replace('"expires":"2020', '"expires":"2099', $key);
createOrUpdate($uac, $key); // signature check fails
// after
createOrUpdate($uac, $originalUnmodifiedKey);
Defensive patterns

Strategy: try-catch

Validate before calling

// before submitting, verify locally:
// base64 -d key.b64 | gpg --verify - 2>&1

Try / catch

try {
    $dto = $form->parse($key);
} catch (SubscriptionSignatureException $e) {
    Log::error($e->getMessage()); // includes underlying GPG verify error
    // do not retry with a modified key; request a fresh key
}

Prevention

When it happens

Trigger: parse() calls _verifySignature() and $this->getGpg()->verify($subscriptionSigned, $subscription) throws — tampered payload, signature made by a key not matching the imported vendor public key, corrupted armored message, or the gpg keyring/OpenPGP backend malfunctioning (e.g. gnupg extension issue, stale keyring).

Common situations: Manually editing the subscription JSON then re-submitting; a key issued for a different passbolt product; mixed or corrupted Gnupg keyring under the web-server user (e.g. ~/.gnupg ownership problems); PHP gnupg/OpenPGP-PGP backend mismatch after server migration.

Related errors


AI-assisted analysis of passbolt/passbolt_api@31c1bbc10f (2026-09-17). Data as JSON: /api/errors/1a6cf3d882911bda. Report an issue: GitHub.

Appendix: source

Thrown at plugins/PassboltEe/Subscription/src/Form/SubscriptionKeyAsciiForm.php:197

     */
    protected function _verifySignature(string $subscriptionSigned): string
    {
        $msg = __('The subscription key cannot be verified.');
        $subscription = '';
        $filePublicKey = Configure::read('passbolt.plugins.edition.subscriptionKey.public');

        if (!$filePublicKey || !file_exists($filePublicKey)) {
            $msg .= ' ' . __('The passbolt OpenPGP public key could not be found.');
            throw new SubscriptionSignatureException($subscriptionSigned, $msg);
        }
        $subscriptionPublicKey = file_get_contents($filePublicKey);
        $fingerprint = $this->getGpg()->importKeyIntoKeyring($subscriptionPublicKey);
        $this->getGpg()->setVerifyKeyFromFingerprint($fingerprint);
        try {
            $this->getGpg()->verify($subscriptionSigned, $subscription);
        } catch (Exception $e) {
            $msg .= ' ' . $e->getMessage();
            throw new SubscriptionSignatureException($subscriptionSigned, $msg);
        }

        /** @psalm-suppress NullableReturnStatement this is always a string */
        return $subscription;
    }

    /**
     * @return \App\Utility\OpenPGP\OpenPGPBackend
     */
    private function getGpg(): OpenPGPBackend
    {
        if (is_null($this->_gpg)) {
            $this->_gpg = OpenPGPBackendFactory::get();
        }

        return $this->_gpg;
    }

View on GitHub (pinned to 31c1bbc10f)