12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file.
42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chromeos/network/onc/onc_utils.h"
62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/base64.h"
82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/json/json_reader.h"
92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/logging.h"
10c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/metrics/histogram.h"
11868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string_util.h"
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/values.h"
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chromeos/network/network_event_log.h"
14c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chromeos/network/onc/onc_mapper.h"
15c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chromeos/network/onc/onc_signature.h"
16c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chromeos/network/onc/onc_utils.h"
17c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chromeos/network/onc/onc_validator.h"
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "crypto/encryptor.h"
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "crypto/hmac.h"
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "crypto/symmetric_key.h"
21eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "net/cert/pem_tokenizer.h"
22eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "net/cert/x509_certificate.h"
232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#define ONC_LOG_WARNING(message) NET_LOG_WARNING("ONC", message)
252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#define ONC_LOG_ERROR(message) NET_LOG_ERROR("ONC", message)
262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
274e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)using namespace ::onc;
284e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace chromeos {
302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace onc {
312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace {
332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const char kUnableToDecrypt[] = "Unable to decrypt encrypted ONC";
352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const char kUnableToDecode[] = "Unable to decode encrypted ONC";
362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace
382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const char kEmptyUnencryptedConfiguration[] =
402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    "{\"Type\":\"UnencryptedConfiguration\",\"NetworkConfigurations\":[],"
412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    "\"Certificates\":[]}";
422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)scoped_ptr<base::DictionaryValue> ReadDictionaryFromJson(
442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& json) {
452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string error;
462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::Value* root = base::JSONReader::ReadAndReturnError(
472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      json, base::JSON_ALLOW_TRAILING_COMMAS, NULL, &error);
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::DictionaryValue* dict_ptr = NULL;
502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!root || !root->GetAsDictionary(&dict_ptr)) {
512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ONC_LOG_ERROR("Invalid JSON Dictionary: " + error);
522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    delete root;
532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return make_scoped_ptr(dict_ptr);
562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)scoped_ptr<base::DictionaryValue> Decrypt(const std::string& passphrase,
592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                          const base::DictionaryValue& root) {
602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const int kKeySizeInBits = 256;
612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const int kMaxIterationCount = 500000;
622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string onc_type;
632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string initial_vector;
642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string salt;
652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string cipher;
662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string stretch_method;
672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string hmac_method;
682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string hmac;
692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int iterations;
702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string ciphertext;
712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!root.GetString(encrypted::kCiphertext, &ciphertext) ||
732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      !root.GetString(encrypted::kCipher, &cipher) ||
742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      !root.GetString(encrypted::kHMAC, &hmac) ||
752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      !root.GetString(encrypted::kHMACMethod, &hmac_method) ||
762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      !root.GetString(encrypted::kIV, &initial_vector) ||
772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      !root.GetInteger(encrypted::kIterations, &iterations) ||
782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      !root.GetString(encrypted::kSalt, &salt) ||
792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      !root.GetString(encrypted::kStretch, &stretch_method) ||
802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      !root.GetString(toplevel_config::kType, &onc_type) ||
812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      onc_type != toplevel_config::kEncryptedConfiguration) {
822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ONC_LOG_ERROR("Encrypted ONC malformed.");
842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return scoped_ptr<base::DictionaryValue>();
852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (hmac_method != encrypted::kSHA1 ||
882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      cipher != encrypted::kAES256 ||
892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      stretch_method != encrypted::kPBKDF2) {
902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ONC_LOG_ERROR("Encrypted ONC unsupported encryption scheme.");
912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return scoped_ptr<base::DictionaryValue>();
922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Make sure iterations != 0, since that's not valid.
952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (iterations == 0) {
962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ONC_LOG_ERROR(kUnableToDecrypt);
972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return scoped_ptr<base::DictionaryValue>();
982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Simply a sanity check to make sure we can't lock up the machine
1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // for too long with a huge number (or a negative number).
1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (iterations < 0 || iterations > kMaxIterationCount) {
1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ONC_LOG_ERROR("Too many iterations in encrypted ONC");
1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return scoped_ptr<base::DictionaryValue>();
1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!base::Base64Decode(salt, &salt)) {
1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ONC_LOG_ERROR(kUnableToDecode);
1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return scoped_ptr<base::DictionaryValue>();
1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<crypto::SymmetricKey> key(
1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      crypto::SymmetricKey::DeriveKeyFromPassword(crypto::SymmetricKey::AES,
1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                                  passphrase,
1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                                  salt,
1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                                  iterations,
1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                                  kKeySizeInBits));
1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!base::Base64Decode(initial_vector, &initial_vector)) {
1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ONC_LOG_ERROR(kUnableToDecode);
1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return scoped_ptr<base::DictionaryValue>();
1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!base::Base64Decode(ciphertext, &ciphertext)) {
1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ONC_LOG_ERROR(kUnableToDecode);
1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return scoped_ptr<base::DictionaryValue>();
1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!base::Base64Decode(hmac, &hmac)) {
1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ONC_LOG_ERROR(kUnableToDecode);
1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return scoped_ptr<base::DictionaryValue>();
1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  crypto::HMAC hmac_verifier(crypto::HMAC::SHA1);
1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!hmac_verifier.Init(key.get()) ||
1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      !hmac_verifier.Verify(ciphertext, hmac)) {
1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ONC_LOG_ERROR(kUnableToDecrypt);
1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return scoped_ptr<base::DictionaryValue>();
1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  crypto::Encryptor decryptor;
1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!decryptor.Init(key.get(), crypto::Encryptor::CBC, initial_vector))  {
1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ONC_LOG_ERROR(kUnableToDecrypt);
1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return scoped_ptr<base::DictionaryValue>();
1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string plaintext;
1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!decryptor.Decrypt(ciphertext, &plaintext)) {
1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ONC_LOG_ERROR(kUnableToDecrypt);
1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return scoped_ptr<base::DictionaryValue>();
1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<base::DictionaryValue> new_root =
1522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      ReadDictionaryFromJson(plaintext);
1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (new_root.get() == NULL) {
1542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ONC_LOG_ERROR("Property dictionary malformed.");
1552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return scoped_ptr<base::DictionaryValue>();
1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return new_root.Pass();
1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)std::string GetSourceAsString(ONCSource source) {
1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  switch (source) {
1631320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    case ONC_SOURCE_UNKNOWN:
1641320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      return "unknown";
1651320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    case ONC_SOURCE_NONE:
1661320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      return "none";
1672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case ONC_SOURCE_DEVICE_POLICY:
1682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return "device policy";
1692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case ONC_SOURCE_USER_POLICY:
1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return "user policy";
1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case ONC_SOURCE_USER_IMPORT:
1722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return "user import";
1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  NOTREACHED() << "unknown ONC source " << source;
1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return "unknown";
1762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1783551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void ExpandField(const std::string& fieldname,
1792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 const StringSubstitution& substitution,
1802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 base::DictionaryValue* onc_object) {
1812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string user_string;
1822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!onc_object->GetStringWithoutPathExpansion(fieldname, &user_string))
1832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
1842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string login_id;
1862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (substitution.GetSubstitute(substitutes::kLoginIDField, &login_id)) {
1872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ReplaceSubstringsAfterOffset(&user_string, 0,
188eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                 substitutes::kLoginIDField,
1892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                 login_id);
1902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string email;
1932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (substitution.GetSubstitute(substitutes::kEmailField, &email)) {
1942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ReplaceSubstringsAfterOffset(&user_string, 0,
195eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                 substitutes::kEmailField,
1962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                 email);
1972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  onc_object->SetStringWithoutPathExpansion(fieldname, user_string);
2002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ExpandStringsInOncObject(
2032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const OncValueSignature& signature,
2042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const StringSubstitution& substitution,
2052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::DictionaryValue* onc_object) {
2062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (&signature == &kEAPSignature) {
2072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ExpandField(eap::kAnonymousIdentity, substitution, onc_object);
2082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ExpandField(eap::kIdentity, substitution, onc_object);
2092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else if (&signature == &kL2TPSignature ||
2102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)             &signature == &kOpenVPNSignature) {
2112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ExpandField(vpn::kUsername, substitution, onc_object);
2122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Recurse into nested objects.
2152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (base::DictionaryValue::Iterator it(*onc_object); !it.IsAtEnd();
2162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)       it.Advance()) {
2172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::DictionaryValue* inner_object = NULL;
2182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!onc_object->GetDictionaryWithoutPathExpansion(it.key(), &inner_object))
2192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      continue;
2202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const OncFieldSignature* field_signature =
2222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        GetFieldSignature(signature, it.key());
223c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (!field_signature)
224c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      continue;
2252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ExpandStringsInOncObject(*field_signature->value_signature,
2272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                             substitution, inner_object);
2282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
231ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochvoid ExpandStringsInNetworks(const StringSubstitution& substitution,
232ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch                             base::ListValue* network_configs) {
233ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  for (base::ListValue::iterator it = network_configs->begin();
234ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch       it != network_configs->end(); ++it) {
235ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    base::DictionaryValue* network = NULL;
236ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    (*it)->GetAsDictionary(&network);
237ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    DCHECK(network);
238ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    ExpandStringsInOncObject(
239ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        kNetworkConfigurationSignature, substitution, network);
240ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  }
241ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
242ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
243c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)namespace {
244c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
245eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochclass OncMaskValues : public Mapper {
246c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) public:
247c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  static scoped_ptr<base::DictionaryValue> Mask(
248eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      const OncValueSignature& signature,
249c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      const base::DictionaryValue& onc_object,
250c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      const std::string& mask) {
251c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    OncMaskValues masker(mask);
252c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    bool unused_error;
253c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return masker.MapObject(signature, onc_object, &unused_error);
254c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
255c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
256c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) protected:
257c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  explicit OncMaskValues(const std::string& mask)
258c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      : mask_(mask) {
259c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
260c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
261c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  virtual scoped_ptr<base::Value> MapField(
262c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      const std::string& field_name,
263eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      const OncValueSignature& object_signature,
264c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      const base::Value& onc_value,
265c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      bool* found_unknown_field,
266c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      bool* error) OVERRIDE {
267eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    if (FieldIsCredential(object_signature, field_name)) {
268c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      return scoped_ptr<base::Value>(new base::StringValue(mask_));
269c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    } else {
270eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      return Mapper::MapField(field_name, object_signature, onc_value,
271eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                              found_unknown_field, error);
272c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
273c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
274c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
275c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Mask to insert in place of the sensitive values.
276c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  std::string mask_;
277c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)};
278c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
279c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}  // namespace
280c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
281c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)scoped_ptr<base::DictionaryValue> MaskCredentialsInOncObject(
282eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    const OncValueSignature& signature,
283c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const base::DictionaryValue& onc_object,
284c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const std::string& mask) {
285c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return OncMaskValues::Mask(signature, onc_object, mask);
286c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
287c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
288ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochnamespace {
289ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
290ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochstd::string DecodePEM(const std::string& pem_encoded) {
291ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // The PEM block header used for DER certificates
292ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  const char kCertificateHeader[] = "CERTIFICATE";
293ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
294ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  // This is an older PEM marker for DER certificates.
295ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  const char kX509CertificateHeader[] = "X509 CERTIFICATE";
296ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
297ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  std::vector<std::string> pem_headers;
298ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  pem_headers.push_back(kCertificateHeader);
299ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  pem_headers.push_back(kX509CertificateHeader);
300ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
301ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  net::PEMTokenizer pem_tokenizer(pem_encoded, pem_headers);
302ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  std::string decoded;
303ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (pem_tokenizer.GetNext()) {
304ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    decoded = pem_tokenizer.data();
305ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  } else {
306ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    // If we failed to read the data as a PEM file, then try plain base64 decode
307ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    // in case the PEM marker strings are missing. For this to work, there has
308ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    // to be no white space, and it has to only contain the base64-encoded data.
309ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    if (!base::Base64Decode(pem_encoded, &decoded)) {
310ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      LOG(ERROR) << "Unable to base64 decode X509 data: " << pem_encoded;
311ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      return std::string();
312ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    }
313ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  }
314ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  return decoded;
315ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
316ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
317ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben MurdochCertPEMsByGUIDMap GetServerAndCACertsByGUID(
318ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    const base::ListValue& certificates) {
319ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  CertPEMsByGUIDMap certs_by_guid;
320ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  for (base::ListValue::const_iterator it = certificates.begin();
321ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      it != certificates.end(); ++it) {
322ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    base::DictionaryValue* cert = NULL;
323ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    (*it)->GetAsDictionary(&cert);
324ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
325ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    std::string guid;
326ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    cert->GetStringWithoutPathExpansion(certificate::kGUID, &guid);
327ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    std::string cert_type;
328ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    cert->GetStringWithoutPathExpansion(certificate::kType, &cert_type);
329ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    if (cert_type != certificate::kServer &&
330ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        cert_type != certificate::kAuthority) {
331ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      continue;
332ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    }
333ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    std::string x509_data;
334ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    cert->GetStringWithoutPathExpansion(certificate::kX509, &x509_data);
335ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
336ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    std::string der = DecodePEM(x509_data);
337ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    std::string pem;
338ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    if (der.empty() || !net::X509Certificate::GetPEMEncodedFromDER(der, &pem)) {
339ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      LOG(ERROR) << "Certificate with GUID " << guid
340ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch                 << " is not in PEM encoding.";
341ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      continue;
342ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    }
343ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    certs_by_guid[guid] = pem;
344ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  }
345ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
346ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  return certs_by_guid;
347ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
348ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
349ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}  // namespace
350ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
351eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochbool ParseAndValidateOncForImport(const std::string& onc_blob,
352eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                  ONCSource onc_source,
353eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                  const std::string& passphrase,
354eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                  base::ListValue* network_configs,
3558bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)                                  base::DictionaryValue* global_network_config,
356eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                  base::ListValue* certificates) {
357c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  network_configs->Clear();
3588bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  global_network_config->Clear();
3598bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  certificates->Clear();
360c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (onc_blob.empty())
361c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return true;
362c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
363c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  scoped_ptr<base::DictionaryValue> toplevel_onc =
364eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      ReadDictionaryFromJson(onc_blob);
365c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (toplevel_onc.get() == NULL) {
366eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    LOG(ERROR) << "ONC loaded from " << GetSourceAsString(onc_source)
367c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)               << " is not a valid JSON dictionary.";
368c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return false;
369c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
370c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
371c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Check and see if this is an encrypted ONC file. If so, decrypt it.
372c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  std::string onc_type;
373eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  toplevel_onc->GetStringWithoutPathExpansion(toplevel_config::kType,
374c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                              &onc_type);
375eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (onc_type == toplevel_config::kEncryptedConfiguration) {
376eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    toplevel_onc = Decrypt(passphrase, *toplevel_onc);
377c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (toplevel_onc.get() == NULL) {
378c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      LOG(ERROR) << "Couldn't decrypt the ONC from "
379eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                 << GetSourceAsString(onc_source);
380c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      return false;
381c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
382c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
383c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
384eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  bool from_policy = (onc_source == ONC_SOURCE_USER_POLICY ||
385eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                      onc_source == ONC_SOURCE_DEVICE_POLICY);
386c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
387c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Validate the ONC dictionary. We are liberal and ignore unknown field
388c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // names and ignore invalid field names in kRecommended arrays.
389eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  Validator validator(false,  // Ignore unknown fields.
390eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                      false,  // Ignore invalid recommended field names.
391eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                      true,   // Fail on missing fields.
392eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                      from_policy);
393c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  validator.SetOncSource(onc_source);
394c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
395eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  Validator::Result validation_result;
396c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  toplevel_onc = validator.ValidateAndRepairObject(
397eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      &kToplevelConfigurationSignature,
398c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      *toplevel_onc,
399c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      &validation_result);
400c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
401c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (from_policy) {
402c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    UMA_HISTOGRAM_BOOLEAN("Enterprise.ONC.PolicyValidation",
403eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                          validation_result == Validator::VALID);
404c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
405c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
406c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  bool success = true;
407eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (validation_result == Validator::VALID_WITH_WARNINGS) {
408eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    LOG(WARNING) << "ONC from " << GetSourceAsString(onc_source)
409c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                 << " produced warnings.";
410c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    success = false;
411eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  } else if (validation_result == Validator::INVALID || toplevel_onc == NULL) {
412eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    LOG(ERROR) << "ONC from " << GetSourceAsString(onc_source)
413c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)               << " is invalid and couldn't be repaired.";
414c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return false;
415c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
416c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
417c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::ListValue* validated_certs = NULL;
418eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (toplevel_onc->GetListWithoutPathExpansion(toplevel_config::kCertificates,
419eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                                &validated_certs)) {
420c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    certificates->Swap(validated_certs);
421c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
422c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
423c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::ListValue* validated_networks = NULL;
424c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (toplevel_onc->GetListWithoutPathExpansion(
425eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch          toplevel_config::kNetworkConfigurations, &validated_networks)) {
426ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    CertPEMsByGUIDMap server_and_ca_certs =
427ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        GetServerAndCACertsByGUID(*certificates);
428ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
429ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    if (!ResolveServerCertRefsInNetworks(server_and_ca_certs,
430ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch                                         validated_networks)) {
431ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      LOG(ERROR) << "Some certificate references in the ONC policy for source "
432ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch                 << GetSourceAsString(onc_source) << " could not be resolved.";
433ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      success = false;
434ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    }
435ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
436c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    network_configs->Swap(validated_networks);
437c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
438c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
4398bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  base::DictionaryValue* validated_global_config = NULL;
4408bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  if (toplevel_onc->GetDictionaryWithoutPathExpansion(
4418bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)          toplevel_config::kGlobalNetworkConfiguration,
4428bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)          &validated_global_config)) {
4438bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    global_network_config->Swap(validated_global_config);
4448bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  }
4458bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
446c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return success;
447c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
448c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
449eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochscoped_refptr<net::X509Certificate> DecodePEMCertificate(
450eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    const std::string& pem_encoded) {
451eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  std::string decoded = DecodePEM(pem_encoded);
452eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  scoped_refptr<net::X509Certificate> cert =
453eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      net::X509Certificate::CreateFromBytes(decoded.data(), decoded.size());
4547dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  LOG_IF(ERROR, !cert.get()) << "Couldn't create certificate from X509 data: "
4557dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                             << decoded;
456eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  return cert;
457eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
458eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
459eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochnamespace {
460eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
461ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochbool GUIDRefToPEMEncoding(const CertPEMsByGUIDMap& certs_by_guid,
462eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                          const std::string& guid_ref,
463eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                          std::string* pem_encoded) {
464ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  CertPEMsByGUIDMap::const_iterator it = certs_by_guid.find(guid_ref);
465eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (it == certs_by_guid.end()) {
466eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    LOG(ERROR) << "Couldn't resolve certificate reference " << guid_ref;
467eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    return false;
468eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
469ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  *pem_encoded = it->second;
470ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (pem_encoded->empty()) {
471eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    LOG(ERROR) << "Couldn't PEM-encode certificate with GUID " << guid_ref;
472eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    return false;
473eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
474eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  return true;
475eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
476eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
477ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochbool ResolveSingleCertRef(const CertPEMsByGUIDMap& certs_by_guid,
478eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                          const std::string& key_guid_ref,
479eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                          const std::string& key_pem,
480eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                          base::DictionaryValue* onc_object) {
481eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  std::string guid_ref;
482eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (!onc_object->GetStringWithoutPathExpansion(key_guid_ref, &guid_ref))
483eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    return true;
484eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
485eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  std::string pem_encoded;
486eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (!GUIDRefToPEMEncoding(certs_by_guid, guid_ref, &pem_encoded))
487eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    return false;
488eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
489eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  onc_object->RemoveWithoutPathExpansion(key_guid_ref, NULL);
490eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  onc_object->SetStringWithoutPathExpansion(key_pem, pem_encoded);
491eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  return true;
492eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
493eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
494ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochbool ResolveCertRefList(const CertPEMsByGUIDMap& certs_by_guid,
495eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                        const std::string& key_guid_ref_list,
496eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                        const std::string& key_pem_list,
497eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                        base::DictionaryValue* onc_object) {
498eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  const base::ListValue* guid_ref_list = NULL;
499eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (!onc_object->GetListWithoutPathExpansion(key_guid_ref_list,
500eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                               &guid_ref_list)) {
501eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    return true;
502eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
503eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
504eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  scoped_ptr<base::ListValue> pem_list(new base::ListValue);
505eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  for (base::ListValue::const_iterator it = guid_ref_list->begin();
506eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch       it != guid_ref_list->end(); ++it) {
507eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    std::string guid_ref;
508eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    (*it)->GetAsString(&guid_ref);
509eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
510eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    std::string pem_encoded;
511eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    if (!GUIDRefToPEMEncoding(certs_by_guid, guid_ref, &pem_encoded))
512eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      return false;
513eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
514eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    pem_list->AppendString(pem_encoded);
515eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
516eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
517eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  onc_object->RemoveWithoutPathExpansion(key_guid_ref_list, NULL);
518eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  onc_object->SetWithoutPathExpansion(key_pem_list, pem_list.release());
519eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  return true;
520eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
521eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
522ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochbool ResolveSingleCertRefToList(const CertPEMsByGUIDMap& certs_by_guid,
523eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                const std::string& key_guid_ref,
524eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                const std::string& key_pem_list,
525eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                base::DictionaryValue* onc_object) {
526eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  std::string guid_ref;
527eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (!onc_object->GetStringWithoutPathExpansion(key_guid_ref, &guid_ref))
528eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    return true;
529eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
530eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  std::string pem_encoded;
531eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (!GUIDRefToPEMEncoding(certs_by_guid, guid_ref, &pem_encoded))
532eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    return false;
533eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
534eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  scoped_ptr<base::ListValue> pem_list(new base::ListValue);
535eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  pem_list->AppendString(pem_encoded);
536eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  onc_object->RemoveWithoutPathExpansion(key_guid_ref, NULL);
537eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  onc_object->SetWithoutPathExpansion(key_pem_list, pem_list.release());
538eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  return true;
539eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
540eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
5415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Resolves the reference list at |key_guid_refs| if present and otherwise the
5425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// single reference at |key_guid_ref|. Returns whether the respective resolving
5435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// was successful.
5445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool ResolveCertRefsOrRefToList(const CertPEMsByGUIDMap& certs_by_guid,
5455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                const std::string& key_guid_refs,
5465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                const std::string& key_guid_ref,
5475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                const std::string& key_pem_list,
5485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                base::DictionaryValue* onc_object) {
5495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (onc_object->HasKey(key_guid_refs)) {
5505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (onc_object->HasKey(key_guid_ref)) {
5515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      LOG(ERROR) << "Found both " << key_guid_refs << " and " << key_guid_ref
5525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 << ". Ignoring and removing the latter.";
5535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      onc_object->RemoveWithoutPathExpansion(key_guid_ref, NULL);
5545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
5555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return ResolveCertRefList(
5565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        certs_by_guid, key_guid_refs, key_pem_list, onc_object);
5575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
5585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
5595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Only resolve |key_guid_ref| if |key_guid_refs| isn't present.
5605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return ResolveSingleCertRefToList(
5615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      certs_by_guid, key_guid_ref, key_pem_list, onc_object);
5625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
5635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
564ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochbool ResolveServerCertRefsInObject(const CertPEMsByGUIDMap& certs_by_guid,
565eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                   const OncValueSignature& signature,
566eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                   base::DictionaryValue* onc_object) {
567eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (&signature == &kCertificatePatternSignature) {
568116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    if (!ResolveCertRefList(certs_by_guid,
569116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                            client_cert::kIssuerCARef,
570116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                            client_cert::kIssuerCAPEMs,
571116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                            onc_object)) {
572eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      return false;
573eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    }
574eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  } else if (&signature == &kEAPSignature) {
5755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (!ResolveCertRefsOrRefToList(certs_by_guid,
5765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                    eap::kServerCARefs,
5775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                    eap::kServerCARef,
5785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                    eap::kServerCAPEMs,
5795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                    onc_object)) {
580eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      return false;
581eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    }
582eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  } else if (&signature == &kIPsecSignature) {
5835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (!ResolveCertRefsOrRefToList(certs_by_guid,
5845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                    ipsec::kServerCARefs,
5855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                    ipsec::kServerCARef,
5865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                    ipsec::kServerCAPEMs,
5875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                    onc_object)) {
588eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      return false;
589eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    }
590eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  } else if (&signature == &kIPsecSignature ||
591eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch             &signature == &kOpenVPNSignature) {
5925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (!ResolveSingleCertRef(certs_by_guid,
5935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                              openvpn::kServerCertRef,
5945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                              openvpn::kServerCertPEM,
5955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                              onc_object) ||
5965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        !ResolveCertRefsOrRefToList(certs_by_guid,
5975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                    openvpn::kServerCARefs,
5985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                    openvpn::kServerCARef,
5995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                    openvpn::kServerCAPEMs,
6005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                    onc_object)) {
601eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      return false;
602eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    }
603eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
604eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
605eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // Recurse into nested objects.
606eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  for (base::DictionaryValue::Iterator it(*onc_object); !it.IsAtEnd();
607eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch       it.Advance()) {
608eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    base::DictionaryValue* inner_object = NULL;
609eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    if (!onc_object->GetDictionaryWithoutPathExpansion(it.key(), &inner_object))
610eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      continue;
611eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
612eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    const OncFieldSignature* field_signature =
613eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        GetFieldSignature(signature, it.key());
614eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    if (!field_signature)
615eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      continue;
616eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
617eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    if (!ResolveServerCertRefsInObject(certs_by_guid,
618eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                       *field_signature->value_signature,
619eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                       inner_object)) {
620eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      return false;
621eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    }
622eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
623eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  return true;
624eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
625eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
626eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}  // namespace
627eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
628ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochbool ResolveServerCertRefsInNetworks(const CertPEMsByGUIDMap& certs_by_guid,
629eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                     base::ListValue* network_configs) {
630eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  bool success = true;
631eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  for (base::ListValue::iterator it = network_configs->begin();
632eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch       it != network_configs->end(); ) {
633eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    base::DictionaryValue* network = NULL;
634eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    (*it)->GetAsDictionary(&network);
635eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    if (!ResolveServerCertRefsInNetwork(certs_by_guid, network)) {
636eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      std::string guid;
637eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      network->GetStringWithoutPathExpansion(network_config::kGUID, &guid);
638eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      // This might happen even with correct validation, if the referenced
639eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      // certificate couldn't be imported.
640eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      LOG(ERROR) << "Couldn't resolve some certificate reference of network "
641eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                 << guid;
642eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      it = network_configs->Erase(it, NULL);
643eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      success = false;
644eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      continue;
645eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    }
646eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    ++it;
647eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
648eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  return success;
649eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
650eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
651ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochbool ResolveServerCertRefsInNetwork(const CertPEMsByGUIDMap& certs_by_guid,
652eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                    base::DictionaryValue* network_config) {
653eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  return ResolveServerCertRefsInObject(certs_by_guid,
654eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                       kNetworkConfigurationSignature,
655eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                       network_config);
656eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
657eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
658010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)NetworkTypePattern NetworkTypePatternFromOncType(const std::string& type) {
659010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  if (type == ::onc::network_type::kAllTypes)
660010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    return NetworkTypePattern::Default();
661010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  if (type == ::onc::network_type::kCellular)
662010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    return NetworkTypePattern::Cellular();
663010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  if (type == ::onc::network_type::kEthernet)
664010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    return NetworkTypePattern::Ethernet();
665010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  if (type == ::onc::network_type::kVPN)
666010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    return NetworkTypePattern::VPN();
667010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  if (type == ::onc::network_type::kWiFi)
668010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    return NetworkTypePattern::WiFi();
669cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (type == ::onc::network_type::kWimax)
670cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return NetworkTypePattern::Wimax();
671cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (type == ::onc::network_type::kWireless)
672cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return NetworkTypePattern::Wireless();
673010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  NOTREACHED();
674010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  return NetworkTypePattern::Default();
675010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)}
676010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
6775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)bool IsRecommendedValue(const base::DictionaryValue* onc,
6785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                        const std::string& property_key) {
6795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  std::string property_basename, recommended_property_key;
6805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  size_t pos = property_key.find_last_of('.');
6815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (pos != std::string::npos) {
6825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    // 'WiFi.AutoConnect' -> 'AutoConnect', 'WiFi.Recommended'
6835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    property_basename = property_key.substr(pos + 1);
6845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    recommended_property_key =
6855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        property_key.substr(0, pos + 1) + ::onc::kRecommended;
6865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  } else {
6875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    // 'Name' -> 'Name', 'Recommended'
6885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    property_basename = property_key;
6895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    recommended_property_key = ::onc::kRecommended;
6905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
6915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
6925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  const base::ListValue* recommended_keys = NULL;
6935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return (onc->GetList(recommended_property_key, &recommended_keys) &&
6945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          recommended_keys->Find(base::StringValue(property_basename)) !=
6955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          recommended_keys->end());
6965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
6975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
6982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace onc
6992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace chromeos
700