// registerSKI associates the SKI of a public key with a particular keyserver. func (c *Client) registerSKI(server string, ski gokeyless.SKI) (err error) { log.Debugf("Registering key @ %s with SKI: %02x", server, ski) var r Remote if server == "" { r = c.DefaultRemote if r == nil { err = errors.New("no default remote") log.Error(err) return } } else { var ok bool c.m.RLock() r, ok = c.servers[server] c.m.RUnlock() if ok { server = "" } else { if r, err = c.LookupServer(server); err != nil { return } } } c.AddRemote(server, r, ski) return }
// 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 { log.Error(err) } log.Info("Initializing signer") if s, err = sign.SignerFromConfig(c); err != nil { log.Warningf("couldn't initialize signer: %v", err) } registerHandlers() addr := net.JoinHostPort(conf.Address, strconv.Itoa(conf.Port)) log.Info("Now listening on ", addr) return http.ListenAndServe(addr, 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) }
func revokeMain(args []string, c cli.Config) (err 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)") } var db *sql.DB db, err = certdb.DBFromConfig(c.DBConfigFile) if err != nil { return err } var reasonCode int reasonCode, err = ocsp.ReasonStringToCode(c.Reason) if err != nil { log.Error("Invalid reason code: ", err) return } err = certdb.RevokeCertificate(db, c.Serial, reasonCode) return }
// Handle responds to requests for a ocsp signature. It creates and signs // a ocsp response for the provided certificate and status. If the status // is revoked then it also adds reason and revoked_at. The response is // base64 encoded. func (h *Handler) Handle(w http.ResponseWriter, r *http.Request) error { body, err := ioutil.ReadAll(r.Body) if err != nil { return err } r.Body.Close() // Default the status to good so it matches the cli req := &jsonSignRequest{ Status: "good", } err = json.Unmarshal(body, req) if err != nil { return errors.NewBadRequestString("Unable to parse sign request") } cert, err := helpers.ParseCertificatePEM([]byte(req.Certificate)) if err != nil { log.Error("Error from ParseCertificatePEM", err) return errors.NewBadRequestString("Malformed certificate") } signReq := ocsp.SignRequest{ Certificate: cert, Status: req.Status, } // We need to convert the time from being a string to a time.Time if req.Status == "revoked" { signReq.Reason = req.Reason // "now" is accepted and the default on the cli so default that here if req.RevokedAt == "" || req.RevokedAt == "now" { signReq.RevokedAt = time.Now() } else { signReq.RevokedAt, err = time.Parse("2006-01-02", req.RevokedAt) if err != nil { return errors.NewBadRequestString("Malformed revocation time") } } } if req.IssuerHash != "" { issuerHash, ok := nameToHash[req.IssuerHash] if !ok { return errors.NewBadRequestString("Unsupported hash algorithm in request") } signReq.IssuerHash = issuerHash } resp, err := h.signer.Sign(signReq) if err != nil { return err } b64Resp := base64.StdEncoding.EncodeToString(resp) result := map[string]string{"ocspResponse": b64Resp} return api.SendResponse(w, result) }
// Serve accepts incoming connections on the Listener l, creating a new service goroutine for each. func (s *Server) Serve(l net.Listener) error { defer l.Close() for { if c, err := l.Accept(); err != nil { log.Error(err) } else { go s.handle(gokeyless.NewConn(tls.Server(c, s.Config))) } } }
func (ctx *context) RunScans(host string) { fmt.Printf("Scanning %s...\n", host) results, err := scan.Default.RunScans(host, ctx.c.IP, ctx.c.Family, ctx.c.Scanner, ctx.c.Timeout) fmt.Printf("=== %s ===\n", host) if err != nil { log.Error(err) } else { printJSON(results) } ctx.Done() }
func main() { flagAddr := flag.String("a", ":8888", "listening address") flagRootFile := flag.String("roots", "", "configuration file specifying root keys") flagDefaultLabel := flag.String("l", "", "specify a default label") flag.IntVar(&log.Level, "loglevel", log.LevelInfo, "log level (0 = DEBUG, 4 = ERROR)") flag.Parse() if *flagRootFile == "" { log.Criticalf("no root file specified") os.Exit(1) } roots, err := config.Parse(*flagRootFile) if err != nil { log.Criticalf("%v", err) os.Exit(1) } for label, root := range roots { s, err := parseSigner(root) if err != nil { log.Criticalf("%v", err) } signers[label] = s if root.ACL != nil { whitelists[label] = root.ACL } log.Info("loaded signer ", label) } defaultLabel = *flagDefaultLabel initStats() infoHandler, err := info.NewMultiHandler(signers, defaultLabel) if err != nil { log.Criticalf("%v", err) } var localhost = whitelist.NewBasic() localhost.Add(net.ParseIP("127.0.0.1")) localhost.Add(net.ParseIP("::1")) metrics, err := whitelist.NewHandlerFunc(dumpMetrics, metricsDisallowed, localhost) if err != nil { log.Criticalf("failed to set up the metrics whitelist: %v", err) } http.HandleFunc("/api/v1/cfssl/authsign", dispatchRequest) http.Handle("/api/v1/cfssl/info", infoHandler) http.Handle("/api/v1/cfssl/metrics", metrics) log.Info("listening on ", *flagAddr) log.Error(http.ListenAndServe(*flagAddr, nil)) }
// Handle responds to requests for the CA to sign the certificate request // present in the "certificate_request" parameter for the host named // in the "hostname" parameter. The certificate should be PEM-encoded. If // provided, subject information from the "subject" parameter will be used // in place of the subject information from the CSR. func (h *SignHandler) Handle(w http.ResponseWriter, r *http.Request) error { log.Info("signature request received") body, err := ioutil.ReadAll(r.Body) if err != nil { return err } r.Body.Close() var req signer.SignRequest err = json.Unmarshal(body, &req) if err != nil { return err } if len(req.Hosts) == 0 { return errors.NewBadRequestString("missing paratmeter 'hosts'") } if req.Request == "" { return errors.NewBadRequestString("missing parameter 'certificate_request'") } var cert []byte var profile *config.SigningProfile policy := h.signer.Policy() if policy != nil && policy.Profiles != nil && req.Profile != "" { profile = policy.Profiles[req.Profile] } if profile == nil && policy != nil { profile = policy.Default } if profile.Provider != nil { log.Error("profile requires authentication") return errors.NewBadRequestString("authentication required") } cert, err = h.signer.Sign(req) if err != nil { log.Warningf("failed to sign request: %v", err) return err } result := map[string]string{"certificate": string(cert)} log.Info("wrote response") return api.SendResponse(w, result) }
func heartbeat() { system, err := provider.SystemGet() if err != nil { log.Error(err) return } apps, err := models.ListApps() if err != nil { log.Error(err) return } helpers.TrackEvent("kernel-heartbeat", map[string]interface{}{ "app_count": len(apps), "instance_count": system.Count, "instance_type": system.Type, "region": os.Getenv("AWS_REGION"), "version": system.Version, }) }
func loadTest(test testFunc) error { errs := make(chan error) for i := 0; i < loadSize; i++ { go func() { for { errs <- test() } }() } for err := range errs { if err != nil { log.Error(err) } } return nil }
// Handle responds to requests for the CA to sign the certificate request // present in the "certificate_request" parameter for the host named // in the "hostname" parameter. The certificate should be PEM-encoded. If // provided, subject information from the "subject" parameter will be used // in place of the subject information from the CSR. func (h *Handler) Handle(w http.ResponseWriter, r *http.Request) error { log.Info("signature request received") body, err := ioutil.ReadAll(r.Body) if err != nil { return err } r.Body.Close() var req jsonSignRequest err = json.Unmarshal(body, &req) if err != nil { return errors.NewBadRequestString("Unable to parse sign request") } signReq := jsonReqToTrue(req) if req.Request == "" { return errors.NewBadRequestString("missing parameter 'certificate_request'") } var cert []byte profile, err := signer.Profile(h.signer, req.Profile) if err != nil { return err } if profile.Provider != nil { log.Error("profile requires authentication") return errors.NewBadRequestString("authentication required") } cert, err = h.signer.Sign(signReq) if err != nil { log.Warningf("failed to sign request: %v", err) return err } result := map[string]string{"certificate": string(cert)} log.Info("wrote response") return api.SendResponse(w, result) }
// RunServerTests load tests a server with a given number of workers and ammount of time. func RunServerTests(testLen time.Duration, workers int, c *client.Client, server string, privkeys []*client.PrivateKey) { log.Infof("Testing %s and %d keys for %v with %d workers...", server, len(privkeys), testLen, workers) running := make(chan bool, workers) errs := make(chan error) for i := 0; i < workers; i++ { running <- true go func() { for range running { errs <- testConnect(c, server) for _, priv := range privkeys { errs <- testKey(priv) } running <- true } }() } timeout := time.After(testLen) var testCount, errCount int for { select { case err := <-errs: testCount++ fmt.Print(".") if err != nil { log.Error(err) errCount++ } case <-timeout: close(running) log.Infof("Completed with %d errors / %d tests", errCount, testCount) return } } }
// ocspdumpMain is the main CLI of OCSP dump functionality. func ocspdumpMain(args []string, c cli.Config) (err error) { if c.DBConfigFile == "" { log.Error("need DB config file (provide with -db-config)") return } var db *sql.DB db, err = certdb.DBFromConfig(c.DBConfigFile) if err != nil { return err } var records []*certdb.OCSPRecord records, err = certdb.GetUnexpiredOCSPs(db) if err != nil { return err } for _, certRecord := range records { fmt.Printf("%s\n", base64.StdEncoding.EncodeToString([]byte(certRecord.Body))) } return nil }
// ParseAndLoad converts HashAlgo and KeyAlgo to corresponding ubiquity value and load // certificates into internal KeyStore from KeyStoreFiles func (p *Platform) ParseAndLoad() (ok bool) { p.HashUbiquity = p.hashUbiquity() p.KeyAlgoUbiquity = p.keyAlgoUbiquity() p.KeyStore = map[string]bool{} if p.KeyStoreFile != "" { pemBytes, err := ioutil.ReadFile(p.KeyStoreFile) if err != nil { log.Error(err) return false } // Best effort parsing the PEMs such that ignore all borken pem, // since some of CA certs have negative serial number which trigger errors. for len(pemBytes) > 0 { var certs []*x509.Certificate certs, rest, err := helpers.ParseOneCertificateFromPEM(pemBytes) // If one certificate object is parsed, possibly a PKCS#7 // structure containing multiple certs, record the raw SHA1 hash(es). if err == nil && certs != nil { for _, cert := range certs { p.KeyStore.Add(cert) } } if len(rest) < len(pemBytes) { pemBytes = rest } else { // No progress in bytes parsing, bail out. break } } } if p.HashUbiquity <= UnknownHashUbiquity || p.KeyAlgoUbiquity <= UnknownAlgoUbiquity { return false } return true }
// 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 } p.ExtensionWhitelist = map[string]bool{} for _, oid := range p.AllowedExtensions { p.ExtensionWhitelist[asn1.ObjectIdentifier(oid).String()] = true } return nil }
func gencertMain(args []string, c cli.Config) error { if c.RenewCA { log.Infof("re-generate a CA certificate from CA cert and key") cert, err := initca.RenewFromPEM(c.CAFile, c.CAKeyFile) if err != nil { log.Errorf("%v\n", err) return err } cli.PrintCert(nil, nil, cert) return nil } csrJSONFile, args, err := cli.PopFirstArgument(args) if err != nil { return err } csrJSONFileBytes, err := cli.ReadStdin(csrJSONFile) if err != nil { return err } req := csr.CertificateRequest{ KeyRequest: csr.NewBasicKeyRequest(), } err = json.Unmarshal(csrJSONFileBytes, &req) if err != nil { return err } switch { case c.IsCA: var key, csrPEM, cert []byte if c.CAKeyFile != "" { log.Infof("re-generate a CA certificate from CSR and CA key") cert, csrPEM, err = initca.NewFromPEM(&req, c.CAKeyFile) if err != nil { log.Errorf("%v\n", err) return err } } else { log.Infof("generating a new CA key and certificate from CSR") cert, csrPEM, key, err = initca.New(&req) if err != nil { return err } } cli.PrintCert(key, csrPEM, cert) default: if req.CA != nil { err = errors.New("ca section only permitted in initca") return err } // Remote can be forced on the command line or in the config if c.Remote == "" && c.CFG == nil { if c.CAFile == "" { log.Error("need a CA certificate (provide one with -ca)") return nil } if c.CAKeyFile == "" { log.Error("need a CA key (provide one with -ca-key)") return nil } } var key, csrBytes []byte g := &csr.Generator{Validator: genkey.Validator} csrBytes, key, err = g.ProcessRequest(&req) if err != nil { key = nil return err } s, err := sign.SignerFromConfig(c) if err != nil { return err } var cert []byte req := signer.SignRequest{ Request: string(csrBytes), Hosts: signer.SplitHosts(c.Hostname), Profile: c.Profile, Label: c.Label, } cert, err = s.Sign(req) if err != nil { return err } cli.PrintCert(key, csrBytes, cert) } return nil }
// signerMain is the main CLI of signer functionality. // [TODO: zi] Decide whether to drop the argument list and only use flags to specify all the inputs. func signerMain(args []string, c cli.Config) (err error) { if c.CSRFile == "" { c.CSRFile, args, err = cli.PopFirstArgument(args) if err != nil { return } } var subjectData *signer.Subject if len(args) > 0 { var subjectFile string subjectFile, args, err = cli.PopFirstArgument(args) if err != nil { return } var subjectJSON []byte subjectJSON, err = ioutil.ReadFile(subjectFile) if err != nil { return } subjectData = new(signer.Subject) err = json.Unmarshal(subjectJSON, subjectData) if err != nil { return } } csr, err := cli.ReadStdin(c.CSRFile) if err != nil { return } // Remote can be forced on the command line or in the config if c.Remote == "" && c.CFG == nil { if c.CAFile == "" { log.Error("need CA certificate (provide one with -ca)") return } if c.CAKeyFile == "" { log.Error("need CA key (provide one with -ca-key)") return } } s, err := SignerFromConfig(c) if err != nil { return } req := signer.SignRequest{ Hosts: signer.SplitHosts(c.Hostname), Request: string(csr), Subject: subjectData, Profile: c.Profile, Label: c.Label, } cert, err := s.Sign(req) if err != nil { return } cli.PrintCert(nil, csr, cert) return }
// Sign signs a new certificate based on the PEM-encoded client // certificate or certificate request with the signing profile, // specified by profileName. func (s *Signer) Sign(req signer.SignRequest) (cert []byte, err error) { profile, err := signer.Profile(s, req.Profile) if err != nil { return } block, _ := pem.Decode([]byte(req.Request)) if block == nil { return nil, cferr.New(cferr.CSRError, cferr.DecodeFailed) } if block.Type != "NEW CERTIFICATE REQUEST" && block.Type != "CERTIFICATE REQUEST" { return nil, cferr.Wrap(cferr.CSRError, cferr.BadRequest, errors.New("not a certificate or csr")) } csrTemplate, err := signer.ParseCertificateRequest(s, block.Bytes) if err != nil { return nil, err } // Copy out only the fields from the CSR authorized by policy. safeTemplate := x509.Certificate{} // If the profile contains no explicit whitelist, assume that all fields // should be copied from the CSR. if profile.CSRWhitelist == nil { safeTemplate = *csrTemplate } else { if profile.CSRWhitelist.Subject { safeTemplate.Subject = csrTemplate.Subject } if profile.CSRWhitelist.PublicKeyAlgorithm { safeTemplate.PublicKeyAlgorithm = csrTemplate.PublicKeyAlgorithm } if profile.CSRWhitelist.PublicKey { safeTemplate.PublicKey = csrTemplate.PublicKey } if profile.CSRWhitelist.SignatureAlgorithm { safeTemplate.SignatureAlgorithm = csrTemplate.SignatureAlgorithm } if profile.CSRWhitelist.DNSNames { safeTemplate.DNSNames = csrTemplate.DNSNames } if profile.CSRWhitelist.IPAddresses { safeTemplate.IPAddresses = csrTemplate.IPAddresses } if profile.CSRWhitelist.EmailAddresses { safeTemplate.EmailAddresses = csrTemplate.EmailAddresses } } if req.CRLOverride != "" { safeTemplate.CRLDistributionPoints = []string{req.CRLOverride} } if safeTemplate.IsCA { if !profile.CAConstraint.IsCA { log.Error("local signer policy disallows issuing CA certificate") return nil, cferr.New(cferr.PolicyError, cferr.InvalidRequest) } if s.ca != nil && s.ca.MaxPathLen > 0 { if safeTemplate.MaxPathLen >= s.ca.MaxPathLen { log.Error("local signer certificate disallows CA MaxPathLen extending") // do not sign a cert with pathlen > current return nil, cferr.New(cferr.PolicyError, cferr.InvalidRequest) } } else if s.ca != nil && s.ca.MaxPathLen == 0 && s.ca.MaxPathLenZero { log.Error("local signer certificate disallows issuing CA certificate") // signer has pathlen of 0, do not sign more intermediate CAs return nil, cferr.New(cferr.PolicyError, cferr.InvalidRequest) } } OverrideHosts(&safeTemplate, req.Hosts) safeTemplate.Subject = PopulateSubjectFromCSR(req.Subject, safeTemplate.Subject) // If there is a whitelist, ensure that both the Common Name and SAN DNSNames match if profile.NameWhitelist != nil { if safeTemplate.Subject.CommonName != "" { if profile.NameWhitelist.Find([]byte(safeTemplate.Subject.CommonName)) == nil { return nil, cferr.New(cferr.PolicyError, cferr.UnmatchedWhitelist) } } for _, name := range safeTemplate.DNSNames { if profile.NameWhitelist.Find([]byte(name)) == nil { return nil, cferr.New(cferr.PolicyError, cferr.UnmatchedWhitelist) } } for _, name := range safeTemplate.EmailAddresses { if profile.NameWhitelist.Find([]byte(name)) == nil { return nil, cferr.New(cferr.PolicyError, cferr.UnmatchedWhitelist) } } } if profile.ClientProvidesSerialNumbers { if req.Serial == nil { return nil, cferr.New(cferr.CertificateError, cferr.MissingSerial) } safeTemplate.SerialNumber = req.Serial } else { // RFC 5280 4.1.2.2: // Certificate users MUST be able to handle serialNumber // values up to 20 octets. Conforming CAs MUST NOT use // serialNumber values longer than 20 octets. // // If CFSSL is providing the serial numbers, it makes // sense to use the max supported size. serialNumber := make([]byte, 20) _, err = io.ReadFull(rand.Reader, serialNumber) if err != nil { return nil, cferr.Wrap(cferr.CertificateError, cferr.Unknown, err) } // SetBytes interprets buf as the bytes of a big-endian // unsigned integer. The leading byte should be masked // off to ensure it isn't negative. serialNumber[0] &= 0x7F safeTemplate.SerialNumber = new(big.Int).SetBytes(serialNumber) } if len(req.Extensions) > 0 { for _, ext := range req.Extensions { oid := asn1.ObjectIdentifier(ext.ID) if !profile.ExtensionWhitelist[oid.String()] { return nil, cferr.New(cferr.CertificateError, cferr.InvalidRequest) } rawValue, err := hex.DecodeString(ext.Value) if err != nil { return nil, cferr.Wrap(cferr.CertificateError, cferr.InvalidRequest, err) } safeTemplate.ExtraExtensions = append(safeTemplate.ExtraExtensions, pkix.Extension{ Id: oid, Critical: ext.Critical, Value: rawValue, }) } } var certTBS = safeTemplate if len(profile.CTLogServers) > 0 { // Add a poison extension which prevents validation var poisonExtension = pkix.Extension{Id: signer.CTPoisonOID, Critical: true, Value: []byte{0x05, 0x00}} var poisonedPreCert = certTBS poisonedPreCert.ExtraExtensions = append(safeTemplate.ExtraExtensions, poisonExtension) cert, err = s.sign(&poisonedPreCert, profile) if err != nil { return } derCert, _ := pem.Decode(cert) prechain := []ct.ASN1Cert{derCert.Bytes, s.ca.Raw} var sctList []ct.SignedCertificateTimestamp for _, server := range profile.CTLogServers { log.Infof("submitting poisoned precertificate to %s", server) var ctclient = client.New(server, nil) var resp *ct.SignedCertificateTimestamp resp, err = ctclient.AddPreChain(prechain) if err != nil { return nil, cferr.Wrap(cferr.CTError, cferr.PrecertSubmissionFailed, err) } sctList = append(sctList, *resp) } var serializedSCTList []byte serializedSCTList, err = serializeSCTList(sctList) if err != nil { return nil, cferr.Wrap(cferr.CTError, cferr.Unknown, err) } // Serialize again as an octet string before embedding serializedSCTList, err = asn1.Marshal(serializedSCTList) if err != nil { return nil, cferr.Wrap(cferr.CTError, cferr.Unknown, err) } var SCTListExtension = pkix.Extension{Id: signer.SCTListOID, Critical: false, Value: serializedSCTList} certTBS.ExtraExtensions = append(certTBS.ExtraExtensions, SCTListExtension) } var signedCert []byte signedCert, err = s.sign(&certTBS, profile) if err != nil { return nil, err } if s.dbAccessor != nil { var certRecord = certdb.CertificateRecord{ Serial: certTBS.SerialNumber.String(), // this relies on the specific behavior of x509.CreateCertificate // which updates certTBS AuthorityKeyId from the signer's SubjectKeyId AKI: hex.EncodeToString(certTBS.AuthorityKeyId), CALabel: req.Label, Status: "good", Expiry: certTBS.NotAfter, PEM: string(signedCert), } err = s.dbAccessor.InsertCertificate(certRecord) if err != nil { return nil, err } log.Debug("saved certificate with serial number ", certTBS.SerialNumber) } return signedCert, nil }
func (s *Server) handle(conn *gokeyless.Conn) { defer conn.Close() log.Debug("Handling new connection...") // Continuosly read request Headers from conn and respond // until a connection error (Read/Write failure) is encountered. var connError error for connError == nil { conn.SetDeadline(time.Now().Add(time.Hour)) var h *gokeyless.Header if h, connError = conn.ReadHeader(); connError != nil { continue } requestBegin := time.Now() log.Debugf("version:%d.%d id:%d body:%s", h.MajorVers, h.MinorVers, h.ID, h.Body) var opts crypto.SignerOpts var key crypto.Signer var ok bool switch h.Body.Opcode { case gokeyless.OpPing: connError = conn.RespondPong(h.ID, h.Body.Payload) s.stats.logRequest(requestBegin) continue case gokeyless.OpRSADecrypt: if key, ok = s.Keys.Get(h.Body); !ok { log.Error(gokeyless.ErrKeyNotFound) connError = conn.RespondError(h.ID, gokeyless.ErrKeyNotFound) s.stats.logInvalid(requestBegin) continue } if _, ok = key.Public().(*rsa.PublicKey); !ok { log.Errorf("%s: Key is not RSA\n", gokeyless.ErrCrypto) connError = conn.RespondError(h.ID, gokeyless.ErrCrypto) s.stats.logInvalid(requestBegin) continue } rsaKey, ok := key.(crypto.Decrypter) if !ok { log.Errorf("%s: Key is not Decrypter\n", gokeyless.ErrCrypto) connError = conn.RespondError(h.ID, gokeyless.ErrCrypto) s.stats.logInvalid(requestBegin) continue } ptxt, err := rsaKey.Decrypt(nil, h.Body.Payload, nil) if err != nil { log.Errorf("%s: Decryption error: %v", gokeyless.ErrCrypto, err) connError = conn.RespondError(h.ID, gokeyless.ErrCrypto) s.stats.logInvalid(requestBegin) continue } connError = conn.Respond(h.ID, ptxt) s.stats.logRequest(requestBegin) continue case gokeyless.OpRSASignMD5SHA1, gokeyless.OpECDSASignMD5SHA1: opts = crypto.MD5SHA1 case gokeyless.OpRSASignSHA1, gokeyless.OpECDSASignSHA1: opts = crypto.SHA1 case gokeyless.OpRSASignSHA224, gokeyless.OpECDSASignSHA224: opts = crypto.SHA224 case gokeyless.OpRSASignSHA256, gokeyless.OpECDSASignSHA256: opts = crypto.SHA256 case gokeyless.OpRSASignSHA384, gokeyless.OpECDSASignSHA384: opts = crypto.SHA384 case gokeyless.OpRSASignSHA512, gokeyless.OpECDSASignSHA512: opts = crypto.SHA512 case gokeyless.OpActivate: if len(s.ActivationToken) > 0 { hashedToken := sha256.Sum256(s.ActivationToken) connError = conn.Respond(h.ID, hashedToken[:]) s.stats.logRequest(requestBegin) } else { connError = conn.RespondError(h.ID, gokeyless.ErrBadOpcode) s.stats.logInvalid(requestBegin) } continue case gokeyless.OpPong, gokeyless.OpResponse, gokeyless.OpError: log.Errorf("%s: %s is not a valid request Opcode\n", gokeyless.ErrUnexpectedOpcode, h.Body.Opcode) connError = conn.RespondError(h.ID, gokeyless.ErrUnexpectedOpcode) s.stats.logInvalid(requestBegin) continue default: connError = conn.RespondError(h.ID, gokeyless.ErrBadOpcode) s.stats.logInvalid(requestBegin) continue } if key, ok = s.Keys.Get(h.Body); !ok { log.Error(gokeyless.ErrKeyNotFound) connError = conn.RespondError(h.ID, gokeyless.ErrKeyNotFound) s.stats.logInvalid(requestBegin) continue } // Ensure we don't perform an ECDSA sign for an RSA request. switch h.Body.Opcode { case gokeyless.OpRSASignMD5SHA1, gokeyless.OpRSASignSHA1, gokeyless.OpRSASignSHA224, gokeyless.OpRSASignSHA256, gokeyless.OpRSASignSHA384, gokeyless.OpRSASignSHA512: if _, ok := key.Public().(*rsa.PublicKey); !ok { log.Errorf("%s: request is RSA, but key isn't\n", gokeyless.ErrCrypto) connError = conn.RespondError(h.ID, gokeyless.ErrCrypto) s.stats.logInvalid(requestBegin) continue } } sig, err := key.Sign(rand.Reader, h.Body.Payload, opts) if err != nil { log.Errorf("%s: Signing error: %v\n", gokeyless.ErrCrypto, err) connError = conn.RespondError(h.ID, gokeyless.ErrCrypto) s.stats.logInvalid(requestBegin) continue } connError = conn.Respond(h.ID, sig) s.stats.logRequest(requestBegin) } if connError == io.EOF { log.Debug("connection closed by client") } else { log.Errorf("connection error: %v\n", connError) } }
func gencertMain(args []string, c cli.Config) error { if c.RenewCA { log.Infof("re-generate a CA certificate from CA cert and key") cert, err := initca.RenewFromPEM(c.CAFile, c.CAKeyFile) if err != nil { log.Errorf("%v\n", err) return err } cli.PrintCert(nil, nil, cert) return nil } csrJSONFile, args, err := cli.PopFirstArgument(args) if err != nil { return err } csrJSONFileBytes, err := cli.ReadStdin(csrJSONFile) if err != nil { return err } req := csr.CertificateRequest{ KeyRequest: csr.NewBasicKeyRequest(), } err = json.Unmarshal(csrJSONFileBytes, &req) if err != nil { return err } if c.CNOverride != "" { req.CN = c.CNOverride } switch { case c.IsCA: var key, csrPEM, cert []byte if c.CAKeyFile != "" { log.Infof("re-generate a CA certificate from CSR and CA key") cert, csrPEM, err = initca.NewFromPEM(&req, c.CAKeyFile) if err != nil { log.Errorf("%v\n", err) return err } } else { log.Infof("generating a new CA key and certificate from CSR") cert, csrPEM, key, err = initca.New(&req) if err != nil { return err } } cli.PrintCert(key, csrPEM, cert) default: if req.CA != nil { err = errors.New("ca section only permitted in initca") return err } if c.Hostname != "" { req.Hosts = signer.SplitHosts(c.Hostname) } // Remote can be forced on the command line or in the config if c.Remote == "" && c.CFG == nil { if c.CAFile == "" { log.Error("need a CA certificate (provide one with -ca)") return nil } if c.CAKeyFile == "" { log.Error("need a CA key (provide one with -ca-key)") return nil } } var key, csrBytes []byte g := &csr.Generator{Validator: genkey.Validator} csrBytes, key, err = g.ProcessRequest(&req) if err != nil { key = nil return err } s, err := sign.SignerFromConfig(c) if err != nil { return err } var cert []byte signReq := signer.SignRequest{ Request: string(csrBytes), Hosts: signer.SplitHosts(c.Hostname), Profile: c.Profile, Label: c.Label, } if c.CRL != "" { signReq.CRLOverride = c.CRL } cert, err = s.Sign(signReq) if err != nil { return err } // This follows the Baseline Requirements for the Issuance and // Management of Publicly-Trusted Certificates, v.1.1.6, from the CA/Browser // Forum (https://cabforum.org). Specifically, section 10.2.3 ("Information // Requirements"), states: // // "Applicant information MUST include, but not be limited to, at least one // Fully-Qualified Domain Name or IP address to be included in the Certificate’s // SubjectAltName extension." if len(signReq.Hosts) == 0 && len(req.Hosts) == 0 { log.Warning(generator.CSRNoHostMessage) } cli.PrintCert(key, csrBytes, cert) } return nil }
// Handle receives the incoming request, validates it, and processes it. func (h *AuthHandler) Handle(w http.ResponseWriter, r *http.Request) error { log.Info("signature request received") body, err := ioutil.ReadAll(r.Body) if err != nil { log.Errorf("failed to read response body: %v", err) return err } r.Body.Close() var aReq auth.AuthenticatedRequest err = json.Unmarshal(body, &aReq) if err != nil { log.Errorf("failed to unmarshal authenticated request: %v", err) return errors.NewBadRequest(err) } var req jsonSignRequest err = json.Unmarshal(aReq.Request, &req) if err != nil { log.Errorf("failed to unmarshal request from authenticated request: %v", err) return errors.NewBadRequestString("Unable to parse authenticated sign request") } // Sanity checks to ensure that we have a valid policy. This // should have been checked in NewAuthHandler. policy := h.signer.Policy() if policy == nil { log.Critical("signer was initialised without a signing policy") return errors.NewBadRequestString("invalid policy") } profile, err := signer.Profile(h.signer, req.Profile) if err != nil { return err } if profile.Provider == nil { log.Error("profile has no authentication provider") return errors.NewBadRequestString("no authentication provider") } if !profile.Provider.Verify(&aReq) { log.Warning("received authenticated request with invalid token") return errors.NewBadRequestString("invalid token") } signReq := jsonReqToTrue(req) if signReq.Request == "" { return errors.NewBadRequestString("missing parameter 'certificate_request'") } cert, err := h.signer.Sign(signReq) if err != nil { log.Errorf("signature failed: %v", err) return err } result := map[string]string{"certificate": string(cert)} log.Info("wrote response") return api.SendResponse(w, result) }
// Handle responds to requests for crl generation. It creates this crl // based off of the given certificate, serial numbers, and private key func crlHandler(w http.ResponseWriter, r *http.Request) error { var revokedCerts []pkix.RevokedCertificate var oneWeek = time.Duration(604800) * time.Second var newExpiryTime = time.Now() body, err := ioutil.ReadAll(r.Body) if err != nil { return err } r.Body.Close() req := &jsonCRLRequest{} err = json.Unmarshal(body, req) if err != nil { log.Error(err) } if req.ExpiryTime != "" { expiryTime := strings.TrimSpace(req.ExpiryTime) expiryInt, err := strconv.ParseInt(expiryTime, 0, 32) if err != nil { return err } newExpiryTime = time.Now().Add((time.Duration(expiryInt) * time.Second)) } if req.ExpiryTime == "" { newExpiryTime = time.Now().Add(oneWeek) } if err != nil { return err } cert, err := helpers.ParseCertificatePEM([]byte(req.Certificate)) if err != nil { log.Error("Error from ParseCertificatePEM", err) return errors.NewBadRequestString("Malformed certificate") } for _, value := range req.SerialNumber { tempBigInt := new(big.Int) tempBigInt.SetString(value, 10) tempCert := pkix.RevokedCertificate{ SerialNumber: tempBigInt, RevocationTime: time.Now(), } revokedCerts = append(revokedCerts, tempCert) } key, err := helpers.ParsePrivateKeyPEM([]byte(req.PrivateKey)) if err != nil { log.Debug("Malformed private key %v", err) return errors.NewBadRequestString("Malformed Private Key") } result, err := cert.CreateCRL(rand.Reader, key, revokedCerts, time.Now(), newExpiryTime) return api.SendResponse(w, result) }
// ocsprefreshMain is the main CLI of OCSP refresh functionality. func ocsprefreshMain(args []string, c cli.Config) (err error) { if c.DBConfigFile == "" { log.Error("need DB config file (provide with -db-config)") return } if c.ResponderFile == "" { log.Error("need responder certificate (provide with -responder)") return } if c.ResponderKeyFile == "" { log.Error("need responder key (provide with -responder-key)") return } if c.CAFile == "" { log.Error("need CA certificate (provide with -ca)") return } s, err := SignerFromConfig(c) if err != nil { log.Critical("Unable to create OCSP signer: ", err) return err } var db *sql.DB db, err = certdb.DBFromConfig(c.DBConfigFile) if err != nil { return err } var certs []*certdb.CertificateRecord certs, err = certdb.GetUnexpiredCertificates(db) 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 = certdb.UpsertOCSP(db, cert.SerialNumber.String(), string(resp), ocspExpiry) if err != nil { log.Critical("Unable to save OCSP response: ", err) return err } } return nil }
func gencertMain(args []string) (err error) { if Config.hostname == "" && !Config.isCA { Config.hostname, args, err = popFirstArgument(args) if err != nil { return } } csrFile, args, err := popFirstArgument(args) if err != nil { return } csrFileBytes, err := readStdin(csrFile) if err != nil { return } var req csr.CertificateRequest err = json.Unmarshal(csrFileBytes, &req) if err != nil { return } if Config.isCA { var key, cert []byte cert, key, err = initca.New(&req) if err != nil { return } printCert(key, nil, cert) } else { if Config.remote != "" { return gencertRemotely(req) } if Config.caFile == "" { log.Error("cannot sign certificate without a CA certificate (provide one with -ca)") return } if Config.caKeyFile == "" { log.Error("cannot sign certificate without a CA key (provide one with -ca-key)") return } var policy *config.Signing // If there is a config, use its signing policy. Otherwise, leave policy == nil // and NewSigner will use DefaultConfig(). if Config.cfg != nil { policy = Config.cfg.Signing } var key, csrPEM []byte g := &csr.Generator{validator} csrPEM, key, err = g.ProcessRequest(&req) if err != nil { key = nil return } var sign *signer.Signer sign, err = signer.NewSigner(Config.caFile, Config.caKeyFile, policy) if err != nil { return } var cert []byte cert, err = sign.Sign(Config.hostname, csrPEM, Config.profile) if err != nil { return } printCert(key, csrPEM, cert) } return nil }