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

Side by Side Diff: chromeos/network/onc/onc_utils.cc

Issue 17471005: Move PEM certificate decoding to onc_utils. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Addressed comments. Created 7 years, 6 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 | Annotate | Revision Log
« no previous file with comments | « chromeos/network/onc/onc_utils.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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 "chromeos/network/onc/onc_utils.h" 5 #include "chromeos/network/onc/onc_utils.h"
6 6
7 #include "base/base64.h" 7 #include "base/base64.h"
8 #include "base/json/json_reader.h" 8 #include "base/json/json_reader.h"
9 #include "base/logging.h" 9 #include "base/logging.h"
10 #include "base/metrics/histogram.h" 10 #include "base/metrics/histogram.h"
11 #include "base/strings/string_util.h" 11 #include "base/strings/string_util.h"
12 #include "base/values.h" 12 #include "base/values.h"
13 #include "chromeos/network/network_event_log.h" 13 #include "chromeos/network/network_event_log.h"
14 #include "chromeos/network/onc/onc_mapper.h" 14 #include "chromeos/network/onc/onc_mapper.h"
15 #include "chromeos/network/onc/onc_signature.h" 15 #include "chromeos/network/onc/onc_signature.h"
16 #include "chromeos/network/onc/onc_utils.h" 16 #include "chromeos/network/onc/onc_utils.h"
17 #include "chromeos/network/onc/onc_validator.h" 17 #include "chromeos/network/onc/onc_validator.h"
18 #include "crypto/encryptor.h" 18 #include "crypto/encryptor.h"
19 #include "crypto/hmac.h" 19 #include "crypto/hmac.h"
20 #include "crypto/symmetric_key.h" 20 #include "crypto/symmetric_key.h"
21 #include "net/cert/pem_tokenizer.h"
21 22
22 #define ONC_LOG_WARNING(message) NET_LOG_WARNING("ONC", message) 23 #define ONC_LOG_WARNING(message) NET_LOG_WARNING("ONC", message)
23 #define ONC_LOG_ERROR(message) NET_LOG_ERROR("ONC", message) 24 #define ONC_LOG_ERROR(message) NET_LOG_ERROR("ONC", message)
24 25
25 namespace chromeos { 26 namespace chromeos {
26 namespace onc { 27 namespace onc {
27 28
28 namespace { 29 namespace {
29 30
30 const char kUnableToDecrypt[] = "Unable to decrypt encrypted ONC"; 31 const char kUnableToDecrypt[] = "Unable to decrypt encrypted ONC";
(...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after
172 void ExpandField(const std::string fieldname, 173 void ExpandField(const std::string fieldname,
173 const StringSubstitution& substitution, 174 const StringSubstitution& substitution,
174 base::DictionaryValue* onc_object) { 175 base::DictionaryValue* onc_object) {
175 std::string user_string; 176 std::string user_string;
176 if (!onc_object->GetStringWithoutPathExpansion(fieldname, &user_string)) 177 if (!onc_object->GetStringWithoutPathExpansion(fieldname, &user_string))
177 return; 178 return;
178 179
179 std::string login_id; 180 std::string login_id;
180 if (substitution.GetSubstitute(substitutes::kLoginIDField, &login_id)) { 181 if (substitution.GetSubstitute(substitutes::kLoginIDField, &login_id)) {
181 ReplaceSubstringsAfterOffset(&user_string, 0, 182 ReplaceSubstringsAfterOffset(&user_string, 0,
182 onc::substitutes::kLoginIDField, 183 substitutes::kLoginIDField,
183 login_id); 184 login_id);
184 } 185 }
185 186
186 std::string email; 187 std::string email;
187 if (substitution.GetSubstitute(substitutes::kEmailField, &email)) { 188 if (substitution.GetSubstitute(substitutes::kEmailField, &email)) {
188 ReplaceSubstringsAfterOffset(&user_string, 0, 189 ReplaceSubstringsAfterOffset(&user_string, 0,
189 onc::substitutes::kEmailField, 190 substitutes::kEmailField,
190 email); 191 email);
191 } 192 }
192 193
193 onc_object->SetStringWithoutPathExpansion(fieldname, user_string); 194 onc_object->SetStringWithoutPathExpansion(fieldname, user_string);
194 } 195 }
195 196
196 void ExpandStringsInOncObject( 197 void ExpandStringsInOncObject(
197 const OncValueSignature& signature, 198 const OncValueSignature& signature,
198 const StringSubstitution& substitution, 199 const StringSubstitution& substitution,
199 base::DictionaryValue* onc_object) { 200 base::DictionaryValue* onc_object) {
(...skipping 17 matching lines...) Expand all
217 if (!field_signature) 218 if (!field_signature)
218 continue; 219 continue;
219 220
220 ExpandStringsInOncObject(*field_signature->value_signature, 221 ExpandStringsInOncObject(*field_signature->value_signature,
221 substitution, inner_object); 222 substitution, inner_object);
222 } 223 }
223 } 224 }
224 225
225 namespace { 226 namespace {
226 227
227 class OncMaskValues : public onc::Mapper { 228 class OncMaskValues : public Mapper {
228 public: 229 public:
229 static scoped_ptr<base::DictionaryValue> Mask( 230 static scoped_ptr<base::DictionaryValue> Mask(
230 const onc::OncValueSignature& signature, 231 const OncValueSignature& signature,
231 const base::DictionaryValue& onc_object, 232 const base::DictionaryValue& onc_object,
232 const std::string& mask) { 233 const std::string& mask) {
233 OncMaskValues masker(mask); 234 OncMaskValues masker(mask);
234 bool unused_error; 235 bool unused_error;
235 return masker.MapObject(signature, onc_object, &unused_error); 236 return masker.MapObject(signature, onc_object, &unused_error);
236 } 237 }
237 238
238 protected: 239 protected:
239 explicit OncMaskValues(const std::string& mask) 240 explicit OncMaskValues(const std::string& mask)
240 : mask_(mask) { 241 : mask_(mask) {
241 } 242 }
242 243
243 virtual scoped_ptr<base::Value> MapField( 244 virtual scoped_ptr<base::Value> MapField(
244 const std::string& field_name, 245 const std::string& field_name,
245 const onc::OncValueSignature& object_signature, 246 const OncValueSignature& object_signature,
246 const base::Value& onc_value, 247 const base::Value& onc_value,
247 bool* found_unknown_field, 248 bool* found_unknown_field,
248 bool* error) OVERRIDE { 249 bool* error) OVERRIDE {
249 if (onc::FieldIsCredential(object_signature, field_name)) { 250 if (FieldIsCredential(object_signature, field_name)) {
250 return scoped_ptr<base::Value>(new base::StringValue(mask_)); 251 return scoped_ptr<base::Value>(new base::StringValue(mask_));
251 } else { 252 } else {
252 return onc::Mapper::MapField(field_name, object_signature, onc_value, 253 return Mapper::MapField(field_name, object_signature, onc_value,
253 found_unknown_field, error); 254 found_unknown_field, error);
254 } 255 }
255 } 256 }
256 257
257 // Mask to insert in place of the sensitive values. 258 // Mask to insert in place of the sensitive values.
258 std::string mask_; 259 std::string mask_;
259 }; 260 };
260 261
261 } // namespace 262 } // namespace
262 263
263 scoped_ptr<base::DictionaryValue> MaskCredentialsInOncObject( 264 scoped_ptr<base::DictionaryValue> MaskCredentialsInOncObject(
264 const onc::OncValueSignature& signature, 265 const OncValueSignature& signature,
265 const base::DictionaryValue& onc_object, 266 const base::DictionaryValue& onc_object,
266 const std::string& mask) { 267 const std::string& mask) {
267 return OncMaskValues::Mask(signature, onc_object, mask); 268 return OncMaskValues::Mask(signature, onc_object, mask);
268 } 269 }
269 270
270 bool ParseAndValidateOncForImport( 271 bool ParseAndValidateOncForImport(const std::string& onc_blob,
271 const std::string& onc_blob, 272 ONCSource onc_source,
272 chromeos::onc::ONCSource onc_source, 273 const std::string& passphrase,
273 const std::string& passphrase, 274 base::ListValue* network_configs,
274 base::ListValue* network_configs, 275 base::ListValue* certificates) {
275 base::ListValue* certificates) {
276 certificates->Clear(); 276 certificates->Clear();
277 network_configs->Clear(); 277 network_configs->Clear();
278 if (onc_blob.empty()) 278 if (onc_blob.empty())
279 return true; 279 return true;
280 280
281 scoped_ptr<base::DictionaryValue> toplevel_onc = 281 scoped_ptr<base::DictionaryValue> toplevel_onc =
282 onc::ReadDictionaryFromJson(onc_blob); 282 ReadDictionaryFromJson(onc_blob);
283 if (toplevel_onc.get() == NULL) { 283 if (toplevel_onc.get() == NULL) {
284 LOG(ERROR) << "ONC loaded from " << onc::GetSourceAsString(onc_source) 284 LOG(ERROR) << "ONC loaded from " << GetSourceAsString(onc_source)
285 << " is not a valid JSON dictionary."; 285 << " is not a valid JSON dictionary.";
286 return false; 286 return false;
287 } 287 }
288 288
289 // Check and see if this is an encrypted ONC file. If so, decrypt it. 289 // Check and see if this is an encrypted ONC file. If so, decrypt it.
290 std::string onc_type; 290 std::string onc_type;
291 toplevel_onc->GetStringWithoutPathExpansion(onc::toplevel_config::kType, 291 toplevel_onc->GetStringWithoutPathExpansion(toplevel_config::kType,
292 &onc_type); 292 &onc_type);
293 if (onc_type == onc::toplevel_config::kEncryptedConfiguration) { 293 if (onc_type == toplevel_config::kEncryptedConfiguration) {
294 toplevel_onc = onc::Decrypt(passphrase, *toplevel_onc); 294 toplevel_onc = Decrypt(passphrase, *toplevel_onc);
295 if (toplevel_onc.get() == NULL) { 295 if (toplevel_onc.get() == NULL) {
296 LOG(ERROR) << "Couldn't decrypt the ONC from " 296 LOG(ERROR) << "Couldn't decrypt the ONC from "
297 << onc::GetSourceAsString(onc_source); 297 << GetSourceAsString(onc_source);
298 return false; 298 return false;
299 } 299 }
300 } 300 }
301 301
302 bool from_policy = (onc_source == onc::ONC_SOURCE_USER_POLICY || 302 bool from_policy = (onc_source == ONC_SOURCE_USER_POLICY ||
303 onc_source == onc::ONC_SOURCE_DEVICE_POLICY); 303 onc_source == ONC_SOURCE_DEVICE_POLICY);
304 304
305 // Validate the ONC dictionary. We are liberal and ignore unknown field 305 // Validate the ONC dictionary. We are liberal and ignore unknown field
306 // names and ignore invalid field names in kRecommended arrays. 306 // names and ignore invalid field names in kRecommended arrays.
307 onc::Validator validator(false, // Ignore unknown fields. 307 Validator validator(false, // Ignore unknown fields.
308 false, // Ignore invalid recommended field names. 308 false, // Ignore invalid recommended field names.
309 true, // Fail on missing fields. 309 true, // Fail on missing fields.
310 from_policy); 310 from_policy);
311 validator.SetOncSource(onc_source); 311 validator.SetOncSource(onc_source);
312 312
313 onc::Validator::Result validation_result; 313 Validator::Result validation_result;
314 toplevel_onc = validator.ValidateAndRepairObject( 314 toplevel_onc = validator.ValidateAndRepairObject(
315 &onc::kToplevelConfigurationSignature, 315 &kToplevelConfigurationSignature,
316 *toplevel_onc, 316 *toplevel_onc,
317 &validation_result); 317 &validation_result);
318 318
319 if (from_policy) { 319 if (from_policy) {
320 UMA_HISTOGRAM_BOOLEAN("Enterprise.ONC.PolicyValidation", 320 UMA_HISTOGRAM_BOOLEAN("Enterprise.ONC.PolicyValidation",
321 validation_result == onc::Validator::VALID); 321 validation_result == Validator::VALID);
322 } 322 }
323 323
324 bool success = true; 324 bool success = true;
325 if (validation_result == onc::Validator::VALID_WITH_WARNINGS) { 325 if (validation_result == Validator::VALID_WITH_WARNINGS) {
326 LOG(WARNING) << "ONC from " << onc::GetSourceAsString(onc_source) 326 LOG(WARNING) << "ONC from " << GetSourceAsString(onc_source)
327 << " produced warnings."; 327 << " produced warnings.";
328 success = false; 328 success = false;
329 } else if (validation_result == onc::Validator::INVALID || 329 } else if (validation_result == Validator::INVALID || toplevel_onc == NULL) {
330 toplevel_onc == NULL) { 330 LOG(ERROR) << "ONC from " << GetSourceAsString(onc_source)
331 LOG(ERROR) << "ONC from " << onc::GetSourceAsString(onc_source)
332 << " is invalid and couldn't be repaired."; 331 << " is invalid and couldn't be repaired.";
333 return false; 332 return false;
334 } 333 }
335 334
336 base::ListValue* validated_certs = NULL; 335 base::ListValue* validated_certs = NULL;
337 if (toplevel_onc->GetListWithoutPathExpansion( 336 if (toplevel_onc->GetListWithoutPathExpansion(toplevel_config::kCertificates,
338 onc::toplevel_config::kCertificates, &validated_certs)) { 337 &validated_certs)) {
339 certificates->Swap(validated_certs); 338 certificates->Swap(validated_certs);
340 } 339 }
341 340
342 base::ListValue* validated_networks = NULL; 341 base::ListValue* validated_networks = NULL;
343 if (toplevel_onc->GetListWithoutPathExpansion( 342 if (toplevel_onc->GetListWithoutPathExpansion(
344 onc::toplevel_config::kNetworkConfigurations, &validated_networks)) { 343 toplevel_config::kNetworkConfigurations, &validated_networks)) {
345 network_configs->Swap(validated_networks); 344 network_configs->Swap(validated_networks);
346 } 345 }
347 346
348 return success; 347 return success;
349 } 348 }
350 349
350 scoped_refptr<net::X509Certificate> DecodePEMCertificate(
351 const std::string& pem_encoded,
352 const std::string& nickname) {
353 // The PEM block header used for DER certificates
354 static const char kCertificateHeader[] = "CERTIFICATE";
355 // This is an older PEM marker for DER certificates.
356 static const char kX509CertificateHeader[] = "X509 CERTIFICATE";
357
358 std::vector<std::string> pem_headers;
359 pem_headers.push_back(kCertificateHeader);
360 pem_headers.push_back(kX509CertificateHeader);
361
362 net::PEMTokenizer pem_tokenizer(pem_encoded, pem_headers);
363 std::string decoded;
364 if (pem_tokenizer.GetNext()) {
365 decoded = pem_tokenizer.data();
366 } else {
367 // If we failed to read the data as a PEM file, then try plain base64 decode
368 // in case the PEM marker strings are missing. For this to work, there has
369 // to be no white space, and it has to only contain the base64-encoded data.
370 if (!base::Base64Decode(pem_encoded, &decoded)) {
371 LOG(ERROR) << "Unable to base64 decode X509 data: " << pem_encoded;
372 return scoped_refptr<net::X509Certificate>();
373 }
374 }
375
376 scoped_refptr<net::X509Certificate> cert =
377 net::X509Certificate::CreateFromBytesWithNickname(decoded.data(),
378 decoded.size(),
379 nickname.c_str());
380 LOG_IF(ERROR, !cert) << "Couldn't create certificate from X509 data: "
381 << decoded;
382 return cert;
383 }
384
351 } // namespace onc 385 } // namespace onc
352 } // namespace chromeos 386 } // namespace chromeos
OLDNEW
« no previous file with comments | « chromeos/network/onc/onc_utils.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698