// 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