duandaotuo5542 2017-03-08 06:08
浏览 318

如何使用Go TLS手动验证客户端证书?

We are building a server in Golang that opens a TCP port over SSL.

We would like to enable mutual-authentication between the client and the server. But also detect when a client attempts to connect to our server without a valid client certificate and return them a error message over SSL - such as "invalid client certificate detected, please contact company ABC for assistance".

Just to be clear: we are adamant about our requirement to return data over SSL to clients that fail to mutually authenticate with the server. We do not want to disconnect them.

The approach we have taken is to use the 'VerifyClientCertIfGiven' configuration setting for TLS.

Whereby, we verify the client certificate if it is given, but we still allow an SSL connection to be established if it isn't.

How can we find out:

  1. Was a client certificate provided?
  2. If so, did it pass the mutual authentication checks performed by TLS?

Below is the code of our server:

package main

import(
  "fmt"
  "io/ioutil"
  "crypto/tls"
  "crypto/x509"
)

func main(){
  // Configure SSL
  cert, err := tls.LoadX509KeyPair("server.crt", "server.key")
  caCert, _ := ioutil.ReadFile("client.crt")
  caCertPool := x509.NewCertPool()
  caCertPool.AppendCertsFromPEM(caCert)
  config := &tls.Config{
    Certificates: []tls.Certificate{cert},
    ClientCAs: caCertPool,
    ClientAuth: tls.VerifyClientCertIfGiven,
  }
  config.BuildNameToCertificate()
  // Listen on port 443
  listener, _ := tls.Listen("tcp", ":443", config)
  defer listener.Close()
  // Accept incoming connection
  conn, _ := listener.Accept()
  defer conn.Close()
  // Print ConnectionState
  tlscon, _ := conn.(*tls.Conn)
  fmt.Println(tlscon.ConnectionState())
}

And below is the code of our client:

package main
import (
  "io/ioutil"
  "crypto/tls"
  "crypto/x509"
)

func main(){
  //Configure SSL
  cert, _ := tls.LoadX509KeyPair("client.crt", "client.key"
  caCert, _ := io.util.ReadFile("server.crt")
  caCertPool := x509.NewCertPool()
  caCertPool.AppendCertsFromPEM(caCert)
  config := &tls.Config{
    Certificates: []tls.Certificate{cert},
    RootCAs:      caCertPool,
  }
  config.BuildNameToCertificate()
  // Connect to server
  conn, _ := tls.Dial("tcp", "127.0.0.1:443", config)
  defer conn.Close()
}

The output:

{0 false false 0  false  [] [] [] [] []}

We've tried implementing conn.ConnectionState().PeerCertificates on the server but in all our attempts, it was an empty byte array.

Thank you in advance. We appreciate your time trying to help us.

Kind Regards,

Julian

  • 写回答

1条回答 默认 最新

  • douxian9706 2017-04-25 09:36
    关注

    I spent the best of my afternoon on this one too.

    Once the server accepts the connection you will need to explicitely call tlscon.Handshake() to get the client's certificate, otherwise the tls package will do it automatically after the first i/o. https://golang.org/pkg/crypto/tls/#Conn.Handshake

    You can see a example here.

    评论

报告相同问题?

悬赏问题

  • ¥15 matlab用simulink求解一个二阶微分方程,要求截图
  • ¥30 matlab解优化问题代码
  • ¥15 写论文,需要数据支撑
  • ¥15 identifier of an instance of 类 was altered from xx to xx错误
  • ¥100 反编译微信小游戏求指导
  • ¥15 docker模式webrtc-streamer 无法播放公网rtsp
  • ¥15 学不会递归,理解不了汉诺塔参数变化
  • ¥15 基于图神经网络的COVID-19药物筛选研究
  • ¥30 软件自定义无线电该怎样使用
  • ¥15 R语言mediation包做中介分析,直接效应和间接效应都很小,为什么?