handshake_info.go 11 KB

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