| // Copyright 2014 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "content/child/webcrypto/structured_clone.h" |
| |
| #include "base/logging.h" |
| #include "content/child/webcrypto/algorithm_dispatch.h" |
| #include "content/child/webcrypto/platform_crypto.h" |
| #include "content/child/webcrypto/status.h" |
| #include "content/child/webcrypto/webcrypto_util.h" |
| #include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h" |
| |
| namespace content { |
| |
| namespace webcrypto { |
| |
| namespace { |
| |
| // Returns the key format to use for structured cloning. |
| blink::WebCryptoKeyFormat GetCloneFormatForKeyType( |
| blink::WebCryptoKeyType type) { |
| switch (type) { |
| case blink::WebCryptoKeyTypeSecret: |
| return blink::WebCryptoKeyFormatRaw; |
| case blink::WebCryptoKeyTypePublic: |
| return blink::WebCryptoKeyFormatSpki; |
| case blink::WebCryptoKeyTypePrivate: |
| return blink::WebCryptoKeyFormatPkcs8; |
| } |
| |
| NOTREACHED(); |
| return blink::WebCryptoKeyFormatRaw; |
| } |
| |
| // Converts a KeyAlgorithm into an equivalent Algorithm for import. |
| blink::WebCryptoAlgorithm KeyAlgorithmToImportAlgorithm( |
| const blink::WebCryptoKeyAlgorithm& algorithm) { |
| switch (algorithm.paramsType()) { |
| case blink::WebCryptoKeyAlgorithmParamsTypeAes: |
| return CreateAlgorithm(algorithm.id()); |
| case blink::WebCryptoKeyAlgorithmParamsTypeHmac: |
| return CreateHmacImportAlgorithm(algorithm.hmacParams()->hash().id()); |
| case blink::WebCryptoKeyAlgorithmParamsTypeRsaHashed: |
| return CreateRsaHashedImportAlgorithm( |
| algorithm.id(), algorithm.rsaHashedParams()->hash().id()); |
| case blink::WebCryptoKeyAlgorithmParamsTypeNone: |
| break; |
| default: |
| break; |
| } |
| return blink::WebCryptoAlgorithm::createNull(); |
| } |
| |
| // There is some duplicated information in the serialized format used by |
| // structured clone (since the KeyAlgorithm is serialized separately from the |
| // key data). Use this extra information to further validate what was |
| // deserialized from the key data. |
| // |
| // A failure here implies either a bug in the code, or that the serialized data |
| // was corrupted. |
| bool ValidateDeserializedKey(const blink::WebCryptoKey& key, |
| const blink::WebCryptoKeyAlgorithm& algorithm, |
| blink::WebCryptoKeyType type) { |
| if (algorithm.id() != key.algorithm().id()) |
| return false; |
| |
| if (key.type() != type) |
| return false; |
| |
| switch (algorithm.paramsType()) { |
| case blink::WebCryptoKeyAlgorithmParamsTypeAes: |
| if (algorithm.aesParams()->lengthBits() != |
| key.algorithm().aesParams()->lengthBits()) |
| return false; |
| break; |
| case blink::WebCryptoKeyAlgorithmParamsTypeRsaHashed: |
| if (algorithm.rsaHashedParams()->modulusLengthBits() != |
| key.algorithm().rsaHashedParams()->modulusLengthBits()) |
| return false; |
| if (algorithm.rsaHashedParams()->publicExponent().size() != |
| key.algorithm().rsaHashedParams()->publicExponent().size()) |
| return false; |
| if (memcmp(algorithm.rsaHashedParams()->publicExponent().data(), |
| key.algorithm().rsaHashedParams()->publicExponent().data(), |
| key.algorithm().rsaHashedParams()->publicExponent().size()) != |
| 0) |
| return false; |
| break; |
| case blink::WebCryptoKeyAlgorithmParamsTypeNone: |
| case blink::WebCryptoKeyAlgorithmParamsTypeHmac: |
| break; |
| default: |
| return false; |
| } |
| |
| return true; |
| } |
| |
| } // namespace |
| |
| // Note that this function is called from the target Blink thread. |
| bool SerializeKeyForClone(const blink::WebCryptoKey& key, |
| blink::WebVector<uint8_t>* key_data) { |
| return PlatformSerializeKeyForClone(key, key_data); |
| } |
| |
| // Note that this function is called from the target Blink thread. |
| bool DeserializeKeyForClone(const blink::WebCryptoKeyAlgorithm& algorithm, |
| blink::WebCryptoKeyType type, |
| bool extractable, |
| blink::WebCryptoKeyUsageMask usage_mask, |
| const CryptoData& key_data, |
| blink::WebCryptoKey* key) { |
| // TODO(eroman): This should not call into the platform crypto layer. |
| // Otherwise it runs the risk of stalling while the NSS/OpenSSL global locks |
| // are held. |
| // |
| // An alternate approach is to defer the key import until the key is used. |
| // However this means that any deserialization errors would have to be |
| // surfaced as WebCrypto errors, leading to slightly different behaviors. For |
| // instance you could clone a key which fails to be deserialized. |
| Status status = ImportKey(GetCloneFormatForKeyType(type), |
| key_data, |
| KeyAlgorithmToImportAlgorithm(algorithm), |
| extractable, |
| usage_mask, |
| key); |
| if (status.IsError()) |
| return false; |
| return ValidateDeserializedKey(*key, algorithm, type); |
| } |
| |
| } // namespace webcrypto |
| |
| } // namespace content |