| Index: chromeos/network/onc/onc_utils.cc
|
| diff --git a/chromeos/network/onc/onc_utils.cc b/chromeos/network/onc/onc_utils.cc
|
| index 3feb9139c462b679a1e8a0f4f087e9e8c84a47d6..9e66005e8dbd550953870955977aefdfc33ad38a 100644
|
| --- a/chromeos/network/onc/onc_utils.cc
|
| +++ b/chromeos/network/onc/onc_utils.cc
|
| @@ -8,6 +8,7 @@
|
| #include "base/json/json_reader.h"
|
| #include "base/logging.h"
|
| #include "base/metrics/histogram.h"
|
| +#include "base/strings/string_number_conversions.h"
|
| #include "base/strings/string_util.h"
|
| #include "base/values.h"
|
| #include "chromeos/network/network_event_log.h"
|
| @@ -19,6 +20,7 @@
|
| #include "crypto/encryptor.h"
|
| #include "crypto/hmac.h"
|
| #include "crypto/symmetric_key.h"
|
| +#include "net/base/hash_value.h"
|
|
|
| #define ONC_LOG_WARNING(message) NET_LOG_WARNING("ONC", message)
|
| #define ONC_LOG_ERROR(message) NET_LOG_ERROR("ONC", message)
|
| @@ -354,5 +356,147 @@ bool ParseAndValidateOncForImport(
|
| return success;
|
| }
|
|
|
| +std::string GetHexFingerprintOfCert(const net::X509Certificate& cert) {
|
| + net::SHA1HashValue fingerprint = cert.fingerprint();
|
| + return base::HexEncode(fingerprint.data, sizeof(fingerprint.data));
|
| +}
|
| +
|
| +net::X509Certificate* FindCertByFingerprint(
|
| + const net::CertificateList& cert_list, const std::string& fingerprint) {
|
| + net::X509Certificate* found = NULL;
|
| + for (net::CertificateList::const_iterator it = cert_list.begin();
|
| + it != cert_list.end(); ++it) {
|
| + if (GetHexFingerprintOfCert(**it) != fingerprint)
|
| + continue;
|
| + if (found != NULL) {
|
| + LOG(ERROR) << "Certificate fingerprints collided.";
|
| + return NULL;
|
| + }
|
| + found = it->get();
|
| + }
|
| + return found;
|
| +}
|
| +
|
| +std::string GetPEMEncodedCertFromFingerprint(
|
| + const net::CertificateList& cert_list,
|
| + const std::string& fingerprint) {
|
| + net::X509Certificate* cert = FindCertByFingerprint(cert_list, fingerprint);
|
| + if (!cert) {
|
| + LOG(ERROR) << "Couldn't find a certificate with fingerprint "
|
| + << fingerprint;
|
| + return std::string();
|
| + }
|
| +
|
| + std::string pem_encoded_cert;
|
| + if (!cert->GetPEMEncoded(&pem_encoded_cert)) {
|
| + LOG(ERROR) << "Couldn't PEM-encode certificate with fingerprint "
|
| + << fingerprint;
|
| + return std::string();
|
| + }
|
| +
|
| + return pem_encoded_cert;
|
| +}
|
| +
|
| +namespace {
|
| +
|
| +bool ResolveCertRef(
|
| + const std::map<std::string,
|
| + scoped_refptr<net::X509Certificate> >& certs_by_guid,
|
| + const std::string& key_guid_ref,
|
| + const std::string& key_fingerprint,
|
| + base::DictionaryValue* dict) {
|
| + std::string guid_ref;
|
| + if (!dict->GetStringWithoutPathExpansion(key_guid_ref, &guid_ref))
|
| + return true;
|
| + std::map<std::string, scoped_refptr<net::X509Certificate> >::const_iterator
|
| + it = certs_by_guid.find(guid_ref);
|
| + if (it == certs_by_guid.end()) {
|
| + LOG(ERROR) << "Couldn't resolve certificate reference " << guid_ref;
|
| + return false;
|
| + }
|
| +
|
| + dict->SetStringWithoutPathExpansion(
|
| + key_fingerprint,
|
| + GetHexFingerprintOfCert(*it->second));
|
| + return true;
|
| +}
|
| +
|
| +bool ResolveServerCertRefsInObject(
|
| + const std::map<std::string,
|
| + scoped_refptr<net::X509Certificate> >& certs_by_guid,
|
| + const OncValueSignature& signature,
|
| + base::DictionaryValue* onc_object) {
|
| + if (&signature == &kEAPSignature) {
|
| + if (!ResolveCertRef(certs_by_guid, eap::kServerCARef,
|
| + eap::kServerCAFingerprint, onc_object)) {
|
| + return false;
|
| + }
|
| + } else if (&signature == &kL2TPSignature ||
|
| + &signature == &kOpenVPNSignature) {
|
| + if (!ResolveCertRef(certs_by_guid, vpn::kServerCARef,
|
| + vpn::kServerCAFingerprint, onc_object) ||
|
| + !ResolveCertRef(certs_by_guid, vpn::kServerCertRef,
|
| + vpn::kServerCertFingerprint, onc_object)) {
|
| + return false;;
|
| + }
|
| + }
|
| +
|
| + // Recurse into nested objects.
|
| + for (base::DictionaryValue::Iterator it(*onc_object); !it.IsAtEnd();
|
| + it.Advance()) {
|
| + base::DictionaryValue* inner_object = NULL;
|
| + if (!onc_object->GetDictionaryWithoutPathExpansion(it.key(), &inner_object))
|
| + continue;
|
| +
|
| + const OncFieldSignature* field_signature =
|
| + GetFieldSignature(signature, it.key());
|
| + if (!field_signature)
|
| + continue;
|
| +
|
| + if (!ResolveServerCertRefsInObject(certs_by_guid,
|
| + *field_signature->value_signature,
|
| + inner_object)) {
|
| + return false;
|
| + }
|
| + }
|
| + return true;
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| +bool ResolveServerCertRefsInNetworks(
|
| + const std::map<std::string,
|
| + scoped_refptr<net::X509Certificate> >& certs_by_guid,
|
| + base::ListValue* network_configs) {
|
| + bool success = true;
|
| + for (base::ListValue::iterator it = network_configs->begin();
|
| + it != network_configs->end(); ) {
|
| + base::DictionaryValue* network = NULL;
|
| + (*it)->GetAsDictionary(&network);
|
| + if (!ResolveServerCertRefsInNetwork(certs_by_guid, network)) {
|
| + std::string guid;
|
| + network->GetStringWithoutPathExpansion(network_config::kGUID, &guid);
|
| + // This might happen even with correct validation, if the referenced
|
| + // certificate couldn't be imported.
|
| + LOG(ERROR) << "Couldn't resolve some certificate reference of network "
|
| + << guid;
|
| + it = network_configs->Erase(it, NULL);
|
| + success = false;
|
| + continue;
|
| + }
|
| + ++it;
|
| + }
|
| + return success;
|
| +}
|
| +
|
| +bool ResolveServerCertRefsInNetwork(
|
| + const std::map<std::string,
|
| + scoped_refptr<net::X509Certificate> >& certs_by_guid,
|
| + base::DictionaryValue* network_config) {
|
| + return ResolveServerCertRefsInObject(certs_by_guid,
|
| + kNetworkConfigurationSignature,
|
| + network_config);
|
| +}
|
| +
|
| } // namespace onc
|
| } // namespace chromeos
|
|
|