Base64 decoding should handle lack of newlines in encoded string
If there are no new lines in the input string, it seems we have to set
the BIO_FLAGS_BASE64_NO_NL flag. Without this flag, BIO_read just
returns a decode string full of zeroes. So in this CL, we canonicalize
the input by stripping of all the newlines and then set this flag so
that decoding work for all cases.
Note: Currently the unit tests use a different library than what paygen
uses and happens to encode a string with newline (which is why the
previous code worked fine and we only found out this issue when paygen
code changes were done). Hence we canonicalize the input.
Work Item 34173 tracks adding a no-new-line variation to the unit tests
so that it tests both case.
BUG=chromium-os:35423
TEST=Unit Tests pass, tested end to end on ZGB.
Change-Id: Ieccb94c91feb5147ea19664e5a381e24cd5ff646
Reviewed-on: https://gerrit.chromium.org/gerrit/35857
Reviewed-by: Gilad Arnold <garnold@chromium.org>
Commit-Ready: Jay Srinivasan <jaysri@chromium.org>
Tested-by: Jay Srinivasan <jaysri@chromium.org>
diff --git a/omaha_hash_calculator.cc b/omaha_hash_calculator.cc
index 9fe82a2..33d8a9e 100644
--- a/omaha_hash_calculator.cc
+++ b/omaha_hash_calculator.cc
@@ -123,21 +123,34 @@
return success;
}
-bool OmahaHashCalculator::Base64Decode(const string& in,
+bool OmahaHashCalculator::Base64Decode(const string& raw_in,
vector<char>* out) {
+ out->clear();
+
ScopedBioHandle b64(BIO_new(BIO_f_base64()));
if (!b64.bio()) {
- LOG(ERROR) << "Unable to create BIO object to decode base64 hash.";
+ LOG(ERROR) << "Unable to create BIO object to decode base64 hash";
return false;
}
+ // Canonicalize the raw input to get rid of all newlines in the string
+ // and set the NO_NL flag so that BIO_read decodes properly. Otherwise
+ // BIO_read would just return 0 without decode anything.
+ string in;
+ for (size_t i = 0; i < raw_in.size(); i++)
+ if (raw_in[i] != '\n')
+ in.push_back(raw_in[i]);
+
+ BIO_set_flags(b64.bio(), BIO_FLAGS_BASE64_NO_NL);
+
BIO *bmem = BIO_new_mem_buf(const_cast<char*>(in.c_str()), in.size());
if (!bmem) {
- LOG(ERROR) << "Unable to get BIO buffer to decode base64 hash.";
+ LOG(ERROR) << "Unable to get BIO buffer to decode base64 hash";
return false;
}
b64.set_bio(BIO_push(b64.bio(), bmem));
+
const int kOutBufferSize = 1024;
char out_buffer[kOutBufferSize];
int num_bytes_read = 1; // any non-zero value is fine to enter the loop.
@@ -147,6 +160,8 @@
out->push_back(out_buffer[i]);
}
+ LOG(INFO) << "Decoded " << out->size()
+ << " bytes from " << in.size() << " base64-encoded bytes";
return true;
}
diff --git a/omaha_hash_calculator.h b/omaha_hash_calculator.h
index a9c59d4..bea3cc9 100644
--- a/omaha_hash_calculator.h
+++ b/omaha_hash_calculator.h
@@ -79,8 +79,9 @@
// Decodes given base64-encoded in string into the out vector. Since the
// output can have null characters, we're returning a byte vector instead of
- // a string.
- static bool Base64Decode(const std::string& in, std::vector<char>* out);
+ // a string. This method works fine even if |raw_in| has any newlines.
+ // Any existing contents of |out| will be erased.
+ static bool Base64Decode(const std::string& raw_in, std::vector<char>* out);
private:
// If non-empty, the final base64 encoded hash and the raw hash. Will only be