Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / content / child / webcrypto / webcrypto_util.cc
1 // Copyright 2014 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
5 #include "content/child/webcrypto/webcrypto_util.h"
6
7 #include <set>
8
9 #include "base/logging.h"
10 #include "base/strings/stringprintf.h"
11 #include "content/child/webcrypto/status.h"
12 #include "third_party/WebKit/public/platform/WebCryptoAlgorithm.h"
13 #include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h"
14 #include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h"
15
16 namespace content {
17
18 namespace webcrypto {
19
20 namespace {
21
22 // Converts a (big-endian) WebCrypto BigInteger, with or without leading zeros,
23 // to unsigned int.
24 bool BigIntegerToUint(const uint8_t* data,
25                       unsigned int data_size,
26                       unsigned int* result) {
27   if (data_size == 0)
28     return false;
29
30   *result = 0;
31   for (size_t i = 0; i < data_size; ++i) {
32     size_t reverse_i = data_size - i - 1;
33
34     if (reverse_i >= sizeof(*result) && data[i])
35       return false;  // Too large for a uint.
36
37     *result |= data[i] << 8 * reverse_i;
38   }
39   return true;
40 }
41
42 }  // namespace
43
44 struct JwkToWebCryptoUsage {
45   const char* const jwk_key_op;
46   const blink::WebCryptoKeyUsage webcrypto_usage;
47 };
48
49 // Keep this ordered according to the definition
50 // order of WebCrypto's "recognized key usage
51 // values".
52 //
53 // This is not required for spec compliance,
54 // however it makes the ordering of key_ops match
55 // that of WebCrypto's Key.usages.
56 const JwkToWebCryptoUsage kJwkWebCryptoUsageMap[] = {
57     {"encrypt", blink::WebCryptoKeyUsageEncrypt},
58     {"decrypt", blink::WebCryptoKeyUsageDecrypt},
59     {"sign", blink::WebCryptoKeyUsageSign},
60     {"verify", blink::WebCryptoKeyUsageVerify},
61     {"deriveKey", blink::WebCryptoKeyUsageDeriveKey},
62     {"deriveBits", blink::WebCryptoKeyUsageDeriveBits},
63     {"wrapKey", blink::WebCryptoKeyUsageWrapKey},
64     {"unwrapKey", blink::WebCryptoKeyUsageUnwrapKey}};
65
66 bool JwkKeyOpToWebCryptoUsage(const std::string& key_op,
67                               blink::WebCryptoKeyUsage* usage) {
68   for (size_t i = 0; i < arraysize(kJwkWebCryptoUsageMap); ++i) {
69     if (kJwkWebCryptoUsageMap[i].jwk_key_op == key_op) {
70       *usage = kJwkWebCryptoUsageMap[i].webcrypto_usage;
71       return true;
72     }
73   }
74   return false;
75 }
76
77 // Composes a Web Crypto usage mask from an array of JWK key_ops values.
78 Status GetWebCryptoUsagesFromJwkKeyOps(const base::ListValue* key_ops,
79                                        blink::WebCryptoKeyUsageMask* usages) {
80   // This set keeps track of all unrecognized key_ops values.
81   std::set<std::string> unrecognized_usages;
82
83   *usages = 0;
84   for (size_t i = 0; i < key_ops->GetSize(); ++i) {
85     std::string key_op;
86     if (!key_ops->GetString(i, &key_op)) {
87       return Status::ErrorJwkPropertyWrongType(
88           base::StringPrintf("key_ops[%d]", static_cast<int>(i)), "string");
89     }
90
91     blink::WebCryptoKeyUsage usage;
92     if (JwkKeyOpToWebCryptoUsage(key_op, &usage)) {
93       // Ensure there are no duplicate usages.
94       if (*usages & usage)
95         return Status::ErrorJwkDuplicateKeyOps();
96       *usages |= usage;
97     }
98
99     // Reaching here means the usage was unrecognized. Such usages are skipped
100     // over, however they are kept track of in a set to ensure there were no
101     // duplicates.
102     if (!unrecognized_usages.insert(key_op).second)
103       return Status::ErrorJwkDuplicateKeyOps();
104   }
105   return Status::Success();
106 }
107
108 // Composes a JWK key_ops List from a Web Crypto usage mask.
109 // Note: Caller must assume ownership of returned instance.
110 base::ListValue* CreateJwkKeyOpsFromWebCryptoUsages(
111     blink::WebCryptoKeyUsageMask usages) {
112   base::ListValue* jwk_key_ops = new base::ListValue();
113   for (size_t i = 0; i < arraysize(kJwkWebCryptoUsageMap); ++i) {
114     if (usages & kJwkWebCryptoUsageMap[i].webcrypto_usage)
115       jwk_key_ops->AppendString(kJwkWebCryptoUsageMap[i].jwk_key_op);
116   }
117   return jwk_key_ops;
118 }
119
120 blink::WebCryptoAlgorithm CreateAlgorithm(blink::WebCryptoAlgorithmId id) {
121   return blink::WebCryptoAlgorithm::adoptParamsAndCreate(id, NULL);
122 }
123
124 blink::WebCryptoAlgorithm CreateHmacImportAlgorithm(
125     blink::WebCryptoAlgorithmId hash_id) {
126   DCHECK(blink::WebCryptoAlgorithm::isHash(hash_id));
127   return blink::WebCryptoAlgorithm::adoptParamsAndCreate(
128       blink::WebCryptoAlgorithmIdHmac,
129       new blink::WebCryptoHmacImportParams(CreateAlgorithm(hash_id)));
130 }
131
132 blink::WebCryptoAlgorithm CreateRsaHashedImportAlgorithm(
133     blink::WebCryptoAlgorithmId id,
134     blink::WebCryptoAlgorithmId hash_id) {
135   DCHECK(blink::WebCryptoAlgorithm::isHash(hash_id));
136   return blink::WebCryptoAlgorithm::adoptParamsAndCreate(
137       id, new blink::WebCryptoRsaHashedImportParams(CreateAlgorithm(hash_id)));
138 }
139
140 bool ContainsKeyUsages(blink::WebCryptoKeyUsageMask a,
141                        blink::WebCryptoKeyUsageMask b) {
142   return (a & b) == b;
143 }
144
145 // TODO(eroman): Move this helper to WebCryptoKey.
146 bool KeyUsageAllows(const blink::WebCryptoKey& key,
147                     const blink::WebCryptoKeyUsage usage) {
148   return ((key.usages() & usage) != 0);
149 }
150
151 // The WebCrypto spec defines the default value for the tag length, as well as
152 // the allowed values for tag length.
153 Status GetAesGcmTagLengthInBits(const blink::WebCryptoAesGcmParams* params,
154                                 unsigned int* tag_length_bits) {
155   *tag_length_bits = 128;
156   if (params->hasTagLengthBits())
157     *tag_length_bits = params->optionalTagLengthBits();
158
159   if (*tag_length_bits != 32 && *tag_length_bits != 64 &&
160       *tag_length_bits != 96 && *tag_length_bits != 104 &&
161       *tag_length_bits != 112 && *tag_length_bits != 120 &&
162       *tag_length_bits != 128)
163     return Status::ErrorInvalidAesGcmTagLength();
164
165   return Status::Success();
166 }
167
168 Status GetAesKeyGenLengthInBits(const blink::WebCryptoAesKeyGenParams* params,
169                                 unsigned int* keylen_bits) {
170   *keylen_bits = params->lengthBits();
171
172   if (*keylen_bits == 128 || *keylen_bits == 256)
173     return Status::Success();
174
175   // BoringSSL does not support 192-bit AES.
176   if (*keylen_bits == 192)
177     return Status::ErrorAes192BitUnsupported();
178
179   return Status::ErrorGenerateKeyLength();
180 }
181
182 Status GetHmacKeyGenLengthInBits(const blink::WebCryptoHmacKeyGenParams* params,
183                                  unsigned int* keylen_bits) {
184   if (!params->hasLengthBits()) {
185     switch (params->hash().id()) {
186       case blink::WebCryptoAlgorithmIdSha1:
187       case blink::WebCryptoAlgorithmIdSha256:
188         *keylen_bits = 512;
189         return Status::Success();
190       case blink::WebCryptoAlgorithmIdSha384:
191       case blink::WebCryptoAlgorithmIdSha512:
192         *keylen_bits = 1024;
193         return Status::Success();
194       default:
195         return Status::ErrorUnsupported();
196     }
197   }
198
199   if (params->optionalLengthBits() % 8)
200     return Status::ErrorGenerateKeyLength();
201
202   *keylen_bits = params->optionalLengthBits();
203
204   // TODO(eroman): NSS fails when generating a zero-length secret key.
205   if (*keylen_bits == 0)
206     return Status::ErrorGenerateKeyLength();
207
208   return Status::Success();
209 }
210
211 Status VerifyAesKeyLengthForImport(unsigned int keylen_bytes) {
212   if (keylen_bytes == 16 || keylen_bytes == 32)
213     return Status::Success();
214
215   // BoringSSL does not support 192-bit AES.
216   if (keylen_bytes == 24)
217     return Status::ErrorAes192BitUnsupported();
218
219   return Status::ErrorImportAesKeyLength();
220 }
221
222 Status CheckKeyCreationUsages(blink::WebCryptoKeyUsageMask all_possible_usages,
223                               blink::WebCryptoKeyUsageMask actual_usages) {
224   if (!ContainsKeyUsages(all_possible_usages, actual_usages))
225     return Status::ErrorCreateKeyBadUsages();
226   return Status::Success();
227 }
228
229 Status GetRsaKeyGenParameters(
230     const blink::WebCryptoRsaHashedKeyGenParams* params,
231     unsigned int* public_exponent,
232     unsigned int* modulus_length_bits) {
233   *modulus_length_bits = params->modulusLengthBits();
234
235   // Limit key sizes to those supported by NSS:
236   //   * Multiple of 8 bits
237   //   * 256 bits to 16K bits
238   if (*modulus_length_bits < 256 || *modulus_length_bits > 16384 ||
239       (*modulus_length_bits % 8) != 0) {
240     return Status::ErrorGenerateRsaUnsupportedModulus();
241   }
242
243   if (!BigIntegerToUint(params->publicExponent().data(),
244                         params->publicExponent().size(),
245                         public_exponent)) {
246     return Status::ErrorGenerateKeyPublicExponent();
247   }
248
249   // OpenSSL hangs when given bad public exponents, whereas NSS simply fails. To
250   // avoid feeding OpenSSL data that will hang use a whitelist.
251   if (*public_exponent != 3 && *public_exponent != 65537)
252     return Status::ErrorGenerateKeyPublicExponent();
253
254   return Status::Success();
255 }
256
257 }  // namespace webcrypto
258
259 }  // namespace content