• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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