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
QuicCryptoServerStream(const QuicCryptoServerConfig & crypto_config,QuicSession * session)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
~QuicCryptoServerStream()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
OnHandshakeMessage(const CryptoHandshakeMessage & message)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
FinishProcessingHandshakeMessage(const CryptoHandshakeMessage & message,const ValidateClientHelloResultCallback::Result & result)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
GetBase64SHA256ClientChannelID(string * output) const127 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
ProcessClientHello(const CryptoHandshakeMessage & message,const ValidateClientHelloResultCallback::Result & result,CryptoHandshakeMessage * reply,string * error_details)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
ValidateCallback(QuicCryptoServerStream * parent)173 QuicCryptoServerStream::ValidateCallback::ValidateCallback(
174 QuicCryptoServerStream* parent) : parent_(parent) {
175 }
176
Cancel()177 void QuicCryptoServerStream::ValidateCallback::Cancel() {
178 parent_ = NULL;
179 }
180
RunImpl(const CryptoHandshakeMessage & client_hello,const Result & result)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