• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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       num_handshake_messages_(0) {
25 }
26 
~QuicCryptoServerStream()27 QuicCryptoServerStream::~QuicCryptoServerStream() {
28   CancelOutstandingCallbacks();
29 }
30 
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();
35   }
36 }
37 
OnHandshakeMessage(const CryptoHandshakeMessage & message)38 void QuicCryptoServerStream::OnHandshakeMessage(
39     const CryptoHandshakeMessage& message) {
40   QuicCryptoStream::OnHandshakeMessage(message);
41   ++num_handshake_messages_;
42 
43   // Do not process handshake messages after the handshake is confirmed.
44   if (handshake_confirmed_) {
45     CloseConnection(QUIC_CRYPTO_MESSAGE_AFTER_HANDSHAKE_COMPLETE);
46     return;
47   }
48 
49   if (message.tag() != kCHLO) {
50     CloseConnection(QUIC_INVALID_CRYPTO_MESSAGE_TYPE);
51     return;
52   }
53 
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);
59     return;
60   }
61 
62   validate_client_hello_cb_ = new ValidateCallback(this);
63   return crypto_config_.ValidateClientHello(
64       message,
65       session()->connection()->peer_address(),
66       session()->connection()->clock(),
67       validate_client_hello_cb_);
68 }
69 
FinishProcessingHandshakeMessage(const CryptoHandshakeMessage & message,const ValidateClientHelloResultCallback::Result & result)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;
76 
77   string error_details;
78   CryptoHandshakeMessage reply;
79   QuicErrorCode error = ProcessClientHello(
80       message, result, &reply, &error_details);
81 
82   if (error != QUIC_NO_ERROR) {
83     CloseConnectionWithDetails(error, error_details);
84     return;
85   }
86 
87   if (reply.tag() != kSHLO) {
88     SendHandshakeMessage(reply);
89     return;
90   }
91 
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);
98     return;
99   }
100   session()->OnConfigNegotiated();
101 
102   config->ToHandshakeMessage(&reply);
103 
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
106   // write key.
107   //
108   // NOTE: the SHLO will be encrypted with the new server write key.
109   session()->connection()->SetEncrypter(
110       ENCRYPTION_INITIAL,
111       crypto_negotiated_params_.initial_crypters.encrypter.release());
112   session()->connection()->SetDefaultEncryptionLevel(
113       ENCRYPTION_INITIAL);
114   // Set the decrypter immediately so that we no longer accept unencrypted
115   // packets.
116   session()->connection()->SetDecrypter(
117       crypto_negotiated_params_.initial_crypters.decrypter.release(),
118       ENCRYPTION_INITIAL);
119   SendHandshakeMessage(reply);
120 
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 */);
129 
130   encryption_established_ = true;
131   handshake_confirmed_ = true;
132   session()->OnCryptoHandshakeEvent(QuicSession::HANDSHAKE_CONFIRMED);
133 }
134 
GetBase64SHA256ClientChannelID(string * output) const135 bool QuicCryptoServerStream::GetBase64SHA256ClientChannelID(
136     string* output) const {
137   if (!encryption_established_ ||
138       crypto_negotiated_params_.channel_id.empty()) {
139     return false;
140   }
141 
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());
146   uint8 digest[32];
147   hash->Finish(digest, sizeof(digest));
148 
149   base::Base64Encode(string(
150       reinterpret_cast<const char*>(digest), sizeof(digest)), output);
151   // Remove padding.
152   size_t len = output->size();
153   if (len >= 2) {
154     if ((*output)[len - 1] == '=') {
155       len--;
156       if ((*output)[len - 1] == '=') {
157         len--;
158       }
159       output->resize(len);
160     }
161   }
162   return true;
163 }
164 
ProcessClientHello(const CryptoHandshakeMessage & message,const ValidateClientHelloResultCallback::Result & result,CryptoHandshakeMessage * reply,string * error_details)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(
171       result,
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);
179 }
180 
OverrideQuicConfigDefaults(QuicConfig * config)181 void QuicCryptoServerStream::OverrideQuicConfigDefaults(QuicConfig* config) {
182 }
183 
ValidateCallback(QuicCryptoServerStream * parent)184 QuicCryptoServerStream::ValidateCallback::ValidateCallback(
185     QuicCryptoServerStream* parent) : parent_(parent) {
186 }
187 
Cancel()188 void QuicCryptoServerStream::ValidateCallback::Cancel() {
189   parent_ = NULL;
190 }
191 
RunImpl(const CryptoHandshakeMessage & client_hello,const Result & result)192 void QuicCryptoServerStream::ValidateCallback::RunImpl(
193     const CryptoHandshakeMessage& client_hello,
194     const Result& result) {
195   if (parent_ != NULL) {
196     parent_->FinishProcessingHandshakeMessage(client_hello, result);
197   }
198 }
199 
200 }  // namespace net
201