1 // Copyright 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/child/webcrypto/structured_clone.h" 6 7 #include "base/logging.h" 8 #include "content/child/webcrypto/algorithm_dispatch.h" 9 #include "content/child/webcrypto/platform_crypto.h" 10 #include "content/child/webcrypto/status.h" 11 #include "content/child/webcrypto/webcrypto_util.h" 12 #include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h" 13 14 namespace content { 15 16 namespace webcrypto { 17 18 namespace { 19 20 // Returns the key format to use for structured cloning. 21 blink::WebCryptoKeyFormat GetCloneFormatForKeyType( 22 blink::WebCryptoKeyType type) { 23 switch (type) { 24 case blink::WebCryptoKeyTypeSecret: 25 return blink::WebCryptoKeyFormatRaw; 26 case blink::WebCryptoKeyTypePublic: 27 return blink::WebCryptoKeyFormatSpki; 28 case blink::WebCryptoKeyTypePrivate: 29 return blink::WebCryptoKeyFormatPkcs8; 30 } 31 32 NOTREACHED(); 33 return blink::WebCryptoKeyFormatRaw; 34 } 35 36 // Converts a KeyAlgorithm into an equivalent Algorithm for import. 37 blink::WebCryptoAlgorithm KeyAlgorithmToImportAlgorithm( 38 const blink::WebCryptoKeyAlgorithm& algorithm) { 39 switch (algorithm.paramsType()) { 40 case blink::WebCryptoKeyAlgorithmParamsTypeAes: 41 return CreateAlgorithm(algorithm.id()); 42 case blink::WebCryptoKeyAlgorithmParamsTypeHmac: 43 return CreateHmacImportAlgorithm(algorithm.hmacParams()->hash().id()); 44 case blink::WebCryptoKeyAlgorithmParamsTypeRsaHashed: 45 return CreateRsaHashedImportAlgorithm( 46 algorithm.id(), algorithm.rsaHashedParams()->hash().id()); 47 case blink::WebCryptoKeyAlgorithmParamsTypeNone: 48 break; 49 default: 50 break; 51 } 52 return blink::WebCryptoAlgorithm::createNull(); 53 } 54 55 // There is some duplicated information in the serialized format used by 56 // structured clone (since the KeyAlgorithm is serialized separately from the 57 // key data). Use this extra information to further validate what was 58 // deserialized from the key data. 59 // 60 // A failure here implies either a bug in the code, or that the serialized data 61 // was corrupted. 62 bool ValidateDeserializedKey(const blink::WebCryptoKey& key, 63 const blink::WebCryptoKeyAlgorithm& algorithm, 64 blink::WebCryptoKeyType type) { 65 if (algorithm.id() != key.algorithm().id()) 66 return false; 67 68 if (key.type() != type) 69 return false; 70 71 switch (algorithm.paramsType()) { 72 case blink::WebCryptoKeyAlgorithmParamsTypeAes: 73 if (algorithm.aesParams()->lengthBits() != 74 key.algorithm().aesParams()->lengthBits()) 75 return false; 76 break; 77 case blink::WebCryptoKeyAlgorithmParamsTypeRsaHashed: 78 if (algorithm.rsaHashedParams()->modulusLengthBits() != 79 key.algorithm().rsaHashedParams()->modulusLengthBits()) 80 return false; 81 if (algorithm.rsaHashedParams()->publicExponent().size() != 82 key.algorithm().rsaHashedParams()->publicExponent().size()) 83 return false; 84 if (memcmp(algorithm.rsaHashedParams()->publicExponent().data(), 85 key.algorithm().rsaHashedParams()->publicExponent().data(), 86 key.algorithm().rsaHashedParams()->publicExponent().size()) != 87 0) 88 return false; 89 break; 90 case blink::WebCryptoKeyAlgorithmParamsTypeNone: 91 case blink::WebCryptoKeyAlgorithmParamsTypeHmac: 92 break; 93 default: 94 return false; 95 } 96 97 return true; 98 } 99 100 } // namespace 101 102 // Note that this function is called from the target Blink thread. 103 bool SerializeKeyForClone(const blink::WebCryptoKey& key, 104 blink::WebVector<uint8_t>* key_data) { 105 return PlatformSerializeKeyForClone(key, key_data); 106 } 107 108 // Note that this function is called from the target Blink thread. 109 bool DeserializeKeyForClone(const blink::WebCryptoKeyAlgorithm& algorithm, 110 blink::WebCryptoKeyType type, 111 bool extractable, 112 blink::WebCryptoKeyUsageMask usage_mask, 113 const CryptoData& key_data, 114 blink::WebCryptoKey* key) { 115 // TODO(eroman): This should not call into the platform crypto layer. 116 // Otherwise it runs the risk of stalling while the NSS/OpenSSL global locks 117 // are held. 118 // 119 // An alternate approach is to defer the key import until the key is used. 120 // However this means that any deserialization errors would have to be 121 // surfaced as WebCrypto errors, leading to slightly different behaviors. For 122 // instance you could clone a key which fails to be deserialized. 123 Status status = ImportKey(GetCloneFormatForKeyType(type), 124 key_data, 125 KeyAlgorithmToImportAlgorithm(algorithm), 126 extractable, 127 usage_mask, 128 key); 129 if (status.IsError()) 130 return false; 131 return ValidateDeserializedKey(*key, algorithm, type); 132 } 133 134 } // namespace webcrypto 135 136 } // namespace content 137