func fail(w http.ResponseWriter, req *http.Request, status, code int, msg, ad string) { incErrors() if ad != "" { ad = " (" + ad + ")" } log.Errorf("[HTTP %d] %d - %s%s", status, code, msg, ad) dumpReq, err := httputil.DumpRequest(req, true) if err != nil { fmt.Printf("%v#v\n", req) } else { fmt.Printf("%s\n", dumpReq) } res := api.NewErrorResponse(msg, code) w.WriteHeader(status) jenc := json.NewEncoder(w) jenc.Encode(res) }
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)) }