1

I get this error : Fatal error: Curl failed with error #58: unable to use client certificate (no key found or wrong pass phrase?)

I have a script that extracts the certificate information from a .p12 file. I thought this was the problem to start, however I used this to paste the contents of my generated .pem file : https://www.sslshopper.com/certificate-decoder.html and it decodes/sees it all fine. So I assume the .pem is ok.

$ch = curl_init();
            curl_setopt ($ch, CURLOPT_SSL_VERIFYHOST, 0);
                  curl_setopt ($ch, CURLOPT_SSL_VERIFYPEER, 0); 
            curl_setopt($ch, CURLOPT_URL, $url);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
            curl_setopt($ch, CURLOPT_SSLCERT, 'cert.pem'); 
            curl_setopt($ch, CURLOPT_TIMEOUT, 10);
            curl_setopt($ch, CURLOPT_POST, true);
            curl_setopt($ch, CURLOPT_POSTFIELDS, $xml_post_string);
            curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
            // converting
            $response = curl_exec($ch); 
            // converting
            $response1 = str_replace("<soap:Body>","",$response);
            $response2 = str_replace("</soap:Body>","",$response1);
            if($response === false){
              throw new Exception(curl_error($ch), curl_errno($ch));
            }

The pem file is as such :

-----BEGIN CERTIFICATE-----
<cert bla bla>
-----END CERTIFICATE-----
-----BEGIN PRIVATE KEY-----
<key bla bla>
-----END PRIVATE KEY-----
-----BEGIN CERTIFICATE-----
<cert bla bla>
-----END CERTIFICATE-----–

Any suggestions welcomed.

Thanks

Mark
  • 2,423
  • 4
  • 24
  • 40
  • I think you also need to provide an SSL key; though, perhaps, what you may want to try is use `CURLOPT_CAINFO` instead. – Ja͢ck Nov 17 '14 at 16:24
  • 3
    Independently of your specific problem, using `curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0)` and `curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0)` is [generally a bad idea](http://stackoverflow.com/a/13742121/372643). – Bruno Nov 17 '14 at 16:52
  • 3
    Pasting what you've decoded from the .p12 file into a remote website is also a bad idea, if this contains your private key too. – Bruno Nov 17 '14 at 16:54
  • 1
    Does your extraction script produce something that says `-----BEGIN PRIVATE KEY-----` or just `-----BEGIN CERTIFICATE-----`? – Bruno Nov 17 '14 at 19:59
  • -----BEGIN CERTIFICATE----- -----END CERTIFICATE----- -----BEGIN PRIVATE KEY----- -----END PRIVATE KEY----- -----BEGIN CERTIFICATE----- -----END CERTIFICATE----- – Mark Nov 17 '14 at 22:05

1 Answers1

-2

Firstly a couple of comments:

  • By using these settings, you're opening yourself to potential MITM attacks:

    curl_setopt ($ch, CURLOPT_SSL_VERIFYHOST, 0);
    curl_setopt ($ch, CURLOPT_SSL_VERIFYPEER, 0);
    

    You'd normally want VERIFYHOST=2 and VERIFYPEER=true (which should be the default anyway). Doing the verification correctly also implies you're going to need to set up a CA cert or the server cert in CAINFO or CAPATH. I'll quote the PHP/curl documentation for this option here:

    Alternate certificates to verify against can be specified with the CURLOPT_CAINFO option or a certificate directory can be specified with the CURLOPT_CAPATH option.

  • Pasting your private key (which you get in the -----BEGIN PRIVATE KEY----- block) into a remote website you don't know much about isn't necessarily a good idea. Your private key is meant to remain private. You can use openssl x509 and openssl rsa to check the formats are as you expect.

There are two options in libcurl: CURLOPT_SSLCERT and CURLOPT_SSLKEY, for the certificate and its private key, respectively. I must admit I haven't tried the PHP cURL bindings recently, and some tools will indeed let you put both cert and private key in the same file (like you've done), but while some comments in the PHP documentation suggest you can do this, this isn't really mentioned in libcurl's documentation (you're not using the P12 format here). In addition, libcurl itself doesn't document CURLOPT_SSLCERTPASSWD (which would make sense for a password-protected key in the cert file), so there might be some slight difference in the PHP bindings and libcurl itself (you'll find most other options are almost a direct mapping).

I'd suggest moving what's between -----BEGIN/END PRIVATE KEY----- into a separate file and pointing CURLOPT_SSLKEY to that file path, and keeping the certificate (and presumably its chain, the following certs) with the current settings. Make sure the certificate chain is in the right order, in particular make sure that the first one is your client cert (for which you have the private key). You can check the content of each -----BEGIN/END CERTIFICATE----- block by pasting it into the standard input of openssl x509 -text -noout. Each of these blocks will give you a subject and issuer. A certificate with Subject X and Issuer Y should be followed by a certificate with Subject Y and Issuer Z (and so on).

Community
  • 1
  • 1
Bruno
  • 119,590
  • 31
  • 270
  • 376
  • @Mark, someone visibly didn't like this answer (not sure why) but I'd still recommend to try to split the private key into a separate file. Just wondering if that helped you in the right direction. (Another thing is that you need to make sure your PHP script is allowed to read those files. That's obvious but can easily be overlooked.) – Bruno Nov 19 '14 at 11:23