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_server_config.h"
     11 #include "net/quic/crypto/crypto_utils.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 }
     24 
     25 QuicCryptoServerStream::~QuicCryptoServerStream() {
     26 }
     27 
     28 void QuicCryptoServerStream::OnHandshakeMessage(
     29     const CryptoHandshakeMessage& message) {
     30   // Do not process handshake messages after the handshake is confirmed.
     31   if (handshake_confirmed_) {
     32     CloseConnection(QUIC_CRYPTO_MESSAGE_AFTER_HANDSHAKE_COMPLETE);
     33     return;
     34   }
     35 
     36   if (message.tag() != kCHLO) {
     37     CloseConnection(QUIC_INVALID_CRYPTO_MESSAGE_TYPE);
     38     return;
     39   }
     40 
     41   string error_details;
     42   CryptoHandshakeMessage reply;
     43 
     44   QuicErrorCode error = ProcessClientHello(message, &reply, &error_details);
     45 
     46   if (error != QUIC_NO_ERROR) {
     47     CloseConnectionWithDetails(error, error_details);
     48     return;
     49   }
     50 
     51   if (reply.tag() != kSHLO) {
     52     SendHandshakeMessage(reply);
     53     return;
     54   }
     55 
     56   // If we are returning a SHLO then we accepted the handshake.
     57   QuicConfig* config = session()->config();
     58   error = config->ProcessClientHello(message, &error_details);
     59   if (error != QUIC_NO_ERROR) {
     60     CloseConnectionWithDetails(error, error_details);
     61     return;
     62   }
     63 
     64   config->ToHandshakeMessage(&reply);
     65 
     66   // Receiving a full CHLO implies the client is prepared to decrypt with
     67   // the new server write key.  We can start to encrypt with the new server
     68   // write key.
     69   //
     70   // NOTE: the SHLO will be encrypted with the new server write key.
     71   session()->connection()->SetEncrypter(
     72       ENCRYPTION_INITIAL,
     73       crypto_negotiated_params_.initial_crypters.encrypter.release());
     74   session()->connection()->SetDefaultEncryptionLevel(
     75       ENCRYPTION_INITIAL);
     76   // Set the decrypter immediately so that we no longer accept unencrypted
     77   // packets.
     78   session()->connection()->SetDecrypter(
     79       crypto_negotiated_params_.initial_crypters.decrypter.release());
     80   SendHandshakeMessage(reply);
     81 
     82   session()->connection()->SetEncrypter(
     83       ENCRYPTION_FORWARD_SECURE,
     84       crypto_negotiated_params_.forward_secure_crypters.encrypter.release());
     85   session()->connection()->SetDefaultEncryptionLevel(
     86       ENCRYPTION_FORWARD_SECURE);
     87   session()->connection()->SetAlternativeDecrypter(
     88       crypto_negotiated_params_.forward_secure_crypters.decrypter.release(),
     89       false /* don't latch */);
     90 
     91   encryption_established_ = true;
     92   handshake_confirmed_ = true;
     93   session()->OnCryptoHandshakeEvent(QuicSession::HANDSHAKE_CONFIRMED);
     94 }
     95 
     96 bool QuicCryptoServerStream::GetBase64SHA256ClientChannelID(
     97     string* output) const {
     98   if (!encryption_established_ ||
     99       crypto_negotiated_params_.channel_id.empty()) {
    100     return false;
    101   }
    102 
    103   const string& channel_id(crypto_negotiated_params_.channel_id);
    104   scoped_ptr<crypto::SecureHash> hash(
    105       crypto::SecureHash::Create(crypto::SecureHash::SHA256));
    106   hash->Update(channel_id.data(), channel_id.size());
    107   uint8 digest[32];
    108   hash->Finish(digest, sizeof(digest));
    109 
    110   base::Base64Encode(string(
    111       reinterpret_cast<const char*>(digest), sizeof(digest)), output);
    112   // Remove padding.
    113   size_t len = output->size();
    114   if (len >= 2) {
    115     if ((*output)[len - 1] == '=') {
    116       len--;
    117       if ((*output)[len - 1] == '=') {
    118         len--;
    119       }
    120       output->resize(len);
    121     }
    122   }
    123   return true;
    124 }
    125 
    126 QuicErrorCode QuicCryptoServerStream::ProcessClientHello(
    127     const CryptoHandshakeMessage& message,
    128     CryptoHandshakeMessage* reply,
    129     string* error_details) {
    130   return crypto_config_.ProcessClientHello(
    131       message,
    132       session()->connection()->version(),
    133       session()->connection()->guid(),
    134       session()->connection()->peer_address(),
    135       session()->connection()->clock(),
    136       session()->connection()->random_generator(),
    137       &crypto_negotiated_params_, reply, error_details);
    138 }
    139 
    140 }  // namespace net
    141