1 //
2 //
3 // Copyright 2016 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/ext/transport/chttp2/transport/bin_decoder.h"
22 
23 #include "absl/base/attributes.h"
24 
25 #include <grpc/support/alloc.h>
26 #include <grpc/support/log.h>
27 
28 #include "src/core/lib/slice/slice.h"
29 
30 static uint8_t decode_table[] = {
31     0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
32     0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
33     0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
34     0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 62,   0x40, 0x40, 0x40, 63,
35     52,   53,   54,   55,   56,   57,   58,   59,   60,   61,   0x40, 0x40,
36     0x40, 0x40, 0x40, 0x40, 0x40, 0,    1,    2,    3,    4,    5,    6,
37     7,    8,    9,    10,   11,   12,   13,   14,   15,   16,   17,   18,
38     19,   20,   21,   22,   23,   24,   25,   0x40, 0x40, 0x40, 0x40, 0x40,
39     0x40, 26,   27,   28,   29,   30,   31,   32,   33,   34,   35,   36,
40     37,   38,   39,   40,   41,   42,   43,   44,   45,   46,   47,   48,
41     49,   50,   51,   0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
42     0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
43     0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
44     0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
45     0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
46     0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
47     0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
48     0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
49     0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
50     0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
51     0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
52     0x40, 0x40, 0x40, 0x40};
53 
54 static const uint8_t tail_xtra[4] = {0, 0, 1, 2};
55 
input_is_valid(const uint8_t * input_ptr,size_t length)56 static bool input_is_valid(const uint8_t* input_ptr, size_t length) {
57   size_t i;
58 
59   for (i = 0; i < length; ++i) {
60     if (GPR_UNLIKELY((decode_table[input_ptr[i]] & 0xC0) != 0)) {
61       gpr_log(GPR_ERROR,
62               "Base64 decoding failed, invalid character '%c' in base64 "
63               "input.\n",
64               static_cast<char>(*input_ptr));
65       return false;
66     }
67   }
68   return true;
69 }
70 
71 #define COMPOSE_OUTPUT_BYTE_0(input_ptr)          \
72   (uint8_t)((decode_table[(input_ptr)[0]] << 2) | \
73             (decode_table[(input_ptr)[1]] >> 4))
74 
75 #define COMPOSE_OUTPUT_BYTE_1(input_ptr)          \
76   (uint8_t)((decode_table[(input_ptr)[1]] << 4) | \
77             (decode_table[(input_ptr)[2]] >> 2))
78 
79 #define COMPOSE_OUTPUT_BYTE_2(input_ptr) \
80   (uint8_t)((decode_table[(input_ptr)[2]] << 6) | decode_table[(input_ptr)[3]])
81 
82 // By RFC 4648, if the length of the encoded string without padding is 4n+r,
83 // the length of decoded string is: 1) 3n if r = 0, 2) 3n + 1 if r = 2, 3, or
84 // 3) invalid if r = 1.
grpc_chttp2_base64_infer_length_after_decode(const grpc_slice & slice)85 size_t grpc_chttp2_base64_infer_length_after_decode(const grpc_slice& slice) {
86   size_t len = GRPC_SLICE_LENGTH(slice);
87   const uint8_t* bytes = GRPC_SLICE_START_PTR(slice);
88   while (len > 0 && bytes[len - 1] == '=') {
89     len--;
90   }
91   if (GPR_UNLIKELY(GRPC_SLICE_LENGTH(slice) - len > 2)) {
92     gpr_log(GPR_ERROR,
93             "Base64 decoding failed. Input has more than 2 paddings.");
94     return 0;
95   }
96   size_t tuples = len / 4;
97   size_t tail_case = len % 4;
98   if (GPR_UNLIKELY(tail_case == 1)) {
99     gpr_log(GPR_ERROR,
100             "Base64 decoding failed. Input has a length of %zu (without"
101             " padding), which is invalid.\n",
102             len);
103     return 0;
104   }
105   return tuples * 3 + tail_xtra[tail_case];
106 }
107 
grpc_base64_decode_partial(struct grpc_base64_decode_context * ctx)108 bool grpc_base64_decode_partial(struct grpc_base64_decode_context* ctx) {
109   size_t input_tail;
110 
111   if (ctx->input_cur > ctx->input_end || ctx->output_cur > ctx->output_end) {
112     return false;
113   }
114 
115   // Process a block of 4 input characters and 3 output bytes
116   while (ctx->input_end >= ctx->input_cur + 4 &&
117          ctx->output_end >= ctx->output_cur + 3) {
118     if (!input_is_valid(ctx->input_cur, 4)) return false;
119     ctx->output_cur[0] = COMPOSE_OUTPUT_BYTE_0(ctx->input_cur);
120     ctx->output_cur[1] = COMPOSE_OUTPUT_BYTE_1(ctx->input_cur);
121     ctx->output_cur[2] = COMPOSE_OUTPUT_BYTE_2(ctx->input_cur);
122     ctx->output_cur += 3;
123     ctx->input_cur += 4;
124   }
125 
126   // Process the tail of input data
127   input_tail = static_cast<size_t>(ctx->input_end - ctx->input_cur);
128   if (input_tail == 4) {
129     // Process the input data with pad chars
130     if (ctx->input_cur[3] == '=') {
131       if (ctx->input_cur[2] == '=' && ctx->output_end >= ctx->output_cur + 1) {
132         if (!input_is_valid(ctx->input_cur, 2)) return false;
133         *(ctx->output_cur++) = COMPOSE_OUTPUT_BYTE_0(ctx->input_cur);
134         ctx->input_cur += 4;
135       } else if (ctx->output_end >= ctx->output_cur + 2) {
136         if (!input_is_valid(ctx->input_cur, 3)) return false;
137         *(ctx->output_cur++) = COMPOSE_OUTPUT_BYTE_0(ctx->input_cur);
138         *(ctx->output_cur++) = COMPOSE_OUTPUT_BYTE_1(ctx->input_cur);
139         ;
140         ctx->input_cur += 4;
141       }
142     }
143 
144   } else if (ctx->contains_tail && input_tail > 1) {
145     // Process the input data without pad chars, but constains_tail is set
146     if (ctx->output_end >= ctx->output_cur + tail_xtra[input_tail]) {
147       if (!input_is_valid(ctx->input_cur, input_tail)) return false;
148       switch (input_tail) {
149         case 3:
150           ctx->output_cur[1] = COMPOSE_OUTPUT_BYTE_1(ctx->input_cur);
151           ABSL_FALLTHROUGH_INTENDED;
152         case 2:
153           ctx->output_cur[0] = COMPOSE_OUTPUT_BYTE_0(ctx->input_cur);
154       }
155       ctx->output_cur += tail_xtra[input_tail];
156       ctx->input_cur += input_tail;
157     }
158   }
159 
160   return true;
161 }
162 
grpc_chttp2_base64_decode(const grpc_slice & input)163 grpc_slice grpc_chttp2_base64_decode(const grpc_slice& input) {
164   size_t input_length = GRPC_SLICE_LENGTH(input);
165   size_t output_length = input_length / 4 * 3;
166   struct grpc_base64_decode_context ctx;
167   grpc_slice output;
168 
169   if (GPR_UNLIKELY(input_length % 4 != 0)) {
170     gpr_log(GPR_ERROR,
171             "Base64 decoding failed, input of "
172             "grpc_chttp2_base64_decode has a length of %d, which is not a "
173             "multiple of 4.\n",
174             static_cast<int>(input_length));
175     return grpc_empty_slice();
176   }
177 
178   if (input_length > 0) {
179     const uint8_t* input_end = GRPC_SLICE_END_PTR(input);
180     if (*(--input_end) == '=') {
181       output_length--;
182       if (*(--input_end) == '=') {
183         output_length--;
184       }
185     }
186   }
187   output = GRPC_SLICE_MALLOC(output_length);
188 
189   ctx.input_cur = GRPC_SLICE_START_PTR(input);
190   ctx.input_end = GRPC_SLICE_END_PTR(input);
191   ctx.output_cur = GRPC_SLICE_START_PTR(output);
192   ctx.output_end = GRPC_SLICE_END_PTR(output);
193   ctx.contains_tail = false;
194 
195   if (GPR_UNLIKELY(!grpc_base64_decode_partial(&ctx))) {
196     char* s = grpc_slice_to_c_string(input);
197     gpr_log(GPR_ERROR, "Base64 decoding failed, input string:\n%s\n", s);
198     gpr_free(s);
199     grpc_core::CSliceUnref(output);
200     return grpc_empty_slice();
201   }
202   GPR_ASSERT(ctx.output_cur == GRPC_SLICE_END_PTR(output));
203   GPR_ASSERT(ctx.input_cur == GRPC_SLICE_END_PTR(input));
204   return output;
205 }
206 
grpc_chttp2_base64_decode_with_length(const grpc_slice & input,size_t output_length)207 grpc_slice grpc_chttp2_base64_decode_with_length(const grpc_slice& input,
208                                                  size_t output_length) {
209   size_t input_length = GRPC_SLICE_LENGTH(input);
210   grpc_slice output = GRPC_SLICE_MALLOC(output_length);
211   struct grpc_base64_decode_context ctx;
212 
213   // The length of a base64 string cannot be 4 * n + 1
214   if (GPR_UNLIKELY(input_length % 4 == 1)) {
215     gpr_log(GPR_ERROR,
216             "Base64 decoding failed, input of "
217             "grpc_chttp2_base64_decode_with_length has a length of %d, which "
218             "has a tail of 1 byte.\n",
219             static_cast<int>(input_length));
220     grpc_core::CSliceUnref(output);
221     return grpc_empty_slice();
222   }
223 
224   if (GPR_UNLIKELY(output_length >
225                    input_length / 4 * 3 + tail_xtra[input_length % 4])) {
226     gpr_log(
227         GPR_ERROR,
228         "Base64 decoding failed, output_length %d is longer "
229         "than the max possible output length %d.\n",
230         static_cast<int>(output_length),
231         static_cast<int>(input_length / 4 * 3 + tail_xtra[input_length % 4]));
232     grpc_core::CSliceUnref(output);
233     return grpc_empty_slice();
234   }
235 
236   ctx.input_cur = GRPC_SLICE_START_PTR(input);
237   ctx.input_end = GRPC_SLICE_END_PTR(input);
238   ctx.output_cur = GRPC_SLICE_START_PTR(output);
239   ctx.output_end = GRPC_SLICE_END_PTR(output);
240   ctx.contains_tail = true;
241 
242   if (GPR_UNLIKELY(!grpc_base64_decode_partial(&ctx))) {
243     char* s = grpc_slice_to_c_string(input);
244     gpr_log(GPR_ERROR, "Base64 decoding failed, input string:\n%s\n", s);
245     gpr_free(s);
246     grpc_core::CSliceUnref(output);
247     return grpc_empty_slice();
248   }
249   GPR_ASSERT(ctx.output_cur == GRPC_SLICE_END_PTR(output));
250   GPR_ASSERT(ctx.input_cur <= GRPC_SLICE_END_PTR(input));
251   return output;
252 }
253