1// Package certinfo implements the HTTP handler for the certinfo command.
2package certinfo
3
4import (
5	"errors"
6	"net/http"
7
8	"github.com/cloudflare/cfssl/api"
9	"github.com/cloudflare/cfssl/certdb"
10	"github.com/cloudflare/cfssl/certinfo"
11	"github.com/cloudflare/cfssl/log"
12)
13
14// Handler accepts requests for either remote or uploaded
15// certificates to be bundled, and returns a certificate bundle (or
16// error).
17type Handler struct {
18	dbAccessor certdb.Accessor
19}
20
21// NewHandler creates a new bundler that uses the root bundle and
22// intermediate bundle in the trust chain.
23func NewHandler() http.Handler {
24	return api.HTTPHandler{Handler: new(Handler), Methods: []string{"POST"}}
25}
26
27// NewAccessorHandler creates a new bundler with database access via the
28// certdb.Accessor interface. If this handler is constructed it will be possible
29// to lookup certificates issued earlier by the CA.
30func NewAccessorHandler(dbAccessor certdb.Accessor) http.Handler {
31	return api.HTTPHandler{
32		Handler: &Handler{
33			dbAccessor: dbAccessor,
34		},
35		Methods: []string{"POST"},
36	}
37}
38
39// Handle implements an http.Handler interface for the bundle handler.
40func (h *Handler) Handle(w http.ResponseWriter, r *http.Request) (err error) {
41	blob, matched, err := api.ProcessRequestFirstMatchOf(r,
42		[][]string{
43			{"certificate"},
44			{"domain"},
45			{"serial", "authority_key_id"},
46		})
47	if err != nil {
48		log.Warningf("invalid request: %v", err)
49		return err
50	}
51
52	var cert *certinfo.Certificate
53	switch matched[0] {
54	case "domain":
55		if cert, err = certinfo.ParseCertificateDomain(blob["domain"]); err != nil {
56			log.Warningf("couldn't parse remote certificate: %v", err)
57			return err
58		}
59	case "certificate":
60		if cert, err = certinfo.ParseCertificatePEM([]byte(blob["certificate"])); err != nil {
61			log.Warningf("bad PEM certifcate: %v", err)
62			return err
63		}
64	case "serial", "authority_key_id":
65		if h.dbAccessor == nil {
66			log.Warning("could not find certificates with db access")
67
68			return errors.New("cannot lookup certificate from serial without db access")
69		}
70
71		if cert, err = certinfo.ParseSerialNumber(blob["serial"], blob["authority_key_id"], h.dbAccessor); err != nil {
72			log.Warningf("couldn't find certificate: %v", err)
73
74			return err
75		}
76	}
77
78	return api.SendResponse(w, cert)
79}
80