csr.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436
  1. // Package csr implements certificate requests for CFSSL.
  2. package csr
  3. import (
  4. "crypto"
  5. "crypto/ecdsa"
  6. "crypto/elliptic"
  7. "crypto/rand"
  8. "crypto/rsa"
  9. "crypto/x509"
  10. "crypto/x509/pkix"
  11. "encoding/asn1"
  12. "encoding/pem"
  13. "errors"
  14. "net"
  15. "net/mail"
  16. "strings"
  17. cferr "github.com/cloudflare/cfssl/errors"
  18. "github.com/cloudflare/cfssl/helpers"
  19. "github.com/cloudflare/cfssl/log"
  20. )
  21. const (
  22. curveP256 = 256
  23. curveP384 = 384
  24. curveP521 = 521
  25. )
  26. // A Name contains the SubjectInfo fields.
  27. type Name struct {
  28. C string // Country
  29. ST string // State
  30. L string // Locality
  31. O string // OrganisationName
  32. OU string // OrganisationalUnitName
  33. SerialNumber string
  34. }
  35. // A KeyRequest is a generic request for a new key.
  36. type KeyRequest interface {
  37. Algo() string
  38. Size() int
  39. Generate() (crypto.PrivateKey, error)
  40. SigAlgo() x509.SignatureAlgorithm
  41. }
  42. // A BasicKeyRequest contains the algorithm and key size for a new private key.
  43. type BasicKeyRequest struct {
  44. A string `json:"algo" yaml:"algo"`
  45. S int `json:"size" yaml:"size"`
  46. }
  47. // NewBasicKeyRequest returns a default BasicKeyRequest.
  48. func NewBasicKeyRequest() *BasicKeyRequest {
  49. return &BasicKeyRequest{"ecdsa", curveP256}
  50. }
  51. // Algo returns the requested key algorithm represented as a string.
  52. func (kr *BasicKeyRequest) Algo() string {
  53. return kr.A
  54. }
  55. // Size returns the requested key size.
  56. func (kr *BasicKeyRequest) Size() int {
  57. return kr.S
  58. }
  59. // Generate generates a key as specified in the request. Currently,
  60. // only ECDSA and RSA are supported.
  61. func (kr *BasicKeyRequest) Generate() (crypto.PrivateKey, error) {
  62. log.Debugf("generate key from request: algo=%s, size=%d", kr.Algo(), kr.Size())
  63. switch kr.Algo() {
  64. case "rsa":
  65. if kr.Size() < 2048 {
  66. return nil, errors.New("RSA key is too weak")
  67. }
  68. if kr.Size() > 8192 {
  69. return nil, errors.New("RSA key size too large")
  70. }
  71. return rsa.GenerateKey(rand.Reader, kr.Size())
  72. case "ecdsa":
  73. var curve elliptic.Curve
  74. switch kr.Size() {
  75. case curveP256:
  76. curve = elliptic.P256()
  77. case curveP384:
  78. curve = elliptic.P384()
  79. case curveP521:
  80. curve = elliptic.P521()
  81. default:
  82. return nil, errors.New("invalid curve")
  83. }
  84. return ecdsa.GenerateKey(curve, rand.Reader)
  85. default:
  86. return nil, errors.New("invalid algorithm")
  87. }
  88. }
  89. // SigAlgo returns an appropriate X.509 signature algorithm given the
  90. // key request's type and size.
  91. func (kr *BasicKeyRequest) SigAlgo() x509.SignatureAlgorithm {
  92. switch kr.Algo() {
  93. case "rsa":
  94. switch {
  95. case kr.Size() >= 4096:
  96. return x509.SHA512WithRSA
  97. case kr.Size() >= 3072:
  98. return x509.SHA384WithRSA
  99. case kr.Size() >= 2048:
  100. return x509.SHA256WithRSA
  101. default:
  102. return x509.SHA1WithRSA
  103. }
  104. case "ecdsa":
  105. switch kr.Size() {
  106. case curveP521:
  107. return x509.ECDSAWithSHA512
  108. case curveP384:
  109. return x509.ECDSAWithSHA384
  110. case curveP256:
  111. return x509.ECDSAWithSHA256
  112. default:
  113. return x509.ECDSAWithSHA1
  114. }
  115. default:
  116. return x509.UnknownSignatureAlgorithm
  117. }
  118. }
  119. // CAConfig is a section used in the requests initialising a new CA.
  120. type CAConfig struct {
  121. PathLength int `json:"pathlen" yaml:"pathlen"`
  122. PathLenZero bool `json:"pathlenzero" yaml:"pathlenzero"`
  123. Expiry string `json:"expiry" yaml:"expiry"`
  124. Backdate string `json:"backdate" yaml:"backdate"`
  125. }
  126. // A CertificateRequest encapsulates the API interface to the
  127. // certificate request functionality.
  128. type CertificateRequest struct {
  129. CN string
  130. Names []Name `json:"names" yaml:"names"`
  131. Hosts []string `json:"hosts" yaml:"hosts"`
  132. KeyRequest KeyRequest `json:"key,omitempty" yaml:"key,omitempty"`
  133. CA *CAConfig `json:"ca,omitempty" yaml:"ca,omitempty"`
  134. SerialNumber string `json:"serialnumber,omitempty" yaml:"serialnumber,omitempty"`
  135. Extensions []pkix.Extension `json:"extensions,omitempty" yaml:"extensions,omitempty"`
  136. }
  137. // New returns a new, empty CertificateRequest with a
  138. // BasicKeyRequest.
  139. func New() *CertificateRequest {
  140. return &CertificateRequest{
  141. KeyRequest: NewBasicKeyRequest(),
  142. }
  143. }
  144. // appendIf appends to a if s is not an empty string.
  145. func appendIf(s string, a *[]string) {
  146. if s != "" {
  147. *a = append(*a, s)
  148. }
  149. }
  150. // Name returns the PKIX name for the request.
  151. func (cr *CertificateRequest) Name() pkix.Name {
  152. var name pkix.Name
  153. name.CommonName = cr.CN
  154. for _, n := range cr.Names {
  155. appendIf(n.C, &name.Country)
  156. appendIf(n.ST, &name.Province)
  157. appendIf(n.L, &name.Locality)
  158. appendIf(n.O, &name.Organization)
  159. appendIf(n.OU, &name.OrganizationalUnit)
  160. }
  161. name.SerialNumber = cr.SerialNumber
  162. return name
  163. }
  164. // BasicConstraints CSR information RFC 5280, 4.2.1.9
  165. type BasicConstraints struct {
  166. IsCA bool `asn1:"optional"`
  167. MaxPathLen int `asn1:"optional,default:-1"`
  168. }
  169. // ParseRequest takes a certificate request and generates a key and
  170. // CSR from it. It does no validation -- caveat emptor. It will,
  171. // however, fail if the key request is not valid (i.e., an unsupported
  172. // curve or RSA key size). The lack of validation was specifically
  173. // chosen to allow the end user to define a policy and validate the
  174. // request appropriately before calling this function.
  175. func ParseRequest(req *CertificateRequest) (csr, key []byte, err error) {
  176. log.Info("received CSR")
  177. if req.KeyRequest == nil {
  178. req.KeyRequest = NewBasicKeyRequest()
  179. }
  180. log.Infof("generating key: %s-%d", req.KeyRequest.Algo(), req.KeyRequest.Size())
  181. priv, err := req.KeyRequest.Generate()
  182. if err != nil {
  183. err = cferr.Wrap(cferr.PrivateKeyError, cferr.GenerationFailed, err)
  184. return
  185. }
  186. switch priv := priv.(type) {
  187. case *rsa.PrivateKey:
  188. key = x509.MarshalPKCS1PrivateKey(priv)
  189. block := pem.Block{
  190. Type: "RSA PRIVATE KEY",
  191. Bytes: key,
  192. }
  193. key = pem.EncodeToMemory(&block)
  194. case *ecdsa.PrivateKey:
  195. key, err = x509.MarshalECPrivateKey(priv)
  196. if err != nil {
  197. err = cferr.Wrap(cferr.PrivateKeyError, cferr.Unknown, err)
  198. return
  199. }
  200. block := pem.Block{
  201. Type: "EC PRIVATE KEY",
  202. Bytes: key,
  203. }
  204. key = pem.EncodeToMemory(&block)
  205. default:
  206. panic("Generate should have failed to produce a valid key.")
  207. }
  208. csr, err = Generate(priv.(crypto.Signer), req)
  209. if err != nil {
  210. log.Errorf("failed to generate a CSR: %v", err)
  211. err = cferr.Wrap(cferr.CSRError, cferr.BadRequest, err)
  212. }
  213. return
  214. }
  215. // ExtractCertificateRequest extracts a CertificateRequest from
  216. // x509.Certificate. It is aimed to used for generating a new certificate
  217. // from an existing certificate. For a root certificate, the CA expiry
  218. // length is calculated as the duration between cert.NotAfter and cert.NotBefore.
  219. func ExtractCertificateRequest(cert *x509.Certificate) *CertificateRequest {
  220. req := New()
  221. req.CN = cert.Subject.CommonName
  222. req.Names = getNames(cert.Subject)
  223. req.Hosts = getHosts(cert)
  224. req.SerialNumber = cert.Subject.SerialNumber
  225. if cert.IsCA {
  226. req.CA = new(CAConfig)
  227. // CA expiry length is calculated based on the input cert
  228. // issue date and expiry date.
  229. req.CA.Expiry = cert.NotAfter.Sub(cert.NotBefore).String()
  230. req.CA.PathLength = cert.MaxPathLen
  231. req.CA.PathLenZero = cert.MaxPathLenZero
  232. }
  233. return req
  234. }
  235. func getHosts(cert *x509.Certificate) []string {
  236. var hosts []string
  237. for _, ip := range cert.IPAddresses {
  238. hosts = append(hosts, ip.String())
  239. }
  240. for _, dns := range cert.DNSNames {
  241. hosts = append(hosts, dns)
  242. }
  243. for _, email := range cert.EmailAddresses {
  244. hosts = append(hosts, email)
  245. }
  246. return hosts
  247. }
  248. // getNames returns an array of Names from the certificate
  249. // It onnly cares about Country, Organization, OrganizationalUnit, Locality, Province
  250. func getNames(sub pkix.Name) []Name {
  251. // anonymous func for finding the max of a list of interger
  252. max := func(v1 int, vn ...int) (max int) {
  253. max = v1
  254. for i := 0; i < len(vn); i++ {
  255. if vn[i] > max {
  256. max = vn[i]
  257. }
  258. }
  259. return max
  260. }
  261. nc := len(sub.Country)
  262. norg := len(sub.Organization)
  263. nou := len(sub.OrganizationalUnit)
  264. nl := len(sub.Locality)
  265. np := len(sub.Province)
  266. n := max(nc, norg, nou, nl, np)
  267. names := make([]Name, n)
  268. for i := range names {
  269. if i < nc {
  270. names[i].C = sub.Country[i]
  271. }
  272. if i < norg {
  273. names[i].O = sub.Organization[i]
  274. }
  275. if i < nou {
  276. names[i].OU = sub.OrganizationalUnit[i]
  277. }
  278. if i < nl {
  279. names[i].L = sub.Locality[i]
  280. }
  281. if i < np {
  282. names[i].ST = sub.Province[i]
  283. }
  284. }
  285. return names
  286. }
  287. // A Generator is responsible for validating certificate requests.
  288. type Generator struct {
  289. Validator func(*CertificateRequest) error
  290. }
  291. // ProcessRequest validates and processes the incoming request. It is
  292. // a wrapper around a validator and the ParseRequest function.
  293. func (g *Generator) ProcessRequest(req *CertificateRequest) (csr, key []byte, err error) {
  294. log.Info("generate received request")
  295. err = g.Validator(req)
  296. if err != nil {
  297. log.Warningf("invalid request: %v", err)
  298. return nil, nil, err
  299. }
  300. csr, key, err = ParseRequest(req)
  301. if err != nil {
  302. return nil, nil, err
  303. }
  304. return
  305. }
  306. // IsNameEmpty returns true if the name has no identifying information in it.
  307. func IsNameEmpty(n Name) bool {
  308. empty := func(s string) bool { return strings.TrimSpace(s) == "" }
  309. if empty(n.C) && empty(n.ST) && empty(n.L) && empty(n.O) && empty(n.OU) {
  310. return true
  311. }
  312. return false
  313. }
  314. // Regenerate uses the provided CSR as a template for signing a new
  315. // CSR using priv.
  316. func Regenerate(priv crypto.Signer, csr []byte) ([]byte, error) {
  317. req, extra, err := helpers.ParseCSR(csr)
  318. if err != nil {
  319. return nil, err
  320. } else if len(extra) > 0 {
  321. return nil, errors.New("csr: trailing data in certificate request")
  322. }
  323. return x509.CreateCertificateRequest(rand.Reader, req, priv)
  324. }
  325. // Generate creates a new CSR from a CertificateRequest structure and
  326. // an existing key. The KeyRequest field is ignored.
  327. func Generate(priv crypto.Signer, req *CertificateRequest) (csr []byte, err error) {
  328. sigAlgo := helpers.SignerAlgo(priv)
  329. if sigAlgo == x509.UnknownSignatureAlgorithm {
  330. return nil, cferr.New(cferr.PrivateKeyError, cferr.Unavailable)
  331. }
  332. var tpl = x509.CertificateRequest{
  333. Subject: req.Name(),
  334. SignatureAlgorithm: sigAlgo,
  335. }
  336. for i := range req.Hosts {
  337. if ip := net.ParseIP(req.Hosts[i]); ip != nil {
  338. tpl.IPAddresses = append(tpl.IPAddresses, ip)
  339. } else if email, err := mail.ParseAddress(req.Hosts[i]); err == nil && email != nil {
  340. tpl.EmailAddresses = append(tpl.EmailAddresses, email.Address)
  341. } else {
  342. tpl.DNSNames = append(tpl.DNSNames, req.Hosts[i])
  343. }
  344. }
  345. if req.CA != nil {
  346. err = appendCAInfoToCSR(req.CA, &tpl)
  347. if err != nil {
  348. err = cferr.Wrap(cferr.CSRError, cferr.GenerationFailed, err)
  349. return
  350. }
  351. }
  352. if req.Extensions != nil {
  353. tpl.ExtraExtensions = append(tpl.ExtraExtensions, req.Extensions...)
  354. }
  355. csr, err = x509.CreateCertificateRequest(rand.Reader, &tpl, priv)
  356. if err != nil {
  357. log.Errorf("failed to generate a CSR: %v", err)
  358. err = cferr.Wrap(cferr.CSRError, cferr.BadRequest, err)
  359. return
  360. }
  361. block := pem.Block{
  362. Type: "CERTIFICATE REQUEST",
  363. Bytes: csr,
  364. }
  365. log.Info("encoded CSR")
  366. csr = pem.EncodeToMemory(&block)
  367. return
  368. }
  369. // appendCAInfoToCSR appends CAConfig BasicConstraint extension to a CSR
  370. func appendCAInfoToCSR(reqConf *CAConfig, csr *x509.CertificateRequest) error {
  371. pathlen := reqConf.PathLength
  372. if pathlen == 0 && !reqConf.PathLenZero {
  373. pathlen = -1
  374. }
  375. val, err := asn1.Marshal(BasicConstraints{true, pathlen})
  376. if err != nil {
  377. return err
  378. }
  379. csr.ExtraExtensions = append(csr.ExtraExtensions, pkix.Extension{
  380. Id: asn1.ObjectIdentifier{2, 5, 29, 19},
  381. Value: val,
  382. Critical: true,
  383. })
  384. return nil
  385. }