blob: a977b94602cc74bb9c1ba36af382328703cb9adc [file] [log] [blame]
[email protected]408699c2013-07-17 21:23:161// 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
3// found in the LICENSE file.
4
[email protected]3da6b212013-09-27 05:02:365#include "content/renderer/webcrypto/webcrypto_impl.h"
[email protected]408699c2013-07-17 21:23:166
[email protected]b28852b2013-12-04 04:57:117#include <algorithm>
8#include <functional>
9#include <map>
10#include "base/json/json_reader.h"
11#include "base/lazy_instance.h"
[email protected]c1b944a2013-10-23 06:33:2112#include "base/logging.h"
[email protected]1c879bc92013-09-18 07:45:3213#include "base/memory/scoped_ptr.h"
[email protected]b28852b2013-12-04 04:57:1114#include "base/strings/string_piece.h"
15#include "base/values.h"
16#include "content/renderer/webcrypto/webcrypto_util.h"
[email protected]1c879bc92013-09-18 07:45:3217#include "third_party/WebKit/public/platform/WebCryptoAlgorithm.h"
[email protected]b28852b2013-12-04 04:57:1118#include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h"
[email protected]1c879bc92013-09-18 07:45:3219#include "third_party/WebKit/public/platform/WebCryptoKey.h"
[email protected]408699c2013-07-17 21:23:1620
21namespace content {
22
[email protected]043cf1d32013-11-02 13:27:3023namespace {
24
[email protected]180ef242013-11-07 06:50:4625bool IsAlgorithmAsymmetric(const blink::WebCryptoAlgorithm& algorithm) {
[email protected]043cf1d32013-11-02 13:27:3026 // TODO(padolph): include all other asymmetric algorithms once they are
27 // defined, e.g. EC and DH.
[email protected]180ef242013-11-07 06:50:4628 return (algorithm.id() == blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5 ||
29 algorithm.id() == blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5 ||
30 algorithm.id() == blink::WebCryptoAlgorithmIdRsaOaep);
[email protected]043cf1d32013-11-02 13:27:3031}
32
[email protected]b28852b2013-12-04 04:57:1133// Binds a specific key length value to a compatible factory function.
34typedef blink::WebCryptoAlgorithm (*AlgFactoryFuncWithOneShortArg)(
35 unsigned short);
36template <AlgFactoryFuncWithOneShortArg func, unsigned short key_length>
37blink::WebCryptoAlgorithm BindAlgFactoryWithKeyLen() {
38 return func(key_length);
39}
40
41// Binds a WebCryptoAlgorithmId value to a compatible factory function.
42typedef blink::WebCryptoAlgorithm (*AlgFactoryFuncWithWebCryptoAlgIdArg)(
43 blink::WebCryptoAlgorithmId);
44template <AlgFactoryFuncWithWebCryptoAlgIdArg func,
45 blink::WebCryptoAlgorithmId algorithm_id>
46blink::WebCryptoAlgorithm BindAlgFactoryAlgorithmId() {
47 return func(algorithm_id);
48}
49
50// Defines a map between a JWK 'alg' string ID and a corresponding Web Crypto
51// factory function.
52typedef blink::WebCryptoAlgorithm (*AlgFactoryFuncNoArgs)();
53typedef std::map<std::string, AlgFactoryFuncNoArgs> JwkAlgFactoryMap;
54
55class JwkAlgorithmFactoryMap {
56 public:
57 JwkAlgorithmFactoryMap() {
58 map_["HS256"] =
59 &BindAlgFactoryWithKeyLen<webcrypto::CreateHmacAlgorithmByHashOutputLen,
60 256>;
61 map_["HS384"] =
62 &BindAlgFactoryWithKeyLen<webcrypto::CreateHmacAlgorithmByHashOutputLen,
63 384>;
64 map_["HS512"] =
65 &BindAlgFactoryWithKeyLen<webcrypto::CreateHmacAlgorithmByHashOutputLen,
66 512>;
67 map_["RS256"] =
68 &BindAlgFactoryAlgorithmId<webcrypto::CreateRsaSsaAlgorithm,
69 blink::WebCryptoAlgorithmIdSha256>;
70 map_["RS384"] =
71 &BindAlgFactoryAlgorithmId<webcrypto::CreateRsaSsaAlgorithm,
72 blink::WebCryptoAlgorithmIdSha384>;
73 map_["RS512"] =
74 &BindAlgFactoryAlgorithmId<webcrypto::CreateRsaSsaAlgorithm,
75 blink::WebCryptoAlgorithmIdSha512>;
76 map_["RSA1_5"] =
77 &BindAlgFactoryAlgorithmId<webcrypto::CreateAlgorithm,
78 blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5>;
79 map_["RSA-OAEP"] =
80 &BindAlgFactoryAlgorithmId<webcrypto::CreateRsaOaepAlgorithm,
81 blink::WebCryptoAlgorithmIdSha1>;
82 // TODO(padolph): The Web Crypto spec does not enumerate AES-KW 128 yet
83 map_["A128KW"] = &blink::WebCryptoAlgorithm::createNull;
84 // TODO(padolph): The Web Crypto spec does not enumerate AES-KW 256 yet
85 map_["A256KW"] = &blink::WebCryptoAlgorithm::createNull;
86 map_["A128GCM"] =
87 &BindAlgFactoryAlgorithmId<webcrypto::CreateAlgorithm,
88 blink::WebCryptoAlgorithmIdAesGcm>;
89 map_["A256GCM"] =
90 &BindAlgFactoryAlgorithmId<webcrypto::CreateAlgorithm,
91 blink::WebCryptoAlgorithmIdAesGcm>;
92 map_["A128CBC"] =
93 &BindAlgFactoryAlgorithmId<webcrypto::CreateAlgorithm,
94 blink::WebCryptoAlgorithmIdAesCbc>;
95 map_["A192CBC"] =
96 &BindAlgFactoryAlgorithmId<webcrypto::CreateAlgorithm,
97 blink::WebCryptoAlgorithmIdAesCbc>;
98 map_["A256CBC"] =
99 &BindAlgFactoryAlgorithmId<webcrypto::CreateAlgorithm,
100 blink::WebCryptoAlgorithmIdAesCbc>;
101 }
102
103 blink::WebCryptoAlgorithm CreateAlgorithmFromName(const std::string& alg_id)
104 const {
105 const JwkAlgFactoryMap::const_iterator pos = map_.find(alg_id);
106 if (pos == map_.end())
107 return blink::WebCryptoAlgorithm::createNull();
108 return pos->second();
109 }
110
111 private:
112 JwkAlgFactoryMap map_;
113};
114
115base::LazyInstance<JwkAlgorithmFactoryMap> jwk_alg_factory =
116 LAZY_INSTANCE_INITIALIZER;
117
118bool WebCryptoAlgorithmsConsistent(const blink::WebCryptoAlgorithm& alg1,
119 const blink::WebCryptoAlgorithm& alg2) {
120 DCHECK(!alg1.isNull());
121 DCHECK(!alg2.isNull());
122 if (alg1.id() != alg2.id())
123 return false;
124 switch (alg1.id()) {
125 case blink::WebCryptoAlgorithmIdHmac:
126 case blink::WebCryptoAlgorithmIdRsaOaep:
127 case blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5:
128 if (WebCryptoAlgorithmsConsistent(
129 webcrypto::GetInnerHashAlgorithm(alg1),
130 webcrypto::GetInnerHashAlgorithm(alg2))) {
131 return true;
132 }
133 break;
134 case blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5:
135 case blink::WebCryptoAlgorithmIdSha1:
136 case blink::WebCryptoAlgorithmIdSha224:
137 case blink::WebCryptoAlgorithmIdSha256:
138 case blink::WebCryptoAlgorithmIdSha384:
139 case blink::WebCryptoAlgorithmIdSha512:
140 case blink::WebCryptoAlgorithmIdAesCbc:
141 case blink::WebCryptoAlgorithmIdAesGcm:
142 case blink::WebCryptoAlgorithmIdAesCtr:
143 return true;
144 default:
145 NOTREACHED(); // Not a supported algorithm.
146 break;
147 }
148 return false;
149}
150
[email protected]e1134b32013-12-04 23:54:32151bool GetDecodedUrl64ValueByKey(
152 const base::DictionaryValue& dict,
153 const std::string& key,
154 std::string* decoded) {
155 std::string value_url64;
156 if (!dict.GetString(key, &value_url64) ||
157 !webcrypto::Base64DecodeUrlSafe(value_url64, decoded) ||
158 !decoded->size()) {
159 return false;
160 }
161 return true;
162}
163
[email protected]043cf1d32013-11-02 13:27:30164} // namespace
165
[email protected]7e4c36f2013-09-12 06:10:19166WebCryptoImpl::WebCryptoImpl() {
167 Init();
168}
169
[email protected]a2a06c732013-09-27 10:50:54170void WebCryptoImpl::encrypt(
[email protected]180ef242013-11-07 06:50:46171 const blink::WebCryptoAlgorithm& algorithm,
172 const blink::WebCryptoKey& key,
[email protected]a2a06c732013-09-27 10:50:54173 const unsigned char* data,
174 unsigned data_size,
[email protected]180ef242013-11-07 06:50:46175 blink::WebCryptoResult result) {
[email protected]2213f252013-10-31 04:33:34176 DCHECK(!algorithm.isNull());
[email protected]180ef242013-11-07 06:50:46177 blink::WebArrayBuffer buffer;
[email protected]a2a06c732013-09-27 10:50:54178 if (!EncryptInternal(algorithm, key, data, data_size, &buffer)) {
179 result.completeWithError();
180 } else {
181 result.completeWithBuffer(buffer);
182 }
183}
184
[email protected]868085a92013-10-01 00:42:30185void WebCryptoImpl::decrypt(
[email protected]180ef242013-11-07 06:50:46186 const blink::WebCryptoAlgorithm& algorithm,
187 const blink::WebCryptoKey& key,
[email protected]868085a92013-10-01 00:42:30188 const unsigned char* data,
189 unsigned data_size,
[email protected]180ef242013-11-07 06:50:46190 blink::WebCryptoResult result) {
[email protected]2213f252013-10-31 04:33:34191 DCHECK(!algorithm.isNull());
[email protected]180ef242013-11-07 06:50:46192 blink::WebArrayBuffer buffer;
[email protected]868085a92013-10-01 00:42:30193 if (!DecryptInternal(algorithm, key, data, data_size, &buffer)) {
194 result.completeWithError();
195 } else {
196 result.completeWithBuffer(buffer);
197 }
198}
199
[email protected]e5b794b2013-08-30 01:32:54200void WebCryptoImpl::digest(
[email protected]180ef242013-11-07 06:50:46201 const blink::WebCryptoAlgorithm& algorithm,
[email protected]e5b794b2013-08-30 01:32:54202 const unsigned char* data,
[email protected]ed80a092013-09-10 16:36:38203 unsigned data_size,
[email protected]180ef242013-11-07 06:50:46204 blink::WebCryptoResult result) {
[email protected]2213f252013-10-31 04:33:34205 DCHECK(!algorithm.isNull());
[email protected]180ef242013-11-07 06:50:46206 blink::WebArrayBuffer buffer;
[email protected]ed80a092013-09-10 16:36:38207 if (!DigestInternal(algorithm, data, data_size, &buffer)) {
[email protected]e5b794b2013-08-30 01:32:54208 result.completeWithError();
209 } else {
210 result.completeWithBuffer(buffer);
[email protected]408699c2013-07-17 21:23:16211 }
212}
213
[email protected]dfae8ab2013-10-10 19:45:06214void WebCryptoImpl::generateKey(
[email protected]180ef242013-11-07 06:50:46215 const blink::WebCryptoAlgorithm& algorithm,
[email protected]2213f252013-10-31 04:33:34216 bool extractable,
[email protected]180ef242013-11-07 06:50:46217 blink::WebCryptoKeyUsageMask usage_mask,
218 blink::WebCryptoResult result) {
[email protected]2213f252013-10-31 04:33:34219 DCHECK(!algorithm.isNull());
[email protected]043cf1d32013-11-02 13:27:30220 if (IsAlgorithmAsymmetric(algorithm)) {
[email protected]180ef242013-11-07 06:50:46221 blink::WebCryptoKey public_key = blink::WebCryptoKey::createNull();
222 blink::WebCryptoKey private_key = blink::WebCryptoKey::createNull();
[email protected]043cf1d32013-11-02 13:27:30223 if (!GenerateKeyPairInternal(
224 algorithm, extractable, usage_mask, &public_key, &private_key)) {
225 result.completeWithError();
226 } else {
227 DCHECK(public_key.handle());
228 DCHECK(private_key.handle());
229 DCHECK_EQ(algorithm.id(), public_key.algorithm().id());
230 DCHECK_EQ(algorithm.id(), private_key.algorithm().id());
231 // TODO(padolph): The public key should probably always be extractable,
232 // regardless of the input 'extractable' parameter, but that is not called
233 // out in the Web Crypto API spec.
234 // See https://www.w3.org/Bugs/Public/show_bug.cgi?id=23695
235 DCHECK_EQ(extractable, public_key.extractable());
236 DCHECK_EQ(extractable, private_key.extractable());
237 DCHECK_EQ(usage_mask, public_key.usages());
238 DCHECK_EQ(usage_mask, private_key.usages());
239 result.completeWithKeyPair(public_key, private_key);
240 }
[email protected]dfae8ab2013-10-10 19:45:06241 } else {
[email protected]180ef242013-11-07 06:50:46242 blink::WebCryptoKey key = blink::WebCryptoKey::createNull();
[email protected]043cf1d32013-11-02 13:27:30243 if (!GenerateKeyInternal(algorithm, extractable, usage_mask, &key)) {
244 result.completeWithError();
245 } else {
246 DCHECK(key.handle());
247 DCHECK_EQ(algorithm.id(), key.algorithm().id());
248 DCHECK_EQ(extractable, key.extractable());
249 DCHECK_EQ(usage_mask, key.usages());
250 result.completeWithKey(key);
251 }
[email protected]dfae8ab2013-10-10 19:45:06252 }
253}
254
[email protected]1c879bc92013-09-18 07:45:32255void WebCryptoImpl::importKey(
[email protected]180ef242013-11-07 06:50:46256 blink::WebCryptoKeyFormat format,
[email protected]1c879bc92013-09-18 07:45:32257 const unsigned char* key_data,
258 unsigned key_data_size,
[email protected]180ef242013-11-07 06:50:46259 const blink::WebCryptoAlgorithm& algorithm_or_null,
[email protected]1c879bc92013-09-18 07:45:32260 bool extractable,
[email protected]180ef242013-11-07 06:50:46261 blink::WebCryptoKeyUsageMask usage_mask,
262 blink::WebCryptoResult result) {
263 blink::WebCryptoKey key = blink::WebCryptoKey::createNull();
[email protected]b28852b2013-12-04 04:57:11264 if (format == blink::WebCryptoKeyFormatJwk) {
265 if (!ImportKeyJwk(key_data,
266 key_data_size,
267 algorithm_or_null,
268 extractable,
269 usage_mask,
270 &key)) {
271 result.completeWithError();
272 return;
273 }
274 } else {
275 if (!ImportKeyInternal(format,
276 key_data,
277 key_data_size,
278 algorithm_or_null,
279 extractable,
280 usage_mask,
281 &key)) {
282 result.completeWithError();
283 return;
284 }
[email protected]1c879bc92013-09-18 07:45:32285 }
[email protected]2213f252013-10-31 04:33:34286 DCHECK(key.handle());
287 DCHECK(!key.algorithm().isNull());
288 DCHECK_EQ(extractable, key.extractable());
[email protected]1c879bc92013-09-18 07:45:32289 result.completeWithKey(key);
290}
291
[email protected]e9b2c102013-11-26 04:26:33292void WebCryptoImpl::exportKey(
293 blink::WebCryptoKeyFormat format,
294 const blink::WebCryptoKey& key,
295 blink::WebCryptoResult result) {
296 blink::WebArrayBuffer buffer;
297 if (!ExportKeyInternal(format, key, &buffer)) {
298 result.completeWithError();
299 return;
300 }
301 result.completeWithBuffer(buffer);
302}
303
[email protected]1c879bc92013-09-18 07:45:32304void WebCryptoImpl::sign(
[email protected]180ef242013-11-07 06:50:46305 const blink::WebCryptoAlgorithm& algorithm,
306 const blink::WebCryptoKey& key,
[email protected]1c879bc92013-09-18 07:45:32307 const unsigned char* data,
308 unsigned data_size,
[email protected]180ef242013-11-07 06:50:46309 blink::WebCryptoResult result) {
[email protected]2213f252013-10-31 04:33:34310 DCHECK(!algorithm.isNull());
[email protected]180ef242013-11-07 06:50:46311 blink::WebArrayBuffer buffer;
[email protected]1c879bc92013-09-18 07:45:32312 if (!SignInternal(algorithm, key, data, data_size, &buffer)) {
313 result.completeWithError();
314 } else {
315 result.completeWithBuffer(buffer);
316 }
317}
318
[email protected]3ed00262013-09-26 22:28:10319void WebCryptoImpl::verifySignature(
[email protected]180ef242013-11-07 06:50:46320 const blink::WebCryptoAlgorithm& algorithm,
321 const blink::WebCryptoKey& key,
[email protected]3ed00262013-09-26 22:28:10322 const unsigned char* signature,
323 unsigned signature_size,
324 const unsigned char* data,
325 unsigned data_size,
[email protected]180ef242013-11-07 06:50:46326 blink::WebCryptoResult result) {
[email protected]2213f252013-10-31 04:33:34327 DCHECK(!algorithm.isNull());
[email protected]3ed00262013-09-26 22:28:10328 bool signature_match = false;
329 if (!VerifySignatureInternal(algorithm,
330 key,
331 signature,
332 signature_size,
333 data,
334 data_size,
335 &signature_match)) {
336 result.completeWithError();
337 } else {
338 result.completeWithBoolean(signature_match);
339 }
340}
341
[email protected]b28852b2013-12-04 04:57:11342bool WebCryptoImpl::ImportKeyJwk(
343 const unsigned char* key_data,
344 unsigned key_data_size,
345 const blink::WebCryptoAlgorithm& algorithm_or_null,
346 bool extractable,
347 blink::WebCryptoKeyUsageMask usage_mask,
348 blink::WebCryptoKey* key) {
349
350 // The goal of this method is to extract key material and meta data from the
351 // incoming JWK, combine them with the input parameters, and ultimately import
352 // a Web Crypto Key.
353 //
354 // JSON Web Key Format (JWK)
355 // http://tools.ietf.org/html/draft-ietf-jose-json-web-key-16
356 // TODO(padolph): Not all possible values are handled by this code right now
357 //
358 // A JWK is a simple JSON dictionary with the following entries
359 // - "kty" (Key Type) Parameter, REQUIRED
360 // - <kty-specific parameters, see below>, REQUIRED
361 // - "use" (Key Use) Parameter, OPTIONAL
362 // - "alg" (Algorithm) Parameter, OPTIONAL
363 // - "extractable" (Key Exportability), OPTIONAL [NOTE: not yet part of JOSE,
364 // see https://www.w3.org/Bugs/Public/show_bug.cgi?id=23796]
365 // (all other entries are ignored)
366 //
367 // OPTIONAL here means that this code does not require the entry to be present
368 // in the incoming JWK, because the method input parameters contain similar
369 // information. If the optional JWK entry is present, it will be validated
370 // against the corresponding input parameter for consistency and combined with
371 // it according to rules defined below. A special case is that the method
372 // input parameter 'algorithm' is also optional. If it is null, the JWK 'alg'
373 // value (if present) is used as a fallback.
374 //
375 // Input 'key_data' contains the JWK. To build a Web Crypto Key, the JWK
376 // values are parsed out and combined with the method input parameters to
377 // build a Web Crypto Key:
378 // Web Crypto Key type <-- (deduced)
379 // Web Crypto Key extractable <-- JWK extractable + input extractable
380 // Web Crypto Key algorithm <-- JWK alg + input algorithm
381 // Web Crypto Key keyUsage <-- JWK use + input usage_mask
382 // Web Crypto Key keying material <-- kty-specific parameters
383 //
384 // Values for each JWK entry are case-sensitive and defined in
385 // http://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-16.
386 // Note that not all values specified by JOSE are handled by this code. Only
387 // handled values are listed.
388 // - kty (Key Type)
389 // +-------+--------------------------------------------------------------+
390 // | "RSA" | RSA [RFC3447] |
391 // | "oct" | Octet sequence (used to represent symmetric keys) |
392 // +-------+--------------------------------------------------------------+
393 // - use (Key Use)
394 // +-------+--------------------------------------------------------------+
395 // | "enc" | encrypt and decrypt operations |
396 // | "sig" | sign and verify (MAC) operations |
397 // | "wrap"| key wrap and unwrap [not yet part of JOSE] |
398 // +-------+--------------------------------------------------------------+
399 // - extractable (Key Exportability)
400 // +-------+--------------------------------------------------------------+
401 // | true | Key may be exported from the trusted environment |
402 // | false | Key cannot exit the trusted environment |
403 // +-------+--------------------------------------------------------------+
404 // - alg (Algorithm)
405 // See http://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-16
406 // +--------------+-------------------------------------------------------+
407 // | Digital Signature or MAC Algorithm |
408 // +--------------+-------------------------------------------------------+
409 // | "HS256" | HMAC using SHA-256 hash algorithm |
410 // | "HS384" | HMAC using SHA-384 hash algorithm |
411 // | "HS512" | HMAC using SHA-512 hash algorithm |
412 // | "RS256" | RSASSA using SHA-256 hash algorithm |
413 // | "RS384" | RSASSA using SHA-384 hash algorithm |
414 // | "RS512" | RSASSA using SHA-512 hash algorithm |
415 // +--------------+-------------------------------------------------------|
416 // | Key Management Algorithm |
417 // +--------------+-------------------------------------------------------+
418 // | "RSA1_5" | RSAES-PKCS1-V1_5 [RFC3447] |
419 // | "RSA-OAEP" | RSAES using Optimal Asymmetric Encryption Padding |
420 // | | (OAEP) [RFC3447], with the default parameters |
421 // | | specified by RFC3447 in Section A.2.1 |
422 // | "A128KW" | Advanced Encryption Standard (AES) Key Wrap Algorithm |
423 // | | [RFC3394] using 128 bit keys |
424 // | "A256KW" | AES Key Wrap Algorithm using 256 bit keys |
425 // | "A128GCM" | AES in Galois/Counter Mode (GCM) [NIST.800-38D] using |
426 // | | 128 bit keys |
427 // | "A256GCM" | AES GCM using 256 bit keys |
428 // | "A128CBC" | AES in Cipher Block Chaining Mode (CBC) with PKCS #5 |
429 // | | padding [NIST.800-38A] [not yet part of JOSE, see |
430 // | | https://www.w3.org/Bugs/Public/show_bug.cgi?id=23796 |
431 // | "A192CBC" | AES CBC using 192 bit keys [not yet part of JOSE] |
432 // | "A256CBC" | AES CBC using 256 bit keys [not yet part of JOSE] |
433 // +--------------+-------------------------------------------------------+
434 //
435 // kty-specific parameters
436 // The value of kty determines the type and content of the keying material
437 // carried in the JWK to be imported. Currently only two possibilities are
438 // supported: a raw key or an RSA public key. RSA private keys are not
439 // supported because typical applications seldom need to import a private key,
440 // and the large number of JWK parameters required to describe one.
441 // - kty == "oct" (symmetric or other raw key)
442 // +-------+--------------------------------------------------------------+
443 // | "k" | Contains the value of the symmetric (or other single-valued) |
444 // | | key. It is represented as the base64url encoding of the |
445 // | | octet sequence containing the key value. |
446 // +-------+--------------------------------------------------------------+
447 // - kty == "RSA" (RSA public key)
448 // +-------+--------------------------------------------------------------+
449 // | "n" | Contains the modulus value for the RSA public key. It is |
450 // | | represented as the base64url encoding of the value's |
451 // | | unsigned big endian representation as an octet sequence. |
452 // +-------+--------------------------------------------------------------+
453 // | "e" | Contains the exponent value for the RSA public key. It is |
454 // | | represented as the base64url encoding of the value's |
455 // | | unsigned big endian representation as an octet sequence. |
456 // +-------+--------------------------------------------------------------+
457 //
458 // Consistency and conflict resolution
459 // The 'algorithm_or_null', 'extractable', and 'usage_mask' input parameters
460 // may be different than the corresponding values inside the JWK. The Web
461 // Crypto spec says that if a JWK value is present but is inconsistent with
462 // the input value, it is an error and the operation must fail. If no
463 // inconsistency is found, the input and JWK values are combined as follows:
464 //
465 // algorithm
466 // If an algorithm is provided by both the input parameter and the JWK,
467 // consistency between the two is based only on algorithm ID's (including an
468 // inner hash algorithm if present). In this case if the consistency
469 // check is passed, the input algorithm is used. If only one of either the
470 // input algorithm and JWK alg is provided, it is used as the final
471 // algorithm.
472 //
473 // extractable
474 // If the JWK extractable is true but the input parameter is false, make the
475 // Web Crypto Key non-extractable. Conversely, if the JWK extractable is
476 // false but the input parameter is true, it is an inconsistency. If both
477 // are true or both are false, use that value.
478 //
479 // usage_mask
480 // The input usage_mask must be a strict subset of the interpreted JWK use
481 // value, else it is judged inconsistent. In all cases the input usage_mask
482 // is used as the final usage_mask.
483 //
484
485 if (!key_data_size)
486 return false;
487 DCHECK(key);
488
489 // Parse the incoming JWK JSON.
490 base::StringPiece json_string(reinterpret_cast<const char*>(key_data),
491 key_data_size);
492 scoped_ptr<base::Value> value(base::JSONReader::Read(json_string));
493 // Note, bare pointer dict_value is ok since it points into scoped value.
494 base::DictionaryValue* dict_value = NULL;
495 if (!value.get() || !value->GetAsDictionary(&dict_value) || !dict_value)
496 return false;
497
498 // JWK "kty". Exit early if this required JWK parameter is missing.
499 std::string jwk_kty_value;
500 if (!dict_value->GetString("kty", &jwk_kty_value))
501 return false;
502
503 // JWK "extractable" (optional) --> extractable parameter
504 {
505 bool jwk_extractable_value;
506 if (dict_value->GetBoolean("extractable", &jwk_extractable_value)) {
507 if (!jwk_extractable_value && extractable)
508 return false;
509 extractable = extractable && jwk_extractable_value;
510 }
511 }
512
513 // JWK "alg" (optional) --> algorithm parameter
514 // Note: input algorithm is also optional, so we have six cases to handle.
515 // 1. JWK alg present but unrecognized: error
516 // 2. JWK alg valid AND input algorithm isNull: use JWK value
517 // 3. JWK alg valid AND input algorithm specified, but JWK value
518 // inconsistent with input: error
519 // 4. JWK alg valid AND input algorithm specified, both consistent: use
520 // input value (because it has potentially more details)
521 // 5. JWK alg missing AND input algorithm isNull: error
522 // 6. JWK alg missing AND input algorithm specified: use input value
523 blink::WebCryptoAlgorithm algorithm = blink::WebCryptoAlgorithm::createNull();
524 std::string jwk_alg_value;
525 if (dict_value->GetString("alg", &jwk_alg_value)) {
526 // JWK alg present
[email protected]e1134b32013-12-04 23:54:32527
528 // TODO(padolph): Validate alg vs kty. For example kty="RSA" implies alg can
529 // only be from the RSA family.
530
[email protected]b28852b2013-12-04 04:57:11531 const blink::WebCryptoAlgorithm jwk_algorithm =
532 jwk_alg_factory.Get().CreateAlgorithmFromName(jwk_alg_value);
533 if (jwk_algorithm.isNull()) {
534 // JWK alg unrecognized
535 return false; // case 1
536 }
537 // JWK alg valid
538 if (algorithm_or_null.isNull()) {
539 // input algorithm not specified
540 algorithm = jwk_algorithm; // case 2
541 } else {
542 // input algorithm specified
543 if (!WebCryptoAlgorithmsConsistent(jwk_algorithm, algorithm_or_null))
544 return false; // case 3
545 algorithm = algorithm_or_null; // case 4
546 }
547 } else {
548 // JWK alg missing
549 if (algorithm_or_null.isNull())
550 return false; // case 5
551 algorithm = algorithm_or_null; // case 6
552 }
553 DCHECK(!algorithm.isNull());
554
555 // JWK "use" (optional) --> usage_mask parameter
556 std::string jwk_use_value;
557 if (dict_value->GetString("use", &jwk_use_value)) {
558 blink::WebCryptoKeyUsageMask jwk_usage_mask = 0;
559 if (jwk_use_value == "enc") {
560 jwk_usage_mask =
561 blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageDecrypt;
562 } else if (jwk_use_value == "sig") {
563 jwk_usage_mask =
564 blink::WebCryptoKeyUsageSign | blink::WebCryptoKeyUsageVerify;
565 } else if (jwk_use_value == "wrap") {
566 jwk_usage_mask =
567 blink::WebCryptoKeyUsageWrapKey | blink::WebCryptoKeyUsageUnwrapKey;
568 } else {
569 return false;
570 }
571 if ((jwk_usage_mask & usage_mask) != usage_mask) {
572 // A usage_mask must be a subset of jwk_usage_mask.
573 return false;
574 }
575 }
576
577 // JWK keying material --> ImportKeyInternal()
578 if (jwk_kty_value == "oct") {
[email protected]e1134b32013-12-04 23:54:32579
[email protected]b28852b2013-12-04 04:57:11580 std::string jwk_k_value;
[email protected]e1134b32013-12-04 23:54:32581 if (!GetDecodedUrl64ValueByKey(*dict_value, "k", &jwk_k_value))
[email protected]b28852b2013-12-04 04:57:11582 return false;
[email protected]b28852b2013-12-04 04:57:11583
584 // TODO(padolph): Some JWK alg ID's embed information about the key length
585 // in the alg ID string. For example "A128" implies the JWK carries 128 bits
586 // of key material, and "HS512" implies the JWK carries _at least_ 512 bits
587 // of key material. For such keys validate the actual key length against the
588 // value in the ID.
589
590 return ImportKeyInternal(blink::WebCryptoKeyFormatRaw,
591 reinterpret_cast<const uint8*>(jwk_k_value.data()),
592 jwk_k_value.size(),
593 algorithm,
594 extractable,
595 usage_mask,
596 key);
597 } else if (jwk_kty_value == "RSA") {
[email protected]e1134b32013-12-04 23:54:32598
599 // An RSA public key must have an "n" (modulus) and an "e" (exponent) entry
600 // in the JWK, while an RSA private key must have those, plus at least a "d"
601 // (private exponent) entry.
602 // See http://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-18,
603 // section 6.3.
604
605 // RSA private key import is not currently supported, so fail here if a "d"
606 // entry is found.
607 // TODO(padolph): Support RSA private key import.
608 if (dict_value->HasKey("d"))
609 return false;
610
611 std::string jwk_n_value;
612 if (!GetDecodedUrl64ValueByKey(*dict_value, "n", &jwk_n_value))
613 return false;
614 std::string jwk_e_value;
615 if (!GetDecodedUrl64ValueByKey(*dict_value, "e", &jwk_e_value))
616 return false;
617
618 return ImportRsaPublicKeyInternal(
619 reinterpret_cast<const uint8*>(jwk_n_value.data()),
620 jwk_n_value.size(),
621 reinterpret_cast<const uint8*>(jwk_e_value.data()),
622 jwk_e_value.size(),
623 algorithm,
624 extractable,
625 usage_mask,
626 key);
627
[email protected]b28852b2013-12-04 04:57:11628 } else {
629 return false;
630 }
631
632 return true;
633}
634
[email protected]408699c2013-07-17 21:23:16635} // namespace content