Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(411)

Side by Side Diff: content/renderer/webcrypto/shared_crypto.cc

Issue 155623005: Refactor to share more code between OpenSSL and NSS implementations. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: address sleevi comments (except for explicit ctor) Created 6 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 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.
4
5 #include "content/renderer/webcrypto/shared_crypto.h"
6
7 #include "base/logging.h"
8 #include "content/renderer/webcrypto/crypto_data.h"
9 #include "content/renderer/webcrypto/platform_crypto.h"
10 #include "content/renderer/webcrypto/webcrypto_util.h"
11 #include "crypto/secure_util.h"
12 #include "third_party/WebKit/public/platform/WebCryptoAlgorithm.h"
13 #include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h"
14 #include "third_party/WebKit/public/platform/WebCryptoKey.h"
15
16 namespace content {
17
18 namespace webcrypto {
19
20 namespace {
21
22 // TODO(eroman): Move this helper to WebCryptoKey.
23 bool KeyUsageAllows(const blink::WebCryptoKey& key,
24 const blink::WebCryptoKeyUsage usage) {
25 return ((key.usages() & usage) != 0);
26 }
27
28 const size_t kAesBlockSizeBytes = 16;
29
30 Status EncryptAesCbc(const blink::WebCryptoAlgorithm& algorithm,
31 const blink::WebCryptoKey& key,
32 const CryptoData& data,
33 blink::WebArrayBuffer* buffer) {
34 platform::SymKey* sym_key = platform::ToSymKey(key);
35 if (!sym_key)
36 return Status::ErrorUnexpectedKeyType();
37
38 const blink::WebCryptoAesCbcParams* params = algorithm.aesCbcParams();
39 if (!params)
40 return Status::ErrorUnexpected();
41
42 CryptoData iv(params->iv().data(), params->iv().size());
43 if (iv.byte_length() != kAesBlockSizeBytes)
44 return Status::ErrorIncorrectSizeAesCbcIv();
45
46 return platform::EncryptAesCbc(sym_key, iv, data, buffer);
47 }
48
49 Status DecryptAesCbc(const blink::WebCryptoAlgorithm& algorithm,
50 const blink::WebCryptoKey& key,
51 const CryptoData& data,
52 blink::WebArrayBuffer* buffer) {
53 platform::SymKey* sym_key = platform::ToSymKey(key);
54 if (!sym_key)
55 return Status::ErrorUnexpectedKeyType();
56
57 const blink::WebCryptoAesCbcParams* params = algorithm.aesCbcParams();
58 if (!params)
59 return Status::ErrorUnexpected();
60
61 CryptoData iv(params->iv().data(), params->iv().size());
62 if (iv.byte_length() != kAesBlockSizeBytes)
63 return Status::ErrorIncorrectSizeAesCbcIv();
64
65 return platform::DecryptAesCbc(sym_key, iv, data, buffer);
66 }
67
68 Status EncryptAesGcm(const blink::WebCryptoAlgorithm& algorithm,
69 const blink::WebCryptoKey& key,
70 const CryptoData& data,
71 blink::WebArrayBuffer* buffer) {
72 platform::SymKey* sym_key = platform::ToSymKey(key);
73 if (!sym_key)
74 return Status::ErrorUnexpectedKeyType();
75
76 const blink::WebCryptoAesGcmParams* params = algorithm.aesGcmParams();
77 if (!params)
78 return Status::ErrorUnexpected();
79
80 return platform::EncryptAesGcm(sym_key, params, data, buffer);
81 }
82
83 Status DecryptAesGcm(const blink::WebCryptoAlgorithm& algorithm,
84 const blink::WebCryptoKey& key,
85 const CryptoData& data,
86 blink::WebArrayBuffer* buffer) {
87 platform::SymKey* sym_key = platform::ToSymKey(key);
88 if (!sym_key)
89 return Status::ErrorUnexpectedKeyType();
90
91 const blink::WebCryptoAesGcmParams* params = algorithm.aesGcmParams();
92 if (!params)
93 return Status::ErrorUnexpected();
94
95 return platform::DecryptAesGcm(sym_key, params, data, buffer);
96 }
97
98 Status EncryptRsaEsPkcs1v1_5(const blink::WebCryptoAlgorithm& algorithm,
99 const blink::WebCryptoKey& key,
100 const CryptoData& data,
101 blink::WebArrayBuffer* buffer) {
102 platform::PublicKey* public_key = platform::ToPublicKey(key);
103 if (!public_key)
104 return Status::ErrorUnexpectedKeyType();
105
106 // RSAES encryption does not support empty input
107 if (!data.byte_length())
108 return Status::Error();
109
110 return platform::EncryptRsaEsPkcs1v1_5(public_key, data, buffer);
111 }
112
113 Status DecryptRsaEsPkcs1v1_5(const blink::WebCryptoAlgorithm& algorithm,
114 const blink::WebCryptoKey& key,
115 const CryptoData& data,
116 blink::WebArrayBuffer* buffer) {
117 platform::PrivateKey* private_key = platform::ToPrivateKey(key);
118 if (!private_key)
119 return Status::ErrorUnexpectedKeyType();
120
121 // RSAES decryption does not support empty input
122 if (!data.byte_length())
123 return Status::Error();
124
125 return platform::DecryptRsaEsPkcs1v1_5(private_key, data, buffer);
126 }
127
128 Status SignHmac(const blink::WebCryptoAlgorithm& algorithm,
129 const blink::WebCryptoKey& key,
130 const CryptoData& data,
131 blink::WebArrayBuffer* buffer) {
132 platform::SymKey* sym_key = platform::ToSymKey(key);
133 if (!sym_key)
134 return Status::ErrorUnexpectedKeyType();
135
136 const blink::WebCryptoHmacParams* params = algorithm.hmacParams();
137 if (!params)
138 return Status::ErrorUnexpected();
139
140 if (!IsHashAlgorithm(params->hash().id()))
141 return Status::ErrorUnexpected();
142
143 if (params->hash().id() != GetInnerHashAlgorithm(key.algorithm()).id())
144 return Status::ErrorKeyAlgorithmMismatch();
145
146 return platform::SignHmac(sym_key, params->hash(), data, buffer);
147 }
148
149 Status VerifyHmac(const blink::WebCryptoAlgorithm& algorithm,
150 const blink::WebCryptoKey& key,
151 const CryptoData& signature,
152 const CryptoData& data,
153 bool* signature_match) {
154 blink::WebArrayBuffer result;
155 Status status = SignHmac(algorithm, key, data, &result);
156 if (status.IsError())
157 return status;
158
159 // Do not allow verification of truncated signatures.
160 *signature_match =
161 result.byteLength() == signature.byte_length() &&
162 crypto::SecureMemEqual(
163 result.data(), signature.bytes(), signature.byte_length());
164
165 return Status::Success();
166 }
167
168 Status SignRsaSsaPkcs1v1_5(const blink::WebCryptoAlgorithm& algorithm,
169 const blink::WebCryptoKey& key,
170 const CryptoData& data,
171 blink::WebArrayBuffer* buffer) {
172 platform::PrivateKey* private_key = platform::ToPrivateKey(key);
173 if (!private_key)
174 return Status::ErrorUnexpectedKeyType();
175
176 const blink::WebCryptoRsaSsaParams* params = algorithm.rsaSsaParams();
177 if (!params)
178 return Status::ErrorUnexpected();
179
180 if (!IsHashAlgorithm(params->hash().id()))
181 return Status::ErrorUnexpected();
182
183 // TODO(eroman): Verify the key has not been used with any other hash.
184
185 return platform::SignRsaSsaPkcs1v1_5(
186 private_key, params->hash(), data, buffer);
187 }
188
189 Status VerifyRsaSsaPkcs1v1_5(const blink::WebCryptoAlgorithm& algorithm,
190 const blink::WebCryptoKey& key,
191 const CryptoData& signature,
192 const CryptoData& data,
193 bool* signature_match) {
194 platform::PublicKey* public_key = platform::ToPublicKey(key);
195 if (!public_key)
196 return Status::ErrorUnexpectedKeyType();
197
198 const blink::WebCryptoRsaSsaParams* params = algorithm.rsaSsaParams();
199 if (!params)
200 return Status::ErrorUnexpected();
201
202 if (!IsHashAlgorithm(params->hash().id()))
203 return Status::ErrorUnexpected();
204
205 // TODO(eroman): Verify the key has not been used with any other hash.
206
207 return platform::VerifyRsaSsaPkcs1v1_5(
208 public_key, params->hash(), signature, data, signature_match);
209 }
210
211 Status ImportKeyRaw(const CryptoData& key_data,
212 const blink::WebCryptoAlgorithm& algorithm_or_null,
213 bool extractable,
214 blink::WebCryptoKeyUsageMask usage_mask,
215 blink::WebCryptoKey* key) {
216 if (algorithm_or_null.isNull())
217 return Status::ErrorMissingAlgorithmImportRawKey();
218
219 switch (algorithm_or_null.id()) {
220 case blink::WebCryptoAlgorithmIdAesCbc:
221 if (key_data.byte_length() != 16 && key_data.byte_length() != 24 &&
222 key_data.byte_length() != 32) {
223 return Status::Error();
224 }
225 // Fallthrough intentional!
226 case blink::WebCryptoAlgorithmIdHmac:
227 case blink::WebCryptoAlgorithmIdAesKw:
228 case blink::WebCryptoAlgorithmIdAesGcm:
229 return platform::ImportKeyRaw(
230 key_data, algorithm_or_null, extractable, usage_mask, key);
231
232 default:
233 return Status::ErrorUnsupported();
234 }
235 }
236
237 } // namespace
238
239 void Init() {
240 platform::Init();
241 }
242
243 Status Encrypt(const blink::WebCryptoAlgorithm& algorithm,
244 const blink::WebCryptoKey& key,
245 const CryptoData& data,
246 blink::WebArrayBuffer* buffer) {
247 if (!KeyUsageAllows(key, blink::WebCryptoKeyUsageEncrypt))
248 return Status::ErrorUnexpected();
249 if (algorithm.id() != key.algorithm().id())
250 return Status::ErrorKeyAlgorithmMismatch();
251
252 switch (algorithm.id()) {
253 case blink::WebCryptoAlgorithmIdAesCbc:
254 return EncryptAesCbc(algorithm, key, data, buffer);
255 case blink::WebCryptoAlgorithmIdAesGcm:
256 return EncryptAesGcm(algorithm, key, data, buffer);
257 case blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5:
258 return EncryptRsaEsPkcs1v1_5(algorithm, key, data, buffer);
259 default:
260 return Status::ErrorUnsupported();
261 }
262 }
263
264 Status Decrypt(const blink::WebCryptoAlgorithm& algorithm,
265 const blink::WebCryptoKey& key,
266 const CryptoData& data,
267 blink::WebArrayBuffer* buffer) {
268 if (!KeyUsageAllows(key, blink::WebCryptoKeyUsageDecrypt))
269 return Status::ErrorUnexpected();
270 if (algorithm.id() != key.algorithm().id())
271 return Status::ErrorKeyAlgorithmMismatch();
272
273 switch (algorithm.id()) {
274 case blink::WebCryptoAlgorithmIdAesCbc:
275 return DecryptAesCbc(algorithm, key, data, buffer);
276 case blink::WebCryptoAlgorithmIdAesGcm:
277 return DecryptAesGcm(algorithm, key, data, buffer);
278 case blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5:
279 return DecryptRsaEsPkcs1v1_5(algorithm, key, data, buffer);
280 default:
281 return Status::ErrorUnsupported();
282 }
283 }
284
285 Status Digest(const blink::WebCryptoAlgorithm& algorithm,
286 const CryptoData& data,
287 blink::WebArrayBuffer* buffer) {
288 switch (algorithm.id()) {
289 case blink::WebCryptoAlgorithmIdSha1:
290 case blink::WebCryptoAlgorithmIdSha224:
291 case blink::WebCryptoAlgorithmIdSha256:
292 case blink::WebCryptoAlgorithmIdSha384:
293 case blink::WebCryptoAlgorithmIdSha512:
294 return platform::DigestSha(algorithm.id(), data, buffer);
295 default:
296 return Status::ErrorUnsupported();
297 }
298 }
299
300 Status GenerateSecretKey(const blink::WebCryptoAlgorithm& algorithm,
301 bool extractable,
302 blink::WebCryptoKeyUsageMask usage_mask,
303 blink::WebCryptoKey* key) {
304 unsigned int keylen_bytes = 0;
305
306 // Get the secret key length in bytes from generation parameters.
307 // This resolves any defaults.
308 switch (algorithm.id()) {
309 case blink::WebCryptoAlgorithmIdAesCbc:
310 case blink::WebCryptoAlgorithmIdAesGcm:
311 case blink::WebCryptoAlgorithmIdAesKw: {
312 if ((algorithm.aesKeyGenParams()->lengthBits() % 8) != 0)
313 return Status::ErrorGenerateKeyLength();
314 keylen_bytes = algorithm.aesKeyGenParams()->lengthBits() / 8;
315 break;
316 }
317 case blink::WebCryptoAlgorithmIdHmac: {
318 const blink::WebCryptoHmacKeyParams* params = algorithm.hmacKeyParams();
319 DCHECK(params);
320 if (params->hasLengthBytes()) {
321 keylen_bytes = params->optionalLengthBytes();
322 } else {
323 keylen_bytes = ShaBlockSizeBytes(params->hash().id());
324 if (keylen_bytes == 0)
325 return Status::ErrorUnsupported();
326 }
327 break;
328 }
329
330 default:
331 return Status::ErrorUnsupported();
332 }
333
334 // TODO(eroman): Is this correct? HMAC can import zero-length keys, so should
335 // probably be able to allowed to generate them too.
336 if (keylen_bytes == 0)
337 return Status::ErrorGenerateKeyLength();
338
339 return platform::GenerateSecretKey(
340 algorithm, extractable, usage_mask, keylen_bytes, key);
341 }
342
343 Status GenerateKeyPair(const blink::WebCryptoAlgorithm& algorithm,
344 bool extractable,
345 blink::WebCryptoKeyUsageMask usage_mask,
346 blink::WebCryptoKey* public_key,
347 blink::WebCryptoKey* private_key) {
348 // TODO(padolph): Handle other asymmetric algorithm key generation.
349 switch (algorithm.id()) {
350 case blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5:
351 case blink::WebCryptoAlgorithmIdRsaOaep:
352 case blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5:
353 if (!algorithm.rsaKeyGenParams())
354 return Status::ErrorUnexpected();
355 return platform::GenerateRsaKeyPair(
356 algorithm, extractable, usage_mask, public_key, private_key);
357 default:
358 return Status::ErrorUnsupported();
359 }
360 }
361
362 Status ImportKey(blink::WebCryptoKeyFormat format,
363 const CryptoData& key_data,
364 const blink::WebCryptoAlgorithm& algorithm_or_null,
365 bool extractable,
366 blink::WebCryptoKeyUsageMask usage_mask,
367 blink::WebCryptoKey* key) {
368 switch (format) {
369 case blink::WebCryptoKeyFormatRaw:
370 return ImportKeyRaw(
371 key_data, algorithm_or_null, extractable, usage_mask, key);
372 return platform::ImportKeyRaw(
373 key_data, algorithm_or_null, extractable, usage_mask, key);
374 case blink::WebCryptoKeyFormatSpki:
375 return platform::ImportKeySpki(
376 key_data, algorithm_or_null, extractable, usage_mask, key);
377 case blink::WebCryptoKeyFormatPkcs8:
378 return platform::ImportKeyPkcs8(
379 key_data, algorithm_or_null, extractable, usage_mask, key);
380 case blink::WebCryptoKeyFormatJwk:
381 return ImportKeyJwk(
382 key_data, algorithm_or_null, extractable, usage_mask, key);
383 default:
384 return Status::ErrorUnsupported();
385 }
386 }
387
388 Status ExportKey(blink::WebCryptoKeyFormat format,
389 const blink::WebCryptoKey& key,
390 blink::WebArrayBuffer* buffer) {
391 if (!key.extractable())
392 return Status::ErrorKeyNotExtractable();
393
394 switch (format) {
395 case blink::WebCryptoKeyFormatRaw: {
396 platform::SymKey* sym_key = platform::ToSymKey(key);
397 if (!sym_key)
398 return Status::ErrorUnexpectedKeyType();
399 return platform::ExportKeyRaw(sym_key, buffer);
400 }
401 case blink::WebCryptoKeyFormatSpki: {
402 platform::PublicKey* public_key = platform::ToPublicKey(key);
403 if (!public_key)
404 return Status::ErrorUnexpectedKeyType();
405 return platform::ExportKeySpki(public_key, buffer);
406 }
407 case blink::WebCryptoKeyFormatPkcs8:
408 case blink::WebCryptoKeyFormatJwk:
409 // TODO(eroman):
410 return Status::ErrorUnsupported();
411 default:
412 return Status::ErrorUnsupported();
413 }
414 }
415
416 Status Sign(const blink::WebCryptoAlgorithm& algorithm,
417 const blink::WebCryptoKey& key,
418 const CryptoData& data,
419 blink::WebArrayBuffer* buffer) {
420 if (!KeyUsageAllows(key, blink::WebCryptoKeyUsageSign))
421 return Status::ErrorUnexpected();
422 if (algorithm.id() != key.algorithm().id())
423 return Status::ErrorKeyAlgorithmMismatch();
424
425 switch (algorithm.id()) {
426 case blink::WebCryptoAlgorithmIdHmac:
427 return SignHmac(algorithm, key, data, buffer);
428 case blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5:
429 return SignRsaSsaPkcs1v1_5(algorithm, key, data, buffer);
430 default:
431 return Status::ErrorUnsupported();
432 }
433 }
434
435 Status VerifySignature(const blink::WebCryptoAlgorithm& algorithm,
436 const blink::WebCryptoKey& key,
437 const CryptoData& signature,
438 const CryptoData& data,
439 bool* signature_match) {
440 if (!KeyUsageAllows(key, blink::WebCryptoKeyUsageVerify))
441 return Status::ErrorUnexpected();
442 if (algorithm.id() != key.algorithm().id())
443 return Status::ErrorKeyAlgorithmMismatch();
444
445 if (!signature.byte_length()) {
446 // None of the algorithms generate valid zero-length signatures so this
447 // will necessarily fail verification. Early return to protect
448 // implementations from dealing with a NULL signature pointer.
449 *signature_match = false;
450 return Status::Success();
451 }
452
453 switch (algorithm.id()) {
454 case blink::WebCryptoAlgorithmIdHmac:
455 return VerifyHmac(algorithm, key, signature, data, signature_match);
456 case blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5:
457 return VerifyRsaSsaPkcs1v1_5(
458 algorithm, key, signature, data, signature_match);
459 default:
460 return Status::ErrorUnsupported();
461 }
462 }
463
464 } // namespace webcrypto
465 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698