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

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

Issue 16946002: Resolve certificate references in ONC by PEM. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Added a unit test for the resolve function. Created 7 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 | Annotate | Revision Log
« no previous file with comments | « chromeos/network/onc/onc_utils.h ('k') | chromeos/network/onc/onc_utils_unittest.cc » ('j') | 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 #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
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 GUIDRefToPEMEncoding(const CertsByGUIDMap& certs_by_guid,
394 const std::string& guid_ref,
395 std::string* pem_encoded) {
396 CertsByGUIDMap::const_iterator it = certs_by_guid.find(guid_ref);
397 if (it == certs_by_guid.end()) {
398 LOG(ERROR) << "Couldn't resolve certificate reference " << guid_ref;
399 return false;
400 }
401 if (!net::X509Certificate::GetPEMEncoded(it->second->os_cert_handle(),
402 pem_encoded)) {
403 LOG(ERROR) << "Couldn't PEM-encode certificate with GUID " << guid_ref;
404 return false;
405 }
406 return true;
407 }
408
409 bool ResolveSingleCertRef(const CertsByGUIDMap& certs_by_guid,
410 const std::string& key_guid_ref,
411 const std::string& key_pem,
412 base::DictionaryValue* onc_object) {
413 std::string guid_ref;
414 if (!onc_object->GetStringWithoutPathExpansion(key_guid_ref, &guid_ref))
415 return true;
416
417 std::string pem_encoded;
418 if (!GUIDRefToPEMEncoding(certs_by_guid, guid_ref, &pem_encoded))
419 return false;
420
421 onc_object->RemoveWithoutPathExpansion(key_guid_ref, NULL);
422 onc_object->SetStringWithoutPathExpansion(key_pem, pem_encoded);
423 return true;
424 }
425
426 bool ResolveCertRefList(const CertsByGUIDMap& certs_by_guid,
427 const std::string& key_guid_ref_list,
428 const std::string& key_pem_list,
429 base::DictionaryValue* onc_object) {
430 const base::ListValue* guid_ref_list = NULL;
431 if (!onc_object->GetListWithoutPathExpansion(key_guid_ref_list,
432 &guid_ref_list)) {
433 return true;
434 }
435
436 scoped_ptr<base::ListValue> pem_list(new base::ListValue);
437 for (base::ListValue::const_iterator it = guid_ref_list->begin();
438 it != guid_ref_list->end(); ++it) {
439 std::string guid_ref;
440 (*it)->GetAsString(&guid_ref);
441
442 std::string pem_encoded;
443 if (!GUIDRefToPEMEncoding(certs_by_guid, guid_ref, &pem_encoded))
444 return false;
445
446 pem_list->AppendString(pem_encoded);
447 }
448
449 onc_object->RemoveWithoutPathExpansion(key_guid_ref_list, NULL);
450 onc_object->SetWithoutPathExpansion(key_pem_list, pem_list.release());
451 return true;
452 }
453
454 bool ResolveSingleCertRefToList(const CertsByGUIDMap& certs_by_guid,
455 const std::string& key_guid_ref,
456 const std::string& key_pem_list,
457 base::DictionaryValue* onc_object) {
458 std::string guid_ref;
459 if (!onc_object->GetStringWithoutPathExpansion(key_guid_ref, &guid_ref))
460 return true;
461
462 std::string pem_encoded;
463 if (!GUIDRefToPEMEncoding(certs_by_guid, guid_ref, &pem_encoded))
464 return false;
465
466 scoped_ptr<base::ListValue> pem_list(new base::ListValue);
467 pem_list->AppendString(pem_encoded);
468 onc_object->RemoveWithoutPathExpansion(key_guid_ref, NULL);
469 onc_object->SetWithoutPathExpansion(key_pem_list, pem_list.release());
470 return true;
471 }
472
473 bool ResolveServerCertRefsInObject(const CertsByGUIDMap& certs_by_guid,
474 const OncValueSignature& signature,
475 base::DictionaryValue* onc_object) {
476 if (&signature == &kCertificatePatternSignature) {
477 if (!ResolveCertRefList(certs_by_guid, certificate::kIssuerCARef,
478 certificate::kIssuerCAPEMs, onc_object)) {
479 return false;
480 }
481 } else if (&signature == &kEAPSignature) {
482 if (!ResolveSingleCertRefToList(certs_by_guid, eap::kServerCARef,
483 eap::kServerCAPEMs, onc_object)) {
484 return false;
485 }
486 } else if (&signature == &kIPsecSignature) {
487 if (!ResolveSingleCertRefToList(certs_by_guid, ipsec::kServerCARef,
488 ipsec::kServerCAPEMs, onc_object)) {
489 return false;
490 }
491 } else if (&signature == &kIPsecSignature ||
492 &signature == &kOpenVPNSignature) {
493 if (!ResolveSingleCertRef(certs_by_guid, openvpn::kServerCertRef,
494 openvpn::kServerCertPEM, onc_object) ||
495 !ResolveSingleCertRefToList(certs_by_guid, openvpn::kServerCARef,
496 openvpn::kServerCAPEMs, onc_object)) {
497 return false;
498 }
499 }
500
501 // Recurse into nested objects.
502 for (base::DictionaryValue::Iterator it(*onc_object); !it.IsAtEnd();
503 it.Advance()) {
504 base::DictionaryValue* inner_object = NULL;
505 if (!onc_object->GetDictionaryWithoutPathExpansion(it.key(), &inner_object))
506 continue;
507
508 const OncFieldSignature* field_signature =
509 GetFieldSignature(signature, it.key());
510 if (!field_signature)
511 continue;
512
513 if (!ResolveServerCertRefsInObject(certs_by_guid,
514 *field_signature->value_signature,
515 inner_object)) {
516 return false;
517 }
518 }
519 return true;
520 }
521
522 } // namespace
523
524 bool ResolveServerCertRefsInNetworks(const CertsByGUIDMap& certs_by_guid,
525 base::ListValue* network_configs) {
526 bool success = true;
527 for (base::ListValue::iterator it = network_configs->begin();
528 it != network_configs->end(); ) {
529 base::DictionaryValue* network = NULL;
530 (*it)->GetAsDictionary(&network);
531 if (!ResolveServerCertRefsInNetwork(certs_by_guid, network)) {
532 std::string guid;
533 network->GetStringWithoutPathExpansion(network_config::kGUID, &guid);
534 // This might happen even with correct validation, if the referenced
535 // certificate couldn't be imported.
536 LOG(ERROR) << "Couldn't resolve some certificate reference of network "
537 << guid;
538 it = network_configs->Erase(it, NULL);
539 success = false;
540 continue;
541 }
542 ++it;
543 }
544 return success;
545 }
546
547 bool ResolveServerCertRefsInNetwork(const CertsByGUIDMap& certs_by_guid,
548 base::DictionaryValue* network_config) {
549 return ResolveServerCertRefsInObject(certs_by_guid,
550 kNetworkConfigurationSignature,
551 network_config);
552 }
553
385 } // namespace onc 554 } // namespace onc
386 } // namespace chromeos 555 } // namespace chromeos
OLDNEW
« no previous file with comments | « chromeos/network/onc/onc_utils.h ('k') | chromeos/network/onc/onc_utils_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698