3 * Copyright 2015 gRPC authors.
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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include <grpc/support/port_platform.h>
21 #include "src/core/tsi/transport_security.h"
23 #include <grpc/support/alloc.h>
24 #include <grpc/support/string_util.h>
29 /* --- Tracing. --- */
31 grpc_core::TraceFlag tsi_tracing_enabled(false, "tsi");
33 /* --- tsi_result common implementation. --- */
35 const char* tsi_result_to_string(tsi_result result) {
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";
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";
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";
83 /* --- tsi_frame_protector common implementation. ---
85 Calls specific implementation after state/input validation. */
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;
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);
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;
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,
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;
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);
135 void tsi_frame_protector_destroy(tsi_frame_protector* self) {
136 if (self == nullptr) return;
137 self->vtable->destroy(self);
140 /* --- tsi_handshaker common implementation. ---
142 Calls specific implementation after state/input validation. */
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;
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);
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;
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);
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);
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;
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;
190 if (self->vtable->extract_peer == nullptr) return TSI_UNIMPLEMENTED;
191 return self->vtable->extract_peer(self, peer);
194 tsi_result tsi_handshaker_create_frame_protector(
195 tsi_handshaker* self, size_t* max_protected_frame_size,
196 tsi_frame_protector** protector) {
198 if (self == nullptr || self->vtable == nullptr || protector == nullptr) {
199 return TSI_INVALID_ARGUMENT;
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,
207 if (result == TSI_OK) {
208 self->frame_protector_created = true;
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);
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);
232 self->handshake_shutdown = true;
235 void tsi_handshaker_destroy(tsi_handshaker* self) {
236 if (self == nullptr) return;
237 self->vtable->destroy(self);
240 /* --- tsi_handshaker_result implementation. --- */
242 tsi_result tsi_handshaker_result_extract_peer(const tsi_handshaker_result* self,
244 if (self == nullptr || self->vtable == nullptr || peer == nullptr) {
245 return TSI_INVALID_ARGUMENT;
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);
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;
258 if (self->vtable->create_frame_protector == nullptr) return TSI_UNIMPLEMENTED;
259 return self->vtable->create_frame_protector(self, max_protected_frame_size,
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;
270 if (self->vtable->get_unused_bytes == nullptr) return TSI_UNIMPLEMENTED;
271 return self->vtable->get_unused_bytes(self, bytes, bytes_size);
274 void tsi_handshaker_result_destroy(tsi_handshaker_result* self) {
275 if (self == nullptr) return;
276 self->vtable->destroy(self);
279 /* --- tsi_peer implementation. --- */
281 tsi_peer_property tsi_init_peer_property(void) {
282 tsi_peer_property property;
283 memset(&property, 0, sizeof(tsi_peer_property));
287 static void tsi_peer_destroy_list_property(tsi_peer_property* children,
288 size_t child_count) {
290 for (i = 0; i < child_count; i++) {
291 tsi_peer_property_destruct(&children[i]);
296 void tsi_peer_property_destruct(tsi_peer_property* property) {
297 if (property->name != nullptr) {
298 gpr_free(property->name);
300 if (property->value.data != nullptr) {
301 gpr_free(property->value.data);
303 *property = tsi_init_peer_property(); /* Reset everything to 0. */
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;
312 self->property_count = 0;
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;
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),
332 tsi_result tsi_construct_string_peer_property(const char* name,
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);
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;
355 const tsi_peer_property* tsi_peer_get_property_by_name(const tsi_peer* peer,
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) {
364 if (name != nullptr && property->name != nullptr &&
365 strcmp(property->name, name) == 0) {