"The OpenPGP key can not be used to encrypt." in FreeBSD [$PATH not set for www user in php-fpm]

Checklist
I have read intro post: About the Installation Issues category
I have read the tutorials, help and searched for similar issues
I provide relevant information about my server (component names and versions, etc.)
I provide a copy of my logs and healthcheck
I describe the steps I have taken to trouble shoot the problem
I describe the steps on how to reproduce the issue

So I’ve been trying to install this on FreeBSD. Most of the installation went smoothly, but I keep running into the dreadful “The OpenPGP key can not be used to encrypt” error (error details below).

{
    "code": 400,
    "body": {
        "gpgkey": {
            "armored_key": "The OpenPGP key can not be used to encrypt."
        }
    }
}

I’ve already ruled out NTP as a problem, as well as a number of other things. Even unsecure[_private].key results in this error. I’ve looked at every single post I could find on this topic (mostly on this forum), but have yet to arrive to a solution.

I’ve tried different types of keys, and all sorts of other things, to no avail (which reminds me: the tutorial is broken for newer GPG versions, as they now default to elliptic curve cryptography).

The issue happens after bin/cake passbolt install, when I’m trying to create a new user via the URL it returns.

Thanks!


System information:

$ uname -a
FreeBSD passbolt 12.4-RELEASE-p1 FreeBSD 12.4-RELEASE-p1 GENERIC  amd64

# (list of relevant PHP packages)
$ pkg info -q | grep '^php' | xargs
php82-8.2.7 php82-composer2-2.5.8 php82-ctype-8.2.7 php82-curl-8.2.7 php82-dom-8.2.7 php82-extensions-1.0 php82-fileinfo-8.2.7 php82-filter-8.2.7 php82-gd-8.2.7 php82-iconv-8.2.7 php82-intl-8.2.7 php82-ldap-8.2.7 php82-mbstring-8.2.7 php82-opcache-8.2.7 php82-pdo-8.2.7 php82-pdo_mysql-8.2.7 php82-pdo_sqlite-8.2.7 php82-pear-1.10.13 php82-pear-Console_CommandLine-1.2.2 php82-pear-Crypt_GPG-1.6.7 php82-pecl-gnupg-1.5.1 php82-phar-8.2.7 php82-posix-8.2.7 php82-session-8.2.7 php82-simplexml-8.2.7 php82-sqlite3-8.2.7 php82-tokenizer-8.2.7 php82-xml-8.2.7 php82-xmlreader-8.2.7 php82-xmlwriter-8.2.7 php82-xsl-8.2.7 php82-zlib-8.2.7

$ gpg --version
gpg (GnuPG) 2.3.8
libgcrypt 1.9.4
Copyright (C) 2021 Free Software Foundation, Inc.
License GNU GPL-3.0-or-later <https://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Home: /var/db/www/.gnupg
Supported algorithms:
Pubkey: RSA, ELG, DSA, ECDH, ECDSA, EDDSA
Cipher: IDEA, 3DES, CAST5, BLOWFISH, AES, AES192, AES256, TWOFISH,
        CAMELLIA128, CAMELLIA192, CAMELLIA256
AEAD: EAX, OCB
Hash: SHA1, RIPEMD160, SHA256, SHA384, SHA512, SHA224
Compression: Uncompressed, ZIP, ZLIB, BZIP2

Output of healthcheck:


 Environment

 [PASS] PHP version 8.2.7.
 [PASS] PCRE compiled with unicode support.
 [PASS] The temporary directory and its content are writable and not executable.
 [PASS] The logs directory and its content are writable.
 [PASS] GD or Imagick extension is installed.
 [PASS] Intl extension is installed.
 [PASS] Mbstring extension is installed.

 Config files

 [PASS] The application config file is present
 [PASS] The passbolt config file is present

 Core config

 [PASS] Debug mode is off.
 [PASS] Cache is working.
 [PASS] Unique value set for security.salt
 [PASS] Full base url is set to https://passbolt.stdrand.com
 [PASS] App.fullBaseUrl validation OK.
 [PASS] /healthcheck/status is reachable.

 SSL Certificate

 [PASS] SSL peer certificate validates
 [PASS] Hostname is matching in SSL certificate.
 [PASS] Not using a self-signed certificate

 Database

 [PASS] The application is able to connect to the database
 [PASS] 30 tables found
 [PASS] Some default content is present
 [PASS] The database schema up to date.

 GPG Configuration

 [PASS] PHP GPG Module is installed and loaded.
 [PASS] The environment variable GNUPGHOME is set to /var/db/www/.gnupg.
 [PASS] The directory /var/db/www/.gnupg containing the keyring is writable by the webserver user.
 [PASS] The server OpenPGP key is not the default one
 [PASS] The public key file is defined in /usr/local/www/passbolt/config/passbolt.php and readable.
 [PASS] The private key file is defined in /usr/local/www/passbolt/config/passbolt.php and readable.
 [PASS] The server key fingerprint matches the one defined in /usr/local/www/passbolt/config/passbolt.php.
 [PASS] The server public key defined in the /usr/local/www/passbolt/config/passbolt.php (or environment variables) is in the keyring.
 [PASS] There is a valid email id defined for the server key.
 [PASS] The public key can be used to encrypt a message.
 [PASS] The private key can be used to sign a message.
 [PASS] The public and private keys can be used to encrypt and sign a message.
 [PASS] The private key can be used to decrypt a message.
 [PASS] The private key can be used to decrypt and verify a message.
 [PASS] The public key can be used to verify a signature.
 [PASS] The server public key format is Gopengpg compatible.
 [PASS] The server private key format is Gopengpg compatible.

 Application configuration

 [PASS] Using latest passbolt version (4.0.2).
 [PASS] Passbolt is configured to force SSL use.
 [PASS] App.fullBaseUrl is set to HTTPS.
 [PASS] Selenium API endpoints are disabled.
 [PASS] Search engine robots are told not to index content.
 [INFO] The Self Registration plugin is enabled.
 [INFO] Registration is closed, only administrators can add users.
 [PASS] The deprecated self registration public setting was not found in /usr/local/www/passbolt/config/passbolt.php.
 [WARN] Host availability checking is disabled.
 [HELP] Make sure this instance is not publicly available on the internet.
 [HELP] Or set the PASSBOLT_EMAIL_VALIDATE_MX environment variable to true.
 [HELP] Or set passbolt.email.validate.mx to true in /usr/local/www/passbolt/config/passbolt.php.
 [PASS] Serving the compiled version of the javascript app.
 [WARN] Some email notifications are disabled by the administrator.

 JWT Authentication

 [PASS] The JWT Authentication plugin is enabled
 [PASS] The /usr/local/www/passbolt/config/jwt/ directory is not writable.
 [PASS] A valid JWT key pair was found

 SMTP Settings

 [PASS] The SMTP Settings plugin is enabled.
 [PASS] SMTP Settings coherent. You may send a test email to validate them.
 [WARN] The SMTP Settings source is: /usr/local/www/passbolt/config/passbolt.php.
 [HELP] It is recommended to set the SMTP Settings in the database through the administration section.
 [WARN] The SMTP Settings plugin endpoints are enabled.
 [HELP] It is recommended to disable the plugin endpoints.
 [HELP] Set the PASSBOLT_SECURITY_SMTP_SETTINGS_ENDPOINTS_DISABLED environment variable to true.
 [HELP] Or set passbolt.security.smtpSettings.endpointsDisabled to true in /usr/local/www/passbolt/config/passbolt.php.

 [PASS] No error found. Nice one sparky!

Relevant portion of error.log:

Request URL: /setup/complete/<snip UUID>
Client IP: <snip IP>
2023-06-21 13:48:23 error: [App\Error\Exception\CustomValidationException] The OpenPGP key can not be used to encrypt. in /usr/local/www/passbolt/src/Service/Setup/SetupCompleteService.php on line 93
Stack Trace:
- /usr/local/www/passbolt/src/Service/Setup/SetupCompleteService.php:52
- /usr/local/www/passbolt/src/Controller/Setup/SetupCompleteController.php:63
- /usr/local/www/passbolt/vendor/cakephp/cakephp/src/Controller/Controller.php:547
- /usr/local/www/passbolt/vendor/cakephp/cakephp/src/Controller/ControllerFactory.php:139
- /usr/local/www/passbolt/vendor/cakephp/cakephp/src/Controller/ControllerFactory.php:114
- /usr/local/www/passbolt/vendor/cakephp/cakephp/src/Http/BaseApplication.php:320
- /usr/local/www/passbolt/vendor/cakephp/cakephp/src/Http/Runner.php:86
- /usr/local/www/passbolt/vendor/cakephp/cakephp/src/Http/Middleware/SecurityHeadersMiddleware.php:255
- /usr/local/www/passbolt/vendor/cakephp/cakephp/src/Http/Runner.php:82
- /usr/local/www/passbolt/src/Middleware/HttpProxyMiddleware.php:50
- /usr/local/www/passbolt/vendor/cakephp/cakephp/src/Http/Runner.php:82
- /usr/local/www/passbolt/vendor/cakephp/cakephp/src/Http/Middleware/CsrfProtectionMiddleware.php:138
- /usr/local/www/passbolt/vendor/cakephp/cakephp/src/Http/Runner.php:82
- /usr/local/www/passbolt/plugins/PassboltCe/JwtAuthentication/src/Middleware/JwtCsrfDetectionMiddleware.php:55
- /usr/local/www/passbolt/vendor/cakephp/cakephp/src/Http/Runner.php:82
- /usr/local/www/passbolt/src/Middleware/GpgAuthHeadersMiddleware.php:40
- /usr/local/www/passbolt/vendor/cakephp/cakephp/src/Http/Runner.php:82
- /usr/local/www/passbolt/plugins/PassboltCe/Locale/src/Middleware/LocaleMiddleware.php:47
- /usr/local/www/passbolt/vendor/cakephp/cakephp/src/Http/Runner.php:82
- /usr/local/www/passbolt/plugins/PassboltCe/MultiFactorAuthentication/src/Middleware/InjectMfaFormMiddleware.php:67
- /usr/local/www/passbolt/vendor/cakephp/cakephp/src/Http/Runner.php:82
- /usr/local/www/passbolt/plugins/PassboltCe/MultiFactorAuthentication/src/Middleware/MfaRequiredCheckMiddleware.php:82
- /usr/local/www/passbolt/vendor/cakephp/cakephp/src/Http/Runner.php:82
- /usr/local/www/passbolt/vendor/cakephp/authentication/src/Middleware/AuthenticationMiddleware.php:124
- /usr/local/www/passbolt/vendor/cakephp/cakephp/src/Http/Runner.php:82
- /usr/local/www/passbolt/plugins/PassboltCe/JwtAuthentication/src/Middleware/JwtDestroySessionMiddleware.php:43
- /usr/local/www/passbolt/vendor/cakephp/cakephp/src/Http/Runner.php:82
- /usr/local/www/passbolt/src/Middleware/SessionAuthPreventDeletedUsersMiddleware.php:46
- /usr/local/www/passbolt/vendor/cakephp/cakephp/src/Http/Runner.php:82
- /usr/local/www/passbolt/vendor/cakephp/cakephp/src/Http/Middleware/BodyParserMiddleware.php:172
- /usr/local/www/passbolt/vendor/cakephp/cakephp/src/Http/Runner.php:82
- /usr/local/www/passbolt/src/Middleware/SessionPreventExtensionMiddleware.php:66
- /usr/local/www/passbolt/vendor/cakephp/cakephp/src/Http/Runner.php:82
- /usr/local/www/passbolt/src/Middleware/ApiVersionMiddleware.php:46
- /usr/local/www/passbolt/vendor/cakephp/cakephp/src/Http/Runner.php:82
- /usr/local/www/passbolt/plugins/PassboltCe/JwtAuthentication/src/Middleware/JwtRouteFilterMiddleware.php:47
- /usr/local/www/passbolt/vendor/cakephp/cakephp/src/Http/Runner.php:82
- /usr/local/www/passbolt/plugins/PassboltCe/JwtAuthentication/src/Middleware/JwtAuthDetectionMiddleware.php:58
- /usr/local/www/passbolt/vendor/cakephp/cakephp/src/Http/Runner.php:82
- /usr/local/www/passbolt/vendor/cakephp/cakephp/src/Routing/Middleware/RoutingMiddleware.php:186
- /usr/local/www/passbolt/vendor/cakephp/cakephp/src/Http/Runner.php:82
- /usr/local/www/passbolt/vendor/cakephp/cakephp/src/Routing/Middleware/AssetMiddleware.php:68
- /usr/local/www/passbolt/vendor/cakephp/cakephp/src/Http/Runner.php:82
- /usr/local/www/passbolt/vendor/cakephp/cakephp/src/Error/Middleware/ErrorHandlerMiddleware.php:131
- /usr/local/www/passbolt/vendor/cakephp/cakephp/src/Http/Runner.php:82
- /usr/local/www/passbolt/src/Middleware/ContentSecurityPolicyMiddleware.php:39
- /usr/local/www/passbolt/vendor/cakephp/cakephp/src/Http/Runner.php:82
- /usr/local/www/passbolt/src/Middleware/ContainerInjectorMiddleware.php:54
- /usr/local/www/passbolt/vendor/cakephp/cakephp/src/Http/Runner.php:82
- /usr/local/www/passbolt/vendor/cakephp/cakephp/src/Http/Runner.php:67
- /usr/local/www/passbolt/vendor/cakephp/cakephp/src/Http/Server.php:90
- /usr/local/www/passbolt/webroot/index.php:40

Hi @darkuranium This error gets thrown when the server public key is tested for functionality. Rotating the server keys is how I would advise since you are just setting it up anyway.

Make sure no passphrase is used for the server keys. It says Docker but the page has steps for other installs too.

Thanks, but I’ve already tried that numerous times (with different algorithms, too), to no avail.

Note that, as stated, even the default key (the “demo” one) fails with this error.

Your server time seems ok (It gets sent in the headers, I checked).

The file permissions on the pubring.kbx file should be checked. Is it owned by the webserver user?

1 Like

The permissions are 644 (-rw-r--r-- — but the .gnupg directory itself is 700), and it is owned by the webserver user, as is the .gnupg directory.

I can try to reproduce. I don’t see why it wouldn’t be working in general. And you are not running this in a jail right?

I completely forgot to mention (sorry!), but yes, I am running this in a jail.
It does have mlock permissions, in case that’s the issue. In other words, no GPG warnings about unsafe memory.

@darkuranium Ok, I will run it in a jail and see how it goes. I have a 13.2 host ready so I’ll give it a shot with that.

So, are you using allow.mlock in your jail.conf?

Also, are you following a tutorial somewhere or trailblazing this one?

Correct, allow.mlock is set.

I’m trailblazing this one. With a few changes, e.g. I set /var/db/www as the home directory for the www user; this way, GPG can directly create a ~/.gnupg.

Thanks for the help, by the way!

1 Like

I have confirmed the error. Just starting to look into it more.

For ref:

Healthcheck
root@passbolttemp:/var/www/passbolt # sudo -u www /s/var/www/passbolt/bin/cake passbolt healthcheck

     ____                  __          ____
    / __ \____  _____ ____/ /_  ____  / / /_
   / /_/ / __ `/ ___/ ___/ __ \/ __ \/ / __/
  / ____/ /_/ (__  |__  ) /_/ / /_/ / / /
 /_/    \__,_/____/____/_.___/\____/_/\__/

 Open source password manager for teams
-------------------------------------------------------------------------------

Passbolt commands should only be executed as the web server user.

The command should be executed with the same user as your web server. By instance:
su -s /bin/bash -c "/s/var/www/passbolt/bin/cake COMMAND" HTTP_USER
where HTTP_USER match your web server user: www-data, nginx, apache, http

 Healthcheck shell
-------------------------------------------------------------------------------

 Environment

 [PASS] PHP version 8.2.4.
 [PASS] PCRE compiled with unicode support.
 [PASS] The temporary directory and its content are writable and not executable.
 [PASS] The logs directory and its content are writable.
 [PASS] GD or Imagick extension is installed.
 [PASS] Intl extension is installed.
 [PASS] Mbstring extension is installed.

 Config files

 [PASS] The application config file is present
 [PASS] The passbolt config file is present

 Core config

 [PASS] Debug mode is off.
 [PASS] Cache is working.
 [PASS] Unique value set for security.salt
 [PASS] Full base url is set to https://passbolttemp.local
 [PASS] App.fullBaseUrl validation OK.
 [PASS] /healthcheck/status is reachable.

 SSL Certificate

 [FAIL] SSL peer certificate does not validate
 [FAIL] Hostname does not match when validating certificates.
 [WARN] Using a self-signed certificate
 [HELP] Check https://help.passbolt.com/faq/hosting/troubleshoot-ssl
 [HELP] cURL Error (60) SSL certificate problem: self signed certificate

 Database

 [PASS] The application is able to connect to the database
 [PASS] 30 tables found
 [PASS] Some default content is present
 [PASS] The database schema up to date.

 GPG Configuration

 [PASS] PHP GPG Module is installed and loaded.
 [PASS] The environment variable GNUPGHOME is set to /var/db/www/.gnupg.
 [PASS] The directory /var/db/www/.gnupg containing the keyring is writable by the webserver user.
 [PASS] The server OpenPGP key is not the default one
 [PASS] The public key file is defined in /s/var/www/passbolt/config/passbolt.php and readable.
 [PASS] The private key file is defined in /s/var/www/passbolt/config/passbolt.php and readable.
 [PASS] The server key fingerprint matches the one defined in /s/var/www/passbolt/config/passbolt.php.
 [PASS] The server public key defined in the /s/var/www/passbolt/config/passbolt.php (or environment variables) is in the keyring.
 [PASS] There is a valid email id defined for the server key.
 [PASS] The public key can be used to encrypt a message.
 [PASS] The private key can be used to sign a message.
 [PASS] The public and private keys can be used to encrypt and sign a message.
 [PASS] The private key can be used to decrypt a message.
 [PASS] The private key can be used to decrypt and verify a message.
 [PASS] The public key can be used to verify a signature.
 [PASS] The server public key format is Gopengpg compatible.
 [PASS] The server private key format is Gopengpg compatible.

 Application configuration

 [PASS] Using latest passbolt version (4.0.2).
 [PASS] Passbolt is configured to force SSL use.
 [PASS] App.fullBaseUrl is set to HTTPS.
 [PASS] Selenium API endpoints are disabled.
 [PASS] Search engine robots are told not to index content.
 [INFO] The Self Registration plugin is enabled.
 [INFO] Registration is closed, only administrators can add users.
 [PASS] The deprecated self registration public setting was not found in /s/var/www/passbolt/config/passbolt.php.
 [WARN] Host availability checking is disabled.
 [HELP] Make sure this instance is not publicly available on the internet.
 [HELP] Or set the PASSBOLT_EMAIL_VALIDATE_MX environment variable to true.
 [HELP] Or set passbolt.email.validate.mx to true in /s/var/www/passbolt/config/passbolt.php.
 [PASS] Serving the compiled version of the javascript app.
 [WARN] Some email notifications are disabled by the administrator.

 JWT Authentication

 [PASS] The JWT Authentication plugin is enabled
 [PASS] The /s/var/www/passbolt/config/jwt/ directory is not writable.
 [PASS] A valid JWT key pair was found

 SMTP Settings

 [PASS] The SMTP Settings plugin is enabled.
 [PASS] SMTP Settings coherent. You may send a test email to validate them.
 [WARN] The SMTP Settings source is: /s/var/www/passbolt/config/passbolt.php.
 [HELP] It is recommended to set the SMTP Settings in the database through the administration section.
 [WARN] The SMTP Settings plugin endpoints are enabled.
 [HELP] It is recommended to disable the plugin endpoints.
 [HELP] Set the PASSBOLT_SECURITY_SMTP_SETTINGS_ENDPOINTS_DISABLED environment variable to true.
 [HELP] Or set passbolt.security.smtpSettings.endpointsDisabled to true in /s/var/www/passbolt/config/passbolt.php.

 [FAIL] 2 error(s) found. Hang in there!
1 Like

The error is actually regarding the new public key that the new user is going to be given…that the app is creating.

When I log the $armoredKey and $fingerprint from the check() function and then import the created private key into Kleopatra to view it, I get the following.

image

The fingerprint matches what was logged. The email address (not shown) is correct.

The subkeys show:

Can someone from the team verify this is right or wrong? Should there be two keys listed?

Downloading the recovery kit > choosing the 3-character color key > error is then thrown at what I believe should be authentication.

Database:
gpgkeys table is empty. There is one user (the one being setup) in users, but not active.

I am able to use the key in Kleopatra to encrypt a string message, and decrypt using the passphrase. I can DM the user key and server fingerprint/public key to someone if you want to have a look.

The error is actually regarding the new public key that the new user is going to be given…that the app is creating.

Hmm, could it be that the app is expecting different things from GPG than the defaults? Because the default in GPG is now an elliptic curve, not RSA (at least in my installation, but I do know that GPG is moving towards that for all installs). It’s EDDSA/ed25519 for the key, and ECDH/cv25519 for the subkey (if my memory serves me right). [1]
And I’ve no idea if the PHP extension and/or the browser frontend can handle those.

On a side-note: I feel like some of these error messages should really be revisited. I can understand hiding the exact details of server-side errors, but at least knowing it’s on the client would be useful!

Can someone from the team verify this is right or wrong? Should there be two keys listed?

I’m no expert (so I still think someone from the team should verify), but I suspect it’s correct — one is the key, and the other is the subkey.
You should be able to verify with gpg --list-keys --keyid-format long, see if the IDs match (--with-subkey-fingerprints might also be useful to compare the subkey fingerprints).


  1. This does make the installation guide outdated, as Key-Length should be replaced by Key-Curve. Analogous for Subkey-Length. Even if manually setup as RSA, GPG appears to change Subkey-Length: 2048 to 3072, implying it hard-enforces a minimum. ↩︎

The error being produced, is the error output from the gnupg library when the created key is used to encrypt a string in order to test that it is valid.

The error is an overlay. No gpg error is thrown.
The function is here passbolt_api/src/Service/OpenPGP/PublicKeyCanEncryptCheckService.php at 41b7f7fa476896caeac9050fd2e5ce996a7b8014 · passbolt/passbolt_api · GitHub

The key being tested was created by the frontend, so I think you are right in that the backend is somehow not compatible. Frontend uses GitHub - openpgpjs/openpgpjs: OpenPGP implementation for JavaScript and RSA is not the default but is being selected. 3072 is also higher than the minimum required in the version it uses (5.2.1). Elliptic curves were introduced in openpgpjs version 3.

I’m out for the weekend but good luck if you can sort it out. I’m sure on Monday the team will have something to say about this or to try.

There is a reason for each choice they make, including compatibility with older passbolt installs, etc. Sometimes it’s an intentional freeeze on dependency updates.

Edit: I am actually getting null for $gpg here passbolt_api/src/Service/OpenPGP/PublicKeyCanEncryptCheckService.php at 41b7f7fa476896caeac9050fd2e5ce996a7b8014 · passbolt/passbolt_api · GitHub

I verified it is reading the putenv okay. Also, the engine is gpg2.

Edit: I am actually getting null for $gpg here passbolt_api/src/Service/OpenPGP/PublicKeyCanEncryptCheckService.php at 41b7f7fa476896caeac9050fd2e5ce996a7b8014 · passbolt/passbolt_api · GitHub

That doesn’t sound right, because it’d trip on the null on L39.

I’m investigating this myself, and it seems to be thrown in Utility/OpenPGP/Backends/Gnupg.php:298. Unfortunately, the error message is simply “import failed”, which isn’t very helpful.

I might have found a part of the problem, which is that getenv('PATH') was empty. According to this comment, that might be one of the issues ($HOME was set, though).
Unfortunately, even if it was a part of the problem, providing a proper $PATH is not enough to resolve the problem — it persists, with the same symptoms.


Edit: Apparently, there is a $_gpg->geterrorinfo() in PHP-GPG, which returns more details. Using that, here is the print_r of the output; I believe it provides some insight:

Array
(
    [generic_message] =>
    [gpgme_code] => 117440633
    [gpgme_source] => GPGME
    [gpgme_message] => Unsupported protocol
)

I’ve tried dumping the key that’s failing, and gpg --import works fine — it’s just doing it via PHP that fails, for some reason.


Edit 2: I just tried making a simple gpgme test application, and it imported the key fine. This means that the problem is likely either in php-gnupg, or Passbolt itself.

Also added some debug logging into the gnupg PHP module (it’s funny what you do while debugging: say, hardcoding a very system-specific absolute path for a logfile), but it seems like it receives the data correctly. So I’m not sure what’s up.

Also made a simple PHP program that imports a key, and that works fine, too. And yes, I’ve removed ~/.gnupg directory before trying each one.


So to sum up so far:

  • gpg --import $key works fine, on the very same key that fails in PHP.
  • My test libgpgme-using program works fine (it’s what the PHP extension uses internally). Again, same key.
  • php-gnupg via CLI works fine.
  • php-gnupg via PHP-FPM fails (I made a separate test without Passbolt).

Must be some configuration difference w.r.t. php-fpm vs CLI PHP, but I’ve been unable to identify the problem as of yet.

New post since above is so big:

I’ve found the problem!

This is a two-fold problem:

  1. $PATH does not have /usr/local/bin in it for PHP-FPM. Thus, php-gnupg cannot find GPG by default. (side-note: suggestion to add a custom $PATH or file_name (accepted by gnupg() ctor) to config?)
  2. The gpgme library itself has a bug, which ultimately made the one of the first things I tried (setting file_name in the gnupg() ctor) a no-op. Explanation follows.

In short:

  • The PHP module calls gpgme_ctx_set_engine_info to set file_name when it’s provided.
  • That ultimately calls _gpgme_set_engine_info.
  • Said function has a bug (see lines 405-413):
    When GPG cannot be found in the path, the context is initialized with a single protocol: Spawn. So when the PHP module (or anyone else, for that matter) tries to set the info for GPGME_PROTOCOL_OpenPGP, it cannot find the appropriate protocol in the list of infos. So the entire thing fails with GPG_ERR_INV_ENGINE. This is the bug in gpgme.
  • Back at the PHP module, the result of gpgme_ctx_set_engine_info is not checked, so the error is silently ignored. In other words, we have a gpgme context with no valid engines/protocols.
    I’m unsure whether ignoring this return value is a bug in php-gnupg or by design (and if it’s by design, it’s poor design).
  • When a $_gpg->import($key) is ultimately attempted, there is no valid OpenPGP protocol, since only the (very minimal) Spawn protocol is present. Hence, GPG_ERR_UNSUPPORTED_PROTOCOL.

The solution is to fix $PATH for my php-fpm install; nevertheless, a “proper” fix would be to make gpgme support file_name properly and maybe add a configuration option to Passbolt, for the path to gpg/gpg2 (because even if it’s available in $PATH, perhaps a different version would be desired).
Though for now, that’s impossible, and only the path to the GPG executable is possible. (since $PATH is the only way to make this work in all cases at the moment)


Bug tickets:

1 Like

For others following:

In:
/usr/local/etc/php-fpm.d/www.conf
uncomment :
env[PATH] = /usr/local/bin:/usr/bin:/bin
then restart with:
service php-fpm restart