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 if (!base::Base64Encode(spake_message
, &base64_message
)) {
160 LOG(DFATAL
) << "Cannot perform base64 encode on certificate";
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());
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