Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(88)

Side by Side Diff: chrome/browser/extensions/api/platform_keys/platform_keys_api.cc

Issue 884073002: Implement chrome.platformKeys.getKeyPair(). (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@cert_impl2
Patch Set: Fix typo in basic.js. Created 5 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/extensions/api/platform_keys/platform_keys_api.h" 5 #include "chrome/browser/extensions/api/platform_keys/platform_keys_api.h"
6 6
7 #include <vector> 7 #include <vector>
8 8
9 #include "base/bind.h" 9 #include "base/bind.h"
10 #include "base/logging.h" 10 #include "base/logging.h"
11 #include "base/values.h"
11 #include "chrome/browser/chromeos/platform_keys/platform_keys.h" 12 #include "chrome/browser/chromeos/platform_keys/platform_keys.h"
12 #include "chrome/browser/chromeos/platform_keys/platform_keys_service.h" 13 #include "chrome/browser/chromeos/platform_keys/platform_keys_service.h"
13 #include "chrome/browser/chromeos/platform_keys/platform_keys_service_factory.h" 14 #include "chrome/browser/chromeos/platform_keys/platform_keys_service_factory.h"
14 #include "chrome/common/extensions/api/platform_keys_internal.h" 15 #include "chrome/common/extensions/api/platform_keys_internal.h"
15 #include "content/public/browser/browser_thread.h" 16 #include "content/public/browser/browser_thread.h"
16 #include "net/cert/x509_certificate.h" 17 #include "net/cert/x509_certificate.h"
17 18
18 namespace extensions { 19 namespace extensions {
19 20
20 namespace api_pk = api::platform_keys; 21 namespace api_pk = api::platform_keys;
21 namespace api_pki = api::platform_keys_internal; 22 namespace api_pki = api::platform_keys_internal;
22 23
24 namespace {
25
26 const char kErrorAlgorithmNotSupported[] = "Algorithm not supported.";
27 const char kErrorInvalidX509Cert[] =
28 "Certificate is not a valid X.509 certificate.";
29
30 struct PublicKeyInfo {
31 // The X.509 Subject Public Key Info of the key in DER encoding.
32 std::string public_key_spki_der;
33
34 // The type of the key.
35 net::X509Certificate::PublicKeyType key_type;
Ryan Sleevi 2015/02/10 21:25:28 Why not default-assign this to unknown, given that
pneubeck (no reviews) 2015/02/11 14:37:05 Looking at the specification of initialization/def
36
37 // The size of the key in bits.
38 size_t key_size_bits = 0;
39 };
40
41 // Builds a partial WebCrypto Algorithm object from the parameters available in
42 // |key_info|, which must the info of an RSA key. This doesn't include sign/hash
43 // parameters and thus isn't complete.
44 // platform_keys::GetPublicKey() enforced the public exponent 65537.
45 void BuildWebCryptoRSAAlgorithmDictionary(const PublicKeyInfo& key_info,
46 base::DictionaryValue* algorithm) {
47 CHECK_EQ(net::X509Certificate::kPublicKeyTypeRSA, key_info.key_type);
48 algorithm->SetStringWithoutPathExpansion("name", "RSASSA-PKCS1-v1_5");
49 algorithm->SetIntegerWithoutPathExpansion("modulusLength",
50 key_info.key_size_bits);
51
52 // Equals 65537.
53 const char defaultPublicExponent[] = {0x01, 0x00, 0x01};
Ryan Sleevi 2015/02/10 21:25:28 nit: For safety (in the event of future type chang
pneubeck (no reviews) 2015/02/11 14:37:05 base::BinaryValue::CreateWithCopiedBuffer takes a
Ryan Sleevi 2015/02/13 03:24:28 At this risk of pedantry, I'd recommend a reinterp
pneubeck (no reviews) 2015/02/14 13:25:14 I don't quite follow. It's {0x01, ...} and not {0x
pneubeck (no reviews) 2015/02/14 13:31:18 added the reinterpert_cast to follow the pattern i
54 algorithm->SetWithoutPathExpansion(
55 "publicExponent",
56 base::BinaryValue::CreateWithCopiedBuffer(
57 defaultPublicExponent, arraysize(defaultPublicExponent)));
58 }
59
60 } // namespace
61
23 namespace platform_keys { 62 namespace platform_keys {
24 63
25 const char kErrorInvalidToken[] = "The token is not valid."; 64 const char kErrorInvalidToken[] = "The token is not valid.";
26 const char kErrorAlgorithmNotSupported[] = "Algorithm not supported.";
27 const char kTokenIdUser[] = "user"; 65 const char kTokenIdUser[] = "user";
28 const char kTokenIdSystem[] = "system"; 66 const char kTokenIdSystem[] = "system";
29 67
30 // Returns whether |token_id| references a known Token. 68 // Returns whether |token_id| references a known Token.
31 bool ValidateToken(const std::string& token_id, 69 bool ValidateToken(const std::string& token_id,
32 std::string* platform_keys_token_id) { 70 std::string* platform_keys_token_id) {
33 platform_keys_token_id->clear(); 71 platform_keys_token_id->clear();
34 if (token_id == kTokenIdUser) { 72 if (token_id == kTokenIdUser) {
35 *platform_keys_token_id = chromeos::platform_keys::kTokenIdUser; 73 *platform_keys_token_id = chromeos::platform_keys::kTokenIdUser;
36 return true; 74 return true;
(...skipping 10 matching lines...) Expand all
47 if (platform_keys_token_id == chromeos::platform_keys::kTokenIdUser) 85 if (platform_keys_token_id == chromeos::platform_keys::kTokenIdUser)
48 return kTokenIdUser; 86 return kTokenIdUser;
49 if (platform_keys_token_id == chromeos::platform_keys::kTokenIdSystem) 87 if (platform_keys_token_id == chromeos::platform_keys::kTokenIdSystem)
50 return kTokenIdSystem; 88 return kTokenIdSystem;
51 89
52 return std::string(); 90 return std::string();
53 } 91 }
54 92
55 } // namespace platform_keys 93 } // namespace platform_keys
56 94
95 PlatformKeysInternalGetPublicKeyFunction::
96 ~PlatformKeysInternalGetPublicKeyFunction() {
97 }
98
99 ExtensionFunction::ResponseAction
100 PlatformKeysInternalGetPublicKeyFunction::Run() {
101 scoped_ptr<api_pki::GetPublicKey::Params> params(
102 api_pki::GetPublicKey::Params::Create(*args_));
103 EXTENSION_FUNCTION_VALIDATE(params);
104
105 const std::vector<char>& cert_der = params->certificate;
Ryan Sleevi 2015/02/10 21:25:28 BUG? What if |cert_der.empty()|
pneubeck (no reviews) 2015/02/11 14:37:05 net::X509Certificate::CreateFromBytes should likel
Ryan Sleevi 2015/02/13 03:24:28 It does not. It's an API violation to supply that.
106 scoped_refptr<net::X509Certificate> cert_x509 =
107 net::X509Certificate::CreateFromBytes(vector_as_array(&cert_der),
108 cert_der.size());
109 if (!cert_x509)
110 return RespondNow(Error(kErrorInvalidX509Cert));
111
112 PublicKeyInfo key_info;
113 if (!chromeos::platform_keys::GetPublicKey(
114 cert_x509, &key_info.public_key_spki_der, &key_info.key_type,
115 &key_info.key_size_bits) ||
116 key_info.key_type != net::X509Certificate::kPublicKeyTypeRSA) {
117 return RespondNow(Error(kErrorAlgorithmNotSupported));
118 }
119
120 api_pki::GetPublicKey::Results::Algorithm algorithm;
121 BuildWebCryptoRSAAlgorithmDictionary(key_info,
122 &algorithm.additional_properties);
123
124 return RespondNow(ArgumentList(api_pki::GetPublicKey::Results::Create(
125 std::vector<char>(key_info.public_key_spki_der.begin(),
Ryan Sleevi 2015/02/10 21:25:28 Why |char| and not |unsigned char|?
pneubeck (no reviews) 2015/02/11 14:37:05 api_pki::GetPublicKey::Results::Create is generate
126 key_info.public_key_spki_der.end()),
127 algorithm)));
128 }
129
57 PlatformKeysInternalSelectClientCertificatesFunction:: 130 PlatformKeysInternalSelectClientCertificatesFunction::
58 ~PlatformKeysInternalSelectClientCertificatesFunction() { 131 ~PlatformKeysInternalSelectClientCertificatesFunction() {
59 } 132 }
60 133
61 ExtensionFunction::ResponseAction 134 ExtensionFunction::ResponseAction
62 PlatformKeysInternalSelectClientCertificatesFunction::Run() { 135 PlatformKeysInternalSelectClientCertificatesFunction::Run() {
63 scoped_ptr<api_pki::SelectClientCertificates::Params> params( 136 scoped_ptr<api_pki::SelectClientCertificates::Params> params(
64 api_pki::SelectClientCertificates::Params::Create(*args_)); 137 api_pki::SelectClientCertificates::Params::Create(*args_));
65 EXTENSION_FUNCTION_VALIDATE(params); 138 EXTENSION_FUNCTION_VALIDATE(params);
66 139
(...skipping 21 matching lines...) Expand all
88 OnSelectedCertificates(scoped_ptr<net::CertificateList> matches, 161 OnSelectedCertificates(scoped_ptr<net::CertificateList> matches,
89 const std::string& error_message) { 162 const std::string& error_message) {
90 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 163 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
91 if (!error_message.empty()) { 164 if (!error_message.empty()) {
92 Respond(Error(error_message)); 165 Respond(Error(error_message));
93 return; 166 return;
94 } 167 }
95 DCHECK(matches); 168 DCHECK(matches);
96 std::vector<linked_ptr<api_pk::Match>> result_matches; 169 std::vector<linked_ptr<api_pk::Match>> result_matches;
97 for (const scoped_refptr<net::X509Certificate>& match : *matches) { 170 for (const scoped_refptr<net::X509Certificate>& match : *matches) {
171 PublicKeyInfo key_info;
172 if (!chromeos::platform_keys::GetPublicKey(
173 match, &key_info.public_key_spki_der, &key_info.key_type,
174 &key_info.key_size_bits)) {
175 LOG(ERROR) << "Could not retrieve public key info.";
176 continue;
177 }
178 if (key_info.key_type != net::X509Certificate::kPublicKeyTypeRSA) {
179 LOG(ERROR) << "Skipping unsupported certificate with non-RSA key.";
180 continue;
181 }
182
98 linked_ptr<api_pk::Match> result_match(new api_pk::Match); 183 linked_ptr<api_pk::Match> result_match(new api_pk::Match);
99 std::string der_encoded_cert; 184 std::string der_encoded_cert;
100 net::X509Certificate::GetDEREncoded(match->os_cert_handle(), 185 net::X509Certificate::GetDEREncoded(match->os_cert_handle(),
101 &der_encoded_cert); 186 &der_encoded_cert);
102 result_match->certificate.assign(der_encoded_cert.begin(), 187 result_match->certificate.assign(der_encoded_cert.begin(),
103 der_encoded_cert.end()); 188 der_encoded_cert.end());
189
190 BuildWebCryptoRSAAlgorithmDictionary(
191 key_info, &result_match->key_algorithm.additional_properties);
104 result_matches.push_back(result_match); 192 result_matches.push_back(result_match);
105 } 193 }
106 Respond(ArgumentList( 194 Respond(ArgumentList(
107 api_pki::SelectClientCertificates::Results::Create(result_matches))); 195 api_pki::SelectClientCertificates::Results::Create(result_matches)));
108 } 196 }
109 197
110 PlatformKeysInternalSignFunction::~PlatformKeysInternalSignFunction() { 198 PlatformKeysInternalSignFunction::~PlatformKeysInternalSignFunction() {
111 } 199 }
112 200
113 ExtensionFunction::ResponseAction PlatformKeysInternalSignFunction::Run() { 201 ExtensionFunction::ResponseAction PlatformKeysInternalSignFunction::Run() {
114 scoped_ptr<api_pki::Sign::Params> params( 202 scoped_ptr<api_pki::Sign::Params> params(
115 api_pki::Sign::Params::Create(*args_)); 203 api_pki::Sign::Params::Create(*args_));
116 EXTENSION_FUNCTION_VALIDATE(params); 204 EXTENSION_FUNCTION_VALIDATE(params);
117 std::string platform_keys_token_id; 205 std::string platform_keys_token_id;
118 if (!platform_keys::ValidateToken(params->token_id, &platform_keys_token_id)) 206 if (!params->token_id.empty() &&
207 !platform_keys::ValidateToken(params->token_id,
208 &platform_keys_token_id)) {
119 return RespondNow(Error(platform_keys::kErrorInvalidToken)); 209 return RespondNow(Error(platform_keys::kErrorInvalidToken));
120 210 }
121 chromeos::platform_keys::HashAlgorithm hash_algorithm;
122 if (params->hash_algorithm_name == "SHA-1")
123 hash_algorithm = chromeos::platform_keys::HASH_ALGORITHM_SHA1;
124 else if (params->hash_algorithm_name == "SHA-256")
125 hash_algorithm = chromeos::platform_keys::HASH_ALGORITHM_SHA256;
126 else if (params->hash_algorithm_name == "SHA-384")
127 hash_algorithm = chromeos::platform_keys::HASH_ALGORITHM_SHA384;
128 else if (params->hash_algorithm_name == "SHA-512")
129 hash_algorithm = chromeos::platform_keys::HASH_ALGORITHM_SHA512;
130 else
131 return RespondNow(Error(platform_keys::kErrorAlgorithmNotSupported));
132 211
133 chromeos::PlatformKeysService* service = 212 chromeos::PlatformKeysService* service =
134 chromeos::PlatformKeysServiceFactory::GetForBrowserContext( 213 chromeos::PlatformKeysServiceFactory::GetForBrowserContext(
135 browser_context()); 214 browser_context());
136 DCHECK(service); 215 DCHECK(service);
137 216
138 service->Sign( 217 if (params->hash_algorithm_name == "none") {
Ryan Sleevi 2015/02/10 21:25:28 Did you mean to do case-sensitive comparisons for
pneubeck (no reviews) 2015/02/11 14:37:05 Yes. This API function is internal and only called
139 platform_keys_token_id, 218 service->SignRSAPKCS1Raw(
140 std::string(params->public_key.begin(), params->public_key.end()), 219 platform_keys_token_id,
141 hash_algorithm, std::string(params->data.begin(), params->data.end()), 220 std::string(params->data.begin(), params->data.end()),
142 extension_id(), 221 std::string(params->public_key.begin(), params->public_key.end()),
143 base::Bind(&PlatformKeysInternalSignFunction::OnSigned, this)); 222 extension_id(),
223 base::Bind(&PlatformKeysInternalSignFunction::OnSigned, this));
224 } else {
225 chromeos::platform_keys::HashAlgorithm hash_algorithm;
226 if (params->hash_algorithm_name == "SHA-1") {
227 hash_algorithm = chromeos::platform_keys::HASH_ALGORITHM_SHA1;
228 } else if (params->hash_algorithm_name == "SHA-256") {
229 hash_algorithm = chromeos::platform_keys::HASH_ALGORITHM_SHA256;
230 } else if (params->hash_algorithm_name == "SHA-384") {
231 hash_algorithm = chromeos::platform_keys::HASH_ALGORITHM_SHA384;
232 } else if (params->hash_algorithm_name == "SHA-512") {
233 hash_algorithm = chromeos::platform_keys::HASH_ALGORITHM_SHA512;
234 } else {
235 return RespondNow(Error(kErrorAlgorithmNotSupported));
236 }
237 service->SignRSAPKCS1Digest(
238 platform_keys_token_id,
239 std::string(params->data.begin(), params->data.end()),
240 std::string(params->public_key.begin(), params->public_key.end()),
241 hash_algorithm, extension_id(),
242 base::Bind(&PlatformKeysInternalSignFunction::OnSigned, this));
243 }
244
144 return RespondLater(); 245 return RespondLater();
145 } 246 }
146 247
147 void PlatformKeysInternalSignFunction::OnSigned( 248 void PlatformKeysInternalSignFunction::OnSigned(
148 const std::string& signature, 249 const std::string& signature,
149 const std::string& error_message) { 250 const std::string& error_message) {
150 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 251 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
151 if (error_message.empty()) 252 if (error_message.empty())
152 Respond(ArgumentList(api_pki::Sign::Results::Create( 253 Respond(ArgumentList(api_pki::Sign::Results::Create(
153 std::vector<char>(signature.begin(), signature.end())))); 254 std::vector<char>(signature.begin(), signature.end()))));
154 else 255 else
155 Respond(Error(error_message)); 256 Respond(Error(error_message));
156 } 257 }
157 258
158 } // namespace extensions 259 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698