无法获取证书信息的凭证在我的WCF服务工作我的、凭证、证书、工作

2023-09-03 06:49:23 作者:瞳孔里de爱ン唯你懂づ

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

I made a console application that hosts a WCF service. I am now trying to modify it. Here is what currently works...

的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);
}

以上所有code ++工程,这是因为:

All the above code works, because:

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

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

I want to add more security, and have the client-side also provide an SSL certificate when connecting to the server. 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:

在我试图使用 ClientCredentialType = BasicHttpMessageCredentialType.Certificate 上的结合,而不是 ClientCredentialType = BasicHttpMessageCredentialType.UserName 。 _channelFactory.Credentials.ClientCertificate.SetCertificate(位置,名称,X509FindType.FindByThumbprint 在连接的方法,我现在设置客户端的证书( ,按手印); )和修改,以采取相应的证书信息的方法(的StoreLocation位置,STORENAME名,字符串指纹)的传球在完全相同的参数来引用,从客户端,相同的证书,它是从服务器端psented $ P $。我已删除了设置 _channelFactory.Credentials.UserName 对象previous逻辑。 I am trying to use ClientCredentialType = BasicHttpMessageCredentialType.Certificate on the binding instead of ClientCredentialType = BasicHttpMessageCredentialType.UserName. 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. I have removed the previous logic that sets the _channelFactory.Credentials.UserName object.

这没有工作,我也得到了以下异常:

This did not work, and I get the following exception:

这是无抵押或担保不正确的故障是由对方收到   派对。请参阅故障code和细节在内的FaultException。

An unsecured or incorrectly secured fault was received from the other party. See the inner FaultException for the fault code and detail.

它的内部异常说:

有关消息验证的安全性时发生错误。

An error occurred when verifying security for the message.

究竟应该何去何从?我不使用IIS,所以我怎么可以跟踪这个错误进一步?我在一个小的损失的。我希望有人能解释什么可能是错误的,我能做些什么来解决这个错误,或者进一步调试。

Where does one go from here? I am not using IIS, so how can I trace this error further? 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.

修改:我想出了一个办法,以进一步调试,但它比我想象的不大有帮助的那样。里面我的App.config ,我增加了以下跟踪:

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:

<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 里面,我看到一堆从服务器端异常的为好。第一个是:

Now inside of WCFTraces.svclog, I see a bunch of exceptions from the server side as well. 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.

我不知道为什么该消息不具有安全头,考虑到我指定的客户端证书。什么是客户端code失踪?

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:

对于Basic256Sha256Rsa15算法的密钥长度的要求   套件不被满足   System.IdentityModel.Tokens.X509SecurityToken'令牌有钥匙   对8192的大小。

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字节的私钥和公钥,但绝不能是一个很好的比赛对我的选择 AlgorithmSuite = SecurityAlgorithmSuite.Basic256Sha256Rsa15 。有谁知道我应该在这里做,让此证书?我可以尝试使用256位密钥这个...或者是签名算法为512位在我的证书问题?

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. 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?

推荐答案

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

I figured it out, at last. The errors mislead me down a dark path, but now I got it.

问题

这似乎是一个不成文的规定。当指定模式= BasicHttpsSecurityMode.TransportWithMessageCredential 来告诉它使用两个消息和传输凭据,然后您使用证书的留言凭据,

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,

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

您不能使用证书消息的凭据,如果它拥有超过4096位的密钥。

解决方案

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

I made a new self-signed certificate with a 4096-bit RSA keypair, using SHA 512 as the signature algorithm.