csr.go 13 KB

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