Home | History | Annotate | Download | only in quic
      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_client_stream.h"
      6 
      7 #include "net/base/completion_callback.h"
      8 #include "net/base/net_errors.h"
      9 #include "net/quic/crypto/crypto_protocol.h"
     10 #include "net/quic/crypto/crypto_utils.h"
     11 #include "net/quic/crypto/null_encrypter.h"
     12 #include "net/quic/crypto/proof_verifier.h"
     13 #include "net/quic/crypto/proof_verifier_chromium.h"
     14 #include "net/quic/quic_protocol.h"
     15 #include "net/quic/quic_session.h"
     16 #include "net/ssl/ssl_connection_status_flags.h"
     17 #include "net/ssl/ssl_info.h"
     18 
     19 namespace net {
     20 
     21 namespace {
     22 
     23 // Copies CertVerifyResult from |verify_details| to |cert_verify_result|.
     24 void CopyCertVerifyResult(
     25     const ProofVerifyDetails* verify_details,
     26     scoped_ptr<CertVerifyResult>* cert_verify_result) {
     27   const CertVerifyResult* cert_verify_result_other =
     28       &(reinterpret_cast<const ProofVerifyDetailsChromium*>(
     29           verify_details))->cert_verify_result;
     30   CertVerifyResult* result_copy = new CertVerifyResult;
     31   result_copy->CopyFrom(*cert_verify_result_other);
     32   cert_verify_result->reset(result_copy);
     33 }
     34 
     35 }  // namespace
     36 
     37 QuicCryptoClientStream::ProofVerifierCallbackImpl::ProofVerifierCallbackImpl(
     38     QuicCryptoClientStream* stream)
     39     : stream_(stream) {}
     40 
     41 QuicCryptoClientStream::ProofVerifierCallbackImpl::
     42     ~ProofVerifierCallbackImpl() {}
     43 
     44 void QuicCryptoClientStream::ProofVerifierCallbackImpl::Run(
     45     bool ok,
     46     const string& error_details,
     47     scoped_ptr<ProofVerifyDetails>* details) {
     48   if (stream_ == NULL) {
     49     return;
     50   }
     51 
     52   stream_->verify_ok_ = ok;
     53   stream_->verify_error_details_ = error_details;
     54   stream_->verify_details_.reset(details->release());
     55   stream_->proof_verify_callback_ = NULL;
     56   stream_->DoHandshakeLoop(NULL);
     57 
     58   // The ProofVerifier owns this object and will delete it when this method
     59   // returns.
     60 }
     61 
     62 void QuicCryptoClientStream::ProofVerifierCallbackImpl::Cancel() {
     63   stream_ = NULL;
     64 }
     65 
     66 
     67 QuicCryptoClientStream::QuicCryptoClientStream(
     68     const string& server_hostname,
     69     QuicSession* session,
     70     QuicCryptoClientConfig* crypto_config)
     71     : QuicCryptoStream(session),
     72       next_state_(STATE_IDLE),
     73       num_client_hellos_(0),
     74       crypto_config_(crypto_config),
     75       server_hostname_(server_hostname),
     76       generation_counter_(0),
     77       proof_verify_callback_(NULL) {
     78 }
     79 
     80 QuicCryptoClientStream::~QuicCryptoClientStream() {
     81   if (proof_verify_callback_) {
     82     proof_verify_callback_->Cancel();
     83   }
     84 }
     85 
     86 void QuicCryptoClientStream::OnHandshakeMessage(
     87     const CryptoHandshakeMessage& message) {
     88   DoHandshakeLoop(&message);
     89 }
     90 
     91 bool QuicCryptoClientStream::CryptoConnect() {
     92   next_state_ = STATE_SEND_CHLO;
     93   DoHandshakeLoop(NULL);
     94   return true;
     95 }
     96 
     97 int QuicCryptoClientStream::num_sent_client_hellos() const {
     98   return num_client_hellos_;
     99 }
    100 
    101 // TODO(rtenneti): Add unittests for GetSSLInfo which exercise the various ways
    102 // we learn about SSL info (sync vs async vs cached).
    103 bool QuicCryptoClientStream::GetSSLInfo(SSLInfo* ssl_info) {
    104   ssl_info->Reset();
    105   if (!cert_verify_result_) {
    106     return false;
    107   }
    108 
    109   ssl_info->cert_status = cert_verify_result_->cert_status;
    110   ssl_info->cert = cert_verify_result_->verified_cert;
    111 
    112   // TODO(rtenneti): Figure out what to set for the following.
    113   // Temporarily hard coded cipher_suite as 0xc031 to represent
    114   // TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (from
    115   // net/ssl/ssl_cipher_suite_names.cc) and encryption as 256.
    116   int cipher_suite = 0xc02f;
    117   int ssl_connection_status = 0;
    118   ssl_connection_status |=
    119       (cipher_suite & SSL_CONNECTION_CIPHERSUITE_MASK) <<
    120        SSL_CONNECTION_CIPHERSUITE_SHIFT;
    121   ssl_connection_status |=
    122       (SSL_CONNECTION_VERSION_TLS1_2 & SSL_CONNECTION_VERSION_MASK) <<
    123        SSL_CONNECTION_VERSION_SHIFT;
    124 
    125   ssl_info->public_key_hashes = cert_verify_result_->public_key_hashes;
    126   ssl_info->is_issued_by_known_root =
    127       cert_verify_result_->is_issued_by_known_root;
    128 
    129   ssl_info->connection_status = ssl_connection_status;
    130   ssl_info->client_cert_sent = false;
    131   ssl_info->channel_id_sent = false;
    132   ssl_info->security_bits = 256;
    133   ssl_info->handshake_type = SSLInfo::HANDSHAKE_FULL;
    134   return true;
    135 }
    136 
    137 // kMaxClientHellos is the maximum number of times that we'll send a client
    138 // hello. The value 3 accounts for:
    139 //   * One failure due to an incorrect or missing source-address token.
    140 //   * One failure due the server's certificate chain being unavailible and the
    141 //     server being unwilling to send it without a valid source-address token.
    142 static const int kMaxClientHellos = 3;
    143 
    144 void QuicCryptoClientStream::DoHandshakeLoop(
    145     const CryptoHandshakeMessage* in) {
    146   CryptoHandshakeMessage out;
    147   QuicErrorCode error;
    148   string error_details;
    149   QuicCryptoClientConfig::CachedState* cached =
    150       crypto_config_->LookupOrCreate(server_hostname_);
    151 
    152   if (in != NULL) {
    153     DVLOG(1) << "Client received: " << in->DebugString();
    154   }
    155 
    156   for (;;) {
    157     const State state = next_state_;
    158     next_state_ = STATE_IDLE;
    159     switch (state) {
    160       case STATE_SEND_CHLO: {
    161         // Send the client hello in plaintext.
    162         session()->connection()->SetDefaultEncryptionLevel(ENCRYPTION_NONE);
    163         if (num_client_hellos_ > kMaxClientHellos) {
    164           CloseConnection(QUIC_CRYPTO_TOO_MANY_REJECTS);
    165           return;
    166         }
    167         num_client_hellos_++;
    168 
    169         if (!cached->IsComplete(session()->connection()->clock()->WallNow())) {
    170           crypto_config_->FillInchoateClientHello(
    171               server_hostname_, cached, &crypto_negotiated_params_, &out);
    172           next_state_ = STATE_RECV_REJ;
    173           DVLOG(1) << "Client Sending: " << out.DebugString();
    174           SendHandshakeMessage(out);
    175           return;
    176         }
    177         session()->config()->ToHandshakeMessage(&out);
    178         error = crypto_config_->FillClientHello(
    179             server_hostname_,
    180             session()->connection()->guid(),
    181             cached,
    182             session()->connection()->clock()->WallNow(),
    183             session()->connection()->random_generator(),
    184             &crypto_negotiated_params_,
    185             &out,
    186             &error_details);
    187         if (error != QUIC_NO_ERROR) {
    188           // Flush the cached config so that, if it's bad, the server has a
    189           // chance to send us another in the future.
    190           cached->InvalidateServerConfig();
    191           CloseConnectionWithDetails(error, error_details);
    192           return;
    193         }
    194         if (cached->proof_verify_details()) {
    195           CopyCertVerifyResult(cached->proof_verify_details(),
    196                                &cert_verify_result_);
    197         } else {
    198           cert_verify_result_.reset();
    199         }
    200         next_state_ = STATE_RECV_SHLO;
    201         DVLOG(1) << "Client Sending: " << out.DebugString();
    202         SendHandshakeMessage(out);
    203         // Be prepared to decrypt with the new server write key.
    204         session()->connection()->SetAlternativeDecrypter(
    205             crypto_negotiated_params_.initial_crypters.decrypter.release(),
    206             true /* latch once used */);
    207         // Send subsequent packets under encryption on the assumption that the
    208         // server will accept the handshake.
    209         session()->connection()->SetEncrypter(
    210             ENCRYPTION_INITIAL,
    211             crypto_negotiated_params_.initial_crypters.encrypter.release());
    212         session()->connection()->SetDefaultEncryptionLevel(
    213             ENCRYPTION_INITIAL);
    214         if (!encryption_established_) {
    215           encryption_established_ = true;
    216           session()->OnCryptoHandshakeEvent(
    217               QuicSession::ENCRYPTION_FIRST_ESTABLISHED);
    218         } else {
    219           session()->OnCryptoHandshakeEvent(
    220               QuicSession::ENCRYPTION_REESTABLISHED);
    221         }
    222         return;
    223       }
    224       case STATE_RECV_REJ:
    225         // We sent a dummy CHLO because we didn't have enough information to
    226         // perform a handshake, or we sent a full hello that the server
    227         // rejected. Here we hope to have a REJ that contains the information
    228         // that we need.
    229         if (in->tag() != kREJ) {
    230           CloseConnectionWithDetails(QUIC_INVALID_CRYPTO_MESSAGE_TYPE,
    231                                      "Expected REJ");
    232           return;
    233         }
    234         error = crypto_config_->ProcessRejection(
    235             cached, *in, session()->connection()->clock()->WallNow(),
    236             &crypto_negotiated_params_, &error_details);
    237         if (error != QUIC_NO_ERROR) {
    238           CloseConnectionWithDetails(error, error_details);
    239           return;
    240         }
    241         if (!cached->proof_valid()) {
    242           ProofVerifier* verifier = crypto_config_->proof_verifier();
    243           if (!verifier) {
    244             // If no verifier is set then we don't check the certificates.
    245             cached->SetProofValid();
    246           } else if (!cached->signature().empty()) {
    247             next_state_ = STATE_VERIFY_PROOF;
    248             break;
    249           }
    250         }
    251         next_state_ = STATE_SEND_CHLO;
    252         break;
    253       case STATE_VERIFY_PROOF: {
    254         ProofVerifier* verifier = crypto_config_->proof_verifier();
    255         DCHECK(verifier);
    256         next_state_ = STATE_VERIFY_PROOF_COMPLETE;
    257         generation_counter_ = cached->generation_counter();
    258 
    259         ProofVerifierCallbackImpl* proof_verify_callback =
    260             new ProofVerifierCallbackImpl(this);
    261 
    262         verify_ok_ = false;
    263 
    264         ProofVerifier::Status status = verifier->VerifyProof(
    265             session()->connection()->version(),
    266             server_hostname_,
    267             cached->server_config(),
    268             cached->certs(),
    269             cached->signature(),
    270             &verify_error_details_,
    271             &verify_details_,
    272             proof_verify_callback);
    273 
    274         switch (status) {
    275           case ProofVerifier::PENDING:
    276             proof_verify_callback_ = proof_verify_callback;
    277             DVLOG(1) << "Doing VerifyProof";
    278             return;
    279           case ProofVerifier::FAILURE:
    280             break;
    281           case ProofVerifier::SUCCESS:
    282             verify_ok_ = true;
    283             break;
    284         }
    285         break;
    286       }
    287       case STATE_VERIFY_PROOF_COMPLETE:
    288         if (!verify_ok_) {
    289           CopyCertVerifyResult(verify_details_.get(), &cert_verify_result_);
    290           CloseConnectionWithDetails(
    291               QUIC_PROOF_INVALID, "Proof invalid: " + verify_error_details_);
    292           return;
    293         }
    294         // Check if generation_counter has changed between STATE_VERIFY_PROOF
    295         // and STATE_VERIFY_PROOF_COMPLETE state changes.
    296         if (generation_counter_ != cached->generation_counter()) {
    297           next_state_ = STATE_VERIFY_PROOF;
    298         } else {
    299           cached->SetProofValid();
    300           cached->SetProofVerifyDetails(verify_details_.release());
    301           next_state_ = STATE_SEND_CHLO;
    302         }
    303         break;
    304       case STATE_RECV_SHLO: {
    305         // We sent a CHLO that we expected to be accepted and now we're hoping
    306         // for a SHLO from the server to confirm that.
    307         if (in->tag() == kREJ) {
    308           // alternative_decrypter will be NULL if the original alternative
    309           // decrypter latched and became the primary decrypter. That happens
    310           // if we received a message encrypted with the INITIAL key.
    311           if (session()->connection()->alternative_decrypter() == NULL) {
    312             // The rejection was sent encrypted!
    313             CloseConnectionWithDetails(QUIC_CRYPTO_ENCRYPTION_LEVEL_INCORRECT,
    314                                        "encrypted REJ message");
    315             return;
    316           }
    317           next_state_ = STATE_RECV_REJ;
    318           break;
    319         }
    320         if (in->tag() != kSHLO) {
    321           CloseConnectionWithDetails(QUIC_INVALID_CRYPTO_MESSAGE_TYPE,
    322                                      "Expected SHLO or REJ");
    323           return;
    324         }
    325         // alternative_decrypter will be NULL if the original alternative
    326         // decrypter latched and became the primary decrypter. That happens
    327         // if we received a message encrypted with the INITIAL key.
    328         if (session()->connection()->alternative_decrypter() != NULL) {
    329           // The server hello was sent without encryption.
    330           CloseConnectionWithDetails(QUIC_CRYPTO_ENCRYPTION_LEVEL_INCORRECT,
    331                                      "unencrypted SHLO message");
    332           return;
    333         }
    334         error = crypto_config_->ProcessServerHello(
    335             *in, session()->connection()->guid(), &crypto_negotiated_params_,
    336             &error_details);
    337         if (error != QUIC_NO_ERROR) {
    338           CloseConnectionWithDetails(
    339               error, "Server hello invalid: " + error_details);
    340           return;
    341         }
    342         error = session()->config()->ProcessServerHello(*in, &error_details);
    343         if (error != QUIC_NO_ERROR) {
    344           CloseConnectionWithDetails(
    345               error, "Server hello invalid: " + error_details);
    346           return;
    347         }
    348         CrypterPair* crypters =
    349             &crypto_negotiated_params_.forward_secure_crypters;
    350         // TODO(agl): we don't currently latch this decrypter because the idea
    351         // has been floated that the server shouldn't send packets encrypted
    352         // with the FORWARD_SECURE key until it receives a FORWARD_SECURE
    353         // packet from the client.
    354         session()->connection()->SetAlternativeDecrypter(
    355             crypters->decrypter.release(), false /* don't latch */);
    356         session()->connection()->SetEncrypter(
    357             ENCRYPTION_FORWARD_SECURE, crypters->encrypter.release());
    358         session()->connection()->SetDefaultEncryptionLevel(
    359             ENCRYPTION_FORWARD_SECURE);
    360 
    361         handshake_confirmed_ = true;
    362         session()->OnCryptoHandshakeEvent(QuicSession::HANDSHAKE_CONFIRMED);
    363         return;
    364       }
    365       case STATE_IDLE:
    366         // This means that the peer sent us a message that we weren't expecting.
    367         CloseConnection(QUIC_INVALID_CRYPTO_MESSAGE_TYPE);
    368         return;
    369     }
    370   }
    371 }
    372 
    373 }  // namespace net
    374