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 "crypto/rsa_private_key.h"
10 #include "remoting/base/constants.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 const crypto::RSAPrivateKey
& local_private_key
,
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_private_key_
.reset(local_private_key
.Copy());
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 DCHECK_EQ(state(), WAITING_MESSAGE
);
86 // Parse the certificate.
87 std::string base64_cert
= message
->TextNamed(kCertificateTag
);
88 if (!base64_cert
.empty()) {
89 if (!base::Base64Decode(base64_cert
, &remote_cert_
)) {
90 LOG(WARNING
) << "Failed to decode certificate received from the peer.";
95 // Client always expect certificate in the first message.
96 if (!is_host_side() && remote_cert_
.empty()) {
97 LOG(WARNING
) << "No valid host certificate.";
99 rejection_reason_
= PROTOCOL_ERROR
;
103 const buzz::XmlElement
* eke_element
= message
->FirstNamed(kEkeTag
);
105 LOG(WARNING
) << "No eke-message found.";
107 rejection_reason_
= PROTOCOL_ERROR
;
111 for (; eke_element
; eke_element
= eke_element
->NextNamed(kEkeTag
)) {
112 std::string base64_message
= eke_element
->BodyText();
113 std::string spake_message
;
114 if (base64_message
.empty() ||
115 !base::Base64Decode(base64_message
, &spake_message
)) {
116 LOG(WARNING
) << "Failed to decode auth message received from the peer.";
118 rejection_reason_
= PROTOCOL_ERROR
;
122 P224EncryptedKeyExchange::Result result
=
123 key_exchange_impl_
.ProcessMessage(spake_message
);
125 case P224EncryptedKeyExchange::kResultPending
:
126 pending_messages_
.push(key_exchange_impl_
.GetMessage());
129 case P224EncryptedKeyExchange::kResultFailed
:
131 rejection_reason_
= INVALID_CREDENTIALS
;
134 case P224EncryptedKeyExchange::kResultSuccess
:
135 auth_key_
= key_exchange_impl_
.GetKey();
141 state_
= MESSAGE_READY
;
144 scoped_ptr
<buzz::XmlElement
> V2Authenticator::GetNextMessage() {
145 DCHECK_EQ(state(), MESSAGE_READY
);
147 scoped_ptr
<buzz::XmlElement
> message
= CreateEmptyAuthenticatorMessage();
149 DCHECK(!pending_messages_
.empty());
150 while (!pending_messages_
.empty()) {
151 const std::string
& spake_message
= pending_messages_
.front();
152 std::string base64_message
;
153 if (!base::Base64Encode(spake_message
, &base64_message
)) {
154 LOG(DFATAL
) << "Cannot perform base64 encode on certificate";
158 buzz::XmlElement
* eke_tag
= new buzz::XmlElement(kEkeTag
);
159 eke_tag
->SetBodyText(base64_message
);
160 message
->AddElement(eke_tag
);
162 pending_messages_
.pop();
165 if (!local_cert_
.empty() && !certificate_sent_
) {
166 buzz::XmlElement
* certificate_tag
= new buzz::XmlElement(kCertificateTag
);
167 std::string base64_cert
;
168 if (!base::Base64Encode(local_cert_
, &base64_cert
)) {
169 LOG(DFATAL
) << "Cannot perform base64 encode on certificate";
171 certificate_tag
->SetBodyText(base64_cert
);
172 message
->AddElement(certificate_tag
);
173 certificate_sent_
= true;
176 if (state_
!= ACCEPTED
) {
177 state_
= WAITING_MESSAGE
;
179 return message
.Pass();
182 scoped_ptr
<ChannelAuthenticator
>
183 V2Authenticator::CreateChannelAuthenticator() const {
184 DCHECK_EQ(state(), ACCEPTED
);
185 CHECK(!auth_key_
.empty());
187 if (is_host_side()) {
188 return scoped_ptr
<ChannelAuthenticator
>(
189 SslHmacChannelAuthenticator::CreateForHost(
190 local_cert_
, local_private_key_
.get(), auth_key_
).Pass());
192 return scoped_ptr
<ChannelAuthenticator
>(
193 SslHmacChannelAuthenticator::CreateForClient(
194 remote_cert_
, auth_key_
).Pass());
198 bool V2Authenticator::is_host_side() const {
199 return local_private_key_
.get() != NULL
;
202 } // namespace protocol
203 } // namespace remoting