起初......这个程序只是有趣而且不会被发布。它仅用于测试套接字,因此不必关心此连接的安全性。 我编写了一个小信使,您可以在文本框中键入消息,然后将其发送到服务器并从服务器发送到所有客户端。到现在为止还挺好。只是为了好玩,我想使用SSL进行此连接。 但是,当我尝试连接到服务器套接字时,它会在ValidateServerCertificate处返回RemoteCertificateNameMismatch。 添加一些调试消息后,我发现Sslstream.LocalCertificate为null。我该如何修复这个丢失的证书?我正在使用自签名证书。
请帮忙,这是我的代码...是的...抱歉我的英文不好:/:
[...]
public bool ValidateServerCertificate(
object sender,
X509Certificate certificate,
X509Chain chain,
SslPolicyErrors sslPolicyErrors)
{
//sslPolicyErrors returns RemoteCertificateNameMismatch
return true; //Code shortened
}
public X509CertificateCollection getCertificates()
{
X509CertificateCollection cCollection = new X509CertificateCollection();
cCollection.Add(getCertificate());
return cCollection;
}
private X509Certificate getCertificate()
{
string Certificate = "D:/Wlad/Programmierung/Zertifikat/CA/CertificateAuthority.crt";
string ClientCertificatePassword = "...";
return new X509Certificate(Certificate, ClientCertificatePassword);
}
public X509Certificate SelectLocalCertificate(
object sender,
string targetHost,
X509CertificateCollection localCertificates,
X509Certificate remoteCertificate,
string[] acceptableIssuers)
{
foreach(X509Certificate cer in localCertificates) {
return cer;
}
return getCertificate();
}
public void connect(String username)
{
XMLConfigManager xml = XMLConfigManager.getInstance();
String ip = xml.get("ip");
tc = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); ;
tc.Connect(ip, int.Parse(xml.get("port")));
networdstream = new NetworkStream(tc);
using(sslstream = new SslStream(networdstream, false, new RemoteCertificateValidationCallback(ValidateServerCertificate), new LocalCertificateSelectionCallback(SelectLocalCertificate)))
{
sslstream.AuthenticateAsClient(ip, getCertificates(), SslProtocols.Default, true);
}
sendMessage(username);
t = new Thread(new ThreadStart(checkInput));
t.Start();
tm.addThread(t);
th = new Thread(new ThreadStart(userTimer));
th.Start();
tm.addThread(th);
}
public void disconnect()
{
if(sslstream != null) {
sslstream.Close();
}
if(tc != null) {
tc.Close();
}
}
[...]
static byte[] GetBytes(string str)
{
byte[] bytes = new byte[str.Length * sizeof(char)];
System.Buffer.BlockCopy(str.ToCharArray(), 0, bytes, 0, bytes.Length);
return bytes;
}
public void sendMessage(String s)
{
try
{
if ((s != null) && (s.Length > 0))
{
try
{
sslstream.Write(GetBytes(s));
}
catch (Exception)
{
}
}
}
catch (Exception ex)
{
endError(ex);
return;
}
}
public void userTimer()
{
Thread.Sleep(2000);
sendCommand("usercount");
th = new Thread(new ThreadStart(userTimer));
th.Start();
tm.addThread(th);
}
[...]
static String ReadMessage(SslStream sslStream)
{
byte[] buffer = new byte[2048];
StringBuilder messageData = new StringBuilder();
int bytes = -1;
do
{
bytes = sslStream.Read(buffer, 0, buffer.Length);
// Use Decoder class to convert from bytes to UTF8
// in case a character spans two buffers.
Decoder decoder = Encoding.UTF8.GetDecoder();
char[] chars = new char[decoder.GetCharCount(buffer, 0, bytes)];
decoder.GetChars(buffer, 0, bytes, chars, 0);
messageData.Append(chars);
} while (bytes != 0);
return messageData.ToString();
}
public void checkInput()
{
try
{
Form2 f2 = f1.f;
if(!isConnected()) {
t.Abort();
return;
}
String s = ReadMessage(sslstream);
if(s == null) {
t.Abort();
return;
}
CommandHandler ch = new CommandHandler();
Boolean handle = ch.handle(s, f1.f);
if (!handle) {
if (s == "Der Benutzername ist schon vergeben.")
{
endDuplicatename();
return;
}
f2.Invoke(new Action(() => f2.chat.Items.Add(s)));
f2.Invoke(new Action(() => f2.select_newest()));
}
}
finally
{
t = new Thread(new ThreadStart(checkInput));
t.Start();
tm.addThread(t);
}
}
package de.wladhd.server;
import java.net.Socket;
import javax.net.ssl.SSLServerSocket;
import javax.net.ssl.SSLServerSocketFactory;
import javax.net.ssl.SSLSocket;
import de.wladhd.client.Client;
import de.wladhd.client.ClientManager;
import de.wladhd.logs.Log;
import de.wladhd.logs.LogType;
public class DateServer {
private SSLServerSocket server;
private boolean running = true;
private String keyStore = "D:/Wlad/Programmierung/Zertifikat/CA/CertificateAuthority.pfx";
private String keyStorePassword = "...";
private String keyStoreType = "PKCS12";
private String trustStore = "D:/Wlad/Programmierung/Zertifikat/CA/CertificateAuthority.pfx";
private String trustStorePassword = "...";
private String trustStoreType = "PKCS12";
public void execute() throws Exception {
//System.setProperty("javax.net.debug","all");
System.setProperty("javax.net.ssl.keyStoreType", keyStoreType);
System.setProperty("javax.net.ssl.keyStore", keyStore);
System.setProperty("javax.net.ssl.keyStorePassword", keyStorePassword);
System.setProperty("javax.net.ssl.trustStoreType", trustStoreType);
System.setProperty("javax.net.ssl.trustStore", trustStore);
System.setProperty("javax.net.ssl.trustStorePassword", trustStorePassword);
//System.setProperty("javax.net.ssl.trustStore", "de.wladhd.server.Trusting");
SSLServerSocketFactory serverFactory = (SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
if(serverFactory == null) {
new Log("Error occured... Server Factory == null!", LogType.ERROR);
return;
}
server = (SSLServerSocket) serverFactory.createServerSocket(9090);
running = true;
new Log("Server now running on query: " + server.getInetAddress().getHostAddress() + ":" + server.getLocalPort(), LogType.INFO);
while (running) {
try {
if(server.isClosed()) {
return;
}
new Log("Client connecting...", LogType.DEBUG);
final Socket rawsocket = server.accept();
if(!(rawsocket instanceof SSLSocket)) {
new Log("Client isnt an instance of SSLSocket!", LogType.DEBUG);
return;
}
final SSLSocket socket = (SSLSocket) rawsocket;
try {
socket.startHandshake();
} catch (Exception ex) {
}
new Log("Client - Connected: " + socket.isConnected(), LogType.DEBUG);
new Log("Client - Protocol: " + socket.getSession().getProtocol(), LogType.DEBUG);
new Log("Client - Session valid: " + socket.getSession().isValid(), LogType.DEBUG);
new Log("Client - CipherSuite: " + socket.getSession().getCipherSuite(), LogType.DEBUG);
new Log("Client - NeedClientAuth: " + socket.getNeedClientAuth(), LogType.DEBUG);
new Log("Client - WantClientAuth: " + socket.getWantClientAuth(), LogType.DEBUG);
Client c = new Client(socket);
//socket.getHandshakeSession() returns null and peer not authenticated exception...
} catch (Exception ex) {
ex.printStackTrace();
continue;
}
}
}
public void disconnect() throws Exception {
new Log("Server disconnecting...", LogType.INFO);
setRunning(false);
ClientManager.getInstance().disconnectClients();
if(server != null) {
server.close();
}
new Log("Server successfully disconnected!", LogType.INFO);
}
public boolean isRunning() {
return running;
}
public void setRunning(boolean state) {
running = state;
}
}
如果您需要什么,请告诉我......
答案 0 :(得分:0)
RemoteCertificateNameMismatch策略错误与缺少的本地证书无关。此错误只是告诉您收到的服务器证书中的SAN(主题备用名称),或者,如果没有SAN,则接收到的服务器证书的主题名称的公用名称与您的主机名不匹配连接至。如果您不希望在这两个位置之一中看到证书中的主机名,则可以忽略此错误。
我猜您没有本地证书,因为您正在从文件加载证书,并且Windows私钥存储中没有此证书的相应私钥。
尝试使用MMC将证书和私钥(例如,从具有证书和私钥的PFX文件)导入到本地计算机个人证书存储区,然后加载 证书这里使用.NET证书存储API。只要您可以访问私钥(如果您是导入PFX的Windows用户),那么您应该可以使用此客户端证书进行连接。
在您的代码中,不是从文件中读取证书,而是从证书存储区加载,如下所示:
UIViewController
您可以使用其他指纹来寻找它 - 这只是一个例子。这就是SelectLocalCertificate返回的内容。