cert.go 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411
  1. package dbdata
  2. import (
  3. "crypto"
  4. "crypto/ecdsa"
  5. "crypto/elliptic"
  6. "crypto/rand"
  7. "crypto/rsa"
  8. "crypto/tls"
  9. "crypto/x509"
  10. "crypto/x509/pkix"
  11. "encoding/pem"
  12. "errors"
  13. "fmt"
  14. "math/big"
  15. "net"
  16. "os"
  17. "strings"
  18. "sync"
  19. "time"
  20. "github.com/pion/dtls/v2/pkg/crypto/selfsign"
  21. "github.com/bjdgyc/anylink/base"
  22. "github.com/go-acme/lego/v4/certcrypto"
  23. "github.com/go-acme/lego/v4/certificate"
  24. "github.com/go-acme/lego/v4/challenge"
  25. "github.com/go-acme/lego/v4/challenge/dns01"
  26. "github.com/go-acme/lego/v4/lego"
  27. "github.com/go-acme/lego/v4/providers/dns/alidns"
  28. "github.com/go-acme/lego/v4/providers/dns/cloudflare"
  29. "github.com/go-acme/lego/v4/providers/dns/tencentcloud"
  30. "github.com/go-acme/lego/v4/registration"
  31. )
  32. var (
  33. // nameToCertificate mutex
  34. ntcMux sync.RWMutex
  35. nameToCertificate = make(map[string]*tls.Certificate)
  36. tempCert *tls.Certificate
  37. )
  38. func init() {
  39. c, _ := selfsign.GenerateSelfSignedWithDNS("localhost")
  40. tempCert = &c
  41. }
  42. type SettingLetsEncrypt struct {
  43. Domain string `json:"domain"`
  44. Legomail string `json:"legomail"`
  45. Name string `json:"name"`
  46. Renew bool `json:"renew"`
  47. DNSProvider
  48. }
  49. type DNSProvider struct {
  50. AliYun struct {
  51. APIKey string `json:"apiKey"`
  52. SecretKey string `json:"secretKey"`
  53. } `json:"aliyun"`
  54. TXCloud struct {
  55. SecretID string `json:"secretId"`
  56. SecretKey string `json:"secretKey"`
  57. } `json:"txcloud"`
  58. CfCloud struct {
  59. AuthToken string `json:"authToken"`
  60. } `json:"cfcloud"`
  61. }
  62. type LegoUserData struct {
  63. Email string `json:"email"`
  64. Registration *registration.Resource `json:"registration"`
  65. Key []byte `json:"key"`
  66. }
  67. type LegoUser struct {
  68. Email string
  69. Registration *registration.Resource
  70. Key *ecdsa.PrivateKey
  71. }
  72. type LeGoClient struct {
  73. mutex sync.Mutex
  74. Client *lego.Client
  75. Cert *certificate.Resource
  76. LegoUserData
  77. }
  78. func GetDNSProvider(l *SettingLetsEncrypt) (Provider challenge.Provider, err error) {
  79. switch l.Name {
  80. case "aliyun":
  81. if Provider, err = alidns.NewDNSProviderConfig(&alidns.Config{APIKey: l.DNSProvider.AliYun.APIKey, SecretKey: l.DNSProvider.AliYun.SecretKey, PropagationTimeout: 60 * time.Second, PollingInterval: 2 * time.Second, TTL: 600}); err != nil {
  82. return
  83. }
  84. case "txcloud":
  85. if Provider, err = tencentcloud.NewDNSProviderConfig(&tencentcloud.Config{SecretID: l.DNSProvider.TXCloud.SecretID, SecretKey: l.DNSProvider.TXCloud.SecretKey, PropagationTimeout: 60 * time.Second, PollingInterval: 2 * time.Second, TTL: 600}); err != nil {
  86. return
  87. }
  88. case "cfcloud":
  89. if Provider, err = cloudflare.NewDNSProviderConfig(&cloudflare.Config{AuthToken: l.DNSProvider.CfCloud.AuthToken, PropagationTimeout: 60 * time.Second, PollingInterval: 2 * time.Second, TTL: 600}); err != nil {
  90. return
  91. }
  92. }
  93. return
  94. }
  95. func (u *LegoUser) GetEmail() string {
  96. return u.Email
  97. }
  98. func (u LegoUser) GetRegistration() *registration.Resource {
  99. return u.Registration
  100. }
  101. func (u *LegoUser) GetPrivateKey() crypto.PrivateKey {
  102. return u.Key
  103. }
  104. func (l *LegoUserData) SaveUserData(u *LegoUser) error {
  105. key, err := x509.MarshalECPrivateKey(u.Key)
  106. if err != nil {
  107. return err
  108. }
  109. l.Email = u.Email
  110. l.Registration = u.Registration
  111. l.Key = key
  112. if err := SettingSet(l); err != nil {
  113. return err
  114. }
  115. return nil
  116. }
  117. func (l *LegoUserData) GetUserData(d *SettingLetsEncrypt) (*LegoUser, error) {
  118. if err := SettingGet(l); err != nil {
  119. return nil, err
  120. }
  121. if l.Email != "" {
  122. key, err := x509.ParseECPrivateKey(l.Key)
  123. if err != nil {
  124. return nil, err
  125. }
  126. return &LegoUser{
  127. Email: l.Email,
  128. Registration: l.Registration,
  129. Key: key,
  130. }, nil
  131. }
  132. privateKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
  133. if err != nil {
  134. return nil, err
  135. }
  136. return &LegoUser{
  137. Email: d.Legomail,
  138. Key: privateKey,
  139. }, nil
  140. }
  141. func ReNewCert() {
  142. _, certtime, err := ParseCert()
  143. if err != nil {
  144. base.Error(err)
  145. return
  146. }
  147. if certtime.AddDate(0, 0, -7).Before(time.Now()) {
  148. config := &SettingLetsEncrypt{}
  149. if err := SettingGet(config); err != nil {
  150. base.Error(err)
  151. return
  152. }
  153. if config.Renew {
  154. client := &LeGoClient{}
  155. if err := client.NewClient(config); err != nil {
  156. base.Error(err)
  157. return
  158. }
  159. if err := client.RenewCert(base.Cfg.CertFile, base.Cfg.CertKey); err != nil {
  160. base.Error(err)
  161. return
  162. }
  163. base.Info("证书续期成功")
  164. }
  165. } else {
  166. base.Info(fmt.Sprintf("证书过期时间:%s", certtime.Local().Format("2006-1-2 15:04:05")))
  167. }
  168. }
  169. func (c *LeGoClient) NewClient(l *SettingLetsEncrypt) error {
  170. c.mutex.Lock()
  171. defer c.mutex.Unlock()
  172. legouser, err := c.GetUserData(l)
  173. if err != nil {
  174. return err
  175. }
  176. config := lego.NewConfig(legouser)
  177. config.CADirURL = lego.LEDirectoryProduction
  178. config.Certificate.KeyType = certcrypto.RSA2048
  179. client, err := lego.NewClient(config)
  180. if err != nil {
  181. return err
  182. }
  183. Provider, err := GetDNSProvider(l)
  184. if err != nil {
  185. return err
  186. }
  187. if err := client.Challenge.SetDNS01Provider(Provider, dns01.AddRecursiveNameservers([]string{"114.114.114.114", "114.114.115.115"})); err != nil {
  188. return err
  189. }
  190. if legouser.Registration == nil {
  191. reg, err := client.Registration.Register(registration.RegisterOptions{TermsOfServiceAgreed: true})
  192. if err != nil {
  193. return err
  194. }
  195. legouser.Registration = reg
  196. c.SaveUserData(legouser)
  197. }
  198. c.Client = client
  199. return nil
  200. }
  201. func (c *LeGoClient) GetCert(domain string) error {
  202. // 申请证书
  203. certificates, err := c.Client.Certificate.Obtain(
  204. certificate.ObtainRequest{
  205. Domains: []string{domain},
  206. Bundle: true,
  207. })
  208. if err != nil {
  209. return err
  210. }
  211. c.Cert = certificates
  212. // 保存证书
  213. if err := c.SaveCert(); err != nil {
  214. return err
  215. }
  216. return nil
  217. }
  218. func (c *LeGoClient) RenewCert(certFile, keyFile string) error {
  219. cert, err := os.ReadFile(certFile)
  220. if err != nil {
  221. return err
  222. }
  223. key, err := os.ReadFile(keyFile)
  224. if err != nil {
  225. return err
  226. }
  227. // 续期证书
  228. renewcert, err := c.Client.Certificate.Renew(certificate.Resource{
  229. Certificate: cert,
  230. PrivateKey: key,
  231. }, true, false, "")
  232. if err != nil {
  233. return err
  234. }
  235. c.Cert = renewcert
  236. // 保存更新证书
  237. if err := c.SaveCert(); err != nil {
  238. return err
  239. }
  240. return nil
  241. }
  242. func (c *LeGoClient) SaveCert() error {
  243. err := os.WriteFile(base.Cfg.CertFile, c.Cert.Certificate, 0600)
  244. if err != nil {
  245. return err
  246. }
  247. err = os.WriteFile(base.Cfg.CertKey, c.Cert.PrivateKey, 0600)
  248. if err != nil {
  249. return err
  250. }
  251. if tlscert, _, err := ParseCert(); err != nil {
  252. return err
  253. } else {
  254. LoadCertificate(tlscert)
  255. }
  256. return nil
  257. }
  258. func ParseCert() (*tls.Certificate, *time.Time, error) {
  259. _, errCert := os.Stat(base.Cfg.CertFile)
  260. _, errKey := os.Stat(base.Cfg.CertKey)
  261. if os.IsNotExist(errCert) || os.IsNotExist(errKey) {
  262. err := PrivateCert()
  263. if err != nil {
  264. return nil, nil, err
  265. }
  266. }
  267. cert, err := tls.LoadX509KeyPair(base.Cfg.CertFile, base.Cfg.CertKey)
  268. if err != nil || errors.Is(err, os.ErrNotExist) {
  269. PrivateCert()
  270. return nil, nil, err
  271. }
  272. parseCert, err := x509.ParseCertificate(cert.Certificate[0])
  273. if err != nil {
  274. return nil, nil, err
  275. }
  276. return &cert, &parseCert.NotAfter, nil
  277. }
  278. func PrivateCert() error {
  279. // 创建一个RSA密钥对
  280. priv, _ := rsa.GenerateKey(rand.Reader, 2048)
  281. pub := &priv.PublicKey
  282. // 生成一个自签名证书
  283. template := x509.Certificate{
  284. SerialNumber: big.NewInt(1658),
  285. Subject: pkix.Name{CommonName: "localhost"},
  286. NotBefore: time.Now(),
  287. NotAfter: time.Now().Add(time.Hour * 24 * 365),
  288. KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
  289. ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
  290. BasicConstraintsValid: true,
  291. IPAddresses: []net.IP{},
  292. }
  293. derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, pub, priv)
  294. if err != nil {
  295. return err
  296. }
  297. // 将证书编码为PEM格式并将其写入文件
  298. certOut, _ := os.OpenFile(base.Cfg.CertFile, os.O_WRONLY|os.O_TRUNC|os.O_CREATE, 0600)
  299. pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes})
  300. certOut.Close()
  301. // 将私钥编码为PEM格式并将其写入文件
  302. keyOut, _ := os.OpenFile(base.Cfg.CertKey, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
  303. pem.Encode(keyOut, &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(priv)})
  304. keyOut.Close()
  305. cert, err := tls.LoadX509KeyPair(base.Cfg.CertFile, base.Cfg.CertKey)
  306. if err != nil {
  307. return err
  308. }
  309. LoadCertificate(&cert)
  310. return nil
  311. }
  312. func getTempCertificate() (*tls.Certificate, error) {
  313. var err error
  314. var cert tls.Certificate
  315. if tempCert == nil {
  316. cert, err = selfsign.GenerateSelfSignedWithDNS("localhost")
  317. tempCert = &cert
  318. }
  319. return tempCert, err
  320. }
  321. func GetCertificateBySNI(commonName string) (*tls.Certificate, error) {
  322. ntcMux.RLock()
  323. defer ntcMux.RUnlock()
  324. // Copy from tls.Config getCertificate()
  325. name := strings.ToLower(commonName)
  326. if cert, ok := nameToCertificate[name]; ok {
  327. return cert, nil
  328. }
  329. if len(name) > 0 {
  330. labels := strings.Split(name, ".")
  331. labels[0] = "*"
  332. wildcardName := strings.Join(labels, ".")
  333. if cert, ok := nameToCertificate[wildcardName]; ok {
  334. return cert, nil
  335. }
  336. }
  337. // TODO 默认证书 兼容不支持 SNI 的客户端
  338. if cert, ok := nameToCertificate["default"]; ok {
  339. return cert, nil
  340. }
  341. return getTempCertificate()
  342. }
  343. func LoadCertificate(cert *tls.Certificate) {
  344. buildNameToCertificate(cert)
  345. }
  346. // Copy from tls.Config BuildNameToCertificate()
  347. func buildNameToCertificate(cert *tls.Certificate) {
  348. ntcMux.Lock()
  349. defer ntcMux.Unlock()
  350. // TODO 设置默认证书
  351. nameToCertificate["default"] = cert
  352. x509Cert, err := x509.ParseCertificate(cert.Certificate[0])
  353. if err != nil {
  354. return
  355. }
  356. startTime := x509Cert.NotBefore.String()
  357. expiredTime := x509Cert.NotAfter.String()
  358. if x509Cert.Subject.CommonName != "" && len(x509Cert.DNSNames) == 0 {
  359. commonName := x509Cert.Subject.CommonName
  360. fmt.Printf("┏ Load Certificate: %s\n", commonName)
  361. fmt.Printf("┠╌╌ Start Time: %s\n", startTime)
  362. fmt.Printf("┖╌╌ Expired Time: %s\n", expiredTime)
  363. nameToCertificate[commonName] = cert
  364. }
  365. for _, san := range x509Cert.DNSNames {
  366. fmt.Printf("┏ Load Certificate: %s\n", san)
  367. fmt.Printf("┠╌╌ Start Time: %s\n", startTime)
  368. fmt.Printf("┖╌╌ Expired Time: %s\n", expiredTime)
  369. nameToCertificate[san] = cert
  370. }
  371. }
  372. // func Scrypt(passwd string) string {
  373. // salt := []byte{0xc8, 0x28, 0xf2, 0x58, 0xa7, 0x6a, 0xad, 0x7b}
  374. // hashPasswd, err := scrypt.Key([]byte(passwd), salt, 1<<15, 8, 1, 32)
  375. // if err != nil {
  376. // return err.Error()
  377. // }
  378. // return base64.StdEncoding.EncodeToString(hashPasswd)
  379. // }