blob: fe4603665fd240a1ff42ff6320fbb02a6b118e45 [file] [log] [blame]
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/extensions/api/enterprise_platform_keys/enterprise_platform_keys_api.h"
#include <utility>
#include "base/bind.h"
#include "base/values.h"
#include "chrome/browser/chromeos/platform_keys/platform_keys.h"
#include "chrome/browser/chromeos/platform_keys/platform_keys_service.h"
#include "chrome/browser/chromeos/platform_keys/platform_keys_service_factory.h"
#include "chrome/browser/extensions/api/platform_keys/platform_keys_api.h"
#include "chrome/common/extensions/api/enterprise_platform_keys.h"
#include "chrome/common/extensions/api/enterprise_platform_keys_internal.h"
#include "content/public/browser/browser_thread.h"
#include "net/cert/x509_certificate.h"
namespace extensions {
namespace {
namespace api_epk = api::enterprise_platform_keys;
namespace api_epki = api::enterprise_platform_keys_internal;
// This error will occur if a token is removed and will be exposed to the
// extension. Keep this in sync with the custom binding in Javascript.
const char kErrorInternal[] = "Internal Error.";
const char kErrorInvalidX509Cert[] =
"Certificate is not a valid X.509 certificate.";
std::vector<char> VectorFromString(const std::string& s) {
return std::vector<char>(s.begin(), s.end());
}
std::string StringFromVector(const std::vector<char>& v) {
return std::string(v.begin(), v.end());
}
} // namespace
EnterprisePlatformKeysInternalGenerateKeyFunction::
~EnterprisePlatformKeysInternalGenerateKeyFunction() {
}
ExtensionFunction::ResponseAction
EnterprisePlatformKeysInternalGenerateKeyFunction::Run() {
std::unique_ptr<api_epki::GenerateKey::Params> params(
api_epki::GenerateKey::Params::Create(*args_));
// TODO(pneubeck): Add support for unsigned integers to IDL.
EXTENSION_FUNCTION_VALIDATE(params && params->modulus_length >= 0);
std::string platform_keys_token_id;
if (!platform_keys::ValidateToken(params->token_id, &platform_keys_token_id))
return RespondNow(Error(platform_keys::kErrorInvalidToken));
chromeos::PlatformKeysService* service =
chromeos::PlatformKeysServiceFactory::GetForBrowserContext(
browser_context());
DCHECK(service);
service->GenerateRSAKey(
platform_keys_token_id,
params->modulus_length,
extension_id(),
base::Bind(
&EnterprisePlatformKeysInternalGenerateKeyFunction::OnGeneratedKey,
this));
return RespondLater();
}
void EnterprisePlatformKeysInternalGenerateKeyFunction::OnGeneratedKey(
const std::string& public_key_der,
const std::string& error_message) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
if (error_message.empty()) {
Respond(ArgumentList(api_epki::GenerateKey::Results::Create(
std::vector<char>(public_key_der.begin(), public_key_der.end()))));
} else {
Respond(Error(error_message));
}
}
EnterprisePlatformKeysGetCertificatesFunction::
~EnterprisePlatformKeysGetCertificatesFunction() {
}
ExtensionFunction::ResponseAction
EnterprisePlatformKeysGetCertificatesFunction::Run() {
std::unique_ptr<api_epk::GetCertificates::Params> params(
api_epk::GetCertificates::Params::Create(*args_));
EXTENSION_FUNCTION_VALIDATE(params);
std::string platform_keys_token_id;
if (!platform_keys::ValidateToken(params->token_id, &platform_keys_token_id))
return RespondNow(Error(platform_keys::kErrorInvalidToken));
chromeos::platform_keys::GetCertificates(
platform_keys_token_id,
base::Bind(
&EnterprisePlatformKeysGetCertificatesFunction::OnGotCertificates,
this),
browser_context());
return RespondLater();
}
void EnterprisePlatformKeysGetCertificatesFunction::OnGotCertificates(
std::unique_ptr<net::CertificateList> certs,
const std::string& error_message) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
if (!error_message.empty()) {
Respond(Error(error_message));
return;
}
std::unique_ptr<base::ListValue> client_certs(new base::ListValue());
for (net::CertificateList::const_iterator it = certs->begin();
it != certs->end();
++it) {
std::string der_encoding;
net::X509Certificate::GetDEREncoded((*it)->os_cert_handle(), &der_encoding);
client_certs->Append(base::BinaryValue::CreateWithCopiedBuffer(
der_encoding.data(), der_encoding.size()));
}
std::unique_ptr<base::ListValue> results(new base::ListValue());
results->Append(std::move(client_certs));
Respond(ArgumentList(std::move(results)));
}
EnterprisePlatformKeysImportCertificateFunction::
~EnterprisePlatformKeysImportCertificateFunction() {
}
ExtensionFunction::ResponseAction
EnterprisePlatformKeysImportCertificateFunction::Run() {
std::unique_ptr<api_epk::ImportCertificate::Params> params(
api_epk::ImportCertificate::Params::Create(*args_));
EXTENSION_FUNCTION_VALIDATE(params);
std::string platform_keys_token_id;
if (!platform_keys::ValidateToken(params->token_id, &platform_keys_token_id))
return RespondNow(Error(platform_keys::kErrorInvalidToken));
const std::vector<char>& cert_der = params->certificate;
scoped_refptr<net::X509Certificate> cert_x509 =
net::X509Certificate::CreateFromBytes(cert_der.data(), cert_der.size());
if (!cert_x509.get())
return RespondNow(Error(kErrorInvalidX509Cert));
chromeos::platform_keys::ImportCertificate(
platform_keys_token_id,
cert_x509,
base::Bind(&EnterprisePlatformKeysImportCertificateFunction::
OnImportedCertificate,
this),
browser_context());
return RespondLater();
}
void EnterprisePlatformKeysImportCertificateFunction::OnImportedCertificate(
const std::string& error_message) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
if (error_message.empty())
Respond(NoArguments());
else
Respond(Error(error_message));
}
EnterprisePlatformKeysRemoveCertificateFunction::
~EnterprisePlatformKeysRemoveCertificateFunction() {
}
ExtensionFunction::ResponseAction
EnterprisePlatformKeysRemoveCertificateFunction::Run() {
std::unique_ptr<api_epk::RemoveCertificate::Params> params(
api_epk::RemoveCertificate::Params::Create(*args_));
EXTENSION_FUNCTION_VALIDATE(params);
std::string platform_keys_token_id;
if (!platform_keys::ValidateToken(params->token_id, &platform_keys_token_id))
return RespondNow(Error(platform_keys::kErrorInvalidToken));
const std::vector<char>& cert_der = params->certificate;
scoped_refptr<net::X509Certificate> cert_x509 =
net::X509Certificate::CreateFromBytes(cert_der.data(), cert_der.size());
if (!cert_x509.get())
return RespondNow(Error(kErrorInvalidX509Cert));
chromeos::platform_keys::RemoveCertificate(
platform_keys_token_id,
cert_x509,
base::Bind(&EnterprisePlatformKeysRemoveCertificateFunction::
OnRemovedCertificate,
this),
browser_context());
return RespondLater();
}
void EnterprisePlatformKeysRemoveCertificateFunction::OnRemovedCertificate(
const std::string& error_message) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
if (error_message.empty())
Respond(NoArguments());
else
Respond(Error(error_message));
}
EnterprisePlatformKeysInternalGetTokensFunction::
~EnterprisePlatformKeysInternalGetTokensFunction() {
}
ExtensionFunction::ResponseAction
EnterprisePlatformKeysInternalGetTokensFunction::Run() {
EXTENSION_FUNCTION_VALIDATE(args_->empty());
chromeos::platform_keys::GetTokens(
base::Bind(&EnterprisePlatformKeysInternalGetTokensFunction::OnGotTokens,
this),
browser_context());
return RespondLater();
}
void EnterprisePlatformKeysInternalGetTokensFunction::OnGotTokens(
std::unique_ptr<std::vector<std::string>> platform_keys_token_ids,
const std::string& error_message) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
if (!error_message.empty()) {
Respond(Error(error_message));
return;
}
std::vector<std::string> token_ids;
for (std::vector<std::string>::const_iterator it =
platform_keys_token_ids->begin();
it != platform_keys_token_ids->end();
++it) {
std::string token_id = platform_keys::PlatformKeysTokenIdToApiId(*it);
if (token_id.empty()) {
Respond(Error(kErrorInternal));
return;
}
token_ids.push_back(token_id);
}
Respond(ArgumentList(api_epki::GetTokens::Results::Create(token_ids)));
}
EnterprisePlatformKeysChallengeMachineKeyFunction::
EnterprisePlatformKeysChallengeMachineKeyFunction()
: default_impl_(new EPKPChallengeMachineKey), impl_(default_impl_.get()) {}
EnterprisePlatformKeysChallengeMachineKeyFunction::
EnterprisePlatformKeysChallengeMachineKeyFunction(
EPKPChallengeMachineKey* impl_for_testing)
: impl_(impl_for_testing) {}
EnterprisePlatformKeysChallengeMachineKeyFunction::
~EnterprisePlatformKeysChallengeMachineKeyFunction() = default;
ExtensionFunction::ResponseAction
EnterprisePlatformKeysChallengeMachineKeyFunction::Run() {
std::unique_ptr<api_epk::ChallengeMachineKey::Params> params(
api_epk::ChallengeMachineKey::Params::Create(*args_));
EXTENSION_FUNCTION_VALIDATE(params);
ChallengeKeyCallback callback = base::Bind(
&EnterprisePlatformKeysChallengeMachineKeyFunction::OnChallengedKey,
this);
// base::Unretained is safe on impl_ since its life-cycle matches |this| and
// |callback| holds a reference to |this|.
base::Closure task = base::Bind(
&EPKPChallengeMachineKey::Run, base::Unretained(impl_),
scoped_refptr<UIThreadExtensionFunction>(AsUIThreadExtensionFunction()),
callback, StringFromVector(params->challenge));
content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, task);
return RespondLater();
}
void EnterprisePlatformKeysChallengeMachineKeyFunction::OnChallengedKey(
bool success,
const std::string& data) {
if (success) {
Respond(ArgumentList(
api_epk::ChallengeMachineKey::Results::Create(VectorFromString(data))));
} else {
Respond(Error(data));
}
}
EnterprisePlatformKeysChallengeUserKeyFunction::
EnterprisePlatformKeysChallengeUserKeyFunction()
: default_impl_(new EPKPChallengeUserKey), impl_(default_impl_.get()) {}
EnterprisePlatformKeysChallengeUserKeyFunction::
EnterprisePlatformKeysChallengeUserKeyFunction(
EPKPChallengeUserKey* impl_for_testing)
: impl_(impl_for_testing) {}
EnterprisePlatformKeysChallengeUserKeyFunction::
~EnterprisePlatformKeysChallengeUserKeyFunction() = default;
ExtensionFunction::ResponseAction
EnterprisePlatformKeysChallengeUserKeyFunction::Run() {
std::unique_ptr<api_epk::ChallengeUserKey::Params> params(
api_epk::ChallengeUserKey::Params::Create(*args_));
EXTENSION_FUNCTION_VALIDATE(params);
ChallengeKeyCallback callback = base::Bind(
&EnterprisePlatformKeysChallengeUserKeyFunction::OnChallengedKey, this);
// base::Unretained is safe on impl_ since its life-cycle matches |this| and
// |callback| holds a reference to |this|.
base::Closure task = base::Bind(
&EPKPChallengeUserKey::Run, base::Unretained(impl_),
scoped_refptr<UIThreadExtensionFunction>(AsUIThreadExtensionFunction()),
callback, StringFromVector(params->challenge), params->register_key);
content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, task);
return RespondLater();
}
void EnterprisePlatformKeysChallengeUserKeyFunction::OnChallengedKey(
bool success,
const std::string& data) {
if (success) {
Respond(ArgumentList(
api_epk::ChallengeUserKey::Results::Create(VectorFromString(data))));
} else {
Respond(Error(data));
}
}
} // namespace extensions