| OLD | NEW |
| 1 // Copyright 2017 The Chromium Authors. All rights reserved. | 1 // Copyright 2017 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 package webpagereplay | 5 package webpagereplay |
| 6 | 6 |
| 7 import ( | 7 import ( |
| 8 "crypto" | 8 "crypto" |
| 9 "crypto/rand" | 9 "crypto/rand" |
| 10 "crypto/tls" | 10 "crypto/tls" |
| 11 "crypto/x509" | 11 "crypto/x509" |
| 12 "fmt" | 12 "fmt" |
| 13 "io" | 13 "io" |
| 14 "net" |
| 14 "time" | 15 "time" |
| 15 ) | 16 ) |
| 16 | 17 |
| 17 // Returns a TLS configuration that serves a recorded server leaf cert signed by | 18 // Returns a TLS configuration that serves a recorded server leaf cert signed by |
| 18 // root CA. | 19 // root CA. |
| 19 func ReplayTLSConfig(root tls.Certificate, a *Archive) (*tls.Config, error) { | 20 func ReplayTLSConfig(root tls.Certificate, a *Archive) (*tls.Config, error) { |
| 20 root_cert, err := getRootCert(root) | 21 root_cert, err := getRootCert(root) |
| 21 if err != nil { | 22 if err != nil { |
| 22 return nil, fmt.Errorf("bad local cert: %v", err) | 23 return nil, fmt.Errorf("bad local cert: %v", err) |
| 23 } | 24 } |
| 24 » tp := &tlsProxy{&root, root_cert, a, nil} | 25 » tp := &tlsProxy{&root, root_cert, a, nil, make(map[string][]byte)} |
| 25 return &tls.Config{ | 26 return &tls.Config{ |
| 26 GetConfigForClient: tp.getReplayConfigForClient, | 27 GetConfigForClient: tp.getReplayConfigForClient, |
| 27 }, nil | 28 }, nil |
| 28 } | 29 } |
| 29 | 30 |
| 30 // Returns a TLS configuration that serves a server leaf cert fetched over the | 31 // Returns a TLS configuration that serves a server leaf cert fetched over the |
| 31 // network on demand. | 32 // network on demand. |
| 32 func RecordTLSConfig(root tls.Certificate, w *WritableArchive) (*tls.Config, err
or) { | 33 func RecordTLSConfig(root tls.Certificate, w *WritableArchive) (*tls.Config, err
or) { |
| 33 root_cert, err := getRootCert(root) | 34 root_cert, err := getRootCert(root) |
| 34 if err != nil { | 35 if err != nil { |
| 35 return nil, fmt.Errorf("bad local cert: %v", err) | 36 return nil, fmt.Errorf("bad local cert: %v", err) |
| 36 } | 37 } |
| 37 » tp := &tlsProxy{&root, root_cert, nil, w} | 38 » tp := &tlsProxy{&root, root_cert, nil, w, nil} |
| 38 return &tls.Config{ | 39 return &tls.Config{ |
| 39 GetConfigForClient: tp.getRecordConfigForClient, | 40 GetConfigForClient: tp.getRecordConfigForClient, |
| 40 }, nil | 41 }, nil |
| 41 } | 42 } |
| 42 | 43 |
| 43 func getRootCert(root tls.Certificate) (*x509.Certificate, error) { | 44 func getRootCert(root tls.Certificate) (*x509.Certificate, error) { |
| 44 root_cert, err := x509.ParseCertificate(root.Certificate[0]) | 45 root_cert, err := x509.ParseCertificate(root.Certificate[0]) |
| 45 if err != nil { | 46 if err != nil { |
| 46 return nil, err | 47 return nil, err |
| 47 } | 48 } |
| 48 root_cert.IsCA = true | 49 root_cert.IsCA = true |
| 49 root_cert.BasicConstraintsValid = true | 50 root_cert.BasicConstraintsValid = true |
| 50 return root_cert, nil | 51 return root_cert, nil |
| 51 } | 52 } |
| 52 | 53 |
| 54 // Mints a dummy server cert when the real one is not recorded. |
| 55 func MintDummyCertificate(serverName string, rootCert *x509.Certificate, rootKey
crypto.PrivateKey) ([]byte, string, error) { |
| 56 template := rootCert |
| 57 if ip := net.ParseIP(serverName); ip != nil { |
| 58 template.IPAddresses = []net.IP{ip} |
| 59 } else { |
| 60 template.DNSNames = []string{serverName} |
| 61 } |
| 62 var buf [20]byte |
| 63 if _, err := io.ReadFull(rand.Reader, buf[:]); err != nil { |
| 64 return nil, "", fmt.Errorf("create cert failed: %v", err) |
| 65 } |
| 66 template.SerialNumber.SetBytes(buf[:]) |
| 67 template.Issuer = template.Subject |
| 68 derBytes, err := x509.CreateCertificate(rand.Reader, template, template,
template.PublicKey, rootKey) |
| 69 if err != nil { |
| 70 return nil, "", fmt.Errorf("create cert failed: %v", err) |
| 71 } |
| 72 return derBytes, "", err |
| 73 } |
| 74 |
| 53 // Returns DER encoded server cert. | 75 // Returns DER encoded server cert. |
| 54 func MintServerCert(serverName string, rootCert *x509.Certificate, rootKey crypt
o.PrivateKey) ([]byte, string, error) { | 76 func MintServerCert(serverName string, rootCert *x509.Certificate, rootKey crypt
o.PrivateKey) ([]byte, string, error) { |
| 55 conn, err := tls.Dial("tcp", fmt.Sprintf("%s:443", serverName), &tls.Con
fig{ | 77 conn, err := tls.Dial("tcp", fmt.Sprintf("%s:443", serverName), &tls.Con
fig{ |
| 56 NextProtos: []string{"h2", "http/1.1"}, | 78 NextProtos: []string{"h2", "http/1.1"}, |
| 57 }) | 79 }) |
| 58 if err != nil { | 80 if err != nil { |
| 59 return nil, "", fmt.Errorf("Couldn't reach host %s: %v", serverN
ame, err) | 81 return nil, "", fmt.Errorf("Couldn't reach host %s: %v", serverN
ame, err) |
| 60 } | 82 } |
| 61 defer conn.Close() | 83 defer conn.Close() |
| 62 conn.Handshake() | 84 conn.Handshake() |
| (...skipping 15 matching lines...) Expand all Loading... |
| 78 negotiatedProtocol := conn.ConnectionState().NegotiatedProtocol | 100 negotiatedProtocol := conn.ConnectionState().NegotiatedProtocol |
| 79 derBytes, err := x509.CreateCertificate(rand.Reader, template, rootCert,
template.PublicKey, rootKey) | 101 derBytes, err := x509.CreateCertificate(rand.Reader, template, rootCert,
template.PublicKey, rootKey) |
| 80 return derBytes, negotiatedProtocol, err | 102 return derBytes, negotiatedProtocol, err |
| 81 } | 103 } |
| 82 | 104 |
| 83 type tlsProxy struct { | 105 type tlsProxy struct { |
| 84 root *tls.Certificate | 106 root *tls.Certificate |
| 85 root_cert *x509.Certificate | 107 root_cert *x509.Certificate |
| 86 archive *Archive | 108 archive *Archive |
| 87 writable_archive *WritableArchive | 109 writable_archive *WritableArchive |
| 110 dummy_certs_map map[string][]byte |
| 88 } | 111 } |
| 89 | 112 |
| 90 // TODO: For now, this just returns a self-signed cert using the given ServerNam
e. | 113 // TODO: For now, this just returns a self-signed cert using the given ServerNam
e. |
| 91 // In the future, for better HTTP/2 support, we may want to record host equivale
nce | 114 // In the future, for better HTTP/2 support, we may want to record host equivale
nce |
| 92 // classes in the archive, where an equivalence class contains all hosts that ca
n be | 115 // classes in the archive, where an equivalence class contains all hosts that ca
n be |
| 93 // served by the same IP. We can then run a DNS proxy that maps all hostnames in
the | 116 // served by the same IP. We can then run a DNS proxy that maps all hostnames in
the |
| 94 // same equivalence class to the same local port, which models the possibility t
hat | 117 // same equivalence class to the same local port, which models the possibility t
hat |
| 95 // every equivalence class of hostnames can be served over the same HTTP/2 conne
ction. | 118 // every equivalence class of hostnames can be served over the same HTTP/2 conne
ction. |
| 96 func (tp *tlsProxy) getReplayConfigForClient(clientHello *tls.ClientHelloInfo) (
*tls.Config, error) { | 119 func (tp *tlsProxy) getReplayConfigForClient(clientHello *tls.ClientHelloInfo) (
*tls.Config, error) { |
| 97 h := clientHello.ServerName | 120 h := clientHello.ServerName |
| 98 if h == "" { | 121 if h == "" { |
| 99 return &tls.Config{ | 122 return &tls.Config{ |
| 100 Certificates: []tls.Certificate{*tp.root}, | 123 Certificates: []tls.Certificate{*tp.root}, |
| 101 }, nil | 124 }, nil |
| 102 } | 125 } |
| 103 | 126 |
| 104 derBytes, negotiatedProtocol, err := tp.archive.FindHostTlsConfig(h) | 127 derBytes, negotiatedProtocol, err := tp.archive.FindHostTlsConfig(h) |
| 105 if err != nil || derBytes == nil { | 128 if err != nil || derBytes == nil { |
| 106 » » return nil, fmt.Errorf("No archived cert for %s", h) | 129 » » if _, ok := tp.dummy_certs_map[h]; !ok { |
| 130 » » » derBytes, negotiatedProtocol, err = MintDummyCertificate
(h, tp.root_cert, tp.root.PrivateKey) |
| 131 » » » if err != nil { |
| 132 » » » » return nil, err |
| 133 » » » } |
| 134 » » » tp.dummy_certs_map[h] = derBytes |
| 135 » » } |
| 136 » » derBytes = tp.dummy_certs_map[h] |
| 107 } | 137 } |
| 108 return &tls.Config{ | 138 return &tls.Config{ |
| 109 Certificates: []tls.Certificate{ | 139 Certificates: []tls.Certificate{ |
| 110 tls.Certificate{ | 140 tls.Certificate{ |
| 111 Certificate: [][]byte{derBytes}, | 141 Certificate: [][]byte{derBytes}, |
| 112 PrivateKey: tp.root.PrivateKey, | 142 PrivateKey: tp.root.PrivateKey, |
| 113 }}, | 143 }}, |
| 114 » » NextProtos: []string{negotiatedProtocol}, | 144 » » NextProtos: buildNextProtos(negotiatedProtocol), |
| 115 }, nil | 145 }, nil |
| 116 } | 146 } |
| 117 | 147 |
| 118 func buildNextProtos(negotiatedProtocol string) []string { | 148 func buildNextProtos(negotiatedProtocol string) []string { |
| 119 if negotiatedProtocol == "h2" { | 149 if negotiatedProtocol == "h2" { |
| 120 return []string{"h2", "http/1.1"} | 150 return []string{"h2", "http/1.1"} |
| 121 } | 151 } |
| 122 return []string{"http/1.1"} | 152 return []string{"http/1.1"} |
| 123 } | 153 } |
| 124 | 154 |
| (...skipping 24 matching lines...) Expand all Loading... |
| 149 tp.writable_archive.RecordTlsConfig(h, derBytes, negotiatedProtocol) | 179 tp.writable_archive.RecordTlsConfig(h, derBytes, negotiatedProtocol) |
| 150 | 180 |
| 151 return &tls.Config{ | 181 return &tls.Config{ |
| 152 Certificates: []tls.Certificate{ | 182 Certificates: []tls.Certificate{ |
| 153 tls.Certificate{ | 183 tls.Certificate{ |
| 154 Certificate: [][]byte{derBytes}, | 184 Certificate: [][]byte{derBytes}, |
| 155 PrivateKey: tp.root.PrivateKey}}, | 185 PrivateKey: tp.root.PrivateKey}}, |
| 156 NextProtos: buildNextProtos(negotiatedProtocol), | 186 NextProtos: buildNextProtos(negotiatedProtocol), |
| 157 }, nil | 187 }, nil |
| 158 } | 188 } |
| OLD | NEW |