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
17namespace net {
18
19void 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
28QuicCryptoServerStream::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
38QuicCryptoServerStream::~QuicCryptoServerStream() {
39  CancelOutstandingCallbacks();
40}
41
42void 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
49void 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
81void 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
159void 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
186void QuicCryptoServerStream::OnServerHelloAcked() {
187  session()->connection()->OnHandshakeComplete();
188}
189
190bool 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
220QuicErrorCode 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
236void QuicCryptoServerStream::OverrideQuicConfigDefaults(QuicConfig* config) {
237}
238
239QuicCryptoServerStream::ValidateCallback::ValidateCallback(
240    QuicCryptoServerStream* parent) : parent_(parent) {
241}
242
243void QuicCryptoServerStream::ValidateCallback::Cancel() {
244  parent_ = NULL;
245}
246
247void 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