SSL client/server mutual authentication
Hello I am trying to do in C# an ssl client/server communication with mutual authentication using server and client certificate. A managed to do the ssl communication only using server certificate, where on the client side I use sth like that:
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;
}
I assume I would need t开发者_如何学编程o use
AuthenticateAsClient(string targetHost, X509CertificateCollection clientCertificates, SslProtocols enabledSslProtocols, bool checkCertificateRevocation)
method, am I corrent? Could anyone please show me how to use it with all things around?Even on the server side, or point me to a basic example?
Thank you a lot.
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;
}
- You need a x509 self certificate, to create it simple, download pluralsight self cert
- Generate certificate as in image
- Create new web site, there choose wcf service.
- Add in solution new console application, to test our service.
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/>
In Service class, delete existing methods and add:
public string TestAccess() { return OperationContext.Current.ServiceSecurityContext.PrimaryIdentity.Name; }
in IService delete Data Contract, delete operation contracts and add new operation contract:
[OperationContract]
public string TestAccess();Run service and add service reference in client application to our service
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>
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();- if you dont want to use windows login/password you have to create a custom user/passwd validator ->msdn:
Regards,
Sergiu.
精彩评论