Chromium Code Reviews| 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> | |
|
Ryan Sleevi
2014/05/08 20:52:04
style: newline
pneubeck (no reviews)
2014/05/14 15:01:49
Done.
| |
| 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 const TokenMethod::ErrorCallback& error_callback, | |
| 46 net::NSSCertDatabase* cert_db) { | |
| 47 if (!cert_db) { | |
| 48 LOG(ERROR) << "Couldn't get NSSCertDatabase."; | |
| 49 error_callback.Run(kErrorInternal); | |
| 50 return; | |
| 51 } | |
| 52 | |
| 53 crypto::ScopedPK11Slot slot = cert_db->GetPrivateSlot(); | |
| 54 if (!slot) { | |
| 55 LOG(ERROR) << "No private slot"; | |
| 56 error_callback.Run(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 const TokenMethod::ErrorCallback& error_callback, | |
| 65 Profile* profile) { | |
| 66 GetNSSCertDatabaseForProfile( | |
| 67 profile, base::Bind(&DidGetCertDB, callback, error_callback)); | |
| 68 } | |
| 69 | |
| 70 class GenerateKey : public TokenMethod { | |
| 71 public: | |
| 72 GenerateKey(scoped_ptr<api_epki::GenerateKey::Params> params, | |
| 73 const GenerateKeyCallback& callback, | |
| 74 const ErrorCallback& error_callback, | |
| 75 Profile* profile); | |
| 76 virtual ~GenerateKey() {} | |
| 77 virtual void Run() OVERRIDE; | |
| 78 | |
| 79 void DidGetDB(crypto::ScopedPK11Slot slot, net::NSSCertDatabase* cert_db); | |
|
Ryan Sleevi
2014/05/08 20:52:04
Document
pneubeck (no reviews)
2014/05/14 15:01:49
Done.
| |
| 80 | |
| 81 private: | |
| 82 scoped_ptr<api_epki::GenerateKey::Params> params_; | |
| 83 GenerateKeyCallback callback_; | |
| 84 base::WeakPtrFactory<GenerateKey> weak_factory_; | |
| 85 }; | |
| 86 | |
| 87 class Sign : public TokenMethod { | |
| 88 public: | |
| 89 Sign(scoped_ptr<api_epki::Sign::Params> params, | |
| 90 EnterprisePlatformKeysTokenMethodExtensionFunction* func); | |
| 91 virtual ~Sign() {} | |
| 92 virtual void Run() OVERRIDE; | |
| 93 | |
| 94 void DidGetDB(crypto::ScopedPK11Slot slot, net::NSSCertDatabase* cert_db); | |
|
Ryan Sleevi
2014/05/08 20:52:04
Document
pneubeck (no reviews)
2014/05/14 15:01:49
Done.
| |
| 95 | |
| 96 private: | |
| 97 scoped_ptr<api_epki::Sign::Params> params_; | |
| 98 base::WeakPtrFactory<Sign> weak_factory_; | |
| 99 }; | |
| 100 | |
| 101 class GetCertificates : public TokenMethod { | |
| 102 public: | |
| 103 GetCertificates(scoped_ptr<api_epk::GetCertificates::Params> params, | |
| 104 EnterprisePlatformKeysTokenMethodExtensionFunction* func); | |
| 105 virtual ~GetCertificates() {} | |
| 106 virtual void Run() OVERRIDE; | |
| 107 | |
| 108 void DidGetDB(crypto::ScopedPK11Slot slot, net::NSSCertDatabase* cert_db); | |
|
Ryan Sleevi
2014/05/08 20:52:04
Document
pneubeck (no reviews)
2014/05/14 15:01:49
Done.
| |
| 109 void DidGetCertificates(scoped_ptr<net::CertificateList> certs); | |
| 110 | |
| 111 private: | |
| 112 scoped_ptr<api_epk::GetCertificates::Params> params_; | |
| 113 crypto::ScopedPK11Slot slot_; | |
| 114 base::WeakPtrFactory<GetCertificates> weak_factory_; | |
| 115 }; | |
| 116 | |
| 117 class ImportCertificate : public TokenMethod { | |
| 118 public: | |
| 119 ImportCertificate(scoped_ptr<api_epk::ImportCertificate::Params> params, | |
| 120 EnterprisePlatformKeysTokenMethodExtensionFunction* func); | |
| 121 virtual ~ImportCertificate() {} | |
| 122 virtual void Run() OVERRIDE; | |
| 123 | |
| 124 void DidGetDB(crypto::ScopedPK11Slot slot, net::NSSCertDatabase* cert_db); | |
|
Ryan Sleevi
2014/05/08 20:52:04
Document
pneubeck (no reviews)
2014/05/14 15:01:49
Done.
| |
| 125 | |
| 126 private: | |
| 127 scoped_ptr<api_epk::ImportCertificate::Params> params_; | |
| 128 base::WeakPtrFactory<ImportCertificate> weak_factory_; | |
| 129 }; | |
| 130 | |
| 131 class RemoveCertificate : public TokenMethod { | |
| 132 public: | |
| 133 RemoveCertificate(scoped_ptr<api_epk::RemoveCertificate::Params> params, | |
| 134 EnterprisePlatformKeysTokenMethodExtensionFunction* func); | |
| 135 virtual ~RemoveCertificate() {} | |
| 136 virtual void Run() OVERRIDE; | |
| 137 | |
| 138 void DidGetDB(crypto::ScopedPK11Slot slot, net::NSSCertDatabase* cert_db); | |
|
Ryan Sleevi
2014/05/08 20:52:04
Document
pneubeck (no reviews)
2014/05/14 15:01:49
Done.
| |
| 139 | |
| 140 private: | |
| 141 scoped_ptr<api_epk::RemoveCertificate::Params> params_; | |
| 142 base::WeakPtrFactory<RemoveCertificate> weak_factory_; | |
| 143 }; | |
| 144 | |
| 145 GenerateKey::GenerateKey(scoped_ptr<api_epki::GenerateKey::Params> params, | |
| 146 const GenerateKeyCallback& callback, | |
| 147 const TokenMethod::ErrorCallback& error_callback, | |
| 148 Profile* profile) | |
| 149 : TokenMethod(error_callback, profile), | |
| 150 params_(params.Pass()), | |
| 151 callback_(callback), | |
| 152 weak_factory_(this) { | |
| 153 } | |
| 154 | |
| 155 void GenerateKey::Run() { | |
| 156 GetCertDatabase( | |
| 157 params_->token_id, | |
| 158 base::Bind(&GenerateKey::DidGetDB, weak_factory_.GetWeakPtr()), | |
| 159 error_callback_, | |
| 160 profile_); | |
| 161 } | |
| 162 | |
| 163 void GenerateKey::DidGetDB(crypto::ScopedPK11Slot slot, | |
| 164 net::NSSCertDatabase* cert_db) { | |
| 165 const int modulus_length = params_->modulus_length; | |
| 166 if (modulus_length > 2048) { | |
|
Ryan Sleevi
2014/05/08 20:52:04
Why do this check here?
Is it because the TPM doe
pneubeck (no reviews)
2014/05/14 15:01:49
RSAPrivateKey seems to understand 'sensitive' as '
Ryan Sleevi
2014/05/15 19:57:13
Hrm. I really wish Chaps used separate slots then,
| |
| 167 error_callback_.Run(kErrorAlgorithmNotSupported); | |
| 168 return; | |
| 169 } | |
| 170 scoped_ptr<crypto::RSAPrivateKey> rsa_key( | |
| 171 crypto::RSAPrivateKey::CreateSensitive(slot.get(), modulus_length)); | |
|
Ryan Sleevi
2014/05/08 20:52:04
What thread will this run on? It will block whatev
pneubeck (no reviews)
2014/05/14 15:01:49
Yes, I still have to move that to another thread.
Ryan Sleevi
2014/05/15 19:57:13
I don't think we should enable this API until that
| |
| 172 if (!rsa_key) { | |
| 173 LOG(ERROR) << "Couldn't create key."; | |
| 174 error_callback_.Run(kErrorInternal); | |
| 175 return; | |
| 176 } | |
| 177 | |
| 178 std::vector<uint8> public_key_der; | |
| 179 if (!rsa_key->ExportPublicKey(&public_key_der)) { | |
|
Ryan Sleevi
2014/05/08 20:52:04
Don't use this function if you want this API to be
pneubeck (no reviews)
2014/05/14 15:01:49
Hm. I thought about this one too and stopped inves
Ryan Sleevi
2014/05/15 19:57:13
Yeah, I did. Thanks for digging in.
| |
| 180 // TODO(pneubeck): Remove rsa_key from storage. | |
| 181 LOG(ERROR) << "Couldn't export public key."; | |
| 182 error_callback_.Run(kErrorInternal); | |
| 183 return; | |
| 184 } | |
| 185 std::string public_key_der_str(public_key_der.begin(), public_key_der.end()); | |
| 186 callback_.Run(public_key_der_str); | |
| 187 } | |
| 188 | |
| 189 /* | |
| 190 Sign::Sign(scoped_ptr<api_epki::Sign::Params> params, | |
| 191 EnterprisePlatformKeysTokenMethodExtensionFunction* func) | |
| 192 : TokenMethod(func), params_(params.Pass()), weak_factory_(this) { | |
| 193 } | |
| 194 | |
| 195 void Sign::Run() { | |
| 196 GetCertDatabase(params_->token_id, | |
| 197 base::Bind(&Sign::DidGetDB, weak_factory_.GetWeakPtr()), | |
| 198 func_); | |
| 199 } | |
| 200 | |
| 201 void Sign::DidGetDB(crypto::ScopedPK11Slot slot, | |
|
Ryan Sleevi
2014/05/08 20:52:04
Should this class be "RSASign", since you've coupl
pneubeck (no reviews)
2014/05/14 15:01:49
Done.
| |
| 202 net::NSSCertDatabase* cert_db) { | |
| 203 const std::string& public_key = params_->public_key; | |
| 204 const uint8* public_key_uint8 = | |
| 205 reinterpret_cast<const uint8*>(public_key.data()); | |
| 206 std::vector<uint8> public_key_vector(public_key_uint8, | |
| 207 public_key_uint8 + public_key.size()); | |
| 208 | |
| 209 // TODO(pneubeck): This searches all slots. Change to look only at |slot_|. | |
| 210 scoped_ptr<crypto::RSAPrivateKey> rsa_key( | |
| 211 crypto::RSAPrivateKey::FindFromPublicKeyInfo(public_key_vector)); | |
| 212 if (!rsa_key) { | |
| 213 func_->RespondWithError(kErrorKeyNotFound); | |
| 214 return; | |
| 215 } | |
| 216 | |
| 217 const std::string& data = params_->data; | |
| 218 SECItem sign_result = {siBuffer, NULL, 0}; | |
| 219 if (SEC_SignData(&sign_result, | |
| 220 reinterpret_cast<const unsigned char*>(data.data()), | |
| 221 data.size(), | |
| 222 rsa_key->key(), | |
| 223 SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION) != SECSuccess) { | |
| 224 LOG(ERROR) << "Couldn't sign."; | |
| 225 func_->RespondWithError(kErrorInternal); | |
| 226 return; | |
| 227 } | |
| 228 | |
| 229 std::string signature(reinterpret_cast<const char*>(sign_result.data), | |
| 230 sign_result.len); | |
| 231 func_->RespondWithResults(api_epki::Sign::Results::Create(signature)); | |
| 232 } | |
| 233 | |
| 234 GetCertificates::GetCertificates( | |
| 235 scoped_ptr<api_epk::GetCertificates::Params> params, | |
| 236 EnterprisePlatformKeysTokenMethodExtensionFunction* func) | |
| 237 : TokenMethod(func), params_(params.Pass()), weak_factory_(this) { | |
| 238 } | |
| 239 | |
| 240 void GetCertificates::Run() { | |
| 241 GetCertDatabase( | |
| 242 params_->token_id, | |
| 243 base::Bind(&GetCertificates::DidGetDB, weak_factory_.GetWeakPtr()), | |
| 244 func_); | |
| 245 } | |
| 246 | |
| 247 void GetCertificates::DidGetDB(crypto::ScopedPK11Slot slot, | |
| 248 net::NSSCertDatabase* cert_db) { | |
| 249 slot_ = slot.Pass(); | |
| 250 cert_db->ListCertsInSlot(base::Bind(&GetCertificates::DidGetCertificates, | |
| 251 weak_factory_.GetWeakPtr()), | |
| 252 slot_.get()); | |
| 253 } | |
| 254 | |
| 255 void GetCertificates::DidGetCertificates( | |
| 256 scoped_ptr<net::CertificateList> certs) { | |
| 257 // std::vector<std::string> client_certs; | |
| 258 scoped_ptr<base::ListValue> client_certs(new base::ListValue()); | |
| 259 for (net::CertificateList::const_iterator it = certs->begin(); | |
| 260 it != certs->end(); | |
| 261 ++it) { | |
| 262 net::X509Certificate::OSCertHandle cert_handle = (*it)->os_cert_handle(); | |
| 263 crypto::ScopedPK11Slot cert_slot(PK11_KeyForCertExists(cert_handle, | |
| 264 NULL, // keyPtr | |
| 265 NULL)); // wincx | |
| 266 | |
| 267 // Keep only user certificate, i.e. certs for which the private key is | |
| 268 // present, and certs where the private key is stored in the queried slot. | |
| 269 if (cert_slot != slot_) | |
| 270 continue; | |
| 271 | |
| 272 std::string der_encoding; | |
| 273 net::X509Certificate::GetDEREncoded(cert_handle, &der_encoding); | |
| 274 // client_certs.push_back(der_encoding); | |
|
Ryan Sleevi
2014/05/08 20:52:04
delete?
pneubeck (no reviews)
2014/05/14 15:01:49
Done.
| |
| 275 client_certs->Append(base::BinaryValue::CreateWithCopiedBuffer( | |
| 276 der_encoding.data(), der_encoding.size())); | |
| 277 } | |
| 278 scoped_ptr<base::ListValue> results(new base::ListValue()); | |
| 279 results->Append(client_certs.release()); | |
| 280 func_->RespondWithResults(results.Pass()); | |
| 281 // results_ = api_eci::GetClientCertificates::Results::Create(client_certs); | |
|
Ryan Sleevi
2014/05/08 20:52:04
delete?
pneubeck (no reviews)
2014/05/14 15:01:49
Done.
| |
| 282 } | |
| 283 | |
| 284 ImportCertificate::ImportCertificate( | |
| 285 scoped_ptr<api_epk::ImportCertificate::Params> params, | |
| 286 EnterprisePlatformKeysTokenMethodExtensionFunction* func) | |
| 287 : TokenMethod(func), params_(params.Pass()), weak_factory_(this) { | |
|
Ryan Sleevi
2014/05/08 20:52:04
git cl format will show this is bad style.
pneubeck (no reviews)
2014/05/14 15:01:49
sorry to disappoint you, it doesn't.
I can change
| |
| 288 } | |
| 289 | |
| 290 void ImportCertificate::Run() { | |
| 291 GetCertDatabase( | |
| 292 params_->token_id, | |
| 293 base::Bind(&ImportCertificate::DidGetDB, weak_factory_.GetWeakPtr()), | |
| 294 func_); | |
| 295 } | |
| 296 | |
| 297 void ImportCertificate::DidGetDB(crypto::ScopedPK11Slot slot, | |
| 298 net::NSSCertDatabase* cert_db) { | |
| 299 const std::string& certificate = params_->certificate; | |
| 300 scoped_refptr<net::X509Certificate> cert_x509 = | |
| 301 net::X509Certificate::CreateFromBytes(certificate.data(), | |
| 302 certificate.size()); | |
| 303 if (!cert_x509) { | |
| 304 func_->RespondWithError(kErrorInvalidX509Cert); | |
| 305 return; | |
| 306 } | |
| 307 | |
| 308 net::CertDatabase* db = net::CertDatabase::GetInstance(); | |
| 309 | |
| 310 const net::Error cert_status = db->CheckUserCert(cert_x509); | |
| 311 if (cert_status == net::ERR_NO_PRIVATE_KEY_FOR_CERT) { | |
| 312 func_->RespondWithError(kErrorKeyNotFound); | |
| 313 return; | |
| 314 } else if (cert_status != net::OK) { | |
| 315 func_->RespondWithError(net::ErrorToString(cert_status)); | |
| 316 return; | |
| 317 } | |
| 318 | |
| 319 const net::Error import_status = db->AddUserCert(cert_x509.get()); | |
| 320 if (import_status != net::OK) { | |
| 321 LOG(ERROR) << "Could not import certificate."; | |
| 322 func_->RespondWithError(net::ErrorToString(import_status)); | |
| 323 return; | |
| 324 } | |
| 325 | |
| 326 func_->RespondWithoutResult(); | |
| 327 } | |
| 328 | |
| 329 RemoveCertificate::RemoveCertificate( | |
| 330 scoped_ptr<api_epk::RemoveCertificate::Params> params, | |
| 331 EnterprisePlatformKeysTokenMethodExtensionFunction* func) | |
| 332 : TokenMethod(func), params_(params.Pass()), weak_factory_(this) { | |
| 333 } | |
| 334 | |
| 335 void RemoveCertificate::Run() { | |
| 336 GetCertDatabase( | |
| 337 params_->token_id, | |
| 338 base::Bind(&RemoveCertificate::DidGetDB, weak_factory_.GetWeakPtr()), | |
| 339 func_); | |
| 340 } | |
| 341 | |
| 342 void RemoveCertificate::DidGetDB(crypto::ScopedPK11Slot slot, | |
| 343 net::NSSCertDatabase* cert_db) { | |
| 344 const std::string& certificate = params_->certificate; | |
| 345 scoped_refptr<net::X509Certificate> cert_x509 = | |
| 346 net::X509Certificate::CreateFromBytes(certificate.data(), | |
| 347 certificate.size()); | |
| 348 if (!cert_x509) { | |
| 349 func_->RespondWithError(kErrorInvalidX509Cert); | |
| 350 return; | |
| 351 } | |
| 352 | |
| 353 bool certificate_found = cert_x509->os_cert_handle()->isperm; | |
| 354 bool success = cert_db->DeleteCertAndKey(cert_x509); | |
| 355 | |
| 356 // CertificateNotFound error has precedence over an internal error. | |
| 357 if (!certificate_found) { | |
| 358 func_->RespondWithError(kErrorCertificateNotFound); | |
| 359 return; | |
| 360 } | |
| 361 if (!success) { | |
| 362 func_->RespondWithError(kErrorInternal); | |
| 363 return; | |
| 364 } | |
| 365 | |
| 366 func_->RespondWithoutResult(); | |
| 367 } | |
| 368 */ | |
| 369 | |
| 370 } // namespace | |
| 371 | |
| 372 scoped_ptr<TokenMethod> CreateGenerateKey( | |
| 373 scoped_ptr<api_epki::GenerateKey::Params> params, | |
| 374 const GenerateKeyCallback& callback, | |
| 375 const TokenMethod::ErrorCallback& error_callback, | |
| 376 Profile* profile) { | |
| 377 return scoped_ptr<TokenMethod>( | |
| 378 new GenerateKey(params.Pass(), callback, error_callback, profile)); | |
| 379 } | |
| 380 | |
| 381 scoped_ptr<TokenMethod> CreateSign( | |
| 382 scoped_ptr<api_epki::Sign::Params> params, | |
| 383 EnterprisePlatformKeysTokenMethodExtensionFunction* func) { | |
| 384 return scoped_ptr<TokenMethod>(new Sign(params.Pass(), func)); | |
| 385 } | |
| 386 | |
| 387 scoped_ptr<TokenMethod> CreateGetCertificates( | |
| 388 scoped_ptr<api_epk::GetCertificates::Params> params, | |
| 389 EnterprisePlatformKeysTokenMethodExtensionFunction* func) { | |
| 390 return scoped_ptr<TokenMethod>(new GetCertificates(params.Pass(), func)); | |
| 391 } | |
| 392 | |
| 393 scoped_ptr<TokenMethod> CreateImportCertificate( | |
| 394 scoped_ptr<api_epk::ImportCertificate::Params> params, | |
| 395 EnterprisePlatformKeysTokenMethodExtensionFunction* func) { | |
| 396 return scoped_ptr<TokenMethod>(new ImportCertificate(params.Pass(), func)); | |
| 397 } | |
| 398 | |
| 399 scoped_ptr<TokenMethod> CreateRemoveCertificate( | |
| 400 scoped_ptr<api_epk::RemoveCertificate::Params> params, | |
| 401 EnterprisePlatformKeysTokenMethodExtensionFunction* func) { | |
| 402 return scoped_ptr<TokenMethod>(new RemoveCertificate(params.Pass(), func)); | |
| 403 } | |
| 404 | |
| 405 } // namespace enterprise_platform_keys_details | |
| 406 | |
| 407 } // namespace extensions | |
| OLD | NEW |