csr.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433
  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. }
  136. // New returns a new, empty CertificateRequest with a
  137. // BasicKeyRequest.
  138. func New() *CertificateRequest {
  139. return &CertificateRequest{
  140. KeyRequest: NewBasicKeyRequest(),
  141. }
  142. }
  143. // appendIf appends to a if s is not an empty string.
  144. func appendIf(s string, a *[]string) {
  145. if s != "" {
  146. *a = append(*a, s)
  147. }
  148. }
  149. // Name returns the PKIX name for the request.
  150. func (cr *CertificateRequest) Name() pkix.Name {
  151. var name pkix.Name
  152. name.CommonName = cr.CN
  153. for _, n := range cr.Names {
  154. appendIf(n.C, &name.Country)
  155. appendIf(n.ST, &name.Province)
  156. appendIf(n.L, &name.Locality)
  157. appendIf(n.O, &name.Organization)
  158. appendIf(n.OU, &name.OrganizationalUnit)
  159. }
  160. name.SerialNumber = cr.SerialNumber
  161. return name
  162. }
  163. // BasicConstraints CSR information RFC 5280, 4.2.1.9
  164. type BasicConstraints struct {
  165. IsCA bool `asn1:"optional"`
  166. MaxPathLen int `asn1:"optional,default:-1"`
  167. }
  168. // ParseRequest takes a certificate request and generates a key and
  169. // CSR from it. It does no validation -- caveat emptor. It will,
  170. // however, fail if the key request is not valid (i.e., an unsupported
  171. // curve or RSA key size). The lack of validation was specifically
  172. // chosen to allow the end user to define a policy and validate the
  173. // request appropriately before calling this function.
  174. func ParseRequest(req *CertificateRequest) (csr, key []byte, err error) {
  175. log.Info("received CSR")
  176. if req.KeyRequest == nil {
  177. req.KeyRequest = NewBasicKeyRequest()
  178. }
  179. log.Infof("generating key: %s-%d", req.KeyRequest.Algo(), req.KeyRequest.Size())
  180. priv, err := req.KeyRequest.Generate()
  181. if err != nil {
  182. err = cferr.Wrap(cferr.PrivateKeyError, cferr.GenerationFailed, err)
  183. return
  184. }
  185. switch priv := priv.(type) {
  186. case *rsa.PrivateKey:
  187. key = x509.MarshalPKCS1PrivateKey(priv)
  188. block := pem.Block{
  189. Type: "RSA PRIVATE KEY",
  190. Bytes: key,
  191. }
  192. key = pem.EncodeToMemory(&block)
  193. case *ecdsa.PrivateKey:
  194. key, err = x509.MarshalECPrivateKey(priv)
  195. if err != nil {
  196. err = cferr.Wrap(cferr.PrivateKeyError, cferr.Unknown, err)
  197. return
  198. }
  199. block := pem.Block{
  200. Type: "EC PRIVATE KEY",
  201. Bytes: key,
  202. }
  203. key = pem.EncodeToMemory(&block)
  204. default:
  205. panic("Generate should have failed to produce a valid key.")
  206. }
  207. csr, err = Generate(priv.(crypto.Signer), req)
  208. if err != nil {
  209. log.Errorf("failed to generate a CSR: %v", err)
  210. err = cferr.Wrap(cferr.CSRError, cferr.BadRequest, err)
  211. }
  212. return
  213. }
  214. // ExtractCertificateRequest extracts a CertificateRequest from
  215. // x509.Certificate. It is aimed to used for generating a new certificate
  216. // from an existing certificate. For a root certificate, the CA expiry
  217. // length is calculated as the duration between cert.NotAfter and cert.NotBefore.
  218. func ExtractCertificateRequest(cert *x509.Certificate) *CertificateRequest {
  219. req := New()
  220. req.CN = cert.Subject.CommonName
  221. req.Names = getNames(cert.Subject)
  222. req.Hosts = getHosts(cert)
  223. req.SerialNumber = cert.Subject.SerialNumber
  224. if cert.IsCA {
  225. req.CA = new(CAConfig)
  226. // CA expiry length is calculated based on the input cert
  227. // issue date and expiry date.
  228. req.CA.Expiry = cert.NotAfter.Sub(cert.NotBefore).String()
  229. req.CA.PathLength = cert.MaxPathLen
  230. req.CA.PathLenZero = cert.MaxPathLenZero
  231. }
  232. return req
  233. }
  234. func getHosts(cert *x509.Certificate) []string {
  235. var hosts []string
  236. for _, ip := range cert.IPAddresses {
  237. hosts = append(hosts, ip.String())
  238. }
  239. for _, dns := range cert.DNSNames {
  240. hosts = append(hosts, dns)
  241. }
  242. for _, email := range cert.EmailAddresses {
  243. hosts = append(hosts, email)
  244. }
  245. return hosts
  246. }
  247. // getNames returns an array of Names from the certificate
  248. // It onnly cares about Country, Organization, OrganizationalUnit, Locality, Province
  249. func getNames(sub pkix.Name) []Name {
  250. // anonymous func for finding the max of a list of interger
  251. max := func(v1 int, vn ...int) (max int) {
  252. max = v1
  253. for i := 0; i < len(vn); i++ {
  254. if vn[i] > max {
  255. max = vn[i]
  256. }
  257. }
  258. return max
  259. }
  260. nc := len(sub.Country)
  261. norg := len(sub.Organization)
  262. nou := len(sub.OrganizationalUnit)
  263. nl := len(sub.Locality)
  264. np := len(sub.Province)
  265. n := max(nc, norg, nou, nl, np)
  266. names := make([]Name, n)
  267. for i := range names {
  268. if i < nc {
  269. names[i].C = sub.Country[i]
  270. }
  271. if i < norg {
  272. names[i].O = sub.Organization[i]
  273. }
  274. if i < nou {
  275. names[i].OU = sub.OrganizationalUnit[i]
  276. }
  277. if i < nl {
  278. names[i].L = sub.Locality[i]
  279. }
  280. if i < np {
  281. names[i].ST = sub.Province[i]
  282. }
  283. }
  284. return names
  285. }
  286. // A Generator is responsible for validating certificate requests.
  287. type Generator struct {
  288. Validator func(*CertificateRequest) error
  289. }
  290. // ProcessRequest validates and processes the incoming request. It is
  291. // a wrapper around a validator and the ParseRequest function.
  292. func (g *Generator) ProcessRequest(req *CertificateRequest) (csr, key []byte, err error) {
  293. log.Info("generate received request")
  294. err = g.Validator(req)
  295. if err != nil {
  296. log.Warningf("invalid request: %v", err)
  297. return nil, nil, err
  298. }
  299. csr, key, err = ParseRequest(req)
  300. if err != nil {
  301. return nil, nil, err
  302. }
  303. return
  304. }
  305. // IsNameEmpty returns true if the name has no identifying information in it.
  306. func IsNameEmpty(n Name) bool {
  307. empty := func(s string) bool { return strings.TrimSpace(s) == "" }
  308. if empty(n.C) && empty(n.ST) && empty(n.L) && empty(n.O) && empty(n.OU) {
  309. return true
  310. }
  311. return false
  312. }
  313. // Regenerate uses the provided CSR as a template for signing a new
  314. // CSR using priv.
  315. func Regenerate(priv crypto.Signer, csr []byte) ([]byte, error) {
  316. req, extra, err := helpers.ParseCSR(csr)
  317. if err != nil {
  318. return nil, err
  319. } else if len(extra) > 0 {
  320. return nil, errors.New("csr: trailing data in certificate request")
  321. }
  322. return x509.CreateCertificateRequest(rand.Reader, req, priv)
  323. }
  324. // Generate creates a new CSR from a CertificateRequest structure and
  325. // an existing key. The KeyRequest field is ignored.
  326. func Generate(priv crypto.Signer, req *CertificateRequest) (csr []byte, err error) {
  327. sigAlgo := helpers.SignerAlgo(priv)
  328. if sigAlgo == x509.UnknownSignatureAlgorithm {
  329. return nil, cferr.New(cferr.PrivateKeyError, cferr.Unavailable)
  330. }
  331. var tpl = x509.CertificateRequest{
  332. Subject: req.Name(),
  333. SignatureAlgorithm: sigAlgo,
  334. }
  335. for i := range req.Hosts {
  336. if ip := net.ParseIP(req.Hosts[i]); ip != nil {
  337. tpl.IPAddresses = append(tpl.IPAddresses, ip)
  338. } else if email, err := mail.ParseAddress(req.Hosts[i]); err == nil && email != nil {
  339. tpl.EmailAddresses = append(tpl.EmailAddresses, email.Address)
  340. } else {
  341. tpl.DNSNames = append(tpl.DNSNames, req.Hosts[i])
  342. }
  343. }
  344. if req.CA != nil {
  345. err = appendCAInfoToCSR(req.CA, &tpl)
  346. if err != nil {
  347. err = cferr.Wrap(cferr.CSRError, cferr.GenerationFailed, err)
  348. return
  349. }
  350. }
  351. csr, err = x509.CreateCertificateRequest(rand.Reader, &tpl, priv)
  352. if err != nil {
  353. log.Errorf("failed to generate a CSR: %v", err)
  354. err = cferr.Wrap(cferr.CSRError, cferr.BadRequest, err)
  355. return
  356. }
  357. block := pem.Block{
  358. Type: "CERTIFICATE REQUEST",
  359. Bytes: csr,
  360. }
  361. log.Info("encoded CSR")
  362. csr = pem.EncodeToMemory(&block)
  363. return
  364. }
  365. // appendCAInfoToCSR appends CAConfig BasicConstraint extension to a CSR
  366. func appendCAInfoToCSR(reqConf *CAConfig, csr *x509.CertificateRequest) error {
  367. pathlen := reqConf.PathLength
  368. if pathlen == 0 && !reqConf.PathLenZero {
  369. pathlen = -1
  370. }
  371. val, err := asn1.Marshal(BasicConstraints{true, pathlen})
  372. if err != nil {
  373. return err
  374. }
  375. csr.ExtraExtensions = []pkix.Extension{
  376. {
  377. Id: asn1.ObjectIdentifier{2, 5, 29, 19},
  378. Value: val,
  379. Critical: true,
  380. },
  381. }
  382. return nil
  383. }