Eines vorweg: Der richtige Ort zum Speichern von Zertifikaten ist der Certificate Store. Wenn das, aus welchen Gründen auch immer, problematisch ist, kann man das Zertifikat bzw. den privaten Schlüssel auch manuell laden und WCF übergeben. Die nachfolgenden Notizen beschreiben dies, indem gezeigt wird, wie man eine Applikation, die sich auf den Certificate Store abstützt, auf eine Verwendug ohne Certificate Store umstellen kann.
1. Privaten Schlüssel aus Cert-Store exportieren. Damit dies möglich ist, muss der Schlüssel beim Importieren in den Certificate Store als "exportierbar" markiert werden.
2. Benutzerdefinierte ServiceHostFactory erstellen (siehe unten)
3. ServiceHostFactory in .svc-Datei angeben:
<%@ ServiceHost Language="C#" Debug="true" Service="FlugService.FlugService" Factory="FlugService.CustomFactory" CodeBehind="FlugService.svc.cs" %>
4. Validierung gegen Cert-Store am Client abschalten:
[...]
c.ClientCredentials.UserName.UserName = "soa";
c.ClientCredentials.UserName.Password = "geheim";
c.ClientCredentials.ServiceCertificate.Authentication.CertificateValidationMode = X509CertificateValidationMode.None;
[...]
5. Validierung gegen das Zertifikat erfolgt über <identity>-Tag in Client-Konfig:
<identity>
<certificate encodedValue="..." />
</identity>
Nachfolgend noch der Quellcode für die benutzerdefinierte ServiceHostFactory:
using System.Web;
using System.ServiceModel.Activation;
using System.ServiceModel.Description;
using System.Security.Cryptography.X509Certificates;
namespace FlugService
{
public class CustomFactory : ServiceHostFactory
{
protected override System.ServiceModel.ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
{
var sh = base.CreateServiceHost(serviceType, baseAddresses);
ServiceCredentials sc = (ServiceCredentials)sh.Description.Behaviors.Where(b => b is ServiceCredentials).FirstOrDefault();
if (sc == null)
{
throw new Exception("ServiceCredentials erwartet!");
}
// Cert inkl. privaten Schlüssel laden
sc.ServiceCertificate.Certificate = new X509Certificate2(@"c:\temp\test\my.pfx", "P@ssw0rd");
return sh;
}
}
}