Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MAMP & PHP “SSL operation failed with code 1”

EDIT I’m on the move at the moment, and only have SO on the Stack Exchange app on my iPhone, so there’s some weird formatting with the quotes in the code below - Apologies! I have real ones in the real code :)

I’ve been trying to figure this out for two days with some other questions on SO, but here goes...

Just trying to use file_get_contents() to capture the webpage of another file located on the same server and same domain, and include that. I’m using MAMP with a self signed cert for production (so that I can have the server force SSL etc) so there’s that, and I also have that certificate as “Always Trusted” locally on my Mac as it’s self-signed obviously.

So now I have the issue where I want one page to capture the contents of another.. I initially tried using cURL and it was failing without giving me any exceptions, and no information using curl_error() so I switched over to file_get_contents() where I get the exception SSL operation failed with code 1... ssl3_get_server_certificate:certificate verify failed

I assume this is in issue with OpenSSL not trusting the self-signed (but I thought it used the trusted CA’s of the underlying OS?) and I can’t get it to work using the following stream context:

stream_context_create([
   "ssl" => [
      "allow_self_signed" => true
   ]
]);

And if I set verify_peer and verify_peer_name to false, the request is made but HTTPS cookies aren’t sent which breaks the whole thing.

I’ve tried adding the actual text of the cert to the cacert.pem file under the OpenSSL directory in MAMP, and set that file in the openssl.cafile option in the php.ini file as stated in another answer, but alas no luck...

Any ideas? Your help would be much appreciated! Thank you! ☺️💛

EDIT 2 So I tried it again using cURL, and this time got cURL to give me some verbose output to a file, and this is what it gives me (note the line third from the bottom):

*   Trying ::1...
* TCP_NODELAY set
* Connected to admin.voyagerisc (::1) port 8890 (#0)
* ALPN, offering http/1.1
* Cipher selection: ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!LOW:!RC4:@STRENGTH
* successfully set certificate verify locations:
*   CAfile: /Applications/MAMP/Library/OpenSSL/certs/cacert.pem   CApath: none
* SSL certificate problem: unable to get local issuer certificate
* Curl_http_done: called premature == 1
* Closing connection 0

...and this is the file where I have added the raw certificate to the top.. ugh, STUCK!

like image 486
FrankieDee Avatar asked Jan 01 '23 11:01

FrankieDee


2 Answers

TLDR; You need to become your own (mini) CA so you have a Root Cert that can be trusted

So after a few painstaking days, I have finally figured this out and I hope below will help those few MAMP / PHP users who will undoubtedly run into this issue!!

Basically, file_get_contents() and cURL operate above OpenSSL, and (as I have now learnt, I was an SSL noob!) OpenSSL, like every device basically has big list of all the main Certificate Authority's root certificates. So if any certificate has been signed by one of those root certificates in can be trusted in the eyes of OpenSSL.

Now you can go into that file that OpenSSL uses that has all the big root certs, and I thought it would be as easy as placing the raw self-signed certificate of the development site at the top of the list and everything would fall into place. However, for some reason OpenSSL wouldn't trust it if it's not a ROOT CERTIFICATE.

So long story short, here's the steps:

  1. Follow this guide to becoming your own CA in literally under 5 minutes. (As a side note, this now means that you can trust just the newly created root certificate, and for every development site you want with SSL, self-sign with that root certificate and you won't need to re-trust etc)
  2. Once you've trusted the root certificate as per the article, and pointed MAMP to the key and certificate for the specific site, in your IDE open up the .pem file for the ROOT CERTIFICATE that you created, NOT the specific one for your development site
  3. For MAMP, the file OpenSSL uses as the core list of trusted Certificate Authorities is located in /Applications/MAMP/Library/OpenSSL/certs/ - Open the cacert.pem in your IDE as well
  4. Now, under the comments and before the first real CA, copy and paste in the raw data of your Root Certificate. You can also add in before that long piece of data (and BEFORE the -----BEGIN CERTIFICATE----- line) the name you set for your Certificate Authority earlier in Step 1, and format it with the ='s as is with the other Certificate Authorities.
  5. The usual: Save & restart MAMP

Now, if you're running a local development server with MAMP and have self-signed SSL enabled, you should now be able to make the SSL calls back to the server itself, and have the server trust.... itself? I guess? Weird when you think about it!

As a final note, if you had visited any other similar questions here on SO, you would've seen many answers prompt you to create either a stream context with get_file_contents() or set some options with your cURL resource that suggested turning "verify_peer" => false & "verify_peer_name" => false in a stream context, or the equivalent options for cURL. I cannot stress enough that the approach completely defeats the purpose of SSL and shouldn't even be used for local development, due to the possibility of you forgetting to turn it back on or some other obscure event that causes trust to remain off within production.

The method I described above is more tedious, yes, but it will get you through development until you have a real SSL cert in production signed by a true CA, at which point this won't even be an issue anymore.

Feel free to comment if this explanation is not clear / precise enough, I'm only still getting my head around it! Cheers :)

like image 197
FrankieDee Avatar answered Jan 05 '23 18:01

FrankieDee


As Mike mentioned (see comments), in the current version of MAMP (6.4) there's an invalid certificate file added to /Applications/MAMP/Library/OpenSSL/certs/cacert.pem. Just open this file and access the link shown in the 301 redirect (https://curl.se/ca/cacert.pem), download it and replace the file.

like image 41
saschanos Avatar answered Jan 05 '23 20:01

saschanos