initca.go 6.9 KB

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