| Index: chromeos/network/onc/onc_utils.cc
|
| diff --git a/chromeos/network/onc/onc_utils.cc b/chromeos/network/onc/onc_utils.cc
|
| index 79768268f09ec41f31b9502247deed0676cb0167..5d4a0c7ada71d68bcd97465712fd435a79cd9b59 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"
|
| @@ -18,7 +19,9 @@
|
| #include "crypto/encryptor.h"
|
| #include "crypto/hmac.h"
|
| #include "crypto/symmetric_key.h"
|
| +#include "net/base/hash_value.h"
|
| #include "net/cert/pem_tokenizer.h"
|
| +#include "net/cert/x509_certificate.h"
|
|
|
| #define ONC_LOG_WARNING(message) NET_LOG_WARNING("ONC", message)
|
| #define ONC_LOG_ERROR(message) NET_LOG_ERROR("ONC", message)
|
| @@ -347,9 +350,50 @@ bool ParseAndValidateOncForImport(const std::string& onc_blob,
|
| 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) << "Fingerprint not unique in list.";
|
| + 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 (!net::X509Certificate::GetPEMEncoded(cert->os_cert_handle(),
|
| + &pem_encoded_cert)) {
|
| + LOG(ERROR) << "Couldn't PEM-encode certificate with fingerprint "
|
| + << fingerprint;
|
| + return std::string();
|
| + }
|
| +
|
| + return pem_encoded_cert;
|
| +}
|
| +
|
| scoped_refptr<net::X509Certificate> DecodePEMCertificate(
|
| - const std::string& pem_encoded,
|
| - const std::string& nickname) {
|
| + const std::string& pem_encoded) {
|
| // The PEM block header used for DER certificates
|
| static const char kCertificateHeader[] = "CERTIFICATE";
|
| // This is an older PEM marker for DER certificates.
|
| @@ -374,13 +418,112 @@ scoped_refptr<net::X509Certificate> DecodePEMCertificate(
|
| }
|
|
|
| scoped_refptr<net::X509Certificate> cert =
|
| - net::X509Certificate::CreateFromBytesWithNickname(decoded.data(),
|
| - decoded.size(),
|
| - nickname.c_str());
|
| + net::X509Certificate::CreateFromBytes(decoded.data(), decoded.size());
|
| LOG_IF(ERROR, !cert) << "Couldn't create certificate from X509 data: "
|
| << decoded;
|
| return 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
|
|
|