// SignerFromConfigAndDB takes the Config and creates the appropriate // signer.Signer object with a specified db func SignerFromConfigAndDB(c cli.Config, db *sql.DB) (signer.Signer, error) { // If there is a config, use its signing policy. Otherwise create a default policy. var policy *config.Signing if c.CFG != nil { policy = c.CFG.Signing } else { policy = &config.Signing{ Profiles: map[string]*config.SigningProfile{}, Default: config.DefaultConfig(), } } // Make sure the policy reflects the new remote if c.Remote != "" { err := policy.OverrideRemotes(c.Remote) if err != nil { log.Infof("Invalid remote %v, reverting to configuration default", c.Remote) return nil, err } } s, err := universal.NewSigner(cli.RootFromConfig(&c), policy) if err != nil { return nil, err } if db != nil { dbAccessor := certsql.NewAccessor(db) s.SetDBAccessor(dbAccessor) } return s, nil }
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) }
// SignerFromConfigAndDB takes the Config and creates the appropriate // signer.Signer object with a specified db func SignerFromConfigAndDB(c cli.Config, db *sqlx.DB) (signer.Signer, error) { // If there is a config, use its signing policy. Otherwise create a default policy. var policy *config.Signing if c.CFG != nil { policy = c.CFG.Signing } else { policy = &config.Signing{ Profiles: map[string]*config.SigningProfile{}, Default: config.DefaultConfig(), } } // Make sure the policy reflects the new remote if c.Remote != "" { err := policy.OverrideRemotes(c.Remote) if err != nil { log.Infof("Invalid remote %v, reverting to configuration default", c.Remote) return nil, err } } if c.MutualTLSCertFile != "" && c.MutualTLSKeyFile != "" { err := policy.SetClientCertKeyPairFromFile(c.MutualTLSCertFile, c.MutualTLSKeyFile) if err != nil { log.Infof("Invalid mutual-tls-cert: %s or mutual-tls-key: %s, defaulting to no client auth", c.MutualTLSCertFile, c.MutualTLSKeyFile) return nil, err } log.Infof("Using client auth with mutual-tls-cert: %s and mutual-tls-key: %s", c.MutualTLSCertFile, c.MutualTLSKeyFile) } if c.TLSRemoteCAs != "" { err := policy.SetRemoteCAsFromFile(c.TLSRemoteCAs) if err != nil { log.Infof("Invalid tls-remote-ca: %s, defaulting to system trust store", c.TLSRemoteCAs) return nil, err } log.Infof("Using trusted CA from tls-remote-ca: %s", c.TLSRemoteCAs) } s, err := universal.NewSigner(cli.RootFromConfig(&c), policy) if err != nil { return nil, err } if db != nil { dbAccessor := certsql.NewAccessor(db) s.SetDBAccessor(dbAccessor) } return s, nil }
func prepDB() (certdb.Accessor, error) { db := testdb.SQLiteDB("../../certdb/testdb/certstore_development.db") expirationTime := time.Now().AddDate(1, 0, 0) var cert = &certdb.CertificateRecord{ Serial: "1", Expiry: expirationTime, PEM: "unexpired cert", } dbAccessor := sql.NewAccessor(db) err := dbAccessor.InsertCertificate(cert) if err != nil { return nil, err } return dbAccessor, nil }
func parseSigner(root *config.Root) (signer.Signer, error) { privateKey := root.PrivateKey switch priv := privateKey.(type) { case *rsa.PrivateKey, *ecdsa.PrivateKey: s, err := local.NewSigner(priv, root.Certificate, signer.DefaultSigAlgo(priv), nil) if err != nil { return nil, err } s.SetPolicy(root.Config) if root.DB != nil { dbAccessor := sql.NewAccessor(root.DB) s.SetDBAccessor(dbAccessor) } return s, nil default: return nil, errors.New("unsupported private key type") } }
// 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 }
func TestSignerWithDB(t *testing.T) { db := testdb.SQLiteDB("../../certdb/testdb/certstore_development.db") err := signerMain([]string{"../../testdata/server.csr"}, cli.Config{ CAFile: "../../testdata/server.crt", CAKeyFile: "../../testdata/server.key", Hostname: "www.cloudflare.com", DBConfigFile: "../testdata/db-config.json"}) if err != nil { t.Fatal(err) } dbAccessor := sql.NewAccessor(db) crs, err := dbAccessor.GetUnexpiredCertificates() if err != nil { t.Fatal("Failed to get unexpired certificates") } if len(crs) != 1 { t.Fatal("Expected 1 unexpired certificate in the database after signing 1") } }
"certinfo": func() (http.Handler, error) { return certinfo.NewHandler(), nil }, "ocspsign": func() (http.Handler, error) { if ocspSigner == nil { return nil, errBadSigner } return apiocsp.NewHandler(ocspSigner), nil }, "revoke": func() (http.Handler, error) { if db == nil { return nil, errNoCertDBConfigured } return revoke.NewHandler(certsql.NewAccessor(db)), nil }, "/": func() (http.Handler, error) { if err := staticBox.findStaticBox(); err != nil { return nil, err } return http.FileServer(staticBox), nil }, } // registerHandlers instantiates various handlers and associate them to corresponding endpoints. func registerHandlers() { for path, getHandler := range endpoints { path = v1APIPath(path)
func TestSignerDBPersistence(t *testing.T) { conf, err := config.LoadConfig([]byte(validLocalConfigLongerExpiry)) if err != nil { t.Fatal(err) } var s *local.Signer s, err = local.NewSignerFromFile(testCaFile, testCaKeyFile, conf.Signing) if err != nil { t.Fatal(err) } db := testdb.SQLiteDB("../../certdb/testdb/certstore_development.db") if err != nil { t.Fatal(err) } dbAccessor = sql.NewAccessor(db) s.SetDBAccessor(dbAccessor) var handler *api.HTTPHandler handler, err = NewHandlerFromSigner(signer.Signer(s)) if err != nil { t.Fatal(err) } ts := httptest.NewServer(handler) defer ts.Close() var csrPEM, body []byte csrPEM, err = ioutil.ReadFile(testCSRFile) if err != nil { t.Fatal(err) } blob, err := json.Marshal(&map[string]string{"certificate_request": string(csrPEM)}) if err != nil { t.Fatal(err) } var resp *http.Response resp, err = http.Post(ts.URL, "application/json", bytes.NewReader(blob)) if err != nil { t.Fatal(err) } body, err = ioutil.ReadAll(resp.Body) if err != nil { t.Fatal(err) } if resp.StatusCode != http.StatusOK { t.Fatal(resp.Status, string(body)) } message := new(api.Response) err = json.Unmarshal(body, message) if err != nil { t.Fatalf("failed to read response body: %v", err) } if !message.Success { t.Fatal("API operation failed") } crs, err := dbAccessor.GetUnexpiredCertificates() if err != nil { t.Fatal("Failed to get unexpired certificates") } if len(crs) != 1 { t.Fatal("Expected 1 unexpired certificate in the database after signing 1: len(crs)=", len(crs)) } }
// 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 }
func TestOCSPRefreshMain(t *testing.T) { db := testdb.SQLiteDB("../../certdb/testdb/certstore_development.db") certPEM, err := ioutil.ReadFile("../../ocsp/testdata/cert.pem") if err != nil { t.Fatal(err) } cert, err := helpers.ParseCertificatePEM(certPEM) if err != nil { t.Fatal(err) } expirationTime := time.Now().AddDate(1, 0, 0) certRecord := certdb.CertificateRecord{ Serial: cert.SerialNumber.String(), AKI: hex.EncodeToString(cert.AuthorityKeyId), Expiry: expirationTime, PEM: string(certPEM), Status: "good", } dbAccessor = sql.NewAccessor(db) err = dbAccessor.InsertCertificate(certRecord) if err != nil { t.Fatal(err) } err = ocsprefreshMain([]string{}, cli.Config{ CAFile: "../../ocsp/testdata/ca.pem", ResponderFile: "../../ocsp/testdata/server.crt", ResponderKeyFile: "../../ocsp/testdata/server.key", DBConfigFile: "../testdata/db-config.json", Interval: helpers.OneDay, }) if err != nil { t.Fatal(err) } records, err := dbAccessor.GetUnexpiredOCSPs() if err != nil { t.Fatal("Failed to get OCSP responses") } if len(records) != 1 { t.Fatal("Expected one OCSP response") } var resp *ocsp.Response resp, err = ocsp.ParseResponse([]byte(records[0].Body), nil) if err != nil { t.Fatal("Failed to parse OCSP response") } if resp.Status != ocsp.Good { t.Fatal("Expected cert status 'good'") } err = dbAccessor.RevokeCertificate(certRecord.Serial, certRecord.AKI, ocsp.KeyCompromise) if err != nil { t.Fatal("Failed to revoke certificate") } err = ocsprefreshMain([]string{}, cli.Config{ CAFile: "../../ocsp/testdata/ca.pem", ResponderFile: "../../ocsp/testdata/server.crt", ResponderKeyFile: "../../ocsp/testdata/server.key", DBConfigFile: "../testdata/db-config.json", Interval: helpers.OneDay, }) if err != nil { t.Fatal(err) } records, err = dbAccessor.GetUnexpiredOCSPs() if err != nil { t.Fatal("Failed to get OCSP responses") } if len(records) != 1 { t.Fatal("Expected one OCSP response") } resp, err = ocsp.ParseResponse([]byte(records[0].Body), nil) if err != nil { t.Fatal("Failed to parse OCSP response") } if resp.Status != ocsp.Revoked { t.Fatal("Expected cert status 'revoked'") } }