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 #ifndef GRPC_CORE_TSI_TRANSPORT_SECURITY_INTERFACE_H 20 #define GRPC_CORE_TSI_TRANSPORT_SECURITY_INTERFACE_H 21 22 #include <grpc/support/port_platform.h> 23 24 #include <stdint.h> 25 #include <stdlib.h> 26 27 #include "src/core/lib/debug/trace.h" 28 29 /* --- tsi result --- */ 30 31 typedef enum { 32 TSI_OK = 0, 33 TSI_UNKNOWN_ERROR = 1, 34 TSI_INVALID_ARGUMENT = 2, 35 TSI_PERMISSION_DENIED = 3, 36 TSI_INCOMPLETE_DATA = 4, 37 TSI_FAILED_PRECONDITION = 5, 38 TSI_UNIMPLEMENTED = 6, 39 TSI_INTERNAL_ERROR = 7, 40 TSI_DATA_CORRUPTED = 8, 41 TSI_NOT_FOUND = 9, 42 TSI_PROTOCOL_FAILURE = 10, 43 TSI_HANDSHAKE_IN_PROGRESS = 11, 44 TSI_OUT_OF_RESOURCES = 12, 45 TSI_ASYNC = 13, 46 TSI_HANDSHAKE_SHUTDOWN = 14, 47 } tsi_result; 48 49 typedef enum { 50 // Default option 51 TSI_DONT_REQUEST_CLIENT_CERTIFICATE, 52 TSI_REQUEST_CLIENT_CERTIFICATE_BUT_DONT_VERIFY, 53 TSI_REQUEST_CLIENT_CERTIFICATE_AND_VERIFY, 54 TSI_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_BUT_DONT_VERIFY, 55 TSI_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_AND_VERIFY, 56 } tsi_client_certificate_request_type; 57 58 const char* tsi_result_to_string(tsi_result result); 59 60 /* --- tsi tracing --- */ 61 62 extern grpc_core::TraceFlag tsi_tracing_enabled; 63 64 /* -- tsi_zero_copy_grpc_protector object -- 65 66 This object protects and unprotects grpc slice buffers with zero or minimized 67 memory copy once the handshake is done. Implementations of this object must be 68 thread compatible. This object depends on grpc and the details of this object 69 is defined in transport_security_grpc.h. */ 70 71 typedef struct tsi_zero_copy_grpc_protector tsi_zero_copy_grpc_protector; 72 73 /* --- tsi_frame_protector object --- 74 75 This object protects and unprotects buffers once the handshake is done. 76 Implementations of this object must be thread compatible. */ 77 78 typedef struct tsi_frame_protector tsi_frame_protector; 79 80 /* Outputs protected frames. 81 - unprotected_bytes is an input only parameter and points to the data 82 to be protected. 83 - unprotected_bytes_size is an input/output parameter used by the caller to 84 specify how many bytes are available in unprotected_bytes. The output 85 value is the number of bytes consumed during the call. 86 - protected_output_frames points to a buffer allocated by the caller that 87 will be written. 88 - protected_output_frames_size is an input/output parameter used by the 89 caller to specify how many bytes are available in protected_output_frames. 90 As an output, this value indicates the number of bytes written. 91 - This method returns TSI_OK in case of success or a specific error code in 92 case of failure. Note that even if all the input unprotected bytes are 93 consumed, they may not have been processed into the returned protected 94 output frames. The caller should call the protect_flush method 95 to make sure that there are no more protected bytes buffered in the 96 protector. 97 98 A typical way to call this method would be: 99 100 ------------------------------------------------------------------------ 101 unsigned char protected_buffer[4096]; 102 size_t protected_buffer_size = sizeof(protected_buffer); 103 tsi_result result = TSI_OK; 104 while (message_size > 0) { 105 size_t protected_buffer_size_to_send = protected_buffer_size; 106 size_t processed_message_size = message_size; 107 result = tsi_frame_protector_protect(protector, 108 message_bytes, 109 &processed_message_size, 110 protected_buffer, 111 &protected_buffer_size_to_send); 112 if (result != TSI_OK) break; 113 send_bytes_to_peer(protected_buffer, protected_buffer_size_to_send); 114 message_bytes += processed_message_size; 115 message_size -= processed_message_size; 116 117 // Don't forget to flush. 118 if (message_size == 0) { 119 size_t still_pending_size; 120 do { 121 protected_buffer_size_to_send = protected_buffer_size; 122 result = tsi_frame_protector_protect_flush( 123 protector, protected_buffer, 124 &protected_buffer_size_to_send, &still_pending_size); 125 if (result != TSI_OK) break; 126 send_bytes_to_peer(protected_buffer, protected_buffer_size_to_send); 127 } while (still_pending_size > 0); 128 } 129 } 130 131 if (result != TSI_OK) HandleError(result); 132 ------------------------------------------------------------------------ */ 133 tsi_result tsi_frame_protector_protect(tsi_frame_protector* self, 134 const unsigned char* unprotected_bytes, 135 size_t* unprotected_bytes_size, 136 unsigned char* protected_output_frames, 137 size_t* protected_output_frames_size); 138 139 /* Indicates that we need to flush the bytes buffered in the protector and get 140 the resulting frame. 141 - protected_output_frames points to a buffer allocated by the caller that 142 will be written. 143 - protected_output_frames_size is an input/output parameter used by the 144 caller to specify how many bytes are available in protected_output_frames. 145 - still_pending_bytes is an output parameter indicating the number of bytes 146 that still need to be flushed from the protector.*/ 147 tsi_result tsi_frame_protector_protect_flush( 148 tsi_frame_protector* self, unsigned char* protected_output_frames, 149 size_t* protected_output_frames_size, size_t* still_pending_size); 150 151 /* Outputs unprotected bytes. 152 - protected_frames_bytes is an input only parameter and points to the 153 protected frames to be unprotected. 154 - protected_frames_bytes_size is an input/output only parameter used by the 155 caller to specify how many bytes are available in protected_bytes. The 156 output value is the number of bytes consumed during the call. 157 Implementations will buffer up to a frame of protected data. 158 - unprotected_bytes points to a buffer allocated by the caller that will be 159 written. 160 - unprotected_bytes_size is an input/output parameter used by the caller to 161 specify how many bytes are available in unprotected_bytes. This 162 value is expected to be at most max_protected_frame_size minus overhead 163 which means that max_protected_frame_size is a safe bet. The output value 164 is the number of bytes actually written. 165 If *unprotected_bytes_size is unchanged, there may be more data remaining 166 to unprotect, and the caller should call this function again. 167 168 - This method returns TSI_OK in case of success. Success includes cases where 169 there is not enough data to output a frame in which case 170 unprotected_bytes_size will be set to 0 and cases where the internal buffer 171 needs to be read before new protected data can be processed in which case 172 protected_frames_size will be set to 0. */ 173 tsi_result tsi_frame_protector_unprotect( 174 tsi_frame_protector* self, const unsigned char* protected_frames_bytes, 175 size_t* protected_frames_bytes_size, unsigned char* unprotected_bytes, 176 size_t* unprotected_bytes_size); 177 178 /* Destroys the tsi_frame_protector object. */ 179 void tsi_frame_protector_destroy(tsi_frame_protector* self); 180 181 /* --- tsi_peer objects --- 182 183 tsi_peer objects are a set of properties. The peer owns the properties. */ 184 185 /* This property is of type TSI_PEER_PROPERTY_STRING. */ 186 #define TSI_CERTIFICATE_TYPE_PEER_PROPERTY "certificate_type" 187 188 /* Property values may contain NULL characters just like C++ strings. 189 The length field gives the length of the string. */ 190 typedef struct tsi_peer_property { 191 char* name; 192 struct { 193 char* data; 194 size_t length; 195 } value; 196 } tsi_peer_property; 197 198 typedef struct { 199 tsi_peer_property* properties; 200 size_t property_count; 201 } tsi_peer; 202 203 /* Destructs the tsi_peer object. */ 204 void tsi_peer_destruct(tsi_peer* self); 205 206 /* --- tsi_handshaker_result object --- 207 208 This object contains all necessary handshake results and data such as peer 209 info, negotiated keys, unused handshake bytes, when the handshake completes. 210 Implementations of this object must be thread compatible. */ 211 212 typedef struct tsi_handshaker_result tsi_handshaker_result; 213 214 /* This method extracts tsi peer. It returns TSI_OK assuming there is no fatal 215 error. 216 The caller is responsible for destructing the peer. */ 217 tsi_result tsi_handshaker_result_extract_peer(const tsi_handshaker_result* self, 218 tsi_peer* peer); 219 220 /* This method creates a tsi_frame_protector object. It returns TSI_OK assuming 221 there is no fatal error. 222 The caller is responsible for destroying the protector. */ 223 tsi_result tsi_handshaker_result_create_frame_protector( 224 const tsi_handshaker_result* self, size_t* max_output_protected_frame_size, 225 tsi_frame_protector** protector); 226 227 /* This method returns the unused bytes from the handshake. It returns TSI_OK 228 assuming there is no fatal error. 229 Ownership of the bytes is retained by the handshaker result. As a 230 consequence, the caller must not free the bytes. */ 231 tsi_result tsi_handshaker_result_get_unused_bytes( 232 const tsi_handshaker_result* self, const unsigned char** bytes, 233 size_t* byte_size); 234 235 /* This method releases the tsi_handshaker_handshaker object. After this method 236 is called, no other method can be called on the object. */ 237 void tsi_handshaker_result_destroy(tsi_handshaker_result* self); 238 239 /* --- tsi_handshaker objects ---- 240 241 Implementations of this object must be thread compatible. 242 243 ------------------------------------------------------------------------ 244 245 A typical usage supporting both synchronous and asynchronous TSI handshaker 246 implementations would be: 247 248 ------------------------------------------------------------------------ 249 250 typedef struct { 251 tsi_handshaker *handshaker; 252 tsi_handshaker_result *handshaker_result; 253 unsigned char *handshake_buffer; 254 size_t handshake_buffer_size; 255 ... 256 } security_handshaker; 257 258 void do_handshake(security_handshaker *h, ...) { 259 // Start the handshake by the calling do_handshake_next. 260 do_handshake_next(h, NULL, 0); 261 ... 262 } 263 264 // This method is the callback function when data is received from the 265 // peer. This method will read bytes into the handshake buffer and call 266 // do_handshake_next. 267 void on_handshake_data_received_from_peer(void *user_data) { 268 security_handshaker *h = (security_handshaker *)user_data; 269 size_t bytes_received_size = h->handshake_buffer_size; 270 read_bytes_from_peer(h->handshake_buffer, &bytes_received_size); 271 do_handshake_next(h, h->handshake_buffer, bytes_received_size); 272 } 273 274 // This method processes a step of handshake, calling tsi_handshaker_next. 275 void do_handshake_next(security_handshaker *h, 276 const unsigned char* bytes_received, 277 size_t bytes_received_size) { 278 tsi_result status = TSI_OK; 279 unsigned char *bytes_to_send = NULL; 280 size_t bytes_to_send_size = 0; 281 tsi_handshaker_result *result = NULL; 282 status = tsi_handshaker_next( 283 handshaker, bytes_received, bytes_received_size, &bytes_to_send, 284 &bytes_to_send_size, &result, on_handshake_next_done, h); 285 // If TSI handshaker is asynchronous, on_handshake_next_done will be 286 // executed inside tsi_handshaker_next. 287 if (status == TSI_ASYNC) return; 288 // If TSI handshaker is synchronous, invoke callback directly in this 289 // thread. 290 on_handshake_next_done(status, (void *)h, bytes_to_send, 291 bytes_to_send_size, result); 292 } 293 294 // This is the callback function to execute after tsi_handshaker_next. 295 // It is passed to tsi_handshaker_next as a function parameter. 296 void on_handshake_next_done( 297 tsi_result status, void *user_data, const unsigned char *bytes_to_send, 298 size_t bytes_to_send_size, tsi_handshaker_result *result) { 299 security_handshaker *h = (security_handshaker *)user_data; 300 if (status == TSI_INCOMPLETE_DATA) { 301 // Schedule an asynchronous read from the peer. If handshake data are 302 // received, on_handshake_data_received_from_peer will be called. 303 async_read_from_peer(..., ..., on_handshake_data_received_from_peer); 304 return; 305 } 306 if (status != TSI_OK) return; 307 308 if (bytes_to_send_size > 0) { 309 send_bytes_to_peer(bytes_to_send, bytes_to_send_size); 310 } 311 312 if (result != NULL) { 313 // Handshake completed. 314 h->result = result; 315 // Check the Peer. 316 tsi_peer peer; 317 status = tsi_handshaker_result_extract_peer(result, &peer); 318 if (status != TSI_OK) return; 319 status = check_peer(&peer); 320 tsi_peer_destruct(&peer); 321 if (status != TSI_OK) return; 322 323 // Create the protector. 324 tsi_frame_protector* protector = NULL; 325 status = tsi_handshaker_result_create_frame_protector(result, NULL, 326 &protector); 327 if (status != TSI_OK) return; 328 329 // Do not forget to unprotect outstanding data if any. 330 .... 331 } 332 } 333 ------------------------------------------------------------------------ */ 334 typedef struct tsi_handshaker tsi_handshaker; 335 336 /* TODO(jiangtaoli2016): Cleans up deprecated methods when we are ready. */ 337 338 /* TO BE DEPRECATED SOON. Use tsi_handshaker_next instead. 339 Gets bytes that need to be sent to the peer. 340 - bytes is the buffer that will be written with the data to be sent to the 341 peer. 342 - bytes_size is an input/output parameter specifying the capacity of the 343 bytes parameter as input and the number of bytes written as output. 344 Returns TSI_OK if all the data to send to the peer has been written or if 345 nothing has to be sent to the peer (in which base bytes_size outputs to 0), 346 otherwise returns TSI_INCOMPLETE_DATA which indicates that this method 347 needs to be called again to get all the bytes to send to the peer (there 348 was more data to write than the specified bytes_size). In case of a fatal 349 error in the handshake, another specific error code is returned. */ 350 tsi_result tsi_handshaker_get_bytes_to_send_to_peer(tsi_handshaker* self, 351 unsigned char* bytes, 352 size_t* bytes_size); 353 354 /* TO BE DEPRECATED SOON. Use tsi_handshaker_next instead. 355 Processes bytes received from the peer. 356 - bytes is the buffer containing the data. 357 - bytes_size is an input/output parameter specifying the size of the data as 358 input and the number of bytes consumed as output. 359 Return TSI_OK if the handshake has all the data it needs to process, 360 otherwise return TSI_INCOMPLETE_DATA which indicates that this method 361 needs to be called again to complete the data needed for processing. In 362 case of a fatal error in the handshake, another specific error code is 363 returned. */ 364 tsi_result tsi_handshaker_process_bytes_from_peer(tsi_handshaker* self, 365 const unsigned char* bytes, 366 size_t* bytes_size); 367 368 /* TO BE DEPRECATED SOON. 369 Gets the result of the handshaker. 370 Returns TSI_OK if the hanshake completed successfully and there has been no 371 errors. Returns TSI_HANDSHAKE_IN_PROGRESS if the handshaker is not done yet 372 but no error has been encountered so far. Otherwise the handshaker failed 373 with the returned error. */ 374 tsi_result tsi_handshaker_get_result(tsi_handshaker* self); 375 376 /* TO BE DEPRECATED SOON. 377 Returns 1 if the handshake is in progress, 0 otherwise. */ 378 #define tsi_handshaker_is_in_progress(h) \ 379 (tsi_handshaker_get_result((h)) == TSI_HANDSHAKE_IN_PROGRESS) 380 381 /* TO BE DEPRECATED SOON. Use tsi_handshaker_result_extract_peer instead. 382 This method may return TSI_FAILED_PRECONDITION if 383 tsi_handshaker_is_in_progress returns 1, it returns TSI_OK otherwise 384 assuming the handshaker is not in a fatal error state. 385 The caller is responsible for destructing the peer. */ 386 tsi_result tsi_handshaker_extract_peer(tsi_handshaker* self, tsi_peer* peer); 387 388 /* TO BE DEPRECATED SOON. Use tsi_handshaker_result_create_frame_protector 389 instead. 390 This method creates a tsi_frame_protector object after the handshake phase 391 is done. After this method has been called successfully, the only method 392 that can be called on this object is Destroy. 393 - max_output_protected_frame_size is an input/output parameter specifying the 394 desired max output protected frame size as input and outputing the actual 395 max output frame size as the output. Passing NULL is OK and will result in 396 the implementation choosing the default maximum protected frame size. Note 397 that this size only applies to outgoing frames (generated with 398 tsi_frame_protector_protect) and not incoming frames (input of 399 tsi_frame_protector_unprotect). 400 - protector is an output parameter pointing to the newly created 401 tsi_frame_protector object. 402 This method may return TSI_FAILED_PRECONDITION if 403 tsi_handshaker_is_in_progress returns 1, it returns TSI_OK otherwise assuming 404 the handshaker is not in a fatal error state. 405 The caller is responsible for destroying the protector. */ 406 tsi_result tsi_handshaker_create_frame_protector( 407 tsi_handshaker* self, size_t* max_output_protected_frame_size, 408 tsi_frame_protector** protector); 409 410 /* Callback function definition for tsi_handshaker_next. 411 - status indicates the status of the next operation. 412 - user_data is the argument to callback function passed from the caller. 413 - bytes_to_send is the data buffer to be sent to the peer. 414 - bytes_to_send_size is the size of data buffer to be sent to the peer. 415 - handshaker_result is the result of handshake when the handshake completes, 416 is NULL otherwise. */ 417 typedef void (*tsi_handshaker_on_next_done_cb)( 418 tsi_result status, void* user_data, const unsigned char* bytes_to_send, 419 size_t bytes_to_send_size, tsi_handshaker_result* handshaker_result); 420 421 /* Conduct a next step of the handshake. 422 - received_bytes is the buffer containing the data received from the peer. 423 - received_bytes_size is the size of the data received from the peer. 424 - bytes_to_send is the data buffer to be sent to the peer. 425 - bytes_to_send_size is the size of data buffer to be sent to the peer. 426 - handshaker_result is the result of handshake if the handshake completes. 427 - cb is the callback function defined above. It can be NULL for synchronous 428 TSI handshaker implementation. 429 - user_data is the argument to callback function passed from the caller. 430 This method returns TSI_ASYNC if the TSI handshaker implementation is 431 asynchronous, and in this case, the callback is guaranteed to run in another 432 thread owned by TSI. It returns TSI_OK if the handshake completes or if 433 there are data to send to the peer, otherwise returns TSI_INCOMPLETE_DATA 434 which indicates that this method needs to be called again with more data 435 from the peer. In case of a fatal error in the handshake, another specific 436 error code is returned. 437 The caller is responsible for destroying the handshaker_result. However, 438 the caller should not free bytes_to_send, as the buffer is owned by the 439 tsi_handshaker object. */ 440 tsi_result tsi_handshaker_next( 441 tsi_handshaker* self, const unsigned char* received_bytes, 442 size_t received_bytes_size, const unsigned char** bytes_to_send, 443 size_t* bytes_to_send_size, tsi_handshaker_result** handshaker_result, 444 tsi_handshaker_on_next_done_cb cb, void* user_data); 445 446 /* This method shuts down a TSI handshake that is in progress. 447 * 448 * This method will be invoked when TSI handshake should be terminated before 449 * being finished in order to free any resources being used. 450 */ 451 void tsi_handshaker_shutdown(tsi_handshaker* self); 452 453 /* This method releases the tsi_handshaker object. After this method is called, 454 no other method can be called on the object. */ 455 void tsi_handshaker_destroy(tsi_handshaker* self); 456 457 /* This method initializes the necessary shared objects used for tsi 458 implementation. */ 459 void tsi_init(); 460 461 /* This method destroys the shared objects created by tsi_init. */ 462 void tsi_destroy(); 463 464 #endif /* GRPC_CORE_TSI_TRANSPORT_SECURITY_INTERFACE_H */ 465