// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <openssl/asn1.h>
#include <openssl/x509.h>
#include <cstdlib>
#include <iostream>
#include <string>
#include <vector>
#include "base/notreached.h"
#include "base/time/time.h"
#include "components/media_router/common/providers/cast/certificate/cast_cert_reader.h"
#include "components/media_router/common/providers/cast/channel/cast_auth_util_fuzzer_shared.h"
#include "components/media_router/common/providers/cast/channel/fuzz_proto/fuzzer_inputs.pb.h"
// Generated by the "cast_auth_util_fuzzer_certs" data_headers target.
#include "components/test/data/media_router/common/providers/cast/certificate/certificates/chromecast_gen1_data.h"
#include "testing/libfuzzer/proto/lpm_interface.h"
#include "third_party/openscreen/src/cast/common/public/parsed_certificate.h"
#include "third_party/openscreen/src/cast/common/public/trust_store.h"
#include "third_party/openscreen/src/cast/sender/channel/cast_auth_util.h"
namespace cast_channel {
namespace fuzz {
namespace {
using ::openscreen::cast::TrustStore;
using ::openscreen::cast::proto::CastMessage;
const uint8_t kCertData[] = {
// Generated by //net/data/ssl/certificates:generate_fuzzer_cert_includes
#include "net/data/ssl/certificates/wildcard.inc"
};
static std::vector<std::string>* InitializeCertsOnce() {
static std::vector<std::string> certs =
cast_certificate::ReadCertificateChainFromString(
openscreen::cast::kChromecastGen1);
CHECK(certs.size() >= 1) << "We should always have at least one certificate.";
return &certs;
}
static TrustStore* InitializeCastTrustStoreOnce() {
static TrustStore* cast_trust_store =
openscreen::cast::CastTrustStore::Create().release();
return cast_trust_store;
}
static TrustStore* InitializeCastCRLTrustStoreOnce() {
static TrustStore* crl_trust_store =
openscreen::cast::CastCRLTrustStore::Create().release();
return crl_trust_store;
}
time_t GenerateCertTime(TimeBoundCase c, int direction) {
base::Time t;
switch (c) {
case TimeBoundCase::VALID:
// Create bound that include the current date.
t = base::Time::Now() + base::Days(direction);
break;
case TimeBoundCase::INVALID:
// Create a bound that excludes the current date.
t = base::Time::Now() + base::Days(-direction);
break;
case TimeBoundCase::OOB:
// Create a bound so far in the past/future it's not valid.
t = base::Time::Now() + base::Days(direction * 10000);
break;
case TimeBoundCase::MISSING:
// Remove any existing bound.
t = base::Time();
break;
default:
NOTREACHED_IN_MIGRATION();
}
return t.ToTimeT();
}
DEFINE_PROTO_FUZZER(CastAuthUtilInputs& input_union) {
std::vector<std::string>* certs = InitializeCertsOnce();
TrustStore* cast_trust_store = InitializeCastTrustStoreOnce();
TrustStore* crl_trust_store = InitializeCastCRLTrustStoreOnce();
if (input_union.input_case() !=
CastAuthUtilInputs::kAuthenticateChallengeReplyInput) {
return;
}
CastAuthUtilInputs::AuthenticateChallengeReplyInput& 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.
std::vector<uint8_t> cert_data{std::begin(kCertData), std::end(kCertData)};
std::unique_ptr<openscreen::cast::ParsedCertificate> peer_cert = std::move(
openscreen::cast::ParsedCertificate::ParseFromDER(cert_data).value());
time_t not_before_time = GenerateCertTime(input.start_case(), -1);
time_t not_after_time = GenerateCertTime(input.expiry_case(), 1);
peer_cert->SetNotBeforeTimeForTesting(not_before_time);
peer_cert->SetNotAfterTimeForTesting(not_after_time);
auto context = openscreen::cast::AuthContext::CreateForTest(input.nonce());
openscreen::cast::AuthenticateChallengeReply(input.cast_message(), *peer_cert,
context, cast_trust_store,
crl_trust_store);
}
} // namespace
} // namespace fuzz
} // namespace cast_channel