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

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

Issue 16946002: Resolve certificate references in ONC by PEM. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: removed automation part. Created 7 years, 6 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 (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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.h" 5 #include "chromeos/network/onc/onc_certificate_importer.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 24 matching lines...) Expand all
35 35
36 namespace chromeos { 36 namespace chromeos {
37 namespace onc { 37 namespace onc {
38 38
39 CertificateImporter::CertificateImporter(bool allow_trust_imports) 39 CertificateImporter::CertificateImporter(bool allow_trust_imports)
40 : allow_trust_imports_(allow_trust_imports) { 40 : allow_trust_imports_(allow_trust_imports) {
41 } 41 }
42 42
43 CertificateImporter::ParseResult CertificateImporter::ParseAndStoreCertificates( 43 CertificateImporter::ParseResult CertificateImporter::ParseAndStoreCertificates(
44 const base::ListValue& certificates, 44 const base::ListValue& certificates,
45 net::CertificateList* onc_trusted_certificates) { 45 net::CertificateList* onc_trusted_certificates,
46 CertsByGUID* imported_server_and_ca_certs) {
46 size_t successful_imports = 0; 47 size_t successful_imports = 0;
47 for (size_t i = 0; i < certificates.GetSize(); ++i) { 48 for (size_t i = 0; i < certificates.GetSize(); ++i) {
48 const base::DictionaryValue* certificate = NULL; 49 const base::DictionaryValue* certificate = NULL;
49 certificates.GetDictionary(i, &certificate); 50 certificates.GetDictionary(i, &certificate);
50 DCHECK(certificate != NULL); 51 DCHECK(certificate != NULL);
51 52
52 VLOG(2) << "Parsing certificate at index " << i << ": " << *certificate; 53 VLOG(2) << "Parsing certificate at index " << i << ": " << *certificate;
53 54
54 if (!ParseAndStoreCertificate(*certificate, onc_trusted_certificates)) { 55 if (!ParseAndStoreCertificate(*certificate, onc_trusted_certificates,
56 imported_server_and_ca_certs)) {
55 ONC_LOG_ERROR( 57 ONC_LOG_ERROR(
56 base::StringPrintf("Cannot parse certificate at index %zu", i)); 58 base::StringPrintf("Cannot parse certificate at index %zu", i));
57 } else { 59 } else {
58 VLOG(2) << "Successfully imported certificate at index " << i; 60 VLOG(2) << "Successfully imported certificate at index " << i;
59 ++successful_imports; 61 ++successful_imports;
60 } 62 }
61 } 63 }
62 64
63 if (successful_imports == certificates.GetSize()) { 65 if (successful_imports == certificates.GetSize()) {
64 return IMPORT_OK; 66 return IMPORT_OK;
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
122 // delete could fail, but still... The other choice is to return 124 // delete could fail, but still... The other choice is to return
123 // failure immediately, but that doesn't seem to do what is intended. 125 // failure immediately, but that doesn't seem to do what is intended.
124 if (!net::NSSCertDatabase::GetInstance()->DeleteCertAndKey(iter->get())) 126 if (!net::NSSCertDatabase::GetInstance()->DeleteCertAndKey(iter->get()))
125 result = false; 127 result = false;
126 } 128 }
127 return result; 129 return result;
128 } 130 }
129 131
130 bool CertificateImporter::ParseAndStoreCertificate( 132 bool CertificateImporter::ParseAndStoreCertificate(
131 const base::DictionaryValue& certificate, 133 const base::DictionaryValue& certificate,
132 net::CertificateList* onc_trusted_certificates) { 134 net::CertificateList* onc_trusted_certificates,
135 CertsByGUID* imported_server_and_ca_certs) {
133 // Get out the attributes of the given certificate. 136 // Get out the attributes of the given certificate.
134 std::string guid; 137 std::string guid;
135 certificate.GetStringWithoutPathExpansion(certificate::kGUID, &guid); 138 certificate.GetStringWithoutPathExpansion(certificate::kGUID, &guid);
136 DCHECK(!guid.empty()); 139 DCHECK(!guid.empty());
137 140
138 bool remove = false; 141 bool remove = false;
139 if (certificate.GetBooleanWithoutPathExpansion(kRemove, &remove) && remove) { 142 if (certificate.GetBooleanWithoutPathExpansion(kRemove, &remove) && remove) {
140 if (!DeleteCertAndKeyByNickname(guid)) { 143 if (!DeleteCertAndKeyByNickname(guid)) {
141 ONC_LOG_ERROR("Unable to delete certificate"); 144 ONC_LOG_ERROR("Unable to delete certificate");
142 return false; 145 return false;
143 } else { 146 } else {
144 return true; 147 return true;
145 } 148 }
146 } 149 }
147 150
148 // Not removing, so let's get the data we need to add this certificate. 151 // Not removing, so let's get the data we need to add this certificate.
149 std::string cert_type; 152 std::string cert_type;
150 certificate.GetStringWithoutPathExpansion(certificate::kType, &cert_type); 153 certificate.GetStringWithoutPathExpansion(certificate::kType, &cert_type);
151 if (cert_type == certificate::kServer || 154 if (cert_type == certificate::kServer ||
152 cert_type == certificate::kAuthority) { 155 cert_type == certificate::kAuthority) {
153 return ParseServerOrCaCertificate( 156 return ParseServerOrCaCertificate(cert_type, guid, certificate,
154 cert_type, guid, certificate, onc_trusted_certificates); 157 onc_trusted_certificates,
158 imported_server_and_ca_certs);
155 } else if (cert_type == certificate::kClient) { 159 } else if (cert_type == certificate::kClient) {
156 return ParseClientCertificate(guid, certificate); 160 return ParseClientCertificate(guid, certificate);
157 } 161 }
158 162
159 NOTREACHED(); 163 NOTREACHED();
160 return false; 164 return false;
161 } 165 }
162 166
163 bool CertificateImporter::ParseServerOrCaCertificate( 167 bool CertificateImporter::ParseServerOrCaCertificate(
164 const std::string& cert_type, 168 const std::string& cert_type,
165 const std::string& guid, 169 const std::string& guid,
166 const base::DictionaryValue& certificate, 170 const base::DictionaryValue& certificate,
167 net::CertificateList* onc_trusted_certificates) { 171 net::CertificateList* onc_trusted_certificates,
172 CertsByGUID* imported_server_and_ca_certs) {
168 bool web_trust_flag = false; 173 bool web_trust_flag = false;
169 const base::ListValue* trust_list = NULL; 174 const base::ListValue* trust_list = NULL;
170 if (certificate.GetListWithoutPathExpansion(certificate::kTrustBits, 175 if (certificate.GetListWithoutPathExpansion(certificate::kTrustBits,
171 &trust_list)) { 176 &trust_list)) {
172 for (base::ListValue::const_iterator it = trust_list->begin(); 177 for (base::ListValue::const_iterator it = trust_list->begin();
173 it != trust_list->end(); ++it) { 178 it != trust_list->end(); ++it) {
174 std::string trust_type; 179 std::string trust_type;
175 if (!(*it)->GetAsString(&trust_type)) 180 if (!(*it)->GetAsString(&trust_type))
176 NOTREACHED(); 181 NOTREACHED();
177 182
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
221 // only contain the base64-encoded data. 226 // only contain the base64-encoded data.
222 if (!base::Base64Decode(x509_data, &decoded_x509)) { 227 if (!base::Base64Decode(x509_data, &decoded_x509)) {
223 ONC_LOG_ERROR("Unable to base64 decode X509 data: " + x509_data); 228 ONC_LOG_ERROR("Unable to base64 decode X509 data: " + x509_data);
224 return false; 229 return false;
225 } 230 }
226 } else { 231 } else {
227 decoded_x509 = pem_tokenizer.data(); 232 decoded_x509 = pem_tokenizer.data();
228 } 233 }
229 234
230 scoped_refptr<net::X509Certificate> x509_cert = 235 scoped_refptr<net::X509Certificate> x509_cert =
231 net::X509Certificate::CreateFromBytesWithNickname( 236 net::X509Certificate::CreateFromBytes(decoded_x509.data(),
232 decoded_x509.data(), 237 decoded_x509.size());
233 decoded_x509.size(),
234 guid.c_str());
235 if (!x509_cert.get()) { 238 if (!x509_cert.get()) {
236 ONC_LOG_ERROR("Unable to create X509 certificate from bytes."); 239 ONC_LOG_ERROR("Unable to create X509 certificate from bytes.");
237 return false; 240 return false;
238 } 241 }
239 242
240 // Due to a mismatch regarding cert identity between NSS (cert identity is
241 // determined by the raw bytes) and ONC (cert identity is determined by
242 // GUIDs), we have to special-case a number of situations here:
243 //
244 // a) The cert bits we're trying to insert are already present in the NSS cert
245 // store. This is indicated by the isperm bit in CERTCertificateStr. Since
246 // we might have to update the nick name, we just delete the existing cert
247 // and reimport the cert bits.
248 // b) NSS gives us an actual temporary certificate. In this case, there is no
249 // identical certificate known to NSS, so we can safely import the
250 // certificate. The GUID being imported may still be on a different
251 // certificate, and we could jump through hoops to reimport the existing
252 // certificate with a different nickname. However, that would mean lots of
253 // effort for a case that's pretty much illegal (reusing GUIDs contradicts
254 // the intention of GUIDs), so we just report an error.
255 //
256 // TODO(mnissler, gspencer): We should probably switch to a mode where we
257 // keep our own database for mapping GUIDs to certs in order to enable several
258 // GUIDs to map to the same cert. See http://crosbug.com/26073.
259 net::NSSCertDatabase* cert_database = net::NSSCertDatabase::GetInstance();
260 if (x509_cert->os_cert_handle()->isperm) {
261 if (!cert_database->DeleteCertAndKey(x509_cert.get())) {
262 ONC_LOG_ERROR("Unable to delete X509 certificate.");
263 return false;
264 }
265
266 // Reload the cert here to get an actual temporary cert instance.
267 x509_cert = net::X509Certificate::CreateFromBytesWithNickname(
268 decoded_x509.data(),
269 decoded_x509.size(),
270 guid.c_str());
271 if (!x509_cert.get()) {
272 ONC_LOG_ERROR("Unable to create X509 certificate from bytes.");
273 return false;
274 }
275 DCHECK(!x509_cert->os_cert_handle()->isperm);
276 DCHECK(x509_cert->os_cert_handle()->istemp);
277 }
278
279 // Make sure the GUID is not already taken. Note that for the reimport case we
280 // have removed the existing cert above.
281 net::CertificateList certs;
282 ListCertsWithNickname(guid, &certs);
283 if (!certs.empty()) {
284 ONC_LOG_ERROR("Certificate GUID is already in use: " + guid);
285 return false;
286 }
287
288 net::CertificateList cert_list;
289 cert_list.push_back(x509_cert);
290 net::NSSCertDatabase::ImportCertFailureList failures;
291 bool success = false;
292 net::NSSCertDatabase::TrustBits trust = import_with_ssl_trust ? 243 net::NSSCertDatabase::TrustBits trust = import_with_ssl_trust ?
293 net::NSSCertDatabase::TRUSTED_SSL : 244 net::NSSCertDatabase::TRUSTED_SSL :
294 net::NSSCertDatabase::TRUST_DEFAULT; 245 net::NSSCertDatabase::TRUST_DEFAULT;
295 if (cert_type == certificate::kServer) {
296 success = cert_database->ImportServerCert(cert_list, trust, &failures);
297 } else { // Authority cert
298 success = cert_database->ImportCACerts(cert_list, trust, &failures);
299 }
300 246
301 if (!failures.empty()) { 247 net::NSSCertDatabase* cert_database = net::NSSCertDatabase::GetInstance();
302 ONC_LOG_ERROR(base::StringPrintf("Error ( %s ) importing %s certificate", 248 if (x509_cert->os_cert_handle()->isperm) {
303 net::ErrorToString(failures[0].net_error), 249 VLOG(1) << "Certificate is already installed.";
304 cert_type.c_str())); 250 if (!cert_database->SetCertTrust(
305 return false; 251 x509_cert,
306 } 252 cert_type == certificate::kServer ? net::SERVER_CERT : net::CA_CERT,
307 if (!success) { 253 trust)) {
308 ONC_LOG_ERROR("Unknown error importing " + cert_type + " certificate."); 254 ONC_LOG_ERROR("Certificate of type " + cert_type +
309 return false; 255 " was already present, but trust couldn't be set.");
256 }
257 } else {
258 net::CertificateList cert_list;
259 cert_list.push_back(x509_cert);
260 net::NSSCertDatabase::ImportCertFailureList failures;
261 bool success = false;
262 if (cert_type == certificate::kServer)
263 success = cert_database->ImportServerCert(cert_list, trust, &failures);
264 else // Authority cert
265 success = cert_database->ImportCACerts(cert_list, trust, &failures);
266
267 if (!failures.empty()) {
268 ONC_LOG_ERROR(
269 base::StringPrintf("Error ( %s ) importing %s certificate",
270 net::ErrorToString(failures[0].net_error),
271 cert_type.c_str()));
272 return false;
273 }
274 if (!success) {
275 ONC_LOG_ERROR("Unknown error importing " + cert_type + " certificate.");
276 return false;
277 }
310 } 278 }
311 279
312 if (web_trust_flag && onc_trusted_certificates) 280 if (web_trust_flag && onc_trusted_certificates)
313 onc_trusted_certificates->push_back(x509_cert); 281 onc_trusted_certificates->push_back(x509_cert);
314 282
283 if (imported_server_and_ca_certs)
284 (*imported_server_and_ca_certs)[guid] = x509_cert;
285
315 return true; 286 return true;
316 } 287 }
317 288
318 bool CertificateImporter::ParseClientCertificate( 289 bool CertificateImporter::ParseClientCertificate(
319 const std::string& guid, 290 const std::string& guid,
320 const base::DictionaryValue& certificate) { 291 const base::DictionaryValue& certificate) {
321 std::string pkcs12_data; 292 std::string pkcs12_data;
322 if (!certificate.GetStringWithoutPathExpansion(certificate::kPKCS12, 293 if (!certificate.GetStringWithoutPathExpansion(certificate::kPKCS12,
323 &pkcs12_data) || 294 &pkcs12_data) ||
324 pkcs12_data.empty()) { 295 pkcs12_data.empty()) {
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
369 PK11_SetPrivateKeyNickname(private_key, const_cast<char*>(guid.c_str())); 340 PK11_SetPrivateKeyNickname(private_key, const_cast<char*>(guid.c_str()));
370 SECKEY_DestroyPrivateKey(private_key); 341 SECKEY_DestroyPrivateKey(private_key);
371 } else { 342 } else {
372 ONC_LOG_WARNING("Unable to find private key for certificate."); 343 ONC_LOG_WARNING("Unable to find private key for certificate.");
373 } 344 }
374 return true; 345 return true;
375 } 346 }
376 347
377 } // namespace onc 348 } // namespace onc
378 } // namespace chromeos 349 } // namespace chromeos
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698