initca.go 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. // Package initca contains code to initialise a certificate authority,
  2. // generating a new root key and certificate.
  3. package initca
  4. import (
  5. "crypto"
  6. "crypto/ecdsa"
  7. "crypto/rsa"
  8. "crypto/x509"
  9. "errors"
  10. "time"
  11. "github.com/cloudflare/cfssl/config"
  12. "github.com/cloudflare/cfssl/csr"
  13. cferr "github.com/cloudflare/cfssl/errors"
  14. "github.com/cloudflare/cfssl/helpers"
  15. "github.com/cloudflare/cfssl/log"
  16. "github.com/cloudflare/cfssl/signer"
  17. "github.com/cloudflare/cfssl/signer/local"
  18. )
  19. // validator contains the default validation logic for certificate
  20. // authority certificates. The only requirement here is that the
  21. // certificate have a non-empty subject field.
  22. func validator(req *csr.CertificateRequest) error {
  23. if req.CN != "" {
  24. return nil
  25. }
  26. if len(req.Names) == 0 {
  27. return cferr.Wrap(cferr.PolicyError, cferr.InvalidRequest, errors.New("missing subject information"))
  28. }
  29. for i := range req.Names {
  30. if csr.IsNameEmpty(req.Names[i]) {
  31. return cferr.Wrap(cferr.PolicyError, cferr.InvalidRequest, errors.New("missing subject information"))
  32. }
  33. }
  34. return nil
  35. }
  36. // New creates a new root certificate from the certificate request.
  37. func New(req *csr.CertificateRequest) (cert, csrPEM, key []byte, err error) {
  38. policy := CAPolicy()
  39. if req.CA != nil {
  40. if req.CA.Expiry != "" {
  41. policy.Default.ExpiryString = req.CA.Expiry
  42. policy.Default.Expiry, err = time.ParseDuration(req.CA.Expiry)
  43. if err != nil {
  44. return
  45. }
  46. }
  47. policy.Default.CAConstraint.MaxPathLen = req.CA.PathLength
  48. if req.CA.PathLength != 0 && req.CA.PathLenZero {
  49. log.Infof("ignore invalid 'pathlenzero' value")
  50. } else {
  51. policy.Default.CAConstraint.MaxPathLenZero = req.CA.PathLenZero
  52. }
  53. }
  54. g := &csr.Generator{Validator: validator}
  55. csrPEM, key, err = g.ProcessRequest(req)
  56. if err != nil {
  57. log.Errorf("failed to process request: %v", err)
  58. key = nil
  59. return
  60. }
  61. priv, err := helpers.ParsePrivateKeyPEM(key)
  62. if err != nil {
  63. log.Errorf("failed to parse private key: %v", err)
  64. return
  65. }
  66. s, err := local.NewSigner(priv, nil, signer.DefaultSigAlgo(priv), policy)
  67. if err != nil {
  68. log.Errorf("failed to create signer: %v", err)
  69. return
  70. }
  71. signReq := signer.SignRequest{Hosts: req.Hosts, Request: string(csrPEM)}
  72. cert, err = s.Sign(signReq)
  73. return
  74. }
  75. // NewFromPEM creates a new root certificate from the key file passed in.
  76. func NewFromPEM(req *csr.CertificateRequest, keyFile string) (cert, csrPEM []byte, err error) {
  77. privData, err := helpers.ReadBytes(keyFile)
  78. if err != nil {
  79. return nil, nil, err
  80. }
  81. priv, err := helpers.ParsePrivateKeyPEM(privData)
  82. if err != nil {
  83. return nil, nil, err
  84. }
  85. return NewFromSigner(req, priv)
  86. }
  87. // RenewFromPEM re-creates a root certificate from the CA cert and key
  88. // files. The resulting root certificate will have the input CA certificate
  89. // as the template and have the same expiry length. E.g. the exsiting CA
  90. // is valid for a year from Jan 01 2015 to Jan 01 2016, the renewed certificate
  91. // will be valid from now and expire in one year as well.
  92. func RenewFromPEM(caFile, keyFile string) ([]byte, error) {
  93. caBytes, err := helpers.ReadBytes(caFile)
  94. if err != nil {
  95. return nil, err
  96. }
  97. ca, err := helpers.ParseCertificatePEM(caBytes)
  98. if err != nil {
  99. return nil, err
  100. }
  101. keyBytes, err := helpers.ReadBytes(keyFile)
  102. if err != nil {
  103. return nil, err
  104. }
  105. key, err := helpers.ParsePrivateKeyPEM(keyBytes)
  106. if err != nil {
  107. return nil, err
  108. }
  109. return RenewFromSigner(ca, key)
  110. }
  111. // NewFromSigner creates a new root certificate from a crypto.Signer.
  112. func NewFromSigner(req *csr.CertificateRequest, priv crypto.Signer) (cert, csrPEM []byte, err error) {
  113. policy := CAPolicy()
  114. if req.CA != nil {
  115. if req.CA.Expiry != "" {
  116. policy.Default.ExpiryString = req.CA.Expiry
  117. policy.Default.Expiry, err = time.ParseDuration(req.CA.Expiry)
  118. if err != nil {
  119. return nil, nil, err
  120. }
  121. }
  122. policy.Default.CAConstraint.MaxPathLen = req.CA.PathLength
  123. if req.CA.PathLength != 0 && req.CA.PathLenZero == true {
  124. log.Infof("ignore invalid 'pathlenzero' value")
  125. } else {
  126. policy.Default.CAConstraint.MaxPathLenZero = req.CA.PathLenZero
  127. }
  128. }
  129. csrPEM, err = csr.Generate(priv, req)
  130. if err != nil {
  131. return nil, nil, err
  132. }
  133. s, err := local.NewSigner(priv, nil, signer.DefaultSigAlgo(priv), policy)
  134. if err != nil {
  135. log.Errorf("failed to create signer: %v", err)
  136. return
  137. }
  138. signReq := signer.SignRequest{Request: string(csrPEM)}
  139. cert, err = s.Sign(signReq)
  140. return
  141. }
  142. // RenewFromSigner re-creates a root certificate from the CA cert and crypto.Signer.
  143. // The resulting root certificate will have ca certificate
  144. // as the template and have the same expiry length. E.g. the exsiting CA
  145. // is valid for a year from Jan 01 2015 to Jan 01 2016, the renewed certificate
  146. // will be valid from now and expire in one year as well.
  147. func RenewFromSigner(ca *x509.Certificate, priv crypto.Signer) ([]byte, error) {
  148. if !ca.IsCA {
  149. return nil, errors.New("input certificate is not a CA cert")
  150. }
  151. // matching certificate public key vs private key
  152. switch {
  153. case ca.PublicKeyAlgorithm == x509.RSA:
  154. var rsaPublicKey *rsa.PublicKey
  155. var ok bool
  156. if rsaPublicKey, ok = priv.Public().(*rsa.PublicKey); !ok {
  157. return nil, cferr.New(cferr.PrivateKeyError, cferr.KeyMismatch)
  158. }
  159. if ca.PublicKey.(*rsa.PublicKey).N.Cmp(rsaPublicKey.N) != 0 {
  160. return nil, cferr.New(cferr.PrivateKeyError, cferr.KeyMismatch)
  161. }
  162. case ca.PublicKeyAlgorithm == x509.ECDSA:
  163. var ecdsaPublicKey *ecdsa.PublicKey
  164. var ok bool
  165. if ecdsaPublicKey, ok = priv.Public().(*ecdsa.PublicKey); !ok {
  166. return nil, cferr.New(cferr.PrivateKeyError, cferr.KeyMismatch)
  167. }
  168. if ca.PublicKey.(*ecdsa.PublicKey).X.Cmp(ecdsaPublicKey.X) != 0 {
  169. return nil, cferr.New(cferr.PrivateKeyError, cferr.KeyMismatch)
  170. }
  171. default:
  172. return nil, cferr.New(cferr.PrivateKeyError, cferr.NotRSAOrECC)
  173. }
  174. req := csr.ExtractCertificateRequest(ca)
  175. cert, _, err := NewFromSigner(req, priv)
  176. return cert, err
  177. }
  178. // CAPolicy contains the CA issuing policy as default policy.
  179. var CAPolicy = func() *config.Signing {
  180. return &config.Signing{
  181. Default: &config.SigningProfile{
  182. Usage: []string{"cert sign", "crl sign"},
  183. ExpiryString: "43800h",
  184. Expiry: 5 * helpers.OneYear,
  185. CAConstraint: config.CAConstraint{IsCA: true},
  186. },
  187. }
  188. }