Php SoapClient verify_peer=>true fails with ca-signed certificate

Macke picture Macke · Aug 27, 2013 · Viewed 18.8k times · Source

When doing a soap request to a https soap server using php:s SoapClient fails with a SoapFault:

faultstring: Could not connect to host
faultcode: HTTP

I have to be sure that the soap servers ssl certificate is valid so i am using

 <?php
 $soap=new SoapClient("mwsdl.wsdl"
           ,array(
                  "location"=>"https:examplesoapserver.com"
                  ,"trace"=>1
                  ,"stream_context"=>stream_context_create(array(
                         "ssl"=>array(
                                      "verify_peer"=>true
                                      ,"allow_self_signed"=>false
                                      )
                              )
                           )
                        )
                     );

But this gives me the SoapFault.

I have tested with different settings:

OK
location: has self-signed certificate
verify_peer=>true
allow_self_signed=>true
OK (without setting verify_peer)
location: has self-signed certificate
allow_self_signed=>false
NOT OK
location: has self-signed certificate
verify_peer=>true
allow_self_signed=>false
OK (without setting verify_peer)
location: ca-signed certificate
allow_self_signed=>false
NOT OK
location: ca-signed certificate
verify_peer=>true
allow_self_signed=>false

I have:

php version: 5.3.3
CentOS 6.4
Apache/2.2.15

Ask for more details if it helps figuring out the problem.

Thank you in advance for any help!

Answer

Macke picture Macke · Aug 28, 2013

The problem was that php has by default insecure settings to handle https requests. It will not verify the certificate or check that the domain in the certificate is correct.

You have to download the file that is used to verify the certificate yourself too.

You can download one at: http://curl.haxx.se/ca/cacert.pem

The settings to handle them properly are

<?php
$client = new SoapClient("my-wsdlfile.wsdl"
                ,array(
                       "location"=>"https://examplesoapserver.com"
                       ,"stream_context"=>stream_context_create(
                          array(
                            "ssl"=>array(
                                "verify_peer"=>true
                                ,"allow_self_signed"=>false
                                ,"cafile"=>"path/to/cacert.pem"
                                ,"verify_depth"=>5
                                ,"CN_match"=>"examplesoapserver.com"
                                )
                            )
                        )
                    )
                );

There is the same problem with other php functions that can use https ( like file_get_contents ) so the same solution for makeing it secure should work.

CURL has secure settings by default so if possible it is easier to use it.

Here is a great and more detailed explanation of how php handles https:

http://phpsecurity.readthedocs.org/en/latest/Transport-Layer-Security-(HTTPS-SSL-and-TLS).html#php-streams