Home | History | Annotate | Download | only in base64
      1 /* Copyright (c) 2014, Google Inc.
      2  *
      3  * Permission to use, copy, modify, and/or distribute this software for any
      4  * purpose with or without fee is hereby granted, provided that the above
      5  * copyright notice and this permission notice appear in all copies.
      6  *
      7  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
      8  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
      9  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
     10  * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     11  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
     12  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
     13  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
     14 
     15 #include <stdio.h>
     16 #include <string.h>
     17 
     18 #include <string>
     19 #include <vector>
     20 
     21 #include <openssl/base64.h>
     22 #include <openssl/crypto.h>
     23 #include <openssl/err.h>
     24 
     25 #include "../internal.h"
     26 
     27 
     28 enum encoding_relation {
     29   // canonical indicates that the encoding is the expected encoding of the
     30   // input.
     31   canonical,
     32   // valid indicates that the encoding is /a/ valid encoding of the input, but
     33   // need not be the canonical one.
     34   valid,
     35   // invalid indicates that the encoded data is valid.
     36   invalid,
     37 };
     38 
     39 struct TestVector {
     40   enum encoding_relation relation;
     41   const char *decoded;
     42   const char *encoded;
     43 };
     44 
     45 // Test vectors from RFC 4648.
     46 static const TestVector kTestVectors[] = {
     47     {canonical, "", ""},
     48     {canonical, "f", "Zg==\n"},
     49     {canonical, "fo", "Zm8=\n"},
     50     {canonical, "foo", "Zm9v\n"},
     51     {canonical, "foob", "Zm9vYg==\n"},
     52     {canonical, "fooba", "Zm9vYmE=\n"},
     53     {canonical, "foobar", "Zm9vYmFy\n"},
     54     {valid, "foobar", "Zm9vYmFy\n\n"},
     55     {valid, "foobar", " Zm9vYmFy\n\n"},
     56     {valid, "foobar", " Z m 9 v Y m F y\n\n"},
     57     {invalid, "", "Zm9vYmFy=\n"},
     58     {invalid, "", "Zm9vYmFy==\n"},
     59     {invalid, "", "Zm9vYmFy===\n"},
     60     {invalid, "", "Z"},
     61     {invalid, "", "Z\n"},
     62     {invalid, "", "ab!c"},
     63     {invalid, "", "ab=c"},
     64     {invalid, "", "abc"},
     65 
     66     {canonical, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
     67      "eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eA==\n"},
     68     {valid, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
     69      "eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eA\n==\n"},
     70     {valid, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
     71      "eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eA=\n=\n"},
     72     {invalid, "",
     73      "eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eA=\n==\n"},
     74     {canonical, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
     75      "eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4\neHh4eHh"
     76      "4eHh4eHh4\n"},
     77     {canonical,
     78      "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
     79      "eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4\neHh4eHh"
     80      "4eHh4eHh4eHh4eA==\n"},
     81     {valid, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
     82      "eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh\n4eHh4eHh"
     83      "4eHh4eHh4eHh4eA==\n"},
     84     {valid, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
     85      "eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4e"
     86      "Hh4eHh4eHh4eA==\n"},
     87     {invalid, "",
     88      "eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eA=="
     89      "\neHh4eHh4eHh4eHh4eHh4eHh4\n"},
     90 
     91     // A '-' has traditionally been treated as the end of the data by OpenSSL
     92     // and anything following would be ignored. BoringSSL does not accept this
     93     // non-standard extension.
     94     {invalid, "", "Zm9vYmFy-anythinggoes"},
     95     {invalid, "", "Zm9vYmFy\n-anythinggoes"},
     96 
     97     // CVE-2015-0292
     98     {invalid, "",
     99      "ZW5jb2RlIG1lCg==========================================================="
    100      "=======\n"},
    101 };
    102 
    103 static const size_t kNumTests = OPENSSL_ARRAY_SIZE(kTestVectors);
    104 
    105 // RemoveNewlines returns a copy of |in| with all '\n' characters removed.
    106 static std::string RemoveNewlines(const char *in) {
    107   std::string ret;
    108   const size_t in_len = strlen(in);
    109 
    110   for (size_t i = 0; i < in_len; i++) {
    111     if (in[i] != '\n') {
    112       ret.push_back(in[i]);
    113     }
    114   }
    115 
    116   return ret;
    117 }
    118 
    119 static bool TestEncodeBlock() {
    120   for (unsigned i = 0; i < kNumTests; i++) {
    121     const TestVector *t = &kTestVectors[i];
    122     if (t->relation != canonical) {
    123       continue;
    124     }
    125 
    126     const size_t decoded_len = strlen(t->decoded);
    127     size_t max_encoded_len;
    128     if (!EVP_EncodedLength(&max_encoded_len, decoded_len)) {
    129       fprintf(stderr, "#%u: EVP_EncodedLength failed\n", i);
    130       return false;
    131     }
    132 
    133     std::vector<uint8_t> out_vec(max_encoded_len);
    134     uint8_t *out = out_vec.data();
    135     size_t len = EVP_EncodeBlock(out, (const uint8_t *)t->decoded, decoded_len);
    136 
    137     std::string encoded(RemoveNewlines(t->encoded));
    138     if (len != encoded.size() ||
    139         OPENSSL_memcmp(out, encoded.data(), len) != 0) {
    140       fprintf(stderr, "encode(\"%s\") = \"%.*s\", want \"%s\"\n",
    141               t->decoded, (int)len, (const char*)out, encoded.c_str());
    142       return false;
    143     }
    144   }
    145 
    146   return true;
    147 }
    148 
    149 static bool TestDecodeBase64() {
    150   size_t len;
    151 
    152   for (unsigned i = 0; i < kNumTests; i++) {
    153     const TestVector *t = &kTestVectors[i];
    154 
    155     if (t->relation == valid) {
    156       // The non-canonical encodings will generally have odd whitespace etc
    157       // that |EVP_DecodeBase64| will reject.
    158       continue;
    159     }
    160 
    161     const std::string encoded(RemoveNewlines(t->encoded));
    162     std::vector<uint8_t> out_vec(encoded.size());
    163     uint8_t *out = out_vec.data();
    164 
    165     int ok = EVP_DecodeBase64(out, &len, out_vec.size(),
    166                               (const uint8_t *)encoded.data(), encoded.size());
    167 
    168     if (t->relation == invalid) {
    169       if (ok) {
    170         fprintf(stderr, "decode(\"%s\") didn't fail but should have\n",
    171                 encoded.c_str());
    172         return false;
    173       }
    174     } else if (t->relation == canonical) {
    175       if (!ok) {
    176         fprintf(stderr, "decode(\"%s\") failed\n", encoded.c_str());
    177         return false;
    178       }
    179 
    180       if (len != strlen(t->decoded) ||
    181           OPENSSL_memcmp(out, t->decoded, len) != 0) {
    182         fprintf(stderr, "decode(\"%s\") = \"%.*s\", want \"%s\"\n",
    183                 encoded.c_str(), (int)len, (const char*)out, t->decoded);
    184         return false;
    185       }
    186     }
    187   }
    188 
    189   return true;
    190 }
    191 
    192 static bool TestDecodeBlock() {
    193   for (unsigned i = 0; i < kNumTests; i++) {
    194     const TestVector *t = &kTestVectors[i];
    195     if (t->relation != canonical) {
    196       continue;
    197     }
    198 
    199     std::string encoded(RemoveNewlines(t->encoded));
    200 
    201     std::vector<uint8_t> out_vec(encoded.size());
    202     uint8_t *out = out_vec.data();
    203 
    204     // Test that the padding behavior of the deprecated API is preserved.
    205     int ret =
    206         EVP_DecodeBlock(out, (const uint8_t *)encoded.data(), encoded.size());
    207     if (ret < 0) {
    208       fprintf(stderr, "EVP_DecodeBlock(\"%s\") failed\n", t->encoded);
    209       return false;
    210     }
    211     if (ret % 3 != 0) {
    212       fprintf(stderr, "EVP_DecodeBlock did not ignore padding\n");
    213       return false;
    214     }
    215     size_t expected_len = strlen(t->decoded);
    216     if (expected_len % 3 != 0) {
    217       ret -= 3 - (expected_len % 3);
    218     }
    219     if (static_cast<size_t>(ret) != strlen(t->decoded) ||
    220         OPENSSL_memcmp(out, t->decoded, ret) != 0) {
    221       fprintf(stderr, "decode(\"%s\") = \"%.*s\", want \"%s\"\n",
    222               t->encoded, ret, (const char*)out, t->decoded);
    223       return false;
    224     }
    225   }
    226 
    227   return true;
    228 }
    229 
    230 static bool TestEncodeDecode() {
    231   for (unsigned test_num = 0; test_num < kNumTests; test_num++) {
    232     const TestVector *t = &kTestVectors[test_num];
    233 
    234     EVP_ENCODE_CTX ctx;
    235     const size_t decoded_len = strlen(t->decoded);
    236 
    237     if (t->relation == canonical) {
    238       size_t max_encoded_len;
    239       if (!EVP_EncodedLength(&max_encoded_len, decoded_len)) {
    240         fprintf(stderr, "#%u: EVP_EncodedLength failed\n", test_num);
    241         return false;
    242       }
    243 
    244       // EVP_EncodeUpdate will output new lines every 64 bytes of output so we
    245       // need slightly more than |EVP_EncodedLength| returns. */
    246       max_encoded_len += (max_encoded_len + 63) >> 6;
    247       std::vector<uint8_t> out_vec(max_encoded_len);
    248       uint8_t *out = out_vec.data();
    249 
    250       EVP_EncodeInit(&ctx);
    251 
    252       int out_len;
    253       EVP_EncodeUpdate(&ctx, out, &out_len,
    254                        reinterpret_cast<const uint8_t *>(t->decoded),
    255                        decoded_len);
    256       size_t total = out_len;
    257 
    258       EVP_EncodeFinal(&ctx, out + total, &out_len);
    259       total += out_len;
    260 
    261       if (total != strlen(t->encoded) ||
    262           OPENSSL_memcmp(out, t->encoded, total) != 0) {
    263         fprintf(stderr, "#%u: EVP_EncodeUpdate produced different output: '%s' (%u)\n",
    264                 test_num, out, static_cast<unsigned>(total));
    265         return false;
    266       }
    267     }
    268 
    269     std::vector<uint8_t> out_vec(strlen(t->encoded));
    270     uint8_t *out = out_vec.data();
    271 
    272     EVP_DecodeInit(&ctx);
    273     int out_len;
    274     size_t total = 0;
    275     int ret = EVP_DecodeUpdate(&ctx, out, &out_len,
    276                                reinterpret_cast<const uint8_t *>(t->encoded),
    277                                strlen(t->encoded));
    278     if (ret != -1) {
    279       total = out_len;
    280       ret = EVP_DecodeFinal(&ctx, out + total, &out_len);
    281       total += out_len;
    282     }
    283 
    284     switch (t->relation) {
    285       case canonical:
    286       case valid:
    287         if (ret == -1) {
    288           fprintf(stderr, "#%u: EVP_DecodeUpdate failed\n", test_num);
    289           return false;
    290         }
    291         if (total != decoded_len ||
    292             OPENSSL_memcmp(out, t->decoded, decoded_len)) {
    293           fprintf(stderr, "#%u: EVP_DecodeUpdate produced incorrect output\n",
    294                   test_num);
    295           return false;
    296         }
    297         break;
    298 
    299       case invalid:
    300         if (ret != -1) {
    301           fprintf(stderr, "#%u: EVP_DecodeUpdate was successful but shouldn't have been\n", test_num);
    302           return false;
    303         }
    304         break;
    305     }
    306   }
    307 
    308   return true;
    309 }
    310 
    311 static bool TestDecodeUpdateStreaming() {
    312   for (unsigned test_num = 0; test_num < kNumTests; test_num++) {
    313     const TestVector *t = &kTestVectors[test_num];
    314     if (t->relation == invalid) {
    315       continue;
    316     }
    317 
    318     const size_t encoded_len = strlen(t->encoded);
    319 
    320     std::vector<uint8_t> out(encoded_len);
    321 
    322     for (size_t chunk_size = 1; chunk_size <= encoded_len; chunk_size++) {
    323       size_t out_len = 0;
    324       EVP_ENCODE_CTX ctx;
    325       EVP_DecodeInit(&ctx);
    326 
    327       for (size_t i = 0; i < encoded_len;) {
    328         size_t todo = encoded_len - i;
    329         if (todo > chunk_size) {
    330           todo = chunk_size;
    331         }
    332 
    333         int bytes_written;
    334         int ret = EVP_DecodeUpdate(
    335             &ctx, out.data() + out_len, &bytes_written,
    336             reinterpret_cast<const uint8_t *>(t->encoded + i), todo);
    337         i += todo;
    338 
    339         switch (ret) {
    340           case -1:
    341             fprintf(stderr, "#%u: EVP_DecodeUpdate returned error\n", test_num);
    342             return 0;
    343           case 0:
    344             out_len += bytes_written;
    345             if (i == encoded_len ||
    346                 (i + 1 == encoded_len && t->encoded[i] == '\n') ||
    347                 /* If there was an '-' in the input (which means EOF) then
    348                  * this loop will continue to test that |EVP_DecodeUpdate| will
    349                  * ignore the remainder of the input. */
    350                 strchr(t->encoded, '-') != nullptr) {
    351               break;
    352             }
    353 
    354             fprintf(stderr,
    355                     "#%u: EVP_DecodeUpdate returned zero before end of "
    356                     "encoded data\n",
    357                     test_num);
    358             return 0;
    359           default:
    360             out_len += bytes_written;
    361         }
    362       }
    363 
    364       int bytes_written;
    365       int ret = EVP_DecodeFinal(&ctx, out.data() + out_len, &bytes_written);
    366       if (ret == -1) {
    367         fprintf(stderr, "#%u: EVP_DecodeFinal returned error\n", test_num);
    368         return 0;
    369       }
    370       out_len += bytes_written;
    371 
    372       if (out_len != strlen(t->decoded) ||
    373           OPENSSL_memcmp(out.data(), t->decoded, out_len) != 0) {
    374         fprintf(stderr, "#%u: incorrect output\n", test_num);
    375         return 0;
    376       }
    377     }
    378   }
    379 
    380   return true;
    381 }
    382 
    383 int main(void) {
    384   CRYPTO_library_init();
    385 
    386   if (!TestEncodeBlock() ||
    387       !TestDecodeBase64() ||
    388       !TestDecodeBlock() ||
    389       !TestDecodeUpdateStreaming() ||
    390       !TestEncodeDecode()) {
    391     return 1;
    392   }
    393 
    394   printf("PASS\n");
    395   return 0;
    396 }
    397