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.
5 #include "net/quic/quic_crypto_server_stream.h"
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"
18 QuicCryptoServerStream::QuicCryptoServerStream(
19 const QuicCryptoServerConfig
& crypto_config
,
21 : QuicCryptoStream(session
),
22 crypto_config_(crypto_config
),
23 validate_client_hello_cb_(NULL
),
24 num_handshake_messages_(0) {
27 QuicCryptoServerStream::~QuicCryptoServerStream() {
28 CancelOutstandingCallbacks();
31 void QuicCryptoServerStream::CancelOutstandingCallbacks() {
32 // Detach from the validation callback. Calling this multiple times is safe.
33 if (validate_client_hello_cb_
!= NULL
) {
34 validate_client_hello_cb_
->Cancel();
38 void QuicCryptoServerStream::OnHandshakeMessage(
39 const CryptoHandshakeMessage
& message
) {
40 QuicCryptoStream::OnHandshakeMessage(message
);
41 ++num_handshake_messages_
;
43 // Do not process handshake messages after the handshake is confirmed.
44 if (handshake_confirmed_
) {
45 CloseConnection(QUIC_CRYPTO_MESSAGE_AFTER_HANDSHAKE_COMPLETE
);
49 if (message
.tag() != kCHLO
) {
50 CloseConnection(QUIC_INVALID_CRYPTO_MESSAGE_TYPE
);
54 if (validate_client_hello_cb_
!= NULL
) {
55 // Already processing some other handshake message. The protocol
56 // does not allow for clients to send multiple handshake messages
57 // before the server has a chance to respond.
58 CloseConnection(QUIC_CRYPTO_MESSAGE_WHILE_VALIDATING_CLIENT_HELLO
);
62 validate_client_hello_cb_
= new ValidateCallback(this);
63 return crypto_config_
.ValidateClientHello(
65 session()->connection()->peer_address(),
66 session()->connection()->clock(),
67 validate_client_hello_cb_
);
70 void QuicCryptoServerStream::FinishProcessingHandshakeMessage(
71 const CryptoHandshakeMessage
& message
,
72 const ValidateClientHelloResultCallback::Result
& result
) {
73 // Clear the callback that got us here.
74 DCHECK(validate_client_hello_cb_
!= NULL
);
75 validate_client_hello_cb_
= NULL
;
78 CryptoHandshakeMessage reply
;
79 QuicErrorCode error
= ProcessClientHello(
80 message
, result
, &reply
, &error_details
);
82 if (error
!= QUIC_NO_ERROR
) {
83 CloseConnectionWithDetails(error
, error_details
);
87 if (reply
.tag() != kSHLO
) {
88 SendHandshakeMessage(reply
);
92 // If we are returning a SHLO then we accepted the handshake.
93 QuicConfig
* config
= session()->config();
94 OverrideQuicConfigDefaults(config
);
95 error
= config
->ProcessPeerHello(message
, CLIENT
, &error_details
);
96 if (error
!= QUIC_NO_ERROR
) {
97 CloseConnectionWithDetails(error
, error_details
);
100 session()->OnConfigNegotiated();
102 config
->ToHandshakeMessage(&reply
);
104 // Receiving a full CHLO implies the client is prepared to decrypt with
105 // the new server write key. We can start to encrypt with the new server
108 // NOTE: the SHLO will be encrypted with the new server write key.
109 session()->connection()->SetEncrypter(
111 crypto_negotiated_params_
.initial_crypters
.encrypter
.release());
112 session()->connection()->SetDefaultEncryptionLevel(
114 // Set the decrypter immediately so that we no longer accept unencrypted
116 session()->connection()->SetDecrypter(
117 crypto_negotiated_params_
.initial_crypters
.decrypter
.release(),
119 SendHandshakeMessage(reply
);
121 session()->connection()->SetEncrypter(
122 ENCRYPTION_FORWARD_SECURE
,
123 crypto_negotiated_params_
.forward_secure_crypters
.encrypter
.release());
124 session()->connection()->SetDefaultEncryptionLevel(
125 ENCRYPTION_FORWARD_SECURE
);
126 session()->connection()->SetAlternativeDecrypter(
127 crypto_negotiated_params_
.forward_secure_crypters
.decrypter
.release(),
128 ENCRYPTION_FORWARD_SECURE
, false /* don't latch */);
130 encryption_established_
= true;
131 handshake_confirmed_
= true;
132 session()->OnCryptoHandshakeEvent(QuicSession::HANDSHAKE_CONFIRMED
);
135 bool QuicCryptoServerStream::GetBase64SHA256ClientChannelID(
136 string
* output
) const {
137 if (!encryption_established_
||
138 crypto_negotiated_params_
.channel_id
.empty()) {
142 const string
& channel_id(crypto_negotiated_params_
.channel_id
);
143 scoped_ptr
<crypto::SecureHash
> hash(
144 crypto::SecureHash::Create(crypto::SecureHash::SHA256
));
145 hash
->Update(channel_id
.data(), channel_id
.size());
147 hash
->Finish(digest
, sizeof(digest
));
149 base::Base64Encode(string(
150 reinterpret_cast<const char*>(digest
), sizeof(digest
)), output
);
152 size_t len
= output
->size();
154 if ((*output
)[len
- 1] == '=') {
156 if ((*output
)[len
- 1] == '=') {
165 QuicErrorCode
QuicCryptoServerStream::ProcessClientHello(
166 const CryptoHandshakeMessage
& message
,
167 const ValidateClientHelloResultCallback::Result
& result
,
168 CryptoHandshakeMessage
* reply
,
169 string
* error_details
) {
170 return crypto_config_
.ProcessClientHello(
172 session()->connection()->connection_id(),
173 session()->connection()->peer_address(),
174 session()->connection()->version(),
175 session()->connection()->supported_versions(),
176 session()->connection()->clock(),
177 session()->connection()->random_generator(),
178 &crypto_negotiated_params_
, reply
, error_details
);
181 void QuicCryptoServerStream::OverrideQuicConfigDefaults(QuicConfig
* config
) {
184 QuicCryptoServerStream::ValidateCallback::ValidateCallback(
185 QuicCryptoServerStream
* parent
) : parent_(parent
) {
188 void QuicCryptoServerStream::ValidateCallback::Cancel() {
192 void QuicCryptoServerStream::ValidateCallback::RunImpl(
193 const CryptoHandshakeMessage
& client_hello
,
194 const Result
& result
) {
195 if (parent_
!= NULL
) {
196 parent_
->FinishProcessingHandshakeMessage(client_hello
, result
);