sign.go 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. // Package sign implements the sign command.
  2. package sign
  3. import (
  4. "encoding/json"
  5. "errors"
  6. "os"
  7. "github.com/cloudflare/cfssl/certdb/dbconf"
  8. certsql "github.com/cloudflare/cfssl/certdb/sql"
  9. "github.com/cloudflare/cfssl/cli"
  10. "github.com/cloudflare/cfssl/config"
  11. "github.com/cloudflare/cfssl/log"
  12. "github.com/cloudflare/cfssl/signer"
  13. "github.com/cloudflare/cfssl/signer/universal"
  14. "github.com/jmoiron/sqlx"
  15. )
  16. // Usage text of 'cfssl sign'
  17. var signerUsageText = `cfssl sign -- signs a client cert with a host name by a given CA and CA key
  18. Usage of sign:
  19. cfssl sign -ca cert -ca-key key [mutual-tls-cert cert] [mutual-tls-key key] [-config config] [-profile profile] [-hostname hostname] [-db-config db-config] CSR [SUBJECT]
  20. cfssl sign -remote remote_host [mutual-tls-cert cert] [mutual-tls-key key] [-config config] [-profile profile] [-label label] [-hostname hostname] CSR [SUBJECT]
  21. Arguments:
  22. CSR: PEM file for certificate request, use '-' for reading PEM from stdin.
  23. Note: CSR can also be supplied via flag values; flag value will take precedence over the argument.
  24. SUBJECT is an optional file containing subject information to use for the certificate instead of the subject information in the CSR.
  25. Flags:
  26. `
  27. // Flags of 'cfssl sign'
  28. var signerFlags = []string{"hostname", "csr", "ca", "ca-key", "config", "profile", "label", "remote",
  29. "mutual-tls-cert", "mutual-tls-key", "db-config"}
  30. // SignerFromConfigAndDB takes the Config and creates the appropriate
  31. // signer.Signer object with a specified db
  32. func SignerFromConfigAndDB(c cli.Config, db *sqlx.DB) (signer.Signer, error) {
  33. // If there is a config, use its signing policy. Otherwise create a default policy.
  34. var policy *config.Signing
  35. if c.CFG != nil {
  36. policy = c.CFG.Signing
  37. } else {
  38. policy = &config.Signing{
  39. Profiles: map[string]*config.SigningProfile{},
  40. Default: config.DefaultConfig(),
  41. }
  42. }
  43. // Make sure the policy reflects the new remote
  44. if c.Remote != "" {
  45. err := policy.OverrideRemotes(c.Remote)
  46. if err != nil {
  47. log.Infof("Invalid remote %v, reverting to configuration default", c.Remote)
  48. return nil, err
  49. }
  50. }
  51. if c.MutualTLSCertFile != "" && c.MutualTLSKeyFile != "" {
  52. err := policy.SetClientCertKeyPairFromFile(c.MutualTLSCertFile, c.MutualTLSKeyFile)
  53. if err != nil {
  54. log.Infof("Invalid mutual-tls-cert: %s or mutual-tls-key: %s, defaulting to no client auth", c.MutualTLSCertFile, c.MutualTLSKeyFile)
  55. return nil, err
  56. }
  57. log.Infof("Using client auth with mutual-tls-cert: %s and mutual-tls-key: %s", c.MutualTLSCertFile, c.MutualTLSKeyFile)
  58. }
  59. if c.TLSRemoteCAs != "" {
  60. err := policy.SetRemoteCAsFromFile(c.TLSRemoteCAs)
  61. if err != nil {
  62. log.Infof("Invalid tls-remote-ca: %s, defaulting to system trust store", c.TLSRemoteCAs)
  63. return nil, err
  64. }
  65. log.Infof("Using trusted CA from tls-remote-ca: %s", c.TLSRemoteCAs)
  66. }
  67. s, err := universal.NewSigner(cli.RootFromConfig(&c), policy)
  68. if err != nil {
  69. return nil, err
  70. }
  71. if db != nil {
  72. dbAccessor := certsql.NewAccessor(db)
  73. s.SetDBAccessor(dbAccessor)
  74. }
  75. return s, nil
  76. }
  77. // SignerFromConfig takes the Config and creates the appropriate
  78. // signer.Signer object
  79. func SignerFromConfig(c cli.Config) (s signer.Signer, err error) {
  80. var db *sqlx.DB
  81. if c.DBConfigFile != "" {
  82. db, err = dbconf.DBFromConfig(c.DBConfigFile)
  83. if err != nil {
  84. return nil, err
  85. }
  86. }
  87. return SignerFromConfigAndDB(c, db)
  88. }
  89. // signerMain is the main CLI of signer functionality.
  90. // [TODO: zi] Decide whether to drop the argument list and only use flags to specify all the inputs.
  91. func signerMain(args []string, c cli.Config) (err error) {
  92. if c.CSRFile == "" {
  93. c.CSRFile, args, err = cli.PopFirstArgument(args)
  94. if err != nil {
  95. return
  96. }
  97. }
  98. var subjectData *signer.Subject
  99. if len(args) > 0 {
  100. var subjectFile string
  101. subjectFile, args, err = cli.PopFirstArgument(args)
  102. if err != nil {
  103. return
  104. }
  105. if len(args) > 0 {
  106. return errors.New("too many arguments are provided, please check with usage")
  107. }
  108. var subjectJSON []byte
  109. subjectJSON, err = os.ReadFile(subjectFile)
  110. if err != nil {
  111. return
  112. }
  113. subjectData = new(signer.Subject)
  114. err = json.Unmarshal(subjectJSON, subjectData)
  115. if err != nil {
  116. return
  117. }
  118. }
  119. csr, err := cli.ReadStdin(c.CSRFile)
  120. if err != nil {
  121. return
  122. }
  123. // Remote can be forced on the command line or in the config
  124. if c.Remote == "" && c.CFG == nil {
  125. if c.CAFile == "" {
  126. log.Error("need CA certificate (provide one with -ca)")
  127. return
  128. }
  129. if c.CAKeyFile == "" {
  130. log.Error("need CA key (provide one with -ca-key)")
  131. return
  132. }
  133. }
  134. s, err := SignerFromConfig(c)
  135. if err != nil {
  136. return
  137. }
  138. req := signer.SignRequest{
  139. Hosts: signer.SplitHosts(c.Hostname),
  140. Request: string(csr),
  141. Subject: subjectData,
  142. Profile: c.Profile,
  143. Label: c.Label,
  144. }
  145. cert, err := s.Sign(req)
  146. if err != nil {
  147. return
  148. }
  149. cli.PrintCert(nil, csr, cert)
  150. return
  151. }
  152. // Command assembles the definition of Command 'sign'
  153. var Command = &cli.Command{UsageText: signerUsageText, Flags: signerFlags, Main: signerMain}