1 // Copyright 2019 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "cast/receiver/channel/device_auth_namespace_handler.h"
6
7 #include <openssl/evp.h>
8
9 #include <memory>
10 #include <utility>
11
12 #include "cast/common/certificate/cast_cert_validator.h"
13 #include "cast/common/channel/message_util.h"
14 #include "cast/common/channel/proto/cast_channel.pb.h"
15 #include "cast/common/channel/virtual_connection.h"
16 #include "cast/common/channel/virtual_connection_router.h"
17 #include "platform/base/tls_credentials.h"
18 #include "util/crypto/digest_sign.h"
19
20 using ::cast::channel::AuthChallenge;
21 using ::cast::channel::AuthError;
22 using ::cast::channel::AuthResponse;
23 using ::cast::channel::CastMessage;
24 using ::cast::channel::DeviceAuthMessage;
25 using ::cast::channel::HashAlgorithm;
26 using ::cast::channel::SignatureAlgorithm;
27
28 namespace openscreen {
29 namespace cast {
30
31 namespace {
32
GenerateErrorMessage(AuthError::ErrorType error_type)33 CastMessage GenerateErrorMessage(AuthError::ErrorType error_type) {
34 DeviceAuthMessage message;
35 AuthError* error = message.mutable_error();
36 error->set_error_type(error_type);
37 std::string payload;
38 message.SerializeToString(&payload);
39
40 CastMessage response;
41 response.set_protocol_version(
42 ::cast::channel::CastMessage_ProtocolVersion_CASTV2_1_0);
43 response.set_namespace_(kAuthNamespace);
44 response.set_payload_type(::cast::channel::CastMessage_PayloadType_BINARY);
45 response.set_payload_binary(std::move(payload));
46 return response;
47 }
48
49 } // namespace
50
DeviceAuthNamespaceHandler(CredentialsProvider * creds_provider)51 DeviceAuthNamespaceHandler::DeviceAuthNamespaceHandler(
52 CredentialsProvider* creds_provider)
53 : creds_provider_(creds_provider) {}
54
55 DeviceAuthNamespaceHandler::~DeviceAuthNamespaceHandler() = default;
56
OnMessage(VirtualConnectionRouter * router,CastSocket * socket,CastMessage message)57 void DeviceAuthNamespaceHandler::OnMessage(VirtualConnectionRouter* router,
58 CastSocket* socket,
59 CastMessage message) {
60 if (!socket) {
61 return; // Don't handle auth messages from local senders. That's nonsense.
62 }
63 if (message.payload_type() !=
64 ::cast::channel::CastMessage_PayloadType_BINARY) {
65 return;
66 }
67 const std::string& payload = message.payload_binary();
68 DeviceAuthMessage device_auth_message;
69 if (!device_auth_message.ParseFromArray(payload.data(), payload.length())) {
70 // TODO(btolsch): Consider all of these cases for future error reporting
71 // mechanism.
72 return;
73 }
74
75 if (!device_auth_message.has_challenge()) {
76 return;
77 }
78
79 if (device_auth_message.has_response() || device_auth_message.has_error()) {
80 return;
81 }
82
83 const VirtualConnection virtual_conn{
84 message.destination_id(), message.source_id(), socket->socket_id()};
85 const AuthChallenge& challenge = device_auth_message.challenge();
86 const SignatureAlgorithm sig_alg = challenge.signature_algorithm();
87 HashAlgorithm hash_alg = challenge.hash_algorithm();
88 // TODO(btolsch): Reconsider supporting SHA1 after further metrics
89 // investigation.
90 if ((sig_alg != ::cast::channel::UNSPECIFIED &&
91 sig_alg != ::cast::channel::RSASSA_PKCS1v15) ||
92 (hash_alg != ::cast::channel::SHA1 &&
93 hash_alg != ::cast::channel::SHA256)) {
94 router->Send(virtual_conn, GenerateErrorMessage(
95 AuthError::SIGNATURE_ALGORITHM_UNAVAILABLE));
96 return;
97 }
98 const EVP_MD* digest =
99 hash_alg == ::cast::channel::SHA256 ? EVP_sha256() : EVP_sha1();
100
101 const absl::Span<const uint8_t> tls_cert_der =
102 creds_provider_->GetCurrentTlsCertAsDer();
103 const DeviceCredentials& device_creds =
104 creds_provider_->GetCurrentDeviceCredentials();
105 if (tls_cert_der.empty() || device_creds.certs.empty() ||
106 !device_creds.private_key) {
107 // TODO(btolsch): Add this to future error reporting.
108 router->Send(virtual_conn, GenerateErrorMessage(AuthError::INTERNAL_ERROR));
109 return;
110 }
111
112 std::unique_ptr<AuthResponse> auth_response(new AuthResponse());
113 auth_response->set_client_auth_certificate(device_creds.certs[0]);
114 for (auto it = device_creds.certs.begin() + 1; it != device_creds.certs.end();
115 ++it) {
116 auth_response->add_intermediate_certificate(*it);
117 }
118 auth_response->set_signature_algorithm(::cast::channel::RSASSA_PKCS1v15);
119 auth_response->set_hash_algorithm(hash_alg);
120 std::string sender_nonce;
121 if (challenge.has_sender_nonce()) {
122 sender_nonce = challenge.sender_nonce();
123 auth_response->set_sender_nonce(sender_nonce);
124 }
125
126 auth_response->set_crl(device_creds.serialized_crl);
127
128 std::vector<uint8_t> to_be_signed;
129 to_be_signed.reserve(sender_nonce.size() + tls_cert_der.size());
130 to_be_signed.insert(to_be_signed.end(), sender_nonce.begin(),
131 sender_nonce.end());
132 to_be_signed.insert(to_be_signed.end(), tls_cert_der.begin(),
133 tls_cert_der.end());
134
135 ErrorOr<std::string> signature =
136 SignData(digest, device_creds.private_key.get(), to_be_signed);
137 if (!signature) {
138 router->Send(virtual_conn, GenerateErrorMessage(AuthError::INTERNAL_ERROR));
139 return;
140 }
141 auth_response->set_signature(std::move(signature.value()));
142
143 DeviceAuthMessage response_auth_message;
144 response_auth_message.set_allocated_response(auth_response.release());
145
146 std::string response_string;
147 response_auth_message.SerializeToString(&response_string);
148 CastMessage response;
149 response.set_protocol_version(
150 ::cast::channel::CastMessage_ProtocolVersion_CASTV2_1_0);
151 response.set_namespace_(kAuthNamespace);
152 response.set_payload_type(::cast::channel::CastMessage_PayloadType_BINARY);
153 response.set_payload_binary(std::move(response_string));
154 router->Send(virtual_conn, std::move(response));
155 }
156
157 } // namespace cast
158 } // namespace openscreen
159