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 #include "test/core/tsi/alts/fake_handshaker/fake_handshaker_server.h"
19
20 #include <grpc/grpc.h>
21 #include <grpcpp/impl/sync.h>
22 #include <grpcpp/security/server_credentials.h>
23 #include <grpcpp/server.h>
24 #include <grpcpp/server_builder.h>
25 #include <grpcpp/server_context.h>
26 #include <grpcpp/support/async_stream.h>
27
28 #include <memory>
29 #include <sstream>
30 #include <string>
31
32 #include "absl/log/check.h"
33 #include "absl/log/log.h"
34 #include "absl/strings/str_format.h"
35 #include "src/core/util/crash.h"
36 #include "test/core/tsi/alts/fake_handshaker/handshaker.grpc.pb.h"
37 #include "test/core/tsi/alts/fake_handshaker/handshaker.pb.h"
38 #include "test/core/tsi/alts/fake_handshaker/transport_security_common.pb.h"
39
40 // Fake handshake messages.
41 constexpr char kClientInitFrame[] = "ClientInit";
42 constexpr char kServerFrame[] = "ServerInitAndFinished";
43 constexpr char kClientFinishFrame[] = "ClientFinished";
44 // Error messages.
45 constexpr char kInvalidFrameError[] = "Invalid input frame.";
46 constexpr char kWrongStateError[] = "Wrong handshake state.";
47
48 namespace grpc {
49 namespace gcp {
50
51 // FakeHandshakeService implements a fake handshaker service using a fake key
52 // exchange protocol. The fake key exchange protocol is a 3-message protocol:
53 // - Client first sends ClientInit message to Server.
54 // - Server then sends ServerInitAndFinished message back to Client.
55 // - Client finally sends ClientFinished message to Server.
56 // This fake handshaker service is intended for ALTS integration testing without
57 // relying on real ALTS handshaker service inside GCE.
58 // It is thread-safe.
59 class FakeHandshakerService : public HandshakerService::Service {
60 public:
FakeHandshakerService(const std::string & peer_identity)61 explicit FakeHandshakerService(const std::string& peer_identity)
62 : peer_identity_(peer_identity) {}
63
DoHandshake(ServerContext *,ServerReaderWriter<HandshakerResp,HandshakerReq> * stream)64 Status DoHandshake(
65 ServerContext* /*server_context*/,
66 ServerReaderWriter<HandshakerResp, HandshakerReq>* stream) override {
67 Status status;
68 HandshakerContext context;
69 HandshakerReq request;
70 HandshakerResp response;
71 VLOG(2) << "Start a new handshake.";
72 while (stream->Read(&request)) {
73 status = ProcessRequest(&context, request, &response);
74 if (!status.ok()) return WriteErrorResponse(stream, status);
75 stream->Write(response);
76 if (context.state == COMPLETED) return Status::OK;
77 request.Clear();
78 }
79 return Status::OK;
80 }
81
82 private:
83 // HandshakeState is used by fake handshaker server to keep track of client's
84 // handshake status. In the beginning of a handshake, the state is INITIAL.
85 // If start_client or start_server request is called, the state becomes at
86 // least STARTED. When the handshaker server produces the first fame, the
87 // state becomes SENT. After the handshaker server processes the final frame
88 // from the peer, the state becomes COMPLETED.
89 enum HandshakeState { INITIAL, STARTED, SENT, COMPLETED };
90
91 struct HandshakerContext {
92 bool is_client = true;
93 HandshakeState state = INITIAL;
94 };
95
ProcessRequest(HandshakerContext * context,const HandshakerReq & request,HandshakerResp * response)96 Status ProcessRequest(HandshakerContext* context,
97 const HandshakerReq& request,
98 HandshakerResp* response) {
99 CHECK(context != nullptr);
100 CHECK_NE(response, nullptr);
101 response->Clear();
102 if (request.has_client_start()) {
103 VLOG(2) << "Process client start request.";
104 return ProcessClientStart(context, request.client_start(), response);
105 } else if (request.has_server_start()) {
106 VLOG(2) << "Process server start request.";
107 return ProcessServerStart(context, request.server_start(), response);
108 } else if (request.has_next()) {
109 VLOG(2) << "Process next request.";
110 return ProcessNext(context, request.next(), response);
111 }
112 return Status(StatusCode::INVALID_ARGUMENT, "Request is empty.");
113 }
114
ProcessClientStart(HandshakerContext * context,const StartClientHandshakeReq & request,HandshakerResp * response)115 Status ProcessClientStart(HandshakerContext* context,
116 const StartClientHandshakeReq& request,
117 HandshakerResp* response) {
118 CHECK(context != nullptr);
119 CHECK_NE(response, nullptr);
120 // Checks request.
121 if (context->state != INITIAL) {
122 return Status(StatusCode::FAILED_PRECONDITION, kWrongStateError);
123 }
124 if (request.application_protocols_size() == 0) {
125 return Status(StatusCode::INVALID_ARGUMENT,
126 "At least one application protocol needed.");
127 }
128 if (request.record_protocols_size() == 0) {
129 return Status(StatusCode::INVALID_ARGUMENT,
130 "At least one record protocol needed.");
131 }
132 // Sets response.
133 response->set_out_frames(kClientInitFrame);
134 response->set_bytes_consumed(0);
135 response->mutable_status()->set_code(StatusCode::OK);
136 // Updates handshaker context.
137 context->is_client = true;
138 context->state = SENT;
139 return Status::OK;
140 }
141
ProcessServerStart(HandshakerContext * context,const StartServerHandshakeReq & request,HandshakerResp * response)142 Status ProcessServerStart(HandshakerContext* context,
143 const StartServerHandshakeReq& request,
144 HandshakerResp* response) {
145 CHECK(context != nullptr);
146 CHECK_NE(response, nullptr);
147 // Checks request.
148 if (context->state != INITIAL) {
149 return Status(StatusCode::FAILED_PRECONDITION, kWrongStateError);
150 }
151 if (request.application_protocols_size() == 0) {
152 return Status(StatusCode::INVALID_ARGUMENT,
153 "At least one application protocol needed.");
154 }
155 if (request.handshake_parameters().empty()) {
156 return Status(StatusCode::INVALID_ARGUMENT,
157 "At least one set of handshake parameters needed.");
158 }
159 // Sets response.
160 if (request.in_bytes().empty()) {
161 // start_server request does not have in_bytes.
162 response->set_bytes_consumed(0);
163 context->state = STARTED;
164 } else {
165 // start_server request has in_bytes.
166 if (request.in_bytes() == kClientInitFrame) {
167 response->set_out_frames(kServerFrame);
168 response->set_bytes_consumed(strlen(kClientInitFrame));
169 context->state = SENT;
170 } else {
171 return Status(StatusCode::UNKNOWN, kInvalidFrameError);
172 }
173 }
174 response->mutable_status()->set_code(StatusCode::OK);
175 context->is_client = false;
176 return Status::OK;
177 }
178
ProcessNext(HandshakerContext * context,const NextHandshakeMessageReq & request,HandshakerResp * response)179 Status ProcessNext(HandshakerContext* context,
180 const NextHandshakeMessageReq& request,
181 HandshakerResp* response) {
182 CHECK(context != nullptr);
183 CHECK_NE(response, nullptr);
184 if (context->is_client) {
185 // Processes next request on client side.
186 if (context->state != SENT) {
187 return Status(StatusCode::FAILED_PRECONDITION, kWrongStateError);
188 }
189 if (request.in_bytes() != kServerFrame) {
190 return Status(StatusCode::UNKNOWN, kInvalidFrameError);
191 }
192 response->set_out_frames(kClientFinishFrame);
193 response->set_bytes_consumed(strlen(kServerFrame));
194 context->state = COMPLETED;
195 } else {
196 // Processes next request on server side.
197 HandshakeState current_state = context->state;
198 if (current_state == STARTED) {
199 if (request.in_bytes() != kClientInitFrame) {
200 return Status(StatusCode::UNKNOWN, kInvalidFrameError);
201 }
202 response->set_out_frames(kServerFrame);
203 response->set_bytes_consumed(strlen(kClientInitFrame));
204 context->state = SENT;
205 } else if (current_state == SENT) {
206 // Client finish frame may be sent along with the first payload from the
207 // client, handshaker only consumes the client finish frame.
208 if (request.in_bytes().substr(0, strlen(kClientFinishFrame)) !=
209 kClientFinishFrame) {
210 return Status(StatusCode::UNKNOWN, kInvalidFrameError);
211 }
212 response->set_bytes_consumed(strlen(kClientFinishFrame));
213 context->state = COMPLETED;
214 } else {
215 return Status(StatusCode::FAILED_PRECONDITION, kWrongStateError);
216 }
217 }
218 // At this point, processing next request succeeded.
219 response->mutable_status()->set_code(StatusCode::OK);
220 if (context->state == COMPLETED) {
221 *response->mutable_result() = GetHandshakerResult();
222 }
223 return Status::OK;
224 }
225
WriteErrorResponse(ServerReaderWriter<HandshakerResp,HandshakerReq> * stream,const Status & status)226 Status WriteErrorResponse(
227 ServerReaderWriter<HandshakerResp, HandshakerReq>* stream,
228 const Status& status) {
229 CHECK(!status.ok());
230 HandshakerResp response;
231 response.mutable_status()->set_code(status.error_code());
232 response.mutable_status()->set_details(status.error_message());
233 stream->Write(response);
234 return status;
235 }
236
GetHandshakerResult()237 HandshakerResult GetHandshakerResult() {
238 HandshakerResult result;
239 result.set_application_protocol("grpc");
240 result.set_record_protocol("ALTSRP_GCM_AES128_REKEY");
241 result.mutable_peer_identity()->set_service_account(peer_identity_);
242 result.mutable_local_identity()->set_service_account("local_identity");
243 string key(1024, '\0');
244 result.set_key_data(key);
245 result.set_max_frame_size(16384);
246 result.mutable_peer_rpc_versions()->mutable_max_rpc_version()->set_major(2);
247 result.mutable_peer_rpc_versions()->mutable_max_rpc_version()->set_minor(1);
248 result.mutable_peer_rpc_versions()->mutable_min_rpc_version()->set_major(2);
249 result.mutable_peer_rpc_versions()->mutable_min_rpc_version()->set_minor(1);
250 return result;
251 }
252
253 const std::string peer_identity_;
254 };
255
CreateFakeHandshakerService(const std::string & peer_identity)256 std::unique_ptr<grpc::Service> CreateFakeHandshakerService(
257 const std::string& peer_identity) {
258 return std::unique_ptr<grpc::Service>{
259 new grpc::gcp::FakeHandshakerService(peer_identity)};
260 }
261
262 } // namespace gcp
263 } // namespace grpc
264