func WithSANs(sans []string) WithOption {
	return func(p Profile) error {
		dnsNames, ips, emails, uris := SplitSANs(sans)
		cert := p.Subject()
		cert.DNSNames = dnsNames
		cert.IPAddresses = ips
		cert.EmailAddresses = emails
		cert.URIs = uris
		return nil
	}
}
WithSANs returns a profile modifier which set the dnsNames, emailAddresses,
ipAddresses, and URIs attributes of the Certificate.
package x509util
import (
	"crypto"
	"crypto/rand"
	"crypto/rsa"
	"crypto/sha1"
	"crypto/x509"
	"crypto/x509/pkix"
	"encoding/asn1"
	"encoding/pem"
	"math/big"
	"net"
	"net/url"
	"strings"
	"time"
	"github.com/pkg/errors"
	"github.com/smallstep/cli/crypto/keys"
	"github.com/smallstep/cli/crypto/pemutil"
	"github.com/smallstep/cli/utils"
)
var (
	oidExtSubjectKeyID          = asn1.ObjectIdentifier([]int{2, 5, 29, 14})
	oidExtKeyUsage              = asn1.ObjectIdentifier([]int{2, 5, 29, 15})
	oidExtExtendedKeyUsage      = asn1.ObjectIdentifier([]int{2, 5, 29, 37})
	oidExtAuthorityKeyID        = asn1.ObjectIdentifier([]int{2, 5, 29, 35})
	oidExtBasicConstraints      = asn1.ObjectIdentifier([]int{2, 5, 29, 19})
	oidExtSubjectAltName        = asn1.ObjectIdentifier([]int{2, 5, 29, 17})
	oidExtCertificatePolicies   = asn1.ObjectIdentifier([]int{2, 5, 29, 32})
	oidExtNameConstraints       = asn1.ObjectIdentifier([]int{2, 5, 29, 30})
	oidExtCRLDistributionPoints = asn1.ObjectIdentifier([]int{2, 5, 29, 31})
	oidExtAuthorityInfoAccess   = asn1.ObjectIdentifier([]int{1, 3, 6, 1, 5, 5, 7, 1, 1})
	oidStdExtHashMap            = map[string]struct{}{}
	emptyStruct                 struct{}
)
func init() {
	oidStdExtHashMap[oidExtSubjectKeyID.String()] = emptyStruct
	oidStdExtHashMap[oidExtKeyUsage.String()] = emptyStruct
	oidStdExtHashMap[oidExtExtendedKeyUsage.String()] = emptyStruct
	oidStdExtHashMap[oidExtAuthorityKeyID.String()] = emptyStruct
	oidStdExtHashMap[oidExtBasicConstraints.String()] = emptyStruct
	oidStdExtHashMap[oidExtSubjectAltName.String()] = emptyStruct
	oidStdExtHashMap[oidExtCertificatePolicies.String()] = emptyStruct
	oidStdExtHashMap[oidExtNameConstraints.String()] = emptyStruct
	oidStdExtHashMap[oidExtCRLDistributionPoints.String()] = emptyStruct
	oidStdExtHashMap[oidExtAuthorityInfoAccess.String()] = emptyStruct
}
var (
	DefaultCertValidity = 24 * time.Hour
	DefaultTLSMinVersion = TLSVersion(1.2)
	DefaultTLSMaxVersion = TLSVersion(1.2)
	DefaultTLSRenegotiation = false  
	DefaultTLSCipherSuites = CipherSuites{
		"TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305",
		"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
	}
	ApprovedTLSCipherSuites = CipherSuites{
		"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA",
		"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256",
		"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
		"TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA",
		"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
		"TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305",
		"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA",
		"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256",
		"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
		"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA",
		"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
		"TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305",
	}
	oidExtensionCTPoison = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 11129, 2, 4, 3}
)
type Profile interface {
	Issuer() *x509.Certificate
	Subject() *x509.Certificate
	SubjectPrivateKey() interface{}
	SubjectPublicKey() interface{}
	SetIssuer(*x509.Certificate)
	SetSubject(*x509.Certificate)
	SetSubjectPrivateKey(interface{})
	SetSubjectPublicKey(interface{})
	SetIssuerPrivateKey(interface{})
	CreateCertificate() ([]byte, error)
	GenerateKeyPair(string, string, int) error
	DefaultDuration() time.Duration
	CreateWriteCertificate(crtOut, keyOut, pass string) ([]byte, error)
	AddExtension(pkix.Extension)
	RemoveExtension(asn1.ObjectIdentifier)
}
type base struct {
	iss     *x509.Certificate
	sub     *x509.Certificate
	ext     []pkix.Extension
	subPub  interface{}
	subPriv interface{}
	issPriv interface{}
}
type WithOption func(Profile) error
func GenerateKeyPair(kty, crv string, size int) WithOption {
	return func(p Profile) error {
		return p.GenerateKeyPair(kty, crv, size)
	}
}
func GenerateDefaultKeyPair(p Profile) error {
	pub, priv, err := keys.GenerateDefaultKeyPair()
	if err != nil {
		return err
	}
	p.SetSubjectPublicKey(pub)
	p.SetSubjectPrivateKey(priv)
	return nil
}
func WithPublicKey(pub interface{}) WithOption {
	return func(p Profile) error {
		p.SetSubjectPublicKey(pub)
		return nil
	}
}
func WithSubject(sub pkix.Name) WithOption {
	return func(p Profile) error {
		crt := p.Subject()
		crt.Subject = sub
		return nil
	}
}
func WithIssuer(iss pkix.Name) WithOption {
	return func(p Profile) error {
		crt := p.Subject()
		crt.Issuer = iss
		return nil
	}
}
func WithNotBeforeAfterDuration(nb, na time.Time, d time.Duration) WithOption {
	return func(p Profile) error {
		crt := p.Subject()
		now := time.Now()
		if nb.IsZero() {
			nb = now
		}
		if na.IsZero() {
			if d == 0 {
				na = nb.Add(p.DefaultDuration())
			} else {
				na = nb.Add(d)
			}
		}
		crt.NotBefore = nb
		crt.NotAfter = na
		return nil
	}
}
func appendIfMissingString(slice []string, s string) []string {
	for _, e := range slice {
		if e == s {
			return slice
		}
	}
	return append(slice, s)
}
func appendIfMissingIP(ips []net.IP, ip net.IP) []net.IP {
	for _, e := range ips {
		if ip.Equal(e) {
			return ips
		}
	}
	return append(ips, ip)
}
func WithDNSNames(dns []string) WithOption {
	return func(p Profile) error {
		crt := p.Subject()
		crt.DNSNames = dns
		return nil
	}
}
func WithIPAddresses(ips []net.IP) WithOption {
	return func(p Profile) error {
		crt := p.Subject()
		crt.IPAddresses = ips
		return nil
	}
}
func WithEmailAddresses(emails []string) WithOption {
	return func(p Profile) error {
		crt := p.Subject()
		crt.EmailAddresses = emails
		return nil
	}
}
func WithURIs(uris []*url.URL) WithOption {
	return func(p Profile) error {
		crt := p.Subject()
		crt.URIs = uris
		return nil
	}
}