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**>(&param->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**>(&param->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**>(&param->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