Add ENABLE_MEDIA_ROUTER define to builds other than Android and iOS.
[chromium-blink-merge.git] / chrome / browser / extensions / api / platform_keys / platform_keys_api.cc
blob117618736aed3136333e9d78c8fb52b858e206da
1 // Copyright 2015 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.
5 #include "chrome/browser/extensions/api/platform_keys/platform_keys_api.h"
7 #include <vector>
9 #include "base/bind.h"
10 #include "base/logging.h"
11 #include "base/values.h"
12 #include "chrome/browser/chromeos/platform_keys/platform_keys.h"
13 #include "chrome/browser/chromeos/platform_keys/platform_keys_service.h"
14 #include "chrome/browser/chromeos/platform_keys/platform_keys_service_factory.h"
15 #include "chrome/common/extensions/api/platform_keys_internal.h"
16 #include "content/public/browser/browser_thread.h"
17 #include "net/cert/x509_certificate.h"
19 namespace extensions {
21 namespace api_pk = api::platform_keys;
22 namespace api_pki = api::platform_keys_internal;
24 namespace {
26 const char kErrorAlgorithmNotSupported[] = "Algorithm not supported.";
27 const char kErrorAlgorithmNotPermittedByCertificate[] =
28 "The requested Algorithm is not permitted by the certificate.";
29 const char kErrorInvalidX509Cert[] =
30 "Certificate is not a valid X.509 certificate.";
32 const char kWebCryptoRSASSA_PKCS1_v1_5[] = "RSASSA-PKCS1-v1_5";
34 struct PublicKeyInfo {
35 // The X.509 Subject Public Key Info of the key in DER encoding.
36 std::string public_key_spki_der;
38 // The type of the key.
39 net::X509Certificate::PublicKeyType key_type =
40 net::X509Certificate::kPublicKeyTypeUnknown;
42 // The size of the key in bits.
43 size_t key_size_bits = 0;
46 // Builds a partial WebCrypto Algorithm object from the parameters available in
47 // |key_info|, which must the info of an RSA key. This doesn't include sign/hash
48 // parameters and thus isn't complete.
49 // platform_keys::GetPublicKey() enforced the public exponent 65537.
50 void BuildWebCryptoRSAAlgorithmDictionary(const PublicKeyInfo& key_info,
51 base::DictionaryValue* algorithm) {
52 CHECK_EQ(net::X509Certificate::kPublicKeyTypeRSA, key_info.key_type);
53 algorithm->SetStringWithoutPathExpansion("name", kWebCryptoRSASSA_PKCS1_v1_5);
54 algorithm->SetIntegerWithoutPathExpansion("modulusLength",
55 key_info.key_size_bits);
57 // Equals 65537.
58 const unsigned char defaultPublicExponent[] = {0x01, 0x00, 0x01};
59 algorithm->SetWithoutPathExpansion(
60 "publicExponent",
61 base::BinaryValue::CreateWithCopiedBuffer(
62 reinterpret_cast<const char*>(defaultPublicExponent),
63 arraysize(defaultPublicExponent)));
66 } // namespace
68 namespace platform_keys {
70 const char kErrorInvalidToken[] = "The token is not valid.";
71 const char kTokenIdUser[] = "user";
72 const char kTokenIdSystem[] = "system";
74 // Returns whether |token_id| references a known Token.
75 bool ValidateToken(const std::string& token_id,
76 std::string* platform_keys_token_id) {
77 platform_keys_token_id->clear();
78 if (token_id == kTokenIdUser) {
79 *platform_keys_token_id = chromeos::platform_keys::kTokenIdUser;
80 return true;
82 if (token_id == kTokenIdSystem) {
83 *platform_keys_token_id = chromeos::platform_keys::kTokenIdSystem;
84 return true;
86 return false;
89 std::string PlatformKeysTokenIdToApiId(
90 const std::string& platform_keys_token_id) {
91 if (platform_keys_token_id == chromeos::platform_keys::kTokenIdUser)
92 return kTokenIdUser;
93 if (platform_keys_token_id == chromeos::platform_keys::kTokenIdSystem)
94 return kTokenIdSystem;
96 return std::string();
99 } // namespace platform_keys
101 PlatformKeysInternalGetPublicKeyFunction::
102 ~PlatformKeysInternalGetPublicKeyFunction() {
105 ExtensionFunction::ResponseAction
106 PlatformKeysInternalGetPublicKeyFunction::Run() {
107 scoped_ptr<api_pki::GetPublicKey::Params> params(
108 api_pki::GetPublicKey::Params::Create(*args_));
109 EXTENSION_FUNCTION_VALIDATE(params);
111 const std::vector<char>& cert_der = params->certificate;
112 if (cert_der.empty())
113 return RespondNow(Error(kErrorInvalidX509Cert));
114 scoped_refptr<net::X509Certificate> cert_x509 =
115 net::X509Certificate::CreateFromBytes(vector_as_array(&cert_der),
116 cert_der.size());
117 if (!cert_x509)
118 return RespondNow(Error(kErrorInvalidX509Cert));
120 PublicKeyInfo key_info;
121 key_info.public_key_spki_der =
122 chromeos::platform_keys::GetSubjectPublicKeyInfo(cert_x509);
123 if (!chromeos::platform_keys::GetPublicKey(cert_x509, &key_info.key_type,
124 &key_info.key_size_bits) ||
125 key_info.key_type != net::X509Certificate::kPublicKeyTypeRSA) {
126 return RespondNow(Error(kErrorAlgorithmNotSupported));
129 // Currently, the only supported combination is:
130 // A certificate declaring rsaEncryption in the SubjectPublicKeyInfo used
131 // with the RSASSA-PKCS1-v1.5 algorithm.
132 if (params->algorithm_name != kWebCryptoRSASSA_PKCS1_v1_5) {
133 return RespondNow(Error(kErrorAlgorithmNotPermittedByCertificate));
136 api_pki::GetPublicKey::Results::Algorithm algorithm;
137 BuildWebCryptoRSAAlgorithmDictionary(key_info,
138 &algorithm.additional_properties);
140 return RespondNow(ArgumentList(api_pki::GetPublicKey::Results::Create(
141 std::vector<char>(key_info.public_key_spki_der.begin(),
142 key_info.public_key_spki_der.end()),
143 algorithm)));
146 PlatformKeysInternalSelectClientCertificatesFunction::
147 ~PlatformKeysInternalSelectClientCertificatesFunction() {
150 ExtensionFunction::ResponseAction
151 PlatformKeysInternalSelectClientCertificatesFunction::Run() {
152 scoped_ptr<api_pki::SelectClientCertificates::Params> params(
153 api_pki::SelectClientCertificates::Params::Create(*args_));
154 EXTENSION_FUNCTION_VALIDATE(params);
156 chromeos::PlatformKeysService* service =
157 chromeos::PlatformKeysServiceFactory::GetForBrowserContext(
158 browser_context());
159 DCHECK(service);
161 chromeos::platform_keys::ClientCertificateRequest request;
162 for (const std::vector<char>& cert_authority :
163 params->details.request.certificate_authorities) {
164 request.certificate_authorities.push_back(
165 std::string(cert_authority.begin(), cert_authority.end()));
168 service->SelectClientCertificates(
169 request, params->details.interactive, extension_id(),
170 base::Bind(&PlatformKeysInternalSelectClientCertificatesFunction::
171 OnSelectedCertificates,
172 this),
173 GetAssociatedWebContents());
174 return RespondLater();
177 void PlatformKeysInternalSelectClientCertificatesFunction::
178 OnSelectedCertificates(scoped_ptr<net::CertificateList> matches,
179 const std::string& error_message) {
180 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
181 if (!error_message.empty()) {
182 Respond(Error(error_message));
183 return;
185 DCHECK(matches);
186 std::vector<linked_ptr<api_pk::Match>> result_matches;
187 for (const scoped_refptr<net::X509Certificate>& match : *matches) {
188 PublicKeyInfo key_info;
189 key_info.public_key_spki_der =
190 chromeos::platform_keys::GetSubjectPublicKeyInfo(match);
191 if (!chromeos::platform_keys::GetPublicKey(match, &key_info.key_type,
192 &key_info.key_size_bits)) {
193 LOG(ERROR) << "Could not retrieve public key info.";
194 continue;
196 if (key_info.key_type != net::X509Certificate::kPublicKeyTypeRSA) {
197 LOG(ERROR) << "Skipping unsupported certificate with non-RSA key.";
198 continue;
201 linked_ptr<api_pk::Match> result_match(new api_pk::Match);
202 std::string der_encoded_cert;
203 net::X509Certificate::GetDEREncoded(match->os_cert_handle(),
204 &der_encoded_cert);
205 result_match->certificate.assign(der_encoded_cert.begin(),
206 der_encoded_cert.end());
208 BuildWebCryptoRSAAlgorithmDictionary(
209 key_info, &result_match->key_algorithm.additional_properties);
210 result_matches.push_back(result_match);
212 Respond(ArgumentList(
213 api_pki::SelectClientCertificates::Results::Create(result_matches)));
216 PlatformKeysInternalSignFunction::~PlatformKeysInternalSignFunction() {
219 ExtensionFunction::ResponseAction PlatformKeysInternalSignFunction::Run() {
220 scoped_ptr<api_pki::Sign::Params> params(
221 api_pki::Sign::Params::Create(*args_));
222 EXTENSION_FUNCTION_VALIDATE(params);
223 std::string platform_keys_token_id;
224 if (!params->token_id.empty() &&
225 !platform_keys::ValidateToken(params->token_id,
226 &platform_keys_token_id)) {
227 return RespondNow(Error(platform_keys::kErrorInvalidToken));
230 chromeos::PlatformKeysService* service =
231 chromeos::PlatformKeysServiceFactory::GetForBrowserContext(
232 browser_context());
233 DCHECK(service);
235 if (params->hash_algorithm_name == "none") {
236 service->SignRSAPKCS1Raw(
237 platform_keys_token_id,
238 std::string(params->data.begin(), params->data.end()),
239 std::string(params->public_key.begin(), params->public_key.end()),
240 extension_id(),
241 base::Bind(&PlatformKeysInternalSignFunction::OnSigned, this));
242 } else {
243 chromeos::platform_keys::HashAlgorithm hash_algorithm;
244 if (params->hash_algorithm_name == "SHA-1") {
245 hash_algorithm = chromeos::platform_keys::HASH_ALGORITHM_SHA1;
246 } else if (params->hash_algorithm_name == "SHA-256") {
247 hash_algorithm = chromeos::platform_keys::HASH_ALGORITHM_SHA256;
248 } else if (params->hash_algorithm_name == "SHA-384") {
249 hash_algorithm = chromeos::platform_keys::HASH_ALGORITHM_SHA384;
250 } else if (params->hash_algorithm_name == "SHA-512") {
251 hash_algorithm = chromeos::platform_keys::HASH_ALGORITHM_SHA512;
252 } else {
253 return RespondNow(Error(kErrorAlgorithmNotSupported));
255 service->SignRSAPKCS1Digest(
256 platform_keys_token_id,
257 std::string(params->data.begin(), params->data.end()),
258 std::string(params->public_key.begin(), params->public_key.end()),
259 hash_algorithm, extension_id(),
260 base::Bind(&PlatformKeysInternalSignFunction::OnSigned, this));
263 return RespondLater();
266 void PlatformKeysInternalSignFunction::OnSigned(
267 const std::string& signature,
268 const std::string& error_message) {
269 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
270 if (error_message.empty())
271 Respond(ArgumentList(api_pki::Sign::Results::Create(
272 std::vector<char>(signature.begin(), signature.end()))));
273 else
274 Respond(Error(error_message));
277 } // namespace extensions