Disable client certificate validation in IIS 10 for an Asp.net website but allow app to request incoming client certificate - asp.net

I have an Asp.net API website which does custom client certificate validation. When hosting this website on IIS 10, I get the following from failed request logs when I call my API.
A certificate chain processed, but terminated in a root certificate
which is not trusted by the trust provider.
My web.config has
<configuration>
<system.webServer>
<access sslFlags="Ssl, SslRequireCert" />
</system.webServer>
and in applicationHost.config I have
<section name="access" overrideModeDefault="Allow" />
What am I missing here? How do I configure IIS to just pass through the certificate and not validate it ?
The reason I want to do this is because, this is a test environment and I want to trust all clients who calls my API with their self-signed certificates. I will internal do the validation of the certificate inside my API.
Note: I hosted the same website on Azure AppService and set "Incoming client certificates" to ON. It worked like a charm. So, what is the difference when I host it on my machine IIS ?

We use Client Certificates to validate hardware devices connecting to our API. For context, our devices are provisioned with an SSL cert at manufacture, and that cert is self signed by us. When a device out in the wild attempts to connect to our API, we handle the client certificate validation within the .NET API application itself.
This requires the following IIS SSL settings, and also a manual step to rebind the SSL binding (which we do for a very specific technical limitation).
So firstly, within the web.config file we have this config:
<security>
<access sslFlags="Ssl" />
</security>
If we add the SslNegotiateCert or SslRequireCert sslFlags, then IIS attempts to validate the client certificate before our application code is even called. So we set only the Ssl flag.
Secondly, in the SSL settings of the IIS site we set:
Require SSL [x]
Client Certificate:
[x] Ignore
[ ] Accept
[ ] Require
So essentially we aren't asking IIS to negotiate the client certificates on our behalf.
The final configuration change we make is to Enable "Negotiate Client Certificate" on the SSL binding. By default, when you create an SSL binding in IIS the "Negotiate Client Certificate" property is set to false.
From my understanding this means that IIS will not negotiate client certificates on the initial TLS negotiation. What would happen is when client certificates are required, a TLS renegotiation is triggered, and the server would request a client certificate from the client.
In our case, our devices pass the client certificate on the initial request, and will not handle a TLS renegotiation. So, by Enabling "Negotiate Client Certificate" then client certificates can be passed in the initial request.
So rebind the SSL binding takes some command line magic to find the current binding, delete it, and readd the binding this time with "Negotiate Client Certificate" enabled.
Step 1 - Find your SSL binding:
Run the following command in a CMD terminal:
netsh http show sslcert > sslcerts.txt
This will push all details of your current SSL bindings into sslcerts.txt
The file will looks like the following:
SSL Certificate bindings:
Hostname:port : yourhostname:443
Certificate Hash : your_certificate_hash
Application ID : {your_applicationID_Guid}
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
Note, your sslcerts.txt file will contain many instances of these bindings. You need to find the correct one for the application/site you are working with.
Note also the above output shows "Negotiate Client Certificate : Disabled"
Step 2 - Delete the current binding
Run the following command to delete the current binding
netsh http delete sslcert hostnameport=yourhostname:443
This will delete the SSL binding for the site.
Step 3 - Rebind the SSL with "Negotiate Client Certificate" enabled
Run the following command at the CMD prompt:
netsh http add sslcert hostnameport=yourhostname:443 certhash=your_certificate_hash appid={your_applicationID_Guid} certstorename=MY verifyclientcertrevocation=Enable VerifyRevocationWithCachedClientCertOnly=Disable UsageCheck=Enable clientcertnegotiation=Enable
Note here you are filling in the properties of the binding from the details you retrieved in sslcerts.txt, except you are setting clientcertnegotiation=Enable
Now we have an IIS Application which will negotiate for a client certificate up front, but it will not validate it, and allow us to validate it in code.
We then use an AuthorizationFilterAttribute to grab the client certificate and validate it based on our rules.
public class ValidateDeviceClientCertificateAttribute : AuthorizationFilterAttribute
{
public override void OnAuthorization(HttpActionContext actionContext)
{
X509Certificate2 cert = actionContext.Request.GetClientCertificate();
// Validation rules here i.e. check Hash of the signing cert, does it match your accepted value?
}
}
In our validation we have a known Intermediate CA that we use to sign our device certificates, so we check to ensure that the client certificate was signed by that Intermediate Cert, or at least one of our device signing intermediate certificates.

Related

WCF Message Level Security using Certificate (X.509) Message Signed and Encrypted

I have a common use case to implement a web service (WCF) and a web client which is consuming this web service. Both Client and Service are sending and receiving Signed and Encrypted messages (Message Level Security).
I can have multiple clients those are using my service, hence multiple client certificate need to be installed on Server where Service project is running.
I have installed 2 Certificates (Service Certificate and Client Certificate) in local machine store under personal and trusted root certification authorities.
makecert -sr LocalMachine -ss My -a sha1 -n "CN=WCFServer" -len 2048 -sky exchange -pe
makecert -sr LocalMachine -ss My -a sha1 -n "CN=WCFClient" -len 2048 -sky exchange -pe
Although Certificate give me error of "integrity of licence can not be guaranteed" but now i dont care about this issue.
Web Client need to Sign the request message through its own Private Key and Encrypt message through Service Certificate Public key.
Service receive the request and verify the signature of message through client Public Key and Decrypt the contents through own Private Key
Than process the request and create a response object.
Now Service must sign the response by own private key and encrypt the message through client public key.
Now client get Signed and Encrpted response. Now it verify the response through Service Public Key and Decrypt the message by its own private key.
This is whole Szenerio . I have installed both(Client and Service) X.509 Certificates on my local development machine. I am using wsHttpBinding and communication is working fine.
I am using [ServiceContract(ProtectionLevel=ProtectionLevel.EncryptAndSign)] for ServuceContract and [OperationContract(ProtectionLevel = ProtectionLevel.EncryptAndSign, IsOneWay = false)] for OperationContract.
I have following question:
do i need to Sign and Encrypt/Decrypt Request or Response message in my Code (once in client and once in service code) or Configurations in web.config on Service Project and Client project are enough to do all this stuff?
I go through following code project and its working fine.
http://www.codeproject.com/Articles/36683/simple-steps-to-enable-X-certificates-on-WCF
My Source code (Visual Studio Project) Including both certificates is available on Bitbucket for download here
Can any one tell me, do i need to do all this stuff in code or its done through my current configurations.
Thanks in advance.
i got following answer from MSDN forum.
do i need to Sign and Encrypt/Decrypt Request or Response message in my Code (once in client and once in service code) or Configurations in web.config on Service Project and Client project are enough to do all this stuff?
If we have configured the service to use the certificate authentication in the config file, then as you said all the response and request message will be Encrypted/Decrypted by the client certficate's private key/ public key and service certificate's private key/ public key. So in my mind it is enough to do all the stuff in the configure file.
For more information, please try to refer to the following articles:
Certificate authentication:
https://msdn.microsoft.com/en-us/library/ff648360.aspx .
Message and Transport Security:
https://msdn.microsoft.com/en-us/library/ff648863.aspx .
i have few more questions which may be any one can answer me.
I have multiple clients (external web applications ) which will access my service. do each client need to create their own certificate? client will deliver us certificate without private key which need to be install on Service Host server? is this a correct way?
Each client certificate need to be configured in web.config ?
I need to export my service certificate without private key and send to clients. clients must install and configure certificate on their application server? is this correct?
here i got another ver good answer (step by step guide) from MSDN Team.
https://social.msdn.microsoft.com/Forums/vstudio/en-US/a9d85e9f-6d35-425c-ac6d-b3cd883760e4/wcf-message-level-security-using-certificate-x509-message-signed-and-encrypted?forum=wcf&prof=required

AspNet.Security.OpenIdConnect.Server (ASP.NET vNext) Authority Configuration in Mixed http/https Environments

I am using Visual Studio 2015 Enterprise and ASP.NET vNext Beta8 to build an endpoint that both issues and consumes JWT tokens as described in detail here. As explained in that article the endpoint uses AspNet.Security.OpenIdConnect.Server (AKA OIDC) to do the heavy lifting.
While standing this prototype up in our internal development environment we have encountered a problem using it with a load balancer. In particular, we think it has to do with the "Authority" setting on app.UseJwtBearerAuthentication and our peculiar mix of http/https. With our load balanced environment, any attempt to call a REST method using the token yields this exception:
WebException: The remote name could not be resolved: 'devapi.contoso.com.well-known'
HttpRequestException: An error occurred while sending the request.
IOException: IDX10804: Unable to retrieve document from: 'https://devapi.contoso.com.well-known/openid-configuration'.
Consider the following steps to reproduce (this is for prototyping and should not be considered production worthy):
We created a beta8 prototype using OIDC as described here.
We deployed the project to 2 identically configured IIS 8.5 servers running on Server 2012 R2. The IIS servers host a beta8 site called "API" with bindings to port 80 and 443 for the host name "devapi.contoso.com" (sanitized for purposes of this post) on all available IP addresses.
Both IIS servers have a host entry that point to themselves:
127.0.0.1 devapi.contoso.com
Our network admin has bound a * certificate (*.contoso.com) with our Kemp load balancer and configured the DNS entry for https://devapi.contoso.com to resolve to the load balancer.
Now this is important, the load balancer has also been configured to proxy https traffic to the IIS servers using http (not, repeat, not on https). It has been explained to me that this is standard operating procedure for our company because they only have to install the certificate in one place. We're not sure why our network admin bound 443 in IIS since it, in theory, never receives any traffic on this port.
We make a secure post via https to https://devapi.contoso.com/authorize/v1 to fetch a token, which works fine (the details of how to make this post are here ):
{
"sub": "todo",
"iss": "https://devapi.contoso.com/",
"aud": "https://devapi.contoso.com/",
"exp": 1446158373,
"nbf": 1446154773
}
We then use this token in another secure get via https to https://devapi.contoso.com/values/v1/5.
OpenIdConnect.OpenIdConnectConfigurationRetriever throws the exception:
WebException: The remote name could not be resolved: 'devapi.contoso.com.well-known'
HttpRequestException: An error occurred while sending the request.
IOException: IDX10804: Unable to retrieve document from: 'https://devapi.contoso.com.well-known/openid-configuration'.
We think this is happening because OIDC is attempting to consult the host specified in "options.Authority", which we set at startup time to https://devapi.contoso.com/. Further we speculate that because our environment has been configured to translate https traffic to non https traffic between the load balancer and IIS something is going wrong when the framework tries to resolve https://devapi.contoso.com/. We have tried many configuration changes including even pointing the authority to non-secure http://devapi.contoso.com to no avail.
Any assistance in helping us understand this problem would be greatly appreciated.
#Pinpoint was right. This exception was caused by the OIDC configuration code path that allows IdentityModel to initiate non-HTTPS calls. In particular the code sample we were using was sensitive to missing trailing slash in the authority URI. Here is a code fragment that uses the Uri class to combine paths in a reliable way, regardless of whether the Authority URI has a trailing slash:
public void Configure(IApplicationBuilder app, IOptions<AppSettings> appSettings)
{
.
.
.
// Add a new middleware validating access tokens issued by the OIDC server.
app.UseJwtBearerAuthentication
(
options =>
{
options.AuthenticationScheme = JwtBearerDefaults.AuthenticationScheme ;
options.AutomaticAuthentication = false ;
options.Authority = new Uri(appSettings.Value.AuthAuthority).ToString() ;
options.Audience = new Uri(appSettings.Value.AuthAuthority).ToString() ;
// Allow IdentityModel to use HTTP
options.ConfigurationManager =
new ConfigurationManager<OpenIdConnectConfiguration>
(
metadataAddress : new Uri(new Uri(options.Authority), ".well-known/openid-configuration").ToString(),
configRetriever : new OpenIdConnectConfigurationRetriever() ,
docRetriever : new HttpDocumentRetriever { RequireHttps = false }
);
}
);
.
.
.
}
In this example we're pulling in the Authority URI from config.json via "appSettings.Value.AuthAuthority" and then sanitizing/combining it using the Uri class.

Invalid remote certificate while accessing PayPal Sandbox transaction service

I am testing my application with PayPal sandbox.
The URI I use for the transaction is https://sandbox.paypal.com/cgi-bin/webscr?cmd=_xclick.
In my return page I read the data from PayPal then I form a new string to send back with cmd = _notify-validate.
When I make a call to https://sandbox.paypal.com/cgi-bin/webscr I am getting error saying "The remote certificate is invalid according to the validation procedure."
I tried making a call to https://www.paypal.com/cgi-bin/webscr instead and it always return t "INVALID".
This appears to be an SSL issue: This error message is caused because the process is not being able to validate the Server Certificate supplied by the Server during an HTTPS (SSL) request. The very first troubleshooting step should be to see if the server supplied certificate and every certificate in the chain is trouble free.

Certificate validation failed

Actors
-Asp.net site - Client
-Wcf services - Server
Both applications runs on IIS-7.
I want to make integration test between the two applications. The client access the Server through 'https'.
I have created a certificate and assigned it to the server. I also added the certificate to the 'Trusted Root Certification Authorities' to be considered a valid certificate. When I 'hit' the server's services through my browser (IE, chrome...) the certificate appears to be valid. But when my client application tries to access the server then I get the following error:
Could not establish trust relationship for the SSL/TLS secure channel with authority **** --->
The remote certificate is invalid according to the validation procedure.
Is there any way to skip the validation procedure or to make the certificate valid for my client application?
Just to know:
1. I cannot purchase a certificate because I will only use it for testing purposes.
2. I cannot make any changes on any of the application's code (server-client)
I finally managed to figured it out.
The problem was a previous (expired) certificate with the same name that was already added to the 'Trusted Root Certification Authorities'. Every time I was installing my new certificate through the 'Certificate Import Wizard' (or through MMC) the wizard informed me that it was successfully added. However, it was keeping the instance of the previous certificate without overwriting it.
Modify the validation callback to always return true:
ServicePointManager.ServerCertificateValidationCallback += (sender, certificate, chain, policyErrors) => true;
Or does that violate the 'no changes to code' condition?
How did you install the certificate into your trusted root store?
If you went through a browser to do it, most likely you only added it to the current user. Try adding it through the MMC snap-in for the Local Computer Account instead; this is where we install our self-signed IIS Express certificates and WCF seems happy with them.

Calling Remote Web Service -- "The request failed with HTTP status 401: Unauthorized"

I am calling a remote service and authenticating using a certificate. When testing with a Console App, everything works fine. When calling from an ASP.NET Website (.NET 4.0, IIS7) I receive a response code of 401 -- Unauthorized.
I am adding the certificate using code such as:
var client = new TheGeneratedProxy();
client.ClientCertificates.Add(new X509Certificate("D:\cert.pfx", "myPassword"));
(NOTE: I have also loaded the .pfx into the local Certificate Store using IE. The certificate is loaded into my "Personal" store -- so I suspect this to be the problem, since the Website will be running under a different account.)
I think the problem is that your IIS user (Network Service / ASPNET) doesn't have access to the certificate. In order to grant Network Service to access the certificate in the store, download the following tool: winhttpcertcfg (http://www.microsoft.com/downloads/details.aspx?familyid=c42e27ac-3409-40e9-8667-c748e422833f&displaylang=en)
Now open command prompt and type:
winhttpcertcfg –g –c LOCAL_MACHINE\My –s ORGNAME –a "Network Service"
Please note that "Network Service" can be substituted with any other account. I.e. if you you have configured a custom user for your app pool, you should put this user as the value for the -a parameter.
ORGNAME should be substituted with the Organisation name you specified during the creation of your cert.

Resources