OLD | NEW |
(Empty) | |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "chrome/browser/extensions/api/enterprise_platform_keys/token_method_ns
s.h" |
| 6 |
| 7 #include <cryptohi.h> |
| 8 #include "base/bind.h" |
| 9 #include "base/bind_helpers.h" |
| 10 #include "base/callback.h" |
| 11 #include "base/logging.h" |
| 12 #include "chrome/browser/extensions/api/enterprise_platform_keys/enterprise_plat
form_keys_api.h" |
| 13 #include "chrome/browser/net/nss_context.h" |
| 14 #include "crypto/rsa_private_key.h" |
| 15 #include "net/base/crypto_module.h" |
| 16 #include "net/base/net_errors.h" |
| 17 #include "net/cert/cert_database.h" |
| 18 #include "net/cert/nss_cert_database.h" |
| 19 #include "net/cert/x509_certificate.h" |
| 20 |
| 21 namespace { |
| 22 const char kErrorInternal[] = "Internal Error"; |
| 23 const char kErrorKeyNotFound[] = "Key not found."; |
| 24 const char kErrorInvalidX509Cert[] = |
| 25 "Certificate is not a valid X.509 certificate."; |
| 26 const char kErrorCertificateNotFound[] = "Certificate could not be found."; |
| 27 } |
| 28 |
| 29 namespace extensions { |
| 30 |
| 31 namespace enterprise_platform_keys { |
| 32 |
| 33 namespace nss { |
| 34 |
| 35 namespace { |
| 36 |
| 37 namespace api_epk = api::enterprise_platform_keys; |
| 38 namespace api_epki = api::enterprise_platform_keys_internal; |
| 39 |
| 40 typedef base::Callback<bool(scoped_refptr<TokenMethodExtensionFunction> func, |
| 41 crypto::ScopedPK11Slot slot, |
| 42 net::NSSCertDatabase* cert_db)> GetCertDBCallback; |
| 43 |
| 44 void DidGetCertDB(scoped_refptr<TokenMethodExtensionFunction> func, |
| 45 const GetCertDBCallback& callback, |
| 46 net::NSSCertDatabase* cert_db) { |
| 47 if (!cert_db) { |
| 48 LOG(ERROR) << "Couldn't get NSSCertDatabase."; |
| 49 func->SetError(kErrorInternal); |
| 50 func->SendResponse(false); |
| 51 return; |
| 52 } |
| 53 |
| 54 crypto::ScopedPK11Slot slot = cert_db->GetPrivateSlot(); |
| 55 if (!slot) { |
| 56 LOG(ERROR) << "No private slot"; |
| 57 func->SetError(kErrorInternal); |
| 58 func->SendResponse(false); |
| 59 return; |
| 60 } |
| 61 if (!callback.Run(func, slot.Pass(), cert_db)) |
| 62 func->SendResponse(false); |
| 63 } |
| 64 |
| 65 void GetCertDatabase(scoped_refptr<TokenMethodExtensionFunction> func, |
| 66 const std::string& token_id, |
| 67 const GetCertDBCallback& callback) { |
| 68 GetNSSCertDatabaseForProfile(func->GetProfile(), |
| 69 base::Bind(&DidGetCertDB, func, callback)); |
| 70 } |
| 71 |
| 72 bool GenerateWithDB(scoped_ptr<api_epki::GenerateKey::Params> params, |
| 73 scoped_refptr<TokenMethodExtensionFunction> func, |
| 74 crypto::ScopedPK11Slot slot, |
| 75 net::NSSCertDatabase* cert_db) { |
| 76 scoped_ptr<crypto::RSAPrivateKey> rsa_key( |
| 77 crypto::RSAPrivateKey::CreateSensitive(slot.get(), 512)); |
| 78 if (!rsa_key) { |
| 79 LOG(ERROR) << "Couldn't create key."; |
| 80 func->SetError(kErrorInternal); |
| 81 return false; |
| 82 } |
| 83 |
| 84 std::vector<uint8> public_key_der; |
| 85 if (!rsa_key->ExportPublicKey(&public_key_der)) { |
| 86 // TODO(pneubeck): Remove rsa_key from storage. |
| 87 LOG(ERROR) << "Couldn't export public key."; |
| 88 func->SetError(kErrorInternal); |
| 89 return false; |
| 90 } |
| 91 std::string public_key_der_str(public_key_der.begin(), public_key_der.end()); |
| 92 |
| 93 func->SetResults(api_epki::GenerateKey::Results::Create(public_key_der_str)); |
| 94 func->SendResponse(true); |
| 95 return true; |
| 96 } |
| 97 |
| 98 bool SignWithDB(scoped_ptr<api_epki::Sign::Params> params, |
| 99 scoped_refptr<TokenMethodExtensionFunction> func, |
| 100 crypto::ScopedPK11Slot slot, |
| 101 net::NSSCertDatabase* cert_db) { |
| 102 const std::string& public_key = params->public_key; |
| 103 const uint8* public_key_uint8 = |
| 104 reinterpret_cast<const uint8*>(public_key.data()); |
| 105 std::vector<uint8> public_key_vector(public_key_uint8, |
| 106 public_key_uint8 + public_key.size()); |
| 107 |
| 108 // TODO(pneubeck): This searches all slots. Change to look only at |slot_|. |
| 109 scoped_ptr<crypto::RSAPrivateKey> rsa_key( |
| 110 crypto::RSAPrivateKey::FindFromPublicKeyInfo(public_key_vector)); |
| 111 if (!rsa_key) { |
| 112 func->SetError(kErrorKeyNotFound); |
| 113 return false; |
| 114 } |
| 115 |
| 116 const std::string& data = params->data; |
| 117 SECItem sign_result = {siBuffer, NULL, 0}; |
| 118 if (SEC_SignData(&sign_result, |
| 119 reinterpret_cast<const unsigned char*>(data.data()), |
| 120 data.size(), |
| 121 rsa_key->key(), |
| 122 SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION) != SECSuccess) { |
| 123 LOG(ERROR) << "Couldn't sign."; |
| 124 func->SetError(kErrorInternal); |
| 125 return false; |
| 126 } |
| 127 |
| 128 std::string signature(reinterpret_cast<const char*>(sign_result.data), |
| 129 sign_result.len); |
| 130 func->SetResults(api_epki::Sign::Results::Create(signature)); |
| 131 func->SendResponse(true); |
| 132 return true; |
| 133 } |
| 134 |
| 135 void DidGetCerts(scoped_refptr<TokenMethodExtensionFunction> func, |
| 136 crypto::ScopedPK11Slot slot, |
| 137 scoped_ptr<net::CertificateList> certs) { |
| 138 // std::vector<std::string> client_certs; |
| 139 scoped_ptr<base::ListValue> client_certs(new base::ListValue()); |
| 140 for (net::CertificateList::const_iterator it = certs->begin(); |
| 141 it != certs->end(); |
| 142 ++it) { |
| 143 net::X509Certificate::OSCertHandle cert_handle = (*it)->os_cert_handle(); |
| 144 crypto::ScopedPK11Slot cert_slot(PK11_KeyForCertExists(cert_handle, |
| 145 NULL, // keyPtr |
| 146 NULL)); // wincx |
| 147 |
| 148 // Keep only user certificate, i.e. certs for which the private key is |
| 149 // present, and certs where the private key is stored in the queried slot. |
| 150 if (cert_slot != slot) |
| 151 continue; |
| 152 |
| 153 std::string der_encoding; |
| 154 net::X509Certificate::GetDEREncoded(cert_handle, &der_encoding); |
| 155 // client_certs.push_back(der_encoding); |
| 156 client_certs->Append(base::BinaryValue::CreateWithCopiedBuffer( |
| 157 der_encoding.data(), der_encoding.size())); |
| 158 } |
| 159 scoped_ptr<base::ListValue> results(new base::ListValue()); |
| 160 results->Append(client_certs.release()); |
| 161 func->SetResults(results.Pass()); |
| 162 // results_ = api_eci::GetClientCertificates::Results::Create(client_certs); |
| 163 func->SendResponse(true); |
| 164 } |
| 165 |
| 166 bool GetCertsWithDB(scoped_ptr<api_epk::GetCertificates::Params> params, |
| 167 scoped_refptr<TokenMethodExtensionFunction> func, |
| 168 crypto::ScopedPK11Slot slot, |
| 169 net::NSSCertDatabase* cert_db) { |
| 170 PK11SlotInfo* slot_ptr = slot.get(); |
| 171 cert_db->ListCertsInSlot(base::Bind(&DidGetCerts, func, base::Passed(&slot)), |
| 172 slot_ptr); |
| 173 return true; |
| 174 } |
| 175 |
| 176 bool ImportWithDB(scoped_ptr<api_epk::ImportCertificate::Params> params, |
| 177 scoped_refptr<TokenMethodExtensionFunction> func, |
| 178 crypto::ScopedPK11Slot slot, |
| 179 net::NSSCertDatabase* cert_db) { |
| 180 const std::string& certificate = params->certificate; |
| 181 scoped_refptr<net::X509Certificate> cert_x509 = |
| 182 net::X509Certificate::CreateFromBytes(certificate.data(), |
| 183 certificate.size()); |
| 184 if (!cert_x509) { |
| 185 func->SetError(kErrorInvalidX509Cert); |
| 186 return false; |
| 187 } |
| 188 |
| 189 net::CertDatabase* db = net::CertDatabase::GetInstance(); |
| 190 |
| 191 const net::Error cert_status = db->CheckUserCert(cert_x509); |
| 192 if (cert_status == net::ERR_NO_PRIVATE_KEY_FOR_CERT) { |
| 193 func->SetError(kErrorKeyNotFound); |
| 194 return false; |
| 195 } else if (cert_status != net::OK) { |
| 196 func->SetError(net::ErrorToString(cert_status)); |
| 197 return false; |
| 198 } |
| 199 |
| 200 const net::Error import_status = db->AddUserCert(cert_x509.get()); |
| 201 if (import_status != net::OK) { |
| 202 LOG(ERROR) << "Could not import certificate."; |
| 203 func->SetError(net::ErrorToString(import_status)); |
| 204 return false; |
| 205 } |
| 206 |
| 207 func->SendResponse(true); |
| 208 return true; |
| 209 } |
| 210 |
| 211 bool RemoveWithDB(scoped_ptr<api_epk::RemoveCertificate::Params> params, |
| 212 scoped_refptr<TokenMethodExtensionFunction> func, |
| 213 crypto::ScopedPK11Slot slot, |
| 214 net::NSSCertDatabase* cert_db) { |
| 215 const std::string& certificate = params->certificate; |
| 216 scoped_refptr<net::X509Certificate> cert_x509 = |
| 217 net::X509Certificate::CreateFromBytes(certificate.data(), |
| 218 certificate.size()); |
| 219 if (!cert_x509) { |
| 220 func->SetError(kErrorInvalidX509Cert); |
| 221 return false; |
| 222 } |
| 223 |
| 224 bool certificate_found = cert_x509->os_cert_handle()->isperm; |
| 225 bool success = cert_db->DeleteCertAndKey(cert_x509); |
| 226 |
| 227 // CertificateNotFound error has precedence over an internal error. |
| 228 if (!certificate_found) { |
| 229 func->SetError(kErrorCertificateNotFound); |
| 230 return false; |
| 231 } |
| 232 if (!success) { |
| 233 func->SetError(kErrorInternal); |
| 234 return false; |
| 235 } |
| 236 |
| 237 func->SendResponse(true); |
| 238 return true; |
| 239 } |
| 240 |
| 241 } // namespace |
| 242 |
| 243 void Generate(scoped_refptr<TokenMethodExtensionFunction> func, |
| 244 scoped_ptr<api_epki::GenerateKey::Params> params) { |
| 245 GetCertDatabase(func, |
| 246 params->token_id, |
| 247 base::Bind(GenerateWithDB, base::Passed(¶ms))); |
| 248 } |
| 249 |
| 250 void Sign(scoped_refptr<TokenMethodExtensionFunction> func, |
| 251 scoped_ptr<api_epki::Sign::Params> params) { |
| 252 GetCertDatabase( |
| 253 func, params->token_id, base::Bind(SignWithDB, base::Passed(¶ms))); |
| 254 } |
| 255 |
| 256 void GetCerts(scoped_refptr<TokenMethodExtensionFunction> func, |
| 257 scoped_ptr<api_epk::GetCertificates::Params> params) { |
| 258 GetCertDatabase(func, |
| 259 params->token_id, |
| 260 base::Bind(GetCertsWithDB, base::Passed(¶ms))); |
| 261 } |
| 262 |
| 263 void Import(scoped_refptr<TokenMethodExtensionFunction> func, |
| 264 scoped_ptr<api_epk::ImportCertificate::Params> params) { |
| 265 GetCertDatabase( |
| 266 func, params->token_id, base::Bind(ImportWithDB, base::Passed(¶ms))); |
| 267 } |
| 268 |
| 269 void Remove(scoped_refptr<TokenMethodExtensionFunction> func, |
| 270 scoped_ptr<api_epk::RemoveCertificate::Params> params) { |
| 271 GetCertDatabase( |
| 272 func, params->token_id, base::Bind(RemoveWithDB, base::Passed(¶ms))); |
| 273 } |
| 274 |
| 275 } // namespace nss |
| 276 |
| 277 } // namespace enterprise_platform_keys |
| 278 |
| 279 } // namespace extensions |
OLD | NEW |