handshaker.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368
  1. /*
  2. *
  3. * Copyright 2018 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. // Package handshaker provides ALTS handshaking functionality for GCP.
  19. package handshaker
  20. import (
  21. "context"
  22. "errors"
  23. "fmt"
  24. "io"
  25. "net"
  26. "golang.org/x/sync/semaphore"
  27. grpc "google.golang.org/grpc"
  28. "google.golang.org/grpc/codes"
  29. "google.golang.org/grpc/credentials"
  30. core "google.golang.org/grpc/credentials/alts/internal"
  31. "google.golang.org/grpc/credentials/alts/internal/authinfo"
  32. "google.golang.org/grpc/credentials/alts/internal/conn"
  33. altsgrpc "google.golang.org/grpc/credentials/alts/internal/proto/grpc_gcp"
  34. altspb "google.golang.org/grpc/credentials/alts/internal/proto/grpc_gcp"
  35. "google.golang.org/grpc/internal/envconfig"
  36. )
  37. const (
  38. // The maximum byte size of receive frames.
  39. frameLimit = 64 * 1024 // 64 KB
  40. rekeyRecordProtocolName = "ALTSRP_GCM_AES128_REKEY"
  41. )
  42. var (
  43. hsProtocol = altspb.HandshakeProtocol_ALTS
  44. appProtocols = []string{"grpc"}
  45. recordProtocols = []string{rekeyRecordProtocolName}
  46. keyLength = map[string]int{
  47. rekeyRecordProtocolName: 44,
  48. }
  49. altsRecordFuncs = map[string]conn.ALTSRecordFunc{
  50. // ALTS handshaker protocols.
  51. rekeyRecordProtocolName: func(s core.Side, keyData []byte) (conn.ALTSRecordCrypto, error) {
  52. return conn.NewAES128GCMRekey(s, keyData)
  53. },
  54. }
  55. // control number of concurrent created (but not closed) handshakes.
  56. clientHandshakes = semaphore.NewWeighted(int64(envconfig.ALTSMaxConcurrentHandshakes))
  57. serverHandshakes = semaphore.NewWeighted(int64(envconfig.ALTSMaxConcurrentHandshakes))
  58. // errDropped occurs when maxPendingHandshakes is reached.
  59. errDropped = errors.New("maximum number of concurrent ALTS handshakes is reached")
  60. // errOutOfBound occurs when the handshake service returns a consumed
  61. // bytes value larger than the buffer that was passed to it originally.
  62. errOutOfBound = errors.New("handshaker service consumed bytes value is out-of-bound")
  63. )
  64. func init() {
  65. for protocol, f := range altsRecordFuncs {
  66. if err := conn.RegisterProtocol(protocol, f); err != nil {
  67. panic(err)
  68. }
  69. }
  70. }
  71. // ClientHandshakerOptions contains the client handshaker options that can
  72. // provided by the caller.
  73. type ClientHandshakerOptions struct {
  74. // ClientIdentity is the handshaker client local identity.
  75. ClientIdentity *altspb.Identity
  76. // TargetName is the server service account name for secure name
  77. // checking.
  78. TargetName string
  79. // TargetServiceAccounts contains a list of expected target service
  80. // accounts. One of these accounts should match one of the accounts in
  81. // the handshaker results. Otherwise, the handshake fails.
  82. TargetServiceAccounts []string
  83. // RPCVersions specifies the gRPC versions accepted by the client.
  84. RPCVersions *altspb.RpcProtocolVersions
  85. }
  86. // ServerHandshakerOptions contains the server handshaker options that can
  87. // provided by the caller.
  88. type ServerHandshakerOptions struct {
  89. // RPCVersions specifies the gRPC versions accepted by the server.
  90. RPCVersions *altspb.RpcProtocolVersions
  91. }
  92. // DefaultClientHandshakerOptions returns the default client handshaker options.
  93. func DefaultClientHandshakerOptions() *ClientHandshakerOptions {
  94. return &ClientHandshakerOptions{}
  95. }
  96. // DefaultServerHandshakerOptions returns the default client handshaker options.
  97. func DefaultServerHandshakerOptions() *ServerHandshakerOptions {
  98. return &ServerHandshakerOptions{}
  99. }
  100. // altsHandshaker is used to complete an ALTS handshake between client and
  101. // server. This handshaker talks to the ALTS handshaker service in the metadata
  102. // server.
  103. type altsHandshaker struct {
  104. // RPC stream used to access the ALTS Handshaker service.
  105. stream altsgrpc.HandshakerService_DoHandshakeClient
  106. // the connection to the peer.
  107. conn net.Conn
  108. // a virtual connection to the ALTS handshaker service.
  109. clientConn *grpc.ClientConn
  110. // client handshake options.
  111. clientOpts *ClientHandshakerOptions
  112. // server handshake options.
  113. serverOpts *ServerHandshakerOptions
  114. // defines the side doing the handshake, client or server.
  115. side core.Side
  116. }
  117. // NewClientHandshaker creates a core.Handshaker that performs a client-side
  118. // ALTS handshake by acting as a proxy between the peer and the ALTS handshaker
  119. // service in the metadata server.
  120. func NewClientHandshaker(ctx context.Context, conn *grpc.ClientConn, c net.Conn, opts *ClientHandshakerOptions) (core.Handshaker, error) {
  121. return &altsHandshaker{
  122. stream: nil,
  123. conn: c,
  124. clientConn: conn,
  125. clientOpts: opts,
  126. side: core.ClientSide,
  127. }, nil
  128. }
  129. // NewServerHandshaker creates a core.Handshaker that performs a server-side
  130. // ALTS handshake by acting as a proxy between the peer and the ALTS handshaker
  131. // service in the metadata server.
  132. func NewServerHandshaker(ctx context.Context, conn *grpc.ClientConn, c net.Conn, opts *ServerHandshakerOptions) (core.Handshaker, error) {
  133. return &altsHandshaker{
  134. stream: nil,
  135. conn: c,
  136. clientConn: conn,
  137. serverOpts: opts,
  138. side: core.ServerSide,
  139. }, nil
  140. }
  141. // ClientHandshake starts and completes a client ALTS handshake for GCP. Once
  142. // done, ClientHandshake returns a secure connection.
  143. func (h *altsHandshaker) ClientHandshake(ctx context.Context) (net.Conn, credentials.AuthInfo, error) {
  144. if !clientHandshakes.TryAcquire(1) {
  145. return nil, nil, errDropped
  146. }
  147. defer clientHandshakes.Release(1)
  148. if h.side != core.ClientSide {
  149. return nil, nil, errors.New("only handshakers created using NewClientHandshaker can perform a client handshaker")
  150. }
  151. // TODO(matthewstevenson88): Change unit tests to use public APIs so
  152. // that h.stream can unconditionally be set based on h.clientConn.
  153. if h.stream == nil {
  154. stream, err := altsgrpc.NewHandshakerServiceClient(h.clientConn).DoHandshake(ctx)
  155. if err != nil {
  156. return nil, nil, fmt.Errorf("failed to establish stream to ALTS handshaker service: %v", err)
  157. }
  158. h.stream = stream
  159. }
  160. // Create target identities from service account list.
  161. targetIdentities := make([]*altspb.Identity, 0, len(h.clientOpts.TargetServiceAccounts))
  162. for _, account := range h.clientOpts.TargetServiceAccounts {
  163. targetIdentities = append(targetIdentities, &altspb.Identity{
  164. IdentityOneof: &altspb.Identity_ServiceAccount{
  165. ServiceAccount: account,
  166. },
  167. })
  168. }
  169. req := &altspb.HandshakerReq{
  170. ReqOneof: &altspb.HandshakerReq_ClientStart{
  171. ClientStart: &altspb.StartClientHandshakeReq{
  172. HandshakeSecurityProtocol: hsProtocol,
  173. ApplicationProtocols: appProtocols,
  174. RecordProtocols: recordProtocols,
  175. TargetIdentities: targetIdentities,
  176. LocalIdentity: h.clientOpts.ClientIdentity,
  177. TargetName: h.clientOpts.TargetName,
  178. RpcVersions: h.clientOpts.RPCVersions,
  179. },
  180. },
  181. }
  182. conn, result, err := h.doHandshake(req)
  183. if err != nil {
  184. return nil, nil, err
  185. }
  186. authInfo := authinfo.New(result)
  187. return conn, authInfo, nil
  188. }
  189. // ServerHandshake starts and completes a server ALTS handshake for GCP. Once
  190. // done, ServerHandshake returns a secure connection.
  191. func (h *altsHandshaker) ServerHandshake(ctx context.Context) (net.Conn, credentials.AuthInfo, error) {
  192. if !serverHandshakes.TryAcquire(1) {
  193. return nil, nil, errDropped
  194. }
  195. defer serverHandshakes.Release(1)
  196. if h.side != core.ServerSide {
  197. return nil, nil, errors.New("only handshakers created using NewServerHandshaker can perform a server handshaker")
  198. }
  199. // TODO(matthewstevenson88): Change unit tests to use public APIs so
  200. // that h.stream can unconditionally be set based on h.clientConn.
  201. if h.stream == nil {
  202. stream, err := altsgrpc.NewHandshakerServiceClient(h.clientConn).DoHandshake(ctx)
  203. if err != nil {
  204. return nil, nil, fmt.Errorf("failed to establish stream to ALTS handshaker service: %v", err)
  205. }
  206. h.stream = stream
  207. }
  208. p := make([]byte, frameLimit)
  209. n, err := h.conn.Read(p)
  210. if err != nil {
  211. return nil, nil, err
  212. }
  213. // Prepare server parameters.
  214. params := make(map[int32]*altspb.ServerHandshakeParameters)
  215. params[int32(altspb.HandshakeProtocol_ALTS)] = &altspb.ServerHandshakeParameters{
  216. RecordProtocols: recordProtocols,
  217. }
  218. req := &altspb.HandshakerReq{
  219. ReqOneof: &altspb.HandshakerReq_ServerStart{
  220. ServerStart: &altspb.StartServerHandshakeReq{
  221. ApplicationProtocols: appProtocols,
  222. HandshakeParameters: params,
  223. InBytes: p[:n],
  224. RpcVersions: h.serverOpts.RPCVersions,
  225. },
  226. },
  227. }
  228. conn, result, err := h.doHandshake(req)
  229. if err != nil {
  230. return nil, nil, err
  231. }
  232. authInfo := authinfo.New(result)
  233. return conn, authInfo, nil
  234. }
  235. func (h *altsHandshaker) doHandshake(req *altspb.HandshakerReq) (net.Conn, *altspb.HandshakerResult, error) {
  236. resp, err := h.accessHandshakerService(req)
  237. if err != nil {
  238. return nil, nil, err
  239. }
  240. // Check of the returned status is an error.
  241. if resp.GetStatus() != nil {
  242. if got, want := resp.GetStatus().Code, uint32(codes.OK); got != want {
  243. return nil, nil, fmt.Errorf("%v", resp.GetStatus().Details)
  244. }
  245. }
  246. var extra []byte
  247. if req.GetServerStart() != nil {
  248. if resp.GetBytesConsumed() > uint32(len(req.GetServerStart().GetInBytes())) {
  249. return nil, nil, errOutOfBound
  250. }
  251. extra = req.GetServerStart().GetInBytes()[resp.GetBytesConsumed():]
  252. }
  253. result, extra, err := h.processUntilDone(resp, extra)
  254. if err != nil {
  255. return nil, nil, err
  256. }
  257. // The handshaker returns a 128 bytes key. It should be truncated based
  258. // on the returned record protocol.
  259. keyLen, ok := keyLength[result.RecordProtocol]
  260. if !ok {
  261. return nil, nil, fmt.Errorf("unknown resulted record protocol %v", result.RecordProtocol)
  262. }
  263. sc, err := conn.NewConn(h.conn, h.side, result.GetRecordProtocol(), result.KeyData[:keyLen], extra)
  264. if err != nil {
  265. return nil, nil, err
  266. }
  267. return sc, result, nil
  268. }
  269. func (h *altsHandshaker) accessHandshakerService(req *altspb.HandshakerReq) (*altspb.HandshakerResp, error) {
  270. if err := h.stream.Send(req); err != nil {
  271. return nil, err
  272. }
  273. resp, err := h.stream.Recv()
  274. if err != nil {
  275. return nil, err
  276. }
  277. return resp, nil
  278. }
  279. // processUntilDone processes the handshake until the handshaker service returns
  280. // the results. Handshaker service takes care of frame parsing, so we read
  281. // whatever received from the network and send it to the handshaker service.
  282. func (h *altsHandshaker) processUntilDone(resp *altspb.HandshakerResp, extra []byte) (*altspb.HandshakerResult, []byte, error) {
  283. for {
  284. if len(resp.OutFrames) > 0 {
  285. if _, err := h.conn.Write(resp.OutFrames); err != nil {
  286. return nil, nil, err
  287. }
  288. }
  289. if resp.Result != nil {
  290. return resp.Result, extra, nil
  291. }
  292. buf := make([]byte, frameLimit)
  293. n, err := h.conn.Read(buf)
  294. if err != nil && err != io.EOF {
  295. return nil, nil, err
  296. }
  297. // If there is nothing to send to the handshaker service, and
  298. // nothing is received from the peer, then we are stuck.
  299. // This covers the case when the peer is not responding. Note
  300. // that handshaker service connection issues are caught in
  301. // accessHandshakerService before we even get here.
  302. if len(resp.OutFrames) == 0 && n == 0 {
  303. return nil, nil, core.PeerNotRespondingError
  304. }
  305. // Append extra bytes from the previous interaction with the
  306. // handshaker service with the current buffer read from conn.
  307. p := append(extra, buf[:n]...)
  308. // From here on, p and extra point to the same slice.
  309. resp, err = h.accessHandshakerService(&altspb.HandshakerReq{
  310. ReqOneof: &altspb.HandshakerReq_Next{
  311. Next: &altspb.NextHandshakeMessageReq{
  312. InBytes: p,
  313. },
  314. },
  315. })
  316. if err != nil {
  317. return nil, nil, err
  318. }
  319. // Set extra based on handshaker service response.
  320. if resp.GetBytesConsumed() > uint32(len(p)) {
  321. return nil, nil, errOutOfBound
  322. }
  323. extra = p[resp.GetBytesConsumed():]
  324. }
  325. }
  326. // Close terminates the Handshaker. It should be called when the caller obtains
  327. // the secure connection.
  328. func (h *altsHandshaker) Close() {
  329. if h.stream != nil {
  330. h.stream.CloseSend()
  331. }
  332. }
  333. // ResetConcurrentHandshakeSemaphoreForTesting resets the handshake semaphores
  334. // to allow numberOfAllowedHandshakes concurrent handshakes each.
  335. func ResetConcurrentHandshakeSemaphoreForTesting(numberOfAllowedHandshakes int64) {
  336. clientHandshakes = semaphore.NewWeighted(numberOfAllowedHandshakes)
  337. serverHandshakes = semaphore.NewWeighted(numberOfAllowedHandshakes)
  338. }