Home | History | Annotate | Download | only in 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 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.
     23 package credentials
     24 
     25 import (
     26 	"crypto/tls"
     27 	"crypto/x509"
     28 	"errors"
     29 	"fmt"
     30 	"io/ioutil"
     31 	"net"
     32 	"strings"
     33 
     34 	"github.com/golang/protobuf/proto"
     35 	"golang.org/x/net/context"
     36 )
     37 
     38 // alpnProtoStr are the specified application level protocols for gRPC.
     39 var alpnProtoStr = []string{"h2"}
     40 
     41 // PerRPCCredentials defines the common interface for the credentials which need to
     42 // attach security information to every RPC (e.g., oauth2).
     43 type PerRPCCredentials interface {
     44 	// GetRequestMetadata gets the current request metadata, refreshing
     45 	// tokens if required. This should be called by the transport layer on
     46 	// each request, and the data should be populated in headers or other
     47 	// context. If a status code is returned, it will be used as the status
     48 	// for the RPC. uri is the URI of the entry point for the request.
     49 	// When supported by the underlying implementation, ctx can be used for
     50 	// timeout and cancellation.
     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.
     61 type 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.
     73 type 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.
     79 var 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).
     83 type 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 // TLSInfo contains the auth information for a TLS authenticated connection.
    112 // It implements the AuthInfo interface.
    113 type TLSInfo struct {
    114 	State tls.ConnectionState
    115 }
    116 
    117 // AuthType returns the type of TLSInfo as a string.
    118 func (t TLSInfo) AuthType() string {
    119 	return "tls"
    120 }
    121 
    122 // GetChannelzSecurityValue returns security info requested by channelz.
    123 func (t TLSInfo) GetChannelzSecurityValue() ChannelzSecurityValue {
    124 	v := &TLSChannelzSecurityValue{
    125 		StandardName: cipherSuiteLookup[t.State.CipherSuite],
    126 	}
    127 	// Currently there's no way to get LocalCertificate info from tls package.
    128 	if len(t.State.PeerCertificates) > 0 {
    129 		v.RemoteCertificate = t.State.PeerCertificates[0].Raw
    130 	}
    131 	return v
    132 }
    133 
    134 // tlsCreds is the credentials required for authenticating a connection using TLS.
    135 type tlsCreds struct {
    136 	// TLS configuration
    137 	config *tls.Config
    138 }
    139 
    140 func (c tlsCreds) Info() ProtocolInfo {
    141 	return ProtocolInfo{
    142 		SecurityProtocol: "tls",
    143 		SecurityVersion:  "1.2",
    144 		ServerName:       c.config.ServerName,
    145 	}
    146 }
    147 
    148 func (c *tlsCreds) ClientHandshake(ctx context.Context, authority string, rawConn net.Conn) (_ net.Conn, _ AuthInfo, err error) {
    149 	// use local cfg to avoid clobbering ServerName if using multiple endpoints
    150 	cfg := cloneTLSConfig(c.config)
    151 	if cfg.ServerName == "" {
    152 		colonPos := strings.LastIndex(authority, ":")
    153 		if colonPos == -1 {
    154 			colonPos = len(authority)
    155 		}
    156 		cfg.ServerName = authority[:colonPos]
    157 	}
    158 	conn := tls.Client(rawConn, cfg)
    159 	errChannel := make(chan error, 1)
    160 	go func() {
    161 		errChannel <- conn.Handshake()
    162 	}()
    163 	select {
    164 	case err := <-errChannel:
    165 		if err != nil {
    166 			return nil, nil, err
    167 		}
    168 	case <-ctx.Done():
    169 		return nil, nil, ctx.Err()
    170 	}
    171 	return tlsConn{Conn: conn, rawConn: rawConn}, TLSInfo{conn.ConnectionState()}, nil
    172 }
    173 
    174 func (c *tlsCreds) ServerHandshake(rawConn net.Conn) (net.Conn, AuthInfo, error) {
    175 	conn := tls.Server(rawConn, c.config)
    176 	if err := conn.Handshake(); err != nil {
    177 		return nil, nil, err
    178 	}
    179 	return tlsConn{Conn: conn, rawConn: rawConn}, TLSInfo{conn.ConnectionState()}, nil
    180 }
    181 
    182 func (c *tlsCreds) Clone() TransportCredentials {
    183 	return NewTLS(c.config)
    184 }
    185 
    186 func (c *tlsCreds) OverrideServerName(serverNameOverride string) error {
    187 	c.config.ServerName = serverNameOverride
    188 	return nil
    189 }
    190 
    191 // NewTLS uses c to construct a TransportCredentials based on TLS.
    192 func NewTLS(c *tls.Config) TransportCredentials {
    193 	tc := &tlsCreds{cloneTLSConfig(c)}
    194 	tc.config.NextProtos = alpnProtoStr
    195 	return tc
    196 }
    197 
    198 // NewClientTLSFromCert constructs TLS credentials from the input certificate for client.
    199 // serverNameOverride is for testing only. If set to a non empty string,
    200 // it will override the virtual host name of authority (e.g. :authority header field) in requests.
    201 func NewClientTLSFromCert(cp *x509.CertPool, serverNameOverride string) TransportCredentials {
    202 	return NewTLS(&tls.Config{ServerName: serverNameOverride, RootCAs: cp})
    203 }
    204 
    205 // NewClientTLSFromFile constructs TLS credentials from the input certificate file for client.
    206 // serverNameOverride is for testing only. If set to a non empty string,
    207 // it will override the virtual host name of authority (e.g. :authority header field) in requests.
    208 func NewClientTLSFromFile(certFile, serverNameOverride string) (TransportCredentials, error) {
    209 	b, err := ioutil.ReadFile(certFile)
    210 	if err != nil {
    211 		return nil, err
    212 	}
    213 	cp := x509.NewCertPool()
    214 	if !cp.AppendCertsFromPEM(b) {
    215 		return nil, fmt.Errorf("credentials: failed to append certificates")
    216 	}
    217 	return NewTLS(&tls.Config{ServerName: serverNameOverride, RootCAs: cp}), nil
    218 }
    219 
    220 // NewServerTLSFromCert constructs TLS credentials from the input certificate for server.
    221 func NewServerTLSFromCert(cert *tls.Certificate) TransportCredentials {
    222 	return NewTLS(&tls.Config{Certificates: []tls.Certificate{*cert}})
    223 }
    224 
    225 // NewServerTLSFromFile constructs TLS credentials from the input certificate file and key
    226 // file for server.
    227 func NewServerTLSFromFile(certFile, keyFile string) (TransportCredentials, error) {
    228 	cert, err := tls.LoadX509KeyPair(certFile, keyFile)
    229 	if err != nil {
    230 		return nil, err
    231 	}
    232 	return NewTLS(&tls.Config{Certificates: []tls.Certificate{cert}}), nil
    233 }
    234 
    235 // ChannelzSecurityInfo defines the interface that security protocols should implement
    236 // in order to provide security info to channelz.
    237 type ChannelzSecurityInfo interface {
    238 	GetSecurityValue() ChannelzSecurityValue
    239 }
    240 
    241 // ChannelzSecurityValue defines the interface that GetSecurityValue() return value
    242 // should satisfy. This interface should only be satisfied by *TLSChannelzSecurityValue
    243 // and *OtherChannelzSecurityValue.
    244 type ChannelzSecurityValue interface {
    245 	isChannelzSecurityValue()
    246 }
    247 
    248 // TLSChannelzSecurityValue defines the struct that TLS protocol should return
    249 // from GetSecurityValue(), containing security info like cipher and certificate used.
    250 type TLSChannelzSecurityValue struct {
    251 	StandardName      string
    252 	LocalCertificate  []byte
    253 	RemoteCertificate []byte
    254 }
    255 
    256 func (*TLSChannelzSecurityValue) isChannelzSecurityValue() {}
    257 
    258 // OtherChannelzSecurityValue defines the struct that non-TLS protocol should return
    259 // from GetSecurityValue(), which contains protocol specific security info. Note
    260 // the Value field will be sent to users of channelz requesting channel info, and
    261 // thus sensitive info should better be avoided.
    262 type OtherChannelzSecurityValue struct {
    263 	Name  string
    264 	Value proto.Message
    265 }
    266 
    267 func (*OtherChannelzSecurityValue) isChannelzSecurityValue() {}
    268