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   QuicCryptoStream::OnHandshakeMessage(message);
     89 
     90   DoHandshakeLoop(&message);
     91 }
     92 
     93 bool QuicCryptoClientStream::CryptoConnect() {
     94   next_state_ = STATE_SEND_CHLO;
     95   DoHandshakeLoop(NULL);
     96   return true;
     97 }
     98 
     99 int QuicCryptoClientStream::num_sent_client_hellos() const {
    100   return num_client_hellos_;
    101 }
    102 
    103 // TODO(rtenneti): Add unittests for GetSSLInfo which exercise the various ways
    104 // we learn about SSL info (sync vs async vs cached).
    105 bool QuicCryptoClientStream::GetSSLInfo(SSLInfo* ssl_info) {
    106   ssl_info->Reset();
    107   if (!cert_verify_result_) {
    108     return false;
    109   }
    110 
    111   ssl_info->cert_status = cert_verify_result_->cert_status;
    112   ssl_info->cert = cert_verify_result_->verified_cert;
    113 
    114   // TODO(rtenneti): Figure out what to set for the following.
    115   // Temporarily hard coded cipher_suite as 0xc031 to represent
    116   // TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (from
    117   // net/ssl/ssl_cipher_suite_names.cc) and encryption as 256.
    118   int cipher_suite = 0xc02f;
    119   int ssl_connection_status = 0;
    120   ssl_connection_status |=
    121       (cipher_suite & SSL_CONNECTION_CIPHERSUITE_MASK) <<
    122        SSL_CONNECTION_CIPHERSUITE_SHIFT;
    123   ssl_connection_status |=
    124       (SSL_CONNECTION_VERSION_TLS1_2 & SSL_CONNECTION_VERSION_MASK) <<
    125        SSL_CONNECTION_VERSION_SHIFT;
    126 
    127   ssl_info->public_key_hashes = cert_verify_result_->public_key_hashes;
    128   ssl_info->is_issued_by_known_root =
    129       cert_verify_result_->is_issued_by_known_root;
    130 
    131   ssl_info->connection_status = ssl_connection_status;
    132   ssl_info->client_cert_sent = false;
    133   ssl_info->channel_id_sent = false;
    134   ssl_info->security_bits = 256;
    135   ssl_info->handshake_type = SSLInfo::HANDSHAKE_FULL;
    136   return true;
    137 }
    138 
    139 // kMaxClientHellos is the maximum number of times that we'll send a client
    140 // hello. The value 3 accounts for:
    141 //   * One failure due to an incorrect or missing source-address token.
    142 //   * One failure due the server's certificate chain being unavailible and the
    143 //     server being unwilling to send it without a valid source-address token.
    144 static const int kMaxClientHellos = 3;
    145 
    146 void QuicCryptoClientStream::DoHandshakeLoop(
    147     const CryptoHandshakeMessage* in) {
    148   CryptoHandshakeMessage out;
    149   QuicErrorCode error;
    150   string error_details;
    151   QuicCryptoClientConfig::CachedState* cached =
    152       crypto_config_->LookupOrCreate(server_hostname_);
    153 
    154   if (in != NULL) {
    155     DVLOG(1) << "Client: Received " << in->DebugString();
    156   }
    157 
    158   for (;;) {
    159     const State state = next_state_;
    160     next_state_ = STATE_IDLE;
    161     switch (state) {
    162       case STATE_SEND_CHLO: {
    163         // Send the client hello in plaintext.
    164         session()->connection()->SetDefaultEncryptionLevel(ENCRYPTION_NONE);
    165         if (num_client_hellos_ > kMaxClientHellos) {
    166           CloseConnection(QUIC_CRYPTO_TOO_MANY_REJECTS);
    167           return;
    168         }
    169         num_client_hellos_++;
    170 
    171         if (!cached->IsComplete(session()->connection()->clock()->WallNow())) {
    172           crypto_config_->FillInchoateClientHello(
    173               server_hostname_,
    174               session()->connection()->supported_versions().front(),
    175               cached, &crypto_negotiated_params_, &out);
    176           // Pad the inchoate client hello to fill up a packet.
    177           const size_t kFramingOverhead = 50;  // A rough estimate.
    178           const size_t max_packet_size =
    179               session()->connection()->options()->max_packet_length;
    180           if (max_packet_size <= kFramingOverhead) {
    181             DLOG(DFATAL) << "max_packet_length (" << max_packet_size
    182                          << ") has no room for framing overhead.";
    183             CloseConnection(QUIC_INTERNAL_ERROR);
    184             return;
    185           }
    186           if (kClientHelloMinimumSize > max_packet_size - kFramingOverhead) {
    187             DLOG(DFATAL) << "Client hello won't fit in a single packet.";
    188             CloseConnection(QUIC_INTERNAL_ERROR);
    189             return;
    190           }
    191           out.set_minimum_size(max_packet_size - kFramingOverhead);
    192           next_state_ = STATE_RECV_REJ;
    193           DVLOG(1) << "Client: Sending " << out.DebugString();
    194           SendHandshakeMessage(out);
    195           return;
    196         }
    197         session()->config()->ToHandshakeMessage(&out);
    198         error = crypto_config_->FillClientHello(
    199             server_hostname_,
    200             session()->connection()->guid(),
    201             session()->connection()->supported_versions().front(),
    202             cached,
    203             session()->connection()->clock()->WallNow(),
    204             session()->connection()->random_generator(),
    205             &crypto_negotiated_params_,
    206             &out,
    207             &error_details);
    208         if (error != QUIC_NO_ERROR) {
    209           // Flush the cached config so that, if it's bad, the server has a
    210           // chance to send us another in the future.
    211           cached->InvalidateServerConfig();
    212           CloseConnectionWithDetails(error, error_details);
    213           return;
    214         }
    215         if (cached->proof_verify_details()) {
    216           CopyCertVerifyResult(cached->proof_verify_details(),
    217                                &cert_verify_result_);
    218         } else {
    219           cert_verify_result_.reset();
    220         }
    221         next_state_ = STATE_RECV_SHLO;
    222         DVLOG(1) << "Client: Sending " << out.DebugString();
    223         SendHandshakeMessage(out);
    224         // Be prepared to decrypt with the new server write key.
    225         session()->connection()->SetAlternativeDecrypter(
    226             crypto_negotiated_params_.initial_crypters.decrypter.release(),
    227             true /* latch once used */);
    228         // Send subsequent packets under encryption on the assumption that the
    229         // server will accept the handshake.
    230         session()->connection()->SetEncrypter(
    231             ENCRYPTION_INITIAL,
    232             crypto_negotiated_params_.initial_crypters.encrypter.release());
    233         session()->connection()->SetDefaultEncryptionLevel(
    234             ENCRYPTION_INITIAL);
    235         if (!encryption_established_) {
    236           encryption_established_ = true;
    237           session()->OnCryptoHandshakeEvent(
    238               QuicSession::ENCRYPTION_FIRST_ESTABLISHED);
    239         } else {
    240           session()->OnCryptoHandshakeEvent(
    241               QuicSession::ENCRYPTION_REESTABLISHED);
    242         }
    243         return;
    244       }
    245       case STATE_RECV_REJ:
    246         // We sent a dummy CHLO because we didn't have enough information to
    247         // perform a handshake, or we sent a full hello that the server
    248         // rejected. Here we hope to have a REJ that contains the information
    249         // that we need.
    250         if (in->tag() != kREJ) {
    251           CloseConnectionWithDetails(QUIC_INVALID_CRYPTO_MESSAGE_TYPE,
    252                                      "Expected REJ");
    253           return;
    254         }
    255         error = crypto_config_->ProcessRejection(
    256             *in, session()->connection()->clock()->WallNow(), cached,
    257             &crypto_negotiated_params_, &error_details);
    258         if (error != QUIC_NO_ERROR) {
    259           CloseConnectionWithDetails(error, error_details);
    260           return;
    261         }
    262         if (!cached->proof_valid()) {
    263           ProofVerifier* verifier = crypto_config_->proof_verifier();
    264           if (!verifier) {
    265             // If no verifier is set then we don't check the certificates.
    266             cached->SetProofValid();
    267           } else if (!cached->signature().empty()) {
    268             next_state_ = STATE_VERIFY_PROOF;
    269             break;
    270           }
    271         }
    272         next_state_ = STATE_SEND_CHLO;
    273         break;
    274       case STATE_VERIFY_PROOF: {
    275         ProofVerifier* verifier = crypto_config_->proof_verifier();
    276         DCHECK(verifier);
    277         next_state_ = STATE_VERIFY_PROOF_COMPLETE;
    278         generation_counter_ = cached->generation_counter();
    279 
    280         ProofVerifierCallbackImpl* proof_verify_callback =
    281             new ProofVerifierCallbackImpl(this);
    282 
    283         verify_ok_ = false;
    284 
    285         ProofVerifier::Status status = verifier->VerifyProof(
    286             server_hostname_,
    287             cached->server_config(),
    288             cached->certs(),
    289             cached->signature(),
    290             &verify_error_details_,
    291             &verify_details_,
    292             proof_verify_callback);
    293 
    294         switch (status) {
    295           case ProofVerifier::PENDING:
    296             proof_verify_callback_ = proof_verify_callback;
    297             DVLOG(1) << "Doing VerifyProof";
    298             return;
    299           case ProofVerifier::FAILURE:
    300             break;
    301           case ProofVerifier::SUCCESS:
    302             verify_ok_ = true;
    303             break;
    304         }
    305         break;
    306       }
    307       case STATE_VERIFY_PROOF_COMPLETE:
    308         if (!verify_ok_) {
    309           CopyCertVerifyResult(verify_details_.get(), &cert_verify_result_);
    310           CloseConnectionWithDetails(
    311               QUIC_PROOF_INVALID, "Proof invalid: " + verify_error_details_);
    312           return;
    313         }
    314         // Check if generation_counter has changed between STATE_VERIFY_PROOF
    315         // and STATE_VERIFY_PROOF_COMPLETE state changes.
    316         if (generation_counter_ != cached->generation_counter()) {
    317           next_state_ = STATE_VERIFY_PROOF;
    318         } else {
    319           cached->SetProofValid();
    320           cached->SetProofVerifyDetails(verify_details_.release());
    321           next_state_ = STATE_SEND_CHLO;
    322         }
    323         break;
    324       case STATE_RECV_SHLO: {
    325         // We sent a CHLO that we expected to be accepted and now we're hoping
    326         // for a SHLO from the server to confirm that.
    327         if (in->tag() == kREJ) {
    328           // alternative_decrypter will be NULL if the original alternative
    329           // decrypter latched and became the primary decrypter. That happens
    330           // if we received a message encrypted with the INITIAL key.
    331           if (session()->connection()->alternative_decrypter() == NULL) {
    332             // The rejection was sent encrypted!
    333             CloseConnectionWithDetails(QUIC_CRYPTO_ENCRYPTION_LEVEL_INCORRECT,
    334                                        "encrypted REJ message");
    335             return;
    336           }
    337           next_state_ = STATE_RECV_REJ;
    338           break;
    339         }
    340         if (in->tag() != kSHLO) {
    341           CloseConnectionWithDetails(QUIC_INVALID_CRYPTO_MESSAGE_TYPE,
    342                                      "Expected SHLO or REJ");
    343           return;
    344         }
    345         // alternative_decrypter will be NULL if the original alternative
    346         // decrypter latched and became the primary decrypter. That happens
    347         // if we received a message encrypted with the INITIAL key.
    348         if (session()->connection()->alternative_decrypter() != NULL) {
    349           // The server hello was sent without encryption.
    350           CloseConnectionWithDetails(QUIC_CRYPTO_ENCRYPTION_LEVEL_INCORRECT,
    351                                      "unencrypted SHLO message");
    352           return;
    353         }
    354         error = crypto_config_->ProcessServerHello(
    355             *in, session()->connection()->guid(),
    356             session()->connection()->server_supported_versions(),
    357             cached, &crypto_negotiated_params_, &error_details);
    358 
    359         if (error != QUIC_NO_ERROR) {
    360           CloseConnectionWithDetails(
    361               error, "Server hello invalid: " + error_details);
    362           return;
    363         }
    364         error = session()->config()->ProcessServerHello(*in, &error_details);
    365         if (error != QUIC_NO_ERROR) {
    366           CloseConnectionWithDetails(
    367               error, "Server hello invalid: " + error_details);
    368           return;
    369         }
    370         session()->OnConfigNegotiated();
    371 
    372         CrypterPair* crypters =
    373             &crypto_negotiated_params_.forward_secure_crypters;
    374         // TODO(agl): we don't currently latch this decrypter because the idea
    375         // has been floated that the server shouldn't send packets encrypted
    376         // with the FORWARD_SECURE key until it receives a FORWARD_SECURE
    377         // packet from the client.
    378         session()->connection()->SetAlternativeDecrypter(
    379             crypters->decrypter.release(), false /* don't latch */);
    380         session()->connection()->SetEncrypter(
    381             ENCRYPTION_FORWARD_SECURE, crypters->encrypter.release());
    382         session()->connection()->SetDefaultEncryptionLevel(
    383             ENCRYPTION_FORWARD_SECURE);
    384 
    385         handshake_confirmed_ = true;
    386         session()->OnCryptoHandshakeEvent(QuicSession::HANDSHAKE_CONFIRMED);
    387         return;
    388       }
    389       case STATE_IDLE:
    390         // This means that the peer sent us a message that we weren't expecting.
    391         CloseConnection(QUIC_INVALID_CRYPTO_MESSAGE_TYPE);
    392         return;
    393     }
    394   }
    395 }
    396 
    397 }  // namespace net
    398