Skip to content
This repository was archived by the owner on Dec 20, 2024. It is now read-only.

Commit e40b16a

Browse files
committed
draft impl
Signed-off-by: YanzheL <[email protected]>
1 parent def2b21 commit e40b16a

File tree

2 files changed

+92
-1
lines changed

2 files changed

+92
-1
lines changed

dfdaemon/proxy/cert.go

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
/*
2+
* Copyright The Dragonfly Authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package proxy
18+
19+
import (
20+
"crypto"
21+
"crypto/rand"
22+
"crypto/tls"
23+
"crypto/x509"
24+
"crypto/x509/pkix"
25+
"errors"
26+
"math/big"
27+
"time"
28+
29+
"github.com/sirupsen/logrus"
30+
)
31+
32+
type LeafCertSpec struct {
33+
publicKey crypto.PublicKey
34+
35+
privateKey crypto.PrivateKey
36+
37+
signatureAlgorithm x509.SignatureAlgorithm
38+
}
39+
40+
func genLeafCert(ca *tls.Certificate, leafCertSpec *LeafCertSpec, commonName string, dnsNames ...string) (*tls.Certificate, error) {
41+
now := time.Now().Add(-1 * time.Hour).UTC()
42+
if !ca.Leaf.IsCA {
43+
return nil, errors.New("CA cert is not a CA")
44+
}
45+
serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
46+
serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
47+
if err != nil {
48+
logrus.Errorf("failed to generate serial number: %s", err)
49+
return nil, err
50+
}
51+
tmpl := &x509.Certificate{
52+
SerialNumber: serialNumber,
53+
Subject: pkix.Name{CommonName: commonName},
54+
NotBefore: now,
55+
NotAfter: now.Add(24 * time.Hour),
56+
KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment | x509.KeyUsageDataEncipherment | x509.KeyUsageKeyAgreement,
57+
BasicConstraintsValid: true,
58+
DNSNames: dnsNames,
59+
SignatureAlgorithm: leafCertSpec.signatureAlgorithm,
60+
}
61+
newCert, err := x509.CreateCertificate(rand.Reader, tmpl, ca.Leaf, leafCertSpec.publicKey, ca.PrivateKey)
62+
if err != nil {
63+
logrus.Errorf("failed to generate leaf cert %s", err)
64+
return nil, err
65+
}
66+
cert := new(tls.Certificate)
67+
cert.Certificate = append(cert.Certificate, newCert)
68+
cert.PrivateKey = leafCertSpec.privateKey
69+
cert.Leaf, _ = x509.ParseCertificate(newCert)
70+
return cert, nil
71+
}

dfdaemon/proxy/proxy.go

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package proxy
1818

1919
import (
2020
"crypto/tls"
21+
"crypto/x509"
2122
"fmt"
2223
"io"
2324
"net"
@@ -72,6 +73,11 @@ func WithCertFromFile(certFile, keyFile string) Option {
7273
return errors.Wrap(err, "load cert")
7374
}
7475
logrus.Infof("use self-signed certificate (%s, %s) for https hijacking", certFile, keyFile)
76+
leaf, err := x509.ParseCertificate(cert.Certificate[0])
77+
if err != nil {
78+
return errors.Wrap(err, "load leaf cert")
79+
}
80+
cert.Leaf = leaf
7581
p.cert = &cert
7682
return nil
7783
}
@@ -314,7 +320,21 @@ func (proxy *Proxy) handleHTTPS(w http.ResponseWriter, r *http.Request) {
314320
logrus.Debugln("hijack https request to", r.Host)
315321

316322
sConfig := new(tls.Config)
317-
sConfig.Certificates = []tls.Certificate{*proxy.cert}
323+
if proxy.cert.Leaf != nil && proxy.cert.Leaf.IsCA {
324+
logrus.Debugf("hijack https request with CA <%s>", proxy.cert.Leaf.Subject.CommonName)
325+
leafCertSpec := LeafCertSpec{
326+
proxy.cert.Leaf.PublicKey,
327+
proxy.cert.PrivateKey,
328+
proxy.cert.Leaf.SignatureAlgorithm}
329+
host, _, _ := net.SplitHostPort(r.Host)
330+
sConfig.GetCertificate = func(hello *tls.ClientHelloInfo) (*tls.Certificate, error) {
331+
cConfig.ServerName = hello.ServerName
332+
logrus.Debugf("Generate temporal leaf TLS cert for host <%s>", hello.ServerName)
333+
return genLeafCert(proxy.cert, &leafCertSpec, hello.ServerName, host)
334+
}
335+
} else {
336+
sConfig.Certificates = []tls.Certificate{*proxy.cert}
337+
}
318338

319339
sConn, err := handshake(w, sConfig)
320340
if err != nil {

0 commit comments

Comments
 (0)