Ejemplo n.º 1
0
// 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
}
Ejemplo n.º 2
0
// 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)
}
Ejemplo n.º 3
0
// 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)
}
Ejemplo n.º 4
0
// 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
}
Ejemplo n.º 5
0
// 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)
}
Ejemplo n.º 6
0
// 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)
}
Ejemplo n.º 7
0
// 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
}
Ejemplo n.º 8
0
// 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))
}
Ejemplo n.º 9
0
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))
}
Ejemplo n.º 10
0
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)
	}
}