summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuke Shumaker <lukeshu@sbcglobal.net>2016-11-18 03:23:25 -0500
committerLuke Shumaker <lukeshu@sbcglobal.net>2016-11-18 03:23:25 -0500
commit89fa60bdf5ed6bd729f4d7931c9603e896d38665 (patch)
treeb13004ac9c45976ae340e6dba13774dac1ea4abb
parentc4f6d3489ef91c539ba88e372635e4d0d87e6ad2 (diff)
more
-rw-r--r--.gitignore1
-rw-r--r--Makefile7
-rw-r--r--diff.go15
-rw-r--r--tls-getcerts.go19
-rw-r--r--tls-pem2html.go202
5 files changed, 228 insertions, 16 deletions
diff --git a/.gitignore b/.gitignore
index 40ffbfc..93d345c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,4 +5,5 @@ NET-*
crtsh-pem2html
tls-getcerts
+tls-pem2html
diff
diff --git a/Makefile b/Makefile
index 157fd34..6315ace 100644
--- a/Makefile
+++ b/Makefile
@@ -12,8 +12,11 @@ crtsh.pem: crtsh-getcerts config-domains.txt NET-crtsh
crtsh.html: %.html: %.pem crtsh-pem2html
./crtsh-pem2html < $< > $@
-tls.pem: tls-getcerts config-servers.txt NET-tls
- ./tls-getcerts $$(cat config-servers.txt) > $@
+tls.pem: tls-getcerts config-sockets.txt NET-tls
+ ./tls-getcerts $$(cat config-sockets.txt) > $@
+
+tls.html: %.html: %.pem tls-pem2html
+ ./tls-pem2html < $< > $@
diff.txt: diff tls.pem crtsh.pem
./diff tls.pem crtsh.pem > $@
diff --git a/diff.go b/diff.go
index 24fa228..25c9028 100644
--- a/diff.go
+++ b/diff.go
@@ -80,6 +80,13 @@ func keys(m map[string]*x509.Certificate) []string {
return ret
}
+func fmtCert(cert *x509.Certificate) string {
+ return fmt.Sprintf("%s %s %s",
+ cert.Subject.CommonName,
+ cert.NotBefore.Format("2006-01-02 15:04:05 MST(-07)"),
+ cert.NotAfter.Format("2006-01-02 15:04:05 MST(-07)"))
+}
+
func main() {
if len(os.Args) != 3 {
fmt.Fprintf(os.Stderr, "Usage: %s TLS-file crt.sh-file\n", os.Args[0])
@@ -97,12 +104,12 @@ func main() {
certTLS := certsTLS[host]
certCrtSh, okCrtSh := certsCrtSh[host]
if !okCrtSh {
- fmt.Printf("-%s %s\n", host, certTLS.NotBefore.Format("2006-01-02 15:04:05 MST(-07)"))
+ fmt.Printf("-%s %s\n", host, fmtCert(certTLS))
} else if !certTLS.Equal(certCrtSh) {
- fmt.Printf("-%s %s\n", host, certTLS.NotBefore.Format("2006-01-02 15:04:05 MST(-07)"))
- fmt.Printf("+%s %s\n", host, certCrtSh.NotBefore.Format("2006-01-02 15:04:05 MST(-07)"))
+ fmt.Printf("-%s %s\n", host, fmtCert(certTLS))
+ fmt.Printf("+%s %s\n", host, fmtCert(certCrtSh))
} else {
- fmt.Printf(" %s %s\n", host, certTLS.NotBefore.Format("2006-01-02 15:04:05 MST(-07)"))
+ fmt.Printf(" %s %s\n", host, fmtCert(certTLS))
}
}
}
diff --git a/tls-getcerts.go b/tls-getcerts.go
index b0d4533..ba951c9 100644
--- a/tls-getcerts.go
+++ b/tls-getcerts.go
@@ -3,31 +3,30 @@ package main
import (
"crypto/tls"
"crypto/x509"
+ "encoding/pem"
"fmt"
"os"
- "encoding/pem"
)
-func getcert(server string) (*x509.Certificate, error){
- conn, err := tls.Dial("tcp", fmt.Sprintf("%s:443", server), &tls.Config{ServerName: server})
+func getcert(socket string) (*x509.Certificate, error){
+ conn, err := tls.Dial("tcp", socket, &tls.Config{InsecureSkipVerify: true})
if err != nil {
return nil, err
}
defer conn.Close()
- chain := conn.ConnectionState().PeerCertificates
- return chain[len(chain)-2], nil
+ return conn.ConnectionState().PeerCertificates[0], nil
}
func main() {
- for _, server := range os.Args[1:] {
- cert, err := getcert(server)
- if err != nil {
- fmt.Fprintf(os.Stderr, "Could not get certificate from server %q: %q\n", server, err)
+ for _, socket := range os.Args[1:] {
+ cert, err := getcert(socket)
+ if cert == nil {
+ fmt.Fprintf(os.Stderr, "Could not get certificate for socket %q: %q\n", socket, err)
os.Exit(1)
}
block := pem.Block{
Type: "CERTIFICATE",
- Headers: nil,
+ Headers: map[string]string{"X-Socket": socket},
Bytes: cert.Raw,
}
pem.Encode(os.Stdout, &block)
diff --git a/tls-pem2html.go b/tls-pem2html.go
new file mode 100644
index 0000000..efefd68
--- /dev/null
+++ b/tls-pem2html.go
@@ -0,0 +1,202 @@
+package main
+
+import (
+ "crypto/x509"
+ "encoding/pem"
+ "fmt"
+ "html/template"
+ "io/ioutil"
+ "os"
+ "sort"
+ "time"
+)
+
+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...)
+ }
+}
+
+var tmpl = template.Must(template.New("pem2html").
+ Funcs(template.FuncMap{
+ "red": red,
+ "green": green,
+ }).Parse(`<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="utf-8">
+ <title>CT log</title>
+ <style>
+ html {
+ height: 100%;
+ }
+ body {
+ font-size: 10px;
+ font-family: monospace;
+ height: 100%;
+ margin: 0;
+ display: flex;
+ align-items: center;
+ }
+ body > * {
+ margin: auto;
+ }
+ table {
+ border-collapse: collapse;
+ }
+ caption p {
+ margin: 0;
+ }
+ td, th {
+ padding: 0;
+ border: solid 1px black;
+ white-space: nowrap;
+ }
+ td {
+ background-color: #F3F3F3;
+ }
+ tr:hover td {
+ background-color: #AAAAF3 !important;
+ }
+ td a {
+ padding: 0.1em 0.25em;
+ display: block;
+ width: 100%;
+ height: 100%;
+ color: black;
+ }
+ tr.expired td {
+ background-color: #F30000;
+ }
+ </style>
+ <script src="sorttable.js"></script>
+</head>
+<body>
+<table class=sortable>
+ <caption>
+ <p>Updated {{.now.Local.Format "2006-01-02 15:04:05"}}</p>
+ </caption>
+ <tr>
+ <th>NotBefore</th>
+ <th>NotAfter</th>
+ <th>Subject.CN</th>
+ <th>Socket</th>
+ </tr>
+{{range $cert := .certs}}
+ <tr>
+ <td style="background-color: ${$cert.X509.NotBefore | green}}">{{$cert.X509.NotBefore.Local.Format "2006-01-02"}}</td>
+ <td style="background-color: {{$cert.X509.NotAfter | red}}" >{{$cert.X509.NotAfter.Local.Format "2006-01-02"}}</td>
+ <td>{{$cert.X509.Subject.CommonName | html}}</td>
+ <td>{{$cert.Socket | html}}</td>
+ </tr>
+{{end}}
+</table>
+</body>
+</html>
+`))
+
+var now = time.Now()
+
+type interpolation struct {
+ ta, tb time.Time
+ ba, bb byte
+}
+
+func (i interpolation) interpolate(tc time.Time) byte {
+ db := i.tb.Sub(i.ta)
+ dc := tc.Sub(i.ta)
+
+ pct := float64(dc) / float64(db)
+ if pct < 0 {
+ pct = 0
+ } else if pct > 1 {
+ pct = 1
+ }
+
+ sb := int16(i.bb) - int16(i.ba)
+ sc := int16(pct * float64(sb))
+
+ return byte(int16(i.ba) + sc)
+}
+
+var daysago = interpolation{
+ ta: now.AddDate(0, 0, -30),
+ tb: now,
+ ba: 0xF3,
+ bb: 0x00,
+}
+
+var daysuntil = interpolation{
+ ta: now,
+ tb: now.AddDate(0, 0, 30),
+ ba: 0x00,
+ bb: 0xF3,
+}
+
+func green(t time.Time) string {
+ b := daysago.interpolate(t)
+ return fmt.Sprintf("#%02X%02X%02X", b, 0xF3, b)
+}
+
+func red(t time.Time) string {
+ b := daysuntil.interpolate(t)
+ return fmt.Sprintf("#%02X%02X%02X", 0xF3, b, b)
+}
+
+type Cert struct {
+ Socket string
+ 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].X509.NotAfter.UTC().After(l[j].X509.NotAfter.UTC())
+}
+
+// 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.Socket, ok = certPem.Headers["X-Socket"]
+ handleBool(ok, "Did not get X-Socket\n")
+
+ 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")
+}