// Copyright 2020 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 #include #include #include #include "base/no_destructor.h" #include "base/notreached.h" #include "base/time/time_override.h" #include "components/cast_certificate/cast_cert_reader.h" #include "components/cast_certificate/cast_cert_test_helpers.h" #include "components/cast_channel/cast_auth_util.h" #include "components/cast_channel/cast_auth_util_fuzzer_shared.h" #include "components/cast_channel/fuzz_proto/fuzzer_inputs.pb.h" // Generated by the "cast_auth_util_fuzzer_certs" data_headers target. #include "components/test/data/cast_certificate/certificates/chromecast_gen1_data.h" #include "net/cert/x509_certificate.h" #include "net/cert/x509_util.h" #include "net/test/test_certificate_data.h" #include "testing/libfuzzer/proto/lpm_interface.h" namespace cast_channel { namespace fuzz { namespace { const uint8_t kCertData[] = { // Generated by //net/data/ssl/certificates:generate_fuzzer_cert_includes #include "net/data/ssl/certificates/wildcard.inc" }; base::NoDestructor> certs; static bool InitializeOnce() { *certs = cast_certificate::ReadCertificateChainFromString( openscreen::cast::kChromecastGen1); CHECK(certs->size() >= 1) << "We should always have at least one certificate."; return true; } void UpdateTime(TimeBoundCase c, const base::Time* time, int direction) { auto& mtime = const_cast(*time); switch (c) { case TimeBoundCase::VALID: // Create bound that include the current date. mtime = base::Time::Now() + base::Days(direction); break; case TimeBoundCase::INVALID: // Create a bound that excludes the current date. mtime = base::Time::Now() + base::Days(-direction); break; case TimeBoundCase::OOB: // Create a bound so far in the past/future it's not valid. mtime = base::Time::Now() + base::Days(direction * 10000); break; case TimeBoundCase::MISSING: // Remove any existing bound. mtime = base::Time(); break; default: NOTREACHED(); } } DEFINE_PROTO_FUZZER(CastAuthUtilInputs& input_union) { static bool init = InitializeOnce(); CHECK(init); if (input_union.input_case() != CastAuthUtilInputs::kAuthenticateChallengeReplyInput) { return; } auto& input = *input_union.mutable_authenticate_challenge_reply_input(); SetupAuthenticateChallengeReplyInput(*certs, &input); // Build a well-formed cert with start and expiry times relative to the // current time. The actual cert doesn't matter for testing purposes // because validation failures are ignored. scoped_refptr peer_cert = net::X509Certificate::CreateFromBytes(kCertData); UpdateTime(input.start_case(), &peer_cert->valid_start(), -1); UpdateTime(input.expiry_case(), &peer_cert->valid_expiry(), +1); AuthContext context = AuthContext::CreateForTest(input.nonce()); AuthenticateChallengeReply(input.cast_message(), *peer_cert, context); } } // namespace } // namespace fuzz } // namespace cast_channel