无法获取证书消息凭证在我的WCF服务工作(Can't get certificate mes

2019-10-23 18:23发布

我做了承载WCF服务控制台应用程序。 我现在想修改它。 以下是当前工作...

Program.cs中

namespace FileRetrievalPoC
{
    class Program
    {
        static void Main(string[] args)
        {
            var address = "https://localhost:8000/FileRetrievalPoC";
            Console.WriteLine("Starting a service at {0}...", address);
            FileRetrievalService.Start(address, StoreLocation.LocalMachine, StoreName.TrustedPeople, "b7ba8f6e4c33ba55053f2e85898b383e40bf8ac9");
            Console.WriteLine("Service started.");
            Console.WriteLine("Press Enter to create a new proxy client and call the Get method.");
            Console.WriteLine("Press Escape to end the application.");
            while (true)
            {
                var key = Console.ReadKey();
                if (key.Key == ConsoleKey.Enter)
                {
                    var proxy = FileRetrievalService.Connect(address, "localhost", "username", "password");
                    Console.WriteLine("Read the following from the server: {0}", proxy.Get(@"C:\Users\User\Desktop\Document.txt"));
                    FileRetrievalService.CloseClients();
                }
                else if (key.Key == ConsoleKey.Escape)
                    break;
            }
            FileRetrievalService.CloseServer();
        }
    }
}

FileRetrievalService.cs:

class FileRetrievalService : IFileRetrieval
{

    private static BasicHttpsBinding _binding = new BasicHttpsBinding()
    {
        HostNameComparisonMode = HostNameComparisonMode.Exact,
        Security = new BasicHttpsSecurity()
        {
            Message = new BasicHttpMessageSecurity()
            {
                AlgorithmSuite = SecurityAlgorithmSuite.Basic256Sha256Rsa15,
                ClientCredentialType = BasicHttpMessageCredentialType.UserName
            },
            Mode = BasicHttpsSecurityMode.TransportWithMessageCredential,
            Transport = new HttpTransportSecurity()
            {
                ClientCredentialType = HttpClientCredentialType.Windows,
            }
        }
    };
    private static ChannelFactory<IFileRetrieval> _channelFactory;
    private static ServiceHost _host;

    public static void Start(string address, StoreLocation location, StoreName name, string thumbprint)
    {
        _host = new ServiceHost(typeof(FileRetrievalService));
        _host.Credentials.ServiceCertificate.SetCertificate(location, name, X509FindType.FindByThumbprint, thumbprint);
        _host.AddServiceEndpoint(typeof(IFileRetrieval), _binding, address);
        _host.Open();
    }

    public static void CloseClients()
    {
        if (_channelFactory != null)
            _channelFactory.Close();
        _channelFactory = null;
    }

    public static void CloseServer()
    {
        if (_host != null)
            _host.Close();
        _host = null;
    }

    public static void CloseServerAndClients()
    {
        CloseServer();
        CloseClients();
    }

    public static IFileRetrieval Connect(string address, string domain, string username, string password)
    {
        if (_channelFactory == null)
        {
            _channelFactory = new ChannelFactory<IFileRetrieval>(_binding, address);
            _channelFactory.Credentials.UserName.UserName = domain + '\\' + username;
            _channelFactory.Credentials.UserName.Password = password;
            _channelFactory.Credentials.Windows.ClientCredential = new NetworkCredential(username, password, domain);
        }
        return _channelFactory.CreateChannel();
    }

    public string Get(string path)
    {
        return File.ReadAllText(path);
    }

    public void Set(string path, string contents)
    {
        File.WriteAllText(path, contents);
    }
}

IFileRetrieval.cs:

[ServiceContract]
public interface IFileRetrieval
{
    [OperationContract]
    string Get(string path);
    [OperationContract]
    void Set(string path, string contents);
}

所有上面的代码工作,这是因为:

  1. 服务器端具有ClientCredentialType = BasicHttpMessageCredentialType.UserName上的约束力。
  2. 客户端设置的用户名凭据_channelFactory.Credentials.UserName对象。

我要添加更多的安全性,并有连接到服务器时,客户端还提供了一个SSL证书。 为了尽量要做到这一点,我已经在点1和2有以下逻辑的代码如下替换:

  1. 我试图用ClientCredentialType = BasicHttpMessageCredentialType.Certificate的结合,而不是ClientCredentialType = BasicHttpMessageCredentialType.UserName
  2. Connect方法,我现在设置客户端的证书( _channelFactory.Credentials.ClientCertificate.SetCertificate(location, name, X509FindType.FindByThumbprint, thumbprint); )和修改,以采取相应的证书信息的方法( StoreLocation location, StoreName name, string thumbprint )使在完全相同的参数来引用,从所述客户端中,从所述服务器端提供的相同的证书。 我已删除了之前的逻辑设置_channelFactory.Credentials.UserName对象。

这并没有工作,我得到下面的异常:

不安全或不正确的安全故障从对方收到。 参见故障代码和细节在内的FaultException。

它的内部异常说:

该消息确认安全时发生错误。

究竟应该怎样走? 我不使用IIS,所以我怎么能进一步追查这个错误? 我是一个有点损失。 我希望有人能解释什么可能是错误的,我能做些什么,以进一步修复错误或调试。

编辑 :我想出了一个办法,以进一步调试它,但它不是更有益的比我想象的那样。 里面我的App.config ,我增加了以下跟踪:

<system.diagnostics>
  <sources>
    <source name="System.ServiceModel" switchValue="Verbose, ActivityTracing" propagateActivity="true">
      <listeners>
        <add name="listener" type="System.Diagnostics.XmlWriterTraceListener" initializeData= "C:\Users\YourAccountUsername\Desktop\WCFTraces.svclog" />
      </listeners>
    </source>
    <source name="System.ServiceModel.MessageLogging" switchValue="Verbose, ActivityTracing" propagateActivity="true">
      <listeners>
        <add name="listener" type="System.Diagnostics.XmlWriterTraceListener" initializeData= "C:\Users\YourAccountUsername\Desktop\WCFTraces.svclog" />
      </listeners>
    </source>
  </sources>
</system.diagnostics>

现在里面WCFTraces.svclog ,我看到一堆例外的从服务器端也是如此。 第一个是:

安全处理器是无法找到消息中的安全头。 这可能是因为消息是不安全的故障或因为在通信双方之间具有约束力的不匹配。 如果该服务进行了安全配置和客户端没有使用安全措施可能出现这种情况。

我不知道为什么消息没有安全头,考虑到我所指定的客户端证书。 什么是客户端代码丢失?

编辑 :嗯,我也看到了这个错误:

对于“Basic256Sha256Rsa15”算法套件的关键尺寸要求不被“System.IdentityModel.Tokens.X509SecurityToken”令牌,该令牌有“8192”密钥大小满足。

其根据接收的字节。 我的证书有一个8192字节的私钥和公钥,但是这不能成为我的选择的一个很好的匹配AlgorithmSuite = SecurityAlgorithmSuite.Basic256Sha256Rsa15 。 有谁知道我应该做的事情在这里,让此证书? 我可以...尝试使用256位密钥这还是指签名算法是我的证件512位的问题?

Answer 1:

我想通了,最后。 这些错误误导了我一条黑暗的道路,但是现在我知道了。

问题

这似乎是一个不成文的规定。 当您指定Mode = BasicHttpsSecurityMode.TransportWithMessageCredential告诉它同时使用信息和运输凭证,然后您使用证书的留言凭据,

Message = new BasicHttpMessageSecurity()
{
    AlgorithmSuite = SecurityAlgorithmSuite.Basic256Sha256Rsa15,
    ClientCredentialType = BasicHttpMessageCredentialType.Certificate
}

不能使用证书的留言凭据,如果它拥有超过4096位为它的键。

解决方案

我做了一个新的自签名证书有4096位RSA密钥,使用SHA 512作为签名算法。



文章来源: Can't get certificate message credentials to work in my WCF service