I have self-hosted WCF REST service. I would like to use SSL and consume service from browser. I used this blog post as initial point. Basically following steps:
Create and register certificate
makecert.exe -sk RootCA -sky signature -pe -n CN=localhost -r -sr LocalMachine -ss Root MyCA.cer
makecert.exe -sk server -sky exchange -pe -n CN=localhost -ir
LocalMachine -is Root -ic MyCA.cer -sr LocalMachine -ss My
MyAdHocTestCert.cer
bind certificate to port
netsh http add urlacl url="https://+:8015/" user=Domain\User
netsh http add sslcert ipport=0.0.0.0:8015
certhash=somehash
appid={601A2F31-E812-479A-B5EA-1B78A9683EE0}
Then I try to call some methods from chrome... and nothing happens.
Here is my WCF config:
<bindings>
<webHttpBinding>
<binding name="NewBinding0">
<security mode="Transport">
<transport clientCredentialType="Certificate" />
</security>
</binding>
</webHttpBinding>
</bindings>
<services>
<service behaviorConfiguration="Security" name="Microsoft.Samples.BasicHttpService.Service">
<endpoint address="https://localhost:8015" binding="webHttpBinding"
bindingConfiguration="NewBinding0" name="test" contract="Microsoft.Samples.BasicHttpService.IService"
kind="webHttpEndpoint" endpointConfiguration="" />
<endpoint address="https://localhost:8016" binding="mexHttpsBinding"
bindingConfiguration="" name="MEX" contract="IMetadataExchange"
kind="mexEndpoint" endpointConfiguration="mex" />
</service>
</services>
WCF trace log shows warning: Client certificate is required. No certificate was found in the request.
While using chrome://net-internals/#events shows error:
SSL_CERTIFICATES_RECEIVED
--> certificates =
-----BEGIN CERTIFICATE-----
base64 certificate
-----END CERTIFICATE-----
t=1386677875080 [st= 4] SOCKET_BYTES_SENT
--> byte_count = 59
t=1386677875080 [st= 4] -SSL_CONNECT
... (send/receive part)...
t=1386677875123 [st=47] SSL_CLIENT_CERT_REQUESTED
t=1386677875123 [st=47] SSL_READ_ERROR
--> **net_error = -110 (ERR_SSL_CLIENT_AUTH_CERT_NEEDED)**
...
Here is what going on according to fiddler:
Tunel to localhost:8015 (Standart SSL handshaking)
**Request**
CONNECT localhost:8015 HTTP/1.1
Host: localhost:8015
....
A SSLv3-compatible ClientHello handshake was found. Fiddler extracted the parameters below.
....
Standard response with server certificate common data.
After handshaking browser sends GET request without any information about certificate or SSL at all and as a result 403 Forbidden.
The funny part is that the first time I did it, I could setup Fiddler with ClientCertificate and use Fiddler as a proxy everything worked(still direct calls from browser without Fiddler didn't work). Now after some manipulations (deleting sslcert, create new certs and so on) I've broken even this Fiddler behavior,so nothing works -- with or without Fiddler...
1) So, what steps did I missed? Should I create or import certificate for browser?
2) Who is responsible for establishing SSL connection, I mean who responded with server certificate?... I guess it is OS part (WinInet.dll). It is definitly not my service,because I didn't specify any certificate info, neither for service nor for client.
3) Should I specify serviceCertificate or clientCertificate in serviceCredentials?
Thanks in advance!
Your server is configured to demand that the client send it a certificate that identifies the caller of the API. You've described how you've configured the server to provide a certificate that identifies the server, but you haven't stated that you expect the client to authenticate. Do you? If not, you probably need to get rid of this line:
<transport clientCredentialType="Certificate" />
The server accepts connections via HTTP.SYS (WinINET is a client stack used by IE, and not Chrome) although I don't know how that's relevant to your question.
Related
We have a WCF server , Our client claim they can not get pass our IIS 8.5 authentication using the client certificate we provided.
<bindings>
<basicHttpBinding>
<binding name="CustomBinding" sendTimeout="00:01:30">
<security mode="Transport">
<transport clientCredentialType="Certificate" />
</security>
</binding>
</basicHttpBinding>
</bindings>
From our IIS log , we can see the client get ether 403 13 2148081683 or 403 16 2148204809
I am certain that the cert we ask the client to use is good, because we bought it from a globally trusted CA and we tested it on our end and it work perfectly fine.
And we do send them the full .pfx cert including the private key and gave them the password as well.
I am suspect that they are either not using the cert we provided or they do not install the cert properly.
The reason I suspect they are not using the correct cert is because they get 403 13 2148081683 , our fire wall only open for our cert CA to download the Certificate Revocation List(CRL), if they pass a wrong cert , they will get 403.13 because we are not be able to download the CRL.
The reason I suspect they are not install the cert properly is because they get 403.16.
So My question is :
Is there any way from IIS I can check what cert they send us and do they have properly installed the cert ?
Found an article today..
https://www.codeproject.com/Articles/1088156/Connecting-External-Systems-using-HTTPS-and-Certif
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\HTTP\Parameters\SslBindingInfo\IP:Port]
"DefaultSslCertCheckMode"=dword:00000001
I'm working on a WCF service that is to be consumed by a client that is not developed by me and also it's not .NET (possibly Java).
In any case, the service should support mutual SSL authentication, where both the service and the client authenticate with certificates X.509 certs at the transport layer. The certificates have been exchanged between parties at a prior moment.
My problem is that I cannot seem to get the right WCF configuration such that client certificate authentication works correctly. What I expect is that, as part of the TLS handshake, the server also includes a Certificate Request, as seen below:
Following this, the client should answer with a `Certificate Verify' among other things:
The (latest) service configuration is this one. I'm using a custom binding, with authentication mode set to MutualSslNegotiated.
<bindings>
<customBinding>
<binding name="CarShareSecureHttpBindingCustom">
<textMessageEncoding messageVersion="Soap11" />
<security authenticationMode="MutualSslNegotiated"/>
<httpsTransport requireClientCertificate="true" />
</binding>
</customBinding>
</bindings>
...
<serviceBehaviors>
<behavior name="ServiceBehavior">
<serviceMetadata httpGetEnabled="false" httpsGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" httpHelpPageEnabled="false" />
<serviceCredentials>
<serviceCertificate findValue="..." storeLocation="LocalMachine" x509FindType="FindByIssuerName" storeName="My" />
<clientCertificate>
<certificate findValue="..." storeName="My" storeLocation="LocalMachine" x509FindType="FindByIssuerName"/>
</clientCertificate>
</serviceCredentials>
</behavior>
</serviceBehaviors>
The Server Hello part of the handshake looks like this for all service configurations I have tried, with no CertificateRequest.
Other things I should mention:
The service is self hosted and listening on a non-default port (not 443). The server SSL certificate has been bound to this port.
I have also tried a basicHttpBinding and a wsHttpBidning with security mode set to Transport and client authentication set to Certificate, with no results (same results actually).
Any ideas would be appreciated.
OK, after a few more tries I figured it out. Posting this in case others run into the same issue.
I should continue by mentioning that this behavior really needs to be mentioned somewhere on MSDN, in a location that is really visible for anyone looking for WCF security information and not buried deep in some tool's documentation.
The platforms where I've been able to reproduce and fix this: Windows 8.1 x64 and Windows Server 2008 R2 Standard.
As I mentioned, my issue was that I could not configure WCF security such that the service would require client certificates. A common confusion that I noticed while looking for a solution is that many people believe that the client can send the certificate if it has it, unchallenged. This is, of course, not the case - the server needs to ask for it first and, moreover, specify which CAs are allowed through a CertificateRequest reply.
To summarize, my situation was:
Service is self-hosted.
Service runs on HTTPS, on a non standard port (not 443 but 9000).
This meant that I had to create an SSL certificate binding for port 9000 by using netsh.exe http add sslcert. Well, the binding had been created but there was a catch. I only found the issue after running netsh http show sslcert just to check on my binding:
IP:port : 0.0.0.0:9000
Certificate Hash : ...
Application ID : ...
Certificate Store Name : MY
Verify Client Certificate Revocation : Enabled
Verify Revocation Using Cached Client Certificate Only : Disabled
Usage Check : Enabled
Revocation Freshness Time : 0
URL Retrieval Timeout : 0
Ctl Identifier : (null)
Ctl Store Name : (null)
DS Mapper Usage : Disabled
-->Negotiate Client Certificate : Disabled
The culprit was the last property of the binding, "Negotiate Client Certificate", documented here. Apparently, by default, this property is disabled. You need to enable it explicitly while creating the binding.
Recreating binding with the statement below solved the issue:
netsh.exe http add sslcert ipport=0.0.0.0:9000 certhash=... appid=... certstorename=MY verifyclientcertrevocation=Enable VerifyRevocationWithCachedClientCertOnly=Disable UsageCheck=Enable clientcertnegotiation=Enable
Prior to checking the bindings I tried hosting a simple WCF service in IIS and enable client certificate authentication from there. It was very curious to see that although there was no CertificateRequest issued by IIS, it still failed with a 403.7. Even IIS didn't create the binding with the appropriate parameters.
Anyway, now it works and this is how you can fix it.
Not to forget, the service configuration changed as well (the binding security) in order to allow certificate negotiation:
<customBinding>
<binding name="CustomHttpBindingCustom" receiveTimeout="01:00:00">
<textMessageEncoding messageVersion="Soap11" />
<security authenticationMode="SecureConversation" requireSecurityContextCancellation="true">
<secureConversationBootstrap allowInsecureTransport="false" authenticationMode="MutualSslNegotiated" requireSecurityContextCancellation="true"></secureConversationBootstrap>
</security>
<httpsTransport requireClientCertificate="true" />
</binding>
</customBinding>
I had the same issue when my bosses were questioning why was our IIS hosted WCF service which implemented "2 way SSL" (mutual certificate authentication) not observed to be sending "Certificate Request" in the TLS handshake. After some investigation, we finally found that the certificate port binding configuration for Negotiate Client Certificate is disabled.
Get the current binding information by running the below.
netsh http show sslcert
Get the certificate hash and the application GUID from the first record (or the relevant SSL port), then run the following netsh command using an administrator console on the IIS server.
netsh http add sslcert ipport=0.0.0.0:443 certhash=xxxx appid={xxxxx} clientcertnegotiation=enable
Note that if an existing binding already exists for the IIS address and port, the following error will be reported.
SSL Certificate add failed, Error: 183 Cannot create a file when that file already exists.
Run the delete command to remove the existing binding before retrying to add it back again.
netsh http delete sslcert ipport=0.0.0.0:443
After the reconfiguration, the observed Wireshark TLS handshake became as expected. However, in my opinion, this setting doesn't matter in the end as the client certification is used for authentication whether during the initial handshake or afterwards within the encrypted exchange and 2 way SSL is achieved.
I'm trying to setup a self hosted WCF service, exposed in endpoint with https address, and I want just certain clients can call the service.
Client authentication should be done by certificate provided by client.
I'm in a corporate network, all certificates are issued by same authority, so i'm using certificateValidationMode="PeerTrust" in server side to identify authorized clients.
The server certificate binding to port is done.
Service binding configured as:
<security mode="Transport">
<transport clientCredentialType="Certificate" />
</security>
Service behaviour configured as:
<serviceCredentials>
<clientCertificate>
<authentication certificateValidationMode="PeerTrust" trustedStoreLocation="LocalMachine"></authentication>
</clientCertificate>
</serviceCredentials>
The client certificate is in windows trust (trusted people) in server side.
The server certificate is in windows store (trusted people) in client side.
Communication between client and servers works OK so far...SSL handshake OK...
but, when I remove the client's certificate from Trusted People on server side, the client still can call the service, and I'm expecting just the opposite:
"If client's certificate not in server trusted people store, then dont accept call."
all cache already removed, server restarted... client app still can call the service from same previously authorized client workstation.
any suggestions ??
I have a problem with getting a MVC web app with HTTPS to call a WCF Service that also uses HTTPS. The MVC web app must authenticate with a certificate to the WCF Service.
I'm using Windows 7, IIS 7.5, VS 2010 with C# and .NET Framework 4.0.
Here is what I've done so far:
I created a Certificate Authority called 'Development Authority':
makecert -pe -n "CN=Development Authority" -ss my -sr LocalMachine -a sha1 -sky signature -r "c:\Development Authority.cer"
I imported the newly created certificate with the MMC tool in the 'Trusted Root Certification Authorities' folder and in the 'Third-Party Root Certification Authorities' folder (Local Computer). This certificate can also be found in the 'Personal' folder.
I saw that if I import the CA only in the 'Trusted Root CA' it will still give a 'not trusted' warning. After importing the CA in the 'Third-Party Root CA' folder, the warning dissappeared.
I created two other certificates (signed by the newly created CA), using the following command :
makecert -pe -n "CN=mvc.localhost" -ss my -sr LocalMachine -a sha1 -sky exchange -eku 1.3.6.1.5.5.7.3.1 -in "Development Authority" -is MY -ir LocalMachine -sp "Microsoft RSA SChannel Cryptographic Provider" -sy 12 c:\mvc.localhost.cer
In this way I created 'mvc.localhost' and 'wcf.localhost' certificates. I imported them into the 'Personal' folder (for Local Computer), using the MMC tool.
In my Windows hosts files I created two aliases for the two applications that are going to be hosted with IIS (MVC app and WCF Service app). I updated my hosts file with the following lines:
#development
127.0.0.1 mvc.localhost
127.0.0.1 wcf.localhost
Under IIS, I mapped a new website 'mvc.localhost' to a very simple MVC web app.
I also mapped a new website 'wcf.localhost' to a basic newly created WCF Service.
mcv.localhost:
Application pool: .NET Framework 4.0 running using 'ApplicationPoolIdentity'.
Anonymous Authentication: enabled and set to 'Specific User' : 'IUSR'.
Bindings:
HTTP (hostname 'mvc.localhost', port 80) -> can access with 'http://mvc.localhost/'
HTTPS (hostname 'mvc.localhost', port 1234) -> can access with 'https://mvc.localhost:1234/'. Added with the 'mvc.localhost' certificate.
wcf.localhost:
Application pool: .NET Framework 4.0 running using 'ApplicationPoolIdentity'.
Anonymous Authentication: enabled and set to 'Specific User' : 'IUSR'.
Bindings:
HTTP (hostname 'wcf.localhost', port 80) -> can access with 'http://wcf.localhost/'
HTTPS (hostname 'wcf.localhost', port 443) -> can access with 'https://wcf.localhost/'. Added with the 'wcf.localhost' certificate.
To modify the hostnames for the HTTPS bindings I used the following command:
c:\Windows\System32\inetsrv>appcmd set site /site.name:"wcf.localhost" /bindings.[protocol='https',bindingInformation='*:443:'].bindingInformation:*:443:wcf.localhost
I tested the two websites separately with HTTPS and they worked without problems (except Firefox that has a strict policy when I comes to local certificates created for testing purposes and gives you a 'sec_error_unknown_issuer' warning, but this is not my problem for now).
WCF Service configuration for certificate authentication:
<bindings>
<wsHttpBinding>
<binding name="wsHttpEndpointBinding">
<security mode="Transport">
<transport clientCredentialType="Certificate"/>
</security>
</binding>
</wsHttpBinding>
</bindings>
<services>
<service name="wcf.localhost.WelcomeService" behaviorConfiguration="wcf.localhost.WelcomeServiceBehavior">
<endpoint address="https://wcf.localhost/WelcomeService.svc" binding="wsHttpBinding" bindingConfiguration="wsHttpEndpointBinding" contract="wcf.localhost.IWelcomeService">
</endpoint>
<!--<endpoint address="mex" binding="mexHttpsBinding"
name="mexEndpoint" contract="IMetadataExchange"/>-->
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="wcf.localhost.WelcomeServiceBehavior">
<serviceMetadata httpsGetEnabled="true" httpGetEnabled="false"/>
<serviceDebug includeExceptionDetailInFaults="false"/>
<serviceCredentials>
<clientCertificate>
<authentication revocationMode="NoCheck" certificateValidationMode="PeerOrChainTrust" />
</clientCertificate>
<serviceCertificate findValue="<<wcf.localhost Certificate Thumbprint inserted here>>" storeLocation="LocalMachine" storeName="My" x509FindType="FindByThumbprint"/>
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
In IIS, for SSL Settings I set 'Require SSL' with the 'Require' option.
The service WelcomeService exposes a method called 'SayHello(string)' that concatenates 'Hello' to the input parameter and returns the new string.
I can reach 'https://wcf.localhost/welcomeservice.svc' without problems.
MVC web app configuration:
<bindings>
<wsHttpBinding>
<binding name="WSHttpBinding_IWelcomeService" closeTimeout="00:01:00"
openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
bypassProxyOnLocal="false" transactionFlow="false" hostNameComparisonMode="StrongWildcard"
maxBufferPoolSize="524288" maxReceivedMessageSize="65536" messageEncoding="Text"
textEncoding="utf-8" useDefaultWebProxy="true" allowCookies="false">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
maxBytesPerRead="4096" maxNameTableCharCount="16384" />
<reliableSession ordered="true" inactivityTimeout="00:10:00"
enabled="false" />
<security mode="Transport">
<transport clientCredentialType="Certificate"/>
</security>
</binding>
</wsHttpBinding>
</bindings>
<client>
<endpoint address="https://wcf.localhost/WelcomeService.svc"
binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_IWelcomeService"
contract="WelcomeService.IWelcomeService" name="WSHttpBinding_IWelcomeService" behaviorConfiguration="CustomBehavior">
</endpoint>
</client>
<behaviors>
<endpointBehaviors>
<behavior name="CustomBehavior" >
<clientCredentials>
<clientCertificate findValue="<<mvc.localhost Certificate Thumbprint inserted here>>"
storeLocation="LocalMachine"
storeName="My"
x509FindType="FindByThumbprint"/>
<serviceCertificate>
<authentication certificateValidationMode="PeerOrChainTrust" revocationMode="NoCheck"></authentication>
</serviceCertificate>
</clientCredentials>
</behavior>
</endpointBehaviors>
</behaviors>
Now for the problem :
After using the MVC app to call the WCF service I get the following error :
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.Net.WebException: The remote server returned an error: (403) Forbidden.
Source Error:
Line 48:
Line 49: public void SayHello(string name) {
Line 50: base.Channel.SayHello(name);
Line 51: }
Line 52: }
Source File: C:\Projects\ssl.research\mvc.localhost\Service References\WelcomeService\Reference.cs Line: 50
Stack Trace:
[WebException: The remote server returned an error: (403) Forbidden.]
System.Net.HttpWebRequest.GetResponse() +7859156
System.ServiceModel.Channels.HttpChannelRequest.WaitForReply(TimeSpan timeout) +99
[MessageSecurityException: The HTTP request was forbidden with client authentication scheme 'Anonymous'.]
System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg) +4727747
System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type) +1725
mvc.localhost.WelcomeService.IWelcomeService.SayHello(String name) +0
mvc.localhost.WelcomeService.WelcomeServiceClient.SayHello(String name) in C:\Projects\ssl.research\mvc.localhost\Service References\WelcomeService\Reference.cs:50
mvc.localhost.Controllers.HomeController.CallService(HomeModel model) in C:\Projects\ssl.research\mvc.localhost\Controllers\HomeController.cs:33
lambda_method(Closure , ControllerBase , Object[] ) +127
System.Web.Mvc.ReflectedActionDescriptor.Execute(ControllerContext controllerContext, IDictionary`2 parameters) +264
System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary`2 parameters) +39
System.Web.Mvc.<>c__DisplayClass15.<InvokeActionMethodWithFilters>b__12() +129
System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodFilter(IActionFilter filter, ActionExecutingContext preContext, Func`1 continuation) +826410
System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodWithFilters(ControllerContext controllerContext, IList`1 filters, ActionDescriptor actionDescriptor, IDictionary`2 parameters) +314
System.Web.Mvc.ControllerActionInvoker.InvokeAction(ControllerContext controllerContext, String actionName) +825632
System.Web.Mvc.Controller.ExecuteCore() +159
System.Web.Mvc.ControllerBase.Execute(RequestContext requestContext) +335
System.Web.Mvc.<>c__DisplayClassb.<BeginProcessRequest>b__5() +62
System.Web.Mvc.Async.<>c__DisplayClass1.<MakeVoidDelegate>b__0() +20
System.Web.Mvc.<>c__DisplayClasse.<EndProcessRequest>b__d() +54
System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +469
System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +375
Version Information: Microsoft .NET Framework Version:4.0.30319; ASP.NET Version:4.0.30319.237
On the client side I also tried:
ServicePointManager.ServerCertificateValidationCallback += customXertificateValidation
...
private static bool customXertificateValidation(object sender, X509Certificate cert,
X509Chain chain, SslPolicyErrors error)
{
return true;
}
Using the service certificate thumbprint to authenticate with the service.
Different certificateValidationMode values.
Nothing worked.
I used SSL Diagnostics 1.1 to verify the two web applications and their certificates.
No errors were shown. The SSL Handshake Simulation went fine, without errors.
I feel that I am quite close to finishing the test project (having resolved other issues along the way).
Searching the web, I could find only HTTP WCF services or WCF services that didn't use a certificate for authentication or WCF service that use certificate authentication but are HTTP.
I'm trying to have a HTTPS running MVC web app call a HTTPS running WCF Service that requires a certificate for authentication.
Many of the great articles out there helped me with other problems with this project.
Now I'm stuck and I cannot seem to find a solution.
Any suggestion is appreciated.
Thank you, Bogdan.
UPDATE
I noticed that both of my certificates have as their purpose(s):
'Ensures the identity of a remote computer' (serverAuth) but I don't see anything about the clientAuth.
Also, Chrome browser prompts me to select a certificate when I access the MVC web app. In the certificates list I cannot see the two certificates that I created.
I can see only one certificate that has as one of its purposes (but is a different certificate from the ones that I plan on using!) :
'Proves your identity to a remote computer'
Maybe this is why I get the error? Maybe I cannot use either of my newly created certificates to authenticate the client to the server?
Any thoughts? If I'm right, how can I add clientAuth purpose to any of my certificates?
Thanks
Together with Rajesh I could find the solution.
The problem was with the client certificate (mvc.localhost) that was generated using the "-eku" attribute which gave the certificate the purpose "Ensures the identity of a remote computer" (serverAuth) but not the needed purpose of "Client Authentication".
You can verify a certificate purpose on the "General" tab on its details.
So, I had to generate a new client certificate, eliminating the "-eku" attribute, which gave the certificate "All application policies" purpose (including Client Authentication).
I did this with the following command :
C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC>makecert -sr LocalMachine
-ss my -a sha1 -n "CN=mvc.localhost" -sky exchange -pe -in "Development Author
ity" -is MY -ir LocalMachine -sp "Microsoft RSA SChannel Cryptographic Provider"
-sy 12 c:\mvc.localhost.cer
Succeeded
Be careful! After generating the certificates using the makecert tool, they will appear available in the "Local Machine/Personal" store. Whenever you have to copy/import a certain certificate in a different store, be sure to first export the original certificate ("Local Machine/Personal" store) as a .pfx file. Then you can import the .pfx file in the other stores and not the .cer file!!
After this, just add the two certificates to the right stores :
Local Machine --> Personal store --> has the two certificates (automatically added when the certificates were created with the makecert tool). IIS picks the certificates from this store (in order to use one when creating a https binding) so I don't recommend deleting the client certificate.
Local Machine --> Trusted People --> imported mvc.localhost.pfx
Current User --> Personal store --> imported mvc.localhost.pfx (this also imported the mvc.localhost CA in this folder)
Current User --> Trusted root certificate Authority --> imported wcf.localhost.pfx
Thanks Rajesh.
PS: you can also check the solution here : WCF Forum Thread
When using certificates for authentication you need to make sure that the certificates are placed in the appropriate store.
You need to have the client certificate as follows:
On the client machine :
Current User --> Personal folder should have client certificate mvc.localhost.pfx installed
On Server machines:
Local Machine --> TrusterPeople should have mvc.localhost.cer installed
The 403 forbidden error is because the server machine is not able to validate the client with the certificate it is recieveing as it might not be in its trusted store.
If the client and server are the same machine just follow make sure that the certificates are installed as said. In your case you need to have the certificates as below:
Local Machine --> Personal store needs to have the server certificate (wcf.localhost)
Local Machine --> Trusted People store to have the client certificate (mvc.localhost)
Current User --> Personal store to have the client certificate (mvc.localhost)
Current User --> Trusted root certificate Authority store to have server certifcate (wcf.localhost)
If you have teh following then try to browse to the service from IE and you should be able to see the service and its wsdl.
Also go to IE and then Tools --> Internet Options --> Security --> Internet --> Custom Level
Now scroll down to Misc section to find the option "Dont Prompt for client certificate selection when no certificate is present or only one certificate is present" to Diable.
Now restart IE and browse to the service and IE should ask you to select a client certificate from the personal store and you need to select mvc.localhost.
If mvc.localhost is not visible then your client certificate is not in the appropriate store.
Adding to Bogdan's fine answer (as I had the same problem), I added the OID_PKIX_KP_CLIENT_AUTH OID (1.3.6.1.5.5.7.3.2) to the -eku argument which gave me both purposes which is what you probably want rather than brute force "All application policies".
e.g. (remove obvious line-breaks)
makecert -iv SignRoot.pvk -ic signroot.cer -cy end -pe -n CN="DEV dual purpose"
-eku 1.3.6.1.5.5.7.3.1,1.3.6.1.5.5.7.3.2 -ss my
-sr localmachine -sky exchange
-sp "Microsoft RSA SChannel Cryptographic Provider" -sy 12
I'm trying to access a publicly-hosted SOAP web service (not WCF) over https, and I'm getting an error that I've never seen before. First, here are the facts:
This service requires client certificates. I have a certificate that is signed by the same CA as the server's certificate.
I know that the URL is available, as I can hit it in Internet Explorer. IE brings up the "choose certificate" window, and if I pick it (and ignore the server-host-name-does-not-match-certificate error), it goes on and gives me an HTTP 500 error.
If I open the site in Chrome, after picking the cert and ignoring the error, I get a normal error message about WSA Action = null.
If I open the site in FireFox, after ignoring the error, I get a page about how the server couldn't validate my certificate. It never asked me to pick one, so that makes perfect sense.
Now, the exception:
Error occurred while executing test 12302: System.ServiceModel.Security.SecurityNegotiationException: Could not establish secure channel for SSL/TLS with authority 'ihexds.nist.gov:9085'. ---> System.Net.WebException: The request was aborted: Could not create SSL/TLS secure channel.
at System.Net.HttpWebRequest.GetResponse()
at System.ServiceModel.Channels.HttpChannelFactory.HttpRequestChannel.HttpChannelRequest.WaitForReply(TimeSpan timeout)
I've traced the interaction with WireShark, but because I'm not an expert in the TLS protocol, I could be missing clues as to what's going on. Here, however, is what I do see:
C -> S Client Hello
Contains things like a random number, date/time, cypher suites supported, etc
S -> C Server Hello, Certificate, Certificate Request, Server Hello Done
Contains the server's certificate, and a request for a client certificate
C -> S Certificate, Client Key Exchange, Change Cipher Spec, Encrypted Handshake Message
HERE IS THE INTERESTING PART -- The first part of this packet is the Certificate handshake, where I assume the client certificate would be, but there are no certificates present (Certificates Length: 0).
S -> C Alert (Level: Fatal, Description: Bad Certificate)
Well, yeah, there was no certificate sent.
My binding is set up as follows:
<binding name="https_binding">
<textMessageEncoding />
<httpsTransport useDefaultWebProxy="false" />
</binding>
My behavior is set up as follows:
<behavior name="clientcred">
<clientCredentials>
<clientCertificate findValue="69b6fbbc615a20dc272a79caa201fe3f505664c3" storeLocation="CurrentUser" storeName="My" x509FindType="FindByThumbprint" />
<serviceCertificate>
<authentication certificateValidationMode="None" revocationMode="NoCheck" />
</serviceCertificate>
</clientCredentials>
<messageInspector />
</behavior>
My endpoint is set up to use both the binding and the behavior. Why does WCF refuse to send the certificate when it creates the https connection?
I solved the problem, but I do not understand why this configuration change fixed it. I changed this line:
<httpsTransport useDefaultWebProxy="false" />
to this:
<httpsTransport useDefaultWebProxy="false" requireClientCertificate="true" />
and magically it started working. I had understood that the requireClientCertificate "knob" was for server-side, so I hadn't tried it during my wrangling. Apparently I was wrong.
There should have been a CertificateRequest from the server, naming acceptable cert types and CAs. If your certificate doesn't match those it won't be sent.
It could be a problem negotiating which security protocol to use. Specifically im thinking that the server might not like WCF trying to use TLS 1.0.
To see if this is the case try to add the following before invoking the service
System.Net.ServicePointManager.SecurityProtocol = System.Net.SecurityProtocolType.Ssl3
This could be added either in client code or by placing it in an IEndpointBehavior