Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get remote ssl certificate in golang

Tags:

ssl

go

I want to receive a TCP connection over TLS. I want to validate client certificate and use it to authenticate the client to my application. Go has the standard crypto/tls package. It can validate client/server certificates. But I can't find way to get details of the remote (client) certificate, like the common name.

like image 568
Rekby Avatar asked Jul 31 '15 17:07

Rekby


4 Answers

Have to call crypto/tls/Conn.Handshake. Then you can read peer certificate: tlsconn.ConnectionState().PeerCertificates[0].Subject.CommonName

like image 74
Rekby Avatar answered Nov 07 '22 09:11

Rekby


Following code may help you get your answer

package main

import (
    "crypto/tls"
    "fmt"
    "log"
)

func main() {
    conf := &tls.Config{
        InsecureSkipVerify: true,
    }

    conn, err := tls.Dial("tcp", "www.google.com:443", conf)
    if err != nil {
        log.Println("Error in Dial", err)
        return
    }
    defer conn.Close()
    certs := conn.ConnectionState().PeerCertificates
    for _, cert := range certs {
        fmt.Printf("Issuer Name: %s\n", cert.Issuer)
        fmt.Printf("Expiry: %s \n", cert.NotAfter.Format("2006-January-02"))
        fmt.Printf("Common Name: %s \n", cert.Issuer.CommonName)

    }
}
like image 35
Prince Kumar Avatar answered Nov 07 '22 09:11

Prince Kumar


When working with crypto/tls you can query any Conn object for ConnectionState:

func (c *Conn) ConnectionState() ConnectionState

The ConnectionState struct contains information about the client certificate:

type ConnectionState struct {
        PeerCertificates            []*x509.Certificate   // certificate chain presented by remote peer
}

The x509.Certificate should be pretty straightforward to work with.

Before the server requests for client authentication, you have to configure the connection with the server certificate, client CA (otherwise you will have to verify the trust chain manually, you really don't want that), and tls.RequireAndVerifyClientCert. For example:

// Load my SSL key and certificate
cert, err := tls.LoadX509KeyPair(settings.MyCertificateFile, settings.MyKeyFile)
checkError(err, "LoadX509KeyPair")

// Load the CA certificate for client certificate validation
capool := x509.NewCertPool()
cacert, err := ioutil.ReadFile(settings.CAKeyFile)
checkError(err, "loadCACert")
capool.AppendCertsFromPEM(cacert)

// Prepare server configuration
config := tls.Config{Certificates: []tls.Certificate{cert}, ClientCAs: capool, ClientAuth: tls.RequireAndVerifyClientCert}
config.NextProtos = []string{"http/1.1"}
config.Rand = rand.Reader
like image 4
user918176 Avatar answered Nov 07 '22 09:11

user918176


There is an easier way to do that:

func renewCert(w http.ResponseWriter, r *http.Request) {

  if r.TLS != nil && len(r.TLS.PeerCertificates) > 0 {
    cn := strings.ToLower(r.TLS.PeerCertificates[0].Subject.CommonName)
    fmt.Println("CN: %s", cn)
  }

}
like image 1
Arturo Avatar answered Nov 07 '22 08:11

Arturo