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