func certEnd(end time.Time) string {
	now := time.Now()
	month, _ := time.ParseDuration("720h")
	threshold := now.Add(month)
	if threshold.Before(end) {
		return timeString(end, green)
	} else if now.Before(end) {
		return timeString(end, yellow)
	} else {
		return timeString(end, red)
	}
}
certEnd takes a given end time for the validity of
a certificate and returns that time colored properly
based on how close it is to expiry. If the certificate
is more than a month away from expiring it returns a
green string. If the certificate is less than a month
from expiry it returns a yellow string. If the certificate
is expired it returns a red string.
package lib
import (
	"bufio"
	"bytes"
	"crypto/x509"
	"encoding/json"
	"encoding/pem"
	"fmt"
	"text/template"
	"time"
	"crypto/x509/pkix"
	"github.com/Masterminds/sprig"
	"github.com/fatih/color"
)
var verboseLayout = `
{{- define "PkixName" -}}
{{- range .Names}}
	{{ .Type | oidName }}: {{ .Value }}
{{- end -}}
{{end -}}
{{- if .Alias}}{{.Alias}}
{{end}}Serial: {{.SerialNumber}}
Valid: {{.NotBefore | certStart}} to {{.NotAfter | certEnd}}
Signature: {{.SignatureAlgorithm | highlightAlgorithm}}{{if .IsSelfSigned}} (self-signed){{end}}
Subject Info:
	{{- template "PkixName" .Subject.Name}}
Issuer Info:
	{{- template "PkixName" .Issuer.Name}}
{{- if .Subject.KeyID}}
Subject Key ID: {{.Subject.KeyID | hexify}}
{{- end}}
{{- if .Issuer.KeyID}}
Authority Key ID: {{.Issuer.KeyID | hexify}}
{{- end}}
{{- if .BasicConstraints}}
Basic Constraints: CA:{{.BasicConstraints.IsCA}}{{if .BasicConstraints.MaxPathLen}}, pathlen:{{.BasicConstraints.MaxPathLen}}{{end}}{{end}}
{{- if .NameConstraints}}
Name Constraints{{if .NameConstraints.Critical}} (critical){{end}}: 
{{- if .NameConstraints.PermittedDNSDomains}}
Permitted DNS domains:
	{{wrapWith .Width "\n\t" (join ", " .NameConstraints.PermittedDNSDomains)}}
{{- end -}}
{{- if .NameConstraints.PermittedEmailAddresses}}
Permitted email addresses:
	{{wrapWith .Width "\n\t" (join ", " .NameConstraints.PermittedEmailAddresses)}}
{{- end -}}
{{- if .NameConstraints.PermittedIPRanges}}
Permitted IP ranges:
	{{wrapWith .Width "\n\t" (join ", " .NameConstraints.PermittedIPRanges)}}
{{- end -}}
{{- if .NameConstraints.PermittedURIDomains}}
Permitted URI domains:
	{{wrapWith .Width "\n\t" (join ", " .NameConstraints.PermittedURIDomains)}}
{{- end}}
{{- if .NameConstraints.ExcludedDNSDomains}}
Excluded DNS domains:
	{{wrapWith .Width "\n\t" (join ", " .NameConstraints.ExcludedDNSDomains)}}
{{- end}}
{{- if .NameConstraints.ExcludedEmailAddresses}}
Excluded email addresses:
	{{wrapWith .Width "\n\t" (join ", " .NameConstraints.ExcludedEmailAddresses)}}
{{- end}}
{{- if .NameConstraints.ExcludedIPRanges}}
Excluded IP ranges:
	{{wrapWith .Width "\n\t" (join ", " .NameConstraints.ExcludedIPRanges)}}
{{- end}}
{{- if .NameConstraints.ExcludedURIDomains}}
Excluded URI domains:
	{{wrapWith .Width "\n\t" (join ", " .NameConstraints.ExcludedURIDomains)}}
{{- end}}
{{- end}}
{{- if .OCSPServer}}
OCSP Server(s):
	{{wrapWith .Width "\n\t" (join ", " .OCSPServer)}}
{{- end}}
{{- if .IssuingCertificateURL}}
Issuing Certificate URL(s):
	{{wrapWith .Width "\n\t" (join ", " .IssuingCertificateURL)}}
{{- end}}
{{- if .KeyUsage}}
Key Usage:
{{- range .KeyUsage | keyUsage}}
	{{.}}
{{- end}}
{{- end}}
{{- if .ExtKeyUsage}}
Extended Key Usage:
{{- range .ExtKeyUsage}}
	{{. | extKeyUsage}}{{end}}
{{- end}}
{{- if .AltDNSNames}}
DNS Names:
	{{wrapWith .Width "\n\t" (join ", " .AltDNSNames)}}
{{- end}}
{{- if .AltIPAddresses}}
IP Addresses:
	{{wrapWith .Width "\n\t" (join ", " .AltIPAddresses)}}
{{- end}}
{{- if .URINames}}
URI Names:
	{{wrapWith .Width "\n\t" (join ", " .URINames)}}
{{- end}}
{{- if .EmailAddresses}}
Email Addresses:
	{{wrapWith .Width "\n\t" (join ", " .EmailAddresses)}}
{{- end}}
{{- if .Warnings}}
Warnings:
{{- range .Warnings}}
	{{. | redify}}
{{- end}}
{{- end}}`
var layout = `
{{- if .Alias}}{{.Alias}}
{{end -}}
Valid: {{.NotBefore | certStart}} to {{.NotAfter | certEnd}}
Subject:
	{{wrapWith .Width "\n\t" (.Subject.Name | printShortName)}}
Issuer:
	{{wrapWith .Width "\n\t" (.Issuer.Name | printShortName)}}
{{- if .AltDNSNames}}
DNS Names:
	{{wrapWith .Width "\n\t" (join ", " .AltDNSNames)}}{{end}}
{{- if .AltIPAddresses}}
IP Addresses:
	{{wrapWith .Width "\n\t" (join ", " .AltIPAddresses)}}{{end}}
{{- if .URINames}}
URI Names:
	{{wrapWith .Width "\n\t" (join ", " .URINames)}}{{end}}
{{- if .EmailAddresses}}
Email Addresses:
	{{wrapWith .Width "\n\t" (join ", " .EmailAddresses)}}{{end}}
{{- if .Warnings}}
Warnings:{{range .Warnings}}
	{{. | redify}}{{end}}{{end}}`
type certWithName struct {
	name string
	file string
	cert *x509.Certificate
}
func (c certWithName) MarshalJSON() ([]byte, error) {
	out := createSimpleCertificate(c.name, c.cert)
	return json.Marshal(out)
}
func createSimpleCertificateFromX509(block *pem.Block) (simpleCertificate, error) {
	raw, err := x509.ParseCertificate(block.Bytes)
	if err != nil {
		return simpleCertificate{}, fmt.Errorf("error reading cert: %s", err)
	}
	cert := certWithName{cert: raw}
	if val, ok := block.Headers[nameHeader]; ok {
		cert.name = val
	}
	if val, ok := block.Headers[fileHeader]; ok {
		cert.file = val
	}
	return createSimpleCertificate(cert.name, cert.cert), nil
}
func EncodeX509ToJSON(cert *x509.Certificate) []byte {
	out := createSimpleCertificate("", cert)
	raw, err := json.Marshal(out)
	if err != nil {
		panic(err)
	}
	return raw
}
func EncodeX509ToObject(cert *x509.Certificate) interface{} {
	return createSimpleCertificate("", cert)
}
func EncodeX509ToText(cert *x509.Certificate, terminalWidth int, verbose bool) []byte {
	c := createSimpleCertificate("", cert)
	c.Width = terminalWidth - 8  
	return displayCert(c, verbose)
}
func displayCert(cert simpleCertificate, verbose bool) []byte {
	funcMap := sprig.TxtFuncMap()
	extras := template.FuncMap{
		"certStart":          certStart,
		"certEnd":            certEnd,
		"redify":             redify,
		"highlightAlgorithm": highlightAlgorithm,
		"hexify":             hexify,
		"keyUsage":           keyUsage,
		"extKeyUsage":        extKeyUsage,
		"oidName":            oidName,
		"oidShort":           oidShort,
		"printShortName":     PrintShortName,
		"printCommonName":    PrintCommonName,
	}
	for k, v := range extras {
		funcMap[k] = v
	}
	t := template.New("Cert template").Funcs(funcMap)
	var err error
	if verbose {
		t, err = t.Parse(verboseLayout)
	} else {
		t, err = t.Parse(layout)
	}
	if err != nil {
		panic(err)
	}
	var buffer bytes.Buffer
	w := bufio.NewWriter(&buffer)
	err = t.Execute(w, cert)
	if err != nil {
		panic(err)
	}
	w.Flush()
	return buffer.Bytes()
}
var (
	green  = color.New(color.Bold, color.FgGreen)
	yellow = color.New(color.Bold, color.FgYellow)
	red    = color.New(color.Bold, color.FgRed)
)
var algorithmColors = map[x509.SignatureAlgorithm]*color.Color{
	x509.MD2WithRSA:      red,
	x509.MD5WithRSA:      red,
	x509.SHA1WithRSA:     red,
	x509.SHA256WithRSA:   green,
	x509.SHA384WithRSA:   green,
	x509.SHA512WithRSA:   green,
	x509.DSAWithSHA1:     red,
	x509.DSAWithSHA256:   red,
	x509.ECDSAWithSHA1:   red,
	x509.ECDSAWithSHA256: green,
	x509.ECDSAWithSHA384: green,
	x509.ECDSAWithSHA512: green,
}
func highlightAlgorithm(sigAlg simpleSigAlg) string {
	sig := x509.SignatureAlgorithm(sigAlg)
	color, ok := algorithmColors[sig]
	if !ok {
		return algString(sig)
	}
	return color.SprintFunc()(algString(sig))
}
func timeString(t time.Time, c *color.Color) string {
	return c.SprintfFunc()(t.Format("2006-01-02 15:04 MST"))
}
func certStart(start time.Time) string {
	now := time.Now()
	day, _ := time.ParseDuration("24h")
	threshold := start.Add(day)
	if now.After(threshold) {
		return timeString(start, green)
	} else if now.After(start) {
		return timeString(start, yellow)
	} else {
		return timeString(start, red)
	}
}