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