简体   繁体   English

无法获得证书消息凭据以在我的WCF服务中工作

[英]Can't get certificate message credentials to work in my WCF service

I made a console application that hosts a WCF service. 我制作了一个承载WCF服务的控制台应用程序。 I am now trying to modify it. 我现在正在尝试对其进行修改。 Here is what currently works... 这是目前有效的...

Program.cs : 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 : 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 : IFileRetrieval.cs

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

All the above code works, because: 以上所有代码均有效,因为:

  1. Server-side has ClientCredentialType = BasicHttpMessageCredentialType.UserName on the binding. 服务器端在绑定上具有ClientCredentialType = BasicHttpMessageCredentialType.UserName
  2. Client-side sets the username credentials on the _channelFactory.Credentials.UserName object. 客户端在_channelFactory.Credentials.UserName对象上设置用户名凭据。

I want to add more security, and have the client-side also provide an SSL certificate when connecting to the server. 我想增加安全性,并让客户端在连接到服务器时也提供SSL证书。 In order to try to do this, I have made the following replacements in the code for points 1 and 2 with the following logic: 为了尝试执行此操作,我在代码中用以下逻辑替换了点1和2:

  1. I am trying to use ClientCredentialType = BasicHttpMessageCredentialType.Certificate on the binding instead of ClientCredentialType = BasicHttpMessageCredentialType.UserName . 我正在尝试在绑定上使用ClientCredentialType = BasicHttpMessageCredentialType.Certificate而不是ClientCredentialType = BasicHttpMessageCredentialType.UserName
  2. In the Connect method, I am now setting the client's certificate ( _channelFactory.Credentials.ClientCertificate.SetCertificate(location, name, X509FindType.FindByThumbprint, thumbprint); ) and modified the method to take the appropriate certificate information ( StoreLocation location, StoreName name, string thumbprint ) passing in exactly the same parameters to reference, from the client-side, the same certificate that is presented from the server-side. Connect方法中,我现在设置了客户端的证书( _channelFactory.Credentials.ClientCertificate.SetCertificate(location, name, X509FindType.FindByThumbprint, thumbprint); ),并修改了该方法以采用适当的证书信息( StoreLocation location, StoreName name, string thumbprint )传递完全相同的参数,以从客户端引用从服务器端提供的相同证书。 I have removed the previous logic that sets the _channelFactory.Credentials.UserName object. 我已经删除了设置_channelFactory.Credentials.UserName对象的先前逻辑。

This did not work, and I get the following exception: 这不起作用,并且出现以下异常:

An unsecured or incorrectly secured fault was received from the other party. 接收到来自另一方的不安全或不正确安全的故障。 See the inner FaultException for the fault code and detail. 有关错误代码和详细信息,请参见内部FaultException。

Its inner exception says: 其内部异常表示:

An error occurred when verifying security for the message. 验证消息的安全性时发生错误。

Where does one go from here? 一个人从这里去哪里? I am not using IIS, so how can I trace this error further? 我没有使用IIS,那么如何进一步跟踪此错误? I am at a bit of a loss. 我有点茫然。 I was hoping someone could explain what might be wrong, and what I can do to fix the error or debug it further. 我希望有人可以解释什么地方出了问题,以及如何解决该错误或进一步对其进行调试。

Edit : I figured out a way to debug it further, but its not much more helpful than I thought it would be. 编辑 :我想出了一种进一步调试它的方法,但是它并没有比我想象的有用得多。 Inside of my App.config , I added the following tracing: 在我的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>

Now inside of WCFTraces.svclog , I see a bunch of exceptions from the server side as well. 现在在WCFTraces.svclog内部,我也从服务器端看到了很多异常。 The first one being: 第一个是:

Security processor was unable to find a security header in the message. 安全处理器无法在消息中找到安全标头。 This might be because the message is an unsecured fault or because there is a binding mismatch between the communicating parties. 这可能是因为该消息是不安全的故障,或者是由于通信双方之间存在绑定不匹配。 This can occur if the service is configured for security and the client is not using security. 如果将服务配置为具有安全性,并且客户端未使用安全性,则会发生这种情况。

I'm not sure why the message does not have a security header, considering I've specified the client certificate. 考虑到我已经指定了客户端证书,我不确定为什么该消息没有安全标头。 What is the client code missing? 客户端代码丢失了什么?

Edit : Ah, I also see this error: 编辑 :啊,我也看到此错误:

The key size requirements for the 'Basic256Sha256Rsa15' algorithm suite are not met by the 'System.IdentityModel.Tokens.X509SecurityToken' token which has key size of '8192'. 密钥大小为'8192'的'System.IdentityModel.Tokens.X509SecurityToken'令牌不满足'Basic256Sha256Rsa15'算法套件的密钥大小要求。

Its under received bytes. 它的接收字节不足。 My certificate has an 8192-byte private and public key, but this must not be a good match for my selected AlgorithmSuite = SecurityAlgorithmSuite.Basic256Sha256Rsa15 . 我的证书具有8192字节的私钥和公钥,但这不能与我选择的AlgorithmSuite = SecurityAlgorithmSuite.Basic256Sha256Rsa15很好地匹配。 Does anyone know what I should do here to allow this certificate? 有人知道我在这里应该怎么允许这个证书吗? I can try using a 256 bit key for this...or is the problem that the signature algorithm is 512 bits on my certificate? 我可以尝试为此使用256位密钥...还是我的证书上的签名算法是512位的问题?

I figured it out, at last. 我终于知道了。 The errors mislead me down a dark path, but now I got it. 错误使我误入了一条黑暗的道路,但现在我明白了。

The Problem 问题

It seems an unwritten rule. 这似乎是一条未成文的规则。 When you specify Mode = BasicHttpsSecurityMode.TransportWithMessageCredential to tell it to use both message and transport credentials, and you then use a certificate for your message credentials, 当您指定Mode = BasicHttpsSecurityMode.TransportWithMessageCredential告诉它同时使用消息和传输凭据时,然后使用证书作为消息凭据,

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

You cannot use a certificate for your message credentials if it has over 4096 bits for its keys. 如果证书的密钥超过4096位,则不能使用证书作为消息凭据。

The Solution 解决方案

I made a new self-signed certificate with a 4096-bit RSA keypair, using SHA 512 as the signature algorithm. 我使用SHA 512作为签名算法,使用4096位RSA密钥对制作了一个新的自签名证书。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM