Пример #1
0
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)
}
Пример #2
0
// 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
}
Пример #3
0
// 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)
}
Пример #4
0
// 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
}
Пример #6
0
// 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
}