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 16namespace net { 17 18QuicCryptoServerStream::QuicCryptoServerStream( 19 const QuicCryptoServerConfig& crypto_config, 20 QuicSession* session) 21 : QuicCryptoStream(session), 22 crypto_config_(crypto_config) { 23} 24 25QuicCryptoServerStream::~QuicCryptoServerStream() { 26} 27 28void 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 96bool 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 126QuicErrorCode 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