github.com/hxx258456/ccgo@v0.0.5-0.20230213014102-48b35f46f66f/grpc/credentials/tls.go (about)

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