| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "net/quic/quic_crypto_client_stream.h" | 5 #include "net/quic/quic_crypto_client_stream.h" |
| 6 | 6 |
| 7 #include "net/quic/crypto/crypto_protocol.h" | 7 #include "net/quic/crypto/crypto_protocol.h" |
| 8 #include "net/quic/crypto/crypto_utils.h" | 8 #include "net/quic/crypto/crypto_utils.h" |
| 9 #include "net/quic/quic_protocol.h" | 9 #include "net/quic/quic_protocol.h" |
| 10 #include "net/quic/quic_session.h" | 10 #include "net/quic/quic_session.h" |
| 11 | 11 |
| 12 namespace net { | 12 namespace net { |
| 13 | 13 |
| 14 QuicCryptoClientStream::QuicCryptoClientStream(QuicSession* session, | 14 QuicCryptoClientStream::QuicCryptoClientStream( |
| 15 const string& server_hostname) | 15 const string& server_hostname, |
| 16 const QuicConfig& config, |
| 17 QuicSession* session, |
| 18 QuicCryptoClientConfig* crypto_config) |
| 16 : QuicCryptoStream(session), | 19 : QuicCryptoStream(session), |
| 17 next_state_(STATE_IDLE), | 20 next_state_(STATE_IDLE), |
| 21 num_client_hellos_(0), |
| 22 config_(config), |
| 23 crypto_config_(crypto_config), |
| 18 decrypter_pushed_(false), | 24 decrypter_pushed_(false), |
| 19 server_hostname_(server_hostname) { | 25 server_hostname_(server_hostname) { |
| 20 config_.SetDefaults(); | |
| 21 crypto_config_.SetDefaults(); | |
| 22 } | 26 } |
| 23 | 27 |
| 24 QuicCryptoClientStream::~QuicCryptoClientStream() { | 28 QuicCryptoClientStream::~QuicCryptoClientStream() { |
| 25 } | 29 } |
| 26 | 30 |
| 27 void QuicCryptoClientStream::OnHandshakeMessage( | 31 void QuicCryptoClientStream::OnHandshakeMessage( |
| 28 const CryptoHandshakeMessage& message) { | 32 const CryptoHandshakeMessage& message) { |
| 29 DoHandshakeLoop(&message); | 33 DoHandshakeLoop(&message); |
| 30 } | 34 } |
| 31 | 35 |
| 32 bool QuicCryptoClientStream::CryptoConnect() { | 36 bool QuicCryptoClientStream::CryptoConnect() { |
| 33 next_state_ = STATE_SEND_CHLO; | 37 next_state_ = STATE_SEND_CHLO; |
| 34 DoHandshakeLoop(NULL); | 38 DoHandshakeLoop(NULL); |
| 35 return true; | 39 return true; |
| 36 } | 40 } |
| 37 | 41 |
| 38 const QuicNegotiatedParameters& | 42 const QuicNegotiatedParameters& |
| 39 QuicCryptoClientStream::negotiated_params() const { | 43 QuicCryptoClientStream::negotiated_params() const { |
| 40 return negotiated_params_; | 44 return negotiated_params_; |
| 41 } | 45 } |
| 42 | 46 |
| 43 const QuicCryptoNegotiatedParameters& | 47 const QuicCryptoNegotiatedParameters& |
| 44 QuicCryptoClientStream::crypto_negotiated_params() const { | 48 QuicCryptoClientStream::crypto_negotiated_params() const { |
| 45 return crypto_negotiated_params_; | 49 return crypto_negotiated_params_; |
| 46 } | 50 } |
| 47 | 51 |
| 52 // kMaxClientHellos is the maximum number of times that we'll send a client |
| 53 // hello. The value 3 accounts for: |
| 54 // * One failure due to an incorrect or missing source-address token. |
| 55 // * One failure due the server's certificate chain being unavailible and the |
| 56 // server being unwilling to send it without a valid source-address token. |
| 57 static const int kMaxClientHellos = 3; |
| 58 |
| 48 void QuicCryptoClientStream::DoHandshakeLoop( | 59 void QuicCryptoClientStream::DoHandshakeLoop( |
| 49 const CryptoHandshakeMessage* in) { | 60 const CryptoHandshakeMessage* in) { |
| 50 CryptoHandshakeMessage out; | 61 CryptoHandshakeMessage out; |
| 51 QuicErrorCode error; | 62 QuicErrorCode error; |
| 52 string error_details; | 63 string error_details; |
| 53 | 64 |
| 54 if (in != NULL) { | 65 if (in != NULL) { |
| 55 DLOG(INFO) << "Client received: " << in->DebugString(); | 66 DLOG(INFO) << "Client received: " << in->DebugString(); |
| 56 } | 67 } |
| 57 | 68 |
| 58 for (;;) { | 69 for (;;) { |
| 59 const State state = next_state_; | 70 const State state = next_state_; |
| 60 next_state_ = STATE_IDLE; | 71 next_state_ = STATE_IDLE; |
| 61 switch (state) { | 72 switch (state) { |
| 62 case STATE_SEND_CHLO: { | 73 case STATE_SEND_CHLO: { |
| 74 if (num_client_hellos_ > kMaxClientHellos) { |
| 75 CloseConnection(QUIC_CRYPTO_TOO_MANY_REJECTS); |
| 76 return; |
| 77 } |
| 78 num_client_hellos_++; |
| 79 |
| 63 const QuicCryptoClientConfig::CachedState* cached = | 80 const QuicCryptoClientConfig::CachedState* cached = |
| 64 crypto_config_.Lookup(server_hostname_); | 81 crypto_config_->Lookup(server_hostname_); |
| 65 if (!cached || !cached->is_complete()) { | 82 if (!cached || !cached->is_complete()) { |
| 66 crypto_config_.FillInchoateClientHello(server_hostname_, cached, | 83 crypto_config_->FillInchoateClientHello(server_hostname_, cached, |
| 67 &out); | 84 &out); |
| 68 next_state_ = STATE_RECV_REJ; | 85 next_state_ = STATE_RECV_REJ; |
| 69 DLOG(INFO) << "Client Sending: " << out.DebugString(); | 86 DLOG(INFO) << "Client Sending: " << out.DebugString(); |
| 70 SendHandshakeMessage(out); | 87 SendHandshakeMessage(out); |
| 71 return; | 88 return; |
| 72 } | 89 } |
| 73 const CryptoHandshakeMessage* scfg = cached->GetServerConfig(); | 90 const CryptoHandshakeMessage* scfg = cached->GetServerConfig(); |
| 74 config_.ToHandshakeMessage(&out); | 91 config_.ToHandshakeMessage(&out); |
| 75 error = crypto_config_.FillClientHello( | 92 error = crypto_config_->FillClientHello( |
| 76 server_hostname_, | 93 server_hostname_, |
| 77 session()->connection()->guid(), | 94 session()->connection()->guid(), |
| 78 cached, | 95 cached, |
| 79 session()->connection()->clock(), | 96 session()->connection()->clock(), |
| 80 session()->connection()->random_generator(), | 97 session()->connection()->random_generator(), |
| 81 &crypto_negotiated_params_, | 98 &crypto_negotiated_params_, |
| 82 &out, | 99 &out, |
| 83 &error_details); | 100 &error_details); |
| 84 if (error != QUIC_NO_ERROR) { | 101 if (error != QUIC_NO_ERROR) { |
| 85 CloseConnectionWithDetails(error, error_details); | 102 CloseConnectionWithDetails(error, error_details); |
| 86 return; | 103 return; |
| 87 } | 104 } |
| 88 error = config_.ProcessFinalPeerHandshake( | 105 error = config_.ProcessFinalPeerHandshake( |
| 89 *scfg, CryptoUtils::PEER_PRIORITY, &negotiated_params_, | 106 *scfg, CryptoUtils::PEER_PRIORITY, &negotiated_params_, |
| 90 &error_details); | 107 &error_details); |
| 91 if (error != QUIC_NO_ERROR) { | 108 if (error != QUIC_NO_ERROR) { |
| 92 CloseConnectionWithDetails(error, error_details); | 109 CloseConnectionWithDetails(error, error_details); |
| 93 return; | 110 return; |
| 94 } | 111 } |
| 95 next_state_ = STATE_RECV_SHLO; | 112 next_state_ = STATE_RECV_SHLO; |
| 96 DLOG(INFO) << "Client Sending: " << out.DebugString(); | 113 DLOG(INFO) << "Client Sending: " << out.DebugString(); |
| 97 SendHandshakeMessage(out); | 114 SendHandshakeMessage(out); |
| 98 // Be prepared to decrypt with the new server write key. | 115 // Be prepared to decrypt with the new server write key. |
| 99 session()->connection()->PushDecrypter( | 116 session()->connection()->PushDecrypter( |
| 100 crypto_negotiated_params_.decrypter.release()); | 117 crypto_negotiated_params_.decrypter.release()); |
| 101 decrypter_pushed_ = true; | 118 decrypter_pushed_ = true; |
| 102 return; | 119 return; |
| 103 } | 120 } |
| 104 case STATE_RECV_REJ: | 121 case STATE_RECV_REJ: |
| 105 // We sent a dummy CHLO because we don't have enough information to | 122 // We sent a dummy CHLO because we didn't have enough information to |
| 106 // perform a handshake. Here we hope to have a REJ that contains the | 123 // perform a handshake, or we sent a full hello that the server |
| 107 // information that we need. | 124 // rejected. Here we hope to have a REJ that contains the information |
| 125 // that we need. |
| 108 if (in->tag() != kREJ) { | 126 if (in->tag() != kREJ) { |
| 109 CloseConnectionWithDetails(QUIC_INVALID_CRYPTO_MESSAGE_TYPE, | 127 CloseConnectionWithDetails(QUIC_INVALID_CRYPTO_MESSAGE_TYPE, |
| 110 "Expected REJ"); | 128 "Expected REJ"); |
| 111 return; | 129 return; |
| 112 } | 130 } |
| 113 error = crypto_config_.ProcessRejection(server_hostname_, *in, | 131 error = crypto_config_->ProcessRejection(server_hostname_, *in, |
| 114 &error_details); | 132 &crypto_negotiated_params_, |
| 133 &error_details); |
| 115 if (error != QUIC_NO_ERROR) { | 134 if (error != QUIC_NO_ERROR) { |
| 116 CloseConnectionWithDetails(error, error_details); | 135 CloseConnectionWithDetails(error, error_details); |
| 117 return; | 136 return; |
| 118 } | 137 } |
| 119 // Clear any new server write key that we may have set before. | 138 // Clear any new server write key that we may have set before. |
| 120 if (decrypter_pushed_) { | 139 if (decrypter_pushed_) { |
| 121 session()->connection()->PopDecrypter(); | 140 session()->connection()->PopDecrypter(); |
| 122 decrypter_pushed_ = false; | 141 decrypter_pushed_ = false; |
| 123 } | 142 } |
| 124 next_state_ = STATE_SEND_CHLO; | 143 next_state_ = STATE_SEND_CHLO; |
| 125 break; | 144 break; |
| 126 case STATE_RECV_SHLO: | 145 case STATE_RECV_SHLO: |
| 127 // We sent a CHLO that we expected to be accepted and now we're hoping | 146 // We sent a CHLO that we expected to be accepted and now we're hoping |
| 128 // for a SHLO from the server to confirm that. | 147 // for a SHLO from the server to confirm that. |
| 148 if (in->tag() == kREJ) { |
| 149 next_state_ = STATE_RECV_REJ; |
| 150 break; |
| 151 } |
| 129 if (in->tag() != kSHLO) { | 152 if (in->tag() != kSHLO) { |
| 130 // TODO(agl): in the future we would attempt the handshake again. | |
| 131 CloseConnectionWithDetails(QUIC_INVALID_CRYPTO_MESSAGE_TYPE, | 153 CloseConnectionWithDetails(QUIC_INVALID_CRYPTO_MESSAGE_TYPE, |
| 132 "Expected SHLO"); | 154 "Expected SHLO or REJ"); |
| 133 return; | 155 return; |
| 134 } | 156 } |
| 135 // Receiving SHLO implies the server must have processed our full | 157 // Receiving SHLO implies the server must have processed our full |
| 136 // CHLO and is ready to decrypt with the new client write key. We | 158 // CHLO and is ready to decrypt with the new client write key. We |
| 137 // can start to encrypt with the new client write key. | 159 // can start to encrypt with the new client write key. |
| 138 // TODO(wtc): when we support 0-RTT, we will need to change the | 160 // TODO(wtc): when we support 0-RTT, we will need to change the |
| 139 // encrypter when we send a full CHLO because we will be sending | 161 // encrypter when we send a full CHLO because we will be sending |
| 140 // application data immediately after. | 162 // application data immediately after. |
| 141 session()->connection()->ChangeEncrypter( | 163 session()->connection()->ChangeEncrypter( |
| 142 crypto_negotiated_params_.encrypter.release()); | 164 crypto_negotiated_params_.encrypter.release()); |
| 143 SetHandshakeComplete(QUIC_NO_ERROR); | 165 SetHandshakeComplete(QUIC_NO_ERROR); |
| 144 return; | 166 return; |
| 145 case STATE_IDLE: | 167 case STATE_IDLE: |
| 146 // This means that the peer sent us a message that we weren't expecting. | 168 // This means that the peer sent us a message that we weren't expecting. |
| 147 CloseConnection(QUIC_INVALID_CRYPTO_MESSAGE_TYPE); | 169 CloseConnection(QUIC_INVALID_CRYPTO_MESSAGE_TYPE); |
| 148 return; | 170 return; |
| 149 } | 171 } |
| 150 } | 172 } |
| 151 } | 173 } |
| 152 | 174 |
| 153 } // namespace net | 175 } // namespace net |
| OLD | NEW |