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 }