C# 客户端通过 SSL 连接到 Java 服务器

Posted

技术标签:

【中文标题】C# 客户端通过 SSL 连接到 Java 服务器【英文标题】:C# client connecting to a Java server over SSL 【发布时间】:2010-10-17 16:49:03 【问题描述】:

作为一个团队项目,我需要从 C# 客户端连接到 Java 6.5 SSL 服务器,但是当我到达 stream.AuthenticateAsClient 行时,它会挂起。

C# 连接代码

public static void connect(string server, Int32 port)

  try
  
    client = new TcpClient(server, port);
    stream = new SslStream(client.GetStream(), false);
    stream.AuthenticateAsClient("MyCNfield");
...
...

如果我连接到https://mail.google.com 之类的东西并将MyCNfield 设置为mail.google.com,它工作正常,所以我认为它是Java 端。

Java Init 部分是:

public void initSSL() throws IOException, KeyStoreException, NoSuchAlgorithmException,
                             CertificateException, UnrecoverableKeyException, KeyManagementException 
    char[] passphrase = "scared".toCharArray();
    System.out.println(java.security.KeyStore.getDefaultType());
    boolean handshakedone=false;

    KeyStore keystore1 = KeyStore.getInstance("jks");
    FileInputStream fis = new FileInputStream("C:\\\\temp\\\\work.jks");
    keystore1.load(fis, passphrase);
    fis.close();
    KeyStore ksTrust = KeyStore.getInstance("jks");
    FileInputStream fis2 =  new FileInputStream("C:\\\\temp\\\\work.jks");
    ksTrust.load(fis2, passphrase);

    KeyManagerFactory kmf =    KeyManagerFactory.getInstance("SunX509");

    // KeyManager's decide which key material to use.
    kmf.init(keystore1, passphrase);

    // TrustManager's decide whether to allow connections.
    TrustManagerFactory tmf =   TrustManagerFactory.getInstance("SunX509");
    tmf.init(ksTrust);

    SSLContext sslContext = SSLContext.getInstance("TLS");
    sslContext.init( kmf.getKeyManagers(), tmf.getTrustManagers(), null);

    SSLServerSocketFactory sslserversocketfactory =(SSLServerSocketFactory) sslContext.getServerSocketFactory();
    sslserversocket =(SSLServerSocket) sslserversocketfactory.createServerSocket(2443);
    sslserversocket.setUseClientMode(false);

    //Context conte
    ServerSocketFactory serversocketfactory =(ServerSocketFactory) sslContext.getServerSocketFactory();

    //  serverSocket = new ServerSocket(2443);
    System.out.println("OK we are set up");

它被调用:

sslsocket = (SSLSocket) sslserversocket.accept();

并继续,即使连接未完全验证。

需要改变什么来解决这个问题:JKS 有一个证书MyCNfield,它由我创建的 CA 签名。如何在我的 C# 中将证书链导入我的私有 CA,或者如何使用 Java 和 C# 交换自签名证书,然后丢弃我当前的 JKS?

【问题讨论】:

【参考方案1】:

您需要使用 RemoteCertificateValidationCallback 回调机制来提供证书认证。你不应该关闭这个问题,这是很多人可能有的一个有效问题。这个答案是谷歌搜索的第一个热门,这要归功于 *** 的出色 SEO,因此它可能会导致人们走错路。

使用 RemoteCertificateValidationCallback 回调。

private readonly bool allowSsl;

// callback used to validate the certificate in an SSL conversation
private static bool ValidateRemoteCertificate(
object sender,
    X509Certificate certificate,
    X509Chain chain,
    SslPolicyErrors policyErrors
)

    if (allowSsl)
    
        // allow any certificate...
        return true;
    
    else
    
        return policyErrors == SslPolicyErrors.None;
    

下面是您如何将它与 TCPClient 一起使用:

TcpClient client = new TcpClient(machineName,443);
Console.WriteLine("Client connected.");

// Create an SSL stream, specifying the callback above.
SslStream sslStream = new SslStream(
    client.GetStream(), 
    false, 
    new RemoteCertificateValidationCallback (ValidateRemoteCertificate), 
    null
    );

【讨论】:

我不知道这是否可行,我无法测试它,因为该项目早已不复存在,但我会给你接受的答案,因为你似乎知道你在说什么。 它有效,我刚刚做了一个 POC。唯一需要注意的是,您必须确保您的私钥在本地机器存储中。这与允许您将任何位置指定为密钥库的 java 不同。只需确保将证书安装在本地机器商店中即可。

以上是关于C# 客户端通过 SSL 连接到 Java 服务器的主要内容,如果未能解决你的问题,请参考以下文章

在 C# 中使用 SSL 连接到 MySQL

C++ 客户端通过 SSL 连接到 IBM MQ

从 Java bean 到 Web 服务的 SSL 连接问题

如何使用 Python 通过 SSL 连接到远程 PostgreSQL 数据库

通过 SSL 将 phpMyAdmin 连接到 MySQL 服务器

使用自签名证书连接到 SSL 服务器的客户端