Programmatic WCF Message Security with Certificates

六眼飞鱼酱① 提交于 2019-12-12 07:31:13

问题


I've written a self-hosted WCF service using WSHttpBindings and I'm trying to implement message-level security using certificates I've generated myself. Unfortunately I'm getting a buried exception (via the Service Trace Viewer) stating "The credentials supplied to the package were not recognized."

A couple notes:

  1. This has to be done in code, not in configuration
  2. (Server/Client)Cert are certificates that are in the local machine store with accessible private keys to my user while debugging.
  3. I've googled the hell out of this and found a good resource for setting up WCF message based security here

I'm not sure what I'm missing. Most of this stuff seems straight forward except for creating the endpoint identities. It fails with the same message whether I use DnsEndpointIdentities, cert based ones, or no identities at all.

Can anyone point me in the right direction?

Server side:

var binding = new WSHttpBinding
    {
      Security =
      {
        Mode = SecurityMode.Message,
        Message = 
        {
          ClientCredentialType = MessageCredentialType.Certificate,
          AlgorithmSuite = SecurityAlgorithmSuite.Basic256Sha256Rsa15
        }
      }
    };

_host = new ServiceHost(this)
{
  Credentials =
  {
    ServiceCertificate =
    {
      Certificate = ServiceCert
    },
    ClientCertificate =
    {
      Certificate = ClientCert,
      Authentication =
      {
        TrustedStoreLocation = StoreLocation.LocalMachine,
        RevocationMode = X509RevocationMode.NoCheck,
        CertificateValidationMode = X509CertificateValidationMode.PeerOrChainTrust
       }
    }
  }
};
var address = new Uri(string.Format(@"http://serviceaddress"));
var ep = _host.AddServiceEndpoint(typeof (IService), binding, address);
ep.Address = new EndpointAddress(address, EndpointIdentity.CreateX509CertificateIdentity(ServiceCert));
_host.Open();

Client side:

var binding = new WSHttpBinding
    {
      Security =
      {
        Mode = SecurityMode.Message,
        Message =
        { 
          ClientCredentialType = MessageCredentialType.Certificate,
          AlgorithmSuite = SecurityAlgorithmSuite.Basic256Sha256Rsa15
        }
      }
    };
var address = new Uri(@"http://serviceaddress");
var endpoint = new EndpointAddress(address, EndpointIdentity.CreateX509CertificateIdentity(ServerCert));
var channelFactory = new ChannelFactory<IService>(binding, endpoint)
    {
      Credentials =
      {
        ServiceCertificate =
        {
          DefaultCertificate = ServerCert,
          Authentication =
          {
            RevocationMode = X509RevocationMode.NoCheck,
            TrustedStoreLocation = StoreLocation.LocalMachine,
            CertificateValidationMode = X509CertificateValidationMode.PeerOrChainTrust
          }
        },
        ClientCertificate =
        {
          Certificate = ClientCert
        }
      }
    };
var channel = channelFactory.CreateChannel();

回答1:


this msdn article helped tremendously. I think the root of the problem was setting the following message security parameters to false:

httpBinding.Security.Message.NegotiateServiceCredential = false;
httpBinding.Security.Message.EstablishSecurityContext = false;

So now the overall code for the server side looks more like:

var httpBinding = new WSHttpBinding(SecurityMode.Message);
httpBinding.Security.Message.ClientCredentialType = MessageCredentialType.Certificate;
httpBinding.Security.Message.NegotiateServiceCredential = false;
httpBinding.Security.Message.EstablishSecurityContext = false;
var httpUri = new Uri("http://serviceaddress");
_host = new ServiceHost(this, httpUri);
_host.Credentials.ServiceCertificate.SetCertificate(StoreLocation.LocalMachine, StoreName.TrustedPeople, X509FindType.FindByThumbprint, serverThumbprint);
_host.Credentials.ClientCertificate.Authentication.RevocationMode = X509RevocationMode.NoCheck;
_host.Credentials.ClientCertificate.Authentication.TrustedStoreLocation = StoreLocation.LocalMachine;
_host.AddServiceEndpoint(typeof(IMetaService), httpBinding, httpUri);
_host.Open();

and the client side:

var httpBinding = new WSHttpBinding(SecurityMode.Message);
httpBinding.Security.Message.ClientCredentialType = MessageCredentialType.Certificate;
httpBinding.Security.Message.NegotiateServiceCredential = false;
httpBinding.Security.Message.EstablishSecurityContext = false;
var httpUri = new Uri("http://serviceaddress");
var httpEndpoint = new EndpointAddress(httpUri, EndpointIdentity.CreateDnsIdentity("name of server cert"));
var newFactory = new ChannelFactory<IMetaService>(httpBinding, httpEndpoint);
newFactory.Credentials.ClientCertificate.SetCertificate(StoreLocation.LocalMachine, StoreName.TrustedPeople, X509FindType.FindByThumbprint, "client certificate thumbprint");
newFactory.Credentials.ServiceCertificate.SetDefaultCertificate(StoreLocation.LocalMachine, StoreName.TrustedPeople, X509FindType.FindByThumbprint, "server certificate thumbprint");
var channel = newFactory.CreateChannel();


来源:https://stackoverflow.com/questions/6039282/programmatic-wcf-message-security-with-certificates

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!