13

I have a web service which I have registered via "add service reference" that requires HTTPS and a certificate. Below is my code for instantiating my service:

        service = new MyReferencedWebService();

        X509Certificate2 cert = new X509Certificate2();

        var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("Mycert.cer");
        var bytes = new byte[stream.Length];

        stream.Read(bytes, 0, bytes.Length);

        cert.Import(bytes, MYPASSWORD, X509KeyStorageFlags.DefaultKeySet);

        service.ClientCredentials.ClientCertificate.Certificate = cert;

and my config looks like this:

<system.serviceModel>
    <bindings>
        <basicHttpBinding>
            <binding name="RecordGeneratorWebServiceSoapHttp">
                <security mode="Transport">
                    <transport clientCredentialType="Certificate" />
                </security>
            </binding>
        </basicHttpBinding>
    </bindings>
    <client>
        <endpoint address="https://mywebserviceurl"
            binding="basicHttpBinding" bindingConfiguration="RecordGeneratorWebServiceSoapHttp"
            contract="MyService.RecordGeneratorWebServiceInterface"
            name="RecordGeneratorWebServicePort" />
    </client>
</system.serviceModel>

If I create a simple winforms .exe and use the above code I get a response from my web service. However, if I put this same code in ASP.NET I get the following:

The request was aborted: Could not create SSL/TLS secure channel.

How do I make this work in ASP.NET?

EDIT: I should add. The client certificate that I am using is tied to a smart card and requires a PIN to be entered for use. Not sure if that makes any difference or not.

When a client logs into the application it prompts them for their certificate PIN. In this case they have a CAC card inserted into a CAC reader. So maybe I can somehow use the Request.ClientCertificate?

Coltech
  • 1,670
  • 3
  • 16
  • 31
  • this could due to a number of things - windows version, .net version, access to cert, valid cert, etc. if you haven't already, check the comments and answers of this question http://stackoverflow.com/questions/2859790/the-request-was-aborted-could-not-create-ssl-tls-secure-channel – hubson bropa Feb 14 '14 at 17:39
  • 1
    Oh yeah I have, nothing seems to work. – Coltech Feb 14 '14 at 17:45
  • Did you setup IIS so that it knows to request the client certificate? http://technet.microsoft.com/en-us/library/cc753983%28v=ws.10%29.aspx – iamkrillin Feb 18 '14 at 19:04

3 Answers3

2

What is your plan here? In other words:

Who is going to be entering the PIN? Who is going to be inserting a smart card?

You cannot establish the secure channel between the ASP.NET web server and the web service without the smart card and the pin, because the client (i.e. the ASP.NET web server) must access the private key on the smart card (and needs the pin to do that). I fear the only way you're going to get this to work is to get that entire certificate (including the private key) off of the smart card (which should be very difficult if not impossible by design).

Your best course of action is to:

A) Request a "server certificate" (non smart-card) that can be used as the client certificate for the channel between the ASP.NET web server and the target web service.

or

B) Re-architect your solution so that the clients (the folks who have the smart cards and the pins) access the secure web service directly using their smart card and PIN.

mikey
  • 5,090
  • 3
  • 24
  • 27
  • Here is the deal. When a client logs into the application it prompts them for their certificate PIN. In this case they have a CAC card inserted into a CAC reader. – Coltech Feb 17 '14 at 13:34
  • And therein lies the problem -- you now have 2 channels: [CLIENT] <--> [WEB SERVER] and [WEB SERVER] <--> [WEB SERVICE]. Before you had only one channel: [CLIENT (via Windows Forms Application)] <--> [WEB SERVICE] is that correct? – mikey Feb 17 '14 at 14:15
  • Yes. What I need is for the client to log in to the web server with their certificate (working) and THEN have the web server hit a web service using the same certificate (not working) – Coltech Feb 17 '14 at 14:21
  • 2
    Unfortunately that is not possible. In order for it to work the web server would need to have access to the client certificate's private key. The private key is never transmitted to your web server (nor should it be). The only options I see are: A) try to get a server certificate for your web server that is trusted by the web service which you can use as a client certificate. B) Architect a solution where the client accesses the web service directly. – mikey Feb 17 '14 at 15:00
  • Thanks for the info. I kinda thought this line: cert.Import(bytes, MYPASSWORD, X509KeyStorageFlags.DefaultKeySet) was giving the server my certs private key. But I guess there is a difference between the PIN and the private key? – Coltech Feb 17 '14 at 15:55
  • I've never dealt with a *.cer file that had a private key in it, but usually a password-protected certificate file like a *.pfx is password protected because it does include a private key. How did you generate or where did you get the Mycert.cer file? See: http://security.stackexchange.com/questions/29425/difference-between-pfx-and-cert-certificates -- Also, yes a smart card pin is separate from its cert's private key. Here is a resource on that: http://security.stackexchange.com/questions/38924/how-does-storing-gpg-ssh-private-keys-on-smart-cards-compare-to-plain-usb-drives – mikey Feb 17 '14 at 19:19
  • +1 for two different channels and impossibility to impersonate certificate authentication. Besides suggested solutions, you could architect the product to extract the authentication party into separate entity. I.e. the client will authenticate to the dedicated server, and both client and web app will talk to server to confirm the authentication. – Mikl X Feb 23 '14 at 22:56
0

Is the certificate's root certificate accessible? If you imported it yourself it was imported to your user's certificate store which iis can't access (import it to the machine store instead)

The documentation for the class' constructor says that the class will access a CSP to store the certificate's (for pfx) private key. This shouldn't be necessary for a cer file, but perhaps you still run into permission issues if you're running as an app pool user?

Try switching the app pool to run as a user with permissions and see if that helps, or try import the certificate to the machine certificate store and access it from there.

EventHorizon
  • 2,916
  • 22
  • 30
  • In my case switching the app pool identity is not possible due to constraints on my hosting environment. – Coltech Feb 17 '14 at 13:51
0

Configuration of Your WCF Client

Just in case, ensure the address of your end point is of the form:

"https://hostname[:port]/ServiceDirectory/MyService.svc"

Assuming the configuration of your service is correct, the binding configuration of your ASP.NET application should be:

<system.serviceModel>
    <bindings>
        <basicHttpBinding>
            <binding name="RecordGeneratorWebServiceSoapHttp">
                <security mode="Transport">
                    <transport clientCredentialType="Certificate" proxyCredentialType="None" />
                </security>
            </binding>
        </basicHttpBinding>
    </bindings>
    <client>
        <endpoint address="https://hostname[:port]/ServiceDirectory/MyService.svc"
            binding="basicHttpBinding" bindingConfiguration="RecordGeneratorWebServiceSoapHttp"
            contract="MyService.RecordGeneratorWebServiceInterface"
            name="RecordGeneratorWebServicePort" />
    </client>
</system.serviceModel>

An issue you may face is passing/supplying the client certificate to your service.

If your service is hosted in IIS 6.0 or IIS 7.0, you should configure the IIS hosting your WCF service to accept client certificates.

Your asp.net application is the WCF client. See this page on using a smart card certificate and Securing WCF Services with Certificates.

You will also need a server SSL certificate to be installed in IIS where you are hosting your WCF service to support HTTPS.

Configuration of Your WCF Service

Your service endpoint should include secure http binding and also the service behavior to enable httpsGetEnabled and disable httpGetEnabled:

<service name="MyService">
   <endpoint address="" contract="MyServiceInterface" binding="basicHttpBinding" bindingConfiguration="secureHttpBinding"/>
</service>

<serviceBehaviors>
  <behavior name="">
    <serviceMetadata  httpGetEnabled="false" httpsGetEnabled="true" />
  </behavior>
</serviceBehaviors>

<basicHttpBinding>
   <binding name="secureHttpBinding">
      <security mode="Transport">
         <transport clientCredentialType="Certificate" proxyCredentialType="None"/>
      </security>
   </binding>
</basicHttpBinding>
Only You
  • 2,051
  • 1
  • 21
  • 34