diff options
author | Luke Shumaker <lukeshu@lukeshu.com> | 2018-03-14 18:18:31 -0400 |
---|---|---|
committer | Luke Shumaker <lukeshu@lukeshu.com> | 2018-03-17 13:49:41 -0400 |
commit | b54a1c9686eec3c1114e9b58cb67679ba59c45bd (patch) | |
tree | 0bdb2f3ed51ff077a8c3e337e4bc556aacec108e /bin-src/crtsh-pem2html.go | |
parent | 54feeb027d6e5a760b49769dfe695ea2591dc6fe (diff) |
directories
Diffstat (limited to 'bin-src/crtsh-pem2html.go')
-rw-r--r-- | bin-src/crtsh-pem2html.go | 150 |
1 files changed, 150 insertions, 0 deletions
diff --git a/bin-src/crtsh-pem2html.go b/bin-src/crtsh-pem2html.go new file mode 100644 index 0000000..109917c --- /dev/null +++ b/bin-src/crtsh-pem2html.go @@ -0,0 +1,150 @@ +package main + +import ( + "crypto/x509" + "encoding/pem" + "fmt" + "html/template" + "io/ioutil" + "os" + "sort" + "time" + + "./util" +) + +func handleErr(err error, str string, a ...interface{}) { + a = append([]interface{}{err}, a...) + if err != nil { + fmt.Fprintf(os.Stderr, str, a...) + os.Exit(1) + } +} + +func handleBool(ok bool, str string, a ...interface{}) { + if !ok { + fmt.Fprintf(os.Stderr, str, a...) + os.Exit(1) + } +} + +var tmpl = template.Must(template.New("pem2html"). + Funcs(template.FuncMap{ + "red": red, + "green": green, + "date": util.Date2HTML, + "datetime": util.DateTime2HTML, + "colorDatetime": util.DateTime2ColorHTML, + }).Parse(`<table class=sortable> + <caption> + <p>CT log (Updated {{.now | colorDatetime}})</p> + </caption> + <tr> + <th>Logged</th> + <th>NotBefore</th> + <th>NotAfter</th> + <th>Subject.CN</th> + <th>Issuer.O</th> + </tr> +{{range $cert := .certs}} + <tr> + <td style="background-color: {{$cert.Updated | green}}"><a target="_blank" href="{{$cert.Url}}">{{$cert.Updated | date}}</a></td> + <td style="background-color: {{$cert.X509.NotBefore | green}}"><a target="_blank" href="{{$cert.Url}}">{{$cert.X509.NotBefore | date}}</a></td> + <td style="background-color: {{$cert.X509.NotAfter | red }}"><a target="_blank" href="{{$cert.Url}}">{{$cert.X509.NotAfter | date}}</a></td> + <td><a target="_blank" href="{{$cert.Url}}">{{$cert.X509.Subject.CommonName}}</a></td> + <td><a target="_blank" href="{{$cert.Url}}">{{$cert.X509.Issuer.Organization}}</a></td> + </tr> +{{end}} +</table> +`)) + +func getNow() time.Time { + stat, err := os.Stdin.Stat() + if err == nil { + return stat.ModTime() + } else { + return time.Now() + } +} + +var now = getNow() + +func green(t time.Time) string { + max := byte(0xF3) + // When did we get the cert? + // - 30 days ago => 0 green + // - just now => max green + greenness := util.MapRange( + util.TimeRange{now.AddDate(0, 0, -30), now}, + util.ByteRange{0, max}, + t) + return fmt.Sprintf("#%02X%02X%02X", max-greenness, max, max-greenness) +} + +func red(t time.Time) string { + max := byte(0xF3) + // When with the cert expire? + // - now => max red + // - 30 days from now => 0 red + redness := util.MapRange( + util.TimeRange{now, now.AddDate(0, 0, 30)}, + util.ByteRange{max, 0}, + t) + return fmt.Sprintf("#%02X%02X%02X", max, max-redness, max-redness) +} + +type Cert struct { + Url string + Updated time.Time + X509 *x509.Certificate +} + +type Certs []Cert + +// Len is the number of elements in the collection. +func (l Certs) 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) +} + +// Swap swaps the elements with indexes i and j. +func (l Certs) Swap(i, j int) { + tmp := l[i] + l[i] = l[j] + l[j] = tmp +} + +func main() { + data, err := ioutil.ReadAll(os.Stdin) + handleErr(err, "Error reading stdin: %v\n") + + var certs Certs + for len(data) > 0 { + var certPem *pem.Block + certPem, data = pem.Decode(data) + + var ok bool + var cert Cert + + cert.Url, ok = certPem.Headers["X-Crt-Sh-Url"] + handleBool(ok, "Did not get X-Crt-Sh-Url\n") + + str, ok := certPem.Headers["X-Crt-Sh-Updated"] + handleBool(ok, "Did not get X-Crt-Sh-Updated\n") + cert.Updated, err = time.Parse("2006-01-02T15:04:05Z", str) + handleErr(err, "Could not parse updated time") + + cert.X509, err = x509.ParseCertificate(certPem.Bytes) + handleErr(err, "Error parsing cert: %v\n") + + certs = append(certs, cert) + } + + sort.Sort(certs) + handleErr(tmpl.Execute(os.Stdout, map[string]interface{}{"certs": certs, "now": now}), "Could not execute template: %v\n") +} |