how to check what certificates being sent to iis - wcf

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

Related

Mutual SSL authentication with WCF: no CertificateRequest and CertificateVerify in handshake phase

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.

WCF REST. SSL. "Client certificate is required" error

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.

Disable wcf x509 certificate, using clientCredentialType="UserName"

I want to retrieve the username and password of user that requires the service operation. For this i need to specify the following configuration:
<binding name="NewBinding0">
<security mode="Message">
<message clientCredentialType="UserName" negotiateServiceCredential="false"
establishSecurityContext="false" />
</security>
</binding>
Now it requires the x509 certificate. Can i disable it, or modify the security mode or message credentialType, but to provide the same functionality?
When you specify message security it always expects service certificate. The reason is that user name and password should be send over secured channel otherwise password is send as a plain text and everybody on the network can see that.
All default bindings will allow you sending user name and password only when you are using HTTPS (security mode set to TransportWithMessageCredential - it also requires certificate) or if you are using WS-Security where service certificate is needed (security mode set to Message).
In WCF 4 (and with special KB patch in earlier versions) you can create custom binding where user name and password can be send over unsecured channel but it is almost the same as no security. It should be used only if your channel is secured with some another infrastructure like VPN.

azure WCF and mutual certificate auth - how?

I have got quite a long way with this. I want a WCF service hosted in azure that uses client certificate authentication.
Everything works with the client cert requirement turned off and server cert on; ie
<transport clientCredentialType="None" />
but when I change to
<transport clientCredentialType="Certificate" />
I get
The SSL settings for the service 'SslRequireCert' does not match those of the IIS 'None'.
This seems to suggest that I need to change my IIS configuration. But I am running inside azure emulator, not IIS.
I tried adding
<system.webServer>
<security>
<access sslFlags="ssl">
</security>
</system.webServer>
but the web server did not like that at all; says this is a locked configuration option
All help gratefully received
answer: unlock the iis config file with appcmd
unlock the iis config file with appcmd

WCF - Cannot Find the x.509 Certificate Using the Following Search Criteria

Ok, I have seen several questions related to this issue, and I have tried a lot of the ideas presented in them with no success. Here's my situation:
I'm hitting a web service over my company's intranet. I have used svcutil.exe to generate the client class for WCF. I was able to run the web service call with no problem when the service was in development and did not require authentication credentials, so I know the code works. At the time, the code was running over SSL. I imported the required certificate into the Trusted Root Certification Authorities store, and everything was fine.
We just moved to a stage environment, and the service was upgraded to require credentials to connect. I switched my connection to the new endpoint, and added code to authenticate. This is my first time working with wcf, so please bear with me on any obvious mistakes. My problem is that I cannot locate the certificate via code to pass to the service for authentication. I am basing this off of some online code examples I found.
Here is an example of my config generated by svcutil:
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding
name="xxxSOAPBinding"
.... (irrelevant config settings)....
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
maxBytesPerRead="4096" maxNameTableCharCount="16384" />
<security mode="Transport">
<transport clientCredentialType="Certificate" />
</security>
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="https://xxxServices_1_0_0"
binding="basicHttpBinding" bindingConfiguration="xxxSOAPBinding"
contract="xxxService" name="xxxService" />
</client>
</system.serviceModel>
And here is the code I am using to try to connect. The exception is thrown as soon as I attempt to locate the certificate:
using (var svc = new xxxServiceClient())
{
svc.ClientCredentials.UserName.UserName = "XXX";
svc.ClientCredentials.UserName.Password = "XXX";
svc.ClientCredentials.ClientCertificate
.SetCertificate(StoreLocation.LocalMachine, StoreName.Root,
X509FindType.FindBySubjectName, "xxx");
...
}
I have tried several different X509FindTypes, and matched them to the values on the cert with no success. Is there something wrong with my code? Is there another way I can query the cert store to validate the values I am passing?
The dev machine where I am running Visual Studio has had the cert imported.
Two silly questions:
are you sure your certificiate is installed at all?
is this a certificiate specifically for this staging machine?
Also, it seems a bit odd you're first of all setting username/password, and then also setting the credential. Can you comment out the username/password part? Does that make any difference?
Marc
Are you sure the the certificate has been imported to the local machine store, it could be in the CurrentUser store.
This may sound stupid, but are you certain the new cert for the staging service has been installed into your cert store? That's most likely your problem.
Also, since you didn't mention what exception is thrown, it's possible the problem is that you've set username/password credentials before setting clientcertificate credentials, when your binding does not indicate the use of username/password. Could be a problem there; they're mutually exclusive, IIRC.