IIS Client certificate not working. Returns 403 error - iis

I'm trying to setup IIS 8 (Windows Server 2012) to accept client certificates for a secured WebAPI endpoint. Following this post I created a self signed certificate and a client certificate:
makecert.exe -r -n "CN=MyCompany" -pe -sv MyCompany.pvk -a sha1 -len 2048 -cy authority MyCompany.cer
makecert.exe -iv MyCompany.pvk -ic MyCompany.cer -n "CN=MY Client" -pe -sv MyClient.pvk -a sha1 -len 2048 -sky exchange MyClient.cer -eku 1.3.6.1.5.5.7.3.2
pvk2pfx.exe -pvk MyClient.pvk -spc MyClient.cer -pfx MyClient.pfx -po THE_PASSWORD
I installed the root certificate MyCompany.cer on the IIS server, then on IIS Manager/SSL Settings I selected the "Accept" radio button to allow the website accept client certificates.
On the client side a have a C# test console app that loads the client cert MyClient.pfx file and calls the WebAPI endpoint:
var certHandler = new WebRequestHandler();
certHandler.ClientCertificateOptions = ClientCertificateOption.Manual;
certHandler.UseProxy = false;
var certificate = new X509Certificate2(File.ReadAllBytes(#"C:\MyClient.pfx"), "THE_PASSWORD");
certHandler.ClientCertificates.Add(certificate);
var client = new HttpClient(certHandler);
var result = client.GetAsync("https://MyServer/api/MyEndpoint").Result;
string resultStr = result.Content.ReadAsStringAsync().Result;
Console.WriteLine(resultStr);
I'm getting back a 403 error:
403 - Forbidden: Access is denied.
You do not have permission to view this directory or page using the credentials that you supplied.
I tried the same setup on my local IIS (Windows 7): Imported the MyCompany.cer file, setup SSL in IIS. This time everything works fine and the WebAPI endpoint can see the client certificate with no problem.
Any ideas?
-- Update 1
I enabled Failed REquest Tracing on IIS and I get this:
<failedRequest url="https://myserver:443/"
siteId="35"
appPoolId="CertTest"
processId="7248"
verb="GET"
authenticationType="NOT_AVAILABLE" activityId="{00000000-0000-0000-B0AA-0280000000E0}"
failureReason="STATUS_CODE"
statusCode="403.16"
triggerStatusCode="403.16"
timeTaken="0"
xmlns:freb="http://schemas.microsoft.com/win/2006/06/iis/freb"
>
If I understand right the error is 403.16. I understand that happens when the certificate on the server is not imported into the Trusted Root Certification Authorities under Local Computer. I double checked and that's not my case.

Check that
On your IIS machine you have installed Server's cert issuer certificate to Trusted Root Certification Authorities under Local Computer
On your IIS machine you have installed Client's cert issuer certificate to Trusted Root Certification Authorities under Local Computer
On your client machine you have installed Server's cert issuer certificate to Trusted Root Certification Authorities under Windows User that runs console app
On your client machine you have installed Client's cert issuer certificate to Trusted Root Certification Authorities under Windows User that runs console app. Or you can make sure to include all necessary certificate's chain to pfx file
In code use X509Certificate2's ctor version with X509KeyStorageFlags.UserKeySet explicitly.
If it won't help,
try to open url in IE (under the same Windows User Account that runs console app).
open *.cer files with double click on a client machine under Windows User Account that runs console app and see what Windows says about they validity.
change IIS SSL settings to ignore client certificate to see if it's all good with server certificate. Try both browser and console app.

Have a look at the following blog post: https://configmgrblog.com/2014/02/23/configmgr-2012-r2-internet-facing-mp-windows-server-2012-r2-note/
In short: There seems to be an issue with client certificate authentication and IIS 8.x in Windows Server 2012 (R2), that might cause status code 403.16 to be returned when using client certificates. Solution:
Set registry DWORD entries under HKey_Local_Machine\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL on your server:
SendTrustedIssuerList = 0
ClientAuthTrustMode = 2
The post further mentions that if your get a 403.13 (client certificate revoked) after fixing the in initial problem (403.16), you should disable client certificate revocation check on the server. I would not recommend that. Please make sure that the CDP is correctly set in the client certificate. The CDP has to be reachable from the server and the revocation list should be valid and not outdated.

Related

How to disable all built-in SSL certificates in wget and just use self-signed one?

I would like to use wget (or curl) to connect to my website using only my self signed SSL certificate. The website also has some root CA signed wildcard certificates.
wget -O- --ca-certificate=my.pem --ca-directory=/dev/null --certificate=my.pem https://example.com
This works on my server with the self signed certificate, but it also establishes a connection to any regular SSL-enabled public website (when changing example.com). So it seems to not disable build-in root CAs.
How can I disable all build-in root CAs in wget so only my private certificate can establish a secure connection and it fails without (to test if the self signed cert is installed correctly)?
Got some help on stackexchange: real openssl s_client (check with openssl version) supports the parameter -verify_return_error which will catch certificate verification errors.

certutil -repairstore opening the smartCard

I am trying to install the certificate on an IIS 8.5 server on Windows server 2012.
When going to the IIS manager, I went to 'Server certificates' -> Complete Certificate Request, I select my certificate .p7b and I go to 'Binds' to select the certificate for port 443 of https it is not in the list.
The problem that is happening is: when I import the certificate, it appears that it was imported. But when you refresh the list of certificates, it does not list any linked / added certificates.
Searching, I found a possible solution:
run -> cmd -> run certutil -repairstore my "paste the serial # in here"
But this command is loading the 'Smart card'.

Download SSL Corproate Proxy Cert via Linux CLI

How do I download a proxy's SSL cert and save it to a file using the Linux command line.
It's possible to download an ssl cert via the openssl tool: https://superuser.com/questions/97201/how-to-save-a-remote-server-ssl-certificate-locally-as-a-file. But this does not work when behind a corporate proxy that re-writes the SSL cert. I would like to download the proxy's ssl cert. Changing the HOST and PORT to my proxy's host and port does not work either.
Downloading the cert using my browser works but I need to do this in a bash script.
You can only extract certificates from the connection which actually get send inside the connection. Within a MITM proxy the root CA you want to have usually does not get send since it is expected to be installed locally as trusted, similar to a public root CA. And the reason you can extract this MITM CA within your browser is because the browser already has this CA as trusted in the CA store and can thus export it.
As mentioned here, openssl 1.1.0 and above support the -proxy argument so you can get the proxy's certificates with a command like (jcenter.bintray.com is just an example host to connect to)
openssl s_client -showcerts -proxy $https_proxy -connect jcenter.bintray.com:443
Also see this script for a more complete example how to import the certificate(s) to a JVM keystore and the system certificates.

SSL handshake failure with node.js https

I have an API running with express using https. For testing, I've been using tinycert.org for the certificates, which work fine on my machine.
I'm using docker to package up the app, and docker-machine with docker-compose to run it on a digital ocean server.
When I try to connect with Chrome, I get ERR_SSL_VERSION_OR_CIPHER_MISMATCH. When running this with curl, I get a handshake failure: curl: (35) SSL peer handshake failed, the server most likely requires a client certificate to connect.
I tried to debug with Wireshark's SSL dissector, but it hasn't given me much more info: I can see the "Client Hello" and then the next frame is "Handshake Failure (40)".
I considered that maybe node on the docker container has no available ciphers, but it has a huge list, so it can't be that. I'm unsure as to what's going on and how to remedy it.
EDIT
Here's my createServer() block:
let app = express();
let httpsOpts = {
key: fs.readFileSync("./secure/key.pem"),
cert: fs.readFileSync("./secure/cert.pem")
};
let port = 8080;
https.createServer(httpsOpts, app).listen(port);
I've had this problem for a really long time too, there's a weird fix:
Don't convert your certs to .pem; it works fine as .crt and .key files.
Add ca: fs.readFileSync("path to CA bundle file") to the https options.
It looks like your server is only sending the top certificate and the CA bundle file has the intermediate and root certificates which you'll need for non-browser use.
IMPORTANT! Reinstall or update node to the latest version.
You can use sudo apt-get upgrade if you're on Linux (it may take a while).
Re-download your certificate or get a new one.
If you are acting as your own certificate authority it could be not recognizing / trusting the certificate, so try testing your site on ssllabs.com.
If you're using the http2 API try adding allowHTTP1: true to the options.

Using self signed client certificate in development

I'm trying to set up a dev env for a web application that require ssl + client certificate.
So the server & client is the same, it's my laptop.
What's I've done so far, using several different tutorial found on the net:
- Created a self signed Root CA
- Created a "Server" certificate using this root CA, and configure IIS ssl with this certificate.
- Created a "Client" certificate (still using the same root certificate), with all roles
The command used to create certificates looks like this:
makecert -n "CN=Dev Client" -iv DevCA.pvk -ic DevCA.cer -pe -ss my -sr localmachine -sv DevClient.pvk DevClient.cer
pvk2pfx -pvk DevClient.pvk -spc DevClient.cer -pfx DevClient.pfx
So both Client & Server certificate has the same root certificate.
Then I:
- Added the Root certificate in the "Trusted authority store" of both current user and local machine
- Added the Client certificate in the "Personal store" of "Current user"
- Added the Server certificate in the "Personal store" of "Local computer"
When I check Client certificate properties, it correctly found the root certificate.
But now, the problem is that it doesn't works in IIS.
If I set client certificate as "required", I've an HTTP 403.4 Forbidden
If I set client certificate as "accepted", the site indeed works but doesn't receive the certificate
Does someone know how to make this works?
You should use
makecert ... -sky exchange
for server certificate and
makecert ... -sky signature
for client certificate in order to server has the ability to secure connection and client has the ability to authenticate himself.

Resources