💾 Archived View for thrig.me › tech › ssl › certid.go captured on 2023-11-04 at 13:06:32.

View Raw

More Information

⬅️ Previous capture (2023-04-19)

-=-=-=-=-=-=-

// certid - calculate a fingerprint for a certificate, from amfora,
// which is where certID and origCertID came from, via client/tofu.go

package main

import (
	"crypto/sha256"
	"crypto/x509"
	"encoding/pem"
	"fmt"
	"io/ioutil"
	"log"
	"os"
)

// certID returns a generic string representing a cert or domain.
func certID(cert *x509.Certificate) string {
	h := sha256.New()
	h.Write(cert.RawSubjectPublicKeyInfo) // Better than cert.Raw, see #7
	return fmt.Sprintf("%X", h.Sum(nil))
}

// origCertID uses cert.Raw, which was used in v1.0.0 of the app.
func origCertID(cert *x509.Certificate) string {
	h := sha256.New()
	h.Write(cert.Raw)
	return fmt.Sprintf("%X", h.Sum(nil))
}

// tls.LoadX509KeyPair needs a private key, so instead we use the
// following, which probably needs better error handling. notably
// ParseCertificate likes to panic if you give this /dev/null, which is
// maybe not so good a user experience
func load_cert(file string) *x509.Certificate {
	content, err := ioutil.ReadFile(file)
	if err != nil {
		log.Fatalf("%v - '%s'", err, file)
	}
	if len(content) == 0 {
		log.Fatalf("empty file '%v'", file)
	}
	block, _ := pem.Decode([]byte(content))
	cert, err := x509.ParseCertificate(block.Bytes)
	if err != nil {
		log.Fatalf("%v - '%s'", err, file)
	}
	return cert
}

func main() {
	var cert *x509.Certificate
	if len(os.Args) != 2 {
		fmt.Fprintln(os.Stderr, "Usage: certid certificate-file")
		os.Exit(64)
	}
	cert = load_cert(os.Args[1])
	fmt.Println("old ", origCertID(cert))
	fmt.Println("new ", certID(cert))
}