| OLD | NEW |
| (Empty) |
| 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>* 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>* 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>* 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>* 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>* 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>* 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>* 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>* 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 // TODO(eroman): Move this into implementation which need it instead. | |
| 216 if (!signature.byte_length()) { | |
| 217 // None of the algorithms generate valid zero-length signatures so this | |
| 218 // will necessarily fail verification. Early return to protect | |
| 219 // implementations from dealing with a NULL signature pointer. | |
| 220 *signature_match = false; | |
| 221 return Status::Success(); | |
| 222 } | |
| 223 | |
| 224 const AlgorithmImplementation* impl = NULL; | |
| 225 Status status = GetAlgorithmImplementation(algorithm.id(), &impl); | |
| 226 if (status.IsError()) | |
| 227 return status; | |
| 228 | |
| 229 return impl->Verify(algorithm, key, signature, data, signature_match); | |
| 230 } | |
| 231 | |
| 232 Status WrapKey(blink::WebCryptoKeyFormat format, | |
| 233 const blink::WebCryptoKey& key_to_wrap, | |
| 234 const blink::WebCryptoKey& wrapping_key, | |
| 235 const blink::WebCryptoAlgorithm& wrapping_algorithm, | |
| 236 std::vector<uint8>* buffer) { | |
| 237 if (!KeyUsageAllows(wrapping_key, blink::WebCryptoKeyUsageWrapKey)) | |
| 238 return Status::ErrorUnexpected(); | |
| 239 | |
| 240 std::vector<uint8> exported_data; | |
| 241 Status status = ExportKey(format, key_to_wrap, &exported_data); | |
| 242 if (status.IsError()) | |
| 243 return status; | |
| 244 return EncryptDontCheckUsage( | |
| 245 wrapping_algorithm, wrapping_key, CryptoData(exported_data), buffer); | |
| 246 } | |
| 247 | |
| 248 Status UnwrapKey(blink::WebCryptoKeyFormat format, | |
| 249 const CryptoData& wrapped_key_data, | |
| 250 const blink::WebCryptoKey& wrapping_key, | |
| 251 const blink::WebCryptoAlgorithm& wrapping_algorithm, | |
| 252 const blink::WebCryptoAlgorithm& algorithm, | |
| 253 bool extractable, | |
| 254 blink::WebCryptoKeyUsageMask usage_mask, | |
| 255 blink::WebCryptoKey* key) { | |
| 256 if (!KeyUsageAllows(wrapping_key, blink::WebCryptoKeyUsageUnwrapKey)) | |
| 257 return Status::ErrorUnexpected(); | |
| 258 if (wrapping_algorithm.id() != wrapping_key.algorithm().id()) | |
| 259 return Status::ErrorUnexpected(); | |
| 260 | |
| 261 // Fail fast if the import is doomed to fail. | |
| 262 const AlgorithmImplementation* import_impl = NULL; | |
| 263 Status status = GetAlgorithmImplementation(algorithm.id(), &import_impl); | |
| 264 if (status.IsError()) | |
| 265 return status; | |
| 266 | |
| 267 status = import_impl->VerifyKeyUsagesBeforeImportKey(format, usage_mask); | |
| 268 if (status.IsError()) | |
| 269 return status; | |
| 270 | |
| 271 std::vector<uint8> buffer; | |
| 272 status = DecryptDontCheckKeyUsage( | |
| 273 wrapping_algorithm, wrapping_key, wrapped_key_data, &buffer); | |
| 274 if (status.IsError()) | |
| 275 return status; | |
| 276 | |
| 277 // NOTE that returning the details of ImportKey() failures may leak | |
| 278 // information about the plaintext of the encrypted key (for instance the JWK | |
| 279 // key_ops). As long as the ImportKey error messages don't describe actual | |
| 280 // key bytes however this should be OK. For more discussion see | |
| 281 // http://crubg.com/372040 | |
| 282 return ImportKey( | |
| 283 format, CryptoData(buffer), algorithm, extractable, usage_mask, key); | |
| 284 } | |
| 285 | |
| 286 scoped_ptr<blink::WebCryptoDigestor> CreateDigestor( | |
| 287 blink::WebCryptoAlgorithmId algorithm) { | |
| 288 return CreatePlatformDigestor(algorithm); | |
| 289 } | |
| 290 | |
| 291 } // namespace webcrypto | |
| 292 | |
| 293 } // namespace content | |
| OLD | NEW |