| // Copyright 2016 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 "components/webcrypto/fuzzer_support.h" |
| |
| #include "base/command_line.h" |
| #include "base/lazy_instance.h" |
| #include "base/message_loop/message_loop.h" |
| #include "base/numerics/safe_conversions.h" |
| #include "components/webcrypto/algorithm_dispatch.h" |
| #include "components/webcrypto/crypto_data.h" |
| #include "components/webcrypto/status.h" |
| #include "mojo/core/embedder/embedder.h" |
| #include "third_party/blink/public/platform/platform.h" |
| #include "third_party/blink/public/platform/web_crypto_algorithm_params.h" |
| #include "third_party/blink/public/web/blink.h" |
| |
| namespace webcrypto { |
| |
| namespace { |
| |
| // This mock is used to initialize blink. |
| class InitOnce : public blink::Platform { |
| public: |
| InitOnce() { |
| base::CommandLine::Init(0, nullptr); |
| mojo::core::Init(); |
| blink::Platform::CreateMainThreadAndInitialize(this); |
| } |
| ~InitOnce() override {} |
| |
| private: |
| base::MessageLoop loop_; |
| }; |
| |
| base::LazyInstance<InitOnce>::Leaky g_once = LAZY_INSTANCE_INITIALIZER; |
| |
| void EnsureInitialized() { |
| g_once.Get(); |
| } |
| |
| blink::WebCryptoAlgorithm CreateRsaHashedImportAlgorithm( |
| blink::WebCryptoAlgorithmId id, |
| blink::WebCryptoAlgorithmId hash_id) { |
| DCHECK(blink::WebCryptoAlgorithm::IsHash(hash_id)); |
| return blink::WebCryptoAlgorithm::AdoptParamsAndCreate( |
| id, |
| new blink::WebCryptoRsaHashedImportParams( |
| blink::WebCryptoAlgorithm::AdoptParamsAndCreate(hash_id, nullptr))); |
| } |
| |
| blink::WebCryptoAlgorithm CreateEcImportAlgorithm( |
| blink::WebCryptoAlgorithmId id, |
| blink::WebCryptoNamedCurve named_curve) { |
| return blink::WebCryptoAlgorithm::AdoptParamsAndCreate( |
| id, new blink::WebCryptoEcKeyImportParams(named_curve)); |
| } |
| |
| } // namespace |
| |
| blink::WebCryptoKeyUsageMask GetCompatibleKeyUsages( |
| blink::WebCryptoKeyFormat format) { |
| // SPKI format implies import of a public key, whereas PKCS8 implies import |
| // of a private key. Pick usages that are compatible with a signature |
| // algorithm. |
| return format == blink::kWebCryptoKeyFormatSpki |
| ? blink::kWebCryptoKeyUsageVerify |
| : blink::kWebCryptoKeyUsageSign; |
| } |
| |
| void ImportEcKeyFromDerFuzzData(const uint8_t* data, |
| size_t size, |
| blink::WebCryptoKeyFormat format) { |
| DCHECK(format == blink::kWebCryptoKeyFormatSpki || |
| format == blink::kWebCryptoKeyFormatPkcs8); |
| EnsureInitialized(); |
| |
| // There are 3 possible EC named curves. Fix this parameter. It shouldn't |
| // matter based on the current implementation for PKCS8 or SPKI. But it |
| // will have an impact when parsing JWK format. |
| blink::WebCryptoNamedCurve curve = blink::kWebCryptoNamedCurveP384; |
| |
| // Always use ECDSA as the algorithm. Shouldn't make much difference for |
| // non-JWK formats. |
| blink::WebCryptoAlgorithmId algorithm_id = blink::kWebCryptoAlgorithmIdEcdsa; |
| |
| // Use key usages that are compatible with the chosen algorithm and key type. |
| blink::WebCryptoKeyUsageMask usages = GetCompatibleKeyUsages(format); |
| |
| blink::WebCryptoKey key; |
| webcrypto::Status status = webcrypto::ImportKey( |
| format, webcrypto::CryptoData(data, base::checked_cast<uint32_t>(size)), |
| CreateEcImportAlgorithm(algorithm_id, curve), true, usages, &key); |
| |
| // These errors imply a bad setup of parameters, and means ImportKey() may not |
| // be testing the actual parsing. |
| DCHECK_NE(status.error_details(), |
| Status::ErrorUnsupportedImportKeyFormat().error_details()); |
| DCHECK_NE(status.error_details(), |
| Status::ErrorCreateKeyBadUsages().error_details()); |
| } |
| |
| void ImportEcKeyFromRawFuzzData(const uint8_t* data, size_t size) { |
| EnsureInitialized(); |
| |
| // There are 3 possible EC named curves. Consume the first byte to decide on |
| // the curve. |
| uint8_t curve_index = 0; |
| if (size > 0) { |
| curve_index = data[0]; |
| data++; |
| size--; |
| } |
| |
| blink::WebCryptoNamedCurve curve; |
| |
| switch (curve_index % 3) { |
| case 0: |
| curve = blink::kWebCryptoNamedCurveP256; |
| break; |
| case 1: |
| curve = blink::kWebCryptoNamedCurveP384; |
| break; |
| default: |
| curve = blink::kWebCryptoNamedCurveP521; |
| break; |
| } |
| |
| // Always use ECDSA as the algorithm. Shouldn't make an difference for import. |
| blink::WebCryptoAlgorithmId algorithm_id = blink::kWebCryptoAlgorithmIdEcdsa; |
| |
| // Use key usages that are compatible with the chosen algorithm and key type. |
| blink::WebCryptoKeyUsageMask usages = blink::kWebCryptoKeyUsageVerify; |
| |
| blink::WebCryptoKey key; |
| webcrypto::Status status = webcrypto::ImportKey( |
| blink::kWebCryptoKeyFormatRaw, |
| webcrypto::CryptoData(data, base::checked_cast<uint32_t>(size)), |
| CreateEcImportAlgorithm(algorithm_id, curve), true, usages, &key); |
| |
| // These errors imply a bad setup of parameters, and means ImportKey() may not |
| // be testing the actual parsing. |
| DCHECK_NE(status.error_details(), |
| Status::ErrorUnsupportedImportKeyFormat().error_details()); |
| DCHECK_NE(status.error_details(), |
| Status::ErrorCreateKeyBadUsages().error_details()); |
| } |
| |
| void ImportRsaKeyFromDerFuzzData(const uint8_t* data, |
| size_t size, |
| blink::WebCryptoKeyFormat format) { |
| DCHECK(format == blink::kWebCryptoKeyFormatSpki || |
| format == blink::kWebCryptoKeyFormatPkcs8); |
| EnsureInitialized(); |
| |
| // There are several possible hash functions. Fix this parameter. It shouldn't |
| // matter based on the current implementation for PKCS8 or SPKI. But it |
| // will have an impact when parsing JWK format. |
| blink::WebCryptoAlgorithmId hash_id = blink::kWebCryptoAlgorithmIdSha256; |
| |
| // Always use RSA-SSA PKCS#1 as the algorithm. Shouldn't make much difference |
| // for non-JWK formats. |
| blink::WebCryptoAlgorithmId algorithm_id = |
| blink::kWebCryptoAlgorithmIdRsaSsaPkcs1v1_5; |
| |
| // Use key usages that are compatible with the chosen algorithm and key type. |
| blink::WebCryptoKeyUsageMask usages = GetCompatibleKeyUsages(format); |
| |
| blink::WebCryptoKey key; |
| webcrypto::Status status = webcrypto::ImportKey( |
| format, webcrypto::CryptoData(data, base::checked_cast<uint32_t>(size)), |
| CreateRsaHashedImportAlgorithm(algorithm_id, hash_id), true, usages, |
| &key); |
| |
| // These errors imply a bad setup of parameters, and means ImportKey() may not |
| // be testing the actual parsing. |
| DCHECK_NE(status.error_details(), |
| Status::ErrorUnsupportedImportKeyFormat().error_details()); |
| DCHECK_NE(status.error_details(), |
| Status::ErrorCreateKeyBadUsages().error_details()); |
| } |
| |
| } // namespace webcrypto |