github.com/hellobchain/third_party@v0.0.0-20230331131523-deb0478a2e52/cloudflare/cfssl/config/config.go (about)

     1  // Package config contains the configuration logic for CFSSL.
     2  package config
     3  
     4  import (
     5  	"encoding/asn1"
     6  	"encoding/json"
     7  	"errors"
     8  	"fmt"
     9  	"github.com/hellobchain/newcryptosm/tls"
    10  	"github.com/hellobchain/newcryptosm/x509"
    11  	"io/ioutil"
    12  	"regexp"
    13  	"strconv"
    14  	"strings"
    15  	"time"
    16  
    17  	"github.com/hellobchain/third_party/cloudflare/cfssl/auth"
    18  	cferr "github.com/hellobchain/third_party/cloudflare/cfssl/errors"
    19  	"github.com/hellobchain/third_party/cloudflare/cfssl/helpers"
    20  	"github.com/hellobchain/third_party/cloudflare/cfssl/log"
    21  	ocspConfig "github.com/hellobchain/third_party/cloudflare/cfssl/ocsp/config"
    22  )
    23  
    24  // A CSRWhitelist stores booleans for fields in the CSR. If a CSRWhitelist is
    25  // not present in a SigningProfile, all of these fields may be copied from the
    26  // CSR into the signed certificate. If a CSRWhitelist *is* present in a
    27  // SigningProfile, only those fields with a `true` value in the CSRWhitelist may
    28  // be copied from the CSR to the signed certificate. Note that some of these
    29  // fields, like Subject, can be provided or partially provided through the API.
    30  // Since API clients are expected to be trusted, but CSRs are not, fields
    31  // provided through the API are not subject to whitelisting through this
    32  // mechanism.
    33  type CSRWhitelist struct {
    34  	Subject, PublicKeyAlgorithm, PublicKey, SignatureAlgorithm bool
    35  	DNSNames, IPAddresses, EmailAddresses                      bool
    36  }
    37  
    38  // OID is our own version of asn1's ObjectIdentifier, so we can define a custom
    39  // JSON marshal / unmarshal.
    40  type OID asn1.ObjectIdentifier
    41  
    42  // CertificatePolicy represents the ASN.1 PolicyInformation structure from
    43  // https://tools.ietf.org/html/rfc3280.html#page-106.
    44  // Valid values of Type are "id-qt-unotice" and "id-qt-cps"
    45  type CertificatePolicy struct {
    46  	ID         OID
    47  	Qualifiers []CertificatePolicyQualifier
    48  }
    49  
    50  // CertificatePolicyQualifier represents a single qualifier from an ASN.1
    51  // PolicyInformation structure.
    52  type CertificatePolicyQualifier struct {
    53  	Type  string
    54  	Value string
    55  }
    56  
    57  // AuthRemote is an authenticated remote signer.
    58  type AuthRemote struct {
    59  	RemoteName  string `json:"remote"`
    60  	AuthKeyName string `json:"auth_key"`
    61  }
    62  
    63  // CAConstraint specifies various CA constraints on the signed certificate.
    64  // CAConstraint would verify against (and override) the CA
    65  // extensions in the given CSR.
    66  type CAConstraint struct {
    67  	IsCA           bool `json:"is_ca"`
    68  	MaxPathLen     int  `json:"max_path_len"`
    69  	MaxPathLenZero bool `json:"max_path_len_zero"`
    70  }
    71  
    72  // A SigningProfile stores information that the CA needs to store
    73  // signature policy.
    74  type SigningProfile struct {
    75  	Usage               []string     `json:"usages"`
    76  	IssuerURL           []string     `json:"issuer_urls"`
    77  	OCSP                string       `json:"ocsp_url"`
    78  	CRL                 string       `json:"crl_url"`
    79  	CAConstraint        CAConstraint `json:"ca_constraint"`
    80  	OCSPNoCheck         bool         `json:"ocsp_no_check"`
    81  	ExpiryString        string       `json:"expiry"`
    82  	BackdateString      string       `json:"backdate"`
    83  	AuthKeyName         string       `json:"auth_key"`
    84  	RemoteName          string       `json:"remote"`
    85  	NotBefore           time.Time    `json:"not_before"`
    86  	NotAfter            time.Time    `json:"not_after"`
    87  	NameWhitelistString string       `json:"name_whitelist"`
    88  	AuthRemote          AuthRemote   `json:"auth_remote"`
    89  	CTLogServers        []string     `json:"ct_log_servers"`
    90  	AllowedExtensions   []OID        `json:"allowed_extensions"`
    91  	CertStore           string       `json:"cert_store"`
    92  
    93  	Policies                    []CertificatePolicy
    94  	Expiry                      time.Duration
    95  	Backdate                    time.Duration
    96  	Provider                    auth.Provider
    97  	RemoteProvider              auth.Provider
    98  	RemoteServer                string
    99  	RemoteCAs                   *x509.CertPool
   100  	ClientCert                  *tls.Certificate
   101  	CSRWhitelist                *CSRWhitelist
   102  	NameWhitelist               *regexp.Regexp
   103  	ExtensionWhitelist          map[string]bool
   104  	ClientProvidesSerialNumbers bool
   105  }
   106  
   107  // UnmarshalJSON unmarshals a JSON string into an OID.
   108  func (oid *OID) UnmarshalJSON(data []byte) (err error) {
   109  	if data[0] != '"' || data[len(data)-1] != '"' {
   110  		return errors.New("OID JSON string not wrapped in quotes." + string(data))
   111  	}
   112  	data = data[1 : len(data)-1]
   113  	parsedOid, err := parseObjectIdentifier(string(data))
   114  	if err != nil {
   115  		return err
   116  	}
   117  	*oid = OID(parsedOid)
   118  	return
   119  }
   120  
   121  // MarshalJSON marshals an oid into a JSON string.
   122  func (oid OID) MarshalJSON() ([]byte, error) {
   123  	return []byte(fmt.Sprintf(`"%v"`, asn1.ObjectIdentifier(oid))), nil
   124  }
   125  
   126  func parseObjectIdentifier(oidString string) (oid asn1.ObjectIdentifier, err error) {
   127  	validOID, err := regexp.MatchString("\\d(\\.\\d+)*", oidString)
   128  	if err != nil {
   129  		return
   130  	}
   131  	if !validOID {
   132  		err = errors.New("Invalid OID")
   133  		return
   134  	}
   135  
   136  	segments := strings.Split(oidString, ".")
   137  	oid = make(asn1.ObjectIdentifier, len(segments))
   138  	for i, intString := range segments {
   139  		oid[i], err = strconv.Atoi(intString)
   140  		if err != nil {
   141  			return
   142  		}
   143  	}
   144  	return
   145  }
   146  
   147  const timeFormat = "2006-01-02T15:04:05"
   148  
   149  // populate is used to fill in the fields that are not in JSON
   150  //
   151  // First, the ExpiryString parameter is needed to parse
   152  // expiration timestamps from JSON. The JSON decoder is not able to
   153  // decode a string time duration to a time.Duration, so this is called
   154  // when loading the configuration to properly parse and fill out the
   155  // Expiry parameter.
   156  // This function is also used to create references to the auth key
   157  // and default remote for the profile.
   158  // It returns true if ExpiryString is a valid representation of a
   159  // time.Duration, and the AuthKeyString and RemoteName point to
   160  // valid objects. It returns false otherwise.
   161  func (p *SigningProfile) populate(cfg *Config) error {
   162  	if p == nil {
   163  		return cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy, errors.New("can't parse nil profile"))
   164  	}
   165  
   166  	var err error
   167  	if p.RemoteName == "" && p.AuthRemote.RemoteName == "" {
   168  		log.Debugf("parse expiry in profile")
   169  		if p.ExpiryString == "" {
   170  			return cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy, errors.New("empty expiry string"))
   171  		}
   172  
   173  		dur, err := time.ParseDuration(p.ExpiryString)
   174  		if err != nil {
   175  			return cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy, err)
   176  		}
   177  
   178  		log.Debugf("expiry is valid")
   179  		p.Expiry = dur
   180  
   181  		if p.BackdateString != "" {
   182  			dur, err = time.ParseDuration(p.BackdateString)
   183  			if err != nil {
   184  				return cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy, err)
   185  			}
   186  
   187  			p.Backdate = dur
   188  		}
   189  
   190  		if !p.NotBefore.IsZero() && !p.NotAfter.IsZero() && p.NotAfter.Before(p.NotBefore) {
   191  			return cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy, err)
   192  		}
   193  
   194  		if len(p.Policies) > 0 {
   195  			for _, policy := range p.Policies {
   196  				for _, qualifier := range policy.Qualifiers {
   197  					if qualifier.Type != "" && qualifier.Type != "id-qt-unotice" && qualifier.Type != "id-qt-cps" {
   198  						return cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy,
   199  							errors.New("invalid policy qualifier type"))
   200  					}
   201  				}
   202  			}
   203  		}
   204  	} else if p.RemoteName != "" {
   205  		log.Debug("match remote in profile to remotes section")
   206  		if p.AuthRemote.RemoteName != "" {
   207  			log.Error("profile has both a remote and an auth remote specified")
   208  			return cferr.New(cferr.PolicyError, cferr.InvalidPolicy)
   209  		}
   210  		if remote := cfg.Remotes[p.RemoteName]; remote != "" {
   211  			if err := p.updateRemote(remote); err != nil {
   212  				return err
   213  			}
   214  		} else {
   215  			return cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy,
   216  				errors.New("failed to find remote in remotes section"))
   217  		}
   218  	} else {
   219  		log.Debug("match auth remote in profile to remotes section")
   220  		if remote := cfg.Remotes[p.AuthRemote.RemoteName]; remote != "" {
   221  			if err := p.updateRemote(remote); err != nil {
   222  				return err
   223  			}
   224  		} else {
   225  			return cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy,
   226  				errors.New("failed to find remote in remotes section"))
   227  		}
   228  	}
   229  
   230  	if p.AuthKeyName != "" {
   231  		log.Debug("match auth key in profile to auth_keys section")
   232  		if key, ok := cfg.AuthKeys[p.AuthKeyName]; ok == true {
   233  			if key.Type == "standard" {
   234  				p.Provider, err = auth.New(key.Key, nil)
   235  				if err != nil {
   236  					log.Debugf("failed to create new standard auth provider: %v", err)
   237  					return cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy,
   238  						errors.New("failed to create new standard auth provider"))
   239  				}
   240  			} else {
   241  				log.Debugf("unknown authentication type %v", key.Type)
   242  				return cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy,
   243  					errors.New("unknown authentication type"))
   244  			}
   245  		} else {
   246  			return cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy,
   247  				errors.New("failed to find auth_key in auth_keys section"))
   248  		}
   249  	}
   250  
   251  	if p.AuthRemote.AuthKeyName != "" {
   252  		log.Debug("match auth remote key in profile to auth_keys section")
   253  		if key, ok := cfg.AuthKeys[p.AuthRemote.AuthKeyName]; ok == true {
   254  			if key.Type == "standard" {
   255  				p.RemoteProvider, err = auth.New(key.Key, nil)
   256  				if err != nil {
   257  					log.Debugf("failed to create new standard auth provider: %v", err)
   258  					return cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy,
   259  						errors.New("failed to create new standard auth provider"))
   260  				}
   261  			} else {
   262  				log.Debugf("unknown authentication type %v", key.Type)
   263  				return cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy,
   264  					errors.New("unknown authentication type"))
   265  			}
   266  		} else {
   267  			return cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy,
   268  				errors.New("failed to find auth_remote's auth_key in auth_keys section"))
   269  		}
   270  	}
   271  
   272  	if p.NameWhitelistString != "" {
   273  		log.Debug("compiling whitelist regular expression")
   274  		rule, err := regexp.Compile(p.NameWhitelistString)
   275  		if err != nil {
   276  			return cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy,
   277  				errors.New("failed to compile name whitelist section"))
   278  		}
   279  		p.NameWhitelist = rule
   280  	}
   281  
   282  	p.ExtensionWhitelist = map[string]bool{}
   283  	for _, oid := range p.AllowedExtensions {
   284  		p.ExtensionWhitelist[asn1.ObjectIdentifier(oid).String()] = true
   285  	}
   286  
   287  	return nil
   288  }
   289  
   290  // updateRemote takes a signing profile and initializes the remote server object
   291  // to the hostname:port combination sent by remote.
   292  func (p *SigningProfile) updateRemote(remote string) error {
   293  	if remote != "" {
   294  		p.RemoteServer = remote
   295  	}
   296  	return nil
   297  }
   298  
   299  // OverrideRemotes takes a signing configuration and updates the remote server object
   300  // to the hostname:port combination sent by remote
   301  func (p *Signing) OverrideRemotes(remote string) error {
   302  	if remote != "" {
   303  		var err error
   304  		for _, profile := range p.Profiles {
   305  			err = profile.updateRemote(remote)
   306  			if err != nil {
   307  				return err
   308  			}
   309  		}
   310  		err = p.Default.updateRemote(remote)
   311  		if err != nil {
   312  			return err
   313  		}
   314  	}
   315  	return nil
   316  }
   317  
   318  // SetClientCertKeyPairFromFile updates the properties to set client certificates for mutual
   319  // authenticated TLS remote requests
   320  func (p *Signing) SetClientCertKeyPairFromFile(certFile string, keyFile string) error {
   321  	if certFile != "" && keyFile != "" {
   322  		cert, err := helpers.LoadClientCertificate(certFile, keyFile)
   323  		if err != nil {
   324  			return err
   325  		}
   326  		for _, profile := range p.Profiles {
   327  			profile.ClientCert = cert
   328  		}
   329  		p.Default.ClientCert = cert
   330  	}
   331  	return nil
   332  }
   333  
   334  // SetRemoteCAsFromFile reads root CAs from file and updates the properties to set remote CAs for TLS
   335  // remote requests
   336  func (p *Signing) SetRemoteCAsFromFile(caFile string) error {
   337  	if caFile != "" {
   338  		remoteCAs, err := helpers.LoadPEMCertPool(caFile)
   339  		if err != nil {
   340  			return err
   341  		}
   342  		p.SetRemoteCAs(remoteCAs)
   343  	}
   344  	return nil
   345  }
   346  
   347  // SetRemoteCAs updates the properties to set remote CAs for TLS
   348  // remote requests
   349  func (p *Signing) SetRemoteCAs(remoteCAs *x509.CertPool) {
   350  	for _, profile := range p.Profiles {
   351  		profile.RemoteCAs = remoteCAs
   352  	}
   353  	p.Default.RemoteCAs = remoteCAs
   354  }
   355  
   356  // NeedsRemoteSigner returns true if one of the profiles has a remote set
   357  func (p *Signing) NeedsRemoteSigner() bool {
   358  	for _, profile := range p.Profiles {
   359  		if profile.RemoteServer != "" {
   360  			return true
   361  		}
   362  	}
   363  
   364  	if p.Default.RemoteServer != "" {
   365  		return true
   366  	}
   367  
   368  	return false
   369  }
   370  
   371  // NeedsLocalSigner returns true if one of the profiles doe not have a remote set
   372  func (p *Signing) NeedsLocalSigner() bool {
   373  	for _, profile := range p.Profiles {
   374  		if profile.RemoteServer == "" {
   375  			return true
   376  		}
   377  	}
   378  
   379  	if p.Default.RemoteServer == "" {
   380  		return true
   381  	}
   382  
   383  	return false
   384  }
   385  
   386  // Usages parses the list of key uses in the profile, translating them
   387  // to a list of X.509 key usages and extended key usages.  The unknown
   388  // uses are collected into a slice that is also returned.
   389  func (p *SigningProfile) Usages() (ku x509.KeyUsage, eku []x509.ExtKeyUsage, unk []string) {
   390  	for _, keyUse := range p.Usage {
   391  		if kuse, ok := KeyUsage[keyUse]; ok {
   392  			ku |= kuse
   393  		} else if ekuse, ok := ExtKeyUsage[keyUse]; ok {
   394  			eku = append(eku, ekuse)
   395  		} else {
   396  			unk = append(unk, keyUse)
   397  		}
   398  	}
   399  	return
   400  }
   401  
   402  // A valid profile must be a valid local profile or a valid remote profile.
   403  // A valid local profile has defined at least key usages to be used, and a
   404  // valid local default profile has defined at least a default expiration.
   405  // A valid remote profile (default or not) has remote signer initialized.
   406  // In addition, a remote profile must has a valid auth provider if auth
   407  // key defined.
   408  func (p *SigningProfile) validProfile(isDefault bool) bool {
   409  	if p == nil {
   410  		return false
   411  	}
   412  
   413  	if p.AuthRemote.RemoteName == "" && p.AuthRemote.AuthKeyName != "" {
   414  		log.Debugf("invalid auth remote profile: no remote signer specified")
   415  		return false
   416  	}
   417  
   418  	if p.RemoteName != "" {
   419  		log.Debugf("validate remote profile")
   420  
   421  		if p.RemoteServer == "" {
   422  			log.Debugf("invalid remote profile: no remote signer specified")
   423  			return false
   424  		}
   425  
   426  		if p.AuthKeyName != "" && p.Provider == nil {
   427  			log.Debugf("invalid remote profile: auth key name is defined but no auth provider is set")
   428  			return false
   429  		}
   430  
   431  		if p.AuthRemote.RemoteName != "" {
   432  			log.Debugf("invalid remote profile: auth remote is also specified")
   433  			return false
   434  		}
   435  	} else if p.AuthRemote.RemoteName != "" {
   436  		log.Debugf("validate auth remote profile")
   437  		if p.RemoteServer == "" {
   438  			log.Debugf("invalid auth remote profile: no remote signer specified")
   439  			return false
   440  		}
   441  
   442  		if p.AuthRemote.AuthKeyName == "" || p.RemoteProvider == nil {
   443  			log.Debugf("invalid auth remote profile: no auth key is defined")
   444  			return false
   445  		}
   446  	} else {
   447  		log.Debugf("validate local profile")
   448  		if !isDefault {
   449  			if len(p.Usage) == 0 {
   450  				log.Debugf("invalid local profile: no usages specified")
   451  				return false
   452  			} else if _, _, unk := p.Usages(); len(unk) == len(p.Usage) {
   453  				log.Debugf("invalid local profile: no valid usages")
   454  				return false
   455  			}
   456  		} else {
   457  			if p.Expiry == 0 {
   458  				log.Debugf("invalid local profile: no expiry set")
   459  				return false
   460  			}
   461  		}
   462  	}
   463  
   464  	log.Debugf("profile is valid")
   465  	return true
   466  }
   467  
   468  // This checks if the SigningProfile object contains configurations that are only effective with a local signer
   469  // which has access to CA private key.
   470  func (p *SigningProfile) hasLocalConfig() bool {
   471  	if p.Usage != nil ||
   472  		p.IssuerURL != nil ||
   473  		p.OCSP != "" ||
   474  		p.ExpiryString != "" ||
   475  		p.BackdateString != "" ||
   476  		p.CAConstraint.IsCA != false ||
   477  		!p.NotBefore.IsZero() ||
   478  		!p.NotAfter.IsZero() ||
   479  		p.NameWhitelistString != "" ||
   480  		len(p.CTLogServers) != 0 {
   481  		return true
   482  	}
   483  	return false
   484  }
   485  
   486  // warnSkippedSettings prints a log warning message about skipped settings
   487  // in a SigningProfile, usually due to remote signer.
   488  func (p *Signing) warnSkippedSettings() {
   489  	const warningMessage = `The configuration value by "usages", "issuer_urls", "ocsp_url", "crl_url", "ca_constraint", "expiry", "backdate", "not_before", "not_after", "cert_store" and "ct_log_servers" are skipped`
   490  	if p == nil {
   491  		return
   492  	}
   493  
   494  	if (p.Default.RemoteName != "" || p.Default.AuthRemote.RemoteName != "") && p.Default.hasLocalConfig() {
   495  		log.Warning("default profile points to a remote signer: ", warningMessage)
   496  	}
   497  
   498  	for name, profile := range p.Profiles {
   499  		if (profile.RemoteName != "" || profile.AuthRemote.RemoteName != "") && profile.hasLocalConfig() {
   500  			log.Warningf("Profiles[%s] points to a remote signer: %s", name, warningMessage)
   501  		}
   502  	}
   503  }
   504  
   505  // Signing codifies the signature configuration policy for a CA.
   506  type Signing struct {
   507  	Profiles map[string]*SigningProfile `json:"profiles"`
   508  	Default  *SigningProfile            `json:"default"`
   509  }
   510  
   511  // Config stores configuration information for the CA.
   512  type Config struct {
   513  	Signing  *Signing           `json:"signing"`
   514  	OCSP     *ocspConfig.Config `json:"ocsp"`
   515  	AuthKeys map[string]AuthKey `json:"auth_keys,omitempty"`
   516  	Remotes  map[string]string  `json:"remotes,omitempty"`
   517  }
   518  
   519  // Valid ensures that Config is a valid configuration. It should be
   520  // called immediately after parsing a configuration file.
   521  func (c *Config) Valid() bool {
   522  	return c.Signing.Valid()
   523  }
   524  
   525  // Valid checks the signature policies, ensuring they are valid
   526  // policies. A policy is valid if it has defined at least key usages
   527  // to be used, and a valid default profile has defined at least a
   528  // default expiration.
   529  func (p *Signing) Valid() bool {
   530  	if p == nil {
   531  		return false
   532  	}
   533  
   534  	log.Debugf("validating configuration")
   535  	if !p.Default.validProfile(true) {
   536  		log.Debugf("default profile is invalid")
   537  		return false
   538  	}
   539  
   540  	for _, sp := range p.Profiles {
   541  		if !sp.validProfile(false) {
   542  			log.Debugf("invalid profile")
   543  			return false
   544  		}
   545  	}
   546  
   547  	p.warnSkippedSettings()
   548  
   549  	return true
   550  }
   551  
   552  // KeyUsage contains a mapping of string names to key usages.
   553  var KeyUsage = map[string]x509.KeyUsage{
   554  	"signing":             x509.KeyUsageDigitalSignature,
   555  	"digital signature":   x509.KeyUsageDigitalSignature,
   556  	"content committment": x509.KeyUsageContentCommitment,
   557  	"key encipherment":    x509.KeyUsageKeyEncipherment,
   558  	"key agreement":       x509.KeyUsageKeyAgreement,
   559  	"data encipherment":   x509.KeyUsageDataEncipherment,
   560  	"cert sign":           x509.KeyUsageCertSign,
   561  	"crl sign":            x509.KeyUsageCRLSign,
   562  	"encipher only":       x509.KeyUsageEncipherOnly,
   563  	"decipher only":       x509.KeyUsageDecipherOnly,
   564  }
   565  
   566  // ExtKeyUsage contains a mapping of string names to extended key
   567  // usages.
   568  var ExtKeyUsage = map[string]x509.ExtKeyUsage{
   569  	"any":              x509.ExtKeyUsageAny,
   570  	"server auth":      x509.ExtKeyUsageServerAuth,
   571  	"client auth":      x509.ExtKeyUsageClientAuth,
   572  	"code signing":     x509.ExtKeyUsageCodeSigning,
   573  	"email protection": x509.ExtKeyUsageEmailProtection,
   574  	"s/mime":           x509.ExtKeyUsageEmailProtection,
   575  	"ipsec end system": x509.ExtKeyUsageIPSECEndSystem,
   576  	"ipsec tunnel":     x509.ExtKeyUsageIPSECTunnel,
   577  	"ipsec user":       x509.ExtKeyUsageIPSECUser,
   578  	"timestamping":     x509.ExtKeyUsageTimeStamping,
   579  	"ocsp signing":     x509.ExtKeyUsageOCSPSigning,
   580  	"microsoft sgc":    x509.ExtKeyUsageMicrosoftServerGatedCrypto,
   581  	"netscape sgc":     x509.ExtKeyUsageNetscapeServerGatedCrypto,
   582  }
   583  
   584  // An AuthKey contains an entry for a key used for authentication.
   585  type AuthKey struct {
   586  	// Type contains information needed to select the appropriate
   587  	// constructor. For example, "standard" for HMAC-SHA-256,
   588  	// "standard-ip" for HMAC-SHA-256 incorporating the client's
   589  	// IP.
   590  	Type string `json:"type"`
   591  	// Key contains the key information, such as a hex-encoded
   592  	// HMAC key.
   593  	Key string `json:"key"`
   594  }
   595  
   596  // DefaultConfig returns a default configuration specifying basic key
   597  // usage and a 1 year expiration time. The key usages chosen are
   598  // signing, key encipherment, client auth and server auth.
   599  func DefaultConfig() *SigningProfile {
   600  	d := helpers.OneYear
   601  	return &SigningProfile{
   602  		Usage:        []string{"signing", "key encipherment", "server auth", "client auth"},
   603  		Expiry:       d,
   604  		ExpiryString: "8760h",
   605  	}
   606  }
   607  
   608  // LoadFile attempts to load the configuration file stored at the path
   609  // and returns the configuration. On error, it returns nil.
   610  func LoadFile(path string) (*Config, error) {
   611  	log.Debugf("loading configuration file from %s", path)
   612  	if path == "" {
   613  		return nil, cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy, errors.New("invalid path"))
   614  	}
   615  
   616  	body, err := ioutil.ReadFile(path)
   617  	if err != nil {
   618  		return nil, cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy, errors.New("could not read configuration file"))
   619  	}
   620  
   621  	return LoadConfig(body)
   622  }
   623  
   624  // LoadConfig attempts to load the configuration from a byte slice.
   625  // On error, it returns nil.
   626  func LoadConfig(config []byte) (*Config, error) {
   627  	var cfg = &Config{}
   628  	err := json.Unmarshal(config, &cfg)
   629  	if err != nil {
   630  		return nil, cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy,
   631  			errors.New("failed to unmarshal configuration: "+err.Error()))
   632  	}
   633  
   634  	if cfg.Signing == nil {
   635  		return nil, errors.New("No \"signing\" field present")
   636  	}
   637  
   638  	if cfg.Signing.Default == nil {
   639  		log.Debugf("no default given: using default config")
   640  		cfg.Signing.Default = DefaultConfig()
   641  	} else {
   642  		if err := cfg.Signing.Default.populate(cfg); err != nil {
   643  			return nil, err
   644  		}
   645  	}
   646  
   647  	for k := range cfg.Signing.Profiles {
   648  		if err := cfg.Signing.Profiles[k].populate(cfg); err != nil {
   649  			return nil, err
   650  		}
   651  	}
   652  
   653  	if !cfg.Valid() {
   654  		return nil, cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy, errors.New("invalid configuration"))
   655  	}
   656  
   657  	log.Debugf("configuration ok")
   658  	return cfg, nil
   659  }