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 }
func dispatchRequest(w http.ResponseWriter, req *http.Request) { incRequests() if req.Method != "POST" { fail(w, req, http.StatusMethodNotAllowed, 1, "only POST is permitted", "") return } body, err := ioutil.ReadAll(req.Body) if err != nil { fail(w, req, http.StatusInternalServerError, 1, err.Error(), "while reading request body") return } defer req.Body.Close() var authReq auth.AuthenticatedRequest err = json.Unmarshal(body, &authReq) if err != nil { fail(w, req, http.StatusBadRequest, 1, err.Error(), "while unmarshaling request body") return } var sigRequest signer.SignRequest err = json.Unmarshal(authReq.Request, &sigRequest) if err != nil { fail(w, req, http.StatusBadRequest, 1, err.Error(), "while unmarshalling authenticated request") return } if sigRequest.Label == "" { sigRequest.Label = defaultLabel } s, ok := signers[sigRequest.Label] if !ok { fail(w, req, http.StatusBadRequest, 1, "bad request", "request is for non-existent label "+sigRequest.Label) return } stats.Requests[sigRequest.Label].Counter.Inc(1) stats.Requests[sigRequest.Label].Rate.Mark(1) // Sanity checks to ensure that we have a valid policy. This // should have been checked in NewAuthSignHandler. policy := s.Policy() if policy == nil { fail(w, req, http.StatusInternalServerError, 1, "invalid policy", "signer was initialised without a signing policy") return } profile := policy.Default if policy.Profiles != nil && sigRequest.Profile != "" { profile = policy.Profiles[sigRequest.Profile] if profile == nil { fail(w, req, http.StatusBadRequest, 1, "invalid profile", "failed to look up profile with name: "+sigRequest.Profile) return } } if profile == nil { fail(w, req, http.StatusInternalServerError, 1, "invalid profile", "signer was initialised without any valid profiles") return } if profile.Provider == nil { fail(w, req, http.StatusUnauthorized, 1, "authorisation required", "received unauthenticated request") return } if !profile.Provider.Verify(&authReq) { fail(w, req, http.StatusBadRequest, 1, "invalid token", "received authenticated request with invalid token") return } if sigRequest.Request == "" { fail(w, req, http.StatusBadRequest, 1, "invalid request", "empty request") return } cert, err := s.Sign(sigRequest) if err != nil { fail(w, req, http.StatusBadRequest, 1, "bad request", "signature failed: "+err.Error()) return } x509Cert, err := helpers.ParseCertificatePEM(cert) if err != nil { fail(w, req, http.StatusInternalServerError, 1, "bad certificate", err.Error()) } log.Infof("signature: requester=%s, label=%s, profile=%s, serialno=%s", req.RemoteAddr, sigRequest.Label, sigRequest.Profile, x509Cert.SerialNumber) res := api.NewSuccessResponse(&SignatureResponse{Certificate: string(cert)}) jenc := json.NewEncoder(w) err = jenc.Encode(res) if err != nil { log.Errorf("error writing response: %v", err) } }