为什么 TLS 握手在 Java 应用程序中失败?

问题描述 投票:0回答:1

我正在制作一个客户端-服务器应用程序。我正在尝试建立 TLS 通信,但 TLS 握手失败。服务器和客户端都在同一台计算机、同一个虚拟机上。我已经检查过我生成的证书不是使用 DSA,而是使用 sha256WithRSAEncryption。它基于我生成的 3072 位长的密钥。我使用 certtool 命令生成了它们。我使用 keytool 命令根据此证书和私钥生成了服务器的密钥库和客户端的信任库。 这是我收到的错误

java -jar target/testNio-1.0-SNAPSHOT.jar 

Server launched on port 8443
Boss capture thread launches
Server handler launches
Worker thread launches
Thread sending messages launches
Attempted connection detected
TCP connection established with /127.0.0.1:44448
Attempted tls connection detected
NEED_UNWRAP
flag 1
NEED_TASK
NEED_WRAP
flag 2

javax.net.ssl.SSLHandshakeException: No available authentication scheme
    at java.base/sun.security.ssl.Alert.createSSLException(Alert.java:130)
    at java.base/sun.security.ssl.Alert.createSSLException(Alert.java:117)
    at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:365)
    at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:321)
    at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:312)
    at java.base/sun.security.ssl.CertificateMessage$T13CertificateProducer.onProduceCertificate(CertificateMessage.java:975)
    at java.base/sun.security.ssl.CertificateMessage$T13CertificateProducer.produce(CertificateMessage.java:964)
    at java.base/sun.security.ssl.SSLHandshake.produce(SSLHandshake.java:437)
    at java.base/sun.security.ssl.ClientHello$T13ClientHelloConsumer.goServerHello(ClientHello.java:1245)
    at java.base/sun.security.ssl.ClientHello$T13ClientHelloConsumer.consume(ClientHello.java:1181)
    at java.base/sun.security.ssl.ClientHello$ClientHelloConsumer.onClientHello(ClientHello.java:839)
    at java.base/sun.security.ssl.ClientHello$ClientHelloConsumer.consume(ClientHello.java:800)
    at java.base/sun.security.ssl.SSLHandshake.consume(SSLHandshake.java:393)
    at java.base/sun.security.ssl.HandshakeContext.dispatch(HandshakeContext.java:476)
    at java.base/sun.security.ssl.SSLEngineImpl$DelegatedTask$DelegatedAction.run(SSLEngineImpl.java:1274)
    at java.base/sun.security.ssl.SSLEngineImpl$DelegatedTask$DelegatedAction.run(SSLEngineImpl.java:1260)
    at java.base/java.security.AccessController.doPrivileged(AccessController.java:714)
    at java.base/sun.security.ssl.SSLEngineImpl$DelegatedTask.run(SSLEngineImpl.java:1205)
    at io.test2.Boss.handleTLSConnection2(Boss.java:169)
    at io.test2.Boss.run(Boss.java:218)

这是负责建立tls连接的类的代码。

package io.test2;

import java.io.IOException;
import java.nio.ByteBuffer;
//import java.net.InetSocketAddress;
//import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import javax.net.ssl.*;

public class Boss extends Thread {
    public Selector acceptor;
    public Selector com;
    public ServerSocketChannel serverChannel;
    public boolean running;
    public ArrayList<Session> sessions;
    public ArrayList<Session> sessionsTemp;
    public SSLContext sslContext;

    public Boss (Selector acceptor, Selector com, ServerSocketChannel ssc, 
    ArrayList<Session> sessions, SSLContext sslc) throws Exception{
        this.acceptor = acceptor;
        this.com = com;
        this.serverChannel = ssc;
        this.sessions = sessions;
        running = true;
        this.sslContext = sslc;
        sessionsTemp = new ArrayList<Session>();
    }

    public void shutdown() {
        running = false;
        acceptor.wakeup();
    }

    public void clientClose(TLSConnectionInformation info, SocketChannel client) throws IOException{
        for (int i = 0; i < sessionsTemp.size(); i++) {
            if (sessions.get(i).id.equals(info.id)) {
                sessions.remove(i);
                break;
            }
        }
        try {
            ByteBuffer dummy = ByteBuffer.allocate(0);
            ByteBuffer outBuffer = ByteBuffer.allocate(info.engine.getSession().getPacketBufferSize());
            info.engine.wrap(dummy, outBuffer);
            info.engine.closeOutbound();
            info.engine.closeInbound();
        } catch(SSLException e) {
            e.printStackTrace();}
        client.close();
    }

    public void handleTCPConnection(ServerSocketChannel ssc, Selector slct) throws IOException {
        
        SocketChannel clientChannel = serverChannel.accept();
        System.out.println("TCP connection established with " + clientChannel.getRemoteAddress());
        if (clientChannel != null) {
            SSLEngine engine = sslContext.createSSLEngine();
            //System.out.println(Arrays.toString(engine.getEnabledCipherSuites()));
            engine.setUseClientMode(false); // Mode serveur
            clientChannel.configureBlocking(false);
            Session s = new Session(clientChannel, engine);
            sessionsTemp.add(s);
            clientChannel.register(acceptor, SelectionKey.OP_READ, new TLSConnectionInformation(engine, s.id));
            engine.beginHandshake();
        }
    }

    public void handleTLSConnection(SelectionKey key) throws IOException {
        SocketChannel client = (SocketChannel) key.channel();
        TLSConnectionInformation info = (TLSConnectionInformation) key.attachment();
        SSLEngine engine = info.engine;
        ByteBuffer appBuffer = ByteBuffer.allocate(engine.getSession().getApplicationBufferSize());
        ByteBuffer netBuffer = ByteBuffer.allocate(engine.getSession().getPacketBufferSize());
        int bytesRead = client.read(netBuffer);
        if (bytesRead == -1) {
            clientClose(info, client);
            return;
        }
        netBuffer.flip();

        SSLEngineResult res = engine.unwrap(netBuffer, appBuffer);
        //appBuffer.compact();
        if (!isTLSHandShake(netBuffer)) {
            System.out.println("Non-TLS attempted connection. Closing connection");
            clientClose(info, client);
            return;
        }
        /*
         * If some tasks are required to end the establishment of the TLS connection
         */
        if (res.getHandshakeStatus() == SSLEngineResult.HandshakeStatus.NEED_TASK) {
            Runnable task;
            while ((task = engine.getDelegatedTask()) != null)
                task.run();
        }
        if (res.getHandshakeStatus() == SSLEngineResult.HandshakeStatus.FINISHED) {
            for (int i = 0; i < sessionsTemp.size(); i++) {
                if (sessionsTemp.get(i).sc.equals(client)) {
                    System.out.println("Connection accepted from " + sessionsTemp.get(i).id.toString());
                    sessions.add(sessionsTemp.get(i));
                    sessionsTemp.remove(i);
                    synchronized (com) {
                        com.wakeup();
                        client.register(com, SelectionKey.OP_READ, info);
                    }
                    break;
                }
            }
        }
    }

    public boolean isTLSHandShake(ByteBuffer buffer) {
        
        if (buffer.remaining() < 5)
            return false;
        if (buffer.get(0) == 22 && buffer.get(1) == 3)
            return true;
        return false;
    }

    public void handleTLSConnection2(SelectionKey key) throws IOException {
        System.out.println("Attempted tls connection detected");
        SocketChannel client = (SocketChannel) key.channel();
        TLSConnectionInformation info = (TLSConnectionInformation) key.attachment();
        SSLEngine engine = info.engine;
        ByteBuffer appBuffer = ByteBuffer.allocate(engine.getSession().getApplicationBufferSize());
        ByteBuffer netBuffer = ByteBuffer.allocate(engine.getSession().getPacketBufferSize());
        while (true) {
            SSLEngineResult.HandshakeStatus handshakeStatus = engine.getHandshakeStatus();
            switch (handshakeStatus) {
                case NEED_WRAP:
                    System.out.println("NEED_WRAP");
                    netBuffer.clear();
                    System.out.println("flag 2");
                    ByteBuffer buf = ByteBuffer.allocate(10);
                    SSLEngineResult wrapResult = engine.wrap(buf, netBuffer);        //HERE2
                    System.out.println("flag 3");
                    if (wrapResult.getStatus() == SSLEngineResult.Status.CLOSED) {
                        throw new IOException("Handshake failed: Engine closed during wrap");
                    }
                    System.out.println("flag 4");
                    netBuffer.flip();
                    if (netBuffer.hasRemaining()) {
                        client.write(netBuffer);
                    }
                    System.out.println("flag 5");
                    break;
                case NEED_UNWRAP:
                System.out.println("NEED_UNWRAP");
                    if (client.read(netBuffer) <= 0) {
                        throw new IOException("Handshake failed: No data available during unwrap");
                    }
                    netBuffer.flip();
                    SSLEngineResult unwrapResult = engine.unwrap(netBuffer, appBuffer);
                    netBuffer.compact();
                    if (unwrapResult.getStatus() == SSLEngineResult.Status.CLOSED) {
                        throw new IOException("Handshake failed: Engine closed during unwrap");
                    }
                    System.out.println("flag 1");
                    break;
                case NEED_TASK:
                System.out.println("NEED_TASK");
                    Runnable task;
                    while ((task = engine.getDelegatedTask()) != null) {
                        task.run();        //HERE
                    }
                    break;
                case FINISHED:
                    System.out.println("Handshake finished");
                    for (int i = 0; i < sessionsTemp.size(); i++) {
                        if (sessionsTemp.get(i).sc.equals(client)) {
                            System.out.println("Connection accepted from " + sessionsTemp.get(i).id.toString());
                            sessions.add(sessionsTemp.get(i));
                            sessionsTemp.remove(i);
                            synchronized (com) {
                                com.wakeup();
                                client.register(com, SelectionKey.OP_READ, info);
                            }
                            break;
                        }
                    }
                    return;
                case NOT_HANDSHAKING:
                    return;
                default:
                    throw new IllegalStateException("Unexpected handshake status: " + handshakeStatus);     
            }
            if (handshakeStatus == SSLEngineResult.HandshakeStatus.NEED_WRAP) 
                client.register(acceptor, SelectionKey.OP_WRITE, info);
            else if (handshakeStatus == SSLEngineResult.HandshakeStatus.NEED_UNWRAP)
                client.register(acceptor, SelectionKey.OP_READ, info);
        }
    }

    public void run() {
        System.out.println("Boss capture thread launches");
        while (running) {
            try {
                acceptor.select();
                Iterator<SelectionKey> keys = acceptor.selectedKeys().iterator();

                while (keys.hasNext()) {
                    SelectionKey key = keys.next();
                    keys.remove();

                    if (key.isAcceptable()) {
                        System.out.println("Attempted connection detected");
                        handleTCPConnection(serverChannel, acceptor);
                    }
                    else
                        handleTLSConnection2(key);
                }
            } catch (IOException | RuntimeException e) 
                { e.printStackTrace(); }
        }
        sessionsTemp.clear();
        System.out.println("Boss capture thread shutting down");
    }
}

因此,错误表明我可能存在证书问题,但问题也来自

//HERE
方法中的
handleTLSConnection2
行。 但如果我查看标准输出,程序不会超过标志 2,即
//HERE2
。 所以我的错误可能来自
engine.wrap()
调用;启动的可运行任务;证书有问题,或者我不知道的事情。 输入钥匙;

keytool -list -v -keystore keystoreServer.jks 

Enter keystore password:  

Keystore type: PKCS12

Keystore provider: SUN



Your keystore contains 1 entry



Alias name: server

Creation date: 14 janv. 2025

Entry type: trustedCertEntry



Owner: C=France, UID=1.0, CN=server

Issuer: C=France, UID=1.0, CN=server

Serial number: 3

Valid from: Mon Jan 13 22:39:56 CET 2025 until: Mon Jan 20 22:40:02 CET 2025

Certificate fingerprints:

     SHA1: 4C:D8:8C:C6:3F:93:AE:F9:BC:A0:E9:B4:D5:1B:14:39:8D:87:B4:A9

     SHA256: DD:F2:77:4C:F6:E5:61:3B:D1:6B:22:00:1C:5D:10:EC:F3:A9:9A:5C:FE:6F:FC:B2:8F:0C:0A:47:26:70:9E:DC

Signature algorithm name: SHA256withRSA

Subject Public Key Algorithm: 3072-bit RSA key

Version: 3



Extensions: 



#1: ObjectId: 2.5.29.19 Criticality=true

BasicConstraints:[

  CA:false

  PathLen: undefined

]



#2: ObjectId: 2.5.29.37 Criticality=false

ExtendedKeyUsages [

  serverAuth

  codeSigning

  timeStamping

]



#3: ObjectId: 2.5.29.15 Criticality=true

KeyUsage [

  DigitalSignature

  Key_Encipherment

  Data_Encipherment

]



#4: ObjectId: 2.5.29.17 Criticality=false

SubjectAlternativeName [

  DNSName: nio

]



#5: ObjectId: 2.5.29.14 Criticality=false

SubjectKeyIdentifier [

KeyIdentifier [

0000: 87 43 6A 3D 37 5B 8B 88   F1 26 78 5F EF 79 4B 51  .Cj=7[...&x_.yKQ

0010: 91 6A AA CC                                        .j..

]

]







*******************************************

*******************************************

任何帮助表示赞赏。 感谢您的宝贵时间。

java ssl certificate tls1.3 sslengine
1个回答
0
投票

您在哪里设置 SSL/TLS 证书? 您肯定需要一个来完成 TLS 握手

© www.soinside.com 2019 - 2024. All rights reserved.