Imported Upstream version 1.27.0
[platform/upstream/grpc.git] / src / core / tsi / transport_security.cc
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
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 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
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
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
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
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
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   return self->vtable->get_bytes_to_send_to_peer(self, bytes, bytes_size);
156 }
157
158 tsi_result tsi_handshaker_process_bytes_from_peer(tsi_handshaker* self,
159                                                   const unsigned char* bytes,
160                                                   size_t* bytes_size) {
161   if (self == nullptr || self->vtable == nullptr || bytes == nullptr ||
162       bytes_size == nullptr) {
163     return TSI_INVALID_ARGUMENT;
164   }
165   if (self->frame_protector_created) return TSI_FAILED_PRECONDITION;
166   if (self->handshake_shutdown) return TSI_HANDSHAKE_SHUTDOWN;
167   if (self->vtable->process_bytes_from_peer == nullptr)
168     return TSI_UNIMPLEMENTED;
169   return self->vtable->process_bytes_from_peer(self, bytes, bytes_size);
170 }
171
172 tsi_result tsi_handshaker_get_result(tsi_handshaker* self) {
173   if (self == nullptr || self->vtable == nullptr) return TSI_INVALID_ARGUMENT;
174   if (self->frame_protector_created) return TSI_FAILED_PRECONDITION;
175   if (self->handshake_shutdown) return TSI_HANDSHAKE_SHUTDOWN;
176   if (self->vtable->get_result == nullptr) return TSI_UNIMPLEMENTED;
177   return self->vtable->get_result(self);
178 }
179
180 tsi_result tsi_handshaker_extract_peer(tsi_handshaker* self, tsi_peer* peer) {
181   if (self == nullptr || self->vtable == nullptr || peer == nullptr) {
182     return TSI_INVALID_ARGUMENT;
183   }
184   memset(peer, 0, sizeof(tsi_peer));
185   if (self->frame_protector_created) return TSI_FAILED_PRECONDITION;
186   if (self->handshake_shutdown) return TSI_HANDSHAKE_SHUTDOWN;
187   if (tsi_handshaker_get_result(self) != TSI_OK) {
188     return TSI_FAILED_PRECONDITION;
189   }
190   if (self->vtable->extract_peer == nullptr) return TSI_UNIMPLEMENTED;
191   return self->vtable->extract_peer(self, peer);
192 }
193
194 tsi_result tsi_handshaker_create_frame_protector(
195     tsi_handshaker* self, size_t* max_protected_frame_size,
196     tsi_frame_protector** protector) {
197   tsi_result result;
198   if (self == nullptr || self->vtable == nullptr || protector == nullptr) {
199     return TSI_INVALID_ARGUMENT;
200   }
201   if (self->frame_protector_created) return TSI_FAILED_PRECONDITION;
202   if (self->handshake_shutdown) return TSI_HANDSHAKE_SHUTDOWN;
203   if (tsi_handshaker_get_result(self) != TSI_OK) return TSI_FAILED_PRECONDITION;
204   if (self->vtable->create_frame_protector == nullptr) return TSI_UNIMPLEMENTED;
205   result = self->vtable->create_frame_protector(self, max_protected_frame_size,
206                                                 protector);
207   if (result == TSI_OK) {
208     self->frame_protector_created = true;
209   }
210   return result;
211 }
212
213 tsi_result tsi_handshaker_next(
214     tsi_handshaker* self, const unsigned char* received_bytes,
215     size_t received_bytes_size, const unsigned char** bytes_to_send,
216     size_t* bytes_to_send_size, tsi_handshaker_result** handshaker_result,
217     tsi_handshaker_on_next_done_cb cb, void* user_data) {
218   if (self == nullptr || self->vtable == nullptr) return TSI_INVALID_ARGUMENT;
219   if (self->handshaker_result_created) return TSI_FAILED_PRECONDITION;
220   if (self->handshake_shutdown) return TSI_HANDSHAKE_SHUTDOWN;
221   if (self->vtable->next == nullptr) return TSI_UNIMPLEMENTED;
222   return self->vtable->next(self, received_bytes, received_bytes_size,
223                             bytes_to_send, bytes_to_send_size,
224                             handshaker_result, cb, user_data);
225 }
226
227 void tsi_handshaker_shutdown(tsi_handshaker* self) {
228   if (self == nullptr || self->vtable == nullptr) return;
229   if (self->vtable->shutdown != nullptr) {
230     self->vtable->shutdown(self);
231   }
232   self->handshake_shutdown = true;
233 }
234
235 void tsi_handshaker_destroy(tsi_handshaker* self) {
236   if (self == nullptr) return;
237   self->vtable->destroy(self);
238 }
239
240 /* --- tsi_handshaker_result implementation. --- */
241
242 tsi_result tsi_handshaker_result_extract_peer(const tsi_handshaker_result* self,
243                                               tsi_peer* peer) {
244   if (self == nullptr || self->vtable == nullptr || peer == nullptr) {
245     return TSI_INVALID_ARGUMENT;
246   }
247   memset(peer, 0, sizeof(tsi_peer));
248   if (self->vtable->extract_peer == nullptr) return TSI_UNIMPLEMENTED;
249   return self->vtable->extract_peer(self, peer);
250 }
251
252 tsi_result tsi_handshaker_result_create_frame_protector(
253     const tsi_handshaker_result* self, size_t* max_protected_frame_size,
254     tsi_frame_protector** protector) {
255   if (self == nullptr || self->vtable == nullptr || protector == nullptr) {
256     return TSI_INVALID_ARGUMENT;
257   }
258   if (self->vtable->create_frame_protector == nullptr) return TSI_UNIMPLEMENTED;
259   return self->vtable->create_frame_protector(self, max_protected_frame_size,
260                                               protector);
261 }
262
263 tsi_result tsi_handshaker_result_get_unused_bytes(
264     const tsi_handshaker_result* self, const unsigned char** bytes,
265     size_t* bytes_size) {
266   if (self == nullptr || self->vtable == nullptr || bytes == nullptr ||
267       bytes_size == nullptr) {
268     return TSI_INVALID_ARGUMENT;
269   }
270   if (self->vtable->get_unused_bytes == nullptr) return TSI_UNIMPLEMENTED;
271   return self->vtable->get_unused_bytes(self, bytes, bytes_size);
272 }
273
274 void tsi_handshaker_result_destroy(tsi_handshaker_result* self) {
275   if (self == nullptr) return;
276   self->vtable->destroy(self);
277 }
278
279 /* --- tsi_peer implementation. --- */
280
281 tsi_peer_property tsi_init_peer_property(void) {
282   tsi_peer_property property;
283   memset(&property, 0, sizeof(tsi_peer_property));
284   return property;
285 }
286
287 static void tsi_peer_destroy_list_property(tsi_peer_property* children,
288                                            size_t child_count) {
289   size_t i;
290   for (i = 0; i < child_count; i++) {
291     tsi_peer_property_destruct(&children[i]);
292   }
293   gpr_free(children);
294 }
295
296 void tsi_peer_property_destruct(tsi_peer_property* property) {
297   if (property->name != nullptr) {
298     gpr_free(property->name);
299   }
300   if (property->value.data != nullptr) {
301     gpr_free(property->value.data);
302   }
303   *property = tsi_init_peer_property(); /* Reset everything to 0. */
304 }
305
306 void tsi_peer_destruct(tsi_peer* self) {
307   if (self == nullptr) return;
308   if (self->properties != nullptr) {
309     tsi_peer_destroy_list_property(self->properties, self->property_count);
310     self->properties = nullptr;
311   }
312   self->property_count = 0;
313 }
314
315 tsi_result tsi_construct_allocated_string_peer_property(
316     const char* name, size_t value_length, tsi_peer_property* property) {
317   *property = tsi_init_peer_property();
318   if (name != nullptr) property->name = gpr_strdup(name);
319   if (value_length > 0) {
320     property->value.data = static_cast<char*>(gpr_zalloc(value_length));
321     property->value.length = value_length;
322   }
323   return TSI_OK;
324 }
325
326 tsi_result tsi_construct_string_peer_property_from_cstring(
327     const char* name, const char* value, tsi_peer_property* property) {
328   return tsi_construct_string_peer_property(name, value, strlen(value),
329                                             property);
330 }
331
332 tsi_result tsi_construct_string_peer_property(const char* name,
333                                               const char* value,
334                                               size_t value_length,
335                                               tsi_peer_property* property) {
336   tsi_result result = tsi_construct_allocated_string_peer_property(
337       name, value_length, property);
338   if (result != TSI_OK) return result;
339   if (value_length > 0) {
340     memcpy(property->value.data, value, value_length);
341   }
342   return TSI_OK;
343 }
344
345 tsi_result tsi_construct_peer(size_t property_count, tsi_peer* peer) {
346   memset(peer, 0, sizeof(tsi_peer));
347   if (property_count > 0) {
348     peer->properties = static_cast<tsi_peer_property*>(
349         gpr_zalloc(property_count * sizeof(tsi_peer_property)));
350     peer->property_count = property_count;
351   }
352   return TSI_OK;
353 }
354
355 const tsi_peer_property* tsi_peer_get_property_by_name(const tsi_peer* peer,
356                                                        const char* name) {
357   size_t i;
358   if (peer == nullptr) return nullptr;
359   for (i = 0; i < peer->property_count; i++) {
360     const tsi_peer_property* property = &peer->properties[i];
361     if (name == nullptr && property->name == nullptr) {
362       return property;
363     }
364     if (name != nullptr && property->name != nullptr &&
365         strcmp(property->name, name) == 0) {
366       return property;
367     }
368   }
369   return nullptr;
370 }