• 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 }
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