| 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 |