OLD | NEW |
---|---|
(Empty) | |
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 | |
3 // found in the LICENSE file. | |
4 | |
5 #include "components/gcm_driver/crypto/encryption_header_parsers.h" | |
6 | |
7 #include "base/base64.h" | |
8 #include "base/strings/string_number_conversions.h" | |
9 #include "base/strings/string_piece.h" | |
10 #include "base/strings/string_util.h" | |
11 #include "net/http/http_util.h" | |
12 | |
13 namespace gcm { | |
14 | |
15 namespace { | |
16 | |
17 // The default record size in bytes, as defined in section two of | |
18 // https://tools.ietf.org/html/draft-thomson-http-encryption-01. | |
19 const int64_t kDefaultRecordSizeBytes = 4096; | |
eroman
2015/09/25 18:18:19
uint64_t
Peter Beverloo
2015/09/28 11:27:15
Done.
| |
20 | |
21 bool Base64URLDecode(const base::StringPiece& input, std::string* output) { | |
eroman
2015/09/25 18:18:19
There are already several duplications of base64ur
Peter Beverloo
2015/09/28 11:27:15
Certainly agreed. I filed https://crbug.com/536745
eroman
2015/09/28 16:25:29
sgtm
| |
22 size_t padded_size = | |
23 input.size() % 4 ? input.size() + 4 - (input.size() % 4) : input.size(); | |
24 | |
25 // Add padding to |input|. | |
26 std::string padded_input(input.begin(), input.end()); | |
27 padded_input.resize(padded_size, '='); | |
28 | |
29 // Convert to standard base64 alphabet. | |
eroman
2015/09/25 18:18:19
It looks like this was copied from GCMNetworkChann
Peter Beverloo
2015/09/28 11:27:15
Yes, and I now mixed in parts from components/prox
| |
30 base::ReplaceChars(padded_input, "-", "+", &padded_input); | |
31 base::ReplaceChars(padded_input, "_", "/", &padded_input); | |
eroman
2015/09/25 18:18:19
This parsing is too permissive, in that it will al
Peter Beverloo
2015/09/28 11:27:15
I've included a check that the characters "/" and
| |
32 | |
33 return base::Base64Decode(padded_input, output); | |
34 } | |
35 | |
36 bool ValueToDecodedString(const std::string::const_iterator& begin, | |
37 const std::string::const_iterator& end, | |
38 std::string* salt) { | |
39 const base::StringPiece value(begin, end); | |
40 if (value.empty()) | |
41 return false; | |
42 | |
43 return Base64URLDecode(value, salt); | |
44 } | |
45 | |
46 bool RecordSizeToInt(const std::string::const_iterator& begin, | |
47 const std::string::const_iterator& end, | |
48 int64_t* rs) { | |
49 const base::StringPiece value(begin, end); | |
50 if (value.empty()) | |
51 return false; | |
52 | |
53 if (!base::StringToInt64(value, rs)) | |
eroman
2015/09/25 18:18:19
why not use a uint64 and StringToUint64() since ne
Peter Beverloo
2015/09/28 11:27:15
Done.
| |
54 return false; | |
55 | |
56 // The record size MUST be greater than 1. | |
57 return *rs > 1; | |
58 } | |
59 | |
60 bool ParseEncryptionHeaderImpl(const std::string& input, | |
61 std::string* keyid, | |
62 std::string* salt, | |
63 int64_t* rs) { | |
64 net::HttpUtil::NameValuePairsIterator name_value_pairs( | |
65 input.begin(), input.end(), ';', | |
66 net::HttpUtil::NameValuePairsIterator::VALUES_NOT_OPTIONAL); | |
67 | |
68 while (name_value_pairs.GetNext()) { | |
69 const base::StringPiece name(name_value_pairs.name_begin(), | |
70 name_value_pairs.name_end()); | |
71 | |
72 if (base::LowerCaseEqualsASCII(name, "keyid")) { | |
73 keyid->assign(name_value_pairs.value_begin(), | |
74 name_value_pairs.value_end()); | |
75 } else if (base::LowerCaseEqualsASCII(name, "salt")) { | |
76 if (!ValueToDecodedString(name_value_pairs.value_begin(), | |
77 name_value_pairs.value_end(), salt)) { | |
78 return false; | |
79 } | |
80 } else if (base::LowerCaseEqualsASCII(name, "rs")) { | |
81 if (!RecordSizeToInt(name_value_pairs.value_begin(), | |
82 name_value_pairs.value_end(), rs)) { | |
83 return false; | |
84 } | |
85 } else { | |
86 // Silently ignore unknown directives for forward compatibility. | |
87 } | |
88 } | |
89 | |
90 return name_value_pairs.valid(); | |
91 } | |
92 | |
93 bool ParseEncryptionKeyHeaderImpl(const std::string& input, | |
94 std::string* keyid, | |
95 std::string* key, | |
96 std::string* dh) { | |
97 net::HttpUtil::NameValuePairsIterator name_value_pairs( | |
98 input.begin(), input.end(), ';', | |
99 net::HttpUtil::NameValuePairsIterator::VALUES_NOT_OPTIONAL); | |
100 | |
101 while (name_value_pairs.GetNext()) { | |
102 const base::StringPiece name(name_value_pairs.name_begin(), | |
103 name_value_pairs.name_end()); | |
104 | |
105 if (base::LowerCaseEqualsASCII(name, "keyid")) { | |
106 keyid->assign(name_value_pairs.value_begin(), | |
107 name_value_pairs.value_end()); | |
108 } else if (base::LowerCaseEqualsASCII(name, "key")) { | |
109 if (!ValueToDecodedString(name_value_pairs.value_begin(), | |
110 name_value_pairs.value_end(), key)) { | |
111 return false; | |
112 } | |
113 } else if (base::LowerCaseEqualsASCII(name, "dh")) { | |
114 if (!ValueToDecodedString(name_value_pairs.value_begin(), | |
115 name_value_pairs.value_end(), dh)) { | |
116 return false; | |
117 } | |
118 } else { | |
119 // Silently ignore unknown directives for forward compatibility. | |
120 } | |
121 } | |
122 | |
123 return name_value_pairs.valid(); | |
124 } | |
125 | |
126 } // namespace | |
127 | |
128 // "Encryption" ":" | |
129 // [ "keyid" "=" string ] | |
130 // [ ";" "salt" "=" base64url ] | |
131 // [ ";" "rs" "=" octet-count ] | |
132 bool ParseEncryptionHeader(const std::string& input, | |
133 std::string* keyid, | |
134 std::string* salt, | |
135 int64_t* rs) { | |
136 std::string candidate_keyid; | |
137 std::string candidate_salt; | |
138 int64_t candidate_rs = kDefaultRecordSizeBytes; | |
139 | |
140 if (!ParseEncryptionHeaderImpl(input, &candidate_keyid, &candidate_salt, | |
141 &candidate_rs)) { | |
142 return false; | |
143 } | |
144 | |
145 keyid->swap(candidate_keyid); | |
146 salt->swap(candidate_salt); | |
147 *rs = candidate_rs; | |
148 return true; | |
149 } | |
150 | |
151 // "Encryption-Key" ":" | |
152 // [ "keyid" "=" string ] | |
153 // [ ";" "key" "=" base64url ] | |
154 // [ ";" "dh" "=" base64url ] | |
155 bool ParseEncryptionKeyHeader(const std::string& input, | |
156 std::string* keyid, | |
157 std::string* key, | |
158 std::string* dh) { | |
159 std::string candidate_keyid; | |
160 std::string candidate_key; | |
161 std::string candidate_dh; | |
162 | |
163 if (!ParseEncryptionKeyHeaderImpl(input, &candidate_keyid, &candidate_key, | |
164 &candidate_dh)) { | |
165 return false; | |
166 } | |
167 | |
168 keyid->swap(candidate_keyid); | |
169 key->swap(candidate_key); | |
170 dh->swap(candidate_dh); | |
171 return true; | |
172 } | |
173 | |
174 } // namespace gcm | |
OLD | NEW |