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_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 |
11 #include "base/base64.h" | 11 #include "base/base64.h" |
12 #include "base/logging.h" | 12 #include "base/logging.h" |
13 #include "base/values.h" | 13 #include "base/values.h" |
14 #include "chromeos/network/network_event_log.h" | 14 #include "chromeos/network/network_event_log.h" |
15 #include "chromeos/network/onc/onc_constants.h" | 15 #include "chromeos/network/onc/onc_constants.h" |
16 #include "chromeos/network/onc/onc_utils.h" | 16 #include "chromeos/network/onc/onc_utils.h" |
17 #include "net/base/crypto_module.h" | 17 #include "net/base/crypto_module.h" |
18 #include "net/base/net_errors.h" | 18 #include "net/base/net_errors.h" |
19 #include "net/cert/nss_cert_database.h" | 19 #include "net/cert/nss_cert_database.h" |
20 #include "net/cert/x509_certificate.h" | 20 #include "net/cert/x509_certificate.h" |
21 | 21 |
22 #define ONC_LOG_WARNING(message) \ | 22 #define ONC_LOG_WARNING(message) \ |
23 NET_LOG_DEBUG("ONC Certificate Import Warning", message) | 23 NET_LOG_DEBUG("ONC Certificate Import Warning", message) |
24 #define ONC_LOG_ERROR(message) \ | 24 #define ONC_LOG_ERROR(message) \ |
25 NET_LOG_ERROR("ONC Certificate Import Error", message) | 25 NET_LOG_ERROR("ONC Certificate Import Error", message) |
26 | 26 |
27 namespace chromeos { | 27 namespace chromeos { |
28 namespace onc { | 28 namespace onc { |
29 | 29 |
30 CertificateImporter::CertificateImporter(bool allow_trust_imports) | 30 CertificateImporterImpl::CertificateImporterImpl() { |
31 : allow_trust_imports_(allow_trust_imports) { | |
32 } | 31 } |
33 | 32 |
34 CertificateImporter::ParseResult CertificateImporter::ParseAndStoreCertificates( | 33 bool CertificateImporterImpl::ImportCertificates( |
| 34 const base::ListValue& certificates, |
| 35 onc::ONCSource source, |
| 36 net::CertificateList* onc_trusted_certificates) { |
| 37 VLOG(2) << "ONC file has " << certificates.GetSize() << " certificates"; |
| 38 |
| 39 // Web trust is only granted to certificates imported by the user. |
| 40 bool allow_trust_imports = source == onc::ONC_SOURCE_USER_IMPORT; |
| 41 if (!ParseAndStoreCertificates( |
| 42 allow_trust_imports, certificates, onc_trusted_certificates, NULL)) { |
| 43 LOG(ERROR) << "Cannot parse some of the certificates in the ONC from " |
| 44 << onc::GetSourceAsString(source); |
| 45 return false; |
| 46 } |
| 47 return true; |
| 48 } |
| 49 |
| 50 bool CertificateImporterImpl::ParseAndStoreCertificates( |
| 51 bool allow_trust_imports, |
35 const base::ListValue& certificates, | 52 const base::ListValue& certificates, |
36 net::CertificateList* onc_trusted_certificates, | 53 net::CertificateList* onc_trusted_certificates, |
37 CertsByGUID* imported_server_and_ca_certs) { | 54 CertsByGUID* imported_server_and_ca_certs) { |
38 size_t successful_imports = 0; | 55 bool success = true; |
39 for (size_t i = 0; i < certificates.GetSize(); ++i) { | 56 for (size_t i = 0; i < certificates.GetSize(); ++i) { |
40 const base::DictionaryValue* certificate = NULL; | 57 const base::DictionaryValue* certificate = NULL; |
41 certificates.GetDictionary(i, &certificate); | 58 certificates.GetDictionary(i, &certificate); |
42 DCHECK(certificate != NULL); | 59 DCHECK(certificate != NULL); |
43 | 60 |
44 VLOG(2) << "Parsing certificate at index " << i << ": " << *certificate; | 61 VLOG(2) << "Parsing certificate at index " << i << ": " << *certificate; |
45 | 62 |
46 if (!ParseAndStoreCertificate(*certificate, onc_trusted_certificates, | 63 if (!ParseAndStoreCertificate(allow_trust_imports, |
| 64 *certificate, |
| 65 onc_trusted_certificates, |
47 imported_server_and_ca_certs)) { | 66 imported_server_and_ca_certs)) { |
| 67 success = false; |
48 ONC_LOG_ERROR( | 68 ONC_LOG_ERROR( |
49 base::StringPrintf("Cannot parse certificate at index %zu", i)); | 69 base::StringPrintf("Cannot parse certificate at index %zu", i)); |
50 } else { | 70 } else { |
51 VLOG(2) << "Successfully imported certificate at index " << i; | 71 VLOG(2) << "Successfully imported certificate at index " << i; |
52 ++successful_imports; | |
53 } | 72 } |
54 } | 73 } |
55 | 74 return success; |
56 if (successful_imports == certificates.GetSize()) { | |
57 return IMPORT_OK; | |
58 } else if (successful_imports == 0) { | |
59 return IMPORT_FAILED; | |
60 } else { | |
61 return IMPORT_INCOMPLETE; | |
62 } | |
63 } | 75 } |
64 | 76 |
65 // static | 77 // static |
66 void CertificateImporter::ListCertsWithNickname(const std::string& label, | 78 void CertificateImporterImpl::ListCertsWithNickname(const std::string& label, |
67 net::CertificateList* result) { | 79 net::CertificateList* result) { |
68 net::CertificateList all_certs; | 80 net::CertificateList all_certs; |
69 net::NSSCertDatabase::GetInstance()->ListCerts(&all_certs); | 81 net::NSSCertDatabase::GetInstance()->ListCerts(&all_certs); |
70 result->clear(); | 82 result->clear(); |
71 for (net::CertificateList::iterator iter = all_certs.begin(); | 83 for (net::CertificateList::iterator iter = all_certs.begin(); |
72 iter != all_certs.end(); ++iter) { | 84 iter != all_certs.end(); ++iter) { |
73 if (iter->get()->os_cert_handle()->nickname) { | 85 if (iter->get()->os_cert_handle()->nickname) { |
74 // Separate the nickname stored in the certificate at the colon, since | 86 // Separate the nickname stored in the certificate at the colon, since |
75 // NSS likes to store it as token:nickname. | 87 // NSS likes to store it as token:nickname. |
76 const char* delimiter = | 88 const char* delimiter = |
(...skipping 17 matching lines...) Expand all Loading... |
94 char* private_key_nickname = PK11_GetPrivateKeyNickname(private_key); | 106 char* private_key_nickname = PK11_GetPrivateKeyNickname(private_key); |
95 if (private_key_nickname && std::string(label) == private_key_nickname) | 107 if (private_key_nickname && std::string(label) == private_key_nickname) |
96 result->push_back(*iter); | 108 result->push_back(*iter); |
97 PORT_Free(private_key_nickname); | 109 PORT_Free(private_key_nickname); |
98 SECKEY_DestroyPrivateKey(private_key); | 110 SECKEY_DestroyPrivateKey(private_key); |
99 } | 111 } |
100 } | 112 } |
101 } | 113 } |
102 | 114 |
103 // static | 115 // static |
104 bool CertificateImporter::DeleteCertAndKeyByNickname(const std::string& label) { | 116 bool CertificateImporterImpl::DeleteCertAndKeyByNickname( |
| 117 const std::string& label) { |
105 net::CertificateList cert_list; | 118 net::CertificateList cert_list; |
106 ListCertsWithNickname(label, &cert_list); | 119 ListCertsWithNickname(label, &cert_list); |
107 bool result = true; | 120 bool result = true; |
108 for (net::CertificateList::iterator iter = cert_list.begin(); | 121 for (net::CertificateList::iterator iter = cert_list.begin(); |
109 iter != cert_list.end(); ++iter) { | 122 iter != cert_list.end(); ++iter) { |
110 // If we fail, we try and delete the rest still. | 123 // If we fail, we try and delete the rest still. |
111 // TODO(gspencer): this isn't very "transactional". If we fail on some, but | 124 // TODO(gspencer): this isn't very "transactional". If we fail on some, but |
112 // not all, then it's possible to leave things in a weird state. | 125 // not all, then it's possible to leave things in a weird state. |
113 // Luckily there should only be one cert with a particular | 126 // Luckily there should only be one cert with a particular |
114 // label, and the cert not being found is one of the few reasons the | 127 // label, and the cert not being found is one of the few reasons the |
115 // delete could fail, but still... The other choice is to return | 128 // delete could fail, but still... The other choice is to return |
116 // failure immediately, but that doesn't seem to do what is intended. | 129 // failure immediately, but that doesn't seem to do what is intended. |
117 if (!net::NSSCertDatabase::GetInstance()->DeleteCertAndKey(iter->get())) | 130 if (!net::NSSCertDatabase::GetInstance()->DeleteCertAndKey(iter->get())) |
118 result = false; | 131 result = false; |
119 } | 132 } |
120 return result; | 133 return result; |
121 } | 134 } |
122 | 135 |
123 bool CertificateImporter::ParseAndStoreCertificate( | 136 bool CertificateImporterImpl::ParseAndStoreCertificate( |
| 137 bool allow_trust_imports, |
124 const base::DictionaryValue& certificate, | 138 const base::DictionaryValue& certificate, |
125 net::CertificateList* onc_trusted_certificates, | 139 net::CertificateList* onc_trusted_certificates, |
126 CertsByGUID* imported_server_and_ca_certs) { | 140 CertsByGUID* imported_server_and_ca_certs) { |
127 // Get out the attributes of the given certificate. | 141 // Get out the attributes of the given certificate. |
128 std::string guid; | 142 std::string guid; |
129 certificate.GetStringWithoutPathExpansion(certificate::kGUID, &guid); | 143 certificate.GetStringWithoutPathExpansion(certificate::kGUID, &guid); |
130 DCHECK(!guid.empty()); | 144 DCHECK(!guid.empty()); |
131 | 145 |
132 bool remove = false; | 146 bool remove = false; |
133 if (certificate.GetBooleanWithoutPathExpansion(kRemove, &remove) && remove) { | 147 if (certificate.GetBooleanWithoutPathExpansion(kRemove, &remove) && remove) { |
134 if (!DeleteCertAndKeyByNickname(guid)) { | 148 if (!DeleteCertAndKeyByNickname(guid)) { |
135 ONC_LOG_ERROR("Unable to delete certificate"); | 149 ONC_LOG_ERROR("Unable to delete certificate"); |
136 return false; | 150 return false; |
137 } else { | 151 } else { |
138 return true; | 152 return true; |
139 } | 153 } |
140 } | 154 } |
141 | 155 |
142 // Not removing, so let's get the data we need to add this certificate. | 156 // Not removing, so let's get the data we need to add this certificate. |
143 std::string cert_type; | 157 std::string cert_type; |
144 certificate.GetStringWithoutPathExpansion(certificate::kType, &cert_type); | 158 certificate.GetStringWithoutPathExpansion(certificate::kType, &cert_type); |
145 if (cert_type == certificate::kServer || | 159 if (cert_type == certificate::kServer || |
146 cert_type == certificate::kAuthority) { | 160 cert_type == certificate::kAuthority) { |
147 return ParseServerOrCaCertificate(cert_type, guid, certificate, | 161 return ParseServerOrCaCertificate(allow_trust_imports, |
| 162 cert_type, |
| 163 guid, |
| 164 certificate, |
148 onc_trusted_certificates, | 165 onc_trusted_certificates, |
149 imported_server_and_ca_certs); | 166 imported_server_and_ca_certs); |
150 } else if (cert_type == certificate::kClient) { | 167 } else if (cert_type == certificate::kClient) { |
151 return ParseClientCertificate(guid, certificate); | 168 return ParseClientCertificate(guid, certificate); |
152 } | 169 } |
153 | 170 |
154 NOTREACHED(); | 171 NOTREACHED(); |
155 return false; | 172 return false; |
156 } | 173 } |
157 | 174 |
158 bool CertificateImporter::ParseServerOrCaCertificate( | 175 bool CertificateImporterImpl::ParseServerOrCaCertificate( |
| 176 bool allow_trust_imports, |
159 const std::string& cert_type, | 177 const std::string& cert_type, |
160 const std::string& guid, | 178 const std::string& guid, |
161 const base::DictionaryValue& certificate, | 179 const base::DictionaryValue& certificate, |
162 net::CertificateList* onc_trusted_certificates, | 180 net::CertificateList* onc_trusted_certificates, |
163 CertsByGUID* imported_server_and_ca_certs) { | 181 CertsByGUID* imported_server_and_ca_certs) { |
164 bool web_trust_flag = false; | 182 bool web_trust_flag = false; |
165 const base::ListValue* trust_list = NULL; | 183 const base::ListValue* trust_list = NULL; |
166 if (certificate.GetListWithoutPathExpansion(certificate::kTrustBits, | 184 if (certificate.GetListWithoutPathExpansion(certificate::kTrustBits, |
167 &trust_list)) { | 185 &trust_list)) { |
168 for (base::ListValue::const_iterator it = trust_list->begin(); | 186 for (base::ListValue::const_iterator it = trust_list->begin(); |
(...skipping 10 matching lines...) Expand all Loading... |
179 // Trust bits should only increase trust and never restrict. Thus, | 197 // Trust bits should only increase trust and never restrict. Thus, |
180 // ignoring unknown bits should be safe. | 198 // ignoring unknown bits should be safe. |
181 ONC_LOG_WARNING("Certificate contains unknown trust type " + | 199 ONC_LOG_WARNING("Certificate contains unknown trust type " + |
182 trust_type); | 200 trust_type); |
183 } | 201 } |
184 } | 202 } |
185 } | 203 } |
186 | 204 |
187 bool import_with_ssl_trust = false; | 205 bool import_with_ssl_trust = false; |
188 if (web_trust_flag) { | 206 if (web_trust_flag) { |
189 if (!allow_trust_imports_) | 207 if (!allow_trust_imports) |
190 ONC_LOG_WARNING("Web trust not granted for certificate: " + guid); | 208 ONC_LOG_WARNING("Web trust not granted for certificate: " + guid); |
191 else | 209 else |
192 import_with_ssl_trust = true; | 210 import_with_ssl_trust = true; |
193 } | 211 } |
194 | 212 |
195 std::string x509_data; | 213 std::string x509_data; |
196 if (!certificate.GetStringWithoutPathExpansion(certificate::kX509, | 214 if (!certificate.GetStringWithoutPathExpansion(certificate::kX509, |
197 &x509_data) || | 215 &x509_data) || |
198 x509_data.empty()) { | 216 x509_data.empty()) { |
199 ONC_LOG_ERROR( | 217 ONC_LOG_ERROR( |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
263 | 281 |
264 if (web_trust_flag && onc_trusted_certificates) | 282 if (web_trust_flag && onc_trusted_certificates) |
265 onc_trusted_certificates->push_back(x509_cert); | 283 onc_trusted_certificates->push_back(x509_cert); |
266 | 284 |
267 if (imported_server_and_ca_certs) | 285 if (imported_server_and_ca_certs) |
268 (*imported_server_and_ca_certs)[guid] = x509_cert; | 286 (*imported_server_and_ca_certs)[guid] = x509_cert; |
269 | 287 |
270 return true; | 288 return true; |
271 } | 289 } |
272 | 290 |
273 bool CertificateImporter::ParseClientCertificate( | 291 bool CertificateImporterImpl::ParseClientCertificate( |
274 const std::string& guid, | 292 const std::string& guid, |
275 const base::DictionaryValue& certificate) { | 293 const base::DictionaryValue& certificate) { |
276 std::string pkcs12_data; | 294 std::string pkcs12_data; |
277 if (!certificate.GetStringWithoutPathExpansion(certificate::kPKCS12, | 295 if (!certificate.GetStringWithoutPathExpansion(certificate::kPKCS12, |
278 &pkcs12_data) || | 296 &pkcs12_data) || |
279 pkcs12_data.empty()) { | 297 pkcs12_data.empty()) { |
280 ONC_LOG_ERROR("PKCS12 data is missing for client certificate."); | 298 ONC_LOG_ERROR("PKCS12 data is missing for client certificate."); |
281 return false; | 299 return false; |
282 } | 300 } |
283 | 301 |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
324 PK11_SetPrivateKeyNickname(private_key, const_cast<char*>(guid.c_str())); | 342 PK11_SetPrivateKeyNickname(private_key, const_cast<char*>(guid.c_str())); |
325 SECKEY_DestroyPrivateKey(private_key); | 343 SECKEY_DestroyPrivateKey(private_key); |
326 } else { | 344 } else { |
327 ONC_LOG_WARNING("Unable to find private key for certificate."); | 345 ONC_LOG_WARNING("Unable to find private key for certificate."); |
328 } | 346 } |
329 return true; | 347 return true; |
330 } | 348 } |
331 | 349 |
332 } // namespace onc | 350 } // namespace onc |
333 } // namespace chromeos | 351 } // namespace chromeos |
OLD | NEW |