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