Is it possible to implement certificate pinning using the Win32 WinHTTP API, and if so how? I.e. how can I check the returned server certificate against a 'known good' one, preferably without having to permanently write the cert into the local certificate store.
2 Answers
(inspired by jww's answer)
Firstly I found this page to be excellent background reading about pinning and the choice between certificate and public key pinning.
I implemented certificate pinning using WinHTTP API as follows:
After WinHttpOpen but before WinHttpConnect, setup a callback for when requests are sent:
WinHttpSetStatusCallback(hSession, &callbackFunc, WINHTTP_CALLBACK_SENDING_REQUEST, NULL);
In the callback function, retrieve the raw certificate blob:
PCCERT_CONTEXT pCert=NULL; DWORD dwSize=sizeof(pCert); WinHttpQueryOption(hInternet, WINHTTP_OPTION_SERVER_CERT_CONTEXT, &pCert, &dwSize);
Then if doing full certificate pinning, compare
sha1(pCert->pbCertEncoded)
against a known good certificate SHA1 thumbprint.-Or- if doing public key pinning instead, compare
sha1(pCert->pCertInfo->SubjectPublicKeyInfo.PublicKey.cbData)
against a known good SHA1 of a server public key.

- 4,694
- 27
- 45
-
Note that you usually want to hash the full Subject Public Key Info (SPKI), for security and to match the pins used in HTTP Public Key Pinning (RFC 7230). You can get this using `CryptEncodeObject(X509_ASN_ENCODING, X509_PUBLIC_KEY_INFO, ...)` before hashing. Incidentally, WINHTTP_CALLBACK_STATUS_SENDING_REQUEST now also seems to be deprecated, with no obvious replacement available :-( – bobince Aug 24 '15 at 13:48
-
You don't need to implement a sha1 function. Instead, use this API `CertGetCertificateContextProperty(pCertContext, CERT_HASH_PROP_ID, thumbprint, &thumbprint_size)` to get the thumbprint, i.e. the SHA1 hash. – Robert Jan 28 '21 at 03:15
Is it possible to implement certificate pinning using the Win32 WinHTTP API, and if so how?
It looks like you can pin the certificate. You can set a callback with WINHTTP_STATUS_CALLBACK
. When the callback is invoked with WINHTTP_CALLBACK_STATUS_CONNECTED_TO_SERVER
, you can check the certificate with WinHttpQueryOption
and WINHTTP_OPTION_SECURITY_CERTIFICATE_STRUCT
. The server certificate is returned in a WINHTTP_CERTIFICATE_INFO
structure.
There's a page at SSL in WinHTTP that offers more information.
... without having to permanently write the cert into the local certificate store.
The problem with the certificate store is another authority could claim to certify the site you're connecting to. In this case, the real trusted authority does not even need to be in the store to get pwn'd. That's one of the [obvious] problem with the web app/browser security model and the CA Zoo.

- 97,681
- 90
- 411
- 885
-
1Hi your answer pointed me in the right direction but can I propose two changes before I accept: (1) WINHTTP_OPTION_SECURITY_CERTIFICATE_STRUCT does not give enough information to pin the certificate, use WINHTTP_OPTION_SERVER_CERT_CONTEXT instead to get the full encoded cert. And (2) WINHTTP_CALLBACK_STATUS_CONNECTED_TO_SERVER is deprecated and also happens before the cert is available - WINHTTP_CALLBACK_STATUS_SENDING_REQUEST works instead. – snowcrash09 Aug 05 '14 at 15:29
-
1@snowcrash09 - no big deal. Provide your own answer and accept it. I won't take offense and I'll upvote it because its a better answer :) That's how SO works. – jww Aug 05 '14 at 15:42