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

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

Powered by Google App Engine
This is Rietveld 408576698