// NewCertGeneratorHandler builds a new handler for generating // certificates directly from certificate requests; the validator covers // the certificate request and the CA's key and certificate are used to // sign the generated request. If remote is not an empty string, the // handler will send signature requests to the CFSSL instance contained // in remote. func NewCertGeneratorHandler(validator Validator, caFile, caKeyFile string, policy *config.Signing) (http.Handler, error) { var err error log.Info("setting up new generator / signer") cg := new(CertGeneratorHandler) if policy == nil { policy = &config.Signing{ Default: config.DefaultConfig(), Profiles: nil, } } root := universal.Root{ Config: map[string]string{ "ca-file": caFile, "ca-key-file": caKeyFile, }, } if cg.signer, err = universal.NewSigner(root, policy); err != nil { log.Errorf("setting up signer failed: %v", err) return nil, err } cg.generator = &csr.Generator{Validator: validator} return api.HTTPHandler{Handler: cg, Methods: []string{"POST"}}, nil }
// NewSigner generates a new certificate signer from a Root structure. // This is one of two standard signers: local or remote. If the root // structure specifies a force remote, then a remote signer is created, // otherwise either a remote or local signer is generated based on the // policy. For a local signer, the CertFile and KeyFile need to be // defined in Root. func NewSigner(root Root, policy *config.Signing) (signer.Signer, error) { if policy == nil { policy = &config.Signing{ Profiles: map[string]*config.SigningProfile{}, Default: config.DefaultConfig(), } } if !policy.Valid() { return nil, cferr.New(cferr.PolicyError, cferr.InvalidPolicy) } var s signer.Signer var err error if root.ForceRemote { s, err = remote.NewSigner(policy) } else { if policy.NeedsLocalSigner() && policy.NeedsRemoteSigner() { // Currently we don't support a hybrid signer return nil, cferr.New(cferr.PolicyError, cferr.InvalidPolicy) } if policy.NeedsLocalSigner() { // shouldProvide indicates whether the // function *should* have produced a key. If // it's true, we should use the signer and // error returned. Otherwise, keep looking for // signers. var shouldProvide bool // localSignerList is defined in the // universal_signers*.go files. These activate // and deactivate signers based on build // flags; for example, // universal_signers_pkcs11.go contains a list // of valid signers when PKCS #11 is turned // on. for _, possibleSigner := range localSignerList { s, shouldProvide, err = possibleSigner(&root, policy) if shouldProvide { break } } if s == nil { err = cferr.New(cferr.PrivateKeyError, cferr.Unknown) } } if policy.NeedsRemoteSigner() { s, err = remote.NewSigner(policy) } } return s, err }
// NewSigner creates a new Signer directly from a // private key and certificate, with optional policy. func NewSigner(priv crypto.Signer, cert *x509.Certificate, sigAlgo x509.SignatureAlgorithm, policy *config.Signing) (*Signer, error) { if policy == nil { policy = &config.Signing{ Profiles: map[string]*config.SigningProfile{}, Default: config.DefaultConfig()} } if !policy.Valid() { return nil, cferr.New(cferr.PolicyError, cferr.InvalidPolicy) } return &Signer{ ca: cert, priv: priv, sigAlgo: sigAlgo, policy: policy, }, nil }
func TestRebundleExpiring(t *testing.T) { // make a policy that generate a cert expires in one hour. expiry := 1 * time.Hour policy := &config.Signing{ Profiles: map[string]*config.SigningProfile{ "expireIn1Hour": &config.SigningProfile{ Usage: []string{"cert sign"}, Expiry: expiry, CA: true, }, }, Default: config.DefaultConfig(), } // Generate a intermediate cert that expires in one hour. expiringPEM := createInterCert(t, interL1CSR, policy, "expireIn1Hour") rootBundlePEM, _ := ioutil.ReadFile(testCFSSLRootBundle) // Use the expiring intermediate to initiate a bundler. bundler, err := NewBundlerFromPEM(rootBundlePEM, expiringPEM) if err != nil { t.Fatalf("bundle failed. %s", err.Error()) } newBundle, err := bundler.BundleFromPEMorDER(expiredBundlePEM, nil, Optimal, "") if err != nil { t.Fatalf("Re-bundle failed. %s", err.Error()) } // Check the bundle content. newChain := newBundle.Chain if len(newChain) != 2 { t.Fatalf("Expected bundle chain length is 2. Got %d.", len(newChain)) } // The status must be {Code: ExpiringBit is set, IsRebundled:true, ExpiringSKIs:{"8860BA18A477B841041BD5EF7751C25B14BA203F"}} if len(newBundle.Status.ExpiringSKIs) != 1 || !newBundle.Status.IsRebundled || newBundle.Status.Code&errors.BundleExpiringBit == 0 { t.Fatal("Rebundle Status is incorrect.") } expectedSKI := "8860BA18A477B841041BD5EF7751C25B14BA203F" if newBundle.Status.ExpiringSKIs[0] != expectedSKI { t.Fatalf("Expected expiring cert SKI is %s, got %s\n", expectedSKI, newBundle.Status.ExpiringSKIs[0]) } }
func selfSignMain(args []string, c cli.Config) (err error) { if c.Hostname == "" && !c.IsCA { c.Hostname, args, err = cli.PopFirstArgument(args) if err != nil { return } } csrFile, args, err := cli.PopFirstArgument(args) if err != nil { return } csrFileBytes, err := cli.ReadStdin(csrFile) if err != nil { return } var req csr.CertificateRequest err = json.Unmarshal(csrFileBytes, &req) if err != nil { return } var key, csrPEM []byte g := &csr.Generator{Validator: genkey.Validator} csrPEM, key, err = g.ProcessRequest(&req) if err != nil { key = nil return } priv, err := helpers.ParsePrivateKeyPEM(key) if err != nil { key = nil return } var profile *config.SigningProfile // If there is a config, use its signing policy. Otherwise, leave policy == nil // and NewSigner will use DefaultConfig(). if c.CFG != nil { if c.Profile != "" && c.CFG.Signing.Profiles != nil { profile = c.CFG.Signing.Profiles[c.Profile] } } if profile == nil { profile = config.DefaultConfig() profile.Expiry = 2190 * time.Hour } cert, err := selfsign.Sign(priv, csrPEM, profile) if err != nil { key = nil priv = nil return } fmt.Fprintf(os.Stderr, `*** WARNING *** Self-signed certificates are dangerous. Use this self-signed certificate at your own risk. It is strongly recommended that these certificates NOT be used in production. *** WARNING *** `) cli.PrintCert(key, csrPEM, cert) return }