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