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 "content/child/webcrypto/webcrypto_util.h"
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"
20 // Converts a (big-endian) WebCrypto BigInteger, with or without leading zeros,
22 bool BigIntegerToUint(const uint8_t* data
,
23 unsigned int data_size
,
24 unsigned int* result
) {
29 for (size_t i
= 0; i
< data_size
; ++i
) {
30 size_t reverse_i
= data_size
- i
- 1;
32 if (reverse_i
>= sizeof(*result
) && data
[i
])
33 return false; // Too large for a uint.
35 *result
|= data
[i
] << 8 * reverse_i
;
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();
52 return Status::ErrorUnsupported();
58 blink::WebCryptoAlgorithm
CreateAlgorithm(blink::WebCryptoAlgorithmId id
) {
59 return blink::WebCryptoAlgorithm::adoptParamsAndCreate(id
, NULL
);
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,
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));
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
)));
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
));
95 bool ContainsKeyUsages(blink::WebCryptoKeyUsageMask a
,
96 blink::WebCryptoKeyUsageMask b
) {
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);
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();
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();
120 return Status::Success();
123 Status
GetAesKeyGenLengthInBits(const blink::WebCryptoAesKeyGenParams
* params
,
124 unsigned int* keylen_bits
) {
125 *keylen_bits
= params
->lengthBits();
127 if (*keylen_bits
== 128 || *keylen_bits
== 256)
128 return Status::Success();
130 // BoringSSL does not support 192-bit AES.
131 if (*keylen_bits
== 192)
132 return Status::ErrorAes192BitUnsupported();
134 return Status::ErrorGenerateAesKeyLength();
137 Status
GetHmacKeyGenLengthInBits(const blink::WebCryptoHmacKeyGenParams
* params
,
138 unsigned int* keylen_bits
) {
139 if (!params
->hasLengthBits())
140 return GetShaBlockSizeBits(params
->hash(), keylen_bits
);
142 *keylen_bits
= params
->optionalLengthBits();
144 // Zero-length HMAC keys are disallowed by the spec.
145 if (*keylen_bits
== 0)
146 return Status::ErrorGenerateHmacKeyLengthZero();
148 return Status::Success();
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();
158 // Make sure that the key data's length can be represented in bits without
160 base::CheckedNumeric
<unsigned int> checked_keylen_bits(key_data_byte_length
);
161 checked_keylen_bits
*= 8;
163 if (!checked_keylen_bits
.IsValid())
164 return Status::ErrorDataTooLarge();
166 unsigned int data_keylen_bits
= checked_keylen_bits
.ValueOrDie();
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();
179 return Status::Success();
182 Status
VerifyAesKeyLengthForImport(unsigned int keylen_bytes
) {
183 if (keylen_bytes
== 16 || keylen_bytes
== 32)
184 return Status::Success();
186 // BoringSSL does not support 192-bit AES.
187 if (keylen_bytes
== 24)
188 return Status::ErrorAes192BitUnsupported();
190 return Status::ErrorImportAesKeyLength();
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();
199 if (!ContainsKeyUsages(all_possible_usages
, actual_usages
))
200 return Status::ErrorCreateKeyBadUsages();
201 return Status::Success();
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();
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();
218 if (!BigIntegerToUint(params
->publicExponent().data(),
219 params
->publicExponent().size(), public_exponent
)) {
220 return Status::ErrorGenerateKeyPublicExponent();
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();
228 return Status::Success();
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
) {
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();
251 return Status::Success();
254 return Status::ErrorUnsupportedImportKeyFormat();
258 void TruncateToBitLength(size_t length_bits
, std::vector
<uint8_t>* bytes
) {
259 size_t length_bytes
= NumBitsToBytes(length_bits
);
261 if (bytes
->size() != length_bytes
) {
262 CHECK_LT(length_bytes
, bytes
->size());
263 bytes
->resize(length_bytes
);
266 size_t remainder_bits
= length_bits
% 8;
268 // Zero any "unused bits" in the final byte
270 (*bytes
)[bytes
->size() - 1] &= ~((0xFF) >> remainder_bits
);
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();
279 *has_length_bits
= true;
280 *length_bits
= params
->lengthBits();
282 if (*length_bits
== 128 || *length_bits
== 256)
283 return Status::Success();
285 // BoringSSL does not support 192-bit AES.
286 if (*length_bits
== 192)
287 return Status::ErrorAes192BitUnsupported();
289 return Status::ErrorGetAesKeyLength();
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();
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();
306 *has_length_bits
= true;
307 return GetShaBlockSizeBits(params
->hash(), length_bits
);
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())
321 *public_usages
= combined_usages
& all_public_usages
;
322 *private_usages
= combined_usages
& all_private_usages
;
324 if (*private_usages
== 0)
325 return Status::ErrorCreateKeyEmptyUsages();
327 return Status::Success();
330 } // namespace webcrypto
332 } // namespace content