func revokeMain(args []string, c cli.Config) error { if len(args) > 0 { return errors.New("argument is provided but not defined; please refer to the usage by flag -h") } if len(c.Serial) == 0 { return errors.New("serial number is required but not provided") } if c.DBConfigFile == "" { return errors.New("need DB config file (provide with -db-config)") } db, err := dbconf.DBFromConfig(c.DBConfigFile) if err != nil { return err } dbAccessor := sql.NewAccessor(db) reasonCode, err := ocsp.ReasonStringToCode(c.Reason) if err != nil { log.Error("Invalid reason code: ", err) return err } return dbAccessor.RevokeCertificate(c.Serial, reasonCode) }
// LoadRoot parses a config structure into a Root structure func LoadRoot(cfg map[string]string) (*Root, error) { var root Root var err error spec, ok := cfg["private"] if !ok { return nil, ErrMissingPrivateKey } certPath, ok := cfg["certificate"] if !ok { return nil, ErrMissingCertificatePath } configPath, ok := cfg["config"] if !ok { return nil, ErrMissingConfigPath } root.PrivateKey, err = parsePrivateKeySpec(spec, cfg) if err != nil { return nil, err } in, err := ioutil.ReadFile(certPath) if err != nil { return nil, err } root.Certificate, err = helpers.ParseCertificatePEM(in) if err != nil { return nil, err } conf, err := config.LoadFile(configPath) if err != nil { return nil, err } root.Config = conf.Signing nets := cfg["nets"] if nets != "" { root.ACL, err = parseACL(nets) if err != nil { return nil, err } } dbConfig := cfg["dbconfig"] if dbConfig != "" { db, err := dbconf.DBFromConfig(dbConfig) if err != nil { return nil, err } root.DB = db } return &root, nil }
// SignerFromConfig takes the Config and creates the appropriate // signer.Signer object func SignerFromConfig(c cli.Config) (s signer.Signer, err error) { var db *sqlx.DB if c.DBConfigFile != "" { db, err = dbconf.DBFromConfig(c.DBConfigFile) if err != nil { return nil, err } } return SignerFromConfigAndDB(c, db) }
// serverMain is the command line entry point to the API server. It sets up a // new HTTP server to handle sign, bundle, and validate requests. func serverMain(args []string, c cli.Config) error { conf = c // serve doesn't support arguments. if len(args) > 0 { return errors.New("argument is provided but not defined; please refer to the usage by flag -h") } bundler.IntermediateStash = conf.IntDir var err error if err = ubiquity.LoadPlatforms(conf.Metadata); err != nil { return err } if c.DBConfigFile != "" { db, err = dbconf.DBFromConfig(c.DBConfigFile) if err != nil { return err } } log.Info("Initializing signer") if s, err = sign.SignerFromConfigAndDB(c, db); err != nil { log.Warningf("couldn't initialize signer: %v", err) } if ocspSigner, err = ocspsign.SignerFromConfig(c); err != nil { log.Warningf("couldn't initialize ocsp signer: %v", err) } registerHandlers() addr := net.JoinHostPort(conf.Address, strconv.Itoa(conf.Port)) if conf.TLSCertFile == "" || conf.TLSKeyFile == "" { log.Info("Now listening on ", addr) return http.ListenAndServe(addr, nil) } log.Info("Now listening on https://", addr) return http.ListenAndServeTLS(addr, conf.TLSCertFile, conf.TLSKeyFile, nil) }
// ocspdumpMain is the main CLI of OCSP dump functionality. func ocspdumpMain(args []string, c cli.Config) error { if c.DBConfigFile == "" { return errors.New("need DB config file (provide with -db-config)") } db, err := dbconf.DBFromConfig(c.DBConfigFile) if err != nil { return err } dbAccessor := sql.NewAccessor(db) records, err := dbAccessor.GetUnexpiredOCSPs() if err != nil { return err } for _, certRecord := range records { fmt.Printf("%s\n", base64.StdEncoding.EncodeToString([]byte(certRecord.Body))) } return nil }
// serverMain is the command line entry point to the API server. It sets up a // new HTTP server to handle sign, bundle, and validate requests. func serverMain(args []string, c cli.Config) error { conf = c // serve doesn't support arguments. if len(args) > 0 { return errors.New("argument is provided but not defined; please refer to the usage by flag -h") } bundler.IntermediateStash = conf.IntDir var err error if err = ubiquity.LoadPlatforms(conf.Metadata); err != nil { return err } if c.DBConfigFile != "" { db, err = dbconf.DBFromConfig(c.DBConfigFile) if err != nil { return err } } log.Info("Initializing signer") if s, err = sign.SignerFromConfigAndDB(c, db); err != nil { log.Warningf("couldn't initialize signer: %v", err) } if ocspSigner, err = ocspsign.SignerFromConfig(c); err != nil { log.Warningf("couldn't initialize ocsp signer: %v", err) } registerHandlers() addr := net.JoinHostPort(conf.Address, strconv.Itoa(conf.Port)) if conf.TLSCertFile == "" || conf.TLSKeyFile == "" { log.Info("Now listening on ", addr) return http.ListenAndServe(addr, nil) } if conf.MutualTLSCAFile != "" { clientPool, err := helpers.LoadPEMCertPool(conf.MutualTLSCAFile) if err != nil { return fmt.Errorf("failed to load mutual TLS CA file: %s", err) } server := http.Server{ Addr: addr, TLSConfig: &tls.Config{ ClientAuth: tls.RequireAndVerifyClientCert, ClientCAs: clientPool, }, } if conf.MutualTLSCNRegex != "" { log.Debugf(`Requiring CN matches regex "%s" for client connections`, conf.MutualTLSCNRegex) re, err := regexp.Compile(conf.MutualTLSCNRegex) if err != nil { return fmt.Errorf("malformed CN regex: %s", err) } server.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if r != nil && r.TLS != nil && len(r.TLS.PeerCertificates) > 0 { if re.MatchString(r.TLS.PeerCertificates[0].Subject.CommonName) { http.DefaultServeMux.ServeHTTP(w, r) return } log.Warningf(`Rejected client cert CN "%s" does not match regex %s`, r.TLS.PeerCertificates[0].Subject.CommonName, conf.MutualTLSCNRegex) } http.Error(w, "Invalid CN", http.StatusForbidden) }) } log.Info("Now listening with mutual TLS on https://", addr) return server.ListenAndServeTLS(conf.TLSCertFile, conf.TLSKeyFile) } log.Info("Now listening on https://", addr) return http.ListenAndServeTLS(addr, conf.TLSCertFile, conf.TLSKeyFile, nil) }
// ocsprefreshMain is the main CLI of OCSP refresh functionality. func ocsprefreshMain(args []string, c cli.Config) error { if c.DBConfigFile == "" { return errors.New("need DB config file (provide with -db-config)") } if c.ResponderFile == "" { return errors.New("need responder certificate (provide with -responder)") } if c.ResponderKeyFile == "" { return errors.New("need responder key (provide with -responder-key)") } if c.CAFile == "" { return errors.New("need CA certificate (provide with -ca)") } s, err := SignerFromConfig(c) if err != nil { log.Critical("Unable to create OCSP signer: ", err) return err } db, err := dbconf.DBFromConfig(c.DBConfigFile) if err != nil { return err } dbAccessor := sql.NewAccessor(db) certs, err := dbAccessor.GetUnexpiredCertificates() if err != nil { return err } // Set an expiry timestamp for all certificates refreshed in this batch ocspExpiry := time.Now().Add(c.Interval) for _, certRecord := range certs { cert, err := helpers.ParseCertificatePEM([]byte(certRecord.PEM)) if err != nil { log.Critical("Unable to parse certificate: ", err) return err } req := ocsp.SignRequest{ Certificate: cert, Status: certRecord.Status, } if certRecord.Status == "revoked" { req.Reason = int(certRecord.Reason) req.RevokedAt = certRecord.RevokedAt } resp, err := s.Sign(req) if err != nil { log.Critical("Unable to sign OCSP response: ", err) return err } err = dbAccessor.UpsertOCSP(cert.SerialNumber.String(), hex.EncodeToString(cert.AuthorityKeyId), string(resp), ocspExpiry) if err != nil { log.Critical("Unable to save OCSP response: ", err) return err } } return nil }