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/enterprise_platform_keys_api.h"
6
7 #include "base/bind.h"
8 #include "base/values.h"
9 #include "chrome/browser/chromeos/platform_keys/platform_keys.h"
10 #include "chrome/browser/chromeos/platform_keys/platform_keys_service.h"
11 #include "chrome/browser/chromeos/platform_keys/platform_keys_service_factory.h"
12 #include "chrome/common/extensions/api/enterprise_platform_keys.h"
13 #include "chrome/common/extensions/api/enterprise_platform_keys_internal.h"
14 #include "content/public/browser/browser_thread.h"
15 #include "net/cert/x509_certificate.h"
16
17 namespace extensions {
18
19 namespace {
20
21 namespace api_epk = api::enterprise_platform_keys;
22 namespace api_epki = api::enterprise_platform_keys_internal;
23
24 // This error will occur if a token is removed and will be exposed to the
25 // extension. Keep this in sync with the custom binding in Javascript.
26 const char kErrorInvalidToken[] = "The token is not valid.";
27
28 const char kErrorAlgorithmNotSupported[] = "Algorithm not supported.";
29 const char kErrorInvalidX509Cert[] =
30 "Certificate is not a valid X.509 certificate.";
31 const char kTokenIdUser[] = "user";
32
33 // Returns whether |token_id| references a known Token.
ValidateToken(const std::string & token_id)34 bool ValidateToken(const std::string& token_id) {
35 // For now, the user token is the only valid one.
36 return token_id == kTokenIdUser;
37 }
38
39 } // namespace
40
41 EnterprisePlatformKeysInternalGenerateKeyFunction::
~EnterprisePlatformKeysInternalGenerateKeyFunction()42 ~EnterprisePlatformKeysInternalGenerateKeyFunction() {
43 }
44
45 ExtensionFunction::ResponseAction
Run()46 EnterprisePlatformKeysInternalGenerateKeyFunction::Run() {
47 scoped_ptr<api_epki::GenerateKey::Params> params(
48 api_epki::GenerateKey::Params::Create(*args_));
49 // TODO(pneubeck): Add support for unsigned integers to IDL.
50 EXTENSION_FUNCTION_VALIDATE(params && params->modulus_length >= 0);
51 if (!ValidateToken(params->token_id))
52 return RespondNow(Error(kErrorInvalidToken));
53
54 chromeos::PlatformKeysService* service =
55 chromeos::PlatformKeysServiceFactory::GetForBrowserContext(
56 browser_context());
57 DCHECK(service);
58
59 service->GenerateRSAKey(
60 params->token_id,
61 params->modulus_length,
62 extension_id(),
63 base::Bind(
64 &EnterprisePlatformKeysInternalGenerateKeyFunction::OnGeneratedKey,
65 this));
66 return RespondLater();
67 }
68
OnGeneratedKey(const std::string & public_key_der,const std::string & error_message)69 void EnterprisePlatformKeysInternalGenerateKeyFunction::OnGeneratedKey(
70 const std::string& public_key_der,
71 const std::string& error_message) {
72 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
73 if (error_message.empty()) {
74 Respond(
75 ArgumentList(api_epki::GenerateKey::Results::Create(public_key_der)));
76 } else {
77 Respond(Error(error_message));
78 }
79 }
80
81 EnterprisePlatformKeysInternalSignFunction::
~EnterprisePlatformKeysInternalSignFunction()82 ~EnterprisePlatformKeysInternalSignFunction() {
83 }
84
85 ExtensionFunction::ResponseAction
Run()86 EnterprisePlatformKeysInternalSignFunction::Run() {
87 scoped_ptr<api_epki::Sign::Params> params(
88 api_epki::Sign::Params::Create(*args_));
89 EXTENSION_FUNCTION_VALIDATE(params);
90 if (!ValidateToken(params->token_id))
91 return RespondNow(Error(kErrorInvalidToken));
92
93 chromeos::platform_keys::HashAlgorithm hash_algorithm;
94 if (params->hash_algorithm_name == "SHA-1")
95 hash_algorithm = chromeos::platform_keys::HASH_ALGORITHM_SHA1;
96 else if (params->hash_algorithm_name == "SHA-256")
97 hash_algorithm = chromeos::platform_keys::HASH_ALGORITHM_SHA256;
98 else if (params->hash_algorithm_name == "SHA-384")
99 hash_algorithm = chromeos::platform_keys::HASH_ALGORITHM_SHA384;
100 else if (params->hash_algorithm_name == "SHA-512")
101 hash_algorithm = chromeos::platform_keys::HASH_ALGORITHM_SHA512;
102 else
103 return RespondNow(Error(kErrorAlgorithmNotSupported));
104
105 chromeos::PlatformKeysService* service =
106 chromeos::PlatformKeysServiceFactory::GetForBrowserContext(
107 browser_context());
108 DCHECK(service);
109
110 service->Sign(
111 params->token_id,
112 params->public_key,
113 hash_algorithm,
114 params->data,
115 extension_id(),
116 base::Bind(&EnterprisePlatformKeysInternalSignFunction::OnSigned, this));
117 return RespondLater();
118 }
119
OnSigned(const std::string & signature,const std::string & error_message)120 void EnterprisePlatformKeysInternalSignFunction::OnSigned(
121 const std::string& signature,
122 const std::string& error_message) {
123 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
124 if (error_message.empty())
125 Respond(ArgumentList(api_epki::Sign::Results::Create(signature)));
126 else
127 Respond(Error(error_message));
128 }
129
130 EnterprisePlatformKeysGetCertificatesFunction::
~EnterprisePlatformKeysGetCertificatesFunction()131 ~EnterprisePlatformKeysGetCertificatesFunction() {
132 }
133
134 ExtensionFunction::ResponseAction
Run()135 EnterprisePlatformKeysGetCertificatesFunction::Run() {
136 scoped_ptr<api_epk::GetCertificates::Params> params(
137 api_epk::GetCertificates::Params::Create(*args_));
138 EXTENSION_FUNCTION_VALIDATE(params);
139 if (!ValidateToken(params->token_id))
140 return RespondNow(Error(kErrorInvalidToken));
141
142 chromeos::platform_keys::GetCertificates(
143 params->token_id,
144 base::Bind(
145 &EnterprisePlatformKeysGetCertificatesFunction::OnGotCertificates,
146 this),
147 browser_context());
148 return RespondLater();
149 }
150
OnGotCertificates(scoped_ptr<net::CertificateList> certs,const std::string & error_message)151 void EnterprisePlatformKeysGetCertificatesFunction::OnGotCertificates(
152 scoped_ptr<net::CertificateList> certs,
153 const std::string& error_message) {
154 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
155 if (!error_message.empty()) {
156 Respond(Error(error_message));
157 return;
158 }
159
160 scoped_ptr<base::ListValue> client_certs(new base::ListValue());
161 for (net::CertificateList::const_iterator it = certs->begin();
162 it != certs->end();
163 ++it) {
164 std::string der_encoding;
165 net::X509Certificate::GetDEREncoded((*it)->os_cert_handle(), &der_encoding);
166 client_certs->Append(base::BinaryValue::CreateWithCopiedBuffer(
167 der_encoding.data(), der_encoding.size()));
168 }
169
170 scoped_ptr<base::ListValue> results(new base::ListValue());
171 results->Append(client_certs.release());
172 Respond(ArgumentList(results.Pass()));
173 }
174
175 EnterprisePlatformKeysImportCertificateFunction::
~EnterprisePlatformKeysImportCertificateFunction()176 ~EnterprisePlatformKeysImportCertificateFunction() {
177 }
178
179 ExtensionFunction::ResponseAction
Run()180 EnterprisePlatformKeysImportCertificateFunction::Run() {
181 scoped_ptr<api_epk::ImportCertificate::Params> params(
182 api_epk::ImportCertificate::Params::Create(*args_));
183 EXTENSION_FUNCTION_VALIDATE(params);
184 if (!ValidateToken(params->token_id))
185 return RespondNow(Error(kErrorInvalidToken));
186
187 const std::string& cert_der = params->certificate;
188 scoped_refptr<net::X509Certificate> cert_x509 =
189 net::X509Certificate::CreateFromBytes(cert_der.data(), cert_der.size());
190 if (!cert_x509)
191 return RespondNow(Error(kErrorInvalidX509Cert));
192
193 chromeos::platform_keys::ImportCertificate(
194 params->token_id,
195 cert_x509,
196 base::Bind(&EnterprisePlatformKeysImportCertificateFunction::
197 OnImportedCertificate,
198 this),
199 browser_context());
200 return RespondLater();
201 }
202
OnImportedCertificate(const std::string & error_message)203 void EnterprisePlatformKeysImportCertificateFunction::OnImportedCertificate(
204 const std::string& error_message) {
205 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
206 if (error_message.empty())
207 Respond(NoArguments());
208 else
209 Respond(Error(error_message));
210 }
211
212 EnterprisePlatformKeysRemoveCertificateFunction::
~EnterprisePlatformKeysRemoveCertificateFunction()213 ~EnterprisePlatformKeysRemoveCertificateFunction() {
214 }
215
216 ExtensionFunction::ResponseAction
Run()217 EnterprisePlatformKeysRemoveCertificateFunction::Run() {
218 scoped_ptr<api_epk::RemoveCertificate::Params> params(
219 api_epk::RemoveCertificate::Params::Create(*args_));
220 EXTENSION_FUNCTION_VALIDATE(params);
221 if (!ValidateToken(params->token_id))
222 return RespondNow(Error(kErrorInvalidToken));
223
224 const std::string& cert_der = params->certificate;
225 scoped_refptr<net::X509Certificate> cert_x509 =
226 net::X509Certificate::CreateFromBytes(cert_der.data(), cert_der.size());
227 if (!cert_x509)
228 return RespondNow(Error(kErrorInvalidX509Cert));
229
230 chromeos::platform_keys::RemoveCertificate(
231 params->token_id,
232 cert_x509,
233 base::Bind(&EnterprisePlatformKeysRemoveCertificateFunction::
234 OnRemovedCertificate,
235 this),
236 browser_context());
237 return RespondLater();
238 }
239
OnRemovedCertificate(const std::string & error_message)240 void EnterprisePlatformKeysRemoveCertificateFunction::OnRemovedCertificate(
241 const std::string& error_message) {
242 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
243 if (error_message.empty())
244 Respond(NoArguments());
245 else
246 Respond(Error(error_message));
247 }
248
249 EnterprisePlatformKeysInternalGetTokensFunction::
~EnterprisePlatformKeysInternalGetTokensFunction()250 ~EnterprisePlatformKeysInternalGetTokensFunction() {
251 }
252
253 ExtensionFunction::ResponseAction
Run()254 EnterprisePlatformKeysInternalGetTokensFunction::Run() {
255 EXTENSION_FUNCTION_VALIDATE(args_->empty());
256
257 std::vector<std::string> token_ids;
258 token_ids.push_back(kTokenIdUser);
259 return RespondNow(
260 ArgumentList(api_epki::GetTokens::Results::Create(token_ids)));
261 }
262
263 } // namespace extensions
264