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)
25 const buzz::StaticQName kEkeTag
= { kChromotingXmlNamespace
,
27 const buzz::StaticQName kCertificateTag
= { kChromotingXmlNamespace
,
33 bool V2Authenticator::IsEkeMessage(const buzz::XmlElement
* message
) {
34 return message
->FirstNamed(kEkeTag
) != NULL
;
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
));
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())
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.";
101 // Client always expect certificate in the first message.
102 if (!is_host_side() && remote_cert_
.empty()) {
103 LOG(WARNING
) << "No valid host certificate.";
105 rejection_reason_
= PROTOCOL_ERROR
;
109 const buzz::XmlElement
* eke_element
= message
->FirstNamed(kEkeTag
);
111 LOG(WARNING
) << "No eke-message found.";
113 rejection_reason_
= PROTOCOL_ERROR
;
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.";
124 rejection_reason_
= PROTOCOL_ERROR
;
128 P224EncryptedKeyExchange::Result result
=
129 key_exchange_impl_
.ProcessMessage(spake_message
);
131 case P224EncryptedKeyExchange::kResultPending
:
132 pending_messages_
.push(key_exchange_impl_
.GetMessage());
135 case P224EncryptedKeyExchange::kResultFailed
:
137 rejection_reason_
= INVALID_CREDENTIALS
;
140 case P224EncryptedKeyExchange::kResultSuccess
:
141 auth_key_
= key_exchange_impl_
.GetKey();
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 base::Base64Encode(spake_message
, &base64_message
);
161 buzz::XmlElement
* eke_tag
= new buzz::XmlElement(kEkeTag
);
162 eke_tag
->SetBodyText(base64_message
);
163 message
->AddElement(eke_tag
);
165 pending_messages_
.pop();
168 if (!local_cert_
.empty() && !certificate_sent_
) {
169 buzz::XmlElement
* certificate_tag
= new buzz::XmlElement(kCertificateTag
);
170 std::string base64_cert
;
171 base::Base64Encode(local_cert_
, &base64_cert
);
172 certificate_tag
->SetBodyText(base64_cert
);
173 message
->AddElement(certificate_tag
);
174 certificate_sent_
= true;
177 if (state_
!= ACCEPTED
) {
178 state_
= WAITING_MESSAGE
;
180 return message
.Pass();
183 scoped_ptr
<ChannelAuthenticator
>
184 V2Authenticator::CreateChannelAuthenticator() const {
185 DCHECK_EQ(state(), ACCEPTED
);
186 CHECK(!auth_key_
.empty());
188 if (is_host_side()) {
189 return scoped_ptr
<ChannelAuthenticator
>(
190 SslHmacChannelAuthenticator::CreateForHost(
191 local_cert_
, local_key_pair_
, auth_key_
).Pass());
193 return scoped_ptr
<ChannelAuthenticator
>(
194 SslHmacChannelAuthenticator::CreateForClient(
195 remote_cert_
, auth_key_
).Pass());
199 bool V2Authenticator::is_host_side() const {
200 return local_key_pair_
.get() != NULL
;
203 } // namespace protocol
204 } // namespace remoting