Skip to content

Commit 50f0838

Browse files
implemented CaSigner with cache
1 parent 8bc3341 commit 50f0838

File tree

3 files changed

+78
-4
lines changed

3 files changed

+78
-4
lines changed

ca.go

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
mrand "math/rand"
1111
"net"
1212
"sort"
13+
"sync"
1314
"time"
1415
)
1516

@@ -100,6 +101,74 @@ s39uFDUnxsMb2Nl3JcNJHYBTm9ubjAZSo/3NuB0z/Gm+ssOcExTD//vW7BxxSAcs
100101
/xlPPTPbY5qoMAT7kK71kd4Ypnqbcs3UPpAHtcPkjWpuWOlebK0J7UYToj4f
101102
-----END RSA PRIVATE KEY-----`)
102103

104+
type CaSigner struct {
105+
Ca *tls.Certificate
106+
mu sync.RWMutex
107+
certMap map[string]*tls.Certificate
108+
certList []string
109+
certIndex int
110+
certMax int
111+
}
112+
113+
func NewCaSigner() *CaSigner {
114+
return NewCaSignerCache(0)
115+
}
116+
117+
func NewCaSignerCache(max int) *CaSigner {
118+
if max < 0 {
119+
max = 0
120+
}
121+
return &CaSigner{
122+
certMap: make(map[string]*tls.Certificate),
123+
certList: make([]string, max),
124+
certIndex: 0,
125+
certMax: max,
126+
}
127+
}
128+
129+
func (c *CaSigner) SignHost(host string) (cert *tls.Certificate) {
130+
if host == "" {
131+
return
132+
}
133+
if c.certMax <= 0 {
134+
crt, err := signHosts(*c.Ca, []string{host})
135+
if err != nil {
136+
return nil
137+
}
138+
cert = &crt
139+
return
140+
}
141+
func() {
142+
c.mu.RLock()
143+
defer c.mu.RUnlock()
144+
cert = c.certMap[host]
145+
}()
146+
if cert != nil {
147+
return
148+
}
149+
c.mu.Lock()
150+
defer c.mu.Unlock()
151+
cert = c.certMap[host]
152+
if cert != nil {
153+
return
154+
}
155+
crt, err := signHosts(*c.Ca, []string{host})
156+
if err != nil {
157+
return nil
158+
}
159+
cert = &crt
160+
if len(c.certMap) >= c.certMax {
161+
delete(c.certMap, c.certList[c.certIndex])
162+
}
163+
c.certMap[host] = cert
164+
c.certList[c.certIndex] = host
165+
c.certIndex++
166+
if c.certIndex >= c.certMax {
167+
c.certIndex = 0
168+
}
169+
return
170+
}
171+
103172
func signHosts(ca tls.Certificate, hosts []string) (cert tls.Certificate, error error) {
104173
var x509ca *x509.Certificate
105174
if x509ca, error = x509.ParseCertificate(ca.Certificate[0]); error != nil {

doing.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -153,13 +153,13 @@ func doConnect(ctx *Context, w http.ResponseWriter, r *http.Request) (w2 http.Re
153153
remoteConn.Close()
154154
case ConnectMitm:
155155
tlsConfig := &tls.Config{}
156-
cert, err := signHosts(ctx.Prx.Ca, []string{stripPort(host)})
157-
if err != nil {
156+
cert := ctx.Prx.signer.SignHost(stripPort(host))
157+
if cert == nil {
158158
hijConn.Close()
159159
doError(ctx, "Connect", ErrTLSSignHost, err)
160160
return
161161
}
162-
tlsConfig.Certificates = append(tlsConfig.Certificates, cert)
162+
tlsConfig.Certificates = append(tlsConfig.Certificates, *cert)
163163
if _, err := hijConn.Write([]byte("HTTP/1.1 200 OK\r\n\r\n")); err != nil {
164164
hijConn.Close()
165165
if !isConnectionClosed(err) {

httpproxy.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,8 @@ type Proxy struct {
7878
MitmChunked bool
7979

8080
AuthType string
81+
82+
signer *CaSigner
8183
}
8284

8385
// NewProxy returns a new Proxy has default CA certificate and key.
@@ -89,8 +91,11 @@ func NewProxy() (*Proxy, error) {
8991
func NewProxyCert(caCert, caKey []byte) (result *Proxy, error error) {
9092
result = &Proxy{
9193
Rt: &http.Transport{TLSClientConfig: &tls.Config{},
92-
Proxy: http.ProxyFromEnvironment}, MitmChunked: true,
94+
Proxy: http.ProxyFromEnvironment},
95+
MitmChunked: true,
96+
signer: NewCaSignerCache(1024),
9397
}
98+
result.signer.Ca = &result.Ca
9499
if caCert == nil {
95100
caCert = DefaultCaCert
96101
}

0 commit comments

Comments
 (0)