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.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/compiler_specific.h" |
| 12 #include "base/logging.h" |
| 13 #include "base/memory/weak_ptr.h" |
| 14 #include "chrome/browser/extensions/api/enterprise_platform_keys/enterprise_plat
form_keys_api.h" |
| 15 #include "chrome/browser/net/nss_context.h" |
| 16 #include "crypto/rsa_private_key.h" |
| 17 #include "net/base/crypto_module.h" |
| 18 #include "net/base/net_errors.h" |
| 19 #include "net/cert/cert_database.h" |
| 20 #include "net/cert/nss_cert_database.h" |
| 21 #include "net/cert/x509_certificate.h" |
| 22 |
| 23 namespace { |
| 24 const char kErrorInternal[] = "Internal Error"; |
| 25 const char kErrorKeyNotFound[] = "Key not found."; |
| 26 const char kErrorInvalidX509Cert[] = |
| 27 "Certificate is not a valid X.509 certificate."; |
| 28 const char kErrorCertificateNotFound[] = "Certificate could not be found."; |
| 29 const char kErrorAlgorithmNotSupported[] = "Algorithm not supported."; |
| 30 } |
| 31 |
| 32 namespace extensions { |
| 33 |
| 34 namespace enterprise_platform_keys_details { |
| 35 |
| 36 namespace { |
| 37 |
| 38 namespace api_epk = api::enterprise_platform_keys; |
| 39 namespace api_epki = api::enterprise_platform_keys_internal; |
| 40 |
| 41 typedef base::Callback<void(crypto::ScopedPK11Slot slot, |
| 42 net::NSSCertDatabase* cert_db)> GetCertDBCallback; |
| 43 |
| 44 void DidGetCertDB(const GetCertDBCallback& callback, |
| 45 EnterprisePlatformKeysTokenMethodExtensionFunction* func, |
| 46 net::NSSCertDatabase* cert_db) { |
| 47 if (!cert_db) { |
| 48 LOG(ERROR) << "Couldn't get NSSCertDatabase."; |
| 49 func->RespondWithError(kErrorInternal); |
| 50 return; |
| 51 } |
| 52 |
| 53 crypto::ScopedPK11Slot slot = cert_db->GetPrivateSlot(); |
| 54 if (!slot) { |
| 55 LOG(ERROR) << "No private slot"; |
| 56 func->RespondWithError(kErrorInternal); |
| 57 return; |
| 58 } |
| 59 callback.Run(slot.Pass(), cert_db); |
| 60 } |
| 61 |
| 62 void GetCertDatabase(const std::string& token_id, |
| 63 const GetCertDBCallback& callback, |
| 64 EnterprisePlatformKeysTokenMethodExtensionFunction* func) { |
| 65 GetNSSCertDatabaseForProfile( |
| 66 func->GetProfile(), |
| 67 base::Bind(&DidGetCertDB, callback, base::Unretained(func))); |
| 68 } |
| 69 |
| 70 class GenerateKey : public TokenMethod { |
| 71 public: |
| 72 GenerateKey(scoped_ptr<api_epki::GenerateKey::Params> params, |
| 73 EnterprisePlatformKeysTokenMethodExtensionFunction* func); |
| 74 virtual ~GenerateKey() {} |
| 75 virtual void Run() OVERRIDE; |
| 76 |
| 77 void DidGetDB(crypto::ScopedPK11Slot slot, net::NSSCertDatabase* cert_db); |
| 78 |
| 79 private: |
| 80 scoped_ptr<api_epki::GenerateKey::Params> params_; |
| 81 base::WeakPtrFactory<GenerateKey> weak_factory_; |
| 82 }; |
| 83 |
| 84 class Sign : public TokenMethod { |
| 85 public: |
| 86 Sign(scoped_ptr<api_epki::Sign::Params> params, |
| 87 EnterprisePlatformKeysTokenMethodExtensionFunction* func); |
| 88 virtual ~Sign() {} |
| 89 virtual void Run() OVERRIDE; |
| 90 |
| 91 void DidGetDB(crypto::ScopedPK11Slot slot, net::NSSCertDatabase* cert_db); |
| 92 |
| 93 private: |
| 94 scoped_ptr<api_epki::Sign::Params> params_; |
| 95 base::WeakPtrFactory<Sign> weak_factory_; |
| 96 }; |
| 97 |
| 98 class GetCertificates : public TokenMethod { |
| 99 public: |
| 100 GetCertificates(scoped_ptr<api_epk::GetCertificates::Params> params, |
| 101 EnterprisePlatformKeysTokenMethodExtensionFunction* func); |
| 102 virtual ~GetCertificates() {} |
| 103 virtual void Run() OVERRIDE; |
| 104 |
| 105 void DidGetDB(crypto::ScopedPK11Slot slot, net::NSSCertDatabase* cert_db); |
| 106 void DidGetCertificates(scoped_ptr<net::CertificateList> certs); |
| 107 |
| 108 private: |
| 109 scoped_ptr<api_epk::GetCertificates::Params> params_; |
| 110 crypto::ScopedPK11Slot slot_; |
| 111 base::WeakPtrFactory<GetCertificates> weak_factory_; |
| 112 }; |
| 113 |
| 114 class ImportCertificate : public TokenMethod { |
| 115 public: |
| 116 ImportCertificate(scoped_ptr<api_epk::ImportCertificate::Params> params, |
| 117 EnterprisePlatformKeysTokenMethodExtensionFunction* func); |
| 118 virtual ~ImportCertificate() {} |
| 119 virtual void Run() OVERRIDE; |
| 120 |
| 121 void DidGetDB(crypto::ScopedPK11Slot slot, net::NSSCertDatabase* cert_db); |
| 122 |
| 123 private: |
| 124 scoped_ptr<api_epk::ImportCertificate::Params> params_; |
| 125 base::WeakPtrFactory<ImportCertificate> weak_factory_; |
| 126 }; |
| 127 |
| 128 class RemoveCertificate : public TokenMethod { |
| 129 public: |
| 130 RemoveCertificate(scoped_ptr<api_epk::RemoveCertificate::Params> params, |
| 131 EnterprisePlatformKeysTokenMethodExtensionFunction* func); |
| 132 virtual ~RemoveCertificate() {} |
| 133 virtual void Run() OVERRIDE; |
| 134 |
| 135 void DidGetDB(crypto::ScopedPK11Slot slot, net::NSSCertDatabase* cert_db); |
| 136 |
| 137 private: |
| 138 scoped_ptr<api_epk::RemoveCertificate::Params> params_; |
| 139 base::WeakPtrFactory<RemoveCertificate> weak_factory_; |
| 140 }; |
| 141 |
| 142 GenerateKey::GenerateKey( |
| 143 scoped_ptr<api_epki::GenerateKey::Params> params, |
| 144 EnterprisePlatformKeysTokenMethodExtensionFunction* func) |
| 145 : TokenMethod(func), params_(params.Pass()), weak_factory_(this) { |
| 146 } |
| 147 |
| 148 void GenerateKey::Run() { |
| 149 GetCertDatabase( |
| 150 params_->token_id, |
| 151 base::Bind(&GenerateKey::DidGetDB, weak_factory_.GetWeakPtr()), |
| 152 func_); |
| 153 } |
| 154 |
| 155 void GenerateKey::DidGetDB(crypto::ScopedPK11Slot slot, |
| 156 net::NSSCertDatabase* cert_db) { |
| 157 const int modulus_length = params_->modulus_length; |
| 158 if (modulus_length > 2048) { |
| 159 func_->RespondWithError(kErrorAlgorithmNotSupported); |
| 160 return; |
| 161 } |
| 162 scoped_ptr<crypto::RSAPrivateKey> rsa_key( |
| 163 crypto::RSAPrivateKey::CreateSensitive(slot.get(), modulus_length)); |
| 164 if (!rsa_key) { |
| 165 LOG(ERROR) << "Couldn't create key."; |
| 166 func_->RespondWithError(kErrorInternal); |
| 167 return; |
| 168 } |
| 169 |
| 170 std::vector<uint8> public_key_der; |
| 171 if (!rsa_key->ExportPublicKey(&public_key_der)) { |
| 172 // TODO(pneubeck): Remove rsa_key from storage. |
| 173 LOG(ERROR) << "Couldn't export public key."; |
| 174 func_->RespondWithError(kErrorInternal); |
| 175 return; |
| 176 } |
| 177 std::string public_key_der_str(public_key_der.begin(), public_key_der.end()); |
| 178 |
| 179 func_->RespondWithResults( |
| 180 api_epki::GenerateKey::Results::Create(public_key_der_str)); |
| 181 } |
| 182 |
| 183 Sign::Sign(scoped_ptr<api_epki::Sign::Params> params, |
| 184 EnterprisePlatformKeysTokenMethodExtensionFunction* func) |
| 185 : TokenMethod(func), params_(params.Pass()), weak_factory_(this) { |
| 186 } |
| 187 |
| 188 void Sign::Run() { |
| 189 GetCertDatabase(params_->token_id, |
| 190 base::Bind(&Sign::DidGetDB, weak_factory_.GetWeakPtr()), |
| 191 func_); |
| 192 } |
| 193 |
| 194 void Sign::DidGetDB(crypto::ScopedPK11Slot slot, |
| 195 net::NSSCertDatabase* cert_db) { |
| 196 const std::string& public_key = params_->public_key; |
| 197 const uint8* public_key_uint8 = |
| 198 reinterpret_cast<const uint8*>(public_key.data()); |
| 199 std::vector<uint8> public_key_vector(public_key_uint8, |
| 200 public_key_uint8 + public_key.size()); |
| 201 |
| 202 // TODO(pneubeck): This searches all slots. Change to look only at |slot_|. |
| 203 scoped_ptr<crypto::RSAPrivateKey> rsa_key( |
| 204 crypto::RSAPrivateKey::FindFromPublicKeyInfo(public_key_vector)); |
| 205 if (!rsa_key) { |
| 206 func_->RespondWithError(kErrorKeyNotFound); |
| 207 return; |
| 208 } |
| 209 |
| 210 const std::string& data = params_->data; |
| 211 SECItem sign_result = {siBuffer, NULL, 0}; |
| 212 if (SEC_SignData(&sign_result, |
| 213 reinterpret_cast<const unsigned char*>(data.data()), |
| 214 data.size(), |
| 215 rsa_key->key(), |
| 216 SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION) != SECSuccess) { |
| 217 LOG(ERROR) << "Couldn't sign."; |
| 218 func_->RespondWithError(kErrorInternal); |
| 219 return; |
| 220 } |
| 221 |
| 222 std::string signature(reinterpret_cast<const char*>(sign_result.data), |
| 223 sign_result.len); |
| 224 func_->RespondWithResults(api_epki::Sign::Results::Create(signature)); |
| 225 } |
| 226 |
| 227 GetCertificates::GetCertificates( |
| 228 scoped_ptr<api_epk::GetCertificates::Params> params, |
| 229 EnterprisePlatformKeysTokenMethodExtensionFunction* func) |
| 230 : TokenMethod(func), params_(params.Pass()), weak_factory_(this) { |
| 231 } |
| 232 |
| 233 void GetCertificates::Run() { |
| 234 GetCertDatabase( |
| 235 params_->token_id, |
| 236 base::Bind(&GetCertificates::DidGetDB, weak_factory_.GetWeakPtr()), |
| 237 func_); |
| 238 } |
| 239 |
| 240 void GetCertificates::DidGetDB(crypto::ScopedPK11Slot slot, |
| 241 net::NSSCertDatabase* cert_db) { |
| 242 slot_ = slot.Pass(); |
| 243 cert_db->ListCertsInSlot(base::Bind(&GetCertificates::DidGetCertificates, |
| 244 weak_factory_.GetWeakPtr()), |
| 245 slot_.get()); |
| 246 } |
| 247 |
| 248 void GetCertificates::DidGetCertificates( |
| 249 scoped_ptr<net::CertificateList> certs) { |
| 250 // std::vector<std::string> client_certs; |
| 251 scoped_ptr<base::ListValue> client_certs(new base::ListValue()); |
| 252 for (net::CertificateList::const_iterator it = certs->begin(); |
| 253 it != certs->end(); |
| 254 ++it) { |
| 255 net::X509Certificate::OSCertHandle cert_handle = (*it)->os_cert_handle(); |
| 256 crypto::ScopedPK11Slot cert_slot(PK11_KeyForCertExists(cert_handle, |
| 257 NULL, // keyPtr |
| 258 NULL)); // wincx |
| 259 |
| 260 // Keep only user certificate, i.e. certs for which the private key is |
| 261 // present, and certs where the private key is stored in the queried slot. |
| 262 if (cert_slot != slot_) |
| 263 continue; |
| 264 |
| 265 std::string der_encoding; |
| 266 net::X509Certificate::GetDEREncoded(cert_handle, &der_encoding); |
| 267 // client_certs.push_back(der_encoding); |
| 268 client_certs->Append(base::BinaryValue::CreateWithCopiedBuffer( |
| 269 der_encoding.data(), der_encoding.size())); |
| 270 } |
| 271 scoped_ptr<base::ListValue> results(new base::ListValue()); |
| 272 results->Append(client_certs.release()); |
| 273 func_->RespondWithResults(results.Pass()); |
| 274 // results_ = api_eci::GetClientCertificates::Results::Create(client_certs); |
| 275 } |
| 276 |
| 277 ImportCertificate::ImportCertificate( |
| 278 scoped_ptr<api_epk::ImportCertificate::Params> params, |
| 279 EnterprisePlatformKeysTokenMethodExtensionFunction* func) |
| 280 : TokenMethod(func), params_(params.Pass()), weak_factory_(this) { |
| 281 } |
| 282 |
| 283 void ImportCertificate::Run() { |
| 284 GetCertDatabase( |
| 285 params_->token_id, |
| 286 base::Bind(&ImportCertificate::DidGetDB, weak_factory_.GetWeakPtr()), |
| 287 func_); |
| 288 } |
| 289 |
| 290 void ImportCertificate::DidGetDB(crypto::ScopedPK11Slot slot, |
| 291 net::NSSCertDatabase* cert_db) { |
| 292 const std::string& certificate = params_->certificate; |
| 293 scoped_refptr<net::X509Certificate> cert_x509 = |
| 294 net::X509Certificate::CreateFromBytes(certificate.data(), |
| 295 certificate.size()); |
| 296 if (!cert_x509) { |
| 297 func_->RespondWithError(kErrorInvalidX509Cert); |
| 298 return; |
| 299 } |
| 300 |
| 301 net::CertDatabase* db = net::CertDatabase::GetInstance(); |
| 302 |
| 303 const net::Error cert_status = db->CheckUserCert(cert_x509); |
| 304 if (cert_status == net::ERR_NO_PRIVATE_KEY_FOR_CERT) { |
| 305 func_->RespondWithError(kErrorKeyNotFound); |
| 306 return; |
| 307 } else if (cert_status != net::OK) { |
| 308 func_->RespondWithError(net::ErrorToString(cert_status)); |
| 309 return; |
| 310 } |
| 311 |
| 312 const net::Error import_status = db->AddUserCert(cert_x509.get()); |
| 313 if (import_status != net::OK) { |
| 314 LOG(ERROR) << "Could not import certificate."; |
| 315 func_->RespondWithError(net::ErrorToString(import_status)); |
| 316 return; |
| 317 } |
| 318 |
| 319 func_->RespondWithoutResult(); |
| 320 } |
| 321 |
| 322 RemoveCertificate::RemoveCertificate( |
| 323 scoped_ptr<api_epk::RemoveCertificate::Params> params, |
| 324 EnterprisePlatformKeysTokenMethodExtensionFunction* func) |
| 325 : TokenMethod(func), params_(params.Pass()), weak_factory_(this) { |
| 326 } |
| 327 |
| 328 void RemoveCertificate::Run() { |
| 329 GetCertDatabase( |
| 330 params_->token_id, |
| 331 base::Bind(&RemoveCertificate::DidGetDB, weak_factory_.GetWeakPtr()), |
| 332 func_); |
| 333 } |
| 334 |
| 335 void RemoveCertificate::DidGetDB(crypto::ScopedPK11Slot slot, |
| 336 net::NSSCertDatabase* cert_db) { |
| 337 const std::string& certificate = params_->certificate; |
| 338 scoped_refptr<net::X509Certificate> cert_x509 = |
| 339 net::X509Certificate::CreateFromBytes(certificate.data(), |
| 340 certificate.size()); |
| 341 if (!cert_x509) { |
| 342 func_->RespondWithError(kErrorInvalidX509Cert); |
| 343 return; |
| 344 } |
| 345 |
| 346 bool certificate_found = cert_x509->os_cert_handle()->isperm; |
| 347 bool success = cert_db->DeleteCertAndKey(cert_x509); |
| 348 |
| 349 // CertificateNotFound error has precedence over an internal error. |
| 350 if (!certificate_found) { |
| 351 func_->RespondWithError(kErrorCertificateNotFound); |
| 352 return; |
| 353 } |
| 354 if (!success) { |
| 355 func_->RespondWithError(kErrorInternal); |
| 356 return; |
| 357 } |
| 358 |
| 359 func_->RespondWithoutResult(); |
| 360 } |
| 361 |
| 362 } // namespace |
| 363 |
| 364 scoped_ptr<TokenMethod> CreateGenerateKey( |
| 365 scoped_ptr<api_epki::GenerateKey::Params> params, |
| 366 EnterprisePlatformKeysTokenMethodExtensionFunction* func) { |
| 367 return scoped_ptr<TokenMethod>(new GenerateKey(params.Pass(), func)); |
| 368 } |
| 369 |
| 370 scoped_ptr<TokenMethod> CreateSign( |
| 371 scoped_ptr<api_epki::Sign::Params> params, |
| 372 EnterprisePlatformKeysTokenMethodExtensionFunction* func) { |
| 373 return scoped_ptr<TokenMethod>(new Sign(params.Pass(), func)); |
| 374 } |
| 375 |
| 376 scoped_ptr<TokenMethod> CreateGetCertificates( |
| 377 scoped_ptr<api_epk::GetCertificates::Params> params, |
| 378 EnterprisePlatformKeysTokenMethodExtensionFunction* func) { |
| 379 return scoped_ptr<TokenMethod>(new GetCertificates(params.Pass(), func)); |
| 380 } |
| 381 |
| 382 scoped_ptr<TokenMethod> CreateImportCertificate( |
| 383 scoped_ptr<api_epk::ImportCertificate::Params> params, |
| 384 EnterprisePlatformKeysTokenMethodExtensionFunction* func) { |
| 385 return scoped_ptr<TokenMethod>(new ImportCertificate(params.Pass(), func)); |
| 386 } |
| 387 |
| 388 scoped_ptr<TokenMethod> CreateRemoveCertificate( |
| 389 scoped_ptr<api_epk::RemoveCertificate::Params> params, |
| 390 EnterprisePlatformKeysTokenMethodExtensionFunction* func) { |
| 391 return scoped_ptr<TokenMethod>(new RemoveCertificate(params.Pass(), func)); |
| 392 } |
| 393 |
| 394 } // namespace enterprise_platform_keys_details |
| 395 |
| 396 } // namespace extensions |
OLD | NEW |