From 56087b0ea0d53640f1f1fe0656eed064463b2c8f Mon Sep 17 00:00:00 2001 From: Luke Shumaker Date: Wed, 26 Dec 2018 16:41:28 -0500 Subject: crtsh-pem2html: Try a decent precert visualization --- bin-src/crtsh-pem2html.go | 90 +++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 76 insertions(+), 14 deletions(-) diff --git a/bin-src/crtsh-pem2html.go b/bin-src/crtsh-pem2html.go index 2c9debb..432020e 100644 --- a/bin-src/crtsh-pem2html.go +++ b/bin-src/crtsh-pem2html.go @@ -51,18 +51,20 @@ var tmpl = template.Must(template.New("pem2html"). Logged NotBefore NotAfter - Type Subject.CN Issuer.O + SCTs {{range $cert := .certs}} - {{$cert.Updated | date}} - {{$cert.X509.NotBefore | date}} - {{$cert.X509.NotAfter | date}} - {{$cert.X509 | rfc6962type}} - {{$cert.X509.Subject.CommonName}} - {{$cert.X509.Issuer.Organization}} + {{$cert.Updated | date}} + {{$cert.Main.X509.NotBefore | date}} + {{$cert.Main.X509.NotAfter | date}} + {{$cert.Main.X509.Subject.CommonName}} + {{$cert.Main.X509.Issuer.Organization}} + {{range $i, $sct := $cert.Precerts}} + [{{$i}}] + {{end}} {{end}} @@ -109,21 +111,75 @@ type Cert struct { X509 *x509.Certificate } -type Certs []Cert +// A CertSet is a set of certificates all sharing the same +// SerialNumber. Normally, this will be 1 regular certificate, and +// any number of pre-certificates. +type CertSet []Cert + +// Given a list of certificates all sharing the same serial number, +// return a list of CertSets. If there are multiple regular +// certificates, it returns a seprate CertSet for each. +func NewCertSet(certs []Cert) []CertSet { + if len(certs) == 0 { + return nil + } + var retCerts []Cert + var retPrecerts []Cert + for _, cert := range certs { + if util.IsPrecertificate(cert.X509) { + retPrecerts = append(retPrecerts, cert) + } else { + retCerts = append(retCerts, cert) + } + } + if len(retCerts) == 0 { + return []CertSet{CertSet(retPrecerts)} + } + ret := make([]CertSet, len(retCerts)) + for i := range ret { + ret[i] = append(CertSet{retCerts[i]}, retPrecerts...) + } + return ret +} + +func (certs CertSet) Main() Cert { + //if util.IsPrecertificate(certs[0].X509) { + // return Cert{X509: new(x509.Certificate)} + //} + return certs[0] +} + +func (certs CertSet) Precerts() []Cert { + return certs[1:] +} + +// Updated returns the most recent "Updated" timestamp of any of the +// certificates in the CertSet. +func (certs CertSet) Updated() time.Time { + ret := certs[0].Updated + for _, cert := range certs { + if cert.Updated.After(ret) { + ret = cert.Updated + } + } + return ret +} + +type CertList []CertSet // Len is the number of elements in the collection. -func (l Certs) Len() int { +func (l CertList) Len() int { return len(l) } // Less reports whether the element with // index i should sort before the element with index j. -func (l Certs) Less(i, j int) bool { - return l[i].Updated.After(l[j].Updated) +func (l CertList) Less(i, j int) bool { + return l[i].Updated().After(l[j].Updated()) } // Swap swaps the elements with indexes i and j. -func (l Certs) Swap(i, j int) { +func (l CertList) Swap(i, j int) { tmp := l[i] l[i] = l[j] l[j] = tmp @@ -133,7 +189,7 @@ func main() { data, err := ioutil.ReadAll(os.Stdin) handleErr(err, "Error reading stdin: %v\n") - var certs Certs + bySerial := make(map[string][]Cert) for len(data) > 0 { var certPem *pem.Block certPem, data = pem.Decode(data) @@ -152,7 +208,13 @@ func main() { cert.X509, err = x509.ParseCertificate(certPem.Bytes) handleErr(err, "Error parsing cert: %v\n") - certs = append(certs, cert) + serial := fmt.Sprintf("%036x", cert.X509.SerialNumber) + bySerial[serial] = append(bySerial[serial], cert) + } + + var certs CertList + for _, set := range bySerial { + certs = append(certs, NewCertSet(set)...) } sort.Sort(certs) -- cgit v1.2.3