handshaker.go 12 KB

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