gitee.com/ks-custle/core-gm@v0.0.0-20230922171213-b83bdd97b62c/grpc/internal/credentials/xds/handshake_info.go (about)

     1  /*
     2   *
     3   * Copyright 2020 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 contains non-user facing functionality of the xds credentials.
    20  package xds
    21  
    22  import (
    23  	"context"
    24  	"errors"
    25  	"fmt"
    26  	"strings"
    27  	"sync"
    28  
    29  	"gitee.com/ks-custle/core-gm/x509"
    30  
    31  	tls "gitee.com/ks-custle/core-gm/gmtls"
    32  
    33  	"gitee.com/ks-custle/core-gm/grpc/attributes"
    34  	"gitee.com/ks-custle/core-gm/grpc/credentials/tls/certprovider"
    35  	"gitee.com/ks-custle/core-gm/grpc/internal"
    36  	"gitee.com/ks-custle/core-gm/grpc/internal/xds/matcher"
    37  	"gitee.com/ks-custle/core-gm/grpc/resolver"
    38  )
    39  
    40  func init() {
    41  	internal.GetXDSHandshakeInfoForTesting = GetHandshakeInfo
    42  }
    43  
    44  // handshakeAttrKey is the type used as the key to store HandshakeInfo in
    45  // the Attributes field of resolver.Address.
    46  type handshakeAttrKey struct{}
    47  
    48  // Equal reports whether the handshake info structs are identical (have the
    49  // same pointer).  This is sufficient as all subconns from one CDS balancer use
    50  // the same one.
    51  func (hi *HandshakeInfo) Equal(o interface{}) bool {
    52  	oh, ok := o.(*HandshakeInfo)
    53  	return ok && oh == hi
    54  }
    55  
    56  // SetHandshakeInfo returns a copy of addr in which the Attributes field is
    57  // updated with hInfo.
    58  func SetHandshakeInfo(addr resolver.Address, hInfo *HandshakeInfo) resolver.Address {
    59  	addr.Attributes = addr.Attributes.WithValue(handshakeAttrKey{}, hInfo)
    60  	return addr
    61  }
    62  
    63  // GetHandshakeInfo returns a pointer to the HandshakeInfo stored in attr.
    64  func GetHandshakeInfo(attr *attributes.Attributes) *HandshakeInfo {
    65  	v := attr.Value(handshakeAttrKey{})
    66  	hi, _ := v.(*HandshakeInfo)
    67  	return hi
    68  }
    69  
    70  // HandshakeInfo wraps all the security configuration required by client and
    71  // server handshake methods in xds credentials. The xDS implementation will be
    72  // responsible for populating these fields.
    73  //
    74  // Safe for concurrent access.
    75  type HandshakeInfo struct {
    76  	mu                sync.Mutex
    77  	rootProvider      certprovider.Provider
    78  	identityProvider  certprovider.Provider
    79  	sanMatchers       []matcher.StringMatcher // Only on the client side.
    80  	requireClientCert bool                    // Only on server side.
    81  }
    82  
    83  // SetRootCertProvider updates the root certificate provider.
    84  func (hi *HandshakeInfo) SetRootCertProvider(root certprovider.Provider) {
    85  	hi.mu.Lock()
    86  	hi.rootProvider = root
    87  	hi.mu.Unlock()
    88  }
    89  
    90  // SetIdentityCertProvider updates the identity certificate provider.
    91  func (hi *HandshakeInfo) SetIdentityCertProvider(identity certprovider.Provider) {
    92  	hi.mu.Lock()
    93  	hi.identityProvider = identity
    94  	hi.mu.Unlock()
    95  }
    96  
    97  // SetSANMatchers updates the list of SAN matchers.
    98  func (hi *HandshakeInfo) SetSANMatchers(sanMatchers []matcher.StringMatcher) {
    99  	hi.mu.Lock()
   100  	hi.sanMatchers = sanMatchers
   101  	hi.mu.Unlock()
   102  }
   103  
   104  // SetRequireClientCert updates whether a client cert is required during the
   105  // ServerHandshake(). A value of true indicates that we are performing mTLS.
   106  func (hi *HandshakeInfo) SetRequireClientCert(require bool) {
   107  	hi.mu.Lock()
   108  	hi.requireClientCert = require
   109  	hi.mu.Unlock()
   110  }
   111  
   112  // UseFallbackCreds returns true when fallback credentials are to be used based
   113  // on the contents of the HandshakeInfo.
   114  func (hi *HandshakeInfo) UseFallbackCreds() bool {
   115  	if hi == nil {
   116  		return true
   117  	}
   118  
   119  	hi.mu.Lock()
   120  	defer hi.mu.Unlock()
   121  	return hi.identityProvider == nil && hi.rootProvider == nil
   122  }
   123  
   124  // GetSANMatchersForTesting returns the SAN matchers stored in HandshakeInfo.
   125  // To be used only for testing purposes.
   126  func (hi *HandshakeInfo) GetSANMatchersForTesting() []matcher.StringMatcher {
   127  	hi.mu.Lock()
   128  	defer hi.mu.Unlock()
   129  	return append([]matcher.StringMatcher{}, hi.sanMatchers...)
   130  }
   131  
   132  // ClientSideTLSConfig constructs a tls.Config to be used in a client-side
   133  // handshake based on the contents of the HandshakeInfo.
   134  func (hi *HandshakeInfo) ClientSideTLSConfig(ctx context.Context) (*tls.Config, error) {
   135  	hi.mu.Lock()
   136  	// On the client side, rootProvider is mandatory. IdentityProvider is
   137  	// optional based on whether the client is doing TLS or mTLS.
   138  	if hi.rootProvider == nil {
   139  		return nil, errors.New("xds: CertificateProvider to fetch trusted roots is missing, cannot perform TLS handshake. Please check configuration on the management server")
   140  	}
   141  	// Since the call to KeyMaterial() can block, we read the providers under
   142  	// the lock but call the actual function after releasing the lock.
   143  	rootProv, idProv := hi.rootProvider, hi.identityProvider
   144  	hi.mu.Unlock()
   145  
   146  	// InsecureSkipVerify needs to be set to true because we need to perform
   147  	// custom verification to check the SAN on the received certificate.
   148  	// Currently the Go stdlib does complete verification of the cert (which
   149  	// includes hostname verification) or none. We are forced to go with the
   150  	// latter and perform the normal cert validation ourselves.
   151  	cfg := &tls.Config{
   152  		InsecureSkipVerify: true,
   153  		NextProtos:         []string{"h2"},
   154  	}
   155  
   156  	km, err := rootProv.KeyMaterial(ctx)
   157  	if err != nil {
   158  		return nil, fmt.Errorf("xds: fetching trusted roots from CertificateProvider failed: %v", err)
   159  	}
   160  	cfg.RootCAs = km.Roots
   161  
   162  	if idProv != nil {
   163  		km, err := idProv.KeyMaterial(ctx)
   164  		if err != nil {
   165  			return nil, fmt.Errorf("xds: fetching identity certificates from CertificateProvider failed: %v", err)
   166  		}
   167  		cfg.Certificates = km.Certs
   168  	}
   169  	return cfg, nil
   170  }
   171  
   172  // ServerSideTLSConfig constructs a tls.Config to be used in a server-side
   173  // handshake based on the contents of the HandshakeInfo.
   174  func (hi *HandshakeInfo) ServerSideTLSConfig(ctx context.Context) (*tls.Config, error) {
   175  	cfg := &tls.Config{
   176  		ClientAuth: tls.NoClientCert,
   177  		NextProtos: []string{"h2"},
   178  	}
   179  	hi.mu.Lock()
   180  	// On the server side, identityProvider is mandatory. RootProvider is
   181  	// optional based on whether the server is doing TLS or mTLS.
   182  	if hi.identityProvider == nil {
   183  		return nil, errors.New("xds: CertificateProvider to fetch identity certificate is missing, cannot perform TLS handshake. Please check configuration on the management server")
   184  	}
   185  	// Since the call to KeyMaterial() can block, we read the providers under
   186  	// the lock but call the actual function after releasing the lock.
   187  	rootProv, idProv := hi.rootProvider, hi.identityProvider
   188  	if hi.requireClientCert {
   189  		cfg.ClientAuth = tls.RequireAndVerifyClientCert
   190  	}
   191  	hi.mu.Unlock()
   192  
   193  	// identityProvider is mandatory on the server side.
   194  	km, err := idProv.KeyMaterial(ctx)
   195  	if err != nil {
   196  		return nil, fmt.Errorf("xds: fetching identity certificates from CertificateProvider failed: %v", err)
   197  	}
   198  	cfg.Certificates = km.Certs
   199  
   200  	if rootProv != nil {
   201  		km, err := rootProv.KeyMaterial(ctx)
   202  		if err != nil {
   203  			return nil, fmt.Errorf("xds: fetching trusted roots from CertificateProvider failed: %v", err)
   204  		}
   205  		cfg.ClientCAs = km.Roots
   206  	}
   207  	return cfg, nil
   208  }
   209  
   210  // MatchingSANExists returns true if the SANs contained in cert match the
   211  // criteria enforced by the list of SAN matchers in HandshakeInfo.
   212  //
   213  // If the list of SAN matchers in the HandshakeInfo is empty, this function
   214  // returns true for all input certificates.
   215  func (hi *HandshakeInfo) MatchingSANExists(cert *x509.Certificate) bool {
   216  	hi.mu.Lock()
   217  	defer hi.mu.Unlock()
   218  	if len(hi.sanMatchers) == 0 {
   219  		return true
   220  	}
   221  
   222  	// SANs can be specified in any of these four fields on the parsed cert.
   223  	for _, san := range cert.DNSNames {
   224  		if hi.matchSAN(san, true) {
   225  			return true
   226  		}
   227  	}
   228  	for _, san := range cert.EmailAddresses {
   229  		if hi.matchSAN(san, false) {
   230  			return true
   231  		}
   232  	}
   233  	for _, san := range cert.IPAddresses {
   234  		if hi.matchSAN(san.String(), false) {
   235  			return true
   236  		}
   237  	}
   238  	for _, san := range cert.URIs {
   239  		if hi.matchSAN(san.String(), false) {
   240  			return true
   241  		}
   242  	}
   243  	return false
   244  }
   245  
   246  // Caller must hold mu.
   247  func (hi *HandshakeInfo) matchSAN(san string, isDNS bool) bool {
   248  	for _, sanMatcher := range hi.sanMatchers {
   249  		if em := sanMatcher.ExactMatch(); em != "" && isDNS {
   250  			// This is a special case which is documented in the xDS protos.
   251  			// If the DNS SAN is a wildcard entry, and the match criteria is
   252  			// `exact`, then we need to perform DNS wildcard matching
   253  			// instead of regular string comparison.
   254  			if dnsMatch(em, san) {
   255  				return true
   256  			}
   257  			continue
   258  		}
   259  		if sanMatcher.Match(san) {
   260  			return true
   261  		}
   262  	}
   263  	return false
   264  }
   265  
   266  // dnsMatch implements a DNS wildcard matching algorithm based on RFC2828 and
   267  // grpc-java's implementation in `OkHostnameVerifier` class.
   268  //
   269  // NOTE: Here the `host` argument is the one from the set of string matchers in
   270  // the xDS proto and the `san` argument is a DNS SAN from the certificate, and
   271  // this is the one which can potentially contain a wildcard pattern.
   272  func dnsMatch(host, san string) bool {
   273  	// Add trailing "." and turn them into absolute domain names.
   274  	if !strings.HasSuffix(host, ".") {
   275  		host += "."
   276  	}
   277  	if !strings.HasSuffix(san, ".") {
   278  		san += "."
   279  	}
   280  	// Domain names are case-insensitive.
   281  	host = strings.ToLower(host)
   282  	san = strings.ToLower(san)
   283  
   284  	// If san does not contain a wildcard, do exact match.
   285  	if !strings.Contains(san, "*") {
   286  		return host == san
   287  	}
   288  
   289  	// Wildcard dns matching rules
   290  	// - '*' is only permitted in the left-most label and must be the only
   291  	//   character in that label. For example, *.example.com is permitted, while
   292  	//   *a.example.com, a*.example.com, a*b.example.com, a.*.example.com are
   293  	//   not permitted.
   294  	// - '*' matches a single domain name component. For example, *.example.com
   295  	//   matches test.example.com but does not match sub.test.example.com.
   296  	// - Wildcard patterns for single-label domain names are not permitted.
   297  	if san == "*." || !strings.HasPrefix(san, "*.") || strings.Contains(san[1:], "*") {
   298  		return false
   299  	}
   300  	// Optimization: at this point, we know that the san contains a '*' and
   301  	// is the first domain component of san. So, the host name must be at
   302  	// least as long as the san to be able to match.
   303  	if len(host) < len(san) {
   304  		return false
   305  	}
   306  	// Hostname must end with the non-wildcard portion of san.
   307  	if !strings.HasSuffix(host, san[1:]) {
   308  		return false
   309  	}
   310  	// At this point we know that the hostName and san share the same suffix
   311  	// (the non-wildcard portion of san). Now, we just need to make sure
   312  	// that the '*' does not match across domain components.
   313  	hostPrefix := strings.TrimSuffix(host, san[1:])
   314  	return !strings.Contains(hostPrefix, ".")
   315  }
   316  
   317  // NewHandshakeInfo returns a new instance of HandshakeInfo with the given root
   318  // and identity certificate providers.
   319  func NewHandshakeInfo(root, identity certprovider.Provider) *HandshakeInfo {
   320  	return &HandshakeInfo{rootProvider: root, identityProvider: identity}
   321  }