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