Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using a self-signed certificate with .NET's HttpWebRequest/Response

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?

like image 615
Dominic Scheirlinck Avatar asked Feb 08 '09 23:02

Dominic Scheirlinck


People also ask

Is self signed certificate better than HTTP?

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.

How do I deploy a self signed certificate?

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.


2 Answers

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).

like image 80
Dominic Scheirlinck Avatar answered Sep 28 '22 11:09

Dominic Scheirlinck


@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; } 
like image 23
devstuff Avatar answered Sep 28 '22 11:09

devstuff