Get certificate fingerprint in golang

Published: by

  • Categories:

Fingerprint is a great way to get a "hash" for a specific version of certificate. Openssl provides a -fingerprint option to get that hash.

➤ echo | openssl s_client -connect abhi.host:443 -servername abhi.host 2>&1| openssl x509 -noout -fingerprint -md5
MD5 Fingerprint=82:D4:F7:0C:EB:F4:A9:A4:AD:00:11:9E:CC:D4:64:60
➤

From the manpage:-

-fingerprint
Calculates and outputs the digest of the DER encoded version of the entire certificate (see digest options). This is commonly called a "fingerprint". Because of the nature of message digests, the fingerprint of a certificate is unique to that certificate and two certificates with the same fingerprint can be considered to be the same.

So, we need to get the DER (Distinguised Encoding Rules) encoded bytes and use that as the data to get the md5 hash.

From the Golang docs, https://golang.org/pkg/crypto/x509/#Certificate,

type Certificate struct {
    Raw                     []byte // Complete ASN.1 DER content (certificate, signature algorithm and signature).

Perfect, Raw field in x509.Certificate provides the DER content we want.

Here's the full code to get the fingerprint from a live endpoint.

package main

import (
	"bytes"
	"crypto/md5"
	"crypto/tls"
	"flag"
	"fmt"
)

func main() {
	// Parse cmdline arguments using flag package
	server := flag.String("server", "abhi.host", "Server to ping")
	port := flag.Uint("port", 443, "Port that has TLS")
	flag.Parse()

	conn, err := tls.Dial("tcp", fmt.Sprintf("%s:%d", *server, *port), &tls.Config{})
	if err != nil {
		panic("failed to connect: " + err.Error())
	}

	// Get the ConnectionState struct as that's the one which gives us x509.Certificate struct
	cert := conn.ConnectionState().PeerCertificates[0]
	fingerprint := md5.Sum(cert.Raw)

	var buf bytes.Buffer
	for i, f := range fingerprint {
		if i > 0 {
			fmt.Fprintf(&buf, ":")
		}
		fmt.Fprintf(&buf, "%02X", f)
	}
	fmt.Printf("Fingerprint for %s: %s", *server, buf.String())

	conn.Close()
}

Usage:-

➤ go run main.go
Fingerprint for abhi.host: 82:D4:F7:0C:EB:F4:A9:A4:AD:00:11:9E:CC:D4:64:60
➤