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/strings/stringprintf.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
) {
25 // TODO(eroman): Fix handling of empty biginteger. http://crbug.com/373552
30 for (size_t i
= 0; i
< data_size
; ++i
) {
31 size_t reverse_i
= data_size
- i
- 1;
33 if (reverse_i
>= sizeof(*result
) && data
[i
])
34 return false; // Too large for a uint.
36 *result
|= data
[i
] << 8 * reverse_i
;
43 struct JwkToWebCryptoUsage
{
44 const char* const jwk_key_op
;
45 const blink::WebCryptoKeyUsage webcrypto_usage
;
48 // Keep this ordered according to the definition
49 // order of WebCrypto's "recognized key usage
52 // This is not required for spec compliance,
53 // however it makes the ordering of key_ops match
54 // that of WebCrypto's Key.usages.
55 const JwkToWebCryptoUsage kJwkWebCryptoUsageMap
[] = {
56 {"encrypt", blink::WebCryptoKeyUsageEncrypt
},
57 {"decrypt", blink::WebCryptoKeyUsageDecrypt
},
58 {"sign", blink::WebCryptoKeyUsageSign
},
59 {"verify", blink::WebCryptoKeyUsageVerify
},
60 {"deriveKey", blink::WebCryptoKeyUsageDeriveKey
},
61 {"deriveBits", blink::WebCryptoKeyUsageDeriveBits
},
62 {"wrapKey", blink::WebCryptoKeyUsageWrapKey
},
63 {"unwrapKey", blink::WebCryptoKeyUsageUnwrapKey
}};
65 // Modifies the input usage_mask by according to the key_op value.
66 bool JwkKeyOpToWebCryptoUsage(const std::string
& key_op
,
67 blink::WebCryptoKeyUsageMask
* usage_mask
) {
68 for (size_t i
= 0; i
< arraysize(kJwkWebCryptoUsageMap
); ++i
) {
69 if (kJwkWebCryptoUsageMap
[i
].jwk_key_op
== key_op
) {
70 *usage_mask
|= kJwkWebCryptoUsageMap
[i
].webcrypto_usage
;
77 // Composes a Web Crypto usage mask from an array of JWK key_ops values.
78 Status
GetWebCryptoUsagesFromJwkKeyOps(
79 const base::ListValue
* jwk_key_ops_value
,
80 blink::WebCryptoKeyUsageMask
* usage_mask
) {
82 for (size_t i
= 0; i
< jwk_key_ops_value
->GetSize(); ++i
) {
84 if (!jwk_key_ops_value
->GetString(i
, &key_op
)) {
85 return Status::ErrorJwkPropertyWrongType(
86 base::StringPrintf("key_ops[%d]", static_cast<int>(i
)), "string");
88 // Unrecognized key_ops are silently skipped.
89 ignore_result(JwkKeyOpToWebCryptoUsage(key_op
, usage_mask
));
91 return Status::Success();
94 // Composes a JWK key_ops List from a Web Crypto usage mask.
95 // Note: Caller must assume ownership of returned instance.
96 base::ListValue
* CreateJwkKeyOpsFromWebCryptoUsages(
97 blink::WebCryptoKeyUsageMask usage_mask
) {
98 base::ListValue
* jwk_key_ops
= new base::ListValue();
99 for (size_t i
= 0; i
< arraysize(kJwkWebCryptoUsageMap
); ++i
) {
100 if (usage_mask
& kJwkWebCryptoUsageMap
[i
].webcrypto_usage
)
101 jwk_key_ops
->AppendString(kJwkWebCryptoUsageMap
[i
].jwk_key_op
);
106 blink::WebCryptoAlgorithm
CreateAlgorithm(blink::WebCryptoAlgorithmId id
) {
107 return blink::WebCryptoAlgorithm::adoptParamsAndCreate(id
, NULL
);
110 blink::WebCryptoAlgorithm
CreateHmacImportAlgorithm(
111 blink::WebCryptoAlgorithmId hash_id
) {
112 DCHECK(blink::WebCryptoAlgorithm::isHash(hash_id
));
113 return blink::WebCryptoAlgorithm::adoptParamsAndCreate(
114 blink::WebCryptoAlgorithmIdHmac
,
115 new blink::WebCryptoHmacImportParams(CreateAlgorithm(hash_id
)));
118 blink::WebCryptoAlgorithm
CreateRsaHashedImportAlgorithm(
119 blink::WebCryptoAlgorithmId id
,
120 blink::WebCryptoAlgorithmId hash_id
) {
121 DCHECK(blink::WebCryptoAlgorithm::isHash(hash_id
));
122 DCHECK(id
== blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5
||
123 id
== blink::WebCryptoAlgorithmIdRsaOaep
);
124 return blink::WebCryptoAlgorithm::adoptParamsAndCreate(
125 id
, new blink::WebCryptoRsaHashedImportParams(CreateAlgorithm(hash_id
)));
128 bool ContainsKeyUsages(blink::WebCryptoKeyUsageMask a
,
129 blink::WebCryptoKeyUsageMask b
) {
133 // TODO(eroman): Move this helper to WebCryptoKey.
134 bool KeyUsageAllows(const blink::WebCryptoKey
& key
,
135 const blink::WebCryptoKeyUsage usage
) {
136 return ((key
.usages() & usage
) != 0);
139 bool IsAlgorithmRsa(blink::WebCryptoAlgorithmId alg_id
) {
140 return alg_id
== blink::WebCryptoAlgorithmIdRsaOaep
||
141 alg_id
== blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5
;
144 bool IsAlgorithmAsymmetric(blink::WebCryptoAlgorithmId alg_id
) {
145 // TODO(padolph): include all other asymmetric algorithms once they are
146 // defined, e.g. EC and DH.
147 return IsAlgorithmRsa(alg_id
);
150 // The WebCrypto spec defines the default value for the tag length, as well as
151 // the allowed values for tag length.
152 Status
GetAesGcmTagLengthInBits(const blink::WebCryptoAesGcmParams
* params
,
153 unsigned int* tag_length_bits
) {
154 *tag_length_bits
= 128;
155 if (params
->hasTagLengthBits())
156 *tag_length_bits
= params
->optionalTagLengthBits();
158 if (*tag_length_bits
!= 32 && *tag_length_bits
!= 64 &&
159 *tag_length_bits
!= 96 && *tag_length_bits
!= 104 &&
160 *tag_length_bits
!= 112 && *tag_length_bits
!= 120 &&
161 *tag_length_bits
!= 128)
162 return Status::ErrorInvalidAesGcmTagLength();
164 return Status::Success();
167 Status
GetAesKeyGenLengthInBits(const blink::WebCryptoAesKeyGenParams
* params
,
168 unsigned int* keylen_bits
) {
169 *keylen_bits
= params
->lengthBits();
171 if (*keylen_bits
== 128 || *keylen_bits
== 256)
172 return Status::Success();
174 // BoringSSL does not support 192-bit AES.
175 if (*keylen_bits
== 192)
176 return Status::ErrorAes192BitUnsupported();
178 return Status::ErrorGenerateKeyLength();
181 Status
GetHmacKeyGenLengthInBits(const blink::WebCryptoHmacKeyGenParams
* params
,
182 unsigned int* keylen_bits
) {
183 if (!params
->hasLengthBits()) {
184 switch (params
->hash().id()) {
185 case blink::WebCryptoAlgorithmIdSha1
:
186 case blink::WebCryptoAlgorithmIdSha256
:
188 return Status::Success();
189 case blink::WebCryptoAlgorithmIdSha384
:
190 case blink::WebCryptoAlgorithmIdSha512
:
192 return Status::Success();
194 return Status::ErrorUnsupported();
198 if (params
->optionalLengthBits() % 8)
199 return Status::ErrorGenerateKeyLength();
201 *keylen_bits
= params
->optionalLengthBits();
203 // TODO(eroman): NSS fails when generating a zero-length secret key.
204 if (*keylen_bits
== 0)
205 return Status::ErrorGenerateKeyLength();
207 return Status::Success();
210 Status
VerifyAesKeyLengthForImport(unsigned int keylen_bytes
) {
211 if (keylen_bytes
== 16 || keylen_bytes
== 32)
212 return Status::Success();
214 // BoringSSL does not support 192-bit AES.
215 if (keylen_bytes
== 24)
216 return Status::ErrorAes192BitUnsupported();
218 return Status::ErrorImportAesKeyLength();
221 Status
CheckKeyCreationUsages(blink::WebCryptoKeyUsageMask all_possible_usages
,
222 blink::WebCryptoKeyUsageMask actual_usages
) {
223 if (!ContainsKeyUsages(all_possible_usages
, actual_usages
))
224 return Status::ErrorCreateKeyBadUsages();
225 return Status::Success();
228 Status
GetRsaKeyGenParameters(
229 const blink::WebCryptoRsaHashedKeyGenParams
* params
,
230 unsigned int* public_exponent
,
231 unsigned int* modulus_length_bits
) {
232 *modulus_length_bits
= params
->modulusLengthBits();
234 // Limit key sizes to those supported by NSS:
235 // * Multiple of 8 bits
236 // * 256 bits to 16K bits
237 if (*modulus_length_bits
< 256 || *modulus_length_bits
> 16384 ||
238 (*modulus_length_bits
% 8) != 0) {
239 return Status::ErrorGenerateRsaUnsupportedModulus();
242 if (!BigIntegerToUint(params
->publicExponent().data(),
243 params
->publicExponent().size(),
245 return Status::ErrorGenerateKeyPublicExponent();
248 // OpenSSL hangs when given bad public exponents, whereas NSS simply fails. To
249 // avoid feeding OpenSSL data that will hang use a whitelist.
250 if (*public_exponent
!= 3 && *public_exponent
!= 65537)
251 return Status::ErrorGenerateKeyPublicExponent();
253 return Status::Success();
256 } // namespace webcrypto
258 } // namespace content