telemetry: Support custom 'out' directory
[chromium-blink-merge.git] / remoting / protocol / v2_authenticator.cc
blob80f7af3d5c8ad7a5cc3997ce13f979fa17ed7091
1 // Copyright (c) 2012 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.
5 #include "remoting/protocol/v2_authenticator.h"
7 #include "base/base64.h"
8 #include "base/logging.h"
9 #include "remoting/base/constants.h"
10 #include "remoting/base/rsa_key_pair.h"
11 #include "remoting/protocol/ssl_hmac_channel_authenticator.h"
12 #include "third_party/libjingle/source/talk/xmllite/xmlelement.h"
14 using crypto::P224EncryptedKeyExchange;
16 #if defined(_WIN32) && defined(GetMessage)
17 #undef GetMessage
18 #endif
20 namespace remoting {
21 namespace protocol {
23 namespace {
25 const buzz::StaticQName kEkeTag = { kChromotingXmlNamespace,
26 "eke-message" };
27 const buzz::StaticQName kCertificateTag = { kChromotingXmlNamespace,
28 "certificate" };
30 } // namespace
32 // static
33 bool V2Authenticator::IsEkeMessage(const buzz::XmlElement* message) {
34 return message->FirstNamed(kEkeTag) != NULL;
37 // static
38 scoped_ptr<Authenticator> V2Authenticator::CreateForClient(
39 const std::string& shared_secret,
40 Authenticator::State initial_state) {
41 return scoped_ptr<Authenticator>(new V2Authenticator(
42 P224EncryptedKeyExchange::kPeerTypeClient, shared_secret, initial_state));
45 // static
46 scoped_ptr<Authenticator> V2Authenticator::CreateForHost(
47 const std::string& local_cert,
48 scoped_refptr<RsaKeyPair> key_pair,
49 const std::string& shared_secret,
50 Authenticator::State initial_state) {
51 scoped_ptr<V2Authenticator> result(new V2Authenticator(
52 P224EncryptedKeyExchange::kPeerTypeServer, shared_secret, initial_state));
53 result->local_cert_ = local_cert;
54 result->local_key_pair_ = key_pair;
55 return scoped_ptr<Authenticator>(result.Pass());
58 V2Authenticator::V2Authenticator(
59 crypto::P224EncryptedKeyExchange::PeerType type,
60 const std::string& shared_secret,
61 Authenticator::State initial_state)
62 : certificate_sent_(false),
63 key_exchange_impl_(type, shared_secret),
64 state_(initial_state),
65 rejection_reason_(INVALID_CREDENTIALS) {
66 pending_messages_.push(key_exchange_impl_.GetMessage());
69 V2Authenticator::~V2Authenticator() {
72 Authenticator::State V2Authenticator::state() const {
73 if (state_ == ACCEPTED && !pending_messages_.empty())
74 return MESSAGE_READY;
75 return state_;
78 Authenticator::RejectionReason V2Authenticator::rejection_reason() const {
79 DCHECK_EQ(state(), REJECTED);
80 return rejection_reason_;
83 void V2Authenticator::ProcessMessage(const buzz::XmlElement* message,
84 const base::Closure& resume_callback) {
85 ProcessMessageInternal(message);
86 resume_callback.Run();
89 void V2Authenticator::ProcessMessageInternal(const buzz::XmlElement* message) {
90 DCHECK_EQ(state(), WAITING_MESSAGE);
92 // Parse the certificate.
93 std::string base64_cert = message->TextNamed(kCertificateTag);
94 if (!base64_cert.empty()) {
95 if (!base::Base64Decode(base64_cert, &remote_cert_)) {
96 LOG(WARNING) << "Failed to decode certificate received from the peer.";
97 remote_cert_.clear();
101 // Client always expect certificate in the first message.
102 if (!is_host_side() && remote_cert_.empty()) {
103 LOG(WARNING) << "No valid host certificate.";
104 state_ = REJECTED;
105 rejection_reason_ = PROTOCOL_ERROR;
106 return;
109 const buzz::XmlElement* eke_element = message->FirstNamed(kEkeTag);
110 if (!eke_element) {
111 LOG(WARNING) << "No eke-message found.";
112 state_ = REJECTED;
113 rejection_reason_ = PROTOCOL_ERROR;
114 return;
117 for (; eke_element; eke_element = eke_element->NextNamed(kEkeTag)) {
118 std::string base64_message = eke_element->BodyText();
119 std::string spake_message;
120 if (base64_message.empty() ||
121 !base::Base64Decode(base64_message, &spake_message)) {
122 LOG(WARNING) << "Failed to decode auth message received from the peer.";
123 state_ = REJECTED;
124 rejection_reason_ = PROTOCOL_ERROR;
125 return;
128 P224EncryptedKeyExchange::Result result =
129 key_exchange_impl_.ProcessMessage(spake_message);
130 switch (result) {
131 case P224EncryptedKeyExchange::kResultPending:
132 pending_messages_.push(key_exchange_impl_.GetMessage());
133 break;
135 case P224EncryptedKeyExchange::kResultFailed:
136 state_ = REJECTED;
137 rejection_reason_ = INVALID_CREDENTIALS;
138 return;
140 case P224EncryptedKeyExchange::kResultSuccess:
141 auth_key_ = key_exchange_impl_.GetKey();
142 state_ = ACCEPTED;
143 return;
147 state_ = MESSAGE_READY;
150 scoped_ptr<buzz::XmlElement> V2Authenticator::GetNextMessage() {
151 DCHECK_EQ(state(), MESSAGE_READY);
153 scoped_ptr<buzz::XmlElement> message = CreateEmptyAuthenticatorMessage();
155 DCHECK(!pending_messages_.empty());
156 while (!pending_messages_.empty()) {
157 const std::string& spake_message = pending_messages_.front();
158 std::string base64_message;
159 if (!base::Base64Encode(spake_message, &base64_message)) {
160 LOG(DFATAL) << "Cannot perform base64 encode on certificate";
161 continue;
164 buzz::XmlElement* eke_tag = new buzz::XmlElement(kEkeTag);
165 eke_tag->SetBodyText(base64_message);
166 message->AddElement(eke_tag);
168 pending_messages_.pop();
171 if (!local_cert_.empty() && !certificate_sent_) {
172 buzz::XmlElement* certificate_tag = new buzz::XmlElement(kCertificateTag);
173 std::string base64_cert;
174 if (!base::Base64Encode(local_cert_, &base64_cert)) {
175 LOG(DFATAL) << "Cannot perform base64 encode on certificate";
177 certificate_tag->SetBodyText(base64_cert);
178 message->AddElement(certificate_tag);
179 certificate_sent_ = true;
182 if (state_ != ACCEPTED) {
183 state_ = WAITING_MESSAGE;
185 return message.Pass();
188 scoped_ptr<ChannelAuthenticator>
189 V2Authenticator::CreateChannelAuthenticator() const {
190 DCHECK_EQ(state(), ACCEPTED);
191 CHECK(!auth_key_.empty());
193 if (is_host_side()) {
194 return scoped_ptr<ChannelAuthenticator>(
195 SslHmacChannelAuthenticator::CreateForHost(
196 local_cert_, local_key_pair_, auth_key_).Pass());
197 } else {
198 return scoped_ptr<ChannelAuthenticator>(
199 SslHmacChannelAuthenticator::CreateForClient(
200 remote_cert_, auth_key_).Pass());
204 bool V2Authenticator::is_host_side() const {
205 return local_key_pair_.get() != NULL;
208 } // namespace protocol
209 } // namespace remoting