composer: Composer is not trusting locally installed CAs on macOS
On macOS, to add custom CAs to openssl (installed via homebrew), one should copy the .pem file to /usr/local/etc/openssl/certs
and run /usr/local/opt/openssl/bin/c_rehash
, which creates a symlink to the certificate under /usr/local/etc/openssl/certs
(source).
At $WORK, we have an internal CA which is used to sign the SSL certificate used in our local composer repository (we use Artifactory). After installing our company’s CA to the Mac’s Keychain and also adding it to /usr/local/etc/openssl/certs and creating the appropriate symlink with c_rehash, every tool (openssl, curl, etc.) and language (PHP, Ruby, Python) recognize this CA, except for composer.
PHP itself does recognize said certificates:
$ php --version
PHP 5.6.30 (cli) (built: Mar 11 2017 09:56:18)
Copyright (c) 1997-2016 The PHP Group
Zend Engine v2.6.0, Copyright (c) 1998-2016 Zend Technologies
$ php -r "file_get_contents('https://composer.intranet');"
$
However, composer does not recognize the certificates installed this way because it only reads the default bundle at /usr/local/etc/openssl/cert.pem
(see the output from composer install --prefer-dist -vvv
below).
My composer.json
:
{
"repositories": [
{"type": "composer", "url": "https://composer.intranet"},
{"packagist": false}
]
}
Output of composer diagnose
:
Checking composer.json: WARNING
No license specified, it is recommended to do so. For closed-source software you may use "proprietary" as license.
Checking platform settings: OK
Checking git settings: OK
Checking http connectivity to packagist: OK
Checking https connectivity to packagist: OK
Checking github.com rate limit: OK
Checking disk free space: OK
Checking pubkeys:
Tags Public Key Fingerprint: 57815BA2 7E54DC31 7ECC7CC5 573090D0 87719BA6 8F3BB723 4E5D42D0 84A14642
Dev Public Key Fingerprint: 4AC45767 E5EC2265 2F0C1167 CBBB8A2B 0C708369 153E328C AD90147D AFE50952
OK
Checking composer version: WARNING
You are not running the latest stable version, run `composer self-update` to update (1.4.1 => 1.4.2)
When I run this command:
composer install --prefer-dist -vvv
I get the following output:
Reading ./composer.json
Loading config file ./composer.json
Checked CA file /usr/local/etc/openssl/cert.pem: valid
Executing command (/private/tmp/composer-test): git branch --no-color --no-abbrev -v
Executing command (/private/tmp/composer-test): git describe --exact-match --tags
Executing command (/private/tmp/composer-test): git log --pretty="%H" -n1 HEAD
Executing command (/private/tmp/composer-test): hg branch
Executing command (/private/tmp/composer-test): fossil branch list
Executing command (/private/tmp/composer-test): fossil tag list
Executing command (/private/tmp/composer-test): svn info --xml
Failed to initialize global composer: Composer could not find the config file: /Users/dserodio/.composer/composer.json
To initialize a project, please create a composer.json file as described in the https://getcomposer.org/ "Getting Started" section
Reading /private/tmp/composer-test/vendor/composer/installed.json
Running 1.4.1 (2017-03-10 09:29:45) with PHP 5.5.38 on Darwin / 15.6.0
Loading composer repositories with package information
Downloading https://composer.intranet/packages.json
Downloading https://composer.intranet/packages.json
Downloading https://composer.intranet/packages.json
[Composer\Downloader\TransportException]
The "https://composer.intranet/packages.json" file could not be downloaded: SSL operation failed with code 1. OpenSSL Error messages:
error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed
Failed to enable crypto
failed to open stream: operation failed
Exception trace:
() at phar:///usr/local/Cellar/composer/1.4.1/libexec/composer.phar/src/Composer/Util/RemoteFilesystem.php:482
Composer\Util\RemoteFilesystem->get() at phar:///usr/local/Cellar/composer/1.4.1/libexec/composer.phar/src/Composer/Util/RemoteFilesystem.php:101
Composer\Util\RemoteFilesystem->getContents() at phar:///usr/local/Cellar/composer/1.4.1/libexec/composer.phar/src/Composer/Repository/ComposerRepository.php:661
Composer\Repository\ComposerRepository->fetchFile() at phar:///usr/local/Cellar/composer/1.4.1/libexec/composer.phar/src/Composer/Repository/ComposerRepository.php:479
Composer\Repository\ComposerRepository->loadRootServerFile() at phar:///usr/local/Cellar/composer/1.4.1/libexec/composer.phar/src/Composer/Repository/ComposerRepository.php:258
Composer\Repository\ComposerRepository->hasProviders() at phar:///usr/local/Cellar/composer/1.4.1/libexec/composer.phar/src/Composer/DependencyResolver/Pool.php:99
Composer\DependencyResolver\Pool->addRepository() at phar:///usr/local/Cellar/composer/1.4.1/libexec/composer.phar/src/Composer/Installer.php:376
Composer\Installer->doInstall() at phar:///usr/local/Cellar/composer/1.4.1/libexec/composer.phar/src/Composer/Installer.php:223
Composer\Installer->run() at phar:///usr/local/Cellar/composer/1.4.1/libexec/composer.phar/src/Composer/Command/InstallCommand.php:119
Composer\Command\InstallCommand->execute() at phar:///usr/local/Cellar/composer/1.4.1/libexec/composer.phar/vendor/symfony/console/Command/Command.php:267
Symfony\Component\Console\Command\Command->run() at phar:///usr/local/Cellar/composer/1.4.1/libexec/composer.phar/vendor/symfony/console/Application.php:846
Symfony\Component\Console\Application->doRunCommand() at phar:///usr/local/Cellar/composer/1.4.1/libexec/composer.phar/vendor/symfony/console/Application.php:191
Symfony\Component\Console\Application->doRun() at phar:///usr/local/Cellar/composer/1.4.1/libexec/composer.phar/src/Composer/Console/Application.php:227
Composer\Console\Application->doRun() at phar:///usr/local/Cellar/composer/1.4.1/libexec/composer.phar/vendor/symfony/console/Application.php:122
Symfony\Component\Console\Application->run() at phar:///usr/local/Cellar/composer/1.4.1/libexec/composer.phar/src/Composer/Console/Application.php:100
Composer\Console\Application->run() at phar:///usr/local/Cellar/composer/1.4.1/libexec/composer.phar/bin/composer:54
require() at /usr/local/Cellar/composer/1.4.1/libexec/composer.phar:24
install [--prefer-source] [--prefer-dist] [--dry-run] [--dev] [--no-dev] [--no-custom-installers] [--no-autoloader] [--no-scripts] [--no-progress] [--no-suggest] [-v|vv|vvv|--verbose] [-o|--optimize-autoloader] [-a|--classmap-authoritative] [--apcu-autoloader] [--ignore-platform-reqs] [--] [<packages>]...
About this issue
- Original URL
- State: closed
- Created 7 years ago
- Reactions: 1
- Comments: 28 (9 by maintainers)
Commits related to this issue
- https://stackoverflow.com/questions/47897823/use-openssl-1-0-2-in-python-on-travis-ci-osx-image composer/composer#6427 — committed to b23prodtm/TravisCI-OSX-PHP by b23prodtm 5 years ago
- https://stackoverflow.com/questions/47897823/use-openssl-1-0-2-in-python-on-travis-ci-osx-image composer/composer#6427 — committed to b23prodtm/TravisCI-OSX-PHP by b23prodtm 5 years ago
- Feature/openssl cross-platform patch (#1) * fix openssl : https://stackoverflow.com/questions/47897823/use-openssl-1-0-2-in-python-on-travis-ci-osx-image composer/composer#6427 * php@7.0 removal d... — committed to b23prodtm/TravisCI-OSX-PHP by b23prodtm 5 years ago
- https://stackoverflow.com/questions/47897823/use-openssl-1-0-2-in-python-on-travis-ci-osx-image composer/composer#6427 — committed to b23prodtm/TravisCI-OSX-PHP by b23prodtm 5 years ago
Mac OS X: Look for the location of your cafile by:
php -r 'var_dump(openssl_get_cert_locations());'
Then set composer to use this (with the example in my case):composer config --global cafile '<location of cafile>'
Example:composer config --global cafile '/usr/local/etc/openssl/cert.pem'
Windows: https://support.microsoft.com/en-us/help/931125/how-to-get-a-root-certificate-update-for-windows
Linux Debian: apt-get install --only-upgrade ca-certificates
RedHat / CentOS: yum update ca-certificates
Ref: https://typo3.org/article/certificate-issue-with-composer/
I agree with @brianlmoon the problem is that composer provides only file or directory and not both. I’m now in the same situation and everything on my mac works nice with the certificates, everything that uses openssl. Except for composer.
Imho composer should have an option/setting to disable the ca-bundle and use the defaults of PHP and OpenSSL.
I’l try to explain it better.
If you specify both cafile and capath, than (like @brianlmoon already mentioned) first it will try to use the cafile and than fallback to the certs in capath.
In the current case composer provides only one of them and forces the usage of only one of them.
This leads to the case that if you provide a cafile it will work for everything which is signed by an official authority. If you provide capath with your custom authority certificate, than only this will be used and not the official CAs. This will make your custom domain working (which is signed with a cert file from capath) but will fail on packagist.org because it is signed by an authority from cafile which was not provided to the context.
This is not the intended behaviour of OpenSSL and breaks composer if you want to use satis hosted on a domain signed by your companies CA and Packagist in parallel.
Still an issue in Composer 1.9.0.
Setting
openssl.cafile
andopenssl.capath
in php.ini instead of relying on defaults “fixes” this, but it shouldn’t be required. PHP works fine with the defaults, but Composer breaks this with unnecessary stream options.@alcohol Maybe this script will help me be more clear.
output:
It only proves my case even more. There is something wrong with your certs. I simply cannot reproduce this scenario.