I'm trying to connect to an API that uses a self-signed SSL certificate. I'm doing so using .NET's HttpWebRequest and HttpWebResponse objects. And I'm getting an exception that:
The underlying connection was closed: Could not establish trust relationship for the SSL/TLS secure channel.
I understand what this means. And I understand why .NET feels it should warn me and close the connection. But in this case, I'd like to just connect to the API anyway, man-in-the-middle attacks be damned.
So, how do I go about adding an exception for this self-signed certificate? Or is the approach to tell HttpWebRequest/Response not to validate the certificate at all? How would I do that?
Self signed certificates are not strictly worse than certificates signed by a reputable CA, and in all technical ways they are better than plain HTTP. From the signing and encryption perspective they are identical. Both can sign and encrypt traffic so that it is not feasible for others to snoop or make modifications.
Import the self-signed certificate to the client Windows computer. On the Windows computer, start MMC (mmc.exe). Add the Certificates snap-in for the computer account and manage certificates for the local computer. Import the self-signed certificate into Trusted Root Certification Authorities > Certificates.
Turns out, if you just want to disable certificate validation altogether, you can change the ServerCertificateValidationCallback on the ServicePointManager, like so:
ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
This will validate all certificates (including invalid, expired or self-signed ones).
@Domster: that works, but you might want to enforce a bit of security by checking if the certificate hash matches what you expect. So an expanded version looks a bit like this (based on some live code we're using):
static readonly byte[] apiCertHash = { 0xZZ, 0xYY, ....}; /// <summary> /// Somewhere in your application's startup/init sequence... /// </summary> void InitPhase() { // Override automatic validation of SSL server certificates. ServicePointManager.ServerCertificateValidationCallback = ValidateServerCertficate; } /// <summary> /// Validates the SSL server certificate. /// </summary> /// <param name="sender">An object that contains state information for this /// validation.</param> /// <param name="cert">The certificate used to authenticate the remote party.</param> /// <param name="chain">The chain of certificate authorities associated with the /// remote certificate.</param> /// <param name="sslPolicyErrors">One or more errors associated with the remote /// certificate.</param> /// <returns>Returns a boolean value that determines whether the specified /// certificate is accepted for authentication; true to accept or false to /// reject.</returns> private static bool ValidateServerCertficate( object sender, X509Certificate cert, X509Chain chain, SslPolicyErrors sslPolicyErrors) { if (sslPolicyErrors == SslPolicyErrors.None) { // Good certificate. return true; } log.DebugFormat("SSL certificate error: {0}", sslPolicyErrors); bool certMatch = false; // Assume failure byte[] certHash = cert.GetCertHash(); if (certHash.Length == apiCertHash.Length) { certMatch = true; // Now assume success. for (int idx = 0; idx < certHash.Length; idx++) { if (certHash[idx] != apiCertHash[idx]) { certMatch = false; // No match break; } } } // Return true => allow unauthenticated server, // false => disallow unauthenticated server. return certMatch; }
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