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

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: Fix trust update. Add a utils test. Remove X509 dependency from Shill parsing. 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
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/sha1.h"
12 #include "base/strings/string_number_conversions.h"
11 #include "base/strings/string_util.h" 13 #include "base/strings/string_util.h"
12 #include "base/values.h" 14 #include "base/values.h"
13 #include "chromeos/network/network_event_log.h" 15 #include "chromeos/network/network_event_log.h"
14 #include "chromeos/network/onc/onc_mapper.h" 16 #include "chromeos/network/onc/onc_mapper.h"
15 #include "chromeos/network/onc/onc_signature.h" 17 #include "chromeos/network/onc/onc_signature.h"
16 #include "chromeos/network/onc/onc_utils.h" 18 #include "chromeos/network/onc/onc_utils.h"
17 #include "chromeos/network/onc/onc_validator.h" 19 #include "chromeos/network/onc/onc_validator.h"
18 #include "crypto/encryptor.h" 20 #include "crypto/encryptor.h"
19 #include "crypto/hmac.h" 21 #include "crypto/hmac.h"
20 #include "crypto/symmetric_key.h" 22 #include "crypto/symmetric_key.h"
23 #include "net/base/hash_value.h"
21 #include "net/cert/pem_tokenizer.h" 24 #include "net/cert/pem_tokenizer.h"
25 #include "net/cert/x509_certificate.h"
22 26
23 #define ONC_LOG_WARNING(message) NET_LOG_WARNING("ONC", message) 27 #define ONC_LOG_WARNING(message) NET_LOG_WARNING("ONC", message)
24 #define ONC_LOG_ERROR(message) NET_LOG_ERROR("ONC", message) 28 #define ONC_LOG_ERROR(message) NET_LOG_ERROR("ONC", message)
25 29
26 namespace chromeos { 30 namespace chromeos {
27 namespace onc { 31 namespace onc {
28 32
29 namespace { 33 namespace {
30 34
31 const char kUnableToDecrypt[] = "Unable to decrypt encrypted ONC"; 35 const char kUnableToDecrypt[] = "Unable to decrypt encrypted ONC";
(...skipping 308 matching lines...) Expand 10 before | Expand all | Expand 10 after
340 344
341 base::ListValue* validated_networks = NULL; 345 base::ListValue* validated_networks = NULL;
342 if (toplevel_onc->GetListWithoutPathExpansion( 346 if (toplevel_onc->GetListWithoutPathExpansion(
343 toplevel_config::kNetworkConfigurations, &validated_networks)) { 347 toplevel_config::kNetworkConfigurations, &validated_networks)) {
344 network_configs->Swap(validated_networks); 348 network_configs->Swap(validated_networks);
345 } 349 }
346 350
347 return success; 351 return success;
348 } 352 }
349 353
350 scoped_refptr<net::X509Certificate> DecodePEMCertificate( 354 namespace {
351 const std::string& pem_encoded, 355
352 const std::string& nickname) { 356 std::string DecodePEM(const std::string& pem_encoded) {
353 // The PEM block header used for DER certificates 357 // The PEM block header used for DER certificates
354 static const char kCertificateHeader[] = "CERTIFICATE"; 358 static const char kCertificateHeader[] = "CERTIFICATE";
355 // This is an older PEM marker for DER certificates. 359 // This is an older PEM marker for DER certificates.
356 static const char kX509CertificateHeader[] = "X509 CERTIFICATE"; 360 static const char kX509CertificateHeader[] = "X509 CERTIFICATE";
357 361
358 std::vector<std::string> pem_headers; 362 std::vector<std::string> pem_headers;
359 pem_headers.push_back(kCertificateHeader); 363 pem_headers.push_back(kCertificateHeader);
360 pem_headers.push_back(kX509CertificateHeader); 364 pem_headers.push_back(kX509CertificateHeader);
361 365
362 net::PEMTokenizer pem_tokenizer(pem_encoded, pem_headers); 366 net::PEMTokenizer pem_tokenizer(pem_encoded, pem_headers);
363 std::string decoded; 367 std::string decoded;
364 if (pem_tokenizer.GetNext()) { 368 if (pem_tokenizer.GetNext()) {
365 decoded = pem_tokenizer.data(); 369 decoded = pem_tokenizer.data();
366 } else { 370 } else {
367 // If we failed to read the data as a PEM file, then try plain base64 decode 371 // 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 372 // 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. 373 // to be no white space, and it has to only contain the base64-encoded data.
370 if (!base::Base64Decode(pem_encoded, &decoded)) { 374 if (!base::Base64Decode(pem_encoded, &decoded)) {
371 LOG(ERROR) << "Unable to base64 decode X509 data: " << pem_encoded; 375 LOG(ERROR) << "Unable to base64 decode X509 data: " << pem_encoded;
372 return scoped_refptr<net::X509Certificate>(); 376 return std::string();
373 } 377 }
374 } 378 }
379 return decoded;
380 }
375 381
382 } // namespace
383
384 std::string GetHexFingerprintOfCert(const net::X509Certificate& cert) {
385 net::SHA1HashValue fingerprint = cert.fingerprint();
386 return base::HexEncode(fingerprint.data, sizeof(fingerprint.data));
387 }
388
389 std::string GetHexFingerprintOfPEMCert(const std::string& pem_encoded_cert) {
390 std::string decoded = DecodePEM(pem_encoded_cert);
391 if (decoded.empty()) {
392 LOG(ERROR) << "Could not decode the PEM encoding of a certificate.";
393 return std::string();
394 }
395 std::string sha1 = base::SHA1HashString(decoded);
396 return base::HexEncode(sha1.data(), sha1.length());
397 }
398
399 net::X509Certificate* FindCertByFingerprint(
400 const net::CertificateList& cert_list, const std::string& fingerprint) {
401 net::X509Certificate* found = NULL;
402 for (net::CertificateList::const_iterator it = cert_list.begin();
403 it != cert_list.end(); ++it) {
404 if (GetHexFingerprintOfCert(**it) != fingerprint)
405 continue;
406 if (found != NULL && !found->Equals(it->get())) {
407 LOG(ERROR) << "Fingerprint not unique in list.";
408 return NULL;
409 }
410 found = it->get();
411 }
412 return found;
413 }
414
415 std::string GetPEMEncodedCertFromFingerprint(
416 const net::CertificateList& cert_list,
417 const std::string& fingerprint) {
418 net::X509Certificate* cert = FindCertByFingerprint(cert_list, fingerprint);
419 if (!cert) {
420 LOG(ERROR) << "Couldn't find a certificate with fingerprint "
421 << fingerprint;
422 return std::string();
423 }
424
425 std::string pem_encoded_cert;
426 if (!net::X509Certificate::GetPEMEncoded(cert->os_cert_handle(),
427 &pem_encoded_cert)) {
428 LOG(ERROR) << "Couldn't PEM-encode certificate with fingerprint "
429 << fingerprint;
430 return std::string();
431 }
432
433 return pem_encoded_cert;
434 }
435
436 scoped_refptr<net::X509Certificate> DecodePEMCertificate(
437 const std::string& pem_encoded) {
438 std::string decoded = DecodePEM(pem_encoded);
376 scoped_refptr<net::X509Certificate> cert = 439 scoped_refptr<net::X509Certificate> cert =
377 net::X509Certificate::CreateFromBytesWithNickname(decoded.data(), 440 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: " 441 LOG_IF(ERROR, !cert) << "Couldn't create certificate from X509 data: "
381 << decoded; 442 << decoded;
382 return cert; 443 return cert;
383 } 444 }
384 445
446 namespace {
447
448 bool ResolveCertRef(
449 const std::map<std::string,
450 scoped_refptr<net::X509Certificate> >& certs_by_guid,
451 const std::string& key_guid_ref,
452 const std::string& key_fingerprint,
453 base::DictionaryValue* dict) {
454 std::string guid_ref;
455 if (!dict->GetStringWithoutPathExpansion(key_guid_ref, &guid_ref))
456 return true;
457 std::map<std::string, scoped_refptr<net::X509Certificate> >::const_iterator
458 it = certs_by_guid.find(guid_ref);
459 if (it == certs_by_guid.end()) {
460 LOG(ERROR) << "Couldn't resolve certificate reference " << guid_ref;
461 return false;
462 }
463
464 dict->SetStringWithoutPathExpansion(
465 key_fingerprint,
466 GetHexFingerprintOfCert(*it->second));
467 return true;
468 }
469
470 bool ResolveServerCertRefsInObject(
471 const std::map<std::string,
472 scoped_refptr<net::X509Certificate> >& certs_by_guid,
473 const OncValueSignature& signature,
474 base::DictionaryValue* onc_object) {
475 if (&signature == &kEAPSignature) {
476 if (!ResolveCertRef(certs_by_guid, eap::kServerCARef,
477 eap::kServerCAFingerprint, onc_object)) {
478 return false;
479 }
480 } else if (&signature == &kL2TPSignature ||
481 &signature == &kOpenVPNSignature) {
482 if (!ResolveCertRef(certs_by_guid, vpn::kServerCARef,
483 vpn::kServerCAFingerprint, onc_object) ||
484 !ResolveCertRef(certs_by_guid, vpn::kServerCertRef,
485 vpn::kServerCertFingerprint, onc_object)) {
486 return false;;
487 }
488 }
489
490 // Recurse into nested objects.
491 for (base::DictionaryValue::Iterator it(*onc_object); !it.IsAtEnd();
492 it.Advance()) {
493 base::DictionaryValue* inner_object = NULL;
494 if (!onc_object->GetDictionaryWithoutPathExpansion(it.key(), &inner_object))
495 continue;
496
497 const OncFieldSignature* field_signature =
498 GetFieldSignature(signature, it.key());
499 if (!field_signature)
500 continue;
501
502 if (!ResolveServerCertRefsInObject(certs_by_guid,
503 *field_signature->value_signature,
504 inner_object)) {
505 return false;
506 }
507 }
508 return true;
509 }
510
511 } // namespace
512
513 bool ResolveServerCertRefsInNetworks(
514 const std::map<std::string,
515 scoped_refptr<net::X509Certificate> >& certs_by_guid,
516 base::ListValue* network_configs) {
517 bool success = true;
518 for (base::ListValue::iterator it = network_configs->begin();
519 it != network_configs->end(); ) {
520 base::DictionaryValue* network = NULL;
521 (*it)->GetAsDictionary(&network);
522 if (!ResolveServerCertRefsInNetwork(certs_by_guid, network)) {
523 std::string guid;
524 network->GetStringWithoutPathExpansion(network_config::kGUID, &guid);
525 // This might happen even with correct validation, if the referenced
526 // certificate couldn't be imported.
527 LOG(ERROR) << "Couldn't resolve some certificate reference of network "
528 << guid;
529 it = network_configs->Erase(it, NULL);
530 success = false;
531 continue;
532 }
533 ++it;
534 }
535 return success;
536 }
537
538 bool ResolveServerCertRefsInNetwork(
539 const std::map<std::string,
540 scoped_refptr<net::X509Certificate> >& certs_by_guid,
541 base::DictionaryValue* network_config) {
542 return ResolveServerCertRefsInObject(certs_by_guid,
543 kNetworkConfigurationSignature,
544 network_config);
545 }
546
385 } // namespace onc 547 } // namespace onc
386 } // namespace chromeos 548 } // namespace chromeos
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698