...

Source file src/google.golang.org/grpc/internal/credentials/xds/handshake_info_test.go

Documentation: google.golang.org/grpc/internal/credentials/xds

     1  /*
     2   *
     3   * Copyright 2021 gRPC authors.
     4   *
     5   * Licensed under the Apache License, Version 2.0 (the "License");
     6   * you may not use this file except in compliance with the License.
     7   * You may obtain a copy of the License at
     8   *
     9   *     http://www.apache.org/licenses/LICENSE-2.0
    10   *
    11   * Unless required by applicable law or agreed to in writing, software
    12   * distributed under the License is distributed on an "AS IS" BASIS,
    13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14   * See the License for the specific language governing permissions and
    15   * limitations under the License.
    16   *
    17   */
    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