package main import ( "crypto/x509" "encoding/json" "encoding/pem" "flag" "fmt" "io/ioutil" "os" ) func main() { jsonOut := flag.Bool("json", false, "output JSON with all certs/fields") flag.Parse() if flag.NArg() < 1 { fmt.Println("usage: certinfo [--json] ") os.Exit(2) } path := flag.Arg(0) certs, err := ParseCertinfo(path) if err != nil { fmt.Println("parse error:", err) os.Exit(1) } if *jsonOut { jsonBytes, err := json.Marshal(certs) if err != nil { fmt.Println("marshal error:", err) os.Exit(1) } fmt.Println(string(jsonBytes)) return } // Usually just the first one is interesting cert := certs[0] fmt.Println("Subject:", cert.Subject.String()) fmt.Println("Issuer:", cert.Issuer.String()) fmt.Println("Serial:", cert.SerialNumber.String()) fmt.Println("NotBefore:", cert.NotBefore) fmt.Println("NotAfter:", cert.NotAfter) if len(cert.DNSNames) > 0 { fmt.Println("DNS SANs:", cert.DNSNames) } fmt.Println("Signature Algorithm:", cert.SignatureAlgorithm) fmt.Println("Public Key Algorithm:", cert.PublicKeyAlgorithm) } func ParseCertinfo(filename string) ([]*x509.Certificate, error) { data, err := ioutil.ReadFile(filename) if err != nil { return nil, err } var certs []*x509.Certificate for { var block *pem.Block block, data = pem.Decode(data) if block == nil { break } if block.Type != "CERTIFICATE" { fmt.Fprintf(os.Stderr, "warning: Ignoring block type: %s\n", block.Type) continue } cert, err := x509.ParseCertificate(block.Bytes) if err != nil { return nil, err } certs = append(certs, cert) } return certs, nil }