1
18
19 package xds
20
21 import (
22 "crypto/x509"
23 "net"
24 "net/url"
25 "regexp"
26 "testing"
27
28 "google.golang.org/grpc/internal/xds/matcher"
29 )
30
31 func TestDNSMatch(t *testing.T) {
32 tests := []struct {
33 desc string
34 host string
35 pattern string
36 wantMatch bool
37 }{
38 {
39 desc: "invalid wildcard 1",
40 host: "aa.example.com",
41 pattern: "*a.example.com",
42 wantMatch: false,
43 },
44 {
45 desc: "invalid wildcard 2",
46 host: "aa.example.com",
47 pattern: "a*.example.com",
48 wantMatch: false,
49 },
50 {
51 desc: "invalid wildcard 3",
52 host: "abc.example.com",
53 pattern: "a*c.example.com",
54 wantMatch: false,
55 },
56 {
57 desc: "wildcard in one of the middle components",
58 host: "abc.test.example.com",
59 pattern: "abc.*.example.com",
60 wantMatch: false,
61 },
62 {
63 desc: "single component wildcard",
64 host: "a.example.com",
65 pattern: "*",
66 wantMatch: false,
67 },
68 {
69 desc: "short host name",
70 host: "a.com",
71 pattern: "*.example.com",
72 wantMatch: false,
73 },
74 {
75 desc: "suffix mismatch",
76 host: "a.notexample.com",
77 pattern: "*.example.com",
78 wantMatch: false,
79 },
80 {
81 desc: "wildcard match across components",
82 host: "sub.test.example.com",
83 pattern: "*.example.com.",
84 wantMatch: false,
85 },
86 {
87 desc: "host doesn't end in period",
88 host: "test.example.com",
89 pattern: "test.example.com.",
90 wantMatch: true,
91 },
92 {
93 desc: "pattern doesn't end in period",
94 host: "test.example.com.",
95 pattern: "test.example.com",
96 wantMatch: true,
97 },
98 {
99 desc: "case insensitive",
100 host: "TEST.EXAMPLE.COM.",
101 pattern: "test.example.com.",
102 wantMatch: true,
103 },
104 {
105 desc: "simple match",
106 host: "test.example.com",
107 pattern: "test.example.com",
108 wantMatch: true,
109 },
110 {
111 desc: "good wildcard",
112 host: "a.example.com",
113 pattern: "*.example.com",
114 wantMatch: true,
115 },
116 }
117
118 for _, test := range tests {
119 t.Run(test.desc, func(t *testing.T) {
120 gotMatch := dnsMatch(test.host, test.pattern)
121 if gotMatch != test.wantMatch {
122 t.Fatalf("dnsMatch(%s, %s) = %v, want %v", test.host, test.pattern, gotMatch, test.wantMatch)
123 }
124 })
125 }
126 }
127
128 func TestMatchingSANExists_FailureCases(t *testing.T) {
129 url1, err := url.Parse("http://golang.org")
130 if err != nil {
131 t.Fatalf("url.Parse() failed: %v", err)
132 }
133 url2, err := url.Parse("https://github.com/grpc/grpc-go")
134 if err != nil {
135 t.Fatalf("url.Parse() failed: %v", err)
136 }
137 inputCert := &x509.Certificate{
138 DNSNames: []string{"foo.bar.example.com", "bar.baz.test.com", "*.example.com"},
139 EmailAddresses: []string{"foobar@example.com", "barbaz@test.com"},
140 IPAddresses: []net.IP{net.ParseIP("192.0.0.1"), net.ParseIP("2001:db8::68")},
141 URIs: []*url.URL{url1, url2},
142 }
143
144 tests := []struct {
145 desc string
146 sanMatchers []matcher.StringMatcher
147 }{
148 {
149 desc: "exact match",
150 sanMatchers: []matcher.StringMatcher{
151 matcher.StringMatcherForTesting(newStringP("abcd.test.com"), nil, nil, nil, nil, false),
152 matcher.StringMatcherForTesting(newStringP("http://golang"), nil, nil, nil, nil, false),
153 matcher.StringMatcherForTesting(newStringP("HTTP://GOLANG.ORG"), nil, nil, nil, nil, false),
154 },
155 },
156 {
157 desc: "prefix match",
158 sanMatchers: []matcher.StringMatcher{
159 matcher.StringMatcherForTesting(nil, newStringP("i-aint-the-one"), nil, nil, nil, false),
160 matcher.StringMatcherForTesting(nil, newStringP("192.168.1.1"), nil, nil, nil, false),
161 matcher.StringMatcherForTesting(nil, newStringP("FOO.BAR"), nil, nil, nil, false),
162 },
163 },
164 {
165 desc: "suffix match",
166 sanMatchers: []matcher.StringMatcher{
167 matcher.StringMatcherForTesting(nil, nil, newStringP("i-aint-the-one"), nil, nil, false),
168 matcher.StringMatcherForTesting(nil, nil, newStringP("1::68"), nil, nil, false),
169 matcher.StringMatcherForTesting(nil, nil, newStringP(".COM"), nil, nil, false),
170 },
171 },
172 {
173 desc: "regex match",
174 sanMatchers: []matcher.StringMatcher{
175 matcher.StringMatcherForTesting(nil, nil, nil, nil, regexp.MustCompile(`.*\.examples\.com`), false),
176 matcher.StringMatcherForTesting(nil, nil, nil, nil, regexp.MustCompile(`192\.[0-9]{1,3}\.1\.1`), false),
177 },
178 },
179 {
180 desc: "contains match",
181 sanMatchers: []matcher.StringMatcher{
182 matcher.StringMatcherForTesting(nil, nil, nil, newStringP("i-aint-the-one"), nil, false),
183 matcher.StringMatcherForTesting(nil, nil, nil, newStringP("2001:db8:1:1::68"), nil, false),
184 matcher.StringMatcherForTesting(nil, nil, nil, newStringP("GRPC"), nil, false),
185 },
186 },
187 }
188
189 for _, test := range tests {
190 t.Run(test.desc, func(t *testing.T) {
191 hi := NewHandshakeInfo(nil, nil, test.sanMatchers, false)
192
193 if hi.MatchingSANExists(inputCert) {
194 t.Fatalf("hi.MatchingSANExists(%+v) with SAN matchers +%v succeeded when expected to fail", inputCert, test.sanMatchers)
195 }
196 })
197 }
198 }
199
200 func TestMatchingSANExists_Success(t *testing.T) {
201 url1, err := url.Parse("http://golang.org")
202 if err != nil {
203 t.Fatalf("url.Parse() failed: %v", err)
204 }
205 url2, err := url.Parse("https://github.com/grpc/grpc-go")
206 if err != nil {
207 t.Fatalf("url.Parse() failed: %v", err)
208 }
209 inputCert := &x509.Certificate{
210 DNSNames: []string{"baz.test.com", "*.example.com"},
211 EmailAddresses: []string{"foobar@example.com", "barbaz@test.com"},
212 IPAddresses: []net.IP{net.ParseIP("192.0.0.1"), net.ParseIP("2001:db8::68")},
213 URIs: []*url.URL{url1, url2},
214 }
215
216 tests := []struct {
217 desc string
218 sanMatchers []matcher.StringMatcher
219 }{
220 {
221 desc: "no san matchers",
222 },
223 {
224 desc: "exact match dns wildcard",
225 sanMatchers: []matcher.StringMatcher{
226 matcher.StringMatcherForTesting(nil, newStringP("192.168.1.1"), nil, nil, nil, false),
227 matcher.StringMatcherForTesting(newStringP("https://github.com/grpc/grpc-java"), nil, nil, nil, nil, false),
228 matcher.StringMatcherForTesting(newStringP("abc.example.com"), nil, nil, nil, nil, false),
229 },
230 },
231 {
232 desc: "exact match ignore case",
233 sanMatchers: []matcher.StringMatcher{
234 matcher.StringMatcherForTesting(newStringP("FOOBAR@EXAMPLE.COM"), nil, nil, nil, nil, true),
235 },
236 },
237 {
238 desc: "prefix match",
239 sanMatchers: []matcher.StringMatcher{
240 matcher.StringMatcherForTesting(nil, nil, newStringP(".co.in"), nil, nil, false),
241 matcher.StringMatcherForTesting(nil, newStringP("192.168.1.1"), nil, nil, nil, false),
242 matcher.StringMatcherForTesting(nil, newStringP("baz.test"), nil, nil, nil, false),
243 },
244 },
245 {
246 desc: "prefix match ignore case",
247 sanMatchers: []matcher.StringMatcher{
248 matcher.StringMatcherForTesting(nil, newStringP("BAZ.test"), nil, nil, nil, true),
249 },
250 },
251 {
252 desc: "suffix match",
253 sanMatchers: []matcher.StringMatcher{
254 matcher.StringMatcherForTesting(nil, nil, nil, nil, regexp.MustCompile(`192\.[0-9]{1,3}\.1\.1`), false),
255 matcher.StringMatcherForTesting(nil, nil, newStringP("192.168.1.1"), nil, nil, false),
256 matcher.StringMatcherForTesting(nil, nil, newStringP("@test.com"), nil, nil, false),
257 },
258 },
259 {
260 desc: "suffix match ignore case",
261 sanMatchers: []matcher.StringMatcher{
262 matcher.StringMatcherForTesting(nil, nil, newStringP("@test.COM"), nil, nil, true),
263 },
264 },
265 {
266 desc: "regex match",
267 sanMatchers: []matcher.StringMatcher{
268 matcher.StringMatcherForTesting(nil, nil, nil, newStringP("https://github.com/grpc/grpc-java"), nil, false),
269 matcher.StringMatcherForTesting(nil, nil, nil, nil, regexp.MustCompile(`192\.[0-9]{1,3}\.1\.1`), false),
270 matcher.StringMatcherForTesting(nil, nil, nil, nil, regexp.MustCompile(`.*\.test\.com`), false),
271 },
272 },
273 {
274 desc: "contains match",
275 sanMatchers: []matcher.StringMatcher{
276 matcher.StringMatcherForTesting(newStringP("https://github.com/grpc/grpc-java"), nil, nil, nil, nil, false),
277 matcher.StringMatcherForTesting(nil, nil, nil, newStringP("2001:68::db8"), nil, false),
278 matcher.StringMatcherForTesting(nil, nil, nil, newStringP("192.0.0"), nil, false),
279 },
280 },
281 {
282 desc: "contains match ignore case",
283 sanMatchers: []matcher.StringMatcher{
284 matcher.StringMatcherForTesting(nil, nil, nil, newStringP("GRPC"), nil, true),
285 },
286 },
287 }
288
289 for _, test := range tests {
290 t.Run(test.desc, func(t *testing.T) {
291 hi := NewHandshakeInfo(nil, nil, test.sanMatchers, false)
292
293 if !hi.MatchingSANExists(inputCert) {
294 t.Fatalf("hi.MatchingSANExists(%+v) with SAN matchers +%v failed when expected to succeed", inputCert, test.sanMatchers)
295 }
296 })
297 }
298 }
299
300 func newStringP(s string) *string {
301 return &s
302 }
303
View as plain text