From e18d36ebae30536c77c61cd5da123991e0ca1629 Mon Sep 17 00:00:00 2001 From: Rasmus Dahlberg Date: Sun, 31 Dec 2023 09:39:25 +0100 Subject: Add drafty prototype --- pkg/crtutil/crt_util.go | 71 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 pkg/crtutil/crt_util.go (limited to 'pkg/crtutil/crt_util.go') diff --git a/pkg/crtutil/crt_util.go b/pkg/crtutil/crt_util.go new file mode 100644 index 0000000..11bcd7e --- /dev/null +++ b/pkg/crtutil/crt_util.go @@ -0,0 +1,71 @@ +// Package crtutil provides utility functions for working with certificates. +package crtutil + +import ( + "crypto/sha256" + "encoding/pem" + "fmt" + + ct "github.com/google/certificate-transparency-go" + "github.com/google/certificate-transparency-go/x509" +) + +// CertificateChainFromPEM parses a certificate chain in PEM format. At least +// one certificate must be in the chain. The first certificate must be a leaf, +// whereas all other certificates must CA certificates (intermdiates/roots). +func CertificateChainFromPEM(b []byte) ([]x509.Certificate, error) { + var chain []x509.Certificate + + for { + block, rest := pem.Decode(b) + if block == nil { + break + } + crt, err := x509.ParseCertificate(block.Bytes) + if err != nil { + return nil, fmt.Errorf("parse certificate: %v", err) + } + + chain = append(chain, *crt) + b = rest + } + + if len(chain) == 0 { + return nil, fmt.Errorf("no certificates in the provided chain") + } + if chain[0].IsCA { + return nil, fmt.Errorf("leaf certificate has the CA bit set") + } + for _, crt := range chain[1:] { + if !crt.IsCA { + return nil, fmt.Errorf("non-leaf certificate without the CA bit set") + } + } + + return chain, nil +} + +// CertificateFromLogEntry parses the (pre-)certificate in a log entry +func CertificateFromLogEntry(leafData, extraData []byte) (x509.Certificate, error) { + entry, err := ct.LogEntryFromLeaf(0, &ct.LeafEntry{LeafInput: leafData, ExtraData: extraData}) + if err != nil { + return x509.Certificate{}, fmt.Errorf("parse leaf: %v", err) + } + if entry.Precert == nil && entry.X509Cert == nil { + return x509.Certificate{}, fmt.Errorf("neither precertificate nor certificate in leaf") + } + if entry.Precert != nil && entry.X509Cert != nil { + return x509.Certificate{}, fmt.Errorf("both certificate and precertificate in leaf") + } + if entry.Precert != nil { + return *entry.Precert.TBSCertificate, nil + } + return *entry.X509Cert, nil +} + +// UniqueID derives a unique certificate ID. The same value is derived +// regardless of if the (pre-)certificate is logged multiple times. +func UniqueID(crt x509.Certificate) string { + h := sha256.Sum256([]byte(crt.SerialNumber.String())) + return fmt.Sprintf("FIXME:%x", h[:]) // not a secure mapping +} -- cgit v1.2.3