1// Package bundle implements the HTTP handler for the bundle command. 2package bundle 3 4import ( 5 "net/http" 6 7 "github.com/cloudflare/cfssl/api" 8 "github.com/cloudflare/cfssl/bundler" 9 "github.com/cloudflare/cfssl/errors" 10 "github.com/cloudflare/cfssl/log" 11) 12 13// Handler accepts requests for either remote or uploaded 14// certificates to be bundled, and returns a certificate bundle (or 15// error). 16type Handler struct { 17 bundler *bundler.Bundler 18} 19 20// NewHandler creates a new bundler that uses the root bundle and 21// intermediate bundle in the trust chain. 22func NewHandler(caBundleFile, intBundleFile string) (http.Handler, error) { 23 var err error 24 25 b := new(Handler) 26 if b.bundler, err = bundler.NewBundler(caBundleFile, intBundleFile); err != nil { 27 return nil, err 28 } 29 30 log.Info("bundler API ready") 31 return api.HTTPHandler{Handler: b, Methods: []string{"POST"}}, nil 32} 33 34// Handle implements an http.Handler interface for the bundle handler. 35func (h *Handler) Handle(w http.ResponseWriter, r *http.Request) error { 36 blob, matched, err := api.ProcessRequestFirstMatchOf(r, 37 [][]string{ 38 {"certificate"}, 39 {"domain"}, 40 }) 41 if err != nil { 42 log.Warningf("invalid request: %v", err) 43 return err 44 } 45 46 flavor := blob["flavor"] 47 bf := bundler.Ubiquitous 48 if flavor != "" { 49 bf = bundler.BundleFlavor(flavor) 50 } 51 log.Infof("request for flavor %v", bf) 52 53 var result *bundler.Bundle 54 switch matched[0] { 55 case "domain": 56 bundle, err := h.bundler.BundleFromRemote(blob["domain"], blob["ip"], bf) 57 if err != nil { 58 log.Warningf("couldn't bundle from remote: %v", err) 59 return err 60 } 61 result = bundle 62 case "certificate": 63 bundle, err := h.bundler.BundleFromPEMorDER([]byte(blob["certificate"]), []byte(blob["private_key"]), bf, "") 64 if err != nil { 65 log.Warning("bad PEM certifcate or private key") 66 return err 67 } 68 69 serverName := blob["domain"] 70 ip := blob["ip"] 71 72 if serverName != "" { 73 err := bundle.Cert.VerifyHostname(serverName) 74 if err != nil { 75 return errors.Wrap(errors.CertificateError, errors.VerifyFailed, err) 76 } 77 78 } 79 80 if ip != "" { 81 err := bundle.Cert.VerifyHostname(ip) 82 if err != nil { 83 return errors.Wrap(errors.CertificateError, errors.VerifyFailed, err) 84 } 85 } 86 87 result = bundle 88 } 89 log.Info("wrote response") 90 return api.SendResponse(w, result) 91} 92