// 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/algorithm_dispatch.h" #include "base/logging.h" #include "content/child/webcrypto/algorithm_implementation.h" #include "content/child/webcrypto/algorithm_registry.h" #include "content/child/webcrypto/crypto_data.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 { Status DecryptDontCheckKeyUsage(const blink::WebCryptoAlgorithm& algorithm, const blink::WebCryptoKey& key, const CryptoData& data, std::vector<uint8_t>* buffer) { if (algorithm.id() != key.algorithm().id()) return Status::ErrorUnexpected(); const AlgorithmImplementation* impl = NULL; Status status = GetAlgorithmImplementation(algorithm.id(), &impl); if (status.IsError()) return status; return impl->Decrypt(algorithm, key, data, buffer); } Status EncryptDontCheckUsage(const blink::WebCryptoAlgorithm& algorithm, const blink::WebCryptoKey& key, const CryptoData& data, std::vector<uint8_t>* buffer) { if (algorithm.id() != key.algorithm().id()) return Status::ErrorUnexpected(); const AlgorithmImplementation* impl = NULL; Status status = GetAlgorithmImplementation(algorithm.id(), &impl); if (status.IsError()) return status; return impl->Encrypt(algorithm, key, data, buffer); } Status ExportKeyDontCheckExtractability(blink::WebCryptoKeyFormat format, const blink::WebCryptoKey& key, std::vector<uint8_t>* buffer) { const AlgorithmImplementation* impl = NULL; Status status = GetAlgorithmImplementation(key.algorithm().id(), &impl); if (status.IsError()) return status; switch (format) { case blink::WebCryptoKeyFormatRaw: return impl->ExportKeyRaw(key, buffer); case blink::WebCryptoKeyFormatSpki: return impl->ExportKeySpki(key, buffer); case blink::WebCryptoKeyFormatPkcs8: return impl->ExportKeyPkcs8(key, buffer); case blink::WebCryptoKeyFormatJwk: return impl->ExportKeyJwk(key, buffer); default: return Status::ErrorUnsupported(); } } } // namespace Status Encrypt(const blink::WebCryptoAlgorithm& algorithm, const blink::WebCryptoKey& key, const CryptoData& data, std::vector<uint8_t>* buffer) { if (!KeyUsageAllows(key, blink::WebCryptoKeyUsageEncrypt)) return Status::ErrorUnexpected(); return EncryptDontCheckUsage(algorithm, key, data, buffer); } Status Decrypt(const blink::WebCryptoAlgorithm& algorithm, const blink::WebCryptoKey& key, const CryptoData& data, std::vector<uint8_t>* buffer) { if (!KeyUsageAllows(key, blink::WebCryptoKeyUsageDecrypt)) return Status::ErrorUnexpected(); return DecryptDontCheckKeyUsage(algorithm, key, data, buffer); } Status Digest(const blink::WebCryptoAlgorithm& algorithm, const CryptoData& data, std::vector<uint8_t>* buffer) { const AlgorithmImplementation* impl = NULL; Status status = GetAlgorithmImplementation(algorithm.id(), &impl); if (status.IsError()) return status; return impl->Digest(algorithm, data, buffer); } Status GenerateSecretKey(const blink::WebCryptoAlgorithm& algorithm, bool extractable, blink::WebCryptoKeyUsageMask usage_mask, blink::WebCryptoKey* key) { const AlgorithmImplementation* impl = NULL; Status status = GetAlgorithmImplementation(algorithm.id(), &impl); if (status.IsError()) return status; status = impl->VerifyKeyUsagesBeforeGenerateKey(usage_mask); if (status.IsError()) return status; return impl->GenerateSecretKey(algorithm, extractable, usage_mask, key); } Status GenerateKeyPair(const blink::WebCryptoAlgorithm& algorithm, bool extractable, blink::WebCryptoKeyUsageMask combined_usage_mask, blink::WebCryptoKey* public_key, blink::WebCryptoKey* private_key) { const AlgorithmImplementation* impl = NULL; Status status = GetAlgorithmImplementation(algorithm.id(), &impl); if (status.IsError()) return status; blink::WebCryptoKeyUsageMask public_usage_mask; blink::WebCryptoKeyUsageMask private_usage_mask; status = impl->VerifyKeyUsagesBeforeGenerateKeyPair( combined_usage_mask, &public_usage_mask, &private_usage_mask); if (status.IsError()) return status; return impl->GenerateKeyPair(algorithm, extractable, public_usage_mask, private_usage_mask, public_key, private_key); } // Note that this function may be called from the target Blink thread. Status ImportKey(blink::WebCryptoKeyFormat format, const CryptoData& key_data, const blink::WebCryptoAlgorithm& algorithm, bool extractable, blink::WebCryptoKeyUsageMask usage_mask, blink::WebCryptoKey* key) { const AlgorithmImplementation* impl = NULL; Status status = GetAlgorithmImplementation(algorithm.id(), &impl); if (status.IsError()) return status; status = impl->VerifyKeyUsagesBeforeImportKey(format, usage_mask); if (status.IsError()) return status; switch (format) { case blink::WebCryptoKeyFormatRaw: return impl->ImportKeyRaw( key_data, algorithm, extractable, usage_mask, key); case blink::WebCryptoKeyFormatSpki: return impl->ImportKeySpki( key_data, algorithm, extractable, usage_mask, key); case blink::WebCryptoKeyFormatPkcs8: return impl->ImportKeyPkcs8( key_data, algorithm, extractable, usage_mask, key); case blink::WebCryptoKeyFormatJwk: return impl->ImportKeyJwk( key_data, algorithm, extractable, usage_mask, key); default: return Status::ErrorUnsupported(); } } Status ExportKey(blink::WebCryptoKeyFormat format, const blink::WebCryptoKey& key, std::vector<uint8_t>* buffer) { if (!key.extractable()) return Status::ErrorKeyNotExtractable(); return ExportKeyDontCheckExtractability(format, key, buffer); } Status Sign(const blink::WebCryptoAlgorithm& algorithm, const blink::WebCryptoKey& key, const CryptoData& data, std::vector<uint8_t>* buffer) { if (!KeyUsageAllows(key, blink::WebCryptoKeyUsageSign)) return Status::ErrorUnexpected(); if (algorithm.id() != key.algorithm().id()) return Status::ErrorUnexpected(); const AlgorithmImplementation* impl = NULL; Status status = GetAlgorithmImplementation(algorithm.id(), &impl); if (status.IsError()) return status; return impl->Sign(algorithm, key, data, buffer); } Status Verify(const blink::WebCryptoAlgorithm& algorithm, const blink::WebCryptoKey& key, const CryptoData& signature, const CryptoData& data, bool* signature_match) { if (!KeyUsageAllows(key, blink::WebCryptoKeyUsageVerify)) return Status::ErrorUnexpected(); if (algorithm.id() != key.algorithm().id()) return Status::ErrorUnexpected(); const AlgorithmImplementation* impl = NULL; Status status = GetAlgorithmImplementation(algorithm.id(), &impl); if (status.IsError()) return status; return impl->Verify(algorithm, key, signature, data, signature_match); } Status WrapKey(blink::WebCryptoKeyFormat format, const blink::WebCryptoKey& key_to_wrap, const blink::WebCryptoKey& wrapping_key, const blink::WebCryptoAlgorithm& wrapping_algorithm, std::vector<uint8_t>* buffer) { if (!KeyUsageAllows(wrapping_key, blink::WebCryptoKeyUsageWrapKey)) return Status::ErrorUnexpected(); std::vector<uint8_t> exported_data; Status status = ExportKey(format, key_to_wrap, &exported_data); if (status.IsError()) return status; return EncryptDontCheckUsage( wrapping_algorithm, wrapping_key, CryptoData(exported_data), buffer); } Status UnwrapKey(blink::WebCryptoKeyFormat format, const CryptoData& wrapped_key_data, const blink::WebCryptoKey& wrapping_key, const blink::WebCryptoAlgorithm& wrapping_algorithm, const blink::WebCryptoAlgorithm& algorithm, bool extractable, blink::WebCryptoKeyUsageMask usage_mask, blink::WebCryptoKey* key) { if (!KeyUsageAllows(wrapping_key, blink::WebCryptoKeyUsageUnwrapKey)) return Status::ErrorUnexpected(); if (wrapping_algorithm.id() != wrapping_key.algorithm().id()) return Status::ErrorUnexpected(); // Fail fast if the import is doomed to fail. const AlgorithmImplementation* import_impl = NULL; Status status = GetAlgorithmImplementation(algorithm.id(), &import_impl); if (status.IsError()) return status; status = import_impl->VerifyKeyUsagesBeforeImportKey(format, usage_mask); if (status.IsError()) return status; std::vector<uint8_t> buffer; status = DecryptDontCheckKeyUsage( wrapping_algorithm, wrapping_key, wrapped_key_data, &buffer); if (status.IsError()) return status; // NOTE that returning the details of ImportKey() failures may leak // information about the plaintext of the encrypted key (for instance the JWK // key_ops). As long as the ImportKey error messages don't describe actual // key bytes however this should be OK. For more discussion see // http://crubg.com/372040 return ImportKey( format, CryptoData(buffer), algorithm, extractable, usage_mask, key); } scoped_ptr<blink::WebCryptoDigestor> CreateDigestor( blink::WebCryptoAlgorithmId algorithm) { PlatformInit(); return CreatePlatformDigestor(algorithm); } } // namespace webcrypto } // namespace content