So I was looking at an example of how to implement public key pinning for when your app connects to your web service and you want to have your app ensure it's really talking to your server.


They do a test HTTPS request and then check the thumbprint of the certificate:

private async Task DemoSSLRoot()
    // Send a get request to Bing
    HttpClient client = new HttpClient();
    Uri bingUri = new Uri("https://www.bing.com");
    HttpResponseMessage response = await client.GetAsync(bingUri);

    // Get the list of certificates that were used to validate the server's identity
    IReadOnlyList<Certificate> serverCertificates = response.RequestMessage.TransportInformation.ServerIntermediateCertificates;

    // Perform validation
    if (!ValidCertificates(serverCertificates))
        // Close connection as chain is not valid

    PrintResults("Validation passed\n");
    // Validation passed, continue with connection to service

private bool ValidCertificates(IReadOnlyList<Certificate> certs)
    // In this example, we iterate through the certificates and check that the chain contains
    // one specific certificate we are expecting
    for(int i=0; i<certs.Count; i++)
        PrintResults("Cert# " + i + ": " + certs[i].Subject + "\n");
        byte[] thumbprint = certs[i].GetHashValue();

        // Check if the thumbprint matches whatever you are expecting
        // ‎d4 de 20 d0 5e 66 fc 53 fe 1a 50 88 2c 78 db 28 52 ca e4 74
        byte[] expected = new byte[] { 212, 222, 32, 208, 94, 102, 252, 83, 254, 26, 80, 136, 44, 120, 219, 40, 82, 202, 228, 116 };

        if (ThumbprintMatches(thumbprint, expected))
            return true;

    return false;

Now my question is: With this approach, couldn't an attacker selectively allow your app to authenticate the first time to your web server and establish that it's trusted, and then immediately switch over to their malicious HTTPS server? It seems so, since only the initial "Hello World" request is validated...

1 Answer 1


During the initial TLS handshake, a "master secret" is created

The client and server then use the random numbers and PreMasterSecret to compute a common secret, called the "master secret". All other key data for this connection is derived from this master secret (and the client- and server-generated random values), which is passed through a carefully designed pseudorandom function.

As this secret is used throughout the communication a MiTM attempting to impersonate either the client or server mid-conversation would need to have the master secret (and likely other secrets) to encrypt and decrypt communication. But being that this secret is only known by the original client and server, a MiTM is impossible (or at least very difficult).

  • But that's just the thing that concerns me. In the example, they initiate a new connection in the DemoSSLRoot function (HttpClient client = new HttpClient();) and it will then fall out of scope when the function ends. When the app performs the "real" connection to start pulling down data, won't it be an entirely new connection, and won't the TLS handshake have to be renegotiated? Or perhaps you have to continue to use the same HTTPClient object?
    – John
    Oct 29, 2015 at 16:19
  • I believe that this comment // Validation passed, continue with connection to service means that you continue the connection in that function using the client variable. Perhaps the comment should have been better written. You are correct that once you let the connection close, you need to redo the entire handshake, cert pinning included. Oct 29, 2015 at 16:28

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .