initca.go 6.2 KB

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