Disclaimer: Questions with titles like this one are common, but no answer has provided a solution for me so I need to ask it anyway (with a new set of parameters).
Problem
A webservice client endpoint is declared in web.config like this:
<behaviors>
<endpointBehaviors>
<behavior name="bankid">
<clientCredentials>
<clientCertificate findValue="FP Testcert 2"
storeLocation="LocalMachine"
storeName="Root"
x509FindType="FindBySubjectName"/>
<serviceCertificate>
<defaultCertificate findValue="Test BankID SSL Root CA v1 Test"
storeLocation="LocalMachine"
storeName="Root"
x509FindType="FindBySubjectName"/>
<authentication certificateValidationMode="None"
revocationMode="NoCheck"
trustedStoreLocation="LocalMachine"/>
</serviceCertificate>
</clientCredentials>
</behavior>
</endpointBehaviors>
</behaviors>
The certificates (client and server certificate) are installed using the "Manage computer certificates" app. They are stored in a .cer file (server certificate) and a .pfx file (client certificate) respectively. They are both stored in "Trusted Root Certification Authorities".
Success
Running the client using the visual studio debug webserver (IIS Express) is successful.
Failure
However, when I try to run it in IIS, I get the error message
Could not establish secure channel for SSL/TLS with authority 'site.com'
Problem solving method
I have tried to create a web api function that lets me know if the server finds the certificates in question. It does. The code looks like
[HttpGet]
[Route("Debug/certs")]
public CertsOutput certs()
{
var certStore = new X509Store(StoreName.Root, StoreLocation.LocalMachine);
certStore.Open(OpenFlags.ReadOnly);
var config = System.Web.Configuration.WebConfigurationManager
.OpenWebConfiguration("~");
var group = ServiceModelSectionGroup.GetSectionGroup(config);
var endPointBehaviors = group.Behaviors.EndpointBehaviors;
var endpointBehavior = endPointBehaviors[0];
var ClientCredential = (ClientCredentialsElement) endpointBehavior[0];
var clientCert = ClientCredential.ClientCertificate;
var serverCert = ClientCredential.ServiceCertificate.DefaultCertificate;
var result = new CertsOutput
{
clientCert = new CertsOutput.Cert
{
FindValue = clientCert.FindValue,
StoreName = clientCert.StoreName.ToString(),
StoreLocation = clientCert.StoreLocation.ToString(),
FindType = clientCert.X509FindType.ToString()
},
serverCert = new CertsOutput.Cert
{
FindValue = serverCert.FindValue,
StoreName = serverCert.StoreName.ToString(),
StoreLocation = serverCert.StoreLocation.ToString(),
FindType = serverCert.X509FindType.ToString()
}
};
return result;
}
public class CertsOutput
{
public Cert clientCert { get; set; }
public Cert serverCert { get; set; }
public class Cert
{
public string FindValue { get; set; }
public string StoreName { get; set; }
public string StoreLocation { get; set; }
public string FindType { get; set; }
public string Expiration => Certificate?.GetExpirationDateString()
?? "Cant find cert";
X509Certificate _certificate = null;
private X509Certificate Certificate
{
get
{
if (_certificate != null)
return _certificate;
StoreName storeNameEnum;
switch(StoreName)
{
case "My":
storeNameEnum = System_StoreName.My;
break;
case "Root":
storeNameEnum = System_StoreName.Root;
break;
default:
throw new Exception("Unknown store name: " + StoreName);
}
StoreLocation storeLocationEnum;
switch(StoreLocation)
{
case "LocalMachine":
storeLocationEnum = System_StoreLocation.LocalMachine;
break;
case "CurrentUser":
storeLocationEnum = System_StoreLocation.CurrentUser;
break;
default:
throw new Exception("Unknown store location: " + StoreLocation);
}
var certStore = new X509Store(storeNameEnum, storeLocationEnum);
certStore.Open(OpenFlags.ReadOnly);
var certCollection = certStore.Certificates.Find
(X509FindType.FindBySubjectName, FindValue, validOnly:false);
certStore.Close();
var result = certCollection[0];
_certificate = result;
return result;
}
}
}
}
Even if I am running this on IIS, I get an output like this (using console.log in chrome):
So the certs are clearly visible to the IIS, although they are stored in "Trusted Root Certification Authorities". The only way expire dates could have been retrieved is using the store.