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

发布于 2024-07-17 08:59:38 字数 2388 浏览 9 评论 0原文

作为一个团队项目,我需要从 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 有一个由我创建的 CA 签名的证书 MyCNfield。 如何将证书链导入到 C# 中的私有 CA,或者如何使用 Java 和 C# 交换自签名证书,然后扔掉当前的 JKS?

As a team project I need to connect from a C# client to a Java 6.5 SSL server, however when I get to the stream.AuthenticateAsClient line it hangs.

C# connect code

public static void connect(string server, Int32 port)
{
  try
  {
    client = new TcpClient(server, port);
    stream = new SslStream(client.GetStream(), false);
    stream.AuthenticateAsClient("MyCNfield");
...
...

If I connect to something like https://mail.google.com and set MyCNfield to mail.google.com, it works fine, so I think it is the Java side.

The Java Init section is:

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

it gets called:

sslsocket = (SSLSocket) sslserversocket.accept();

and continues on, even though the connection was not fully authenticated.

What needs to be changed to fix this: the JKS has a cert MyCNfield that is signed by a CA that I created. How do I either import the cert chain to my private CA in my C#, or how do I excange self-signed certs with Java and C#, and just throw out my current JKS?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

意犹 2024-07-24 08:59:38

您需要使用RemoteCertificateValidationCallback回调机制来提供证书身份验证。 您不应该关闭这个问题,这是很多人可能有的一个有效问题。 这个答案是谷歌搜索的第一批点击之一,这要归功于 stackoverflow 出色的 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
    );

You need to use the RemoteCertificateValidationCallback callback mechanism to provide certificate authentication. You shouldn't have closed the question, this is a valid question that many people may have. This answer was one of the first hits on a google search, thanks to the great SEO of stackoverflow, so it may lead people down the wrong path.

Use the RemoteCertificateValidationCallback callback.

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

And here is how you would use it with 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
    );
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文