| Index: components/gcm_driver/crypto/encryption_header_parsers.cc
|
| diff --git a/components/gcm_driver/crypto/encryption_header_parsers.cc b/components/gcm_driver/crypto/encryption_header_parsers.cc
|
| index 1932527b9fefac8c389f27f7aedd87e2d8de97e6..4f199bd9f96939b7c65487fc9903f507f20fc70d 100644
|
| --- a/components/gcm_driver/crypto/encryption_header_parsers.cc
|
| +++ b/components/gcm_driver/crypto/encryption_header_parsers.cc
|
| @@ -6,24 +6,21 @@
|
|
|
| #include "base/base64url.h"
|
| #include "base/strings/string_number_conversions.h"
|
| -#include "base/strings/string_piece.h"
|
| +
|
| #include "base/strings/string_util.h"
|
| -#include "net/http/http_util.h"
|
| +
|
|
|
| namespace gcm {
|
|
|
| namespace {
|
|
|
| // The default record size in bytes, as defined in section two of
|
| -// https://tools.ietf.org/html/draft-thomson-http-encryption-02.
|
| +// https://tools.ietf.org/html/draft-thomson-http-encryption.
|
| const uint64_t kDefaultRecordSizeBytes = 4096;
|
|
|
| -// Decodes the string between |begin| and |end| using base64url, and writes the
|
| -// decoded value to |*salt|. Returns whether the string could be decoded.
|
| -bool ValueToDecodedString(const std::string::const_iterator& begin,
|
| - const std::string::const_iterator& end,
|
| - std::string* salt) {
|
| - const base::StringPiece value(begin, end);
|
| +// Decodes the string in |value| using base64url and writes the decoded value to
|
| +// |*salt|. Returns whether the string is not empty and could be decoded.
|
| +bool ValueToDecodedString(base::StringPiece value, std::string* salt) {
|
| if (value.empty())
|
| return false;
|
|
|
| @@ -31,70 +28,67 @@ bool ValueToDecodedString(const std::string::const_iterator& begin,
|
| value, base::Base64UrlDecodePolicy::IGNORE_PADDING, salt);
|
| }
|
|
|
| -// Parses the record size between |begin| and |end|, and writes the value to
|
| -// |*rs|. The value must be an unsigned, 64-bit integer greater than zero that
|
| -// does not start with a plus. Returns whether the record size was valid.
|
| -bool RecordSizeToInt(const std::string::const_iterator& begin,
|
| - const std::string::const_iterator& end,
|
| - uint64_t* rs) {
|
| - const base::StringPiece value(begin, end);
|
| +// Parses the record size in |value| and writes the value to |*rs|. The value
|
| +// must be a positive decimal integer greater than one that does not start
|
| +// with a plus. Returns whether the record size was valid.
|
| +bool RecordSizeToInt(base::StringPiece value, uint64_t* rs) {
|
| if (value.empty())
|
| return false;
|
|
|
| - // Parsing the "rs" parameter uses stricter semantics than parsing rules for
|
| - // normal integers, in that we want to reject values such as "+5" for
|
| - // compatibility with UAs that use other number parsing mechanisms.
|
| + // Reject a leading plus, as the fact that the value must be positive is
|
| + // dictated by the specification.
|
| if (value[0] == '+')
|
| return false;
|
|
|
| - if (!base::StringToUint64(value, rs))
|
| + uint64_t candidate_rs;
|
| + if (!base::StringToUint64(value, &candidate_rs))
|
| return false;
|
|
|
| - // The record size MUST be greater than 1.
|
| - return *rs > 1;
|
| + // The record size MUST be greater than one byte.
|
| + if (candidate_rs <= 1)
|
| + return false;
|
| +
|
| + *rs = candidate_rs;
|
| + return true;
|
| }
|
|
|
| -// Parses the string between |input_begin| and |input_end| according to the
|
| -// extended ABNF syntax for the Encryption HTTP header, per the "parameter"
|
| -// rule from RFC 7231 (https://tools.ietf.org/html/rfc7231).
|
| -//
|
| -// encryption_params = [ parameter *( ";" parameter ) ]
|
| -//
|
| -// This implementation applies the parameters defined in section 3.1 of the
|
| -// HTTP encryption encoding document:
|
| -//
|
| -// https://tools.ietf.org/html/draft-thomson-http-encryption-02#section-3.1
|
| -//
|
| -// This means that the three supported parameters are:
|
| -//
|
| -// [ "keyid" "=" string ]
|
| -// [ ";" "salt" "=" base64url ]
|
| -// [ ";" "rs" "=" octet-count ]
|
| -bool ParseEncryptionHeaderValuesImpl(std::string::const_iterator input_begin,
|
| - std::string::const_iterator input_end,
|
| - EncryptionHeaderValues* values) {
|
| +} // namespace
|
| +
|
| +EncryptionHeaderIterator::EncryptionHeaderIterator(
|
| + std::string::const_iterator header_begin,
|
| + std::string::const_iterator header_end)
|
| + : iterator_(header_begin, header_end, ','),
|
| + rs_(kDefaultRecordSizeBytes) {}
|
| +
|
| +EncryptionHeaderIterator::~EncryptionHeaderIterator() {}
|
| +
|
| +bool EncryptionHeaderIterator::GetNext() {
|
| + keyid_.clear();
|
| + salt_.clear();
|
| + rs_ = kDefaultRecordSizeBytes;
|
| +
|
| + if (!iterator_.GetNext())
|
| + return false;
|
| +
|
| net::HttpUtil::NameValuePairsIterator name_value_pairs(
|
| - input_begin, input_end, ';',
|
| + iterator_.value_begin(), iterator_.value_end(), ';',
|
| net::HttpUtil::NameValuePairsIterator::Values::REQUIRED,
|
| net::HttpUtil::NameValuePairsIterator::Quotes::NOT_STRICT);
|
|
|
| while (name_value_pairs.GetNext()) {
|
| const base::StringPiece name(name_value_pairs.name_begin(),
|
| name_value_pairs.name_end());
|
| + const base::StringPiece value(name_value_pairs.value_begin(),
|
| + name_value_pairs.value_end());
|
|
|
| if (base::LowerCaseEqualsASCII(name, "keyid")) {
|
| - values->keyid.assign(name_value_pairs.value_begin(),
|
| - name_value_pairs.value_end());
|
| + value.CopyToString(&keyid_);
|
| } else if (base::LowerCaseEqualsASCII(name, "salt")) {
|
| - if (!ValueToDecodedString(name_value_pairs.value_begin(),
|
| - name_value_pairs.value_end(), &values->salt)) {
|
| + if (!ValueToDecodedString(value, &salt_))
|
| return false;
|
| - }
|
| } else if (base::LowerCaseEqualsASCII(name, "rs")) {
|
| - if (!RecordSizeToInt(name_value_pairs.value_begin(),
|
| - name_value_pairs.value_end(), &values->rs)) {
|
| + if (!RecordSizeToInt(value, &rs_))
|
| return false;
|
| - }
|
| } else {
|
| // Silently ignore unknown directives for forward compatibility.
|
| }
|
| @@ -103,48 +97,40 @@ bool ParseEncryptionHeaderValuesImpl(std::string::const_iterator input_begin,
|
| return name_value_pairs.valid();
|
| }
|
|
|
| -// Parses the string between |input_begin| and |input_end| according to the
|
| -// extended ABNF syntax for the Crypto-Key HTTP header, per the "parameter" rule
|
| -// from RFC 7231 (https://tools.ietf.org/html/rfc7231).
|
| -//
|
| -// encryption_params = [ parameter *( ";" parameter ) ]
|
| -//
|
| -// This implementation applies the parameters defined in section 4 of the
|
| -// HTTP encryption encoding document:
|
| -//
|
| -//https://tools.ietf.org/html/draft-thomson-http-encryption-02#section-4
|
| -//
|
| -// This means that the three supported parameters are:
|
| -//
|
| -// [ "keyid" "=" string ]
|
| -// [ ";" "aesgcm128" "=" base64url ]
|
| -// [ ";" "dh" "=" base64url ]
|
| -bool ParseCryptoKeyHeaderValuesImpl(std::string::const_iterator input_begin,
|
| - std::string::const_iterator input_end,
|
| - CryptoKeyHeaderValues* values) {
|
| +CryptoKeyHeaderIterator::CryptoKeyHeaderIterator(
|
| + std::string::const_iterator header_begin,
|
| + std::string::const_iterator header_end)
|
| + : iterator_(header_begin, header_end, ',') {}
|
| +
|
| +CryptoKeyHeaderIterator::~CryptoKeyHeaderIterator() {}
|
| +
|
| +bool CryptoKeyHeaderIterator::GetNext() {
|
| + keyid_.clear();
|
| + aesgcm128_.clear();
|
| + dh_.clear();
|
| +
|
| + if (!iterator_.GetNext())
|
| + return false;
|
| +
|
| net::HttpUtil::NameValuePairsIterator name_value_pairs(
|
| - input_begin, input_end, ';',
|
| + iterator_.value_begin(), iterator_.value_end(), ';',
|
| net::HttpUtil::NameValuePairsIterator::Values::REQUIRED,
|
| net::HttpUtil::NameValuePairsIterator::Quotes::NOT_STRICT);
|
|
|
| while (name_value_pairs.GetNext()) {
|
| const base::StringPiece name(name_value_pairs.name_begin(),
|
| name_value_pairs.name_end());
|
| + const base::StringPiece value(name_value_pairs.value_begin(),
|
| + name_value_pairs.value_end());
|
|
|
| if (base::LowerCaseEqualsASCII(name, "keyid")) {
|
| - values->keyid.assign(name_value_pairs.value_begin(),
|
| - name_value_pairs.value_end());
|
| + value.CopyToString(&keyid_);
|
| } else if (base::LowerCaseEqualsASCII(name, "aesgcm128")) {
|
| - if (!ValueToDecodedString(name_value_pairs.value_begin(),
|
| - name_value_pairs.value_end(),
|
| - &values->aesgcm128)) {
|
| + if (!ValueToDecodedString(value, &aesgcm128_))
|
| return false;
|
| - }
|
| } else if (base::LowerCaseEqualsASCII(name, "dh")) {
|
| - if (!ValueToDecodedString(name_value_pairs.value_begin(),
|
| - name_value_pairs.value_end(), &values->dh)) {
|
| + if (!ValueToDecodedString(value, &dh_))
|
| return false;
|
| - }
|
| } else {
|
| // Silently ignore unknown directives for forward compatibility.
|
| }
|
| @@ -153,52 +139,4 @@ bool ParseCryptoKeyHeaderValuesImpl(std::string::const_iterator input_begin,
|
| return name_value_pairs.valid();
|
| }
|
|
|
| -} // namespace
|
| -
|
| -bool ParseEncryptionHeader(const std::string& input,
|
| - std::vector<EncryptionHeaderValues>* values) {
|
| - DCHECK(values);
|
| -
|
| - std::vector<EncryptionHeaderValues> candidate_values;
|
| -
|
| - net::HttpUtil::ValuesIterator value_iterator(input.begin(), input.end(), ',');
|
| - while (value_iterator.GetNext()) {
|
| - EncryptionHeaderValues candidate_value;
|
| - candidate_value.rs = kDefaultRecordSizeBytes;
|
| -
|
| - if (!ParseEncryptionHeaderValuesImpl(value_iterator.value_begin(),
|
| - value_iterator.value_end(),
|
| - &candidate_value)) {
|
| - return false;
|
| - }
|
| -
|
| - candidate_values.push_back(candidate_value);
|
| - }
|
| -
|
| - values->swap(candidate_values);
|
| - return true;
|
| -}
|
| -
|
| -bool ParseCryptoKeyHeader(const std::string& input,
|
| - std::vector<CryptoKeyHeaderValues>* values) {
|
| - DCHECK(values);
|
| -
|
| - std::vector<CryptoKeyHeaderValues> candidate_values;
|
| -
|
| - net::HttpUtil::ValuesIterator value_iterator(input.begin(), input.end(), ',');
|
| - while (value_iterator.GetNext()) {
|
| - CryptoKeyHeaderValues candidate_value;
|
| - if (!ParseCryptoKeyHeaderValuesImpl(value_iterator.value_begin(),
|
| - value_iterator.value_end(),
|
| - &candidate_value)) {
|
| - return false;
|
| - }
|
| -
|
| - candidate_values.push_back(candidate_value);
|
| - }
|
| -
|
| - values->swap(candidate_values);
|
| - return true;
|
| -}
|
| -
|
| } // namespace gcm
|
|
|