EricHerlitz / Mobile-BankId-.NET-Example

Working Swedish Mobile BankID implementation written in C# .NET
12 stars 7 forks source link

SSL/TLS #2

Closed AndersBillLinden closed 7 years ago

AndersBillLinden commented 7 years ago

Thanks for the fantastic documentation! I am almost there!

I need some final help, if you are not the right person to ask (maybe you are a volunteer?), let me know.

I am getting a SecurityNegotiationException when I try to use this code in a desktop application (winforms):

private void button1_Click(object sender, EventArgs e)
{
  var client = new RpServicePortTypeClient();

  var request = new SignRequestType
  {
    personalNumber = txtPersonalNumber.Text,
    userVisibleData = txtMessage.Text
  };

  var response = client.Sign(request);
}

The error is

An unhandled exception of type 'System.ServiceModel.Security.SecurityNegotiationException' occurred in mscorlib.dll

Additional information: Could not establish secure channel for SSL/TLS with authority 'appapi2.test.bankid.com'.

having a Web.config that looks like

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <startup> 
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
    </startup>
    <system.serviceModel>
        <bindings>
            <customBinding>
                <binding name="RpServiceSoapBinding">
                    <textMessageEncoding messageVersion="Soap11" />
                    <httpsTransport requireClientCertificate="true" />
                </binding>
            </customBinding>
        </bindings>
        <client>
            <endpoint address="https://appapi2.test.bankid.com/rp/v4"
                binding="customBinding"
                bindingConfiguration="RpServiceSoapBinding"
                contract="BankIDService.RpServicePortType"
                name="RpServiceSoapPort"
                behaviorConfiguration="bankid"/>
        </client>
        <behaviors>
            <endpointBehaviors>
                <behavior name="bankid">
                    <clientCredentials>
                        <clientCertificate findValue="FP Testcert 2"
                            x509FindType="FindBySubjectName"
                            storeLocation="LocalMachine"
                            storeName="My" />
                        <serviceCertificate>
                            <defaultCertificate findValue="Test BankID SSL Root CA v1 Test"
                                storeLocation="LocalMachine"
                                storeName="Root"
                                x509FindType="FindBySubjectName"/>
                            <authentication certificateValidationMode="None"
                                revocationMode="NoCheck"
                                trustedStoreLocation="LocalMachine"/>
                        </serviceCertificate>
                    </clientCredentials>
                </behavior>
            </endpointBehaviors>
        </behaviors>
    </system.serviceModel>
</configuration>

Both the cer and the pfx are installed by double clicking in explorer, both on LocalMachine, the cer as Trusted Root Certification Authorities, the pfx as Personal.

The bankid_test.cer is fetched from https://www.bankid.com/assets/bankid/rp/bankid-relying-party-guidelines-v2.15.pdf and is from chapter 7 Test Environment.

It is significantly larger than the one you had in your example, starting with MIIF0DCCA and ending with WJ5vZOP2HsA==.

I have also tried to change to basicHttpBinding in App.config as DanielCornelius proposed but then, I of course get Additional information: The provided URI scheme 'https' is invalid; expected 'http'..

EricHerlitz commented 7 years ago

It seems as if I need to update my sample to the latest version of the documentation. Anyway, what appear to fail is when the iis app pool tries to access the client certificate.

Regardless of where you keep it your application pool (since you are running a web application) needs to be able to access that specific certificate store. Either run your application pool as a user that can access the CurrentUser store or move it to the LocalMachine store as you've stated and ensure that either the service account running the application pool or she application pool itself can access the specific cert store.

DanielCornelius commented 7 years ago

You can try to get the certificate by its thumbprint, in code, just to see that you can access it. Then you can apply it to the service call manually.

AndersBillLinden commented 7 years ago

@EricHerlitz But there is no IIS application pool in my example. @DanielCornelius I managed to find both certs using code on https://stackoverflow.com/questions/11115511/how-to-find-certificate-by-its-thumbprint-in-c-sharp. I could also find them by subject name.

AndersBillLinden commented 7 years ago

When I try to access the wsdl directly in a browser, I am prompted to select which certificate I want to use to authenticate myself with, only the client certificate shows so I select it. The resulting webpage however is not marked as "safe".

image

AndersBillLinden commented 7 years ago

However, I managed to import the pfx in firefox (instead of chrome) and I do not get any warnings from it.

AndersBillLinden commented 7 years ago

Ok, I was missing the line ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;

Thanks again!