OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "components/webcrypto/webcrypto_util.h" | 5 #include "components/webcrypto/webcrypto_util.h" |
6 | 6 |
7 #include "base/logging.h" | 7 #include "base/logging.h" |
8 #include "base/numerics/safe_math.h" | |
9 #include "components/webcrypto/status.h" | 8 #include "components/webcrypto/status.h" |
10 #include "third_party/WebKit/public/platform/WebCryptoAlgorithm.h" | 9 #include "third_party/WebKit/public/platform/WebCryptoAlgorithm.h" |
11 #include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h" | 10 #include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h" |
12 #include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h" | 11 #include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h" |
13 | 12 |
14 namespace webcrypto { | 13 namespace webcrypto { |
15 | 14 |
16 namespace { | 15 namespace { |
17 | 16 |
18 // Converts a (big-endian) WebCrypto BigInteger, with or without leading zeros, | 17 // Converts a (big-endian) WebCrypto BigInteger, with or without leading zeros, |
19 // to unsigned int. | 18 // to unsigned int. |
20 bool BigIntegerToUint(const uint8_t* data, | 19 bool BigIntegerToUint(const uint8_t* data, |
21 size_t data_size, | 20 size_t data_size, |
22 unsigned int* result) { | 21 unsigned int* result) { |
23 if (data_size == 0) | 22 if (data_size == 0) |
24 return false; | 23 return false; |
25 | 24 |
26 *result = 0; | 25 *result = 0; |
27 for (size_t i = 0; i < data_size; ++i) { | 26 for (size_t i = 0; i < data_size; ++i) { |
28 size_t reverse_i = data_size - i - 1; | 27 size_t reverse_i = data_size - i - 1; |
29 | 28 |
30 if (reverse_i >= sizeof(*result) && data[i]) | 29 if (reverse_i >= sizeof(*result) && data[i]) |
31 return false; // Too large for a uint. | 30 return false; // Too large for a uint. |
32 | 31 |
33 *result |= data[i] << 8 * reverse_i; | 32 *result |= data[i] << 8 * reverse_i; |
34 } | 33 } |
35 return true; | 34 return true; |
36 } | 35 } |
37 | 36 |
38 Status GetShaBlockSizeBits(const blink::WebCryptoAlgorithm& algorithm, | |
39 unsigned int* block_size_bits) { | |
40 switch (algorithm.id()) { | |
41 case blink::WebCryptoAlgorithmIdSha1: | |
42 case blink::WebCryptoAlgorithmIdSha256: | |
43 *block_size_bits = 512; | |
44 return Status::Success(); | |
45 case blink::WebCryptoAlgorithmIdSha384: | |
46 case blink::WebCryptoAlgorithmIdSha512: | |
47 *block_size_bits = 1024; | |
48 return Status::Success(); | |
49 default: | |
50 return Status::ErrorUnsupported(); | |
51 } | |
52 } | |
53 | 37 |
54 } // namespace | 38 } // namespace |
55 | 39 |
56 blink::WebCryptoAlgorithm CreateAlgorithm(blink::WebCryptoAlgorithmId id) { | 40 blink::WebCryptoAlgorithm CreateAlgorithm(blink::WebCryptoAlgorithmId id) { |
57 return blink::WebCryptoAlgorithm::adoptParamsAndCreate(id, NULL); | 41 return blink::WebCryptoAlgorithm::adoptParamsAndCreate(id, NULL); |
58 } | 42 } |
59 | 43 |
60 blink::WebCryptoAlgorithm CreateHmacImportAlgorithm( | |
61 blink::WebCryptoAlgorithmId hash_id, | |
62 unsigned int length_bits) { | |
63 DCHECK(blink::WebCryptoAlgorithm::isHash(hash_id)); | |
64 return blink::WebCryptoAlgorithm::adoptParamsAndCreate( | |
65 blink::WebCryptoAlgorithmIdHmac, | |
66 new blink::WebCryptoHmacImportParams(CreateAlgorithm(hash_id), true, | |
67 length_bits)); | |
68 } | |
69 | |
70 blink::WebCryptoAlgorithm CreateHmacImportAlgorithmNoLength( | |
71 blink::WebCryptoAlgorithmId hash_id) { | |
72 DCHECK(blink::WebCryptoAlgorithm::isHash(hash_id)); | |
73 return blink::WebCryptoAlgorithm::adoptParamsAndCreate( | |
74 blink::WebCryptoAlgorithmIdHmac, | |
75 new blink::WebCryptoHmacImportParams(CreateAlgorithm(hash_id), false, 0)); | |
76 } | |
77 | |
78 blink::WebCryptoAlgorithm CreateRsaHashedImportAlgorithm( | 44 blink::WebCryptoAlgorithm CreateRsaHashedImportAlgorithm( |
79 blink::WebCryptoAlgorithmId id, | 45 blink::WebCryptoAlgorithmId id, |
80 blink::WebCryptoAlgorithmId hash_id) { | 46 blink::WebCryptoAlgorithmId hash_id) { |
81 DCHECK(blink::WebCryptoAlgorithm::isHash(hash_id)); | 47 DCHECK(blink::WebCryptoAlgorithm::isHash(hash_id)); |
82 return blink::WebCryptoAlgorithm::adoptParamsAndCreate( | 48 return blink::WebCryptoAlgorithm::adoptParamsAndCreate( |
83 id, new blink::WebCryptoRsaHashedImportParams(CreateAlgorithm(hash_id))); | 49 id, new blink::WebCryptoRsaHashedImportParams(CreateAlgorithm(hash_id))); |
84 } | 50 } |
85 | 51 |
86 blink::WebCryptoAlgorithm CreateEcImportAlgorithm( | 52 blink::WebCryptoAlgorithm CreateEcImportAlgorithm( |
87 blink::WebCryptoAlgorithmId id, | 53 blink::WebCryptoAlgorithmId id, |
88 blink::WebCryptoNamedCurve named_curve) { | 54 blink::WebCryptoNamedCurve named_curve) { |
89 return blink::WebCryptoAlgorithm::adoptParamsAndCreate( | 55 return blink::WebCryptoAlgorithm::adoptParamsAndCreate( |
90 id, new blink::WebCryptoEcKeyImportParams(named_curve)); | 56 id, new blink::WebCryptoEcKeyImportParams(named_curve)); |
91 } | 57 } |
92 | 58 |
93 bool ContainsKeyUsages(blink::WebCryptoKeyUsageMask a, | 59 bool ContainsKeyUsages(blink::WebCryptoKeyUsageMask a, |
94 blink::WebCryptoKeyUsageMask b) { | 60 blink::WebCryptoKeyUsageMask b) { |
95 return (a & b) == b; | 61 return (a & b) == b; |
96 } | 62 } |
97 | 63 |
98 // The WebCrypto spec defines the default value for the tag length, as well as | |
99 // the allowed values for tag length. | |
100 Status GetAesGcmTagLengthInBits(const blink::WebCryptoAesGcmParams* params, | |
101 unsigned int* tag_length_bits) { | |
102 *tag_length_bits = 128; | |
103 if (params->hasTagLengthBits()) | |
104 *tag_length_bits = params->optionalTagLengthBits(); | |
105 | |
106 if (*tag_length_bits != 32 && *tag_length_bits != 64 && | |
107 *tag_length_bits != 96 && *tag_length_bits != 104 && | |
108 *tag_length_bits != 112 && *tag_length_bits != 120 && | |
109 *tag_length_bits != 128) | |
110 return Status::ErrorInvalidAesGcmTagLength(); | |
111 | |
112 return Status::Success(); | |
113 } | |
114 | |
115 Status GetAesKeyGenLengthInBits(const blink::WebCryptoAesKeyGenParams* params, | |
116 unsigned int* keylen_bits) { | |
117 *keylen_bits = params->lengthBits(); | |
118 | |
119 if (*keylen_bits == 128 || *keylen_bits == 256) | |
120 return Status::Success(); | |
121 | |
122 // BoringSSL does not support 192-bit AES. | |
123 if (*keylen_bits == 192) | |
124 return Status::ErrorAes192BitUnsupported(); | |
125 | |
126 return Status::ErrorGenerateAesKeyLength(); | |
127 } | |
128 | |
129 Status GetHmacKeyGenLengthInBits(const blink::WebCryptoHmacKeyGenParams* params, | |
130 unsigned int* keylen_bits) { | |
131 if (!params->hasLengthBits()) | |
132 return GetShaBlockSizeBits(params->hash(), keylen_bits); | |
133 | |
134 *keylen_bits = params->optionalLengthBits(); | |
135 | |
136 // Zero-length HMAC keys are disallowed by the spec. | |
137 if (*keylen_bits == 0) | |
138 return Status::ErrorGenerateHmacKeyLengthZero(); | |
139 | |
140 return Status::Success(); | |
141 } | |
142 | |
143 Status GetHmacImportKeyLengthBits( | |
144 const blink::WebCryptoHmacImportParams* params, | |
145 unsigned int key_data_byte_length, | |
146 unsigned int* keylen_bits) { | |
147 if (key_data_byte_length == 0) | |
148 return Status::ErrorHmacImportEmptyKey(); | |
149 | |
150 // Make sure that the key data's length can be represented in bits without | |
151 // overflow. | |
152 base::CheckedNumeric<unsigned int> checked_keylen_bits(key_data_byte_length); | |
153 checked_keylen_bits *= 8; | |
154 | |
155 if (!checked_keylen_bits.IsValid()) | |
156 return Status::ErrorDataTooLarge(); | |
157 | |
158 unsigned int data_keylen_bits = checked_keylen_bits.ValueOrDie(); | |
159 | |
160 // Determine how many bits of the input to use. | |
161 *keylen_bits = data_keylen_bits; | |
162 if (params->hasLengthBits()) { | |
163 // The requested bit length must be: | |
164 // * No longer than the input data length | |
165 // * At most 7 bits shorter. | |
166 if (NumBitsToBytes(params->optionalLengthBits()) != key_data_byte_length) | |
167 return Status::ErrorHmacImportBadLength(); | |
168 *keylen_bits = params->optionalLengthBits(); | |
169 } | |
170 | |
171 return Status::Success(); | |
172 } | |
173 | |
174 Status VerifyAesKeyLengthForImport(unsigned int keylen_bytes) { | |
175 if (keylen_bytes == 16 || keylen_bytes == 32) | |
176 return Status::Success(); | |
177 | |
178 // BoringSSL does not support 192-bit AES. | |
179 if (keylen_bytes == 24) | |
180 return Status::ErrorAes192BitUnsupported(); | |
181 | |
182 return Status::ErrorImportAesKeyLength(); | |
183 } | |
184 | 64 |
185 Status CheckKeyCreationUsages(blink::WebCryptoKeyUsageMask all_possible_usages, | 65 Status CheckKeyCreationUsages(blink::WebCryptoKeyUsageMask all_possible_usages, |
186 blink::WebCryptoKeyUsageMask actual_usages, | 66 blink::WebCryptoKeyUsageMask actual_usages, |
187 bool allow_empty_usages) { | 67 bool allow_empty_usages) { |
188 if (!allow_empty_usages && actual_usages == 0) | 68 if (!allow_empty_usages && actual_usages == 0) |
189 return Status::ErrorCreateKeyEmptyUsages(); | 69 return Status::ErrorCreateKeyEmptyUsages(); |
190 | 70 |
191 if (!ContainsKeyUsages(all_possible_usages, actual_usages)) | 71 if (!ContainsKeyUsages(all_possible_usages, actual_usages)) |
192 return Status::ErrorCreateKeyBadUsages(); | 72 return Status::ErrorCreateKeyBadUsages(); |
193 return Status::Success(); | 73 return Status::Success(); |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
257 bytes->resize(length_bytes); | 137 bytes->resize(length_bytes); |
258 } | 138 } |
259 | 139 |
260 size_t remainder_bits = length_bits % 8; | 140 size_t remainder_bits = length_bits % 8; |
261 | 141 |
262 // Zero any "unused bits" in the final byte | 142 // Zero any "unused bits" in the final byte |
263 if (remainder_bits) | 143 if (remainder_bits) |
264 (*bytes)[bytes->size() - 1] &= ~((0xFF) >> remainder_bits); | 144 (*bytes)[bytes->size() - 1] &= ~((0xFF) >> remainder_bits); |
265 } | 145 } |
266 | 146 |
267 Status GetAesKeyLength(const blink::WebCryptoAlgorithm& key_length_algorithm, | |
268 bool* has_length_bits, | |
269 unsigned int* length_bits) { | |
270 const blink::WebCryptoAesDerivedKeyParams* params = | |
271 key_length_algorithm.aesDerivedKeyParams(); | |
272 | |
273 *has_length_bits = true; | |
274 *length_bits = params->lengthBits(); | |
275 | |
276 if (*length_bits == 128 || *length_bits == 256) | |
277 return Status::Success(); | |
278 | |
279 // BoringSSL does not support 192-bit AES. | |
280 if (*length_bits == 192) | |
281 return Status::ErrorAes192BitUnsupported(); | |
282 | |
283 return Status::ErrorGetAesKeyLength(); | |
284 } | |
285 | |
286 Status GetHmacKeyLength(const blink::WebCryptoAlgorithm& key_length_algorithm, | |
287 bool* has_length_bits, | |
288 unsigned int* length_bits) { | |
289 const blink::WebCryptoHmacImportParams* params = | |
290 key_length_algorithm.hmacImportParams(); | |
291 | |
292 if (params->hasLengthBits()) { | |
293 *has_length_bits = true; | |
294 *length_bits = params->optionalLengthBits(); | |
295 if (*length_bits == 0) | |
296 return Status::ErrorGetHmacKeyLengthZero(); | |
297 return Status::Success(); | |
298 } | |
299 | |
300 *has_length_bits = true; | |
301 return GetShaBlockSizeBits(params->hash(), length_bits); | |
302 } | |
303 | 147 |
304 Status GetUsagesForGenerateAsymmetricKey( | 148 Status GetUsagesForGenerateAsymmetricKey( |
305 blink::WebCryptoKeyUsageMask combined_usages, | 149 blink::WebCryptoKeyUsageMask combined_usages, |
306 blink::WebCryptoKeyUsageMask all_public_usages, | 150 blink::WebCryptoKeyUsageMask all_public_usages, |
307 blink::WebCryptoKeyUsageMask all_private_usages, | 151 blink::WebCryptoKeyUsageMask all_private_usages, |
308 blink::WebCryptoKeyUsageMask* public_usages, | 152 blink::WebCryptoKeyUsageMask* public_usages, |
309 blink::WebCryptoKeyUsageMask* private_usages) { | 153 blink::WebCryptoKeyUsageMask* private_usages) { |
310 Status status = CheckKeyCreationUsages(all_public_usages | all_private_usages, | 154 Status status = CheckKeyCreationUsages(all_public_usages | all_private_usages, |
311 combined_usages, true); | 155 combined_usages, true); |
312 if (status.IsError()) | 156 if (status.IsError()) |
313 return status; | 157 return status; |
314 | 158 |
315 *public_usages = combined_usages & all_public_usages; | 159 *public_usages = combined_usages & all_public_usages; |
316 *private_usages = combined_usages & all_private_usages; | 160 *private_usages = combined_usages & all_private_usages; |
317 | 161 |
318 if (*private_usages == 0) | 162 if (*private_usages == 0) |
319 return Status::ErrorCreateKeyEmptyUsages(); | 163 return Status::ErrorCreateKeyEmptyUsages(); |
320 | 164 |
321 return Status::Success(); | 165 return Status::Success(); |
322 } | 166 } |
323 | 167 |
324 } // namespace webcrypto | 168 } // namespace webcrypto |
OLD | NEW |