Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(804)

Side by Side Diff: chromeos/network/onc/onc_certificate_importer_impl.cc

Issue 148183013: Use per-user nssdb in onc certificate importer (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: . Created 6 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chromeos/network/onc/onc_certificate_importer_impl.h" 5 #include "chromeos/network/onc/onc_certificate_importer_impl.h"
6 6
7 #include <cert.h> 7 #include <cert.h>
8 #include <keyhi.h> 8 #include <keyhi.h>
9 #include <pk11pub.h> 9 #include <pk11pub.h>
10 10
(...skipping 15 matching lines...) Expand all
26 26
27 namespace chromeos { 27 namespace chromeos {
28 namespace onc { 28 namespace onc {
29 29
30 CertificateImporterImpl::CertificateImporterImpl() { 30 CertificateImporterImpl::CertificateImporterImpl() {
31 } 31 }
32 32
33 bool CertificateImporterImpl::ImportCertificates( 33 bool CertificateImporterImpl::ImportCertificates(
34 const base::ListValue& certificates, 34 const base::ListValue& certificates,
35 ::onc::ONCSource source, 35 ::onc::ONCSource source,
36 net::NSSCertDatabase* target_nssdb,
36 net::CertificateList* onc_trusted_certificates) { 37 net::CertificateList* onc_trusted_certificates) {
37 VLOG(2) << "ONC file has " << certificates.GetSize() << " certificates"; 38 VLOG(2) << "ONC file has " << certificates.GetSize() << " certificates";
38 39
39 // Web trust is only granted to certificates imported by the user. 40 // Web trust is only granted to certificates imported by the user.
40 bool allow_trust_imports = source == ::onc::ONC_SOURCE_USER_IMPORT; 41 bool allow_trust_imports = source == ::onc::ONC_SOURCE_USER_IMPORT;
41 if (!ParseAndStoreCertificates( 42 if (!ParseAndStoreCertificates(allow_trust_imports,
42 allow_trust_imports, certificates, onc_trusted_certificates, NULL)) { 43 certificates,
44 onc_trusted_certificates,
45 target_nssdb,
46 NULL)) {
43 LOG(ERROR) << "Cannot parse some of the certificates in the ONC from " 47 LOG(ERROR) << "Cannot parse some of the certificates in the ONC from "
44 << onc::GetSourceAsString(source); 48 << onc::GetSourceAsString(source);
45 return false; 49 return false;
46 } 50 }
47 return true; 51 return true;
48 } 52 }
49 53
50 bool CertificateImporterImpl::ParseAndStoreCertificates( 54 bool CertificateImporterImpl::ParseAndStoreCertificates(
51 bool allow_trust_imports, 55 bool allow_trust_imports,
52 const base::ListValue& certificates, 56 const base::ListValue& certificates,
53 net::CertificateList* onc_trusted_certificates, 57 net::CertificateList* onc_trusted_certificates,
58 net::NSSCertDatabase* target_nssdb,
54 CertsByGUID* imported_server_and_ca_certs) { 59 CertsByGUID* imported_server_and_ca_certs) {
60 DCHECK(target_nssdb);
61
55 bool success = true; 62 bool success = true;
56 for (size_t i = 0; i < certificates.GetSize(); ++i) { 63 for (size_t i = 0; i < certificates.GetSize(); ++i) {
57 const base::DictionaryValue* certificate = NULL; 64 const base::DictionaryValue* certificate = NULL;
58 certificates.GetDictionary(i, &certificate); 65 certificates.GetDictionary(i, &certificate);
59 DCHECK(certificate != NULL); 66 DCHECK(certificate != NULL);
60 67
61 VLOG(2) << "Parsing certificate at index " << i << ": " << *certificate; 68 VLOG(2) << "Parsing certificate at index " << i << ": " << *certificate;
62 69
63 if (!ParseAndStoreCertificate(allow_trust_imports, 70 if (!ParseAndStoreCertificate(allow_trust_imports,
64 *certificate, 71 *certificate,
65 onc_trusted_certificates, 72 onc_trusted_certificates,
73 target_nssdb,
66 imported_server_and_ca_certs)) { 74 imported_server_and_ca_certs)) {
67 success = false; 75 success = false;
68 ONC_LOG_ERROR( 76 ONC_LOG_ERROR(
69 base::StringPrintf("Cannot parse certificate at index %zu", i)); 77 base::StringPrintf("Cannot parse certificate at index %zu", i));
70 } else { 78 } else {
71 VLOG(2) << "Successfully imported certificate at index " << i; 79 VLOG(2) << "Successfully imported certificate at index " << i;
72 } 80 }
73 } 81 }
74 return success; 82 return success;
75 } 83 }
76 84
77 // static 85 // static
78 void CertificateImporterImpl::ListCertsWithNickname(const std::string& label, 86 void CertificateImporterImpl::ListCertsWithNickname(
79 net::CertificateList* result) { 87 const std::string& label,
88 net::CertificateList* result,
89 net::NSSCertDatabase* target_nssdb) {
80 net::CertificateList all_certs; 90 net::CertificateList all_certs;
81 net::NSSCertDatabase::GetInstance()->ListCerts(&all_certs); 91 target_nssdb->ListCerts(&all_certs);
82 result->clear(); 92 result->clear();
83 for (net::CertificateList::iterator iter = all_certs.begin(); 93 for (net::CertificateList::iterator iter = all_certs.begin();
84 iter != all_certs.end(); ++iter) { 94 iter != all_certs.end(); ++iter) {
85 if (iter->get()->os_cert_handle()->nickname) { 95 if (iter->get()->os_cert_handle()->nickname) {
86 // Separate the nickname stored in the certificate at the colon, since 96 // Separate the nickname stored in the certificate at the colon, since
87 // NSS likes to store it as token:nickname. 97 // NSS likes to store it as token:nickname.
88 const char* delimiter = 98 const char* delimiter =
89 ::strchr(iter->get()->os_cert_handle()->nickname, ':'); 99 ::strchr(iter->get()->os_cert_handle()->nickname, ':');
90 if (delimiter) { 100 if (delimiter) {
91 ++delimiter; // move past the colon. 101 ++delimiter; // move past the colon.
(...skipping 15 matching lines...) Expand all
107 if (private_key_nickname && std::string(label) == private_key_nickname) 117 if (private_key_nickname && std::string(label) == private_key_nickname)
108 result->push_back(*iter); 118 result->push_back(*iter);
109 PORT_Free(private_key_nickname); 119 PORT_Free(private_key_nickname);
110 SECKEY_DestroyPrivateKey(private_key); 120 SECKEY_DestroyPrivateKey(private_key);
111 } 121 }
112 } 122 }
113 } 123 }
114 124
115 // static 125 // static
116 bool CertificateImporterImpl::DeleteCertAndKeyByNickname( 126 bool CertificateImporterImpl::DeleteCertAndKeyByNickname(
117 const std::string& label) { 127 const std::string& label,
128 net::NSSCertDatabase* target_nssdb) {
118 net::CertificateList cert_list; 129 net::CertificateList cert_list;
119 ListCertsWithNickname(label, &cert_list); 130 ListCertsWithNickname(label, &cert_list, target_nssdb);
120 bool result = true; 131 bool result = true;
121 for (net::CertificateList::iterator iter = cert_list.begin(); 132 for (net::CertificateList::iterator iter = cert_list.begin();
122 iter != cert_list.end(); ++iter) { 133 iter != cert_list.end(); ++iter) {
123 // If we fail, we try and delete the rest still. 134 // If we fail, we try and delete the rest still.
124 // TODO(gspencer): this isn't very "transactional". If we fail on some, but 135 // TODO(gspencer): this isn't very "transactional". If we fail on some, but
125 // not all, then it's possible to leave things in a weird state. 136 // not all, then it's possible to leave things in a weird state.
126 // Luckily there should only be one cert with a particular 137 // Luckily there should only be one cert with a particular
127 // label, and the cert not being found is one of the few reasons the 138 // label, and the cert not being found is one of the few reasons the
128 // delete could fail, but still... The other choice is to return 139 // delete could fail, but still... The other choice is to return
129 // failure immediately, but that doesn't seem to do what is intended. 140 // failure immediately, but that doesn't seem to do what is intended.
130 if (!net::NSSCertDatabase::GetInstance()->DeleteCertAndKey(iter->get())) 141 if (!target_nssdb->DeleteCertAndKey(iter->get()))
131 result = false; 142 result = false;
132 } 143 }
133 return result; 144 return result;
134 } 145 }
135 146
136 bool CertificateImporterImpl::ParseAndStoreCertificate( 147 bool CertificateImporterImpl::ParseAndStoreCertificate(
137 bool allow_trust_imports, 148 bool allow_trust_imports,
138 const base::DictionaryValue& certificate, 149 const base::DictionaryValue& certificate,
139 net::CertificateList* onc_trusted_certificates, 150 net::CertificateList* onc_trusted_certificates,
151 net::NSSCertDatabase* target_nssdb,
140 CertsByGUID* imported_server_and_ca_certs) { 152 CertsByGUID* imported_server_and_ca_certs) {
141 // Get out the attributes of the given certificate. 153 // Get out the attributes of the given certificate.
142 std::string guid; 154 std::string guid;
143 certificate.GetStringWithoutPathExpansion(::onc::certificate::kGUID, &guid); 155 certificate.GetStringWithoutPathExpansion(::onc::certificate::kGUID, &guid);
144 DCHECK(!guid.empty()); 156 DCHECK(!guid.empty());
145 157
146 bool remove = false; 158 bool remove = false;
147 if (certificate.GetBooleanWithoutPathExpansion(::onc::kRemove, &remove) && 159 if (certificate.GetBooleanWithoutPathExpansion(::onc::kRemove, &remove) &&
148 remove) { 160 remove) {
149 if (!DeleteCertAndKeyByNickname(guid)) { 161 if (!DeleteCertAndKeyByNickname(guid, target_nssdb)) {
150 ONC_LOG_ERROR("Unable to delete certificate"); 162 ONC_LOG_ERROR("Unable to delete certificate");
151 return false; 163 return false;
152 } else { 164 } else {
153 return true; 165 return true;
154 } 166 }
155 } 167 }
156 168
157 // Not removing, so let's get the data we need to add this certificate. 169 // Not removing, so let's get the data we need to add this certificate.
158 std::string cert_type; 170 std::string cert_type;
159 certificate.GetStringWithoutPathExpansion(::onc::certificate::kType, 171 certificate.GetStringWithoutPathExpansion(::onc::certificate::kType,
160 &cert_type); 172 &cert_type);
161 if (cert_type == ::onc::certificate::kServer || 173 if (cert_type == ::onc::certificate::kServer ||
162 cert_type == ::onc::certificate::kAuthority) { 174 cert_type == ::onc::certificate::kAuthority) {
163 return ParseServerOrCaCertificate(allow_trust_imports, 175 return ParseServerOrCaCertificate(allow_trust_imports,
164 cert_type, 176 cert_type,
165 guid, 177 guid,
166 certificate, 178 certificate,
167 onc_trusted_certificates, 179 onc_trusted_certificates,
180 target_nssdb,
168 imported_server_and_ca_certs); 181 imported_server_and_ca_certs);
169 } else if (cert_type == ::onc::certificate::kClient) { 182 } else if (cert_type == ::onc::certificate::kClient) {
170 return ParseClientCertificate(guid, certificate); 183 return ParseClientCertificate(guid, certificate, target_nssdb);
171 } 184 }
172 185
173 NOTREACHED(); 186 NOTREACHED();
174 return false; 187 return false;
175 } 188 }
176 189
177 bool CertificateImporterImpl::ParseServerOrCaCertificate( 190 bool CertificateImporterImpl::ParseServerOrCaCertificate(
178 bool allow_trust_imports, 191 bool allow_trust_imports,
179 const std::string& cert_type, 192 const std::string& cert_type,
180 const std::string& guid, 193 const std::string& guid,
181 const base::DictionaryValue& certificate, 194 const base::DictionaryValue& certificate,
182 net::CertificateList* onc_trusted_certificates, 195 net::CertificateList* onc_trusted_certificates,
196 net::NSSCertDatabase* target_nssdb,
183 CertsByGUID* imported_server_and_ca_certs) { 197 CertsByGUID* imported_server_and_ca_certs) {
184 bool web_trust_flag = false; 198 bool web_trust_flag = false;
185 const base::ListValue* trust_list = NULL; 199 const base::ListValue* trust_list = NULL;
186 if (certificate.GetListWithoutPathExpansion(::onc::certificate::kTrustBits, 200 if (certificate.GetListWithoutPathExpansion(::onc::certificate::kTrustBits,
187 &trust_list)) { 201 &trust_list)) {
188 for (base::ListValue::const_iterator it = trust_list->begin(); 202 for (base::ListValue::const_iterator it = trust_list->begin();
189 it != trust_list->end(); ++it) { 203 it != trust_list->end(); ++it) {
190 std::string trust_type; 204 std::string trust_type;
191 if (!(*it)->GetAsString(&trust_type)) 205 if (!(*it)->GetAsString(&trust_type))
192 NOTREACHED(); 206 NOTREACHED();
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
227 if (!x509_cert.get()) { 241 if (!x509_cert.get()) {
228 ONC_LOG_ERROR("Unable to create certificate from PEM encoding, type: " + 242 ONC_LOG_ERROR("Unable to create certificate from PEM encoding, type: " +
229 cert_type); 243 cert_type);
230 return false; 244 return false;
231 } 245 }
232 246
233 net::NSSCertDatabase::TrustBits trust = (import_with_ssl_trust ? 247 net::NSSCertDatabase::TrustBits trust = (import_with_ssl_trust ?
234 net::NSSCertDatabase::TRUSTED_SSL : 248 net::NSSCertDatabase::TRUSTED_SSL :
235 net::NSSCertDatabase::TRUST_DEFAULT); 249 net::NSSCertDatabase::TRUST_DEFAULT);
236 250
237 net::NSSCertDatabase* cert_database = net::NSSCertDatabase::GetInstance();
238 if (x509_cert->os_cert_handle()->isperm) { 251 if (x509_cert->os_cert_handle()->isperm) {
239 net::CertType net_cert_type = 252 net::CertType net_cert_type =
240 cert_type == ::onc::certificate::kServer ? net::SERVER_CERT 253 cert_type == ::onc::certificate::kServer ? net::SERVER_CERT
241 : net::CA_CERT; 254 : net::CA_CERT;
242 VLOG(1) << "Certificate is already installed."; 255 VLOG(1) << "Certificate is already installed.";
243 net::NSSCertDatabase::TrustBits missing_trust_bits = 256 net::NSSCertDatabase::TrustBits missing_trust_bits =
244 trust & ~cert_database->GetCertTrust(x509_cert.get(), net_cert_type); 257 trust & ~target_nssdb->GetCertTrust(x509_cert.get(), net_cert_type);
245 if (missing_trust_bits) { 258 if (missing_trust_bits) {
246 std::string error_reason; 259 std::string error_reason;
247 bool success = false; 260 bool success = false;
248 if (cert_database->IsReadOnly(x509_cert.get())) { 261 if (target_nssdb->IsReadOnly(x509_cert.get())) {
249 error_reason = " Certificate is stored read-only."; 262 error_reason = " Certificate is stored read-only.";
250 } else { 263 } else {
251 success = cert_database->SetCertTrust(x509_cert.get(), 264 success = target_nssdb->SetCertTrust(x509_cert.get(),
252 net_cert_type, 265 net_cert_type,
253 trust); 266 trust);
254 } 267 }
255 if (!success) { 268 if (!success) {
256 ONC_LOG_ERROR("Certificate of type " + cert_type + 269 ONC_LOG_ERROR("Certificate of type " + cert_type +
257 " was already present, but trust couldn't be set." + 270 " was already present, but trust couldn't be set." +
258 error_reason); 271 error_reason);
259 } 272 }
260 } 273 }
261 } else { 274 } else {
262 net::CertificateList cert_list; 275 net::CertificateList cert_list;
263 cert_list.push_back(x509_cert); 276 cert_list.push_back(x509_cert);
264 net::NSSCertDatabase::ImportCertFailureList failures; 277 net::NSSCertDatabase::ImportCertFailureList failures;
265 bool success = false; 278 bool success = false;
266 if (cert_type == ::onc::certificate::kServer) 279 if (cert_type == ::onc::certificate::kServer)
267 success = cert_database->ImportServerCert(cert_list, trust, &failures); 280 success = target_nssdb->ImportServerCert(cert_list, trust, &failures);
268 else // Authority cert 281 else // Authority cert
269 success = cert_database->ImportCACerts(cert_list, trust, &failures); 282 success = target_nssdb->ImportCACerts(cert_list, trust, &failures);
270 283
271 if (!failures.empty()) { 284 if (!failures.empty()) {
272 ONC_LOG_ERROR( 285 ONC_LOG_ERROR(
273 base::StringPrintf("Error ( %s ) importing %s certificate", 286 base::StringPrintf("Error ( %s ) importing %s certificate",
274 net::ErrorToString(failures[0].net_error), 287 net::ErrorToString(failures[0].net_error),
275 cert_type.c_str())); 288 cert_type.c_str()));
276 return false; 289 return false;
277 } 290 }
278 291
279 if (!success) { 292 if (!success) {
280 ONC_LOG_ERROR("Unknown error importing " + cert_type + " certificate."); 293 ONC_LOG_ERROR("Unknown error importing " + cert_type + " certificate.");
281 return false; 294 return false;
282 } 295 }
283 } 296 }
284 297
285 if (web_trust_flag && onc_trusted_certificates) 298 if (web_trust_flag && onc_trusted_certificates)
286 onc_trusted_certificates->push_back(x509_cert); 299 onc_trusted_certificates->push_back(x509_cert);
287 300
288 if (imported_server_and_ca_certs) 301 if (imported_server_and_ca_certs)
289 (*imported_server_and_ca_certs)[guid] = x509_cert; 302 (*imported_server_and_ca_certs)[guid] = x509_cert;
290 303
291 return true; 304 return true;
292 } 305 }
293 306
294 bool CertificateImporterImpl::ParseClientCertificate( 307 bool CertificateImporterImpl::ParseClientCertificate(
295 const std::string& guid, 308 const std::string& guid,
296 const base::DictionaryValue& certificate) { 309 const base::DictionaryValue& certificate,
310 net::NSSCertDatabase* target_nssdb) {
297 std::string pkcs12_data; 311 std::string pkcs12_data;
298 if (!certificate.GetStringWithoutPathExpansion(::onc::certificate::kPKCS12, 312 if (!certificate.GetStringWithoutPathExpansion(::onc::certificate::kPKCS12,
299 &pkcs12_data) || 313 &pkcs12_data) ||
300 pkcs12_data.empty()) { 314 pkcs12_data.empty()) {
301 ONC_LOG_ERROR("PKCS12 data is missing for client certificate."); 315 ONC_LOG_ERROR("PKCS12 data is missing for client certificate.");
302 return false; 316 return false;
303 } 317 }
304 318
305 std::string decoded_pkcs12; 319 std::string decoded_pkcs12;
306 if (!base::Base64Decode(pkcs12_data, &decoded_pkcs12)) { 320 if (!base::Base64Decode(pkcs12_data, &decoded_pkcs12)) {
307 ONC_LOG_ERROR( 321 ONC_LOG_ERROR(
308 "Unable to base64 decode PKCS#12 data: \"" + pkcs12_data + "\"."); 322 "Unable to base64 decode PKCS#12 data: \"" + pkcs12_data + "\".");
309 return false; 323 return false;
310 } 324 }
311 325
312 // Since this has a private key, always use the private module. 326 // Since this has a private key, always use the private module.
313 net::NSSCertDatabase* cert_database = net::NSSCertDatabase::GetInstance(); 327 scoped_refptr<net::CryptoModule> module(net::CryptoModule::CreateFromHandle(
314 scoped_refptr<net::CryptoModule> module(cert_database->GetPrivateModule()); 328 target_nssdb->GetPrivateSlot().get()));
315 net::CertificateList imported_certs; 329 net::CertificateList imported_certs;
316 330
317 int import_result = cert_database->ImportFromPKCS12( 331 int import_result = target_nssdb->ImportFromPKCS12(
318 module.get(), decoded_pkcs12, base::string16(), false, &imported_certs); 332 module.get(), decoded_pkcs12, base::string16(), false, &imported_certs);
319 if (import_result != net::OK) { 333 if (import_result != net::OK) {
320 ONC_LOG_ERROR( 334 ONC_LOG_ERROR(
321 base::StringPrintf("Unable to import client certificate (error %s)", 335 base::StringPrintf("Unable to import client certificate (error %s)",
322 net::ErrorToString(import_result))); 336 net::ErrorToString(import_result)));
323 return false; 337 return false;
324 } 338 }
325 339
326 if (imported_certs.size() == 0) { 340 if (imported_certs.size() == 0) {
327 ONC_LOG_WARNING("PKCS12 data contains no importable certificates."); 341 ONC_LOG_WARNING("PKCS12 data contains no importable certificates.");
(...skipping 17 matching lines...) Expand all
345 PK11_SetPrivateKeyNickname(private_key, const_cast<char*>(guid.c_str())); 359 PK11_SetPrivateKeyNickname(private_key, const_cast<char*>(guid.c_str()));
346 SECKEY_DestroyPrivateKey(private_key); 360 SECKEY_DestroyPrivateKey(private_key);
347 } else { 361 } else {
348 ONC_LOG_WARNING("Unable to find private key for certificate."); 362 ONC_LOG_WARNING("Unable to find private key for certificate.");
349 } 363 }
350 return true; 364 return true;
351 } 365 }
352 366
353 } // namespace onc 367 } // namespace onc
354 } // namespace chromeos 368 } // namespace chromeos
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698