使用 SSLSockets 的正确方法是什么?为什么会收到这些错误?

发布于 2024-11-02 11:56:53 字数 8881 浏览 0 评论 0原文

我正在尝试保护旨在通过多台计算机连接的应用程序系统。当我开始从普通套接字切换到 SSLSockets 时,我开始收到两个错误:

客户端:

“javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX 路径构建失败: sun.security.provider.certpath.SunCertPathBuilderException: 无法找到有效的认证 请求目标的路径”

服务器端:

“javax.net.ssl.SSLHandshakeException: 收到致命警报: 证书_未知”

我将代码剥离为仅套接字并将它们放入一个程序中:

package sslTest;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.UnknownHostException;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;

import javax.net.ServerSocketFactory;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLServerSocket;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;

public class TestMain { 
    public class TestModuleReceive {
        int port = 4445;
        SSLServerSocket ss;
        SSLSocket socket;

        TestModuleReceive() {
            initServerSocket();
            receiveConnection();
        }

        private void initServerSocket() {
            try {
                KeyStore ks = KeyStore.getInstance("JKS");
                ks.load(new FileInputStream("/home/uName/.keystore"), ("password").toCharArray());

                KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
                kmf.init(ks, ("password").toCharArray());
                SSLContext sslcontext = SSLContext.getInstance("SSLv3");
                sslcontext.init(kmf.getKeyManagers(), null, null);
                ServerSocketFactory ssf =
                    sslcontext.getServerSocketFactory();
                ss = (SSLServerSocket)
                    ssf.createServerSocket();
                ss.setReceiveBufferSize(8200);
                ss.bind(new InetSocketAddress(port));
            } 
            catch (KeyStoreException e) { e.printStackTrace(); } 
            catch (NoSuchAlgorithmException e) { e.printStackTrace(); } 
            catch (CertificateException e) { e.printStackTrace(); } 
            catch (FileNotFoundException e) { e.printStackTrace(); } 
            catch (IOException e) { e.printStackTrace(); } 
            catch (UnrecoverableKeyException e) { e.printStackTrace(); } 
            catch (KeyManagementException e) { e.printStackTrace(); }
        }

        public void receiveConnection() {
            new Thread() { public void run() {
                try {
                    socket = (SSLSocket) ss.accept();
                    receiveData();
                } 
                catch (IOException e) { e.printStackTrace(); } 
            }}.start();
        }

        public void receiveData() {
            try {
                System.out.println(socket.getInputStream().read());
            } 
            catch (IOException e) { e.printStackTrace(); } 
        }
    }

    public class TestModuleSend {

        int port = 4445;
        String address = "localhost";
        SSLSocketFactory factory;
        SSLSocket socket;

        TestModuleSend() {
            initFactory();
            addConnection();
            sendData();
        }

        private void initFactory() {
            try {
                KeyStore ks = KeyStore.getInstance("JKS");
                ks.load(new FileInputStream("/home/uName/.keystore"), ("password").toCharArray());
                KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
                kmf.init(ks, ("password").toCharArray());
                SSLContext sslcontext = SSLContext.getInstance("SSLv3");
                sslcontext.init(kmf.getKeyManagers(), null, null);
                factory = sslcontext.getSocketFactory();
            } 
            catch (KeyStoreException e) { e.printStackTrace(); } 
            catch (NoSuchAlgorithmException e) { e.printStackTrace(); } 
            catch (CertificateException e) { e.printStackTrace(); } 
            catch (FileNotFoundException e) { e.printStackTrace(); } 
            catch (IOException e) { e.printStackTrace(); } 
            catch (UnrecoverableKeyException e) { e.printStackTrace(); } 
            catch (KeyManagementException e) { e.printStackTrace(); }
        }

        public void addConnection() {
            // Initialize socket
            try {
                socket = (SSLSocket) factory.createSocket(InetAddress.getByName(address), port);
            } 
            catch (UnknownHostException e1) { e1.printStackTrace(); } 
            catch (IOException e1) { e1.printStackTrace(); }
        }

        public void sendData() {
            // Send single byte
            try {
                socket.getOutputStream().write((byte)0x00);
            } 
            catch (IOException e) { e.printStackTrace(); }
        }
    }

    TestMain() {
        TestModuleReceive receive = new TestModuleReceive();
        TestModuleSend send = new TestModuleSend();
    }

    public static void main(String[] args) {
        TestMain testMain = new TestMain();
    }
}

当我运行此代码时,我得到以下堆栈跟踪:

javax.net.ssl.SSLHandshakeException: Received fatal alert: certificate_unknown
    at sun.security.ssl.Alerts.getSSLException(Alerts.java:192)
    at sun.security.ssl.Alerts.getSSLException(Alerts.java:154)
    at sun.security.ssl.SSLSocketImpl.recvAlert(SSLSocketImpl.java:1731)
    at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:974)
    at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1158)
    at sun.security.ssl.SSLSocketImpl.readDataRecord(SSLSocketImpl.java:773)
    at sun.security.ssl.AppInputStream.read(AppInputStream.java:94)
    at sun.security.ssl.AppInputStream.read(AppInputStream.java:69)
    at sslTest.TestMain$TestModuleReceive.receiveData(TestMain.java:71)
    at sslTest.TestMain$TestModuleReceive$1.run(TestMain.java:63)
javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
    at sun.security.ssl.Alerts.getSSLException(Alerts.java:192)
    at sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1665)
    at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:258)
    at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:252)
    at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1165)
    at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:154)
    at sun.security.ssl.Handshaker.processLoop(Handshaker.java:610)
    at sun.security.ssl.Handshaker.process_record(Handshaker.java:546)
    at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:913)
    at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1158)
    at sun.security.ssl.SSLSocketImpl.writeRecord(SSLSocketImpl.java:652)
    at sun.security.ssl.AppOutputStream.write(AppOutputStream.java:78)
    at sun.security.ssl.AppOutputStream.write(AppOutputStream.java:92)
    at sslTest.TestMain$TestModuleSend.sendData(TestMain.java:121)
    at sslTest.TestMain$TestModuleSend.<init>(TestMain.java:87)
    at sslTest.TestMain.<init>(TestMain.java:129)
    at sslTest.TestMain.main(TestMain.java:133)
Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
    at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:324)
    at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:224)
    at sun.security.validator.Validator.validate(Validator.java:235)
    at sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:147)
    at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:230)
    at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:270)
    at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1144)
    ... 12 more
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
    at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:197)
    at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:255)
    at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:319)
    ... 18 more

有人能告诉我我做错了什么吗?

I am trying to secure a system of applications which are meant to be connected over multiple machines. When I started making the switch from plain Sockets to SSLSockets, I started getting two errors:

Client-side:

"javax.net.ssl.SSLHandshakeException:
sun.security.validator.ValidatorException:
PKIX path building failed:
sun.security.provider.certpath.SunCertPathBuilderException:
unable to find valid certification
path to requested target"

Server-side:

"javax.net.ssl.SSLHandshakeException:
Received fatal alert:
certificate_unknown"

I stripped down the code to just the sockets and put them into one program:

package sslTest;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.UnknownHostException;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;

import javax.net.ServerSocketFactory;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLServerSocket;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;

public class TestMain { 
    public class TestModuleReceive {
        int port = 4445;
        SSLServerSocket ss;
        SSLSocket socket;

        TestModuleReceive() {
            initServerSocket();
            receiveConnection();
        }

        private void initServerSocket() {
            try {
                KeyStore ks = KeyStore.getInstance("JKS");
                ks.load(new FileInputStream("/home/uName/.keystore"), ("password").toCharArray());

                KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
                kmf.init(ks, ("password").toCharArray());
                SSLContext sslcontext = SSLContext.getInstance("SSLv3");
                sslcontext.init(kmf.getKeyManagers(), null, null);
                ServerSocketFactory ssf =
                    sslcontext.getServerSocketFactory();
                ss = (SSLServerSocket)
                    ssf.createServerSocket();
                ss.setReceiveBufferSize(8200);
                ss.bind(new InetSocketAddress(port));
            } 
            catch (KeyStoreException e) { e.printStackTrace(); } 
            catch (NoSuchAlgorithmException e) { e.printStackTrace(); } 
            catch (CertificateException e) { e.printStackTrace(); } 
            catch (FileNotFoundException e) { e.printStackTrace(); } 
            catch (IOException e) { e.printStackTrace(); } 
            catch (UnrecoverableKeyException e) { e.printStackTrace(); } 
            catch (KeyManagementException e) { e.printStackTrace(); }
        }

        public void receiveConnection() {
            new Thread() { public void run() {
                try {
                    socket = (SSLSocket) ss.accept();
                    receiveData();
                } 
                catch (IOException e) { e.printStackTrace(); } 
            }}.start();
        }

        public void receiveData() {
            try {
                System.out.println(socket.getInputStream().read());
            } 
            catch (IOException e) { e.printStackTrace(); } 
        }
    }

    public class TestModuleSend {

        int port = 4445;
        String address = "localhost";
        SSLSocketFactory factory;
        SSLSocket socket;

        TestModuleSend() {
            initFactory();
            addConnection();
            sendData();
        }

        private void initFactory() {
            try {
                KeyStore ks = KeyStore.getInstance("JKS");
                ks.load(new FileInputStream("/home/uName/.keystore"), ("password").toCharArray());
                KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
                kmf.init(ks, ("password").toCharArray());
                SSLContext sslcontext = SSLContext.getInstance("SSLv3");
                sslcontext.init(kmf.getKeyManagers(), null, null);
                factory = sslcontext.getSocketFactory();
            } 
            catch (KeyStoreException e) { e.printStackTrace(); } 
            catch (NoSuchAlgorithmException e) { e.printStackTrace(); } 
            catch (CertificateException e) { e.printStackTrace(); } 
            catch (FileNotFoundException e) { e.printStackTrace(); } 
            catch (IOException e) { e.printStackTrace(); } 
            catch (UnrecoverableKeyException e) { e.printStackTrace(); } 
            catch (KeyManagementException e) { e.printStackTrace(); }
        }

        public void addConnection() {
            // Initialize socket
            try {
                socket = (SSLSocket) factory.createSocket(InetAddress.getByName(address), port);
            } 
            catch (UnknownHostException e1) { e1.printStackTrace(); } 
            catch (IOException e1) { e1.printStackTrace(); }
        }

        public void sendData() {
            // Send single byte
            try {
                socket.getOutputStream().write((byte)0x00);
            } 
            catch (IOException e) { e.printStackTrace(); }
        }
    }

    TestMain() {
        TestModuleReceive receive = new TestModuleReceive();
        TestModuleSend send = new TestModuleSend();
    }

    public static void main(String[] args) {
        TestMain testMain = new TestMain();
    }
}

When I run this code, I get the following stack trace:

javax.net.ssl.SSLHandshakeException: Received fatal alert: certificate_unknown
    at sun.security.ssl.Alerts.getSSLException(Alerts.java:192)
    at sun.security.ssl.Alerts.getSSLException(Alerts.java:154)
    at sun.security.ssl.SSLSocketImpl.recvAlert(SSLSocketImpl.java:1731)
    at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:974)
    at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1158)
    at sun.security.ssl.SSLSocketImpl.readDataRecord(SSLSocketImpl.java:773)
    at sun.security.ssl.AppInputStream.read(AppInputStream.java:94)
    at sun.security.ssl.AppInputStream.read(AppInputStream.java:69)
    at sslTest.TestMain$TestModuleReceive.receiveData(TestMain.java:71)
    at sslTest.TestMain$TestModuleReceive$1.run(TestMain.java:63)
javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
    at sun.security.ssl.Alerts.getSSLException(Alerts.java:192)
    at sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1665)
    at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:258)
    at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:252)
    at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1165)
    at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:154)
    at sun.security.ssl.Handshaker.processLoop(Handshaker.java:610)
    at sun.security.ssl.Handshaker.process_record(Handshaker.java:546)
    at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:913)
    at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1158)
    at sun.security.ssl.SSLSocketImpl.writeRecord(SSLSocketImpl.java:652)
    at sun.security.ssl.AppOutputStream.write(AppOutputStream.java:78)
    at sun.security.ssl.AppOutputStream.write(AppOutputStream.java:92)
    at sslTest.TestMain$TestModuleSend.sendData(TestMain.java:121)
    at sslTest.TestMain$TestModuleSend.<init>(TestMain.java:87)
    at sslTest.TestMain.<init>(TestMain.java:129)
    at sslTest.TestMain.main(TestMain.java:133)
Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
    at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:324)
    at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:224)
    at sun.security.validator.Validator.validate(Validator.java:235)
    at sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:147)
    at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:230)
    at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:270)
    at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1144)
    ... 12 more
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
    at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:197)
    at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:255)
    at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:319)
    ... 18 more

Could anyone tell me what I am doing wrong?

Thanks.

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

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

发布评论

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

评论(1

倾其所爱 2024-11-09 11:56:53

在客户端,您不应该使用 KeyManager,而应该使用 TrustManager,因为您的客户端必须决定信任谁。

更改

            KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
            ...
            sslcontext.init(kmf.getKeyManagers(), null, null);

            TrustManagerFactory kmf = TrustManagerFactory.getInstance("SunX509");
            ...
            sslcontext.init(null, tmf.getTrustManagers(), null);

当然,在实际应用程序中,客户端的密钥库应仅包含带有公钥的证书,而不包含服务器的私钥。

On the client side you should not use KeyManager, but TrustManager, since your client has to decide whom to trust.

Change

            KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
            ...
            sslcontext.init(kmf.getKeyManagers(), null, null);

to

            TrustManagerFactory kmf = TrustManagerFactory.getInstance("SunX509");
            ...
            sslcontext.init(null, tmf.getTrustManagers(), null);

Of course, in a real application the client's keystore should only contain the certificates with the public keys, not the private keys of the server.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文