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

Side by Side Diff: content/renderer/webcrypto/webcrypto_impl.cc

Issue 155623005: Refactor to share more code between OpenSSL and NSS implementations. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Change header guard Created 6 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 | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2013 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 "content/renderer/webcrypto/webcrypto_impl.h" 5 #include "content/renderer/webcrypto/webcrypto_impl.h"
6 6
7 #include <algorithm>
8 #include <functional>
9 #include <map>
10 #include "base/json/json_reader.h"
11 #include "base/lazy_instance.h"
12 #include "base/logging.h" 7 #include "base/logging.h"
13 #include "base/memory/scoped_ptr.h" 8 #include "content/renderer/webcrypto/crypto_data.h"
14 #include "base/strings/string_piece.h" 9 #include "content/renderer/webcrypto/shared_crypto.h"
15 #include "base/values.h"
16 #include "content/renderer/webcrypto/webcrypto_util.h" 10 #include "content/renderer/webcrypto/webcrypto_util.h"
17 #include "third_party/WebKit/public/platform/WebCryptoAlgorithm.h"
18 #include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h"
19 #include "third_party/WebKit/public/platform/WebCryptoKey.h"
20 #include "third_party/WebKit/public/platform/WebString.h" 11 #include "third_party/WebKit/public/platform/WebString.h"
21 12
22 namespace content { 13 namespace content {
23 14
24 using webcrypto::Status; 15 using webcrypto::Status;
25 16
26 namespace { 17 namespace {
27 18
28 void CompleteWithError(const Status& status, blink::WebCryptoResult* result) { 19 void CompleteWithError(const Status& status, blink::WebCryptoResult* result) {
29 DCHECK(status.IsError()); 20 DCHECK(status.IsError());
30 if (status.HasErrorDetails()) 21 if (status.HasErrorDetails())
31 result->completeWithError(blink::WebString::fromUTF8(status.ToString())); 22 result->completeWithError(blink::WebString::fromUTF8(status.ToString()));
32 else 23 else
33 result->completeWithError(); 24 result->completeWithError();
34 } 25 }
35 26
36 bool IsAlgorithmAsymmetric(const blink::WebCryptoAlgorithm& algorithm) { 27 bool IsAlgorithmAsymmetric(const blink::WebCryptoAlgorithm& algorithm) {
37 // TODO(padolph): include all other asymmetric algorithms once they are 28 // TODO(padolph): include all other asymmetric algorithms once they are
38 // defined, e.g. EC and DH. 29 // defined, e.g. EC and DH.
39 return (algorithm.id() == blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5 || 30 return (algorithm.id() == blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5 ||
40 algorithm.id() == blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5 || 31 algorithm.id() == blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5 ||
41 algorithm.id() == blink::WebCryptoAlgorithmIdRsaOaep); 32 algorithm.id() == blink::WebCryptoAlgorithmIdRsaOaep);
42 } 33 }
43 34
44 typedef blink::WebCryptoAlgorithm (*AlgorithmCreationFunc)();
45
46 class JwkAlgorithmInfo {
47 public:
48 JwkAlgorithmInfo()
49 : creation_func_(NULL),
50 required_key_length_bytes_(NO_KEY_SIZE_REQUIREMENT) {
51
52 }
53
54 explicit JwkAlgorithmInfo(AlgorithmCreationFunc algorithm_creation_func)
55 : creation_func_(algorithm_creation_func),
56 required_key_length_bytes_(NO_KEY_SIZE_REQUIREMENT) {
57 }
58
59 JwkAlgorithmInfo(AlgorithmCreationFunc algorithm_creation_func,
60 unsigned int required_key_length_bits)
61 : creation_func_(algorithm_creation_func),
62 required_key_length_bytes_(required_key_length_bits / 8) {
63 DCHECK((required_key_length_bits % 8) == 0);
64 }
65
66 bool CreateAlgorithm(blink::WebCryptoAlgorithm* algorithm) const {
67 *algorithm = creation_func_();
68 return !algorithm->isNull();
69 }
70
71 bool IsInvalidKeyByteLength(size_t byte_length) const {
72 if (required_key_length_bytes_ == NO_KEY_SIZE_REQUIREMENT)
73 return false;
74 return required_key_length_bytes_ != byte_length;
75 }
76
77 private:
78 enum { NO_KEY_SIZE_REQUIREMENT = UINT_MAX };
79
80 AlgorithmCreationFunc creation_func_;
81
82 // The expected key size for the algorithm or NO_KEY_SIZE_REQUIREMENT.
83 unsigned int required_key_length_bytes_;
84
85 };
86
87 typedef std::map<std::string, JwkAlgorithmInfo> JwkAlgorithmInfoMap;
88
89 class JwkAlgorithmRegistry {
90 public:
91 JwkAlgorithmRegistry() {
92 // TODO(eroman):
93 // http://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-20
94 // says HMAC with SHA-2 should have a key size at least as large as the
95 // hash output.
96 alg_to_info_["HS256"] = JwkAlgorithmInfo(
97 &BindAlgorithmId<webcrypto::CreateHmacAlgorithmByHashId,
98 blink::WebCryptoAlgorithmIdSha256>);
99 alg_to_info_["HS384"] = JwkAlgorithmInfo(
100 &BindAlgorithmId<webcrypto::CreateHmacAlgorithmByHashId,
101 blink::WebCryptoAlgorithmIdSha384>);
102 alg_to_info_["HS512"] = JwkAlgorithmInfo(
103 &BindAlgorithmId<webcrypto::CreateHmacAlgorithmByHashId,
104 blink::WebCryptoAlgorithmIdSha512>);
105 alg_to_info_["RS256"] = JwkAlgorithmInfo(
106 &BindAlgorithmId<webcrypto::CreateRsaSsaAlgorithm,
107 blink::WebCryptoAlgorithmIdSha256>);
108 alg_to_info_["RS384"] = JwkAlgorithmInfo(
109 &BindAlgorithmId<webcrypto::CreateRsaSsaAlgorithm,
110 blink::WebCryptoAlgorithmIdSha384>);
111 alg_to_info_["RS512"] = JwkAlgorithmInfo(
112 &BindAlgorithmId<webcrypto::CreateRsaSsaAlgorithm,
113 blink::WebCryptoAlgorithmIdSha512>);
114 alg_to_info_["RSA1_5"] = JwkAlgorithmInfo(
115 &BindAlgorithmId<webcrypto::CreateAlgorithm,
116 blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5>);
117 alg_to_info_["RSA-OAEP"] = JwkAlgorithmInfo(
118 &BindAlgorithmId<webcrypto::CreateRsaOaepAlgorithm,
119 blink::WebCryptoAlgorithmIdSha1>);
120 // TODO(padolph): The Web Crypto spec does not enumerate AES-KW 128 yet
121 alg_to_info_["A128KW"] =
122 JwkAlgorithmInfo(&blink::WebCryptoAlgorithm::createNull, 128);
123 // TODO(padolph): The Web Crypto spec does not enumerate AES-KW 256 yet
124 alg_to_info_["A256KW"] =
125 JwkAlgorithmInfo(&blink::WebCryptoAlgorithm::createNull, 256);
126 alg_to_info_["A128GCM"] = JwkAlgorithmInfo(
127 &BindAlgorithmId<webcrypto::CreateAlgorithm,
128 blink::WebCryptoAlgorithmIdAesGcm>, 128);
129 alg_to_info_["A256GCM"] = JwkAlgorithmInfo(
130 &BindAlgorithmId<webcrypto::CreateAlgorithm,
131 blink::WebCryptoAlgorithmIdAesGcm>, 256);
132 alg_to_info_["A128CBC"] = JwkAlgorithmInfo(
133 &BindAlgorithmId<webcrypto::CreateAlgorithm,
134 blink::WebCryptoAlgorithmIdAesCbc>, 128);
135 alg_to_info_["A192CBC"] = JwkAlgorithmInfo(
136 &BindAlgorithmId<webcrypto::CreateAlgorithm,
137 blink::WebCryptoAlgorithmIdAesCbc>, 192);
138 alg_to_info_["A256CBC"] = JwkAlgorithmInfo(
139 &BindAlgorithmId<webcrypto::CreateAlgorithm,
140 blink::WebCryptoAlgorithmIdAesCbc>, 256);
141 }
142
143 // Returns NULL if the algorithm name was not registered.
144 const JwkAlgorithmInfo* GetAlgorithmInfo(const std::string& jwk_alg) const {
145 const JwkAlgorithmInfoMap::const_iterator pos = alg_to_info_.find(jwk_alg);
146 if (pos == alg_to_info_.end())
147 return NULL;
148 return &pos->second;
149 }
150
151 private:
152 // Binds a WebCryptoAlgorithmId value to a compatible factory function.
153 typedef blink::WebCryptoAlgorithm (*FuncWithWebCryptoAlgIdArg)(
154 blink::WebCryptoAlgorithmId);
155 template <FuncWithWebCryptoAlgIdArg func,
156 blink::WebCryptoAlgorithmId algorithm_id>
157 static blink::WebCryptoAlgorithm BindAlgorithmId() {
158 return func(algorithm_id);
159 }
160
161 JwkAlgorithmInfoMap alg_to_info_;
162 };
163
164 base::LazyInstance<JwkAlgorithmRegistry> jwk_alg_registry =
165 LAZY_INSTANCE_INITIALIZER;
166
167 bool WebCryptoAlgorithmsConsistent(const blink::WebCryptoAlgorithm& alg1,
168 const blink::WebCryptoAlgorithm& alg2) {
169 DCHECK(!alg1.isNull());
170 DCHECK(!alg2.isNull());
171 if (alg1.id() != alg2.id())
172 return false;
173 switch (alg1.id()) {
174 case blink::WebCryptoAlgorithmIdHmac:
175 case blink::WebCryptoAlgorithmIdRsaOaep:
176 case blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5:
177 if (WebCryptoAlgorithmsConsistent(
178 webcrypto::GetInnerHashAlgorithm(alg1),
179 webcrypto::GetInnerHashAlgorithm(alg2))) {
180 return true;
181 }
182 break;
183 case blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5:
184 case blink::WebCryptoAlgorithmIdSha1:
185 case blink::WebCryptoAlgorithmIdSha224:
186 case blink::WebCryptoAlgorithmIdSha256:
187 case blink::WebCryptoAlgorithmIdSha384:
188 case blink::WebCryptoAlgorithmIdSha512:
189 case blink::WebCryptoAlgorithmIdAesCbc:
190 case blink::WebCryptoAlgorithmIdAesGcm:
191 case blink::WebCryptoAlgorithmIdAesCtr:
192 return true;
193 default:
194 NOTREACHED(); // Not a supported algorithm.
195 break;
196 }
197 return false;
198 }
199
200 // Extracts the required string property with key |path| from |dict| and saves
201 // the result to |*result|. If the property does not exist or is not a string,
202 // returns an error.
203 Status GetJwkString(base::DictionaryValue* dict,
204 const std::string& path,
205 std::string* result) {
206 base::Value* value = NULL;
207 if (!dict->Get(path, &value))
208 return Status::ErrorJwkPropertyMissing(path);
209 if (!value->GetAsString(result))
210 return Status::ErrorJwkPropertyWrongType(path, "string");
211 return Status::Success();
212 }
213
214 // Extracts the optional string property with key |path| from |dict| and saves
215 // the result to |*result| if it was found. If the property exists and is not a
216 // string, returns an error. Otherwise returns success, and sets
217 // |*property_exists| if it was found.
218 Status GetOptionalJwkString(base::DictionaryValue* dict,
219 const std::string& path,
220 std::string* result,
221 bool* property_exists) {
222 *property_exists = false;
223 base::Value* value = NULL;
224 if (!dict->Get(path, &value))
225 return Status::Success();
226
227 if (!value->GetAsString(result))
228 return Status::ErrorJwkPropertyWrongType(path, "string");
229
230 *property_exists = true;
231 return Status::Success();
232 }
233
234 // Extracts the required string property with key |path| from |dict| and saves
235 // the base64-decoded bytes to |*result|. If the property does not exist or is
236 // not a string, or could not be base64-decoded, returns an error.
237 Status GetJwkBytes(base::DictionaryValue* dict,
238 const std::string& path,
239 std::string* result) {
240 std::string base64_string;
241 Status status = GetJwkString(dict, path, &base64_string);
242 if (status.IsError())
243 return status;
244
245 if (!webcrypto::Base64DecodeUrlSafe(base64_string, result))
246 return Status::ErrorJwkBase64Decode(path);
247
248 return Status::Success();
249 }
250
251 // Extracts the optional boolean property with key |path| from |dict| and saves
252 // the result to |*result| if it was found. If the property exists and is not a
253 // boolean, returns an error. Otherwise returns success, and sets
254 // |*property_exists| if it was found.
255 Status GetOptionalJwkBool(base::DictionaryValue* dict,
256 const std::string& path,
257 bool* result,
258 bool* property_exists) {
259 *property_exists = false;
260 base::Value* value = NULL;
261 if (!dict->Get(path, &value))
262 return Status::Success();
263
264 if (!value->GetAsBoolean(result))
265 return Status::ErrorJwkPropertyWrongType(path, "boolean");
266
267 *property_exists = true;
268 return Status::Success();
269 }
270 35
271 } // namespace 36 } // namespace
272 37
273 WebCryptoImpl::WebCryptoImpl() { 38 WebCryptoImpl::WebCryptoImpl() {
274 Init(); 39 webcrypto::Init();
275 } 40 }
276 41
42 WebCryptoImpl::~WebCryptoImpl() {}
43
277 void WebCryptoImpl::encrypt( 44 void WebCryptoImpl::encrypt(
278 const blink::WebCryptoAlgorithm& algorithm, 45 const blink::WebCryptoAlgorithm& algorithm,
279 const blink::WebCryptoKey& key, 46 const blink::WebCryptoKey& key,
280 const unsigned char* data, 47 const unsigned char* data,
281 unsigned int data_size, 48 unsigned int data_size,
282 blink::WebCryptoResult result) { 49 blink::WebCryptoResult result) {
283 DCHECK(!algorithm.isNull()); 50 DCHECK(!algorithm.isNull());
284 blink::WebArrayBuffer buffer; 51 blink::WebArrayBuffer buffer;
285 Status status = EncryptInternal(algorithm, key, data, data_size, &buffer); 52 Status status = webcrypto::Encrypt(
53 algorithm, key, webcrypto::CryptoData(data, data_size), &buffer);
286 if (status.IsError()) 54 if (status.IsError())
287 CompleteWithError(status, &result); 55 CompleteWithError(status, &result);
288 else 56 else
289 result.completeWithBuffer(buffer); 57 result.completeWithBuffer(buffer);
290 } 58 }
291 59
292 void WebCryptoImpl::decrypt( 60 void WebCryptoImpl::decrypt(
293 const blink::WebCryptoAlgorithm& algorithm, 61 const blink::WebCryptoAlgorithm& algorithm,
294 const blink::WebCryptoKey& key, 62 const blink::WebCryptoKey& key,
295 const unsigned char* data, 63 const unsigned char* data,
296 unsigned int data_size, 64 unsigned int data_size,
297 blink::WebCryptoResult result) { 65 blink::WebCryptoResult result) {
298 DCHECK(!algorithm.isNull()); 66 DCHECK(!algorithm.isNull());
299 blink::WebArrayBuffer buffer; 67 blink::WebArrayBuffer buffer;
300 Status status = DecryptInternal(algorithm, key, data, data_size, &buffer); 68 Status status = webcrypto::Decrypt(
69 algorithm, key, webcrypto::CryptoData(data, data_size), &buffer);
301 if (status.IsError()) 70 if (status.IsError())
302 CompleteWithError(status, &result); 71 CompleteWithError(status, &result);
303 else 72 else
304 result.completeWithBuffer(buffer); 73 result.completeWithBuffer(buffer);
305 } 74 }
306 75
307 void WebCryptoImpl::digest( 76 void WebCryptoImpl::digest(
308 const blink::WebCryptoAlgorithm& algorithm, 77 const blink::WebCryptoAlgorithm& algorithm,
309 const unsigned char* data, 78 const unsigned char* data,
310 unsigned int data_size, 79 unsigned int data_size,
311 blink::WebCryptoResult result) { 80 blink::WebCryptoResult result) {
312 DCHECK(!algorithm.isNull()); 81 DCHECK(!algorithm.isNull());
313 blink::WebArrayBuffer buffer; 82 blink::WebArrayBuffer buffer;
314 Status status = DigestInternal(algorithm, data, data_size, &buffer); 83 Status status = webcrypto::Digest(
84 algorithm, webcrypto::CryptoData(data, data_size), &buffer);
315 if (status.IsError()) 85 if (status.IsError())
316 CompleteWithError(status, &result); 86 CompleteWithError(status, &result);
317 else 87 else
318 result.completeWithBuffer(buffer); 88 result.completeWithBuffer(buffer);
319 } 89 }
320 90
321 void WebCryptoImpl::generateKey( 91 void WebCryptoImpl::generateKey(
322 const blink::WebCryptoAlgorithm& algorithm, 92 const blink::WebCryptoAlgorithm& algorithm,
323 bool extractable, 93 bool extractable,
324 blink::WebCryptoKeyUsageMask usage_mask, 94 blink::WebCryptoKeyUsageMask usage_mask,
325 blink::WebCryptoResult result) { 95 blink::WebCryptoResult result) {
326 DCHECK(!algorithm.isNull()); 96 DCHECK(!algorithm.isNull());
327 if (IsAlgorithmAsymmetric(algorithm)) { 97 if (IsAlgorithmAsymmetric(algorithm)) {
328 blink::WebCryptoKey public_key = blink::WebCryptoKey::createNull(); 98 blink::WebCryptoKey public_key = blink::WebCryptoKey::createNull();
329 blink::WebCryptoKey private_key = blink::WebCryptoKey::createNull(); 99 blink::WebCryptoKey private_key = blink::WebCryptoKey::createNull();
330 Status status = GenerateKeyPairInternal( 100 Status status = webcrypto::GenerateKeyPair(
331 algorithm, extractable, usage_mask, &public_key, &private_key); 101 algorithm, extractable, usage_mask, &public_key, &private_key);
332 if (status.IsError()) { 102 if (status.IsError()) {
333 CompleteWithError(status, &result); 103 CompleteWithError(status, &result);
334 } else { 104 } else {
335 DCHECK(public_key.handle()); 105 DCHECK(public_key.handle());
336 DCHECK(private_key.handle()); 106 DCHECK(private_key.handle());
337 DCHECK_EQ(algorithm.id(), public_key.algorithm().id()); 107 DCHECK_EQ(algorithm.id(), public_key.algorithm().id());
338 DCHECK_EQ(algorithm.id(), private_key.algorithm().id()); 108 DCHECK_EQ(algorithm.id(), private_key.algorithm().id());
339 DCHECK_EQ(true, public_key.extractable()); 109 DCHECK_EQ(true, public_key.extractable());
340 DCHECK_EQ(extractable, private_key.extractable()); 110 DCHECK_EQ(extractable, private_key.extractable());
341 DCHECK_EQ(usage_mask, public_key.usages()); 111 DCHECK_EQ(usage_mask, public_key.usages());
342 DCHECK_EQ(usage_mask, private_key.usages()); 112 DCHECK_EQ(usage_mask, private_key.usages());
343 result.completeWithKeyPair(public_key, private_key); 113 result.completeWithKeyPair(public_key, private_key);
344 } 114 }
345 } else { 115 } else {
346 blink::WebCryptoKey key = blink::WebCryptoKey::createNull(); 116 blink::WebCryptoKey key = blink::WebCryptoKey::createNull();
347 Status status = GenerateSecretKeyInternal( 117 Status status =
348 algorithm, extractable, usage_mask, &key); 118 webcrypto::GenerateSecretKey(algorithm, extractable, usage_mask, &key);
349 if (status.IsError()) { 119 if (status.IsError()) {
350 CompleteWithError(status, &result); 120 CompleteWithError(status, &result);
351 } else { 121 } else {
352 DCHECK(key.handle()); 122 DCHECK(key.handle());
353 DCHECK_EQ(algorithm.id(), key.algorithm().id()); 123 DCHECK_EQ(algorithm.id(), key.algorithm().id());
354 DCHECK_EQ(extractable, key.extractable()); 124 DCHECK_EQ(extractable, key.extractable());
355 DCHECK_EQ(usage_mask, key.usages()); 125 DCHECK_EQ(usage_mask, key.usages());
356 result.completeWithKey(key); 126 result.completeWithKey(key);
357 } 127 }
358 } 128 }
359 } 129 }
360 130
361 void WebCryptoImpl::importKey( 131 void WebCryptoImpl::importKey(
362 blink::WebCryptoKeyFormat format, 132 blink::WebCryptoKeyFormat format,
363 const unsigned char* key_data, 133 const unsigned char* key_data,
364 unsigned int key_data_size, 134 unsigned int key_data_size,
365 const blink::WebCryptoAlgorithm& algorithm_or_null, 135 const blink::WebCryptoAlgorithm& algorithm_or_null,
366 bool extractable, 136 bool extractable,
367 blink::WebCryptoKeyUsageMask usage_mask, 137 blink::WebCryptoKeyUsageMask usage_mask,
368 blink::WebCryptoResult result) { 138 blink::WebCryptoResult result) {
369 blink::WebCryptoKey key = blink::WebCryptoKey::createNull(); 139 blink::WebCryptoKey key = blink::WebCryptoKey::createNull();
370 Status status = Status::Error(); 140 Status status =
371 if (format == blink::WebCryptoKeyFormatJwk) { 141 webcrypto::ImportKey(format,
372 status = ImportKeyJwk(key_data, 142 webcrypto::CryptoData(key_data, key_data_size),
373 key_data_size, 143 algorithm_or_null,
374 algorithm_or_null, 144 extractable,
375 extractable, 145 usage_mask,
376 usage_mask, 146 &key);
377 &key);
378 } else {
379 status = ImportKeyInternal(format,
380 key_data,
381 key_data_size,
382 algorithm_or_null,
383 extractable,
384 usage_mask,
385 &key);
386 }
387 if (status.IsError()) { 147 if (status.IsError()) {
388 CompleteWithError(status, &result); 148 CompleteWithError(status, &result);
389 } else { 149 } else {
390 DCHECK(key.handle()); 150 DCHECK(key.handle());
391 DCHECK(!key.algorithm().isNull()); 151 DCHECK(!key.algorithm().isNull());
392 DCHECK_EQ(extractable, key.extractable()); 152 DCHECK_EQ(extractable, key.extractable());
393 result.completeWithKey(key); 153 result.completeWithKey(key);
394 } 154 }
395 } 155 }
396 156
397 void WebCryptoImpl::exportKey( 157 void WebCryptoImpl::exportKey(
398 blink::WebCryptoKeyFormat format, 158 blink::WebCryptoKeyFormat format,
399 const blink::WebCryptoKey& key, 159 const blink::WebCryptoKey& key,
400 blink::WebCryptoResult result) { 160 blink::WebCryptoResult result) {
401 blink::WebArrayBuffer buffer; 161 blink::WebArrayBuffer buffer;
402 Status status = ExportKeyInternal(format, key, &buffer); 162 Status status = webcrypto::ExportKey(format, key, &buffer);
403 if (status.IsError()) 163 if (status.IsError())
404 CompleteWithError(status, &result); 164 CompleteWithError(status, &result);
405 else 165 else
406 result.completeWithBuffer(buffer); 166 result.completeWithBuffer(buffer);
407 } 167 }
408 168
409 void WebCryptoImpl::sign( 169 void WebCryptoImpl::sign(
410 const blink::WebCryptoAlgorithm& algorithm, 170 const blink::WebCryptoAlgorithm& algorithm,
411 const blink::WebCryptoKey& key, 171 const blink::WebCryptoKey& key,
412 const unsigned char* data, 172 const unsigned char* data,
413 unsigned int data_size, 173 unsigned int data_size,
414 blink::WebCryptoResult result) { 174 blink::WebCryptoResult result) {
415 DCHECK(!algorithm.isNull()); 175 DCHECK(!algorithm.isNull());
416 blink::WebArrayBuffer buffer; 176 blink::WebArrayBuffer buffer;
417 Status status = SignInternal(algorithm, key, data, data_size, &buffer); 177 Status status = webcrypto::Sign(
178 algorithm, key, webcrypto::CryptoData(data, data_size), &buffer);
418 if (status.IsError()) 179 if (status.IsError())
419 CompleteWithError(status, &result); 180 CompleteWithError(status, &result);
420 else 181 else
421 result.completeWithBuffer(buffer); 182 result.completeWithBuffer(buffer);
422 } 183 }
423 184
424 void WebCryptoImpl::verifySignature( 185 void WebCryptoImpl::verifySignature(
425 const blink::WebCryptoAlgorithm& algorithm, 186 const blink::WebCryptoAlgorithm& algorithm,
426 const blink::WebCryptoKey& key, 187 const blink::WebCryptoKey& key,
427 const unsigned char* signature, 188 const unsigned char* signature,
428 unsigned int signature_size, 189 unsigned int signature_size,
429 const unsigned char* data, 190 const unsigned char* data,
430 unsigned int data_size, 191 unsigned int data_size,
431 blink::WebCryptoResult result) { 192 blink::WebCryptoResult result) {
432 DCHECK(!algorithm.isNull()); 193 DCHECK(!algorithm.isNull());
433 bool signature_match = false; 194 bool signature_match = false;
434 Status status = VerifySignatureInternal(algorithm, 195 Status status = webcrypto::VerifySignature(
435 key, 196 algorithm,
436 signature, 197 key,
437 signature_size, 198 webcrypto::CryptoData(signature, signature_size),
438 data, 199 webcrypto::CryptoData(data, data_size),
439 data_size, 200 &signature_match);
440 &signature_match);
441 if (status.IsError()) 201 if (status.IsError())
442 CompleteWithError(status, &result); 202 CompleteWithError(status, &result);
443 else 203 else
444 result.completeWithBoolean(signature_match); 204 result.completeWithBoolean(signature_match);
445 } 205 }
446 206
447 Status WebCryptoImpl::ImportKeyJwk(
448 const unsigned char* key_data,
449 unsigned int key_data_size,
450 const blink::WebCryptoAlgorithm& algorithm_or_null,
451 bool extractable,
452 blink::WebCryptoKeyUsageMask usage_mask,
453 blink::WebCryptoKey* key) {
454
455 // The goal of this method is to extract key material and meta data from the
456 // incoming JWK, combine them with the input parameters, and ultimately import
457 // a Web Crypto Key.
458 //
459 // JSON Web Key Format (JWK)
460 // http://tools.ietf.org/html/draft-ietf-jose-json-web-key-16
461 // TODO(padolph): Not all possible values are handled by this code right now
462 //
463 // A JWK is a simple JSON dictionary with the following entries
464 // - "kty" (Key Type) Parameter, REQUIRED
465 // - <kty-specific parameters, see below>, REQUIRED
466 // - "use" (Key Use) Parameter, OPTIONAL
467 // - "alg" (Algorithm) Parameter, OPTIONAL
468 // - "extractable" (Key Exportability), OPTIONAL [NOTE: not yet part of JOSE,
469 // see https://www.w3.org/Bugs/Public/show_bug.cgi?id=23796]
470 // (all other entries are ignored)
471 //
472 // OPTIONAL here means that this code does not require the entry to be present
473 // in the incoming JWK, because the method input parameters contain similar
474 // information. If the optional JWK entry is present, it will be validated
475 // against the corresponding input parameter for consistency and combined with
476 // it according to rules defined below. A special case is that the method
477 // input parameter 'algorithm' is also optional. If it is null, the JWK 'alg'
478 // value (if present) is used as a fallback.
479 //
480 // Input 'key_data' contains the JWK. To build a Web Crypto Key, the JWK
481 // values are parsed out and combined with the method input parameters to
482 // build a Web Crypto Key:
483 // Web Crypto Key type <-- (deduced)
484 // Web Crypto Key extractable <-- JWK extractable + input extractable
485 // Web Crypto Key algorithm <-- JWK alg + input algorithm
486 // Web Crypto Key keyUsage <-- JWK use + input usage_mask
487 // Web Crypto Key keying material <-- kty-specific parameters
488 //
489 // Values for each JWK entry are case-sensitive and defined in
490 // http://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-16.
491 // Note that not all values specified by JOSE are handled by this code. Only
492 // handled values are listed.
493 // - kty (Key Type)
494 // +-------+--------------------------------------------------------------+
495 // | "RSA" | RSA [RFC3447] |
496 // | "oct" | Octet sequence (used to represent symmetric keys) |
497 // +-------+--------------------------------------------------------------+
498 // - use (Key Use)
499 // +-------+--------------------------------------------------------------+
500 // | "enc" | encrypt and decrypt operations |
501 // | "sig" | sign and verify (MAC) operations |
502 // | "wrap"| key wrap and unwrap [not yet part of JOSE] |
503 // +-------+--------------------------------------------------------------+
504 // - extractable (Key Exportability)
505 // +-------+--------------------------------------------------------------+
506 // | true | Key may be exported from the trusted environment |
507 // | false | Key cannot exit the trusted environment |
508 // +-------+--------------------------------------------------------------+
509 // - alg (Algorithm)
510 // See http://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-16
511 // +--------------+-------------------------------------------------------+
512 // | Digital Signature or MAC Algorithm |
513 // +--------------+-------------------------------------------------------+
514 // | "HS256" | HMAC using SHA-256 hash algorithm |
515 // | "HS384" | HMAC using SHA-384 hash algorithm |
516 // | "HS512" | HMAC using SHA-512 hash algorithm |
517 // | "RS256" | RSASSA using SHA-256 hash algorithm |
518 // | "RS384" | RSASSA using SHA-384 hash algorithm |
519 // | "RS512" | RSASSA using SHA-512 hash algorithm |
520 // +--------------+-------------------------------------------------------|
521 // | Key Management Algorithm |
522 // +--------------+-------------------------------------------------------+
523 // | "RSA1_5" | RSAES-PKCS1-V1_5 [RFC3447] |
524 // | "RSA-OAEP" | RSAES using Optimal Asymmetric Encryption Padding |
525 // | | (OAEP) [RFC3447], with the default parameters |
526 // | | specified by RFC3447 in Section A.2.1 |
527 // | "A128KW" | Advanced Encryption Standard (AES) Key Wrap Algorithm |
528 // | | [RFC3394] using 128 bit keys |
529 // | "A256KW" | AES Key Wrap Algorithm using 256 bit keys |
530 // | "A128GCM" | AES in Galois/Counter Mode (GCM) [NIST.800-38D] using |
531 // | | 128 bit keys |
532 // | "A256GCM" | AES GCM using 256 bit keys |
533 // | "A128CBC" | AES in Cipher Block Chaining Mode (CBC) with PKCS #5 |
534 // | | padding [NIST.800-38A] [not yet part of JOSE, see |
535 // | | https://www.w3.org/Bugs/Public/show_bug.cgi?id=23796 |
536 // | "A192CBC" | AES CBC using 192 bit keys [not yet part of JOSE] |
537 // | "A256CBC" | AES CBC using 256 bit keys [not yet part of JOSE] |
538 // +--------------+-------------------------------------------------------+
539 //
540 // kty-specific parameters
541 // The value of kty determines the type and content of the keying material
542 // carried in the JWK to be imported. Currently only two possibilities are
543 // supported: a raw key or an RSA public key. RSA private keys are not
544 // supported because typical applications seldom need to import a private key,
545 // and the large number of JWK parameters required to describe one.
546 // - kty == "oct" (symmetric or other raw key)
547 // +-------+--------------------------------------------------------------+
548 // | "k" | Contains the value of the symmetric (or other single-valued) |
549 // | | key. It is represented as the base64url encoding of the |
550 // | | octet sequence containing the key value. |
551 // +-------+--------------------------------------------------------------+
552 // - kty == "RSA" (RSA public key)
553 // +-------+--------------------------------------------------------------+
554 // | "n" | Contains the modulus value for the RSA public key. It is |
555 // | | represented as the base64url encoding of the value's |
556 // | | unsigned big endian representation as an octet sequence. |
557 // +-------+--------------------------------------------------------------+
558 // | "e" | Contains the exponent value for the RSA public key. It is |
559 // | | represented as the base64url encoding of the value's |
560 // | | unsigned big endian representation as an octet sequence. |
561 // +-------+--------------------------------------------------------------+
562 //
563 // Consistency and conflict resolution
564 // The 'algorithm_or_null', 'extractable', and 'usage_mask' input parameters
565 // may be different than the corresponding values inside the JWK. The Web
566 // Crypto spec says that if a JWK value is present but is inconsistent with
567 // the input value, it is an error and the operation must fail. If no
568 // inconsistency is found, the input and JWK values are combined as follows:
569 //
570 // algorithm
571 // If an algorithm is provided by both the input parameter and the JWK,
572 // consistency between the two is based only on algorithm ID's (including an
573 // inner hash algorithm if present). In this case if the consistency
574 // check is passed, the input algorithm is used. If only one of either the
575 // input algorithm and JWK alg is provided, it is used as the final
576 // algorithm.
577 //
578 // extractable
579 // If the JWK extractable is true but the input parameter is false, make the
580 // Web Crypto Key non-extractable. Conversely, if the JWK extractable is
581 // false but the input parameter is true, it is an inconsistency. If both
582 // are true or both are false, use that value.
583 //
584 // usage_mask
585 // The input usage_mask must be a strict subset of the interpreted JWK use
586 // value, else it is judged inconsistent. In all cases the input usage_mask
587 // is used as the final usage_mask.
588 //
589
590 if (!key_data_size)
591 return Status::ErrorImportEmptyKeyData();
592 DCHECK(key);
593
594 // Parse the incoming JWK JSON.
595 base::StringPiece json_string(reinterpret_cast<const char*>(key_data),
596 key_data_size);
597 scoped_ptr<base::Value> value(base::JSONReader::Read(json_string));
598 // Note, bare pointer dict_value is ok since it points into scoped value.
599 base::DictionaryValue* dict_value = NULL;
600 if (!value.get() || !value->GetAsDictionary(&dict_value) || !dict_value)
601 return Status::ErrorJwkNotDictionary();
602
603 // JWK "kty". Exit early if this required JWK parameter is missing.
604 std::string jwk_kty_value;
605 Status status = GetJwkString(dict_value, "kty", &jwk_kty_value);
606 if (status.IsError())
607 return status;
608
609 // JWK "extractable" (optional) --> extractable parameter
610 {
611 bool jwk_extractable_value = false;
612 bool has_jwk_extractable;
613 status = GetOptionalJwkBool(dict_value,
614 "extractable",
615 &jwk_extractable_value,
616 &has_jwk_extractable);
617 if (status.IsError())
618 return status;
619 if (has_jwk_extractable && !jwk_extractable_value && extractable)
620 return Status::ErrorJwkExtractableInconsistent();
621 }
622
623 // JWK "alg" (optional) --> algorithm parameter
624 // Note: input algorithm is also optional, so we have six cases to handle.
625 // 1. JWK alg present but unrecognized: error
626 // 2. JWK alg valid AND input algorithm isNull: use JWK value
627 // 3. JWK alg valid AND input algorithm specified, but JWK value
628 // inconsistent with input: error
629 // 4. JWK alg valid AND input algorithm specified, both consistent: use
630 // input value (because it has potentially more details)
631 // 5. JWK alg missing AND input algorithm isNull: error
632 // 6. JWK alg missing AND input algorithm specified: use input value
633 blink::WebCryptoAlgorithm algorithm = blink::WebCryptoAlgorithm::createNull();
634 const JwkAlgorithmInfo* algorithm_info = NULL;
635 std::string jwk_alg_value;
636 bool has_jwk_alg;
637 status =
638 GetOptionalJwkString(dict_value, "alg", &jwk_alg_value, &has_jwk_alg);
639 if (status.IsError())
640 return status;
641
642 if (has_jwk_alg) {
643 // JWK alg present
644
645 // TODO(padolph): Validate alg vs kty. For example kty="RSA" implies alg can
646 // only be from the RSA family.
647
648 blink::WebCryptoAlgorithm jwk_algorithm =
649 blink::WebCryptoAlgorithm::createNull();
650 algorithm_info = jwk_alg_registry.Get().GetAlgorithmInfo(jwk_alg_value);
651 if (!algorithm_info || !algorithm_info->CreateAlgorithm(&jwk_algorithm))
652 return Status::ErrorJwkUnrecognizedAlgorithm(); // case 1
653
654 // JWK alg valid
655 if (algorithm_or_null.isNull()) {
656 // input algorithm not specified
657 algorithm = jwk_algorithm; // case 2
658 } else {
659 // input algorithm specified
660 if (!WebCryptoAlgorithmsConsistent(jwk_algorithm, algorithm_or_null))
661 return Status::ErrorJwkAlgorithmInconsistent(); // case 3
662 algorithm = algorithm_or_null; // case 4
663 }
664 } else {
665 // JWK alg missing
666 if (algorithm_or_null.isNull())
667 return Status::ErrorJwkAlgorithmMissing(); // case 5
668 algorithm = algorithm_or_null; // case 6
669 }
670 DCHECK(!algorithm.isNull());
671
672 // JWK "use" (optional) --> usage_mask parameter
673 std::string jwk_use_value;
674 bool has_jwk_use;
675 status =
676 GetOptionalJwkString(dict_value, "use", &jwk_use_value, &has_jwk_use);
677 if (status.IsError())
678 return status;
679 if (has_jwk_use) {
680 blink::WebCryptoKeyUsageMask jwk_usage_mask = 0;
681 if (jwk_use_value == "enc") {
682 jwk_usage_mask =
683 blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageDecrypt;
684 } else if (jwk_use_value == "sig") {
685 jwk_usage_mask =
686 blink::WebCryptoKeyUsageSign | blink::WebCryptoKeyUsageVerify;
687 } else if (jwk_use_value == "wrap") {
688 jwk_usage_mask =
689 blink::WebCryptoKeyUsageWrapKey | blink::WebCryptoKeyUsageUnwrapKey;
690 } else {
691 return Status::ErrorJwkUnrecognizedUsage();
692 }
693 if ((jwk_usage_mask & usage_mask) != usage_mask) {
694 // A usage_mask must be a subset of jwk_usage_mask.
695 return Status::ErrorJwkUsageInconsistent();
696 }
697 }
698
699 // JWK keying material --> ImportKeyInternal()
700 if (jwk_kty_value == "oct") {
701
702 std::string jwk_k_value;
703 status = GetJwkBytes(dict_value, "k", &jwk_k_value);
704 if (status.IsError())
705 return status;
706
707 // Some JWK alg ID's embed information about the key length in the alg ID
708 // string. For example "A128CBC" implies the JWK carries 128 bits
709 // of key material. For such keys validate that enough bytes were provided.
710 // If this validation is not done, then it would be possible to select a
711 // different algorithm by passing a different lengthed key, since that is
712 // how WebCrypto interprets things.
713 if (algorithm_info &&
714 algorithm_info->IsInvalidKeyByteLength(jwk_k_value.size())) {
715 return Status::ErrorJwkIncorrectKeyLength();
716 }
717
718 return ImportKeyInternal(blink::WebCryptoKeyFormatRaw,
719 reinterpret_cast<const uint8*>(jwk_k_value.data()),
720 jwk_k_value.size(),
721 algorithm,
722 extractable,
723 usage_mask,
724 key);
725 } else if (jwk_kty_value == "RSA") {
726
727 // An RSA public key must have an "n" (modulus) and an "e" (exponent) entry
728 // in the JWK, while an RSA private key must have those, plus at least a "d"
729 // (private exponent) entry.
730 // See http://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-18,
731 // section 6.3.
732
733 // RSA private key import is not currently supported, so fail here if a "d"
734 // entry is found.
735 // TODO(padolph): Support RSA private key import.
736 if (dict_value->HasKey("d"))
737 return Status::ErrorJwkRsaPrivateKeyUnsupported();
738
739 std::string jwk_n_value;
740 status = GetJwkBytes(dict_value, "n", &jwk_n_value);
741 if (status.IsError())
742 return status;
743 std::string jwk_e_value;
744 status = GetJwkBytes(dict_value, "e", &jwk_e_value);
745 if (status.IsError())
746 return status;
747
748 return ImportRsaPublicKeyInternal(
749 reinterpret_cast<const uint8*>(jwk_n_value.data()),
750 jwk_n_value.size(),
751 reinterpret_cast<const uint8*>(jwk_e_value.data()),
752 jwk_e_value.size(),
753 algorithm,
754 extractable,
755 usage_mask,
756 key);
757
758 } else {
759 return Status::ErrorJwkUnrecognizedKty();
760 }
761
762 return Status::Success();
763 }
764
765 } // namespace content 207 } // namespace content
OLDNEW
« no previous file with comments | « content/renderer/webcrypto/webcrypto_impl.h ('k') | content/renderer/webcrypto/webcrypto_impl_nss.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698