title: Calling a REST web service over SSL
body: <p>I'm struggling to connect to a REST web service that's working only over HTTPS / SSL from my .NET application.</p>
  
  <p>I received the certificate and private key to use as two separate files - a <code>certificate.pem</code> file which contains the certificate, and the <code>webservice.key</code> file which contains the private key. Those are both text files with BASE64 encoded binary data contained in them.</p>
  
  <p>The provider also sent me a PDF showing how to call that web service using CURL and those two files, and that works just fine:</p>
  
  <pre><code>curl.exe -k -v "https://(URL)" --cert certificate.pem --key webservice.key
  </code></pre>
  
  <p>I need to use the <code>-k</code> option since there seems to be a self-signed certificate somewhere in the hierarchy of certs. Without this option, the call fails.</p>
  
  <p>In order to call this web service from a .NET application (a console app for now), I used OpenSSL (on Windows) to combine these two files into a <code>*.pfx</code> file using this command:</p>
  
  <pre><code>openssl pkcs12 -export -out webservice.pfx -in certificate.pem -inkey webservice.key 
  </code></pre>
  
  <p>This seems to have worked, too - no errors were reported, the file was created and is about 3K in size and it's a totally binary file.</p>
  
  <p>Now, I tried to call that web service from my .NET code something like this:</p>
  
  <pre><code>try
  {
      // use the SSL protocol (instead of TLS)
      ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3;
  
      // ignore any certificate complaints
      ServicePointManager.ServerCertificateValidationCallback += (sender, certificate, chain, sslPolicyErrors) =&gt; { return true; };
  
      // create HTTP web request with proper content type
      HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest;
      request.ContentType = "application/xml;charset=UTF8";
  
      // grab the PFX as a X.509 certificate from disk
      string certFileName = Path.Combine(certPath, "webservice.pfx");
  
      // load the X.509 certificate and add to the web request
      X509Certificate cert = new X509Certificate(certFileName, "(top-secret password)");
      request.ClientCertificates.Add(cert);
      request.PreAuthenticate = true;
  
      // call the web service and get response
      WebResponse response = request.GetResponse();
  
      Stream responseStream = response.GetResponseStream();
  }
  catch (Exception exc)
  {
      // log and print out error
  }
  </code></pre>
  
  <p>However, I can try whatever I like (fiddling around with various settings, on the <code>ServicePointManager</code> and the <code>HttpWebRequest</code>, but I just keep getting these errors:</p>
  
  <blockquote>
    <p>WebException: The underlying connection was closed: An unexpected error occurred on a send.</p>
    
    <p>IOException: Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host.</p>
    
    <p>SocketException: An existing connection was forcibly closed by the remote host </p>
  </blockquote>
  
  <p>and no response - even though communicating with the service with CURL has worked just fine.....</p>
  
  <p>What am I missing?? I'm a bit puzzled and mystified by all those certificates, private keys, service point manager options and so on - just waaaaay too many knob and switches to turn, set or turn off - what are the <strong>RIGHT</strong> settings here?? </p>
  
  <p><strong>Update:</strong></p>
  
  <p>If I use</p>
  
  <pre><code>ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls;
  </code></pre>
  
  <p>then the error just simply is:</p>
  
  <blockquote>
    <p>WebException: The request was aborted: Could not create SSL/TLS secure channel.</p>
  </blockquote>
  
  <p><strong>S O L U T I O N :</strong></p>
  
  <p>In the end, with looking at the output from <code>curl</code> and a lot of help from @Alexandru and @JurajMajer, I was able to get this to work with this code:</p>
  
  <pre><code>try
  {
      // use the TLS protocol 
      ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls;
  
      // create HTTP web request with proper content type
      HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest;
      request.ContentType = "application/xml;charset=UTF8";
  
      // grab the PFX as a X.509 certificate from disk
      string certFileName = Path.Combine(certPath, "webservice.pfx");
  
      // load the X.509 certificate and add to the web request
      X509Certificate2 cert = new X509Certificate2(certFileName, "(top-secret password)");
      request.ClientCertificates.Add(cert);
      request.PreAuthenticate = true;
  
      // call the web service and get response
      WebResponse response = request.GetResponse();
  
      Stream responseStream = response.GetResponseStream();
  
      string xmlContents = new StreamReader(responseStream).ReadToEnd();
  }
  catch (Exception exc)
  {
      // log and print out error
  }
  </code></pre>