...

Source file src/google.golang.org/grpc/credentials/tls.go

Documentation: google.golang.org/grpc/credentials

     1  /*
     2   *
     3   * Copyright 2014 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 credentials
    20  
    21  import (
    22  	"context"
    23  	"crypto/tls"
    24  	"crypto/x509"
    25  	"fmt"
    26  	"net"
    27  	"net/url"
    28  	"os"
    29  
    30  	credinternal "google.golang.org/grpc/internal/credentials"
    31  )
    32  
    33  // TLSInfo contains the auth information for a TLS authenticated connection.
    34  // It implements the AuthInfo interface.
    35  type TLSInfo struct {
    36  	State tls.ConnectionState
    37  	CommonAuthInfo
    38  	// This API is experimental.
    39  	SPIFFEID *url.URL
    40  }
    41  
    42  // AuthType returns the type of TLSInfo as a string.
    43  func (t TLSInfo) AuthType() string {
    44  	return "tls"
    45  }
    46  
    47  // cipherSuiteLookup returns the string version of a TLS cipher suite ID.
    48  func cipherSuiteLookup(cipherSuiteID uint16) string {
    49  	for _, s := range tls.CipherSuites() {
    50  		if s.ID == cipherSuiteID {
    51  			return s.Name
    52  		}
    53  	}
    54  	for _, s := range tls.InsecureCipherSuites() {
    55  		if s.ID == cipherSuiteID {
    56  			return s.Name
    57  		}
    58  	}
    59  	return fmt.Sprintf("unknown ID: %v", cipherSuiteID)
    60  }
    61  
    62  // GetSecurityValue returns security info requested by channelz.
    63  func (t TLSInfo) GetSecurityValue() ChannelzSecurityValue {
    64  	v := &TLSChannelzSecurityValue{
    65  		StandardName: cipherSuiteLookup(t.State.CipherSuite),
    66  	}
    67  	// Currently there's no way to get LocalCertificate info from tls package.
    68  	if len(t.State.PeerCertificates) > 0 {
    69  		v.RemoteCertificate = t.State.PeerCertificates[0].Raw
    70  	}
    71  	return v
    72  }
    73  
    74  // tlsCreds is the credentials required for authenticating a connection using TLS.
    75  type tlsCreds struct {
    76  	// TLS configuration
    77  	config *tls.Config
    78  }
    79  
    80  func (c tlsCreds) Info() ProtocolInfo {
    81  	return ProtocolInfo{
    82  		SecurityProtocol: "tls",
    83  		SecurityVersion:  "1.2",
    84  		ServerName:       c.config.ServerName,
    85  	}
    86  }
    87  
    88  func (c *tlsCreds) ClientHandshake(ctx context.Context, authority string, rawConn net.Conn) (_ net.Conn, _ AuthInfo, err error) {
    89  	// use local cfg to avoid clobbering ServerName if using multiple endpoints
    90  	cfg := credinternal.CloneTLSConfig(c.config)
    91  	if cfg.ServerName == "" {
    92  		serverName, _, err := net.SplitHostPort(authority)
    93  		if err != nil {
    94  			// If the authority had no host port or if the authority cannot be parsed, use it as-is.
    95  			serverName = authority
    96  		}
    97  		cfg.ServerName = serverName
    98  	}
    99  	conn := tls.Client(rawConn, cfg)
   100  	errChannel := make(chan error, 1)
   101  	go func() {
   102  		errChannel <- conn.Handshake()
   103  		close(errChannel)
   104  	}()
   105  	select {
   106  	case err := <-errChannel:
   107  		if err != nil {
   108  			conn.Close()
   109  			return nil, nil, err
   110  		}
   111  	case <-ctx.Done():
   112  		conn.Close()
   113  		return nil, nil, ctx.Err()
   114  	}
   115  	tlsInfo := TLSInfo{
   116  		State: conn.ConnectionState(),
   117  		CommonAuthInfo: CommonAuthInfo{
   118  			SecurityLevel: PrivacyAndIntegrity,
   119  		},
   120  	}
   121  	id := credinternal.SPIFFEIDFromState(conn.ConnectionState())
   122  	if id != nil {
   123  		tlsInfo.SPIFFEID = id
   124  	}
   125  	return credinternal.WrapSyscallConn(rawConn, conn), tlsInfo, nil
   126  }
   127  
   128  func (c *tlsCreds) ServerHandshake(rawConn net.Conn) (net.Conn, AuthInfo, error) {
   129  	conn := tls.Server(rawConn, c.config)
   130  	if err := conn.Handshake(); err != nil {
   131  		conn.Close()
   132  		return nil, nil, err
   133  	}
   134  	tlsInfo := TLSInfo{
   135  		State: conn.ConnectionState(),
   136  		CommonAuthInfo: CommonAuthInfo{
   137  			SecurityLevel: PrivacyAndIntegrity,
   138  		},
   139  	}
   140  	id := credinternal.SPIFFEIDFromState(conn.ConnectionState())
   141  	if id != nil {
   142  		tlsInfo.SPIFFEID = id
   143  	}
   144  	return credinternal.WrapSyscallConn(rawConn, conn), tlsInfo, nil
   145  }
   146  
   147  func (c *tlsCreds) Clone() TransportCredentials {
   148  	return NewTLS(c.config)
   149  }
   150  
   151  func (c *tlsCreds) OverrideServerName(serverNameOverride string) error {
   152  	c.config.ServerName = serverNameOverride
   153  	return nil
   154  }
   155  
   156  // The following cipher suites are forbidden for use with HTTP/2 by
   157  // https://datatracker.ietf.org/doc/html/rfc7540#appendix-A
   158  var tls12ForbiddenCipherSuites = map[uint16]struct{}{
   159  	tls.TLS_RSA_WITH_AES_128_CBC_SHA:         {},
   160  	tls.TLS_RSA_WITH_AES_256_CBC_SHA:         {},
   161  	tls.TLS_RSA_WITH_AES_128_GCM_SHA256:      {},
   162  	tls.TLS_RSA_WITH_AES_256_GCM_SHA384:      {},
   163  	tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA: {},
   164  	tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA: {},
   165  	tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA:   {},
   166  	tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA:   {},
   167  }
   168  
   169  // NewTLS uses c to construct a TransportCredentials based on TLS.
   170  func NewTLS(c *tls.Config) TransportCredentials {
   171  	tc := &tlsCreds{credinternal.CloneTLSConfig(c)}
   172  	tc.config.NextProtos = credinternal.AppendH2ToNextProtos(tc.config.NextProtos)
   173  	// If the user did not configure a MinVersion and did not configure a
   174  	// MaxVersion < 1.2, use MinVersion=1.2, which is required by
   175  	// https://datatracker.ietf.org/doc/html/rfc7540#section-9.2
   176  	if tc.config.MinVersion == 0 && (tc.config.MaxVersion == 0 || tc.config.MaxVersion >= tls.VersionTLS12) {
   177  		tc.config.MinVersion = tls.VersionTLS12
   178  	}
   179  	// If the user did not configure CipherSuites, use all "secure" cipher
   180  	// suites reported by the TLS package, but remove some explicitly forbidden
   181  	// by https://datatracker.ietf.org/doc/html/rfc7540#appendix-A
   182  	if tc.config.CipherSuites == nil {
   183  		for _, cs := range tls.CipherSuites() {
   184  			if _, ok := tls12ForbiddenCipherSuites[cs.ID]; !ok {
   185  				tc.config.CipherSuites = append(tc.config.CipherSuites, cs.ID)
   186  			}
   187  		}
   188  	}
   189  	return tc
   190  }
   191  
   192  // NewClientTLSFromCert constructs TLS credentials from the provided root
   193  // certificate authority certificate(s) to validate server connections. If
   194  // certificates to establish the identity of the client need to be included in
   195  // the credentials (eg: for mTLS), use NewTLS instead, where a complete
   196  // tls.Config can be specified.
   197  // serverNameOverride is for testing only. If set to a non empty string,
   198  // it will override the virtual host name of authority (e.g. :authority header
   199  // field) in requests.
   200  func NewClientTLSFromCert(cp *x509.CertPool, serverNameOverride string) TransportCredentials {
   201  	return NewTLS(&tls.Config{ServerName: serverNameOverride, RootCAs: cp})
   202  }
   203  
   204  // NewClientTLSFromFile constructs TLS credentials from the provided root
   205  // certificate authority certificate file(s) to validate server connections. If
   206  // certificates to establish the identity of the client need to be included in
   207  // the credentials (eg: for mTLS), use NewTLS instead, where a complete
   208  // tls.Config can be specified.
   209  // serverNameOverride is for testing only. If set to a non empty string,
   210  // it will override the virtual host name of authority (e.g. :authority header
   211  // field) in requests.
   212  func NewClientTLSFromFile(certFile, serverNameOverride string) (TransportCredentials, error) {
   213  	b, err := os.ReadFile(certFile)
   214  	if err != nil {
   215  		return nil, err
   216  	}
   217  	cp := x509.NewCertPool()
   218  	if !cp.AppendCertsFromPEM(b) {
   219  		return nil, fmt.Errorf("credentials: failed to append certificates")
   220  	}
   221  	return NewTLS(&tls.Config{ServerName: serverNameOverride, RootCAs: cp}), nil
   222  }
   223  
   224  // NewServerTLSFromCert constructs TLS credentials from the input certificate for server.
   225  func NewServerTLSFromCert(cert *tls.Certificate) TransportCredentials {
   226  	return NewTLS(&tls.Config{Certificates: []tls.Certificate{*cert}})
   227  }
   228  
   229  // NewServerTLSFromFile constructs TLS credentials from the input certificate file and key
   230  // file for server.
   231  func NewServerTLSFromFile(certFile, keyFile string) (TransportCredentials, error) {
   232  	cert, err := tls.LoadX509KeyPair(certFile, keyFile)
   233  	if err != nil {
   234  		return nil, err
   235  	}
   236  	return NewTLS(&tls.Config{Certificates: []tls.Certificate{cert}}), nil
   237  }
   238  
   239  // TLSChannelzSecurityValue defines the struct that TLS protocol should return
   240  // from GetSecurityValue(), containing security info like cipher and certificate used.
   241  //
   242  // # Experimental
   243  //
   244  // Notice: This type is EXPERIMENTAL and may be changed or removed in a
   245  // later release.
   246  type TLSChannelzSecurityValue struct {
   247  	ChannelzSecurityValue
   248  	StandardName      string
   249  	LocalCertificate  []byte
   250  	RemoteCertificate []byte
   251  }
   252  

View as plain text