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 "base/metrics/histogram.h"
      8 #include "net/quic/crypto/crypto_protocol.h"
      9 #include "net/quic/crypto/crypto_utils.h"
     10 #include "net/quic/crypto/null_encrypter.h"
     11 #include "net/quic/quic_client_session_base.h"
     12 #include "net/quic/quic_protocol.h"
     13 #include "net/quic/quic_session.h"
     14 
     15 namespace net {
     16 
     17 QuicCryptoClientStream::ChannelIDSourceCallbackImpl::
     18 ChannelIDSourceCallbackImpl(QuicCryptoClientStream* stream)
     19     : stream_(stream) {}
     20 
     21 QuicCryptoClientStream::ChannelIDSourceCallbackImpl::
     22 ~ChannelIDSourceCallbackImpl() {}
     23 
     24 void QuicCryptoClientStream::ChannelIDSourceCallbackImpl::Run(
     25     scoped_ptr<ChannelIDKey>* channel_id_key) {
     26   if (stream_ == NULL) {
     27     return;
     28   }
     29 
     30   stream_->channel_id_key_.reset(channel_id_key->release());
     31   stream_->channel_id_source_callback_run_ = true;
     32   stream_->channel_id_source_callback_ = NULL;
     33   stream_->DoHandshakeLoop(NULL);
     34 
     35   // The ChannelIDSource owns this object and will delete it when this method
     36   // returns.
     37 }
     38 
     39 void QuicCryptoClientStream::ChannelIDSourceCallbackImpl::Cancel() {
     40   stream_ = NULL;
     41 }
     42 
     43 QuicCryptoClientStream::ProofVerifierCallbackImpl::ProofVerifierCallbackImpl(
     44     QuicCryptoClientStream* stream)
     45     : stream_(stream) {}
     46 
     47 QuicCryptoClientStream::ProofVerifierCallbackImpl::
     48 ~ProofVerifierCallbackImpl() {}
     49 
     50 void QuicCryptoClientStream::ProofVerifierCallbackImpl::Run(
     51     bool ok,
     52     const string& error_details,
     53     scoped_ptr<ProofVerifyDetails>* details) {
     54   if (stream_ == NULL) {
     55     return;
     56   }
     57 
     58   stream_->verify_ok_ = ok;
     59   stream_->verify_error_details_ = error_details;
     60   stream_->verify_details_.reset(details->release());
     61   stream_->proof_verify_callback_ = NULL;
     62   stream_->DoHandshakeLoop(NULL);
     63 
     64   // The ProofVerifier owns this object and will delete it when this method
     65   // returns.
     66 }
     67 
     68 void QuicCryptoClientStream::ProofVerifierCallbackImpl::Cancel() {
     69   stream_ = NULL;
     70 }
     71 
     72 QuicCryptoClientStream::QuicCryptoClientStream(
     73     const QuicServerId& server_id,
     74     QuicClientSessionBase* session,
     75     ProofVerifyContext* verify_context,
     76     QuicCryptoClientConfig* crypto_config)
     77     : QuicCryptoStream(session),
     78       next_state_(STATE_IDLE),
     79       num_client_hellos_(0),
     80       crypto_config_(crypto_config),
     81       server_id_(server_id),
     82       generation_counter_(0),
     83       channel_id_sent_(false),
     84       channel_id_source_callback_run_(false),
     85       channel_id_source_callback_(NULL),
     86       verify_context_(verify_context),
     87       proof_verify_callback_(NULL) {
     88 }
     89 
     90 QuicCryptoClientStream::~QuicCryptoClientStream() {
     91   if (channel_id_source_callback_) {
     92     channel_id_source_callback_->Cancel();
     93   }
     94   if (proof_verify_callback_) {
     95     proof_verify_callback_->Cancel();
     96   }
     97 }
     98 
     99 void QuicCryptoClientStream::OnHandshakeMessage(
    100     const CryptoHandshakeMessage& message) {
    101   QuicCryptoStream::OnHandshakeMessage(message);
    102 
    103   if (message.tag() == kSCUP) {
    104     if (!handshake_confirmed()) {
    105       CloseConnection(QUIC_CRYPTO_UPDATE_BEFORE_HANDSHAKE_COMPLETE);
    106       return;
    107     }
    108 
    109     // |message| is an update from the server, so we treat it differently from a
    110     // handshake message.
    111     HandleServerConfigUpdateMessage(message);
    112     return;
    113   }
    114 
    115   // Do not process handshake messages after the handshake is confirmed.
    116   if (handshake_confirmed()) {
    117     CloseConnection(QUIC_CRYPTO_MESSAGE_AFTER_HANDSHAKE_COMPLETE);
    118     return;
    119   }
    120 
    121   DoHandshakeLoop(&message);
    122 }
    123 
    124 bool QuicCryptoClientStream::CryptoConnect() {
    125   next_state_ = STATE_INITIALIZE;
    126   DoHandshakeLoop(NULL);
    127   return true;
    128 }
    129 
    130 int QuicCryptoClientStream::num_sent_client_hellos() const {
    131   return num_client_hellos_;
    132 }
    133 
    134 bool QuicCryptoClientStream::WasChannelIDSent() const {
    135   return channel_id_sent_;
    136 }
    137 
    138 bool QuicCryptoClientStream::WasChannelIDSourceCallbackRun() const {
    139   return channel_id_source_callback_run_;
    140 }
    141 
    142 void QuicCryptoClientStream::HandleServerConfigUpdateMessage(
    143     const CryptoHandshakeMessage& server_config_update) {
    144   DCHECK(server_config_update.tag() == kSCUP);
    145   string error_details;
    146   QuicCryptoClientConfig::CachedState* cached =
    147       crypto_config_->LookupOrCreate(server_id_);
    148   QuicErrorCode error = crypto_config_->ProcessServerConfigUpdate(
    149       server_config_update,
    150       session()->connection()->clock()->WallNow(),
    151       cached,
    152       &crypto_negotiated_params_,
    153       &error_details);
    154 
    155   if (error != QUIC_NO_ERROR) {
    156     CloseConnectionWithDetails(
    157         error, "Server config update invalid: " + error_details);
    158     return;
    159   }
    160 
    161   DCHECK(handshake_confirmed());
    162   if (proof_verify_callback_) {
    163     proof_verify_callback_->Cancel();
    164   }
    165   next_state_ = STATE_INITIALIZE_SCUP;
    166   DoHandshakeLoop(NULL);
    167 }
    168 
    169 // kMaxClientHellos is the maximum number of times that we'll send a client
    170 // hello. The value 3 accounts for:
    171 //   * One failure due to an incorrect or missing source-address token.
    172 //   * One failure due the server's certificate chain being unavailible and the
    173 //     server being unwilling to send it without a valid source-address token.
    174 static const int kMaxClientHellos = 3;
    175 
    176 void QuicCryptoClientStream::DoHandshakeLoop(
    177     const CryptoHandshakeMessage* in) {
    178   CryptoHandshakeMessage out;
    179   QuicErrorCode error;
    180   string error_details;
    181   QuicCryptoClientConfig::CachedState* cached =
    182       crypto_config_->LookupOrCreate(server_id_);
    183 
    184   for (;;) {
    185     const State state = next_state_;
    186     next_state_ = STATE_IDLE;
    187     switch (state) {
    188       case STATE_INITIALIZE: {
    189         if (!cached->IsEmpty() && !cached->signature().empty() &&
    190             server_id_.is_https()) {
    191           // Note that we verify the proof even if the cached proof is valid.
    192           // This allows us to respond to CA trust changes or certificate
    193           // expiration because it may have been a while since we last verified
    194           // the proof.
    195           DCHECK(crypto_config_->proof_verifier());
    196           // If the cached state needs to be verified, do it now.
    197           next_state_ = STATE_VERIFY_PROOF;
    198         } else {
    199           next_state_ = STATE_GET_CHANNEL_ID;
    200         }
    201         break;
    202       }
    203       case STATE_SEND_CHLO: {
    204         // Send the client hello in plaintext.
    205         session()->connection()->SetDefaultEncryptionLevel(ENCRYPTION_NONE);
    206         if (num_client_hellos_ > kMaxClientHellos) {
    207           CloseConnection(QUIC_CRYPTO_TOO_MANY_REJECTS);
    208           return;
    209         }
    210         num_client_hellos_++;
    211 
    212         if (!cached->IsComplete(session()->connection()->clock()->WallNow())) {
    213           crypto_config_->FillInchoateClientHello(
    214               server_id_,
    215               session()->connection()->supported_versions().front(),
    216               cached, &crypto_negotiated_params_, &out);
    217           // Pad the inchoate client hello to fill up a packet.
    218           const size_t kFramingOverhead = 50;  // A rough estimate.
    219           const size_t max_packet_size =
    220               session()->connection()->max_packet_length();
    221           if (max_packet_size <= kFramingOverhead) {
    222             DLOG(DFATAL) << "max_packet_length (" << max_packet_size
    223                          << ") has no room for framing overhead.";
    224             CloseConnection(QUIC_INTERNAL_ERROR);
    225             return;
    226           }
    227           if (kClientHelloMinimumSize > max_packet_size - kFramingOverhead) {
    228             DLOG(DFATAL) << "Client hello won't fit in a single packet.";
    229             CloseConnection(QUIC_INTERNAL_ERROR);
    230             return;
    231           }
    232           out.set_minimum_size(max_packet_size - kFramingOverhead);
    233           next_state_ = STATE_RECV_REJ;
    234           SendHandshakeMessage(out);
    235           return;
    236         }
    237         session()->config()->ToHandshakeMessage(&out);
    238         error = crypto_config_->FillClientHello(
    239             server_id_,
    240             session()->connection()->connection_id(),
    241             session()->connection()->supported_versions().front(),
    242             cached,
    243             session()->connection()->clock()->WallNow(),
    244             session()->connection()->random_generator(),
    245             channel_id_key_.get(),
    246             &crypto_negotiated_params_,
    247             &out,
    248             &error_details);
    249         if (error != QUIC_NO_ERROR) {
    250           // Flush the cached config so that, if it's bad, the server has a
    251           // chance to send us another in the future.
    252           cached->InvalidateServerConfig();
    253           CloseConnectionWithDetails(error, error_details);
    254           return;
    255         }
    256         channel_id_sent_ = (channel_id_key_.get() != NULL);
    257         if (cached->proof_verify_details()) {
    258           client_session()->OnProofVerifyDetailsAvailable(
    259               *cached->proof_verify_details());
    260         }
    261         next_state_ = STATE_RECV_SHLO;
    262         SendHandshakeMessage(out);
    263         // Be prepared to decrypt with the new server write key.
    264         session()->connection()->SetAlternativeDecrypter(
    265             crypto_negotiated_params_.initial_crypters.decrypter.release(),
    266             ENCRYPTION_INITIAL,
    267             true /* latch once used */);
    268         // Send subsequent packets under encryption on the assumption that the
    269         // server will accept the handshake.
    270         session()->connection()->SetEncrypter(
    271             ENCRYPTION_INITIAL,
    272             crypto_negotiated_params_.initial_crypters.encrypter.release());
    273         session()->connection()->SetDefaultEncryptionLevel(
    274             ENCRYPTION_INITIAL);
    275         if (!encryption_established_) {
    276           encryption_established_ = true;
    277           session()->OnCryptoHandshakeEvent(
    278               QuicSession::ENCRYPTION_FIRST_ESTABLISHED);
    279         } else {
    280           session()->OnCryptoHandshakeEvent(
    281               QuicSession::ENCRYPTION_REESTABLISHED);
    282         }
    283         return;
    284       }
    285       case STATE_RECV_REJ:
    286         // We sent a dummy CHLO because we didn't have enough information to
    287         // perform a handshake, or we sent a full hello that the server
    288         // rejected. Here we hope to have a REJ that contains the information
    289         // that we need.
    290         if (in->tag() != kREJ) {
    291           CloseConnectionWithDetails(QUIC_INVALID_CRYPTO_MESSAGE_TYPE,
    292                                      "Expected REJ");
    293           return;
    294         }
    295         error = crypto_config_->ProcessRejection(
    296             *in, session()->connection()->clock()->WallNow(), cached,
    297             server_id_.is_https(), &crypto_negotiated_params_, &error_details);
    298         if (error != QUIC_NO_ERROR) {
    299           CloseConnectionWithDetails(error, error_details);
    300           return;
    301         }
    302         if (!cached->proof_valid()) {
    303           if (!server_id_.is_https()) {
    304             // We don't check the certificates for insecure QUIC connections.
    305             SetCachedProofValid(cached);
    306           } else if (!cached->signature().empty()) {
    307             // Note that we only verify the proof if the cached proof is not
    308             // valid. If the cached proof is valid here, someone else must have
    309             // just added the server config to the cache and verified the proof,
    310             // so we can assume no CA trust changes or certificate expiration
    311             // has happened since then.
    312             next_state_ = STATE_VERIFY_PROOF;
    313             break;
    314           }
    315         }
    316         next_state_ = STATE_GET_CHANNEL_ID;
    317         break;
    318       case STATE_VERIFY_PROOF: {
    319         if (QUIC_PENDING == DoVerifyProof(cached)) {
    320           return;
    321         }
    322         break;
    323       }
    324       case STATE_VERIFY_PROOF_COMPLETE:
    325         if (QUIC_PROOF_INVALID == DoVerifyProofComplete(cached)) {
    326           return;
    327         }
    328         break;
    329       case STATE_GET_CHANNEL_ID: {
    330         next_state_ = STATE_GET_CHANNEL_ID_COMPLETE;
    331         channel_id_key_.reset();
    332         if (!RequiresChannelID(cached)) {
    333           next_state_ = STATE_SEND_CHLO;
    334           break;
    335         }
    336 
    337         ChannelIDSourceCallbackImpl* channel_id_source_callback =
    338             new ChannelIDSourceCallbackImpl(this);
    339         QuicAsyncStatus status =
    340             crypto_config_->channel_id_source()->GetChannelIDKey(
    341                 server_id_.host(), &channel_id_key_,
    342                 channel_id_source_callback);
    343 
    344         switch (status) {
    345           case QUIC_PENDING:
    346             channel_id_source_callback_ = channel_id_source_callback;
    347             DVLOG(1) << "Looking up channel ID";
    348             return;
    349           case QUIC_FAILURE:
    350             delete channel_id_source_callback;
    351             CloseConnectionWithDetails(QUIC_INVALID_CHANNEL_ID_SIGNATURE,
    352                                        "Channel ID lookup failed");
    353             return;
    354           case QUIC_SUCCESS:
    355             delete channel_id_source_callback;
    356             break;
    357         }
    358         break;
    359       }
    360       case STATE_GET_CHANNEL_ID_COMPLETE:
    361         if (!channel_id_key_.get()) {
    362           CloseConnectionWithDetails(QUIC_INVALID_CHANNEL_ID_SIGNATURE,
    363                                      "Channel ID lookup failed");
    364           return;
    365         }
    366         next_state_ = STATE_SEND_CHLO;
    367         break;
    368       case STATE_RECV_SHLO: {
    369         // We sent a CHLO that we expected to be accepted and now we're hoping
    370         // for a SHLO from the server to confirm that.
    371         if (in->tag() == kREJ) {
    372           // alternative_decrypter will be NULL if the original alternative
    373           // decrypter latched and became the primary decrypter. That happens
    374           // if we received a message encrypted with the INITIAL key.
    375           if (session()->connection()->alternative_decrypter() == NULL) {
    376             // The rejection was sent encrypted!
    377             CloseConnectionWithDetails(QUIC_CRYPTO_ENCRYPTION_LEVEL_INCORRECT,
    378                                        "encrypted REJ message");
    379             return;
    380           }
    381           next_state_ = STATE_RECV_REJ;
    382           break;
    383         }
    384         if (in->tag() != kSHLO) {
    385           CloseConnectionWithDetails(QUIC_INVALID_CRYPTO_MESSAGE_TYPE,
    386                                      "Expected SHLO or REJ");
    387           return;
    388         }
    389         // alternative_decrypter will be NULL if the original alternative
    390         // decrypter latched and became the primary decrypter. That happens
    391         // if we received a message encrypted with the INITIAL key.
    392         if (session()->connection()->alternative_decrypter() != NULL) {
    393           // The server hello was sent without encryption.
    394           CloseConnectionWithDetails(QUIC_CRYPTO_ENCRYPTION_LEVEL_INCORRECT,
    395                                      "unencrypted SHLO message");
    396           return;
    397         }
    398         error = crypto_config_->ProcessServerHello(
    399             *in, session()->connection()->connection_id(),
    400             session()->connection()->server_supported_versions(),
    401             cached, &crypto_negotiated_params_, &error_details);
    402 
    403         if (error != QUIC_NO_ERROR) {
    404           CloseConnectionWithDetails(
    405               error, "Server hello invalid: " + error_details);
    406           return;
    407         }
    408         error =
    409             session()->config()->ProcessPeerHello(*in, SERVER, &error_details);
    410         if (error != QUIC_NO_ERROR) {
    411           CloseConnectionWithDetails(
    412               error, "Server hello invalid: " + error_details);
    413           return;
    414         }
    415         session()->OnConfigNegotiated();
    416 
    417         CrypterPair* crypters =
    418             &crypto_negotiated_params_.forward_secure_crypters;
    419         // TODO(agl): we don't currently latch this decrypter because the idea
    420         // has been floated that the server shouldn't send packets encrypted
    421         // with the FORWARD_SECURE key until it receives a FORWARD_SECURE
    422         // packet from the client.
    423         session()->connection()->SetAlternativeDecrypter(
    424             crypters->decrypter.release(), ENCRYPTION_FORWARD_SECURE,
    425             false /* don't latch */);
    426         session()->connection()->SetEncrypter(
    427             ENCRYPTION_FORWARD_SECURE, crypters->encrypter.release());
    428         session()->connection()->SetDefaultEncryptionLevel(
    429             ENCRYPTION_FORWARD_SECURE);
    430 
    431         handshake_confirmed_ = true;
    432         session()->OnCryptoHandshakeEvent(QuicSession::HANDSHAKE_CONFIRMED);
    433         session()->connection()->OnHandshakeComplete();
    434         return;
    435       }
    436       case STATE_IDLE:
    437         // This means that the peer sent us a message that we weren't expecting.
    438         CloseConnection(QUIC_INVALID_CRYPTO_MESSAGE_TYPE);
    439         return;
    440       case STATE_INITIALIZE_SCUP:
    441         DoInitializeServerConfigUpdate(cached);
    442         break;
    443       case STATE_VERIFY_PROOF_DONE:
    444         return;  // We are done.
    445     }
    446   }
    447 }
    448 
    449 void QuicCryptoClientStream::DoInitializeServerConfigUpdate(
    450     QuicCryptoClientConfig::CachedState* cached) {
    451   bool update_ignored = false;
    452   if (!server_id_.is_https()) {
    453     // We don't check the certificates for insecure QUIC connections.
    454     SetCachedProofValid(cached);
    455     next_state_ = STATE_VERIFY_PROOF_DONE;
    456   } else if (!cached->IsEmpty() && !cached->signature().empty()) {
    457     // Note that we verify the proof even if the cached proof is valid.
    458     DCHECK(crypto_config_->proof_verifier());
    459     next_state_ = STATE_VERIFY_PROOF;
    460   } else {
    461     update_ignored = true;
    462     next_state_ = STATE_VERIFY_PROOF_DONE;
    463   }
    464   UMA_HISTOGRAM_BOOLEAN("Net.QuicNumServerConfig.UpdateMessagesIgnored",
    465                         update_ignored);
    466 }
    467 
    468 QuicAsyncStatus QuicCryptoClientStream::DoVerifyProof(
    469     QuicCryptoClientConfig::CachedState* cached) {
    470   ProofVerifier* verifier = crypto_config_->proof_verifier();
    471   DCHECK(verifier);
    472   next_state_ = STATE_VERIFY_PROOF_COMPLETE;
    473   generation_counter_ = cached->generation_counter();
    474 
    475   ProofVerifierCallbackImpl* proof_verify_callback =
    476       new ProofVerifierCallbackImpl(this);
    477 
    478   verify_ok_ = false;
    479 
    480   QuicAsyncStatus status = verifier->VerifyProof(
    481       server_id_.host(),
    482       cached->server_config(),
    483       cached->certs(),
    484       cached->signature(),
    485       verify_context_.get(),
    486       &verify_error_details_,
    487       &verify_details_,
    488       proof_verify_callback);
    489 
    490   switch (status) {
    491     case QUIC_PENDING:
    492       proof_verify_callback_ = proof_verify_callback;
    493       DVLOG(1) << "Doing VerifyProof";
    494       break;
    495     case QUIC_FAILURE:
    496       delete proof_verify_callback;
    497       break;
    498     case QUIC_SUCCESS:
    499       delete proof_verify_callback;
    500       verify_ok_ = true;
    501       break;
    502   }
    503   return status;
    504 }
    505 
    506 QuicErrorCode QuicCryptoClientStream::DoVerifyProofComplete(
    507     QuicCryptoClientConfig::CachedState* cached) {
    508   if (!verify_ok_) {
    509     client_session()->OnProofVerifyDetailsAvailable(*verify_details_);
    510     UMA_HISTOGRAM_BOOLEAN("Net.QuicVerifyProofFailed.HandshakeConfirmed",
    511                           handshake_confirmed());
    512     CloseConnectionWithDetails(
    513         QUIC_PROOF_INVALID, "Proof invalid: " + verify_error_details_);
    514     return QUIC_PROOF_INVALID;
    515   }
    516 
    517   // Check if generation_counter has changed between STATE_VERIFY_PROOF and
    518   // STATE_VERIFY_PROOF_COMPLETE state changes.
    519   if (generation_counter_ != cached->generation_counter()) {
    520     next_state_ = STATE_VERIFY_PROOF;
    521   } else {
    522     SetCachedProofValid(cached);
    523     cached->SetProofVerifyDetails(verify_details_.release());
    524     if (!handshake_confirmed()) {
    525       next_state_ = STATE_GET_CHANNEL_ID;
    526     } else {
    527       next_state_ = STATE_VERIFY_PROOF_DONE;
    528     }
    529   }
    530   return QUIC_NO_ERROR;
    531 }
    532 
    533 void QuicCryptoClientStream::SetCachedProofValid(
    534     QuicCryptoClientConfig::CachedState* cached) {
    535   cached->SetProofValid();
    536   client_session()->OnProofValid(*cached);
    537 }
    538 
    539 bool QuicCryptoClientStream::RequiresChannelID(
    540     QuicCryptoClientConfig::CachedState* cached) {
    541   if (!server_id_.is_https() ||
    542       server_id_.privacy_mode() == PRIVACY_MODE_ENABLED ||
    543       !crypto_config_->channel_id_source()) {
    544     return false;
    545   }
    546   const CryptoHandshakeMessage* scfg = cached->GetServerConfig();
    547   if (!scfg) {  // scfg may be null when we send an inchoate CHLO.
    548     return false;
    549   }
    550   const QuicTag* their_proof_demands;
    551   size_t num_their_proof_demands;
    552   if (scfg->GetTaglist(kPDMD, &their_proof_demands,
    553                        &num_their_proof_demands) != QUIC_NO_ERROR) {
    554     return false;
    555   }
    556   for (size_t i = 0; i < num_their_proof_demands; i++) {
    557     if (their_proof_demands[i] == kCHID) {
    558       return true;
    559     }
    560   }
    561   return false;
    562 }
    563 
    564 QuicClientSessionBase* QuicCryptoClientStream::client_session() {
    565   return reinterpret_cast<QuicClientSessionBase*>(session());
    566 }
    567 
    568 }  // namespace net
    569