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