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