| Index: webrtc/base/opensslstreamadapter.cc
 | 
| diff --git a/webrtc/base/opensslstreamadapter.cc b/webrtc/base/opensslstreamadapter.cc
 | 
| index 4b40c389049c326ee5cc4330077ea0cead954e57..6a42003968cf4ff74400818c826b5ff69d069492 100644
 | 
| --- a/webrtc/base/opensslstreamadapter.cc
 | 
| +++ b/webrtc/base/opensslstreamadapter.cc
 | 
| @@ -25,6 +25,7 @@
 | 
|  #include <memory>
 | 
|  #include <vector>
 | 
|  
 | 
| +#include "webrtc/base/checks.h"
 | 
|  #include "webrtc/base/common.h"
 | 
|  #include "webrtc/base/logging.h"
 | 
|  #include "webrtc/base/safe_conversions.h"
 | 
| @@ -290,11 +291,11 @@ OpenSSLStreamAdapter::OpenSSLStreamAdapter(StreamInterface* stream)
 | 
|        ssl_max_version_(SSL_PROTOCOL_TLS_12) {}
 | 
|  
 | 
|  OpenSSLStreamAdapter::~OpenSSLStreamAdapter() {
 | 
| -  Cleanup();
 | 
| +  Cleanup(0);
 | 
|  }
 | 
|  
 | 
|  void OpenSSLStreamAdapter::SetIdentity(SSLIdentity* identity) {
 | 
| -  ASSERT(!identity_);
 | 
| +  RTC_DCHECK(!identity_);
 | 
|    identity_.reset(static_cast<OpenSSLIdentity*>(identity));
 | 
|  }
 | 
|  
 | 
| @@ -309,25 +310,56 @@ std::unique_ptr<SSLCertificate> OpenSSLStreamAdapter::GetPeerCertificate()
 | 
|                             : nullptr;
 | 
|  }
 | 
|  
 | 
| -bool OpenSSLStreamAdapter::SetPeerCertificateDigest(const std::string
 | 
| -                                                    &digest_alg,
 | 
| -                                                    const unsigned char*
 | 
| -                                                    digest_val,
 | 
| -                                                    size_t digest_len) {
 | 
| -  ASSERT(!peer_certificate_);
 | 
| -  ASSERT(peer_certificate_digest_algorithm_.size() == 0);
 | 
| +bool OpenSSLStreamAdapter::SetPeerCertificateDigest(
 | 
| +    const std::string& digest_alg,
 | 
| +    const unsigned char* digest_val,
 | 
| +    size_t digest_len,
 | 
| +    SSLPeerCertificateDigestError* error) {
 | 
| +  RTC_DCHECK(!peer_certificate_verified_);
 | 
| +  RTC_DCHECK(!has_peer_certificate_digest());
 | 
|    size_t expected_len;
 | 
| +  if (error) {
 | 
| +    *error = SSLPeerCertificateDigestError::NONE;
 | 
| +  }
 | 
|  
 | 
|    if (!OpenSSLDigest::GetDigestSize(digest_alg, &expected_len)) {
 | 
|      LOG(LS_WARNING) << "Unknown digest algorithm: " << digest_alg;
 | 
| +    if (error) {
 | 
| +      *error = SSLPeerCertificateDigestError::UNKNOWN_ALGORITHM;
 | 
| +    }
 | 
|      return false;
 | 
|    }
 | 
| -  if (expected_len != digest_len)
 | 
| +  if (expected_len != digest_len) {
 | 
| +    if (error) {
 | 
| +      *error = SSLPeerCertificateDigestError::INVALID_LENGTH;
 | 
| +    }
 | 
|      return false;
 | 
| +  }
 | 
|  
 | 
|    peer_certificate_digest_value_.SetData(digest_val, digest_len);
 | 
|    peer_certificate_digest_algorithm_ = digest_alg;
 | 
|  
 | 
| +  if (!peer_certificate_) {
 | 
| +    // Normal case, where the digest is set before we obtain the certificate
 | 
| +    // from the handshake.
 | 
| +    return true;
 | 
| +  }
 | 
| +
 | 
| +  if (!VerifyPeerCertificate()) {
 | 
| +    Error("SetPeerCertificateDigest", -1, SSL_AD_BAD_CERTIFICATE, false);
 | 
| +    if (error) {
 | 
| +      *error = SSLPeerCertificateDigestError::VERIFICATION_FAILED;
 | 
| +    }
 | 
| +    return false;
 | 
| +  }
 | 
| +
 | 
| +  if (state_ == SSL_CONNECTED) {
 | 
| +    // Post the event asynchronously to unwind the stack. The caller
 | 
| +    // of ContinueSSL may be the same object listening for these
 | 
| +    // events and may not be prepared for reentrancy.
 | 
| +    PostEvent(SE_OPEN | SE_READ | SE_WRITE, 0);
 | 
| +  }
 | 
| +
 | 
|    return true;
 | 
|  }
 | 
|  
 | 
| @@ -450,7 +482,7 @@ bool OpenSSLStreamAdapter::SetDtlsSrtpCryptoSuites(
 | 
|  
 | 
|  bool OpenSSLStreamAdapter::GetDtlsSrtpCryptoSuite(int* crypto_suite) {
 | 
|  #ifdef HAVE_DTLS_SRTP
 | 
| -  ASSERT(state_ == SSL_CONNECTED);
 | 
| +  RTC_DCHECK(state_ == SSL_CONNECTED);
 | 
|    if (state_ != SSL_CONNECTED)
 | 
|      return false;
 | 
|  
 | 
| @@ -461,15 +493,22 @@ bool OpenSSLStreamAdapter::GetDtlsSrtpCryptoSuite(int* crypto_suite) {
 | 
|      return false;
 | 
|  
 | 
|    *crypto_suite = srtp_profile->id;
 | 
| -  ASSERT(!SrtpCryptoSuiteToName(*crypto_suite).empty());
 | 
| +  RTC_DCHECK(!SrtpCryptoSuiteToName(*crypto_suite).empty());
 | 
|    return true;
 | 
|  #else
 | 
|    return false;
 | 
|  #endif
 | 
|  }
 | 
|  
 | 
| +bool OpenSSLStreamAdapter::IsTlsConnected() {
 | 
| +  return state_ == SSL_CONNECTED;
 | 
| +}
 | 
| +
 | 
|  int OpenSSLStreamAdapter::StartSSL() {
 | 
| -  ASSERT(state_ == SSL_NONE);
 | 
| +  if (state_ != SSL_NONE) {
 | 
| +    // Don't allow StartSSL to be called twice.
 | 
| +    return -1;
 | 
| +  }
 | 
|  
 | 
|    if (StreamAdapterInterface::GetState() != SS_OPEN) {
 | 
|      state_ = SSL_WAIT;
 | 
| @@ -478,7 +517,7 @@ int OpenSSLStreamAdapter::StartSSL() {
 | 
|  
 | 
|    state_ = SSL_CONNECTING;
 | 
|    if (int err = BeginSSL()) {
 | 
| -    Error("BeginSSL", err, false);
 | 
| +    Error("BeginSSL", err, 0, false);
 | 
|      return err;
 | 
|    }
 | 
|  
 | 
| @@ -486,12 +525,12 @@ int OpenSSLStreamAdapter::StartSSL() {
 | 
|  }
 | 
|  
 | 
|  void OpenSSLStreamAdapter::SetMode(SSLMode mode) {
 | 
| -  ASSERT(state_ == SSL_NONE);
 | 
| +  RTC_DCHECK(state_ == SSL_NONE);
 | 
|    ssl_mode_ = mode;
 | 
|  }
 | 
|  
 | 
|  void OpenSSLStreamAdapter::SetMaxProtocolVersion(SSLProtocolVersion version) {
 | 
| -  ASSERT(ssl_ctx_ == NULL);
 | 
| +  RTC_DCHECK(ssl_ctx_ == NULL);
 | 
|    ssl_max_version_ = version;
 | 
|  }
 | 
|  
 | 
| @@ -513,6 +552,9 @@ StreamResult OpenSSLStreamAdapter::Write(const void* data, size_t data_len,
 | 
|      return SR_BLOCK;
 | 
|  
 | 
|    case SSL_CONNECTED:
 | 
| +    if (waiting_to_verify_peer_certificate()) {
 | 
| +      return SR_BLOCK;
 | 
| +    }
 | 
|      break;
 | 
|  
 | 
|    case SSL_ERROR:
 | 
| @@ -537,7 +579,7 @@ StreamResult OpenSSLStreamAdapter::Write(const void* data, size_t data_len,
 | 
|    switch (ssl_error) {
 | 
|    case SSL_ERROR_NONE:
 | 
|      LOG(LS_VERBOSE) << " -- success";
 | 
| -    ASSERT(0 < code && static_cast<unsigned>(code) <= data_len);
 | 
| +    RTC_DCHECK(0 < code && static_cast<unsigned>(code) <= data_len);
 | 
|      if (written)
 | 
|        *written = code;
 | 
|      return SR_SUCCESS;
 | 
| @@ -551,7 +593,7 @@ StreamResult OpenSSLStreamAdapter::Write(const void* data, size_t data_len,
 | 
|  
 | 
|    case SSL_ERROR_ZERO_RETURN:
 | 
|    default:
 | 
| -    Error("SSL_write", (ssl_error ? ssl_error : -1), false);
 | 
| +    Error("SSL_write", (ssl_error ? ssl_error : -1), 0, false);
 | 
|      if (error)
 | 
|        *error = ssl_error_code_;
 | 
|      return SR_ERROR;
 | 
| @@ -572,6 +614,9 @@ StreamResult OpenSSLStreamAdapter::Read(void* data, size_t data_len,
 | 
|        return SR_BLOCK;
 | 
|  
 | 
|      case SSL_CONNECTED:
 | 
| +      if (waiting_to_verify_peer_certificate()) {
 | 
| +        return SR_BLOCK;
 | 
| +      }
 | 
|        break;
 | 
|  
 | 
|      case SSL_CLOSED:
 | 
| @@ -598,7 +643,7 @@ StreamResult OpenSSLStreamAdapter::Read(void* data, size_t data_len,
 | 
|    switch (ssl_error) {
 | 
|      case SSL_ERROR_NONE:
 | 
|        LOG(LS_VERBOSE) << " -- success";
 | 
| -      ASSERT(0 < code && static_cast<unsigned>(code) <= data_len);
 | 
| +      RTC_DCHECK(0 < code && static_cast<unsigned>(code) <= data_len);
 | 
|        if (read)
 | 
|          *read = code;
 | 
|  
 | 
| @@ -624,15 +669,12 @@ StreamResult OpenSSLStreamAdapter::Read(void* data, size_t data_len,
 | 
|        return SR_BLOCK;
 | 
|      case SSL_ERROR_ZERO_RETURN:
 | 
|        LOG(LS_VERBOSE) << " -- remote side closed";
 | 
| -      // When we're closed at SSL layer, also close the stream level which
 | 
| -      // performs necessary clean up. Otherwise, a new incoming packet after
 | 
| -      // this could overflow the stream buffer.
 | 
| -      this->stream()->Close();
 | 
| +      Close();
 | 
|        return SR_EOS;
 | 
|        break;
 | 
|      default:
 | 
|        LOG(LS_VERBOSE) << " -- error " << code;
 | 
| -      Error("SSL_read", (ssl_error ? ssl_error : -1), false);
 | 
| +      Error("SSL_read", (ssl_error ? ssl_error : -1), 0, false);
 | 
|        if (error)
 | 
|          *error = ssl_error_code_;
 | 
|        return SR_ERROR;
 | 
| @@ -649,11 +691,11 @@ void OpenSSLStreamAdapter::FlushInput(unsigned int left) {
 | 
|      int code = SSL_read(ssl_, buf, toread);
 | 
|  
 | 
|      int ssl_error = SSL_get_error(ssl_, code);
 | 
| -    ASSERT(ssl_error == SSL_ERROR_NONE);
 | 
| +    RTC_DCHECK(ssl_error == SSL_ERROR_NONE);
 | 
|  
 | 
|      if (ssl_error != SSL_ERROR_NONE) {
 | 
|        LOG(LS_VERBOSE) << " -- error " << code;
 | 
| -      Error("SSL_read", (ssl_error ? ssl_error : -1), false);
 | 
| +      Error("SSL_read", (ssl_error ? ssl_error : -1), 0, false);
 | 
|        return;
 | 
|      }
 | 
|  
 | 
| @@ -663,8 +705,11 @@ void OpenSSLStreamAdapter::FlushInput(unsigned int left) {
 | 
|  }
 | 
|  
 | 
|  void OpenSSLStreamAdapter::Close() {
 | 
| -  Cleanup();
 | 
| -  ASSERT(state_ == SSL_CLOSED || state_ == SSL_ERROR);
 | 
| +  Cleanup(0);
 | 
| +  RTC_DCHECK(state_ == SSL_CLOSED || state_ == SSL_ERROR);
 | 
| +  // When we're closed at SSL layer, also close the stream level which
 | 
| +  // performs necessary clean up. Otherwise, a new incoming packet after
 | 
| +  // this could overflow the stream buffer.
 | 
|    StreamAdapterInterface::Close();
 | 
|  }
 | 
|  
 | 
| @@ -674,6 +719,9 @@ StreamState OpenSSLStreamAdapter::GetState() const {
 | 
|      case SSL_CONNECTING:
 | 
|        return SS_OPENING;
 | 
|      case SSL_CONNECTED:
 | 
| +      if (waiting_to_verify_peer_certificate()) {
 | 
| +        return SS_OPENING;
 | 
| +      }
 | 
|        return SS_OPEN;
 | 
|      default:
 | 
|        return SS_CLOSED;
 | 
| @@ -685,16 +733,16 @@ void OpenSSLStreamAdapter::OnEvent(StreamInterface* stream, int events,
 | 
|                                     int err) {
 | 
|    int events_to_signal = 0;
 | 
|    int signal_error = 0;
 | 
| -  ASSERT(stream == this->stream());
 | 
| +  RTC_DCHECK(stream == this->stream());
 | 
|    if ((events & SE_OPEN)) {
 | 
|      LOG(LS_VERBOSE) << "OpenSSLStreamAdapter::OnEvent SE_OPEN";
 | 
|      if (state_ != SSL_WAIT) {
 | 
| -      ASSERT(state_ == SSL_NONE);
 | 
| +      RTC_DCHECK(state_ == SSL_NONE);
 | 
|        events_to_signal |= SE_OPEN;
 | 
|      } else {
 | 
|        state_ = SSL_CONNECTING;
 | 
|        if (int err = BeginSSL()) {
 | 
| -        Error("BeginSSL", err, true);
 | 
| +        Error("BeginSSL", err, 0, true);
 | 
|          return;
 | 
|        }
 | 
|      }
 | 
| @@ -707,7 +755,7 @@ void OpenSSLStreamAdapter::OnEvent(StreamInterface* stream, int events,
 | 
|        events_to_signal |= events & (SE_READ|SE_WRITE);
 | 
|      } else if (state_ == SSL_CONNECTING) {
 | 
|        if (int err = ContinueSSL()) {
 | 
| -        Error("ContinueSSL", err, true);
 | 
| +        Error("ContinueSSL", err, 0, true);
 | 
|          return;
 | 
|        }
 | 
|      } else if (state_ == SSL_CONNECTED) {
 | 
| @@ -725,10 +773,10 @@ void OpenSSLStreamAdapter::OnEvent(StreamInterface* stream, int events,
 | 
|    }
 | 
|    if ((events & SE_CLOSE)) {
 | 
|      LOG(LS_VERBOSE) << "OpenSSLStreamAdapter::OnEvent(SE_CLOSE, " << err << ")";
 | 
| -    Cleanup();
 | 
| +    Cleanup(0);
 | 
|      events_to_signal |= SE_CLOSE;
 | 
|      // SE_CLOSE is the only event that uses the final parameter to OnEvent().
 | 
| -    ASSERT(signal_error == 0);
 | 
| +    RTC_DCHECK(signal_error == 0);
 | 
|      signal_error = err;
 | 
|    }
 | 
|    if (events_to_signal)
 | 
| @@ -736,16 +784,14 @@ void OpenSSLStreamAdapter::OnEvent(StreamInterface* stream, int events,
 | 
|  }
 | 
|  
 | 
|  int OpenSSLStreamAdapter::BeginSSL() {
 | 
| -  ASSERT(state_ == SSL_CONNECTING);
 | 
| +  RTC_DCHECK(state_ == SSL_CONNECTING);
 | 
|    // The underlying stream has opened.
 | 
| -  // A peer certificate digest must have been specified by now.
 | 
| -  ASSERT(!peer_certificate_digest_algorithm_.empty());
 | 
|    LOG(LS_INFO) << "BeginSSL with peer.";
 | 
|  
 | 
|    BIO* bio = NULL;
 | 
|  
 | 
|    // First set up the context.
 | 
| -  ASSERT(ssl_ctx_ == NULL);
 | 
| +  RTC_DCHECK(ssl_ctx_ == NULL);
 | 
|    ssl_ctx_ = SetupSSLContext();
 | 
|    if (!ssl_ctx_)
 | 
|      return -1;
 | 
| @@ -799,7 +845,7 @@ int OpenSSLStreamAdapter::BeginSSL() {
 | 
|  
 | 
|  int OpenSSLStreamAdapter::ContinueSSL() {
 | 
|    LOG(LS_VERBOSE) << "ContinueSSL";
 | 
| -  ASSERT(state_ == SSL_CONNECTING);
 | 
| +  RTC_DCHECK(state_ == SSL_CONNECTING);
 | 
|  
 | 
|    // Clear the DTLS timer
 | 
|    Thread::Current()->Clear(this, MSG_TIMEOUT);
 | 
| @@ -809,15 +855,21 @@ int OpenSSLStreamAdapter::ContinueSSL() {
 | 
|    switch (ssl_error = SSL_get_error(ssl_, code)) {
 | 
|      case SSL_ERROR_NONE:
 | 
|        LOG(LS_VERBOSE) << " -- success";
 | 
| -
 | 
| -      if (!SSLPostConnectionCheck(ssl_, NULL,
 | 
| -                                  peer_certificate_digest_algorithm_)) {
 | 
| -        LOG(LS_ERROR) << "TLS post connection check failed";
 | 
| -        return -1;
 | 
| -      }
 | 
| +      // By this point, OpenSSL should have given us a certificate, or errored
 | 
| +      // out if one was missing.
 | 
| +      RTC_DCHECK(peer_certificate_ || !client_auth_enabled());
 | 
|  
 | 
|        state_ = SSL_CONNECTED;
 | 
| -      StreamAdapterInterface::OnEvent(stream(), SE_OPEN|SE_READ|SE_WRITE, 0);
 | 
| +      if (!waiting_to_verify_peer_certificate()) {
 | 
| +        // We have everything we need to start the connection, so signal
 | 
| +        // SE_OPEN. If we need a client certificate fingerprint and don't have
 | 
| +        // it yet, we'll instead signal SE_OPEN in SetPeerCertificateDigest.
 | 
| +        //
 | 
| +        // Post the event asynchronously to unwind the stack. The
 | 
| +        // caller of ContinueSSL may be the same object listening
 | 
| +        // for these events and may not be prepared for reentrancy.
 | 
| +        PostEvent(SE_OPEN | SE_READ | SE_WRITE, 0);
 | 
| +      }
 | 
|        break;
 | 
|  
 | 
|      case SSL_ERROR_WANT_READ: {
 | 
| @@ -851,17 +903,20 @@ int OpenSSLStreamAdapter::ContinueSSL() {
 | 
|    return 0;
 | 
|  }
 | 
|  
 | 
| -void OpenSSLStreamAdapter::Error(const char* context, int err, bool signal) {
 | 
| -  LOG(LS_WARNING) << "OpenSSLStreamAdapter::Error("
 | 
| -                  << context << ", " << err << ")";
 | 
| +void OpenSSLStreamAdapter::Error(const char* context,
 | 
| +                                 int err,
 | 
| +                                 uint8_t alert,
 | 
| +                                 bool signal) {
 | 
| +  LOG(LS_WARNING) << "OpenSSLStreamAdapter::Error(" << context << ", " << err
 | 
| +                  << ", " << static_cast<int>(alert) << ")";
 | 
|    state_ = SSL_ERROR;
 | 
|    ssl_error_code_ = err;
 | 
| -  Cleanup();
 | 
| +  Cleanup(alert);
 | 
|    if (signal)
 | 
|      StreamAdapterInterface::OnEvent(stream(), SE_CLOSE, err);
 | 
|  }
 | 
|  
 | 
| -void OpenSSLStreamAdapter::Cleanup() {
 | 
| +void OpenSSLStreamAdapter::Cleanup(uint8_t alert) {
 | 
|    LOG(LS_INFO) << "Cleanup";
 | 
|  
 | 
|    if (state_ != SSL_ERROR) {
 | 
| @@ -870,12 +925,25 @@ void OpenSSLStreamAdapter::Cleanup() {
 | 
|    }
 | 
|  
 | 
|    if (ssl_) {
 | 
| -    int ret = SSL_shutdown(ssl_);
 | 
| -    if (ret < 0) {
 | 
| -      LOG(LS_WARNING) << "SSL_shutdown failed, error = "
 | 
| -                      << SSL_get_error(ssl_, ret);
 | 
| +    int ret;
 | 
| +// SSL_send_fatal_alert is only available in BoringSSL.
 | 
| +#ifdef OPENSSL_IS_BORINGSSL
 | 
| +    if (alert) {
 | 
| +      ret = SSL_send_fatal_alert(ssl_, alert);
 | 
| +      if (ret < 0) {
 | 
| +        LOG(LS_WARNING) << "SSL_send_fatal_alert failed, error = "
 | 
| +                        << SSL_get_error(ssl_, ret);
 | 
| +      }
 | 
| +    } else {
 | 
| +#endif
 | 
| +      ret = SSL_shutdown(ssl_);
 | 
| +      if (ret < 0) {
 | 
| +        LOG(LS_WARNING) << "SSL_shutdown failed, error = "
 | 
| +                        << SSL_get_error(ssl_, ret);
 | 
| +      }
 | 
| +#ifdef OPENSSL_IS_BORINGSSL
 | 
|      }
 | 
| -
 | 
| +#endif
 | 
|      SSL_free(ssl_);
 | 
|      ssl_ = NULL;
 | 
|    }
 | 
| @@ -1033,43 +1101,23 @@ SSL_CTX* OpenSSLStreamAdapter::SetupSSLContext() {
 | 
|    return ctx;
 | 
|  }
 | 
|  
 | 
| -int OpenSSLStreamAdapter::SSLVerifyCallback(int ok, X509_STORE_CTX* store) {
 | 
| -  // Get our SSL structure from the store
 | 
| -  SSL* ssl = reinterpret_cast<SSL*>(X509_STORE_CTX_get_ex_data(
 | 
| -                                        store,
 | 
| -                                        SSL_get_ex_data_X509_STORE_CTX_idx()));
 | 
| -  OpenSSLStreamAdapter* stream =
 | 
| -    reinterpret_cast<OpenSSLStreamAdapter*>(SSL_get_app_data(ssl));
 | 
| -
 | 
| -  if (stream->peer_certificate_digest_algorithm_.empty()) {
 | 
| -    return 0;
 | 
| -  }
 | 
| -  X509* cert = X509_STORE_CTX_get_current_cert(store);
 | 
| -  int depth = X509_STORE_CTX_get_error_depth(store);
 | 
| -
 | 
| -  // For now We ignore the parent certificates and verify the leaf against
 | 
| -  // the digest.
 | 
| -  //
 | 
| -  // TODO(jiayl): Verify the chain is a proper chain and report the chain to
 | 
| -  // |stream->peer_certificate_|.
 | 
| -  if (depth > 0) {
 | 
| -    LOG(LS_INFO) << "Ignored chained certificate at depth " << depth;
 | 
| -    return 1;
 | 
| +bool OpenSSLStreamAdapter::VerifyPeerCertificate() {
 | 
| +  if (!has_peer_certificate_digest() || !peer_certificate_) {
 | 
| +    LOG(LS_WARNING) << "Missing digest or peer certificate.";
 | 
| +    return false;
 | 
|    }
 | 
|  
 | 
|    unsigned char digest[EVP_MAX_MD_SIZE];
 | 
|    size_t digest_length;
 | 
|    if (!OpenSSLCertificate::ComputeDigest(
 | 
| -           cert,
 | 
| -           stream->peer_certificate_digest_algorithm_,
 | 
| -           digest, sizeof(digest),
 | 
| -           &digest_length)) {
 | 
| +          peer_certificate_->x509(), peer_certificate_digest_algorithm_, digest,
 | 
| +          sizeof(digest), &digest_length)) {
 | 
|      LOG(LS_WARNING) << "Failed to compute peer cert digest.";
 | 
| -    return 0;
 | 
| +    return false;
 | 
|    }
 | 
|  
 | 
|    Buffer computed_digest(digest, digest_length);
 | 
| -  if (computed_digest != stream->peer_certificate_digest_value_) {
 | 
| +  if (computed_digest != peer_certificate_digest_value_) {
 | 
|      LOG(LS_WARNING) << "Rejected peer certificate due to mismatched digest.";
 | 
|      return 0;
 | 
|    }
 | 
| @@ -1077,18 +1125,41 @@ int OpenSSLStreamAdapter::SSLVerifyCallback(int ok, X509_STORE_CTX* store) {
 | 
|    // value in checking the validity of a self-signed cert issued by untrusted
 | 
|    // sources.
 | 
|    LOG(LS_INFO) << "Accepted peer certificate.";
 | 
| +  peer_certificate_verified_ = true;
 | 
| +  return true;
 | 
| +}
 | 
| +
 | 
| +int OpenSSLStreamAdapter::SSLVerifyCallback(int ok, X509_STORE_CTX* store) {
 | 
| +  // Get our SSL structure from the store
 | 
| +  SSL* ssl = reinterpret_cast<SSL*>(
 | 
| +      X509_STORE_CTX_get_ex_data(store, SSL_get_ex_data_X509_STORE_CTX_idx()));
 | 
| +  X509* cert = X509_STORE_CTX_get_current_cert(store);
 | 
| +  int depth = X509_STORE_CTX_get_error_depth(store);
 | 
| +
 | 
| +  // For now we ignore the parent certificates and verify the leaf against
 | 
| +  // the digest.
 | 
| +  //
 | 
| +  // TODO(jiayl): Verify the chain is a proper chain and report the chain to
 | 
| +  // |stream->peer_certificate_|.
 | 
| +  if (depth > 0) {
 | 
| +    LOG(LS_INFO) << "Ignored chained certificate at depth " << depth;
 | 
| +    return 1;
 | 
| +  }
 | 
| +
 | 
| +  OpenSSLStreamAdapter* stream =
 | 
| +      reinterpret_cast<OpenSSLStreamAdapter*>(SSL_get_app_data(ssl));
 | 
|  
 | 
|    // Record the peer's certificate.
 | 
|    stream->peer_certificate_.reset(new OpenSSLCertificate(cert));
 | 
| -  return 1;
 | 
| -}
 | 
|  
 | 
| -bool OpenSSLStreamAdapter::SSLPostConnectionCheck(SSL* ssl,
 | 
| -                                                  const X509* peer_cert,
 | 
| -                                                  const std::string
 | 
| -                                                  &peer_digest) {
 | 
| -  ASSERT((peer_cert != NULL) || (!peer_digest.empty()));
 | 
| -  return true;
 | 
| +  // If the peer certificate digest isn't known yet, we'll wait to verify
 | 
| +  // until it's known, and for now just return a success status.
 | 
| +  if (stream->peer_certificate_digest_algorithm_.empty()) {
 | 
| +    LOG(LS_INFO) << "Waiting to verify certificate until digest is known.";
 | 
| +    return 1;
 | 
| +  }
 | 
| +
 | 
| +  return stream->VerifyPeerCertificate();
 | 
|  }
 | 
|  
 | 
|  bool OpenSSLStreamAdapter::HaveDtls() {
 | 
| 
 |