I would like to set up communication between two applications that are secured via TLS 1.2 wherein the public keys of the end-points are pinned. (No certificate authorities involved.)
Further, I don't even want to deal with certificates; just RSA/ECDSA public keys.
Specifically, they are both PHP applications and I'm using curl to facilitate the communication.
Has anyone accomplished this before?
Curl is as secure as a normal HTTP request.
Due to HPKP mechanism complexity and possibility of accidental misuse, browsers deprecated and removed HPKP support in favor of Certificate Transparency and its Expect-CT header.
SSL Pinning Bypass can be prevented using two-way SSL authentication. Using this technique, application acts as SSL client and send its certificate to the SSL server to validate after SSL server validates itself to the SSL client.
The SSL pinning (or public key, or certificate pinning) is a technique mitigating Man-in-the-middle attacks against the secure HTTPS communication. The typical Android solution is to bundle the hash of the certificate, or the exact data of the certificate into the application.
Finally this feature has been implemented in PHP and you can also use it in older PHP versions as long as your cURL version is sufficient!
You can use SHA-256 hashes of the public key(s) in DER format for pinning. Do not confuse this with the certificate fingerprints! You'll pin the public keys, not the certificate here.
It's best to referrer to the official cURL documentation for extracting this keys. However there might be an easier way: The format of the pins is the same as the one used in HPKP. Thus if the webserver uses HPKP I strongly recommend you to use the hashes it sends there! You can simply copy and paste them from the header. You just have to change the format a bit as shown below.
Public-Key-Pins: pin-sha256="cUPcTAZWKaASuYWhhneDttWpY3oBAkE3h2+soZS7sWs="; pin-sha256="M8HztCzM3elUxkcjR2S5P4hhyBNf6lHkmjAHKhpGPWE="; max-age=5184000;
gets to:
sha256//cUPcTAZWKaASuYWhhneDttWpY3oBAkE3h2+soZS7sWs=;sha256//M8HztCzM3elUxkcjR2S5P4hhyBNf6lHkmjAHKhpGPWE
However please note that there is one big difference between HPKP and CURL's CURLOPT_PINNEDPUBLICKEY
: In HPKP you can pin the public keys of intermediate certificates, when using CURL you currently cannot do this!
As there are already many tutorials for HPKP you can also find other good guides for creating these hashes. Here is e.g. an one-liner using an existing certificate file by Scott Helme:
openssl x509 -pubkey < tls.crt | openssl pkey -pubin -outform der | openssl dgst -sha256 -binary | base64
The format of the option finally is shown below. You can pin as much keys as you want and I would also recommend pinning at least one backup key, which is not currently in use, so you can easily switch keys in case of a server breach or something similar.
sha256//Base64EncodedHashOfPublicKey;sha256//Base64EncodedHashOfAnotherPublicKey
Alternatively you can also specify a path to a certificate file instead if you want.
In PHP you can afterwards use it like this:
<?php
// this line makes it possible to use that option in PHP < 7.0.7
defined('CURLOPT_PINNEDPUBLICKEY') || define('CURLOPT_PINNEDPUBLICKEY', 10230);
$ch = curl_init("https://example.com");
curl_setopt($ch, CURLOPT_PINNEDPUBLICKEY, "YourPinsHere!!");
// ...
Afterwards you should test it by specifying an invalid pin. If it does not fail either your requirements are not met or you did an error when implementing it. You can also test it on the console with this command:
curl https://example.com --pinnedpubkey "YourPinsHere!!"
I didn't know the solution, but I can offer you some directions to discover:
Take a look at http://php.net/manual/en/function.curl-setopt.php Particularly at CURLOPT_SSH_HOST_PUBLIC_KEY_MD5 option. It's not allow to verify full public key, just its md5 hash.
As another variant, you can implement your own service dealing with CURL through console. It's allow you to pass any options to curl. It's out of default curl library.
(No certificate authorities involved.)
By default, curl is setup to not trust any CAs. So there's that. And without going into great detail or opinion based responses, here's a well organized "Pinning Cheat Sheet" that may be of some help to you: https://www.owasp.org/index.php/Pinning_Cheat_Sheet (no bounty necessary <3)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With