1558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch// Copyright 2013 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)
5558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch#include "chromeos/network/onc/onc_certificate_importer_impl.h"
62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <cert.h>
82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <keyhi.h>
92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <pk11pub.h>
102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/base64.h"
121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/bind.h"
131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/bind_helpers.h"
141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/callback.h"
151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/location.h"
162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/logging.h"
171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/sequenced_task_runner.h"
181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/single_thread_task_runner.h"
191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/thread_task_runner_handle.h"
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/values.h"
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chromeos/network/network_event_log.h"
22eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "chromeos/network/onc/onc_utils.h"
234e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "components/onc/onc_constants.h"
24a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "crypto/scoped_nss_types.h"
252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "net/base/crypto_module.h"
262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "net/base/net_errors.h"
27c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "net/cert/nss_cert_database.h"
28c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "net/cert/x509_certificate.h"
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace chromeos {
312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace onc {
322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccinamespace {
341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid CallBackOnOriginLoop(
361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    const scoped_refptr<base::SingleThreadTaskRunner>& origin_loop,
371320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    const CertificateImporter::DoneCallback& callback,
381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    bool success,
391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    const net::CertificateList& onc_trusted_certificates) {
401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  origin_loop->PostTask(
411320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      FROM_HERE, base::Bind(callback, success, onc_trusted_certificates));
421320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
431320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}  // namespace
451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)CertificateImporterImpl::CertificateImporterImpl(
471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    const scoped_refptr<base::SequencedTaskRunner>& io_task_runner,
485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    net::NSSCertDatabase* target_nssdb)
491320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    : io_task_runner_(io_task_runner),
501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      target_nssdb_(target_nssdb),
511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      weak_factory_(this) {
525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CHECK(target_nssdb);
532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciCertificateImporterImpl::~CertificateImporterImpl() {
561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
581320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid CertificateImporterImpl::ImportCertificates(
59558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    const base::ListValue& certificates,
604e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    ::onc::ONCSource source,
611320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    const DoneCallback& done_callback) {
62558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  VLOG(2) << "ONC file has " << certificates.GetSize() << " certificates";
631320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // |done_callback| must only be called as long as |this| still exists.
641320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Thereforce, call back to |this|. This check of |this| must happen last and
651320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // on the origin thread.
661320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  DoneCallback callback_to_this =
671320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      base::Bind(&CertificateImporterImpl::RunDoneCallback,
681320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                 weak_factory_.GetWeakPtr(),
691320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                 done_callback);
701320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
711320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // |done_callback| must be called on the origin thread.
721320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  DoneCallback callback_on_origin_loop =
731320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      base::Bind(&CallBackOnOriginLoop,
741320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                 base::ThreadTaskRunnerHandle::Get(),
751320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                 callback_to_this);
761320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
771320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // This is the actual function that imports the certificates.
781320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  base::Closure import_certs_callback =
791320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      base::Bind(&ParseAndStoreCertificates,
801320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                 source,
811320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                 callback_on_origin_loop,
821320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                 base::Owned(certificates.DeepCopy()),
831320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                 target_nssdb_);
841320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
851320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // The NSSCertDatabase must be accessed on |io_task_runner_|
861320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  io_task_runner_->PostTask(FROM_HERE, import_certs_callback);
871320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
88558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
891320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// static
901320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid CertificateImporterImpl::ParseAndStoreCertificates(
911320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    ::onc::ONCSource source,
921320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    const DoneCallback& done_callback,
931320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    base::ListValue* certificates,
941320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    net::NSSCertDatabase* nssdb) {
95558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  // Web trust is only granted to certificates imported by the user.
964e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  bool allow_trust_imports = source == ::onc::ONC_SOURCE_USER_IMPORT;
971320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  net::CertificateList onc_trusted_certificates;
98558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  bool success = true;
991320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  for (size_t i = 0; i < certificates->GetSize(); ++i) {
1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const base::DictionaryValue* certificate = NULL;
1011320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    certificates->GetDictionary(i, &certificate);
1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DCHECK(certificate != NULL);
1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    VLOG(2) << "Parsing certificate at index " << i << ": " << *certificate;
1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
106558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    if (!ParseAndStoreCertificate(allow_trust_imports,
107558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch                                  *certificate,
1081320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                  nssdb,
1091320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                  &onc_trusted_certificates)) {
110558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      success = false;
1111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      LOG(ERROR) << "Cannot parse certificate at index " << i;
1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    } else {
1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      VLOG(2) << "Successfully imported certificate at index " << i;
1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  done_callback.Run(success, onc_trusted_certificates);
1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// static
1215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void CertificateImporterImpl::ListCertsWithNickname(
1225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const std::string& label,
1235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    net::CertificateList* result,
1245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    net::NSSCertDatabase* target_nssdb) {
1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  net::CertificateList all_certs;
1265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // TODO(tbarzic): Use async |ListCerts|.
1275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  target_nssdb->ListCertsSync(&all_certs);
1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  result->clear();
1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (net::CertificateList::iterator iter = all_certs.begin();
1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)       iter != all_certs.end(); ++iter) {
1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (iter->get()->os_cert_handle()->nickname) {
1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // Separate the nickname stored in the certificate at the colon, since
1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // NSS likes to store it as token:nickname.
1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      const char* delimiter =
1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          ::strchr(iter->get()->os_cert_handle()->nickname, ':');
1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (delimiter) {
1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        ++delimiter;  // move past the colon.
1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        if (strcmp(delimiter, label.c_str()) == 0) {
1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          result->push_back(*iter);
1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          continue;
1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        }
1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Now we find the private key for this certificate and see if it has a
1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // nickname that matches.  If there is a private key, and it matches,
1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // then this is a client cert that we are looking for.
1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    SECKEYPrivateKey* private_key = PK11_FindPrivateKeyFromCert(
1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        iter->get()->os_cert_handle()->slot,
1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        iter->get()->os_cert_handle(),
1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        NULL);  // wincx
1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (private_key) {
1522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      char* private_key_nickname = PK11_GetPrivateKeyNickname(private_key);
1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (private_key_nickname && std::string(label) == private_key_nickname)
1542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        result->push_back(*iter);
1552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      PORT_Free(private_key_nickname);
1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      SECKEY_DestroyPrivateKey(private_key);
1572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// static
162558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdochbool CertificateImporterImpl::DeleteCertAndKeyByNickname(
1635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const std::string& label,
1645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    net::NSSCertDatabase* target_nssdb) {
1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  net::CertificateList cert_list;
1665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ListCertsWithNickname(label, &cert_list, target_nssdb);
1672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool result = true;
1682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (net::CertificateList::iterator iter = cert_list.begin();
1692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)       iter != cert_list.end(); ++iter) {
1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // If we fail, we try and delete the rest still.
1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // TODO(gspencer): this isn't very "transactional".  If we fail on some, but
1722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // not all, then it's possible to leave things in a weird state.
1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Luckily there should only be one cert with a particular
1742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // label, and the cert not being found is one of the few reasons the
1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // delete could fail, but still...  The other choice is to return
1762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // failure immediately, but that doesn't seem to do what is intended.
1775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (!target_nssdb->DeleteCertAndKey(iter->get()))
1782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      result = false;
1792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return result;
1812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1831320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid CertificateImporterImpl::RunDoneCallback(
1841320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    const CertificateImporter::DoneCallback& callback,
1851320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    bool success,
1861320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    const net::CertificateList& onc_trusted_certificates) {
1871320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (!success)
1881320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    NET_LOG_ERROR("ONC Certificate Import Error", "");
1891320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  callback.Run(success, onc_trusted_certificates);
1901320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
1911320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
192558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdochbool CertificateImporterImpl::ParseAndStoreCertificate(
193558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    bool allow_trust_imports,
194c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const base::DictionaryValue& certificate,
1951320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    net::NSSCertDatabase* nssdb,
1961320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    net::CertificateList* onc_trusted_certificates) {
197c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Get out the attributes of the given certificate.
198c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  std::string guid;
1994e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  certificate.GetStringWithoutPathExpansion(::onc::certificate::kGUID, &guid);
200c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(!guid.empty());
201c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
202c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  bool remove = false;
2034e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (certificate.GetBooleanWithoutPathExpansion(::onc::kRemove, &remove) &&
2044e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      remove) {
2051320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    if (!DeleteCertAndKeyByNickname(guid, nssdb)) {
2061320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      LOG(ERROR) << "Unable to delete certificate";
207c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      return false;
208c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    } else {
209c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      return true;
210c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
211c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
212c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
213c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Not removing, so let's get the data we need to add this certificate.
214c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  std::string cert_type;
2154e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  certificate.GetStringWithoutPathExpansion(::onc::certificate::kType,
2164e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                            &cert_type);
2174e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (cert_type == ::onc::certificate::kServer ||
2184e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      cert_type == ::onc::certificate::kAuthority) {
219558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    return ParseServerOrCaCertificate(allow_trust_imports,
220558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch                                      cert_type,
221558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch                                      guid,
222558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch                                      certificate,
2231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                      nssdb,
2241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                      onc_trusted_certificates);
2254e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  } else if (cert_type == ::onc::certificate::kClient) {
2261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return ParseClientCertificate(guid, certificate, nssdb);
227c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
228c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
229c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  NOTREACHED();
230c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return false;
231c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
232c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
233558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdochbool CertificateImporterImpl::ParseServerOrCaCertificate(
234558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    bool allow_trust_imports,
2352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& cert_type,
2362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& guid,
237c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const base::DictionaryValue& certificate,
2381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    net::NSSCertDatabase* nssdb,
2391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    net::CertificateList* onc_trusted_certificates) {
240c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  bool web_trust_flag = false;
2412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const base::ListValue* trust_list = NULL;
2424e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (certificate.GetListWithoutPathExpansion(::onc::certificate::kTrustBits,
243c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                              &trust_list)) {
244c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    for (base::ListValue::const_iterator it = trust_list->begin();
245c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)         it != trust_list->end(); ++it) {
2462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      std::string trust_type;
247c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      if (!(*it)->GetAsString(&trust_type))
2482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        NOTREACHED();
2492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2504e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      if (trust_type == ::onc::certificate::kWeb) {
2512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        // "Web" implies that the certificate is to be trusted for SSL
2522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        // identification.
253c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        web_trust_flag = true;
2542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      } else {
255c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        // Trust bits should only increase trust and never restrict. Thus,
256c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        // ignoring unknown bits should be safe.
2571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        LOG(WARNING) << "Certificate contains unknown trust type "
2581320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                     << trust_type;
2592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
2602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
2612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
263c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  bool import_with_ssl_trust = false;
264c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (web_trust_flag) {
265558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    if (!allow_trust_imports)
2661320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      LOG(WARNING) << "Web trust not granted for certificate: " << guid;
267c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    else
268c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      import_with_ssl_trust = true;
2692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string x509_data;
2724e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (!certificate.GetStringWithoutPathExpansion(::onc::certificate::kX509,
273c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                                 &x509_data) ||
2742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      x509_data.empty()) {
2751320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    LOG(ERROR) << "Certificate missing appropriate certificate data for type: "
2761320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci               << cert_type;
2772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
2782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_refptr<net::X509Certificate> x509_cert =
281eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      DecodePEMCertificate(x509_data);
2822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!x509_cert.get()) {
2831320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    LOG(ERROR) << "Unable to create certificate from PEM encoding, type: "
2841320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci               << cert_type;
2852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
2862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
288eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  net::NSSCertDatabase::TrustBits trust = (import_with_ssl_trust ?
289eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                           net::NSSCertDatabase::TRUSTED_SSL :
290eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                           net::NSSCertDatabase::TRUST_DEFAULT);
291eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
2922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (x509_cert->os_cert_handle()->isperm) {
293eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    net::CertType net_cert_type =
2944e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        cert_type == ::onc::certificate::kServer ? net::SERVER_CERT
2954e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                                 : net::CA_CERT;
296eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    VLOG(1) << "Certificate is already installed.";
297eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    net::NSSCertDatabase::TrustBits missing_trust_bits =
2981320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        trust & ~nssdb->GetCertTrust(x509_cert.get(), net_cert_type);
299eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    if (missing_trust_bits) {
300eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      std::string error_reason;
301eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      bool success = false;
3021320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      if (nssdb->IsReadOnly(x509_cert.get())) {
303eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        error_reason = " Certificate is stored read-only.";
304eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      } else {
3051320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        success = nssdb->SetCertTrust(x509_cert.get(), net_cert_type, trust);
306eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      }
307eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      if (!success) {
3081320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        LOG(ERROR) << "Certificate of type " << cert_type
3091320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                   << " was already present, but trust couldn't be set."
3101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                   << error_reason;
311eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      }
312eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    }
313eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  } else {
314eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    net::CertificateList cert_list;
315eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    cert_list.push_back(x509_cert);
316eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    net::NSSCertDatabase::ImportCertFailureList failures;
317eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    bool success = false;
3184e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    if (cert_type == ::onc::certificate::kServer)
3191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      success = nssdb->ImportServerCert(cert_list, trust, &failures);
320eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    else  // Authority cert
3211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      success = nssdb->ImportCACerts(cert_list, trust, &failures);
322eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
323eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    if (!failures.empty()) {
3246e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      std::string error_string = net::ErrorToString(failures[0].net_error);
3251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      LOG(ERROR) << "Error ( " << error_string
3261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                 << " ) importing certificate of type " << cert_type;
3272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return false;
3282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
3292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
330eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    if (!success) {
3311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      LOG(ERROR) << "Unknown error importing " << cert_type << " certificate.";
3322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return false;
3332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
3342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
336c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (web_trust_flag && onc_trusted_certificates)
337c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    onc_trusted_certificates->push_back(x509_cert);
338c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
3392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return true;
3402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
342558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdochbool CertificateImporterImpl::ParseClientCertificate(
3432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& guid,
3441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    const base::DictionaryValue& certificate,
3451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    net::NSSCertDatabase* nssdb) {
3462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string pkcs12_data;
3474e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (!certificate.GetStringWithoutPathExpansion(::onc::certificate::kPKCS12,
348c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                                 &pkcs12_data) ||
3492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      pkcs12_data.empty()) {
3501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    LOG(ERROR) << "PKCS12 data is missing for client certificate.";
3512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
3522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string decoded_pkcs12;
3552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!base::Base64Decode(pkcs12_data, &decoded_pkcs12)) {
3561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    LOG(ERROR) << "Unable to base64 decode PKCS#12 data: \"" << pkcs12_data
3571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci               << "\".";
3582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
3592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Since this has a private key, always use the private module.
3621320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  crypto::ScopedPK11Slot private_slot(nssdb->GetPrivateSlot());
363a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (!private_slot)
364a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return false;
365a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  scoped_refptr<net::CryptoModule> module(
366a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      net::CryptoModule::CreateFromHandle(private_slot.get()));
3672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  net::CertificateList imported_certs;
3682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3691320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  int import_result = nssdb->ImportFromPKCS12(
3705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      module.get(), decoded_pkcs12, base::string16(), false, &imported_certs);
3712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (import_result != net::OK) {
3726e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    std::string error_string = net::ErrorToString(import_result);
3731320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    LOG(ERROR) << "Unable to import client certificate, error: "
3741320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci               << error_string;
3752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
3762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (imported_certs.size() == 0) {
3791320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    LOG(WARNING) << "PKCS12 data contains no importable certificates.";
3802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return true;
3812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (imported_certs.size() != 1) {
3841320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    LOG(WARNING) << "ONC File: PKCS12 data contains more than one certificate. "
3851320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                    "Only the first one will be imported.";
3862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_refptr<net::X509Certificate> cert_result = imported_certs[0];
3892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Find the private key associated with this certificate, and set the
3912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // nickname on it.
3922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  SECKEYPrivateKey* private_key = PK11_FindPrivateKeyFromCert(
3932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      cert_result->os_cert_handle()->slot,
3942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      cert_result->os_cert_handle(),
3952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      NULL);  // wincx
3962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (private_key) {
3972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    PK11_SetPrivateKeyNickname(private_key, const_cast<char*>(guid.c_str()));
3982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    SECKEY_DestroyPrivateKey(private_key);
3992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else {
4001320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    LOG(WARNING) << "Unable to find private key for certificate.";
4012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
4022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return true;
4032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace onc
4062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace chromeos
407