func TestAuthSign(t *testing.T) { s := NewServer("1.1") testProvider, _ = auth.New(testKey, nil) testRequest := []byte(`testing 1 2 3`) as, _ := s.AuthSign(testRequest, testAD, testProvider) if as != nil { t.Fatal("fatal error with auth sign function") } }
func TestMain(m *testing.M) { caKeyPEM, _ := ioutil.ReadFile(caKeyFile) caKey, _ := helpers.ParsePrivateKeyPEM(caKeyPEM) caCertPEM, _ := ioutil.ReadFile(caCertFile) caCert, _ := helpers.ParseCertificatePEM(caCertPEM) // Create an online CFSSL instance // This is designed to mimic what LE plans to do authHandler, _ := auth.New(authKey, nil) policy := &cfsslConfig.Signing{ Profiles: map[string]*cfsslConfig.SigningProfile{ profileName: &cfsslConfig.SigningProfile{ Usage: []string{"server auth"}, CA: false, IssuerURL: []string{"http://not-example.com/issuer-url"}, OCSP: "http://not-example.com/ocsp", CRL: "http://not-example.com/crl", Policies: []asn1.ObjectIdentifier{ asn1.ObjectIdentifier{2, 23, 140, 1, 2, 1}, }, Expiry: 8760 * time.Hour, Backdate: time.Hour, Provider: authHandler, CSRWhitelist: &cfsslConfig.CSRWhitelist{ PublicKeyAlgorithm: true, PublicKey: true, SignatureAlgorithm: true, }, }, }, Default: &cfsslConfig.SigningProfile{ Expiry: time.Hour, }, } cfsslSigner, _ = local.NewSigner(caKey, caCert, x509.SHA256WithRSA, policy) signHandler, _ := apisign.NewAuthHandlerFromSigner(cfsslSigner) http.Handle("/api/v1/cfssl/authsign", signHandler) // This goroutine should get killed when main() return go (func() { http.ListenAndServe(hostPort, nil) })() os.Exit(m.Run()) }
// populate is used to fill in the fields that are not in JSON // // First, the ExpiryString parameter is needed to parse // expiration timestamps from JSON. The JSON decoder is not able to // decode a string time duration to a time.Duration, so this is called // when loading the configuration to properly parse and fill out the // Expiry parameter. // This function is also used to create references to the auth key // and default remote for the profile. // It returns true if ExpiryString is a valid representation of a // time.Duration, and the AuthKeyString and RemoteName point to // valid objects. It returns false otherwise. 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 == true { 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.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 } return nil }
// NewCertificateAuthorityImpl creates a CA that talks to a remote CFSSL // instance. (To use a local signer, simply instantiate CertificateAuthorityImpl // directly.) Communications with the CA are authenticated with MACs, // using CFSSL's authenticated signature scheme. A CA created in this way // issues for a single profile on the remote signer, which is indicated // by name in this constructor. func NewCertificateAuthorityImpl(cadb core.CertificateAuthorityDatabase, config Config) (*CertificateAuthorityImpl, error) { var ca *CertificateAuthorityImpl var err error logger := blog.GetAuditLogger() logger.Notice("Certificate Authority Starting") if config.SerialPrefix <= 0 || config.SerialPrefix >= 256 { err = errors.New("Must have a positive non-zero serial prefix less than 256 for CA.") return nil, err } // Create the remote signer localProfile := cfsslConfig.SigningProfile{ Expiry: time.Hour, // BOGUS: Required by CFSSL, but not used RemoteName: config.Server, // BOGUS: Only used as a flag by CFSSL RemoteServer: config.Server, UseSerialSeq: true, } localProfile.Provider, err = auth.New(config.AuthKey, nil) if err != nil { return nil, err } signer, err := remote.NewSigner(&cfsslConfig.Signing{Default: &localProfile}) if err != nil { return nil, err } issuer, err := loadIssuer(config.IssuerCert) if err != nil { return nil, err } // In test mode, load a private key from a file. // TODO: This should rely on the CFSSL config, to make it easy to use a key // from a file vs an HSM. https://github.com/letsencrypt/boulder/issues/163 issuerKey, err := loadIssuerKey(config.IssuerKey) if err != nil { return nil, err } // Set up our OCSP signer. Note this calls for both the issuer cert and the // OCSP signing cert, which are the same in our case. ocspSigner, err := ocsp.NewSigner(issuer, issuer, issuerKey, time.Hour*24*4) if err != nil { return nil, err } pa := policy.NewPolicyAuthorityImpl() ca = &CertificateAuthorityImpl{ Signer: signer, OCSPSigner: ocspSigner, profile: config.Profile, PA: pa, DB: cadb, Prefix: config.SerialPrefix, log: logger, NotAfter: issuer.NotAfter, } ca.ValidityPeriod, err = time.ParseDuration(config.Expiry) if err != nil { return nil, err } return ca, nil }
// populate is used to fill in the fields that are not in JSON // // First, the ExpiryString parameter is needed to parse // expiration timestamps from JSON. The JSON decoder is not able to // decode a string time duration to a time.Duration, so this is called // when loading the configuration to properly parse and fill out the // Expiry parameter. // This function is also used to create references to the auth key // and default remote for the profile. // It returns true if ExpiryString is a valid representation of a // time.Duration, and the AuthKeyString and RemoteName point to // valid objects. It returns false otherwise. 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 == "" { 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.PolicyStrings) > 0 { p.Policies = make([]asn1.ObjectIdentifier, len(p.PolicyStrings)) for i, oidString := range p.PolicyStrings { p.Policies[i], err = parseObjectIdentifier(oidString) if err != nil { return cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy, err) } } } } else { log.Debug("match remote in profile to remotes section") 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")) } } if p.AuthKeyName != "" { log.Debug("match auth key in profile to auth_keys section") if key, ok := cfg.AuthKeys[p.AuthKeyName]; ok == true { 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")) } } return nil }