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

Side by Side Diff: content/child/webcrypto/webcrypto_util.cc

Issue 1077273002: html_viewer: Move webcrypto to a place where html_viewer can use it. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rebase to ToT Created 5 years, 8 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
« no previous file with comments | « content/child/webcrypto/webcrypto_util.h ('k') | content/content_child.gypi » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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 "base/logging.h"
8 #include "base/numerics/safe_math.h"
9 #include "content/child/webcrypto/status.h"
10 #include "third_party/WebKit/public/platform/WebCryptoAlgorithm.h"
11 #include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h"
12 #include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h"
13
14 namespace content {
15
16 namespace webcrypto {
17
18 namespace {
19
20 // Converts a (big-endian) WebCrypto BigInteger, with or without leading zeros,
21 // to unsigned int.
22 bool BigIntegerToUint(const uint8_t* data,
23 unsigned int data_size,
24 unsigned int* result) {
25 if (data_size == 0)
26 return false;
27
28 *result = 0;
29 for (size_t i = 0; i < data_size; ++i) {
30 size_t reverse_i = data_size - i - 1;
31
32 if (reverse_i >= sizeof(*result) && data[i])
33 return false; // Too large for a uint.
34
35 *result |= data[i] << 8 * reverse_i;
36 }
37 return true;
38 }
39
40 Status GetShaBlockSizeBits(const blink::WebCryptoAlgorithm& algorithm,
41 unsigned int* block_size_bits) {
42 switch (algorithm.id()) {
43 case blink::WebCryptoAlgorithmIdSha1:
44 case blink::WebCryptoAlgorithmIdSha256:
45 *block_size_bits = 512;
46 return Status::Success();
47 case blink::WebCryptoAlgorithmIdSha384:
48 case blink::WebCryptoAlgorithmIdSha512:
49 *block_size_bits = 1024;
50 return Status::Success();
51 default:
52 return Status::ErrorUnsupported();
53 }
54 }
55
56 } // namespace
57
58 blink::WebCryptoAlgorithm CreateAlgorithm(blink::WebCryptoAlgorithmId id) {
59 return blink::WebCryptoAlgorithm::adoptParamsAndCreate(id, NULL);
60 }
61
62 blink::WebCryptoAlgorithm CreateHmacImportAlgorithm(
63 blink::WebCryptoAlgorithmId hash_id,
64 unsigned int length_bits) {
65 DCHECK(blink::WebCryptoAlgorithm::isHash(hash_id));
66 return blink::WebCryptoAlgorithm::adoptParamsAndCreate(
67 blink::WebCryptoAlgorithmIdHmac,
68 new blink::WebCryptoHmacImportParams(CreateAlgorithm(hash_id), true,
69 length_bits));
70 }
71
72 blink::WebCryptoAlgorithm CreateHmacImportAlgorithmNoLength(
73 blink::WebCryptoAlgorithmId hash_id) {
74 DCHECK(blink::WebCryptoAlgorithm::isHash(hash_id));
75 return blink::WebCryptoAlgorithm::adoptParamsAndCreate(
76 blink::WebCryptoAlgorithmIdHmac,
77 new blink::WebCryptoHmacImportParams(CreateAlgorithm(hash_id), false, 0));
78 }
79
80 blink::WebCryptoAlgorithm CreateRsaHashedImportAlgorithm(
81 blink::WebCryptoAlgorithmId id,
82 blink::WebCryptoAlgorithmId hash_id) {
83 DCHECK(blink::WebCryptoAlgorithm::isHash(hash_id));
84 return blink::WebCryptoAlgorithm::adoptParamsAndCreate(
85 id, new blink::WebCryptoRsaHashedImportParams(CreateAlgorithm(hash_id)));
86 }
87
88 blink::WebCryptoAlgorithm CreateEcImportAlgorithm(
89 blink::WebCryptoAlgorithmId id,
90 blink::WebCryptoNamedCurve named_curve) {
91 return blink::WebCryptoAlgorithm::adoptParamsAndCreate(
92 id, new blink::WebCryptoEcKeyImportParams(named_curve));
93 }
94
95 bool ContainsKeyUsages(blink::WebCryptoKeyUsageMask a,
96 blink::WebCryptoKeyUsageMask b) {
97 return (a & b) == b;
98 }
99
100 // TODO(eroman): Move this helper to WebCryptoKey.
101 bool KeyUsageAllows(const blink::WebCryptoKey& key,
102 const blink::WebCryptoKeyUsage usage) {
103 return ((key.usages() & usage) != 0);
104 }
105
106 // The WebCrypto spec defines the default value for the tag length, as well as
107 // the allowed values for tag length.
108 Status GetAesGcmTagLengthInBits(const blink::WebCryptoAesGcmParams* params,
109 unsigned int* tag_length_bits) {
110 *tag_length_bits = 128;
111 if (params->hasTagLengthBits())
112 *tag_length_bits = params->optionalTagLengthBits();
113
114 if (*tag_length_bits != 32 && *tag_length_bits != 64 &&
115 *tag_length_bits != 96 && *tag_length_bits != 104 &&
116 *tag_length_bits != 112 && *tag_length_bits != 120 &&
117 *tag_length_bits != 128)
118 return Status::ErrorInvalidAesGcmTagLength();
119
120 return Status::Success();
121 }
122
123 Status GetAesKeyGenLengthInBits(const blink::WebCryptoAesKeyGenParams* params,
124 unsigned int* keylen_bits) {
125 *keylen_bits = params->lengthBits();
126
127 if (*keylen_bits == 128 || *keylen_bits == 256)
128 return Status::Success();
129
130 // BoringSSL does not support 192-bit AES.
131 if (*keylen_bits == 192)
132 return Status::ErrorAes192BitUnsupported();
133
134 return Status::ErrorGenerateAesKeyLength();
135 }
136
137 Status GetHmacKeyGenLengthInBits(const blink::WebCryptoHmacKeyGenParams* params,
138 unsigned int* keylen_bits) {
139 if (!params->hasLengthBits())
140 return GetShaBlockSizeBits(params->hash(), keylen_bits);
141
142 *keylen_bits = params->optionalLengthBits();
143
144 // Zero-length HMAC keys are disallowed by the spec.
145 if (*keylen_bits == 0)
146 return Status::ErrorGenerateHmacKeyLengthZero();
147
148 return Status::Success();
149 }
150
151 Status GetHmacImportKeyLengthBits(
152 const blink::WebCryptoHmacImportParams* params,
153 unsigned int key_data_byte_length,
154 unsigned int* keylen_bits) {
155 if (key_data_byte_length == 0)
156 return Status::ErrorHmacImportEmptyKey();
157
158 // Make sure that the key data's length can be represented in bits without
159 // overflow.
160 base::CheckedNumeric<unsigned int> checked_keylen_bits(key_data_byte_length);
161 checked_keylen_bits *= 8;
162
163 if (!checked_keylen_bits.IsValid())
164 return Status::ErrorDataTooLarge();
165
166 unsigned int data_keylen_bits = checked_keylen_bits.ValueOrDie();
167
168 // Determine how many bits of the input to use.
169 *keylen_bits = data_keylen_bits;
170 if (params->hasLengthBits()) {
171 // The requested bit length must be:
172 // * No longer than the input data length
173 // * At most 7 bits shorter.
174 if (NumBitsToBytes(params->optionalLengthBits()) != key_data_byte_length)
175 return Status::ErrorHmacImportBadLength();
176 *keylen_bits = params->optionalLengthBits();
177 }
178
179 return Status::Success();
180 }
181
182 Status VerifyAesKeyLengthForImport(unsigned int keylen_bytes) {
183 if (keylen_bytes == 16 || keylen_bytes == 32)
184 return Status::Success();
185
186 // BoringSSL does not support 192-bit AES.
187 if (keylen_bytes == 24)
188 return Status::ErrorAes192BitUnsupported();
189
190 return Status::ErrorImportAesKeyLength();
191 }
192
193 Status CheckKeyCreationUsages(blink::WebCryptoKeyUsageMask all_possible_usages,
194 blink::WebCryptoKeyUsageMask actual_usages,
195 bool allow_empty_usages) {
196 if (!allow_empty_usages && actual_usages == 0)
197 return Status::ErrorCreateKeyEmptyUsages();
198
199 if (!ContainsKeyUsages(all_possible_usages, actual_usages))
200 return Status::ErrorCreateKeyBadUsages();
201 return Status::Success();
202 }
203
204 Status GetRsaKeyGenParameters(
205 const blink::WebCryptoRsaHashedKeyGenParams* params,
206 unsigned int* public_exponent,
207 unsigned int* modulus_length_bits) {
208 *modulus_length_bits = params->modulusLengthBits();
209
210 // Limit key sizes to those supported by NSS:
211 // * Multiple of 8 bits
212 // * 256 bits to 16K bits
213 if (*modulus_length_bits < 256 || *modulus_length_bits > 16384 ||
214 (*modulus_length_bits % 8) != 0) {
215 return Status::ErrorGenerateRsaUnsupportedModulus();
216 }
217
218 if (!BigIntegerToUint(params->publicExponent().data(),
219 params->publicExponent().size(), public_exponent)) {
220 return Status::ErrorGenerateKeyPublicExponent();
221 }
222
223 // OpenSSL hangs when given bad public exponents, whereas NSS simply fails. To
224 // avoid feeding OpenSSL data that will hang use a whitelist.
225 if (*public_exponent != 3 && *public_exponent != 65537)
226 return Status::ErrorGenerateKeyPublicExponent();
227
228 return Status::Success();
229 }
230
231 Status VerifyUsagesBeforeImportAsymmetricKey(
232 blink::WebCryptoKeyFormat format,
233 blink::WebCryptoKeyUsageMask all_public_key_usages,
234 blink::WebCryptoKeyUsageMask all_private_key_usages,
235 blink::WebCryptoKeyUsageMask usages) {
236 switch (format) {
237 case blink::WebCryptoKeyFormatSpki:
238 return CheckKeyCreationUsages(all_public_key_usages, usages, true);
239 case blink::WebCryptoKeyFormatPkcs8:
240 return CheckKeyCreationUsages(all_private_key_usages, usages, false);
241 case blink::WebCryptoKeyFormatJwk: {
242 // The JWK could represent either a public key or private key. The usages
243 // must make sense for one of the two. The usages will be checked again by
244 // ImportKeyJwk() once the key type has been determined.
245 if (CheckKeyCreationUsages(
246 all_public_key_usages, usages, true).IsError() &&
247 CheckKeyCreationUsages(
248 all_private_key_usages, usages, false).IsError()) {
249 return Status::ErrorCreateKeyBadUsages();
250 }
251 return Status::Success();
252 }
253 default:
254 return Status::ErrorUnsupportedImportKeyFormat();
255 }
256 }
257
258 void TruncateToBitLength(size_t length_bits, std::vector<uint8_t>* bytes) {
259 size_t length_bytes = NumBitsToBytes(length_bits);
260
261 if (bytes->size() != length_bytes) {
262 CHECK_LT(length_bytes, bytes->size());
263 bytes->resize(length_bytes);
264 }
265
266 size_t remainder_bits = length_bits % 8;
267
268 // Zero any "unused bits" in the final byte
269 if (remainder_bits)
270 (*bytes)[bytes->size() - 1] &= ~((0xFF) >> remainder_bits);
271 }
272
273 Status GetAesKeyLength(const blink::WebCryptoAlgorithm& key_length_algorithm,
274 bool* has_length_bits,
275 unsigned int* length_bits) {
276 const blink::WebCryptoAesDerivedKeyParams* params =
277 key_length_algorithm.aesDerivedKeyParams();
278
279 *has_length_bits = true;
280 *length_bits = params->lengthBits();
281
282 if (*length_bits == 128 || *length_bits == 256)
283 return Status::Success();
284
285 // BoringSSL does not support 192-bit AES.
286 if (*length_bits == 192)
287 return Status::ErrorAes192BitUnsupported();
288
289 return Status::ErrorGetAesKeyLength();
290 }
291
292 Status GetHmacKeyLength(const blink::WebCryptoAlgorithm& key_length_algorithm,
293 bool* has_length_bits,
294 unsigned int* length_bits) {
295 const blink::WebCryptoHmacImportParams* params =
296 key_length_algorithm.hmacImportParams();
297
298 if (params->hasLengthBits()) {
299 *has_length_bits = true;
300 *length_bits = params->optionalLengthBits();
301 if (*length_bits == 0)
302 return Status::ErrorGetHmacKeyLengthZero();
303 return Status::Success();
304 }
305
306 *has_length_bits = true;
307 return GetShaBlockSizeBits(params->hash(), length_bits);
308 }
309
310 Status GetUsagesForGenerateAsymmetricKey(
311 blink::WebCryptoKeyUsageMask combined_usages,
312 blink::WebCryptoKeyUsageMask all_public_usages,
313 blink::WebCryptoKeyUsageMask all_private_usages,
314 blink::WebCryptoKeyUsageMask* public_usages,
315 blink::WebCryptoKeyUsageMask* private_usages) {
316 Status status = CheckKeyCreationUsages(all_public_usages | all_private_usages,
317 combined_usages, true);
318 if (status.IsError())
319 return status;
320
321 *public_usages = combined_usages & all_public_usages;
322 *private_usages = combined_usages & all_private_usages;
323
324 if (*private_usages == 0)
325 return Status::ErrorCreateKeyEmptyUsages();
326
327 return Status::Success();
328 }
329
330 } // namespace webcrypto
331
332 } // namespace content
OLDNEW
« no previous file with comments | « content/child/webcrypto/webcrypto_util.h ('k') | content/content_child.gypi » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698