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