Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / remoting / protocol / v2_authenticator.cc
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.
4
5 #include "remoting/protocol/v2_authenticator.h"
6
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"
13
14 using crypto::P224EncryptedKeyExchange;
15
16 #if defined(_WIN32) && defined(GetMessage)
17 #undef GetMessage
18 #endif
19
20 namespace remoting {
21 namespace protocol {
22
23 namespace {
24
25 const buzz::StaticQName kEkeTag = { kChromotingXmlNamespace,
26                                     "eke-message" };
27 const buzz::StaticQName kCertificateTag = { kChromotingXmlNamespace,
28                                             "certificate" };
29
30 }  // namespace
31
32 // static
33 bool V2Authenticator::IsEkeMessage(const buzz::XmlElement* message) {
34   return message->FirstNamed(kEkeTag) != NULL;
35 }
36
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));
43 }
44
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());
56 }
57
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       started_(false),
66       rejection_reason_(INVALID_CREDENTIALS) {
67   pending_messages_.push(key_exchange_impl_.GetMessage());
68 }
69
70 V2Authenticator::~V2Authenticator() {
71 }
72
73 Authenticator::State V2Authenticator::state() const {
74   if (state_ == ACCEPTED && !pending_messages_.empty())
75     return MESSAGE_READY;
76   return state_;
77 }
78
79 bool V2Authenticator::started() const {
80   return started_;
81 }
82
83 Authenticator::RejectionReason V2Authenticator::rejection_reason() const {
84   DCHECK_EQ(state(), REJECTED);
85   return rejection_reason_;
86 }
87
88 void V2Authenticator::ProcessMessage(const buzz::XmlElement* message,
89                                      const base::Closure& resume_callback) {
90   ProcessMessageInternal(message);
91   resume_callback.Run();
92 }
93
94 void V2Authenticator::ProcessMessageInternal(const buzz::XmlElement* message) {
95   DCHECK_EQ(state(), WAITING_MESSAGE);
96
97   // Parse the certificate.
98   std::string base64_cert = message->TextNamed(kCertificateTag);
99   if (!base64_cert.empty()) {
100     if (!base::Base64Decode(base64_cert, &remote_cert_)) {
101       LOG(WARNING) << "Failed to decode certificate received from the peer.";
102       remote_cert_.clear();
103     }
104   }
105
106   // Client always expect certificate in the first message.
107   if (!is_host_side() && remote_cert_.empty()) {
108     LOG(WARNING) << "No valid host certificate.";
109     state_ = REJECTED;
110     rejection_reason_ = PROTOCOL_ERROR;
111     return;
112   }
113
114   const buzz::XmlElement* eke_element = message->FirstNamed(kEkeTag);
115   if (!eke_element) {
116     LOG(WARNING) << "No eke-message found.";
117     state_ = REJECTED;
118     rejection_reason_ = PROTOCOL_ERROR;
119     return;
120   }
121
122   for (; eke_element; eke_element = eke_element->NextNamed(kEkeTag)) {
123     std::string base64_message = eke_element->BodyText();
124     std::string spake_message;
125     if (base64_message.empty() ||
126         !base::Base64Decode(base64_message, &spake_message)) {
127       LOG(WARNING) << "Failed to decode auth message received from the peer.";
128       state_ = REJECTED;
129       rejection_reason_ = PROTOCOL_ERROR;
130       return;
131     }
132
133     P224EncryptedKeyExchange::Result result =
134         key_exchange_impl_.ProcessMessage(spake_message);
135     started_ = true;
136     switch (result) {
137       case P224EncryptedKeyExchange::kResultPending:
138         pending_messages_.push(key_exchange_impl_.GetMessage());
139         break;
140
141       case P224EncryptedKeyExchange::kResultFailed:
142         state_ = REJECTED;
143         rejection_reason_ = INVALID_CREDENTIALS;
144         return;
145
146       case P224EncryptedKeyExchange::kResultSuccess:
147         auth_key_ = key_exchange_impl_.GetKey();
148         state_ = ACCEPTED;
149         return;
150     }
151   }
152   state_ = MESSAGE_READY;
153 }
154
155 scoped_ptr<buzz::XmlElement> V2Authenticator::GetNextMessage() {
156   DCHECK_EQ(state(), MESSAGE_READY);
157
158   scoped_ptr<buzz::XmlElement> message = CreateEmptyAuthenticatorMessage();
159
160   DCHECK(!pending_messages_.empty());
161   while (!pending_messages_.empty()) {
162     const std::string& spake_message = pending_messages_.front();
163     std::string base64_message;
164     base::Base64Encode(spake_message, &base64_message);
165
166     buzz::XmlElement* eke_tag = new buzz::XmlElement(kEkeTag);
167     eke_tag->SetBodyText(base64_message);
168     message->AddElement(eke_tag);
169
170     pending_messages_.pop();
171   }
172
173   if (!local_cert_.empty() && !certificate_sent_) {
174     buzz::XmlElement* certificate_tag = new buzz::XmlElement(kCertificateTag);
175     std::string base64_cert;
176     base::Base64Encode(local_cert_, &base64_cert);
177     certificate_tag->SetBodyText(base64_cert);
178     message->AddElement(certificate_tag);
179     certificate_sent_ = true;
180   }
181
182   if (state_ != ACCEPTED) {
183     state_ = WAITING_MESSAGE;
184   }
185   return message.Pass();
186 }
187
188 scoped_ptr<ChannelAuthenticator>
189 V2Authenticator::CreateChannelAuthenticator() const {
190   DCHECK_EQ(state(), ACCEPTED);
191   CHECK(!auth_key_.empty());
192
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());
201   }
202 }
203
204 bool V2Authenticator::is_host_side() const {
205   return local_key_pair_.get() != NULL;
206 }
207
208 }  // namespace protocol
209 }  // namespace remoting