| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "content/child/webcrypto/shared_crypto.h" | 5 #include "content/child/webcrypto/algorithm_dispatch.h" |
| 6 | 6 |
| 7 #include "base/logging.h" | 7 #include "base/logging.h" |
| 8 #include "content/child/webcrypto/algorithm.h" |
| 9 #include "content/child/webcrypto/algorithm_registry.h" |
| 8 #include "content/child/webcrypto/crypto_data.h" | 10 #include "content/child/webcrypto/crypto_data.h" |
| 9 #include "content/child/webcrypto/jwk.h" | |
| 10 #include "content/child/webcrypto/platform_crypto.h" | 11 #include "content/child/webcrypto/platform_crypto.h" |
| 11 #include "content/child/webcrypto/status.h" | 12 #include "content/child/webcrypto/status.h" |
| 12 #include "content/child/webcrypto/webcrypto_util.h" | 13 #include "content/child/webcrypto/webcrypto_util.h" |
| 13 #include "crypto/secure_util.h" | |
| 14 #include "third_party/WebKit/public/platform/WebCryptoAlgorithm.h" | |
| 15 #include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h" | |
| 16 #include "third_party/WebKit/public/platform/WebCryptoKey.h" | |
| 17 #include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h" | 14 #include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h" |
| 18 | 15 |
| 19 namespace content { | 16 namespace content { |
| 20 | 17 |
| 21 namespace webcrypto { | 18 namespace webcrypto { |
| 22 | 19 |
| 23 // ------------ | |
| 24 // Threading: | |
| 25 // ------------ | |
| 26 // | |
| 27 // All functions in this file are called from the webcrypto worker pool except | |
| 28 // for: | |
| 29 // | |
| 30 // * SerializeKeyForClone() | |
| 31 // * DeserializeKeyForClone() | |
| 32 // * ImportKey() // TODO(eroman): Change this. | |
| 33 | |
| 34 namespace { | 20 namespace { |
| 35 | 21 |
| 36 // TODO(eroman): Move this helper to WebCryptoKey. | |
| 37 bool KeyUsageAllows(const blink::WebCryptoKey& key, | |
| 38 const blink::WebCryptoKeyUsage usage) { | |
| 39 return ((key.usages() & usage) != 0); | |
| 40 } | |
| 41 | |
| 42 bool IsValidAesKeyLengthBits(unsigned int length_bits) { | |
| 43 // 192-bit AES is disallowed. | |
| 44 return length_bits == 128 || length_bits == 256; | |
| 45 } | |
| 46 | |
| 47 bool IsValidAesKeyLengthBytes(unsigned int length_bytes) { | |
| 48 // 192-bit AES is disallowed. | |
| 49 return length_bytes == 16 || length_bytes == 32; | |
| 50 } | |
| 51 | |
| 52 const size_t kAesBlockSizeBytes = 16; | |
| 53 | |
| 54 Status EncryptDecryptAesCbc(EncryptOrDecrypt mode, | |
| 55 const blink::WebCryptoAlgorithm& algorithm, | |
| 56 const blink::WebCryptoKey& key, | |
| 57 const CryptoData& data, | |
| 58 std::vector<uint8>* buffer) { | |
| 59 platform::SymKey* sym_key; | |
| 60 Status status = ToPlatformSymKey(key, &sym_key); | |
| 61 if (status.IsError()) | |
| 62 return status; | |
| 63 | |
| 64 const blink::WebCryptoAesCbcParams* params = algorithm.aesCbcParams(); | |
| 65 if (!params) | |
| 66 return Status::ErrorUnexpected(); | |
| 67 | |
| 68 CryptoData iv(params->iv().data(), params->iv().size()); | |
| 69 if (iv.byte_length() != kAesBlockSizeBytes) | |
| 70 return Status::ErrorIncorrectSizeAesCbcIv(); | |
| 71 | |
| 72 return platform::EncryptDecryptAesCbc(mode, sym_key, data, iv, buffer); | |
| 73 } | |
| 74 | |
| 75 Status EncryptDecryptAesGcm(EncryptOrDecrypt mode, | |
| 76 const blink::WebCryptoAlgorithm& algorithm, | |
| 77 const blink::WebCryptoKey& key, | |
| 78 const CryptoData& data, | |
| 79 std::vector<uint8>* buffer) { | |
| 80 platform::SymKey* sym_key; | |
| 81 Status status = ToPlatformSymKey(key, &sym_key); | |
| 82 if (status.IsError()) | |
| 83 return status; | |
| 84 | |
| 85 const blink::WebCryptoAesGcmParams* params = algorithm.aesGcmParams(); | |
| 86 if (!params) | |
| 87 return Status::ErrorUnexpected(); | |
| 88 | |
| 89 unsigned int tag_length_bits = 128; | |
| 90 if (params->hasTagLengthBits()) | |
| 91 tag_length_bits = params->optionalTagLengthBits(); | |
| 92 | |
| 93 if (tag_length_bits != 32 && tag_length_bits != 64 && tag_length_bits != 96 && | |
| 94 tag_length_bits != 104 && tag_length_bits != 112 && | |
| 95 tag_length_bits != 120 && tag_length_bits != 128) | |
| 96 return Status::ErrorInvalidAesGcmTagLength(); | |
| 97 | |
| 98 return platform::EncryptDecryptAesGcm( | |
| 99 mode, | |
| 100 sym_key, | |
| 101 data, | |
| 102 CryptoData(params->iv()), | |
| 103 CryptoData(params->optionalAdditionalData()), | |
| 104 tag_length_bits, | |
| 105 buffer); | |
| 106 } | |
| 107 | |
| 108 Status EncryptRsaOaep(const blink::WebCryptoAlgorithm& algorithm, | |
| 109 const blink::WebCryptoKey& key, | |
| 110 const CryptoData& data, | |
| 111 std::vector<uint8>* buffer) { | |
| 112 platform::PublicKey* public_key; | |
| 113 Status status = ToPlatformPublicKey(key, &public_key); | |
| 114 if (status.IsError()) | |
| 115 return status; | |
| 116 | |
| 117 const blink::WebCryptoRsaOaepParams* params = algorithm.rsaOaepParams(); | |
| 118 if (!params) | |
| 119 return Status::ErrorUnexpected(); | |
| 120 | |
| 121 return platform::EncryptRsaOaep(public_key, | |
| 122 key.algorithm().rsaHashedParams()->hash(), | |
| 123 CryptoData(params->optionalLabel()), | |
| 124 data, | |
| 125 buffer); | |
| 126 } | |
| 127 | |
| 128 Status DecryptRsaOaep(const blink::WebCryptoAlgorithm& algorithm, | |
| 129 const blink::WebCryptoKey& key, | |
| 130 const CryptoData& data, | |
| 131 std::vector<uint8>* buffer) { | |
| 132 platform::PrivateKey* private_key; | |
| 133 Status status = ToPlatformPrivateKey(key, &private_key); | |
| 134 if (status.IsError()) | |
| 135 return status; | |
| 136 | |
| 137 const blink::WebCryptoRsaOaepParams* params = algorithm.rsaOaepParams(); | |
| 138 if (!params) | |
| 139 return Status::ErrorUnexpected(); | |
| 140 | |
| 141 return platform::DecryptRsaOaep(private_key, | |
| 142 key.algorithm().rsaHashedParams()->hash(), | |
| 143 CryptoData(params->optionalLabel()), | |
| 144 data, | |
| 145 buffer); | |
| 146 } | |
| 147 | |
| 148 Status SignHmac(const blink::WebCryptoAlgorithm& algorithm, | |
| 149 const blink::WebCryptoKey& key, | |
| 150 const CryptoData& data, | |
| 151 std::vector<uint8>* buffer) { | |
| 152 platform::SymKey* sym_key; | |
| 153 Status status = ToPlatformSymKey(key, &sym_key); | |
| 154 if (status.IsError()) | |
| 155 return status; | |
| 156 | |
| 157 return platform::SignHmac( | |
| 158 sym_key, key.algorithm().hmacParams()->hash(), data, buffer); | |
| 159 } | |
| 160 | |
| 161 Status VerifyHmac(const blink::WebCryptoAlgorithm& algorithm, | |
| 162 const blink::WebCryptoKey& key, | |
| 163 const CryptoData& signature, | |
| 164 const CryptoData& data, | |
| 165 bool* signature_match) { | |
| 166 std::vector<uint8> result; | |
| 167 Status status = SignHmac(algorithm, key, data, &result); | |
| 168 if (status.IsError()) | |
| 169 return status; | |
| 170 | |
| 171 // Do not allow verification of truncated MACs. | |
| 172 *signature_match = | |
| 173 result.size() == signature.byte_length() && | |
| 174 crypto::SecureMemEqual( | |
| 175 Uint8VectorStart(result), signature.bytes(), signature.byte_length()); | |
| 176 | |
| 177 return Status::Success(); | |
| 178 } | |
| 179 | |
| 180 Status SignRsaSsaPkcs1v1_5(const blink::WebCryptoAlgorithm& algorithm, | |
| 181 const blink::WebCryptoKey& key, | |
| 182 const CryptoData& data, | |
| 183 std::vector<uint8>* buffer) { | |
| 184 platform::PrivateKey* private_key; | |
| 185 Status status = ToPlatformPrivateKey(key, &private_key); | |
| 186 if (status.IsError()) | |
| 187 return status; | |
| 188 | |
| 189 return platform::SignRsaSsaPkcs1v1_5( | |
| 190 private_key, key.algorithm().rsaHashedParams()->hash(), data, buffer); | |
| 191 } | |
| 192 | |
| 193 Status VerifyRsaSsaPkcs1v1_5(const blink::WebCryptoAlgorithm& algorithm, | |
| 194 const blink::WebCryptoKey& key, | |
| 195 const CryptoData& signature, | |
| 196 const CryptoData& data, | |
| 197 bool* signature_match) { | |
| 198 platform::PublicKey* public_key; | |
| 199 Status status = ToPlatformPublicKey(key, &public_key); | |
| 200 if (status.IsError()) | |
| 201 return status; | |
| 202 | |
| 203 return platform::VerifyRsaSsaPkcs1v1_5( | |
| 204 public_key, | |
| 205 key.algorithm().rsaHashedParams()->hash(), | |
| 206 signature, | |
| 207 data, | |
| 208 signature_match); | |
| 209 } | |
| 210 | |
| 211 // Note that this function may be called from the target Blink thread. | |
| 212 Status ImportKeyRaw(const CryptoData& key_data, | |
| 213 const blink::WebCryptoAlgorithm& algorithm, | |
| 214 bool extractable, | |
| 215 blink::WebCryptoKeyUsageMask usage_mask, | |
| 216 blink::WebCryptoKey* key) { | |
| 217 switch (algorithm.id()) { | |
| 218 case blink::WebCryptoAlgorithmIdAesCtr: | |
| 219 case blink::WebCryptoAlgorithmIdAesCbc: | |
| 220 case blink::WebCryptoAlgorithmIdAesGcm: | |
| 221 case blink::WebCryptoAlgorithmIdAesKw: | |
| 222 if (!IsValidAesKeyLengthBytes(key_data.byte_length())) { | |
| 223 return key_data.byte_length() == 24 | |
| 224 ? Status::ErrorAes192BitUnsupported() | |
| 225 : Status::ErrorImportAesKeyLength(); | |
| 226 } | |
| 227 // Fallthrough intentional! | |
| 228 case blink::WebCryptoAlgorithmIdHmac: | |
| 229 return platform::ImportKeyRaw( | |
| 230 algorithm, key_data, extractable, usage_mask, key); | |
| 231 default: | |
| 232 return Status::ErrorUnsupported(); | |
| 233 } | |
| 234 } | |
| 235 | |
| 236 // Returns the key format to use for structured cloning. | |
| 237 blink::WebCryptoKeyFormat GetCloneFormatForKeyType( | |
| 238 blink::WebCryptoKeyType type) { | |
| 239 switch (type) { | |
| 240 case blink::WebCryptoKeyTypeSecret: | |
| 241 return blink::WebCryptoKeyFormatRaw; | |
| 242 case blink::WebCryptoKeyTypePublic: | |
| 243 return blink::WebCryptoKeyFormatSpki; | |
| 244 case blink::WebCryptoKeyTypePrivate: | |
| 245 return blink::WebCryptoKeyFormatPkcs8; | |
| 246 } | |
| 247 | |
| 248 NOTREACHED(); | |
| 249 return blink::WebCryptoKeyFormatRaw; | |
| 250 } | |
| 251 | |
| 252 // Converts a KeyAlgorithm into an equivalent Algorithm for import. | |
| 253 blink::WebCryptoAlgorithm KeyAlgorithmToImportAlgorithm( | |
| 254 const blink::WebCryptoKeyAlgorithm& algorithm) { | |
| 255 switch (algorithm.paramsType()) { | |
| 256 case blink::WebCryptoKeyAlgorithmParamsTypeAes: | |
| 257 return CreateAlgorithm(algorithm.id()); | |
| 258 case blink::WebCryptoKeyAlgorithmParamsTypeHmac: | |
| 259 return CreateHmacImportAlgorithm(algorithm.hmacParams()->hash().id()); | |
| 260 case blink::WebCryptoKeyAlgorithmParamsTypeRsaHashed: | |
| 261 return CreateRsaHashedImportAlgorithm( | |
| 262 algorithm.id(), algorithm.rsaHashedParams()->hash().id()); | |
| 263 case blink::WebCryptoKeyAlgorithmParamsTypeNone: | |
| 264 break; | |
| 265 default: | |
| 266 break; | |
| 267 } | |
| 268 return blink::WebCryptoAlgorithm::createNull(); | |
| 269 } | |
| 270 | |
| 271 // There is some duplicated information in the serialized format used by | |
| 272 // structured clone (since the KeyAlgorithm is serialized separately from the | |
| 273 // key data). Use this extra information to further validate what was | |
| 274 // deserialized from the key data. | |
| 275 // | |
| 276 // A failure here implies either a bug in the code, or that the serialized data | |
| 277 // was corrupted. | |
| 278 bool ValidateDeserializedKey(const blink::WebCryptoKey& key, | |
| 279 const blink::WebCryptoKeyAlgorithm& algorithm, | |
| 280 blink::WebCryptoKeyType type) { | |
| 281 if (algorithm.id() != key.algorithm().id()) | |
| 282 return false; | |
| 283 | |
| 284 if (key.type() != type) | |
| 285 return false; | |
| 286 | |
| 287 switch (algorithm.paramsType()) { | |
| 288 case blink::WebCryptoKeyAlgorithmParamsTypeAes: | |
| 289 if (algorithm.aesParams()->lengthBits() != | |
| 290 key.algorithm().aesParams()->lengthBits()) | |
| 291 return false; | |
| 292 break; | |
| 293 case blink::WebCryptoKeyAlgorithmParamsTypeRsaHashed: | |
| 294 if (algorithm.rsaHashedParams()->modulusLengthBits() != | |
| 295 key.algorithm().rsaHashedParams()->modulusLengthBits()) | |
| 296 return false; | |
| 297 if (algorithm.rsaHashedParams()->publicExponent().size() != | |
| 298 key.algorithm().rsaHashedParams()->publicExponent().size()) | |
| 299 return false; | |
| 300 if (memcmp(algorithm.rsaHashedParams()->publicExponent().data(), | |
| 301 key.algorithm().rsaHashedParams()->publicExponent().data(), | |
| 302 key.algorithm().rsaHashedParams()->publicExponent().size()) != | |
| 303 0) | |
| 304 return false; | |
| 305 break; | |
| 306 case blink::WebCryptoKeyAlgorithmParamsTypeNone: | |
| 307 case blink::WebCryptoKeyAlgorithmParamsTypeHmac: | |
| 308 break; | |
| 309 default: | |
| 310 return false; | |
| 311 } | |
| 312 | |
| 313 return true; | |
| 314 } | |
| 315 | |
| 316 Status EncryptDecryptAesKw(EncryptOrDecrypt mode, | |
| 317 const blink::WebCryptoAlgorithm& algorithm, | |
| 318 const blink::WebCryptoKey& key, | |
| 319 const CryptoData& data, | |
| 320 std::vector<uint8>* buffer) { | |
| 321 platform::SymKey* sym_key; | |
| 322 Status status = ToPlatformSymKey(key, &sym_key); | |
| 323 if (status.IsError()) | |
| 324 return status; | |
| 325 | |
| 326 unsigned int min_length = mode == ENCRYPT ? 16 : 24; | |
| 327 | |
| 328 if (data.byte_length() < min_length) | |
| 329 return Status::ErrorDataTooSmall(); | |
| 330 if (data.byte_length() % 8) | |
| 331 return Status::ErrorInvalidAesKwDataLength(); | |
| 332 | |
| 333 if (status.IsError()) | |
| 334 return status; | |
| 335 return platform::EncryptDecryptAesKw(mode, sym_key, data, buffer); | |
| 336 } | |
| 337 | |
| 338 Status DecryptDontCheckKeyUsage(const blink::WebCryptoAlgorithm& algorithm, | 22 Status DecryptDontCheckKeyUsage(const blink::WebCryptoAlgorithm& algorithm, |
| 339 const blink::WebCryptoKey& key, | 23 const blink::WebCryptoKey& key, |
| 340 const CryptoData& data, | 24 const CryptoData& data, |
| 341 std::vector<uint8>* buffer) { | 25 std::vector<uint8>* buffer) { |
| 342 if (algorithm.id() != key.algorithm().id()) | 26 if (algorithm.id() != key.algorithm().id()) |
| 343 return Status::ErrorUnexpected(); | 27 return Status::ErrorUnexpected(); |
| 344 switch (algorithm.id()) { | 28 |
| 345 case blink::WebCryptoAlgorithmIdAesCbc: | 29 const AlgorithmImplementation* impl = NULL; |
| 346 return EncryptDecryptAesCbc(DECRYPT, algorithm, key, data, buffer); | 30 Status status = GetAlgorithmImplementation(algorithm.id(), &impl); |
| 347 case blink::WebCryptoAlgorithmIdAesGcm: | 31 if (status.IsError()) |
| 348 return EncryptDecryptAesGcm(DECRYPT, algorithm, key, data, buffer); | 32 return status; |
| 349 case blink::WebCryptoAlgorithmIdRsaOaep: | 33 |
| 350 return DecryptRsaOaep(algorithm, key, data, buffer); | 34 return impl->Decrypt(algorithm, key, data, buffer); |
| 351 case blink::WebCryptoAlgorithmIdAesKw: | |
| 352 return EncryptDecryptAesKw(DECRYPT, algorithm, key, data, buffer); | |
| 353 default: | |
| 354 return Status::ErrorUnsupported(); | |
| 355 } | |
| 356 } | 35 } |
| 357 | 36 |
| 358 Status EncryptDontCheckUsage(const blink::WebCryptoAlgorithm& algorithm, | 37 Status EncryptDontCheckUsage(const blink::WebCryptoAlgorithm& algorithm, |
| 359 const blink::WebCryptoKey& key, | 38 const blink::WebCryptoKey& key, |
| 360 const CryptoData& data, | 39 const CryptoData& data, |
| 361 std::vector<uint8>* buffer) { | 40 std::vector<uint8>* buffer) { |
| 362 if (algorithm.id() != key.algorithm().id()) | 41 if (algorithm.id() != key.algorithm().id()) |
| 363 return Status::ErrorUnexpected(); | 42 return Status::ErrorUnexpected(); |
| 364 switch (algorithm.id()) { | 43 |
| 365 case blink::WebCryptoAlgorithmIdAesCbc: | 44 const AlgorithmImplementation* impl = NULL; |
| 366 return EncryptDecryptAesCbc(ENCRYPT, algorithm, key, data, buffer); | 45 Status status = GetAlgorithmImplementation(algorithm.id(), &impl); |
| 367 case blink::WebCryptoAlgorithmIdAesGcm: | 46 if (status.IsError()) |
| 368 return EncryptDecryptAesGcm(ENCRYPT, algorithm, key, data, buffer); | 47 return status; |
| 369 case blink::WebCryptoAlgorithmIdAesKw: | 48 |
| 370 return EncryptDecryptAesKw(ENCRYPT, algorithm, key, data, buffer); | 49 return impl->Encrypt(algorithm, key, data, buffer); |
| 371 case blink::WebCryptoAlgorithmIdRsaOaep: | 50 } |
| 372 return EncryptRsaOaep(algorithm, key, data, buffer); | 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); |
| 373 default: | 69 default: |
| 374 return Status::ErrorUnsupported(); | 70 return Status::ErrorUnsupported(); |
| 375 } | 71 } |
| 376 } | 72 } |
| 377 | 73 |
| 378 Status UnwrapKeyDecryptAndImport( | |
| 379 blink::WebCryptoKeyFormat format, | |
| 380 const CryptoData& wrapped_key_data, | |
| 381 const blink::WebCryptoKey& wrapping_key, | |
| 382 const blink::WebCryptoAlgorithm& wrapping_algorithm, | |
| 383 const blink::WebCryptoAlgorithm& algorithm, | |
| 384 bool extractable, | |
| 385 blink::WebCryptoKeyUsageMask usage_mask, | |
| 386 blink::WebCryptoKey* key) { | |
| 387 std::vector<uint8> buffer; | |
| 388 Status status = DecryptDontCheckKeyUsage( | |
| 389 wrapping_algorithm, wrapping_key, wrapped_key_data, &buffer); | |
| 390 if (status.IsError()) | |
| 391 return status; | |
| 392 // NOTE that returning the details of ImportKey() failures may leak | |
| 393 // information about the plaintext of the encrypted key (for instance the JWK | |
| 394 // key_ops). As long as the ImportKey error messages don't describe actual | |
| 395 // key bytes however this should be OK. For more discussion see | |
| 396 // http://crubg.com/372040 | |
| 397 return ImportKey( | |
| 398 format, CryptoData(buffer), algorithm, extractable, usage_mask, key); | |
| 399 } | |
| 400 | |
| 401 Status WrapKeyExportAndEncrypt( | |
| 402 blink::WebCryptoKeyFormat format, | |
| 403 const blink::WebCryptoKey& key_to_wrap, | |
| 404 const blink::WebCryptoKey& wrapping_key, | |
| 405 const blink::WebCryptoAlgorithm& wrapping_algorithm, | |
| 406 std::vector<uint8>* buffer) { | |
| 407 std::vector<uint8> exported_data; | |
| 408 Status status = ExportKey(format, key_to_wrap, &exported_data); | |
| 409 if (status.IsError()) | |
| 410 return status; | |
| 411 return EncryptDontCheckUsage( | |
| 412 wrapping_algorithm, wrapping_key, CryptoData(exported_data), buffer); | |
| 413 } | |
| 414 | |
| 415 // Returns the internal block size for SHA-* | |
| 416 unsigned int ShaBlockSizeBytes(blink::WebCryptoAlgorithmId hash_id) { | |
| 417 switch (hash_id) { | |
| 418 case blink::WebCryptoAlgorithmIdSha1: | |
| 419 case blink::WebCryptoAlgorithmIdSha256: | |
| 420 return 64; | |
| 421 case blink::WebCryptoAlgorithmIdSha384: | |
| 422 case blink::WebCryptoAlgorithmIdSha512: | |
| 423 return 128; | |
| 424 default: | |
| 425 NOTREACHED(); | |
| 426 return 0; | |
| 427 } | |
| 428 } | |
| 429 | |
| 430 // Returns the mask of all key usages that are possible for |algorithm| and | |
| 431 // |key_type|. If the combination of |algorithm| and |key_type| doesn't make | |
| 432 // sense, then returns 0 (no usages). | |
| 433 blink::WebCryptoKeyUsageMask GetValidKeyUsagesForKeyType( | |
| 434 blink::WebCryptoAlgorithmId algorithm, | |
| 435 blink::WebCryptoKeyType key_type) { | |
| 436 if (IsAlgorithmAsymmetric(algorithm) == | |
| 437 (key_type == blink::WebCryptoKeyTypeSecret)) | |
| 438 return 0; | |
| 439 | |
| 440 switch (algorithm) { | |
| 441 case blink::WebCryptoAlgorithmIdAesCbc: | |
| 442 case blink::WebCryptoAlgorithmIdAesGcm: | |
| 443 case blink::WebCryptoAlgorithmIdAesCtr: | |
| 444 return blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageDecrypt | | |
| 445 blink::WebCryptoKeyUsageWrapKey | | |
| 446 blink::WebCryptoKeyUsageUnwrapKey; | |
| 447 case blink::WebCryptoAlgorithmIdAesKw: | |
| 448 return blink::WebCryptoKeyUsageWrapKey | | |
| 449 blink::WebCryptoKeyUsageUnwrapKey; | |
| 450 case blink::WebCryptoAlgorithmIdHmac: | |
| 451 return blink::WebCryptoKeyUsageSign | blink::WebCryptoKeyUsageVerify; | |
| 452 case blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5: | |
| 453 switch (key_type) { | |
| 454 case blink::WebCryptoKeyTypePublic: | |
| 455 return blink::WebCryptoKeyUsageVerify; | |
| 456 case blink::WebCryptoKeyTypePrivate: | |
| 457 return blink::WebCryptoKeyUsageSign; | |
| 458 default: | |
| 459 return 0; | |
| 460 } | |
| 461 case blink::WebCryptoAlgorithmIdRsaOaep: | |
| 462 switch (key_type) { | |
| 463 case blink::WebCryptoKeyTypePublic: | |
| 464 return blink::WebCryptoKeyUsageEncrypt | | |
| 465 blink::WebCryptoKeyUsageWrapKey; | |
| 466 case blink::WebCryptoKeyTypePrivate: | |
| 467 return blink::WebCryptoKeyUsageDecrypt | | |
| 468 blink::WebCryptoKeyUsageUnwrapKey; | |
| 469 default: | |
| 470 return 0; | |
| 471 } | |
| 472 default: | |
| 473 return 0; | |
| 474 } | |
| 475 } | |
| 476 | |
| 477 // Returns Status::Success() if |usages| is a valid set of key usages for | |
| 478 // |algorithm| and |key_type|. Otherwise returns an error. | |
| 479 // In the case of JWK format the check is incomplete for asymmetric algorithms. | |
| 480 Status BestEffortCheckKeyUsagesForImport(blink::WebCryptoAlgorithmId algorithm, | |
| 481 blink::WebCryptoKeyFormat format, | |
| 482 blink::WebCryptoKeyUsageMask usages) { | |
| 483 if (!IsAlgorithmAsymmetric(algorithm)) | |
| 484 return CheckKeyUsages(algorithm, blink::WebCryptoKeyTypeSecret, usages); | |
| 485 | |
| 486 // Try to infer the key type given the import format. | |
| 487 blink::WebCryptoKeyType key_type; | |
| 488 bool key_type_known = false; | |
| 489 | |
| 490 switch (format) { | |
| 491 case blink::WebCryptoKeyFormatRaw: | |
| 492 // TODO(eroman): The spec defines Diffie-Hellman raw import for public | |
| 493 // keys, so this will need to be updated in the future when DH is | |
| 494 // implemented. | |
| 495 return Status::ErrorUnexpected(); | |
| 496 case blink::WebCryptoKeyFormatSpki: | |
| 497 key_type = blink::WebCryptoKeyTypePublic; | |
| 498 key_type_known = true; | |
| 499 break; | |
| 500 case blink::WebCryptoKeyFormatPkcs8: | |
| 501 key_type = blink::WebCryptoKeyTypePrivate; | |
| 502 key_type_known = true; | |
| 503 break; | |
| 504 case blink::WebCryptoKeyFormatJwk: | |
| 505 key_type_known = false; | |
| 506 break; | |
| 507 default: | |
| 508 return Status::ErrorUnexpected(); | |
| 509 } | |
| 510 | |
| 511 if (key_type_known) | |
| 512 return CheckKeyUsages(algorithm, key_type, usages); | |
| 513 | |
| 514 // If the key type is not known, then the algorithm is asymmetric. Whether the | |
| 515 // key data describes a public or private key isn't known yet. But it must at | |
| 516 // least be ONE of those two. | |
| 517 DCHECK(IsAlgorithmAsymmetric(algorithm)); | |
| 518 | |
| 519 if (CheckKeyUsages(algorithm, blink::WebCryptoKeyTypePublic, usages) | |
| 520 .IsError() && | |
| 521 CheckKeyUsages(algorithm, blink::WebCryptoKeyTypePrivate, usages) | |
| 522 .IsError()) { | |
| 523 return Status::ErrorCreateKeyBadUsages(); | |
| 524 } | |
| 525 | |
| 526 return Status::Success(); | |
| 527 } | |
| 528 | |
| 529 // Returns an error if |combined_usage_mask| is invalid for generating a key | |
| 530 // pair for |algorithm|. Otherwise returns Status::Success(), and fills | |
| 531 // |public_key_usages| with the usages for the public key, and | |
| 532 // |private_key_usages| with those for the private key. | |
| 533 Status CheckKeyUsagesForGenerateKeyPair( | |
| 534 blink::WebCryptoAlgorithmId algorithm, | |
| 535 blink::WebCryptoKeyUsageMask combined_usage_mask, | |
| 536 blink::WebCryptoKeyUsageMask* public_key_usages, | |
| 537 blink::WebCryptoKeyUsageMask* private_key_usages) { | |
| 538 DCHECK(IsAlgorithmAsymmetric(algorithm)); | |
| 539 | |
| 540 blink::WebCryptoKeyUsageMask all_public_key_usages = | |
| 541 GetValidKeyUsagesForKeyType(algorithm, blink::WebCryptoKeyTypePublic); | |
| 542 blink::WebCryptoKeyUsageMask all_private_key_usages = | |
| 543 GetValidKeyUsagesForKeyType(algorithm, blink::WebCryptoKeyTypePrivate); | |
| 544 | |
| 545 if (!ContainsKeyUsages(all_public_key_usages | all_private_key_usages, | |
| 546 combined_usage_mask)) | |
| 547 return Status::ErrorCreateKeyBadUsages(); | |
| 548 | |
| 549 *public_key_usages = combined_usage_mask & all_public_key_usages; | |
| 550 *private_key_usages = combined_usage_mask & all_private_key_usages; | |
| 551 | |
| 552 return Status::Success(); | |
| 553 } | |
| 554 | |
| 555 // Converts a (big-endian) WebCrypto BigInteger, with or without leading zeros, | |
| 556 // to unsigned long. | |
| 557 bool BigIntegerToLong(const uint8* data, | |
| 558 unsigned int data_size, | |
| 559 unsigned long* result) { | |
| 560 // TODO(padolph): Is it correct to say that empty data is an error, or does it | |
| 561 // mean value 0? See https://www.w3.org/Bugs/Public/show_bug.cgi?id=23655 | |
| 562 if (data_size == 0) | |
| 563 return false; | |
| 564 | |
| 565 *result = 0; | |
| 566 for (size_t i = 0; i < data_size; ++i) { | |
| 567 size_t reverse_i = data_size - i - 1; | |
| 568 | |
| 569 if (reverse_i >= sizeof(unsigned long) && data[i]) | |
| 570 return false; // Too large for a long. | |
| 571 | |
| 572 *result |= data[i] << 8 * reverse_i; | |
| 573 } | |
| 574 return true; | |
| 575 } | |
| 576 | |
| 577 | |
| 578 } // namespace | 74 } // namespace |
| 579 | 75 |
| 580 void Init() { platform::Init(); } | |
| 581 | |
| 582 Status Encrypt(const blink::WebCryptoAlgorithm& algorithm, | 76 Status Encrypt(const blink::WebCryptoAlgorithm& algorithm, |
| 583 const blink::WebCryptoKey& key, | 77 const blink::WebCryptoKey& key, |
| 584 const CryptoData& data, | 78 const CryptoData& data, |
| 585 std::vector<uint8>* buffer) { | 79 std::vector<uint8>* buffer) { |
| 586 if (!KeyUsageAllows(key, blink::WebCryptoKeyUsageEncrypt)) | 80 if (!KeyUsageAllows(key, blink::WebCryptoKeyUsageEncrypt)) |
| 587 return Status::ErrorUnexpected(); | 81 return Status::ErrorUnexpected(); |
| 588 return EncryptDontCheckUsage(algorithm, key, data, buffer); | 82 return EncryptDontCheckUsage(algorithm, key, data, buffer); |
| 589 } | 83 } |
| 590 | 84 |
| 591 Status Decrypt(const blink::WebCryptoAlgorithm& algorithm, | 85 Status Decrypt(const blink::WebCryptoAlgorithm& algorithm, |
| 592 const blink::WebCryptoKey& key, | 86 const blink::WebCryptoKey& key, |
| 593 const CryptoData& data, | 87 const CryptoData& data, |
| 594 std::vector<uint8>* buffer) { | 88 std::vector<uint8>* buffer) { |
| 595 if (!KeyUsageAllows(key, blink::WebCryptoKeyUsageDecrypt)) | 89 if (!KeyUsageAllows(key, blink::WebCryptoKeyUsageDecrypt)) |
| 596 return Status::ErrorUnexpected(); | 90 return Status::ErrorUnexpected(); |
| 597 return DecryptDontCheckKeyUsage(algorithm, key, data, buffer); | 91 return DecryptDontCheckKeyUsage(algorithm, key, data, buffer); |
| 598 } | 92 } |
| 599 | 93 |
| 600 Status Digest(const blink::WebCryptoAlgorithm& algorithm, | 94 Status Digest(const blink::WebCryptoAlgorithm& algorithm, |
| 601 const CryptoData& data, | 95 const CryptoData& data, |
| 602 std::vector<uint8>* buffer) { | 96 std::vector<uint8>* buffer) { |
| 603 switch (algorithm.id()) { | 97 const AlgorithmImplementation* impl = NULL; |
| 604 case blink::WebCryptoAlgorithmIdSha1: | 98 Status status = GetAlgorithmImplementation(algorithm.id(), &impl); |
| 605 case blink::WebCryptoAlgorithmIdSha256: | 99 if (status.IsError()) |
| 606 case blink::WebCryptoAlgorithmIdSha384: | 100 return status; |
| 607 case blink::WebCryptoAlgorithmIdSha512: | |
| 608 return platform::DigestSha(algorithm.id(), data, buffer); | |
| 609 default: | |
| 610 return Status::ErrorUnsupported(); | |
| 611 } | |
| 612 } | |
| 613 | 101 |
| 614 scoped_ptr<blink::WebCryptoDigestor> CreateDigestor( | 102 return impl->Digest(algorithm, data, buffer); |
| 615 blink::WebCryptoAlgorithmId algorithm) { | |
| 616 return platform::CreateDigestor(algorithm); | |
| 617 } | 103 } |
| 618 | 104 |
| 619 Status GenerateSecretKey(const blink::WebCryptoAlgorithm& algorithm, | 105 Status GenerateSecretKey(const blink::WebCryptoAlgorithm& algorithm, |
| 620 bool extractable, | 106 bool extractable, |
| 621 blink::WebCryptoKeyUsageMask usage_mask, | 107 blink::WebCryptoKeyUsageMask usage_mask, |
| 622 blink::WebCryptoKey* key) { | 108 blink::WebCryptoKey* key) { |
| 623 Status status = | 109 const AlgorithmImplementation* impl = NULL; |
| 624 CheckKeyUsages(algorithm.id(), blink::WebCryptoKeyTypeSecret, usage_mask); | 110 Status status = GetAlgorithmImplementation(algorithm.id(), &impl); |
| 625 if (status.IsError()) | 111 if (status.IsError()) |
| 626 return status; | 112 return status; |
| 627 | 113 |
| 628 unsigned int keylen_bytes = 0; | 114 status = impl->VerifyKeyUsagesBeforeGenerateKey(usage_mask); |
| 115 if (status.IsError()) |
| 116 return status; |
| 629 | 117 |
| 630 // Get the secret key length in bytes from generation parameters. | 118 return impl->GenerateSecretKey(algorithm, extractable, usage_mask, key); |
| 631 // This resolves any defaults. | |
| 632 switch (algorithm.id()) { | |
| 633 case blink::WebCryptoAlgorithmIdAesCbc: | |
| 634 case blink::WebCryptoAlgorithmIdAesGcm: | |
| 635 case blink::WebCryptoAlgorithmIdAesKw: { | |
| 636 if (!IsValidAesKeyLengthBits(algorithm.aesKeyGenParams()->lengthBits())) { | |
| 637 return algorithm.aesKeyGenParams()->lengthBits() == 192 | |
| 638 ? Status::ErrorAes192BitUnsupported() | |
| 639 : Status::ErrorGenerateKeyLength(); | |
| 640 } | |
| 641 keylen_bytes = algorithm.aesKeyGenParams()->lengthBits() / 8; | |
| 642 break; | |
| 643 } | |
| 644 case blink::WebCryptoAlgorithmIdHmac: { | |
| 645 const blink::WebCryptoHmacKeyGenParams* params = | |
| 646 algorithm.hmacKeyGenParams(); | |
| 647 DCHECK(params); | |
| 648 if (params->hasLengthBits()) { | |
| 649 if (params->optionalLengthBits() % 8) | |
| 650 return Status::ErrorGenerateKeyLength(); | |
| 651 keylen_bytes = params->optionalLengthBits() / 8; | |
| 652 } else { | |
| 653 keylen_bytes = ShaBlockSizeBytes(params->hash().id()); | |
| 654 if (keylen_bytes == 0) | |
| 655 return Status::ErrorUnsupported(); | |
| 656 } | |
| 657 break; | |
| 658 } | |
| 659 | |
| 660 default: | |
| 661 return Status::ErrorUnsupported(); | |
| 662 } | |
| 663 | |
| 664 // TODO(eroman): Is this correct? HMAC can import zero-length keys, so should | |
| 665 // probably be able to allowed to generate them too. | |
| 666 if (keylen_bytes == 0) | |
| 667 return Status::ErrorGenerateKeyLength(); | |
| 668 | |
| 669 return platform::GenerateSecretKey( | |
| 670 algorithm, extractable, usage_mask, keylen_bytes, key); | |
| 671 } | 119 } |
| 672 | 120 |
| 673 Status GenerateKeyPair(const blink::WebCryptoAlgorithm& algorithm, | 121 Status GenerateKeyPair(const blink::WebCryptoAlgorithm& algorithm, |
| 674 bool extractable, | 122 bool extractable, |
| 675 blink::WebCryptoKeyUsageMask combined_usage_mask, | 123 blink::WebCryptoKeyUsageMask combined_usage_mask, |
| 676 blink::WebCryptoKey* public_key, | 124 blink::WebCryptoKey* public_key, |
| 677 blink::WebCryptoKey* private_key) { | 125 blink::WebCryptoKey* private_key) { |
| 678 blink::WebCryptoKeyUsageMask public_key_usage_mask = 0; | 126 const AlgorithmImplementation* impl = NULL; |
| 679 blink::WebCryptoKeyUsageMask private_key_usage_mask = 0; | 127 Status status = GetAlgorithmImplementation(algorithm.id(), &impl); |
| 680 | |
| 681 Status status = CheckKeyUsagesForGenerateKeyPair(algorithm.id(), | |
| 682 combined_usage_mask, | |
| 683 &public_key_usage_mask, | |
| 684 &private_key_usage_mask); | |
| 685 if (status.IsError()) | 128 if (status.IsError()) |
| 686 return status; | 129 return status; |
| 687 | 130 |
| 688 // TODO(padolph): Handle other asymmetric algorithm key generation. | 131 blink::WebCryptoKeyUsageMask public_usage_mask; |
| 689 switch (algorithm.paramsType()) { | 132 blink::WebCryptoKeyUsageMask private_usage_mask; |
| 690 case blink::WebCryptoAlgorithmParamsTypeRsaHashedKeyGenParams: { | 133 status = impl->VerifyKeyUsagesBeforeGenerateKeyPair( |
| 691 const blink::WebCryptoRsaHashedKeyGenParams* params = | 134 combined_usage_mask, &public_usage_mask, &private_usage_mask); |
| 692 algorithm.rsaHashedKeyGenParams(); | 135 if (status.IsError()) |
| 136 return status; |
| 693 | 137 |
| 694 if (!params->modulusLengthBits()) | 138 return impl->GenerateKeyPair(algorithm, |
| 695 return Status::ErrorGenerateRsaZeroModulus(); | 139 extractable, |
| 696 | 140 public_usage_mask, |
| 697 unsigned long public_exponent = 0; | 141 private_usage_mask, |
| 698 if (!BigIntegerToLong(params->publicExponent().data(), | 142 public_key, |
| 699 params->publicExponent().size(), | 143 private_key); |
| 700 &public_exponent) || | |
| 701 (public_exponent != 3 && public_exponent != 65537)) { | |
| 702 return Status::ErrorGenerateKeyPublicExponent(); | |
| 703 } | |
| 704 | |
| 705 return platform::GenerateRsaKeyPair(algorithm, | |
| 706 extractable, | |
| 707 public_key_usage_mask, | |
| 708 private_key_usage_mask, | |
| 709 params->modulusLengthBits(), | |
| 710 public_exponent, | |
| 711 public_key, | |
| 712 private_key); | |
| 713 } | |
| 714 default: | |
| 715 return Status::ErrorUnsupported(); | |
| 716 } | |
| 717 } | 144 } |
| 718 | 145 |
| 719 // Note that this function may be called from the target Blink thread. | 146 // Note that this function may be called from the target Blink thread. |
| 720 Status ImportKey(blink::WebCryptoKeyFormat format, | 147 Status ImportKey(blink::WebCryptoKeyFormat format, |
| 721 const CryptoData& key_data, | 148 const CryptoData& key_data, |
| 722 const blink::WebCryptoAlgorithm& algorithm, | 149 const blink::WebCryptoAlgorithm& algorithm, |
| 723 bool extractable, | 150 bool extractable, |
| 724 blink::WebCryptoKeyUsageMask usage_mask, | 151 blink::WebCryptoKeyUsageMask usage_mask, |
| 725 blink::WebCryptoKey* key) { | 152 blink::WebCryptoKey* key) { |
| 726 // This is "best effort" because it is incomplete for JWK (for which the key | 153 const AlgorithmImplementation* impl = NULL; |
| 727 // type is not yet known). ImportKeyJwk() does extra checks on key usage once | 154 Status status = GetAlgorithmImplementation(algorithm.id(), &impl); |
| 728 // the key type has been determined. | 155 if (status.IsError()) |
| 729 Status status = | 156 return status; |
| 730 BestEffortCheckKeyUsagesForImport(algorithm.id(), format, usage_mask); | 157 |
| 158 status = impl->VerifyKeyUsagesBeforeImportKey(format, usage_mask); |
| 731 if (status.IsError()) | 159 if (status.IsError()) |
| 732 return status; | 160 return status; |
| 733 | 161 |
| 734 switch (format) { | 162 switch (format) { |
| 735 case blink::WebCryptoKeyFormatRaw: | 163 case blink::WebCryptoKeyFormatRaw: |
| 736 return ImportKeyRaw(key_data, algorithm, extractable, usage_mask, key); | 164 return impl->ImportKeyRaw( |
| 165 key_data, algorithm, extractable, usage_mask, key); |
| 737 case blink::WebCryptoKeyFormatSpki: | 166 case blink::WebCryptoKeyFormatSpki: |
| 738 return platform::ImportKeySpki( | 167 return impl->ImportKeySpki( |
| 739 algorithm, key_data, extractable, usage_mask, key); | 168 key_data, algorithm, extractable, usage_mask, key); |
| 740 case blink::WebCryptoKeyFormatPkcs8: | 169 case blink::WebCryptoKeyFormatPkcs8: |
| 741 return platform::ImportKeyPkcs8( | 170 return impl->ImportKeyPkcs8( |
| 742 algorithm, key_data, extractable, usage_mask, key); | 171 key_data, algorithm, extractable, usage_mask, key); |
| 743 case blink::WebCryptoKeyFormatJwk: | 172 case blink::WebCryptoKeyFormatJwk: |
| 744 return ImportKeyJwk(key_data, algorithm, extractable, usage_mask, key); | 173 return impl->ImportKeyJwk( |
| 174 key_data, algorithm, extractable, usage_mask, key); |
| 745 default: | 175 default: |
| 746 return Status::ErrorUnsupported(); | 176 return Status::ErrorUnsupported(); |
| 747 } | 177 } |
| 748 } | |
| 749 | |
| 750 // TODO(eroman): Move this to anonymous namespace. | |
| 751 Status ExportKeyDontCheckExtractability(blink::WebCryptoKeyFormat format, | |
| 752 const blink::WebCryptoKey& key, | |
| 753 std::vector<uint8>* buffer) { | |
| 754 switch (format) { | |
| 755 case blink::WebCryptoKeyFormatRaw: { | |
| 756 platform::SymKey* sym_key; | |
| 757 Status status = ToPlatformSymKey(key, &sym_key); | |
| 758 if (status.IsError()) | |
| 759 return status; | |
| 760 return platform::ExportKeyRaw(sym_key, buffer); | |
| 761 } | |
| 762 case blink::WebCryptoKeyFormatSpki: { | |
| 763 platform::PublicKey* public_key; | |
| 764 Status status = ToPlatformPublicKey(key, &public_key); | |
| 765 if (status.IsError()) | |
| 766 return status; | |
| 767 return platform::ExportKeySpki(public_key, buffer); | |
| 768 } | |
| 769 case blink::WebCryptoKeyFormatPkcs8: { | |
| 770 platform::PrivateKey* private_key; | |
| 771 Status status = ToPlatformPrivateKey(key, &private_key); | |
| 772 if (status.IsError()) | |
| 773 return status; | |
| 774 return platform::ExportKeyPkcs8(private_key, key.algorithm(), buffer); | |
| 775 } | |
| 776 case blink::WebCryptoKeyFormatJwk: | |
| 777 return ExportKeyJwk(key, buffer); | |
| 778 default: | |
| 779 return Status::ErrorUnsupported(); | |
| 780 } | |
| 781 } | 178 } |
| 782 | 179 |
| 783 Status ExportKey(blink::WebCryptoKeyFormat format, | 180 Status ExportKey(blink::WebCryptoKeyFormat format, |
| 784 const blink::WebCryptoKey& key, | 181 const blink::WebCryptoKey& key, |
| 785 std::vector<uint8>* buffer) { | 182 std::vector<uint8>* buffer) { |
| 786 if (!key.extractable()) | 183 if (!key.extractable()) |
| 787 return Status::ErrorKeyNotExtractable(); | 184 return Status::ErrorKeyNotExtractable(); |
| 788 return ExportKeyDontCheckExtractability(format, key, buffer); | 185 return ExportKeyDontCheckExtractability(format, key, buffer); |
| 789 } | 186 } |
| 790 | 187 |
| 791 Status Sign(const blink::WebCryptoAlgorithm& algorithm, | 188 Status Sign(const blink::WebCryptoAlgorithm& algorithm, |
| 792 const blink::WebCryptoKey& key, | 189 const blink::WebCryptoKey& key, |
| 793 const CryptoData& data, | 190 const CryptoData& data, |
| 794 std::vector<uint8>* buffer) { | 191 std::vector<uint8>* buffer) { |
| 795 if (!KeyUsageAllows(key, blink::WebCryptoKeyUsageSign)) | 192 if (!KeyUsageAllows(key, blink::WebCryptoKeyUsageSign)) |
| 796 return Status::ErrorUnexpected(); | 193 return Status::ErrorUnexpected(); |
| 797 if (algorithm.id() != key.algorithm().id()) | 194 if (algorithm.id() != key.algorithm().id()) |
| 798 return Status::ErrorUnexpected(); | 195 return Status::ErrorUnexpected(); |
| 799 | 196 |
| 800 switch (algorithm.id()) { | 197 const AlgorithmImplementation* impl = NULL; |
| 801 case blink::WebCryptoAlgorithmIdHmac: | 198 Status status = GetAlgorithmImplementation(algorithm.id(), &impl); |
| 802 return SignHmac(algorithm, key, data, buffer); | 199 if (status.IsError()) |
| 803 case blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5: | 200 return status; |
| 804 return SignRsaSsaPkcs1v1_5(algorithm, key, data, buffer); | 201 |
| 805 default: | 202 return impl->Sign(algorithm, key, data, buffer); |
| 806 return Status::ErrorUnsupported(); | |
| 807 } | |
| 808 } | 203 } |
| 809 | 204 |
| 810 Status VerifySignature(const blink::WebCryptoAlgorithm& algorithm, | 205 Status Verify(const blink::WebCryptoAlgorithm& algorithm, |
| 811 const blink::WebCryptoKey& key, | 206 const blink::WebCryptoKey& key, |
| 812 const CryptoData& signature, | 207 const CryptoData& signature, |
| 813 const CryptoData& data, | 208 const CryptoData& data, |
| 814 bool* signature_match) { | 209 bool* signature_match) { |
| 815 if (!KeyUsageAllows(key, blink::WebCryptoKeyUsageVerify)) | 210 if (!KeyUsageAllows(key, blink::WebCryptoKeyUsageVerify)) |
| 816 return Status::ErrorUnexpected(); | 211 return Status::ErrorUnexpected(); |
| 817 if (algorithm.id() != key.algorithm().id()) | 212 if (algorithm.id() != key.algorithm().id()) |
| 818 return Status::ErrorUnexpected(); | 213 return Status::ErrorUnexpected(); |
| 819 | 214 |
| 215 // TODO(eroman): Move this into implementation which need it instead. |
| 820 if (!signature.byte_length()) { | 216 if (!signature.byte_length()) { |
| 821 // None of the algorithms generate valid zero-length signatures so this | 217 // None of the algorithms generate valid zero-length signatures so this |
| 822 // will necessarily fail verification. Early return to protect | 218 // will necessarily fail verification. Early return to protect |
| 823 // implementations from dealing with a NULL signature pointer. | 219 // implementations from dealing with a NULL signature pointer. |
| 824 *signature_match = false; | 220 *signature_match = false; |
| 825 return Status::Success(); | 221 return Status::Success(); |
| 826 } | 222 } |
| 827 | 223 |
| 828 switch (algorithm.id()) { | 224 const AlgorithmImplementation* impl = NULL; |
| 829 case blink::WebCryptoAlgorithmIdHmac: | 225 Status status = GetAlgorithmImplementation(algorithm.id(), &impl); |
| 830 return VerifyHmac(algorithm, key, signature, data, signature_match); | 226 if (status.IsError()) |
| 831 case blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5: | 227 return status; |
| 832 return VerifyRsaSsaPkcs1v1_5( | 228 |
| 833 algorithm, key, signature, data, signature_match); | 229 return impl->Verify(algorithm, key, signature, data, signature_match); |
| 834 default: | |
| 835 return Status::ErrorUnsupported(); | |
| 836 } | |
| 837 } | 230 } |
| 838 | 231 |
| 839 Status WrapKey(blink::WebCryptoKeyFormat format, | 232 Status WrapKey(blink::WebCryptoKeyFormat format, |
| 840 const blink::WebCryptoKey& key_to_wrap, | 233 const blink::WebCryptoKey& key_to_wrap, |
| 841 const blink::WebCryptoKey& wrapping_key, | 234 const blink::WebCryptoKey& wrapping_key, |
| 842 const blink::WebCryptoAlgorithm& wrapping_algorithm, | 235 const blink::WebCryptoAlgorithm& wrapping_algorithm, |
| 843 std::vector<uint8>* buffer) { | 236 std::vector<uint8>* buffer) { |
| 844 if (!KeyUsageAllows(wrapping_key, blink::WebCryptoKeyUsageWrapKey)) | 237 if (!KeyUsageAllows(wrapping_key, blink::WebCryptoKeyUsageWrapKey)) |
| 845 return Status::ErrorUnexpected(); | 238 return Status::ErrorUnexpected(); |
| 846 if (wrapping_algorithm.id() != wrapping_key.algorithm().id()) | |
| 847 return Status::ErrorUnexpected(); | |
| 848 | 239 |
| 849 return WrapKeyExportAndEncrypt( | 240 std::vector<uint8> exported_data; |
| 850 format, key_to_wrap, wrapping_key, wrapping_algorithm, buffer); | 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); |
| 851 } | 246 } |
| 852 | 247 |
| 853 Status UnwrapKey(blink::WebCryptoKeyFormat format, | 248 Status UnwrapKey(blink::WebCryptoKeyFormat format, |
| 854 const CryptoData& wrapped_key_data, | 249 const CryptoData& wrapped_key_data, |
| 855 const blink::WebCryptoKey& wrapping_key, | 250 const blink::WebCryptoKey& wrapping_key, |
| 856 const blink::WebCryptoAlgorithm& wrapping_algorithm, | 251 const blink::WebCryptoAlgorithm& wrapping_algorithm, |
| 857 const blink::WebCryptoAlgorithm& algorithm, | 252 const blink::WebCryptoAlgorithm& algorithm, |
| 858 bool extractable, | 253 bool extractable, |
| 859 blink::WebCryptoKeyUsageMask usage_mask, | 254 blink::WebCryptoKeyUsageMask usage_mask, |
| 860 blink::WebCryptoKey* key) { | 255 blink::WebCryptoKey* key) { |
| 861 if (!KeyUsageAllows(wrapping_key, blink::WebCryptoKeyUsageUnwrapKey)) | 256 if (!KeyUsageAllows(wrapping_key, blink::WebCryptoKeyUsageUnwrapKey)) |
| 862 return Status::ErrorUnexpected(); | 257 return Status::ErrorUnexpected(); |
| 863 if (wrapping_algorithm.id() != wrapping_key.algorithm().id()) | 258 if (wrapping_algorithm.id() != wrapping_key.algorithm().id()) |
| 864 return Status::ErrorUnexpected(); | 259 return Status::ErrorUnexpected(); |
| 865 | 260 |
| 866 // Fail-fast if the key usages don't make sense. This avoids decrypting the | 261 // Fail fast if the import is doomed to fail. |
| 867 // key only to then have import fail. It is "best effort" because when | 262 const AlgorithmImplementation* import_impl = NULL; |
| 868 // unwrapping JWK for asymmetric algorithms the key type isn't known yet. | 263 Status status = GetAlgorithmImplementation(algorithm.id(), &import_impl); |
| 869 Status status = | |
| 870 BestEffortCheckKeyUsagesForImport(algorithm.id(), format, usage_mask); | |
| 871 if (status.IsError()) | 264 if (status.IsError()) |
| 872 return status; | 265 return status; |
| 873 | 266 |
| 874 return UnwrapKeyDecryptAndImport(format, | 267 status = import_impl->VerifyKeyUsagesBeforeImportKey(format, usage_mask); |
| 875 wrapped_key_data, | 268 if (status.IsError()) |
| 876 wrapping_key, | 269 return status; |
| 877 wrapping_algorithm, | 270 |
| 878 algorithm, | 271 std::vector<uint8> buffer; |
| 879 extractable, | 272 status = DecryptDontCheckKeyUsage( |
| 880 usage_mask, | 273 wrapping_algorithm, wrapping_key, wrapped_key_data, &buffer); |
| 881 key); | 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); |
| 882 } | 284 } |
| 883 | 285 |
| 884 // Note that this function is called from the target Blink thread. | 286 scoped_ptr<blink::WebCryptoDigestor> CreateDigestor( |
| 885 bool SerializeKeyForClone(const blink::WebCryptoKey& key, | 287 blink::WebCryptoAlgorithmId algorithm) { |
| 886 blink::WebVector<uint8>* key_data) { | 288 return CreatePlatformDigestor(algorithm); |
| 887 return static_cast<webcrypto::platform::Key*>(key.handle()) | |
| 888 ->ThreadSafeSerializeForClone(key_data); | |
| 889 } | |
| 890 | |
| 891 // Note that this function is called from the target Blink thread. | |
| 892 bool DeserializeKeyForClone(const blink::WebCryptoKeyAlgorithm& algorithm, | |
| 893 blink::WebCryptoKeyType type, | |
| 894 bool extractable, | |
| 895 blink::WebCryptoKeyUsageMask usage_mask, | |
| 896 const CryptoData& key_data, | |
| 897 blink::WebCryptoKey* key) { | |
| 898 // TODO(eroman): This should not call into the platform crypto layer. | |
| 899 // Otherwise it runs the risk of stalling while the NSS/OpenSSL global locks | |
| 900 // are held. | |
| 901 // | |
| 902 // An alternate approach is to defer the key import until the key is used. | |
| 903 // However this means that any deserialization errors would have to be | |
| 904 // surfaced as WebCrypto errors, leading to slightly different behaviors. For | |
| 905 // instance you could clone a key which fails to be deserialized. | |
| 906 Status status = ImportKey(GetCloneFormatForKeyType(type), | |
| 907 key_data, | |
| 908 KeyAlgorithmToImportAlgorithm(algorithm), | |
| 909 extractable, | |
| 910 usage_mask, | |
| 911 key); | |
| 912 if (status.IsError()) | |
| 913 return false; | |
| 914 return ValidateDeserializedKey(*key, algorithm, type); | |
| 915 } | |
| 916 | |
| 917 Status ToPlatformSymKey(const blink::WebCryptoKey& key, | |
| 918 platform::SymKey** out) { | |
| 919 *out = static_cast<platform::Key*>(key.handle())->AsSymKey(); | |
| 920 if (!*out) | |
| 921 return Status::ErrorUnexpectedKeyType(); | |
| 922 return Status::Success(); | |
| 923 } | |
| 924 | |
| 925 Status ToPlatformPublicKey(const blink::WebCryptoKey& key, | |
| 926 platform::PublicKey** out) { | |
| 927 *out = static_cast<platform::Key*>(key.handle())->AsPublicKey(); | |
| 928 if (!*out) | |
| 929 return Status::ErrorUnexpectedKeyType(); | |
| 930 return Status::Success(); | |
| 931 } | |
| 932 | |
| 933 Status ToPlatformPrivateKey(const blink::WebCryptoKey& key, | |
| 934 platform::PrivateKey** out) { | |
| 935 *out = static_cast<platform::Key*>(key.handle())->AsPrivateKey(); | |
| 936 if (!*out) | |
| 937 return Status::ErrorUnexpectedKeyType(); | |
| 938 return Status::Success(); | |
| 939 } | |
| 940 | |
| 941 // Returns Status::Success() if |usages| is a valid set of key usages for | |
| 942 // |algorithm| and |key_type|. Otherwise returns an error. | |
| 943 Status CheckKeyUsages(blink::WebCryptoAlgorithmId algorithm, | |
| 944 blink::WebCryptoKeyType key_type, | |
| 945 blink::WebCryptoKeyUsageMask usages) { | |
| 946 if (!ContainsKeyUsages(GetValidKeyUsagesForKeyType(algorithm, key_type), | |
| 947 usages)) | |
| 948 return Status::ErrorCreateKeyBadUsages(); | |
| 949 | |
| 950 return Status::Success(); | |
| 951 } | 289 } |
| 952 | 290 |
| 953 } // namespace webcrypto | 291 } // namespace webcrypto |
| 954 | 292 |
| 955 } // namespace content | 293 } // namespace content |
| OLD | NEW |