Index: web_page_replay_go/src/webpagereplay/certs.go |
diff --git a/web_page_replay_go/src/webpagereplay/certs.go b/web_page_replay_go/src/webpagereplay/certs.go |
index 8841c42040223109bd6951b3cb55952413f0b4ea..8e8c39d03ca620d154a1d6a0f8667c8591017efb 100644 |
--- a/web_page_replay_go/src/webpagereplay/certs.go |
+++ b/web_page_replay_go/src/webpagereplay/certs.go |
@@ -11,6 +11,7 @@ import ( |
"crypto/x509" |
"fmt" |
"io" |
+ "net" |
"time" |
) |
@@ -21,7 +22,7 @@ func ReplayTLSConfig(root tls.Certificate, a *Archive) (*tls.Config, error) { |
if err != nil { |
return nil, fmt.Errorf("bad local cert: %v", err) |
} |
- tp := &tlsProxy{&root, root_cert, a, nil} |
+ tp := &tlsProxy{&root, root_cert, a, nil, make(map[string][]byte)} |
return &tls.Config{ |
GetConfigForClient: tp.getReplayConfigForClient, |
}, nil |
@@ -34,7 +35,7 @@ func RecordTLSConfig(root tls.Certificate, w *WritableArchive) (*tls.Config, err |
if err != nil { |
return nil, fmt.Errorf("bad local cert: %v", err) |
} |
- tp := &tlsProxy{&root, root_cert, nil, w} |
+ tp := &tlsProxy{&root, root_cert, nil, w, nil} |
return &tls.Config{ |
GetConfigForClient: tp.getRecordConfigForClient, |
}, nil |
@@ -50,6 +51,27 @@ func getRootCert(root tls.Certificate) (*x509.Certificate, error) { |
return root_cert, nil |
} |
+// Mints a dummy server cert when the real one is not recorded. |
+func MintDummyCertificate(serverName string, rootCert *x509.Certificate, rootKey crypto.PrivateKey) ([]byte, string, error) { |
+ template := rootCert |
+ if ip := net.ParseIP(serverName); ip != nil { |
+ template.IPAddresses = []net.IP{ip} |
+ } else { |
+ template.DNSNames = []string{serverName} |
+ } |
+ var buf [20]byte |
+ if _, err := io.ReadFull(rand.Reader, buf[:]); err != nil { |
+ return nil, "", fmt.Errorf("create cert failed: %v", err) |
+ } |
+ template.SerialNumber.SetBytes(buf[:]) |
+ template.Issuer = template.Subject |
+ derBytes, err := x509.CreateCertificate(rand.Reader, template, template, template.PublicKey, rootKey) |
+ if err != nil { |
+ return nil, "", fmt.Errorf("create cert failed: %v", err) |
+ } |
+ return derBytes, "", err |
+} |
+ |
// Returns DER encoded server cert. |
func MintServerCert(serverName string, rootCert *x509.Certificate, rootKey crypto.PrivateKey) ([]byte, string, error) { |
conn, err := tls.Dial("tcp", fmt.Sprintf("%s:443", serverName), &tls.Config{ |
@@ -85,6 +107,7 @@ type tlsProxy struct { |
root_cert *x509.Certificate |
archive *Archive |
writable_archive *WritableArchive |
+ dummy_certs_map map[string][]byte |
} |
// TODO: For now, this just returns a self-signed cert using the given ServerName. |
@@ -103,7 +126,14 @@ func (tp *tlsProxy) getReplayConfigForClient(clientHello *tls.ClientHelloInfo) ( |
derBytes, negotiatedProtocol, err := tp.archive.FindHostTlsConfig(h) |
if err != nil || derBytes == nil { |
- return nil, fmt.Errorf("No archived cert for %s", h) |
+ if _, ok := tp.dummy_certs_map[h]; !ok { |
+ derBytes, negotiatedProtocol, err = MintDummyCertificate(h, tp.root_cert, tp.root.PrivateKey) |
+ if err != nil { |
+ return nil, err |
+ } |
+ tp.dummy_certs_map[h] = derBytes |
+ } |
+ derBytes = tp.dummy_certs_map[h] |
} |
return &tls.Config{ |
Certificates: []tls.Certificate{ |
@@ -111,7 +141,7 @@ func (tp *tlsProxy) getReplayConfigForClient(clientHello *tls.ClientHelloInfo) ( |
Certificate: [][]byte{derBytes}, |
PrivateKey: tp.root.PrivateKey, |
}}, |
- NextProtos: []string{negotiatedProtocol}, |
+ NextProtos: buildNextProtos(negotiatedProtocol), |
}, nil |
} |