Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

https: certificate pinning #314

Open
marnef opened this issue Dec 15, 2016 · 15 comments
Open

https: certificate pinning #314

marnef opened this issue Dec 15, 2016 · 15 comments

Comments

@marnef
Copy link

marnef commented Dec 15, 2016

Hi all,

I'm trying to implement certificate pinning. This means that the server is sending the untrusted certificate [which is why I need to call http_client_config::set_validate_certificates(false) -> unsafe] and I have to compare its public key or a hash value of it with a value known at compile time. That's all under Windows, which means there is no set_ssl_context_callback.

Does anyone have an idea how I can install a callback that allows my check of the hash or any other idea? Or how can I access the certificate at all?

@marnef
Copy link
Author

marnef commented Dec 16, 2016

To make it clearer: I want to inject a method that checks the certificate during SSL handshake. If the method returns true the certificate is accepted.

@marnef
Copy link
Author

marnef commented Dec 21, 2016

Here is an example how easy that works in .net: https://www.owasp.org/index.php/Certificate_and_Public_Key_Pinning#.Net

I think a good solution would be an analog callback in the http_client_config class. It would be called in asio_connection:async_handshake.

@deeringc
Copy link
Contributor

Have a look, it's been implemented in this fork: https://github.com/glukacsy/cpprestsdk

@marnef
Copy link
Author

marnef commented Dec 30, 2016

Thank you for that information. Good to see that there is progress on that topic. Although the discussion on #135 seems to have been stopped some time ago.

@idotene
Copy link

idotene commented Jun 12, 2017

I'm looking forward for a solution for certificate pinning as well, for linux & OSX though.

@marnef
Copy link
Author

marnef commented Jun 15, 2017

My workaround is the following (under Windows, but probably you can adapt for other OS):

::HINTERNET hInternet = nullptr;
http_client_config config;
config.set_nativehandle_options([&](native_handle hNative)
{ if(hInternet == nullptr) hInternet = reinterpret_cast<::HINTERNET>(hNative);
});

bool bCertTested = false;
http_request request;
rRequest.set_progress_handler([&](message_direction::direction eDirection, utility::size64_t uiProgress)
{ if(hInternet != nullptr && !bCertTested)
{ ::PCCERT_CONTEXT pCertificateEncoded;
DWORD dwCertificateInfoSize = sizeof(pCertificateEncoded);
if(::WinHttpQueryOption(hInternet, WINHTTP_OPTION_SERVER_CERT_CONTEXT, &pCertificateEncoded, &dwCertificateInfoSize))
{ const uint8_t *puiCertificate = reinterpret_cast<const uint8_t*>(pCertificateEncoded->pCertInfo->SubjectPublicKeyInfo.PublicKey.pbData);
size_t uiCertificateSize = pCertificateEncoded->pCertInfo->SubjectPublicKeyInfo.PublicKey.cbData;
::CertFreeCertificateContext(pCertificateEncoded);
...

@marnef
Copy link
Author

marnef commented Jun 15, 2017

Not so nice about this solution: The content is downloaded before the certificate is checked. I consider a certificate error as just that and so for me that is ok.

@idotene
Copy link

idotene commented Jun 15, 2017

Hi @marnef, I tried to implement this for linux, yet in my case the appropriate object is SSL (instead of HINTERNET), and it is never filled with the certificate data, not in the progress_handler, and not afterwards when I parse the actual response.
I suspect that the SSL object is freed before calling to the progress handler.
What I plan to do now is cloning the sources and try fixing the http_client_asio file so it will check the certificate according to the configuration.
Currently it is checked with a predefined method and ignoring the injected method in the configuration.
The method to change is 'handle_cert_verification' inside http_client_asio

@idotene
Copy link

idotene commented Jun 18, 2017

Anyway as suggested above, in order to achieve pinning here is what I did:

In the file https://github.com/Microsoft/cpprestsdk/blob/master/Release/src/http/client/http_client_asio.cpp

override the method

bool handle_cert_verification(bool preverified, boost::asio::ssl::verify_context &verifyCtx)
then recompile the library and replace it in your project.

The correct fix is to call the predefined set_verify_callback, which should be done in http_client_asio instead of calling a predefined validation function.

@Tom883
Copy link

Tom883 commented Jul 23, 2017

Hi @marnef ,
How did you end up solving this issue?
I'm currently facing the same problem on windows .

@marnef
Copy link
Author

marnef commented Jul 24, 2017

Hi @Tom883, see my comment from June 15. It works fine, but is not really nice because it's OS dependent.

@chogorma
Copy link

chogorma commented Aug 8, 2017

Hi,
We have updated how we do our cert-pinning: https://github.com/glukacsy/cpprestsdk

The design changed along with our requirements for accepting the certificate chain.
What happens now, Casablanca calls back with the encoded data of the full certificate chain, where using OpenSSL the consumer will decide on whether to accept or reject the connection.

Using this approach we leave the validation of the certificate chain up to the consumer of casablanca.

@matra774
Copy link

@chogorma, can you prepare pull requests? This seams like a really useful option.

@chogorma
Copy link

@matra774, yes i can do that, will get the PR open as soon as i can.

@chogorma
Copy link

Opened a PR for the approach we have taken: #702

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants