Suppression for crbug.com/489779.
[chromium-blink-merge.git] / components / webcrypto / webcrypto_util.cc
blob2e80c1f8afe9288472b1edbe12628b18e852fc3c
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.
5 #include "components/webcrypto/webcrypto_util.h"
7 #include "base/logging.h"
8 #include "base/numerics/safe_math.h"
9 #include "components/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"
14 namespace webcrypto {
16 namespace {
18 // Converts a (big-endian) WebCrypto BigInteger, with or without leading zeros,
19 // to unsigned int.
20 bool BigIntegerToUint(const uint8_t* data,
21 size_t data_size,
22 unsigned int* result) {
23 if (data_size == 0)
24 return false;
26 *result = 0;
27 for (size_t i = 0; i < data_size; ++i) {
28 size_t reverse_i = data_size - i - 1;
30 if (reverse_i >= sizeof(*result) && data[i])
31 return false; // Too large for a uint.
33 *result |= data[i] << 8 * reverse_i;
35 return true;
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();
54 } // namespace
56 blink::WebCryptoAlgorithm CreateAlgorithm(blink::WebCryptoAlgorithmId id) {
57 return blink::WebCryptoAlgorithm::adoptParamsAndCreate(id, NULL);
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));
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));
78 blink::WebCryptoAlgorithm CreateRsaHashedImportAlgorithm(
79 blink::WebCryptoAlgorithmId id,
80 blink::WebCryptoAlgorithmId hash_id) {
81 DCHECK(blink::WebCryptoAlgorithm::isHash(hash_id));
82 return blink::WebCryptoAlgorithm::adoptParamsAndCreate(
83 id, new blink::WebCryptoRsaHashedImportParams(CreateAlgorithm(hash_id)));
86 blink::WebCryptoAlgorithm CreateEcImportAlgorithm(
87 blink::WebCryptoAlgorithmId id,
88 blink::WebCryptoNamedCurve named_curve) {
89 return blink::WebCryptoAlgorithm::adoptParamsAndCreate(
90 id, new blink::WebCryptoEcKeyImportParams(named_curve));
93 bool ContainsKeyUsages(blink::WebCryptoKeyUsageMask a,
94 blink::WebCryptoKeyUsageMask b) {
95 return (a & b) == b;
98 // TODO(eroman): Move this helper to WebCryptoKey.
99 bool KeyUsageAllows(const blink::WebCryptoKey& key,
100 const blink::WebCryptoKeyUsage usage) {
101 return ((key.usages() & usage) != 0);
104 // The WebCrypto spec defines the default value for the tag length, as well as
105 // the allowed values for tag length.
106 Status GetAesGcmTagLengthInBits(const blink::WebCryptoAesGcmParams* params,
107 unsigned int* tag_length_bits) {
108 *tag_length_bits = 128;
109 if (params->hasTagLengthBits())
110 *tag_length_bits = params->optionalTagLengthBits();
112 if (*tag_length_bits != 32 && *tag_length_bits != 64 &&
113 *tag_length_bits != 96 && *tag_length_bits != 104 &&
114 *tag_length_bits != 112 && *tag_length_bits != 120 &&
115 *tag_length_bits != 128)
116 return Status::ErrorInvalidAesGcmTagLength();
118 return Status::Success();
121 Status GetAesKeyGenLengthInBits(const blink::WebCryptoAesKeyGenParams* params,
122 unsigned int* keylen_bits) {
123 *keylen_bits = params->lengthBits();
125 if (*keylen_bits == 128 || *keylen_bits == 256)
126 return Status::Success();
128 // BoringSSL does not support 192-bit AES.
129 if (*keylen_bits == 192)
130 return Status::ErrorAes192BitUnsupported();
132 return Status::ErrorGenerateAesKeyLength();
135 Status GetHmacKeyGenLengthInBits(const blink::WebCryptoHmacKeyGenParams* params,
136 unsigned int* keylen_bits) {
137 if (!params->hasLengthBits())
138 return GetShaBlockSizeBits(params->hash(), keylen_bits);
140 *keylen_bits = params->optionalLengthBits();
142 // Zero-length HMAC keys are disallowed by the spec.
143 if (*keylen_bits == 0)
144 return Status::ErrorGenerateHmacKeyLengthZero();
146 return Status::Success();
149 Status GetHmacImportKeyLengthBits(
150 const blink::WebCryptoHmacImportParams* params,
151 unsigned int key_data_byte_length,
152 unsigned int* keylen_bits) {
153 if (key_data_byte_length == 0)
154 return Status::ErrorHmacImportEmptyKey();
156 // Make sure that the key data's length can be represented in bits without
157 // overflow.
158 base::CheckedNumeric<unsigned int> checked_keylen_bits(key_data_byte_length);
159 checked_keylen_bits *= 8;
161 if (!checked_keylen_bits.IsValid())
162 return Status::ErrorDataTooLarge();
164 unsigned int data_keylen_bits = checked_keylen_bits.ValueOrDie();
166 // Determine how many bits of the input to use.
167 *keylen_bits = data_keylen_bits;
168 if (params->hasLengthBits()) {
169 // The requested bit length must be:
170 // * No longer than the input data length
171 // * At most 7 bits shorter.
172 if (NumBitsToBytes(params->optionalLengthBits()) != key_data_byte_length)
173 return Status::ErrorHmacImportBadLength();
174 *keylen_bits = params->optionalLengthBits();
177 return Status::Success();
180 Status VerifyAesKeyLengthForImport(unsigned int keylen_bytes) {
181 if (keylen_bytes == 16 || keylen_bytes == 32)
182 return Status::Success();
184 // BoringSSL does not support 192-bit AES.
185 if (keylen_bytes == 24)
186 return Status::ErrorAes192BitUnsupported();
188 return Status::ErrorImportAesKeyLength();
191 Status CheckKeyCreationUsages(blink::WebCryptoKeyUsageMask all_possible_usages,
192 blink::WebCryptoKeyUsageMask actual_usages,
193 bool allow_empty_usages) {
194 if (!allow_empty_usages && actual_usages == 0)
195 return Status::ErrorCreateKeyEmptyUsages();
197 if (!ContainsKeyUsages(all_possible_usages, actual_usages))
198 return Status::ErrorCreateKeyBadUsages();
199 return Status::Success();
202 Status GetRsaKeyGenParameters(
203 const blink::WebCryptoRsaHashedKeyGenParams* params,
204 unsigned int* public_exponent,
205 unsigned int* modulus_length_bits) {
206 *modulus_length_bits = params->modulusLengthBits();
208 // Limit key sizes to those supported by NSS:
209 // * Multiple of 8 bits
210 // * 256 bits to 16K bits
211 if (*modulus_length_bits < 256 || *modulus_length_bits > 16384 ||
212 (*modulus_length_bits % 8) != 0) {
213 return Status::ErrorGenerateRsaUnsupportedModulus();
216 if (!BigIntegerToUint(params->publicExponent().data(),
217 params->publicExponent().size(), public_exponent)) {
218 return Status::ErrorGenerateKeyPublicExponent();
221 // OpenSSL hangs when given bad public exponents, whereas NSS simply fails. To
222 // avoid feeding OpenSSL data that will hang use a whitelist.
223 if (*public_exponent != 3 && *public_exponent != 65537)
224 return Status::ErrorGenerateKeyPublicExponent();
226 return Status::Success();
229 Status VerifyUsagesBeforeImportAsymmetricKey(
230 blink::WebCryptoKeyFormat format,
231 blink::WebCryptoKeyUsageMask all_public_key_usages,
232 blink::WebCryptoKeyUsageMask all_private_key_usages,
233 blink::WebCryptoKeyUsageMask usages) {
234 switch (format) {
235 case blink::WebCryptoKeyFormatSpki:
236 return CheckKeyCreationUsages(all_public_key_usages, usages, true);
237 case blink::WebCryptoKeyFormatPkcs8:
238 return CheckKeyCreationUsages(all_private_key_usages, usages, false);
239 case blink::WebCryptoKeyFormatJwk: {
240 // The JWK could represent either a public key or private key. The usages
241 // must make sense for one of the two. The usages will be checked again by
242 // ImportKeyJwk() once the key type has been determined.
243 if (CheckKeyCreationUsages(all_public_key_usages, usages, true)
244 .IsError() &&
245 CheckKeyCreationUsages(all_private_key_usages, usages, false)
246 .IsError()) {
247 return Status::ErrorCreateKeyBadUsages();
249 return Status::Success();
251 default:
252 return Status::ErrorUnsupportedImportKeyFormat();
256 void TruncateToBitLength(size_t length_bits, std::vector<uint8_t>* bytes) {
257 size_t length_bytes = NumBitsToBytes(length_bits);
259 if (bytes->size() != length_bytes) {
260 CHECK_LT(length_bytes, bytes->size());
261 bytes->resize(length_bytes);
264 size_t remainder_bits = length_bits % 8;
266 // Zero any "unused bits" in the final byte
267 if (remainder_bits)
268 (*bytes)[bytes->size() - 1] &= ~((0xFF) >> remainder_bits);
271 Status GetAesKeyLength(const blink::WebCryptoAlgorithm& key_length_algorithm,
272 bool* has_length_bits,
273 unsigned int* length_bits) {
274 const blink::WebCryptoAesDerivedKeyParams* params =
275 key_length_algorithm.aesDerivedKeyParams();
277 *has_length_bits = true;
278 *length_bits = params->lengthBits();
280 if (*length_bits == 128 || *length_bits == 256)
281 return Status::Success();
283 // BoringSSL does not support 192-bit AES.
284 if (*length_bits == 192)
285 return Status::ErrorAes192BitUnsupported();
287 return Status::ErrorGetAesKeyLength();
290 Status GetHmacKeyLength(const blink::WebCryptoAlgorithm& key_length_algorithm,
291 bool* has_length_bits,
292 unsigned int* length_bits) {
293 const blink::WebCryptoHmacImportParams* params =
294 key_length_algorithm.hmacImportParams();
296 if (params->hasLengthBits()) {
297 *has_length_bits = true;
298 *length_bits = params->optionalLengthBits();
299 if (*length_bits == 0)
300 return Status::ErrorGetHmacKeyLengthZero();
301 return Status::Success();
304 *has_length_bits = true;
305 return GetShaBlockSizeBits(params->hash(), length_bits);
308 Status GetUsagesForGenerateAsymmetricKey(
309 blink::WebCryptoKeyUsageMask combined_usages,
310 blink::WebCryptoKeyUsageMask all_public_usages,
311 blink::WebCryptoKeyUsageMask all_private_usages,
312 blink::WebCryptoKeyUsageMask* public_usages,
313 blink::WebCryptoKeyUsageMask* private_usages) {
314 Status status = CheckKeyCreationUsages(all_public_usages | all_private_usages,
315 combined_usages, true);
316 if (status.IsError())
317 return status;
319 *public_usages = combined_usages & all_public_usages;
320 *private_usages = combined_usages & all_private_usages;
322 if (*private_usages == 0)
323 return Status::ErrorCreateKeyEmptyUsages();
325 return Status::Success();
328 } // namespace webcrypto