OLD | NEW |
---|---|
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 #include "net/cert/pem_tokenizer.h" |
22 #include "net/cert/x509_certificate.h" | |
22 | 23 |
23 #define ONC_LOG_WARNING(message) NET_LOG_WARNING("ONC", message) | 24 #define ONC_LOG_WARNING(message) NET_LOG_WARNING("ONC", message) |
24 #define ONC_LOG_ERROR(message) NET_LOG_ERROR("ONC", message) | 25 #define ONC_LOG_ERROR(message) NET_LOG_ERROR("ONC", message) |
25 | 26 |
26 namespace chromeos { | 27 namespace chromeos { |
27 namespace onc { | 28 namespace onc { |
28 | 29 |
29 namespace { | 30 namespace { |
30 | 31 |
31 const char kUnableToDecrypt[] = "Unable to decrypt encrypted ONC"; | 32 const char kUnableToDecrypt[] = "Unable to decrypt encrypted ONC"; |
(...skipping 308 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
340 | 341 |
341 base::ListValue* validated_networks = NULL; | 342 base::ListValue* validated_networks = NULL; |
342 if (toplevel_onc->GetListWithoutPathExpansion( | 343 if (toplevel_onc->GetListWithoutPathExpansion( |
343 toplevel_config::kNetworkConfigurations, &validated_networks)) { | 344 toplevel_config::kNetworkConfigurations, &validated_networks)) { |
344 network_configs->Swap(validated_networks); | 345 network_configs->Swap(validated_networks); |
345 } | 346 } |
346 | 347 |
347 return success; | 348 return success; |
348 } | 349 } |
349 | 350 |
350 scoped_refptr<net::X509Certificate> DecodePEMCertificate( | 351 namespace { |
351 const std::string& pem_encoded, | 352 |
352 const std::string& nickname) { | 353 std::string DecodePEM(const std::string& pem_encoded) { |
353 // The PEM block header used for DER certificates | 354 // The PEM block header used for DER certificates |
354 static const char kCertificateHeader[] = "CERTIFICATE"; | 355 static const char kCertificateHeader[] = "CERTIFICATE"; |
355 // This is an older PEM marker for DER certificates. | 356 // This is an older PEM marker for DER certificates. |
356 static const char kX509CertificateHeader[] = "X509 CERTIFICATE"; | 357 static const char kX509CertificateHeader[] = "X509 CERTIFICATE"; |
357 | 358 |
358 std::vector<std::string> pem_headers; | 359 std::vector<std::string> pem_headers; |
359 pem_headers.push_back(kCertificateHeader); | 360 pem_headers.push_back(kCertificateHeader); |
360 pem_headers.push_back(kX509CertificateHeader); | 361 pem_headers.push_back(kX509CertificateHeader); |
361 | 362 |
362 net::PEMTokenizer pem_tokenizer(pem_encoded, pem_headers); | 363 net::PEMTokenizer pem_tokenizer(pem_encoded, pem_headers); |
363 std::string decoded; | 364 std::string decoded; |
364 if (pem_tokenizer.GetNext()) { | 365 if (pem_tokenizer.GetNext()) { |
365 decoded = pem_tokenizer.data(); | 366 decoded = pem_tokenizer.data(); |
366 } else { | 367 } else { |
367 // If we failed to read the data as a PEM file, then try plain base64 decode | 368 // 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 // 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 // to be no white space, and it has to only contain the base64-encoded data. |
370 if (!base::Base64Decode(pem_encoded, &decoded)) { | 371 if (!base::Base64Decode(pem_encoded, &decoded)) { |
371 LOG(ERROR) << "Unable to base64 decode X509 data: " << pem_encoded; | 372 LOG(ERROR) << "Unable to base64 decode X509 data: " << pem_encoded; |
372 return scoped_refptr<net::X509Certificate>(); | 373 return std::string(); |
373 } | 374 } |
374 } | 375 } |
376 return decoded; | |
377 } | |
375 | 378 |
379 } // namespace | |
380 | |
381 scoped_refptr<net::X509Certificate> DecodePEMCertificate( | |
382 const std::string& pem_encoded) { | |
383 std::string decoded = DecodePEM(pem_encoded); | |
376 scoped_refptr<net::X509Certificate> cert = | 384 scoped_refptr<net::X509Certificate> cert = |
377 net::X509Certificate::CreateFromBytesWithNickname(decoded.data(), | 385 net::X509Certificate::CreateFromBytes(decoded.data(), decoded.size()); |
378 decoded.size(), | |
379 nickname.c_str()); | |
380 LOG_IF(ERROR, !cert) << "Couldn't create certificate from X509 data: " | 386 LOG_IF(ERROR, !cert) << "Couldn't create certificate from X509 data: " |
381 << decoded; | 387 << decoded; |
382 return cert; | 388 return cert; |
383 } | 389 } |
384 | 390 |
391 namespace { | |
392 | |
393 bool ResolveSingleCertRef( | |
394 const std::map<std::string, | |
395 scoped_refptr<net::X509Certificate> >& certs_by_guid, | |
stevenjb
2013/06/28 18:00:27
Use typedef here and below
pneubeck (no reviews)
2013/07/01 15:12:14
Done.
| |
396 const std::string& key_guid_ref, | |
397 const std::string& key_pem, | |
398 base::DictionaryValue* dict) { | |
399 std::string guid_ref; | |
400 if (!dict->GetStringWithoutPathExpansion(key_guid_ref, &guid_ref)) | |
401 return true; | |
402 std::map<std::string, scoped_refptr<net::X509Certificate> >::const_iterator | |
403 it = certs_by_guid.find(guid_ref); | |
404 if (it == certs_by_guid.end()) { | |
405 LOG(ERROR) << "Couldn't resolve certificate reference " << guid_ref; | |
406 return false; | |
407 } | |
408 | |
409 std::string pem_encoded; | |
410 if (!net::X509Certificate::GetPEMEncoded(it->second->os_cert_handle(), | |
411 &pem_encoded)) { | |
412 LOG(ERROR) << "Couldn't PEM-encode certificate with GUID " << guid_ref; | |
413 return false; | |
414 } | |
415 | |
416 dict->SetStringWithoutPathExpansion(key_pem, pem_encoded); | |
417 return true; | |
418 } | |
419 | |
420 bool ResolveOpenVPNCaCertRefs( | |
421 const std::map<std::string, | |
422 scoped_refptr<net::X509Certificate> >& certs_by_guid, | |
423 base::DictionaryValue* openvpn) { | |
424 std::string guid_ref; | |
425 if (!openvpn->GetStringWithoutPathExpansion(openvpn::kServerCARef, &guid_ref)) | |
426 return true; | |
427 std::map<std::string, scoped_refptr<net::X509Certificate> >::const_iterator | |
428 it = certs_by_guid.find(guid_ref); | |
429 if (it == certs_by_guid.end()) { | |
430 LOG(ERROR) << "Couldn't resolve certificate reference " << guid_ref; | |
431 return false; | |
432 } | |
433 | |
434 std::string pem_encoded; | |
435 if (!net::X509Certificate::GetPEMEncoded(it->second->os_cert_handle(), | |
436 &pem_encoded)) { | |
437 LOG(ERROR) << "Couldn't PEM-encode certificate with GUID " << guid_ref; | |
438 return false; | |
439 } | |
440 | |
441 scoped_ptr<base::ListValue> pem_list(new base::ListValue); | |
442 pem_list->AppendString(pem_encoded); | |
443 openvpn->SetWithoutPathExpansion(openvpn::kServerCAPEMs, pem_list.release()); | |
444 return true; | |
445 } | |
446 | |
447 bool ResolveServerCertRefsInObject( | |
448 const std::map<std::string, | |
449 scoped_refptr<net::X509Certificate> >& certs_by_guid, | |
450 const OncValueSignature& signature, | |
451 base::DictionaryValue* onc_object) { | |
452 if (&signature == &kEAPSignature) { | |
453 if (!ResolveSingleCertRef(certs_by_guid, eap::kServerCARef, | |
454 eap::kServerCAPEM, onc_object)) { | |
455 return false; | |
456 } | |
457 } else if (&signature == &kL2TPSignature) { | |
458 if (!ResolveSingleCertRef(certs_by_guid, ipsec::kServerCARef, | |
459 ipsec::kServerCAPEM, onc_object)) { | |
460 return false; | |
461 } | |
462 } else if (&signature == &kL2TPSignature || | |
463 &signature == &kOpenVPNSignature) { | |
464 if (!ResolveSingleCertRef(certs_by_guid, vpn::kServerCertRef, | |
465 vpn::kServerCertPEM, onc_object) || | |
466 !ResolveOpenVPNCaCertRefs(certs_by_guid, onc_object)) { | |
467 return false; | |
468 } | |
469 } | |
470 | |
471 // Recurse into nested objects. | |
472 for (base::DictionaryValue::Iterator it(*onc_object); !it.IsAtEnd(); | |
473 it.Advance()) { | |
474 base::DictionaryValue* inner_object = NULL; | |
475 if (!onc_object->GetDictionaryWithoutPathExpansion(it.key(), &inner_object)) | |
476 continue; | |
477 | |
478 const OncFieldSignature* field_signature = | |
479 GetFieldSignature(signature, it.key()); | |
480 if (!field_signature) | |
481 continue; | |
482 | |
483 if (!ResolveServerCertRefsInObject(certs_by_guid, | |
484 *field_signature->value_signature, | |
485 inner_object)) { | |
486 return false; | |
487 } | |
488 } | |
489 return true; | |
490 } | |
491 | |
492 } // namespace | |
493 | |
494 bool ResolveServerCertRefsInNetworks( | |
495 const std::map<std::string, | |
496 scoped_refptr<net::X509Certificate> >& certs_by_guid, | |
497 base::ListValue* network_configs) { | |
498 bool success = true; | |
499 for (base::ListValue::iterator it = network_configs->begin(); | |
500 it != network_configs->end(); ) { | |
501 base::DictionaryValue* network = NULL; | |
502 (*it)->GetAsDictionary(&network); | |
503 if (!ResolveServerCertRefsInNetwork(certs_by_guid, network)) { | |
504 std::string guid; | |
505 network->GetStringWithoutPathExpansion(network_config::kGUID, &guid); | |
506 // This might happen even with correct validation, if the referenced | |
507 // certificate couldn't be imported. | |
508 LOG(ERROR) << "Couldn't resolve some certificate reference of network " | |
509 << guid; | |
510 it = network_configs->Erase(it, NULL); | |
511 success = false; | |
512 continue; | |
513 } | |
514 ++it; | |
515 } | |
516 return success; | |
517 } | |
518 | |
519 bool ResolveServerCertRefsInNetwork( | |
520 const std::map<std::string, | |
521 scoped_refptr<net::X509Certificate> >& certs_by_guid, | |
522 base::DictionaryValue* network_config) { | |
523 return ResolveServerCertRefsInObject(certs_by_guid, | |
524 kNetworkConfigurationSignature, | |
525 network_config); | |
526 } | |
527 | |
385 } // namespace onc | 528 } // namespace onc |
386 } // namespace chromeos | 529 } // namespace chromeos |
OLD | NEW |