Chromium Code Reviews| Index: content/child/webcrypto/shared_crypto.cc |
| diff --git a/content/child/webcrypto/shared_crypto.cc b/content/child/webcrypto/shared_crypto.cc |
| index b0097c1cad593c903258e167bf641a44c76f8aa1..7d54bdf26168614cdc5cdcf73f04fafcb58c6211 100644 |
| --- a/content/child/webcrypto/shared_crypto.cc |
| +++ b/content/child/webcrypto/shared_crypto.cc |
| @@ -26,6 +26,11 @@ bool KeyUsageAllows(const blink::WebCryptoKey& key, |
| return ((key.usages() & usage) != 0); |
| } |
| +bool KeyUsageAllowsAnyOf(const blink::WebCryptoKey& key, |
| + const blink::WebCryptoKeyUsageMask usage_mask) { |
| + return ((key.usages() & usage_mask) != 0); |
| +} |
| + |
| bool IsValidAesKeyLengthBits(unsigned int length_bits) { |
| return length_bits == 128 || length_bits == 192 || length_bits == 256; |
| } |
| @@ -233,6 +238,104 @@ Status ImportKeyRaw(const CryptoData& key_data, |
| } |
| } |
| +// Validates the size of data input to AES-KW. AES-KW requires the input data |
| +// size to be at least 24 bytes and a multiple of 8 bytes. |
| +Status CheckAesKwInputSize(const CryptoData& aeskw_input_data) { |
| + if (aeskw_input_data.byte_length() < 24) |
| + return Status::ErrorDataTooSmall(); |
| + if (aeskw_input_data.byte_length() % 8) |
| + return Status::ErrorInvalidAesKwDataLength(); |
| + return Status::Success(); |
| +} |
| + |
| +Status UnwrapKeyRaw(const CryptoData& wrapped_key_data, |
| + const blink::WebCryptoKey& wrapping_key, |
| + const blink::WebCryptoAlgorithm& wrapping_algorithm, |
| + const blink::WebCryptoAlgorithm& algorithm_or_null, |
| + bool extractable, |
| + blink::WebCryptoKeyUsageMask usage_mask, |
| + blink::WebCryptoKey* key) { |
| + // Must provide an algorithm when unwrapping a raw key |
| + if (algorithm_or_null.isNull()) |
| + return Status::ErrorMissingAlgorithmUnwrapRawKey(); |
| + |
| + // TODO(padolph): Handle other wrapping algorithms |
| + switch (wrapping_algorithm.id()) { |
| + case blink::WebCryptoAlgorithmIdAesKw: { |
| + platform::SymKey* platform_wrapping_key; |
| + Status status = ToPlatformSymKey(wrapping_key, &platform_wrapping_key); |
| + if (status.IsError()) |
| + return status; |
| + status = CheckAesKwInputSize(wrapped_key_data); |
| + if (status.IsError()) |
| + return status; |
| + return platform::UnwrapSymKeyAesKw(wrapped_key_data, |
| + platform_wrapping_key, |
| + algorithm_or_null, |
| + extractable, |
| + usage_mask, |
| + key); |
| + } |
| + case blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5: { |
| + platform::PrivateKey* platform_wrapping_key; |
| + Status status = |
| + ToPlatformPrivateKey(wrapping_key, &platform_wrapping_key); |
| + if (status.IsError()) |
| + return status; |
| + if (!wrapped_key_data.byte_length()) |
| + return Status::ErrorDataTooSmall(); |
| + return platform::UnwrapSymKeyRsaEs(wrapped_key_data, |
| + platform_wrapping_key, |
| + algorithm_or_null, |
| + extractable, |
| + usage_mask, |
| + key); |
| + } |
| + default: |
| + return Status::ErrorUnsupported(); |
| + } |
| +} |
| + |
| +Status UnwrapKeyDecryptAndImport( |
| + blink::WebCryptoKeyFormat format, |
| + const CryptoData& wrapped_key_data, |
| + const blink::WebCryptoKey& wrapping_key, |
| + const blink::WebCryptoAlgorithm& wrapping_algorithm, |
| + const blink::WebCryptoAlgorithm& algorithm_or_null, |
| + bool extractable, |
| + blink::WebCryptoKeyUsageMask usage_mask, |
| + blink::WebCryptoKey* key) { |
| + blink::WebArrayBuffer buffer; |
| + Status status = |
| + Decrypt(wrapping_algorithm, wrapping_key, wrapped_key_data, &buffer); |
| + if (status.IsError()) |
| + return status; |
| + status = ImportKey(format, |
| + CryptoData(buffer), |
| + algorithm_or_null, |
| + extractable, |
| + usage_mask, |
| + key); |
| + // NOTE! Returning the details of any ImportKey() failure here would leak |
| + // information about the plaintext internals of the encrypted key. Instead, |
| + // collapse any error into the generic Status::Error(). |
| + return status.IsError() ? Status::Error() : Status::Success(); |
| +} |
| + |
| +Status DecryptAesKw(const blink::WebCryptoAlgorithm& algorithm, |
| + const blink::WebCryptoKey& key, |
| + const CryptoData& data, |
| + blink::WebArrayBuffer* buffer) { |
| + platform::SymKey* sym_key; |
| + Status status = ToPlatformSymKey(key, &sym_key); |
| + if (status.IsError()) |
| + return status; |
| + status = CheckAesKwInputSize(data); |
| + if (status.IsError()) |
| + return status; |
| + return platform::DecryptAesKw(sym_key, data, buffer); |
| +} |
| + |
| } // namespace |
| void Init() { platform::Init(); } |
| @@ -262,18 +365,38 @@ Status Decrypt(const blink::WebCryptoAlgorithm& algorithm, |
| const blink::WebCryptoKey& key, |
| const CryptoData& data, |
| blink::WebArrayBuffer* buffer) { |
| - if (!KeyUsageAllows(key, blink::WebCryptoKeyUsageDecrypt)) |
| - return Status::ErrorUnexpected(); |
| if (algorithm.id() != key.algorithm().id()) |
| return Status::ErrorUnexpected(); |
| switch (algorithm.id()) { |
| case blink::WebCryptoAlgorithmIdAesCbc: |
| + case blink::WebCryptoAlgorithmIdAesGcm: |
| + if (!KeyUsageAllows(key, blink::WebCryptoKeyUsageDecrypt)) |
|
eroman
2014/03/17 19:47:47
I don't like having an extra switch for verifying
padolph
2014/03/17 22:12:49
Done.
|
| + return Status::ErrorUnexpected(); |
| + break; |
| + case blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5: |
| + if (!KeyUsageAllowsAnyOf(key, |
| + blink::WebCryptoKeyUsageDecrypt | |
| + blink::WebCryptoKeyUsageUnwrapKey)) |
| + return Status::ErrorUnexpected(); |
| + break; |
| + case blink::WebCryptoAlgorithmIdAesKw: |
| + if (!KeyUsageAllows(key, blink::WebCryptoKeyUsageUnwrapKey)) |
| + return Status::ErrorUnexpected(); |
| + break; |
| + default: |
| + return Status::ErrorUnsupported(); |
| + } |
| + |
| + switch (algorithm.id()) { |
| + case blink::WebCryptoAlgorithmIdAesCbc: |
| return EncryptDecryptAesCbc(DECRYPT, algorithm, key, data, buffer); |
| case blink::WebCryptoAlgorithmIdAesGcm: |
| return EncryptDecryptAesGcm(DECRYPT, algorithm, key, data, buffer); |
| case blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5: |
| return DecryptRsaEsPkcs1v1_5(algorithm, key, data, buffer); |
| + case blink::WebCryptoAlgorithmIdAesKw: |
| + return DecryptAesKw(algorithm, key, data, buffer); |
| default: |
| return Status::ErrorUnsupported(); |
| } |
| @@ -424,8 +547,9 @@ Status ExportKey(blink::WebCryptoKeyFormat format, |
| return status; |
| return platform::ExportKeySpki(public_key, buffer); |
| } |
| - case blink::WebCryptoKeyFormatPkcs8: |
| case blink::WebCryptoKeyFormatJwk: |
| + return ExportKeyJwk(key, buffer); |
| + case blink::WebCryptoKeyFormatPkcs8: |
| // TODO(eroman): |
| return Status::ErrorUnsupported(); |
| default: |
| @@ -539,50 +663,29 @@ Status UnwrapKey(blink::WebCryptoKeyFormat format, |
| if (wrapping_algorithm.id() != wrapping_key.algorithm().id()) |
| return Status::ErrorUnexpected(); |
| - // TODO(padolph): Handle formats other than raw |
| - if (format != blink::WebCryptoKeyFormatRaw) |
| - return Status::ErrorUnsupported(); |
| - |
| - // Must provide an algorithm when unwrapping a raw key |
| - if (format == blink::WebCryptoKeyFormatRaw && algorithm_or_null.isNull()) |
| - return Status::ErrorMissingAlgorithmUnwrapRawKey(); |
| - |
| - // TODO(padolph): Handle other wrapping algorithms |
| - switch (wrapping_algorithm.id()) { |
| - case blink::WebCryptoAlgorithmIdAesKw: { |
| - platform::SymKey* platform_wrapping_key; |
| - Status status = ToPlatformSymKey(wrapping_key, &platform_wrapping_key); |
| - if (status.IsError()) |
| - return status; |
| - // AES-KW requires the wrapped key data size must be at least 24 bytes and |
| - // also a multiple of 8 bytes. |
| - if (wrapped_key_data.byte_length() < 24) |
| - return Status::ErrorDataTooSmall(); |
| - if (wrapped_key_data.byte_length() % 8) |
| - return Status::ErrorInvalidAesKwDataLength(); |
| - return platform::UnwrapSymKeyAesKw(wrapped_key_data, |
| - platform_wrapping_key, |
| - algorithm_or_null, |
| - extractable, |
| - usage_mask, |
| - key); |
| - } |
| - case blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5: { |
| - platform::PrivateKey* platform_wrapping_key; |
| - Status status = |
| - ToPlatformPrivateKey(wrapping_key, &platform_wrapping_key); |
| - if (status.IsError()) |
| - return status; |
| - if (!wrapped_key_data.byte_length()) |
| - return Status::ErrorDataTooSmall(); |
| - return platform::UnwrapSymKeyRsaEs(wrapped_key_data, |
| - platform_wrapping_key, |
| - algorithm_or_null, |
| - extractable, |
| - usage_mask, |
| - key); |
| - } |
| + switch (format) { |
| + case blink::WebCryptoKeyFormatRaw: |
| + return UnwrapKeyRaw(wrapped_key_data, |
| + wrapping_key, |
| + wrapping_algorithm, |
| + algorithm_or_null, |
| + extractable, |
| + usage_mask, |
| + key); |
| + case blink::WebCryptoKeyFormatJwk: |
| + return UnwrapKeyDecryptAndImport(format, |
| + wrapped_key_data, |
| + wrapping_key, |
| + wrapping_algorithm, |
| + algorithm_or_null, |
| + extractable, |
| + usage_mask, |
| + key); |
| + case blink::WebCryptoKeyFormatSpki: |
| + case blink::WebCryptoKeyFormatPkcs8: |
| + return Status::ErrorUnsupported(); // TODO(padolph) |
| default: |
| + NOTREACHED(); |
| return Status::ErrorUnsupported(); |
| } |
| } |