generator.go 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320
  1. // Package generator implements the HTTP handlers for certificate generation.
  2. package generator
  3. import (
  4. "crypto/md5"
  5. "crypto/sha1"
  6. "crypto/x509"
  7. "encoding/json"
  8. "encoding/pem"
  9. "fmt"
  10. "io/ioutil"
  11. "net/http"
  12. "github.com/cloudflare/cfssl/api"
  13. "github.com/cloudflare/cfssl/bundler"
  14. "github.com/cloudflare/cfssl/config"
  15. "github.com/cloudflare/cfssl/csr"
  16. "github.com/cloudflare/cfssl/errors"
  17. "github.com/cloudflare/cfssl/log"
  18. "github.com/cloudflare/cfssl/signer"
  19. "github.com/cloudflare/cfssl/signer/universal"
  20. )
  21. const (
  22. // CSRNoHostMessage is used to alert the user to a certificate lacking a hosts field.
  23. CSRNoHostMessage = `This certificate lacks a "hosts" field. This makes it unsuitable for
  24. websites. For more information see the Baseline Requirements for the Issuance and Management
  25. of Publicly-Trusted Certificates, v.1.1.6, from the CA/Browser Forum (https://cabforum.org);
  26. specifically, section 10.2.3 ("Information Requirements").`
  27. // NoBundlerMessage is used to alert the user that the server does not have a bundler initialized.
  28. NoBundlerMessage = `This request requires a bundler, but one is not initialized for the API server.`
  29. )
  30. // Sum contains digests for a certificate or certificate request.
  31. type Sum struct {
  32. MD5 string `json:"md5"`
  33. SHA1 string `json:"sha-1"`
  34. }
  35. // Validator is a type of function that contains the logic for validating
  36. // a certificate request.
  37. type Validator func(*csr.CertificateRequest) error
  38. // A CertRequest stores a PEM-encoded private key and corresponding
  39. // CSR; this is returned from the CSR generation endpoint.
  40. type CertRequest struct {
  41. Key string `json:"private_key"`
  42. CSR string `json:"certificate_request"`
  43. Sums map[string]Sum `json:"sums"`
  44. }
  45. // A Handler accepts JSON-encoded certificate requests and
  46. // returns a new private key and certificate request.
  47. type Handler struct {
  48. generator *csr.Generator
  49. }
  50. // NewHandler builds a new Handler from the
  51. // validation function provided.
  52. func NewHandler(validator Validator) (http.Handler, error) {
  53. log.Info("setting up key / CSR generator")
  54. return &api.HTTPHandler{
  55. Handler: &Handler{
  56. generator: &csr.Generator{Validator: validator},
  57. },
  58. Methods: []string{"POST"},
  59. }, nil
  60. }
  61. func computeSum(in []byte) (sum Sum, err error) {
  62. var data []byte
  63. p, _ := pem.Decode(in)
  64. if p == nil {
  65. err = errors.NewBadRequestString("not a CSR or certificate")
  66. return
  67. }
  68. switch p.Type {
  69. case "CERTIFICATE REQUEST":
  70. var req *x509.CertificateRequest
  71. req, err = x509.ParseCertificateRequest(p.Bytes)
  72. if err != nil {
  73. return
  74. }
  75. data = req.Raw
  76. case "CERTIFICATE":
  77. var cert *x509.Certificate
  78. cert, err = x509.ParseCertificate(p.Bytes)
  79. if err != nil {
  80. return
  81. }
  82. data = cert.Raw
  83. default:
  84. err = errors.NewBadRequestString("not a CSR or certificate")
  85. return
  86. }
  87. md5Sum := md5.Sum(data)
  88. sha1Sum := sha1.Sum(data)
  89. sum.MD5 = fmt.Sprintf("%X", md5Sum[:])
  90. sum.SHA1 = fmt.Sprintf("%X", sha1Sum[:])
  91. return
  92. }
  93. // Handle responds to requests for the CA to generate a new private
  94. // key and certificate request on behalf of the client. The format for
  95. // these requests is documented in the API documentation.
  96. func (g *Handler) Handle(w http.ResponseWriter, r *http.Request) error {
  97. log.Info("request for CSR")
  98. body, err := ioutil.ReadAll(r.Body)
  99. if err != nil {
  100. log.Warningf("failed to read request body: %v", err)
  101. return errors.NewBadRequest(err)
  102. }
  103. r.Body.Close()
  104. req := new(csr.CertificateRequest)
  105. req.KeyRequest = csr.NewBasicKeyRequest()
  106. err = json.Unmarshal(body, req)
  107. if err != nil {
  108. log.Warningf("failed to unmarshal request: %v", err)
  109. return errors.NewBadRequest(err)
  110. }
  111. if req.CA != nil {
  112. log.Warningf("request received with CA section")
  113. return errors.NewBadRequestString("ca section only permitted in initca")
  114. }
  115. csr, key, err := g.generator.ProcessRequest(req)
  116. if err != nil {
  117. log.Warningf("failed to process CSR: %v", err)
  118. // The validator returns a *cfssl/errors.HttpError
  119. return err
  120. }
  121. sum, err := computeSum(csr)
  122. if err != nil {
  123. return errors.NewBadRequest(err)
  124. }
  125. // Both key and csr are returned PEM-encoded.
  126. response := api.NewSuccessResponse(&CertRequest{
  127. Key: string(key),
  128. CSR: string(csr),
  129. Sums: map[string]Sum{"certificate_request": sum},
  130. })
  131. w.Header().Set("Content-Type", "application/json")
  132. enc := json.NewEncoder(w)
  133. err = enc.Encode(response)
  134. return err
  135. }
  136. // A CertGeneratorHandler accepts JSON-encoded certificate requests
  137. // and returns a new private key and signed certificate; it handles
  138. // sending the CSR to the server.
  139. type CertGeneratorHandler struct {
  140. generator *csr.Generator
  141. bundler *bundler.Bundler
  142. signer signer.Signer
  143. }
  144. // NewCertGeneratorHandler builds a new handler for generating
  145. // certificates directly from certificate requests; the validator covers
  146. // the certificate request and the CA's key and certificate are used to
  147. // sign the generated request. If remote is not an empty string, the
  148. // handler will send signature requests to the CFSSL instance contained
  149. // in remote.
  150. func NewCertGeneratorHandler(validator Validator, caFile, caKeyFile string, policy *config.Signing) (http.Handler, error) {
  151. var err error
  152. log.Info("setting up new generator / signer")
  153. cg := new(CertGeneratorHandler)
  154. if policy == nil {
  155. policy = &config.Signing{
  156. Default: config.DefaultConfig(),
  157. Profiles: nil,
  158. }
  159. }
  160. root := universal.Root{
  161. Config: map[string]string{
  162. "ca-file": caFile,
  163. "ca-key-file": caKeyFile,
  164. },
  165. }
  166. if cg.signer, err = universal.NewSigner(root, policy); err != nil {
  167. log.Errorf("setting up signer failed: %v", err)
  168. return nil, err
  169. }
  170. cg.generator = &csr.Generator{Validator: validator}
  171. return api.HTTPHandler{Handler: cg, Methods: []string{"POST"}}, nil
  172. }
  173. // NewCertGeneratorHandlerFromSigner returns a handler directly from
  174. // the signer and validation function.
  175. func NewCertGeneratorHandlerFromSigner(validator Validator, signer signer.Signer) http.Handler {
  176. return api.HTTPHandler{
  177. Handler: &CertGeneratorHandler{
  178. generator: &csr.Generator{Validator: validator},
  179. signer: signer,
  180. },
  181. Methods: []string{"POST"},
  182. }
  183. }
  184. // SetBundler allows injecting an optional Bundler into the CertGeneratorHandler.
  185. func (cg *CertGeneratorHandler) SetBundler(caBundleFile, intBundleFile string) (err error) {
  186. cg.bundler, err = bundler.NewBundler(caBundleFile, intBundleFile)
  187. return err
  188. }
  189. type genSignRequest struct {
  190. Request *csr.CertificateRequest `json:"request"`
  191. Profile string `json:"profile"`
  192. Label string `json:"label"`
  193. Bundle bool `json:"bundle"`
  194. }
  195. // Handle responds to requests for the CA to generate a new private
  196. // key and certificate on behalf of the client. The format for these
  197. // requests is documented in the API documentation.
  198. func (cg *CertGeneratorHandler) Handle(w http.ResponseWriter, r *http.Request) error {
  199. log.Info("request for CSR")
  200. req := new(genSignRequest)
  201. req.Request = csr.New()
  202. body, err := ioutil.ReadAll(r.Body)
  203. if err != nil {
  204. log.Warningf("failed to read request body: %v", err)
  205. return errors.NewBadRequest(err)
  206. }
  207. r.Body.Close()
  208. err = json.Unmarshal(body, req)
  209. if err != nil {
  210. log.Warningf("failed to unmarshal request: %v", err)
  211. return errors.NewBadRequest(err)
  212. }
  213. if req.Request == nil {
  214. log.Warning("empty request received")
  215. return errors.NewBadRequestString("missing request section")
  216. }
  217. if req.Request.CA != nil {
  218. log.Warningf("request received with CA section")
  219. return errors.NewBadRequestString("ca section only permitted in initca")
  220. }
  221. csr, key, err := cg.generator.ProcessRequest(req.Request)
  222. if err != nil {
  223. log.Warningf("failed to process CSR: %v", err)
  224. // The validator returns a *cfssl/errors.HttpError
  225. return err
  226. }
  227. signReq := signer.SignRequest{
  228. Request: string(csr),
  229. Profile: req.Profile,
  230. Label: req.Label,
  231. }
  232. certBytes, err := cg.signer.Sign(signReq)
  233. if err != nil {
  234. log.Warningf("failed to sign request: %v", err)
  235. return err
  236. }
  237. reqSum, err := computeSum(csr)
  238. if err != nil {
  239. return errors.NewBadRequest(err)
  240. }
  241. certSum, err := computeSum(certBytes)
  242. if err != nil {
  243. return errors.NewBadRequest(err)
  244. }
  245. result := map[string]interface{}{
  246. "private_key": string(key),
  247. "certificate_request": string(csr),
  248. "certificate": string(certBytes),
  249. "sums": map[string]Sum{
  250. "certificate_request": reqSum,
  251. "certificate": certSum,
  252. },
  253. }
  254. if req.Bundle {
  255. if cg.bundler == nil {
  256. return api.SendResponseWithMessage(w, result, NoBundlerMessage,
  257. errors.New(errors.PolicyError, errors.InvalidRequest).ErrorCode)
  258. }
  259. bundle, err := cg.bundler.BundleFromPEMorDER(certBytes, nil, bundler.Optimal, "")
  260. if err != nil {
  261. return err
  262. }
  263. result["bundle"] = bundle
  264. }
  265. if len(req.Request.Hosts) == 0 {
  266. return api.SendResponseWithMessage(w, result, CSRNoHostMessage,
  267. errors.New(errors.PolicyError, errors.InvalidRequest).ErrorCode)
  268. }
  269. return api.SendResponse(w, result)
  270. }
  271. // CSRValidate does nothing and will never return an error. It exists because NewHandler
  272. // requires a Validator as a parameter.
  273. func CSRValidate(req *csr.CertificateRequest) error {
  274. return nil
  275. }