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?

3

3 Answers 3

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.

Sign up to request clarification or add additional context in comments.

7 Comments

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

1 Comment

In my case switching the app pool identity is not possible due to constraints on my hosting environment.
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> 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.