Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(246)

Side by Side Diff: components/gcm_driver/crypto/encryption_header_parsers.cc

Issue 1509683002: Convert the encryption header parsers to be iterator-based. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Convert the encryption header parsers to be iterator-based. Created 4 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "components/gcm_driver/crypto/encryption_header_parsers.h" 5 #include "components/gcm_driver/crypto/encryption_header_parsers.h"
6 6
7 #include "base/base64url.h" 7 #include "base/base64url.h"
8 #include "base/strings/string_number_conversions.h" 8 #include "base/strings/string_number_conversions.h"
9 #include "base/strings/string_piece.h" 9
10 #include "base/strings/string_util.h" 10 #include "base/strings/string_util.h"
11 #include "net/http/http_util.h" 11
12 12
13 namespace gcm { 13 namespace gcm {
14 14
15 namespace { 15 namespace {
16 16
17 // The default record size in bytes, as defined in section two of 17 // The default record size in bytes, as defined in section two of
18 // https://tools.ietf.org/html/draft-thomson-http-encryption-02. 18 // https://tools.ietf.org/html/draft-thomson-http-encryption.
19 const uint64_t kDefaultRecordSizeBytes = 4096; 19 const uint64_t kDefaultRecordSizeBytes = 4096;
20 20
21 // Decodes the string between |begin| and |end| using base64url, and writes the 21 // Decodes the string in |value| using base64url and writes the decoded value to
22 // decoded value to |*salt|. Returns whether the string could be decoded. 22 // |*salt|. Returns whether the string is not empty and could be decoded.
23 bool ValueToDecodedString(const std::string::const_iterator& begin, 23 bool ValueToDecodedString(base::StringPiece value, std::string* salt) {
24 const std::string::const_iterator& end,
25 std::string* salt) {
26 const base::StringPiece value(begin, end);
27 if (value.empty()) 24 if (value.empty())
28 return false; 25 return false;
29 26
30 return base::Base64UrlDecode( 27 return base::Base64UrlDecode(
31 value, base::Base64UrlDecodePolicy::IGNORE_PADDING, salt); 28 value, base::Base64UrlDecodePolicy::IGNORE_PADDING, salt);
32 } 29 }
33 30
34 // Parses the record size between |begin| and |end|, and writes the value to 31 // Parses the record size in |value| and writes the value to |*rs|. The value
35 // |*rs|. The value must be an unsigned, 64-bit integer greater than zero that 32 // must be a positive decimal integer greater than one that does not start
36 // does not start with a plus. Returns whether the record size was valid. 33 // with a plus. Returns whether the record size was valid.
37 bool RecordSizeToInt(const std::string::const_iterator& begin, 34 bool RecordSizeToInt(base::StringPiece value, uint64_t* rs) {
38 const std::string::const_iterator& end,
39 uint64_t* rs) {
40 const base::StringPiece value(begin, end);
41 if (value.empty()) 35 if (value.empty())
42 return false; 36 return false;
43 37
44 // Parsing the "rs" parameter uses stricter semantics than parsing rules for 38 // Reject a leading plus, as the fact that the value must be positive is
45 // normal integers, in that we want to reject values such as "+5" for 39 // dictated by the specification.
46 // compatibility with UAs that use other number parsing mechanisms.
47 if (value[0] == '+') 40 if (value[0] == '+')
48 return false; 41 return false;
49 42
50 if (!base::StringToUint64(value, rs)) 43 uint64_t candidate_rs;
44 if (!base::StringToUint64(value, &candidate_rs))
51 return false; 45 return false;
52 46
53 // The record size MUST be greater than 1. 47 // The record size MUST be greater than one byte.
54 return *rs > 1; 48 if (candidate_rs <= 1)
49 return false;
50
51 *rs = candidate_rs;
52 return true;
55 } 53 }
56 54
57 // Parses the string between |input_begin| and |input_end| according to the 55 } // namespace
58 // extended ABNF syntax for the Encryption HTTP header, per the "parameter" 56
59 // rule from RFC 7231 (https://tools.ietf.org/html/rfc7231). 57 EncryptionHeaderIterator::EncryptionHeaderIterator(
60 // 58 std::string::const_iterator header_begin,
61 // encryption_params = [ parameter *( ";" parameter ) ] 59 std::string::const_iterator header_end)
62 // 60 : iterator_(header_begin, header_end, ','),
63 // This implementation applies the parameters defined in section 3.1 of the 61 rs_(kDefaultRecordSizeBytes) {}
64 // HTTP encryption encoding document: 62
65 // 63 EncryptionHeaderIterator::~EncryptionHeaderIterator() {}
66 // https://tools.ietf.org/html/draft-thomson-http-encryption-02#section-3.1 64
67 // 65 bool EncryptionHeaderIterator::GetNext() {
68 // This means that the three supported parameters are: 66 keyid_.clear();
69 // 67 salt_.clear();
70 // [ "keyid" "=" string ] 68 rs_ = kDefaultRecordSizeBytes;
71 // [ ";" "salt" "=" base64url ] 69
72 // [ ";" "rs" "=" octet-count ] 70 if (!iterator_.GetNext())
73 bool ParseEncryptionHeaderValuesImpl(std::string::const_iterator input_begin, 71 return false;
74 std::string::const_iterator input_end, 72
75 EncryptionHeaderValues* values) {
76 net::HttpUtil::NameValuePairsIterator name_value_pairs( 73 net::HttpUtil::NameValuePairsIterator name_value_pairs(
77 input_begin, input_end, ';', 74 iterator_.value_begin(), iterator_.value_end(), ';',
78 net::HttpUtil::NameValuePairsIterator::Values::REQUIRED, 75 net::HttpUtil::NameValuePairsIterator::Values::REQUIRED,
79 net::HttpUtil::NameValuePairsIterator::Quotes::NOT_STRICT); 76 net::HttpUtil::NameValuePairsIterator::Quotes::NOT_STRICT);
80 77
81 while (name_value_pairs.GetNext()) { 78 while (name_value_pairs.GetNext()) {
82 const base::StringPiece name(name_value_pairs.name_begin(), 79 const base::StringPiece name(name_value_pairs.name_begin(),
83 name_value_pairs.name_end()); 80 name_value_pairs.name_end());
81 const base::StringPiece value(name_value_pairs.value_begin(),
82 name_value_pairs.value_end());
84 83
85 if (base::LowerCaseEqualsASCII(name, "keyid")) { 84 if (base::LowerCaseEqualsASCII(name, "keyid")) {
86 values->keyid.assign(name_value_pairs.value_begin(), 85 value.CopyToString(&keyid_);
87 name_value_pairs.value_end());
88 } else if (base::LowerCaseEqualsASCII(name, "salt")) { 86 } else if (base::LowerCaseEqualsASCII(name, "salt")) {
89 if (!ValueToDecodedString(name_value_pairs.value_begin(), 87 if (!ValueToDecodedString(value, &salt_))
90 name_value_pairs.value_end(), &values->salt)) {
91 return false; 88 return false;
92 }
93 } else if (base::LowerCaseEqualsASCII(name, "rs")) { 89 } else if (base::LowerCaseEqualsASCII(name, "rs")) {
94 if (!RecordSizeToInt(name_value_pairs.value_begin(), 90 if (!RecordSizeToInt(value, &rs_))
95 name_value_pairs.value_end(), &values->rs)) {
96 return false; 91 return false;
97 }
98 } else { 92 } else {
99 // Silently ignore unknown directives for forward compatibility. 93 // Silently ignore unknown directives for forward compatibility.
100 } 94 }
101 } 95 }
102 96
103 return name_value_pairs.valid(); 97 return name_value_pairs.valid();
104 } 98 }
105 99
106 // Parses the string between |input_begin| and |input_end| according to the 100 CryptoKeyHeaderIterator::CryptoKeyHeaderIterator(
107 // extended ABNF syntax for the Crypto-Key HTTP header, per the "parameter" rule 101 std::string::const_iterator header_begin,
108 // from RFC 7231 (https://tools.ietf.org/html/rfc7231). 102 std::string::const_iterator header_end)
109 // 103 : iterator_(header_begin, header_end, ',') {}
110 // encryption_params = [ parameter *( ";" parameter ) ] 104
111 // 105 CryptoKeyHeaderIterator::~CryptoKeyHeaderIterator() {}
112 // This implementation applies the parameters defined in section 4 of the 106
113 // HTTP encryption encoding document: 107 bool CryptoKeyHeaderIterator::GetNext() {
114 // 108 keyid_.clear();
115 //https://tools.ietf.org/html/draft-thomson-http-encryption-02#section-4 109 aesgcm128_.clear();
116 // 110 dh_.clear();
117 // This means that the three supported parameters are: 111
118 // 112 if (!iterator_.GetNext())
119 // [ "keyid" "=" string ] 113 return false;
120 // [ ";" "aesgcm128" "=" base64url ] 114
121 // [ ";" "dh" "=" base64url ]
122 bool ParseCryptoKeyHeaderValuesImpl(std::string::const_iterator input_begin,
123 std::string::const_iterator input_end,
124 CryptoKeyHeaderValues* values) {
125 net::HttpUtil::NameValuePairsIterator name_value_pairs( 115 net::HttpUtil::NameValuePairsIterator name_value_pairs(
126 input_begin, input_end, ';', 116 iterator_.value_begin(), iterator_.value_end(), ';',
127 net::HttpUtil::NameValuePairsIterator::Values::REQUIRED, 117 net::HttpUtil::NameValuePairsIterator::Values::REQUIRED,
128 net::HttpUtil::NameValuePairsIterator::Quotes::NOT_STRICT); 118 net::HttpUtil::NameValuePairsIterator::Quotes::NOT_STRICT);
129 119
130 while (name_value_pairs.GetNext()) { 120 while (name_value_pairs.GetNext()) {
131 const base::StringPiece name(name_value_pairs.name_begin(), 121 const base::StringPiece name(name_value_pairs.name_begin(),
132 name_value_pairs.name_end()); 122 name_value_pairs.name_end());
123 const base::StringPiece value(name_value_pairs.value_begin(),
124 name_value_pairs.value_end());
133 125
134 if (base::LowerCaseEqualsASCII(name, "keyid")) { 126 if (base::LowerCaseEqualsASCII(name, "keyid")) {
135 values->keyid.assign(name_value_pairs.value_begin(), 127 value.CopyToString(&keyid_);
136 name_value_pairs.value_end());
137 } else if (base::LowerCaseEqualsASCII(name, "aesgcm128")) { 128 } else if (base::LowerCaseEqualsASCII(name, "aesgcm128")) {
138 if (!ValueToDecodedString(name_value_pairs.value_begin(), 129 if (!ValueToDecodedString(value, &aesgcm128_))
139 name_value_pairs.value_end(),
140 &values->aesgcm128)) {
141 return false; 130 return false;
142 }
143 } else if (base::LowerCaseEqualsASCII(name, "dh")) { 131 } else if (base::LowerCaseEqualsASCII(name, "dh")) {
144 if (!ValueToDecodedString(name_value_pairs.value_begin(), 132 if (!ValueToDecodedString(value, &dh_))
145 name_value_pairs.value_end(), &values->dh)) {
146 return false; 133 return false;
147 }
148 } else { 134 } else {
149 // Silently ignore unknown directives for forward compatibility. 135 // Silently ignore unknown directives for forward compatibility.
150 } 136 }
151 } 137 }
152 138
153 return name_value_pairs.valid(); 139 return name_value_pairs.valid();
154 } 140 }
155 141
156 } // namespace
157
158 bool ParseEncryptionHeader(const std::string& input,
159 std::vector<EncryptionHeaderValues>* values) {
160 DCHECK(values);
161
162 std::vector<EncryptionHeaderValues> candidate_values;
163
164 net::HttpUtil::ValuesIterator value_iterator(input.begin(), input.end(), ',');
165 while (value_iterator.GetNext()) {
166 EncryptionHeaderValues candidate_value;
167 candidate_value.rs = kDefaultRecordSizeBytes;
168
169 if (!ParseEncryptionHeaderValuesImpl(value_iterator.value_begin(),
170 value_iterator.value_end(),
171 &candidate_value)) {
172 return false;
173 }
174
175 candidate_values.push_back(candidate_value);
176 }
177
178 values->swap(candidate_values);
179 return true;
180 }
181
182 bool ParseCryptoKeyHeader(const std::string& input,
183 std::vector<CryptoKeyHeaderValues>* values) {
184 DCHECK(values);
185
186 std::vector<CryptoKeyHeaderValues> candidate_values;
187
188 net::HttpUtil::ValuesIterator value_iterator(input.begin(), input.end(), ',');
189 while (value_iterator.GetNext()) {
190 CryptoKeyHeaderValues candidate_value;
191 if (!ParseCryptoKeyHeaderValuesImpl(value_iterator.value_begin(),
192 value_iterator.value_end(),
193 &candidate_value)) {
194 return false;
195 }
196
197 candidate_values.push_back(candidate_value);
198 }
199
200 values->swap(candidate_values);
201 return true;
202 }
203
204 } // namespace gcm 142 } // namespace gcm
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698