Trying to make CURL in PHP work with a self signed certificate. I've made a copy of the cert file available to the client code, and I specify the path to the cert file both in CURLOPT_CAINFO and CURLOPT_CAPATH. Still, I'm getting error 60: SSL certificate problem: unable to get local issuer certificate.
Here are the repro steps. All on Linux (Debian Stretch in my case). Replace example.com with a relevant hostname.
First, I'd generate a private key:
openssl genrsa -out key.pem 2048
Compose a config file:
[req]
prompt=no
distinguished_name=dn
req_extensions=ext
x509_extensions=ext
[dn]
emailAddress=seva#example.com
CN=example.com
O=Seva Alekseyev
L=Chicago
ST=IL
C=US
[ext]
keyUsage=digitalSignature,keyEncipherment
extendedKeyUsage=serverAuth
subjectAltName=#alt
[alt]
DNS=example.com
Save as req.txt, generate a self signed cert:
openssl req -x509 -new -config req.txt -days 3650 -key key.pem -out example.cer
Install example.cer and key.pem in Apache under hostname example.com. Browse to make sure the basic setup works (modulo the scary security message).
Now, the client. Placed a copy of example.cer under $path. The PHP code goes:
$cu = curl_init("https://example.com/");
curl_setopt_array($cu, array(
CURLOPT_HEADER => false,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CAINFO => "$path/example.cer",
CURLOPT_CAPATH => "$path/example.cer"
));
$r = curl_exec($cu);
$c = curl_errno($cu);
$s = curl_error($cu);
curl_close($cu);
echo "$c $s";
Then the error message.
What am I missing here? Some guides suggest the value of CURLOPT_CAINFO/CAPATH should a folder instead, with serial-based symlinks pointing to cert files. Tried that too, same error. The document at https://curl.haxx.se/docs/sslcerts.html says:
Get a CA certificate that can verify the remote server and use the proper option to point out this CA cert for verification when connecting.
But there's no CA there, no cert chain. The signing cert is itself. Should I somehow transform the cert so that CURL sees it as a CA one? Should I generate a fake CA cert first, and sign the SSL cert with that one?
Command line curl, as in curl --cacert example.cer https://example.com/, pops the same message.
Related question here, but I'd rather not mess with systemwide settings.
The certificates pointed to by CURLOPT_CAINFO/CAPATH are expected to be CA certificates - at least when OpenSSL is used. This means that your self-signed certificate need also to be a CA certificate, i.e. it should not only be for serverAuth but also have basic constraints CA:true.
The keyUsage line under [ext] must include keyCertSign, like this:
keyUsage=digitalSignature,keyEncipherment,keyCertSign
Otherwise, it's not a CA cert as far as OpenSSL is concerned.
OBTW, the basicConstraints=CA:true line under [ext], suggested by Steffen, is not necessary, I've checked. At least with CURL 7.52.1 and OpenSSL 1.0.2r it's not.
In the client code, CURLOPT_CAPATH is not necessary, either. CURL supports two alternative ways of specifying the root CA cert bundle. CURLOPT_CAINFO makes CURL read and parse a single file, potentially with multiple certificates in it. CURLOPT_CAPATH makes CURL scan a directory with certificate files identified by their serial numbers - or symlinks to those, as generated by c_rehash. Since in my scenario the effective root CA cert bundle has exactly one cert, the one file approach is sufficient.
Doesn't work under Windows, at least with command line CURL 7.55.1. The Windows version of CURL uses the built-in Schannel library for its SSL implementation, and ignores the --cacert option, instead relying on Windows' built-in trusted CA store. See here.
It might be possible to rebuild CURL for Windows against a different SSL implementation, but the trouble is hardly worth it. Windows comes with its own fleet of HTTP(S) clients.
A week ago I was testing some components in WAMP with PHPMailer and everything worked correctly. The next day it just stopped working. No configuration in WAMP has changed. Using SMTPDebug this is the following error when I try to send an email:
Connection failed. Error #2: stream_socket_enable_crypto(): SSL
operation failed with code 1. OpenSSL Error
messages:error:14090086:SSL
routines:ssl3_get_server_certificate:certificate verify failed
[C:...\SMTP.php line 404]
I did other tests using the x86 version of WAMP and XAMPP (I currently use x64 WAMP) but without success, I get the same error.
All tests were performed with gmail "Allow less secure apps" enabled.
After a quick search in the documentation I discovered that the problem is due to verification of the SSL certificate. And as a workaround I can use the following code to skip this check:
$mail->SMTPOptions = array(
'ssl' => array(
'verify_peer' => false,
'verify_peer_name' => false,
'allow_self_signed' => true
)
);
But as has been said, this is a workaround. I wanted to know where the source of the problem is, I do not understand why it stopped working. I have already tried replacing the certificates in the WAMP / XAMPP folders but without success. Also did extensive research but no results. Any idea how I can solve the certificate verification problem without any workaround?
possible duplicate: Warning: stream_socket_enable_crypto(): SSL operation failed with code 1
there is lot of configs that makes this error come up. but more often is that your system's configuration is not set properly. to do it correctly follow this: 1- check if have cacert.pem file for OPENSSL or not if you have not, download proper version from of cacert.pem according to your php version and config your php.ini file as "2-"
2- if you have this file then you have to lookup inside of your php.ini file and see if it has been set in it or not. to do so: lookup for line
openssl.cafile ="example address..\cacert.pem"
if you find the line with an specific address, look for cacert.pem file in that address, if you find it, than it is all done with cacert.pem file. else, you should use the correct address.
hope this help you.. good luck..!
I'm attempting to interface with the Google PHP API client and I am having issues with the certificate provided by Google:
Google error:
SSL certificate problem, verify that the CA cert is OK.
Retrying with the CA cert bundle from google-api-php-client.
PHP cURL error:
SSL certificate problem: unable to get local issuer certificate
I had no problems whatsoever on a Linux box. These errors are occuring on a Windows box.
I've tried a couple of different solutions:
https://code.google.com/
http://richardwarrender.com/
but to no avail.
PS:
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
won't be acceptable ...
Courtesy of rmckay at webaware dot com dot au:
Please everyone, stop setting CURLOPT_SSL_VERIFYPEER to false or 0. If your PHP installation doesn't have an up-to-date CA root certificate bundle, download the one at the curl website and save it on your server:
http://curl.haxx.se/docs/caextract.html
Then set a path to it in your php.ini file, e.g. on Windows:
curl.cainfo=c:\php\cacert.pem
Turning off CURLOPT_SSL_VERIFYPEER allows man in the middle (MITM) attacks, which you don't want!
\Google_Client::$io->setOptions(array(CURLOPT_SSL_VERIFYPEER => FALSE));
#sKophek is correct and I appreciate the help as I was struggling with this. For those that prefer a touch more detail, here it is: (this is true, at least, for the 0.6.x version of the google-api-php-client)
1) \google-api-php-client\src\io\Google_CurlIO.php
2)
private $curlParams = array (
...
CURLOPT_SSL_VERIFYPEER => false,
... );
I am successfully connecting, using Microsoft C#, to a Microsoft web service. I have to supply a username, password (in the C# code); and install a certificate (in .cer format) into the "Root Certificate Authorities" section of the system's certificates.
How can I connect to such a web service in PHP? The reason I ask is that all methods I have seen (such as wsdl2php, which creates a SoapClient subclass), seem to assume various things, such as SSL certificate, SSL key file and SSL key passphrase.
So it all confuses me. I'm not sure what should go where. I'm not sure where my "root certificate authority" (the .cer file) should go, and where the username and password should go. Any ideas?
all can be done whith soapclient and stream_context_create using ssl options
<?php
$context = stream_context_create(array(
'https' => array(
'cafile' => '/path to file',
'verify_peer' => true
)));
new soapclient("https://localhost/index.php?wsdl",array(
'login'=>'admin',
'password'=>'passss',
'stream_context'=> $context
));
it is not uncommon in soap to not use http auth but just an soap-call, the documnetation is essential
it can be rewarding to use soapclient whith classes using classmap to map soaptypes to php clases
Typically if you're calling a webservice using regular SSL your URL will look like:
https://username:password#myserver.com/mywebservice.php
Then there is the issue of the SSL certificate. I'm using something similar to read from an SSL protected SVN web front. I don't know of any other solution other than to log into the server as the user that is running your webserver (apache/IIS) and accepting the certificate manually. In the case of SVN you could make a checkout and it will ask you to accept the certificate. I'm not entirely sure how this would work for a plain HTTPS request but perhaps you can get the certificate by loading the webservice in a browser? (or using wget or something fancy if you're lucky enough to be running Linux)
Also, is your code the PHP code or the C# code? If it's C# you may need to do something else entirely.
Sometimes fail to call the web service.
This problem happens all the time.
What could be the problem?
Error:
SoapFault exception: [HTTP] Could not connect to host in
0 [internal function]: SoapClient->__doRequest('<?xml version="...', http://.', '', 1, 0)
The problem was solved.The problem is the cache
ini_set('soap.wsdl_cache_enabled',0);
ini_set('soap.wsdl_cache_ttl',0);
I am adding my comment for completeness, as the solutions listed here did not help me. On PHP 5.6, SoapClient makes the first call to the specified WSDL URL in SoapClient::SoapClient and after connecting to it and receiving the result, it tries to connect to the WSDL specified in the result in:
<soap:address location="http://"/>
And the call fails with error Could not connect to host if the WSDL is different than the one you specified in SoapClient::SoapClient and is unreachable (my case was SoapUI using http://host.local/).
The behaviour in PHP 5.4 is different and it always uses the WSDL in SoapClient::SoapClient.
The host is either down or very slow to respond. If it's slow to respond, you can try increasing the timeout via the connection_timeout option or via the default_socket_timeout setting and see if that reduces the failures.
http://www.php.net/manual/en/soapclient.soapclient.php
http://www.php.net/manual/en/filesystem.configuration.php#ini.default-socket-timeout
You can also include error handling as zanlok pointed out to retry a few times. If you have users actually waiting on these SOAP calls then you'll want to queue them up and process them in the background and notify the user when they're finished.
A misconfigured service leaves the default namespace with tempuri.org
This means the connection to the wsdl will work, but the function call will fail.
Stacktrace:
SoapClient->__doRequest('http://example.com...', 'http://tempuri.org....', 2, 0)
To remediate this, you must explicitly set the location using __setLocation()
$this->soapClient = new \SoapClient(WS_URL);
$this->soapClient->__setLocation(WS_URL);
This work for me
$opts = array(
'ssl' => array('verify_peer' => false, 'verify_peer_name' => false)
);
if (!isset($this->soap_client)) {
$this->soap_client = new SoapClient($this->WSDL, array(
'soap_version' => $this->soap_version,
'location' => $this->URL,
'trace' => 1,
'exceptions' => 0,
'stream_context' => stream_context_create($opts)
));
there is a soap config section in your php.ini file, which control the wsdl access cache, may be shown as:
[soap]
; Enables or disables WSDL caching feature.
soap.wsdl_cache_enabled=1 ;
Sets the directory name where SOAP extension will put cache files.
soap.wsdl_cache_dir="/tmp"
; (time to live) Sets the number of second while cached file will be used ; instead of original one.
soap.wsdl_cache_ttl=86400
if wsdl file cache is enabled, it may cause this problem when changing wsdl URI in php code.
in this example, you can just delete file start with wsdl- under /tmp directory.
or you just set soap.wsdl_cache_enabled=0; and soap.wsdl_cache_ttl=0;
PHP will fetch the wsdl file every-time you visit the page.
In our case, it was a Ciphers negotiation problem. We were getting this error randomly. We solved our problem by forcing a Cipher like this:
$soapClient = new SoapClient ('http://example.com/soap.asmx?wsdl',
array (
"stream_context" => stream_context_create (
array (
'ssl' => array (
'ciphers'=>'AES256-SHA'
)
)
)
)
);
Looks like PHP wasn't negotiating the same Ciphers at each service call.
In my case it worked after the connection to the wsdl, use the function __setLocation() to define the location again because the call fails with the error:
Could not connect to the host
This happens if the WSDL is different to the one specified in SoapClient::SoapClient.
I hit this issue myself and after much digging I eventually found this bug for ubuntu:
https://bugs.launchpad.net/ubuntu/+source/openssl/+bug/965371
specifically
https://bugs.launchpad.net/ubuntu/+source/openssl/+bug/965371/comments/62
openssl s_client -connect site.tld:443 failed however openssl s_client -tls1 -connect site.tld:443 gave success. In my particular case part of the output included
New, TLSv1/SSLv3, Cipher is RC4-MD5 so I set the php context ssl/cipher value appropriately.
It seems the error SoapFault exception: Could not connect to host can be caused be several different things. In my cased it wasn't caused by proxy, firewall or DNS (I actually had a SOAP connection from the same machine working using nusoap without any special setup).
Finally I found that it was caused by an invalid pem file which I referenced in the local_cert option in my SoapClient contructor.
Solution:
When I removed the certificate chain from the pem file, so it only contained certificate and private key, the SOAP calls started going through.
For me it was a certificate problem. Following worked for me
$context = stream_context_create([
'ssl' => [
// set some SSL/TLS specific options
'verify_peer' => false,
'verify_peer_name' => false,
'allow_self_signed' => true
]
]);
$client = new SoapClient(null, [
'location' => 'https://...',
'uri' => '...',
'stream_context' => $context
]);
In my case service address in wsdl is wrong.
My wsdl url is.
https://myweb.com:4460/xxx_webservices/services/ABC.ABC?wsdl
But service address in that xml result is.
<soap:address location="http://myweb.com:8080/xxx_webservices/services/ABC.ABC/"/>
I just save that xml to local file and change service address to.
<soap:address location="https://myweb.com:4460/xxx_webservices/services/ABC.ABC/"/>
Good luck.
I finally found the reason,its becuse of the library can't find a CA bundle on your system.
PHP >= v5.6 automatically sets verify_peer to true by default. However, not all systems have a known CA bundle on disk .
You can try one of these procedures:
1.If you have a CA file on your system, set openssl.cafile or curl.cainfo in your php.ini to the path of your CA file.
2.Manually specify your SSL CA file location
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
curl_setopt($cHandler, CURLOPT_CAINFO, $path-of-your-ca-file);
3.disabled verify_peer
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
For those who struggled the same as me with laravel artisan console command that makes a lot of requests to same wsdl of external soap server and then after some time fails with Could not connect to host error.
The problem was because I was creating new SoapClient instance each time before request was made. Do not do that. Create it once and make each request from the same client.
Hope it helps.
For me it was a DNS issue. My VPS's nameservers crapped out, so I switched to Google's by editing my /etc/resolv.conf to be:
nameserver 8.8.8.8
nameserver 8.8.4.4
If you have a firewall on your server, make sure to open the port used by SOAP.
In my case, I had to open the port 1664.
iptables -t filter -A INPUT -p tcp --dport 1664 -j ACCEPT
iptables -t filter -A OUTPUT -p tcp --dport 1664 -j ACCEPT
if ujava's solution can't help you,you can try to use try/catch to catch this fatal,this works fine on me.
try{
$res = $client->__call('LineStopQueryJson',array('Parameters' => $params));
}catch(SoapFault $e){
print_r($client);
}
With me, this problem in base Address in app.config of WCF service:
When I've used:
<baseAddresses><add baseAddress="http://127.0.0.1:9022/Service/GatewayService"/> </baseAddresses>
it's ok if use .net to connect with public ip or domain.
But when use PHP's SoapClient to connect to "http://[online ip]:9022/Service/GatewayService", it's throw exception "Coulod not connect to host"
I've changed baseAddress to [online ip]:9022 and everything's ok.
Another possible reason for this error is when you are creating and keeping too many connections open.
SoapClient sends the HTTP Header Connection: Keep-Alive by default (through the constructor option keep_alive). But if you create a new SoapClient instance for every call in your queue, this will create and keep-open a new connection everytime. If the calls are executed fast enough, you will eventually run into a limit of 1000 open connections or so and this results in SoapFault: Could not connect to host.
So make sure you create the SoapClient once and reuse it for subsequent calls.
I had a bad php.ini configuration. Verify the path and the certificate validity...
[openssl]
openssl.cafile = "C:/good/phpath/ca-bundle.crt"
Because my new \SoapClient($wsdl) was https !
Just to help other people who encounter this error, the url in <soap:address location="https://some.url"/> had an invalid certificate and caused the error.
For me, this was a problem in the httpd service (Fedora 24). A simple restart did the trick:
sudo service httpd restart
If the connection is through SSL, could be a problem of server instead of client (it is my case).
In PHP versions greater than 5.6 and 7, is important to check the CipherSuite used in server certificate.
There is a full list of ciphers allowed by this versions and a full list of ciphers that do not in this web link: https://wiki.mozilla.org/Security/Server_Side_TLS#Recommended_Ciphersuite
If the cipher used is not allowed (it is a deprecated algorithm), SoapClient receives "Could not connect to host" and there is no more trace about it.
The cipher used can be checked by clients like SoapUI in the section of "SSL Info", for example.
There is no thread forum treating about this in internet.
Check this out, too: http://php.net/manual/en/migration56.openssl.php
In my case the host requires TLS 1.2 so needed to enforce using the crypto_method ssl param.
$client = new SoapClient($wsdl,
array(
'location' => $location,
'keep_alive' => false,
"stream_context" => stream_context_create([
'ssl' => [
'crypto_method' => STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT,
]
]),
'trace' => 1, // used for debug
)
);
In my case, disabled SELINUX allow PHP to call my WebService.
I run PHP in FPM with Apache2
SELinux status :
# sestatus
Disable SELinux :
setenforce 0
Enable SELinux :
# setenforce 1
Permanent disable :
edit this file /etc/selinux/config
Version check helped me OpenSSL. OpenSSL_1_0_1f not supported TSLv.1_2 !
Check version and compatibility with TSLv.1_2 on github openssl/openssl
. And regenerate your certificate with new openssl
openssl pkcs12 -in path.p12 -out newfile.pem
P.S I don’t know what they were minus, but this solution will really help.
That most likely refers to a connection issue. It could be either that your internet connection was down, or the web service you are trying to use was down. I suggest using this service to see if the web service is online or not: http://downforeveryoneorjustme.com/