Beispiel #1
0
// 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 signReq.Hosts == nil {
		return errors.NewBadRequestString("missing parameter 'hostname' or 'hosts'")
	}

	if req.Request == "" {
		return errors.NewBadRequestString("missing parameter 'certificate_request'")
	}

	var cert []byte
	var profile *config.SigningProfile

	policy := h.signer.Policy()
	if policy != nil && policy.Profiles != nil && req.Profile != "" {
		profile = policy.Profiles[req.Profile]
	}

	if profile == nil && policy != nil {
		profile = policy.Default
	}

	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)
}
Beispiel #2
0
// NewCertGeneratorHandler builds a new handler for generating
// certificates directly from certificate requests; the validator covers
// the certificate request and the CA's key and certificate are used to
// sign the generated request. If remote is not an empty string, the
// handler will send signature requests to the CFSSL instance contained
// in remote.
func NewCertGeneratorHandler(validator Validator, caFile, caKeyFile string, policy *config.Signing) (http.Handler, error) {
	var err error
	log.Info("setting up new generator / signer")
	cg := new(CertGeneratorHandler)

	if policy == nil {
		policy = &config.Signing{
			Default:  config.DefaultConfig(),
			Profiles: nil,
		}
	}

	root := universal.Root{
		Config: map[string]string{
			"ca-file":     caFile,
			"ca-key-file": caKeyFile,
		},
	}
	if cg.signer, err = universal.NewSigner(root, policy); err != nil {
		log.Errorf("setting up signer failed: %v", err)
		return nil, err
	}

	cg.generator = &csr.Generator{Validator: validator}

	return api.HTTPHandler{Handler: cg, Method: "POST"}, nil
}
Beispiel #3
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")
	req := new(csr.CertificateRequest)
	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)
	}

	key, cert, 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
}
Beispiel #4
0
// Generate creates a new CSR from a CertificateRequest structure and
// an existing key. The KeyRequest field is ignored.
func Generate(priv crypto.Signer, req *CertificateRequest) (csr []byte, err error) {
	sigAlgo := helpers.SignerAlgo(priv, crypto.SHA256)
	if sigAlgo == x509.UnknownSignatureAlgorithm {
		return nil, cferr.New(cferr.PrivateKeyError, cferr.Unavailable)
	}

	var tpl = x509.CertificateRequest{
		Subject:            req.Name(),
		SignatureAlgorithm: sigAlgo,
	}

	for i := range req.Hosts {
		if ip := net.ParseIP(req.Hosts[i]); ip != nil {
			tpl.IPAddresses = append(tpl.IPAddresses, ip)
		} else {
			tpl.DNSNames = append(tpl.DNSNames, req.Hosts[i])
		}
	}

	csr, err = x509.CreateCertificateRequest(rand.Reader, &tpl, priv)
	if err != nil {
		log.Errorf("failed to generate a CSR: %v", err)
		err = cferr.Wrap(cferr.CSRError, cferr.BadRequest, err)
		return
	}
	block := pem.Block{
		Type:  "CERTIFICATE REQUEST",
		Bytes: csr,
	}

	log.Info("encoded CSR")
	csr = pem.EncodeToMemory(&block)
	return
}
Beispiel #5
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
}
Beispiel #6
0
func TestOverrideSubject(t *testing.T) {
	csrPEM, err := ioutil.ReadFile(fullSubjectCSR)
	if err != nil {
		t.Fatalf("%v", err)
	}

	req := &signer.Subject{
		Names: []csr.Name{
			{O: "example.net"},
		},
	}

	s := newCustomSigner(t, testECDSACaFile, testECDSACaKeyFile)

	request := signer.SignRequest{
		Hosts:   []string{"127.0.0.1", "localhost"},
		Request: string(csrPEM),
		Subject: req,
	}

	certPEM, err := s.Sign(request)

	if err != nil {
		t.Fatalf("%v", err)
	}

	cert, err := helpers.ParseCertificatePEM(certPEM)
	if err != nil {
		t.Fatalf("%v", err)
	}

	block, _ := pem.Decode(csrPEM)
	template, err := x509.ParseCertificateRequest(block.Bytes)
	if err != nil {
		t.Fatal(err.Error())
	}
	if cert.Subject.Organization[0] != "example.net" {
		t.Fatalf("Failed to override subject: want example.net but have %s", cert.Subject.Organization[0])
	}

	if cert.Subject.Country[0] != template.Subject.Country[0] {
		t.Fatal("Failed to override Country")
	}

	if cert.Subject.Locality[0] != template.Subject.Locality[0] {
		t.Fatal("Failed to override Locality")
	}

	if cert.Subject.Organization[0] == template.Subject.Organization[0] {
		t.Fatal("Shouldn't have overrode Organization")
	}

	if cert.Subject.OrganizationalUnit[0] != template.Subject.OrganizationalUnit[0] {
		t.Fatal("Failed to override OrganizationalUnit")
	}

	log.Info("Overrode subject info")
}
Beispiel #7
0
// Handle implements an http.Handler interface for the bundle handler.
func (h *Handler) Handle(w http.ResponseWriter, r *http.Request) error {
	blob, matched, err := api.ProcessRequestFirstMatchOf(r,
		[][]string{
			[]string{"certificate"},
			[]string{"domain"},
		})
	if err != nil {
		log.Warningf("invalid request: %v", err)
		return err
	}

	flavor := blob["flavor"]
	bf := bundler.Ubiquitous
	if flavor != "" {
		bf = bundler.BundleFlavor(flavor)
	}
	log.Infof("request for flavor %v", bf)

	var result *bundler.Bundle
	switch matched[0] {
	case "domain":
		bundle, err := h.bundler.BundleFromRemote(blob["domain"], blob["ip"], bf)
		if err != nil {
			log.Warningf("couldn't bundle from remote: %v", err)
			return err
		}
		result = bundle
	case "certificate":
		bundle, err := h.bundler.BundleFromPEM([]byte(blob["certificate"]), []byte(blob["private_key"]), bf)
		if err != nil {
			log.Warning("bad PEM certifcate or private key")
			return err
		}

		serverName := blob["domain"]
		ip := blob["ip"]

		if serverName != "" {
			err := bundle.Cert.VerifyHostname(serverName)
			if err != nil {
				return errors.Wrap(errors.CertificateError, errors.VerifyFailed, err)
			}

		}

		if ip != "" {
			err := bundle.Cert.VerifyHostname(ip)
			if err != nil {
				return errors.Wrap(errors.CertificateError, errors.VerifyFailed, err)
			}
		}

		result = bundle
	}
	log.Info("wrote response")
	return api.SendResponse(w, result)
}
Beispiel #8
0
// NewHandler builds a new Handler from the
// validation function provided.
func NewHandler(validator Validator) (http.Handler, error) {
	log.Info("setting up key / CSR generator")
	return &api.HTTPHandler{
		Handler: &Handler{
			generator: &csr.Generator{Validator: validator},
		},
		Method: "POST",
	}, nil
}
Beispiel #9
0
// NewHandler creates a new bundler that uses the root bundle and
// intermediate bundle in the trust chain.
func NewHandler(caBundleFile, intBundleFile string) (http.Handler, error) {
	var err error

	b := new(Handler)
	if b.bundler, err = bundler.NewBundler(caBundleFile, intBundleFile); err != nil {
		return nil, err
	}

	log.Info("bundler API ready")
	return api.HTTPHandler{Handler: b, Method: "POST"}, nil
}
Beispiel #10
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 {
	log.Info("setting up scan handler")

	err := r.ParseForm()
	log.Info(r.Form)
	if 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)
	err = enc.Encode(response)
	return err
}
Beispiel #11
0
// ProcessRequest validates and processes the incoming request. It is
// a wrapper around a validator and the ParseRequest function.
func (g *Generator) ProcessRequest(req *CertificateRequest) (csr, key []byte, err error) {

	log.Info("generate received request")
	err = g.Validator(req)
	if err != nil {
		log.Warningf("invalid request: %v", err)
		return
	}

	csr, key, err = ParseRequest(req)
	if err != nil {
		return nil, nil, err
	}
	return
}
Beispiel #12
0
func (b *Bundler) verifyChain(chain []*fetchedIntermediate) bool {
	// This process will verify if the root of the (partial) chain is in our root pool,
	// and will fail otherwise.
	log.Debugf("verifying chain")
	for vchain := chain[:]; len(vchain) > 0; vchain = vchain[1:] {
		cert := vchain[0]
		// If this is a certificate in one of the pools, skip it.
		if b.KnownIssuers[string(cert.Cert.Signature)] {
			log.Debugf("certificate is known")
			continue
		}

		_, err := cert.Cert.Verify(b.VerifyOptions())
		if err != nil {
			log.Debugf("certificate failed verification: %v", err)
			return false
		} else if len(chain) == len(vchain) && isChainRootNode(cert.Cert) {
			// The first certificate in the chain is a root; it shouldn't be stored.
			log.Debug("looking at root certificate, will not store")
			continue
		}

		// leaf cert has an empty name, don't store leaf cert.
		if cert.Name == "" {
			continue
		}

		log.Debug("add certificate to intermediate pool:", cert.Name)
		b.IntermediatePool.AddCert(cert.Cert)
		b.KnownIssuers[string(cert.Cert.Signature)] = true

		fileName := filepath.Join(IntermediateStash, cert.Name)

		var block = pem.Block{Type: "CERTIFICATE", Bytes: cert.Cert.Raw}

		log.Debugf("write intermediate to stash directory: %s", fileName)
		// If the write fails, verification should not fail.
		err = ioutil.WriteFile(fileName, pem.EncodeToMemory(&block), 0644)
		if err != nil {
			log.Errorf("failed to write new intermediate: %v", err)
		} else {
			log.Info("stashed new intermediate ", cert.Name)
		}
	}
	return true
}
Beispiel #13
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")
	req := new(csr.CertificateRequest)
	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.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
}
Beispiel #14
0
// serverMain is the command line entry point to the API server. It sets up a
// new HTTP server to handle sign, bundle, and validate requests.
func serverMain(args []string, c cli.Config) error {
	// serve doesn't support arguments.
	if len(args) > 0 {
		return errors.New("argument is provided but not defined; please refer to the usage by flag -h")
	}

	bundler.IntermediateStash = c.IntDir
	err := ubiquity.LoadPlatforms(c.Metadata)
	if err != nil {
		log.Error(err)
	}

	err = registerHandlers(c)
	if err != nil {
		return err
	}

	addr := fmt.Sprintf("%s:%d", c.Address, c.Port)
	log.Info("Now listening on ", addr)
	return http.ListenAndServe(addr, nil)
}
Beispiel #15
0
// 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)
	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
	}

	var certPEM []byte

	var profile *config.SigningProfile
	policy := cg.signer.Policy()
	if policy != nil && policy.Profiles != nil && req.Profile != "" {
		profile = policy.Profiles[req.Profile]
	}

	if profile == nil && policy != nil {
		profile = policy.Default
	}

	// This API does not override the subject because it was already added to the CSR
	signReq := signer.SignRequest{
		Hosts:   signer.SplitHosts(req.Hostname),
		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(certPEM),
		"sums": map[string]Sum{
			"certificate_request": reqSum,
			"certificate":         certSum,
		},
	}
	return api.SendResponse(w, result)
}
Beispiel #16
0
// 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 := policy.Default

	if policy.Profiles != nil && req.Profile != "" {
		profile = policy.Profiles[req.Profile]
	}

	if profile == nil {
		log.Critical("signer was initialised without any valid profiles")
		return errors.NewBadRequestString("invalid profile")
	}

	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.Hosts == nil {
		return errors.NewBadRequestString("missing parameter 'hostname' or 'hosts'")
	}

	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)
}
Beispiel #17
0
// ParseRequest takes a certificate request and generates a key and
// CSR from it. It does no validation -- caveat emptor. It will,
// however, fail if the key request is not valid (i.e., an unsupported
// curve or RSA key size). The lack of validation was specifically
// chosen to allow the end user to define a policy and validate the
// request appropriately before calling this function.
func ParseRequest(req *CertificateRequest) (csr, key []byte, err error) {
	log.Info("received CSR")
	if req.KeyRequest == nil {
		req.KeyRequest = &KeyRequest{
			Algo: DefaultKeyRequest.Algo,
			Size: DefaultKeyRequest.Size,
		}
	}

	log.Infof("generating key: %s-%d", req.KeyRequest.Algo, req.KeyRequest.Size)
	priv, err := req.KeyRequest.Generate()
	if err != nil {
		err = cferr.Wrap(cferr.PrivateKeyError, cferr.GenerationFailed, err)
		return
	}

	switch priv := priv.(type) {
	case *rsa.PrivateKey:
		key = x509.MarshalPKCS1PrivateKey(priv)
		block := pem.Block{
			Type:  "RSA PRIVATE KEY",
			Bytes: key,
		}
		key = pem.EncodeToMemory(&block)
	case *ecdsa.PrivateKey:
		key, err = x509.MarshalECPrivateKey(priv)
		if err != nil {
			err = cferr.Wrap(cferr.PrivateKeyError, cferr.Unknown, err)
			return
		}
		block := pem.Block{
			Type:  "EC PRIVATE KEY",
			Bytes: key,
		}
		key = pem.EncodeToMemory(&block)
	default:
		panic("Generate should have failed to produce a valid key.")
	}

	var tpl = x509.CertificateRequest{
		Subject:            req.Name(),
		SignatureAlgorithm: req.KeyRequest.SigAlgo(),
	}

	for i := range req.Hosts {
		if ip := net.ParseIP(req.Hosts[i]); ip != nil {
			tpl.IPAddresses = append(tpl.IPAddresses, ip)
		} else {
			tpl.DNSNames = append(tpl.DNSNames, req.Hosts[i])
		}
	}

	csr, err = x509.CreateCertificateRequest(rand.Reader, &tpl, priv)
	if err != nil {
		log.Errorf("failed to generate a CSR: %v", err)
		err = cferr.Wrap(cferr.CSRError, cferr.BadRequest, err)
		return
	}
	block := pem.Block{
		Type:  "CERTIFICATE REQUEST",
		Bytes: csr,
	}

	log.Info("encoded CSR")
	csr = pem.EncodeToMemory(&block)
	return
}
Beispiel #18
0
// registerHandlers instantiates various handlers and associate them to corresponding endpoints.
func registerHandlers(c cli.Config) error {
	log.Info("Setting up signer endpoint")
	s, err := sign.SignerFromConfig(c)
	if err != nil {
		log.Warningf("sign and authsign endpoints are disabled: %v", err)
	} else {
		if signHandler, err := apisign.NewHandlerFromSigner(s); err == nil {
			log.Info("Assigning handler to /sign")
			http.Handle("/api/v1/cfssl/sign", signHandler)
		} else {
			log.Warningf("endpoint '/api/v1/cfssl/sign' is disabled: %v", err)
		}

		if signHandler, err := apisign.NewAuthHandlerFromSigner(s); err == nil {
			log.Info("Assigning handler to /authsign")
			http.Handle("/api/v1/cfssl/authsign", signHandler)
		} else {
			log.Warningf("endpoint '/api/v1/cfssl/authsign' is disabled: %v", err)
		}
	}

	log.Info("Setting up info endpoint")
	infoHandler, err := info.NewHandler(s)
	if err != nil {
		log.Warningf("endpoint '/api/v1/cfssl/info' is disabled: %v", err)
	} else {
		http.Handle("/api/v1/cfssl/info", infoHandler)
	}

	log.Info("Setting up new cert endpoint")
	if err != nil {
		log.Errorf("endpoint '/api/v1/cfssl/newcert' is disabled")
	} else {
		newCertGenerator := generator.NewCertGeneratorHandlerFromSigner(generator.CSRValidate, s)
		http.Handle("/api/v1/cfssl/newcert", newCertGenerator)
	}

	log.Info("Setting up bundler endpoint")
	bundleHandler, err := bundle.NewHandler(c.CABundleFile, c.IntBundleFile)
	if err != nil {
		log.Warningf("endpoint '/api/v1/cfssl/bundle' is disabled: %v", err)
	} else {
		http.Handle("/api/v1/cfssl/bundle", bundleHandler)
	}

	log.Info("Setting up CSR endpoint")
	generatorHandler, err := generator.NewHandler(generator.CSRValidate)
	if err != nil {
		log.Errorf("Failed to set up CSR endpoint: %v", err)
		return err
	}
	http.Handle("/api/v1/cfssl/newkey", generatorHandler)

	log.Info("Setting up initial CA endpoint")
	http.Handle("/api/v1/cfssl/init_ca", initca.NewHandler())

	log.Info("Setting up scan endpoint")
	http.Handle("/api/v1/cfssl/scan", scan.NewHandler())

	log.Info("Setting up scaninfo endpoint")
	http.Handle("/api/v1/cfssl/scaninfo", scan.NewInfoHandler())

	log.Info("Handler set up complete.")
	return nil
}
Beispiel #19
0
// ParseRequest takes a certificate request and generates a key and
// CSR from it. It does no validation -- caveat emptor. It will,
// however, fail if the key request is not valid (i.e., an unsupported
// curve or RSA key size). The lack of validation was specifically
// chosen to allow the end user to define a policy and validate the
// request appropriately before calling this function.
func ParseRequest(req *CertificateRequest) (csr, key []byte, err error) {
	log.Info("received CSR")
	if req.KeyRequest == nil {
		req.KeyRequest = &KeyRequest{
			Algo: DefaultKeyRequest.Algo,
			Size: DefaultKeyRequest.Size,
		}
	}

	log.Infof("generating key: %s-%d", req.KeyRequest.Algo, req.KeyRequest.Size)
	priv, err := req.KeyRequest.Generate()
	if err != nil {
		err = cferr.Wrap(cferr.PrivateKeyError, cferr.GenerationFailed, err)
		return
	}

	switch priv := priv.(type) {
	case *rsa.PrivateKey:
		key = x509.MarshalPKCS1PrivateKey(priv)
		block := pem.Block{
			Type:  "RSA PRIVATE KEY",
			Bytes: key,
		}
		key = pem.EncodeToMemory(&block)
	case *ecdsa.PrivateKey:
		key, err = x509.MarshalECPrivateKey(priv)
		if err != nil {
			err = cferr.Wrap(cferr.PrivateKeyError, cferr.Unknown, err)
			return
		}
		block := pem.Block{
			Type:  "EC PRIVATE KEY",
			Bytes: key,
		}
		key = pem.EncodeToMemory(&block)
	default:
		panic("Generate should have failed to produce a valid key.")
	}

	var tpl = x509.CertificateRequest{
		Subject:            req.Name(),
		SignatureAlgorithm: req.KeyRequest.SigAlgo(),
		DNSNames:           req.Hosts,
	}
	csr, err = x509.CreateCertificateRequest(rand.Reader, &tpl, priv)
	if err != nil {
		log.Errorf("failed to generate a CSR: %v", err)
		// The use of CertificateError was a matter of some
		// debate; it is the one edge case in which a new
		// error category specifically for CSRs might be
		// useful, but it was deemed that one edge case did
		// not a new category justify.
		err = cferr.Wrap(cferr.CertificateError, cferr.BadRequest, err)
		return
	}
	block := pem.Block{
		Type:  "CERTIFICATE REQUEST",
		Bytes: csr,
	}

	log.Info("encoded CSR")
	csr = pem.EncodeToMemory(&block)
	return
}