summaryrefslogtreecommitdiff
path: root/chromium/components/cast_channel
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/components/cast_channel')
-rw-r--r--chromium/components/cast_channel/BUILD.gn38
-rw-r--r--chromium/components/cast_channel/README.md30
-rw-r--r--chromium/components/cast_channel/cast_auth_util.cc19
-rw-r--r--chromium/components/cast_channel/cast_auth_util.h2
-rw-r--r--chromium/components/cast_channel/cast_auth_util_fuzzer.cc45
-rw-r--r--chromium/components/cast_channel/cast_framer.cc1
-rw-r--r--chromium/components/cast_channel/cast_framer_ingest_fuzzer.cc (renamed from chromium/components/cast_channel/cast_message_fuzzer.cc)1
-rw-r--r--chromium/components/cast_channel/cast_framer_serialize_fuzzer.cc24
-rw-r--r--chromium/components/cast_channel/cast_message_handler.cc28
-rw-r--r--chromium/components/cast_channel/cast_message_handler.h8
-rw-r--r--chromium/components/cast_channel/cast_message_handler_unittest.cc111
-rw-r--r--chromium/components/cast_channel/cast_message_util.cc6
-rw-r--r--chromium/components/cast_channel/cast_message_util.h18
-rw-r--r--chromium/components/cast_channel/cast_message_util_fuzzer.cc168
-rw-r--r--chromium/components/cast_channel/cast_message_util_unittest.cc21
-rw-r--r--chromium/components/cast_channel/cast_socket.cc9
-rw-r--r--chromium/components/cast_channel/cast_socket_service.cc4
-rw-r--r--chromium/components/cast_channel/cast_test_util.h10
-rw-r--r--chromium/components/cast_channel/enum_table.h4
-rw-r--r--chromium/components/cast_channel/fuzz.dict65
-rw-r--r--chromium/components/cast_channel/proto/BUILD.gn10
-rw-r--r--chromium/components/cast_channel/proto/authority_keys.proto17
-rw-r--r--chromium/components/cast_channel/proto/cast_channel.proto99
-rw-r--r--chromium/components/cast_channel/proto/fuzzer_inputs.proto166
24 files changed, 723 insertions, 181 deletions
diff --git a/chromium/components/cast_channel/BUILD.gn b/chromium/components/cast_channel/BUILD.gn
index 55b42ba169a..a5a972e2d6e 100644
--- a/chromium/components/cast_channel/BUILD.gn
+++ b/chromium/components/cast_channel/BUILD.gn
@@ -101,8 +101,11 @@ source_set("unit_tests") {
]
}
+# TODO(jrw): Rename target to cast_framer_ingest_fuzzer. The name
+# is left unchanged for now to avoid the need to get reviews for
+# various files that include it.
fuzzer_test("cast_message_fuzzer") {
- sources = [ "cast_message_fuzzer.cc" ]
+ sources = [ "cast_framer_ingest_fuzzer.cc" ]
deps = [
":test_support",
"//base",
@@ -115,3 +118,36 @@ fuzzer_test("cast_message_fuzzer") {
# See MessageFramer::MessageHeader::max_message_size()
libfuzzer_options = [ "max_len=65535" ]
}
+
+fuzzer_test("cast_auth_util_fuzzer") {
+ sources = [ "cast_auth_util_fuzzer.cc" ]
+ dict = "fuzz.dict"
+ deps = [
+ ":cast_channel",
+ "//components/cast_channel/proto:cast_channel_fuzzer_inputs_proto",
+ "//net/data/ssl/certificates:generate_fuzzer_cert_includes",
+ "//third_party/libprotobuf-mutator",
+ "//third_party/openscreen/src/cast/common/channel/proto:channel_proto",
+ ]
+}
+
+fuzzer_test("cast_framer_serialize_fuzzer") {
+ sources = [ "cast_framer_serialize_fuzzer.cc" ]
+ deps = [
+ ":cast_channel",
+ "//components/cast_channel/proto:cast_channel_fuzzer_inputs_proto",
+ "//third_party/libprotobuf-mutator",
+ "//third_party/openscreen/src/cast/common/channel/proto:channel_proto",
+ ]
+}
+
+fuzzer_test("cast_message_util_fuzzer") {
+ sources = [ "cast_message_util_fuzzer.cc" ]
+ dict = "fuzz.dict"
+ deps = [
+ ":cast_channel",
+ "//components/cast_channel/proto:cast_channel_fuzzer_inputs_proto",
+ "//third_party/libprotobuf-mutator",
+ "//third_party/openscreen/src/cast/common/channel/proto:channel_proto",
+ ]
+}
diff --git a/chromium/components/cast_channel/README.md b/chromium/components/cast_channel/README.md
new file mode 100644
index 00000000000..3d5e23007f5
--- /dev/null
+++ b/chromium/components/cast_channel/README.md
@@ -0,0 +1,30 @@
+# How to Run a Fuzz Test
+
+Create an appropriate build config:
+
+```shell
+% tools/mb/mb.py gen -m chromium.fuzz -b 'Libfuzzer Upload Linux ASan' out/libfuzzer
+% gn gen out/libfuzzer
+```
+
+Build the fuzz target:
+
+```shell
+% ninja -C out/libfuzzer $TEST_NAME
+```
+
+Create an empty corpus directory:
+
+```shell
+% mkdir ${TEST_NAME}_corpus
+```
+
+Run the fuzz target, turning off detection of ODR violations that occur in
+component builds:
+
+```shell
+% export ASAN_OPTIONS=detect_odr_violation=0
+% ./out/libfuzzer/$TEST_NAME ${TEST_NAME}_corpus
+```
+
+For more details, refer to https://chromium.googlesource.com/chromium/src/testing/libfuzzer/+/refs/heads/master/getting_started.md
diff --git a/chromium/components/cast_channel/cast_auth_util.cc b/chromium/components/cast_channel/cast_auth_util.cc
index ec3aa6913b1..876e85711c0 100644
--- a/chromium/components/cast_channel/cast_auth_util.cc
+++ b/chromium/components/cast_channel/cast_auth_util.cc
@@ -259,9 +259,26 @@ AuthContext AuthContext::Create() {
return AuthContext(CastNonce::Get());
}
+// static
+AuthContext AuthContext::CreateForTest(const std::string& nonce_data) {
+ // Given some garbage data, try to turn it into a string that at least has the
+ // right length.
+ std::string nonce;
+ if (nonce_data.empty()) {
+ nonce = std::string(kNonceSizeInBytes, '0');
+ } else {
+ while (nonce.size() < kNonceSizeInBytes) {
+ nonce += nonce_data;
+ }
+ nonce.erase(kNonceSizeInBytes);
+ }
+ DCHECK(nonce.size() == kNonceSizeInBytes);
+ return AuthContext(nonce);
+}
+
AuthContext::AuthContext(const std::string& nonce) : nonce_(nonce) {}
-AuthContext::~AuthContext() {}
+AuthContext::~AuthContext() = default;
AuthResult AuthContext::VerifySenderNonce(
const std::string& nonce_response) const {
diff --git a/chromium/components/cast_channel/cast_auth_util.h b/chromium/components/cast_channel/cast_auth_util.h
index ea989692829..0818a7d0cb5 100644
--- a/chromium/components/cast_channel/cast_auth_util.h
+++ b/chromium/components/cast_channel/cast_auth_util.h
@@ -77,6 +77,8 @@ class AuthContext {
// The same context must be used in the challenge and reply.
static AuthContext Create();
+ static AuthContext CreateForTest(const std::string& nonce);
+
// Verifies the nonce received in the response is equivalent to the one sent.
// Returns success if |nonce_response| matches nonce_
AuthResult VerifySenderNonce(const std::string& nonce_response) const;
diff --git a/chromium/components/cast_channel/cast_auth_util_fuzzer.cc b/chromium/components/cast_channel/cast_auth_util_fuzzer.cc
new file mode 100644
index 00000000000..c652075efb4
--- /dev/null
+++ b/chromium/components/cast_channel/cast_auth_util_fuzzer.cc
@@ -0,0 +1,45 @@
+// 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 <cstdlib>
+#include <iostream>
+
+#include "base/notreached.h"
+#include "components/cast_channel/cast_auth_util.h"
+#include "components/cast_channel/fuzz_proto/fuzzer_inputs.pb.h"
+#include "net/cert/x509_certificate.h"
+#include "testing/libfuzzer/proto/lpm_interface.h"
+
+namespace cast_channel {
+namespace fuzz {
+
+namespace {
+const char kCertData[] = {
+#include "net/data/ssl/certificates/wildcard.inc"
+};
+} // namespace
+
+DEFINE_PROTO_FUZZER(const CastAuthUtilInputs& input_union) {
+ // TODO(crbug.com/796717): Add tests for AuthenticateChallengeReply and
+ // VerifyTLSCertificate if necessary. Refer to updates on the bug, and check
+ // to see if there is already coverage through BoringSSL
+
+ switch (input_union.input_case()) {
+ case CastAuthUtilInputs::kAuthenticateChallengeReplyInput: {
+ const auto& input = input_union.authenticate_challenge_reply_input();
+ cast::channel::DeviceAuthMessage auth_message = input.auth_message();
+ AuthContext context = AuthContext::CreateForTest(input.nonce());
+ scoped_refptr<net::X509Certificate> peer_cert =
+ net::X509Certificate::CreateFromBytes(kCertData,
+ base::size(kCertData));
+ AuthenticateChallengeReply(input.cast_message(), *peer_cert, context);
+ break;
+ }
+ default:
+ NOTREACHED();
+ }
+}
+
+} // namespace fuzz
+} // namespace cast_channel
diff --git a/chromium/components/cast_channel/cast_framer.cc b/chromium/components/cast_channel/cast_framer.cc
index 3ad9e69255a..b7e355f5838 100644
--- a/chromium/components/cast_channel/cast_framer.cc
+++ b/chromium/components/cast_channel/cast_framer.cc
@@ -10,6 +10,7 @@
#include "base/logging.h"
#include "base/memory/free_deleter.h"
+#include "base/notreached.h"
#include "base/numerics/safe_conversions.h"
#include "base/strings/string_number_conversions.h"
#include "base/sys_byteorder.h"
diff --git a/chromium/components/cast_channel/cast_message_fuzzer.cc b/chromium/components/cast_channel/cast_framer_ingest_fuzzer.cc
index 72cdbae5f46..b5bd9ddee0c 100644
--- a/chromium/components/cast_channel/cast_message_fuzzer.cc
+++ b/chromium/components/cast_channel/cast_framer_ingest_fuzzer.cc
@@ -12,7 +12,6 @@
#include "components/cast_channel/cast_framer.h"
#include "net/base/io_buffer.h"
#include "third_party/openscreen/src/cast/common/channel/proto/cast_channel.pb.h"
-#include "third_party/protobuf/src/google/protobuf/stubs/logging.h"
// Silence logging from the protobuf library.
google::protobuf::LogSilencer log_silencer;
diff --git a/chromium/components/cast_channel/cast_framer_serialize_fuzzer.cc b/chromium/components/cast_channel/cast_framer_serialize_fuzzer.cc
new file mode 100644
index 00000000000..6085c40a564
--- /dev/null
+++ b/chromium/components/cast_channel/cast_framer_serialize_fuzzer.cc
@@ -0,0 +1,24 @@
+// 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 <cstdlib>
+#include <iostream>
+#include <string>
+
+#include "components/cast_channel/cast_framer.h"
+#include "testing/libfuzzer/proto/lpm_interface.h"
+#include "third_party/openscreen/src/cast/common/channel/proto/cast_channel.pb.h"
+
+namespace cast_channel {
+namespace fuzz {
+
+DEFINE_PROTO_FUZZER(const cast::channel::CastMessage& input) {
+ std::string native_input;
+ MessageFramer::Serialize(input, &native_input);
+ if (::getenv("LPM_DUMP_NATIVE_INPUT"))
+ std::cout << native_input << std::endl;
+}
+
+} // namespace fuzz
+} // namespace cast_channel
diff --git a/chromium/components/cast_channel/cast_message_handler.cc b/chromium/components/cast_channel/cast_message_handler.cc
index 43c79aca912..5bff7f19953 100644
--- a/chromium/components/cast_channel/cast_message_handler.cc
+++ b/chromium/components/cast_channel/cast_message_handler.cc
@@ -21,6 +21,9 @@ namespace {
// The max launch timeout amount for session launch requests.
constexpr base::TimeDelta kLaunchMaxTimeout = base::TimeDelta::FromMinutes(2);
+// The max size of Cast Message is 64KB.
+constexpr int kMaxCastMessagePayload = 64 * 1024;
+
void ReportParseError(const std::string& error) {
DVLOG(1) << "Error parsing JSON message: " << error;
}
@@ -169,7 +172,7 @@ void CastMessageHandler::RequestReceiverStatus(int channel_id) {
CreateReceiverStatusRequest(sender_id_, request_id));
}
-void CastMessageHandler::SendBroadcastMessage(
+Result CastMessageHandler::SendBroadcastMessage(
int channel_id,
const std::vector<std::string>& app_ids,
const BroadcastRequest& request) {
@@ -178,7 +181,7 @@ void CastMessageHandler::SendBroadcastMessage(
CastSocket* socket = socket_service_->GetSocket(channel_id);
if (!socket) {
DVLOG(2) << __func__ << ": socket not found: " << channel_id;
- return;
+ return Result::kFailed;
}
int request_id = NextRequestId();
@@ -189,7 +192,11 @@ void CastMessageHandler::SendBroadcastMessage(
// about the response, as broadcasts are fire-and-forget.
CastMessage message =
CreateBroadcastRequest(sender_id_, request_id, app_ids, request);
+ if (message.ByteSizeLong() > kMaxCastMessagePayload) {
+ return Result::kFailed;
+ }
SendCastMessageToSocket(socket, message);
+ return Result::kOk;
}
void CastMessageHandler::LaunchSession(
@@ -197,7 +204,7 @@ void CastMessageHandler::LaunchSession(
const std::string& app_id,
base::TimeDelta launch_timeout,
const std::vector<std::string>& supported_app_types,
- const std::string& app_params,
+ const base::Optional<base::Value>& app_params,
LaunchSessionCallback callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
CastSocket* socket = socket_service_->GetSocket(channel_id);
@@ -213,12 +220,18 @@ void CastMessageHandler::LaunchSession(
launch_timeout = std::min(launch_timeout, kLaunchMaxTimeout);
DVLOG(2) << __func__ << ", channel_id: " << channel_id
<< ", request_id: " << request_id;
+ CastMessage message = CreateLaunchRequest(
+ sender_id_, request_id, app_id, locale_, supported_app_types, app_params);
+ if (message.ByteSizeLong() > kMaxCastMessagePayload) {
+ LaunchSessionResponse response;
+ response.result = LaunchSessionResponse::kError;
+ std::move(callback).Run(std::move(response));
+ return;
+ }
if (requests->AddLaunchRequest(std::make_unique<LaunchSessionRequest>(
request_id, std::move(callback), clock_),
launch_timeout)) {
- SendCastMessageToSocket(
- socket, CreateLaunchRequest(sender_id_, request_id, app_id, locale_,
- supported_app_types));
+ SendCastMessageToSocket(socket, message);
}
}
@@ -264,6 +277,9 @@ Result CastMessageHandler::SendAppMessage(int channel_id,
const CastMessage& message) {
DCHECK(!IsCastInternalNamespace(message.namespace_()))
<< ": unexpected app message namespace: " << message.namespace_();
+ if (message.ByteSizeLong() > kMaxCastMessagePayload) {
+ return Result::kFailed;
+ }
return SendCastMessage(channel_id, message);
}
diff --git a/chromium/components/cast_channel/cast_message_handler.h b/chromium/components/cast_channel/cast_message_handler.h
index f7791e7b871..32d1bef83c6 100644
--- a/chromium/components/cast_channel/cast_message_handler.h
+++ b/chromium/components/cast_channel/cast_message_handler.h
@@ -173,9 +173,9 @@ class CastMessageHandler : public CastSocket::Observer {
// Sends a broadcast message containing |app_ids| and |request| to the socket
// given by |channel_id|.
- virtual void SendBroadcastMessage(int channel_id,
- const std::vector<std::string>& app_ids,
- const BroadcastRequest& request);
+ virtual Result SendBroadcastMessage(int channel_id,
+ const std::vector<std::string>& app_ids,
+ const BroadcastRequest& request);
// Requests a session launch for |app_id| on the device given by |channel_id|.
// |callback| will be invoked with the response or with a timed out result if
@@ -185,7 +185,7 @@ class CastMessageHandler : public CastSocket::Observer {
const std::string& app_id,
base::TimeDelta launch_timeout,
const std::vector<std::string>& supported_app_types,
- const std::string& app_params,
+ const base::Optional<base::Value>& app_params,
LaunchSessionCallback callback);
// Stops the session given by |session_id| on the device given by
diff --git a/chromium/components/cast_channel/cast_message_handler_unittest.cc b/chromium/components/cast_channel/cast_message_handler_unittest.cc
index 81086b606ab..142fdcbb92d 100644
--- a/chromium/components/cast_channel/cast_message_handler_unittest.cc
+++ b/chromium/components/cast_channel/cast_message_handler_unittest.cc
@@ -33,11 +33,25 @@ namespace cast_channel {
namespace {
+constexpr char kAppId1[] = "0F5096E8";
+constexpr char kAppId2[] = "85CDB22F";
constexpr char kTestUserAgentString[] =
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/66.0.3331.0 Safari/537.36";
constexpr char kSourceId[] = "sourceId";
constexpr char kDestinationId[] = "destinationId";
+constexpr char kAppParams[] = R"(
+{
+ "requiredFeatures" : ["STREAM_TRANSFER"],
+ "launchCheckerParams" : {
+ "credentialsData" : {
+ "credentialsType" : "mobile",
+ "credentials" : "99843n2idsguyhga"
+ }
+ }
+}
+)";
+constexpr int kMaxProtocolMessageSize = 64 * 1024;
data_decoder::DataDecoder::ValueOrError ParseJsonLikeDataDecoder(
base::StringPiece json) {
@@ -135,11 +149,11 @@ class CastMessageHandlerTest : public testing::Test {
void CreatePendingRequests() {
EXPECT_CALL(*transport_, SendMessage(_, _)).Times(AnyNumber());
- handler_.LaunchSession(channel_id_, "theAppId", base::TimeDelta::Max(),
- {"WEB"}, /* appParams */ "",
+ handler_.LaunchSession(channel_id_, kAppId1, base::TimeDelta::Max(),
+ {"WEB"}, /* appParams */ base::nullopt,
launch_session_callback_.Get());
for (int i = 0; i < 2; i++) {
- handler_.RequestAppAvailability(&cast_socket_, "theAppId",
+ handler_.RequestAppAvailability(&cast_socket_, kAppId1,
get_app_availability_callback_.Get());
handler_.SendSetVolumeRequest(
channel_id_,
@@ -174,11 +188,11 @@ TEST_F(CastMessageHandlerTest, VirtualConnectionCreatedOnlyOnce) {
ExpectEnsureConnectionThen(CastMessageType::kGetAppAvailability, 2);
handler_.RequestAppAvailability(
- &cast_socket_, "AAAAAAAA",
+ &cast_socket_, kAppId1,
base::BindOnce(&CastMessageHandlerTest::OnAppAvailability,
base::Unretained(this)));
handler_.RequestAppAvailability(
- &cast_socket_, "BBBBBBBB",
+ &cast_socket_, kAppId2,
base::BindOnce(&CastMessageHandlerTest::OnAppAvailability,
base::Unretained(this)));
}
@@ -187,25 +201,25 @@ TEST_F(CastMessageHandlerTest, RecreateVirtualConnectionAfterError) {
ExpectEnsureConnectionThen(CastMessageType::kGetAppAvailability);
handler_.RequestAppAvailability(
- &cast_socket_, "AAAAAAAA",
+ &cast_socket_, kAppId1,
base::BindOnce(&CastMessageHandlerTest::OnAppAvailability,
base::Unretained(this)));
- EXPECT_CALL(*this, DoOnAppAvailability("AAAAAAAA",
- GetAppAvailabilityResult::kUnknown));
+ EXPECT_CALL(*this,
+ DoOnAppAvailability(kAppId1, GetAppAvailabilityResult::kUnknown));
OnError(ChannelError::TRANSPORT_ERROR);
ExpectEnsureConnectionThen(CastMessageType::kGetAppAvailability);
handler_.RequestAppAvailability(
- &cast_socket_, "BBBBBBBB",
+ &cast_socket_, kAppId2,
base::BindOnce(&CastMessageHandlerTest::OnAppAvailability,
base::Unretained(this)));
// The callback is invoked with kUnknown before the PendingRequests is
// destroyed.
- EXPECT_CALL(*this, DoOnAppAvailability("BBBBBBBB",
- GetAppAvailabilityResult::kUnknown));
+ EXPECT_CALL(*this,
+ DoOnAppAvailability(kAppId2, GetAppAvailabilityResult::kUnknown));
}
TEST_F(CastMessageHandlerTest, RequestAppAvailability) {
@@ -317,9 +331,10 @@ TEST_F(CastMessageHandlerTest, CloseConnectionFromReceiver) {
TEST_F(CastMessageHandlerTest, LaunchSession) {
ExpectEnsureConnectionThen(CastMessageType::kLaunch);
+ const base::Optional<base::Value> json = base::JSONReader::Read(kAppParams);
+
handler_.LaunchSession(
- channel_id_, "AAAAAAAA", base::TimeDelta::FromSeconds(30), {"WEB"},
- /* appParams */ "",
+ channel_id_, kAppId1, base::TimeDelta::FromSeconds(30), {"WEB"}, json,
base::BindOnce(&CastMessageHandlerTest::ExpectSessionLaunchResult,
base::Unretained(this),
LaunchSessionResponse::Result::kOk));
@@ -332,6 +347,9 @@ TEST_F(CastMessageHandlerTest, LaunchSession) {
ASSERT_TRUE(request_id_value);
int request_id = request_id_value->GetInt();
EXPECT_GT(request_id, 0);
+ const base::Value* app_params =
+ dict->FindKeyOfType("appParams", base::Value::Type::DICTIONARY);
+ EXPECT_EQ(json.value(), *app_params);
CastMessage response;
response.set_namespace_("urn:x-cast:com.google.cast.receiver");
@@ -357,8 +375,8 @@ TEST_F(CastMessageHandlerTest, LaunchSessionTimedOut) {
ExpectEnsureConnectionThen(CastMessageType::kLaunch);
handler_.LaunchSession(
- channel_id_, "AAAAAAAA", base::TimeDelta::FromSeconds(30), {"WEB"},
- /* appParams */ "",
+ channel_id_, kAppId1, base::TimeDelta::FromSeconds(30), {"WEB"},
+ /* appParams */ base::nullopt,
base::BindOnce(&CastMessageHandlerTest::ExpectSessionLaunchResult,
base::Unretained(this),
LaunchSessionResponse::Result::kTimedOut));
@@ -367,6 +385,19 @@ TEST_F(CastMessageHandlerTest, LaunchSessionTimedOut) {
EXPECT_EQ(1, session_launch_response_count_);
}
+TEST_F(CastMessageHandlerTest, LaunchSessionMessageExceedsSizeLimit) {
+ std::string invalid_URL(kMaxProtocolMessageSize, 'a');
+ base::Value json(base::Value::Type::DICTIONARY);
+ json.SetKey("key", base::Value(invalid_URL));
+ handler_.LaunchSession(
+ channel_id_, kAppId1, base::TimeDelta::FromSeconds(30), {"WEB"},
+ base::make_optional<base::Value>(std::move(json)),
+ base::BindOnce(&CastMessageHandlerTest::ExpectSessionLaunchResult,
+ base::Unretained(this),
+ LaunchSessionResponse::Result::kError));
+ EXPECT_EQ(1, session_launch_response_count_);
+}
+
TEST_F(CastMessageHandlerTest, SendAppMessage) {
base::Value body(base::Value::Type::DICTIONARY);
body.SetKey("foo", base::Value("bar"));
@@ -382,6 +413,16 @@ TEST_F(CastMessageHandlerTest, SendAppMessage) {
EXPECT_EQ(Result::kOk, handler_.SendAppMessage(channel_id_, message));
}
+TEST_F(CastMessageHandlerTest, SendAppMessageExceedsSizeLimit) {
+ std::string invalid_msg(kMaxProtocolMessageSize, 'a');
+ base::Value body(base::Value::Type::DICTIONARY);
+ body.SetKey("foo", base::Value(invalid_msg));
+ CastMessage message =
+ CreateCastMessage("namespace", body, kSourceId, kDestinationId);
+
+ EXPECT_EQ(Result::kFailed, handler_.SendAppMessage(channel_id_, message));
+}
+
// Check that SendMediaRequest sends a message created by CreateMediaRequest and
// returns a request ID.
TEST_F(CastMessageHandlerTest, SendMediaRequest) {
@@ -415,6 +456,31 @@ TEST_F(CastMessageHandlerTest, SendMediaRequest) {
EXPECT_EQ(1, request_id);
}
+TEST_F(CastMessageHandlerTest, SendBroadcastMessage) {
+ BroadcastRequest request = BroadcastRequest("namespace", "message");
+ CastMessage message = CreateBroadcastRequest(
+ "theSourceId", /* request_id */ 1, {kAppId1}, request);
+ {
+ InSequence dummy;
+ ExpectEnsureConnection();
+ EXPECT_CALL(*transport_,
+ SendMessage(HasPayloadUtf8(message.payload_utf8()), _));
+ }
+
+ EXPECT_EQ(Result::kOk,
+ handler_.SendBroadcastMessage(channel_id_, {kAppId1}, request));
+}
+
+TEST_F(CastMessageHandlerTest, SendBroadcastMessageExceedsSizeLimit) {
+ BroadcastRequest request =
+ BroadcastRequest("namespace", std::string(kMaxProtocolMessageSize, 'a'));
+ CastMessage message = CreateBroadcastRequest(
+ "theSourceId", /* request_id */ 1, {kAppId1}, request);
+
+ EXPECT_EQ(Result::kFailed,
+ handler_.SendBroadcastMessage(channel_id_, {kAppId1}, request));
+}
+
// Check that SendVolumeCommand sends a message created by CreateVolumeRequest
// and registers a pending request.
TEST_F(CastMessageHandlerTest, SendVolumeCommand) {
@@ -460,7 +526,7 @@ TEST_F(CastMessageHandlerTest, PendingRequestsDestructor) {
EXPECT_EQ(base::nullopt, response.receiver_status);
});
EXPECT_CALL(get_app_availability_callback_,
- Run("theAppId", GetAppAvailabilityResult::kUnknown))
+ Run(kAppId1, GetAppAvailabilityResult::kUnknown))
.Times(2);
EXPECT_CALL(set_volume_callback_, Run(Result::kFailed)).Times(2);
EXPECT_CALL(stop_session_callback_, Run(Result::kFailed));
@@ -482,7 +548,7 @@ TEST_F(CastMessageHandlerTest, HandlePendingRequest) {
testing::Optional(IsJson(R"({"foo": "bar"})")));
});
EXPECT_CALL(get_app_availability_callback_,
- Run("theAppId", GetAppAvailabilityResult::kAvailable))
+ Run(kAppId1, GetAppAvailabilityResult::kAvailable))
.Times(2);
EXPECT_CALL(set_volume_callback_, Run(Result::kOk)).Times(2);
EXPECT_CALL(stop_session_callback_, Run(Result::kOk));
@@ -498,13 +564,14 @@ TEST_F(CastMessageHandlerTest, HandlePendingRequest) {
})"));
// Handle both pending get app availability requests.
- handler_.HandleCastInternalMessage(channel_id_, "theSourceId",
- "theDestinationId", "theNamespace",
- ParseJsonLikeDataDecoder(R"(
+ handler_.HandleCastInternalMessage(
+ channel_id_, "theSourceId", "theDestinationId", "theNamespace",
+ ParseJsonLikeDataDecoder(base::StringPrintf(R"(
{
"requestId": 2,
- "availability": {"theAppId": "APP_AVAILABLE"},
- })"));
+ "availability": {"%s": "APP_AVAILABLE"},
+ })",
+ kAppId1)));
// Handle pending set volume request (1 of 2).
handler_.HandleCastInternalMessage(
diff --git a/chromium/components/cast_channel/cast_message_util.cc b/chromium/components/cast_channel/cast_message_util.cc
index 8c61928f467..76c70d788ec 100644
--- a/chromium/components/cast_channel/cast_message_util.cc
+++ b/chromium/components/cast_channel/cast_message_util.cc
@@ -426,7 +426,8 @@ CastMessage CreateLaunchRequest(
int request_id,
const std::string& app_id,
const std::string& locale,
- const std::vector<std::string>& supported_app_types) {
+ const std::vector<std::string>& supported_app_types,
+ const base::Optional<base::Value>& app_params) {
Value dict(Value::Type::DICTIONARY);
dict.SetKey("type",
Value(EnumToString<CastMessageType, CastMessageType::kLaunch>()));
@@ -438,6 +439,9 @@ CastMessage CreateLaunchRequest(
supported_app_types_value.push_back(Value(type));
dict.SetKey("supportedAppTypes", Value(supported_app_types_value));
+ if (app_params) {
+ dict.SetKey("appParams", app_params.value().Clone());
+ }
return CreateCastMessage(kReceiverNamespace, dict, source_id,
kPlatformReceiverId);
}
diff --git a/chromium/components/cast_channel/cast_message_util.h b/chromium/components/cast_channel/cast_message_util.h
index 7d3225a040a..d32b77c1a5a 100644
--- a/chromium/components/cast_channel/cast_message_util.h
+++ b/chromium/components/cast_channel/cast_message_util.h
@@ -137,15 +137,23 @@ enum class V2MessageType {
// Receiver App Type determines App types that can be supported by a Cast media
// source. All Cast media sources support the web type.
+// Please keep it in sync with the EnumTable in
+// chrome/common/media_router/providers/cast/cast_media_source.cc.
+// These values are persisted to logs. Entries should not be renumbered and
+// numeric values should never be reused. Please keep it in sync with
+// MediaRouterResponseReceiverAppType in tools/metrics/histograms/enums.xml.
enum class ReceiverAppType {
+ kOther = 0,
+
// Web-based Cast receiver apps. This is supported by all Cast media source
// by default.
- kWeb,
+ kWeb = 1,
// A media source may support launching an Android TV app in addition to a
// Cast web app.
- kAndroidTv,
+ kAndroidTv = 2,
+ // Do not reorder existing entries, and add new types above |kMaxValue|.
kMaxValue = kAndroidTv,
};
@@ -174,9 +182,6 @@ CastMessageType CastMessageTypeFromString(const std::string& type);
// correspond to a known type.
V2MessageType V2MessageTypeFromString(const std::string& type);
-// Returns a human readable string for |message_proto|.
-std::string CastMessageToString(const CastMessage& message_proto);
-
// Returns a human readable string for |message|.
std::string AuthMessageToString(const DeviceAuthMessage& message);
@@ -253,7 +258,8 @@ CastMessage CreateLaunchRequest(
int request_id,
const std::string& app_id,
const std::string& locale,
- const std::vector<std::string>& supported_app_types);
+ const std::vector<std::string>& supported_app_types,
+ const base::Optional<base::Value>& app_params);
CastMessage CreateStopRequest(const std::string& source_id,
int request_id,
diff --git a/chromium/components/cast_channel/cast_message_util_fuzzer.cc b/chromium/components/cast_channel/cast_message_util_fuzzer.cc
new file mode 100644
index 00000000000..753ec618b5f
--- /dev/null
+++ b/chromium/components/cast_channel/cast_message_util_fuzzer.cc
@@ -0,0 +1,168 @@
+// Copyright 2019 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 <string>
+#include <utility>
+#include <vector>
+
+#include "base/values.h"
+#include "components/cast_channel/cast_message_util.h"
+#include "components/cast_channel/enum_table.h"
+#include "components/cast_channel/fuzz_proto/fuzzer_inputs.pb.h"
+#include "testing/libfuzzer/proto/lpm_interface.h"
+
+using cast_util::EnumToString;
+
+namespace cast_channel {
+namespace fuzz {
+
+namespace {
+
+base::Value MakeValue(const JunkValue& junk) {
+ base::Value result(base::Value::Type::DICTIONARY);
+ for (int i = 0; i < junk.field_size(); i++) {
+ const auto& field = junk.field(i);
+ base::Value field_value = field.has_int_value()
+ ? base::Value(field.int_value())
+ : field.has_string_value()
+ ? base::Value(field.string_value())
+ : field.has_float_value()
+ ? base::Value(field.float_value())
+ : base::Value(field.bool_value());
+ result.SetKey(field.name(), std::move(field_value));
+ }
+ return result;
+}
+
+template <typename Field, typename T = typename Field::value_type>
+std::vector<T> MakeVector(const Field& field) {
+ return std::vector<T>(field.cbegin(), field.cend());
+}
+
+} // namespace
+
+DEFINE_PROTO_FUZZER(const CastMessageUtilInputs& input_union) {
+ // TODO(crbug.com/796717): Add test for CreateAuthChallengeMessage()
+ switch (input_union.input_case()) {
+ case CastMessageUtilInputs::kCreateBroadcastRequestInput: {
+ const auto& input = input_union.create_broadcast_request_input();
+ CreateBroadcastRequest(input.source_id(), input.request_id(),
+ MakeVector(input.app_id()),
+ BroadcastRequest(input.broadcast_namespace(),
+ input.broadcast_message()));
+ break;
+ }
+ case CastMessageUtilInputs::kCreateLaunchRequestInput: {
+ const auto& input = input_union.create_launch_request_input();
+ base::Optional<base::Value> app_params;
+ if (input.has_app_params())
+ app_params = MakeValue(input.app_params());
+ CreateLaunchRequest(input.source_id(), input.request_id(), input.app_id(),
+ input.locale(),
+ MakeVector(input.supported_app_types()), app_params);
+ break;
+ }
+ case CastMessageUtilInputs::kCreateStopRequestInput: {
+ const auto& input = input_union.create_stop_request_input();
+ CreateStopRequest(input.source_id(), input.request_id(),
+ input.session_id());
+ break;
+ }
+ case CastMessageUtilInputs::kCreateCastMessageInput: {
+ const auto& input = input_union.create_cast_message_input();
+ base::Value body = MakeValue(input.body());
+ CreateCastMessage(input.message_namespace(), body, input.source_id(),
+ input.destination_id());
+ break;
+ }
+ case CastMessageUtilInputs::kCreateMediaRequestInput: {
+ const auto& input = input_union.create_media_request_input();
+ auto type = static_cast<V2MessageType>(input.type());
+ if (IsMediaRequestMessageType(type)) {
+ base::Value body = MakeValue(input.body());
+ body.SetKey("type", base::Value(*EnumToString(type)));
+ CreateMediaRequest(body, input.request_id(), input.source_id(),
+ input.destination_id());
+ }
+ break;
+ }
+ case CastMessageUtilInputs::kCreateSetVolumeRequestInput: {
+ const auto& input = input_union.create_set_volume_request_input();
+ base::Value body = MakeValue(input.body());
+ body.SetKey(
+ "type",
+ base::Value(
+ EnumToString<V2MessageType, V2MessageType::kSetVolume>()));
+ CreateSetVolumeRequest(body, input.request_id(), input.source_id());
+ break;
+ }
+ case CastMessageUtilInputs::kIntInput: {
+ IsMediaRequestMessageType(
+ static_cast<V2MessageType>(input_union.int_input()));
+ ToString(static_cast<GetAppAvailabilityResult>(input_union.int_input()));
+ ToString(static_cast<CastMessageType>(input_union.int_input()));
+ ToString(static_cast<V2MessageType>(input_union.int_input()));
+ break;
+ }
+ case CastMessageUtilInputs::kStringInput: {
+ IsCastInternalNamespace(input_union.string_input());
+ break;
+ }
+ case CastMessageUtilInputs::kCastMessage: {
+ const auto& message = input_union.cast_message();
+ IsCastMessageValid(message);
+ IsAuthMessage(message);
+ IsReceiverMessage(message);
+ IsPlatformSenderMessage(message);
+ break;
+ }
+ case CastMessageUtilInputs::kCreateVirtualConnectionRequestInput: {
+ const auto& input = input_union.create_virtual_connection_request_input();
+ CreateVirtualConnectionRequest(
+ input.source_id(), input.destination_id(),
+ static_cast<VirtualConnectionType>(input.connection_type()),
+ input.user_agent(), input.browser_version());
+ break;
+ }
+ case CastMessageUtilInputs::kCreateGetAppAvailabilityRequestInput: {
+ const auto& input =
+ input_union.create_get_app_availability_request_input();
+ CreateGetAppAvailabilityRequest(input.source_id(), input.request_id(),
+ input.app_id());
+ break;
+ }
+ case CastMessageUtilInputs::kGetRequestIdFromResponseInput: {
+ const auto& input = input_union.get_request_id_from_response_input();
+ base::Value payload = MakeValue(input.payload());
+ if (input.has_request_id())
+ payload.SetKey("requestId", base::Value(input.request_id()));
+ GetRequestIdFromResponse(payload);
+ break;
+ }
+ case CastMessageUtilInputs::kGetLaunchSessionResponseInput: {
+ const auto& input = input_union.get_launch_session_response_input();
+ base::Value payload = MakeValue(input.payload());
+ GetLaunchSessionResponse(payload);
+ break;
+ }
+ case CastMessageUtilInputs::kParseMessageTypeFromPayloadInput: {
+ const auto& input = input_union.parse_message_type_from_payload_input();
+ base::Value payload = MakeValue(input.payload());
+ if (input.has_type())
+ payload.SetKey("type", base::Value(input.type()));
+ ParseMessageTypeFromPayload(payload);
+ break;
+ }
+ case CastMessageUtilInputs::kCreateReceiverStatusRequestInput: {
+ const auto& input = input_union.create_receiver_status_request_input();
+ CreateReceiverStatusRequest(input.source_id(), input.request_id());
+ break;
+ }
+ default:
+ NOTREACHED();
+ }
+}
+
+} // namespace fuzz
+} // namespace cast_channel
diff --git a/chromium/components/cast_channel/cast_message_util_unittest.cc b/chromium/components/cast_channel/cast_message_util_unittest.cc
index 26b62252a4c..fad8867bdc5 100644
--- a/chromium/components/cast_channel/cast_message_util_unittest.cc
+++ b/chromium/components/cast_channel/cast_message_util_unittest.cc
@@ -4,6 +4,7 @@
#include "components/cast_channel/cast_message_util.h"
+#include "base/strings/strcat.h"
#include "base/test/values_test_util.h"
#include "base/values.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -30,17 +31,27 @@ TEST(CastMessageUtilTest, CastMessageType) {
}
TEST(CastMessageUtilTest, GetLaunchSessionResponseOk) {
- std::string payload = R"(
+ std::string status = R"(
{
- "type": "RECEIVER_STATUS",
- "requestId": 123,
- "status": {}
+ "applications": [
+ {
+ "appId": "2FE23A98",
+ "universalAppId": "AD9AF8E0",
+ "appType": "ANDROID_TV"
+ }
+ ]
}
)";
+ std::string payload = base::StrCat({R"(
+ {
+ "type": "RECEIVER_STATUS",
+ "requestId": 123,
+ "status": )",
+ status, "}"});
LaunchSessionResponse response = GetLaunchSessionResponse(ParseJson(payload));
EXPECT_EQ(LaunchSessionResponse::Result::kOk, response.result);
- EXPECT_TRUE(response.receiver_status);
+ EXPECT_EQ(ParseJson(status), response.receiver_status);
}
TEST(CastMessageUtilTest, GetLaunchSessionResponseError) {
diff --git a/chromium/components/cast_channel/cast_socket.cc b/chromium/components/cast_channel/cast_socket.cc
index 6386c6f45dc..9ca58414254 100644
--- a/chromium/components/cast_channel/cast_socket.cc
+++ b/chromium/components/cast_channel/cast_socket.cc
@@ -21,7 +21,6 @@
#include "base/strings/string_number_conversions.h"
#include "base/strings/stringprintf.h"
#include "base/sys_byteorder.h"
-#include "base/task/post_task.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/time/time.h"
#include "components/cast_channel/cast_auth_util.h"
@@ -68,8 +67,8 @@ void OnConnected(
mojo::ScopedDataPipeConsumerHandle receive_stream,
mojo::ScopedDataPipeProducerHandle send_stream) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
- base::PostTask(
- FROM_HERE, {content::BrowserThread::IO},
+ content::GetIOThreadTaskRunner({})->PostTask(
+ FROM_HERE,
base::BindOnce(std::move(callback), result, local_addr, peer_addr,
std::move(receive_stream), std::move(send_stream)));
}
@@ -380,8 +379,8 @@ int CastSocketImpl::DoTcpConnect() {
VLOG_WITH_CONNECTION(1) << "DoTcpConnect";
SetConnectState(ConnectionState::TCP_CONNECT_COMPLETE);
- base::PostTask(FROM_HERE, {content::BrowserThread::UI},
- base::BindOnce(ConnectOnUIThread, network_context_getter_,
+ content::GetUIThreadTaskRunner({})->PostTask(
+ FROM_HERE, base::BindOnce(ConnectOnUIThread, network_context_getter_,
net::AddressList(open_params_.ip_endpoint),
tcp_socket_.BindNewPipeAndPassReceiver(),
base::BindOnce(&CastSocketImpl::OnConnect,
diff --git a/chromium/components/cast_channel/cast_socket_service.cc b/chromium/components/cast_channel/cast_socket_service.cc
index 687760407ee..f58fc9bf3b5 100644
--- a/chromium/components/cast_channel/cast_socket_service.cc
+++ b/chromium/components/cast_channel/cast_socket_service.cc
@@ -5,7 +5,6 @@
#include "components/cast_channel/cast_socket_service.h"
#include "base/memory/ptr_util.h"
-#include "base/task/post_task.h"
#include "components/cast_channel/cast_socket.h"
#include "components/cast_channel/logger.h"
#include "content/public/browser/browser_task_traits.h"
@@ -23,8 +22,7 @@ CastSocketService::CastSocketService()
// (1) ChromeURLRequestContextGetter::GetURLRequestContext, which is
// called by CastMediaSinkServiceImpl, must run on IO thread. (2) Parts of
// CastChannel extension API functions run on IO thread.
- task_runner_(
- base::CreateSingleThreadTaskRunner({content::BrowserThread::IO})) {}
+ task_runner_(content::GetIOThreadTaskRunner({})) {}
// This is a leaky singleton and the dtor won't be called.
CastSocketService::~CastSocketService() = default;
diff --git a/chromium/components/cast_channel/cast_test_util.h b/chromium/components/cast_channel/cast_test_util.h
index d907a9ae07a..44ec891faa0 100644
--- a/chromium/components/cast_channel/cast_test_util.h
+++ b/chromium/components/cast_channel/cast_test_util.h
@@ -175,15 +175,15 @@ class MockCastMessageHandler : public CastMessageHandler {
GetAppAvailabilityCallback callback));
MOCK_METHOD1(RequestReceiverStatus, void(int channel_id));
MOCK_METHOD3(SendBroadcastMessage,
- void(int,
- const std::vector<std::string>&,
- const BroadcastRequest&));
+ Result(int,
+ const std::vector<std::string>&,
+ const BroadcastRequest&));
MOCK_METHOD6(LaunchSession,
void(int,
const std::string&,
base::TimeDelta,
const std::vector<std::string>&,
- const std::string&,
+ const base::Optional<base::Value>&,
LaunchSessionCallback callback));
MOCK_METHOD4(StopSession,
void(int channel_id,
@@ -192,6 +192,8 @@ class MockCastMessageHandler : public CastMessageHandler {
ResultCallback callback));
MOCK_METHOD2(SendAppMessage,
Result(int channel_id, const CastMessage& message));
+ MOCK_METHOD2(SendCastMessage,
+ Result(int channel_id, const CastMessage& message));
MOCK_METHOD4(SendMediaRequest,
base::Optional<int>(int channel_id,
const base::Value& body,
diff --git a/chromium/components/cast_channel/enum_table.h b/chromium/components/cast_channel/enum_table.h
index 7957f5b203f..85539057d82 100644
--- a/chromium/components/cast_channel/enum_table.h
+++ b/chromium/components/cast_channel/enum_table.h
@@ -8,7 +8,9 @@
#include <cstdint>
#include <cstring>
-#include "base/logging.h"
+#include "base/check_op.h"
+#include "base/macros.h"
+#include "base/notreached.h"
#include "base/optional.h"
#include "base/strings/string_piece.h"
#include "build/build_config.h"
diff --git a/chromium/components/cast_channel/fuzz.dict b/chromium/components/cast_channel/fuzz.dict
new file mode 100644
index 00000000000..056feeb2015
--- /dev/null
+++ b/chromium/components/cast_channel/fuzz.dict
@@ -0,0 +1,65 @@
+# Enum values
+"ANSWER"
+"APP_AVAILABLE"
+"APPLICATION_BROADCAST"
+"APP_UNAVAILABLE"
+"CLOSE"
+"CONNECT"
+"EDIT_TRACKS_INFO"
+"GET_APP_AVAILABILITY"
+"GET_STATUS"
+"LAUNCH"
+"LAUNCH_ERROR"
+"LOAD"
+"MEDIA_GET_STATUS"
+"MEDIA_SET_VOLUME"
+"MEDIA_STATUS"
+"OFFER"
+"PAUSE"
+"PING"
+"PLAY"
+"PONG"
+"PRECACHE"
+"QUEUE_INSERT"
+"QUEUE_LOAD"
+"QUEUE_REMOVE"
+"QUEUE_REORDER"
+"QUEUE_UPDATE"
+"RECEIVER_STATUS"
+"SEEK"
+"SET_VOLUME"
+"STOP"
+"STOP_MEDIA"
+
+# Constants form cast_message_util.h
+"urn:x-cast:com.google.cast."
+"urn:x-cast:com.google.cast.tp.deviceauth"
+"urn:x-cast:com.google.cast.tp.heartbeat"
+"urn:x-cast:com.google.cast.tp.connection"
+"urn:x-cast:com.google.cast.receiver"
+"urn:x-cast:com.google.cast.broadcast"
+"urn:x-cast:com.google.cast.media"
+"sender-0"
+"receiver-0"
+
+# JSON message fields
+"appId"
+"appIds"
+"availability"
+"browserVersion"
+"connectionType"
+"connType"
+"language"
+"message"
+"namespace"
+"origin"
+"platform"
+"requestId"
+"sdkType"
+"senderInfo"
+"sessionId"
+"status"
+"systemVersion"
+"type"
+"userAgent"
+"version"
diff --git a/chromium/components/cast_channel/proto/BUILD.gn b/chromium/components/cast_channel/proto/BUILD.gn
index a1f22bf4c22..ca7ba2952f8 100644
--- a/chromium/components/cast_channel/proto/BUILD.gn
+++ b/chromium/components/cast_channel/proto/BUILD.gn
@@ -2,11 +2,11 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+import("//third_party/libprotobuf-mutator/fuzzable_proto_library.gni")
import("//third_party/protobuf/proto_library.gni")
-proto_library("cast_channel_proto") {
- sources = [
- "authority_keys.proto",
- "cast_channel.proto",
- ]
+fuzzable_proto_library("cast_channel_fuzzer_inputs_proto") {
+ sources = [ "fuzzer_inputs.proto" ]
+ import_dirs = [ "//third_party/openscreen/src/cast/common/channel/proto" ]
+ proto_out_dir = "components/cast_channel/fuzz_proto"
}
diff --git a/chromium/components/cast_channel/proto/authority_keys.proto b/chromium/components/cast_channel/proto/authority_keys.proto
deleted file mode 100644
index 9f62d200dc0..00000000000
--- a/chromium/components/cast_channel/proto/authority_keys.proto
+++ /dev/null
@@ -1,17 +0,0 @@
-// 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.
-
-syntax = "proto2";
-
-option optimize_for = LITE_RUNTIME;
-
-package cast_channel.proto;
-
-message AuthorityKeys {
- message Key {
- required bytes fingerprint = 1;
- required bytes public_key = 2;
- }
- repeated Key keys = 1;
-}
diff --git a/chromium/components/cast_channel/proto/cast_channel.proto b/chromium/components/cast_channel/proto/cast_channel.proto
deleted file mode 100644
index 4cac6db6067..00000000000
--- a/chromium/components/cast_channel/proto/cast_channel.proto
+++ /dev/null
@@ -1,99 +0,0 @@
-// 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.
-
-syntax = "proto2";
-
-option optimize_for = LITE_RUNTIME;
-
-package cast_channel;
-
-message CastMessage {
- // Always pass a version of the protocol for future compatibility
- // requirements.
- enum ProtocolVersion { CASTV2_1_0 = 0; }
- required ProtocolVersion protocol_version = 1;
-
- // source and destination ids identify the origin and destination of the
- // message. They are used to route messages between endpoints that share a
- // device-to-device channel.
- //
- // For messages between applications:
- // - The sender application id is a unique identifier generated on behalf of
- // the sender application.
- // - The receiver id is always the the session id for the application.
- //
- // For messages to or from the sender or receiver platform, the special ids
- // 'sender-0' and 'receiver-0' can be used.
- //
- // For messages intended for all endpoints using a given channel, the
- // wildcard destination_id '*' can be used.
- required string source_id = 2;
- required string destination_id = 3;
-
- // This is the core multiplexing key. All messages are sent on a namespace
- // and endpoints sharing a channel listen on one or more namespaces. The
- // namespace defines the protocol and semantics of the message.
- required string namespace = 4;
-
- // Encoding and payload info follows.
-
- // What type of data do we have in this message.
- enum PayloadType {
- STRING = 0;
- BINARY = 1;
- }
- required PayloadType payload_type = 5;
-
- // Depending on payload_type, exactly one of the following optional fields
- // will always be set.
- optional string payload_utf8 = 6;
- optional bytes payload_binary = 7;
-}
-
-enum SignatureAlgorithm {
- UNSPECIFIED = 0;
- RSASSA_PKCS1v15 = 1;
- RSASSA_PSS = 2;
-}
-
-enum HashAlgorithm {
- SHA1 = 0;
- SHA256 = 1;
-}
-
-// Messages for authentication protocol between a sender and a receiver.
-message AuthChallenge {
- optional SignatureAlgorithm signature_algorithm = 1
- [default = RSASSA_PKCS1v15];
- optional bytes sender_nonce = 2;
- optional HashAlgorithm hash_algorithm = 3 [default = SHA1];
-}
-
-message AuthResponse {
- required bytes signature = 1;
- required bytes client_auth_certificate = 2;
- repeated bytes intermediate_certificate = 3;
- optional SignatureAlgorithm signature_algorithm = 4
- [default = RSASSA_PKCS1v15];
- optional bytes sender_nonce = 5;
- optional HashAlgorithm hash_algorithm = 6 [default = SHA1];
- optional bytes crl = 7;
-}
-
-message AuthError {
- enum ErrorType {
- INTERNAL_ERROR = 0;
- NO_TLS = 1; // The underlying connection is not TLS
- SIGNATURE_ALGORITHM_UNAVAILABLE = 2;
- }
- required ErrorType error_type = 1;
-}
-
-message DeviceAuthMessage {
- // Request fields
- optional AuthChallenge challenge = 1;
- // Response fields
- optional AuthResponse response = 2;
- optional AuthError error = 3;
-}
diff --git a/chromium/components/cast_channel/proto/fuzzer_inputs.proto b/chromium/components/cast_channel/proto/fuzzer_inputs.proto
new file mode 100644
index 00000000000..b57cbe0866e
--- /dev/null
+++ b/chromium/components/cast_channel/proto/fuzzer_inputs.proto
@@ -0,0 +1,166 @@
+// 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.
+
+// Inputs for various fuzz tests
+
+// NOTE(crbug.com/796717): As for this writing, the tests are
+// incomplete, and its not entirely clear what additional tests need
+// to be written. The general priority for tests is:
+//
+// 1. Messages that contain any data passed through the SDK/renderer
+// process.
+// 2. Messages from Cast devices.
+// 3. Messages generated entirely by the native Cast MRP, since they
+// are already from privileged code (at least for now).
+//
+// See also
+// https://chromium-coverage.appspot.com/reports/763373_fuzzers_only/linux/chromium/src/components/cast_channel/report.html
+// for fuzz test coverage.
+
+syntax = "proto2";
+
+import "cast_channel.proto";
+
+option optimize_for = LITE_RUNTIME;
+
+package cast_channel.fuzz;
+
+// Inputs for functions in cast_auth_utils.cc
+message CastAuthUtilInputs {
+ message AuthenticateChallengeReplyInput {
+ required cast.channel.DeviceAuthMessage auth_message = 1;
+ required cast.channel.CastMessage cast_message = 2;
+ required string nonce = 3;
+ }
+
+ oneof input {
+ AuthenticateChallengeReplyInput authenticate_challenge_reply_input = 1;
+ // TODO(crbug.com/796717): Add inputs for other functions to test:
+ // - VerifyTLSCertificate
+ // - VerifyCredentials
+ }
+}
+
+// Inputs for functions in cast_message_utils.cc
+message CastMessageUtilInputs {
+ message CreateBroadcastRequestInput {
+ required string source_id = 1;
+ required int32 request_id = 2;
+ repeated string app_id = 3;
+ required string broadcast_namespace = 4;
+ required string broadcast_message = 5;
+ }
+
+ message CreateLaunchRequestInput {
+ required string source_id = 1;
+ required int32 request_id = 2;
+ required string app_id = 3;
+ required string locale = 4;
+ repeated string supported_app_types = 5;
+ optional JunkValue app_params = 6;
+ }
+
+ message CreateStopRequestInput {
+ required string source_id = 1;
+ required int32 request_id = 2;
+ required string session_id = 3;
+ }
+
+ message CreateCastMessageInput {
+ required string message_namespace = 1;
+ required string source_id = 2;
+ required string destination_id = 3;
+ required JunkValue body = 4;
+ }
+
+ message CreateMediaRequestInput {
+ required int32 request_id = 1;
+ required string source_id = 2;
+ required string destination_id = 3;
+ required int32 type = 4;
+ required JunkValue body = 5;
+ }
+
+ message CreateSetVolumeRequestInput {
+ required int32 request_id = 1;
+ required string source_id = 2;
+ required JunkValue body = 3;
+ }
+
+ message CreateVirtualConnectionRequestInput {
+ required string source_id = 1;
+ required string destination_id = 2;
+ required int32 connection_type = 3;
+ required string user_agent = 4;
+ required string browser_version = 5;
+ }
+
+ message CreateGetAppAvailabilityRequestInput {
+ required string source_id = 1;
+ required int32 request_id = 2;
+ required string app_id = 3;
+ }
+
+ message GetRequestIdFromResponseInput {
+ optional int32 request_id = 1;
+ required JunkValue payload = 2;
+ }
+
+ message GetAppAvailabilityResultFromResponseInput {
+ required JunkValue payload = 1;
+ required string app_id = 2;
+ }
+
+ message GetLaunchSessionResponseInput { required JunkValue payload = 1; }
+
+ message IsCastInternalNamespaceInput {
+ required string message_namespace = 1;
+ }
+
+ message ParseMessageTypeFromPayloadInput {
+ optional string type = 1;
+ required JunkValue payload = 2;
+ }
+
+ message CreateReceiverStatusRequestInput {
+ required string source_id = 1;
+ required int32 request_id = 2;
+ }
+
+ oneof input {
+ CreateBroadcastRequestInput create_broadcast_request_input = 1;
+ CreateLaunchRequestInput create_launch_request_input = 2;
+ CreateStopRequestInput create_stop_request_input = 3;
+ CreateCastMessageInput create_cast_message_input = 4;
+ CreateMediaRequestInput create_media_request_input = 5;
+ CreateSetVolumeRequestInput create_set_volume_request_input = 6;
+ int32 int_input = 7;
+ string string_input = 8;
+ cast.channel.CastMessage cast_message = 9;
+ CreateVirtualConnectionRequestInput
+ create_virtual_connection_request_input = 10;
+ CreateGetAppAvailabilityRequestInput
+ create_get_app_availability_request_input = 11;
+ GetRequestIdFromResponseInput get_request_id_from_response_input = 12;
+ GetLaunchSessionResponseInput get_launch_session_response_input = 13;
+ ParseMessageTypeFromPayloadInput parse_message_type_from_payload_input = 14;
+ CreateReceiverStatusRequestInput create_receiver_status_request_input = 15;
+ }
+}
+
+// Message used to generate a plausible but meaningless instance of
+// base::Value.
+message JunkValue {
+ message Field {
+ required string name = 1;
+ oneof value {
+ int32 int_value = 2;
+ string string_value = 3;
+ float float_value = 4;
+ bool bool_value = 5;
+ }
+ }
+
+ repeated Field field = 1;
+}