OLD | NEW |
| (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 | |
OLD | NEW |