func hexify(arr []byte) string {
	var hexed bytes.Buffer
	for i := 0; i < len(arr); i++ {
		hexed.WriteString(strings.ToUpper(hex.EncodeToString(arr[i : i+1])))
		if i < len(arr)-1 {
			hexed.WriteString(":")
		}
	}
	return hexed.String()
}
hexify returns a colon separated, hexadecimal representation
of a given byte array.
package lib
import (
	"bytes"
	"crypto/dsa"
	"crypto/ecdsa"
	"crypto/rsa"
	"crypto/tls"
	"crypto/x509"
	"crypto/x509/pkix"
	"encoding/hex"
	"encoding/json"
	"encoding/pem"
	"fmt"
	"net"
	"strconv"
	"strings"
	"time"
)
var keyUsages = []x509.KeyUsage{
	x509.KeyUsageDigitalSignature,
	x509.KeyUsageContentCommitment,
	x509.KeyUsageKeyEncipherment,
	x509.KeyUsageDataEncipherment,
	x509.KeyUsageKeyAgreement,
	x509.KeyUsageCertSign,
	x509.KeyUsageCRLSign,
	x509.KeyUsageEncipherOnly,
	x509.KeyUsageDecipherOnly,
}
var signatureSchemeStrings = map[tls.SignatureScheme]string{
	tls.PKCS1WithSHA1:          "RSA-PKCS1 with SHA1",
	tls.PKCS1WithSHA256:        "RSA-PKCS1 with SHA256",
	tls.PKCS1WithSHA384:        "RSA-PKCS1 with SHA384",
	tls.PKCS1WithSHA512:        "RSA-PKCS1 with SHA512",
	tls.PSSWithSHA256:          "RSA-PSS with SHA256",
	tls.PSSWithSHA384:          "RSA-PSS with SHA384",
	tls.PSSWithSHA512:          "RSA-PSS with SHA512",
	tls.ECDSAWithP256AndSHA256: "ECDSA with P256 and SHA256",
	tls.ECDSAWithP384AndSHA384: "ECDSA with P384 and SHA384",
	tls.ECDSAWithP521AndSHA512: "ECDSA with P521 and SHA512",
	0x807: "ED25519",
	0x808: "ED448",
	0x203: "ECDSA with SHA1",
	0x303: "ECDSA with SHA224",
	0x101: "RSA-PKCS1 with MD5",
	0x301: "RSA-PKCS1 with SHA224",
	0x102: "DSA with MD5",
	0x202: "DSA with SHA1",
	0x302: "DSA with SHA224",
	0x402: "DSA with SHA256",
	0x502: "DSA with SHA384",
	0x602: "DSA with SHA512",
	0xeeee: "GOST 34.10-2012 (256)",
	0xefef: "GOST 34.10-2012 (512)",
	0xeded: "GOST 34.10-2001",
}
var keyUsageStrings = map[x509.KeyUsage]string{
	x509.KeyUsageDigitalSignature:  "Digital Signature",
	x509.KeyUsageContentCommitment: "Content Commitment",
	x509.KeyUsageKeyEncipherment:   "Key Encipherment",
	x509.KeyUsageDataEncipherment:  "Data Encipherment",
	x509.KeyUsageKeyAgreement:      "Key Agreement",
	x509.KeyUsageCertSign:          "Cert Sign",
	x509.KeyUsageCRLSign:           "CRL Sign",
	x509.KeyUsageEncipherOnly:      "Encipher Only",
	x509.KeyUsageDecipherOnly:      "Decipher Only",
}
var extKeyUsageStrings = map[x509.ExtKeyUsage]string{
	x509.ExtKeyUsageAny:                        "Any",
	x509.ExtKeyUsageServerAuth:                 "Server Auth",
	x509.ExtKeyUsageClientAuth:                 "Client Auth",
	x509.ExtKeyUsageCodeSigning:                "Code Signing",
	x509.ExtKeyUsageEmailProtection:            "Email Protection",
	x509.ExtKeyUsageIPSECEndSystem:             "IPSEC End System",
	x509.ExtKeyUsageIPSECTunnel:                "IPSEC Tunnel",
	x509.ExtKeyUsageIPSECUser:                  "IPSEC User",
	x509.ExtKeyUsageTimeStamping:               "Time Stamping",
	x509.ExtKeyUsageOCSPSigning:                "OCSP Signing",
	x509.ExtKeyUsageMicrosoftServerGatedCrypto: "Microsoft ServerGatedCrypto",
	x509.ExtKeyUsageNetscapeServerGatedCrypto:  "Netscape ServerGatedCrypto",
}
var algoName = [...]string{
	x509.MD2WithRSA:      "MD2-RSA",
	x509.MD5WithRSA:      "MD5-RSA",
	x509.SHA1WithRSA:     "SHA1-RSA",
	x509.SHA256WithRSA:   "SHA256-RSA",
	x509.SHA384WithRSA:   "SHA384-RSA",
	x509.SHA512WithRSA:   "SHA512-RSA",
	x509.DSAWithSHA1:     "DSA-SHA1",
	x509.DSAWithSHA256:   "DSA-SHA256",
	x509.ECDSAWithSHA1:   "ECDSA-SHA1",
	x509.ECDSAWithSHA256: "ECDSA-SHA256",
	x509.ECDSAWithSHA384: "ECDSA-SHA384",
	x509.ECDSAWithSHA512: "ECDSA-SHA512",
}
type basicConstraints struct {
	IsCA       bool `json:"is_ca"`
	MaxPathLen *int `json:"pathlen,omitempty"`
}
type nameConstraints struct {
	Critical                bool         `json:"critical,omitempty"`
	PermittedDNSDomains     []string     `json:"permitted_dns_domains,omitempty"`
	ExcludedDNSDomains      []string     `json:"excluded_dns_domains,omitempty"`
	PermittedIPRanges       []*net.IPNet `json:"permitted_ip_ranges,omitempty"`
	ExcludedIPRanges        []*net.IPNet `json:"excluded_ip_ranges,omitempty"`
	PermittedEmailAddresses []string     `json:"permitted_email_addresses,omitempty"`
	ExcludedEmailAddresses  []string     `json:"excluded_email_addresses,omitempty"`
	PermittedURIDomains     []string     `json:"permitted_uri_domains,omitempty"`
	ExcludedURIDomains      []string     `json:"excluded_uri_domains,omitempty"`
}
type simpleCertificate struct {
	Alias                 string              `json:"alias,omitempty"`
	SerialNumber          string              `json:"serial"`
	NotBefore             time.Time           `json:"not_before"`
	NotAfter              time.Time           `json:"not_after"`
	SignatureAlgorithm    simpleSigAlg        `json:"signature_algorithm"`
	IsSelfSigned          bool                `json:"is_self_signed"`
	Subject               simplePKIXName      `json:"subject"`
	Issuer                simplePKIXName      `json:"issuer"`
	BasicConstraints      *basicConstraints   `json:"basic_constraints,omitempty"`
	NameConstraints       *nameConstraints    `json:"name_constraints,omitempty"`
	OCSPServer            []string            `json:"ocsp_server,omitempty"`
	IssuingCertificateURL []string            `json:"issuing_certificate,omitempty"`
	KeyUsage              simpleKeyUsage      `json:"key_usage,omitempty"`
	ExtKeyUsage           []simpleExtKeyUsage `json:"extended_key_usage,omitempty"`
	AltDNSNames           []string            `json:"dns_names,omitempty"`
	AltIPAddresses        []net.IP            `json:"ip_addresses,omitempty"`
	URINames              []string            `json:"uri_names,omitempty"`
	EmailAddresses        []string            `json:"email_addresses,omitempty"`
	Warnings              []string            `json:"warnings,omitempty"`
	PEM                   string              `json:"pem,omitempty"`
	Width int `json:"-"`
}
type simplePKIXName struct {
	Name  pkix.Name
	KeyID []byte
}
type simpleKeyUsage x509.KeyUsage
type simpleExtKeyUsage x509.ExtKeyUsage
type simpleSigAlg x509.SignatureAlgorithm
func createSimpleCertificate(name string, cert *x509.Certificate) simpleCertificate {
	out := simpleCertificate{
		Alias:              name,
		SerialNumber:       cert.SerialNumber.String(),
		NotBefore:          cert.NotBefore,
		NotAfter:           cert.NotAfter,
		SignatureAlgorithm: simpleSigAlg(cert.SignatureAlgorithm),
		IsSelfSigned:       IsSelfSigned(cert),
		Subject: simplePKIXName{
			Name:  cert.Subject,
			KeyID: cert.SubjectKeyId,
		},
		Issuer: simplePKIXName{
			Name:  cert.Issuer,
			KeyID: cert.AuthorityKeyId,
		},
		KeyUsage:              simpleKeyUsage(cert.KeyUsage),
		OCSPServer:            cert.OCSPServer,
		IssuingCertificateURL: cert.IssuingCertificateURL,
		AltDNSNames:           cert.DNSNames,
		AltIPAddresses:        cert.IPAddresses,
		EmailAddresses:        cert.EmailAddresses,
		PEM:                   string(pem.EncodeToMemory(EncodeX509ToPEM(cert, nil))),
	}
	for _, uri := range cert.URIs {
		out.URINames = append(out.URINames, uri.String())
	}
	out.Warnings = certWarnings(cert, out.URINames)
	if cert.BasicConstraintsValid {
		out.BasicConstraints = &basicConstraints{
			IsCA: cert.IsCA,
		}
		if cert.MaxPathLen > 0 || cert.MaxPathLenZero {
			out.BasicConstraints.MaxPathLen = &cert.MaxPathLen
		}
	}
	if len(cert.PermittedDNSDomains) > 0 || len(cert.ExcludedDNSDomains) > 0 ||
		len(cert.PermittedIPRanges) > 0 || len(cert.ExcludedIPRanges) > 0 ||
		len(cert.PermittedEmailAddresses) > 0 || len(cert.ExcludedEmailAddresses) > 0 ||
		len(cert.PermittedURIDomains) > 0 || len(cert.ExcludedURIDomains) > 0 {
		out.NameConstraints = &nameConstraints{
			Critical:                cert.PermittedDNSDomainsCritical,
			PermittedDNSDomains:     cert.PermittedDNSDomains,
			ExcludedDNSDomains:      cert.ExcludedDNSDomains,
			PermittedIPRanges:       cert.PermittedIPRanges,
			ExcludedIPRanges:        cert.ExcludedIPRanges,
			PermittedEmailAddresses: cert.PermittedEmailAddresses,
			ExcludedEmailAddresses:  cert.ExcludedEmailAddresses,
			PermittedURIDomains:     cert.PermittedURIDomains,
			ExcludedURIDomains:      cert.ExcludedURIDomains,
		}
	}
	simpleEku := []simpleExtKeyUsage{}
	for _, eku := range cert.ExtKeyUsage {
		simpleEku = append(simpleEku, simpleExtKeyUsage(eku))
	}
	out.ExtKeyUsage = simpleEku
	return out
}
func (p simplePKIXName) MarshalJSON() ([]byte, error) {
	out := map[string]interface{}{}
	for _, rdn := range p.Name.Names {
		oid := describeOid(rdn.Type)
		if prev, ok := out[oid.Slug]; oid.Multiple && ok {
			l := prev.([]interface{})
			out[oid.Slug] = append(l, rdn.Value)
		} else if oid.Multiple {
			out[oid.Slug] = []interface{}{rdn.Value}
		} else {
			out[oid.Slug] = rdn.Value
		}
	}
	if len(p.KeyID) > 0 {
		out["key_id"] = hexify(p.KeyID)
	}
	return json.Marshal(out)
}
func (k simpleKeyUsage) MarshalJSON() ([]byte, error) {
	return json.Marshal(keyUsage(k))
}
func (e simpleExtKeyUsage) MarshalJSON() ([]byte, error) {
	return json.Marshal(extKeyUsage(e))
}
func (s simpleSigAlg) MarshalJSON() ([]byte, error) {
	return json.Marshal(algString(x509.SignatureAlgorithm(s)))
}