OLD | NEW |
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 16 matching lines...) Expand all Loading... |
27 // The PEM block header used for DER certificates | 27 // The PEM block header used for DER certificates |
28 const char kCertificateHeader[] = "CERTIFICATE"; | 28 const char kCertificateHeader[] = "CERTIFICATE"; |
29 // This is an older PEM marker for DER certificates. | 29 // This is an older PEM marker for DER certificates. |
30 const char kX509CertificateHeader[] = "X509 CERTIFICATE"; | 30 const char kX509CertificateHeader[] = "X509 CERTIFICATE"; |
31 | 31 |
32 } // namespace | 32 } // namespace |
33 | 33 |
34 namespace chromeos { | 34 namespace chromeos { |
35 namespace onc { | 35 namespace onc { |
36 | 36 |
37 CertificateImporter::CertificateImporter(bool allow_web_trust) | 37 CertificateImporter::CertificateImporter(bool allow_trust_imports) |
38 : allow_web_trust_(allow_web_trust) { | 38 : allow_trust_imports_(allow_trust_imports) { |
39 } | 39 } |
40 | 40 |
41 CertificateImporter::ParseResult CertificateImporter::ParseAndStoreCertificates( | 41 CertificateImporter::ParseResult CertificateImporter::ParseAndStoreCertificates( |
42 const base::ListValue& certificates) { | 42 const base::ListValue& certificates, |
| 43 net::CertificateList* onc_trusted_certificates) { |
43 size_t successful_imports = 0; | 44 size_t successful_imports = 0; |
44 for (size_t i = 0; i < certificates.GetSize(); ++i) { | 45 for (size_t i = 0; i < certificates.GetSize(); ++i) { |
45 const base::DictionaryValue* certificate = NULL; | 46 const base::DictionaryValue* certificate = NULL; |
46 certificates.GetDictionary(i, &certificate); | 47 certificates.GetDictionary(i, &certificate); |
47 DCHECK(certificate != NULL); | 48 DCHECK(certificate != NULL); |
48 | 49 |
49 VLOG(2) << "Parsing certificate at index " << i << ": " << *certificate; | 50 VLOG(2) << "Parsing certificate at index " << i << ": " << *certificate; |
50 | 51 |
51 if (!ParseAndStoreCertificate(*certificate)) { | 52 if (!ParseAndStoreCertificate(*certificate, onc_trusted_certificates)) { |
52 ONC_LOG_ERROR( | 53 ONC_LOG_ERROR( |
53 base::StringPrintf("Cannot parse certificate at index %zu", i)); | 54 base::StringPrintf("Cannot parse certificate at index %zu", i)); |
54 } else { | 55 } else { |
55 VLOG(2) << "Successfully imported certificate at index " << i; | 56 VLOG(2) << "Successfully imported certificate at index " << i; |
56 ++successful_imports; | 57 ++successful_imports; |
57 } | 58 } |
58 } | 59 } |
59 | 60 |
60 if (successful_imports == certificates.GetSize()) { | 61 if (successful_imports == certificates.GetSize()) { |
61 return IMPORT_OK; | 62 return IMPORT_OK; |
62 } else if (successful_imports == 0) { | 63 } else if (successful_imports == 0) { |
63 return IMPORT_FAILED; | 64 return IMPORT_FAILED; |
64 } else { | 65 } else { |
65 return IMPORT_INCOMPLETE; | 66 return IMPORT_INCOMPLETE; |
66 } | 67 } |
67 } | 68 } |
68 | 69 |
69 bool CertificateImporter::ParseAndStoreCertificate( | |
70 const base::DictionaryValue& certificate) { | |
71 // Get out the attributes of the given certificate. | |
72 std::string guid; | |
73 certificate.GetString(certificate::kGUID, &guid); | |
74 DCHECK(!guid.empty()); | |
75 | |
76 bool remove = false; | |
77 if (certificate.GetBoolean(kRemove, &remove) && remove) { | |
78 if (!DeleteCertAndKeyByNickname(guid)) { | |
79 ONC_LOG_ERROR("Unable to delete certificate"); | |
80 return false; | |
81 } else { | |
82 return true; | |
83 } | |
84 } | |
85 | |
86 // Not removing, so let's get the data we need to add this certificate. | |
87 std::string cert_type; | |
88 certificate.GetString(certificate::kType, &cert_type); | |
89 if (cert_type == certificate::kServer || | |
90 cert_type == certificate::kAuthority) { | |
91 return ParseServerOrCaCertificate(cert_type, guid, certificate); | |
92 } else if (cert_type == certificate::kClient) { | |
93 return ParseClientCertificate(guid, certificate); | |
94 } | |
95 | |
96 NOTREACHED(); | |
97 return false; | |
98 } | |
99 | |
100 // static | 70 // static |
101 void CertificateImporter::ListCertsWithNickname(const std::string& label, | 71 void CertificateImporter::ListCertsWithNickname(const std::string& label, |
102 net::CertificateList* result) { | 72 net::CertificateList* result) { |
103 net::CertificateList all_certs; | 73 net::CertificateList all_certs; |
104 net::NSSCertDatabase::GetInstance()->ListCerts(&all_certs); | 74 net::NSSCertDatabase::GetInstance()->ListCerts(&all_certs); |
105 result->clear(); | 75 result->clear(); |
106 for (net::CertificateList::iterator iter = all_certs.begin(); | 76 for (net::CertificateList::iterator iter = all_certs.begin(); |
107 iter != all_certs.end(); ++iter) { | 77 iter != all_certs.end(); ++iter) { |
108 if (iter->get()->os_cert_handle()->nickname) { | 78 if (iter->get()->os_cert_handle()->nickname) { |
109 // Separate the nickname stored in the certificate at the colon, since | 79 // Separate the nickname stored in the certificate at the colon, since |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
148 // Luckily there should only be one cert with a particular | 118 // Luckily there should only be one cert with a particular |
149 // label, and the cert not being found is one of the few reasons the | 119 // label, and the cert not being found is one of the few reasons the |
150 // delete could fail, but still... The other choice is to return | 120 // delete could fail, but still... The other choice is to return |
151 // failure immediately, but that doesn't seem to do what is intended. | 121 // failure immediately, but that doesn't seem to do what is intended. |
152 if (!net::NSSCertDatabase::GetInstance()->DeleteCertAndKey(iter->get())) | 122 if (!net::NSSCertDatabase::GetInstance()->DeleteCertAndKey(iter->get())) |
153 result = false; | 123 result = false; |
154 } | 124 } |
155 return result; | 125 return result; |
156 } | 126 } |
157 | 127 |
| 128 bool CertificateImporter::ParseAndStoreCertificate( |
| 129 const base::DictionaryValue& certificate, |
| 130 net::CertificateList* onc_trusted_certificates) { |
| 131 // Get out the attributes of the given certificate. |
| 132 std::string guid; |
| 133 certificate.GetString(certificate::kGUID, &guid); |
| 134 DCHECK(!guid.empty()); |
| 135 |
| 136 bool remove = false; |
| 137 if (certificate.GetBoolean(kRemove, &remove) && remove) { |
| 138 if (!DeleteCertAndKeyByNickname(guid)) { |
| 139 ONC_LOG_ERROR("Unable to delete certificate"); |
| 140 return false; |
| 141 } else { |
| 142 return true; |
| 143 } |
| 144 } |
| 145 |
| 146 // Not removing, so let's get the data we need to add this certificate. |
| 147 std::string cert_type; |
| 148 certificate.GetString(certificate::kType, &cert_type); |
| 149 if (cert_type == certificate::kServer || |
| 150 cert_type == certificate::kAuthority) { |
| 151 return ParseServerOrCaCertificate( |
| 152 cert_type, guid, certificate, onc_trusted_certificates); |
| 153 } else if (cert_type == certificate::kClient) { |
| 154 return ParseClientCertificate(guid, certificate); |
| 155 } |
| 156 |
| 157 NOTREACHED(); |
| 158 return false; |
| 159 } |
| 160 |
158 bool CertificateImporter::ParseServerOrCaCertificate( | 161 bool CertificateImporter::ParseServerOrCaCertificate( |
159 const std::string& cert_type, | 162 const std::string& cert_type, |
160 const std::string& guid, | 163 const std::string& guid, |
161 const base::DictionaryValue& certificate) { | 164 const base::DictionaryValue& certificate, |
162 bool web_trust = false; | 165 net::CertificateList* onc_trusted_certificates) { |
| 166 bool web_trust_flag = false; |
163 const base::ListValue* trust_list = NULL; | 167 const base::ListValue* trust_list = NULL; |
164 if (certificate.GetList(certificate::kTrust, &trust_list)) { | 168 if (certificate.GetList(certificate::kTrust, &trust_list)) { |
165 for (size_t i = 0; i < trust_list->GetSize(); ++i) { | 169 for (size_t i = 0; i < trust_list->GetSize(); ++i) { |
166 std::string trust_type; | 170 std::string trust_type; |
167 if (!trust_list->GetString(i, &trust_type)) | 171 if (!trust_list->GetString(i, &trust_type)) |
168 NOTREACHED(); | 172 NOTREACHED(); |
169 | 173 |
170 if (trust_type == certificate::kWeb) { | 174 if (trust_type == certificate::kWeb) { |
171 // "Web" implies that the certificate is to be trusted for SSL | 175 // "Web" implies that the certificate is to be trusted for SSL |
172 // identification. | 176 // identification. |
173 web_trust = true; | 177 web_trust_flag = true; |
174 } else { | 178 } else { |
175 ONC_LOG_ERROR("Certificate contains unknown trust type " + trust_type); | 179 ONC_LOG_ERROR("Certificate contains unknown trust type " + trust_type); |
176 return false; | 180 return false; |
177 } | 181 } |
178 } | 182 } |
179 } | 183 } |
180 | 184 |
181 if (web_trust && !allow_web_trust_) { | 185 bool import_with_ssl_trust = false; |
182 LOG(WARNING) << "Web trust not granted for certificate: " << guid; | 186 if (web_trust_flag) { |
183 web_trust = false; | 187 if (!allow_trust_imports_) |
| 188 LOG(WARNING) << "Web trust not granted for certificate: " << guid; |
| 189 else |
| 190 import_with_ssl_trust = true; |
184 } | 191 } |
185 | 192 |
186 std::string x509_data; | 193 std::string x509_data; |
187 if (!certificate.GetString(certificate::kX509, &x509_data) || | 194 if (!certificate.GetString(certificate::kX509, &x509_data) || |
188 x509_data.empty()) { | 195 x509_data.empty()) { |
189 ONC_LOG_ERROR( | 196 ONC_LOG_ERROR( |
190 "Certificate missing appropriate certificate data for type: " + | 197 "Certificate missing appropriate certificate data for type: " + |
191 cert_type); | 198 cert_type); |
192 return false; | 199 return false; |
193 } | 200 } |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
269 ListCertsWithNickname(guid, &certs); | 276 ListCertsWithNickname(guid, &certs); |
270 if (!certs.empty()) { | 277 if (!certs.empty()) { |
271 ONC_LOG_ERROR("Certificate GUID is already in use: " + guid); | 278 ONC_LOG_ERROR("Certificate GUID is already in use: " + guid); |
272 return false; | 279 return false; |
273 } | 280 } |
274 | 281 |
275 net::CertificateList cert_list; | 282 net::CertificateList cert_list; |
276 cert_list.push_back(x509_cert); | 283 cert_list.push_back(x509_cert); |
277 net::NSSCertDatabase::ImportCertFailureList failures; | 284 net::NSSCertDatabase::ImportCertFailureList failures; |
278 bool success = false; | 285 bool success = false; |
279 net::NSSCertDatabase::TrustBits trust = web_trust ? | 286 net::NSSCertDatabase::TrustBits trust = import_with_ssl_trust ? |
280 net::NSSCertDatabase::TRUSTED_SSL : | 287 net::NSSCertDatabase::TRUSTED_SSL : |
281 net::NSSCertDatabase::TRUST_DEFAULT; | 288 net::NSSCertDatabase::TRUST_DEFAULT; |
282 if (cert_type == certificate::kServer) { | 289 if (cert_type == certificate::kServer) { |
283 success = cert_database->ImportServerCert(cert_list, trust, &failures); | 290 success = cert_database->ImportServerCert(cert_list, trust, &failures); |
284 } else { // Authority cert | 291 } else { // Authority cert |
285 success = cert_database->ImportCACerts(cert_list, trust, &failures); | 292 success = cert_database->ImportCACerts(cert_list, trust, &failures); |
286 } | 293 } |
287 | 294 |
288 if (!failures.empty()) { | 295 if (!failures.empty()) { |
289 ONC_LOG_ERROR("Error (" + net::ErrorToString(failures[0].net_error) + | 296 ONC_LOG_ERROR("Error (" + net::ErrorToString(failures[0].net_error) + |
290 ") importing " + cert_type + " certificate"); | 297 ") importing " + cert_type + " certificate"); |
291 return false; | 298 return false; |
292 } | 299 } |
293 if (!success) { | 300 if (!success) { |
294 ONC_LOG_ERROR("Unknown error importing " + cert_type + " certificate."); | 301 ONC_LOG_ERROR("Unknown error importing " + cert_type + " certificate."); |
295 return false; | 302 return false; |
296 } | 303 } |
297 | 304 |
| 305 if (web_trust_flag && onc_trusted_certificates) |
| 306 onc_trusted_certificates->push_back(x509_cert); |
| 307 |
298 return true; | 308 return true; |
299 } | 309 } |
300 | 310 |
301 bool CertificateImporter::ParseClientCertificate( | 311 bool CertificateImporter::ParseClientCertificate( |
302 const std::string& guid, | 312 const std::string& guid, |
303 const base::DictionaryValue& certificate) { | 313 const base::DictionaryValue& certificate) { |
304 std::string pkcs12_data; | 314 std::string pkcs12_data; |
305 if (!certificate.GetString(certificate::kPKCS12, &pkcs12_data) || | 315 if (!certificate.GetString(certificate::kPKCS12, &pkcs12_data) || |
306 pkcs12_data.empty()) { | 316 pkcs12_data.empty()) { |
307 ONC_LOG_ERROR("PKCS12 data is missing for client certificate."); | 317 ONC_LOG_ERROR("PKCS12 data is missing for client certificate."); |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
350 PK11_SetPrivateKeyNickname(private_key, const_cast<char*>(guid.c_str())); | 360 PK11_SetPrivateKeyNickname(private_key, const_cast<char*>(guid.c_str())); |
351 SECKEY_DestroyPrivateKey(private_key); | 361 SECKEY_DestroyPrivateKey(private_key); |
352 } else { | 362 } else { |
353 ONC_LOG_WARNING("Unable to find private key for certificate."); | 363 ONC_LOG_WARNING("Unable to find private key for certificate."); |
354 } | 364 } |
355 return true; | 365 return true; |
356 } | 366 } |
357 | 367 |
358 } // namespace onc | 368 } // namespace onc |
359 } // namespace chromeos | 369 } // namespace chromeos |
OLD | NEW |