func (p *SigningProfile) validProfile(isDefault bool) bool {
	if p == nil {
		return false
	}
	if p.AuthRemote.RemoteName == "" && p.AuthRemote.AuthKeyName != "" {
		log.Debugf("invalid auth remote profile: no remote signer specified")
		return false
	}
	if p.RemoteName != "" {
		log.Debugf("validate remote profile")
		if p.RemoteServer == "" {
			log.Debugf("invalid remote profile: no remote signer specified")
			return false
		}
		if p.AuthKeyName != "" && p.Provider == nil {
			log.Debugf("invalid remote profile: auth key name is defined but no auth provider is set")
			return false
		}
		if p.AuthRemote.RemoteName != "" {
			log.Debugf("invalid remote profile: auth remote is also specified")
			return false
		}
	} else if p.AuthRemote.RemoteName != "" {
		log.Debugf("validate auth remote profile")
		if p.RemoteServer == "" {
			log.Debugf("invalid auth remote profile: no remote signer specified")
			return false
		}
		if p.AuthRemote.AuthKeyName == "" || p.RemoteProvider == nil {
			log.Debugf("invalid auth remote profile: no auth key is defined")
			return false
		}
	} else {
		log.Debugf("validate local profile")
		if !isDefault {
			if len(p.Usage) == 0 {
				log.Debugf("invalid local profile: no usages specified")
				return false
			} else if _, _, unk := p.Usages(); len(unk) == len(p.Usage) {
				log.Debugf("invalid local profile: no valid usages")
				return false
			}
		} else {
			if p.Expiry == 0 {
				log.Debugf("invalid local profile: no expiry set")
				return false
			}
		}
	}
	log.Debugf("profile is valid")
	return true
}
A valid profile must be a valid local profile or a valid remote profile.
A valid local profile has defined at least key usages to be used, and a
valid local default profile has defined at least a default expiration.
A valid remote profile (default or not) has remote signer initialized.
In addition, a remote profile must has a valid auth provider if auth
key defined.
package config
import (
	"crypto/tls"
	"crypto/x509"
	"encoding/asn1"
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"regexp"
	"strconv"
	"strings"
	"time"
	"github.com/cloudflare/cfssl/auth"
	cferr "github.com/cloudflare/cfssl/errors"
	"github.com/cloudflare/cfssl/helpers"
	"github.com/cloudflare/cfssl/log"
	ocspConfig "github.com/cloudflare/cfssl/ocsp/config"
)
type CSRWhitelist struct {
	Subject, PublicKeyAlgorithm, PublicKey, SignatureAlgorithm bool
	DNSNames, IPAddresses, EmailAddresses, URIs                bool
}
type OID asn1.ObjectIdentifier
type CertificatePolicy struct {
	ID         OID
	Qualifiers []CertificatePolicyQualifier
}
type CertificatePolicyQualifier struct {
	Type  string
	Value string
}
type AuthRemote struct {
	RemoteName  string `json:"remote"`
	AuthKeyName string `json:"auth_key"`
}
type CAConstraint struct {
	IsCA           bool `json:"is_ca"`
	MaxPathLen     int  `json:"max_path_len"`
	MaxPathLenZero bool `json:"max_path_len_zero"`
}
type SigningProfile struct {
	Usage               []string     `json:"usages"`
	IssuerURL           []string     `json:"issuer_urls"`
	OCSP                string       `json:"ocsp_url"`
	CRL                 string       `json:"crl_url"`
	CAConstraint        CAConstraint `json:"ca_constraint"`
	OCSPNoCheck         bool         `json:"ocsp_no_check"`
	ExpiryString        string       `json:"expiry"`
	BackdateString      string       `json:"backdate"`
	AuthKeyName         string       `json:"auth_key"`
	PrevAuthKeyName     string       `json:"prev_auth_key"`  
	RemoteName          string       `json:"remote"`
	NotBefore           time.Time    `json:"not_before"`
	NotAfter            time.Time    `json:"not_after"`
	NameWhitelistString string       `json:"name_whitelist"`
	AuthRemote          AuthRemote   `json:"auth_remote"`
	CTLogServers        []string     `json:"ct_log_servers"`
	AllowedExtensions   []OID        `json:"allowed_extensions"`
	CertStore           string       `json:"cert_store"`
	Policies                    []CertificatePolicy
	Expiry                      time.Duration
	Backdate                    time.Duration
	Provider                    auth.Provider
	PrevProvider                auth.Provider  
	RemoteProvider              auth.Provider
	RemoteServer                string
	RemoteCAs                   *x509.CertPool
	ClientCert                  *tls.Certificate
	CSRWhitelist                *CSRWhitelist
	NameWhitelist               *regexp.Regexp
	ExtensionWhitelist          map[string]bool
	ClientProvidesSerialNumbers bool
}
func (oid *OID) UnmarshalJSON(data []byte) (err error) {
	if data[0] != '"' || data[len(data)-1] != '"' {
		return errors.New("OID JSON string not wrapped in quotes." + string(data))
	}
	data = data[1 : len(data)-1]
	parsedOid, err := parseObjectIdentifier(string(data))
	if err != nil {
		return err
	}
	*oid = OID(parsedOid)
	return
}
func (oid OID) MarshalJSON() ([]byte, error) {
	return []byte(fmt.Sprintf(`"%v"`, asn1.ObjectIdentifier(oid))), nil
}
func parseObjectIdentifier(oidString string) (oid asn1.ObjectIdentifier, err error) {
	validOID, err := regexp.MatchString("\\d(\\.\\d+)*", oidString)
	if err != nil {
		return
	}
	if !validOID {
		err = errors.New("Invalid OID")
		return
	}
	segments := strings.Split(oidString, ".")
	oid = make(asn1.ObjectIdentifier, len(segments))
	for i, intString := range segments {
		oid[i], err = strconv.Atoi(intString)
		if err != nil {
			return
		}
	}
	return
}
const timeFormat = "2006-01-02T15:04:05"
func (p *SigningProfile) populate(cfg *Config) error {
	if p == nil {
		return cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy, errors.New("can't parse nil profile"))
	}
	var err error
	if p.RemoteName == "" && p.AuthRemote.RemoteName == "" {
		log.Debugf("parse expiry in profile")
		if p.ExpiryString == "" {
			return cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy, errors.New("empty expiry string"))
		}
		dur, err := time.ParseDuration(p.ExpiryString)
		if err != nil {
			return cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy, err)
		}
		log.Debugf("expiry is valid")
		p.Expiry = dur
		if p.BackdateString != "" {
			dur, err = time.ParseDuration(p.BackdateString)
			if err != nil {
				return cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy, err)
			}
			p.Backdate = dur
		}
		if !p.NotBefore.IsZero() && !p.NotAfter.IsZero() && p.NotAfter.Before(p.NotBefore) {
			return cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy, err)
		}
		if len(p.Policies) > 0 {
			for _, policy := range p.Policies {
				for _, qualifier := range policy.Qualifiers {
					if qualifier.Type != "" && qualifier.Type != "id-qt-unotice" && qualifier.Type != "id-qt-cps" {
						return cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy,
							errors.New("invalid policy qualifier type"))
					}
				}
			}
		}
	} else if p.RemoteName != "" {
		log.Debug("match remote in profile to remotes section")
		if p.AuthRemote.RemoteName != "" {
			log.Error("profile has both a remote and an auth remote specified")
			return cferr.New(cferr.PolicyError, cferr.InvalidPolicy)
		}
		if remote := cfg.Remotes[p.RemoteName]; remote != "" {
			if err := p.updateRemote(remote); err != nil {
				return err
			}
		} else {
			return cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy,
				errors.New("failed to find remote in remotes section"))
		}
	} else {
		log.Debug("match auth remote in profile to remotes section")
		if remote := cfg.Remotes[p.AuthRemote.RemoteName]; remote != "" {
			if err := p.updateRemote(remote); err != nil {
				return err
			}
		} else {
			return cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy,
				errors.New("failed to find remote in remotes section"))
		}
	}
	if p.AuthKeyName != "" {
		log.Debug("match auth key in profile to auth_keys section")
		if key, ok := cfg.AuthKeys[p.AuthKeyName]; ok {
			if key.Type == "standard" {
				p.Provider, err = auth.New(key.Key, nil)
				if err != nil {
					log.Debugf("failed to create new standard auth provider: %v", err)
					return cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy,
						errors.New("failed to create new standard auth provider"))
				}
			} else {
				log.Debugf("unknown authentication type %v", key.Type)
				return cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy,
					errors.New("unknown authentication type"))
			}
		} else {
			return cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy,
				errors.New("failed to find auth_key in auth_keys section"))
		}
	}
	if p.PrevAuthKeyName != "" {
		log.Debug("match previous auth key in profile to auth_keys section")
		if key, ok := cfg.AuthKeys[p.PrevAuthKeyName]; ok {
			if key.Type == "standard" {
				p.PrevProvider, err = auth.New(key.Key, nil)
				if err != nil {
					log.Debugf("failed to create new standard auth provider: %v", err)
					return cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy,
						errors.New("failed to create new standard auth provider"))
				}
			} else {
				log.Debugf("unknown authentication type %v", key.Type)
				return cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy,
					errors.New("unknown authentication type"))
			}
		} else {
			return cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy,
				errors.New("failed to find prev_auth_key in auth_keys section"))
		}
	}
	if p.AuthRemote.AuthKeyName != "" {
		log.Debug("match auth remote key in profile to auth_keys section")
		if key, ok := cfg.AuthKeys[p.AuthRemote.AuthKeyName]; ok == true {
			if key.Type == "standard" {
				p.RemoteProvider, err = auth.New(key.Key, nil)
				if err != nil {
					log.Debugf("failed to create new standard auth provider: %v", err)
					return cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy,
						errors.New("failed to create new standard auth provider"))
				}
			} else {
				log.Debugf("unknown authentication type %v", key.Type)
				return cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy,
					errors.New("unknown authentication type"))
			}
		} else {
			return cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy,
				errors.New("failed to find auth_remote's auth_key in auth_keys section"))
		}
	}
	if p.NameWhitelistString != "" {
		log.Debug("compiling whitelist regular expression")
		rule, err := regexp.Compile(p.NameWhitelistString)
		if err != nil {
			return cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy,
				errors.New("failed to compile name whitelist section"))
		}
		p.NameWhitelist = rule
	}
	p.ExtensionWhitelist = map[string]bool{}
	for _, oid := range p.AllowedExtensions {
		p.ExtensionWhitelist[asn1.ObjectIdentifier(oid).String()] = true
	}
	return nil
}
func (p *SigningProfile) updateRemote(remote string) error {
	if remote != "" {
		p.RemoteServer = remote
	}
	return nil
}
func (p *Signing) OverrideRemotes(remote string) error {
	if remote != "" {
		var err error
		for _, profile := range p.Profiles {
			err = profile.updateRemote(remote)
			if err != nil {
				return err
			}
		}
		err = p.Default.updateRemote(remote)
		if err != nil {
			return err
		}
	}
	return nil
}
func (p *Signing) SetClientCertKeyPairFromFile(certFile string, keyFile string) error {
	if certFile != "" && keyFile != "" {
		cert, err := helpers.LoadClientCertificate(certFile, keyFile)
		if err != nil {
			return err
		}
		for _, profile := range p.Profiles {
			profile.ClientCert = cert
		}
		p.Default.ClientCert = cert
	}
	return nil
}
func (p *Signing) SetRemoteCAsFromFile(caFile string) error {
	if caFile != "" {
		remoteCAs, err := helpers.LoadPEMCertPool(caFile)
		if err != nil {
			return err
		}
		p.SetRemoteCAs(remoteCAs)
	}
	return nil
}
func (p *Signing) SetRemoteCAs(remoteCAs *x509.CertPool) {
	for _, profile := range p.Profiles {
		profile.RemoteCAs = remoteCAs
	}
	p.Default.RemoteCAs = remoteCAs
}
func (p *Signing) NeedsRemoteSigner() bool {
	for _, profile := range p.Profiles {
		if profile.RemoteServer != "" {
			return true
		}
	}
	if p.Default.RemoteServer != "" {
		return true
	}
	return false
}
func (p *Signing) NeedsLocalSigner() bool {
	for _, profile := range p.Profiles {
		if profile.RemoteServer == "" {
			return true
		}
	}
	if p.Default.RemoteServer == "" {
		return true
	}
	return false
}
func (p *SigningProfile) Usages() (ku x509.KeyUsage, eku []x509.ExtKeyUsage, unk []string) {
	for _, keyUse := range p.Usage {
		if kuse, ok := KeyUsage[keyUse]; ok {
			ku |= kuse
		} else if ekuse, ok := ExtKeyUsage[keyUse]; ok {
			eku = append(eku, ekuse)
		} else {
			unk = append(unk, keyUse)
		}
	}
	return
}