blob: 4d69f0750d596f10941d99b9ccfac007c1d657cf [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]cca897482014-01-30 22:40:1920#include "third_party/WebKit/public/platform/WebString.h"
[email protected]408699c2013-07-17 21:23:1621
22namespace content {
23
[email protected]cca897482014-01-30 22:40:1924using webcrypto::Status;
25
[email protected]043cf1d32013-11-02 13:27:3026namespace {
27
[email protected]cca897482014-01-30 22:40:1928void CompleteWithError(const Status& status, blink::WebCryptoResult* result) {
29 DCHECK(status.IsError());
30 result->completeWithError(blink::WebString::fromUTF8(status.ToString()));
31}
32
[email protected]180ef242013-11-07 06:50:4633bool IsAlgorithmAsymmetric(const blink::WebCryptoAlgorithm& algorithm) {
[email protected]043cf1d32013-11-02 13:27:3034 // TODO(padolph): include all other asymmetric algorithms once they are
35 // defined, e.g. EC and DH.
[email protected]180ef242013-11-07 06:50:4636 return (algorithm.id() == blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5 ||
37 algorithm.id() == blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5 ||
38 algorithm.id() == blink::WebCryptoAlgorithmIdRsaOaep);
[email protected]043cf1d32013-11-02 13:27:3039}
40
[email protected]b28852b2013-12-04 04:57:1141// Binds a specific key length value to a compatible factory function.
42typedef blink::WebCryptoAlgorithm (*AlgFactoryFuncWithOneShortArg)(
43 unsigned short);
44template <AlgFactoryFuncWithOneShortArg func, unsigned short key_length>
45blink::WebCryptoAlgorithm BindAlgFactoryWithKeyLen() {
46 return func(key_length);
47}
48
49// Binds a WebCryptoAlgorithmId value to a compatible factory function.
50typedef blink::WebCryptoAlgorithm (*AlgFactoryFuncWithWebCryptoAlgIdArg)(
51 blink::WebCryptoAlgorithmId);
52template <AlgFactoryFuncWithWebCryptoAlgIdArg func,
53 blink::WebCryptoAlgorithmId algorithm_id>
54blink::WebCryptoAlgorithm BindAlgFactoryAlgorithmId() {
55 return func(algorithm_id);
56}
57
58// Defines a map between a JWK 'alg' string ID and a corresponding Web Crypto
59// factory function.
60typedef blink::WebCryptoAlgorithm (*AlgFactoryFuncNoArgs)();
61typedef std::map<std::string, AlgFactoryFuncNoArgs> JwkAlgFactoryMap;
62
63class JwkAlgorithmFactoryMap {
64 public:
65 JwkAlgorithmFactoryMap() {
66 map_["HS256"] =
[email protected]148dd0ce2013-12-17 07:50:3667 &BindAlgFactoryAlgorithmId<webcrypto::CreateHmacAlgorithmByHashId,
68 blink::WebCryptoAlgorithmIdSha256>;
[email protected]b28852b2013-12-04 04:57:1169 map_["HS384"] =
[email protected]148dd0ce2013-12-17 07:50:3670 &BindAlgFactoryAlgorithmId<webcrypto::CreateHmacAlgorithmByHashId,
71 blink::WebCryptoAlgorithmIdSha384>;
[email protected]b28852b2013-12-04 04:57:1172 map_["HS512"] =
[email protected]148dd0ce2013-12-17 07:50:3673 &BindAlgFactoryAlgorithmId<webcrypto::CreateHmacAlgorithmByHashId,
74 blink::WebCryptoAlgorithmIdSha512>;
[email protected]b28852b2013-12-04 04:57:1175 map_["RS256"] =
76 &BindAlgFactoryAlgorithmId<webcrypto::CreateRsaSsaAlgorithm,
77 blink::WebCryptoAlgorithmIdSha256>;
78 map_["RS384"] =
79 &BindAlgFactoryAlgorithmId<webcrypto::CreateRsaSsaAlgorithm,
80 blink::WebCryptoAlgorithmIdSha384>;
81 map_["RS512"] =
82 &BindAlgFactoryAlgorithmId<webcrypto::CreateRsaSsaAlgorithm,
83 blink::WebCryptoAlgorithmIdSha512>;
84 map_["RSA1_5"] =
85 &BindAlgFactoryAlgorithmId<webcrypto::CreateAlgorithm,
86 blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5>;
87 map_["RSA-OAEP"] =
88 &BindAlgFactoryAlgorithmId<webcrypto::CreateRsaOaepAlgorithm,
89 blink::WebCryptoAlgorithmIdSha1>;
90 // TODO(padolph): The Web Crypto spec does not enumerate AES-KW 128 yet
91 map_["A128KW"] = &blink::WebCryptoAlgorithm::createNull;
92 // TODO(padolph): The Web Crypto spec does not enumerate AES-KW 256 yet
93 map_["A256KW"] = &blink::WebCryptoAlgorithm::createNull;
94 map_["A128GCM"] =
95 &BindAlgFactoryAlgorithmId<webcrypto::CreateAlgorithm,
96 blink::WebCryptoAlgorithmIdAesGcm>;
97 map_["A256GCM"] =
98 &BindAlgFactoryAlgorithmId<webcrypto::CreateAlgorithm,
99 blink::WebCryptoAlgorithmIdAesGcm>;
100 map_["A128CBC"] =
101 &BindAlgFactoryAlgorithmId<webcrypto::CreateAlgorithm,
102 blink::WebCryptoAlgorithmIdAesCbc>;
103 map_["A192CBC"] =
104 &BindAlgFactoryAlgorithmId<webcrypto::CreateAlgorithm,
105 blink::WebCryptoAlgorithmIdAesCbc>;
106 map_["A256CBC"] =
107 &BindAlgFactoryAlgorithmId<webcrypto::CreateAlgorithm,
108 blink::WebCryptoAlgorithmIdAesCbc>;
109 }
110
111 blink::WebCryptoAlgorithm CreateAlgorithmFromName(const std::string& alg_id)
112 const {
113 const JwkAlgFactoryMap::const_iterator pos = map_.find(alg_id);
114 if (pos == map_.end())
115 return blink::WebCryptoAlgorithm::createNull();
116 return pos->second();
117 }
118
119 private:
120 JwkAlgFactoryMap map_;
121};
122
123base::LazyInstance<JwkAlgorithmFactoryMap> jwk_alg_factory =
124 LAZY_INSTANCE_INITIALIZER;
125
126bool WebCryptoAlgorithmsConsistent(const blink::WebCryptoAlgorithm& alg1,
127 const blink::WebCryptoAlgorithm& alg2) {
128 DCHECK(!alg1.isNull());
129 DCHECK(!alg2.isNull());
130 if (alg1.id() != alg2.id())
131 return false;
132 switch (alg1.id()) {
133 case blink::WebCryptoAlgorithmIdHmac:
134 case blink::WebCryptoAlgorithmIdRsaOaep:
135 case blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5:
136 if (WebCryptoAlgorithmsConsistent(
137 webcrypto::GetInnerHashAlgorithm(alg1),
138 webcrypto::GetInnerHashAlgorithm(alg2))) {
139 return true;
140 }
141 break;
142 case blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5:
143 case blink::WebCryptoAlgorithmIdSha1:
144 case blink::WebCryptoAlgorithmIdSha224:
145 case blink::WebCryptoAlgorithmIdSha256:
146 case blink::WebCryptoAlgorithmIdSha384:
147 case blink::WebCryptoAlgorithmIdSha512:
148 case blink::WebCryptoAlgorithmIdAesCbc:
149 case blink::WebCryptoAlgorithmIdAesGcm:
150 case blink::WebCryptoAlgorithmIdAesCtr:
151 return true;
152 default:
153 NOTREACHED(); // Not a supported algorithm.
154 break;
155 }
156 return false;
157}
158
[email protected]e1134b32013-12-04 23:54:32159bool GetDecodedUrl64ValueByKey(
160 const base::DictionaryValue& dict,
161 const std::string& key,
162 std::string* decoded) {
163 std::string value_url64;
164 if (!dict.GetString(key, &value_url64) ||
165 !webcrypto::Base64DecodeUrlSafe(value_url64, decoded) ||
166 !decoded->size()) {
167 return false;
168 }
169 return true;
170}
171
[email protected]043cf1d32013-11-02 13:27:30172} // namespace
173
[email protected]7e4c36f2013-09-12 06:10:19174WebCryptoImpl::WebCryptoImpl() {
175 Init();
176}
177
[email protected]a2a06c732013-09-27 10:50:54178void WebCryptoImpl::encrypt(
[email protected]180ef242013-11-07 06:50:46179 const blink::WebCryptoAlgorithm& algorithm,
180 const blink::WebCryptoKey& key,
[email protected]a2a06c732013-09-27 10:50:54181 const unsigned char* data,
182 unsigned data_size,
[email protected]180ef242013-11-07 06:50:46183 blink::WebCryptoResult result) {
[email protected]2213f252013-10-31 04:33:34184 DCHECK(!algorithm.isNull());
[email protected]180ef242013-11-07 06:50:46185 blink::WebArrayBuffer buffer;
[email protected]cca897482014-01-30 22:40:19186 Status status = EncryptInternal(algorithm, key, data, data_size, &buffer);
187 if (status.IsError()) {
188 CompleteWithError(status, &result);
[email protected]a2a06c732013-09-27 10:50:54189 } else {
190 result.completeWithBuffer(buffer);
191 }
192}
193
[email protected]868085a92013-10-01 00:42:30194void WebCryptoImpl::decrypt(
[email protected]180ef242013-11-07 06:50:46195 const blink::WebCryptoAlgorithm& algorithm,
196 const blink::WebCryptoKey& key,
[email protected]868085a92013-10-01 00:42:30197 const unsigned char* data,
198 unsigned data_size,
[email protected]180ef242013-11-07 06:50:46199 blink::WebCryptoResult result) {
[email protected]2213f252013-10-31 04:33:34200 DCHECK(!algorithm.isNull());
[email protected]180ef242013-11-07 06:50:46201 blink::WebArrayBuffer buffer;
[email protected]cca897482014-01-30 22:40:19202 Status status = DecryptInternal(algorithm, key, data, data_size, &buffer);
203 if (status.IsError()) {
204 CompleteWithError(status, &result);
[email protected]868085a92013-10-01 00:42:30205 } else {
206 result.completeWithBuffer(buffer);
207 }
208}
209
[email protected]e5b794b2013-08-30 01:32:54210void WebCryptoImpl::digest(
[email protected]180ef242013-11-07 06:50:46211 const blink::WebCryptoAlgorithm& algorithm,
[email protected]e5b794b2013-08-30 01:32:54212 const unsigned char* data,
[email protected]ed80a092013-09-10 16:36:38213 unsigned data_size,
[email protected]180ef242013-11-07 06:50:46214 blink::WebCryptoResult result) {
[email protected]2213f252013-10-31 04:33:34215 DCHECK(!algorithm.isNull());
[email protected]180ef242013-11-07 06:50:46216 blink::WebArrayBuffer buffer;
[email protected]cca897482014-01-30 22:40:19217 Status status = DigestInternal(algorithm, data, data_size, &buffer);
218 if (status.IsError()) {
219 CompleteWithError(status, &result);
[email protected]e5b794b2013-08-30 01:32:54220 } else {
221 result.completeWithBuffer(buffer);
[email protected]408699c2013-07-17 21:23:16222 }
223}
224
[email protected]dfae8ab2013-10-10 19:45:06225void WebCryptoImpl::generateKey(
[email protected]180ef242013-11-07 06:50:46226 const blink::WebCryptoAlgorithm& algorithm,
[email protected]2213f252013-10-31 04:33:34227 bool extractable,
[email protected]180ef242013-11-07 06:50:46228 blink::WebCryptoKeyUsageMask usage_mask,
229 blink::WebCryptoResult result) {
[email protected]2213f252013-10-31 04:33:34230 DCHECK(!algorithm.isNull());
[email protected]043cf1d32013-11-02 13:27:30231 if (IsAlgorithmAsymmetric(algorithm)) {
[email protected]180ef242013-11-07 06:50:46232 blink::WebCryptoKey public_key = blink::WebCryptoKey::createNull();
233 blink::WebCryptoKey private_key = blink::WebCryptoKey::createNull();
[email protected]cca897482014-01-30 22:40:19234 Status status = GenerateKeyPairInternal(
235 algorithm, extractable, usage_mask, &public_key, &private_key);
236 if (status.IsError()) {
237 CompleteWithError(status, &result);
[email protected]043cf1d32013-11-02 13:27:30238 } else {
239 DCHECK(public_key.handle());
240 DCHECK(private_key.handle());
241 DCHECK_EQ(algorithm.id(), public_key.algorithm().id());
242 DCHECK_EQ(algorithm.id(), private_key.algorithm().id());
[email protected]0bfa7722013-12-06 02:55:47243 DCHECK_EQ(true, public_key.extractable());
[email protected]043cf1d32013-11-02 13:27:30244 DCHECK_EQ(extractable, private_key.extractable());
245 DCHECK_EQ(usage_mask, public_key.usages());
246 DCHECK_EQ(usage_mask, private_key.usages());
247 result.completeWithKeyPair(public_key, private_key);
248 }
[email protected]dfae8ab2013-10-10 19:45:06249 } else {
[email protected]180ef242013-11-07 06:50:46250 blink::WebCryptoKey key = blink::WebCryptoKey::createNull();
[email protected]cca897482014-01-30 22:40:19251 Status status = GenerateKeyInternal(
252 algorithm, extractable, usage_mask, &key);
253 if (status.IsError()) {
254 CompleteWithError(status, &result);
[email protected]043cf1d32013-11-02 13:27:30255 } else {
256 DCHECK(key.handle());
257 DCHECK_EQ(algorithm.id(), key.algorithm().id());
258 DCHECK_EQ(extractable, key.extractable());
259 DCHECK_EQ(usage_mask, key.usages());
260 result.completeWithKey(key);
261 }
[email protected]dfae8ab2013-10-10 19:45:06262 }
263}
264
[email protected]1c879bc92013-09-18 07:45:32265void WebCryptoImpl::importKey(
[email protected]180ef242013-11-07 06:50:46266 blink::WebCryptoKeyFormat format,
[email protected]1c879bc92013-09-18 07:45:32267 const unsigned char* key_data,
268 unsigned key_data_size,
[email protected]180ef242013-11-07 06:50:46269 const blink::WebCryptoAlgorithm& algorithm_or_null,
[email protected]1c879bc92013-09-18 07:45:32270 bool extractable,
[email protected]180ef242013-11-07 06:50:46271 blink::WebCryptoKeyUsageMask usage_mask,
272 blink::WebCryptoResult result) {
273 blink::WebCryptoKey key = blink::WebCryptoKey::createNull();
[email protected]cca897482014-01-30 22:40:19274 Status status = Status::Error();
[email protected]b28852b2013-12-04 04:57:11275 if (format == blink::WebCryptoKeyFormatJwk) {
[email protected]cca897482014-01-30 22:40:19276 status = ImportKeyJwk(key_data,
277 key_data_size,
278 algorithm_or_null,
279 extractable,
280 usage_mask,
281 &key);
[email protected]b28852b2013-12-04 04:57:11282 } else {
[email protected]cca897482014-01-30 22:40:19283 status = ImportKeyInternal(format,
284 key_data,
285 key_data_size,
286 algorithm_or_null,
287 extractable,
288 usage_mask,
289 &key);
[email protected]1c879bc92013-09-18 07:45:32290 }
[email protected]cca897482014-01-30 22:40:19291 if (status.IsError()) {
292 CompleteWithError(status, &result);
293 } else {
294 DCHECK(key.handle());
295 DCHECK(!key.algorithm().isNull());
296 DCHECK_EQ(extractable, key.extractable());
297 result.completeWithKey(key);
298 }
[email protected]1c879bc92013-09-18 07:45:32299}
300
[email protected]e9b2c102013-11-26 04:26:33301void WebCryptoImpl::exportKey(
302 blink::WebCryptoKeyFormat format,
303 const blink::WebCryptoKey& key,
304 blink::WebCryptoResult result) {
305 blink::WebArrayBuffer buffer;
[email protected]cca897482014-01-30 22:40:19306 Status status = ExportKeyInternal(format, key, &buffer);
307 if (status.IsError()) {
308 CompleteWithError(status, &result);
309 } else {
310 result.completeWithBuffer(buffer);
[email protected]e9b2c102013-11-26 04:26:33311 }
[email protected]e9b2c102013-11-26 04:26:33312}
313
[email protected]1c879bc92013-09-18 07:45:32314void WebCryptoImpl::sign(
[email protected]180ef242013-11-07 06:50:46315 const blink::WebCryptoAlgorithm& algorithm,
316 const blink::WebCryptoKey& key,
[email protected]1c879bc92013-09-18 07:45:32317 const unsigned char* data,
318 unsigned data_size,
[email protected]180ef242013-11-07 06:50:46319 blink::WebCryptoResult result) {
[email protected]2213f252013-10-31 04:33:34320 DCHECK(!algorithm.isNull());
[email protected]180ef242013-11-07 06:50:46321 blink::WebArrayBuffer buffer;
[email protected]cca897482014-01-30 22:40:19322 Status status = SignInternal(algorithm, key, data, data_size, &buffer);
323 if (status.IsError()) {
324 CompleteWithError(status, &result);
[email protected]1c879bc92013-09-18 07:45:32325 } else {
326 result.completeWithBuffer(buffer);
327 }
328}
329
[email protected]3ed00262013-09-26 22:28:10330void WebCryptoImpl::verifySignature(
[email protected]180ef242013-11-07 06:50:46331 const blink::WebCryptoAlgorithm& algorithm,
332 const blink::WebCryptoKey& key,
[email protected]3ed00262013-09-26 22:28:10333 const unsigned char* signature,
334 unsigned signature_size,
335 const unsigned char* data,
336 unsigned data_size,
[email protected]180ef242013-11-07 06:50:46337 blink::WebCryptoResult result) {
[email protected]2213f252013-10-31 04:33:34338 DCHECK(!algorithm.isNull());
[email protected]3ed00262013-09-26 22:28:10339 bool signature_match = false;
[email protected]cca897482014-01-30 22:40:19340 Status status = VerifySignatureInternal(algorithm,
341 key,
342 signature,
343 signature_size,
344 data,
345 data_size,
346 &signature_match);
347 if (status.IsError()) {
348 CompleteWithError(status, &result);
[email protected]3ed00262013-09-26 22:28:10349 } else {
350 result.completeWithBoolean(signature_match);
351 }
352}
353
[email protected]cca897482014-01-30 22:40:19354Status WebCryptoImpl::ImportKeyJwk(
[email protected]b28852b2013-12-04 04:57:11355 const unsigned char* key_data,
356 unsigned key_data_size,
357 const blink::WebCryptoAlgorithm& algorithm_or_null,
358 bool extractable,
359 blink::WebCryptoKeyUsageMask usage_mask,
360 blink::WebCryptoKey* key) {
361
362 // The goal of this method is to extract key material and meta data from the
363 // incoming JWK, combine them with the input parameters, and ultimately import
364 // a Web Crypto Key.
365 //
366 // JSON Web Key Format (JWK)
367 // http://tools.ietf.org/html/draft-ietf-jose-json-web-key-16
368 // TODO(padolph): Not all possible values are handled by this code right now
369 //
370 // A JWK is a simple JSON dictionary with the following entries
371 // - "kty" (Key Type) Parameter, REQUIRED
372 // - <kty-specific parameters, see below>, REQUIRED
373 // - "use" (Key Use) Parameter, OPTIONAL
374 // - "alg" (Algorithm) Parameter, OPTIONAL
375 // - "extractable" (Key Exportability), OPTIONAL [NOTE: not yet part of JOSE,
376 // see https://www.w3.org/Bugs/Public/show_bug.cgi?id=23796]
377 // (all other entries are ignored)
378 //
379 // OPTIONAL here means that this code does not require the entry to be present
380 // in the incoming JWK, because the method input parameters contain similar
381 // information. If the optional JWK entry is present, it will be validated
382 // against the corresponding input parameter for consistency and combined with
383 // it according to rules defined below. A special case is that the method
384 // input parameter 'algorithm' is also optional. If it is null, the JWK 'alg'
385 // value (if present) is used as a fallback.
386 //
387 // Input 'key_data' contains the JWK. To build a Web Crypto Key, the JWK
388 // values are parsed out and combined with the method input parameters to
389 // build a Web Crypto Key:
390 // Web Crypto Key type <-- (deduced)
391 // Web Crypto Key extractable <-- JWK extractable + input extractable
392 // Web Crypto Key algorithm <-- JWK alg + input algorithm
393 // Web Crypto Key keyUsage <-- JWK use + input usage_mask
394 // Web Crypto Key keying material <-- kty-specific parameters
395 //
396 // Values for each JWK entry are case-sensitive and defined in
397 // http://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-16.
398 // Note that not all values specified by JOSE are handled by this code. Only
399 // handled values are listed.
400 // - kty (Key Type)
401 // +-------+--------------------------------------------------------------+
402 // | "RSA" | RSA [RFC3447] |
403 // | "oct" | Octet sequence (used to represent symmetric keys) |
404 // +-------+--------------------------------------------------------------+
405 // - use (Key Use)
406 // +-------+--------------------------------------------------------------+
407 // | "enc" | encrypt and decrypt operations |
408 // | "sig" | sign and verify (MAC) operations |
409 // | "wrap"| key wrap and unwrap [not yet part of JOSE] |
410 // +-------+--------------------------------------------------------------+
411 // - extractable (Key Exportability)
412 // +-------+--------------------------------------------------------------+
413 // | true | Key may be exported from the trusted environment |
414 // | false | Key cannot exit the trusted environment |
415 // +-------+--------------------------------------------------------------+
416 // - alg (Algorithm)
417 // See http://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-16
418 // +--------------+-------------------------------------------------------+
419 // | Digital Signature or MAC Algorithm |
420 // +--------------+-------------------------------------------------------+
421 // | "HS256" | HMAC using SHA-256 hash algorithm |
422 // | "HS384" | HMAC using SHA-384 hash algorithm |
423 // | "HS512" | HMAC using SHA-512 hash algorithm |
424 // | "RS256" | RSASSA using SHA-256 hash algorithm |
425 // | "RS384" | RSASSA using SHA-384 hash algorithm |
426 // | "RS512" | RSASSA using SHA-512 hash algorithm |
427 // +--------------+-------------------------------------------------------|
428 // | Key Management Algorithm |
429 // +--------------+-------------------------------------------------------+
430 // | "RSA1_5" | RSAES-PKCS1-V1_5 [RFC3447] |
431 // | "RSA-OAEP" | RSAES using Optimal Asymmetric Encryption Padding |
432 // | | (OAEP) [RFC3447], with the default parameters |
433 // | | specified by RFC3447 in Section A.2.1 |
434 // | "A128KW" | Advanced Encryption Standard (AES) Key Wrap Algorithm |
435 // | | [RFC3394] using 128 bit keys |
436 // | "A256KW" | AES Key Wrap Algorithm using 256 bit keys |
437 // | "A128GCM" | AES in Galois/Counter Mode (GCM) [NIST.800-38D] using |
438 // | | 128 bit keys |
439 // | "A256GCM" | AES GCM using 256 bit keys |
440 // | "A128CBC" | AES in Cipher Block Chaining Mode (CBC) with PKCS #5 |
441 // | | padding [NIST.800-38A] [not yet part of JOSE, see |
442 // | | https://www.w3.org/Bugs/Public/show_bug.cgi?id=23796 |
443 // | "A192CBC" | AES CBC using 192 bit keys [not yet part of JOSE] |
444 // | "A256CBC" | AES CBC using 256 bit keys [not yet part of JOSE] |
445 // +--------------+-------------------------------------------------------+
446 //
447 // kty-specific parameters
448 // The value of kty determines the type and content of the keying material
449 // carried in the JWK to be imported. Currently only two possibilities are
450 // supported: a raw key or an RSA public key. RSA private keys are not
451 // supported because typical applications seldom need to import a private key,
452 // and the large number of JWK parameters required to describe one.
453 // - kty == "oct" (symmetric or other raw key)
454 // +-------+--------------------------------------------------------------+
455 // | "k" | Contains the value of the symmetric (or other single-valued) |
456 // | | key. It is represented as the base64url encoding of the |
457 // | | octet sequence containing the key value. |
458 // +-------+--------------------------------------------------------------+
459 // - kty == "RSA" (RSA public key)
460 // +-------+--------------------------------------------------------------+
461 // | "n" | Contains the modulus value for the RSA public key. It is |
462 // | | represented as the base64url encoding of the value's |
463 // | | unsigned big endian representation as an octet sequence. |
464 // +-------+--------------------------------------------------------------+
465 // | "e" | Contains the exponent value for the RSA public key. It is |
466 // | | represented as the base64url encoding of the value's |
467 // | | unsigned big endian representation as an octet sequence. |
468 // +-------+--------------------------------------------------------------+
469 //
470 // Consistency and conflict resolution
471 // The 'algorithm_or_null', 'extractable', and 'usage_mask' input parameters
472 // may be different than the corresponding values inside the JWK. The Web
473 // Crypto spec says that if a JWK value is present but is inconsistent with
474 // the input value, it is an error and the operation must fail. If no
475 // inconsistency is found, the input and JWK values are combined as follows:
476 //
477 // algorithm
478 // If an algorithm is provided by both the input parameter and the JWK,
479 // consistency between the two is based only on algorithm ID's (including an
480 // inner hash algorithm if present). In this case if the consistency
481 // check is passed, the input algorithm is used. If only one of either the
482 // input algorithm and JWK alg is provided, it is used as the final
483 // algorithm.
484 //
485 // extractable
486 // If the JWK extractable is true but the input parameter is false, make the
487 // Web Crypto Key non-extractable. Conversely, if the JWK extractable is
488 // false but the input parameter is true, it is an inconsistency. If both
489 // are true or both are false, use that value.
490 //
491 // usage_mask
492 // The input usage_mask must be a strict subset of the interpreted JWK use
493 // value, else it is judged inconsistent. In all cases the input usage_mask
494 // is used as the final usage_mask.
495 //
496
497 if (!key_data_size)
[email protected]cca897482014-01-30 22:40:19498 return Status::ErrorImportEmptyKeyData();
[email protected]b28852b2013-12-04 04:57:11499 DCHECK(key);
500
501 // Parse the incoming JWK JSON.
502 base::StringPiece json_string(reinterpret_cast<const char*>(key_data),
503 key_data_size);
504 scoped_ptr<base::Value> value(base::JSONReader::Read(json_string));
505 // Note, bare pointer dict_value is ok since it points into scoped value.
506 base::DictionaryValue* dict_value = NULL;
507 if (!value.get() || !value->GetAsDictionary(&dict_value) || !dict_value)
[email protected]cca897482014-01-30 22:40:19508 return Status::ErrorJwkNotDictionary();
[email protected]b28852b2013-12-04 04:57:11509
510 // JWK "kty". Exit early if this required JWK parameter is missing.
511 std::string jwk_kty_value;
512 if (!dict_value->GetString("kty", &jwk_kty_value))
[email protected]cca897482014-01-30 22:40:19513 return Status::ErrorJwkMissingKty();
[email protected]b28852b2013-12-04 04:57:11514
515 // JWK "extractable" (optional) --> extractable parameter
[email protected]cca897482014-01-30 22:40:19516 // TODO(eroman): Should error if "extractable" was specified but not a
517 // boolean.
[email protected]b28852b2013-12-04 04:57:11518 {
519 bool jwk_extractable_value;
520 if (dict_value->GetBoolean("extractable", &jwk_extractable_value)) {
521 if (!jwk_extractable_value && extractable)
[email protected]cca897482014-01-30 22:40:19522 return Status::ErrorJwkExtractableInconsistent();
[email protected]b28852b2013-12-04 04:57:11523 extractable = extractable && jwk_extractable_value;
524 }
525 }
526
527 // JWK "alg" (optional) --> algorithm parameter
528 // Note: input algorithm is also optional, so we have six cases to handle.
529 // 1. JWK alg present but unrecognized: error
530 // 2. JWK alg valid AND input algorithm isNull: use JWK value
531 // 3. JWK alg valid AND input algorithm specified, but JWK value
532 // inconsistent with input: error
533 // 4. JWK alg valid AND input algorithm specified, both consistent: use
534 // input value (because it has potentially more details)
535 // 5. JWK alg missing AND input algorithm isNull: error
536 // 6. JWK alg missing AND input algorithm specified: use input value
[email protected]cca897482014-01-30 22:40:19537 // TODO(eroman): Should error if "alg" was specified but not a string.
[email protected]b28852b2013-12-04 04:57:11538 blink::WebCryptoAlgorithm algorithm = blink::WebCryptoAlgorithm::createNull();
539 std::string jwk_alg_value;
540 if (dict_value->GetString("alg", &jwk_alg_value)) {
541 // JWK alg present
[email protected]e1134b32013-12-04 23:54:32542
543 // TODO(padolph): Validate alg vs kty. For example kty="RSA" implies alg can
544 // only be from the RSA family.
545
[email protected]b28852b2013-12-04 04:57:11546 const blink::WebCryptoAlgorithm jwk_algorithm =
547 jwk_alg_factory.Get().CreateAlgorithmFromName(jwk_alg_value);
548 if (jwk_algorithm.isNull()) {
549 // JWK alg unrecognized
[email protected]cca897482014-01-30 22:40:19550 return Status::ErrorJwkUnrecognizedAlgorithm(); // case 1
[email protected]b28852b2013-12-04 04:57:11551 }
552 // JWK alg valid
553 if (algorithm_or_null.isNull()) {
554 // input algorithm not specified
555 algorithm = jwk_algorithm; // case 2
556 } else {
557 // input algorithm specified
558 if (!WebCryptoAlgorithmsConsistent(jwk_algorithm, algorithm_or_null))
[email protected]cca897482014-01-30 22:40:19559 return Status::ErrorJwkAlgorithmInconsistent(); // case 3
[email protected]b28852b2013-12-04 04:57:11560 algorithm = algorithm_or_null; // case 4
561 }
562 } else {
563 // JWK alg missing
564 if (algorithm_or_null.isNull())
[email protected]cca897482014-01-30 22:40:19565 return Status::ErrorJwkAlgorithmMissing(); // case 5
[email protected]b28852b2013-12-04 04:57:11566 algorithm = algorithm_or_null; // case 6
567 }
568 DCHECK(!algorithm.isNull());
569
570 // JWK "use" (optional) --> usage_mask parameter
[email protected]cca897482014-01-30 22:40:19571 // TODO(eroman): Should error if "use" was specified but not a string.
[email protected]b28852b2013-12-04 04:57:11572 std::string jwk_use_value;
573 if (dict_value->GetString("use", &jwk_use_value)) {
574 blink::WebCryptoKeyUsageMask jwk_usage_mask = 0;
575 if (jwk_use_value == "enc") {
576 jwk_usage_mask =
577 blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageDecrypt;
578 } else if (jwk_use_value == "sig") {
579 jwk_usage_mask =
580 blink::WebCryptoKeyUsageSign | blink::WebCryptoKeyUsageVerify;
581 } else if (jwk_use_value == "wrap") {
582 jwk_usage_mask =
583 blink::WebCryptoKeyUsageWrapKey | blink::WebCryptoKeyUsageUnwrapKey;
584 } else {
[email protected]cca897482014-01-30 22:40:19585 return Status::ErrorJwkUnrecognizedUsage();
[email protected]b28852b2013-12-04 04:57:11586 }
587 if ((jwk_usage_mask & usage_mask) != usage_mask) {
588 // A usage_mask must be a subset of jwk_usage_mask.
[email protected]cca897482014-01-30 22:40:19589 return Status::ErrorJwkUsageInconsistent();
[email protected]b28852b2013-12-04 04:57:11590 }
591 }
592
593 // JWK keying material --> ImportKeyInternal()
594 if (jwk_kty_value == "oct") {
[email protected]e1134b32013-12-04 23:54:32595
[email protected]b28852b2013-12-04 04:57:11596 std::string jwk_k_value;
[email protected]e1134b32013-12-04 23:54:32597 if (!GetDecodedUrl64ValueByKey(*dict_value, "k", &jwk_k_value))
[email protected]cca897482014-01-30 22:40:19598 return Status::ErrorJwkDecodeK();
[email protected]b28852b2013-12-04 04:57:11599
600 // TODO(padolph): Some JWK alg ID's embed information about the key length
601 // in the alg ID string. For example "A128" implies the JWK carries 128 bits
602 // of key material, and "HS512" implies the JWK carries _at least_ 512 bits
603 // of key material. For such keys validate the actual key length against the
604 // value in the ID.
605
606 return ImportKeyInternal(blink::WebCryptoKeyFormatRaw,
607 reinterpret_cast<const uint8*>(jwk_k_value.data()),
608 jwk_k_value.size(),
609 algorithm,
610 extractable,
611 usage_mask,
612 key);
613 } else if (jwk_kty_value == "RSA") {
[email protected]e1134b32013-12-04 23:54:32614
615 // An RSA public key must have an "n" (modulus) and an "e" (exponent) entry
616 // in the JWK, while an RSA private key must have those, plus at least a "d"
617 // (private exponent) entry.
618 // See http://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-18,
619 // section 6.3.
620
621 // RSA private key import is not currently supported, so fail here if a "d"
622 // entry is found.
623 // TODO(padolph): Support RSA private key import.
624 if (dict_value->HasKey("d"))
[email protected]cca897482014-01-30 22:40:19625 return Status::ErrorJwkRsaPrivateKeyUnsupported();
[email protected]e1134b32013-12-04 23:54:32626
627 std::string jwk_n_value;
628 if (!GetDecodedUrl64ValueByKey(*dict_value, "n", &jwk_n_value))
[email protected]cca897482014-01-30 22:40:19629 return Status::ErrorJwkDecodeN();
[email protected]e1134b32013-12-04 23:54:32630 std::string jwk_e_value;
631 if (!GetDecodedUrl64ValueByKey(*dict_value, "e", &jwk_e_value))
[email protected]cca897482014-01-30 22:40:19632 return Status::ErrorJwkDecodeE();
[email protected]e1134b32013-12-04 23:54:32633
634 return ImportRsaPublicKeyInternal(
635 reinterpret_cast<const uint8*>(jwk_n_value.data()),
636 jwk_n_value.size(),
637 reinterpret_cast<const uint8*>(jwk_e_value.data()),
638 jwk_e_value.size(),
639 algorithm,
640 extractable,
641 usage_mask,
642 key);
643
[email protected]b28852b2013-12-04 04:57:11644 } else {
[email protected]cca897482014-01-30 22:40:19645 return Status::ErrorJwkUnrecognizedKty();
[email protected]b28852b2013-12-04 04:57:11646 }
647
[email protected]cca897482014-01-30 22:40:19648 return Status::Success();
[email protected]b28852b2013-12-04 04:57:11649}
650
[email protected]408699c2013-07-17 21:23:16651} // namespace content