You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

cert.go 6.1 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. package cmd
  2. import (
  3. "crypto/rand"
  4. "crypto/rsa"
  5. "crypto/x509"
  6. "crypto/x509/pkix"
  7. "encoding/pem"
  8. "fmt"
  9. "math/big"
  10. "os"
  11. "path/filepath"
  12. "time"
  13. "github.com/spf13/cobra"
  14. "gitlink.org.cn/cloudream/jcs-pub/common/pkgs/rpc"
  15. )
  16. func init() {
  17. certCmd := cobra.Command{
  18. Use: "cert",
  19. }
  20. RootCmd.AddCommand(&certCmd)
  21. certRoot := cobra.Command{
  22. Use: "root [outputDir]",
  23. Args: cobra.ExactArgs(1),
  24. Run: func(cmd *cobra.Command, args []string) {
  25. certRoot(args[0])
  26. },
  27. }
  28. certCmd.AddCommand(&certRoot)
  29. var certFilePath string
  30. var keyFilePath string
  31. certServer := cobra.Command{
  32. Use: "server [outputDir]",
  33. Args: cobra.ExactArgs(1),
  34. Run: func(cmd *cobra.Command, args []string) {
  35. certServer(certFilePath, keyFilePath, args[0])
  36. },
  37. }
  38. certServer.Flags().StringVar(&certFilePath, "cert", "", "CA certificate file path")
  39. certServer.Flags().StringVar(&keyFilePath, "key", "", "CA key file path")
  40. certCmd.AddCommand(&certServer)
  41. certClient := cobra.Command{
  42. Use: "client [outputDir]",
  43. Args: cobra.ExactArgs(1),
  44. Run: func(cmd *cobra.Command, args []string) {
  45. certClient(certFilePath, keyFilePath, args[0])
  46. },
  47. }
  48. certClient.Flags().StringVar(&certFilePath, "cert", "", "CA certificate file path")
  49. certClient.Flags().StringVar(&keyFilePath, "key", "", "CA key file path")
  50. certCmd.AddCommand(&certClient)
  51. }
  52. func certRoot(output string) {
  53. caPriv, _ := rsa.GenerateKey(rand.Reader, 2048)
  54. // 创建 CA 证书模板
  55. caTemplate := &x509.Certificate{
  56. SerialNumber: big.NewInt(1),
  57. Subject: pkix.Name{
  58. Organization: []string{"JCS"},
  59. },
  60. NotBefore: time.Now(),
  61. NotAfter: time.Now().AddDate(10, 0, 0), // 有效期10年
  62. KeyUsage: x509.KeyUsageCertSign | x509.KeyUsageDigitalSignature,
  63. BasicConstraintsValid: true,
  64. IsCA: true,
  65. }
  66. // 自签名 CA 证书
  67. caCertDER, _ := x509.CreateCertificate(rand.Reader, caTemplate, caTemplate, &caPriv.PublicKey, caPriv)
  68. // 保存 CA 证书和私钥
  69. writePem(filepath.Join(output, "ca_cert.pem"), "CERTIFICATE", caCertDER)
  70. writePem(filepath.Join(output, "ca_key.pem"), "RSA PRIVATE KEY", x509.MarshalPKCS1PrivateKey(caPriv))
  71. fmt.Println("CA certificate and key saved to", output)
  72. }
  73. func certServer(certFile string, keyFile string, output string) {
  74. // 读取 CA 证书和私钥
  75. caCertPEM, err := os.ReadFile(certFile)
  76. if err != nil {
  77. fmt.Println("Failed to read CA certificate:", err)
  78. return
  79. }
  80. caKeyPEM, err := os.ReadFile(keyFile)
  81. if err != nil {
  82. fmt.Println("Failed to read CA key:", err)
  83. return
  84. }
  85. caCertPEMBlock, _ := pem.Decode(caCertPEM)
  86. if caCertPEMBlock == nil {
  87. fmt.Println("Failed to decode CA certificate")
  88. return
  89. }
  90. caKeyPEMBlock, _ := pem.Decode(caKeyPEM)
  91. if caKeyPEMBlock == nil {
  92. fmt.Println("Failed to decode CA key")
  93. return
  94. }
  95. caCert, err := x509.ParseCertificate(caCertPEMBlock.Bytes)
  96. if err != nil {
  97. fmt.Println("Failed to parse CA certificate:", err)
  98. return
  99. }
  100. caKey, err := x509.ParsePKCS1PrivateKey(caKeyPEMBlock.Bytes)
  101. if err != nil {
  102. fmt.Println("Failed to parse CA key:", err)
  103. return
  104. }
  105. // 生成服务端私钥
  106. serverPriv, _ := rsa.GenerateKey(rand.Reader, 2048)
  107. // 服务端证书模板
  108. serverTemplate := &x509.Certificate{
  109. SerialNumber: big.NewInt(2),
  110. Subject: pkix.Name{
  111. CommonName: "localhost",
  112. },
  113. NotBefore: time.Now(),
  114. NotAfter: time.Now().AddDate(1, 0, 0), // 有效期1年
  115. KeyUsage: x509.KeyUsageDigitalSignature,
  116. ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
  117. BasicConstraintsValid: true,
  118. }
  119. // 添加主机名/IP 到证书
  120. serverTemplate.DNSNames = []string{rpc.ClientAPISNIV1, rpc.InternalAPISNIV1}
  121. // 用 CA 签发服务端证书
  122. serverCertDER, _ := x509.CreateCertificate(rand.Reader, serverTemplate, caCert, &serverPriv.PublicKey, caKey)
  123. // 保存服务端证书和私钥
  124. writePem(filepath.Join(output, "server_cert.pem"), "CERTIFICATE", serverCertDER)
  125. writePem(filepath.Join(output, "server_key.pem"), "RSA PRIVATE KEY", x509.MarshalPKCS1PrivateKey(serverPriv))
  126. fmt.Println("Server certificate and key saved to", output)
  127. }
  128. func certClient(certFile string, keyFile string, output string) {
  129. // 读取 CA 证书和私钥
  130. caCertPEM, err := os.ReadFile(certFile)
  131. if err != nil {
  132. fmt.Println("Failed to read CA certificate:", err)
  133. return
  134. }
  135. caKeyPEM, err := os.ReadFile(keyFile)
  136. if err != nil {
  137. fmt.Println("Failed to read CA key:", err)
  138. return
  139. }
  140. caCertPEMBlock, _ := pem.Decode(caCertPEM)
  141. if caCertPEMBlock == nil {
  142. fmt.Println("Failed to decode CA certificate")
  143. return
  144. }
  145. caKeyPEMBlock, _ := pem.Decode(caKeyPEM)
  146. if caKeyPEMBlock == nil {
  147. fmt.Println("Failed to decode CA key")
  148. return
  149. }
  150. caCert, err := x509.ParseCertificate(caCertPEMBlock.Bytes)
  151. if err != nil {
  152. fmt.Println("Failed to parse CA certificate:", err)
  153. return
  154. }
  155. caKey, err := x509.ParsePKCS1PrivateKey(caKeyPEMBlock.Bytes)
  156. if err != nil {
  157. fmt.Println("Failed to parse CA key:", err)
  158. return
  159. }
  160. // 生成客户端私钥
  161. clientPriv, _ := rsa.GenerateKey(rand.Reader, 2048)
  162. // 客户端证书模板
  163. clientTemplate := &x509.Certificate{
  164. SerialNumber: big.NewInt(3),
  165. Subject: pkix.Name{
  166. CommonName: "client",
  167. },
  168. NotBefore: time.Now(),
  169. NotAfter: time.Now().AddDate(1, 0, 0), // 有效期1年
  170. KeyUsage: x509.KeyUsageDigitalSignature,
  171. ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
  172. BasicConstraintsValid: true,
  173. }
  174. // 用 CA 签发客户端证书
  175. clientCertDER, _ := x509.CreateCertificate(rand.Reader, clientTemplate, caCert, &clientPriv.PublicKey, caKey)
  176. // 保存客户端证书和私钥
  177. writePem(filepath.Join(output, "client_cert.pem"), "CERTIFICATE", clientCertDER)
  178. writePem(filepath.Join(output, "client_key.pem"), "RSA PRIVATE KEY", x509.MarshalPKCS1PrivateKey(clientPriv))
  179. fmt.Println("Client certificate and key saved to", output)
  180. }
  181. func writePem(filename, pemType string, bytes []byte) {
  182. f, _ := os.Create(filename)
  183. pem.Encode(f, &pem.Block{Type: pemType, Bytes: bytes})
  184. f.Close()
  185. }

本项目旨在将云际存储公共基础设施化,使个人及企业可低门槛使用高效的云际存储服务(安装开箱即用云际存储客户端即可,无需关注其他组件的部署),同时支持用户灵活便捷定制云际存储的功能细节。