【问题标题】:Golang: tls.Handshake hangs after connection upgradeGolang:tls.Handshake 在连接升级后挂起
【发布时间】:2016-06-25 22:29:25
【问题描述】:

我正在为我正在进行的项目编写 TCP 文本协议。协议中的命令之一是STARTTLS,它应该将连接升级到 TLS 并继续。我升级连接的代码类似于this question 中的答案。我遇到的问题是当我升级 TLS 连接时,tlsConn.Handshake 将挂起并且永远不会松手。下面有一些代码示例。非常感谢任何帮助。

收到STARTTLS命令后...

// Init a new TLS connection. I need a *tls.Conn type                                                                
// so that I can do the Handshake()                                                                                  
s.Logf("++> Upgrading connection to TLS")
tlsConn := tls.Server(s.Conn, s.Server.TLSConfig)
s.Logf("++> Attempting TLS Handshake")

tlsConn.Handshake()
s.Logf("++> TLS Handshake Successful")

// Here is the trick. Since I do not need to access                                                                  
// any of the TLS functions anymore,                                                                                 
// I can convert tlsConn back in to a net.Conn type                                                                  
s.Conn = net.Conn(tlsConn)

s.Logf("++> Updating read/write buffers")
s.reader = textproto.NewReader(bufio.NewReader(s.Conn))
s.writer = textproto.NewWriter(bufio.NewWriter(s.Conn))

s.Printf("100 SUCCESS")

客户端正在像这样发送STARTTLS 命令后立即升级连接...

c.conn = tls.Client(c.conn, clientTLSConfig)

服务器*tls.Config 长这样...

// Load the key and certificate - paths are provided in flags.                                                                                           
cert, err := tls.LoadX509KeyPair(flagTLSCert, flagTLSKey)                                                                    
if err != nil {                                                                                                              
    log.Fatal(err)                                                                                                       
}

// Create the TLS config                                                                                                     
tlsConfig := &tls.Config{
    Certificates: []tls.Certificate{cert},
    ClientAuth: tls.VerifyClientCertIfGiven,
    ServerName: fqdn(),
}

客户端*tls.Config 长这样...

clientTLSConfig := &tls.Config{
    InsecureSkipVerify: true,
}

【问题讨论】:

  • 能否用 tcpdump 或类似工具检查客户端是否发送 TLS Client Hello 数据包?这会将问题缩小到客户端或服务器端。

标签: ssl go tls1.2 starttls


【解决方案1】:

您是调用 c.conn.Handshake() 还是执行其他操作来在客户端启动 TLS 握手?

如果客户端没有通过发送 TLS Client Hello 来发起握手,服务器将永远等待它。

这是我的最佳猜测,因为您没有提供太多客户端代码。还检查 tcpdump 将有助于缩小问题范围(到服务器或客户端)。

【讨论】: