• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 //
3 // Copyright 2015 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 "src/core/tsi/transport_security.h"
20 
21 #include <grpc/support/alloc.h>
22 #include <grpc/support/port_platform.h>
23 #include <grpc/support/string_util.h>
24 #include <stdlib.h>
25 #include <string.h>
26 
27 // --- tsi_result common implementation. ---
28 
tsi_result_to_string(tsi_result result)29 const char* tsi_result_to_string(tsi_result result) {
30   switch (result) {
31     case TSI_OK:
32       return "TSI_OK";
33     case TSI_UNKNOWN_ERROR:
34       return "TSI_UNKNOWN_ERROR";
35     case TSI_INVALID_ARGUMENT:
36       return "TSI_INVALID_ARGUMENT";
37     case TSI_PERMISSION_DENIED:
38       return "TSI_PERMISSION_DENIED";
39     case TSI_INCOMPLETE_DATA:
40       return "TSI_INCOMPLETE_DATA";
41     case TSI_FAILED_PRECONDITION:
42       return "TSI_FAILED_PRECONDITION";
43     case TSI_UNIMPLEMENTED:
44       return "TSI_UNIMPLEMENTED";
45     case TSI_INTERNAL_ERROR:
46       return "TSI_INTERNAL_ERROR";
47     case TSI_DATA_CORRUPTED:
48       return "TSI_DATA_CORRUPTED";
49     case TSI_NOT_FOUND:
50       return "TSI_NOT_FOUND";
51     case TSI_PROTOCOL_FAILURE:
52       return "TSI_PROTOCOL_FAILURE";
53     case TSI_HANDSHAKE_IN_PROGRESS:
54       return "TSI_HANDSHAKE_IN_PROGRESS";
55     case TSI_OUT_OF_RESOURCES:
56       return "TSI_OUT_OF_RESOURCES";
57     case TSI_ASYNC:
58       return "TSI_ASYNC";
59     default:
60       return "UNKNOWN";
61   }
62 }
63 
tsi_security_level_to_string(tsi_security_level security_level)64 const char* tsi_security_level_to_string(tsi_security_level security_level) {
65   switch (security_level) {
66     case TSI_SECURITY_NONE:
67       return "TSI_SECURITY_NONE";
68     case TSI_INTEGRITY_ONLY:
69       return "TSI_INTEGRITY_ONLY";
70     case TSI_PRIVACY_AND_INTEGRITY:
71       return "TSI_PRIVACY_AND_INTEGRITY";
72     default:
73       return "UNKNOWN";
74   }
75 }
76 
77 // --- tsi_frame_protector common implementation. ---
78 
79 // Calls specific implementation after state/input validation.
80 
tsi_frame_protector_protect(tsi_frame_protector * self,const unsigned char * unprotected_bytes,size_t * unprotected_bytes_size,unsigned char * protected_output_frames,size_t * protected_output_frames_size)81 tsi_result tsi_frame_protector_protect(tsi_frame_protector* self,
82                                        const unsigned char* unprotected_bytes,
83                                        size_t* unprotected_bytes_size,
84                                        unsigned char* protected_output_frames,
85                                        size_t* protected_output_frames_size) {
86   if (self == nullptr || self->vtable == nullptr ||
87       unprotected_bytes == nullptr || unprotected_bytes_size == nullptr ||
88       protected_output_frames == nullptr ||
89       protected_output_frames_size == nullptr) {
90     return TSI_INVALID_ARGUMENT;
91   }
92   if (self->vtable->protect == nullptr) return TSI_UNIMPLEMENTED;
93   return self->vtable->protect(self, unprotected_bytes, unprotected_bytes_size,
94                                protected_output_frames,
95                                protected_output_frames_size);
96 }
97 
tsi_frame_protector_protect_flush(tsi_frame_protector * self,unsigned char * protected_output_frames,size_t * protected_output_frames_size,size_t * still_pending_size)98 tsi_result tsi_frame_protector_protect_flush(
99     tsi_frame_protector* self, unsigned char* protected_output_frames,
100     size_t* protected_output_frames_size, size_t* still_pending_size) {
101   if (self == nullptr || self->vtable == nullptr ||
102       protected_output_frames == nullptr ||
103       protected_output_frames_size == nullptr ||
104       still_pending_size == nullptr) {
105     return TSI_INVALID_ARGUMENT;
106   }
107   if (self->vtable->protect_flush == nullptr) return TSI_UNIMPLEMENTED;
108   return self->vtable->protect_flush(self, protected_output_frames,
109                                      protected_output_frames_size,
110                                      still_pending_size);
111 }
112 
tsi_frame_protector_unprotect(tsi_frame_protector * self,const unsigned char * protected_frames_bytes,size_t * protected_frames_bytes_size,unsigned char * unprotected_bytes,size_t * unprotected_bytes_size)113 tsi_result tsi_frame_protector_unprotect(
114     tsi_frame_protector* self, const unsigned char* protected_frames_bytes,
115     size_t* protected_frames_bytes_size, unsigned char* unprotected_bytes,
116     size_t* unprotected_bytes_size) {
117   if (self == nullptr || self->vtable == nullptr ||
118       protected_frames_bytes == nullptr ||
119       protected_frames_bytes_size == nullptr || unprotected_bytes == nullptr ||
120       unprotected_bytes_size == nullptr) {
121     return TSI_INVALID_ARGUMENT;
122   }
123   if (self->vtable->unprotect == nullptr) return TSI_UNIMPLEMENTED;
124   return self->vtable->unprotect(self, protected_frames_bytes,
125                                  protected_frames_bytes_size, unprotected_bytes,
126                                  unprotected_bytes_size);
127 }
128 
tsi_frame_protector_destroy(tsi_frame_protector * self)129 void tsi_frame_protector_destroy(tsi_frame_protector* self) {
130   if (self == nullptr) return;
131   self->vtable->destroy(self);
132 }
133 
134 // --- tsi_handshaker common implementation. ---
135 
136 // Calls specific implementation after state/input validation.
137 
tsi_handshaker_get_bytes_to_send_to_peer(tsi_handshaker * self,unsigned char * bytes,size_t * bytes_size)138 tsi_result tsi_handshaker_get_bytes_to_send_to_peer(tsi_handshaker* self,
139                                                     unsigned char* bytes,
140                                                     size_t* bytes_size) {
141   if (self == nullptr || self->vtable == nullptr || bytes == nullptr ||
142       bytes_size == nullptr) {
143     return TSI_INVALID_ARGUMENT;
144   }
145   if (self->frame_protector_created) return TSI_FAILED_PRECONDITION;
146   if (self->handshake_shutdown) return TSI_HANDSHAKE_SHUTDOWN;
147   if (self->vtable->get_bytes_to_send_to_peer == nullptr) {
148     return TSI_UNIMPLEMENTED;
149   }
150   return self->vtable->get_bytes_to_send_to_peer(self, bytes, bytes_size);
151 }
152 
tsi_handshaker_process_bytes_from_peer(tsi_handshaker * self,const unsigned char * bytes,size_t * bytes_size)153 tsi_result tsi_handshaker_process_bytes_from_peer(tsi_handshaker* self,
154                                                   const unsigned char* bytes,
155                                                   size_t* bytes_size) {
156   if (self == nullptr || self->vtable == nullptr || bytes == nullptr ||
157       bytes_size == nullptr) {
158     return TSI_INVALID_ARGUMENT;
159   }
160   if (self->frame_protector_created) return TSI_FAILED_PRECONDITION;
161   if (self->handshake_shutdown) return TSI_HANDSHAKE_SHUTDOWN;
162   if (self->vtable->process_bytes_from_peer == nullptr) {
163     return TSI_UNIMPLEMENTED;
164   }
165   return self->vtable->process_bytes_from_peer(self, bytes, bytes_size);
166 }
167 
tsi_handshaker_get_result(tsi_handshaker * self)168 tsi_result tsi_handshaker_get_result(tsi_handshaker* self) {
169   if (self == nullptr || self->vtable == nullptr) return TSI_INVALID_ARGUMENT;
170   if (self->frame_protector_created) return TSI_FAILED_PRECONDITION;
171   if (self->handshake_shutdown) return TSI_HANDSHAKE_SHUTDOWN;
172   if (self->vtable->get_result == nullptr) return TSI_UNIMPLEMENTED;
173   return self->vtable->get_result(self);
174 }
175 
tsi_handshaker_extract_peer(tsi_handshaker * self,tsi_peer * peer)176 tsi_result tsi_handshaker_extract_peer(tsi_handshaker* self, tsi_peer* peer) {
177   if (self == nullptr || self->vtable == nullptr || peer == nullptr) {
178     return TSI_INVALID_ARGUMENT;
179   }
180   memset(peer, 0, sizeof(tsi_peer));
181   if (self->frame_protector_created) return TSI_FAILED_PRECONDITION;
182   if (self->handshake_shutdown) return TSI_HANDSHAKE_SHUTDOWN;
183   if (tsi_handshaker_get_result(self) != TSI_OK) {
184     return TSI_FAILED_PRECONDITION;
185   }
186   if (self->vtable->extract_peer == nullptr) return TSI_UNIMPLEMENTED;
187   return self->vtable->extract_peer(self, peer);
188 }
189 
tsi_handshaker_create_frame_protector(tsi_handshaker * self,size_t * max_output_protected_frame_size,tsi_frame_protector ** protector)190 tsi_result tsi_handshaker_create_frame_protector(
191     tsi_handshaker* self, size_t* max_output_protected_frame_size,
192     tsi_frame_protector** protector) {
193   tsi_result result;
194   if (self == nullptr || self->vtable == nullptr || protector == nullptr) {
195     return TSI_INVALID_ARGUMENT;
196   }
197   if (self->frame_protector_created) return TSI_FAILED_PRECONDITION;
198   if (self->handshake_shutdown) return TSI_HANDSHAKE_SHUTDOWN;
199   if (tsi_handshaker_get_result(self) != TSI_OK) return TSI_FAILED_PRECONDITION;
200   if (self->vtable->create_frame_protector == nullptr) return TSI_UNIMPLEMENTED;
201   result = self->vtable->create_frame_protector(
202       self, max_output_protected_frame_size, protector);
203   if (result == TSI_OK) {
204     self->frame_protector_created = true;
205   }
206   return result;
207 }
208 
tsi_handshaker_next(tsi_handshaker * self,const unsigned char * received_bytes,size_t received_bytes_size,const unsigned char ** bytes_to_send,size_t * bytes_to_send_size,tsi_handshaker_result ** handshaker_result,tsi_handshaker_on_next_done_cb cb,void * user_data,std::string * error)209 tsi_result tsi_handshaker_next(
210     tsi_handshaker* self, const unsigned char* received_bytes,
211     size_t received_bytes_size, const unsigned char** bytes_to_send,
212     size_t* bytes_to_send_size, tsi_handshaker_result** handshaker_result,
213     tsi_handshaker_on_next_done_cb cb, void* user_data, std::string* error) {
214   if (self == nullptr || self->vtable == nullptr) {
215     if (error != nullptr) *error = "invalid argument";
216     return TSI_INVALID_ARGUMENT;
217   }
218   if (self->handshaker_result_created) {
219     if (error != nullptr) *error = "handshaker already returned a result";
220     return TSI_FAILED_PRECONDITION;
221   }
222   if (self->handshake_shutdown) {
223     if (error != nullptr) *error = "handshaker shutdown";
224     return TSI_HANDSHAKE_SHUTDOWN;
225   }
226   if (self->vtable->next == nullptr) {
227     if (error != nullptr) *error = "TSI handshaker does not implement next()";
228     return TSI_UNIMPLEMENTED;
229   }
230   return self->vtable->next(self, received_bytes, received_bytes_size,
231                             bytes_to_send, bytes_to_send_size,
232                             handshaker_result, cb, user_data, error);
233 }
234 
tsi_handshaker_shutdown(tsi_handshaker * self)235 void tsi_handshaker_shutdown(tsi_handshaker* self) {
236   if (self == nullptr || self->vtable == nullptr) return;
237   if (self->vtable->shutdown != nullptr) {
238     self->vtable->shutdown(self);
239   }
240   self->handshake_shutdown = true;
241 }
242 
tsi_handshaker_destroy(tsi_handshaker * self)243 void tsi_handshaker_destroy(tsi_handshaker* self) {
244   if (self == nullptr) return;
245   self->vtable->destroy(self);
246 }
247 
248 // --- tsi_handshaker_result implementation. ---
249 
tsi_handshaker_result_extract_peer(const tsi_handshaker_result * self,tsi_peer * peer)250 tsi_result tsi_handshaker_result_extract_peer(const tsi_handshaker_result* self,
251                                               tsi_peer* peer) {
252   if (self == nullptr || self->vtable == nullptr || peer == nullptr) {
253     return TSI_INVALID_ARGUMENT;
254   }
255   memset(peer, 0, sizeof(tsi_peer));
256   if (self->vtable->extract_peer == nullptr) return TSI_UNIMPLEMENTED;
257   return self->vtable->extract_peer(self, peer);
258 }
259 
tsi_handshaker_result_get_frame_protector_type(const tsi_handshaker_result * self,tsi_frame_protector_type * frame_protector_type)260 tsi_result tsi_handshaker_result_get_frame_protector_type(
261     const tsi_handshaker_result* self,
262     tsi_frame_protector_type* frame_protector_type) {
263   if (self == nullptr || frame_protector_type == nullptr) {
264     return TSI_INVALID_ARGUMENT;
265   }
266   if (self->vtable->get_frame_protector_type == nullptr) {
267     return TSI_UNIMPLEMENTED;
268   }
269   return self->vtable->get_frame_protector_type(self, frame_protector_type);
270 }
271 
tsi_handshaker_result_create_frame_protector(const tsi_handshaker_result * self,size_t * max_output_protected_frame_size,tsi_frame_protector ** protector)272 tsi_result tsi_handshaker_result_create_frame_protector(
273     const tsi_handshaker_result* self, size_t* max_output_protected_frame_size,
274     tsi_frame_protector** protector) {
275   if (self == nullptr || self->vtable == nullptr || protector == nullptr) {
276     return TSI_INVALID_ARGUMENT;
277   }
278   if (self->vtable->create_frame_protector == nullptr) return TSI_UNIMPLEMENTED;
279   return self->vtable->create_frame_protector(
280       self, max_output_protected_frame_size, protector);
281 }
282 
tsi_handshaker_result_get_unused_bytes(const tsi_handshaker_result * self,const unsigned char ** bytes,size_t * bytes_size)283 tsi_result tsi_handshaker_result_get_unused_bytes(
284     const tsi_handshaker_result* self, const unsigned char** bytes,
285     size_t* bytes_size) {
286   if (self == nullptr || self->vtable == nullptr || bytes == nullptr ||
287       bytes_size == nullptr) {
288     return TSI_INVALID_ARGUMENT;
289   }
290   if (self->vtable->get_unused_bytes == nullptr) return TSI_UNIMPLEMENTED;
291   return self->vtable->get_unused_bytes(self, bytes, bytes_size);
292 }
293 
tsi_handshaker_result_destroy(tsi_handshaker_result * self)294 void tsi_handshaker_result_destroy(tsi_handshaker_result* self) {
295   if (self == nullptr) return;
296   self->vtable->destroy(self);
297 }
298 
299 // --- tsi_peer implementation. ---
300 
tsi_init_peer_property(void)301 tsi_peer_property tsi_init_peer_property(void) {
302   tsi_peer_property property;
303   memset(&property, 0, sizeof(tsi_peer_property));
304   return property;
305 }
306 
tsi_peer_destroy_list_property(tsi_peer_property * children,size_t child_count)307 static void tsi_peer_destroy_list_property(tsi_peer_property* children,
308                                            size_t child_count) {
309   size_t i;
310   for (i = 0; i < child_count; i++) {
311     tsi_peer_property_destruct(&children[i]);
312   }
313   gpr_free(children);
314 }
315 
tsi_peer_property_destruct(tsi_peer_property * property)316 void tsi_peer_property_destruct(tsi_peer_property* property) {
317   if (property->name != nullptr) {
318     gpr_free(property->name);
319   }
320   if (property->value.data != nullptr) {
321     gpr_free(property->value.data);
322   }
323   *property = tsi_init_peer_property();  // Reset everything to 0.
324 }
325 
tsi_peer_destruct(tsi_peer * self)326 void tsi_peer_destruct(tsi_peer* self) {
327   if (self == nullptr) return;
328   if (self->properties != nullptr) {
329     tsi_peer_destroy_list_property(self->properties, self->property_count);
330     self->properties = nullptr;
331   }
332   self->property_count = 0;
333 }
334 
tsi_construct_allocated_string_peer_property(const char * name,size_t value_length,tsi_peer_property * property)335 tsi_result tsi_construct_allocated_string_peer_property(
336     const char* name, size_t value_length, tsi_peer_property* property) {
337   *property = tsi_init_peer_property();
338   if (name != nullptr) property->name = gpr_strdup(name);
339   if (value_length > 0) {
340     property->value.data = static_cast<char*>(gpr_zalloc(value_length));
341     property->value.length = value_length;
342   }
343   return TSI_OK;
344 }
345 
tsi_construct_string_peer_property_from_cstring(const char * name,const char * value,tsi_peer_property * property)346 tsi_result tsi_construct_string_peer_property_from_cstring(
347     const char* name, const char* value, tsi_peer_property* property) {
348   return tsi_construct_string_peer_property(name, value, strlen(value),
349                                             property);
350 }
351 
tsi_construct_string_peer_property(const char * name,const char * value,size_t value_length,tsi_peer_property * property)352 tsi_result tsi_construct_string_peer_property(const char* name,
353                                               const char* value,
354                                               size_t value_length,
355                                               tsi_peer_property* property) {
356   tsi_result result = tsi_construct_allocated_string_peer_property(
357       name, value_length, property);
358   if (result != TSI_OK) return result;
359   if (value_length > 0) {
360     memcpy(property->value.data, value, value_length);
361   }
362   return TSI_OK;
363 }
364 
tsi_construct_peer(size_t property_count,tsi_peer * peer)365 tsi_result tsi_construct_peer(size_t property_count, tsi_peer* peer) {
366   memset(peer, 0, sizeof(tsi_peer));
367   if (property_count > 0) {
368     peer->properties = static_cast<tsi_peer_property*>(
369         gpr_zalloc(property_count * sizeof(tsi_peer_property)));
370     peer->property_count = property_count;
371   }
372   return TSI_OK;
373 }
374 
tsi_peer_get_property_by_name(const tsi_peer * peer,const char * name)375 const tsi_peer_property* tsi_peer_get_property_by_name(const tsi_peer* peer,
376                                                        const char* name) {
377   size_t i;
378   if (peer == nullptr) return nullptr;
379   for (i = 0; i < peer->property_count; i++) {
380     const tsi_peer_property* property = &peer->properties[i];
381     if (name == nullptr && property->name == nullptr) {
382       return property;
383     }
384     if (name != nullptr && property->name != nullptr &&
385         strcmp(property->name, name) == 0) {
386       return property;
387     }
388   }
389   return nullptr;
390 }
391