Home | History | Annotate | Download | only in protocol
      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/libjingle/source/talk/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       rejection_reason_(INVALID_CREDENTIALS) {
     66   pending_messages_.push(key_exchange_impl_.GetMessage());
     67 }
     68 
     69 V2Authenticator::~V2Authenticator() {
     70 }
     71 
     72 Authenticator::State V2Authenticator::state() const {
     73   if (state_ == ACCEPTED && !pending_messages_.empty())
     74     return MESSAGE_READY;
     75   return state_;
     76 }
     77 
     78 Authenticator::RejectionReason V2Authenticator::rejection_reason() const {
     79   DCHECK_EQ(state(), REJECTED);
     80   return rejection_reason_;
     81 }
     82 
     83 void V2Authenticator::ProcessMessage(const buzz::XmlElement* message,
     84                                      const base::Closure& resume_callback) {
     85   ProcessMessageInternal(message);
     86   resume_callback.Run();
     87 }
     88 
     89 void V2Authenticator::ProcessMessageInternal(const buzz::XmlElement* message) {
     90   DCHECK_EQ(state(), WAITING_MESSAGE);
     91 
     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.";
     97       remote_cert_.clear();
     98     }
     99   }
    100 
    101   // Client always expect certificate in the first message.
    102   if (!is_host_side() && remote_cert_.empty()) {
    103     LOG(WARNING) << "No valid host certificate.";
    104     state_ = REJECTED;
    105     rejection_reason_ = PROTOCOL_ERROR;
    106     return;
    107   }
    108 
    109   const buzz::XmlElement* eke_element = message->FirstNamed(kEkeTag);
    110   if (!eke_element) {
    111     LOG(WARNING) << "No eke-message found.";
    112     state_ = REJECTED;
    113     rejection_reason_ = PROTOCOL_ERROR;
    114     return;
    115   }
    116 
    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.";
    123       state_ = REJECTED;
    124       rejection_reason_ = PROTOCOL_ERROR;
    125       return;
    126     }
    127 
    128     P224EncryptedKeyExchange::Result result =
    129         key_exchange_impl_.ProcessMessage(spake_message);
    130     switch (result) {
    131       case P224EncryptedKeyExchange::kResultPending:
    132         pending_messages_.push(key_exchange_impl_.GetMessage());
    133         break;
    134 
    135       case P224EncryptedKeyExchange::kResultFailed:
    136         state_ = REJECTED;
    137         rejection_reason_ = INVALID_CREDENTIALS;
    138         return;
    139 
    140       case P224EncryptedKeyExchange::kResultSuccess:
    141         auth_key_ = key_exchange_impl_.GetKey();
    142         state_ = ACCEPTED;
    143         return;
    144     }
    145   }
    146 
    147   state_ = MESSAGE_READY;
    148 }
    149 
    150 scoped_ptr<buzz::XmlElement> V2Authenticator::GetNextMessage() {
    151   DCHECK_EQ(state(), MESSAGE_READY);
    152 
    153   scoped_ptr<buzz::XmlElement> message = CreateEmptyAuthenticatorMessage();
    154 
    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";
    161       continue;
    162     }
    163 
    164     buzz::XmlElement* eke_tag = new buzz::XmlElement(kEkeTag);
    165     eke_tag->SetBodyText(base64_message);
    166     message->AddElement(eke_tag);
    167 
    168     pending_messages_.pop();
    169   }
    170 
    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";
    176     }
    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
    210