// initialCAHandler is an HTTP handler that accepts a JSON blob in the // same format as the CSR endpoint; this blob should contain the // identity information for the CA's root key. This endpoint is not // suitable for creating intermediate certificates. func initialCAHandler(w http.ResponseWriter, r *http.Request) error { log.Info("setting up initial CA handler") body, err := ioutil.ReadAll(r.Body) if err != nil { log.Warningf("failed to read request body: %v", err) return errors.NewBadRequest(err) } r.Body.Close() req := new(csr.CertificateRequest) req.KeyRequest = csr.NewBasicKeyRequest() err = json.Unmarshal(body, req) if err != nil { log.Warningf("failed to unmarshal request: %v", err) return errors.NewBadRequest(err) } cert, _, key, err := initca.New(req) if err != nil { log.Warningf("failed to initialise new CA: %v", err) return err } response := api.NewSuccessResponse(&NewCA{string(key), string(cert)}) enc := json.NewEncoder(w) err = enc.Encode(response) return err }
// Handle accepts client information requests, and uses the label to // look up the signer whose public certificate should be retrieved. If // the label is empty, the default label is used. func (h *MultiHandler) Handle(w http.ResponseWriter, r *http.Request) error { req := new(info.Req) body, err := ioutil.ReadAll(r.Body) if err != nil { log.Warningf("failed to read request body: %v", err) return errors.NewBadRequest(err) } err = json.Unmarshal(body, req) if err != nil { log.Warningf("failed to unmarshal request: %v", err) return errors.NewBadRequest(err) } log.Debug("checking label") if req.Label == "" { req.Label = h.defaultLabel } if _, ok := h.signers[req.Label]; !ok { log.Warningf("request for invalid endpoint") return errors.NewBadRequestString("bad label") } log.Debug("getting info") resp, err := h.signers[req.Label].Info(*req) if err != nil { log.Infof("error getting certificate: %v", err) return err } response := api.NewSuccessResponse(resp) w.Header().Set("Content-Type", "application/json") enc := json.NewEncoder(w) return enc.Encode(response) }
// Handle listens for incoming requests for CA information, and returns // a list containing information on each root certificate. func (h *Handler) Handle(w http.ResponseWriter, r *http.Request) error { req := new(info.Req) body, err := ioutil.ReadAll(r.Body) if err != nil { log.Warningf("failed to read request body: %v", err) return errors.NewBadRequest(err) } r.Body.Close() err = json.Unmarshal(body, req) if err != nil { log.Warningf("failed to unmarshal request: %v", err) return errors.NewBadRequest(err) } resp, err := h.sign.Info(*req) if err != nil { return err } response := api.NewSuccessResponse(resp) w.Header().Set("Content-Type", "application/json") enc := json.NewEncoder(w) return enc.Encode(response) }
// scanInfoHandler is an HTTP handler that returns a JSON blob result describing // the possible families and scans to be run. func scanInfoHandler(w http.ResponseWriter, r *http.Request) error { log.Info("setting up scaninfo handler") response := api.NewSuccessResponse(scan.Default) enc := json.NewEncoder(w) err := enc.Encode(response) return err }
// scanHandler is an HTTP handler that accepts GET parameters for host (required) // family and scanner, and uses these to perform scans, returning a JSON blob result. func scanHandler(w http.ResponseWriter, r *http.Request) error { if err := r.ParseForm(); err != nil { log.Warningf("failed to parse body: %v", err) return errors.NewBadRequest(err) } family := r.Form.Get("family") scanner := r.Form.Get("scanner") ip := r.Form.Get("ip") host := r.Form.Get("host") if host == "" { log.Warningf("no host given") return errors.NewBadRequestString("no host given") } results, err := scan.Default.RunScans(host, ip, family, scanner, 0) if err != nil { log.Warningf("%v", err) return errors.NewBadRequest(err) } response := api.NewSuccessResponse(results) enc := json.NewEncoder(w) return enc.Encode(response) }
// scanHandler is an HTTP handler that accepts GET parameters for host (required) // family and scanner, and uses these to perform scans, returning a JSON blob result. func scanHandler(w http.ResponseWriter, r *http.Request) error { if err := r.ParseForm(); err != nil { log.Warningf("failed to parse body: %v", err) return errors.NewBadRequest(err) } if len(r.Form["host"]) == 0 { log.Warningf("no host given") return errors.NewBadRequestString("no host given") } host := r.Form["host"][0] var family, scanner string if len(r.Form["family"]) > 0 { family = r.Form["family"][0] } if len(r.Form["scanner"]) > 0 { scanner = r.Form["scanner"][0] } results, err := scan.Default.RunScans(host, family, scanner) if err != nil { log.Warningf("%v", err) return errors.NewBadRequest(err) } response := api.NewSuccessResponse(results) enc := json.NewEncoder(w) return enc.Encode(response) }
// Handle responds to requests for the CA to generate a new private // key and certificate request on behalf of the client. The format for // these requests is documented in the API documentation. func (g *Handler) Handle(w http.ResponseWriter, r *http.Request) error { log.Info("request for CSR") body, err := ioutil.ReadAll(r.Body) if err != nil { log.Warningf("failed to read request body: %v", err) return errors.NewBadRequest(err) } r.Body.Close() req := new(csr.CertificateRequest) req.KeyRequest = csr.NewBasicKeyRequest() err = json.Unmarshal(body, req) if err != nil { log.Warningf("failed to unmarshal request: %v", err) return errors.NewBadRequest(err) } if req.CA != nil { log.Warningf("request received with CA section") return errors.NewBadRequestString("ca section only permitted in initca") } csr, key, err := g.generator.ProcessRequest(req) if err != nil { log.Warningf("failed to process CSR: %v", err) // The validator returns a *cfssl/errors.HttpError return err } sum, err := computeSum(csr) if err != nil { return errors.NewBadRequest(err) } // Both key and csr are returned PEM-encoded. response := api.NewSuccessResponse(&CertRequest{ Key: string(key), CSR: string(csr), Sums: map[string]Sum{"certificate_request": sum}, }) w.Header().Set("Content-Type", "application/json") enc := json.NewEncoder(w) err = enc.Encode(response) return err }
// scanHandler is an HTTP handler that accepts GET parameters for host (required) // family and scanner, and uses these to perform scans, returning a JSON blob result. func scanHandler(w http.ResponseWriter, r *http.Request) error { if err := r.ParseForm(); err != nil { log.Warningf("failed to parse body: %v", err) return errors.NewBadRequest(err) } family := r.Form.Get("family") scanner := r.Form.Get("scanner") ip := r.Form.Get("ip") timeoutStr := r.Form.Get("timeout") var timeout time.Duration var err error if timeoutStr != "" { if timeout, err = time.ParseDuration(timeoutStr); err != nil { return errors.NewBadRequest(err) } if timeout < time.Second || timeout > 5*time.Minute { return errors.NewBadRequestString("invalid timeout given") } } else { timeout = time.Minute } host := r.Form.Get("host") if host == "" { log.Warningf("no host given") return errors.NewBadRequestString("no host given") } results, err := scan.Default.RunScans(host, ip, family, scanner, timeout) if err != nil { return errors.NewBadRequest(err) } return json.NewEncoder(w).Encode(api.NewSuccessResponse(results)) }
func (h *signHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { if atomic.LoadUint32(h.flaky) == 1 { w.WriteHeader(http.StatusInternalServerError) } // Check client authentication via mutual TLS. if r.TLS == nil || len(r.TLS.PeerCertificates) == 0 { cfsslErr := cfsslerrors.New(cfsslerrors.APIClientError, cfsslerrors.AuthenticationFailure) errResponse := api.NewErrorResponse("must authenticate sign request with mutual TLS", cfsslErr.ErrorCode) json.NewEncoder(w).Encode(errResponse) return } clientSub := r.TLS.PeerCertificates[0].Subject // The client certificate OU should be for a swarm manager. if len(clientSub.OrganizationalUnit) == 0 || clientSub.OrganizationalUnit[0] != ca.ManagerRole { cfsslErr := cfsslerrors.New(cfsslerrors.APIClientError, cfsslerrors.AuthenticationFailure) errResponse := api.NewErrorResponse(fmt.Sprintf("client certificate OU must be %q", ca.ManagerRole), cfsslErr.ErrorCode) json.NewEncoder(w).Encode(errResponse) return } // The client certificate must have an Org. if len(clientSub.Organization) == 0 { cfsslErr := cfsslerrors.New(cfsslerrors.APIClientError, cfsslerrors.AuthenticationFailure) errResponse := api.NewErrorResponse("client certificate must have an Organization", cfsslErr.ErrorCode) json.NewEncoder(w).Encode(errResponse) return } clientOrg := clientSub.Organization[0] // Decode the certificate signing request. var signReq signer.SignRequest if err := json.NewDecoder(r.Body).Decode(&signReq); err != nil { cfsslErr := cfsslerrors.New(cfsslerrors.APIClientError, cfsslerrors.JSONError) errResponse := api.NewErrorResponse(fmt.Sprintf("unable to decode sign request: %s", err), cfsslErr.ErrorCode) json.NewEncoder(w).Encode(errResponse) return } // The signReq should have additional subject info. reqSub := signReq.Subject if reqSub == nil { cfsslErr := cfsslerrors.New(cfsslerrors.CSRError, cfsslerrors.BadRequest) errResponse := api.NewErrorResponse("sign request must contain a subject field", cfsslErr.ErrorCode) json.NewEncoder(w).Encode(errResponse) return } // The client's Org should match the Org in the sign request subject. if len(reqSub.Name().Organization) == 0 || reqSub.Name().Organization[0] != clientOrg { cfsslErr := cfsslerrors.New(cfsslerrors.CSRError, cfsslerrors.BadRequest) errResponse := api.NewErrorResponse("sign request subject org does not match client certificate org", cfsslErr.ErrorCode) json.NewEncoder(w).Encode(errResponse) return } // Finally, sign the requested certificate. certPEM, err := h.rootCA.Signer.Sign(signReq) if err != nil { cfsslErr := cfsslerrors.New(cfsslerrors.APIClientError, cfsslerrors.ServerRequestFailed) errResponse := api.NewErrorResponse(fmt.Sprintf("unable to sign requested certificate: %s", err), cfsslErr.ErrorCode) json.NewEncoder(w).Encode(errResponse) return } result := map[string]string{ "certificate": string(certPEM), } // Increment the number of certs issued. atomic.AddUint64(h.numIssued, 1) // Return a successful JSON response. json.NewEncoder(w).Encode(api.NewSuccessResponse(result)) }
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) } }