0
votes

I have an MVC 5 application that is using NHtmlUnit's WebClient to connect to another website, I am having trouble making that connection while in debug.

The website I am connecting to requires the following protocol and cipher suites: Text

Initially when trying to connect and retrieve HTML from the target site I encountered an error stating: fatal alert: handshake_failure

To solve this I am now specifying the SLLClientProtocols and SSLClientCipherSuites options on the WebClient to include the above protocol and cipher suites. However now the error I receive each time is: cannot support [cipher suite] with currently installed providers

I've updated the local OS to Server 2019 Datacenter (fully updated), my understanding is that this OS version should include support for TLS 1.2 as well as the cipher suites I need (or at least one of them) evidenced here.

Initially the registry at Computer\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols had no key for TLS 1.2 so I added it with sub keys of Client and Server each with DWORDs of "DisabledByDefault" set to 0 and "Enabled" set to 1.

My project targets .NET Framework 4.7.2. I made sure to verify that the web.config file under system.web specifies the framework version for both compilation and runtime:

<system.web>
<customErrors mode="Off" />
<compilation debug="true" targetFramework="4.7.2" />
<httpRuntime targetFramework="4.7.2" maxRequestLength="1048576" executionTimeout="3600" />
<authentication mode="Forms">
  <forms name=".AuthCookie" loginUrl="~/Account/Login" />
</authentication>
<!--<authentication mode="None" />-->
<membership defaultProvider="ADMembershipProvider">
  <providers>
    <clear />
    <add name="ADMembershipProvider" type="System.Web.Security.ActiveDirectoryMembershipProvider" connectionStringName="ADConnectionString" attributeMapUsername="sAMAccountName" />
  </providers>
</membership>
<pages>
  <namespaces>
    <add namespace="GridMvc" />
  </namespaces>
</pages>
</system.web>

I've also added the following to explicitly set the protocol:

System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;

However this doesn't seem to help as I imagine it is forcing TLS 1.2 but the error seems to be focused on the cipher suite. Without that line my understanding is that ServicePointManager.SecurityProtocol will default to a value of SystemDefault which will allow the application to use the underlying operating system TLS version selection defaults. Is it possible that the cipher suites I want are supported by my OS but not part of these selection defaults?

Here is the code I'm using that is not currently working:

NHtmlUnit.WebClient driver = new NHtmlUnit.WebClient(BrowserVersion.CHROME);
driver.Options.SSLClientProtocols = new String[] { "TLSv1.2" };
driver.Options.SSLClientCipherSuites = new string[] { "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384", "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA" };
HtmlPage page = driver.GetHtmlPage(<website URL>);

When searching for the error message I am receiving I get a lot of results for Java. I assume this is because NHtmlUnit is a .NET wrapper for HtmlUnit which is part of the Java library. I see that NHtmlUnit utilizes OpenJDK, is it possible that OpenJDK is having issues and is what isn't supporting the "installed providers"?

Any help understanding what is going wrong here would be a huge help, thank you.

Edit: I was able to get what I needed using standard System.Net.Http.HttpClient for requests and responses. This leads me to believe the error is isolated to NHtmlUnit.

1
TLS occurs before the HTTP request is sent. The client request the TLS version to server. The server then sends a certificate block with the names of the certificate that can be used. The client then looks up the certificate names in the stores to find the certificate. It looks like the list of certificates that are being sent from server to client are not supported by TLS 1.2. Earlier versions of Net did not support all the encryption modes for TLS 1.2. Net 4.7.2 default to using operating system for TLS. Older Mobile devices may need updating to support the TLS encryption mode.jdweng
You can use a sniffer like wireshark or fiddler to verify the TLS mode and get the list of certificate names that are sent from server to client.jdweng

1 Answers

0
votes

After:WebClient client = new WebClient(); Add this line to force it to use TLS1.2 System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;