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/algorithm_dispatch.h" 6 7 #include "base/logging.h" 8 #include "content/child/webcrypto/algorithm_implementation.h" 9 #include "content/child/webcrypto/algorithm_registry.h" 10 #include "content/child/webcrypto/crypto_data.h" 11 #include "content/child/webcrypto/platform_crypto.h" 12 #include "content/child/webcrypto/status.h" 13 #include "content/child/webcrypto/webcrypto_util.h" 14 #include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h" 15 16 namespace content { 17 18 namespace webcrypto { 19 20 namespace { 21 22 Status DecryptDontCheckKeyUsage(const blink::WebCryptoAlgorithm& algorithm, 23 const blink::WebCryptoKey& key, 24 const CryptoData& data, 25 std::vector<uint8_t>* buffer) { 26 if (algorithm.id() != key.algorithm().id()) 27 return Status::ErrorUnexpected(); 28 29 const AlgorithmImplementation* impl = NULL; 30 Status status = GetAlgorithmImplementation(algorithm.id(), &impl); 31 if (status.IsError()) 32 return status; 33 34 return impl->Decrypt(algorithm, key, data, buffer); 35 } 36 37 Status EncryptDontCheckUsage(const blink::WebCryptoAlgorithm& algorithm, 38 const blink::WebCryptoKey& key, 39 const CryptoData& data, 40 std::vector<uint8_t>* buffer) { 41 if (algorithm.id() != key.algorithm().id()) 42 return Status::ErrorUnexpected(); 43 44 const AlgorithmImplementation* impl = NULL; 45 Status status = GetAlgorithmImplementation(algorithm.id(), &impl); 46 if (status.IsError()) 47 return status; 48 49 return impl->Encrypt(algorithm, key, data, buffer); 50 } 51 52 Status ExportKeyDontCheckExtractability(blink::WebCryptoKeyFormat format, 53 const blink::WebCryptoKey& key, 54 std::vector<uint8_t>* buffer) { 55 const AlgorithmImplementation* impl = NULL; 56 Status status = GetAlgorithmImplementation(key.algorithm().id(), &impl); 57 if (status.IsError()) 58 return status; 59 60 switch (format) { 61 case blink::WebCryptoKeyFormatRaw: 62 return impl->ExportKeyRaw(key, buffer); 63 case blink::WebCryptoKeyFormatSpki: 64 return impl->ExportKeySpki(key, buffer); 65 case blink::WebCryptoKeyFormatPkcs8: 66 return impl->ExportKeyPkcs8(key, buffer); 67 case blink::WebCryptoKeyFormatJwk: 68 return impl->ExportKeyJwk(key, buffer); 69 default: 70 return Status::ErrorUnsupported(); 71 } 72 } 73 74 } // namespace 75 76 Status Encrypt(const blink::WebCryptoAlgorithm& algorithm, 77 const blink::WebCryptoKey& key, 78 const CryptoData& data, 79 std::vector<uint8_t>* buffer) { 80 if (!KeyUsageAllows(key, blink::WebCryptoKeyUsageEncrypt)) 81 return Status::ErrorUnexpected(); 82 return EncryptDontCheckUsage(algorithm, key, data, buffer); 83 } 84 85 Status Decrypt(const blink::WebCryptoAlgorithm& algorithm, 86 const blink::WebCryptoKey& key, 87 const CryptoData& data, 88 std::vector<uint8_t>* buffer) { 89 if (!KeyUsageAllows(key, blink::WebCryptoKeyUsageDecrypt)) 90 return Status::ErrorUnexpected(); 91 return DecryptDontCheckKeyUsage(algorithm, key, data, buffer); 92 } 93 94 Status Digest(const blink::WebCryptoAlgorithm& algorithm, 95 const CryptoData& data, 96 std::vector<uint8_t>* buffer) { 97 const AlgorithmImplementation* impl = NULL; 98 Status status = GetAlgorithmImplementation(algorithm.id(), &impl); 99 if (status.IsError()) 100 return status; 101 102 return impl->Digest(algorithm, data, buffer); 103 } 104 105 Status GenerateSecretKey(const blink::WebCryptoAlgorithm& algorithm, 106 bool extractable, 107 blink::WebCryptoKeyUsageMask usage_mask, 108 blink::WebCryptoKey* key) { 109 const AlgorithmImplementation* impl = NULL; 110 Status status = GetAlgorithmImplementation(algorithm.id(), &impl); 111 if (status.IsError()) 112 return status; 113 114 status = impl->VerifyKeyUsagesBeforeGenerateKey(usage_mask); 115 if (status.IsError()) 116 return status; 117 118 return impl->GenerateSecretKey(algorithm, extractable, usage_mask, key); 119 } 120 121 Status GenerateKeyPair(const blink::WebCryptoAlgorithm& algorithm, 122 bool extractable, 123 blink::WebCryptoKeyUsageMask combined_usage_mask, 124 blink::WebCryptoKey* public_key, 125 blink::WebCryptoKey* private_key) { 126 const AlgorithmImplementation* impl = NULL; 127 Status status = GetAlgorithmImplementation(algorithm.id(), &impl); 128 if (status.IsError()) 129 return status; 130 131 blink::WebCryptoKeyUsageMask public_usage_mask; 132 blink::WebCryptoKeyUsageMask private_usage_mask; 133 status = impl->VerifyKeyUsagesBeforeGenerateKeyPair( 134 combined_usage_mask, &public_usage_mask, &private_usage_mask); 135 if (status.IsError()) 136 return status; 137 138 return impl->GenerateKeyPair(algorithm, 139 extractable, 140 public_usage_mask, 141 private_usage_mask, 142 public_key, 143 private_key); 144 } 145 146 // Note that this function may be called from the target Blink thread. 147 Status ImportKey(blink::WebCryptoKeyFormat format, 148 const CryptoData& key_data, 149 const blink::WebCryptoAlgorithm& algorithm, 150 bool extractable, 151 blink::WebCryptoKeyUsageMask usage_mask, 152 blink::WebCryptoKey* key) { 153 const AlgorithmImplementation* impl = NULL; 154 Status status = GetAlgorithmImplementation(algorithm.id(), &impl); 155 if (status.IsError()) 156 return status; 157 158 status = impl->VerifyKeyUsagesBeforeImportKey(format, usage_mask); 159 if (status.IsError()) 160 return status; 161 162 switch (format) { 163 case blink::WebCryptoKeyFormatRaw: 164 return impl->ImportKeyRaw( 165 key_data, algorithm, extractable, usage_mask, key); 166 case blink::WebCryptoKeyFormatSpki: 167 return impl->ImportKeySpki( 168 key_data, algorithm, extractable, usage_mask, key); 169 case blink::WebCryptoKeyFormatPkcs8: 170 return impl->ImportKeyPkcs8( 171 key_data, algorithm, extractable, usage_mask, key); 172 case blink::WebCryptoKeyFormatJwk: 173 return impl->ImportKeyJwk( 174 key_data, algorithm, extractable, usage_mask, key); 175 default: 176 return Status::ErrorUnsupported(); 177 } 178 } 179 180 Status ExportKey(blink::WebCryptoKeyFormat format, 181 const blink::WebCryptoKey& key, 182 std::vector<uint8_t>* buffer) { 183 if (!key.extractable()) 184 return Status::ErrorKeyNotExtractable(); 185 return ExportKeyDontCheckExtractability(format, key, buffer); 186 } 187 188 Status Sign(const blink::WebCryptoAlgorithm& algorithm, 189 const blink::WebCryptoKey& key, 190 const CryptoData& data, 191 std::vector<uint8_t>* buffer) { 192 if (!KeyUsageAllows(key, blink::WebCryptoKeyUsageSign)) 193 return Status::ErrorUnexpected(); 194 if (algorithm.id() != key.algorithm().id()) 195 return Status::ErrorUnexpected(); 196 197 const AlgorithmImplementation* impl = NULL; 198 Status status = GetAlgorithmImplementation(algorithm.id(), &impl); 199 if (status.IsError()) 200 return status; 201 202 return impl->Sign(algorithm, key, data, buffer); 203 } 204 205 Status Verify(const blink::WebCryptoAlgorithm& algorithm, 206 const blink::WebCryptoKey& key, 207 const CryptoData& signature, 208 const CryptoData& data, 209 bool* signature_match) { 210 if (!KeyUsageAllows(key, blink::WebCryptoKeyUsageVerify)) 211 return Status::ErrorUnexpected(); 212 if (algorithm.id() != key.algorithm().id()) 213 return Status::ErrorUnexpected(); 214 215 const AlgorithmImplementation* impl = NULL; 216 Status status = GetAlgorithmImplementation(algorithm.id(), &impl); 217 if (status.IsError()) 218 return status; 219 220 return impl->Verify(algorithm, key, signature, data, signature_match); 221 } 222 223 Status WrapKey(blink::WebCryptoKeyFormat format, 224 const blink::WebCryptoKey& key_to_wrap, 225 const blink::WebCryptoKey& wrapping_key, 226 const blink::WebCryptoAlgorithm& wrapping_algorithm, 227 std::vector<uint8_t>* buffer) { 228 if (!KeyUsageAllows(wrapping_key, blink::WebCryptoKeyUsageWrapKey)) 229 return Status::ErrorUnexpected(); 230 231 std::vector<uint8_t> exported_data; 232 Status status = ExportKey(format, key_to_wrap, &exported_data); 233 if (status.IsError()) 234 return status; 235 return EncryptDontCheckUsage( 236 wrapping_algorithm, wrapping_key, CryptoData(exported_data), buffer); 237 } 238 239 Status UnwrapKey(blink::WebCryptoKeyFormat format, 240 const CryptoData& wrapped_key_data, 241 const blink::WebCryptoKey& wrapping_key, 242 const blink::WebCryptoAlgorithm& wrapping_algorithm, 243 const blink::WebCryptoAlgorithm& algorithm, 244 bool extractable, 245 blink::WebCryptoKeyUsageMask usage_mask, 246 blink::WebCryptoKey* key) { 247 if (!KeyUsageAllows(wrapping_key, blink::WebCryptoKeyUsageUnwrapKey)) 248 return Status::ErrorUnexpected(); 249 if (wrapping_algorithm.id() != wrapping_key.algorithm().id()) 250 return Status::ErrorUnexpected(); 251 252 // Fail fast if the import is doomed to fail. 253 const AlgorithmImplementation* import_impl = NULL; 254 Status status = GetAlgorithmImplementation(algorithm.id(), &import_impl); 255 if (status.IsError()) 256 return status; 257 258 status = import_impl->VerifyKeyUsagesBeforeImportKey(format, usage_mask); 259 if (status.IsError()) 260 return status; 261 262 std::vector<uint8_t> buffer; 263 status = DecryptDontCheckKeyUsage( 264 wrapping_algorithm, wrapping_key, wrapped_key_data, &buffer); 265 if (status.IsError()) 266 return status; 267 268 // NOTE that returning the details of ImportKey() failures may leak 269 // information about the plaintext of the encrypted key (for instance the JWK 270 // key_ops). As long as the ImportKey error messages don't describe actual 271 // key bytes however this should be OK. For more discussion see 272 // http://crubg.com/372040 273 return ImportKey( 274 format, CryptoData(buffer), algorithm, extractable, usage_mask, key); 275 } 276 277 scoped_ptr<blink::WebCryptoDigestor> CreateDigestor( 278 blink::WebCryptoAlgorithmId algorithm) { 279 PlatformInit(); 280 return CreatePlatformDigestor(algorithm); 281 } 282 283 } // namespace webcrypto 284 285 } // namespace content 286