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