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