MD Downloads: center "Open downloads folder" when there's no downloads
[chromium-blink-merge.git] / remoting / protocol / v2_authenticator.cc
blob212c5f2528e55d9c0b0e6df2ee082b52e2bb4e82
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/webrtc/libjingle/xmllite/xmlelement.h"
14 using crypto::P224EncryptedKeyExchange;
16 namespace remoting {
17 namespace protocol {
19 namespace {
21 const buzz::StaticQName kEkeTag = { kChromotingXmlNamespace,
22 "eke-message" };
23 const buzz::StaticQName kCertificateTag = { kChromotingXmlNamespace,
24 "certificate" };
26 } // namespace
28 // static
29 bool V2Authenticator::IsEkeMessage(const buzz::XmlElement* message) {
30 return message->FirstNamed(kEkeTag) != nullptr;
33 // static
34 scoped_ptr<Authenticator> V2Authenticator::CreateForClient(
35 const std::string& shared_secret,
36 Authenticator::State initial_state) {
37 return make_scoped_ptr(new V2Authenticator(
38 P224EncryptedKeyExchange::kPeerTypeClient, shared_secret, initial_state));
41 // static
42 scoped_ptr<Authenticator> V2Authenticator::CreateForHost(
43 const std::string& local_cert,
44 scoped_refptr<RsaKeyPair> key_pair,
45 const std::string& shared_secret,
46 Authenticator::State initial_state) {
47 scoped_ptr<V2Authenticator> result(new V2Authenticator(
48 P224EncryptedKeyExchange::kPeerTypeServer, shared_secret, initial_state));
49 result->local_cert_ = local_cert;
50 result->local_key_pair_ = key_pair;
51 return result.Pass();
54 V2Authenticator::V2Authenticator(
55 crypto::P224EncryptedKeyExchange::PeerType type,
56 const std::string& shared_secret,
57 Authenticator::State initial_state)
58 : certificate_sent_(false),
59 key_exchange_impl_(type, shared_secret),
60 state_(initial_state),
61 started_(false),
62 rejection_reason_(INVALID_CREDENTIALS) {
63 pending_messages_.push(key_exchange_impl_.GetNextMessage());
66 V2Authenticator::~V2Authenticator() {
69 Authenticator::State V2Authenticator::state() const {
70 if (state_ == ACCEPTED && !pending_messages_.empty())
71 return MESSAGE_READY;
72 return state_;
75 bool V2Authenticator::started() const {
76 return started_;
79 Authenticator::RejectionReason V2Authenticator::rejection_reason() const {
80 DCHECK_EQ(state(), REJECTED);
81 return rejection_reason_;
84 void V2Authenticator::ProcessMessage(const buzz::XmlElement* message,
85 const base::Closure& resume_callback) {
86 ProcessMessageInternal(message);
87 resume_callback.Run();
90 void V2Authenticator::ProcessMessageInternal(const buzz::XmlElement* message) {
91 DCHECK_EQ(state(), WAITING_MESSAGE);
93 // Parse the certificate.
94 std::string base64_cert = message->TextNamed(kCertificateTag);
95 if (!base64_cert.empty()) {
96 if (!base::Base64Decode(base64_cert, &remote_cert_)) {
97 LOG(WARNING) << "Failed to decode certificate received from the peer.";
98 remote_cert_.clear();
102 // Client always expect certificate in the first message.
103 if (!is_host_side() && remote_cert_.empty()) {
104 LOG(WARNING) << "No valid host certificate.";
105 state_ = REJECTED;
106 rejection_reason_ = PROTOCOL_ERROR;
107 return;
110 const buzz::XmlElement* eke_element = message->FirstNamed(kEkeTag);
111 if (!eke_element) {
112 LOG(WARNING) << "No eke-message found.";
113 state_ = REJECTED;
114 rejection_reason_ = PROTOCOL_ERROR;
115 return;
118 for (; eke_element; eke_element = eke_element->NextNamed(kEkeTag)) {
119 std::string base64_message = eke_element->BodyText();
120 std::string spake_message;
121 if (base64_message.empty() ||
122 !base::Base64Decode(base64_message, &spake_message)) {
123 LOG(WARNING) << "Failed to decode auth message received from the peer.";
124 state_ = REJECTED;
125 rejection_reason_ = PROTOCOL_ERROR;
126 return;
129 P224EncryptedKeyExchange::Result result =
130 key_exchange_impl_.ProcessMessage(spake_message);
131 started_ = true;
132 switch (result) {
133 case P224EncryptedKeyExchange::kResultPending:
134 pending_messages_.push(key_exchange_impl_.GetNextMessage());
135 break;
137 case P224EncryptedKeyExchange::kResultFailed:
138 state_ = REJECTED;
139 rejection_reason_ = INVALID_CREDENTIALS;
140 return;
142 case P224EncryptedKeyExchange::kResultSuccess:
143 auth_key_ = key_exchange_impl_.GetKey();
144 state_ = ACCEPTED;
145 return;
148 state_ = MESSAGE_READY;
151 scoped_ptr<buzz::XmlElement> V2Authenticator::GetNextMessage() {
152 DCHECK_EQ(state(), MESSAGE_READY);
154 scoped_ptr<buzz::XmlElement> message = CreateEmptyAuthenticatorMessage();
156 DCHECK(!pending_messages_.empty());
157 while (!pending_messages_.empty()) {
158 const std::string& spake_message = pending_messages_.front();
159 std::string base64_message;
160 base::Base64Encode(spake_message, &base64_message);
162 buzz::XmlElement* eke_tag = new buzz::XmlElement(kEkeTag);
163 eke_tag->SetBodyText(base64_message);
164 message->AddElement(eke_tag);
166 pending_messages_.pop();
169 if (!local_cert_.empty() && !certificate_sent_) {
170 buzz::XmlElement* certificate_tag = new buzz::XmlElement(kCertificateTag);
171 std::string base64_cert;
172 base::Base64Encode(local_cert_, &base64_cert);
173 certificate_tag->SetBodyText(base64_cert);
174 message->AddElement(certificate_tag);
175 certificate_sent_ = true;
178 if (state_ != ACCEPTED) {
179 state_ = WAITING_MESSAGE;
181 return message.Pass();
184 const std::string& V2Authenticator::GetAuthKey() const {
185 return auth_key_;
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 SslHmacChannelAuthenticator::CreateForHost(
195 local_cert_, local_key_pair_, auth_key_);
196 } else {
197 return SslHmacChannelAuthenticator::CreateForClient(
198 remote_cert_, auth_key_);
202 bool V2Authenticator::is_host_side() const {
203 return local_key_pair_.get() != nullptr;
206 } // namespace protocol
207 } // namespace remoting