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