Go语言HTTP连接配置TLS-PSK遇握手失败问题求助
Go语言实现TLS-PSK HTTP连接遇到 cipher suite 不兼容问题
我正在学习用Go语言实现带有TLS-PSK的HTTP连接,使用了tls-psk和tls-ext两个包,按照tls-psk的示例配置操作,但始终无法成功运行。
服务端代码
... type M map[string]interface{} func main() { mux := new(http.ServeMux) mux.HandleFunc("/data", ActionData) s := &http.Server{ Addr: ":9080", Handler: mux, } cfg := &tls.Config{ CipherSuites: []uint16{psk.TLS_DHE_PSK_WITH_AES_128_CBC_SHA, psk.TLS_DHE_PSK_WITH_AES_256_CBC_SHA}, Certificates: []tls.Certificate{{}}, MaxVersion: tls.VersionTLS11, MinVersion: tls.VersionTLS13, Extra: psk.PSKConfig{ GetKey: func(identity string) ([]byte, error) { hexString := "166ACC41EC1D4E1DD001ECC130ED0810" key := make([]byte, hex.DecodedLen(len(hexString))) _, err := hex.Decode(key, []byte(hexString)) if err != nil { return nil, err } return key, nil }, }, } l, err := net.Listen("tcp", ":9080") if err != nil { log.Fatalln("Failed to start web server", err) } l = tls.NewListener(l, cfg) log.Println("Starting server at 9080") if err := s.Serve(l); err != nil { log.Fatalln("error starting server:", err) } } func ActionData(w http.ResponseWriter, r *http.Request) { log.Println("Incoming request with method", r.Method) if r.Method != "POST" { http.Error(w, "method not allowed", http.StatusMethodNotAllowed) return } payload := make(M) err := json.NewDecoder(r.Body).Decode(&payload) if err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return } if _, ok := payload["Name"]; !ok { http.Error(w, "Payload `Name` is required", http.StatusBadRequest) return } data := M{ "Message": fmt.Sprintf("Hello %s", payload["Name"]), "Status": true, } w.Header().Set("Content-Type", "application/json") err = json.NewEncoder(w).Encode(data) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) } }
客户端代码
... type M map[string]interface{} var ( Config = &tls.Config{ // ServerName: "client-PSK-test", PreferServerCipherSuites: true, InsecureSkipVerify: true, CipherSuites: []uint16{psk.TLS_PSK_WITH_AES_128_CBC_SHA}, Certificates: []tls.Certificate{{}}, Extra: psk.PSKConfig{ GetIdentity: func() string { return "123" }, GetKey: func(identity string) ([]byte, error) { hexString := "166ACC41EC1D4E1DD001ECC130ED0810" key := make([]byte, hex.DecodedLen(len(hexString))) _, err := hex.Decode(key, []byte(hexString)) if err != nil { return nil, err } return key, nil }, }, } ) func main() { baseURL := "http://localhost:9080" data := M{"Name": "Noval Agung"} responseBody, err := doRequest(baseURL+"/data", "POST", data) if err != nil { log.Println("ERROR: do request:", err.Error()) return } log.Printf("%#v \n", responseBody) } func doRequest(url, method string, data interface{}) (interface{}, error) { var payload *bytes.Buffer = nil if data != nil { payload = new(bytes.Buffer) err := json.NewEncoder(payload).Encode(data) if err != nil { return nil, fmt.Errorf("error json encoding: %v", err) } } request, err := http.NewRequest(method, url, payload) if err != nil { return nil, fmt.Errorf("error creating new request: %v", err) } request.Header.Set("Content-Type", "application/json") client := &http.Client{ Transport: &http.Transport{ DialTLS: func(network, addr string) (net.Conn, error) { return tls.Dial(network, addr, Config) }, }, } response, err := client.Do(request) if err != nil { return nil, fmt.Errorf("error client.Do(): %v", err) } if response != nil { defer response.Body.Close() } responseBody := make(M) err = json.NewDecoder(response.Body).Decode(&responseBody) if err != nil { return nil, err } return responseBody, nil }
已尝试的解决措施
- 使用
http客户端时,客户端侧出现EOF错误 - 使用
https客户端并调整TLS版本时,出现remote error: tls: handshake failure错误 - 使用TLS 1.3版本时,出现
remote error: tls: internal error错误
更新:错误定位
通过tls-ext包日志发现核心错误为:no cipher suite supported by both client and server,请求解决该问题。
解决方案
统一Cipher Suites:服务端配置的是DHE-PSK类套件,客户端用的是普通PSK套件,两者无交集。需要调整为双方都支持的套件:
示例:服务端CipherSuites改为:CipherSuites: []uint16{psk.TLS_DHE_PSK_WITH_AES_128_CBC_SHA, psk.TLS_DHE_PSK_WITH_AES_256_CBC_SHA, psk.TLS_PSK_WITH_AES_128_CBC_SHA},客户端保持现有配置即可,或者也添加DHE-PSK套件。
修正TLS版本范围:服务端配置的
MaxVersion: tls.VersionTLS11和MinVersion: tls.VersionTLS13矛盾,MinVersion不能大于MaxVersion。调整为合理范围:MaxVersion: tls.VersionTLS12, MinVersion: tls.VersionTLS10,注意TLS 1.3不支持PSK-CBC类套件,不要将MinVersion设为TLS13。
客户端使用HTTPS协议:客户端的
baseURL要改为https://localhost:9080,否则DialTLS不会生效,普通HTTP连接到TLS监听端口会导致EOF错误。移除无用证书配置:TLS-PSK不需要证书,服务端和客户端的
Certificates: []tls.Certificate{{}}可以删除,避免干扰。
调整后的关键配置示例:
- 服务端tls.Config:
cfg := &tls.Config{ CipherSuites: []uint16{psk.TLS_DHE_PSK_WITH_AES_128_CBC_SHA, psk.TLS_PSK_WITH_AES_128_CBC_SHA}, MaxVersion: tls.VersionTLS12, MinVersion: tls.VersionTLS10, Extra: psk.PSKConfig{ GetKey: func(identity string) ([]byte, error) { hexString := "166ACC41EC1D4E1DD001ECC130ED0810" key := make([]byte, hex.DecodedLen(len(hexString))) _, err := hex.Decode(key, []byte(hexString)) if err != nil { return nil, err } return key, nil }, }, }
- 客户端tls.Config:
Config = &tls.Config{ PreferServerCipherSuites: true, InsecureSkipVerify: true, CipherSuites: []uint16{psk.TLS_PSK_WITH_AES_128_CBC_SHA, psk.TLS_DHE_PSK_WITH_AES_128_CBC_SHA}, Extra: psk.PSKConfig{ GetIdentity: func() string { return "123" }, GetKey: func(identity string) ([]byte, error) { hexString := "166ACC41EC1D4E1DD001ECC130ED0810" key := make([]byte, hex.DecodedLen(len(hexString))) _, err := hex.Decode(key, []byte(hexString)) if err != nil { return nil, err } return key, nil }, }, }
- 客户端baseURL改为:
baseURL := "https://localhost:9080"
内容的提问来源于stack exchange,提问作者ansuf
相关产品推荐
相关产品推荐

