Standardize usage of virtual/override/final in content/
[chromium-blink-merge.git] / content / child / webcrypto / webcrypto_util.cc
blob6ea78f2f5e466078ee10f4e0e3784f1227a26a2f
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"
14 namespace content {
16 namespace webcrypto {
18 namespace {
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;
28 *result = 0;
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;
37 return true;
40 } // namespace
42 struct JwkToWebCryptoUsage {
43 const char* const jwk_key_op;
44 const blink::WebCryptoKeyUsage webcrypto_usage;
47 // Keep this ordered according to the definition
48 // order of WebCrypto's "recognized key usage
49 // values".
51 // This is not required for spec compliance,
52 // however it makes the ordering of key_ops match
53 // that of WebCrypto's Key.usages.
54 const JwkToWebCryptoUsage kJwkWebCryptoUsageMap[] = {
55 {"encrypt", blink::WebCryptoKeyUsageEncrypt},
56 {"decrypt", blink::WebCryptoKeyUsageDecrypt},
57 {"sign", blink::WebCryptoKeyUsageSign},
58 {"verify", blink::WebCryptoKeyUsageVerify},
59 {"deriveKey", blink::WebCryptoKeyUsageDeriveKey},
60 {"deriveBits", blink::WebCryptoKeyUsageDeriveBits},
61 {"wrapKey", blink::WebCryptoKeyUsageWrapKey},
62 {"unwrapKey", blink::WebCryptoKeyUsageUnwrapKey}};
64 // Modifies the input usage_mask by according to the key_op value.
65 bool JwkKeyOpToWebCryptoUsage(const std::string& key_op,
66 blink::WebCryptoKeyUsageMask* usage_mask) {
67 for (size_t i = 0; i < arraysize(kJwkWebCryptoUsageMap); ++i) {
68 if (kJwkWebCryptoUsageMap[i].jwk_key_op == key_op) {
69 *usage_mask |= kJwkWebCryptoUsageMap[i].webcrypto_usage;
70 return true;
73 return false;
76 // Composes a Web Crypto usage mask from an array of JWK key_ops values.
77 Status GetWebCryptoUsagesFromJwkKeyOps(
78 const base::ListValue* jwk_key_ops_value,
79 blink::WebCryptoKeyUsageMask* usage_mask) {
80 *usage_mask = 0;
81 for (size_t i = 0; i < jwk_key_ops_value->GetSize(); ++i) {
82 std::string key_op;
83 if (!jwk_key_ops_value->GetString(i, &key_op)) {
84 return Status::ErrorJwkPropertyWrongType(
85 base::StringPrintf("key_ops[%d]", static_cast<int>(i)), "string");
87 // Unrecognized key_ops are silently skipped.
88 ignore_result(JwkKeyOpToWebCryptoUsage(key_op, usage_mask));
90 return Status::Success();
93 // Composes a JWK key_ops List from a Web Crypto usage mask.
94 // Note: Caller must assume ownership of returned instance.
95 base::ListValue* CreateJwkKeyOpsFromWebCryptoUsages(
96 blink::WebCryptoKeyUsageMask usage_mask) {
97 base::ListValue* jwk_key_ops = new base::ListValue();
98 for (size_t i = 0; i < arraysize(kJwkWebCryptoUsageMap); ++i) {
99 if (usage_mask & kJwkWebCryptoUsageMap[i].webcrypto_usage)
100 jwk_key_ops->AppendString(kJwkWebCryptoUsageMap[i].jwk_key_op);
102 return jwk_key_ops;
105 blink::WebCryptoAlgorithm CreateAlgorithm(blink::WebCryptoAlgorithmId id) {
106 return blink::WebCryptoAlgorithm::adoptParamsAndCreate(id, NULL);
109 blink::WebCryptoAlgorithm CreateHmacImportAlgorithm(
110 blink::WebCryptoAlgorithmId hash_id) {
111 DCHECK(blink::WebCryptoAlgorithm::isHash(hash_id));
112 return blink::WebCryptoAlgorithm::adoptParamsAndCreate(
113 blink::WebCryptoAlgorithmIdHmac,
114 new blink::WebCryptoHmacImportParams(CreateAlgorithm(hash_id)));
117 blink::WebCryptoAlgorithm CreateRsaHashedImportAlgorithm(
118 blink::WebCryptoAlgorithmId id,
119 blink::WebCryptoAlgorithmId hash_id) {
120 DCHECK(blink::WebCryptoAlgorithm::isHash(hash_id));
121 return blink::WebCryptoAlgorithm::adoptParamsAndCreate(
122 id, new blink::WebCryptoRsaHashedImportParams(CreateAlgorithm(hash_id)));
125 bool ContainsKeyUsages(blink::WebCryptoKeyUsageMask a,
126 blink::WebCryptoKeyUsageMask b) {
127 return (a & b) == b;
130 // TODO(eroman): Move this helper to WebCryptoKey.
131 bool KeyUsageAllows(const blink::WebCryptoKey& key,
132 const blink::WebCryptoKeyUsage usage) {
133 return ((key.usages() & usage) != 0);
136 bool IsAlgorithmRsa(blink::WebCryptoAlgorithmId alg_id) {
137 return alg_id == blink::WebCryptoAlgorithmIdRsaOaep ||
138 alg_id == blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5 ||
139 alg_id == blink::WebCryptoAlgorithmIdRsaPss;
142 // The WebCrypto spec defines the default value for the tag length, as well as
143 // the allowed values for tag length.
144 Status GetAesGcmTagLengthInBits(const blink::WebCryptoAesGcmParams* params,
145 unsigned int* tag_length_bits) {
146 *tag_length_bits = 128;
147 if (params->hasTagLengthBits())
148 *tag_length_bits = params->optionalTagLengthBits();
150 if (*tag_length_bits != 32 && *tag_length_bits != 64 &&
151 *tag_length_bits != 96 && *tag_length_bits != 104 &&
152 *tag_length_bits != 112 && *tag_length_bits != 120 &&
153 *tag_length_bits != 128)
154 return Status::ErrorInvalidAesGcmTagLength();
156 return Status::Success();
159 Status GetAesKeyGenLengthInBits(const blink::WebCryptoAesKeyGenParams* params,
160 unsigned int* keylen_bits) {
161 *keylen_bits = params->lengthBits();
163 if (*keylen_bits == 128 || *keylen_bits == 256)
164 return Status::Success();
166 // BoringSSL does not support 192-bit AES.
167 if (*keylen_bits == 192)
168 return Status::ErrorAes192BitUnsupported();
170 return Status::ErrorGenerateKeyLength();
173 Status GetHmacKeyGenLengthInBits(const blink::WebCryptoHmacKeyGenParams* params,
174 unsigned int* keylen_bits) {
175 if (!params->hasLengthBits()) {
176 switch (params->hash().id()) {
177 case blink::WebCryptoAlgorithmIdSha1:
178 case blink::WebCryptoAlgorithmIdSha256:
179 *keylen_bits = 512;
180 return Status::Success();
181 case blink::WebCryptoAlgorithmIdSha384:
182 case blink::WebCryptoAlgorithmIdSha512:
183 *keylen_bits = 1024;
184 return Status::Success();
185 default:
186 return Status::ErrorUnsupported();
190 if (params->optionalLengthBits() % 8)
191 return Status::ErrorGenerateKeyLength();
193 *keylen_bits = params->optionalLengthBits();
195 // TODO(eroman): NSS fails when generating a zero-length secret key.
196 if (*keylen_bits == 0)
197 return Status::ErrorGenerateKeyLength();
199 return Status::Success();
202 Status VerifyAesKeyLengthForImport(unsigned int keylen_bytes) {
203 if (keylen_bytes == 16 || keylen_bytes == 32)
204 return Status::Success();
206 // BoringSSL does not support 192-bit AES.
207 if (keylen_bytes == 24)
208 return Status::ErrorAes192BitUnsupported();
210 return Status::ErrorImportAesKeyLength();
213 Status CheckKeyCreationUsages(blink::WebCryptoKeyUsageMask all_possible_usages,
214 blink::WebCryptoKeyUsageMask actual_usages) {
215 if (!ContainsKeyUsages(all_possible_usages, actual_usages))
216 return Status::ErrorCreateKeyBadUsages();
217 return Status::Success();
220 Status GetRsaKeyGenParameters(
221 const blink::WebCryptoRsaHashedKeyGenParams* params,
222 unsigned int* public_exponent,
223 unsigned int* modulus_length_bits) {
224 *modulus_length_bits = params->modulusLengthBits();
226 // Limit key sizes to those supported by NSS:
227 // * Multiple of 8 bits
228 // * 256 bits to 16K bits
229 if (*modulus_length_bits < 256 || *modulus_length_bits > 16384 ||
230 (*modulus_length_bits % 8) != 0) {
231 return Status::ErrorGenerateRsaUnsupportedModulus();
234 if (!BigIntegerToUint(params->publicExponent().data(),
235 params->publicExponent().size(),
236 public_exponent)) {
237 return Status::ErrorGenerateKeyPublicExponent();
240 // OpenSSL hangs when given bad public exponents, whereas NSS simply fails. To
241 // avoid feeding OpenSSL data that will hang use a whitelist.
242 if (*public_exponent != 3 && *public_exponent != 65537)
243 return Status::ErrorGenerateKeyPublicExponent();
245 return Status::Success();
248 } // namespace webcrypto
250 } // namespace content