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 implements various credentials supported by gRPC library, 20// which encapsulate all the state needed by a client to authenticate with a 21// server and make various assertions, e.g., about the client's identity, role, 22// or whether it is authorized to make a particular call. 23package credentials // import "google.golang.org/grpc/credentials" 24 25import ( 26 "context" 27 "crypto/tls" 28 "crypto/x509" 29 "errors" 30 "fmt" 31 "io/ioutil" 32 "net" 33 34 "github.com/golang/protobuf/proto" 35 36 "google.golang.org/grpc/credentials/internal" 37 ginternal "google.golang.org/grpc/internal" 38) 39 40// PerRPCCredentials defines the common interface for the credentials which need to 41// attach security information to every RPC (e.g., oauth2). 42type PerRPCCredentials interface { 43 // GetRequestMetadata gets the current request metadata, refreshing 44 // tokens if required. This should be called by the transport layer on 45 // each request, and the data should be populated in headers or other 46 // context. If a status code is returned, it will be used as the status 47 // for the RPC. uri is the URI of the entry point for the request. 48 // When supported by the underlying implementation, ctx can be used for 49 // timeout and cancellation. Additionally, RequestInfo data will be 50 // available via ctx to this call. 51 // TODO(zhaoq): Define the set of the qualified keys instead of leaving 52 // it as an arbitrary string. 53 GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error) 54 // RequireTransportSecurity indicates whether the credentials requires 55 // transport security. 56 RequireTransportSecurity() bool 57} 58 59// ProtocolInfo provides information regarding the gRPC wire protocol version, 60// security protocol, security protocol version in use, server name, etc. 61type ProtocolInfo struct { 62 // ProtocolVersion is the gRPC wire protocol version. 63 ProtocolVersion string 64 // SecurityProtocol is the security protocol in use. 65 SecurityProtocol string 66 // SecurityVersion is the security protocol version. 67 SecurityVersion string 68 // ServerName is the user-configured server name. 69 ServerName string 70} 71 72// AuthInfo defines the common interface for the auth information the users are interested in. 73type AuthInfo interface { 74 AuthType() string 75} 76 77// ErrConnDispatched indicates that rawConn has been dispatched out of gRPC 78// and the caller should not close rawConn. 79var ErrConnDispatched = errors.New("credentials: rawConn is dispatched out of gRPC") 80 81// TransportCredentials defines the common interface for all the live gRPC wire 82// protocols and supported transport security protocols (e.g., TLS, SSL). 83type TransportCredentials interface { 84 // ClientHandshake does the authentication handshake specified by the corresponding 85 // authentication protocol on rawConn for clients. It returns the authenticated 86 // connection and the corresponding auth information about the connection. 87 // Implementations must use the provided context to implement timely cancellation. 88 // gRPC will try to reconnect if the error returned is a temporary error 89 // (io.EOF, context.DeadlineExceeded or err.Temporary() == true). 90 // If the returned error is a wrapper error, implementations should make sure that 91 // the error implements Temporary() to have the correct retry behaviors. 92 // 93 // If the returned net.Conn is closed, it MUST close the net.Conn provided. 94 ClientHandshake(context.Context, string, net.Conn) (net.Conn, AuthInfo, error) 95 // ServerHandshake does the authentication handshake for servers. It returns 96 // the authenticated connection and the corresponding auth information about 97 // the connection. 98 // 99 // If the returned net.Conn is closed, it MUST close the net.Conn provided. 100 ServerHandshake(net.Conn) (net.Conn, AuthInfo, error) 101 // Info provides the ProtocolInfo of this TransportCredentials. 102 Info() ProtocolInfo 103 // Clone makes a copy of this TransportCredentials. 104 Clone() TransportCredentials 105 // OverrideServerName overrides the server name used to verify the hostname on the returned certificates from the server. 106 // gRPC internals also use it to override the virtual hosting name if it is set. 107 // It must be called before dialing. Currently, this is only used by grpclb. 108 OverrideServerName(string) error 109} 110 111// Bundle is a combination of TransportCredentials and PerRPCCredentials. 112// 113// It also contains a mode switching method, so it can be used as a combination 114// of different credential policies. 115// 116// Bundle cannot be used together with individual TransportCredentials. 117// PerRPCCredentials from Bundle will be appended to other PerRPCCredentials. 118// 119// This API is experimental. 120type Bundle interface { 121 TransportCredentials() TransportCredentials 122 PerRPCCredentials() PerRPCCredentials 123 // NewWithMode should make a copy of Bundle, and switch mode. Modifying the 124 // existing Bundle may cause races. 125 // 126 // NewWithMode returns nil if the requested mode is not supported. 127 NewWithMode(mode string) (Bundle, error) 128} 129 130// TLSInfo contains the auth information for a TLS authenticated connection. 131// It implements the AuthInfo interface. 132type TLSInfo struct { 133 State tls.ConnectionState 134} 135 136// AuthType returns the type of TLSInfo as a string. 137func (t TLSInfo) AuthType() string { 138 return "tls" 139} 140 141// GetSecurityValue returns security info requested by channelz. 142func (t TLSInfo) GetSecurityValue() ChannelzSecurityValue { 143 v := &TLSChannelzSecurityValue{ 144 StandardName: cipherSuiteLookup[t.State.CipherSuite], 145 } 146 // Currently there's no way to get LocalCertificate info from tls package. 147 if len(t.State.PeerCertificates) > 0 { 148 v.RemoteCertificate = t.State.PeerCertificates[0].Raw 149 } 150 return v 151} 152 153// tlsCreds is the credentials required for authenticating a connection using TLS. 154type tlsCreds struct { 155 // TLS configuration 156 config *tls.Config 157} 158 159func (c tlsCreds) Info() ProtocolInfo { 160 return ProtocolInfo{ 161 SecurityProtocol: "tls", 162 SecurityVersion: "1.2", 163 ServerName: c.config.ServerName, 164 } 165} 166 167func (c *tlsCreds) ClientHandshake(ctx context.Context, authority string, rawConn net.Conn) (_ net.Conn, _ AuthInfo, err error) { 168 // use local cfg to avoid clobbering ServerName if using multiple endpoints 169 cfg := cloneTLSConfig(c.config) 170 if cfg.ServerName == "" { 171 serverName, _, err := net.SplitHostPort(authority) 172 if err != nil { 173 // If the authority had no host port or if the authority cannot be parsed, use it as-is. 174 serverName = authority 175 } 176 cfg.ServerName = serverName 177 } 178 conn := tls.Client(rawConn, cfg) 179 errChannel := make(chan error, 1) 180 go func() { 181 errChannel <- conn.Handshake() 182 }() 183 select { 184 case err := <-errChannel: 185 if err != nil { 186 return nil, nil, err 187 } 188 case <-ctx.Done(): 189 return nil, nil, ctx.Err() 190 } 191 return internal.WrapSyscallConn(rawConn, conn), TLSInfo{conn.ConnectionState()}, nil 192} 193 194func (c *tlsCreds) ServerHandshake(rawConn net.Conn) (net.Conn, AuthInfo, error) { 195 conn := tls.Server(rawConn, c.config) 196 if err := conn.Handshake(); err != nil { 197 return nil, nil, err 198 } 199 return internal.WrapSyscallConn(rawConn, conn), TLSInfo{conn.ConnectionState()}, nil 200} 201 202func (c *tlsCreds) Clone() TransportCredentials { 203 return NewTLS(c.config) 204} 205 206func (c *tlsCreds) OverrideServerName(serverNameOverride string) error { 207 c.config.ServerName = serverNameOverride 208 return nil 209} 210 211const alpnProtoStrH2 = "h2" 212 213func appendH2ToNextProtos(ps []string) []string { 214 for _, p := range ps { 215 if p == alpnProtoStrH2 { 216 return ps 217 } 218 } 219 ret := make([]string, 0, len(ps)+1) 220 ret = append(ret, ps...) 221 return append(ret, alpnProtoStrH2) 222} 223 224// NewTLS uses c to construct a TransportCredentials based on TLS. 225func NewTLS(c *tls.Config) TransportCredentials { 226 tc := &tlsCreds{cloneTLSConfig(c)} 227 tc.config.NextProtos = appendH2ToNextProtos(tc.config.NextProtos) 228 return tc 229} 230 231// NewClientTLSFromCert constructs TLS credentials from the input certificate for client. 232// serverNameOverride is for testing only. If set to a non empty string, 233// it will override the virtual host name of authority (e.g. :authority header field) in requests. 234func NewClientTLSFromCert(cp *x509.CertPool, serverNameOverride string) TransportCredentials { 235 return NewTLS(&tls.Config{ServerName: serverNameOverride, RootCAs: cp}) 236} 237 238// NewClientTLSFromFile constructs TLS credentials from the input certificate file for client. 239// serverNameOverride is for testing only. If set to a non empty string, 240// it will override the virtual host name of authority (e.g. :authority header field) in requests. 241func NewClientTLSFromFile(certFile, serverNameOverride string) (TransportCredentials, error) { 242 b, err := ioutil.ReadFile(certFile) 243 if err != nil { 244 return nil, err 245 } 246 cp := x509.NewCertPool() 247 if !cp.AppendCertsFromPEM(b) { 248 return nil, fmt.Errorf("credentials: failed to append certificates") 249 } 250 return NewTLS(&tls.Config{ServerName: serverNameOverride, RootCAs: cp}), nil 251} 252 253// NewServerTLSFromCert constructs TLS credentials from the input certificate for server. 254func NewServerTLSFromCert(cert *tls.Certificate) TransportCredentials { 255 return NewTLS(&tls.Config{Certificates: []tls.Certificate{*cert}}) 256} 257 258// NewServerTLSFromFile constructs TLS credentials from the input certificate file and key 259// file for server. 260func NewServerTLSFromFile(certFile, keyFile string) (TransportCredentials, error) { 261 cert, err := tls.LoadX509KeyPair(certFile, keyFile) 262 if err != nil { 263 return nil, err 264 } 265 return NewTLS(&tls.Config{Certificates: []tls.Certificate{cert}}), nil 266} 267 268// ChannelzSecurityInfo defines the interface that security protocols should implement 269// in order to provide security info to channelz. 270type ChannelzSecurityInfo interface { 271 GetSecurityValue() ChannelzSecurityValue 272} 273 274// ChannelzSecurityValue defines the interface that GetSecurityValue() return value 275// should satisfy. This interface should only be satisfied by *TLSChannelzSecurityValue 276// and *OtherChannelzSecurityValue. 277type ChannelzSecurityValue interface { 278 isChannelzSecurityValue() 279} 280 281// TLSChannelzSecurityValue defines the struct that TLS protocol should return 282// from GetSecurityValue(), containing security info like cipher and certificate used. 283type TLSChannelzSecurityValue struct { 284 ChannelzSecurityValue 285 StandardName string 286 LocalCertificate []byte 287 RemoteCertificate []byte 288} 289 290// OtherChannelzSecurityValue defines the struct that non-TLS protocol should return 291// from GetSecurityValue(), which contains protocol specific security info. Note 292// the Value field will be sent to users of channelz requesting channel info, and 293// thus sensitive info should better be avoided. 294type OtherChannelzSecurityValue struct { 295 ChannelzSecurityValue 296 Name string 297 Value proto.Message 298} 299 300var cipherSuiteLookup = map[uint16]string{ 301 tls.TLS_RSA_WITH_RC4_128_SHA: "TLS_RSA_WITH_RC4_128_SHA", 302 tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA: "TLS_RSA_WITH_3DES_EDE_CBC_SHA", 303 tls.TLS_RSA_WITH_AES_128_CBC_SHA: "TLS_RSA_WITH_AES_128_CBC_SHA", 304 tls.TLS_RSA_WITH_AES_256_CBC_SHA: "TLS_RSA_WITH_AES_256_CBC_SHA", 305 tls.TLS_RSA_WITH_AES_128_GCM_SHA256: "TLS_RSA_WITH_AES_128_GCM_SHA256", 306 tls.TLS_RSA_WITH_AES_256_GCM_SHA384: "TLS_RSA_WITH_AES_256_GCM_SHA384", 307 tls.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA: "TLS_ECDHE_ECDSA_WITH_RC4_128_SHA", 308 tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA: "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", 309 tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA: "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", 310 tls.TLS_ECDHE_RSA_WITH_RC4_128_SHA: "TLS_ECDHE_RSA_WITH_RC4_128_SHA", 311 tls.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA: "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA", 312 tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA: "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", 313 tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA: "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", 314 tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256: "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", 315 tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256: "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", 316 tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384: "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", 317 tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384: "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", 318 tls.TLS_FALLBACK_SCSV: "TLS_FALLBACK_SCSV", 319 tls.TLS_RSA_WITH_AES_128_CBC_SHA256: "TLS_RSA_WITH_AES_128_CBC_SHA256", 320 tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256: "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256", 321 tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256: "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", 322 tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305: "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305", 323 tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305: "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305", 324} 325 326// cloneTLSConfig returns a shallow clone of the exported 327// fields of cfg, ignoring the unexported sync.Once, which 328// contains a mutex and must not be copied. 329// 330// If cfg is nil, a new zero tls.Config is returned. 331// 332// TODO: inline this function if possible. 333func cloneTLSConfig(cfg *tls.Config) *tls.Config { 334 if cfg == nil { 335 return &tls.Config{} 336 } 337 338 return cfg.Clone() 339} 340 341// RequestInfo contains request data attached to the context passed to GetRequestMetadata calls. 342// 343// This API is experimental. 344type RequestInfo struct { 345 // The method passed to Invoke or NewStream for this RPC. (For proto methods, this has the format "/some.Service/Method") 346 Method string 347} 348 349// requestInfoKey is a struct to be used as the key when attaching a RequestInfo to a context object. 350type requestInfoKey struct{} 351 352// RequestInfoFromContext extracts the RequestInfo from the context if it exists. 353// 354// This API is experimental. 355func RequestInfoFromContext(ctx context.Context) (ri RequestInfo, ok bool) { 356 ri, ok = ctx.Value(requestInfoKey{}).(RequestInfo) 357 return 358} 359 360func init() { 361 ginternal.NewRequestInfoContext = func(ctx context.Context, ri RequestInfo) context.Context { 362 return context.WithValue(ctx, requestInfoKey{}, ri) 363 } 364} 365