Add signalSyncPoint to the WebGraphicsContext3D command buffer impls.
[chromium-blink-merge.git] / net / quic / quic_crypto_client_stream.cc
blob97b2b78b24abb9dc914d279fd87435eb8e30a6b5
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_client_stream.h"
7 #include "net/quic/crypto/crypto_protocol.h"
8 #include "net/quic/crypto/crypto_utils.h"
9 #include "net/quic/crypto/proof_verifier.h"
10 #include "net/quic/quic_protocol.h"
11 #include "net/quic/quic_session.h"
13 namespace net {
15 QuicCryptoClientStream::QuicCryptoClientStream(
16 const string& server_hostname,
17 const QuicConfig& config,
18 QuicSession* session,
19 QuicCryptoClientConfig* crypto_config)
20 : QuicCryptoStream(session),
21 next_state_(STATE_IDLE),
22 num_client_hellos_(0),
23 config_(config),
24 crypto_config_(crypto_config),
25 decrypter_pushed_(false),
26 server_hostname_(server_hostname) {
29 QuicCryptoClientStream::~QuicCryptoClientStream() {
32 void QuicCryptoClientStream::OnHandshakeMessage(
33 const CryptoHandshakeMessage& message) {
34 DoHandshakeLoop(&message);
37 bool QuicCryptoClientStream::CryptoConnect() {
38 next_state_ = STATE_SEND_CHLO;
39 DoHandshakeLoop(NULL);
40 return true;
43 const QuicNegotiatedParameters&
44 QuicCryptoClientStream::negotiated_params() const {
45 return negotiated_params_;
48 const QuicCryptoNegotiatedParameters&
49 QuicCryptoClientStream::crypto_negotiated_params() const {
50 return crypto_negotiated_params_;
53 int QuicCryptoClientStream::num_sent_client_hellos() const {
54 return num_client_hellos_;
57 // kMaxClientHellos is the maximum number of times that we'll send a client
58 // hello. The value 3 accounts for:
59 // * One failure due to an incorrect or missing source-address token.
60 // * One failure due the server's certificate chain being unavailible and the
61 // server being unwilling to send it without a valid source-address token.
62 static const int kMaxClientHellos = 3;
64 void QuicCryptoClientStream::DoHandshakeLoop(
65 const CryptoHandshakeMessage* in) {
66 CryptoHandshakeMessage out;
67 QuicErrorCode error;
68 string error_details;
69 QuicCryptoClientConfig::CachedState* cached =
70 crypto_config_->LookupOrCreate(server_hostname_);
72 if (in != NULL) {
73 DLOG(INFO) << "Client received: " << in->DebugString();
76 for (;;) {
77 const State state = next_state_;
78 next_state_ = STATE_IDLE;
79 switch (state) {
80 case STATE_SEND_CHLO: {
81 if (num_client_hellos_ > kMaxClientHellos) {
82 CloseConnection(QUIC_CRYPTO_TOO_MANY_REJECTS);
83 return;
85 num_client_hellos_++;
87 if (!cached->is_complete()) {
88 crypto_config_->FillInchoateClientHello(server_hostname_, cached,
89 &out);
90 next_state_ = STATE_RECV_REJ;
91 DLOG(INFO) << "Client Sending: " << out.DebugString();
92 SendHandshakeMessage(out);
93 return;
95 const CryptoHandshakeMessage* scfg = cached->GetServerConfig();
96 config_.ToHandshakeMessage(&out);
97 error = crypto_config_->FillClientHello(
98 server_hostname_,
99 session()->connection()->guid(),
100 cached,
101 session()->connection()->clock(),
102 session()->connection()->random_generator(),
103 &crypto_negotiated_params_,
104 &out,
105 &error_details);
106 if (error != QUIC_NO_ERROR) {
107 CloseConnectionWithDetails(error, error_details);
108 return;
110 error = config_.ProcessFinalPeerHandshake(
111 *scfg, CryptoUtils::PEER_PRIORITY, &negotiated_params_,
112 &error_details);
113 if (error != QUIC_NO_ERROR) {
114 CloseConnectionWithDetails(error, error_details);
115 return;
117 next_state_ = STATE_RECV_SHLO;
118 DLOG(INFO) << "Client Sending: " << out.DebugString();
119 SendHandshakeMessage(out);
120 // Be prepared to decrypt with the new server write key.
121 session()->connection()->PushDecrypter(
122 crypto_negotiated_params_.decrypter.release());
123 decrypter_pushed_ = true;
124 return;
126 case STATE_RECV_REJ:
127 // We sent a dummy CHLO because we didn't have enough information to
128 // perform a handshake, or we sent a full hello that the server
129 // rejected. Here we hope to have a REJ that contains the information
130 // that we need.
131 if (in->tag() != kREJ) {
132 CloseConnectionWithDetails(QUIC_INVALID_CRYPTO_MESSAGE_TYPE,
133 "Expected REJ");
134 return;
136 error = crypto_config_->ProcessRejection(cached, *in,
137 &crypto_negotiated_params_,
138 &error_details);
139 if (error != QUIC_NO_ERROR) {
140 CloseConnectionWithDetails(error, error_details);
141 return;
143 if (!cached->proof_valid()) {
144 const ProofVerifier* verifier = crypto_config_->proof_verifier();
145 if (!verifier) {
146 // If no verifier is set then we don't check the certificates.
147 cached->SetProofValid();
148 } else if (!cached->signature().empty()) {
149 // TODO(rtenneti): In Chromium, we will need to make VerifyProof()
150 // asynchronous.
151 if (!verifier->VerifyProof(server_hostname_,
152 cached->server_config(),
153 cached->certs(),
154 cached->signature(),
155 &error_details)) {
156 CloseConnectionWithDetails(QUIC_PROOF_INVALID,
157 "Proof invalid: " + error_details);
158 return;
160 cached->SetProofValid();
163 // Clear any new server write key that we may have set before.
164 if (decrypter_pushed_) {
165 session()->connection()->PopDecrypter();
166 decrypter_pushed_ = false;
168 next_state_ = STATE_SEND_CHLO;
169 break;
170 case STATE_RECV_SHLO:
171 // We sent a CHLO that we expected to be accepted and now we're hoping
172 // for a SHLO from the server to confirm that.
173 if (in->tag() == kREJ) {
174 next_state_ = STATE_RECV_REJ;
175 break;
177 if (in->tag() != kSHLO) {
178 CloseConnectionWithDetails(QUIC_INVALID_CRYPTO_MESSAGE_TYPE,
179 "Expected SHLO or REJ");
180 return;
182 // Receiving SHLO implies the server must have processed our full
183 // CHLO and is ready to decrypt with the new client write key. We
184 // can start to encrypt with the new client write key.
185 // TODO(wtc): when we support 0-RTT, we will need to change the
186 // encrypter when we send a full CHLO because we will be sending
187 // application data immediately after.
188 session()->connection()->ChangeEncrypter(
189 crypto_negotiated_params_.encrypter.release());
190 SetHandshakeComplete(QUIC_NO_ERROR);
191 return;
192 case STATE_IDLE:
193 // This means that the peer sent us a message that we weren't expecting.
194 CloseConnection(QUIC_INVALID_CRYPTO_MESSAGE_TYPE);
195 return;
200 } // namespace net