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
input_is_valid(uint8_t * input_ptr,size_t length)54 static bool input_is_valid(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.
grpc_chttp2_base64_infer_length_after_decode(const grpc_slice & slice)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
grpc_base64_decode_partial(struct grpc_base64_decode_context * ctx)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
grpc_chttp2_base64_decode(grpc_slice input)161 grpc_slice grpc_chttp2_base64_decode(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 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
grpc_chttp2_base64_decode_with_length(grpc_slice input,size_t output_length)205 grpc_slice grpc_chttp2_base64_decode_with_length(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 }
251