henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 +0000 | [diff] [blame] | 1 | /* |
| 2 | * Copyright 2011 The WebRTC Project Authors. All rights reserved. |
| 3 | * |
| 4 | * Use of this source code is governed by a BSD-style license |
| 5 | * that can be found in the LICENSE file in the root of the source |
| 6 | * tree. An additional intellectual property rights grant can be found |
| 7 | * in the file PATENTS. All contributing project authors may |
| 8 | * be found in the AUTHORS file in the root of the source tree. |
| 9 | */ |
| 10 | |
zhihuang | ca6d3b6 | 2017-08-23 18:05:50 -0700 | [diff] [blame] | 11 | #include <algorithm> |
jbauch | 555604a | 2016-04-26 03:13:22 -0700 | [diff] [blame] | 12 | #include <memory> |
kwiberg | 0eb15ed | 2015-12-17 03:04:15 -0800 | [diff] [blame] | 13 | #include <utility> |
| 14 | |
zhihuang | ca6d3b6 | 2017-08-23 18:05:50 -0700 | [diff] [blame] | 15 | #include "webrtc/p2p/base/dtlstransport.h" |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 +0000 | [diff] [blame] | 16 | |
| 17 | #include "webrtc/p2p/base/common.h" |
deadbeef | 5bd5ca3 | 2017-02-10 11:31:50 -0800 | [diff] [blame] | 18 | #include "webrtc/p2p/base/packettransportinternal.h" |
Edward Lemur | c20978e | 2017-07-06 19:44:34 +0200 | [diff] [blame] | 19 | #include "webrtc/rtc_base/buffer.h" |
| 20 | #include "webrtc/rtc_base/checks.h" |
| 21 | #include "webrtc/rtc_base/dscp.h" |
| 22 | #include "webrtc/rtc_base/messagequeue.h" |
| 23 | #include "webrtc/rtc_base/sslstreamadapter.h" |
| 24 | #include "webrtc/rtc_base/stream.h" |
| 25 | #include "webrtc/rtc_base/thread.h" |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 +0000 | [diff] [blame] | 26 | |
| 27 | namespace cricket { |
| 28 | |
| 29 | // We don't pull the RTP constants from rtputils.h, to avoid a layer violation. |
| 30 | static const size_t kDtlsRecordHeaderLen = 13; |
| 31 | static const size_t kMaxDtlsPacketLen = 2048; |
| 32 | static const size_t kMinRtpPacketLen = 12; |
| 33 | |
Joachim Bauch | 6f2ef74 | 2015-05-21 17:52:01 +0200 | [diff] [blame] | 34 | // Maximum number of pending packets in the queue. Packets are read immediately |
| 35 | // after they have been written, so a capacity of "1" is sufficient. |
| 36 | static const size_t kMaxPendingPackets = 1; |
| 37 | |
skvlad | d030912 | 2017-02-02 17:18:37 -0800 | [diff] [blame] | 38 | // Minimum and maximum values for the initial DTLS handshake timeout. We'll pick |
| 39 | // an initial timeout based on ICE RTT estimates, but clamp it to this range. |
| 40 | static const int kMinHandshakeTimeout = 50; |
| 41 | static const int kMaxHandshakeTimeout = 3000; |
| 42 | |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 +0000 | [diff] [blame] | 43 | static bool IsDtlsPacket(const char* data, size_t len) { |
Peter Boström | 0c4e06b | 2015-10-07 12:23:21 +0200 | [diff] [blame] | 44 | const uint8_t* u = reinterpret_cast<const uint8_t*>(data); |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 +0000 | [diff] [blame] | 45 | return (len >= kDtlsRecordHeaderLen && (u[0] > 19 && u[0] < 64)); |
| 46 | } |
deadbeef | e84cd2e | 2016-05-04 17:16:34 -0700 | [diff] [blame] | 47 | static bool IsDtlsClientHelloPacket(const char* data, size_t len) { |
| 48 | if (!IsDtlsPacket(data, len)) { |
| 49 | return false; |
| 50 | } |
| 51 | const uint8_t* u = reinterpret_cast<const uint8_t*>(data); |
| 52 | return len > 17 && u[0] == 22 && u[13] == 1; |
| 53 | } |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 +0000 | [diff] [blame] | 54 | static bool IsRtpPacket(const char* data, size_t len) { |
Peter Boström | 0c4e06b | 2015-10-07 12:23:21 +0200 | [diff] [blame] | 55 | const uint8_t* u = reinterpret_cast<const uint8_t*>(data); |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 +0000 | [diff] [blame] | 56 | return (len >= kMinRtpPacketLen && (u[0] & 0xC0) == 0x80); |
| 57 | } |
| 58 | |
zhihuang | b2cdd93 | 2017-01-19 16:54:25 -0800 | [diff] [blame] | 59 | StreamInterfaceChannel::StreamInterfaceChannel( |
| 60 | IceTransportInternal* ice_transport) |
| 61 | : ice_transport_(ice_transport), |
Joachim Bauch | 6f2ef74 | 2015-05-21 17:52:01 +0200 | [diff] [blame] | 62 | state_(rtc::SS_OPEN), |
zhihuang | d06adf6 | 2017-01-12 15:58:31 -0800 | [diff] [blame] | 63 | packets_(kMaxPendingPackets, kMaxDtlsPacketLen) {} |
Joachim Bauch | 6f2ef74 | 2015-05-21 17:52:01 +0200 | [diff] [blame] | 64 | |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 +0000 | [diff] [blame] | 65 | rtc::StreamResult StreamInterfaceChannel::Read(void* buffer, |
zhihuang | ca6d3b6 | 2017-08-23 18:05:50 -0700 | [diff] [blame] | 66 | size_t buffer_len, |
| 67 | size_t* read, |
| 68 | int* error) { |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 +0000 | [diff] [blame] | 69 | if (state_ == rtc::SS_CLOSED) |
| 70 | return rtc::SR_EOS; |
| 71 | if (state_ == rtc::SS_OPENING) |
| 72 | return rtc::SR_BLOCK; |
| 73 | |
Joachim Bauch | 6f2ef74 | 2015-05-21 17:52:01 +0200 | [diff] [blame] | 74 | if (!packets_.ReadFront(buffer, buffer_len, read)) { |
| 75 | return rtc::SR_BLOCK; |
| 76 | } |
| 77 | |
| 78 | return rtc::SR_SUCCESS; |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 +0000 | [diff] [blame] | 79 | } |
| 80 | |
| 81 | rtc::StreamResult StreamInterfaceChannel::Write(const void* data, |
zhihuang | ca6d3b6 | 2017-08-23 18:05:50 -0700 | [diff] [blame] | 82 | size_t data_len, |
| 83 | size_t* written, |
| 84 | int* error) { |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 +0000 | [diff] [blame] | 85 | // Always succeeds, since this is an unreliable transport anyway. |
zhihuang | b2cdd93 | 2017-01-19 16:54:25 -0800 | [diff] [blame] | 86 | // TODO(zhihuang): Should this block if ice_transport_'s temporarily |
| 87 | // unwritable? |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 +0000 | [diff] [blame] | 88 | rtc::PacketOptions packet_options; |
zhihuang | b2cdd93 | 2017-01-19 16:54:25 -0800 | [diff] [blame] | 89 | ice_transport_->SendPacket(static_cast<const char*>(data), data_len, |
| 90 | packet_options); |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 +0000 | [diff] [blame] | 91 | if (written) { |
| 92 | *written = data_len; |
| 93 | } |
| 94 | return rtc::SR_SUCCESS; |
| 95 | } |
| 96 | |
| 97 | bool StreamInterfaceChannel::OnPacketReceived(const char* data, size_t size) { |
Joachim Bauch | 6f2ef74 | 2015-05-21 17:52:01 +0200 | [diff] [blame] | 98 | // We force a read event here to ensure that we don't overflow our queue. |
| 99 | bool ret = packets_.WriteBack(data, size, NULL); |
henrikg | 91d6ede | 2015-09-17 00:24:34 -0700 | [diff] [blame] | 100 | RTC_CHECK(ret) << "Failed to write packet to queue."; |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 +0000 | [diff] [blame] | 101 | if (ret) { |
| 102 | SignalEvent(this, rtc::SE_READ, 0); |
| 103 | } |
| 104 | return ret; |
| 105 | } |
| 106 | |
guoweis | 4cc9f98 | 2016-02-24 11:10:06 -0800 | [diff] [blame] | 107 | void StreamInterfaceChannel::Close() { |
| 108 | packets_.Clear(); |
| 109 | state_ = rtc::SS_CLOSED; |
| 110 | } |
| 111 | |
deadbeef | 7914b8c | 2017-04-21 03:23:33 -0700 | [diff] [blame] | 112 | DtlsTransport::DtlsTransport(IceTransportInternal* ice_transport, |
| 113 | const rtc::CryptoOptions& crypto_options) |
zhihuang | b2cdd93 | 2017-01-19 16:54:25 -0800 | [diff] [blame] | 114 | : transport_name_(ice_transport->transport_name()), |
| 115 | component_(ice_transport->component()), |
johan | 27c3d5b | 2016-10-17 00:54:57 -0700 | [diff] [blame] | 116 | network_thread_(rtc::Thread::Current()), |
zhihuang | b2cdd93 | 2017-01-19 16:54:25 -0800 | [diff] [blame] | 117 | ice_transport_(ice_transport), |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 +0000 | [diff] [blame] | 118 | downward_(NULL), |
deadbeef | 7914b8c | 2017-04-21 03:23:33 -0700 | [diff] [blame] | 119 | srtp_ciphers_(GetSupportedDtlsSrtpCryptoSuites(crypto_options)), |
Joachim Bauch | 831c558 | 2015-05-20 12:48:41 +0200 | [diff] [blame] | 120 | ssl_role_(rtc::SSL_CLIENT), |
jbauch | 5869f50 | 2017-06-29 12:31:36 -0700 | [diff] [blame] | 121 | ssl_max_version_(rtc::SSL_PROTOCOL_DTLS_12), |
| 122 | crypto_options_(crypto_options) { |
zhihuang | b2cdd93 | 2017-01-19 16:54:25 -0800 | [diff] [blame] | 123 | ice_transport_->SignalWritableState.connect(this, |
| 124 | &DtlsTransport::OnWritableState); |
| 125 | ice_transport_->SignalReadPacket.connect(this, &DtlsTransport::OnReadPacket); |
| 126 | ice_transport_->SignalSentPacket.connect(this, &DtlsTransport::OnSentPacket); |
| 127 | ice_transport_->SignalReadyToSend.connect(this, |
| 128 | &DtlsTransport::OnReadyToSend); |
| 129 | ice_transport_->SignalReceivingState.connect( |
| 130 | this, &DtlsTransport::OnReceivingState); |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 +0000 | [diff] [blame] | 131 | } |
| 132 | |
zhihuang | b2cdd93 | 2017-01-19 16:54:25 -0800 | [diff] [blame] | 133 | DtlsTransport::~DtlsTransport() {} |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 +0000 | [diff] [blame] | 134 | |
zhihuang | b2cdd93 | 2017-01-19 16:54:25 -0800 | [diff] [blame] | 135 | bool DtlsTransport::SetLocalCertificate( |
Henrik Boström | f3ecdb9 | 2015-09-08 12:11:54 +0200 | [diff] [blame] | 136 | const rtc::scoped_refptr<rtc::RTCCertificate>& certificate) { |
deadbeef | 2b55867 | 2015-10-26 17:23:29 -0700 | [diff] [blame] | 137 | if (dtls_active_) { |
Henrik Boström | f3ecdb9 | 2015-09-08 12:11:54 +0200 | [diff] [blame] | 138 | if (certificate == local_certificate_) { |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 +0000 | [diff] [blame] | 139 | // This may happen during renegotiation. |
| 140 | LOG_J(LS_INFO, this) << "Ignoring identical DTLS identity"; |
| 141 | return true; |
| 142 | } else { |
| 143 | LOG_J(LS_ERROR, this) << "Can't change DTLS local identity in this state"; |
| 144 | return false; |
| 145 | } |
| 146 | } |
| 147 | |
Henrik Boström | f3ecdb9 | 2015-09-08 12:11:54 +0200 | [diff] [blame] | 148 | if (certificate) { |
| 149 | local_certificate_ = certificate; |
deadbeef | 2b55867 | 2015-10-26 17:23:29 -0700 | [diff] [blame] | 150 | dtls_active_ = true; |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 +0000 | [diff] [blame] | 151 | } else { |
| 152 | LOG_J(LS_INFO, this) << "NULL DTLS identity supplied. Not doing DTLS"; |
| 153 | } |
| 154 | |
| 155 | return true; |
| 156 | } |
| 157 | |
zhihuang | b2cdd93 | 2017-01-19 16:54:25 -0800 | [diff] [blame] | 158 | rtc::scoped_refptr<rtc::RTCCertificate> DtlsTransport::GetLocalCertificate() |
| 159 | const { |
Henrik Boström | f3ecdb9 | 2015-09-08 12:11:54 +0200 | [diff] [blame] | 160 | return local_certificate_; |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 +0000 | [diff] [blame] | 161 | } |
| 162 | |
zhihuang | b2cdd93 | 2017-01-19 16:54:25 -0800 | [diff] [blame] | 163 | bool DtlsTransport::SetSslMaxProtocolVersion(rtc::SSLProtocolVersion version) { |
deadbeef | 2b55867 | 2015-10-26 17:23:29 -0700 | [diff] [blame] | 164 | if (dtls_active_) { |
Joachim Bauch | 831c558 | 2015-05-20 12:48:41 +0200 | [diff] [blame] | 165 | LOG(LS_ERROR) << "Not changing max. protocol version " |
| 166 | << "while DTLS is negotiating"; |
Joachim Bauch | 04e5b49 | 2015-05-29 09:40:39 +0200 | [diff] [blame] | 167 | return false; |
Joachim Bauch | 831c558 | 2015-05-20 12:48:41 +0200 | [diff] [blame] | 168 | } |
| 169 | |
| 170 | ssl_max_version_ = version; |
Joachim Bauch | 04e5b49 | 2015-05-29 09:40:39 +0200 | [diff] [blame] | 171 | return true; |
Joachim Bauch | 831c558 | 2015-05-20 12:48:41 +0200 | [diff] [blame] | 172 | } |
| 173 | |
zhihuang | b2cdd93 | 2017-01-19 16:54:25 -0800 | [diff] [blame] | 174 | bool DtlsTransport::SetSslRole(rtc::SSLRole role) { |
deadbeef | 89824f6 | 2016-09-30 11:55:43 -0700 | [diff] [blame] | 175 | if (dtls_) { |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 +0000 | [diff] [blame] | 176 | if (ssl_role_ != role) { |
| 177 | LOG(LS_ERROR) << "SSL Role can't be reversed after the session is setup."; |
| 178 | return false; |
| 179 | } |
| 180 | return true; |
| 181 | } |
| 182 | |
| 183 | ssl_role_ = role; |
| 184 | return true; |
| 185 | } |
| 186 | |
zhihuang | b2cdd93 | 2017-01-19 16:54:25 -0800 | [diff] [blame] | 187 | bool DtlsTransport::GetSslRole(rtc::SSLRole* role) const { |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 +0000 | [diff] [blame] | 188 | *role = ssl_role_; |
| 189 | return true; |
| 190 | } |
| 191 | |
zhihuang | b2cdd93 | 2017-01-19 16:54:25 -0800 | [diff] [blame] | 192 | bool DtlsTransport::GetSslCipherSuite(int* cipher) { |
deadbeef | 2b55867 | 2015-10-26 17:23:29 -0700 | [diff] [blame] | 193 | if (dtls_state() != DTLS_TRANSPORT_CONNECTED) { |
pthatcher@webrtc.org | 3ee4fe5 | 2015-02-11 22:34:36 +0000 | [diff] [blame] | 194 | return false; |
| 195 | } |
| 196 | |
Guo-wei Shieh | 456696a | 2015-09-30 21:48:54 -0700 | [diff] [blame] | 197 | return dtls_->GetSslCipherSuite(cipher); |
pthatcher@webrtc.org | 3ee4fe5 | 2015-02-11 22:34:36 +0000 | [diff] [blame] | 198 | } |
| 199 | |
zhihuang | b2cdd93 | 2017-01-19 16:54:25 -0800 | [diff] [blame] | 200 | bool DtlsTransport::SetRemoteFingerprint(const std::string& digest_alg, |
| 201 | const uint8_t* digest, |
| 202 | size_t digest_len) { |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 +0000 | [diff] [blame] | 203 | rtc::Buffer remote_fingerprint_value(digest, digest_len); |
| 204 | |
Guo-wei Shieh | 1218d7a | 2015-12-05 09:59:56 -0800 | [diff] [blame] | 205 | // Once we have the local certificate, the same remote fingerprint can be set |
| 206 | // multiple times. |
deadbeef | 2b55867 | 2015-10-26 17:23:29 -0700 | [diff] [blame] | 207 | if (dtls_active_ && remote_fingerprint_value_ == remote_fingerprint_value && |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 +0000 | [diff] [blame] | 208 | !digest_alg.empty()) { |
| 209 | // This may happen during renegotiation. |
| 210 | LOG_J(LS_INFO, this) << "Ignoring identical remote DTLS fingerprint"; |
| 211 | return true; |
| 212 | } |
| 213 | |
Guo-wei Shieh | 1218d7a | 2015-12-05 09:59:56 -0800 | [diff] [blame] | 214 | // If the other side doesn't support DTLS, turn off |dtls_active_|. |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 +0000 | [diff] [blame] | 215 | if (digest_alg.empty()) { |
Guo-wei Shieh | 1218d7a | 2015-12-05 09:59:56 -0800 | [diff] [blame] | 216 | RTC_DCHECK(!digest_len); |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 +0000 | [diff] [blame] | 217 | LOG_J(LS_INFO, this) << "Other side didn't support DTLS."; |
deadbeef | 2b55867 | 2015-10-26 17:23:29 -0700 | [diff] [blame] | 218 | dtls_active_ = false; |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 +0000 | [diff] [blame] | 219 | return true; |
| 220 | } |
| 221 | |
Guo-wei Shieh | 1218d7a | 2015-12-05 09:59:56 -0800 | [diff] [blame] | 222 | // Otherwise, we must have a local certificate before setting remote |
| 223 | // fingerprint. |
| 224 | if (!dtls_active_) { |
| 225 | LOG_J(LS_ERROR, this) << "Can't set DTLS remote settings in this state."; |
| 226 | return false; |
| 227 | } |
| 228 | |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 +0000 | [diff] [blame] | 229 | // At this point we know we are doing DTLS |
deadbeef | 89824f6 | 2016-09-30 11:55:43 -0700 | [diff] [blame] | 230 | bool fingerprint_changing = remote_fingerprint_value_.size() > 0u; |
kwiberg | 0eb15ed | 2015-12-17 03:04:15 -0800 | [diff] [blame] | 231 | remote_fingerprint_value_ = std::move(remote_fingerprint_value); |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 +0000 | [diff] [blame] | 232 | remote_fingerprint_algorithm_ = digest_alg; |
| 233 | |
deadbeef | 89824f6 | 2016-09-30 11:55:43 -0700 | [diff] [blame] | 234 | if (dtls_ && !fingerprint_changing) { |
| 235 | // This can occur if DTLS is set up before a remote fingerprint is |
| 236 | // received. For instance, if we set up DTLS due to receiving an early |
| 237 | // ClientHello. |
| 238 | rtc::SSLPeerCertificateDigestError err; |
| 239 | if (!dtls_->SetPeerCertificateDigest( |
| 240 | remote_fingerprint_algorithm_, |
| 241 | reinterpret_cast<unsigned char*>(remote_fingerprint_value_.data()), |
| 242 | remote_fingerprint_value_.size(), &err)) { |
| 243 | LOG_J(LS_ERROR, this) << "Couldn't set DTLS certificate digest."; |
| 244 | set_dtls_state(DTLS_TRANSPORT_FAILED); |
| 245 | // If the error is "verification failed", don't return false, because |
| 246 | // this means the fingerprint was formatted correctly but didn't match |
| 247 | // the certificate from the DTLS handshake. Thus the DTLS state should go |
| 248 | // to "failed", but SetRemoteDescription shouldn't fail. |
| 249 | return err == rtc::SSLPeerCertificateDigestError::VERIFICATION_FAILED; |
| 250 | } |
| 251 | return true; |
| 252 | } |
| 253 | |
| 254 | // If the fingerprint is changing, we'll tear down the DTLS association and |
| 255 | // create a new one, resetting our state. |
| 256 | if (dtls_ && fingerprint_changing) { |
deadbeef | 367efdc | 2016-07-13 12:10:17 -0700 | [diff] [blame] | 257 | dtls_.reset(nullptr); |
| 258 | set_dtls_state(DTLS_TRANSPORT_NEW); |
| 259 | set_writable(false); |
| 260 | } |
Guo-wei Shieh | 1218d7a | 2015-12-05 09:59:56 -0800 | [diff] [blame] | 261 | |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 +0000 | [diff] [blame] | 262 | if (!SetupDtls()) { |
deadbeef | 2b55867 | 2015-10-26 17:23:29 -0700 | [diff] [blame] | 263 | set_dtls_state(DTLS_TRANSPORT_FAILED); |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 +0000 | [diff] [blame] | 264 | return false; |
| 265 | } |
| 266 | |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 +0000 | [diff] [blame] | 267 | return true; |
| 268 | } |
| 269 | |
zhihuang | b2cdd93 | 2017-01-19 16:54:25 -0800 | [diff] [blame] | 270 | std::unique_ptr<rtc::SSLCertificate> DtlsTransport::GetRemoteSSLCertificate() |
| 271 | const { |
deadbeef | 2b55867 | 2015-10-26 17:23:29 -0700 | [diff] [blame] | 272 | if (!dtls_) { |
kwiberg | b4d01c4 | 2016-04-06 05:15:06 -0700 | [diff] [blame] | 273 | return nullptr; |
deadbeef | 2b55867 | 2015-10-26 17:23:29 -0700 | [diff] [blame] | 274 | } |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 +0000 | [diff] [blame] | 275 | |
kwiberg | b4d01c4 | 2016-04-06 05:15:06 -0700 | [diff] [blame] | 276 | return dtls_->GetPeerCertificate(); |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 +0000 | [diff] [blame] | 277 | } |
| 278 | |
zhihuang | b2cdd93 | 2017-01-19 16:54:25 -0800 | [diff] [blame] | 279 | bool DtlsTransport::SetupDtls() { |
| 280 | StreamInterfaceChannel* downward = new StreamInterfaceChannel(ice_transport_); |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 +0000 | [diff] [blame] | 281 | |
| 282 | dtls_.reset(rtc::SSLStreamAdapter::Create(downward)); |
| 283 | if (!dtls_) { |
| 284 | LOG_J(LS_ERROR, this) << "Failed to create DTLS adapter."; |
| 285 | delete downward; |
| 286 | return false; |
| 287 | } |
| 288 | |
| 289 | downward_ = downward; |
| 290 | |
Henrik Boström | f3ecdb9 | 2015-09-08 12:11:54 +0200 | [diff] [blame] | 291 | dtls_->SetIdentity(local_certificate_->identity()->GetReference()); |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 +0000 | [diff] [blame] | 292 | dtls_->SetMode(rtc::SSL_MODE_DTLS); |
Joachim Bauch | 831c558 | 2015-05-20 12:48:41 +0200 | [diff] [blame] | 293 | dtls_->SetMaxProtocolVersion(ssl_max_version_); |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 +0000 | [diff] [blame] | 294 | dtls_->SetServerRole(ssl_role_); |
zhihuang | b2cdd93 | 2017-01-19 16:54:25 -0800 | [diff] [blame] | 295 | dtls_->SignalEvent.connect(this, &DtlsTransport::OnDtlsEvent); |
| 296 | dtls_->SignalSSLHandshakeError.connect(this, |
| 297 | &DtlsTransport::OnDtlsHandshakeError); |
deadbeef | 89824f6 | 2016-09-30 11:55:43 -0700 | [diff] [blame] | 298 | if (remote_fingerprint_value_.size() && |
| 299 | !dtls_->SetPeerCertificateDigest( |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 +0000 | [diff] [blame] | 300 | remote_fingerprint_algorithm_, |
kwiberg@webrtc.org | eebcab5 | 2015-03-24 09:19:06 +0000 | [diff] [blame] | 301 | reinterpret_cast<unsigned char*>(remote_fingerprint_value_.data()), |
deadbeef | 81f6f4f | 2016-09-19 17:20:52 -0700 | [diff] [blame] | 302 | remote_fingerprint_value_.size())) { |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 +0000 | [diff] [blame] | 303 | LOG_J(LS_ERROR, this) << "Couldn't set DTLS certificate digest."; |
| 304 | return false; |
| 305 | } |
| 306 | |
| 307 | // Set up DTLS-SRTP, if it's been enabled. |
| 308 | if (!srtp_ciphers_.empty()) { |
Guo-wei Shieh | 521ed7b | 2015-11-18 19:41:53 -0800 | [diff] [blame] | 309 | if (!dtls_->SetDtlsSrtpCryptoSuites(srtp_ciphers_)) { |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 +0000 | [diff] [blame] | 310 | LOG_J(LS_ERROR, this) << "Couldn't set DTLS-SRTP ciphers."; |
| 311 | return false; |
| 312 | } |
| 313 | } else { |
deadbeef | 2b55867 | 2015-10-26 17:23:29 -0700 | [diff] [blame] | 314 | LOG_J(LS_INFO, this) << "Not using DTLS-SRTP."; |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 +0000 | [diff] [blame] | 315 | } |
| 316 | |
| 317 | LOG_J(LS_INFO, this) << "DTLS setup complete."; |
deadbeef | 367efdc | 2016-07-13 12:10:17 -0700 | [diff] [blame] | 318 | |
zhihuang | b2cdd93 | 2017-01-19 16:54:25 -0800 | [diff] [blame] | 319 | // If the underlying ice_transport is already writable at this point, we may |
| 320 | // be able to start DTLS right away. |
deadbeef | 367efdc | 2016-07-13 12:10:17 -0700 | [diff] [blame] | 321 | MaybeStartDtls(); |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 +0000 | [diff] [blame] | 322 | return true; |
| 323 | } |
| 324 | |
zhihuang | b2cdd93 | 2017-01-19 16:54:25 -0800 | [diff] [blame] | 325 | bool DtlsTransport::GetSrtpCryptoSuite(int* cipher) { |
deadbeef | 2b55867 | 2015-10-26 17:23:29 -0700 | [diff] [blame] | 326 | if (dtls_state() != DTLS_TRANSPORT_CONNECTED) { |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 +0000 | [diff] [blame] | 327 | return false; |
| 328 | } |
| 329 | |
Guo-wei Shieh | 521ed7b | 2015-11-18 19:41:53 -0800 | [diff] [blame] | 330 | return dtls_->GetDtlsSrtpCryptoSuite(cipher); |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 +0000 | [diff] [blame] | 331 | } |
| 332 | |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 +0000 | [diff] [blame] | 333 | // Called from upper layers to send a media packet. |
zhihuang | b2cdd93 | 2017-01-19 16:54:25 -0800 | [diff] [blame] | 334 | int DtlsTransport::SendPacket(const char* data, |
| 335 | size_t size, |
| 336 | const rtc::PacketOptions& options, |
| 337 | int flags) { |
deadbeef | 2b55867 | 2015-10-26 17:23:29 -0700 | [diff] [blame] | 338 | if (!dtls_active_) { |
| 339 | // Not doing DTLS. |
zhihuang | b2cdd93 | 2017-01-19 16:54:25 -0800 | [diff] [blame] | 340 | return ice_transport_->SendPacket(data, size, options); |
deadbeef | 2b55867 | 2015-10-26 17:23:29 -0700 | [diff] [blame] | 341 | } |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 +0000 | [diff] [blame] | 342 | |
deadbeef | 2b55867 | 2015-10-26 17:23:29 -0700 | [diff] [blame] | 343 | switch (dtls_state()) { |
| 344 | case DTLS_TRANSPORT_NEW: |
| 345 | // Can't send data until the connection is active. |
| 346 | // TODO(ekr@rtfm.com): assert here if dtls_ is NULL? |
| 347 | return -1; |
| 348 | case DTLS_TRANSPORT_CONNECTING: |
| 349 | // Can't send data until the connection is active. |
| 350 | return -1; |
| 351 | case DTLS_TRANSPORT_CONNECTED: |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 +0000 | [diff] [blame] | 352 | if (flags & PF_SRTP_BYPASS) { |
nisse | ede5da4 | 2017-01-12 05:15:36 -0800 | [diff] [blame] | 353 | RTC_DCHECK(!srtp_ciphers_.empty()); |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 +0000 | [diff] [blame] | 354 | if (!IsRtpPacket(data, size)) { |
deadbeef | 2b55867 | 2015-10-26 17:23:29 -0700 | [diff] [blame] | 355 | return -1; |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 +0000 | [diff] [blame] | 356 | } |
| 357 | |
zhihuang | b2cdd93 | 2017-01-19 16:54:25 -0800 | [diff] [blame] | 358 | return ice_transport_->SendPacket(data, size, options); |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 +0000 | [diff] [blame] | 359 | } else { |
deadbeef | 2b55867 | 2015-10-26 17:23:29 -0700 | [diff] [blame] | 360 | return (dtls_->WriteAll(data, size, NULL, NULL) == rtc::SR_SUCCESS) |
| 361 | ? static_cast<int>(size) |
| 362 | : -1; |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 +0000 | [diff] [blame] | 363 | } |
deadbeef | 2b55867 | 2015-10-26 17:23:29 -0700 | [diff] [blame] | 364 | case DTLS_TRANSPORT_FAILED: |
| 365 | case DTLS_TRANSPORT_CLOSED: |
| 366 | // Can't send anything when we're closed. |
| 367 | return -1; |
| 368 | default: |
nisse | c80e741 | 2017-01-11 05:56:46 -0800 | [diff] [blame] | 369 | RTC_NOTREACHED(); |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 +0000 | [diff] [blame] | 370 | return -1; |
| 371 | } |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 +0000 | [diff] [blame] | 372 | } |
| 373 | |
zhihuang | b2cdd93 | 2017-01-19 16:54:25 -0800 | [diff] [blame] | 374 | bool DtlsTransport::IsDtlsConnected() { |
deadbeef | 89824f6 | 2016-09-30 11:55:43 -0700 | [diff] [blame] | 375 | return dtls_ && dtls_->IsTlsConnected(); |
| 376 | } |
| 377 | |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 +0000 | [diff] [blame] | 378 | // The state transition logic here is as follows: |
| 379 | // (1) If we're not doing DTLS-SRTP, then the state is just the |
| 380 | // state of the underlying impl() |
| 381 | // (2) If we're doing DTLS-SRTP: |
Peter Thatcher | 04ac81f | 2015-09-21 11:48:28 -0700 | [diff] [blame] | 382 | // - Prior to the DTLS handshake, the state is neither receiving nor |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 +0000 | [diff] [blame] | 383 | // writable |
| 384 | // - When the impl goes writable for the first time we |
| 385 | // start the DTLS handshake |
| 386 | // - Once the DTLS handshake completes, the state is that of the |
| 387 | // impl again |
deadbeef | 5bd5ca3 | 2017-02-10 11:31:50 -0800 | [diff] [blame] | 388 | void DtlsTransport::OnWritableState(rtc::PacketTransportInternal* transport) { |
nisse | ede5da4 | 2017-01-12 05:15:36 -0800 | [diff] [blame] | 389 | RTC_DCHECK(rtc::Thread::Current() == network_thread_); |
zhihuang | b2cdd93 | 2017-01-19 16:54:25 -0800 | [diff] [blame] | 390 | RTC_DCHECK(transport == ice_transport_); |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 +0000 | [diff] [blame] | 391 | LOG_J(LS_VERBOSE, this) |
zhihuang | b2cdd93 | 2017-01-19 16:54:25 -0800 | [diff] [blame] | 392 | << "DTLSTransportChannelWrapper: ice_transport writable state changed to " |
| 393 | << ice_transport_->writable(); |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 +0000 | [diff] [blame] | 394 | |
deadbeef | 2b55867 | 2015-10-26 17:23:29 -0700 | [diff] [blame] | 395 | if (!dtls_active_) { |
| 396 | // Not doing DTLS. |
| 397 | // Note: SignalWritableState fired by set_writable. |
zhihuang | b2cdd93 | 2017-01-19 16:54:25 -0800 | [diff] [blame] | 398 | set_writable(ice_transport_->writable()); |
deadbeef | 2b55867 | 2015-10-26 17:23:29 -0700 | [diff] [blame] | 399 | return; |
| 400 | } |
| 401 | |
| 402 | switch (dtls_state()) { |
| 403 | case DTLS_TRANSPORT_NEW: |
deadbeef | 367efdc | 2016-07-13 12:10:17 -0700 | [diff] [blame] | 404 | MaybeStartDtls(); |
deadbeef | 2b55867 | 2015-10-26 17:23:29 -0700 | [diff] [blame] | 405 | break; |
| 406 | case DTLS_TRANSPORT_CONNECTED: |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 +0000 | [diff] [blame] | 407 | // Note: SignalWritableState fired by set_writable. |
zhihuang | b2cdd93 | 2017-01-19 16:54:25 -0800 | [diff] [blame] | 408 | set_writable(ice_transport_->writable()); |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 +0000 | [diff] [blame] | 409 | break; |
deadbeef | 2b55867 | 2015-10-26 17:23:29 -0700 | [diff] [blame] | 410 | case DTLS_TRANSPORT_CONNECTING: |
| 411 | // Do nothing. |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 +0000 | [diff] [blame] | 412 | break; |
deadbeef | 2b55867 | 2015-10-26 17:23:29 -0700 | [diff] [blame] | 413 | case DTLS_TRANSPORT_FAILED: |
| 414 | case DTLS_TRANSPORT_CLOSED: |
| 415 | // Should not happen. Do nothing. |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 +0000 | [diff] [blame] | 416 | break; |
| 417 | } |
| 418 | } |
| 419 | |
deadbeef | 5bd5ca3 | 2017-02-10 11:31:50 -0800 | [diff] [blame] | 420 | void DtlsTransport::OnReceivingState(rtc::PacketTransportInternal* transport) { |
nisse | ede5da4 | 2017-01-12 05:15:36 -0800 | [diff] [blame] | 421 | RTC_DCHECK(rtc::Thread::Current() == network_thread_); |
zhihuang | b2cdd93 | 2017-01-19 16:54:25 -0800 | [diff] [blame] | 422 | RTC_DCHECK(transport == ice_transport_); |
| 423 | LOG_J(LS_VERBOSE, this) << "DTLSTransportChannelWrapper: ice_transport " |
| 424 | "receiving state changed to " |
| 425 | << ice_transport_->receiving(); |
deadbeef | 2b55867 | 2015-10-26 17:23:29 -0700 | [diff] [blame] | 426 | if (!dtls_active_ || dtls_state() == DTLS_TRANSPORT_CONNECTED) { |
Peter Thatcher | 5436051 | 2015-07-08 11:08:35 -0700 | [diff] [blame] | 427 | // Note: SignalReceivingState fired by set_receiving. |
zhihuang | b2cdd93 | 2017-01-19 16:54:25 -0800 | [diff] [blame] | 428 | set_receiving(ice_transport_->receiving()); |
Peter Thatcher | 5436051 | 2015-07-08 11:08:35 -0700 | [diff] [blame] | 429 | } |
| 430 | } |
| 431 | |
deadbeef | 5bd5ca3 | 2017-02-10 11:31:50 -0800 | [diff] [blame] | 432 | void DtlsTransport::OnReadPacket(rtc::PacketTransportInternal* transport, |
zhihuang | b2cdd93 | 2017-01-19 16:54:25 -0800 | [diff] [blame] | 433 | const char* data, |
| 434 | size_t size, |
| 435 | const rtc::PacketTime& packet_time, |
| 436 | int flags) { |
nisse | ede5da4 | 2017-01-12 05:15:36 -0800 | [diff] [blame] | 437 | RTC_DCHECK(rtc::Thread::Current() == network_thread_); |
zhihuang | b2cdd93 | 2017-01-19 16:54:25 -0800 | [diff] [blame] | 438 | RTC_DCHECK(transport == ice_transport_); |
nisse | ede5da4 | 2017-01-12 05:15:36 -0800 | [diff] [blame] | 439 | RTC_DCHECK(flags == 0); |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 +0000 | [diff] [blame] | 440 | |
deadbeef | 2b55867 | 2015-10-26 17:23:29 -0700 | [diff] [blame] | 441 | if (!dtls_active_) { |
| 442 | // Not doing DTLS. |
| 443 | SignalReadPacket(this, data, size, packet_time, 0); |
| 444 | return; |
| 445 | } |
| 446 | |
| 447 | switch (dtls_state()) { |
| 448 | case DTLS_TRANSPORT_NEW: |
| 449 | if (dtls_) { |
deadbeef | e84cd2e | 2016-05-04 17:16:34 -0700 | [diff] [blame] | 450 | LOG_J(LS_INFO, this) << "Packet received before DTLS started."; |
deadbeef | 2b55867 | 2015-10-26 17:23:29 -0700 | [diff] [blame] | 451 | } else { |
deadbeef | e84cd2e | 2016-05-04 17:16:34 -0700 | [diff] [blame] | 452 | LOG_J(LS_WARNING, this) << "Packet received before we know if we are " |
| 453 | << "doing DTLS or not."; |
| 454 | } |
| 455 | // Cache a client hello packet received before DTLS has actually started. |
| 456 | if (IsDtlsClientHelloPacket(data, size)) { |
| 457 | LOG_J(LS_INFO, this) << "Caching DTLS ClientHello packet until DTLS is " |
| 458 | << "started."; |
| 459 | cached_client_hello_.SetData(data, size); |
deadbeef | 89824f6 | 2016-09-30 11:55:43 -0700 | [diff] [blame] | 460 | // If we haven't started setting up DTLS yet (because we don't have a |
| 461 | // remote fingerprint/role), we can use the client hello as a clue that |
| 462 | // the peer has chosen the client role, and proceed with the handshake. |
| 463 | // The fingerprint will be verified when it's set. |
| 464 | if (!dtls_ && local_certificate_) { |
| 465 | SetSslRole(rtc::SSL_SERVER); |
| 466 | SetupDtls(); |
| 467 | } |
deadbeef | e84cd2e | 2016-05-04 17:16:34 -0700 | [diff] [blame] | 468 | } else { |
| 469 | LOG_J(LS_INFO, this) << "Not a DTLS ClientHello packet; dropping."; |
deadbeef | 2b55867 | 2015-10-26 17:23:29 -0700 | [diff] [blame] | 470 | } |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 +0000 | [diff] [blame] | 471 | break; |
| 472 | |
deadbeef | 2b55867 | 2015-10-26 17:23:29 -0700 | [diff] [blame] | 473 | case DTLS_TRANSPORT_CONNECTING: |
| 474 | case DTLS_TRANSPORT_CONNECTED: |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 +0000 | [diff] [blame] | 475 | // We should only get DTLS or SRTP packets; STUN's already been demuxed. |
| 476 | // Is this potentially a DTLS packet? |
| 477 | if (IsDtlsPacket(data, size)) { |
| 478 | if (!HandleDtlsPacket(data, size)) { |
| 479 | LOG_J(LS_ERROR, this) << "Failed to handle DTLS packet."; |
| 480 | return; |
| 481 | } |
| 482 | } else { |
| 483 | // Not a DTLS packet; our handshake should be complete by now. |
deadbeef | 2b55867 | 2015-10-26 17:23:29 -0700 | [diff] [blame] | 484 | if (dtls_state() != DTLS_TRANSPORT_CONNECTED) { |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 +0000 | [diff] [blame] | 485 | LOG_J(LS_ERROR, this) << "Received non-DTLS packet before DTLS " |
| 486 | << "complete."; |
| 487 | return; |
| 488 | } |
| 489 | |
| 490 | // And it had better be a SRTP packet. |
| 491 | if (!IsRtpPacket(data, size)) { |
| 492 | LOG_J(LS_ERROR, this) << "Received unexpected non-DTLS packet."; |
| 493 | return; |
| 494 | } |
| 495 | |
| 496 | // Sanity check. |
nisse | ede5da4 | 2017-01-12 05:15:36 -0800 | [diff] [blame] | 497 | RTC_DCHECK(!srtp_ciphers_.empty()); |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 +0000 | [diff] [blame] | 498 | |
| 499 | // Signal this upwards as a bypass packet. |
| 500 | SignalReadPacket(this, data, size, packet_time, PF_SRTP_BYPASS); |
| 501 | } |
| 502 | break; |
deadbeef | 2b55867 | 2015-10-26 17:23:29 -0700 | [diff] [blame] | 503 | case DTLS_TRANSPORT_FAILED: |
| 504 | case DTLS_TRANSPORT_CLOSED: |
| 505 | // This shouldn't be happening. Drop the packet. |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 +0000 | [diff] [blame] | 506 | break; |
| 507 | } |
| 508 | } |
| 509 | |
deadbeef | 5bd5ca3 | 2017-02-10 11:31:50 -0800 | [diff] [blame] | 510 | void DtlsTransport::OnSentPacket(rtc::PacketTransportInternal* transport, |
zhihuang | b2cdd93 | 2017-01-19 16:54:25 -0800 | [diff] [blame] | 511 | const rtc::SentPacket& sent_packet) { |
nisse | ede5da4 | 2017-01-12 05:15:36 -0800 | [diff] [blame] | 512 | RTC_DCHECK(rtc::Thread::Current() == network_thread_); |
stefan | c1aeaf0 | 2015-10-15 07:26:07 -0700 | [diff] [blame] | 513 | |
| 514 | SignalSentPacket(this, sent_packet); |
| 515 | } |
| 516 | |
deadbeef | 5bd5ca3 | 2017-02-10 11:31:50 -0800 | [diff] [blame] | 517 | void DtlsTransport::OnReadyToSend(rtc::PacketTransportInternal* transport) { |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 +0000 | [diff] [blame] | 518 | if (writable()) { |
| 519 | SignalReadyToSend(this); |
| 520 | } |
| 521 | } |
| 522 | |
zhihuang | b2cdd93 | 2017-01-19 16:54:25 -0800 | [diff] [blame] | 523 | void DtlsTransport::OnDtlsEvent(rtc::StreamInterface* dtls, int sig, int err) { |
nisse | ede5da4 | 2017-01-12 05:15:36 -0800 | [diff] [blame] | 524 | RTC_DCHECK(rtc::Thread::Current() == network_thread_); |
| 525 | RTC_DCHECK(dtls == dtls_.get()); |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 +0000 | [diff] [blame] | 526 | if (sig & rtc::SE_OPEN) { |
| 527 | // This is the first time. |
| 528 | LOG_J(LS_INFO, this) << "DTLS handshake complete."; |
| 529 | if (dtls_->GetState() == rtc::SS_OPEN) { |
| 530 | // The check for OPEN shouldn't be necessary but let's make |
| 531 | // sure we don't accidentally frob the state if it's closed. |
deadbeef | 2b55867 | 2015-10-26 17:23:29 -0700 | [diff] [blame] | 532 | set_dtls_state(DTLS_TRANSPORT_CONNECTED); |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 +0000 | [diff] [blame] | 533 | set_writable(true); |
| 534 | } |
| 535 | } |
| 536 | if (sig & rtc::SE_READ) { |
| 537 | char buf[kMaxDtlsPacketLen]; |
| 538 | size_t read; |
deadbeef | 89824f6 | 2016-09-30 11:55:43 -0700 | [diff] [blame] | 539 | int read_error; |
jbauch | 7d0a77e | 2017-07-07 13:44:07 -0700 | [diff] [blame] | 540 | rtc::StreamResult ret; |
| 541 | // The underlying DTLS stream may have received multiple DTLS records in |
| 542 | // one packet, so read all of them. |
| 543 | do { |
| 544 | ret = dtls_->Read(buf, sizeof(buf), &read, &read_error); |
| 545 | if (ret == rtc::SR_SUCCESS) { |
| 546 | SignalReadPacket(this, buf, read, rtc::CreatePacketTime(0), 0); |
| 547 | } else if (ret == rtc::SR_EOS) { |
| 548 | // Remote peer shut down the association with no error. |
| 549 | LOG_J(LS_INFO, this) << "DTLS transport closed"; |
| 550 | set_writable(false); |
| 551 | set_dtls_state(DTLS_TRANSPORT_CLOSED); |
| 552 | } else if (ret == rtc::SR_ERROR) { |
| 553 | // Remote peer shut down the association with an error. |
| 554 | LOG_J(LS_INFO, this) << "DTLS transport error, code=" << read_error; |
| 555 | set_writable(false); |
| 556 | set_dtls_state(DTLS_TRANSPORT_FAILED); |
| 557 | } |
| 558 | } while (ret == rtc::SR_SUCCESS); |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 +0000 | [diff] [blame] | 559 | } |
| 560 | if (sig & rtc::SE_CLOSE) { |
nisse | ede5da4 | 2017-01-12 05:15:36 -0800 | [diff] [blame] | 561 | RTC_DCHECK(sig == rtc::SE_CLOSE); // SE_CLOSE should be by itself. |
deadbeef | 2b55867 | 2015-10-26 17:23:29 -0700 | [diff] [blame] | 562 | set_writable(false); |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 +0000 | [diff] [blame] | 563 | if (!err) { |
zhihuang | b2cdd93 | 2017-01-19 16:54:25 -0800 | [diff] [blame] | 564 | LOG_J(LS_INFO, this) << "DTLS transport closed"; |
deadbeef | 2b55867 | 2015-10-26 17:23:29 -0700 | [diff] [blame] | 565 | set_dtls_state(DTLS_TRANSPORT_CLOSED); |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 +0000 | [diff] [blame] | 566 | } else { |
zhihuang | b2cdd93 | 2017-01-19 16:54:25 -0800 | [diff] [blame] | 567 | LOG_J(LS_INFO, this) << "DTLS transport error, code=" << err; |
deadbeef | 2b55867 | 2015-10-26 17:23:29 -0700 | [diff] [blame] | 568 | set_dtls_state(DTLS_TRANSPORT_FAILED); |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 +0000 | [diff] [blame] | 569 | } |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 +0000 | [diff] [blame] | 570 | } |
| 571 | } |
| 572 | |
zhihuang | b2cdd93 | 2017-01-19 16:54:25 -0800 | [diff] [blame] | 573 | void DtlsTransport::MaybeStartDtls() { |
| 574 | if (dtls_ && ice_transport_->writable()) { |
skvlad | d030912 | 2017-02-02 17:18:37 -0800 | [diff] [blame] | 575 | ConfigureHandshakeTimeout(); |
| 576 | |
Taylor Brandstetter | c8762a8 | 2016-08-11 12:01:49 -0700 | [diff] [blame] | 577 | if (dtls_->StartSSL()) { |
deadbeef | 367efdc | 2016-07-13 12:10:17 -0700 | [diff] [blame] | 578 | // This should never fail: |
| 579 | // Because we are operating in a nonblocking mode and all |
| 580 | // incoming packets come in via OnReadPacket(), which rejects |
| 581 | // packets in this state, the incoming queue must be empty. We |
| 582 | // ignore write errors, thus any errors must be because of |
| 583 | // configuration and therefore are our fault. |
nisse | eb4ca4e | 2017-01-12 02:24:27 -0800 | [diff] [blame] | 584 | RTC_NOTREACHED() << "StartSSL failed."; |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 +0000 | [diff] [blame] | 585 | LOG_J(LS_ERROR, this) << "Couldn't start DTLS handshake"; |
deadbeef | 2b55867 | 2015-10-26 17:23:29 -0700 | [diff] [blame] | 586 | set_dtls_state(DTLS_TRANSPORT_FAILED); |
deadbeef | 367efdc | 2016-07-13 12:10:17 -0700 | [diff] [blame] | 587 | return; |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 +0000 | [diff] [blame] | 588 | } |
zhihuang | b2cdd93 | 2017-01-19 16:54:25 -0800 | [diff] [blame] | 589 | LOG_J(LS_INFO, this) << "DtlsTransport: Started DTLS handshake"; |
deadbeef | 2b55867 | 2015-10-26 17:23:29 -0700 | [diff] [blame] | 590 | set_dtls_state(DTLS_TRANSPORT_CONNECTING); |
deadbeef | e84cd2e | 2016-05-04 17:16:34 -0700 | [diff] [blame] | 591 | // Now that the handshake has started, we can process a cached ClientHello |
| 592 | // (if one exists). |
| 593 | if (cached_client_hello_.size()) { |
| 594 | if (ssl_role_ == rtc::SSL_SERVER) { |
| 595 | LOG_J(LS_INFO, this) << "Handling cached DTLS ClientHello packet."; |
| 596 | if (!HandleDtlsPacket(cached_client_hello_.data<char>(), |
| 597 | cached_client_hello_.size())) { |
| 598 | LOG_J(LS_ERROR, this) << "Failed to handle DTLS packet."; |
| 599 | } |
| 600 | } else { |
| 601 | LOG_J(LS_WARNING, this) << "Discarding cached DTLS ClientHello packet " |
| 602 | << "because we don't have the server role."; |
| 603 | } |
| 604 | cached_client_hello_.Clear(); |
| 605 | } |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 +0000 | [diff] [blame] | 606 | } |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 +0000 | [diff] [blame] | 607 | } |
| 608 | |
| 609 | // Called from OnReadPacket when a DTLS packet is received. |
zhihuang | b2cdd93 | 2017-01-19 16:54:25 -0800 | [diff] [blame] | 610 | bool DtlsTransport::HandleDtlsPacket(const char* data, size_t size) { |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 +0000 | [diff] [blame] | 611 | // Sanity check we're not passing junk that |
| 612 | // just looks like DTLS. |
Peter Boström | 0c4e06b | 2015-10-07 12:23:21 +0200 | [diff] [blame] | 613 | const uint8_t* tmp_data = reinterpret_cast<const uint8_t*>(data); |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 +0000 | [diff] [blame] | 614 | size_t tmp_size = size; |
| 615 | while (tmp_size > 0) { |
| 616 | if (tmp_size < kDtlsRecordHeaderLen) |
| 617 | return false; // Too short for the header |
| 618 | |
| 619 | size_t record_len = (tmp_data[11] << 8) | (tmp_data[12]); |
| 620 | if ((record_len + kDtlsRecordHeaderLen) > tmp_size) |
| 621 | return false; // Body too short |
| 622 | |
| 623 | tmp_data += record_len + kDtlsRecordHeaderLen; |
| 624 | tmp_size -= record_len + kDtlsRecordHeaderLen; |
| 625 | } |
| 626 | |
| 627 | // Looks good. Pass to the SIC which ends up being passed to |
| 628 | // the DTLS stack. |
| 629 | return downward_->OnPacketReceived(data, size); |
| 630 | } |
| 631 | |
zhihuang | b2cdd93 | 2017-01-19 16:54:25 -0800 | [diff] [blame] | 632 | void DtlsTransport::set_receiving(bool receiving) { |
| 633 | if (receiving_ == receiving) { |
| 634 | return; |
| 635 | } |
| 636 | receiving_ = receiving; |
| 637 | SignalReceivingState(this); |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 +0000 | [diff] [blame] | 638 | } |
| 639 | |
zhihuang | b2cdd93 | 2017-01-19 16:54:25 -0800 | [diff] [blame] | 640 | void DtlsTransport::set_writable(bool writable) { |
| 641 | if (writable_ == writable) { |
| 642 | return; |
| 643 | } |
| 644 | LOG_J(LS_VERBOSE, this) << "set_writable from:" << writable_ << " to " |
| 645 | << writable; |
| 646 | writable_ = writable; |
| 647 | if (writable_) { |
| 648 | SignalReadyToSend(this); |
| 649 | } |
| 650 | SignalWritableState(this); |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 +0000 | [diff] [blame] | 651 | } |
| 652 | |
zhihuang | b2cdd93 | 2017-01-19 16:54:25 -0800 | [diff] [blame] | 653 | void DtlsTransport::set_dtls_state(DtlsTransportState state) { |
| 654 | if (dtls_state_ == state) { |
| 655 | return; |
| 656 | } |
| 657 | LOG_J(LS_VERBOSE, this) << "set_dtls_state from:" << dtls_state_ << " to " |
| 658 | << state; |
| 659 | dtls_state_ = state; |
| 660 | SignalDtlsState(this, state); |
Honghai Zhang | 7fb69db | 2016-03-14 11:59:18 -0700 | [diff] [blame] | 661 | } |
| 662 | |
zhihuang | b2cdd93 | 2017-01-19 16:54:25 -0800 | [diff] [blame] | 663 | void DtlsTransport::OnDtlsHandshakeError(rtc::SSLHandshakeError error) { |
zhihuang | d82eee0 | 2016-08-26 11:25:05 -0700 | [diff] [blame] | 664 | SignalDtlsHandshakeError(error); |
| 665 | } |
| 666 | |
skvlad | d030912 | 2017-02-02 17:18:37 -0800 | [diff] [blame] | 667 | void DtlsTransport::ConfigureHandshakeTimeout() { |
| 668 | RTC_DCHECK(dtls_); |
| 669 | rtc::Optional<int> rtt = ice_transport_->GetRttEstimate(); |
| 670 | if (rtt) { |
| 671 | // Limit the timeout to a reasonable range in case the ICE RTT takes |
| 672 | // extreme values. |
| 673 | int initial_timeout = std::max(kMinHandshakeTimeout, |
zhihuang | ca6d3b6 | 2017-08-23 18:05:50 -0700 | [diff] [blame] | 674 | std::min(kMaxHandshakeTimeout, 2 * (*rtt))); |
skvlad | d030912 | 2017-02-02 17:18:37 -0800 | [diff] [blame] | 675 | LOG_J(LS_INFO, this) << "configuring DTLS handshake timeout " |
| 676 | << initial_timeout << " based on ICE RTT " << *rtt; |
| 677 | |
| 678 | dtls_->SetInitialRetransmissionTimeout(initial_timeout); |
| 679 | } else { |
| 680 | LOG_J(LS_INFO, this) |
| 681 | << "no RTT estimate - using default DTLS handshake timeout"; |
| 682 | } |
| 683 | } |
| 684 | |
henrike@webrtc.org | 269fb4b | 2014-10-28 22:20:11 +0000 | [diff] [blame] | 685 | } // namespace cricket |