SSL客户端/服务器相互认证

4

你好,我正在尝试使用C#实现SSL客户端/服务器通信,并使用服务器和客户端证书进行相互认证。我已经成功地使用服务器证书完成了SSL通信,在客户端方面,我使用类似以下的内容:

TcpClient client = new TcpClient(machineName, port);
//Create an SSL stream that will close the client's stream.
   SslStream sslStream = new SslStream(
   client.GetStream(),
   false,
   new RemoteCertificateValidationCallback(ValidateServerCertificate),
   null
   );
try
{
    // The server name must match the name on the server certificate.
    sslStream.AuthenticateAsClient(serverName);
}
catch (AuthenticationException e)
{
    Console.WriteLine("Exception: {0}", e.Message);
    if (e.InnerException != null)
    {
        Console.WriteLine("Inner exception: {0}", e.InnerException.Message);
    }
    Console.WriteLine("Authentication failed - closing the connection.");
    client.Close();
    return;
} 

我假设我需要使用。
AuthenticateAsClient(string targetHost, X509CertificateCollection clientCertificates, SslProtocols enabledSslProtocols, bool checkCertificateRevocation)

方法,我理解得对吗?有人能向我展示如何在所有事情中使用它吗?甚至在服务器端也可以,或者指向一个基本的例子?

非常感谢。


我可以问一下为什么您没有尝试使用WCF框架吗?它们提供了相互认证的选项,并且可以为您完成大量繁重的工作。WCF文档 - Jay
2个回答

6
static void HTTPSClient()
{
    try
    {
        string message = "GET / HTTP/1.0\r\nHost: host.com\r\n\r\n";

        byte[] data = System.Text.Encoding.ASCII.GetBytes(message);

        string server = "host.com";
        int nPort = 443;
        TcpClient client = new TcpClient(server, nPort);

        X509Certificate2Collection cCollection = new X509Certificate2Collection();
        cCollection.Add(new X509Certificate2("cert.pfx", "password"));


        using (SslStream sslStream = new SslStream(client.GetStream(), false, new RemoteCertificateValidationCallback(ValidateServerCertificate), null))
        {
            // Add a client certificate to the ssl connection
            sslStream.AuthenticateAsClient(server, cCollection, System.Security.Authentication.SslProtocols.Default, true);

            sslStream.Write(data, 0, data.Length);

            data = new Byte[8192];
            int bytes = 0;
            string responseData = "";

            do
            {
                bytes = sslStream.Read(data, 0, data.Length);
                if (bytes > 0)
                {
                    responseData += System.Text.Encoding.ASCII.GetString(data, 0, bytes);
                }
            }
            while (bytes > 0);

            Console.WriteLine("Response: " + responseData);
        }

        // Disconnect and close the client
        client.Close();
    }
    catch (Exception ex)
    {
        Console.WriteLine("Error: " + ex.ToString());
    }
}

public static bool ValidateServerCertificate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
{
    if (sslPolicyErrors == SslPolicyErrors.None)
        return true;

    Console.WriteLine("Certificate error: {0}", sslPolicyErrors);

    // Do not allow this client to communicate with unauthenticated servers.
    return false;
}

2
欢迎来到stackoverflow!为了提高帖子的准确性,最好为示例代码提供一个简短的描述 :) - Picrofo Software

2
  1. You need a x509 self certificate, to create it simple, download pluralsight self cert
  2. Generate certificate as in image
  3. Create new web site, there choose wcf service.
  4. Add in solution new console application, to test our service.
  5. In web.config of service put configuration:

    <?xml version="1.0"?>
    <configuration>
     <system.serviceModel>
    <behaviors>
        <serviceBehaviors>
            <behavior name="ServiceCredentialsBehavior">
                <serviceCredentials>
                    <serviceCertificate findValue="cn=cool" storeName="TrustedPeople" storeLocation="CurrentUser" />
                </serviceCredentials>
                <serviceMetadata httpGetEnabled="true" />
            </behavior>
        </serviceBehaviors>
    </behaviors>
    <services>
        <service behaviorConfiguration="ServiceCredentialsBehavior" name="Service">
            <endpoint address="" binding="wsHttpBinding" bindingConfiguration="MessageAndUserName" name="SecuredByTransportEndpoint" contract="IService"/>
        </service>
    </services>
    <bindings>
        <wsHttpBinding>
            <binding name="MessageAndUserName">
                <security mode="Message">
                    <message clientCredentialType="UserName"/>
                </security>
            </binding>
        </wsHttpBinding>
    </bindings>
    <client/>
    

  6. In Service class, delete existing methods and add:

    public string TestAccess() { return OperationContext.Current.ServiceSecurityContext.PrimaryIdentity.Name; }

  7. in IService delete Data Contract, delete operation contracts and add new operation contract:

    [OperationContract]
    public string TestAccess();

  8. Run service and add service reference in client application to our service

  9. Client config:

    <?xml version="1.0" encoding="utf-8"?>
     <configuration>
       <system.serviceModel>
      <behaviors>
        <endpointBehaviors>
            <behavior name="LocalCertValidation">
                <clientCredentials>
                    <serviceCertificate>
                        <authentication certificateValidationMode="PeerTrust" trustedStoreLocation="CurrentUser" />
                    </serviceCertificate>
                </clientCredentials>
            </behavior>
        </endpointBehaviors>
    </behaviors>
    <bindings>
        <wsHttpBinding>
            <binding name="WSHttpBinding_IService" >
                <security mode="Message">
                    <message clientCredentialType="UserName" />
                </security>
            </binding>
        </wsHttpBinding>
    </bindings>
    <client>
        <endpoint address="your service addresss"
                  binding="wsHttpBinding"
                  bindingConfiguration="WSHttpBinding_IService"
                  contract="ServiceReference1.IService"
                  name="WSHttpBinding_IService" behaviorConfiguration="LocalCertValidation">
            <identity>
                <dns value ="cool" />
            </identity>
        </endpoint>
    </client>
    

  10. Client code:

    ServiceClient client = new ServiceClient();
    client.ClientCredentials.UserName.UserName = "Your windows user";
    client.ClientCredentials.UserName.Password = "Your windows user password";
    Console.WriteLine(client.TestAccess());
    Console.ReadLine();

  11. if you dont want to use windows login/password you have to create a custom user/passwd validator ->msdn:
    Regards,

    Sergiu.

4
因为问题没有提及WCF,所以被投票否决,而这个答案全部关于WCF。 - deerchao

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接