tls.go 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. package tlscfg
  2. import (
  3. "encoding/base64"
  4. "strings"
  5. "github.com/golang/protobuf/proto"
  6. "github.com/v2fly/v2ray-core/v5/common/platform/filesystem"
  7. "github.com/v2fly/v2ray-core/v5/infra/conf/cfgcommon"
  8. "github.com/v2fly/v2ray-core/v5/transport/internet/tls"
  9. )
  10. //go:generate go run github.com/v2fly/v2ray-core/v5/common/errors/errorgen
  11. type TLSConfig struct {
  12. Insecure bool `json:"allowInsecure"`
  13. Certs []*TLSCertConfig `json:"certificates"`
  14. ServerName string `json:"serverName"`
  15. ALPN *cfgcommon.StringList `json:"alpn"`
  16. EnableSessionResumption bool `json:"enableSessionResumption"`
  17. DisableSystemRoot bool `json:"disableSystemRoot"`
  18. PinnedPeerCertificateChainSha256 *[]string `json:"pinnedPeerCertificateChainSha256"`
  19. VerifyClientCertificate bool `json:"verifyClientCertificate"`
  20. ECHConfig string `json:"echConfig"`
  21. ECHDOHServer string `json:"echDohServer"`
  22. }
  23. // Build implements Buildable.
  24. func (c *TLSConfig) Build() (proto.Message, error) {
  25. config := new(tls.Config)
  26. config.Certificate = make([]*tls.Certificate, len(c.Certs))
  27. for idx, certConf := range c.Certs {
  28. cert, err := certConf.Build()
  29. if err != nil {
  30. return nil, err
  31. }
  32. config.Certificate[idx] = cert
  33. }
  34. serverName := c.ServerName
  35. config.AllowInsecure = c.Insecure
  36. config.VerifyClientCertificate = c.VerifyClientCertificate
  37. if len(c.ServerName) > 0 {
  38. config.ServerName = serverName
  39. }
  40. if c.ALPN != nil && len(*c.ALPN) > 0 {
  41. config.NextProtocol = []string(*c.ALPN)
  42. }
  43. config.EnableSessionResumption = c.EnableSessionResumption
  44. config.DisableSystemRoot = c.DisableSystemRoot
  45. if c.PinnedPeerCertificateChainSha256 != nil {
  46. config.PinnedPeerCertificateChainSha256 = [][]byte{}
  47. for _, v := range *c.PinnedPeerCertificateChainSha256 {
  48. hashValue, err := base64.StdEncoding.DecodeString(v)
  49. if err != nil {
  50. return nil, err
  51. }
  52. config.PinnedPeerCertificateChainSha256 = append(config.PinnedPeerCertificateChainSha256, hashValue)
  53. }
  54. }
  55. if c.ECHConfig != "" {
  56. ECHConfig, err := base64.StdEncoding.DecodeString(c.ECHConfig)
  57. if err != nil {
  58. return nil, newError("invalid ECH Config", c.ECHConfig)
  59. }
  60. config.EchConfig = ECHConfig
  61. }
  62. config.Ech_DOHserver = c.ECHDOHServer
  63. return config, nil
  64. }
  65. type TLSCertConfig struct {
  66. CertFile string `json:"certificateFile"`
  67. CertStr []string `json:"certificate"`
  68. KeyFile string `json:"keyFile"`
  69. KeyStr []string `json:"key"`
  70. Usage string `json:"usage"`
  71. }
  72. // Build implements Buildable.
  73. func (c *TLSCertConfig) Build() (*tls.Certificate, error) {
  74. certificate := new(tls.Certificate)
  75. cert, err := readFileOrString(c.CertFile, c.CertStr)
  76. if err != nil {
  77. return nil, newError("failed to parse certificate").Base(err)
  78. }
  79. certificate.Certificate = cert
  80. if len(c.KeyFile) > 0 || len(c.KeyStr) > 0 {
  81. key, err := readFileOrString(c.KeyFile, c.KeyStr)
  82. if err != nil {
  83. return nil, newError("failed to parse key").Base(err)
  84. }
  85. certificate.Key = key
  86. }
  87. switch strings.ToLower(c.Usage) {
  88. case "encipherment":
  89. certificate.Usage = tls.Certificate_ENCIPHERMENT
  90. case "verify":
  91. certificate.Usage = tls.Certificate_AUTHORITY_VERIFY
  92. case "verifyclient":
  93. certificate.Usage = tls.Certificate_AUTHORITY_VERIFY_CLIENT
  94. case "issue":
  95. certificate.Usage = tls.Certificate_AUTHORITY_ISSUE
  96. default:
  97. certificate.Usage = tls.Certificate_ENCIPHERMENT
  98. }
  99. return certificate, nil
  100. }
  101. func readFileOrString(f string, s []string) ([]byte, error) {
  102. if len(f) > 0 {
  103. return filesystem.ReadFile(f)
  104. }
  105. if len(s) > 0 {
  106. return []byte(strings.Join(s, "\n")), nil
  107. }
  108. return nil, newError("both file and bytes are empty.")
  109. }