Home | History | Annotate | Download | only in quic
      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 "net/quic/quic_crypto_server_stream.h"
      6 
      7 #include "base/base64.h"
      8 #include "crypto/secure_hash.h"
      9 #include "net/quic/crypto/crypto_protocol.h"
     10 #include "net/quic/crypto/crypto_utils.h"
     11 #include "net/quic/crypto/quic_crypto_server_config.h"
     12 #include "net/quic/crypto/source_address_token.h"
     13 #include "net/quic/quic_config.h"
     14 #include "net/quic/quic_protocol.h"
     15 #include "net/quic/quic_session.h"
     16 
     17 namespace net {
     18 
     19 void ServerHelloNotifier::OnAckNotification(
     20     int num_original_packets,
     21     int num_original_bytes,
     22     int num_retransmitted_packets,
     23     int num_retransmitted_bytes,
     24     QuicTime::Delta delta_largest_observed) {
     25   server_stream_->OnServerHelloAcked();
     26 }
     27 
     28 QuicCryptoServerStream::QuicCryptoServerStream(
     29     const QuicCryptoServerConfig& crypto_config,
     30     QuicSession* session)
     31     : QuicCryptoStream(session),
     32       crypto_config_(crypto_config),
     33       validate_client_hello_cb_(NULL),
     34       num_handshake_messages_(0),
     35       num_server_config_update_messages_sent_(0) {
     36 }
     37 
     38 QuicCryptoServerStream::~QuicCryptoServerStream() {
     39   CancelOutstandingCallbacks();
     40 }
     41 
     42 void QuicCryptoServerStream::CancelOutstandingCallbacks() {
     43   // Detach from the validation callback.  Calling this multiple times is safe.
     44   if (validate_client_hello_cb_ != NULL) {
     45     validate_client_hello_cb_->Cancel();
     46   }
     47 }
     48 
     49 void QuicCryptoServerStream::OnHandshakeMessage(
     50     const CryptoHandshakeMessage& message) {
     51   QuicCryptoStream::OnHandshakeMessage(message);
     52   ++num_handshake_messages_;
     53 
     54   // Do not process handshake messages after the handshake is confirmed.
     55   if (handshake_confirmed_) {
     56     CloseConnection(QUIC_CRYPTO_MESSAGE_AFTER_HANDSHAKE_COMPLETE);
     57     return;
     58   }
     59 
     60   if (message.tag() != kCHLO) {
     61     CloseConnection(QUIC_INVALID_CRYPTO_MESSAGE_TYPE);
     62     return;
     63   }
     64 
     65   if (validate_client_hello_cb_ != NULL) {
     66     // Already processing some other handshake message.  The protocol
     67     // does not allow for clients to send multiple handshake messages
     68     // before the server has a chance to respond.
     69     CloseConnection(QUIC_CRYPTO_MESSAGE_WHILE_VALIDATING_CLIENT_HELLO);
     70     return;
     71   }
     72 
     73   validate_client_hello_cb_ = new ValidateCallback(this);
     74   return crypto_config_.ValidateClientHello(
     75       message,
     76       session()->connection()->peer_address(),
     77       session()->connection()->clock(),
     78       validate_client_hello_cb_);
     79 }
     80 
     81 void QuicCryptoServerStream::FinishProcessingHandshakeMessage(
     82     const CryptoHandshakeMessage& message,
     83     const ValidateClientHelloResultCallback::Result& result) {
     84   // Clear the callback that got us here.
     85   DCHECK(validate_client_hello_cb_ != NULL);
     86   validate_client_hello_cb_ = NULL;
     87 
     88   string error_details;
     89   CryptoHandshakeMessage reply;
     90   QuicErrorCode error = ProcessClientHello(
     91       message, result, &reply, &error_details);
     92 
     93   if (error != QUIC_NO_ERROR) {
     94     CloseConnectionWithDetails(error, error_details);
     95     return;
     96   }
     97 
     98   if (reply.tag() != kSHLO) {
     99     SendHandshakeMessage(reply);
    100     return;
    101   }
    102 
    103   // If we are returning a SHLO then we accepted the handshake.
    104   QuicConfig* config = session()->config();
    105   OverrideQuicConfigDefaults(config);
    106   error = config->ProcessPeerHello(message, CLIENT, &error_details);
    107   if (error != QUIC_NO_ERROR) {
    108     CloseConnectionWithDetails(error, error_details);
    109     return;
    110   }
    111   session()->OnConfigNegotiated();
    112 
    113   config->ToHandshakeMessage(&reply);
    114 
    115   // Receiving a full CHLO implies the client is prepared to decrypt with
    116   // the new server write key.  We can start to encrypt with the new server
    117   // write key.
    118   //
    119   // NOTE: the SHLO will be encrypted with the new server write key.
    120   session()->connection()->SetEncrypter(
    121       ENCRYPTION_INITIAL,
    122       crypto_negotiated_params_.initial_crypters.encrypter.release());
    123   session()->connection()->SetDefaultEncryptionLevel(
    124       ENCRYPTION_INITIAL);
    125   // Set the decrypter immediately so that we no longer accept unencrypted
    126   // packets.
    127   session()->connection()->SetDecrypter(
    128       crypto_negotiated_params_.initial_crypters.decrypter.release(),
    129       ENCRYPTION_INITIAL);
    130 
    131   // We want to be notified when the SHLO is ACKed so that we can disable
    132   // HANDSHAKE_MODE in the sent packet manager.
    133   if (session()->connection()->version() <= QUIC_VERSION_21) {
    134     SendHandshakeMessage(reply);
    135   } else {
    136     scoped_refptr<ServerHelloNotifier> server_hello_notifier(
    137         new ServerHelloNotifier(this));
    138     SendHandshakeMessage(reply, server_hello_notifier.get());
    139   }
    140 
    141   session()->connection()->SetEncrypter(
    142       ENCRYPTION_FORWARD_SECURE,
    143       crypto_negotiated_params_.forward_secure_crypters.encrypter.release());
    144   session()->connection()->SetDefaultEncryptionLevel(
    145       ENCRYPTION_FORWARD_SECURE);
    146   session()->connection()->SetAlternativeDecrypter(
    147       crypto_negotiated_params_.forward_secure_crypters.decrypter.release(),
    148       ENCRYPTION_FORWARD_SECURE, false /* don't latch */);
    149 
    150   encryption_established_ = true;
    151   handshake_confirmed_ = true;
    152   session()->OnCryptoHandshakeEvent(QuicSession::HANDSHAKE_CONFIRMED);
    153 
    154   // Now that the handshake is complete, send an updated server config and
    155   // source-address token to the client.
    156   SendServerConfigUpdate(NULL);
    157 }
    158 
    159 void QuicCryptoServerStream::SendServerConfigUpdate(
    160     const CachedNetworkParameters* cached_network_params) {
    161   if (session()->connection()->version() <= QUIC_VERSION_21 ||
    162       !handshake_confirmed_) {
    163     return;
    164   }
    165 
    166   CryptoHandshakeMessage server_config_update_message;
    167   if (!crypto_config_.BuildServerConfigUpdateMessage(
    168           session()->connection()->peer_address(),
    169           session()->connection()->clock(),
    170           session()->connection()->random_generator(),
    171           crypto_negotiated_params_,
    172           cached_network_params,
    173           &server_config_update_message)) {
    174     DVLOG(1) << "Server: Failed to build server config update (SCUP)!";
    175     return;
    176   }
    177 
    178   DVLOG(1) << "Server: Sending server config update: "
    179            << server_config_update_message.DebugString();
    180   const QuicData& data = server_config_update_message.GetSerialized();
    181   WriteOrBufferData(string(data.data(), data.length()), false, NULL);
    182 
    183   ++num_server_config_update_messages_sent_;
    184 }
    185 
    186 void QuicCryptoServerStream::OnServerHelloAcked() {
    187   session()->connection()->OnHandshakeComplete();
    188 }
    189 
    190 bool QuicCryptoServerStream::GetBase64SHA256ClientChannelID(
    191     string* output) const {
    192   if (!encryption_established_ ||
    193       crypto_negotiated_params_.channel_id.empty()) {
    194     return false;
    195   }
    196 
    197   const string& channel_id(crypto_negotiated_params_.channel_id);
    198   scoped_ptr<crypto::SecureHash> hash(
    199       crypto::SecureHash::Create(crypto::SecureHash::SHA256));
    200   hash->Update(channel_id.data(), channel_id.size());
    201   uint8 digest[32];
    202   hash->Finish(digest, sizeof(digest));
    203 
    204   base::Base64Encode(string(
    205       reinterpret_cast<const char*>(digest), sizeof(digest)), output);
    206   // Remove padding.
    207   size_t len = output->size();
    208   if (len >= 2) {
    209     if ((*output)[len - 1] == '=') {
    210       len--;
    211       if ((*output)[len - 1] == '=') {
    212         len--;
    213       }
    214       output->resize(len);
    215     }
    216   }
    217   return true;
    218 }
    219 
    220 QuicErrorCode QuicCryptoServerStream::ProcessClientHello(
    221     const CryptoHandshakeMessage& message,
    222     const ValidateClientHelloResultCallback::Result& result,
    223     CryptoHandshakeMessage* reply,
    224     string* error_details) {
    225   return crypto_config_.ProcessClientHello(
    226       result,
    227       session()->connection()->connection_id(),
    228       session()->connection()->peer_address(),
    229       session()->connection()->version(),
    230       session()->connection()->supported_versions(),
    231       session()->connection()->clock(),
    232       session()->connection()->random_generator(),
    233       &crypto_negotiated_params_, reply, error_details);
    234 }
    235 
    236 void QuicCryptoServerStream::OverrideQuicConfigDefaults(QuicConfig* config) {
    237 }
    238 
    239 QuicCryptoServerStream::ValidateCallback::ValidateCallback(
    240     QuicCryptoServerStream* parent) : parent_(parent) {
    241 }
    242 
    243 void QuicCryptoServerStream::ValidateCallback::Cancel() {
    244   parent_ = NULL;
    245 }
    246 
    247 void QuicCryptoServerStream::ValidateCallback::RunImpl(
    248     const CryptoHandshakeMessage& client_hello,
    249     const Result& result) {
    250   if (parent_ != NULL) {
    251     parent_->FinishProcessingHandshakeMessage(client_hello, result);
    252   }
    253 }
    254 
    255 }  // namespace net
    256