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
19 #include <grpc/support/port_platform.h>
20
21 #include "src/core/tsi/alts/handshaker/alts_handshaker_service_api.h"
22
23 #include <stdio.h>
24 #include <stdlib.h>
25
26 #include "src/core/tsi/alts/handshaker/transport_security_common_api.h"
27
28 /* HandshakerReq */
grpc_gcp_handshaker_req_create(grpc_gcp_handshaker_req_type type)29 grpc_gcp_handshaker_req* grpc_gcp_handshaker_req_create(
30 grpc_gcp_handshaker_req_type type) {
31 grpc_gcp_handshaker_req* req =
32 static_cast<grpc_gcp_handshaker_req*>(gpr_zalloc(sizeof(*req)));
33 switch (type) {
34 case CLIENT_START_REQ:
35 req->has_client_start = true;
36 break;
37 case SERVER_START_REQ:
38 req->has_server_start = true;
39 break;
40 case NEXT_REQ:
41 req->has_next = true;
42 break;
43 }
44 return req;
45 }
46
grpc_gcp_handshaker_req_destroy(grpc_gcp_handshaker_req * req)47 void grpc_gcp_handshaker_req_destroy(grpc_gcp_handshaker_req* req) {
48 if (req == nullptr) {
49 return;
50 }
51 if (req->has_client_start) {
52 /* Destroy client_start request. */
53 destroy_repeated_field_list_identity(
54 static_cast<repeated_field*>(req->client_start.target_identities.arg));
55 destroy_repeated_field_list_string(static_cast<repeated_field*>(
56 req->client_start.application_protocols.arg));
57 destroy_repeated_field_list_string(
58 static_cast<repeated_field*>(req->client_start.record_protocols.arg));
59 if (req->client_start.has_local_identity) {
60 destroy_slice(static_cast<grpc_slice*>(
61 req->client_start.local_identity.hostname.arg));
62 destroy_slice(static_cast<grpc_slice*>(
63 req->client_start.local_identity.service_account.arg));
64 }
65 if (req->client_start.has_local_endpoint) {
66 destroy_slice(static_cast<grpc_slice*>(
67 req->client_start.local_endpoint.ip_address.arg));
68 }
69 if (req->client_start.has_remote_endpoint) {
70 destroy_slice(static_cast<grpc_slice*>(
71 req->client_start.remote_endpoint.ip_address.arg));
72 }
73 destroy_slice(static_cast<grpc_slice*>(req->client_start.target_name.arg));
74 } else if (req->has_server_start) {
75 /* Destroy server_start request. */
76 size_t i = 0;
77 for (i = 0; i < req->server_start.handshake_parameters_count; i++) {
78 destroy_repeated_field_list_identity(
79 static_cast<repeated_field*>(req->server_start.handshake_parameters[i]
80 .value.local_identities.arg));
81 destroy_repeated_field_list_string(
82 static_cast<repeated_field*>(req->server_start.handshake_parameters[i]
83 .value.record_protocols.arg));
84 }
85 destroy_repeated_field_list_string(static_cast<repeated_field*>(
86 req->server_start.application_protocols.arg));
87 if (req->server_start.has_local_endpoint) {
88 destroy_slice(static_cast<grpc_slice*>(
89 req->server_start.local_endpoint.ip_address.arg));
90 }
91 if (req->server_start.has_remote_endpoint) {
92 destroy_slice(static_cast<grpc_slice*>(
93 req->server_start.remote_endpoint.ip_address.arg));
94 }
95 destroy_slice(static_cast<grpc_slice*>(req->server_start.in_bytes.arg));
96 } else {
97 /* Destroy next request. */
98 destroy_slice(static_cast<grpc_slice*>(req->next.in_bytes.arg));
99 }
100 gpr_free(req);
101 }
102
grpc_gcp_handshaker_req_set_handshake_protocol(grpc_gcp_handshaker_req * req,grpc_gcp_handshake_protocol handshake_protocol)103 bool grpc_gcp_handshaker_req_set_handshake_protocol(
104 grpc_gcp_handshaker_req* req,
105 grpc_gcp_handshake_protocol handshake_protocol) {
106 if (req == nullptr || !req->has_client_start) {
107 gpr_log(GPR_ERROR,
108 "Invalid arguments to "
109 "grpc_gcp_handshaker_req_set_handshake_protocol().");
110 return false;
111 }
112 req->client_start.has_handshake_security_protocol = true;
113 req->client_start.handshake_security_protocol = handshake_protocol;
114 return true;
115 }
116
grpc_gcp_handshaker_req_set_target_name(grpc_gcp_handshaker_req * req,const char * target_name)117 bool grpc_gcp_handshaker_req_set_target_name(grpc_gcp_handshaker_req* req,
118 const char* target_name) {
119 if (req == nullptr || target_name == nullptr || !req->has_client_start) {
120 gpr_log(GPR_ERROR,
121 "Invalid arguments to "
122 "grpc_gcp_handshaker_req_set_target_name().");
123 return false;
124 }
125 grpc_slice* slice = create_slice(target_name, strlen(target_name));
126 req->client_start.target_name.arg = slice;
127 req->client_start.target_name.funcs.encode = encode_string_or_bytes_cb;
128 return true;
129 }
130
grpc_gcp_handshaker_req_add_application_protocol(grpc_gcp_handshaker_req * req,const char * application_protocol)131 bool grpc_gcp_handshaker_req_add_application_protocol(
132 grpc_gcp_handshaker_req* req, const char* application_protocol) {
133 if (req == nullptr || application_protocol == nullptr || req->has_next) {
134 gpr_log(GPR_ERROR,
135 "Invalid arguments to "
136 "grpc_gcp_handshaker_req_add_application_protocol().");
137 return false;
138 }
139 grpc_slice* slice =
140 create_slice(application_protocol, strlen(application_protocol));
141 if (req->has_client_start) {
142 add_repeated_field(reinterpret_cast<repeated_field**>(
143 &req->client_start.application_protocols.arg),
144 slice);
145 req->client_start.application_protocols.funcs.encode =
146 encode_repeated_string_cb;
147 } else {
148 add_repeated_field(reinterpret_cast<repeated_field**>(
149 &req->server_start.application_protocols.arg),
150 slice);
151 req->server_start.application_protocols.funcs.encode =
152 encode_repeated_string_cb;
153 }
154 return true;
155 }
156
grpc_gcp_handshaker_req_add_record_protocol(grpc_gcp_handshaker_req * req,const char * record_protocol)157 bool grpc_gcp_handshaker_req_add_record_protocol(grpc_gcp_handshaker_req* req,
158 const char* record_protocol) {
159 if (req == nullptr || record_protocol == nullptr || !req->has_client_start) {
160 gpr_log(GPR_ERROR,
161 "Invalid arguments to "
162 "grpc_gcp_handshaker_req_add_record_protocol().");
163 return false;
164 }
165 grpc_slice* slice = create_slice(record_protocol, strlen(record_protocol));
166 add_repeated_field(reinterpret_cast<repeated_field**>(
167 &req->client_start.record_protocols.arg),
168 slice);
169 req->client_start.record_protocols.funcs.encode = encode_repeated_string_cb;
170 return true;
171 }
172
set_identity_hostname(grpc_gcp_identity * identity,const char * hostname)173 static void set_identity_hostname(grpc_gcp_identity* identity,
174 const char* hostname) {
175 grpc_slice* slice = create_slice(hostname, strlen(hostname));
176 identity->hostname.arg = slice;
177 identity->hostname.funcs.encode = encode_string_or_bytes_cb;
178 }
179
set_identity_service_account(grpc_gcp_identity * identity,const char * service_account)180 static void set_identity_service_account(grpc_gcp_identity* identity,
181 const char* service_account) {
182 grpc_slice* slice = create_slice(service_account, strlen(service_account));
183 identity->service_account.arg = slice;
184 identity->service_account.funcs.encode = encode_string_or_bytes_cb;
185 }
186
grpc_gcp_handshaker_req_add_target_identity_hostname(grpc_gcp_handshaker_req * req,const char * hostname)187 bool grpc_gcp_handshaker_req_add_target_identity_hostname(
188 grpc_gcp_handshaker_req* req, const char* hostname) {
189 if (req == nullptr || hostname == nullptr || !req->has_client_start) {
190 gpr_log(GPR_ERROR,
191 "Invalid nullptr arguments to "
192 "grpc_gcp_handshaker_req_add_target_identity_hostname().");
193 return false;
194 }
195 grpc_gcp_identity* target_identity =
196 static_cast<grpc_gcp_identity*>(gpr_zalloc(sizeof(*target_identity)));
197 set_identity_hostname(target_identity, hostname);
198 req->client_start.target_identities.funcs.encode =
199 encode_repeated_identity_cb;
200 add_repeated_field(reinterpret_cast<repeated_field**>(
201 &req->client_start.target_identities.arg),
202 target_identity);
203 return true;
204 }
205
grpc_gcp_handshaker_req_add_target_identity_service_account(grpc_gcp_handshaker_req * req,const char * service_account)206 bool grpc_gcp_handshaker_req_add_target_identity_service_account(
207 grpc_gcp_handshaker_req* req, const char* service_account) {
208 if (req == nullptr || service_account == nullptr || !req->has_client_start) {
209 gpr_log(GPR_ERROR,
210 "Invalid nullptr arguments to "
211 "grpc_gcp_handshaker_req_add_target_identity_service_account().");
212 return false;
213 }
214 grpc_gcp_identity* target_identity =
215 static_cast<grpc_gcp_identity*>(gpr_zalloc(sizeof(*target_identity)));
216 set_identity_service_account(target_identity, service_account);
217 req->client_start.target_identities.funcs.encode =
218 encode_repeated_identity_cb;
219 add_repeated_field(reinterpret_cast<repeated_field**>(
220 &req->client_start.target_identities.arg),
221 target_identity);
222 return true;
223 }
224
grpc_gcp_handshaker_req_set_local_identity_hostname(grpc_gcp_handshaker_req * req,const char * hostname)225 bool grpc_gcp_handshaker_req_set_local_identity_hostname(
226 grpc_gcp_handshaker_req* req, const char* hostname) {
227 if (req == nullptr || hostname == nullptr || !req->has_client_start) {
228 gpr_log(GPR_ERROR,
229 "Invalid nullptr arguments to "
230 "grpc_gcp_handshaker_req_set_local_identity_hostname().");
231 return false;
232 }
233 req->client_start.has_local_identity = true;
234 set_identity_hostname(&req->client_start.local_identity, hostname);
235 return true;
236 }
237
grpc_gcp_handshaker_req_set_local_identity_service_account(grpc_gcp_handshaker_req * req,const char * service_account)238 bool grpc_gcp_handshaker_req_set_local_identity_service_account(
239 grpc_gcp_handshaker_req* req, const char* service_account) {
240 if (req == nullptr || service_account == nullptr || !req->has_client_start) {
241 gpr_log(GPR_ERROR,
242 "Invalid nullptr arguments to "
243 "grpc_gcp_handshaker_req_set_local_identity_service_account().");
244 return false;
245 }
246 req->client_start.has_local_identity = true;
247 set_identity_service_account(&req->client_start.local_identity,
248 service_account);
249 return true;
250 }
251
set_endpoint(grpc_gcp_endpoint * endpoint,const char * ip_address,size_t port,grpc_gcp_network_protocol protocol)252 static void set_endpoint(grpc_gcp_endpoint* endpoint, const char* ip_address,
253 size_t port, grpc_gcp_network_protocol protocol) {
254 grpc_slice* slice = create_slice(ip_address, strlen(ip_address));
255 endpoint->ip_address.arg = slice;
256 endpoint->ip_address.funcs.encode = encode_string_or_bytes_cb;
257 endpoint->has_port = true;
258 endpoint->port = static_cast<int32_t>(port);
259 endpoint->has_protocol = true;
260 endpoint->protocol = protocol;
261 }
262
grpc_gcp_handshaker_req_set_rpc_versions(grpc_gcp_handshaker_req * req,uint32_t max_major,uint32_t max_minor,uint32_t min_major,uint32_t min_minor)263 bool grpc_gcp_handshaker_req_set_rpc_versions(grpc_gcp_handshaker_req* req,
264 uint32_t max_major,
265 uint32_t max_minor,
266 uint32_t min_major,
267 uint32_t min_minor) {
268 if (req == nullptr || req->has_next) {
269 gpr_log(GPR_ERROR,
270 "Invalid arguments to "
271 "grpc_gcp_handshaker_req_set_rpc_versions().");
272 return false;
273 }
274 if (req->has_client_start) {
275 req->client_start.has_rpc_versions = true;
276 grpc_gcp_rpc_protocol_versions_set_max(&req->client_start.rpc_versions,
277 max_major, max_minor);
278 grpc_gcp_rpc_protocol_versions_set_min(&req->client_start.rpc_versions,
279 min_major, min_minor);
280 } else {
281 req->server_start.has_rpc_versions = true;
282 grpc_gcp_rpc_protocol_versions_set_max(&req->server_start.rpc_versions,
283 max_major, max_minor);
284 grpc_gcp_rpc_protocol_versions_set_min(&req->server_start.rpc_versions,
285 min_major, min_minor);
286 }
287 return true;
288 }
289
grpc_gcp_handshaker_req_set_local_endpoint(grpc_gcp_handshaker_req * req,const char * ip_address,size_t port,grpc_gcp_network_protocol protocol)290 bool grpc_gcp_handshaker_req_set_local_endpoint(
291 grpc_gcp_handshaker_req* req, const char* ip_address, size_t port,
292 grpc_gcp_network_protocol protocol) {
293 if (req == nullptr || ip_address == nullptr || port > 65535 ||
294 req->has_next) {
295 gpr_log(GPR_ERROR,
296 "Invalid arguments to "
297 "grpc_gcp_handshaker_req_set_local_endpoint().");
298 return false;
299 }
300 if (req->has_client_start) {
301 req->client_start.has_local_endpoint = true;
302 set_endpoint(&req->client_start.local_endpoint, ip_address, port, protocol);
303 } else {
304 req->server_start.has_local_endpoint = true;
305 set_endpoint(&req->server_start.local_endpoint, ip_address, port, protocol);
306 }
307 return true;
308 }
309
grpc_gcp_handshaker_req_set_remote_endpoint(grpc_gcp_handshaker_req * req,const char * ip_address,size_t port,grpc_gcp_network_protocol protocol)310 bool grpc_gcp_handshaker_req_set_remote_endpoint(
311 grpc_gcp_handshaker_req* req, const char* ip_address, size_t port,
312 grpc_gcp_network_protocol protocol) {
313 if (req == nullptr || ip_address == nullptr || port > 65535 ||
314 req->has_next) {
315 gpr_log(GPR_ERROR,
316 "Invalid arguments to "
317 "grpc_gcp_handshaker_req_set_remote_endpoint().");
318 return false;
319 }
320 if (req->has_client_start) {
321 req->client_start.has_remote_endpoint = true;
322 set_endpoint(&req->client_start.remote_endpoint, ip_address, port,
323 protocol);
324 } else {
325 req->server_start.has_remote_endpoint = true;
326 set_endpoint(&req->server_start.remote_endpoint, ip_address, port,
327 protocol);
328 }
329 return true;
330 }
331
grpc_gcp_handshaker_req_set_in_bytes(grpc_gcp_handshaker_req * req,const char * in_bytes,size_t size)332 bool grpc_gcp_handshaker_req_set_in_bytes(grpc_gcp_handshaker_req* req,
333 const char* in_bytes, size_t size) {
334 if (req == nullptr || in_bytes == nullptr || req->has_client_start) {
335 gpr_log(GPR_ERROR,
336 "Invalid arguments to "
337 "grpc_gcp_handshaker_req_set_in_bytes().");
338 return false;
339 }
340 grpc_slice* slice = create_slice(in_bytes, size);
341 if (req->has_next) {
342 req->next.in_bytes.arg = slice;
343 req->next.in_bytes.funcs.encode = &encode_string_or_bytes_cb;
344 } else {
345 req->server_start.in_bytes.arg = slice;
346 req->server_start.in_bytes.funcs.encode = &encode_string_or_bytes_cb;
347 }
348 return true;
349 }
350
server_start_find_param(grpc_gcp_handshaker_req * req,int32_t key)351 static grpc_gcp_server_handshake_parameters* server_start_find_param(
352 grpc_gcp_handshaker_req* req, int32_t key) {
353 size_t i = 0;
354 for (i = 0; i < req->server_start.handshake_parameters_count; i++) {
355 if (req->server_start.handshake_parameters[i].key == key) {
356 return &req->server_start.handshake_parameters[i].value;
357 }
358 }
359 req->server_start
360 .handshake_parameters[req->server_start.handshake_parameters_count]
361 .has_key = true;
362 req->server_start
363 .handshake_parameters[req->server_start.handshake_parameters_count]
364 .has_value = true;
365 req->server_start
366 .handshake_parameters[req->server_start.handshake_parameters_count++]
367 .key = key;
368 return &req->server_start
369 .handshake_parameters
370 [req->server_start.handshake_parameters_count - 1]
371 .value;
372 }
373
grpc_gcp_handshaker_req_param_add_record_protocol(grpc_gcp_handshaker_req * req,grpc_gcp_handshake_protocol key,const char * record_protocol)374 bool grpc_gcp_handshaker_req_param_add_record_protocol(
375 grpc_gcp_handshaker_req* req, grpc_gcp_handshake_protocol key,
376 const char* record_protocol) {
377 if (req == nullptr || record_protocol == nullptr || !req->has_server_start) {
378 gpr_log(GPR_ERROR,
379 "Invalid arguments to "
380 "grpc_gcp_handshaker_req_param_add_record_protocol().");
381 return false;
382 }
383 grpc_gcp_server_handshake_parameters* param =
384 server_start_find_param(req, key);
385 grpc_slice* slice = create_slice(record_protocol, strlen(record_protocol));
386 add_repeated_field(
387 reinterpret_cast<repeated_field**>(¶m->record_protocols.arg), slice);
388 param->record_protocols.funcs.encode = &encode_repeated_string_cb;
389 return true;
390 }
391
grpc_gcp_handshaker_req_param_add_local_identity_hostname(grpc_gcp_handshaker_req * req,grpc_gcp_handshake_protocol key,const char * hostname)392 bool grpc_gcp_handshaker_req_param_add_local_identity_hostname(
393 grpc_gcp_handshaker_req* req, grpc_gcp_handshake_protocol key,
394 const char* hostname) {
395 if (req == nullptr || hostname == nullptr || !req->has_server_start) {
396 gpr_log(GPR_ERROR,
397 "Invalid arguments to "
398 "grpc_gcp_handshaker_req_param_add_local_identity_hostname().");
399 return false;
400 }
401 grpc_gcp_server_handshake_parameters* param =
402 server_start_find_param(req, key);
403 grpc_gcp_identity* local_identity =
404 static_cast<grpc_gcp_identity*>(gpr_zalloc(sizeof(*local_identity)));
405 set_identity_hostname(local_identity, hostname);
406 add_repeated_field(
407 reinterpret_cast<repeated_field**>(¶m->local_identities.arg),
408 local_identity);
409 param->local_identities.funcs.encode = &encode_repeated_identity_cb;
410 return true;
411 }
412
grpc_gcp_handshaker_req_param_add_local_identity_service_account(grpc_gcp_handshaker_req * req,grpc_gcp_handshake_protocol key,const char * service_account)413 bool grpc_gcp_handshaker_req_param_add_local_identity_service_account(
414 grpc_gcp_handshaker_req* req, grpc_gcp_handshake_protocol key,
415 const char* service_account) {
416 if (req == nullptr || service_account == nullptr || !req->has_server_start) {
417 gpr_log(
418 GPR_ERROR,
419 "Invalid arguments to "
420 "grpc_gcp_handshaker_req_param_add_local_identity_service_account().");
421 return false;
422 }
423 grpc_gcp_server_handshake_parameters* param =
424 server_start_find_param(req, key);
425 grpc_gcp_identity* local_identity =
426 static_cast<grpc_gcp_identity*>(gpr_zalloc(sizeof(*local_identity)));
427 set_identity_service_account(local_identity, service_account);
428 add_repeated_field(
429 reinterpret_cast<repeated_field**>(¶m->local_identities.arg),
430 local_identity);
431 param->local_identities.funcs.encode = &encode_repeated_identity_cb;
432 return true;
433 }
434
grpc_gcp_handshaker_req_encode(grpc_gcp_handshaker_req * req,grpc_slice * slice)435 bool grpc_gcp_handshaker_req_encode(grpc_gcp_handshaker_req* req,
436 grpc_slice* slice) {
437 if (req == nullptr || slice == nullptr) {
438 gpr_log(GPR_ERROR,
439 "Invalid nullptr arguments to grpc_gcp_handshaker_req_encode().");
440 return false;
441 }
442 pb_ostream_t size_stream;
443 memset(&size_stream, 0, sizeof(pb_ostream_t));
444 if (!pb_encode(&size_stream, grpc_gcp_HandshakerReq_fields, req)) {
445 gpr_log(GPR_ERROR, "nanopb error: %s", PB_GET_ERROR(&size_stream));
446 return false;
447 }
448 size_t encoded_length = size_stream.bytes_written;
449 *slice = grpc_slice_malloc(encoded_length);
450 pb_ostream_t output_stream =
451 pb_ostream_from_buffer(GRPC_SLICE_START_PTR(*slice), encoded_length);
452 if (!pb_encode(&output_stream, grpc_gcp_HandshakerReq_fields, req) != 0) {
453 gpr_log(GPR_ERROR, "nanopb error: %s", PB_GET_ERROR(&output_stream));
454 return false;
455 }
456 return true;
457 }
458
459 /* HandshakerResp. */
grpc_gcp_handshaker_resp_create(void)460 grpc_gcp_handshaker_resp* grpc_gcp_handshaker_resp_create(void) {
461 grpc_gcp_handshaker_resp* resp =
462 static_cast<grpc_gcp_handshaker_resp*>(gpr_zalloc(sizeof(*resp)));
463 return resp;
464 }
465
grpc_gcp_handshaker_resp_destroy(grpc_gcp_handshaker_resp * resp)466 void grpc_gcp_handshaker_resp_destroy(grpc_gcp_handshaker_resp* resp) {
467 if (resp != nullptr) {
468 destroy_slice(static_cast<grpc_slice*>(resp->out_frames.arg));
469 if (resp->has_status) {
470 destroy_slice(static_cast<grpc_slice*>(resp->status.details.arg));
471 }
472 if (resp->has_result) {
473 destroy_slice(
474 static_cast<grpc_slice*>(resp->result.application_protocol.arg));
475 destroy_slice(static_cast<grpc_slice*>(resp->result.record_protocol.arg));
476 destroy_slice(static_cast<grpc_slice*>(resp->result.key_data.arg));
477 if (resp->result.has_local_identity) {
478 destroy_slice(
479 static_cast<grpc_slice*>(resp->result.local_identity.hostname.arg));
480 destroy_slice(static_cast<grpc_slice*>(
481 resp->result.local_identity.service_account.arg));
482 }
483 if (resp->result.has_peer_identity) {
484 destroy_slice(
485 static_cast<grpc_slice*>(resp->result.peer_identity.hostname.arg));
486 destroy_slice(static_cast<grpc_slice*>(
487 resp->result.peer_identity.service_account.arg));
488 }
489 }
490 gpr_free(resp);
491 }
492 }
493
grpc_gcp_handshaker_resp_decode(grpc_slice encoded_handshaker_resp,grpc_gcp_handshaker_resp * resp)494 bool grpc_gcp_handshaker_resp_decode(grpc_slice encoded_handshaker_resp,
495 grpc_gcp_handshaker_resp* resp) {
496 if (resp == nullptr) {
497 gpr_log(GPR_ERROR,
498 "Invalid nullptr argument to grpc_gcp_handshaker_resp_decode().");
499 return false;
500 }
501 pb_istream_t stream =
502 pb_istream_from_buffer(GRPC_SLICE_START_PTR(encoded_handshaker_resp),
503 GRPC_SLICE_LENGTH(encoded_handshaker_resp));
504 resp->out_frames.funcs.decode = decode_string_or_bytes_cb;
505 resp->status.details.funcs.decode = decode_string_or_bytes_cb;
506 resp->result.application_protocol.funcs.decode = decode_string_or_bytes_cb;
507 resp->result.record_protocol.funcs.decode = decode_string_or_bytes_cb;
508 resp->result.key_data.funcs.decode = decode_string_or_bytes_cb;
509 resp->result.peer_identity.hostname.funcs.decode = decode_string_or_bytes_cb;
510 resp->result.peer_identity.service_account.funcs.decode =
511 decode_string_or_bytes_cb;
512 resp->result.local_identity.hostname.funcs.decode = decode_string_or_bytes_cb;
513 resp->result.local_identity.service_account.funcs.decode =
514 decode_string_or_bytes_cb;
515 if (!pb_decode(&stream, grpc_gcp_HandshakerResp_fields, resp)) {
516 gpr_log(GPR_ERROR, "nanopb error: %s", PB_GET_ERROR(&stream));
517 return false;
518 }
519 return true;
520 }
521