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/quic_config.h"
     13 #include "net/quic/quic_protocol.h"
     14 #include "net/quic/quic_session.h"
     15 
     16 namespace net {
     17 
     18 QuicCryptoServerStream::QuicCryptoServerStream(
     19     const QuicCryptoServerConfig& crypto_config,
     20     QuicSession* session)
     21     : QuicCryptoStream(session),
     22       crypto_config_(crypto_config),
     23       validate_client_hello_cb_(NULL) {
     24 }
     25 
     26 QuicCryptoServerStream::~QuicCryptoServerStream() {
     27   // Detach from the validation callback.
     28   if (validate_client_hello_cb_ != NULL) {
     29     validate_client_hello_cb_->Cancel();
     30   }
     31 }
     32 
     33 void QuicCryptoServerStream::OnHandshakeMessage(
     34     const CryptoHandshakeMessage& message) {
     35   QuicCryptoStream::OnHandshakeMessage(message);
     36 
     37   // Do not process handshake messages after the handshake is confirmed.
     38   if (handshake_confirmed_) {
     39     CloseConnection(QUIC_CRYPTO_MESSAGE_AFTER_HANDSHAKE_COMPLETE);
     40     return;
     41   }
     42 
     43   if (message.tag() != kCHLO) {
     44     CloseConnection(QUIC_INVALID_CRYPTO_MESSAGE_TYPE);
     45     return;
     46   }
     47 
     48   if (validate_client_hello_cb_ != NULL) {
     49     // Already processing some other handshake message.  The protocol
     50     // does not allow for clients to send multiple handshake messages
     51     // before the server has a chance to respond.
     52     CloseConnection(QUIC_CRYPTO_MESSAGE_WHILE_VALIDATING_CLIENT_HELLO);
     53     return;
     54   }
     55 
     56   validate_client_hello_cb_ = new ValidateCallback(this);
     57   return crypto_config_.ValidateClientHello(
     58       message,
     59       session()->connection()->peer_address(),
     60       session()->connection()->clock(),
     61       validate_client_hello_cb_);
     62 }
     63 
     64 void QuicCryptoServerStream::FinishProcessingHandshakeMessage(
     65     const CryptoHandshakeMessage& message,
     66     const ValidateClientHelloResultCallback::Result& result) {
     67   // Clear the callback that got us here.
     68   DCHECK(validate_client_hello_cb_ != NULL);
     69   validate_client_hello_cb_ = NULL;
     70 
     71   string error_details;
     72   CryptoHandshakeMessage reply;
     73   QuicErrorCode error = ProcessClientHello(
     74       message, result, &reply, &error_details);
     75 
     76   if (error != QUIC_NO_ERROR) {
     77     CloseConnectionWithDetails(error, error_details);
     78     return;
     79   }
     80 
     81   if (reply.tag() != kSHLO) {
     82     SendHandshakeMessage(reply);
     83     return;
     84   }
     85 
     86   // If we are returning a SHLO then we accepted the handshake.
     87   QuicConfig* config = session()->config();
     88   error = config->ProcessClientHello(message, &error_details);
     89   if (error != QUIC_NO_ERROR) {
     90     CloseConnectionWithDetails(error, error_details);
     91     return;
     92   }
     93   session()->OnConfigNegotiated();
     94 
     95   config->ToHandshakeMessage(&reply);
     96 
     97   // Receiving a full CHLO implies the client is prepared to decrypt with
     98   // the new server write key.  We can start to encrypt with the new server
     99   // write key.
    100   //
    101   // NOTE: the SHLO will be encrypted with the new server write key.
    102   session()->connection()->SetEncrypter(
    103       ENCRYPTION_INITIAL,
    104       crypto_negotiated_params_.initial_crypters.encrypter.release());
    105   session()->connection()->SetDefaultEncryptionLevel(
    106       ENCRYPTION_INITIAL);
    107   // Set the decrypter immediately so that we no longer accept unencrypted
    108   // packets.
    109   session()->connection()->SetDecrypter(
    110       crypto_negotiated_params_.initial_crypters.decrypter.release());
    111   SendHandshakeMessage(reply);
    112 
    113   session()->connection()->SetEncrypter(
    114       ENCRYPTION_FORWARD_SECURE,
    115       crypto_negotiated_params_.forward_secure_crypters.encrypter.release());
    116   session()->connection()->SetDefaultEncryptionLevel(
    117       ENCRYPTION_FORWARD_SECURE);
    118   session()->connection()->SetAlternativeDecrypter(
    119       crypto_negotiated_params_.forward_secure_crypters.decrypter.release(),
    120       false /* don't latch */);
    121 
    122   encryption_established_ = true;
    123   handshake_confirmed_ = true;
    124   session()->OnCryptoHandshakeEvent(QuicSession::HANDSHAKE_CONFIRMED);
    125 }
    126 
    127 bool QuicCryptoServerStream::GetBase64SHA256ClientChannelID(
    128     string* output) const {
    129   if (!encryption_established_ ||
    130       crypto_negotiated_params_.channel_id.empty()) {
    131     return false;
    132   }
    133 
    134   const string& channel_id(crypto_negotiated_params_.channel_id);
    135   scoped_ptr<crypto::SecureHash> hash(
    136       crypto::SecureHash::Create(crypto::SecureHash::SHA256));
    137   hash->Update(channel_id.data(), channel_id.size());
    138   uint8 digest[32];
    139   hash->Finish(digest, sizeof(digest));
    140 
    141   base::Base64Encode(string(
    142       reinterpret_cast<const char*>(digest), sizeof(digest)), output);
    143   // Remove padding.
    144   size_t len = output->size();
    145   if (len >= 2) {
    146     if ((*output)[len - 1] == '=') {
    147       len--;
    148       if ((*output)[len - 1] == '=') {
    149         len--;
    150       }
    151       output->resize(len);
    152     }
    153   }
    154   return true;
    155 }
    156 
    157 QuicErrorCode QuicCryptoServerStream::ProcessClientHello(
    158     const CryptoHandshakeMessage& message,
    159     const ValidateClientHelloResultCallback::Result& result,
    160     CryptoHandshakeMessage* reply,
    161     string* error_details) {
    162   return crypto_config_.ProcessClientHello(
    163       result,
    164       session()->connection()->guid(),
    165       session()->connection()->peer_address(),
    166       session()->connection()->version(),
    167       session()->connection()->supported_versions(),
    168       session()->connection()->clock(),
    169       session()->connection()->random_generator(),
    170       &crypto_negotiated_params_, reply, error_details);
    171 }
    172 
    173 QuicCryptoServerStream::ValidateCallback::ValidateCallback(
    174     QuicCryptoServerStream* parent) : parent_(parent) {
    175 }
    176 
    177 void QuicCryptoServerStream::ValidateCallback::Cancel() {
    178   parent_ = NULL;
    179 }
    180 
    181 void QuicCryptoServerStream::ValidateCallback::RunImpl(
    182     const CryptoHandshakeMessage& client_hello,
    183     const Result& result) {
    184   if (parent_ != NULL) {
    185     parent_->FinishProcessingHandshakeMessage(client_hello, result);
    186   }
    187 }
    188 
    189 }  // namespace net
    190