Source file
src/crypto/tls/ech_test.go
1
2
3
4
5 package tls
6
7 import (
8 "bytes"
9 "encoding/hex"
10 "strings"
11 "testing"
12
13 "golang.org/x/crypto/cryptobyte"
14 )
15
16 func TestDecodeECHConfigLists(t *testing.T) {
17 for _, tc := range []struct {
18 list string
19 numConfigs int
20 }{
21 {"0045fe0d0041590020002092a01233db2218518ccbbbbc24df20686af417b37388de6460e94011974777090004000100010012636c6f7564666c6172652d6563682e636f6d0000", 1},
22 {"0105badd00050504030201fe0d0066000010004104e62b69e2bf659f97be2f1e0d948a4cd5976bb7a91e0d46fbdda9a91e9ddcba5a01e7d697a80a18f9c3c4a31e56e27c8348db161a1cf51d7ef1942d4bcf7222c1000c000100010001000200010003400e7075626c69632e6578616d706c650000fe0d003d00002000207d661615730214aeee70533366f36a609ead65c0c208e62322346ab5bcd8de1c000411112222400e7075626c69632e6578616d706c650000fe0d004d000020002085bd6a03277c25427b52e269e0c77a8eb524ba1eb3d2f132662d4b0ac6cb7357000c000100010001000200010003400e7075626c69632e6578616d706c650008aaaa000474657374", 3},
23 } {
24 b, err := hex.DecodeString(tc.list)
25 if err != nil {
26 t.Fatal(err)
27 }
28 configs, err := parseECHConfigList(b)
29 if err != nil {
30 t.Fatal(err)
31 }
32 if len(configs) != tc.numConfigs {
33 t.Fatalf("unexpected number of configs parsed: got %d want %d", len(configs), tc.numConfigs)
34 }
35 }
36
37 }
38
39 func TestSkipBadConfigs(t *testing.T) {
40 b, err := hex.DecodeString("00c8badd00050504030201fe0d0029006666000401020304000c000100010001000200010003400e7075626c69632e6578616d706c650000fe0d003d000020002072e8a23b7aef67832bcc89d652e3870a60f88ca684ec65d6eace6b61f136064c000411112222400e7075626c69632e6578616d706c650000fe0d004d00002000200ce95810a81d8023f41e83679bc92701b2acd46c75869f95c72bc61c6b12297c000c000100010001000200010003400e7075626c69632e6578616d706c650008aaaa000474657374")
41 if err != nil {
42 t.Fatal(err)
43 }
44 configs, err := parseECHConfigList(b)
45 if err != nil {
46 t.Fatal(err)
47 }
48 config, _, _, _ := pickECHConfig(configs)
49 if config != nil {
50 t.Fatal("pickECHConfig picked an invalid config")
51 }
52 }
53
54 func TestPickECHConfigWithInvalidAEADID(t *testing.T) {
55 b, err := hex.DecodeString("0045fe0d0041590020002092a01233db2218518ccbbbbc24df20686af417b37388de6460e94011974777090004000100010012636c6f7564666c6172652d6563682e636f6d0000")
56 if err != nil {
57 t.Fatal(err)
58 }
59 buf := bytes.Replace(b, []byte{0x00, 0x01, 0x00, 0x01}, []byte{0x00, 0x01, 0xFF, 0xFF}, 1)
60 configs, err := parseECHConfigList(buf)
61 if err != nil {
62 t.Fatal(err)
63 }
64 if config, _, _, _ := pickECHConfig(configs); config != nil {
65 t.Fatalf("got %v, want nil", config)
66 }
67 }
68
69 func TestECHPadding(t *testing.T) {
70 const maxNameLength = 64
71 for _, tc := range []struct {
72 name string
73 serverName string
74 }{
75 {"Short", "a.test"},
76 {"Medium", strings.Repeat("a", 30) + ".test"},
77 {"MaxLength", strings.Repeat("a", maxNameLength) + ".test"},
78 {"NoSNI", ""},
79 } {
80 t.Run(tc.name, func(t *testing.T) {
81 inner := &clientHelloMsg{
82 vers: VersionTLS13,
83 random: make([]byte, 32),
84 serverName: tc.serverName,
85 cipherSuites: []uint16{TLS_AES_128_GCM_SHA256},
86 compressionMethods: []uint8{0},
87 supportedVersions: []uint16{VersionTLS13},
88 }
89 encoded, err := encodeInnerClientHello(inner, maxNameLength)
90 if err != nil {
91 t.Fatal(err)
92 }
93 if len(encoded)%32 != 0 {
94 t.Errorf("got %d, want multiple of 32", len(encoded))
95 }
96 })
97 }
98
99 t.Run("SetSizeReduction", func(t *testing.T) {
100 sizes := make(map[int]struct{})
101 for sniLen := 1; sniLen <= maxNameLength; sniLen++ {
102 inner := &clientHelloMsg{
103 vers: VersionTLS13,
104 random: make([]byte, 32),
105 serverName: strings.Repeat("a", sniLen) + ".test",
106 cipherSuites: []uint16{TLS_AES_128_GCM_SHA256},
107 compressionMethods: []uint8{0},
108 supportedVersions: []uint16{VersionTLS13},
109 }
110 encoded, err := encodeInnerClientHello(inner, maxNameLength)
111 if err != nil {
112 t.Fatal(err)
113 }
114 sizes[len(encoded)] = struct{}{}
115 }
116 if len(sizes) > 4 {
117 t.Errorf("got %d distinct encoded sizes for SNI lengths 1..%d, want <= 4", len(sizes), maxNameLength)
118 }
119 })
120 }
121
122 func TestDecodeInnerClientHelloOuterExtensions(t *testing.T) {
123 outer := &clientHelloMsg{
124 vers: VersionTLS12,
125 random: make([]byte, 32),
126 cipherSuites: []uint16{TLS_AES_128_GCM_SHA256},
127 compressionMethods: []uint8{compressionNone},
128 ocspStapling: true,
129 supportedCurves: []CurveID{CurveP256},
130 encryptedClientHello: []byte{byte(innerECHExt)},
131 }
132 outer.original = mustMarshal(t, outer)
133
134 encodeInner := func(buildExts func(*cryptobyte.Builder)) []byte {
135 var b cryptobyte.Builder
136 b.AddUint16(VersionTLS12)
137 b.AddBytes(make([]byte, 32))
138 b.AddUint8(0)
139 b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
140 b.AddUint16(TLS_AES_128_GCM_SHA256)
141 })
142 b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) {
143 b.AddUint8(compressionNone)
144 })
145 b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
146 buildExts(b)
147 b.AddUint16(extensionEncryptedClientHello)
148 b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
149 b.AddUint8(uint8(innerECHExt))
150 })
151 b.AddUint16(extensionSupportedVersions)
152 b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
153 b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) {
154 b.AddUint16(VersionTLS13)
155 })
156 })
157 })
158 return b.BytesOrPanic()
159 }
160
161 outerExts := func(b *cryptobyte.Builder, extTypes ...uint16) {
162 b.AddUint16(extensionECHOuterExtensions)
163 b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
164 b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) {
165 for _, extType := range extTypes {
166 b.AddUint16(extType)
167 }
168 })
169 })
170 }
171
172 for _, tc := range []struct {
173 name string
174 buildExts func(*cryptobyte.Builder)
175 wantErr string
176 }{
177 {
178 name: "valid order",
179 buildExts: func(b *cryptobyte.Builder) {
180 outerExts(b, extensionStatusRequest, extensionSupportedCurves)
181 },
182 },
183 {
184 name: "duplicate reference",
185 buildExts: func(b *cryptobyte.Builder) {
186 outerExts(b, extensionStatusRequest, extensionStatusRequest)
187 },
188 wantErr: "tls: invalid outer extensions",
189 },
190 {
191 name: "references encrypted_client_hello",
192 buildExts: func(b *cryptobyte.Builder) {
193 outerExts(b, extensionEncryptedClientHello)
194 },
195 wantErr: "tls: invalid outer extensions",
196 },
197 {
198 name: "references ech_outer_extensions",
199 buildExts: func(b *cryptobyte.Builder) {
200 outerExts(b, extensionECHOuterExtensions)
201 },
202 wantErr: "tls: invalid outer extensions",
203 },
204 {
205 name: "multiple ech_outer_extensions",
206 buildExts: func(b *cryptobyte.Builder) {
207 outerExts(b, extensionStatusRequest)
208 outerExts(b, extensionSupportedCurves)
209 },
210 wantErr: "tls: invalid outer extensions",
211 },
212 {
213 name: "odd-length reference list",
214 buildExts: func(b *cryptobyte.Builder) {
215 b.AddUint16(extensionECHOuterExtensions)
216 b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
217 b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) {
218 b.AddUint8(0)
219 })
220 })
221 },
222 wantErr: "tls: invalid inner client hello",
223 },
224 {
225 name: "empty reference list",
226 buildExts: func(b *cryptobyte.Builder) {
227 b.AddUint16(extensionECHOuterExtensions)
228 b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
229 b.AddUint8(0)
230 })
231 },
232 wantErr: "tls: invalid inner client hello",
233 },
234 } {
235 t.Run(tc.name, func(t *testing.T) {
236 encoded := encodeInner(tc.buildExts)
237 _, err := decodeInnerClientHello(outer, encoded)
238 if tc.wantErr == "" {
239 if err != nil {
240 t.Fatalf("decodeInnerClientHello returned %v, want nil", err)
241 }
242 } else if err == nil || err.Error() != tc.wantErr {
243 t.Fatalf("decodeInnerClientHello returned %v, want %q", err, tc.wantErr)
244 }
245 })
246 }
247 }
248
View as plain text