1 /*
2  *
3  * Copyright 2018 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/alts/frame_protector/alts_frame_protector.h"
22 
23 #include <stdio.h>
24 #include <stdlib.h>
25 
26 #include <algorithm>
27 
28 #include <grpc/support/alloc.h>
29 #include <grpc/support/log.h>
30 
31 #include "src/core/lib/gpr/useful.h"
32 #include "src/core/tsi/alts/crypt/gsec.h"
33 #include "src/core/tsi/alts/frame_protector/alts_crypter.h"
34 #include "src/core/tsi/alts/frame_protector/frame_handler.h"
35 #include "src/core/tsi/transport_security.h"
36 
37 constexpr size_t kMinFrameLength = 1024;
38 constexpr size_t kDefaultFrameLength = 16 * 1024;
39 constexpr size_t kMaxFrameLength = 1024 * 1024;
40 
41 // Limit k on number of frames such that at most 2^(8 * k) frames can be sent.
42 constexpr size_t kAltsRecordProtocolRekeyFrameLimit = 8;
43 constexpr size_t kAltsRecordProtocolFrameLimit = 5;
44 
45 /* Main struct for alts_frame_protector. */
46 struct alts_frame_protector {
47   tsi_frame_protector base;
48   alts_crypter* seal_crypter;
49   alts_crypter* unseal_crypter;
50   alts_frame_writer* writer;
51   alts_frame_reader* reader;
52   unsigned char* in_place_protect_buffer;
53   unsigned char* in_place_unprotect_buffer;
54   size_t in_place_protect_bytes_buffered;
55   size_t in_place_unprotect_bytes_processed;
56   size_t max_protected_frame_size;
57   size_t max_unprotected_frame_size;
58   size_t overhead_length;
59   size_t counter_overflow;
60 };
61 
seal(alts_frame_protector * impl)62 static tsi_result seal(alts_frame_protector* impl) {
63   char* error_details = nullptr;
64   size_t output_size = 0;
65   grpc_status_code status = alts_crypter_process_in_place(
66       impl->seal_crypter, impl->in_place_protect_buffer,
67       impl->max_protected_frame_size, impl->in_place_protect_bytes_buffered,
68       &output_size, &error_details);
69   impl->in_place_protect_bytes_buffered = output_size;
70   if (status != GRPC_STATUS_OK) {
71     gpr_log(GPR_ERROR, "%s", error_details);
72     gpr_free(error_details);
73     return TSI_INTERNAL_ERROR;
74   }
75   return TSI_OK;
76 }
77 
max_encrypted_payload_bytes(alts_frame_protector * impl)78 static size_t max_encrypted_payload_bytes(alts_frame_protector* impl) {
79   return impl->max_protected_frame_size - kFrameHeaderSize;
80 }
81 
alts_protect_flush(tsi_frame_protector * self,unsigned char * protected_output_frames,size_t * protected_output_frames_size,size_t * still_pending_size)82 static tsi_result alts_protect_flush(tsi_frame_protector* self,
83                                      unsigned char* protected_output_frames,
84                                      size_t* protected_output_frames_size,
85                                      size_t* still_pending_size) {
86   if (self == nullptr || protected_output_frames == nullptr ||
87       protected_output_frames_size == nullptr ||
88       still_pending_size == nullptr) {
89     gpr_log(GPR_ERROR, "Invalid nullptr arguments to alts_protect_flush().");
90     return TSI_INVALID_ARGUMENT;
91   }
92   alts_frame_protector* impl = reinterpret_cast<alts_frame_protector*>(self);
93   /**
94    * If there's nothing to flush (i.e., in_place_protect_buffer is empty),
95    * we're done.
96    */
97   if (impl->in_place_protect_bytes_buffered == 0) {
98     *protected_output_frames_size = 0;
99     *still_pending_size = 0;
100     return TSI_OK;
101   }
102   /**
103    * If a new frame can start being processed, we encrypt the payload and reset
104    * the frame writer to point to in_place_protect_buffer that holds the newly
105    * sealed frame.
106    */
107   if (alts_is_frame_writer_done(impl->writer)) {
108     tsi_result result = seal(impl);
109     if (result != TSI_OK) {
110       return result;
111     }
112     if (!alts_reset_frame_writer(impl->writer, impl->in_place_protect_buffer,
113                                  impl->in_place_protect_bytes_buffered)) {
114       gpr_log(GPR_ERROR, "Couldn't reset frame writer.");
115       return TSI_INTERNAL_ERROR;
116     }
117   }
118   /**
119    * Write the sealed frame as much as possible to protected_output_frames. It's
120    * possible a frame will not be written out completely by a single flush
121    * (i.e., still_pending_size != 0), in which case the flush should be called
122    * iteratively until a complete frame has been written out.
123    */
124   size_t written_frame_bytes = *protected_output_frames_size;
125   if (!alts_write_frame_bytes(impl->writer, protected_output_frames,
126                               &written_frame_bytes)) {
127     gpr_log(GPR_ERROR, "Couldn't write frame bytes.");
128     return TSI_INTERNAL_ERROR;
129   }
130   *protected_output_frames_size = written_frame_bytes;
131   *still_pending_size = alts_get_num_writer_bytes_remaining(impl->writer);
132   /**
133    * If the current frame has been finished processing (i.e., sealed and written
134    * out completely), we empty in_place_protect_buffer.
135    */
136   if (alts_is_frame_writer_done(impl->writer)) {
137     impl->in_place_protect_bytes_buffered = 0;
138   }
139   return TSI_OK;
140 }
141 
alts_protect(tsi_frame_protector * self,const unsigned char * unprotected_bytes,size_t * unprotected_bytes_size,unsigned char * protected_output_frames,size_t * protected_output_frames_size)142 static tsi_result alts_protect(tsi_frame_protector* self,
143                                const unsigned char* unprotected_bytes,
144                                size_t* unprotected_bytes_size,
145                                unsigned char* protected_output_frames,
146                                size_t* protected_output_frames_size) {
147   if (self == nullptr || unprotected_bytes == nullptr ||
148       unprotected_bytes_size == nullptr || protected_output_frames == nullptr ||
149       protected_output_frames_size == nullptr) {
150     gpr_log(GPR_ERROR, "Invalid nullptr arguments to alts_protect().");
151     return TSI_INVALID_ARGUMENT;
152   }
153   alts_frame_protector* impl = reinterpret_cast<alts_frame_protector*>(self);
154 
155   /**
156    * If more payload can be buffered, we buffer it as much as possible to
157    * in_place_protect_buffer.
158    */
159   if (impl->in_place_protect_bytes_buffered + impl->overhead_length <
160       max_encrypted_payload_bytes(impl)) {
161     size_t bytes_to_buffer = std::min(
162         *unprotected_bytes_size, max_encrypted_payload_bytes(impl) -
163                                      impl->in_place_protect_bytes_buffered -
164                                      impl->overhead_length);
165     *unprotected_bytes_size = bytes_to_buffer;
166     if (bytes_to_buffer > 0) {
167       memcpy(
168           impl->in_place_protect_buffer + impl->in_place_protect_bytes_buffered,
169           unprotected_bytes, bytes_to_buffer);
170       impl->in_place_protect_bytes_buffered += bytes_to_buffer;
171     }
172   } else {
173     *unprotected_bytes_size = 0;
174   }
175   /**
176    * If a full frame has been buffered, we output it. If the first condition
177    * holds, then there exists an unencrypted full frame. If the second
178    * condition holds, then there exists a full frame that has already been
179    * encrypted.
180    */
181   if (max_encrypted_payload_bytes(impl) ==
182           impl->in_place_protect_bytes_buffered + impl->overhead_length ||
183       max_encrypted_payload_bytes(impl) ==
184           impl->in_place_protect_bytes_buffered) {
185     size_t still_pending_size = 0;
186     return alts_protect_flush(self, protected_output_frames,
187                               protected_output_frames_size,
188                               &still_pending_size);
189   } else {
190     *protected_output_frames_size = 0;
191     return TSI_OK;
192   }
193 }
194 
unseal(alts_frame_protector * impl)195 static tsi_result unseal(alts_frame_protector* impl) {
196   char* error_details = nullptr;
197   size_t output_size = 0;
198   grpc_status_code status = alts_crypter_process_in_place(
199       impl->unseal_crypter, impl->in_place_unprotect_buffer,
200       impl->max_unprotected_frame_size,
201       alts_get_output_bytes_read(impl->reader), &output_size, &error_details);
202   if (status != GRPC_STATUS_OK) {
203     gpr_log(GPR_ERROR, "%s", error_details);
204     gpr_free(error_details);
205     return TSI_DATA_CORRUPTED;
206   }
207   return TSI_OK;
208 }
209 
ensure_buffer_size(alts_frame_protector * impl)210 static void ensure_buffer_size(alts_frame_protector* impl) {
211   if (!alts_has_read_frame_length(impl->reader)) {
212     return;
213   }
214   size_t buffer_space_remaining = impl->max_unprotected_frame_size -
215                                   alts_get_output_bytes_read(impl->reader);
216   /**
217    * Check if we need to resize in_place_unprotect_buffer in order to hold
218    * remaining bytes of a full frame.
219    */
220   if (buffer_space_remaining < alts_get_reader_bytes_remaining(impl->reader)) {
221     size_t buffer_len = alts_get_output_bytes_read(impl->reader) +
222                         alts_get_reader_bytes_remaining(impl->reader);
223     unsigned char* buffer = static_cast<unsigned char*>(gpr_malloc(buffer_len));
224     memcpy(buffer, impl->in_place_unprotect_buffer,
225            alts_get_output_bytes_read(impl->reader));
226     impl->max_unprotected_frame_size = buffer_len;
227     gpr_free(impl->in_place_unprotect_buffer);
228     impl->in_place_unprotect_buffer = buffer;
229     alts_reset_reader_output_buffer(
230         impl->reader, buffer + alts_get_output_bytes_read(impl->reader));
231   }
232 }
233 
alts_unprotect(tsi_frame_protector * self,const unsigned char * protected_frames_bytes,size_t * protected_frames_bytes_size,unsigned char * unprotected_bytes,size_t * unprotected_bytes_size)234 static tsi_result alts_unprotect(tsi_frame_protector* self,
235                                  const unsigned char* protected_frames_bytes,
236                                  size_t* protected_frames_bytes_size,
237                                  unsigned char* unprotected_bytes,
238                                  size_t* unprotected_bytes_size) {
239   if (self == nullptr || protected_frames_bytes == nullptr ||
240       protected_frames_bytes_size == nullptr || unprotected_bytes == nullptr ||
241       unprotected_bytes_size == nullptr) {
242     gpr_log(GPR_ERROR, "Invalid nullptr arguments to alts_unprotect().");
243     return TSI_INVALID_ARGUMENT;
244   }
245   alts_frame_protector* impl = reinterpret_cast<alts_frame_protector*>(self);
246   /**
247    * If a new frame can start being processed, we reset the frame reader to
248    * point to in_place_unprotect_buffer that will be used to hold deframed
249    * result.
250    */
251   if (alts_is_frame_reader_done(impl->reader) &&
252       ((alts_get_output_buffer(impl->reader) == nullptr) ||
253        (alts_get_output_bytes_read(impl->reader) ==
254         impl->in_place_unprotect_bytes_processed + impl->overhead_length))) {
255     if (!alts_reset_frame_reader(impl->reader,
256                                  impl->in_place_unprotect_buffer)) {
257       gpr_log(GPR_ERROR, "Couldn't reset frame reader.");
258       return TSI_INTERNAL_ERROR;
259     }
260     impl->in_place_unprotect_bytes_processed = 0;
261   }
262   /**
263    * If a full frame has not yet been read, we read more bytes from
264    * protected_frames_bytes until a full frame has been read. We also need to
265    * make sure in_place_unprotect_buffer is large enough to hold a complete
266    * frame.
267    */
268   if (!alts_is_frame_reader_done(impl->reader)) {
269     ensure_buffer_size(impl);
270     *protected_frames_bytes_size =
271         std::min(impl->max_unprotected_frame_size -
272                      alts_get_output_bytes_read(impl->reader),
273                  *protected_frames_bytes_size);
274     size_t read_frames_bytes_size = *protected_frames_bytes_size;
275     if (!alts_read_frame_bytes(impl->reader, protected_frames_bytes,
276                                &read_frames_bytes_size)) {
277       gpr_log(GPR_ERROR, "Failed to process frame.");
278       return TSI_INTERNAL_ERROR;
279     }
280     *protected_frames_bytes_size = read_frames_bytes_size;
281   } else {
282     *protected_frames_bytes_size = 0;
283   }
284   /**
285    * If a full frame has been read, we unseal it, and write out the
286    * deframed result to unprotected_bytes.
287    */
288   if (alts_is_frame_reader_done(impl->reader)) {
289     if (impl->in_place_unprotect_bytes_processed == 0) {
290       tsi_result result = unseal(impl);
291       if (result != TSI_OK) {
292         return result;
293       }
294     }
295     size_t bytes_to_write = std::min(
296         *unprotected_bytes_size, alts_get_output_bytes_read(impl->reader) -
297                                      impl->in_place_unprotect_bytes_processed -
298                                      impl->overhead_length);
299     if (bytes_to_write > 0) {
300       memcpy(unprotected_bytes,
301              impl->in_place_unprotect_buffer +
302                  impl->in_place_unprotect_bytes_processed,
303              bytes_to_write);
304     }
305     *unprotected_bytes_size = bytes_to_write;
306     impl->in_place_unprotect_bytes_processed += bytes_to_write;
307     return TSI_OK;
308   } else {
309     *unprotected_bytes_size = 0;
310     return TSI_OK;
311   }
312 }
313 
alts_destroy(tsi_frame_protector * self)314 static void alts_destroy(tsi_frame_protector* self) {
315   alts_frame_protector* impl = reinterpret_cast<alts_frame_protector*>(self);
316   if (impl != nullptr) {
317     alts_crypter_destroy(impl->seal_crypter);
318     alts_crypter_destroy(impl->unseal_crypter);
319     gpr_free(impl->in_place_protect_buffer);
320     gpr_free(impl->in_place_unprotect_buffer);
321     alts_destroy_frame_writer(impl->writer);
322     alts_destroy_frame_reader(impl->reader);
323     gpr_free(impl);
324   }
325 }
326 
327 static const tsi_frame_protector_vtable alts_frame_protector_vtable = {
328     alts_protect, alts_protect_flush, alts_unprotect, alts_destroy};
329 
create_alts_crypters(const uint8_t * key,size_t key_size,bool is_client,bool is_rekey,alts_frame_protector * impl,char ** error_details)330 static grpc_status_code create_alts_crypters(const uint8_t* key,
331                                              size_t key_size, bool is_client,
332                                              bool is_rekey,
333                                              alts_frame_protector* impl,
334                                              char** error_details) {
335   grpc_status_code status;
336   gsec_aead_crypter* aead_crypter_seal = nullptr;
337   gsec_aead_crypter* aead_crypter_unseal = nullptr;
338   status = gsec_aes_gcm_aead_crypter_create(key, key_size, kAesGcmNonceLength,
339                                             kAesGcmTagLength, is_rekey,
340                                             &aead_crypter_seal, error_details);
341   if (status != GRPC_STATUS_OK) {
342     return status;
343   }
344   status = gsec_aes_gcm_aead_crypter_create(
345       key, key_size, kAesGcmNonceLength, kAesGcmTagLength, is_rekey,
346       &aead_crypter_unseal, error_details);
347   if (status != GRPC_STATUS_OK) {
348     return status;
349   }
350   size_t overflow_size = is_rekey ? kAltsRecordProtocolRekeyFrameLimit
351                                   : kAltsRecordProtocolFrameLimit;
352   status = alts_seal_crypter_create(aead_crypter_seal, is_client, overflow_size,
353                                     &impl->seal_crypter, error_details);
354   if (status != GRPC_STATUS_OK) {
355     return status;
356   }
357   status =
358       alts_unseal_crypter_create(aead_crypter_unseal, is_client, overflow_size,
359                                  &impl->unseal_crypter, error_details);
360   return status;
361 }
362 
alts_create_frame_protector(const uint8_t * key,size_t key_size,bool is_client,bool is_rekey,size_t * max_protected_frame_size,tsi_frame_protector ** self)363 tsi_result alts_create_frame_protector(const uint8_t* key, size_t key_size,
364                                        bool is_client, bool is_rekey,
365                                        size_t* max_protected_frame_size,
366                                        tsi_frame_protector** self) {
367   if (key == nullptr || self == nullptr) {
368     gpr_log(GPR_ERROR,
369             "Invalid nullptr arguments to alts_create_frame_protector().");
370     return TSI_INTERNAL_ERROR;
371   }
372   char* error_details = nullptr;
373   alts_frame_protector* impl = grpc_core::Zalloc<alts_frame_protector>();
374   grpc_status_code status = create_alts_crypters(
375       key, key_size, is_client, is_rekey, impl, &error_details);
376   if (status != GRPC_STATUS_OK) {
377     gpr_log(GPR_ERROR, "Failed to create ALTS crypters, %s.", error_details);
378     gpr_free(error_details);
379     return TSI_INTERNAL_ERROR;
380   }
381   /**
382    * Set maximum frame size to be used by a frame protector. If it is nullptr, a
383    * default frame size will be used. Otherwise, the provided frame size will be
384    * adjusted (if not falling into a valid frame range) and used.
385    */
386   size_t max_protected_frame_size_to_set = kDefaultFrameLength;
387   if (max_protected_frame_size != nullptr) {
388     *max_protected_frame_size =
389         std::min(*max_protected_frame_size, kMaxFrameLength);
390     *max_protected_frame_size =
391         std::max(*max_protected_frame_size, kMinFrameLength);
392     max_protected_frame_size_to_set = *max_protected_frame_size;
393   }
394   impl->max_protected_frame_size = max_protected_frame_size_to_set;
395   impl->max_unprotected_frame_size = max_protected_frame_size_to_set;
396   impl->in_place_protect_bytes_buffered = 0;
397   impl->in_place_unprotect_bytes_processed = 0;
398   impl->in_place_protect_buffer = static_cast<unsigned char*>(
399       gpr_malloc(sizeof(unsigned char) * max_protected_frame_size_to_set));
400   impl->in_place_unprotect_buffer = static_cast<unsigned char*>(
401       gpr_malloc(sizeof(unsigned char) * max_protected_frame_size_to_set));
402   impl->overhead_length = alts_crypter_num_overhead_bytes(impl->seal_crypter);
403   impl->writer = alts_create_frame_writer();
404   impl->reader = alts_create_frame_reader();
405   impl->base.vtable = &alts_frame_protector_vtable;
406   *self = &impl->base;
407   return TSI_OK;
408 }
409