Home | History | Annotate | Download | only in transport
      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(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(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 
    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