func computeSum(in []byte) (sum Sum, err error) { var data []byte p, _ := pem.Decode(in) if p == nil { err = errors.NewBadRequestString("not a CSR or certificate") return } switch p.Type { case "CERTIFICATE REQUEST": var req *x509.CertificateRequest req, err = x509.ParseCertificateRequest(p.Bytes) if err != nil { return } data = req.Raw case "CERTIFICATE": var cert *x509.Certificate cert, err = x509.ParseCertificate(p.Bytes) if err != nil { return } data = cert.Raw default: err = errors.NewBadRequestString("not a CSR or certificate") return } md5Sum := md5.Sum(data) sha1Sum := sha1.Sum(data) sum.MD5 = fmt.Sprintf("%X", md5Sum[:]) sum.SHA1 = fmt.Sprintf("%X", sha1Sum[:]) 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") } } } 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) }
// 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 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) }
// ProcessRequestOneOf reads a JSON blob for the request and makes // sure it contains one of a set of keywords. For example, a request // might have the ('foo' && 'bar') keys, OR it might have the 'baz' // key. In either case, we want to accept the request; however, if // none of these sets shows up, the request is a bad request, and it // should be returned. func ProcessRequestOneOf(r *http.Request, keywordSets [][]string) (map[string]string, []string, error) { blob, err := readRequestBlob(r) if err != nil { return nil, nil, err } var matched []string for _, set := range keywordSets { if matchKeywords(blob, set) { if matched != nil { return nil, nil, errors.NewBadRequestString("mismatched parameters") } matched = set } } if matched == nil { return nil, nil, errors.NewBadRequestString("no valid parameter sets found") } return blob, matched, nil }
// ProcessRequestFirstMatchOf reads a JSON blob for the request and returns // the first match of a set of keywords. For example, a request // might have one of the following combinations: (foo=1, bar=2), (foo=1), and (bar=2) // By giving a specific ordering of those combinations, we could decide how to accept // the request. func ProcessRequestFirstMatchOf(r *http.Request, keywordSets [][]string) (map[string]string, []string, error) { blob, err := readRequestBlob(r) if err != nil { return nil, nil, err } for _, set := range keywordSets { if matchKeywords(blob, set) { return blob, set, nil } } return nil, nil, errors.NewBadRequestString("no valid parameter sets found") }
// 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)) }
// 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) } 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 }
// 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) }
// Handle responds to requests for the CA to generate a new private // key and certificate on behalf of the client. The format for these // requests is documented in the API documentation. func (cg *CertGeneratorHandler) Handle(w http.ResponseWriter, r *http.Request) error { log.Info("request for CSR") req := new(genSignRequest) req.Request = csr.New() 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) } if req.Request == nil { log.Warning("empty request received") return errors.NewBadRequestString("missing request section") } if req.Request.CA != nil { log.Warningf("request received with CA section") return errors.NewBadRequestString("ca section only permitted in initca") } csr, key, err := cg.generator.ProcessRequest(req.Request) if err != nil { log.Warningf("failed to process CSR: %v", err) // The validator returns a *cfssl/errors.HttpError return err } signReq := signer.SignRequest{ Request: string(csr), Profile: req.Profile, Label: req.Label, } certBytes, err := cg.signer.Sign(signReq) if err != nil { log.Warningf("failed to sign request: %v", err) return err } reqSum, err := computeSum(csr) if err != nil { return errors.NewBadRequest(err) } certSum, err := computeSum(certBytes) if err != nil { return errors.NewBadRequest(err) } result := map[string]interface{}{ "private_key": string(key), "certificate_request": string(csr), "certificate": string(certBytes), "sums": map[string]Sum{ "certificate_request": reqSum, "certificate": certSum, }, } if len(req.Request.Hosts) == 0 { return api.SendResponseWithMessage(w, result, CSRNoHostMessage, errors.New(errors.PolicyError, errors.InvalidRequest).ErrorCode) } return api.SendResponse(w, result) }
// 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) }